diff options
author | sheaf <sam.derbyshire@gmail.com> | 2022-01-17 10:45:35 +0100 |
---|---|---|
committer | sheaf <sam.derbyshire@gmail.com> | 2022-01-17 14:52:50 +0000 |
commit | f161e890dfd41fd9735f4e259fffe2ce6d00ec1a (patch) | |
tree | e6c54b25f3cbb87458dea92c04e23993997e3746 /compiler/GHC/Rename | |
parent | a13aff98cfccddee285b6550dd08c6ec1a3c4e17 (diff) | |
download | haskell-f161e890dfd41fd9735f4e259fffe2ce6d00ec1a.tar.gz |
Use diagnostic infrastructure in GHC.Tc.Errors
Diffstat (limited to 'compiler/GHC/Rename')
-rw-r--r-- | compiler/GHC/Rename/Env.hs | 105 | ||||
-rw-r--r-- | compiler/GHC/Rename/HsType.hs | 7 | ||||
-rw-r--r-- | compiler/GHC/Rename/Module.hs | 13 | ||||
-rw-r--r-- | compiler/GHC/Rename/Pat.hs | 4 | ||||
-rw-r--r-- | compiler/GHC/Rename/Unbound.hs | 239 | ||||
-rw-r--r-- | compiler/GHC/Rename/Utils.hs | 8 |
6 files changed, 132 insertions, 244 deletions
diff --git a/compiler/GHC/Rename/Env.hs b/compiler/GHC/Rename/Env.hs index b666defcb3..a3c126222f 100644 --- a/compiler/GHC/Rename/Env.hs +++ b/compiler/GHC/Rename/Env.hs @@ -73,6 +73,7 @@ import GHC.Types.Name import GHC.Types.Name.Set import GHC.Types.Name.Env import GHC.Types.Avail +import GHC.Types.Hint import GHC.Types.Error import GHC.Unit.Module import GHC.Unit.Module.ModIface @@ -97,10 +98,9 @@ import GHC.Rename.Unbound import GHC.Rename.Utils import qualified Data.Semigroup as Semi import Data.Either ( partitionEithers ) -import Data.List ( find, sortBy ) +import Data.List ( find ) import qualified Data.List.NonEmpty as NE import Control.Arrow ( first ) -import Data.Function import GHC.Types.FieldLabel import GHC.Data.Bag import GHC.Types.PkgQual @@ -300,7 +300,7 @@ lookupLocatedTopBndrRnN = wrapLocMA (lookupTopBndrRn WL_Anything) -- | Lookup an @Exact@ @RdrName@. See Note [Looking up Exact RdrNames]. -- This never adds an error, but it may return one, see -- Note [Errors in lookup functions] -lookupExactOcc_either :: Name -> RnM (Either SDoc Name) +lookupExactOcc_either :: Name -> RnM (Either NotInScopeError Name) lookupExactOcc_either name | Just thing <- wiredInNameTyThing_maybe name , Just tycon <- case thing of @@ -341,28 +341,12 @@ lookupExactOcc_either name ; th_topnames <- readTcRef th_topnames_var ; if name `elemNameSet` th_topnames then return (Right name) - else return (Left (exactNameErr name)) + else return (Left (NoExactName name)) } } - gres -> return (Left (sameNameErr gres)) -- Ugh! See Note [Template Haskell ambiguity] - } - -sameNameErr :: [GlobalRdrElt] -> SDoc -sameNameErr [] = panic "addSameNameErr: empty list" -sameNameErr gres@(_ : _) - = hang (text "Same exact name in multiple name-spaces:") - 2 (vcat (map pp_one sorted_names) $$ th_hint) - where - sorted_names = sortBy (SrcLoc.leftmost_smallest `on` nameSrcSpan) (map greMangledName gres) - pp_one name - = hang (pprNameSpace (occNameSpace (getOccName name)) - <+> quotes (ppr name) <> comma) - 2 (text "declared at:" <+> ppr (nameSrcLoc name)) - - th_hint = vcat [ text "Probable cause: you bound a unique Template Haskell name (NameU)," - , text "perhaps via newName, in different name-spaces." - , text "If that's it, then -ddump-splices might be useful" ] + gres -> return (Left (SameName gres)) -- Ugh! See Note [Template Haskell ambiguity] + } ----------------------------------------------- lookupInstDeclBndr :: Name -> SDoc -> RdrName -> RnM Name @@ -393,7 +377,7 @@ lookupInstDeclBndr cls what rdr -- when it's used cls doc rdr ; case mb_name of - Left err -> do { addErr (TcRnUnknownMessage $ mkPlainError noHints err) + Left err -> do { addErr (mkTcRnNotInScope rdr err) ; return (mkUnboundNameRdr rdr) } Right nm -> return nm } where @@ -441,7 +425,7 @@ lookupExactOrOrig rdr_name res k ; case men of FoundExactOrOrig n -> return (res n) ExactOrOrigError e -> - do { addErr (TcRnUnknownMessage $ mkPlainError noHints e) + do { addErr (mkTcRnNotInScope rdr_name e) ; return (res (mkUnboundNameRdr rdr_name)) } NotExactOrOrig -> k } @@ -457,9 +441,9 @@ lookupExactOrOrig_maybe rdr_name res k NotExactOrOrig -> k } data ExactOrOrigResult = FoundExactOrOrig Name -- ^ Found an Exact Or Orig Name - | ExactOrOrigError SDoc -- ^ The RdrName was an Exact - -- or Orig, but there was an - -- error looking up the Name + | ExactOrOrigError NotInScopeError -- ^ The RdrName was an Exact + -- or Orig, but there was an + -- error looking up the Name | NotExactOrOrig -- ^ The RdrName is neither an Exact nor -- Orig @@ -848,7 +832,7 @@ lookupSubBndrOcc :: Bool -> Name -- Parent -> SDoc -> RdrName - -> RnM (Either SDoc Name) + -> RnM (Either NotInScopeError Name) -- Find all the things the rdr-name maps to -- and pick the one with the right parent namep lookupSubBndrOcc warn_if_deprec the_parent doc rdr_name = do @@ -857,12 +841,12 @@ lookupSubBndrOcc warn_if_deprec the_parent doc rdr_name = do -- This happens for built-in classes, see mod052 for example lookupSubBndrOcc_helper True warn_if_deprec the_parent rdr_name case res of - NameNotFound -> return (Left (unknownSubordinateErr doc rdr_name)) + NameNotFound -> return (Left (UnknownSubordinate doc)) FoundChild _p child -> return (Right (greNameMangledName child)) IncorrectParent {} -- See [Mismatched class methods and associated type families] -- in TcInstDecls. - -> return $ Left (unknownSubordinateErr doc rdr_name) + -> return $ Left (UnknownSubordinate doc) {- Note [Family instance binders] @@ -1087,17 +1071,14 @@ lookup_demoted rdr_name -- Maybe it's the name of a *data* constructor = do { data_kinds <- xoptM LangExt.DataKinds ; star_is_type <- xoptM LangExt.StarIsType - ; let star_info = starInfo star_is_type rdr_name + ; let is_star_type = if star_is_type then StarIsType else StarIsNotType + star_is_type_hints = noStarIsTypeHints is_star_type rdr_name ; if data_kinds then do { mb_demoted_name <- lookupOccRn_maybe demoted_rdr ; case mb_demoted_name of - Nothing -> unboundNameX looking_for rdr_name star_info + Nothing -> unboundNameX looking_for rdr_name star_is_type_hints Just demoted_name -> - do { let msg = TcRnUnknownMessage $ - mkPlainDiagnostic (WarningWithFlag Opt_WarnUntickedPromotedConstructors) - noHints - (untickedPromConstrWarn demoted_name) - ; addDiagnostic msg + do { addDiagnostic $ TcRnUntickedPromotedConstructor demoted_name ; return demoted_name } } else do { -- We need to check if a data constructor of this name is -- in scope to give good error messages. However, we do @@ -1105,8 +1086,11 @@ lookup_demoted rdr_name -- constructor happens to be out of scope! See #13947. mb_demoted_name <- discardErrs $ lookupOccRn_maybe demoted_rdr - ; let suggestion | isJust mb_demoted_name = suggest_dk - | otherwise = star_info + ; let suggestion | isJust mb_demoted_name + , let additional = text "to refer to the data constructor of that name?" + = [SuggestExtension $ SuggestSingleExtension additional LangExt.DataKinds] + | otherwise + = star_is_type_hints ; unboundNameX looking_for rdr_name suggestion } } | otherwise @@ -1114,14 +1098,6 @@ lookup_demoted rdr_name where looking_for = LF WL_Constructor WL_Anywhere - suggest_dk = text "A data constructor of that name is in scope; did you mean DataKinds?" - untickedPromConstrWarn name = - text "Unticked promoted constructor" <> colon <+> quotes (ppr name) <> dot - $$ - hsep [ text "Use" - , quotes (char '\'' <> ppr name) - , text "instead of" - , quotes (ppr name) <> dot ] -- If the given RdrName can be promoted to the type level and its promoted variant is in scope, -- lookup_promoted returns the corresponding type-level Name. @@ -1822,7 +1798,7 @@ lookupSigCtxtOccRnN ctxt what = wrapLocMA $ \ rdr_name -> do { mb_name <- lookupBindGroupOcc ctxt what rdr_name ; case mb_name of - Left err -> do { addErr (TcRnUnknownMessage $ mkPlainError noHints err) + Left err -> do { addErr (mkTcRnNotInScope rdr_name err) ; return (mkUnboundNameRdr rdr_name) } Right name -> return name } @@ -1835,13 +1811,13 @@ lookupSigCtxtOccRn ctxt what = wrapLocMA $ \ rdr_name -> do { mb_name <- lookupBindGroupOcc ctxt what rdr_name ; case mb_name of - Left err -> do { addErr (TcRnUnknownMessage $ mkPlainError noHints err) + Left err -> do { addErr (mkTcRnNotInScope rdr_name err) ; return (mkUnboundNameRdr rdr_name) } Right name -> return name } lookupBindGroupOcc :: HsSigCtxt -> SDoc - -> RdrName -> RnM (Either SDoc Name) + -> RdrName -> RnM (Either NotInScopeError Name) -- Looks up the RdrName, expecting it to resolve to one of the -- bound names passed in. If not, return an appropriate error message -- @@ -1903,31 +1879,23 @@ lookupBindGroupOcc ctxt what rdr_name | otherwise -> bale_out_with local_msg Nothing -> bale_out_with candidates_msg } - bale_out_with msg - = return (Left (sep [ text "The" <+> what - <+> text "for" <+> quotes (ppr rdr_name) - , nest 2 $ text "lacks an accompanying binding"] - $$ nest 2 msg)) + bale_out_with hints = return (Left $ MissingBinding what hints) - local_msg = parens $ text "The" <+> what <+> text "must be given where" - <+> quotes (ppr rdr_name) <+> text "is declared" + local_msg = [SuggestMoveToDeclarationSite what rdr_name] -- Identify all similar names and produce a message listing them - candidates :: [Name] -> SDoc + candidates :: [Name] -> [GhcHint] candidates names_in_scope - = case similar_names of - [] -> Outputable.empty - [n] -> text "Perhaps you meant" <+> pp_item n - _ -> sep [ text "Perhaps you meant one of these:" - , nest 2 (pprWithCommas pp_item similar_names) ] + | (nm : nms) <- map SimilarName similar_names + = [SuggestSimilarNames rdr_name (nm NE.:| nms)] + | otherwise + = [] where similar_names = fuzzyLookup (unpackFS $ occNameFS $ rdrNameOcc rdr_name) $ map (\x -> ((unpackFS $ occNameFS $ nameOccName x), x)) names_in_scope - pp_item x = quotes (ppr x) <+> parens (pprDefinedAt x) - --------------- lookupLocalTcNames :: HsSigCtxt -> SDoc -> RdrName -> RnM [(RdrName, Name)] @@ -1939,7 +1907,7 @@ lookupLocalTcNames ctxt what rdr_name = do { mb_gres <- mapM lookup (dataTcOccs rdr_name) ; let (errs, names) = partitionEithers mb_gres ; when (null names) $ - addErr (TcRnUnknownMessage $ mkPlainError noHints (head errs)) -- Bleat about one only + addErr (head errs) -- Bleat about one only ; return names } where lookup rdr = do { this_mod <- getModule @@ -1950,10 +1918,11 @@ lookupLocalTcNames ctxt what rdr_name guard_builtin_syntax this_mod rdr (Right name) | Just _ <- isBuiltInOcc_maybe (occName rdr) , this_mod /= nameModule name - = Left (hsep [text "Illegal", what, text "of built-in syntax:", ppr rdr]) + = Left $ TcRnIllegalBuiltinSyntax what rdr | otherwise = Right (rdr, name) - guard_builtin_syntax _ _ (Left err) = Left err + guard_builtin_syntax _ _ (Left err) + = Left $ mkTcRnNotInScope rdr_name err dataTcOccs :: RdrName -> [RdrName] -- Return both the given name and the same name promoted to the TcClsName diff --git a/compiler/GHC/Rename/HsType.hs b/compiler/GHC/Rename/HsType.hs index 6740e02430..145e6f08ec 100644 --- a/compiler/GHC/Rename/HsType.hs +++ b/compiler/GHC/Rename/HsType.hs @@ -51,12 +51,12 @@ import GHC.Rename.Env import GHC.Rename.Utils ( HsDocContext(..), inHsDocContext, withHsDocContext , mapFvRn, pprHsDocContext, bindLocalNamesFV , typeAppErr, newLocalBndrRn, checkDupRdrNamesN - , checkShadowedRdrNames - , warnForallIdentifier ) + , checkShadowedRdrNames, warnForallIdentifier ) import GHC.Rename.Fixity ( lookupFieldFixityRn, lookupFixityRn , lookupTyFixityRn ) import GHC.Rename.Unbound ( notInScopeErr, WhereLooking(WL_LocalOnly) ) import GHC.Tc.Errors.Types +import GHC.Tc.Errors.Ppr ( pprScopeError ) import GHC.Tc.Utils.Monad import GHC.Types.Name.Reader import GHC.Builtin.Names @@ -752,10 +752,11 @@ rnHsTyKi env (XHsType ty) check_in_scope :: RdrName -> RnM () check_in_scope rdr_name = do mb_name <- lookupLocalOccRn_maybe rdr_name + -- TODO: refactor this to avoid TcRnUnknownMessage when (isNothing mb_name) $ addErr $ TcRnUnknownMessage $ mkPlainError noHints $ withHsDocContext (rtke_ctxt env) $ - notInScopeErr WL_LocalOnly rdr_name + pprScopeError rdr_name (notInScopeErr WL_LocalOnly rdr_name) rnHsTyKi env ty@(HsExplicitListTy _ ip tys) = do { data_kinds <- xoptM LangExt.DataKinds diff --git a/compiler/GHC/Rename/Module.hs b/compiler/GHC/Rename/Module.hs index d2f5463d58..5884747609 100644 --- a/compiler/GHC/Rename/Module.hs +++ b/compiler/GHC/Rename/Module.hs @@ -31,10 +31,9 @@ import GHC.Rename.Env import GHC.Rename.Utils ( HsDocContext(..), mapFvRn, bindLocalNames , checkDupRdrNamesN, bindLocalNamesFV , checkShadowedRdrNames, warnUnusedTypePatterns - , warnForallIdentifier , newLocalBndrsRn , withHsDocContext, noNestedForallsContextsErr - , addNoNestedForallsContextsErr, checkInferredVars ) + , addNoNestedForallsContextsErr, checkInferredVars, warnForallIdentifier ) import GHC.Rename.Unbound ( mkUnboundName, notInScopeErr, WhereLooking(WL_Global) ) import GHC.Rename.Names import GHC.Tc.Errors.Types @@ -68,6 +67,7 @@ import GHC.Data.Graph.Directed ( SCC, flattenSCC, flattenSCCs, Node(..) import GHC.Types.Unique.Set import GHC.Data.OrdList import qualified GHC.LanguageExtensions as LangExt +import GHC.Tc.Errors.Ppr (pprScopeError) import Control.Monad import Control.Arrow ( first ) @@ -1353,9 +1353,12 @@ badRuleLhsErr name lhs bad_e $$ text "LHS must be of form (f e1 .. en) where f is not forall'd" where - err = case bad_e of - HsUnboundVar _ uv -> notInScopeErr WL_Global (mkRdrUnqual uv) - _ -> text "Illegal expression:" <+> ppr bad_e + err = + case bad_e of + HsUnboundVar _ uv -> + let rdr = mkRdrUnqual uv + in pprScopeError rdr $ notInScopeErr WL_Global (mkRdrUnqual uv) + _ -> text "Illegal expression:" <+> ppr bad_e {- ************************************************************** * * diff --git a/compiler/GHC/Rename/Pat.hs b/compiler/GHC/Rename/Pat.hs index 79eeaa3477..2062b2e23a 100644 --- a/compiler/GHC/Rename/Pat.hs +++ b/compiler/GHC/Rename/Pat.hs @@ -53,10 +53,10 @@ import GHC.Tc.Utils.Zonk ( hsOverLitName ) import GHC.Rename.Env import GHC.Rename.Fixity import GHC.Rename.Utils ( HsDocContext(..), newLocalBndrRn, bindLocalNames - , warnUnusedMatches, warnForallIdentifier + , warnUnusedMatches, newLocalBndrRn , checkUnusedRecordWildcard , checkDupNames, checkDupAndShadowedNames - , wrapGenSpan, genHsApps, genLHsVar, genHsIntegralLit ) + , wrapGenSpan, genHsApps, genLHsVar, genHsIntegralLit, warnForallIdentifier ) import GHC.Rename.HsType import GHC.Builtin.Names import GHC.Types.Avail ( greNameMangledName ) diff --git a/compiler/GHC/Rename/Unbound.hs b/compiler/GHC/Rename/Unbound.hs index 6139ee8a8e..5774698375 100644 --- a/compiler/GHC/Rename/Unbound.hs +++ b/compiler/GHC/Rename/Unbound.hs @@ -1,3 +1,5 @@ +{-# LANGUAGE PatternSynonyms #-} + {- This module contains helper functions for reporting and creating @@ -18,7 +20,6 @@ module GHC.Rename.Unbound , unboundNameX , notInScopeErr , nameSpacesRelated - , exactNameErr ) where @@ -30,7 +31,6 @@ import GHC.Driver.Ppr import GHC.Tc.Errors.Types import GHC.Tc.Utils.Monad import GHC.Builtin.Names ( mkUnboundName, isUnboundName, getUnique) -import GHC.Utils.Outputable as Outputable import GHC.Utils.Misc import GHC.Data.Maybe @@ -38,7 +38,10 @@ import GHC.Data.FastString import qualified GHC.LanguageExtensions as LangExt -import GHC.Types.Error +import GHC.Types.Hint + ( GhcHint (SuggestExtension, RemindFieldSelectorSuppressed, ImportSuggestion, SuggestSimilarNames) + , LanguageExtensionHint (SuggestSingleExtension) + , ImportSuggestion(..), SimilarName(..), HowInScope(..) ) import GHC.Types.SrcLoc as SrcLoc import GHC.Types.Name import GHC.Types.Name.Reader @@ -48,9 +51,12 @@ import GHC.Unit.Module import GHC.Unit.Module.Imported import GHC.Unit.Home.ModInfo +import GHC.Data.Bag +import GHC.Utils.Outputable (empty) + import Data.List (sortBy, partition, nub) +import Data.List.NonEmpty ( pattern (:|), NonEmpty ) import Data.Function ( on ) -import GHC.Data.Bag {- ************************************************************************ @@ -96,113 +102,89 @@ reportUnboundName :: RdrName -> RnM Name reportUnboundName = reportUnboundName' WL_Anything unboundName :: LookingFor -> RdrName -> RnM Name -unboundName lf rdr = unboundNameX lf rdr Outputable.empty +unboundName lf rdr = unboundNameX lf rdr [] -unboundNameX :: LookingFor -> RdrName -> SDoc -> RnM Name -unboundNameX looking_for rdr_name extra +unboundNameX :: LookingFor -> RdrName -> [GhcHint] -> RnM Name +unboundNameX looking_for rdr_name hints = do { dflags <- getDynFlags ; let show_helpful_errors = gopt Opt_HelpfulErrors dflags - err = notInScopeErr (lf_where looking_for) rdr_name $$ extra + err = notInScopeErr (lf_where looking_for) rdr_name ; if not show_helpful_errors - then addErr (TcRnUnknownMessage $ mkPlainError noHints err) + then addErr $ TcRnNotInScope err rdr_name [] hints else do { local_env <- getLocalRdrEnv ; global_env <- getGlobalRdrEnv ; impInfo <- getImports ; currmod <- getModule ; hpt <- getHpt - ; let suggestions = unknownNameSuggestions_ looking_for - dflags hpt currmod global_env local_env impInfo - rdr_name - ; addErr (TcRnUnknownMessage $ mkPlainError noHints (err $$ suggestions)) } + ; let (imp_errs, suggs) = + unknownNameSuggestions_ looking_for + dflags hpt currmod global_env local_env impInfo + rdr_name + ; addErr $ + TcRnNotInScope err rdr_name imp_errs (hints ++ suggs) } ; return (mkUnboundNameRdr rdr_name) } -notInScopeErr :: WhereLooking -> RdrName -> SDoc -notInScopeErr where_look rdr_name - | Just name <- isExact_maybe rdr_name = exactNameErr name - | WL_LocalTop <- where_look = hang (text "No top-level binding for") - 2 (what <+> quotes (ppr rdr_name) <+> text "in this module") - | otherwise = hang (text "Not in scope:") - 2 (what <+> quotes (ppr rdr_name)) - where - what = pprNonVarNameSpace (occNameSpace (rdrNameOcc rdr_name)) - -type HowInScope = Either SrcSpan ImpDeclSpec - -- Left loc => locally bound at loc - -- Right ispec => imported as specified by ispec +notInScopeErr :: WhereLooking -> RdrName -> NotInScopeError +notInScopeErr where_look rdr_name + | Just name <- isExact_maybe rdr_name + = NoExactName name + | WL_LocalTop <- where_look + = NoTopLevelBinding + | otherwise + = NotInScope -- | Called from the typechecker ("GHC.Tc.Errors") when we find an unbound variable unknownNameSuggestions :: WhatLooking -> DynFlags -> HomePackageTable -> Module -> GlobalRdrEnv -> LocalRdrEnv -> ImportAvails - -> RdrName -> SDoc + -> RdrName -> ([ImportError], [GhcHint]) unknownNameSuggestions what_look = unknownNameSuggestions_ (LF what_look WL_Anywhere) unknownNameSuggestions_ :: LookingFor -> DynFlags -> HomePackageTable -> Module -> GlobalRdrEnv -> LocalRdrEnv -> ImportAvails - -> RdrName -> SDoc + -> RdrName -> ([ImportError], [GhcHint]) unknownNameSuggestions_ looking_for dflags hpt curr_mod global_env local_env - imports tried_rdr_name = - similarNameSuggestions looking_for dflags global_env local_env tried_rdr_name $$ - importSuggestions looking_for global_env hpt - curr_mod imports tried_rdr_name $$ - extensionSuggestions tried_rdr_name $$ - fieldSelectorSuggestions global_env tried_rdr_name + imports tried_rdr_name = (imp_errs, suggs) + where + suggs = mconcat + [ if_ne (SuggestSimilarNames tried_rdr_name) $ + similarNameSuggestions looking_for dflags global_env local_env tried_rdr_name + , map ImportSuggestion imp_suggs + , extensionSuggestions tried_rdr_name + , fieldSelectorSuggestions global_env tried_rdr_name ] + (imp_errs, imp_suggs) = importSuggestions looking_for global_env hpt curr_mod imports tried_rdr_name + + if_ne :: (NonEmpty a -> b) -> [a] -> [b] + if_ne _ [] = [] + if_ne f (a : as) = [f (a :| as)] -- | When the name is in scope as field whose selector has been suppressed by -- NoFieldSelectors, display a helpful message explaining this. -fieldSelectorSuggestions :: GlobalRdrEnv -> RdrName -> SDoc +fieldSelectorSuggestions :: GlobalRdrEnv -> RdrName -> [GhcHint] fieldSelectorSuggestions global_env tried_rdr_name - | null gres = Outputable.empty - | otherwise = text "NB:" - <+> quotes (ppr tried_rdr_name) - <+> text "is a field selector" <+> whose - $$ text "that has been suppressed by NoFieldSelectors" + | null gres = [] + | otherwise = [RemindFieldSelectorSuppressed tried_rdr_name parents] where gres = filter isNoFieldSelectorGRE $ lookupGRE_RdrName' tried_rdr_name global_env parents = [ parent | ParentIs parent <- map gre_par gres ] - -- parents may be empty if this is a pattern synonym field without a selector - whose | null parents = empty - | otherwise = text "belonging to the type" <> plural parents - <+> pprQuotedList parents - similarNameSuggestions :: LookingFor -> DynFlags -> GlobalRdrEnv -> LocalRdrEnv - -> RdrName -> SDoc + -> RdrName -> [SimilarName] similarNameSuggestions looking_for@(LF what_look where_look) dflags global_env local_env tried_rdr_name - = case suggest of - [] -> Outputable.empty - [p] -> perhaps <+> pp_item p - ps -> sep [ perhaps <+> text "one of these:" - , nest 2 (pprWithCommas pp_item ps) ] + = fuzzyLookup (showPpr dflags tried_rdr_name) all_possibilities where - all_possibilities :: [(String, (RdrName, HowInScope))] + all_possibilities :: [(String, SimilarName)] all_possibilities = case what_look of WL_None -> [] - _ -> [ (showPpr dflags r, (r, Left loc)) + _ -> [ (showPpr dflags r, SimilarRdrName r (LocallyBoundAt loc)) | (r,loc) <- local_possibilities local_env ] ++ [ (showPpr dflags r, rp) | (r, rp) <- global_possibilities global_env ] - suggest = fuzzyLookup (showPpr dflags tried_rdr_name) all_possibilities - perhaps = text "Perhaps you meant" - - pp_item :: (RdrName, HowInScope) -> SDoc - pp_item (rdr, Left loc) = pp_ns rdr <+> quotes (ppr rdr) <+> loc' -- Locally defined - where loc' = case loc of - UnhelpfulSpan l -> parens (ppr l) - RealSrcSpan l _ -> parens (text "line" <+> int (srcSpanStartLine l)) - pp_item (rdr, Right is) = pp_ns rdr <+> quotes (ppr rdr) <+> -- Imported - parens (text "imported from" <+> ppr (is_mod is)) - - pp_ns :: RdrName -> SDoc - pp_ns rdr | ns /= tried_ns = pprNameSpace ns - | otherwise = Outputable.empty - where ns = rdrNameSpace rdr - tried_occ = rdrNameOcc tried_rdr_name tried_is_sym = isSymOcc tried_occ tried_ns = occNameSpace tried_occ @@ -228,9 +210,9 @@ similarNameSuggestions looking_for@(LF what_look where_look) dflags global_env , let occ = nameOccName name , correct_name_space occ] - global_possibilities :: GlobalRdrEnv -> [(RdrName, (RdrName, HowInScope))] + global_possibilities :: GlobalRdrEnv -> [(RdrName, SimilarName)] global_possibilities global_env - | tried_is_qual = [ (rdr_qual, (rdr_qual, how)) + | tried_is_qual = [ (rdr_qual, SimilarRdrName rdr_qual how) | gre <- globalRdrEnvElts global_env , isGreOk looking_for gre , let occ = greOccName gre @@ -238,14 +220,14 @@ similarNameSuggestions looking_for@(LF what_look where_look) dflags global_env , (mod, how) <- qualsInScope gre , let rdr_qual = mkRdrQual mod occ ] - | otherwise = [ (rdr_unqual, pair) + | otherwise = [ (rdr_unqual, sim) | gre <- globalRdrEnvElts global_env , isGreOk looking_for gre , let occ = greOccName gre rdr_unqual = mkRdrUnqual occ , correct_name_space occ - , pair <- case (unquals_in_scope gre, quals_only gre) of - (how:_, _) -> [ (rdr_unqual, how) ] + , sim <- case (unquals_in_scope gre, quals_only gre) of + (how:_, _) -> [ SimilarRdrName rdr_unqual how ] ([], pr:_) -> [ pr ] -- See Note [Only-quals] ([], []) -> [] ] @@ -262,98 +244,43 @@ similarNameSuggestions looking_for@(LF what_look where_look) dflags global_env -------------------- unquals_in_scope :: GlobalRdrElt -> [HowInScope] unquals_in_scope (gre@GRE { gre_lcl = lcl, gre_imp = is }) - | lcl = [ Left (greDefinitionSrcSpan gre) ] - | otherwise = [ Right ispec + | lcl = [ LocallyBoundAt (greDefinitionSrcSpan gre) ] + | otherwise = [ ImportedBy ispec | i <- bagToList is, let ispec = is_decl i , not (is_qual ispec) ] -------------------- - quals_only :: GlobalRdrElt -> [(RdrName, HowInScope)] + quals_only :: GlobalRdrElt -> [SimilarName] -- Ones for which *only* the qualified version is in scope quals_only (gre@GRE { gre_imp = is }) - = [ (mkRdrQual (is_as ispec) (greOccName gre), Right ispec) + = [ (SimilarRdrName (mkRdrQual (is_as ispec) (greOccName gre)) (ImportedBy ispec)) | i <- bagToList is, let ispec = is_decl i, is_qual ispec ] --- | Generate helpful suggestions if a qualified name Mod.foo is not in scope. + +-- | Generate errors and helpful suggestions if a qualified name Mod.foo is not in scope. importSuggestions :: LookingFor -> GlobalRdrEnv -> HomePackageTable -> Module - -> ImportAvails -> RdrName -> SDoc + -> ImportAvails -> RdrName -> ([ImportError], [ImportSuggestion]) importSuggestions looking_for global_env hpt currMod imports rdr_name - | WL_LocalOnly <- lf_where looking_for = Outputable.empty - | WL_LocalTop <- lf_where looking_for = Outputable.empty - | not (isQual rdr_name || isUnqual rdr_name) = Outputable.empty + | WL_LocalOnly <- lf_where looking_for = ([], []) + | WL_LocalTop <- lf_where looking_for = ([], []) + | not (isQual rdr_name || isUnqual rdr_name) = ([], []) | null interesting_imports , Just name <- mod_name , show_not_imported_line name - = hsep - [ text "No module named" - , quotes (ppr name) - , text "is imported." - ] + = ([MissingModule name], []) | is_qualified , null helpful_imports - , [(mod,_)] <- interesting_imports - = hsep - [ text "Module" - , quotes (ppr mod) - , text "does not export" - , quotes (ppr occ_name) <> dot - ] - | is_qualified - , null helpful_imports - , not (null interesting_imports) - , mods <- map fst interesting_imports - = hsep - [ text "Neither" - , quotedListWithNor (map ppr mods) - , text "exports" - , quotes (ppr occ_name) <> dot - ] - | [(mod,imv)] <- helpful_imports_non_hiding - = fsep - [ text "Perhaps you want to add" - , quotes (ppr occ_name) - , text "to the import list" - , text "in the import of" - , quotes (ppr mod) - , parens (ppr (imv_span imv)) <> dot - ] - | not (null helpful_imports_non_hiding) - = fsep - [ text "Perhaps you want to add" - , quotes (ppr occ_name) - , text "to one of these import lists:" - ] - $$ - nest 2 (vcat - [ quotes (ppr mod) <+> parens (ppr (imv_span imv)) - | (mod,imv) <- helpful_imports_non_hiding - ]) - | [(mod,imv)] <- helpful_imports_hiding - = fsep - [ text "Perhaps you want to remove" - , quotes (ppr occ_name) - , text "from the explicit hiding list" - , text "in the import of" - , quotes (ppr mod) - , parens (ppr (imv_span imv)) <> dot - ] - | not (null helpful_imports_hiding) - = fsep - [ text "Perhaps you want to remove" - , quotes (ppr occ_name) - , text "from the hiding clauses" - , text "in one of these imports:" - ] - $$ - nest 2 (vcat - [ quotes (ppr mod) <+> parens (ppr (imv_span imv)) - | (mod,imv) <- helpful_imports_hiding - ]) + , (mod : mods) <- map fst interesting_imports + = ([ModulesDoNotExport (mod :| mods) occ_name], []) + | mod : mods <- helpful_imports_non_hiding + = ([], [CouldImportFrom (mod :| mods) occ_name]) + | mod : mods <- helpful_imports_hiding + = ([], [CouldUnhideFrom (mod :| mods) occ_name]) | otherwise - = Outputable.empty + = ([], []) where is_qualified = isQual rdr_name (mod_name, occ_name) = case rdr_name of @@ -409,20 +336,21 @@ importSuggestions looking_for global_env hpt currMod imports rdr_name , (mod, _) <- qualsInScope gre ] -extensionSuggestions :: RdrName -> SDoc +extensionSuggestions :: RdrName -> [GhcHint] extensionSuggestions rdrName | rdrName == mkUnqual varName (fsLit "mdo") || rdrName == mkUnqual varName (fsLit "rec") - = text "Perhaps you meant to use RecursiveDo" - | otherwise = Outputable.empty + = [SuggestExtension $ SuggestSingleExtension empty LangExt.RecursiveDo] + | otherwise + = [] qualsInScope :: GlobalRdrElt -> [(ModuleName, HowInScope)] -- Ones for which the qualified version is in scope qualsInScope gre@GRE { gre_lcl = lcl, gre_imp = is } | lcl = case greDefinitionModule gre of Nothing -> [] - Just m -> [(moduleName m, Left (greDefinitionSrcSpan gre))] - | otherwise = [ (is_as ispec, Right ispec) + Just m -> [(moduleName m, LocallyBoundAt (greDefinitionSrcSpan gre))] + | otherwise = [ (is_as ispec, ImportedBy ispec) | i <- bagToList is, let ispec = is_decl i ] isGreOk :: LookingFor -> GlobalRdrElt -> Bool @@ -510,10 +438,3 @@ there are 2 cases, where we hide the last "no module is imported" line: and we have to check the current module in the last added entry of the HomePackageTable. (See test T15611b) -} - -exactNameErr :: Name -> SDoc -exactNameErr name = - hang (text "The exact Name" <+> quotes (ppr name) <+> text "is not in scope") - 2 (vcat [ text "Probable cause: you used a unique Template Haskell name (NameU), " - , text "perhaps via newName, but did not bind it" - , text "If that's it, then -ddump-splices might be useful" ]) diff --git a/compiler/GHC/Rename/Utils.hs b/compiler/GHC/Rename/Utils.hs index 4041b0b6c8..0c2d426450 100644 --- a/compiler/GHC/Rename/Utils.hs +++ b/compiler/GHC/Rename/Utils.hs @@ -18,7 +18,7 @@ module GHC.Rename.Utils ( warnForallIdentifier, checkUnusedRecordWildcard, mkFieldEnv, - unknownSubordinateErr, badQualBndrErr, typeAppErr, + badQualBndrErr, typeAppErr, wrapGenSpan, genHsVar, genLHsVar, genHsApp, genHsApps, genAppType, genHsIntegralLit, genHsTyLit, HsDocContext(..), pprHsDocContext, @@ -595,12 +595,6 @@ addNameClashErrRn rdr_name gres num_non_flds = length non_flds -unknownSubordinateErr :: SDoc -> RdrName -> SDoc -unknownSubordinateErr doc op -- Doc is "method of class" or - -- "field of constructor" - = quotes (ppr op) <+> text "is not a (visible)" <+> doc - - dupNamesErr :: Outputable n => (n -> SrcSpan) -> NE.NonEmpty n -> RnM () dupNamesErr get_loc names = addErrAt big_loc $ TcRnUnknownMessage $ mkPlainError noHints $ |