summaryrefslogtreecommitdiff
path: root/compiler/GHC/Rename
diff options
context:
space:
mode:
authorsheaf <sam.derbyshire@gmail.com>2022-01-17 10:45:35 +0100
committersheaf <sam.derbyshire@gmail.com>2022-01-17 14:52:50 +0000
commitf161e890dfd41fd9735f4e259fffe2ce6d00ec1a (patch)
treee6c54b25f3cbb87458dea92c04e23993997e3746 /compiler/GHC/Rename
parenta13aff98cfccddee285b6550dd08c6ec1a3c4e17 (diff)
downloadhaskell-f161e890dfd41fd9735f4e259fffe2ce6d00ec1a.tar.gz
Use diagnostic infrastructure in GHC.Tc.Errors
Diffstat (limited to 'compiler/GHC/Rename')
-rw-r--r--compiler/GHC/Rename/Env.hs105
-rw-r--r--compiler/GHC/Rename/HsType.hs7
-rw-r--r--compiler/GHC/Rename/Module.hs13
-rw-r--r--compiler/GHC/Rename/Pat.hs4
-rw-r--r--compiler/GHC/Rename/Unbound.hs239
-rw-r--r--compiler/GHC/Rename/Utils.hs8
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 $