summaryrefslogtreecommitdiff
path: root/compiler/GHC
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
parenta13aff98cfccddee285b6550dd08c6ec1a3c4e17 (diff)
downloadhaskell-f161e890dfd41fd9735f4e259fffe2ce6d00ec1a.tar.gz
Use diagnostic infrastructure in GHC.Tc.Errors
Diffstat (limited to 'compiler/GHC')
-rw-r--r--compiler/GHC/Parser/Errors/Ppr.hs11
-rw-r--r--compiler/GHC/Parser/Errors/Types.hs3
-rw-r--r--compiler/GHC/Parser/PostProcess.hs4
-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
-rw-r--r--compiler/GHC/Tc/Errors.hs1950
-rw-r--r--compiler/GHC/Tc/Errors/Hole.hs46
-rw-r--r--compiler/GHC/Tc/Errors/Hole.hs-boot4
-rw-r--r--compiler/GHC/Tc/Errors/Hole/FitTypes.hs-boot24
-rw-r--r--compiler/GHC/Tc/Errors/Ppr.hs1437
-rw-r--r--compiler/GHC/Tc/Errors/Types.hs718
-rw-r--r--compiler/GHC/Tc/Gen/App.hs4
-rw-r--r--compiler/GHC/Tc/Gen/Expr.hs2
-rw-r--r--compiler/GHC/Tc/Gen/Head.hs53
-rw-r--r--compiler/GHC/Tc/Gen/HsType.hs10
-rw-r--r--compiler/GHC/Tc/Gen/Pat.hs2
-rw-r--r--compiler/GHC/Tc/TyCl.hs2
-rw-r--r--compiler/GHC/Tc/TyCl/Instance.hs2
-rw-r--r--compiler/GHC/Tc/Types/Constraint.hs18
-rw-r--r--compiler/GHC/Tc/Types/Origin.hs41
-rw-r--r--compiler/GHC/Tc/Utils/Unify.hs33
-rw-r--r--compiler/GHC/Tc/Utils/Unify.hs-boot7
-rw-r--r--compiler/GHC/Types/Hint.hs170
-rw-r--r--compiler/GHC/Types/Hint/Ppr.hs115
-rw-r--r--compiler/GHC/Types/Name/Reader.hs82
29 files changed, 3074 insertions, 2040 deletions
diff --git a/compiler/GHC/Parser/Errors/Ppr.hs b/compiler/GHC/Parser/Errors/Ppr.hs
index 138a24ccd5..fe9f74eb73 100644
--- a/compiler/GHC/Parser/Errors/Ppr.hs
+++ b/compiler/GHC/Parser/Errors/Ppr.hs
@@ -14,10 +14,11 @@ import GHC.Parser.Errors.Basic
import GHC.Parser.Errors.Types
import GHC.Parser.Types
import GHC.Types.Basic
+import GHC.Types.Hint
import GHC.Types.Error
import GHC.Types.Hint.Ppr (perhapsAsPat)
import GHC.Types.SrcLoc
-import GHC.Types.Name.Reader (opIsAt, starInfo, rdrNameOcc, mkUnqual)
+import GHC.Types.Name.Reader ( opIsAt, rdrNameOcc, mkUnqual )
import GHC.Types.Name.Occurrence (isSymOcc, occNameFS, varName)
import GHC.Utils.Outputable
import GHC.Utils.Misc
@@ -272,10 +273,9 @@ instance Diagnostic PsMessage where
(ppr v)
PsErrTupleSectionInPat
-> mkSimpleDecorated $ text "Tuple section in pattern context"
- PsErrOpFewArgs (StarIsType star_is_type) op
+ PsErrOpFewArgs _ op
-> mkSimpleDecorated $
text "Operator applied to too few arguments:" <+> ppr op
- $$ starInfo star_is_type op
PsErrVarForTyCon name
-> mkSimpleDecorated $
text "Expecting a type constructor but found a variable,"
@@ -610,7 +610,7 @@ instance Diagnostic PsMessage where
PsWarnHaddockInvalidPos -> noHints
PsWarnHaddockIgnoreMulti -> noHints
PsWarnStarBinder -> [SuggestQualifyStarOperator]
- PsWarnStarIsType -> [SuggestUseTypeFromDataKind]
+ PsWarnStarIsType -> [SuggestUseTypeFromDataKind Nothing]
PsWarnUnrecognisedPragma -> noHints
PsWarnImportPreQualified -> [ SuggestQualifiedAfterModuleName
, suggestExtension LangExt.ImportQualifiedPost]
@@ -668,7 +668,8 @@ instance Diagnostic PsMessage where
PsErrUnsupportedBoxedSumPat{} -> noHints
PsErrUnexpectedQualifiedConstructor{} -> noHints
PsErrTupleSectionInPat{} -> noHints
- PsErrOpFewArgs{} -> noHints
+ PsErrOpFewArgs star_is_type op
+ -> noStarIsTypeHints star_is_type op
PsErrVarForTyCon{} -> noHints
PsErrMalformedEntityString -> noHints
PsErrDotsInRecordUpdate -> noHints
diff --git a/compiler/GHC/Parser/Errors/Types.hs b/compiler/GHC/Parser/Errors/Types.hs
index d39048c441..d50b21d7ad 100644
--- a/compiler/GHC/Parser/Errors/Types.hs
+++ b/compiler/GHC/Parser/Errors/Types.hs
@@ -12,6 +12,7 @@ import GHC.Hs
import GHC.Parser.Types
import GHC.Parser.Errors.Basic
import GHC.Types.Error
+import GHC.Types.Hint
import GHC.Types.Name.Occurrence (OccName)
import GHC.Types.Name.Reader
import GHC.Unit.Module.Name
@@ -452,8 +453,6 @@ data PsMessage
| PsErrInvalidCApiImport
-newtype StarIsType = StarIsType Bool
-
-- | Extra details about a parse error, which helps
-- us in determining which should be the hints to
-- suggest.
diff --git a/compiler/GHC/Parser/PostProcess.hs b/compiler/GHC/Parser/PostProcess.hs
index aab72310ac..83b55f5632 100644
--- a/compiler/GHC/Parser/PostProcess.hs
+++ b/compiler/GHC/Parser/PostProcess.hs
@@ -126,6 +126,7 @@ import GHC.Unit.Module (ModuleName)
import GHC.Types.Basic
import GHC.Types.Error
import GHC.Types.Fixity
+import GHC.Types.Hint
import GHC.Types.SourceText
import GHC.Parser.Types
import GHC.Parser.Lexer
@@ -2788,8 +2789,9 @@ warnStarIsType span = addPsMessage span PsWarnStarIsType
failOpFewArgs :: MonadP m => LocatedN RdrName -> m a
failOpFewArgs (L loc op) =
do { star_is_type <- getBit StarIsTypeBit
+ ; let is_star_type = if star_is_type then StarIsType else StarIsNotType
; addFatalError $ mkPlainErrorMsgEnvelope (locA loc) $
- (PsErrOpFewArgs (StarIsType star_is_type) op) }
+ (PsErrOpFewArgs is_star_type op) }
-----------------------------------------------------------------------------
-- Misc utils
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 $
diff --git a/compiler/GHC/Tc/Errors.hs b/compiler/GHC/Tc/Errors.hs
index 0d84dddb1e..b08fd6b3a8 100644
--- a/compiler/GHC/Tc/Errors.hs
+++ b/compiler/GHC/Tc/Errors.hs
@@ -1,6 +1,7 @@
{-# LANGUAGE LambdaCase #-}
{-# LANGUAGE NamedFieldPuns #-}
+{-# LANGUAGE RecordWildCards #-}
{-# LANGUAGE ScopedTypeVariables #-}
{-# OPTIONS_GHC -Wno-incomplete-uni-patterns #-}
@@ -20,6 +21,8 @@ import GHC.Driver.Session
import GHC.Driver.Ppr
import GHC.Driver.Config.Diagnostic
+import GHC.Rename.Unbound
+
import GHC.Tc.Types
import GHC.Tc.Utils.Monad
import GHC.Tc.Errors.Types
@@ -33,7 +36,7 @@ import GHC.Tc.Types.Evidence
import GHC.Tc.Types.EvTerm
import GHC.Tc.Instance.Family
import GHC.Tc.Utils.Instantiate
-import {-# SOURCE #-} GHC.Tc.Errors.Hole ( findValidHoleFits )
+import {-# SOURCE #-} GHC.Tc.Errors.Hole ( findValidHoleFits, getHoleFitDispConfig, pprHoleFit )
import GHC.Types.Name
import GHC.Types.Name.Reader ( lookupGRE_Name, GlobalRdrEnv, mkRdrUnqual
@@ -43,30 +46,22 @@ import GHC.Types.Var
import GHC.Types.Var.Set
import GHC.Types.Var.Env
import GHC.Types.Name.Env
-import GHC.Types.Name.Set
import GHC.Types.SrcLoc
import GHC.Types.Basic
import GHC.Types.Error
-import GHC.Types.Unique.Set ( nonDetEltsUniqSet )
-import GHC.Rename.Unbound ( unknownNameSuggestions, WhatLooking(..) )
+--import GHC.Rename.Unbound ( unknownNameSuggestions, WhatLooking(..) )
import GHC.Unit.Module
-import GHC.Hs.Binds ( PatSynBind(..) )
-import GHC.Builtin.Names ( typeableClassName, pretendNameIsInScope )
import qualified GHC.LanguageExtensions as LangExt
import GHC.Core.Predicate
import GHC.Core.Type
import GHC.Core.Coercion
-import GHC.Core.TyCo.Rep
-import GHC.Core.TyCo.Ppr ( pprTyVars, pprWithExplicitKindsWhen, pprSourceTyCon
- , pprWithTYPE )
-import GHC.Core.Unify ( tcMatchTys )
+import GHC.Core.TyCo.Ppr ( pprTyVars
+ )
import GHC.Core.InstEnv
import GHC.Core.TyCon
-import GHC.Core.Class
import GHC.Core.DataCon
-import GHC.Core.ConLike ( ConLike(..))
import GHC.Utils.Error (diagReasonSeverity, pprLocMsgEnvelope )
import GHC.Utils.Misc
@@ -76,8 +71,6 @@ import GHC.Utils.Panic.Plain
import GHC.Utils.FV ( fvVarList, unionFV )
import GHC.Data.Bag
-import GHC.Data.FastString
-import GHC.Utils.Trace (pprTraceUserWarning)
import GHC.Data.List.SetOps ( equivClasses, nubOrdBy )
import GHC.Data.Maybe
import qualified GHC.Data.Strict as Strict
@@ -86,12 +79,9 @@ import Control.Monad ( unless, when, foldM, forM_ )
import Data.Foldable ( toList )
import Data.Functor ( (<&>) )
import Data.Function ( on )
-import Data.List ( groupBy, partition, mapAccumL
- , sortBy, tails, unfoldr )
-import Data.Ord ( comparing )
--- import Data.Semigroup ( Semigroup )
-import qualified Data.Semigroup as Semigroup
-
+import Data.List ( partition, mapAccumL )
+import Data.List.NonEmpty ( NonEmpty(..), (<|) )
+import qualified Data.List.NonEmpty as NE ( map, reverse )
{-
************************************************************************
@@ -265,102 +255,15 @@ report_unsolved type_errors expr_holes
-- Internal functions
--------------------------------------------
--- | An error Report collects messages categorised by their importance.
--- See Note [Error report] for details.
-data Report
- = Report { report_important :: [SDoc]
- , report_relevant_bindings :: [SDoc]
- , report_valid_hole_fits :: [SDoc]
- }
-
-instance Outputable Report where -- Debugging only
- ppr (Report { report_important = imp
- , report_relevant_bindings = rel
- , report_valid_hole_fits = val })
- = vcat [ text "important:" <+> vcat imp
- , text "relevant:" <+> vcat rel
- , text "valid:" <+> vcat val ]
-
-{- Note [Error report]
-~~~~~~~~~~~~~~~~~~~~~~
-The idea is that error msgs are divided into three parts: the main msg, the
-context block ("In the second argument of ..."), and the relevant bindings
-block, which are displayed in that order, with a mark to divide them. The
-the main msg ('report_important') varies depending on the error
-in question, but context and relevant bindings are always the same, which
-should simplify visual parsing.
-
-The context is added when the Report is passed off to 'mkErrorReport'.
-Unfortunately, unlike the context, the relevant bindings are added in
-multiple places so they have to be in the Report.
--}
+-- | Make a report from a single 'TcReportMsg'.
+important :: ReportErrCtxt -> TcReportMsg -> SolverReport
+important ctxt doc = mempty { sr_important_msgs = [ReportWithCtxt ctxt doc] }
+
+mk_relevant_bindings :: RelevantBindings -> SolverReport
+mk_relevant_bindings binds = mempty { sr_supplementary = [SupplementaryBindings binds] }
-instance Semigroup Report where
- Report a1 b1 c1 <> Report a2 b2 c2 = Report (a1 ++ a2) (b1 ++ b2) (c1 ++ c2)
-
-instance Monoid Report where
- mempty = Report [] [] []
- mappend = (Semigroup.<>)
-
--- | Put a doc into the important msgs block.
-important :: SDoc -> Report
-important doc = mempty { report_important = [doc] }
-
--- | Put a doc into the relevant bindings block.
-mk_relevant_bindings :: SDoc -> Report
-mk_relevant_bindings doc = mempty { report_relevant_bindings = [doc] }
-
--- | Put a doc into the valid hole fits block.
-valid_hole_fits :: SDoc -> Report
-valid_hole_fits docs = mempty { report_valid_hole_fits = [docs] }
-
-data ReportErrCtxt
- = CEC { cec_encl :: [Implication] -- Enclosing implications
- -- (innermost first)
- -- ic_skols and givens are tidied, rest are not
- , cec_tidy :: TidyEnv
-
- , cec_binds :: EvBindsVar -- Make some errors (depending on cec_defer)
- -- into warnings, and emit evidence bindings
- -- into 'cec_binds' for unsolved constraints
-
- , cec_defer_type_errors :: DiagnosticReason -- Defer type errors until runtime
-
- -- cec_expr_holes is a union of:
- -- cec_type_holes - a set of typed holes: '_', '_a', '_foo'
- -- cec_out_of_scope_holes - a set of variables which are
- -- out of scope: 'x', 'y', 'bar'
- , cec_expr_holes :: DiagnosticReason -- Holes in expressions.
- , cec_type_holes :: DiagnosticReason -- Holes in types.
- , cec_out_of_scope_holes :: DiagnosticReason -- Out of scope holes.
-
- , cec_warn_redundant :: Bool -- True <=> -Wredundant-constraints
- , cec_expand_syns :: Bool -- True <=> -fprint-expanded-synonyms
-
- , cec_suppress :: Bool -- True <=> More important errors have occurred,
- -- so create bindings if need be, but
- -- don't issue any more errors/warnings
- -- See Note [Suppressing error messages]
- }
-
-instance Outputable ReportErrCtxt where
- ppr (CEC { cec_binds = bvar
- , cec_defer_type_errors = dte
- , cec_expr_holes = eh
- , cec_type_holes = th
- , cec_out_of_scope_holes = osh
- , cec_warn_redundant = wr
- , cec_expand_syns = es
- , cec_suppress = sup })
- = text "CEC" <+> braces (vcat
- [ text "cec_binds" <+> equals <+> ppr bvar
- , text "cec_defer_type_errors" <+> equals <+> ppr dte
- , text "cec_expr_holes" <+> equals <+> ppr eh
- , text "cec_type_holes" <+> equals <+> ppr th
- , text "cec_out_of_scope_holes" <+> equals <+> ppr osh
- , text "cec_warn_redundant" <+> equals <+> ppr wr
- , text "cec_expand_syns" <+> equals <+> ppr es
- , text "cec_suppress" <+> equals <+> ppr sup ])
+mk_report_hints :: [GhcHint] -> SolverReport
+mk_report_hints hints = mempty { sr_hints = hints }
-- | Returns True <=> the ReportErrCtxt indicates that something is deferred
deferringAnyBindings :: ReportErrCtxt -> Bool
@@ -479,23 +382,28 @@ warnRedundantConstraints ctxt env info ev_vars
| null redundant_evs
= return ()
- | SigSkol user_ctxt _ _ <- info
+ | SigSkol user_ctxt _ _ <- info
= setLclEnv env $ -- We want to add "In the type signature for f"
-- to the error context, which is a bit tiresome
setSrcSpan (redundantConstraintsSpan user_ctxt) $
- addErrCtxt (text "In" <+> ppr info) $
- do { env <- getLclEnv
- ; msg <- mkErrorReport (WarningWithFlag Opt_WarnRedundantConstraints) ctxt env (important doc)
- ; reportDiagnostic msg }
+ report_redundant_msg True
| otherwise -- But for InstSkol there already *is* a surrounding
-- "In the instance declaration for Eq [a]" context
-- and we don't want to say it twice. Seems a bit ad-hoc
- = do { msg <- mkErrorReport (WarningWithFlag Opt_WarnRedundantConstraints) ctxt env (important doc)
- ; reportDiagnostic msg }
+ = report_redundant_msg False
where
- doc = text "Redundant constraint" <> plural redundant_evs <> colon
- <+> pprEvVarTheta redundant_evs
+ report_redundant_msg :: Bool -- ^ whether to add "In ..." to the diagnostic
+ -> TcRn ()
+ report_redundant_msg show_info
+ = do { lcl_env <- getLclEnv
+ ; msg <-
+ mkErrorReport
+ lcl_env
+ (TcRnRedundantConstraints redundant_evs (info, show_info))
+ (Just ctxt)
+ []
+ ; reportDiagnostic msg }
redundant_evs =
filterOut is_type_error $
@@ -511,14 +419,14 @@ warnRedundantConstraints ctxt env info ev_vars
reportBadTelescope :: ReportErrCtxt -> TcLclEnv -> SkolemInfo -> [TcTyVar] -> TcM ()
reportBadTelescope ctxt env (ForAllSkol telescope) skols
- = do { msg <- mkErrorReport ErrorWithoutFlag ctxt env (important doc)
+ = do { msg <- mkErrorReport
+ env
+ (TcRnSolverReport [report] ErrorWithoutFlag noHints)
+ (Just ctxt)
+ []
; reportDiagnostic msg }
where
- doc = hang (text "These kind and type variables:" <+> telescope $$
- text "are out of dependency order. Perhaps try this ordering:")
- 2 (pprTyVars sorted_tvs)
-
- sorted_tvs = scopedSort skols
+ report = ReportWithCtxt ctxt $ BadTelescope telescope skols
reportBadTelescope _ _ skol_info skols
= pprPanic "reportBadTelescope" (ppr skol_info $$ ppr skols)
@@ -810,21 +718,20 @@ machinery, in cases where it is definitely going to be a no-op.
mkUserTypeErrorReporter :: Reporter
mkUserTypeErrorReporter ctxt
- = mapM_ $ \ct -> do { let err = mkUserTypeError ct
+ = mapM_ $ \ct -> do { let err = important ctxt $ mkUserTypeError ct
; maybeReportError ctxt ct err
; addDeferredBinding ctxt err ct }
-mkUserTypeError :: Ct -> Report
-mkUserTypeError ct = important
- $ pprUserTypeErrorTy
- $ case getUserTypeErrorMsg ct of
- Just msg -> msg
- Nothing -> pprPanic "mkUserTypeError" (ppr ct)
+mkUserTypeError :: Ct -> TcReportMsg
+mkUserTypeError ct =
+ case getUserTypeErrorMsg ct of
+ Just msg -> UserTypeError msg
+ Nothing -> pprPanic "mkUserTypeError" (ppr ct)
mkGivenErrorReporter :: Reporter
-- See Note [Given errors]
mkGivenErrorReporter ctxt cts
- = do { (ctxt, binds_msg, ct) <- relevantBindings True ctxt ct
+ = do { (ctxt, relevant_binds, ct) <- relevantBindings True ctxt ct
; let (implic:_) = cec_encl ctxt
-- Always non-empty when mkGivenErrorReporter is called
ct' = setCtLoc ct (setCtLocEnv (ctLoc ct) (ic_env implic))
@@ -832,17 +739,12 @@ mkGivenErrorReporter ctxt cts
-- with one from the immediately-enclosing implication.
-- See Note [Inaccessible code]
- inaccessible_msg = hang (text "Inaccessible code in")
- 2 (ppr (ic_info implic))
- report = important inaccessible_msg `mappend`
- mk_relevant_bindings binds_msg
-
- ; report <- mkEqErr_help ctxt report ct' ty1 ty2
- ; err <- mkErrorReport (WarningWithFlag Opt_WarnInaccessibleCode) ctxt
- (ctLocEnv (ctLoc ct')) report
-
- ; traceTc "mkGivenErrorReporter" (ppr ct)
- ; reportDiagnostic err }
+ ; (eq_err_msgs, _hints) <- mkEqErr_help ctxt ct' ty1 ty2
+ -- The hints wouldn't help in this situation, so we discard them.
+ ; let supplementary = [ SupplementaryBindings relevant_binds ]
+ msg = TcRnInaccessibleCode implic (NE.reverse . NE.map (ReportWithCtxt ctxt) $ eq_err_msgs)
+ ; msg <- mkErrorReport (ctLocEnv (ctLoc ct')) msg (Just ctxt) supplementary
+ ; reportDiagnostic msg }
where
(ct : _ ) = cts -- Never empty
(ty1, ty2) = getEqPredTys (ctPred ct)
@@ -889,7 +791,7 @@ pattern match which binds some equality constraints. If we
find one, we report the insoluble Given.
-}
-mkGroupReporter :: (ReportErrCtxt -> [Ct] -> TcM Report)
+mkGroupReporter :: (ReportErrCtxt -> [Ct] -> TcM SolverReport)
-- Make error message for a group
-> Reporter -- Deal with lots of constraints
-- Group together errors from same location,
@@ -898,7 +800,7 @@ mkGroupReporter mk_err ctxt cts
= mapM_ (reportGroup mk_err ctxt . toList) (equivClasses cmp_loc cts)
-- Like mkGroupReporter, but doesn't actually print error messages
-mkSuppressReporter :: (ReportErrCtxt -> [Ct] -> TcM Report)
+mkSuppressReporter :: (ReportErrCtxt -> [Ct] -> TcM SolverReport)
-> Reporter
mkSuppressReporter mk_err ctxt cts
= mapM_ (suppressGroup mk_err ctxt . toList) (equivClasses cmp_loc cts)
@@ -917,7 +819,7 @@ cmp_loc ct1 ct2 = get ct1 `compare` get ct2
-- Reduce duplication by reporting only one error from each
-- /starting/ location even if the end location differs
-reportGroup :: (ReportErrCtxt -> [Ct] -> TcM Report) -> Reporter
+reportGroup :: (ReportErrCtxt -> [Ct] -> TcM SolverReport) -> Reporter
reportGroup mk_err ctxt cts
| ct1 : _ <- cts =
do { err <- mk_err ctxt cts
@@ -937,7 +839,7 @@ reportGroup mk_err ctxt cts
-- like reportGroup, but does not actually report messages. It still adds
-- -fdefer-type-errors bindings, though.
-suppressGroup :: (ReportErrCtxt -> [Ct] -> TcM Report) -> Reporter
+suppressGroup :: (ReportErrCtxt -> [Ct] -> TcM SolverReport) -> Reporter
suppressGroup mk_err ctxt cts
= do { err <- mk_err ctxt cts
; traceTc "Suppressing errors for" (ppr cts)
@@ -950,16 +852,17 @@ nonDeferrableOrigin (UsageEnvironmentOf {}) = True
nonDeferrableOrigin (FixedRuntimeRepOrigin {}) = True
nonDeferrableOrigin _ = False
-maybeReportError :: ReportErrCtxt -> Ct -> Report -> TcM ()
-maybeReportError ctxt ct report
+maybeReportError :: ReportErrCtxt -> Ct -> SolverReport -> TcM ()
+maybeReportError ctxt ct (SolverReport { sr_important_msgs = important, sr_supplementary = supp, sr_hints = hints })
= unless (cec_suppress ctxt) $ -- Some worse error has occurred, so suppress this diagnostic
do let reason | nonDeferrableOrigin (ctOrigin ct) = ErrorWithoutFlag
| otherwise = cec_defer_type_errors ctxt
-- See Note [No deferring for multiplicity errors]
- msg <- mkErrorReport reason ctxt (ctLocEnv (ctLoc ct)) report
+ diag = TcRnSolverReport important reason hints
+ msg <- mkErrorReport (ctLocEnv (ctLoc ct)) diag (Just ctxt) supp
reportDiagnostic msg
-addDeferredBinding :: ReportErrCtxt -> Report -> Ct -> TcM ()
+addDeferredBinding :: ReportErrCtxt -> SolverReport -> Ct -> TcM ()
-- See Note [Deferring coercion errors to runtime]
addDeferredBinding ctxt err ct
| deferringAnyBindings ctxt
@@ -981,9 +884,11 @@ addDeferredBinding ctxt err ct
= return ()
mkErrorTerm :: ReportErrCtxt -> CtLoc -> Type -- of the error term
- -> Report -> TcM EvTerm
-mkErrorTerm ctxt ct_loc ty report
- = do { msg <- mkErrorReport ErrorWithoutFlag ctxt (ctLocEnv ct_loc) report
+ -> SolverReport -> TcM EvTerm
+mkErrorTerm ctxt ct_loc ty (SolverReport { sr_important_msgs = important, sr_supplementary = supp })
+ = do { msg <- mkErrorReport
+ (ctLocEnv ct_loc)
+ (TcRnSolverReport important ErrorWithoutFlag noHints) (Just ctxt) supp
-- This will be reported at runtime, so we always want "error:" in the report, never "warning:"
; dflags <- getDynFlags
; let err_msg = pprLocMsgEnvelope msg
@@ -1029,75 +934,79 @@ tryReporter ctxt (str, keep_me, suppress_after, reporter) cts
where
(yeses, nos) = partition (\ct -> keep_me ct (classifyPredType (ctPred ct))) cts
-pprArising :: CtOrigin -> SDoc
--- Used for the main, top-level error message
--- We've done special processing for TypeEq, KindEq, givens
-pprArising (TypeEqOrigin {}) = empty
-pprArising (KindEqOrigin {}) = empty
-pprArising orig | isGivenOrigin orig = empty
- | otherwise = pprCtOrigin orig
-
--- Add the "arising from..." part to a message about bunch of dicts
-addArising :: CtOrigin -> SDoc -> SDoc
-addArising orig msg = hang msg 2 (pprArising orig)
-
-pprWithArising :: [Ct] -> (CtLoc, SDoc)
--- Print something like
--- (Eq a) arising from a use of x at y
--- (Show a) arising from a use of p at q
--- Also return a location for the error message
--- Works for Wanted/Derived only
-pprWithArising []
- = panic "pprWithArising"
-pprWithArising (ct:cts)
- | null cts
- = (loc, addArising (ctLocOrigin loc)
- (pprTheta [ctPred ct]))
- | otherwise
- = (loc, vcat (map ppr_one (ct:cts)))
- where
- loc = ctLoc ct
- ppr_one ct' = hang (parens (pprType (ctPred ct')))
- 2 (pprCtLoc (ctLoc ct'))
-
-mkErrorReport :: DiagnosticReason
- -> ReportErrCtxt
- -> TcLclEnv
- -> Report
+-- | Wrap an input 'TcRnMessage' with additional contextual information,
+-- such as relevant bindings or valid hole fits.
+mkErrorReport :: TcLclEnv
+ -> TcRnMessage
+ -- ^ The main payload of the message.
+ -> Maybe ReportErrCtxt
+ -- ^ The context to add, after the main diagnostic
+ -- but before the supplementary information.
+ -- Nothing <=> don't add any context.
+ -> [SolverReportSupplementary]
+ -- ^ Supplementary information, to be added at the end of the message.
-> TcM (MsgEnvelope TcRnMessage)
-mkErrorReport rea ctxt tcl_env (Report important relevant_bindings valid_subs)
- = do { context <- mkErrInfo (cec_tidy ctxt) (tcl_ctxt tcl_env)
- ; unit_state <- hsc_units <$> getTopEnv ;
- ; let err_info = ErrInfo context (vcat $ relevant_bindings ++ valid_subs)
- ; let msg = TcRnUnknownMessage $ mkPlainDiagnostic rea noHints (vcat important)
+mkErrorReport tcl_env msg mb_ctxt supplementary
+ = do { mb_context <- traverse (\ ctxt -> mkErrInfo (cec_tidy ctxt) (tcl_ctxt tcl_env)) mb_ctxt
+ ; unit_state <- hsc_units <$> getTopEnv
+ ; hfdc <- getHoleFitDispConfig
+ ; let
+ err_info =
+ ErrInfo
+ (fromMaybe empty mb_context)
+ (vcat $ map (pprSolverReportSupplementary hfdc) supplementary)
; mkTcRnMessage
(RealSrcSpan (tcl_loc tcl_env) Strict.Nothing)
- (TcRnMessageWithInfo unit_state $ TcRnMessageDetailed err_info msg)
- }
-
--- This version does not include the context
-mkErrorReportNC :: DiagnosticReason
- -> TcLclEnv
- -> Report
- -> TcM (MsgEnvelope TcRnMessage)
-mkErrorReportNC rea tcl_env (Report important relevant_bindings valid_subs)
- = do { unit_state <- hsc_units <$> getTopEnv ;
- ; let err_info = ErrInfo O.empty (vcat $ relevant_bindings ++ valid_subs)
- ; let msg = TcRnUnknownMessage $ mkPlainDiagnostic rea noHints (vcat important)
- ; mkTcRnMessage
- (RealSrcSpan (tcl_loc tcl_env) Strict.Nothing)
- (TcRnMessageWithInfo unit_state $ TcRnMessageDetailed err_info msg)
- }
-
-type UserGiven = Implication
+ (TcRnMessageWithInfo unit_state $ TcRnMessageDetailed err_info msg) }
+
+-- | Pretty-print supplementary information, to add to an error report.
+pprSolverReportSupplementary :: HoleFitDispConfig -> SolverReportSupplementary -> SDoc
+-- This function should be in "GHC.Tc.Errors.Ppr",
+-- but we need it here because 'TcRnMessageDetails' needs an 'SDoc'.
+pprSolverReportSupplementary hfdc = \case
+ SupplementaryBindings binds -> pprRelevantBindings binds
+ SupplementaryHoleFits fits -> pprValidHoleFits hfdc fits
+ SupplementaryCts cts -> pprConstraintsInclude cts
+
+-- | Display a collection of valid hole fits.
+pprValidHoleFits :: HoleFitDispConfig -> ValidHoleFits -> SDoc
+-- This function should be in "GHC.Tc.Errors.Ppr",
+-- but we need it here because 'TcRnMessageDetails' needs an 'SDoc'.
+pprValidHoleFits hfdc (ValidHoleFits (Fits fits discarded_fits) (Fits refs discarded_refs))
+ = fits_msg $$ refs_msg
-getUserGivens :: ReportErrCtxt -> [UserGiven]
--- One item for each enclosing implication
-getUserGivens (CEC {cec_encl = implics}) = getUserGivensFromImplics implics
-
-getUserGivensFromImplics :: [Implication] -> [UserGiven]
-getUserGivensFromImplics implics
- = reverse (filterOut (null . ic_given) implics)
+ where
+ fits_msg, refs_msg, fits_discard_msg, refs_discard_msg :: SDoc
+ fits_msg = ppUnless (null fits) $
+ hang (text "Valid hole fits include") 2 $
+ vcat (map (pprHoleFit hfdc) fits)
+ $$ ppWhen discarded_fits fits_discard_msg
+ refs_msg = ppUnless (null refs) $
+ hang (text "Valid refinement hole fits include") 2 $
+ vcat (map (pprHoleFit hfdc) refs)
+ $$ ppWhen discarded_refs refs_discard_msg
+ fits_discard_msg =
+ text "(Some hole fits suppressed;" <+>
+ text "use -fmax-valid-hole-fits=N" <+>
+ text "or -fno-max-valid-hole-fits)"
+ refs_discard_msg =
+ text "(Some refinement hole fits suppressed;" <+>
+ text "use -fmax-refinement-hole-fits=N" <+>
+ text "or -fno-max-refinement-hole-fits)"
+
+-- | Add a "Constraints include..." message.
+--
+-- See Note [Constraints include ...]
+pprConstraintsInclude :: [(PredType, RealSrcSpan)] -> SDoc
+-- This function should be in "GHC.Tc.Errors.Ppr",
+-- but we need it here because 'TcRnMessageDetails' needs an 'SDoc'.
+pprConstraintsInclude cts
+ = ppUnless (null cts) $
+ hang (text "Constraints include")
+ 2 (vcat $ map pprConstraint cts)
+ where
+ pprConstraint (constraint, loc) =
+ ppr constraint <+> nest 2 (parens (text "from" <+> ppr loc))
{- Note [Always warn with -fdefer-type-errors]
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
@@ -1201,14 +1110,14 @@ solve it.
************************************************************************
-}
-mkIrredErr :: ReportErrCtxt -> [Ct] -> TcM Report
+mkIrredErr :: ReportErrCtxt -> [Ct] -> TcM SolverReport
mkIrredErr ctxt cts
= do { (ctxt, binds_msg, ct1) <- relevantBindings True ctxt ct1
- ; let orig = ctOrigin ct1
- msg = couldNotDeduce (getUserGivens ctxt) (map ctPred cts, orig)
+ ; let msg = important ctxt $
+ CouldNotDeduce (getUserGivens ctxt) (ct1 :| others) Nothing
; return $ msg `mappend` mk_relevant_bindings binds_msg }
where
- (ct1:_) = cts
+ ct1:others = cts
{- Note [Constructing Hole Errors]
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
@@ -1247,122 +1156,63 @@ See also 'reportUnsolved'.
----------------
-- | Constructs a new hole error, unless this is deferred. See Note [Constructing Hole Errors].
mkHoleError :: NameEnv Type -> [Ct] -> ReportErrCtxt -> Hole -> TcM (MsgEnvelope TcRnMessage)
-mkHoleError _ _tidy_simples ctxt hole@(Hole { hole_occ = occ
- , hole_ty = hole_ty
- , hole_loc = ct_loc })
+mkHoleError _ _tidy_simples ctxt hole@(Hole { hole_occ = occ, hole_loc = ct_loc })
| isOutOfScopeHole hole
= do { dflags <- getDynFlags
; rdr_env <- getGlobalRdrEnv
; imp_info <- getImports
; curr_mod <- getModule
; hpt <- getHpt
- ; let err = important out_of_scope_msg `mappend`
- (mk_relevant_bindings $
- unknownNameSuggestions WL_Anything dflags hpt curr_mod rdr_env
- (tcl_rdr lcl_env) imp_info (mkRdrUnqual occ))
-
- ; maybeAddDeferredBindings ctxt hole err
- ; mkErrorReportNC (cec_out_of_scope_holes ctxt) lcl_env err
- -- Use NC variant: the context is generally not helpful here
+ ; let (imp_errs, hints)
+ = unknownNameSuggestions WL_Anything
+ dflags hpt curr_mod rdr_env
+ (tcl_rdr lcl_env) imp_info (mkRdrUnqual occ)
+ errs = [ReportWithCtxt ctxt (ReportHoleError hole $ OutOfScopeHole imp_errs)]
+ report = SolverReport errs [] hints
+
+ ; maybeAddDeferredBindings ctxt hole report
+ ; mkErrorReport lcl_env (TcRnSolverReport errs (cec_out_of_scope_holes ctxt) hints) Nothing []
+ -- Pass the value 'Nothing' for the context, as it's generally not helpful
+ -- to include the context here.
}
where
- herald | isDataOcc occ = text "Data constructor not in scope:"
- | otherwise = text "Variable not in scope:"
-
- out_of_scope_msg -- Print v :: ty only if the type has structure
- | boring_type = hang herald 2 (ppr occ)
- | otherwise = hang herald 2 (pp_occ_with_type occ hole_ty)
-
- lcl_env = ctLocEnv ct_loc
- boring_type = isTyVarTy hole_ty
+ lcl_env = ctLocEnv ct_loc
-- general case: not an out-of-scope error
-mkHoleError lcl_name_cache tidy_simples ctxt hole@(Hole { hole_occ = occ
- , hole_ty = hole_ty
- , hole_sort = sort
- , hole_loc = ct_loc })
- = do { binds_msg
+mkHoleError lcl_name_cache tidy_simples ctxt
+ hole@(Hole { hole_ty = hole_ty
+ , hole_sort = sort
+ , hole_loc = ct_loc })
+ = do { rel_binds
<- relevant_bindings False lcl_env lcl_name_cache (tyCoVarsOfType hole_ty)
-- The 'False' means "don't filter the bindings"; see Trac #8191
; show_hole_constraints <- goptM Opt_ShowHoleConstraints
- ; let constraints_msg
+ ; let relevant_cts
| ExprHole _ <- sort, show_hole_constraints
- = givenConstraintsMsg ctxt
+ = givenConstraints ctxt
| otherwise
- = empty
+ = []
; show_valid_hole_fits <- goptM Opt_ShowValidHoleFits
- ; (ctxt, sub_msg) <- if show_valid_hole_fits
- then validHoleFits ctxt tidy_simples hole
- else return (ctxt, empty)
+ ; (ctxt, hole_fits) <- if show_valid_hole_fits
+ then validHoleFits ctxt tidy_simples hole
+ else return (ctxt, noValidHoleFits)
- ; let err = important hole_msg `mappend`
- mk_relevant_bindings (binds_msg $$ constraints_msg) `mappend`
- valid_hole_fits sub_msg
+ ; let reason | ExprHole _ <- sort = cec_expr_holes ctxt
+ | otherwise = cec_type_holes ctxt
+ errs = [ReportWithCtxt ctxt $ ReportHoleError hole $ HoleError sort]
+ supp = [ SupplementaryBindings rel_binds
+ , SupplementaryCts relevant_cts
+ , SupplementaryHoleFits hole_fits ]
- ; maybeAddDeferredBindings ctxt hole err
+ ; maybeAddDeferredBindings ctxt hole (SolverReport errs supp [])
- ; let holes | ExprHole _ <- sort = cec_expr_holes ctxt
- | otherwise = cec_type_holes ctxt
- ; mkErrorReport holes ctxt lcl_env err
+ ; mkErrorReport lcl_env (TcRnSolverReport errs reason noHints) (Just ctxt) supp
}
where
- lcl_env = ctLocEnv ct_loc
- hole_kind = tcTypeKind hole_ty
- tyvars = tyCoVarsOfTypeList hole_ty
-
- hole_msg = case sort of
- ExprHole _ -> vcat [ hang (text "Found hole:")
- 2 (pp_occ_with_type occ hole_ty)
- , tyvars_msg, expr_hole_hint ]
- TypeHole -> vcat [ hang (text "Found type wildcard" <+> quotes (ppr occ))
- 2 (text "standing for" <+> quotes pp_hole_type_with_kind)
- , tyvars_msg, type_hole_hint ]
- ConstraintHole -> vcat [ hang (text "Found extra-constraints wildcard standing for")
- 2 (quotes $ pprType hole_ty) -- always kind constraint
- , tyvars_msg, type_hole_hint ]
-
- pp_hole_type_with_kind
- | isLiftedTypeKind hole_kind
- || isCoVarType hole_ty -- Don't print the kind of unlifted
- -- equalities (#15039)
- = pprType hole_ty
- | otherwise
- = pprType hole_ty <+> dcolon <+> pprKind hole_kind
-
- tyvars_msg = ppUnless (null tyvars) $
- text "Where:" <+> (vcat (map loc_msg other_tvs)
- $$ pprSkols ctxt skol_tvs)
- where
- (skol_tvs, other_tvs) = partition is_skol tyvars
- is_skol tv = isTcTyVar tv && isSkolemTyVar tv
- -- Coercion variables can be free in the
- -- hole, via kind casts
-
- type_hole_hint
- | ErrorWithoutFlag <- cec_type_holes ctxt
- = text "To use the inferred type, enable PartialTypeSignatures"
- | otherwise
- = empty
-
- expr_hole_hint -- Give hint for, say, f x = _x
- | lengthFS (occNameFS occ) > 1 -- Don't give this hint for plain "_"
- = text "Or perhaps" <+> quotes (ppr occ)
- <+> text "is mis-spelled, or not in scope"
- | otherwise
- = empty
-
- loc_msg tv
- | isTyVar tv
- = case tcTyVarDetails tv of
- MetaTv {} -> quotes (ppr tv) <+> text "is an ambiguous type variable"
- _ -> empty -- Skolems dealt with already
- | otherwise -- A coercion variable can be free in the hole type
- = ppWhenOption sdocPrintExplicitCoercions $
- quotes (ppr tv) <+> text "is a coercion variable"
-
+ lcl_env = ctLocEnv ct_loc
{- Note [Adding deferred bindings]
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
@@ -1379,7 +1229,7 @@ so that the correct 'Severity' can be computed out of that later on.
-- See Note [Adding deferred bindings].
maybeAddDeferredBindings :: ReportErrCtxt
-> Hole
- -> Report
+ -> SolverReport
-> TcM ()
maybeAddDeferredBindings ctxt hole report = do
case hole_sort hole of
@@ -1394,57 +1244,38 @@ maybeAddDeferredBindings ctxt hole report = do
writeMutVar ref err_tm
_ -> pure ()
-pp_occ_with_type :: OccName -> Type -> SDoc
-pp_occ_with_type occ hole_ty = hang (pprPrefixOcc occ) 2 (dcolon <+> pprType hole_ty)
-
-- We unwrap the ReportErrCtxt here, to avoid introducing a loop in module
-- imports
-validHoleFits :: ReportErrCtxt -- The context we're in, i.e. the
- -- implications and the tidy environment
- -> [Ct] -- Unsolved simple constraints
- -> Hole -- The hole
- -> TcM (ReportErrCtxt, SDoc) -- We return the new context
- -- with a possibly updated
- -- tidy environment, and
- -- the message.
+validHoleFits :: ReportErrCtxt -- ^ The context we're in, i.e. the
+ -- implications and the tidy environment
+ -> [Ct] -- ^ Unsolved simple constraints
+ -> Hole -- ^ The hole
+ -> TcM (ReportErrCtxt, ValidHoleFits)
+ -- ^ We return the new context
+ -- with a possibly updated
+ -- tidy environment, and
+ -- the valid hole fits.
validHoleFits ctxt@(CEC {cec_encl = implics
, cec_tidy = lcl_env}) simps hole
- = do { (tidy_env, msg) <- findValidHoleFits lcl_env implics simps hole
- ; return (ctxt {cec_tidy = tidy_env}, msg) }
+ = do { (tidy_env, fits) <- findValidHoleFits lcl_env implics simps hole
+ ; return (ctxt {cec_tidy = tidy_env}, fits) }
-- See Note [Constraints include ...]
-givenConstraintsMsg :: ReportErrCtxt -> SDoc
-givenConstraintsMsg ctxt =
- let constraints :: [(Type, RealSrcSpan)]
- constraints =
- do { implic@Implic{ ic_given = given } <- cec_encl ctxt
- ; constraint <- given
- ; return (varType constraint, tcl_loc (ic_env implic)) }
-
- pprConstraint (constraint, loc) =
- ppr constraint <+> nest 2 (parens (text "from" <+> ppr loc))
-
- in ppUnless (null constraints) $
- hang (text "Constraints include")
- 2 (vcat $ map pprConstraint constraints)
+givenConstraints :: ReportErrCtxt -> [(Type, RealSrcSpan)]
+givenConstraints ctxt
+ = do { implic@Implic{ ic_given = given } <- cec_encl ctxt
+ ; constraint <- given
+ ; return (varType constraint, tcl_loc (ic_env implic)) }
----------------
-mkIPErr :: ReportErrCtxt -> [Ct] -> TcM Report
+
+mkIPErr :: ReportErrCtxt -> [Ct] -> TcM SolverReport
mkIPErr ctxt cts
= do { (ctxt, binds_msg, ct1) <- relevantBindings True ctxt ct1
- ; let orig = ctOrigin ct1
- preds = map ctPred cts
- givens = getUserGivens ctxt
- msg | null givens
- = important $ addArising orig $
- sep [ text "Unbound implicit parameter" <> plural cts
- , nest 2 (pprParendTheta preds) ]
- | otherwise
- = couldNotDeduce givens (preds, orig)
-
+ ; let msg = important ctxt $ UnboundImplicitParams (ct1 :| others)
; return $ msg `mappend` mk_relevant_bindings binds_msg }
where
- (ct1:_) = cts
+ ct1:others = cts
----------------
@@ -1452,7 +1283,7 @@ mkIPErr ctxt cts
-- Wanted constraints arising from representation-polymorphism checks.
--
-- See Note [Reporting representation-polymorphism errors] in GHC.Tc.Types.Origin.
-mkFRRErr :: ReportErrCtxt -> [Ct] -> TcM Report
+mkFRRErr :: ReportErrCtxt -> [Ct] -> TcM SolverReport
mkFRRErr ctxt cts
= do { -- Zonking/tidying.
; origs <-
@@ -1460,36 +1291,18 @@ mkFRRErr ctxt cts
zonkTidyOrigins (cec_tidy ctxt) (map ctOrigin cts)
<&>
-- Then remove duplicates: only retain one 'CtOrigin' per representation-polymorphic type.
- (nubOrdBy (nonDetCmpType `on` frr_type) . snd)
-
+ (nubOrdBy (nonDetCmpType `on` (snd . frr_orig_and_type)) . snd)
-- Obtain all the errors we want to report (constraints with FixedRuntimeRep origin),
-- with the corresponding types:
-- ty1 :: TYPE rep1, ty2 :: TYPE rep2, ...
- ; let tys = map frr_type origs
- kis = map typeKind tys
-
- -- Assemble the error message: pair up each origin with the corresponding type, e.g.
- -- • FixedRuntimeRep origin msg 1 ...
- -- a :: TYPE r1
- -- • FixedRuntimeRep origin msg 2 ...
- -- b :: TYPE r2
-
- combine_origin_ty_ki :: CtOrigin -> Type -> Kind -> SDoc
- combine_origin_ty_ki orig ty ki =
- -- Add bullet points if there is more than one error.
- (if length tys > 1 then (bullet <+>) else id) $
- vcat [pprArising orig <> colon
- ,nest 2 $ ppr ty <+> dcolon <+> pprWithTYPE ki]
-
- msg :: SDoc
- msg = vcat $ zipWith3 combine_origin_ty_ki origs tys kis
-
- ; return $ important msg }
+ ; let origs_and_tys = map frr_orig_and_type origs
+
+ ; return $ important ctxt $ FixedRuntimeRepError origs_and_tys }
where
- frr_type :: CtOrigin -> Type
- frr_type (FixedRuntimeRepOrigin ty _) = ty
- frr_type orig
+ frr_orig_and_type :: CtOrigin -> (FRROrigin, Type)
+ frr_orig_and_type (FixedRuntimeRepOrigin ty frr_orig) = (frr_orig, ty)
+ frr_orig_and_type orig
= pprPanic "mkFRRErr: not a FixedRuntimeRep origin"
(text "origin =" <+> ppr orig)
@@ -1552,61 +1365,59 @@ any more. So we don't assert that it is.
-- Don't have multiple equality errors from the same location
-- E.g. (Int,Bool) ~ (Bool,Int) one error will do!
-mkEqErr :: ReportErrCtxt -> [Ct] -> TcM Report
+mkEqErr :: ReportErrCtxt -> [Ct] -> TcM SolverReport
mkEqErr ctxt (ct:_) = mkEqErr1 ctxt ct
mkEqErr _ [] = panic "mkEqErr"
-mkEqErr1 :: ReportErrCtxt -> Ct -> TcM Report
+mkEqErr1 :: ReportErrCtxt -> Ct -> TcM SolverReport
mkEqErr1 ctxt ct -- Wanted or derived;
-- givens handled in mkGivenErrorReporter
= do { (ctxt, binds_msg, ct) <- relevantBindings True ctxt ct
; rdr_env <- getGlobalRdrEnv
; fam_envs <- tcGetFamInstEnvs
- ; let coercible_msg = case ctEqRel ct of
- NomEq -> empty
- ReprEq -> mkCoercibleExplanation rdr_env fam_envs ty1 ty2
+ ; let mb_coercible_msg = case ctEqRel ct of
+ NomEq -> Nothing
+ ReprEq -> ReportCoercibleMsg <$> mkCoercibleExplanation rdr_env fam_envs ty1 ty2
; traceTc "mkEqErr1" (ppr ct $$ pprCtOrigin (ctOrigin ct))
- ; let report = mconcat [ important coercible_msg
- , mk_relevant_bindings binds_msg]
- ; mkEqErr_help ctxt report ct ty1 ty2 }
+ ; (last_msg :| prev_msgs, hints) <- mkEqErr_help ctxt ct ty1 ty2
+ ; let
+ report = foldMap (important ctxt) (reverse prev_msgs)
+ `mappend` (important ctxt $ mkTcReportWithInfo last_msg $ maybeToList mb_coercible_msg)
+ `mappend` (mk_relevant_bindings binds_msg)
+ `mappend` (mk_report_hints hints)
+ ; return report }
where
(ty1, ty2) = getEqPredTys (ctPred ct)
-- | This function tries to reconstruct why a "Coercible ty1 ty2" constraint
-- is left over.
mkCoercibleExplanation :: GlobalRdrEnv -> FamInstEnvs
- -> TcType -> TcType -> SDoc
+ -> TcType -> TcType -> Maybe CoercibleMsg
mkCoercibleExplanation rdr_env fam_envs ty1 ty2
| Just (tc, tys) <- tcSplitTyConApp_maybe ty1
, (rep_tc, _, _) <- tcLookupDataFamInst fam_envs tc tys
, Just msg <- coercible_msg_for_tycon rep_tc
- = msg
+ = Just msg
| Just (tc, tys) <- splitTyConApp_maybe ty2
, (rep_tc, _, _) <- tcLookupDataFamInst fam_envs tc tys
, Just msg <- coercible_msg_for_tycon rep_tc
- = msg
+ = Just msg
| Just (s1, _) <- tcSplitAppTy_maybe ty1
, Just (s2, _) <- tcSplitAppTy_maybe ty2
, s1 `eqType` s2
, has_unknown_roles s1
- = hang (text "NB: We cannot know what roles the parameters to" <+>
- quotes (ppr s1) <+> text "have;")
- 2 (text "we must assume that the role is nominal")
+ = Just $ UnknownRoles s1
| otherwise
- = empty
+ = Nothing
where
coercible_msg_for_tycon tc
| isAbstractTyCon tc
- = Just $ hsep [ text "NB: The type constructor"
- , quotes (pprSourceTyCon tc)
- , text "is abstract" ]
+ = Just $ TyConIsAbstract tc
| isNewTyCon tc
, [data_con] <- tyConDataCons tc
, let dc_name = dataConName data_con
, isNothing (lookupGRE_Name rdr_env dc_name)
- = Just $ hang (text "The data constructor" <+> quotes (ppr dc_name))
- 2 (sep [ text "of newtype" <+> quotes (pprSourceTyCon tc)
- , text "is not in scope" ])
+ = Just $ OutOfScopeNewtypeConstructor tc data_con
| otherwise = Nothing
has_unknown_roles ty
@@ -1619,83 +1430,78 @@ mkCoercibleExplanation rdr_env fam_envs ty1 ty2
| otherwise
= False
-mkEqErr_help :: ReportErrCtxt -> Report
+-- | Accumulated messages in reverse order.
+type AccReportMsgs = NonEmpty TcReportMsg
+
+mkEqErr_help :: ReportErrCtxt
-> Ct
- -> TcType -> TcType -> TcM Report
-mkEqErr_help ctxt report ct ty1 ty2
+ -> TcType -> TcType -> TcM (AccReportMsgs, [GhcHint])
+mkEqErr_help ctxt ct ty1 ty2
| Just (tv1, _) <- tcGetCastedTyVar_maybe ty1
- = mkTyVarEqErr ctxt report ct tv1 ty2
+ = mkTyVarEqErr ctxt ct tv1 ty2
| Just (tv2, _) <- tcGetCastedTyVar_maybe ty2
- = mkTyVarEqErr ctxt report ct tv2 ty1
+ = mkTyVarEqErr ctxt ct tv2 ty1
| otherwise
- = return $ reportEqErr ctxt report ct ty1 ty2
+ = return (reportEqErr ctxt ct ty1 ty2 :| [], [])
-reportEqErr :: ReportErrCtxt -> Report
+reportEqErr :: ReportErrCtxt
-> Ct
- -> TcType -> TcType -> Report
-reportEqErr ctxt report ct ty1 ty2
- = mconcat [misMatch, report, eqInfo]
+ -> TcType -> TcType -> TcReportMsg
+reportEqErr ctxt ct ty1 ty2
+ = mkTcReportWithInfo mismatch eqInfos
where
- misMatch = misMatchOrCND False ctxt ct ty1 ty2
- eqInfo = mkEqInfoMsg ct ty1 ty2
+ mismatch = misMatchOrCND False ctxt ct ty1 ty2
+ eqInfos = eqInfoMsgs ct ty1 ty2
-mkTyVarEqErr :: ReportErrCtxt -> Report -> Ct
- -> TcTyVar -> TcType -> TcM Report
+mkTyVarEqErr :: ReportErrCtxt -> Ct
+ -> TcTyVar -> TcType -> TcM (AccReportMsgs, [GhcHint])
-- tv1 and ty2 are already tidied
-mkTyVarEqErr ctxt report ct tv1 ty2
+mkTyVarEqErr ctxt ct tv1 ty2
= do { traceTc "mkTyVarEqErr" (ppr ct $$ ppr tv1 $$ ppr ty2)
; dflags <- getDynFlags
- ; return $ mkTyVarEqErr' dflags ctxt report ct tv1 ty2 }
+ ; return $ mkTyVarEqErr' dflags ctxt ct tv1 ty2 }
-mkTyVarEqErr' :: DynFlags -> ReportErrCtxt -> Report -> Ct
- -> TcTyVar -> TcType -> Report
-mkTyVarEqErr' dflags ctxt report ct tv1 ty2
+mkTyVarEqErr' :: DynFlags -> ReportErrCtxt -> Ct
+ -> TcTyVar -> TcType -> (AccReportMsgs, [GhcHint])
+mkTyVarEqErr' dflags ctxt ct tv1 ty2
-- impredicativity is a simple error to understand; try it first
| check_eq_result `cterHasProblem` cteImpredicative
- = let msg = vcat [ (if isSkolemTyVar tv1
- then text "Cannot equate type variable"
- else text "Cannot instantiate unification variable")
- <+> quotes (ppr tv1)
- , hang (text "with a" <+> what <+> text "involving polytypes:") 2 (ppr ty2) ]
- in
- -- Unlike the other reports, this discards the old 'report_important'
+ , let
+ poly_msg = CannotUnifyWithPolytype ct tv1 ty2
+ tyvar_eq_info = extraTyVarEqInfo tv1 ty2
+ poly_msg_with_info
+ | isSkolemTyVar tv1
+ = mkTcReportWithInfo poly_msg tyvar_eq_info
+ | otherwise
+ = poly_msg
+ = -- Unlike the other reports, this discards the old 'report_important'
-- instead of augmenting it. This is because the details are not likely
-- to be helpful since this is just an unimplemented feature.
- mconcat [ headline_msg
- , important msg
- , if isSkolemTyVar tv1 then extraTyVarEqInfo ctxt tv1 ty2 else mempty
- , report ]
+ (poly_msg_with_info <| headline_msg :| [], [])
| isSkolemTyVar tv1 -- ty2 won't be a meta-tyvar; we would have
-- swapped in Solver.Canonical.canEqTyVarHomo
|| isTyVarTyVar tv1 && not (isTyVarTy ty2)
|| ctEqRel ct == ReprEq
-- The cases below don't really apply to ReprEq (except occurs check)
- = mconcat [ headline_msg
- , extraTyVarEqInfo ctxt tv1 ty2
- , suggestAddSig ctxt ty1 ty2
- , report
- ]
+ = (mkTcReportWithInfo headline_msg tv_extra :| [], add_sig)
| cterHasOccursCheck check_eq_result
-- We report an "occurs check" even for a ~ F t a, where F is a type
-- function; it's not insoluble (because in principle F could reduce)
-- but we have certainly been unable to solve it
- = let extra2 = mkEqInfoMsg ct ty1 ty2
+ = let extras2 = eqInfoMsgs ct ty1 ty2
interesting_tyvars = filter (not . noFreeVarsOfType . tyVarKind) $
filter isTyVar $
fvVarList $
tyCoFVsOfType ty1 `unionFV` tyCoFVsOfType ty2
- extra3 = mk_relevant_bindings $
- ppWhen (not (null interesting_tyvars)) $
- hang (text "Type variable kinds:") 2 $
- vcat (map (tyvar_binding . tidyTyCoVarOcc (cec_tidy ctxt))
- interesting_tyvars)
- tyvar_binding tv = ppr tv <+> dcolon <+> ppr (tyVarKind tv)
- in
- mconcat [headline_msg, extra2, extra3, report]
+ extras3 = case interesting_tyvars of
+ [] -> []
+ (tv : tvs) -> [OccursCheckInterestingTyVars (tv :| tvs)]
+
+ in (mkTcReportWithInfo headline_msg (extras2 ++ extras3) :| [], [])
-- If the immediately-enclosing implication has 'tv' a skolem, and
-- we know by now its an InferSkol kind of skolem, then presumably
@@ -1704,35 +1510,14 @@ mkTyVarEqErr' dflags ctxt report ct tv1 ty2
| (implic:_) <- cec_encl ctxt
, Implic { ic_skols = skols } <- implic
, tv1 `elem` skols
- = mconcat [ misMatchMsg ctxt ct ty1 ty2
- , extraTyVarEqInfo ctxt tv1 ty2
- , report
- ]
+ = (mkTcReportWithInfo mismatch_msg tv_extra :| [], [])
-- Check for skolem escape
| (implic:_) <- cec_encl ctxt -- Get the innermost context
- , Implic { ic_skols = skols, ic_info = skol_info } <- implic
+ , Implic { ic_skols = skols } <- implic
, let esc_skols = filter (`elemVarSet` (tyCoVarsOfType ty2)) skols
, not (null esc_skols)
- = let msg = misMatchMsg ctxt ct ty1 ty2
- esc_doc = sep [ text "because" <+> what <+> text "variable" <> plural esc_skols
- <+> pprQuotedList esc_skols
- , text "would escape" <+>
- if isSingleton esc_skols then text "its scope"
- else text "their scope" ]
- tv_extra = important $
- vcat [ nest 2 $ esc_doc
- , sep [ (if isSingleton esc_skols
- then text "This (rigid, skolem)" <+>
- what <+> text "variable is"
- else text "These (rigid, skolem)" <+>
- what <+> text "variables are")
- <+> text "bound by"
- , nest 2 $ ppr skol_info
- , nest 2 $ text "at" <+>
- ppr (tcl_loc (ic_env implic)) ] ]
- in
- mconcat [msg, tv_extra, report]
+ = (SkolemEscape ct implic esc_skols :| [mismatch_msg], [])
-- Nastiest case: attempt to unify an untouchable variable
-- So tv is a meta tyvar (or started that way before we
@@ -1740,29 +1525,23 @@ mkTyVarEqErr' dflags ctxt report ct tv1 ty2
-- meta tyvar or a TyVarTv, else it'd have been unified
-- See Note [Error messages for untouchables]
| (implic:_) <- cec_encl ctxt -- Get the innermost context
- , Implic { ic_given = given, ic_tclvl = lvl, ic_info = skol_info } <- implic
+ , Implic { ic_tclvl = lvl } <- implic
= assertPpr (not (isTouchableMetaTyVar lvl tv1))
(ppr tv1 $$ ppr lvl) $ -- See Note [Error messages for untouchables]
- let msg = misMatchMsg ctxt ct ty1 ty2
- tclvl_extra = important $
- nest 2 $
- sep [ quotes (ppr tv1) <+> text "is untouchable"
- , nest 2 $ text "inside the constraints:" <+> pprEvVarTheta given
- , nest 2 $ text "bound by" <+> ppr skol_info
- , nest 2 $ text "at" <+>
- ppr (tcl_loc (ic_env implic)) ]
- tv_extra = extraTyVarEqInfo ctxt tv1 ty2
- add_sig = suggestAddSig ctxt ty1 ty2
+ let tclvl_extra = UntouchableVariable tv1 implic
in
- mconcat [msg, tclvl_extra, tv_extra, add_sig, report]
+ (mkTcReportWithInfo tclvl_extra tv_extra :| [mismatch_msg], add_sig)
| otherwise
- = reportEqErr ctxt report ct (mkTyVarTy tv1) ty2
+ = (reportEqErr ctxt ct (mkTyVarTy tv1) ty2 :| [], [])
-- This *can* happen (#6123)
-- Consider an ambiguous top-level constraint (a ~ F a)
-- Not an occurs check, because F is a type function.
where
headline_msg = misMatchOrCND insoluble_occurs_check ctxt ct ty1 ty2
+ mismatch_msg = mkMismatchMsg ct ty1 ty2
+ tv_extra = extraTyVarEqInfo tv1 ty2
+ add_sig = maybeToList $ suggestAddSig ctxt ty1 ty2
ty1 = mkTyVarTy tv1
@@ -1774,42 +1553,37 @@ mkTyVarEqErr' dflags ctxt report ct tv1 ty2
-- variable is on the right, so we don't get useful info for the CIrredCan,
-- and have to compute the result of checkTyVarEq here.
-
insoluble_occurs_check = check_eq_result `cterHasProblem` cteInsolubleOccurs
- what = text $ levelString $
- ctLocTypeOrKind_maybe (ctLoc ct) `orElse` TypeLevel
-
-levelString :: TypeOrKind -> String
-levelString TypeLevel = "type"
-levelString KindLevel = "kind"
-
-mkEqInfoMsg :: Ct -> TcType -> TcType -> Report
+eqInfoMsgs :: Ct -> TcType -> TcType -> [TcReportInfo]
-- Report (a) ambiguity if either side is a type function application
-- e.g. F a0 ~ Int
-- (b) warning about injectivity if both sides are the same
-- type function application F a ~ F b
-- See Note [Non-injective type functions]
-mkEqInfoMsg ct ty1 ty2
- = important (tyfun_msg $$ ambig_msg)
+eqInfoMsgs ct ty1 ty2
+ = catMaybes [tyfun_msg, ambig_msg]
where
mb_fun1 = isTyFun_maybe ty1
mb_fun2 = isTyFun_maybe ty2
+ (ambig_kvs, ambig_tvs) = getAmbigTkvs ct
ambig_msg | isJust mb_fun1 || isJust mb_fun2
- = snd (mkAmbigMsg False ct)
- | otherwise = empty
+ , not (null ambig_kvs && null ambig_tvs)
+ = Just $ Ambiguity False (ambig_kvs, ambig_tvs)
+ | otherwise
+ = Nothing
tyfun_msg | Just tc1 <- mb_fun1
, Just tc2 <- mb_fun2
, tc1 == tc2
, not (isInjectiveTyCon tc1 Nominal)
- = text "NB:" <+> quotes (ppr tc1)
- <+> text "is a non-injective type family"
- | otherwise = empty
+ = Just $ NonInjectiveTyFam tc1
+ | otherwise
+ = Nothing
misMatchOrCND :: Bool -> ReportErrCtxt -> Ct
- -> TcType -> TcType -> Report
+ -> TcType -> TcType -> TcReportMsg
-- If oriented then ty1 is actual, ty2 is expected
misMatchOrCND insoluble_occurs_check ctxt ct ty1 ty2
| insoluble_occurs_check -- See Note [Insoluble occurs check]
@@ -1818,56 +1592,26 @@ misMatchOrCND insoluble_occurs_check ctxt ct ty1 ty2
|| null givens
= -- If the equality is unconditionally insoluble
-- or there is no context, don't report the context
- misMatchMsg ctxt ct ty1 ty2
+ mkMismatchMsg ct ty1 ty2
| otherwise
- = mconcat [ couldNotDeduce givens ([eq_pred], orig)
- , important $ mk_supplementary_ea_msg ctxt level ty1 ty2 orig ]
+ = CouldNotDeduce givens (ct :| []) (Just $ CND_Extra level ty1 ty2)
+
where
ev = ctEvidence ct
- eq_pred = ctEvPred ev
- orig = ctEvOrigin ev
level = ctLocTypeOrKind_maybe (ctEvLoc ev) `orElse` TypeLevel
givens = [ given | given <- getUserGivens ctxt, ic_given_eqs given /= NoGivenEqs ]
-- Keep only UserGivens that have some equalities.
-- See Note [Suppress redundant givens during error reporting]
-couldNotDeduce :: [UserGiven] -> (ThetaType, CtOrigin) -> Report
-couldNotDeduce givens (wanteds, orig)
- = important $
- vcat [ addArising orig (text "Could not deduce:" <+> pprTheta wanteds)
- , vcat (pp_givens givens)]
-
-pp_givens :: [UserGiven] -> [SDoc]
-pp_givens givens
- = case givens of
- [] -> []
- (g:gs) -> ppr_given (text "from the context:") g
- : map (ppr_given (text "or from:")) gs
- where
- ppr_given herald implic@(Implic { ic_given = gs, ic_info = skol_info })
- = hang (herald <+> pprEvVarTheta (mkMinimalBySCs evVarPred gs))
- -- See Note [Suppress redundant givens during error reporting]
- -- for why we use mkMinimalBySCs above.
- 2 (sep [ text "bound by" <+> ppr skol_info
- , text "at" <+> ppr (tcl_loc (ic_env implic)) ])
-
-- These are for the "blocked" equalities, as described in TcCanonical
-- Note [Equalities with incompatible kinds], wrinkle (2). There should
-- always be another unsolved wanted around, which will ordinarily suppress
-- this message. But this can still be printed out with -fdefer-type-errors
-- (sigh), so we must produce a message.
-mkBlockedEqErr :: ReportErrCtxt -> [Ct] -> TcM Report
-mkBlockedEqErr _ (ct:_) = return $ important msg
- where
- msg = vcat [ hang (text "Cannot use equality for substitution:")
- 2 (ppr (ctPred ct))
- , text "Doing so would be ill-kinded." ]
- -- This is a terrible message. Perhaps worse, if the user
- -- has -fprint-explicit-kinds on, they will see that the two
- -- sides have the same kind, as there is an invisible cast.
- -- I really don't know how to do better.
-mkBlockedEqErr _ [] = panic "mkBlockedEqErr no constraints"
+mkBlockedEqErr :: ReportErrCtxt -> [Ct] -> TcM SolverReport
+mkBlockedEqErr ctxt (ct:_) = return $ important ctxt (BlockedEquality ct)
+mkBlockedEqErr _ [] = panic "mkBlockedEqErr no constraints"
{-
Note [Suppress redundant givens during error reporting]
@@ -1909,37 +1653,31 @@ addition to superclasses (see Note [Remove redundant provided dicts]
in GHC.Tc.TyCl.PatSyn).
-}
-extraTyVarEqInfo :: ReportErrCtxt -> TcTyVar -> TcType -> Report
+extraTyVarEqInfo :: TcTyVar -> TcType -> [TcReportInfo]
-- Add on extra info about skolem constants
-- NB: The types themselves are already tidied
-extraTyVarEqInfo ctxt tv1 ty2
- = important (extraTyVarInfo ctxt tv1 $$ ty_extra ty2)
+extraTyVarEqInfo tv1 ty2
+ = extraTyVarInfo tv1 : ty_extra ty2
where
ty_extra ty = case tcGetCastedTyVar_maybe ty of
- Just (tv, _) -> extraTyVarInfo ctxt tv
- Nothing -> empty
-
-extraTyVarInfo :: ReportErrCtxt -> TcTyVar -> SDoc
-extraTyVarInfo ctxt tv
- = assertPpr (isTyVar tv) (ppr tv) $
- case tcTyVarDetails tv of
- SkolemTv {} -> pprSkols ctxt [tv]
- RuntimeUnk {} -> quotes (ppr tv) <+> text "is an interactive-debugger skolem"
- MetaTv {} -> empty
-
-suggestAddSig :: ReportErrCtxt -> TcType -> TcType -> Report
+ Just (tv, _) -> [extraTyVarInfo tv]
+ Nothing -> []
+
+extraTyVarInfo :: TcTyVar -> TcReportInfo
+extraTyVarInfo tv = assertPpr (isTyVar tv) (ppr tv) $ TyVarInfo tv
+
+suggestAddSig :: ReportErrCtxt -> TcType -> TcType -> Maybe GhcHint
-- See Note [Suggest adding a type signature]
suggestAddSig ctxt ty1 _ty2
- | null inferred_bndrs -- No let-bound inferred binders in context
- = mempty
- | [bndr] <- inferred_bndrs
- = important $ text "Possible fix: add a type signature for" <+> quotes (ppr bndr)
+ | bndr : bndrs <- inferred_bndrs
+ = Just $ SuggestAddTypeSignatures $ NamedBindings (bndr :| bndrs)
| otherwise
- = important $ text "Possible fix: add type signatures for some or all of" <+> (ppr inferred_bndrs)
+ = Nothing
where
- inferred_bndrs = case tcGetTyVar_maybe ty1 of
- Just tv | isSkolemTyVar tv -> find (cec_encl ctxt) False tv
- _ -> []
+ inferred_bndrs =
+ case tcGetTyVar_maybe ty1 of
+ Just tv | isSkolemTyVar tv -> find (cec_encl ctxt) False tv
+ _ -> []
-- 'find' returns the binders of an InferSkol for 'tv',
-- provided there is an intervening implication with
@@ -1954,224 +1692,35 @@ suggestAddSig ctxt ty1 _ty2
= find implics (seen_eqs || ic_given_eqs implic /= NoGivenEqs) tv
--------------------
-misMatchMsg :: ReportErrCtxt -> Ct -> TcType -> TcType -> Report
--- Types are already tidy
--- If oriented then ty1 is actual, ty2 is expected
-misMatchMsg ctxt ct ty1 ty2
- = important $
- addArising orig $
- pprWithExplicitKindsWhenMismatch ty1 ty2 orig $
- sep [ case orig of
- TypeEqOrigin {} -> tk_eq_msg ctxt ct ty1 ty2 orig
- KindEqOrigin {} -> tk_eq_msg ctxt ct ty1 ty2 orig
- _ -> headline_eq_msg False ct ty1 ty2
- , sameOccExtra ty2 ty1 ]
- where
- orig = ctOrigin ct
-
-headline_eq_msg :: Bool -> Ct -> Type -> Type -> SDoc
--- Generates the main "Could't match 't1' against 't2'
--- headline message
-headline_eq_msg add_ea ct ty1 ty2
-
- | (isLiftedRuntimeRep ty1 && isUnliftedRuntimeRep ty2) ||
- (isLiftedRuntimeRep ty2 && isUnliftedRuntimeRep ty1) ||
- (isLiftedLevity ty1 && isUnliftedLevity ty2) ||
- (isLiftedLevity ty2 && isUnliftedLevity ty1)
- = text "Couldn't match a lifted type with an unlifted type"
-
- | isAtomicTy ty1 || isAtomicTy ty2
- = -- Print with quotes
- sep [ text herald1 <+> quotes (ppr ty1)
- , nest padding $
- text herald2 <+> quotes (ppr ty2) ]
-
- | otherwise
- = -- Print with vertical layout
- vcat [ text herald1 <> colon <+> ppr ty1
- , nest padding $
- text herald2 <> colon <+> ppr ty2 ]
- where
- herald1 = conc [ "Couldn't match"
- , if is_repr then "representation of" else ""
- , if add_ea then "expected" else ""
- , what ]
- herald2 = conc [ "with"
- , if is_repr then "that of" else ""
- , if add_ea then ("actual " ++ what) else "" ]
-
- padding = length herald1 - length herald2
-
- is_repr = case ctEqRel ct of { ReprEq -> True; NomEq -> False }
-
- what = levelString (ctLocTypeOrKind_maybe (ctLoc ct) `orElse` TypeLevel)
-
- conc :: [String] -> String
- conc = foldr1 add_space
-
- add_space :: String -> String -> String
- add_space s1 s2 | null s1 = s2
- | null s2 = s1
- | otherwise = s1 ++ (' ' : s2)
-
-
-tk_eq_msg :: ReportErrCtxt
- -> Ct -> Type -> Type -> CtOrigin -> SDoc
-tk_eq_msg ctxt ct ty1 ty2 orig@(TypeEqOrigin { uo_actual = act
- , uo_expected = exp
- , uo_thing = mb_thing })
- -- We can use the TypeEqOrigin to
- -- improve the error message quite a lot
-
- | isUnliftedTypeKind act, isLiftedTypeKind exp
- = sep [ text "Expecting a lifted type, but"
- , thing_msg mb_thing (text "an") (text "unlifted") ]
-
- | isLiftedTypeKind act, isUnliftedTypeKind exp
- = sep [ text "Expecting an unlifted type, but"
- , thing_msg mb_thing (text "a") (text "lifted") ]
-
- | tcIsLiftedTypeKind exp
- = maybe_num_args_msg $$
- sep [ text "Expected a type, but"
- , case mb_thing of
- Nothing -> text "found something with kind"
- Just thing -> quotes thing <+> text "has kind"
- , quotes (pprWithTYPE act) ]
-
- | Just nargs_msg <- num_args_msg
- = nargs_msg $$
- mk_ea_msg ctxt (Just ct) level orig
-
- | -- pprTrace "check" (ppr ea_looks_same $$ ppr exp $$ ppr act $$ ppr ty1 $$ ppr ty2) $
- ea_looks_same ty1 ty2 exp act
- = mk_ea_msg ctxt (Just ct) level orig
- | otherwise -- The mismatched types are /inside/ exp and act
- = vcat [ headline_eq_msg False ct ty1 ty2
- , mk_ea_msg ctxt Nothing level orig ]
-
- where
- ct_loc = ctLoc ct
- level = ctLocTypeOrKind_maybe ct_loc `orElse` TypeLevel
-
- thing_msg (Just thing) _ levity = quotes thing <+> text "is" <+> levity
- thing_msg Nothing an levity = text "got" <+> an <+> levity <+> text "type"
-
- num_args_msg = case level of
- KindLevel
- | not (isMetaTyVarTy exp) && not (isMetaTyVarTy act)
- -- if one is a meta-tyvar, then it's possible that the user
- -- has asked for something impredicative, and we couldn't unify.
- -- Don't bother with counting arguments.
- -> let n_act = count_args act
- n_exp = count_args exp in
- case n_act - n_exp of
- n | n > 0 -- we don't know how many args there are, so don't
- -- recommend removing args that aren't
- , Just thing <- mb_thing
- -> Just $ text "Expecting" <+> speakN (abs n) <+>
- more <+> quotes thing
- where
- more
- | n == 1 = text "more argument to"
- | otherwise = text "more arguments to" -- n > 1
- _ -> Nothing
-
- _ -> Nothing
-
- maybe_num_args_msg = num_args_msg `orElse` empty
-
- count_args ty = count isVisibleBinder $ fst $ splitPiTys ty
-
-tk_eq_msg ctxt ct ty1 ty2
- (KindEqOrigin cty1 cty2 sub_o mb_sub_t_or_k)
- = vcat [ headline_eq_msg False ct ty1 ty2
- , supplementary_msg ]
- where
- sub_t_or_k = mb_sub_t_or_k `orElse` TypeLevel
- sub_whats = text (levelString sub_t_or_k) <> char 's'
- -- "types" or "kinds"
-
- supplementary_msg
- = sdocOption sdocPrintExplicitCoercions $ \printExplicitCoercions ->
- if printExplicitCoercions
- || not (cty1 `pickyEqType` cty2)
- then vcat [ hang (text "When matching" <+> sub_whats)
- 2 (vcat [ ppr cty1 <+> dcolon <+>
- ppr (tcTypeKind cty1)
- , ppr cty2 <+> dcolon <+>
- ppr (tcTypeKind cty2) ])
- , mk_supplementary_ea_msg ctxt sub_t_or_k cty1 cty2 sub_o ]
- else text "When matching the kind of" <+> quotes (ppr cty1)
-
-tk_eq_msg _ _ _ _ _ = panic "typeeq_mismatch_msg"
-
-ea_looks_same :: Type -> Type -> Type -> Type -> Bool
--- True if the faulting types (ty1, ty2) look the same as
--- the expected/actual types (exp, act).
--- If so, we don't want to redundantly report the latter
-ea_looks_same ty1 ty2 exp act
- = (act `looks_same` ty1 && exp `looks_same` ty2) ||
- (exp `looks_same` ty1 && act `looks_same` ty2)
+mkMismatchMsg :: Ct -> Type -> Type -> TcReportMsg
+mkMismatchMsg ct ty1 ty2 =
+ case ctOrigin ct of
+ TypeEqOrigin { uo_actual, uo_expected, uo_thing = mb_thing } ->
+ mkTcReportWithInfo
+ (TypeEqMismatch
+ { teq_mismatch_ppr_explicit_kinds = ppr_explicit_kinds
+ , teq_mismatch_ct = ct
+ , teq_mismatch_ty1 = ty1
+ , teq_mismatch_ty2 = ty2
+ , teq_mismatch_actual = uo_actual
+ , teq_mismatch_expected = uo_expected
+ , teq_mismatch_what = mb_thing})
+ extras
+ KindEqOrigin cty1 cty2 sub_o mb_sub_t_or_k ->
+ mkTcReportWithInfo (Mismatch False ct ty1 ty2)
+ (WhenMatching cty1 cty2 sub_o mb_sub_t_or_k : extras)
+ _ ->
+ mkTcReportWithInfo
+ (Mismatch False ct ty1 ty2)
+ extras
where
- looks_same t1 t2 = t1 `pickyEqType` t2
- || t1 `eqType` liftedTypeKind && t2 `eqType` liftedTypeKind
- -- pickyEqType is sensitive to synonyms, so only replies True
- -- when the types really look the same. However,
- -- (TYPE 'LiftedRep) and Type both print the same way.
-
-mk_supplementary_ea_msg :: ReportErrCtxt -> TypeOrKind
- -> Type -> Type -> CtOrigin -> SDoc
-mk_supplementary_ea_msg ctxt level ty1 ty2 orig
- | TypeEqOrigin { uo_expected = exp, uo_actual = act } <- orig
- , not (ea_looks_same ty1 ty2 exp act)
- = mk_ea_msg ctxt Nothing level orig
- | otherwise
- = empty
-
-mk_ea_msg :: ReportErrCtxt -> Maybe Ct -> TypeOrKind -> CtOrigin -> SDoc
--- Constructs a "Couldn't match" message
--- The (Maybe Ct) says whether this is the main top-level message (Just)
--- or a supplementary message (Nothing)
-mk_ea_msg ctxt at_top level
- (TypeEqOrigin { uo_actual = act, uo_expected = exp, uo_thing = mb_thing })
- | Just thing <- mb_thing
- , KindLevel <- level
- = hang (text "Expected" <+> kind_desc <> comma)
- 2 (text "but" <+> quotes thing <+> text "has kind" <+>
- quotes (ppr act))
-
- | otherwise
- = vcat [ case at_top of
- Just ct -> headline_eq_msg True ct exp act
- Nothing -> supplementary_ea_msg
- , ppWhen expand_syns expandedTys ]
-
- where
- supplementary_ea_msg = vcat [ text "Expected:" <+> ppr exp
- , text " Actual:" <+> ppr act ]
-
- kind_desc | tcIsConstraintKind exp = text "a constraint"
- | Just arg <- kindRep_maybe exp -- TYPE t0
- , tcIsTyVarTy arg = sdocOption sdocPrintExplicitRuntimeReps $ \case
- True -> text "kind" <+> quotes (ppr exp)
- False -> text "a type"
- | otherwise = text "kind" <+> quotes (ppr exp)
-
- expand_syns = cec_expand_syns ctxt
-
- expandedTys = ppUnless (expTy1 `pickyEqType` exp && expTy2 `pickyEqType` act) $ vcat
- [ text "Type synonyms expanded:"
- , text "Expected type:" <+> ppr expTy1
- , text " Actual type:" <+> ppr expTy2 ]
-
- (expTy1, expTy2) = expandSynonymsToMatch exp act
-
-mk_ea_msg _ _ _ _ = empty
+ orig = ctOrigin ct
+ extras = sameOccExtras ty2 ty1
+ ppr_explicit_kinds = shouldPprWithExplicitKinds ty1 ty2 orig
--- | Prints explicit kinds (with @-fprint-explicit-kinds@) in an 'SDoc' when a
--- type mismatch occurs to due invisible kind arguments.
+-- | Whether to prints explicit kinds (with @-fprint-explicit-kinds@)
+-- in an 'SDoc' when a type mismatch occurs to due invisible kind arguments.
--
-- This function first checks to see if the 'CtOrigin' argument is a
-- 'TypeEqOrigin', and if so, uses the expected/actual types from that to
@@ -2180,18 +1729,16 @@ mk_ea_msg _ _ _ _ = empty
-- mismatch occurred in an invisible argument position or not). If the
-- 'CtOrigin' is not a 'TypeEqOrigin', fall back on the actual mismatched types
-- themselves.
-pprWithExplicitKindsWhenMismatch :: Type -> Type -> CtOrigin
- -> SDoc -> SDoc
-pprWithExplicitKindsWhenMismatch ty1 ty2 ct
- = pprWithExplicitKindsWhen show_kinds
+shouldPprWithExplicitKinds :: Type -> Type -> CtOrigin -> Bool
+shouldPprWithExplicitKinds ty1 ty2 ct
+ = tcEqTypeVis act_ty exp_ty
+ -- True when the visible bit of the types look the same,
+ -- so we want to show the kinds in the displayed type.
where
(act_ty, exp_ty) = case ct of
TypeEqOrigin { uo_actual = act
, uo_expected = exp } -> (act, exp)
_ -> (ty1, ty2)
- show_kinds = tcEqTypeVis act_ty exp_ty
- -- True when the visible bit of the types look the same,
- -- so we want to show the kinds in the displayed type
{- Note [Insoluble occurs check]
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
@@ -2209,165 +1756,11 @@ This is done in misMatchOrCND (via the insoluble_occurs_check arg)
(NB: there are potentially-soluble ones, like (a ~ F a b), and we don't
want to be as draconian with them.)
-
-Note [Expanding type synonyms to make types similar]
-~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
-
-In type error messages, if -fprint-expanded-types is used, we want to expand
-type synonyms to make expected and found types as similar as possible, but we
-shouldn't expand types too much to make type messages even more verbose and
-harder to understand. The whole point here is to make the difference in expected
-and found types clearer.
-
-`expandSynonymsToMatch` does this, it takes two types, and expands type synonyms
-only as much as necessary. Given two types t1 and t2:
-
- * If they're already same, it just returns the types.
-
- * If they're in form `C1 t1_1 .. t1_n` and `C2 t2_1 .. t2_m` (C1 and C2 are
- type constructors), it expands C1 and C2 if they're different type synonyms.
- Then it recursively does the same thing on expanded types. If C1 and C2 are
- same, then it applies the same procedure to arguments of C1 and arguments of
- C2 to make them as similar as possible.
-
- Most important thing here is to keep number of synonym expansions at
- minimum. For example, if t1 is `T (T3, T5, Int)` and t2 is `T (T5, T3,
- Bool)` where T5 = T4, T4 = T3, ..., T1 = X, it returns `T (T3, T3, Int)` and
- `T (T3, T3, Bool)`.
-
- * Otherwise types don't have same shapes and so the difference is clearly
- visible. It doesn't do any expansions and show these types.
-
-Note that we only expand top-layer type synonyms. Only when top-layer
-constructors are the same we start expanding inner type synonyms.
-
-Suppose top-layer type synonyms of t1 and t2 can expand N and M times,
-respectively. If their type-synonym-expanded forms will meet at some point (i.e.
-will have same shapes according to `sameShapes` function), it's possible to find
-where they meet in O(N+M) top-layer type synonym expansions and O(min(N,M))
-comparisons. We first collect all the top-layer expansions of t1 and t2 in two
-lists, then drop the prefix of the longer list so that they have same lengths.
-Then we search through both lists in parallel, and return the first pair of
-types that have same shapes. Inner types of these two types with same shapes
-are then expanded using the same algorithm.
-
-In case they don't meet, we return the last pair of types in the lists, which
-has top-layer type synonyms completely expanded. (in this case the inner types
-are not expanded at all, as the current form already shows the type error)
-}
--- | Expand type synonyms in given types only enough to make them as similar as
--- possible. Returned types are the same in terms of used type synonyms.
---
--- To expand all synonyms, see 'Type.expandTypeSynonyms'.
---
--- See `ExpandSynsFail` tests in tests testsuite/tests/typecheck/should_fail for
--- some examples of how this should work.
-expandSynonymsToMatch :: Type -> Type -> (Type, Type)
-expandSynonymsToMatch ty1 ty2 = (ty1_ret, ty2_ret)
- where
- (ty1_ret, ty2_ret) = go ty1 ty2
-
- -- | Returns (type synonym expanded version of first type,
- -- type synonym expanded version of second type)
- go :: Type -> Type -> (Type, Type)
- go t1 t2
- | t1 `pickyEqType` t2 =
- -- Types are same, nothing to do
- (t1, t2)
-
- go (TyConApp tc1 tys1) (TyConApp tc2 tys2)
- | tc1 == tc2
- , tys1 `equalLength` tys2 =
- -- Type constructors are same. They may be synonyms, but we don't
- -- expand further. The lengths of tys1 and tys2 must be equal;
- -- for example, with type S a = a, we don't want
- -- to zip (S Monad Int) and (S Bool).
- let (tys1', tys2') =
- unzip (zipWithEqual "expandSynonymsToMatch" go tys1 tys2)
- in (TyConApp tc1 tys1', TyConApp tc2 tys2')
-
- go (AppTy t1_1 t1_2) (AppTy t2_1 t2_2) =
- let (t1_1', t2_1') = go t1_1 t2_1
- (t1_2', t2_2') = go t1_2 t2_2
- in (mkAppTy t1_1' t1_2', mkAppTy t2_1' t2_2')
-
- go ty1@(FunTy _ w1 t1_1 t1_2) ty2@(FunTy _ w2 t2_1 t2_2) | w1 `eqType` w2 =
- let (t1_1', t2_1') = go t1_1 t2_1
- (t1_2', t2_2') = go t1_2 t2_2
- in ( ty1 { ft_arg = t1_1', ft_res = t1_2' }
- , ty2 { ft_arg = t2_1', ft_res = t2_2' })
-
- go (ForAllTy b1 t1) (ForAllTy b2 t2) =
- -- NOTE: We may have a bug here, but we just can't reproduce it easily.
- -- See D1016 comments for details and our attempts at producing a test
- -- case. Short version: We probably need RnEnv2 to really get this right.
- let (t1', t2') = go t1 t2
- in (ForAllTy b1 t1', ForAllTy b2 t2')
-
- go (CastTy ty1 _) ty2 = go ty1 ty2
- go ty1 (CastTy ty2 _) = go ty1 ty2
-
- go t1 t2 =
- -- See Note [Expanding type synonyms to make types similar] for how this
- -- works
- let
- t1_exp_tys = t1 : tyExpansions t1
- t2_exp_tys = t2 : tyExpansions t2
- t1_exps = length t1_exp_tys
- t2_exps = length t2_exp_tys
- dif = abs (t1_exps - t2_exps)
- in
- followExpansions $
- zipEqual "expandSynonymsToMatch.go"
- (if t1_exps > t2_exps then drop dif t1_exp_tys else t1_exp_tys)
- (if t2_exps > t1_exps then drop dif t2_exp_tys else t2_exp_tys)
-
- -- | Expand the top layer type synonyms repeatedly, collect expansions in a
- -- list. The list does not include the original type.
- --
- -- Example, if you have:
- --
- -- type T10 = T9
- -- type T9 = T8
- -- ...
- -- type T0 = Int
- --
- -- `tyExpansions T10` returns [T9, T8, T7, ... Int]
- --
- -- This only expands the top layer, so if you have:
- --
- -- type M a = Maybe a
- --
- -- `tyExpansions (M T10)` returns [Maybe T10] (T10 is not expanded)
- tyExpansions :: Type -> [Type]
- tyExpansions = unfoldr (\t -> (\x -> (x, x)) `fmap` tcView t)
-
- -- | Drop the type pairs until types in a pair look alike (i.e. the outer
- -- constructors are the same).
- followExpansions :: [(Type, Type)] -> (Type, Type)
- followExpansions [] = pprPanic "followExpansions" empty
- followExpansions [(t1, t2)]
- | sameShapes t1 t2 = go t1 t2 -- expand subtrees
- | otherwise = (t1, t2) -- the difference is already visible
- followExpansions ((t1, t2) : tss)
- -- Traverse subtrees when the outer shapes are the same
- | sameShapes t1 t2 = go t1 t2
- -- Otherwise follow the expansions until they look alike
- | otherwise = followExpansions tss
-
- sameShapes :: Type -> Type -> Bool
- sameShapes AppTy{} AppTy{} = True
- sameShapes (TyConApp tc1 _) (TyConApp tc2 _) = tc1 == tc2
- sameShapes (FunTy {}) (FunTy {}) = True
- sameShapes (ForAllTy {}) (ForAllTy {}) = True
- sameShapes (CastTy ty1 _) ty2 = sameShapes ty1 ty2
- sameShapes ty1 (CastTy ty2 _) = sameShapes ty1 ty2
- sameShapes _ _ = False
-
-sameOccExtra :: TcType -> TcType -> SDoc
+sameOccExtras :: TcType -> TcType -> [TcReportInfo]
-- See Note [Disambiguating (X ~ X) errors]
-sameOccExtra ty1 ty2
+sameOccExtras ty1 ty2
| Just (tc1, _) <- tcSplitTyConApp_maybe ty1
, Just (tc2, _) <- tcSplitTyConApp_maybe ty2
, let n1 = tyConName tc1
@@ -2376,23 +1769,9 @@ sameOccExtra ty1 ty2
same_pkg = moduleUnit (nameModule n1) == moduleUnit (nameModule n2)
, n1 /= n2 -- Different Names
, same_occ -- but same OccName
- = text "NB:" <+> (ppr_from same_pkg n1 $$ ppr_from same_pkg n2)
+ = [SameOcc same_pkg n1 n2]
| otherwise
- = empty
- where
- ppr_from same_pkg nm
- | isGoodSrcSpan loc
- = hang (quotes (ppr nm) <+> text "is defined at")
- 2 (ppr loc)
- | otherwise -- Imported things have an UnhelpfulSrcSpan
- = hang (quotes (ppr nm))
- 2 (sep [ text "is defined in" <+> quotes (ppr (moduleName mod))
- , ppUnless (same_pkg || pkg == mainUnit) $
- nest 4 $ text "in package" <+> quotes (ppr pkg) ])
- where
- pkg = moduleUnit mod
- mod = nameModule nm
- loc = nameSrcSpan nm
+ = []
{- Note [Suggest adding a type signature]
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
@@ -2461,7 +1840,7 @@ Warn of loopy local equalities that were dropped.
************************************************************************
-}
-mkDictErr :: HasDebugCallStack => ReportErrCtxt -> [Ct] -> TcM Report
+mkDictErr :: HasDebugCallStack => ReportErrCtxt -> [Ct] -> TcM SolverReport
mkDictErr ctxt cts
= assert (not (null cts)) $
do { inst_envs <- tcGetInstEnvs
@@ -2475,7 +1854,7 @@ mkDictErr ctxt cts
-- have the same source-location origin, to try avoid a cascade
-- of error from one location
; err <- mk_dict_err ctxt (head (no_inst_cts ++ overlap_cts))
- ; return $ important err }
+ ; return $ important ctxt err }
where
no_givens = null (getUserGivens ctxt)
@@ -2507,30 +1886,27 @@ mkDictErr ctxt cts
-- matching and unifying instances, and say "The choice depends on the instantion of ...,
-- and the result of evaluating ...".
mk_dict_err :: HasCallStack => ReportErrCtxt -> (Ct, ClsInstLookupResult)
- -> TcM SDoc
+ -> TcM TcReportMsg
-- Report an overlap error if this class constraint results
-- from an overlap (returning Left clas), otherwise return (Right pred)
-mk_dict_err ctxt@(CEC {cec_encl = implics}) (ct, (matches, unifiers, unsafe_overlapped))
+mk_dict_err ctxt (ct, (matches, unifiers, unsafe_overlapped))
| null matches -- No matches but perhaps several unifiers
- = do { (_, binds_msg, ct) <- relevantBindings True ctxt ct
+ = do { (_, rel_binds, ct) <- relevantBindings True ctxt ct
; candidate_insts <- get_candidate_instances
- ; field_suggestions <- record_field_suggestions
- ; return (cannot_resolve_msg ct candidate_insts binds_msg field_suggestions) }
+ ; (imp_errs, field_suggestions) <- record_field_suggestions
+ ; return (cannot_resolve_msg ct candidate_insts rel_binds imp_errs field_suggestions) }
| null unsafe_overlapped -- Some matches => overlap errors
- = return overlap_msg
+ = return $ overlap_msg
| otherwise
- = return safe_haskell_msg
+ = return $ safe_haskell_msg
where
orig = ctOrigin ct
pred = ctPred ct
(clas, tys) = getClassPredTys pred
ispecs = [ispec | (ispec, _) <- matches]
unsafe_ispecs = [ispec | (ispec, _) <- unsafe_overlapped]
- useful_givens = discardProvCtxtGivens orig (getUserGivensFromImplics implics)
- -- useful_givens are the enclosing implications with non-empty givens,
- -- modulo the horrid discardProvCtxtGivens
get_candidate_instances :: TcM [ClsInst]
-- See Note [Report candidate instances]
@@ -2553,18 +1929,18 @@ mk_dict_err ctxt@(CEC {cec_encl = implics}) (ct, (matches, unifiers, unsafe_over
| otherwise = False
-- See Note [Out-of-scope fields with -XOverloadedRecordDot]
- record_field_suggestions :: TcM SDoc
- record_field_suggestions = flip (maybe $ return empty) record_field $ \name ->
+ record_field_suggestions :: TcM ([ImportError], [GhcHint])
+ record_field_suggestions = flip (maybe $ return ([], noHints)) record_field $ \name ->
do { glb_env <- getGlobalRdrEnv
; lcl_env <- getLocalRdrEnv
; if occ_name_in_scope glb_env lcl_env name
- then return empty
- else do { dflags <- getDynFlags
- ; imp_info <- getImports
- ; curr_mod <- getModule
- ; hpt <- getHpt
- ; return (unknownNameSuggestions WL_RecField dflags hpt curr_mod
- glb_env emptyLocalRdrEnv imp_info (mkRdrUnqual name)) } }
+ then return ([], noHints)
+ else do { dflags <- getDynFlags
+ ; imp_info <- getImports
+ ; curr_mod <- getModule
+ ; hpt <- getHpt
+ ; return (unknownNameSuggestions WL_RecField dflags hpt curr_mod
+ glb_env emptyLocalRdrEnv imp_info (mkRdrUnqual name)) } }
occ_name_in_scope glb_env lcl_env occ_name = not $
null (lookupGlobalRdrEnv glb_env occ_name) &&
@@ -2574,232 +1950,22 @@ mk_dict_err ctxt@(CEC {cec_encl = implics}) (ct, (matches, unifiers, unsafe_over
HasFieldOrigin name -> Just (mkVarOccFS name)
_ -> Nothing
- cannot_resolve_msg :: Ct -> [ClsInst] -> SDoc -> SDoc -> SDoc
- cannot_resolve_msg ct candidate_insts binds_msg field_suggestions
- = vcat [ no_inst_msg
- , nest 2 extra_note
- , vcat (pp_givens useful_givens)
- , mb_patsyn_prov `orElse` empty
- , ppWhen (has_ambig_tvs && not (null unifiers && null useful_givens))
- (vcat [ ppUnless lead_with_ambig ambig_msg, binds_msg, potential_msg ])
-
- , ppWhen (isNothing mb_patsyn_prov) $
- -- Don't suggest fixes for the provided context of a pattern
- -- synonym; the right fix is to bind more in the pattern
- show_fixes (ctxtFixes has_ambig_tvs pred implics
- ++ drv_fixes)
- , ppWhen (not (null candidate_insts))
- (hang (text "There are instances for similar types:")
- 2 (vcat (map ppr candidate_insts)))
- -- See Note [Report candidate instances]
- , field_suggestions ]
- where
- orig = ctOrigin ct
- -- See Note [Highlighting ambiguous type variables]
- lead_with_ambig = has_ambig_tvs && not (any isRuntimeUnkSkol ambig_tvs)
- && not (null unifiers) && null useful_givens
-
- (has_ambig_tvs, ambig_msg) = mkAmbigMsg lead_with_ambig ct
- ambig_tvs = uncurry (++) (getAmbigTkvs ct)
-
- no_inst_msg
- | lead_with_ambig
- = ambig_msg <+> pprArising orig
- $$ text "prevents the constraint" <+> quotes (pprParendType pred)
- <+> text "from being solved."
-
- | null useful_givens
- = addArising orig $ text "No instance for"
- <+> pprParendType pred
-
- | otherwise
- = addArising orig $ text "Could not deduce"
- <+> pprParendType pred
-
- potential_msg
- = ppWhen (not (null unifiers) && want_potential orig) $
- potential_hdr $$
- potentialInstancesErrMsg (PotentialInstances { matches = [], unifiers })
-
- potential_hdr
- = ppWhen lead_with_ambig $
- text "Probable fix: use a type annotation to specify what"
- <+> pprQuotedList ambig_tvs <+> text "should be."
-
- mb_patsyn_prov :: Maybe SDoc
- mb_patsyn_prov
- | not lead_with_ambig
- , ProvCtxtOrigin PSB{ psb_def = L _ pat } <- orig
- = Just (vcat [ text "In other words, a successful match on the pattern"
- , nest 2 $ ppr pat
- , text "does not provide the constraint" <+> pprParendType pred ])
- | otherwise = Nothing
-
- -- Report "potential instances" only when the constraint arises
- -- directly from the user's use of an overloaded function
- want_potential (TypeEqOrigin {}) = False
- want_potential _ = True
-
- extra_note | any isFunTy (filterOutInvisibleTypes (classTyCon clas) tys)
- = text "(maybe you haven't applied a function to enough arguments?)"
- | className clas == typeableClassName -- Avoid mysterious "No instance for (Typeable T)
- , [_,ty] <- tys -- Look for (Typeable (k->*) (T k))
- , Just (tc,_) <- tcSplitTyConApp_maybe ty
- , not (isTypeFamilyTyCon tc)
- = hang (text "GHC can't yet do polykinded")
- 2 (text "Typeable" <+>
- parens (ppr ty <+> dcolon <+> ppr (tcTypeKind ty)))
- | otherwise
- = empty
-
- drv_fixes = case orig of
- DerivClauseOrigin -> [drv_fix False]
- StandAloneDerivOrigin -> [drv_fix True]
- DerivOriginDC _ _ standalone -> [drv_fix standalone]
- DerivOriginCoerce _ _ _ standalone -> [drv_fix standalone]
- _ -> []
-
- drv_fix standalone_wildcard
- | standalone_wildcard
- = text "fill in the wildcard constraint yourself"
- | otherwise
- = hang (text "use a standalone 'deriving instance' declaration,")
- 2 (text "so you can specify the instance context yourself")
+ cannot_resolve_msg :: Ct -> [ClsInst] -> RelevantBindings -> [ImportError] -> [GhcHint] -> TcReportMsg
+ cannot_resolve_msg ct candidate_insts binds imp_errs field_suggestions
+ = CannotResolveInstance ct unifiers candidate_insts imp_errs field_suggestions binds
+ -- Overlap errors.
+ overlap_msg, safe_haskell_msg :: TcReportMsg
-- Normal overlap error
overlap_msg
- = assert (not (null matches)) $
- vcat [ addArising orig (text "Overlapping instances for"
- <+> pprType (mkClassPred clas tys))
-
- , ppUnless (null matching_givens) $
- sep [text "Matching givens (or their superclasses):"
- , nest 2 (vcat matching_givens)]
-
- , potentialInstancesErrMsg
- (PotentialInstances { matches = map fst matches, unifiers })
-
- , ppWhen (null matching_givens && isSingleton matches && null unifiers) $
- -- Intuitively, some given matched the wanted in their
- -- flattened or rewritten (from given equalities) form
- -- but the matcher can't figure that out because the
- -- constraints are non-flat and non-rewritten so we
- -- simply report back the whole given
- -- context. Accelerate Smart.hs showed this problem.
- sep [ text "There exists a (perhaps superclass) match:"
- , nest 2 (vcat (pp_givens useful_givens))]
-
- , ppWhen (isSingleton matches) $
- parens (vcat [ ppUnless (null tyCoVars) $
- text "The choice depends on the instantiation of" <+>
- quotes (pprWithCommas ppr tyCoVars)
- , ppUnless (null famTyCons) $
- if (null tyCoVars)
- then
- text "The choice depends on the result of evaluating" <+>
- quotes (pprWithCommas ppr famTyCons)
- else
- text "and the result of evaluating" <+>
- quotes (pprWithCommas ppr famTyCons)
- , ppWhen (null (matching_givens)) $
- vcat [ text "To pick the first instance above, use IncoherentInstances"
- , text "when compiling the other instance declarations"]
- ])]
- where
- tyCoVars = tyCoVarsOfTypesList tys
- famTyCons = filter isFamilyTyCon $ concatMap (nonDetEltsUniqSet . tyConsOfType) tys
-
- matching_givens = mapMaybe matchable useful_givens
-
- matchable implic@(Implic { ic_given = evvars, ic_info = skol_info })
- = case ev_vars_matching of
- [] -> Nothing
- _ -> Just $ hang (pprTheta ev_vars_matching)
- 2 (sep [ text "bound by" <+> ppr skol_info
- , text "at" <+>
- ppr (tcl_loc (ic_env implic)) ])
- where ev_vars_matching = [ pred
- | ev_var <- evvars
- , let pred = evVarPred ev_var
- , any can_match (pred : transSuperClasses pred) ]
- can_match pred
- = case getClassPredTys_maybe pred of
- Just (clas', tys') -> clas' == clas
- && isJust (tcMatchTys tys tys')
- Nothing -> False
+ = assert (not (null matches)) $ OverlappingInstances ct ispecs unifiers
-- Overlap error because of Safe Haskell (first
-- match should be the most specific match)
safe_haskell_msg
= assert (matches `lengthIs` 1 && not (null unsafe_ispecs)) $
- vcat [ addArising orig (text "Unsafe overlapping instances for"
- <+> pprType (mkClassPred clas tys))
- , sep [text "The matching instance is:",
- nest 2 (pprInstance $ head ispecs)]
- , vcat [ text "It is compiled in a Safe module and as such can only"
- , text "overlap instances from the same module, however it"
- , text "overlaps the following instances from different" <+>
- text "modules:"
- , nest 2 (vcat [pprInstances $ unsafe_ispecs])
- ]
- ]
-
-
-ctxtFixes :: Bool -> PredType -> [Implication] -> [SDoc]
-ctxtFixes has_ambig_tvs pred implics
- | not has_ambig_tvs
- , isTyVarClassPred pred
- , (skol:skols) <- usefulContext implics pred
- , let what | null skols
- , SigSkol (PatSynCtxt {}) _ _ <- skol
- = text "\"required\""
- | otherwise
- = empty
- = [sep [ text "add" <+> pprParendType pred
- <+> text "to the" <+> what <+> text "context of"
- , nest 2 $ ppr_skol skol $$
- vcat [ text "or" <+> ppr_skol skol
- | skol <- skols ] ] ]
- | otherwise = []
- where
- ppr_skol (PatSkol (RealDataCon dc) _) = text "the data constructor" <+> quotes (ppr dc)
- ppr_skol (PatSkol (PatSynCon ps) _) = text "the pattern synonym" <+> quotes (ppr ps)
- ppr_skol skol_info = ppr skol_info
-
-discardProvCtxtGivens :: CtOrigin -> [UserGiven] -> [UserGiven]
-discardProvCtxtGivens orig givens -- See Note [discardProvCtxtGivens]
- | ProvCtxtOrigin (PSB {psb_id = L _ name}) <- orig
- = filterOut (discard name) givens
- | otherwise
- = givens
- where
- discard n (Implic { ic_info = SigSkol (PatSynCtxt n') _ _ }) = n == n'
- discard _ _ = False
-
-usefulContext :: [Implication] -> PredType -> [SkolemInfo]
--- usefulContext picks out the implications whose context
--- the programmer might plausibly augment to solve 'pred'
-usefulContext implics pred
- = go implics
- where
- pred_tvs = tyCoVarsOfType pred
- go [] = []
- go (ic : ics)
- | implausible ic = rest
- | otherwise = ic_info ic : rest
- where
- -- Stop when the context binds a variable free in the predicate
- rest | any (`elemVarSet` pred_tvs) (ic_skols ic) = []
- | otherwise = go ics
-
- implausible ic
- | null (ic_skols ic) = True
- | implausible_info (ic_info ic) = True
- | otherwise = False
-
- implausible_info (SigSkol (InfSigCtxt {}) _ _) = True
- implausible_info _ = False
- -- Do not suggest adding constraints to an *inferred* type signature
+ UnsafeOverlap ct ispecs unsafe_ispecs
+
{- Note [Report candidate instances]
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
@@ -2829,47 +1995,6 @@ from being solved:
Once these conditions are satisfied, we can safely say that ambiguity prevents
the constraint from being solved.
-Note [discardProvCtxtGivens]
-~~~~~~~~~~~~~~~~~~~~~~~~~~~
-In most situations we call all enclosing implications "useful". There is one
-exception, and that is when the constraint that causes the error is from the
-"provided" context of a pattern synonym declaration:
-
- pattern Pat :: (Num a, Eq a) => Show a => a -> Maybe a
- -- required => provided => type
- pattern Pat x <- (Just x, 4)
-
-When checking the pattern RHS we must check that it does actually bind all
-the claimed "provided" constraints; in this case, does the pattern (Just x, 4)
-bind the (Show a) constraint. Answer: no!
-
-But the implication we generate for this will look like
- forall a. (Num a, Eq a) => [W] Show a
-because when checking the pattern we must make the required
-constraints available, since they are needed to match the pattern (in
-this case the literal '4' needs (Num a, Eq a)).
-
-BUT we don't want to suggest adding (Show a) to the "required" constraints
-of the pattern synonym, thus:
- pattern Pat :: (Num a, Eq a, Show a) => Show a => a -> Maybe a
-It would then typecheck but it's silly. We want the /pattern/ to bind
-the alleged "provided" constraints, Show a.
-
-So we suppress that Implication in discardProvCtxtGivens. It's
-painfully ad-hoc but the truth is that adding it to the "required"
-constraints would work. Suppressing it solves two problems. First,
-we never tell the user that we could not deduce a "provided"
-constraint from the "required" context. Second, we never give a
-possible fix that suggests to add a "provided" constraint to the
-"required" context.
-
-For example, without this distinction the above code gives a bad error
-message (showing both problems):
-
- error: Could not deduce (Show a) ... from the context: (Eq a)
- ... Possible fix: add (Show a) to the context of
- the signature for pattern synonym `Pat' ...
-
Note [Out-of-scope fields with -XOverloadedRecordDot]
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
With -XOverloadedRecordDot, when a field isn't in scope, the error that appears
@@ -2899,202 +2024,6 @@ results in
in the import of ‘Data.Monoid’
-}
-show_fixes :: [SDoc] -> SDoc
-show_fixes [] = empty
-show_fixes (f:fs) = sep [ text "Possible fix:"
- , nest 2 (vcat (f : map (text "or" <+>) fs))]
-
-
--- | This datatype collates instances that match or unifier,
--- in order to report an error message for an unsolved typeclass constraint.
-data PotentialInstances
- = PotentialInstances
- { matches :: [ClsInst]
- , unifiers :: [ClsInst]
- }
-
--- | Directly display the given matching and unifying instances,
--- with a header for each: `Matching instances`/`Potentially matching instances`.
-pprPotentialInstances :: (ClsInst -> SDoc) -> PotentialInstances -> SDoc
-pprPotentialInstances ppr_inst (PotentialInstances { matches, unifiers }) =
- vcat
- [ ppWhen (not $ null matches) $
- text "Matching instance" <> plural matches <> colon $$
- nest 2 (vcat (map ppr_inst matches))
- , ppWhen (not $ null unifiers) $
- (text "Potentially matching instance" <> plural unifiers <> colon) $$
- nest 2 (vcat (map ppr_inst unifiers))
- ]
-
--- | Display a summary of available instances, omitting those involving
--- out-of-scope types, in order to explain why we couldn't solve a particular
--- constraint, e.g. due to instance overlap or out-of-scope types.
---
--- To directly display a collection of matching/unifying instances,
--- use 'pprPotentialInstances'.
-potentialInstancesErrMsg :: PotentialInstances -> SDoc
--- See Note [Displaying potential instances]
-potentialInstancesErrMsg potentials =
- sdocOption sdocPrintPotentialInstances $ \print_insts ->
- getPprStyle $ \sty ->
- potentials_msg_with_options potentials print_insts sty
-
--- | Display a summary of available instances, omitting out-of-scope ones.
---
--- Use 'potentialInstancesErrMsg' to automatically set the pretty-printing
--- options.
-potentials_msg_with_options :: PotentialInstances
- -> Bool -- ^ Whether to print /all/ potential instances
- -> PprStyle
- -> SDoc
-potentials_msg_with_options
- (PotentialInstances { matches, unifiers })
- show_all_potentials sty
- | null matches && null unifiers
- = empty
-
- | null show_these_matches && null show_these_unifiers
- = vcat [ not_in_scope_msg empty
- , flag_hint ]
-
- | otherwise
- = vcat [ pprPotentialInstances
- pprInstance -- print instance + location info
- (PotentialInstances
- { matches = show_these_matches
- , unifiers = show_these_unifiers })
- , overlapping_but_not_more_specific_msg sorted_matches
- , nest 2 $ vcat
- [ ppWhen (n_in_scope_hidden > 0) $
- text "...plus"
- <+> speakNOf n_in_scope_hidden (text "other")
- , ppWhen (not_in_scopes > 0) $
- not_in_scope_msg (text "...plus")
- , flag_hint ] ]
- where
- n_show_matches, n_show_unifiers :: Int
- n_show_matches = 3
- n_show_unifiers = 2
-
- (in_scope_matches, not_in_scope_matches) = partition inst_in_scope matches
- (in_scope_unifiers, not_in_scope_unifiers) = partition inst_in_scope unifiers
- sorted_matches = sortBy fuzzyClsInstCmp in_scope_matches
- sorted_unifiers = sortBy fuzzyClsInstCmp in_scope_unifiers
- (show_these_matches, show_these_unifiers)
- | show_all_potentials = (sorted_matches, sorted_unifiers)
- | otherwise = (take n_show_matches sorted_matches
- ,take n_show_unifiers sorted_unifiers)
- n_in_scope_hidden
- = length sorted_matches + length sorted_unifiers
- - length show_these_matches - length show_these_unifiers
-
- -- "in scope" means that all the type constructors
- -- are lexically in scope; these instances are likely
- -- to be more useful
- inst_in_scope :: ClsInst -> Bool
- inst_in_scope cls_inst = nameSetAll name_in_scope $
- orphNamesOfTypes (is_tys cls_inst)
-
- name_in_scope name
- | pretendNameIsInScope name
- = True -- E.g. (->); see Note [pretendNameIsInScope] in GHC.Builtin.Names
- | Just mod <- nameModule_maybe name
- = qual_in_scope (qualName sty mod (nameOccName name))
- | otherwise
- = True
-
- qual_in_scope :: QualifyName -> Bool
- qual_in_scope NameUnqual = True
- qual_in_scope (NameQual {}) = True
- qual_in_scope _ = False
-
- not_in_scopes :: Int
- not_in_scopes = length not_in_scope_matches + length not_in_scope_unifiers
-
- not_in_scope_msg herald =
- hang (herald <+> speakNOf not_in_scopes (text "instance")
- <+> text "involving out-of-scope types")
- 2 (ppWhen show_all_potentials $
- pprPotentialInstances
- pprInstanceHdr -- only print the header, not the instance location info
- (PotentialInstances
- { matches = not_in_scope_matches
- , unifiers = not_in_scope_unifiers
- }))
-
- flag_hint = ppUnless (show_all_potentials
- || (equalLength show_these_matches matches
- && equalLength show_these_unifiers unifiers)) $
- text "(use -fprint-potential-instances to see them all)"
-
--- | Compute a message informing the user of any instances that are overlapped
--- but were not discarded because the instance overlapping them wasn't
--- strictly more specific.
-overlapping_but_not_more_specific_msg :: [ClsInst] -> SDoc
-overlapping_but_not_more_specific_msg insts
- -- Only print one example of "overlapping but not strictly more specific",
- -- to avoid information overload.
- | overlap : _ <- overlapping_but_not_more_specific
- = overlap_header $$ ppr_overlapping overlap
- | otherwise
- = empty
- where
- overlap_header :: SDoc
- overlap_header
- | [_] <- overlapping_but_not_more_specific
- = text "An overlapping instance can only be chosen when it is strictly more specific."
- | otherwise
- = text "Overlapping instances can only be chosen when they are strictly more specific."
- overlapping_but_not_more_specific :: [(ClsInst, ClsInst)]
- overlapping_but_not_more_specific
- = nubOrdBy (comparing (is_dfun . fst))
- [ (overlapper, overlappee)
- | these <- groupBy ((==) `on` is_cls_nm) insts
- -- Take all pairs of distinct instances...
- , one:others <- tails these -- if `these = [inst_1, inst_2, ...]`
- , other <- others -- then we get pairs `(one, other) = (inst_i, inst_j)` with `i < j`
- -- ... such that one instance in the pair overlaps the other...
- , let mb_overlapping
- | hasOverlappingFlag (overlapMode $ is_flag one)
- || hasOverlappableFlag (overlapMode $ is_flag other)
- = [(one, other)]
- | hasOverlappingFlag (overlapMode $ is_flag other)
- || hasOverlappableFlag (overlapMode $ is_flag one)
- = [(other, one)]
- | otherwise
- = []
- , (overlapper, overlappee) <- mb_overlapping
- -- ... but the overlapper is not more specific than the overlappee.
- , not (overlapper `more_specific_than` overlappee)
- ]
- more_specific_than :: ClsInst -> ClsInst -> Bool
- is1 `more_specific_than` is2
- = isJust (tcMatchTys (is_tys is1) (is_tys is2))
- ppr_overlapping :: (ClsInst, ClsInst) -> SDoc
- ppr_overlapping (overlapper, overlappee)
- = text "The first instance that follows overlaps the second, but is not more specific than it:"
- $$ nest 2 (vcat $ map pprInstanceHdr [overlapper, overlappee])
-
-{- Note [Displaying potential instances]
-~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
-When showing a list of instances for
- - overlapping instances (show ones that match)
- - no such instance (show ones that could match)
-we want to give it a bit of structure. Here's the plan
-
-* Say that an instance is "in scope" if all of the
- type constructors it mentions are lexically in scope.
- These are the ones most likely to be useful to the programmer.
-
-* Show at most n_show in-scope instances,
- and summarise the rest ("plus N others")
-
-* Summarise the not-in-scope instances ("plus 4 not in scope")
-
-* Add the flag -fshow-potential-instances which replaces the
- summary with the full list
--}
-
{-
Note [Kind arguments in error messages]
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
@@ -3118,59 +2047,6 @@ the above error message would instead be displayed as:
Which makes it clearer that the culprit is the mismatch between `k2` and `k20`.
-}
-mkAmbigMsg :: Bool -- True when message has to be at beginning of sentence
- -> Ct -> (Bool, SDoc)
-mkAmbigMsg prepend_msg ct
- | null ambig_kvs && null ambig_tvs = (False, empty)
- | otherwise = (True, msg)
- where
- (ambig_kvs, ambig_tvs) = getAmbigTkvs ct
-
- msg | any isRuntimeUnkSkol ambig_kvs -- See Note [Runtime skolems]
- || any isRuntimeUnkSkol ambig_tvs
- = vcat [ text "Cannot resolve unknown runtime type"
- <> plural ambig_tvs <+> pprQuotedList ambig_tvs
- , text "Use :print or :force to determine these types"]
-
- | not (null ambig_tvs)
- = pp_ambig (text "type") ambig_tvs
-
- | otherwise
- = pp_ambig (text "kind") ambig_kvs
-
- pp_ambig what tkvs
- | prepend_msg -- "Ambiguous type variable 't0'"
- = text "Ambiguous" <+> what <+> text "variable"
- <> plural tkvs <+> pprQuotedList tkvs
-
- | otherwise -- "The type variable 't0' is ambiguous"
- = text "The" <+> what <+> text "variable" <> plural tkvs
- <+> pprQuotedList tkvs <+> isOrAre tkvs <+> text "ambiguous"
-
-pprSkols :: ReportErrCtxt -> [TcTyVar] -> SDoc
-pprSkols ctxt tvs
- = vcat (map pp_one (getSkolemInfo (cec_encl ctxt) tvs))
- where
- pp_one (UnkSkol, tvs)
- = vcat [ hang (pprQuotedList tvs)
- 2 (is_or_are tvs "a" "(rigid, skolem)")
- , nest 2 (text "of unknown origin")
- , nest 2 (text "bound at" <+> ppr (foldr1 combineSrcSpans (map getSrcSpan tvs)))
- ]
- pp_one (RuntimeUnkSkol, tvs)
- = hang (pprQuotedList tvs)
- 2 (is_or_are tvs "an" "unknown runtime")
- pp_one (skol_info, tvs)
- = vcat [ hang (pprQuotedList tvs)
- 2 (is_or_are tvs "a" "rigid" <+> text "bound by")
- , nest 2 (pprSkolInfo skol_info)
- , nest 2 (text "at" <+> ppr (foldr1 combineSrcSpans (map getSrcSpan tvs))) ]
-
- is_or_are [_] article adjective = text "is" <+> text article <+> text adjective
- <+> text "type variable"
- is_or_are _ _ adjective = text "are" <+> text adjective
- <+> text "type variables"
-
getAmbigTkvs :: Ct -> ([Var],[Var])
getAmbigTkvs ct
= partition (`elemVarSet` dep_tkv_set) ambig_tkvs
@@ -3178,32 +2054,6 @@ getAmbigTkvs ct
tkvs = tyCoVarsOfCtList ct
ambig_tkvs = filter isAmbiguousTyVar tkvs
dep_tkv_set = tyCoVarsOfTypes (map tyVarKind tkvs)
-
-getSkolemInfo :: [Implication] -> [TcTyVar]
- -> [(SkolemInfo, [TcTyVar])] -- #14628
--- Get the skolem info for some type variables
--- from the implication constraints that bind them.
---
--- In the returned (skolem, tvs) pairs, the 'tvs' part is non-empty
-getSkolemInfo _ []
- = []
-
-getSkolemInfo [] tvs
- | all isRuntimeUnkSkol tvs = [(RuntimeUnkSkol, tvs)] -- #14628
- | otherwise = -- See https://gitlab.haskell.org/ghc/ghc/-/issues?label_name[]=No%20skolem%20info
- pprTraceUserWarning msg [(UnkSkol,tvs)]
- where
- msg = text "No skolem info - we could not find the origin of the following variables" <+> ppr tvs
- $$ text "This should not happen, please report it as a bug following the instructions at:"
- $$ text "https://gitlab.haskell.org/ghc/ghc/wikis/report-a-bug"
-
-
-getSkolemInfo (implic:implics) tvs
- | null tvs_here = getSkolemInfo implics tvs
- | otherwise = (ic_info implic, tvs_here) : getSkolemInfo implics tvs_other
- where
- (tvs_here, tvs_other) = partition (`elem` ic_skols implic) tvs
-
-----------------------
-- relevantBindings looks at the value environment and finds values whose
-- types mention any of the offending type variables. It has to be
@@ -3216,7 +2066,7 @@ getSkolemInfo (implic:implics) tvs
relevantBindings :: Bool -- True <=> filter by tyvar; False <=> no filtering
-- See #8191
-> ReportErrCtxt -> Ct
- -> TcM (ReportErrCtxt, SDoc, Ct)
+ -> TcM (ReportErrCtxt, RelevantBindings, Ct)
-- Also returns the zonked and tidied CtOrigin of the constraint
relevantBindings want_filtering ctxt ct
= do { traceTc "relevantBindings" (ppr ct)
@@ -3235,9 +2085,9 @@ relevantBindings want_filtering ctxt ct
; (env2, lcl_name_cache) <- zonkTidyTcLclEnvs env1 [lcl_env]
- ; doc <- relevant_bindings want_filtering lcl_env lcl_name_cache ct_fvs
+ ; relev_bds <- relevant_bindings want_filtering lcl_env lcl_name_cache ct_fvs
; let ctxt' = ctxt { cec_tidy = env2 }
- ; return (ctxt', doc, ct') }
+ ; return (ctxt', relev_bds, ct') }
where
loc = ctLoc ct
lcl_env = ctLocEnv loc
@@ -3247,7 +2097,7 @@ relevant_bindings :: Bool
-> TcLclEnv
-> NameEnv Type -- Cache of already zonked and tidied types
-> TyCoVarSet
- -> TcM SDoc
+ -> TcM RelevantBindings
relevant_bindings want_filtering lcl_env lcl_name_env ct_tvs
= do { dflags <- getDynFlags
; traceTc "relevant_bindings" $
@@ -3257,18 +2107,12 @@ relevant_bindings want_filtering lcl_env lcl_name_env ct_tvs
, pprWithCommas id
[ ppr id | TcIdBndr_ExpType id _ _ <- tcl_bndrs lcl_env ] ]
- ; (docs, discards)
- <- go dflags (maxRelevantBinds dflags)
- emptyVarSet [] False
+ ; go dflags (maxRelevantBinds dflags)
+ emptyVarSet (RelevantBindings [] False)
(removeBindingShadowing $ tcl_bndrs lcl_env)
-- tcl_bndrs has the innermost bindings first,
-- which are probably the most relevant ones
-
- ; let doc = ppUnless (null docs) $
- hang (text "Relevant bindings include")
- 2 (vcat docs $$ ppWhen discards discardMsg)
-
- ; return doc }
+ }
where
run_out :: Maybe Int -> Bool
run_out Nothing = False
@@ -3278,14 +2122,13 @@ relevant_bindings want_filtering lcl_env lcl_name_env ct_tvs
dec_max = fmap (\n -> n - 1)
- go :: DynFlags -> Maybe Int -> TcTyVarSet -> [SDoc]
- -> Bool -- True <=> some filtered out due to lack of fuel
+ go :: DynFlags -> Maybe Int -> TcTyVarSet
+ -> RelevantBindings
-> [TcBinder]
- -> TcM ([SDoc], Bool) -- The bool says if we filtered any out
- -- because of lack of fuel
- go _ _ _ docs discards []
- = return (reverse docs, discards)
- go dflags n_left tvs_seen docs discards (tc_bndr : tc_bndrs)
+ -> TcM RelevantBindings
+ go _ _ _ (RelevantBindings bds discards) []
+ = return $ RelevantBindings (reverse bds) discards
+ go dflags n_left tvs_seen rels@(RelevantBindings bds discards) (tc_bndr : tc_bndrs)
= case tc_bndr of
TcTvBndr {} -> discard_it
TcIdBndr id top_lvl -> go2 (idName id) top_lvl
@@ -3301,17 +2144,14 @@ relevant_bindings want_filtering lcl_env lcl_name_env ct_tvs
Nothing -> discard_it -- No info; discard
}
where
- discard_it = go dflags n_left tvs_seen docs
- discards tc_bndrs
+ discard_it = go dflags n_left tvs_seen rels tc_bndrs
go2 id_name top_lvl
= do { let tidy_ty = case lookupNameEnv lcl_name_env id_name of
Just tty -> tty
Nothing -> pprPanic "relevant_bindings" (ppr id_name)
; traceTc "relevantBindings 1" (ppr id_name <+> dcolon <+> ppr tidy_ty)
; let id_tvs = tyCoVarsOfType tidy_ty
- doc = sep [ pprPrefixOcc id_name <+> dcolon <+> ppr tidy_ty
- , nest 2 (parens (text "bound at"
- <+> ppr (getSrcLoc id_name)))]
+ bd = (id_name, tidy_ty)
new_seen = tvs_seen `unionVarSet` id_tvs
; if (want_filtering && not (hasPprDebug dflags)
@@ -3328,44 +2168,26 @@ relevant_bindings want_filtering lcl_env lcl_name_env ct_tvs
else if run_out n_left && id_tvs `subVarSet` tvs_seen
-- We've run out of n_left fuel and this binding only
-- mentions already-seen type variables, so discard it
- then go dflags n_left tvs_seen docs
- True -- Record that we have now discarded something
+ then go dflags n_left tvs_seen (RelevantBindings bds True) -- Record that we have now discarded something
tc_bndrs
-- Keep this binding, decrement fuel
else go dflags (dec_max n_left) new_seen
- (doc:docs) discards tc_bndrs }
-
-
-discardMsg :: SDoc
-discardMsg = text "(Some bindings suppressed;" <+>
- text "use -fmax-relevant-binds=N or -fno-max-relevant-binds)"
+ (RelevantBindings (bd:bds) discards) tc_bndrs }
-----------------------
warnDefaulting :: TcTyVar -> [Ct] -> Type -> TcM ()
-warnDefaulting the_tv wanteds default_ty
+warnDefaulting _ [] _
+ = panic "warnDefaulting: empty Wanteds"
+warnDefaulting the_tv wanteds@(ct:_) default_ty
= do { warn_default <- woptM Opt_WarnTypeDefaults
; env0 <- tcInitTidyEnv
; let tidy_env = tidyFreeTyCoVars env0 $
tyCoVarsOfCtsList (listToBag wanteds)
tidy_wanteds = map (tidyCt tidy_env) wanteds
tidy_tv = lookupVarEnv (snd tidy_env) the_tv
- (loc, ppr_wanteds) = pprWithArising tidy_wanteds
- warn_msg =
- hang (hsep $ [ text "Defaulting" ]
- ++
- (case tidy_tv of
- Nothing -> []
- Just tv -> [text "the type variable"
- , quotes (ppr tv)])
- ++
- [ text "to type"
- , quotes (ppr default_ty)
- , text "in the following constraint" <> plural tidy_wanteds ])
- 2
- ppr_wanteds
- ; let diag = TcRnUnknownMessage $
- mkPlainDiagnostic (WarningWithFlag Opt_WarnTypeDefaults) noHints warn_msg
+ diag = TcRnWarnDefaulting tidy_wanteds tidy_tv default_ty
+ loc = ctLoc ct
; setCtLocM loc $ diagnosticTc warn_default diag }
{-
diff --git a/compiler/GHC/Tc/Errors/Hole.hs b/compiler/GHC/Tc/Errors/Hole.hs
index d1c727da35..7d1388c112 100644
--- a/compiler/GHC/Tc/Errors/Hole.hs
+++ b/compiler/GHC/Tc/Errors/Hole.hs
@@ -32,6 +32,8 @@ where
import GHC.Prelude
+import GHC.Tc.Errors.Types ( HoleFitDispConfig(..), FitsMbSuppressed(..)
+ , ValidHoleFits(..), noValidHoleFits )
import GHC.Tc.Types
import GHC.Tc.Utils.Monad
import GHC.Tc.Types.Constraint
@@ -413,12 +415,6 @@ fits like (`id (_ :: a)` and `head (_ :: [a])`) when looking for fits of type
`a`, where `a` is a skolem.
-}
-data HoleFitDispConfig = HFDC { showWrap :: Bool
- , showWrapVars :: Bool
- , showType :: Bool
- , showProv :: Bool
- , showMatches :: Bool }
-
-- We read the various -no-show-*-of-hole-fits flags
-- and set the display config accordingly.
getHoleFitDispConfig :: TcM HoleFitDispConfig
@@ -560,14 +556,13 @@ findValidHoleFits :: TidyEnv -- ^ The tidy_env for zonking
-- ^ The unsolved simple constraints in the implication for
-- the hole.
-> Hole
- -> TcM (TidyEnv, SDoc)
+ -> TcM (TidyEnv, ValidHoleFits)
findValidHoleFits tidy_env implics simples h@(Hole { hole_sort = ExprHole _
, hole_loc = ct_loc
, hole_ty = hole_ty }) =
do { rdr_env <- getGlobalRdrEnv
; lclBinds <- getLocalBindings tidy_env ct_loc
; maxVSubs <- maxValidHoleFits <$> getDynFlags
- ; hfdc <- getHoleFitDispConfig
; sortingAlg <- getHoleFitSortingAlg
; dflags <- getDynFlags
; hfPlugs <- tcg_hf_plugins <$> getGblEnv
@@ -607,12 +602,11 @@ findValidHoleFits tidy_env implics simples h@(Hole { hole_sort = ExprHole _
; let (pVDisc, limited_subs) = possiblyDiscard maxVSubs plugin_handled_subs
vDiscards = pVDisc || searchDiscards
; subs_with_docs <- addHoleFitDocs limited_subs
- ; let vMsg = ppUnless (null subs_with_docs) $
- hang (text "Valid hole fits include") 2 $
- vcat (map (pprHoleFit hfdc) subs_with_docs)
- $$ ppWhen vDiscards subsDiscardMsg
+ ; let subs = Fits subs_with_docs vDiscards
-- Refinement hole fits. See Note [Valid refinement hole fits include ...]
- ; (tidy_env, refMsg) <- if refLevel >= Just 0 then
+ ; (tidy_env, rsubs) <-
+ if refLevel >= Just 0
+ then
do { maxRSubs <- maxRefHoleFits <$> getDynFlags
-- We can use from just, since we know that Nothing >= _ is False.
; let refLvls = [1..(fromJust refLevel)]
@@ -640,14 +634,11 @@ findValidHoleFits tidy_env implics simples h@(Hole { hole_sort = ExprHole _
possiblyDiscard maxRSubs $ plugin_handled_rsubs
rDiscards = pRDisc || any fst refDs
; rsubs_with_docs <- addHoleFitDocs exact_last_rfits
- ; return (tidy_env,
- ppUnless (null rsubs_with_docs) $
- hang (text "Valid refinement hole fits include") 2 $
- vcat (map (pprHoleFit hfdc) rsubs_with_docs)
- $$ ppWhen rDiscards refSubsDiscardMsg) }
- else return (tidy_env, empty)
+ ; return (tidy_env, Fits rsubs_with_docs rDiscards) }
+ else return (tidy_env, Fits [] False)
; traceTc "findingValidHoleFitsFor }" empty
- ; return (tidy_env, vMsg $$ refMsg) }
+ ; let hole_fits = ValidHoleFits subs rsubs
+ ; return (tidy_env, hole_fits) }
where
-- We extract the TcLevel from the constraint.
hole_lvl = ctLocLevel ct_loc
@@ -688,19 +679,6 @@ findValidHoleFits tidy_env implics simples h@(Hole { hole_sort = ExprHole _
<*> sortHoleFitsByGraph (sort gblFits)
where (lclFits, gblFits) = span hfIsLcl subs
- subsDiscardMsg :: SDoc
- subsDiscardMsg =
- text "(Some hole fits suppressed;" <+>
- text "use -fmax-valid-hole-fits=N" <+>
- text "or -fno-max-valid-hole-fits)"
-
- refSubsDiscardMsg :: SDoc
- refSubsDiscardMsg =
- text "(Some refinement hole fits suppressed;" <+>
- text "use -fmax-refinement-hole-fits=N" <+>
- text "or -fno-max-refinement-hole-fits)"
-
-
-- Based on the flags, we might possibly discard some or all the
-- fits we've found.
possiblyDiscard :: Maybe Int -> [HoleFit] -> (Bool, [HoleFit])
@@ -709,7 +687,7 @@ findValidHoleFits tidy_env implics simples h@(Hole { hole_sort = ExprHole _
-- We don't (as of yet) handle holes in types, only in expressions.
-findValidHoleFits env _ _ _ = return (env, empty)
+findValidHoleFits env _ _ _ = return (env, noValidHoleFits)
-- See Note [Relevant constraints]
relevantCts :: Type -> [Ct] -> [Ct]
diff --git a/compiler/GHC/Tc/Errors/Hole.hs-boot b/compiler/GHC/Tc/Errors/Hole.hs-boot
index 8c4bfce546..94d3f51c58 100644
--- a/compiler/GHC/Tc/Errors/Hole.hs-boot
+++ b/compiler/GHC/Tc/Errors/Hole.hs-boot
@@ -5,6 +5,7 @@
module GHC.Tc.Errors.Hole where
import GHC.Types.Var ( Id )
+import GHC.Tc.Errors.Types ( HoleFitDispConfig, ValidHoleFits )
import GHC.Tc.Types ( TcM )
import GHC.Tc.Types.Constraint ( Ct, CtLoc, Hole, Implication )
import GHC.Utils.Outputable ( SDoc )
@@ -18,7 +19,7 @@ import Data.Maybe ( Maybe )
import Data.Int ( Int )
findValidHoleFits :: TidyEnv -> [Implication] -> [Ct] -> Hole
- -> TcM (TidyEnv, SDoc)
+ -> TcM (TidyEnv, ValidHoleFits)
tcCheckHoleFit :: TypedHole -> TcSigmaType -> TcSigmaType
-> TcM (Bool, HsWrapper)
@@ -30,7 +31,6 @@ tcFilterHoleFits :: Maybe Int -> TypedHole -> (TcType, [TcTyVar])
getLocalBindings :: TidyEnv -> CtLoc -> TcM [Id]
addHoleFitDocs :: [HoleFit] -> TcM [HoleFit]
-data HoleFitDispConfig
data HoleFitSortingAlg
pprHoleFit :: HoleFitDispConfig -> HoleFit -> SDoc
diff --git a/compiler/GHC/Tc/Errors/Hole/FitTypes.hs-boot b/compiler/GHC/Tc/Errors/Hole/FitTypes.hs-boot
index 25d3f81aeb..f27d71b41b 100644
--- a/compiler/GHC/Tc/Errors/Hole/FitTypes.hs-boot
+++ b/compiler/GHC/Tc/Errors/Hole/FitTypes.hs-boot
@@ -4,7 +4,27 @@
-- + which needs 'GHC.Tc.Types'
module GHC.Tc.Errors.Hole.FitTypes where
--- Build ordering
-import GHC.Base()
+import GHC.Base (Int, Maybe)
+import {-# SOURCE #-} GHC.Types.Var (Id)
+import GHC.Types.Name (Name)
+import GHC.Types.Name.Reader (GlobalRdrElt)
+import GHC.Tc.Utils.TcType (TcType)
+import GHC.Hs.Doc (HsDocString)
+import GHC.Utils.Outputable (SDoc)
+
+data HoleFitCandidate
+ = IdHFCand Id
+ | NameHFCand Name
+ | GreHFCand GlobalRdrElt
data HoleFitPlugin
+data HoleFit =
+ HoleFit { hfId :: Id
+ , hfCand :: HoleFitCandidate
+ , hfType :: TcType
+ , hfRefLvl :: Int
+ , hfWrap :: [TcType]
+ , hfMatches :: [TcType]
+ , hfDoc :: Maybe HsDocString
+ }
+ | RawHoleFit SDoc
diff --git a/compiler/GHC/Tc/Errors/Ppr.hs b/compiler/GHC/Tc/Errors/Ppr.hs
index eb7a03febb..0fc6407da4 100644
--- a/compiler/GHC/Tc/Errors/Ppr.hs
+++ b/compiler/GHC/Tc/Errors/Ppr.hs
@@ -1,59 +1,104 @@
{-# LANGUAGE LambdaCase #-}
-{-# OPTIONS_GHC -fno-warn-orphans #-} -- instance Diagnostic TcRnMessage
+{-# LANGUAGE NamedFieldPuns #-}
{-# LANGUAGE RecordWildCards #-}
-module GHC.Tc.Errors.Ppr ( pprTypeDoesNotHaveFixedRuntimeRep )
+{-# OPTIONS_GHC -fno-warn-orphans #-} -- instance Diagnostic TcRnMessage
+
+module GHC.Tc.Errors.Ppr
+ ( pprTypeDoesNotHaveFixedRuntimeRep
+ , pprScopeError
+ )
where
import GHC.Prelude
-import Data.Maybe (isJust)
-
import GHC.Builtin.Names
-import GHC.Core.Class (Class(..))
-import GHC.Core.Coercion (pprCoAxBranchUser)
+
+import GHC.Core.Coercion
+import GHC.Core.Unify ( tcMatchTys )
+import GHC.Core.TyCon
+import GHC.Core.Class
+import GHC.Core.DataCon
import GHC.Core.Coercion.Axiom (coAxiomTyCon, coAxiomSingleBranch)
-import GHC.Core.DataCon (DataCon)
+import GHC.Core.ConLike
import GHC.Core.FamInstEnv (famInstAxiom)
import GHC.Core.InstEnv
-import GHC.Core.TyCon (isNewTyCon)
-import GHC.Core.TyCo.Ppr (pprKind, pprParendType, pprType,
- pprWithExplicitKindsWhen, pprTheta, pprClassPred, pprTypeApp,
- pprSourceTyCon)
+import GHC.Core.TyCo.Rep (Type(..))
+import GHC.Core.TyCo.Ppr (pprWithExplicitKindsWhen,
+ pprSourceTyCon, pprTyVars, pprWithTYPE)
+import GHC.Core.Predicate
import GHC.Core.Type
-import GHC.Data.Bag
+
+import GHC.Driver.Flags
+
+import GHC.Hs
+
import GHC.Tc.Errors.Types
+import GHC.Tc.Types.Constraint
+import {-# SOURCE #-} GHC.Tc.Types (getLclEnvLoc)
+import GHC.Tc.Types.Origin
import GHC.Tc.Types.Rank (Rank(..))
-import GHC.Tc.Utils.TcType (TcType, tcSplitForAllTyVars, mkClassPred)
-import GHC.Types.Basic (UnboxedTupleOrSum(..), unboxedTupleOrSumExtension)
+import GHC.Tc.Utils.TcType
import GHC.Types.Error
-import GHC.Types.FieldLabel (FieldLabelString, flIsOverloaded, flSelector)
-import GHC.Types.Id (isRecordSelector)
+import GHC.Types.FieldLabel (flIsOverloaded)
+import GHC.Types.Hint.Ppr () -- Outputable GhcHint
+import GHC.Types.Basic
+import GHC.Types.Id
import GHC.Types.Name
-import GHC.Types.Name.Reader (GreName(..), pprNameProvenance)
-import GHC.Types.SrcLoc (GenLocated(..), unLoc)
+import GHC.Types.Name.Reader ( GreName(..), pprNameProvenance
+ , RdrName, rdrNameOcc, greMangledName )
+import GHC.Types.Name.Set
+import GHC.Types.SrcLoc
import GHC.Types.TyThing
-import GHC.Types.Var.Env (emptyTidyEnv)
-import GHC.Types.Var.Set (pprVarSet, pluralVarSet)
-import GHC.Driver.Flags
-import GHC.Hs
-import GHC.Utils.Misc (capitalise)
-import GHC.Utils.Outputable
+import GHC.Types.Unique.Set ( nonDetEltsUniqSet )
+import GHC.Types.Var
+import GHC.Types.Var.Set
+import GHC.Types.Var.Env
+
import GHC.Unit.State (pprWithUnitState, UnitState)
+import GHC.Unit.Module
+
+import GHC.Data.Bag
+import GHC.Data.FastString
+import GHC.Data.List.SetOps ( nubOrdBy )
+import GHC.Data.Maybe
+import GHC.Utils.Misc
+import GHC.Utils.Outputable
+import GHC.Utils.Panic
+
import qualified GHC.LanguageExtensions as LangExt
+
+import Data.List.NonEmpty (NonEmpty(..))
import qualified Data.List.NonEmpty as NE
+import Data.Function (on)
+import Data.List ( groupBy, sortBy, tails
+ , partition, unfoldr )
+import Data.Ord ( comparing )
instance Diagnostic TcRnMessage where
diagnosticMessage = \case
TcRnUnknownMessage m
-> diagnosticMessage m
- TcRnTypeDoesNotHaveFixedRuntimeRep ty prov (ErrInfo extra supplementary)
- -> mkDecorated [pprTypeDoesNotHaveFixedRuntimeRep ty prov, extra, supplementary]
TcRnMessageWithInfo unit_state msg_with_info
-> case msg_with_info of
TcRnMessageDetailed err_info msg
-> messageWithInfoDiagnosticMessage unit_state err_info (diagnosticMessage msg)
+ TcRnSolverReport msgs _ _
+ -> mkDecorated $
+ map pprReportWithCtxt msgs
+ TcRnRedundantConstraints redundants (info, show_info)
+ -> mkSimpleDecorated $
+ text "Redundant constraint" <> plural redundants <> colon
+ <+> pprEvVarTheta redundants
+ $$ if show_info then text "In" <+> ppr info else empty
+ TcRnInaccessibleCode implic contras
+ -> mkSimpleDecorated $
+ hang (text "Inaccessible code in")
+ 2 (ppr (ic_info implic))
+ $$ vcat (map pprReportWithCtxt (NE.toList contras))
+ TcRnTypeDoesNotHaveFixedRuntimeRep ty prov (ErrInfo extra supplementary)
+ -> mkDecorated [pprTypeDoesNotHaveFixedRuntimeRep ty prov, extra, supplementary]
TcRnImplicitLift id_or_name ErrInfo{..}
-> mkDecorated $
( text "The variable" <+> quotes (ppr id_or_name) <+>
@@ -546,15 +591,45 @@ instance Diagnostic TcRnMessage where
= text "Illegal term-level use of the" <+> what
ns = nameNameSpace name
what = pprNameSpace ns <+> quotes (ppr name)
+ TcRnNotInScope err name imp_errs _
+ -> mkSimpleDecorated $
+ pprScopeError name err $$ vcat (map ppr imp_errs)
+ TcRnUntickedPromotedConstructor name
+ -> mkSimpleDecorated $
+ text "Unticked promoted constructor" <> colon <+> quotes (ppr name) <> dot
+ TcRnIllegalBuiltinSyntax what rdr_name
+ -> mkSimpleDecorated $
+ hsep [text "Illegal", what, text "of built-in syntax:", ppr rdr_name]
+ TcRnWarnDefaulting tidy_wanteds tidy_tv default_ty
+ -> mkSimpleDecorated $
+ hang (hsep $ [ text "Defaulting" ]
+ ++
+ (case tidy_tv of
+ Nothing -> []
+ Just tv -> [text "the type variable"
+ , quotes (ppr tv)])
+ ++
+ [ text "to type"
+ , quotes (ppr default_ty)
+ , text "in the following constraint" <> plural tidy_wanteds ])
+ 2
+ (pprWithArising tidy_wanteds)
+
diagnosticReason = \case
TcRnUnknownMessage m
-> diagnosticReason m
- TcRnTypeDoesNotHaveFixedRuntimeRep{}
- -> ErrorWithoutFlag
TcRnMessageWithInfo _ msg_with_info
-> case msg_with_info of
TcRnMessageDetailed _ m -> diagnosticReason m
+ TcRnSolverReport _ reason _
+ -> reason -- Error, or a Warning if we are deferring type errors
+ TcRnRedundantConstraints {}
+ -> WarningWithFlag Opt_WarnRedundantConstraints
+ TcRnInaccessibleCode {}
+ -> WarningWithFlag Opt_WarnInaccessibleCode
+ TcRnTypeDoesNotHaveFixedRuntimeRep{}
+ -> ErrorWithoutFlag
TcRnImplicitLift{}
-> WarningWithFlag Opt_WarnImplicitLift
TcRnUnusedPatternBinds{}
@@ -768,15 +843,29 @@ instance Diagnostic TcRnMessage where
-> WarningWithFlag Opt_WarnGADTMonoLocalBinds
TcRnIncorrectNameSpace {}
-> ErrorWithoutFlag
+ TcRnNotInScope {}
+ -> ErrorWithoutFlag
+ TcRnUntickedPromotedConstructor {}
+ -> WarningWithFlag Opt_WarnUntickedPromotedConstructors
+ TcRnIllegalBuiltinSyntax {}
+ -> ErrorWithoutFlag
+ TcRnWarnDefaulting {}
+ -> WarningWithFlag Opt_WarnTypeDefaults
diagnosticHints = \case
TcRnUnknownMessage m
-> diagnosticHints m
- TcRnTypeDoesNotHaveFixedRuntimeRep{}
- -> noHints
TcRnMessageWithInfo _ msg_with_info
-> case msg_with_info of
TcRnMessageDetailed _ m -> diagnosticHints m
+ TcRnSolverReport _ _ hints
+ -> hints
+ TcRnRedundantConstraints{}
+ -> noHints
+ TcRnInaccessibleCode{}
+ -> noHints
+ TcRnTypeDoesNotHaveFixedRuntimeRep{}
+ -> noHints
TcRnImplicitLift{}
-> noHints
TcRnUnusedPatternBinds{}
@@ -987,6 +1076,14 @@ instance Diagnostic TcRnMessage where
-> [SuggestAppropriateTHTick $ nameNameSpace nm]
| otherwise
-> noHints
+ TcRnNotInScope err _ _ hints
+ -> scopeErrorHints err ++ hints
+ TcRnUntickedPromotedConstructor name
+ -> [SuggestAddTick name]
+ TcRnIllegalBuiltinSyntax {}
+ -> noHints
+ TcRnWarnDefaulting {}
+ -> noHints
deriveInstanceErrReasonHints :: Class
-> UsingGeneralizedNewtypeDeriving
@@ -1334,3 +1431,1283 @@ derivErrDiagnosticMessage cls cls_tys mb_strat newtype_deriving pprHerald = \cas
ppr2 = derivErrDiagnosticMessage cls cls_tys mb_strat newtype_deriving False that
in cannotMakeDerivedInstanceHerald cls cls_tys mb_strat newtype_deriving pprHerald
(ppr1 $$ text " or" $$ ppr2)
+
+{- *********************************************************************
+* *
+ Outputable ReportErrCtxt (for debugging)
+* *
+**********************************************************************-}
+
+instance Outputable ReportErrCtxt where
+ ppr (CEC { cec_binds = bvar
+ , cec_defer_type_errors = dte
+ , cec_expr_holes = eh
+ , cec_type_holes = th
+ , cec_out_of_scope_holes = osh
+ , cec_warn_redundant = wr
+ , cec_expand_syns = es
+ , cec_suppress = sup })
+ = text "CEC" <+> braces (vcat
+ [ text "cec_binds" <+> equals <+> ppr bvar
+ , text "cec_defer_type_errors" <+> equals <+> ppr dte
+ , text "cec_expr_holes" <+> equals <+> ppr eh
+ , text "cec_type_holes" <+> equals <+> ppr th
+ , text "cec_out_of_scope_holes" <+> equals <+> ppr osh
+ , text "cec_warn_redundant" <+> equals <+> ppr wr
+ , text "cec_expand_syns" <+> equals <+> ppr es
+ , text "cec_suppress" <+> equals <+> ppr sup ])
+
+{- *********************************************************************
+* *
+ Outputting TcReportMsg errors
+* *
+**********************************************************************-}
+
+-- | Pretty-print a 'ReportWithCtxt', containing a 'TcReportMsg'
+-- with its enclosing 'ReportErrCtxt'.
+pprReportWithCtxt :: ReportWithCtxt -> SDoc
+pprReportWithCtxt (ReportWithCtxt { reportContext = ctxt, reportContent = msg })
+ = pprTcReportMsg ctxt msg
+
+-- | Pretty-print a 'TcReportMsg', with its enclosing 'ReportErrCtxt'.
+pprTcReportMsg :: ReportErrCtxt -> TcReportMsg -> SDoc
+pprTcReportMsg ctxt (TcReportWithInfo msg (info :| infos)) =
+ vcat
+ ( pprTcReportMsg ctxt msg
+ : pprTcReportInfo ctxt info
+ : map (pprTcReportInfo ctxt) infos )
+pprTcReportMsg _ (BadTelescope telescope skols) =
+ hang (text "These kind and type variables:" <+> ppr telescope $$
+ text "are out of dependency order. Perhaps try this ordering:")
+ 2 (pprTyVars sorted_tvs)
+ where
+ sorted_tvs = scopedSort skols
+pprTcReportMsg _ (UserTypeError ty) =
+ pprUserTypeErrorTy ty
+pprTcReportMsg ctxt (ReportHoleError hole err) =
+ pprHoleError ctxt hole err
+pprTcReportMsg _ (CannotUnifyWithPolytype ct tv1 ty2) =
+ vcat [ (if isSkolemTyVar tv1
+ then text "Cannot equate type variable"
+ else text "Cannot instantiate unification variable")
+ <+> quotes (ppr tv1)
+ , hang (text "with a" <+> what <+> text "involving polytypes:") 2 (ppr ty2) ]
+ where
+ what = text $ levelString $
+ ctLocTypeOrKind_maybe (ctLoc ct) `orElse` TypeLevel
+pprTcReportMsg _
+ (Mismatch { mismatch_ea = add_ea
+ , mismatch_ct = ct
+ , mismatch_ty1 = ty1
+ , mismatch_ty2 = ty2 })
+ = addArising (ctOrigin ct) msg
+ where
+ msg
+ | (isLiftedRuntimeRep ty1 && isUnliftedRuntimeRep ty2) ||
+ (isLiftedRuntimeRep ty2 && isUnliftedRuntimeRep ty1) ||
+ (isLiftedLevity ty1 && isUnliftedLevity ty2) ||
+ (isLiftedLevity ty2 && isUnliftedLevity ty1)
+ = text "Couldn't match a lifted type with an unlifted type"
+
+ | isAtomicTy ty1 || isAtomicTy ty2
+ = -- Print with quotes
+ sep [ text herald1 <+> quotes (ppr ty1)
+ , nest padding $
+ text herald2 <+> quotes (ppr ty2) ]
+
+ | otherwise
+ = -- Print with vertical layout
+ vcat [ text herald1 <> colon <+> ppr ty1
+ , nest padding $
+ text herald2 <> colon <+> ppr ty2 ]
+
+ herald1 = conc [ "Couldn't match"
+ , if is_repr then "representation of" else ""
+ , if add_ea then "expected" else ""
+ , what ]
+ herald2 = conc [ "with"
+ , if is_repr then "that of" else ""
+ , if add_ea then ("actual " ++ what) else "" ]
+
+ padding = length herald1 - length herald2
+
+ is_repr = case ctEqRel ct of { ReprEq -> True; NomEq -> False }
+
+ what = levelString (ctLocTypeOrKind_maybe (ctLoc ct) `orElse` TypeLevel)
+
+ conc :: [String] -> String
+ conc = foldr1 add_space
+
+ add_space :: String -> String -> String
+ add_space s1 s2 | null s1 = s2
+ | null s2 = s1
+ | otherwise = s1 ++ (' ' : s2)
+pprTcReportMsg _
+ (KindMismatch { kmismatch_what = thing
+ , kmismatch_expected = exp
+ , kmismatch_actual = act })
+ = hang (text "Expected" <+> kind_desc <> comma)
+ 2 (text "but" <+> quotes (ppr thing) <+> text "has kind" <+>
+ quotes (ppr act))
+ where
+ kind_desc | tcIsConstraintKind exp = text "a constraint"
+ | Just arg <- kindRep_maybe exp -- TYPE t0
+ , tcIsTyVarTy arg = sdocOption sdocPrintExplicitRuntimeReps $ \case
+ True -> text "kind" <+> quotes (ppr exp)
+ False -> text "a type"
+ | otherwise = text "kind" <+> quotes (ppr exp)
+
+
+pprTcReportMsg ctxt
+ (TypeEqMismatch { teq_mismatch_ppr_explicit_kinds = ppr_explicit_kinds
+ , teq_mismatch_ct = ct
+ , teq_mismatch_ty1 = ty1
+ , teq_mismatch_ty2 = ty2
+ , teq_mismatch_expected = exp
+ , teq_mismatch_actual = act
+ , teq_mismatch_what = mb_thing })
+ = addArising orig $ pprWithExplicitKindsWhen ppr_explicit_kinds msg
+ where
+ msg
+ | isUnliftedTypeKind act, isLiftedTypeKind exp
+ = sep [ text "Expecting a lifted type, but"
+ , thing_msg mb_thing (text "an") (text "unlifted") ]
+ | isLiftedTypeKind act, isUnliftedTypeKind exp
+ = sep [ text "Expecting an unlifted type, but"
+ , thing_msg mb_thing (text "a") (text "lifted") ]
+ | tcIsLiftedTypeKind exp
+ = maybe_num_args_msg $$
+ sep [ text "Expected a type, but"
+ , case mb_thing of
+ Nothing -> text "found something with kind"
+ Just thing -> quotes (ppr thing) <+> text "has kind"
+ , quotes (pprWithTYPE act) ]
+ | Just nargs_msg <- num_args_msg
+ , Right ea_msg <- mk_ea_msg ctxt (Just ct) level orig
+ = nargs_msg $$ pprTcReportMsg ctxt ea_msg
+ | -- pprTrace "check" (ppr ea_looks_same $$ ppr exp $$ ppr act $$ ppr ty1 $$ ppr ty2) $
+ ea_looks_same ty1 ty2 exp act
+ , Right ea_msg <- mk_ea_msg ctxt (Just ct) level orig
+ = pprTcReportMsg ctxt ea_msg
+ -- The mismatched types are /inside/ exp and act
+ | let mismatch_err = Mismatch False ct ty1 ty2
+ errs = case mk_ea_msg ctxt Nothing level orig of
+ Left ea_info -> [ mkTcReportWithInfo mismatch_err ea_info ]
+ Right ea_err -> [ mismatch_err, ea_err ]
+ = vcat $ map (pprTcReportMsg ctxt) errs
+
+ ct_loc = ctLoc ct
+ orig = ctOrigin ct
+ level = ctLocTypeOrKind_maybe ct_loc `orElse` TypeLevel
+
+ thing_msg (Just thing) _ levity = quotes (ppr thing) <+> text "is" <+> levity
+ thing_msg Nothing an levity = text "got" <+> an <+> levity <+> text "type"
+
+ num_args_msg = case level of
+ KindLevel
+ | not (isMetaTyVarTy exp) && not (isMetaTyVarTy act)
+ -- if one is a meta-tyvar, then it's possible that the user
+ -- has asked for something impredicative, and we couldn't unify.
+ -- Don't bother with counting arguments.
+ -> let n_act = count_args act
+ n_exp = count_args exp in
+ case n_act - n_exp of
+ n | n > 0 -- we don't know how many args there are, so don't
+ -- recommend removing args that aren't
+ , Just thing <- mb_thing
+ -> Just $ pprTcReportMsg ctxt (ExpectingMoreArguments n thing)
+ _ -> Nothing
+
+ _ -> Nothing
+
+ maybe_num_args_msg = num_args_msg `orElse` empty
+
+ count_args ty = count isVisibleBinder $ fst $ splitPiTys ty
+pprTcReportMsg _ (FixedRuntimeRepError origs_and_tys) =
+ let
+ -- Assemble the error message: pair up each origin with the corresponding type, e.g.
+ -- • FixedRuntimeRep origin msg 1 ...
+ -- a :: TYPE r1
+ -- • FixedRuntimeRep origin msg 2 ...
+ -- b :: TYPE r2
+ combine_origin_ty :: FRROrigin -> Type -> SDoc
+ combine_origin_ty frr_orig ty =
+ -- Add bullet points if there is more than one error.
+ (if length origs_and_tys > 1 then (bullet <+>) else id) $
+ vcat [pprFRROrigin frr_orig <> colon
+ ,nest 2 $ ppr ty <+> dcolon <+> pprWithTYPE (typeKind ty)]
+ in
+ vcat $ map (uncurry combine_origin_ty) origs_and_tys
+pprTcReportMsg _ (SkolemEscape ct implic esc_skols) =
+ let
+ esc_doc = sep [ text "because" <+> what <+> text "variable" <> plural esc_skols
+ <+> pprQuotedList esc_skols
+ , text "would escape" <+>
+ if isSingleton esc_skols then text "its scope"
+ else text "their scope" ]
+ in
+ vcat [ nest 2 $ esc_doc
+ , sep [ (if isSingleton esc_skols
+ then text "This (rigid, skolem)" <+>
+ what <+> text "variable is"
+ else text "These (rigid, skolem)" <+>
+ what <+> text "variables are")
+ <+> text "bound by"
+ , nest 2 $ ppr (ic_info implic)
+ , nest 2 $ text "at" <+>
+ ppr (getLclEnvLoc (ic_env implic)) ] ]
+ where
+ what = text $ levelString $
+ ctLocTypeOrKind_maybe (ctLoc ct) `orElse` TypeLevel
+pprTcReportMsg _ (UntouchableVariable tv implic)
+ | Implic { ic_given = given, ic_info = skol_info } <- implic
+ = sep [ quotes (ppr tv) <+> text "is untouchable"
+ , nest 2 $ text "inside the constraints:" <+> pprEvVarTheta given
+ , nest 2 $ text "bound by" <+> ppr skol_info
+ , nest 2 $ text "at" <+>
+ ppr (getLclEnvLoc (ic_env implic)) ]
+pprTcReportMsg _ (BlockedEquality ct) =
+ vcat [ hang (text "Cannot use equality for substitution:")
+ 2 (ppr (ctPred ct))
+ , text "Doing so would be ill-kinded." ]
+pprTcReportMsg _ (ExpectingMoreArguments n thing) =
+ text "Expecting" <+> speakN (abs n) <+>
+ more <+> quotes (ppr thing)
+ where
+ more
+ | n == 1 = text "more argument to"
+ | otherwise = text "more arguments to" -- n > 1
+pprTcReportMsg ctxt (UnboundImplicitParams (ct :| cts)) =
+ let givens = getUserGivens ctxt
+ in if null givens
+ then addArising (ctOrigin ct) $
+ sep [ text "Unbound implicit parameter" <> plural preds
+ , nest 2 (pprParendTheta preds) ]
+ else pprTcReportMsg ctxt (CouldNotDeduce givens (ct :| cts) Nothing)
+ where
+ preds = map ctPred (ct : cts)
+pprTcReportMsg ctxt (CouldNotDeduce useful_givens (ct :| others) mb_extra)
+ = main_msg $$
+ case supplementary of
+ Left infos
+ -> vcat (map (pprTcReportInfo ctxt) infos)
+ Right other_msg
+ -> pprTcReportMsg ctxt other_msg
+ where
+ main_msg
+ | null useful_givens
+ = addArising (ctOrigin ct) no_instance_msg
+ | otherwise
+ = vcat [ addArising (ctOrigin ct) no_deduce_msg
+ , vcat (pp_givens useful_givens) ]
+ supplementary = case mb_extra of
+ Nothing
+ -> Left []
+ Just (CND_Extra level ty1 ty2)
+ -> mk_supplementary_ea_msg ctxt level ty1 ty2 orig
+ (wanted, wanteds) = (ctPred ct, map ctPred others)
+ orig = ctOrigin ct
+ no_instance_msg
+ | null others
+ , Just (tc, _) <- splitTyConApp_maybe wanted
+ , isClassTyCon tc
+ -- Don't say "no instance" for a constraint such as "c" for a type variable c.
+ = text "No instance for" <+> pprParendType wanted
+ | otherwise
+ = text "Could not solve:" <+> pprTheta wanteds
+ no_deduce_msg
+ | null others
+ = text "Could not deduce" <+> pprParendType wanted
+ | otherwise
+ = text "Could not deduce:" <+> pprTheta wanteds
+pprTcReportMsg ctxt (AmbiguityPreventsSolvingCt ct ambigs) =
+ pprTcReportInfo ctxt (Ambiguity True ambigs) <+>
+ pprArising (ctOrigin ct) $$
+ text "prevents the constraint" <+> quotes (pprParendType $ ctPred ct)
+ <+> text "from being solved."
+pprTcReportMsg ctxt@(CEC {cec_encl = implics})
+ (CannotResolveInstance ct unifiers candidates imp_errs suggs binds)
+ =
+ vcat
+ [ pprTcReportMsg ctxt no_inst_msg
+ , nest 2 extra_note
+ , mb_patsyn_prov `orElse` empty
+ , ppWhen (has_ambigs && not (null unifiers && null useful_givens))
+ (vcat [ ppUnless lead_with_ambig $
+ pprTcReportInfo ctxt (Ambiguity False (ambig_kvs, ambig_tvs))
+ , pprRelevantBindings binds
+ , potential_msg ])
+ , ppWhen (isNothing mb_patsyn_prov) $
+ -- Don't suggest fixes for the provided context of a pattern
+ -- synonym; the right fix is to bind more in the pattern
+ show_fixes (ctxtFixes has_ambigs pred implics
+ ++ drv_fixes)
+ , ppWhen (not (null candidates))
+ (hang (text "There are instances for similar types:")
+ 2 (vcat (map ppr candidates)))
+ -- See Note [Report candidate instances]
+ , vcat $ map ppr imp_errs
+ , vcat $ map ppr suggs ]
+ where
+ orig = ctOrigin ct
+ pred = ctPred ct
+ (clas, tys) = getClassPredTys pred
+ -- See Note [Highlighting ambiguous type variables]
+ (ambig_kvs, ambig_tvs) = ambigTkvsOfCt ct
+ ambigs = ambig_kvs ++ ambig_tvs
+ has_ambigs = not (null ambigs)
+ useful_givens = discardProvCtxtGivens orig (getUserGivensFromImplics implics)
+ -- useful_givens are the enclosing implications with non-empty givens,
+ -- modulo the horrid discardProvCtxtGivens
+ lead_with_ambig = not (null ambigs)
+ && not (any isRuntimeUnkSkol ambigs)
+ && not (null unifiers)
+ && null useful_givens
+
+ no_inst_msg :: TcReportMsg
+ no_inst_msg
+ | lead_with_ambig
+ = AmbiguityPreventsSolvingCt ct (ambig_kvs, ambig_tvs)
+ | otherwise
+ = CouldNotDeduce useful_givens (ct :| []) Nothing
+
+ -- Report "potential instances" only when the constraint arises
+ -- directly from the user's use of an overloaded function
+ want_potential (TypeEqOrigin {}) = False
+ want_potential _ = True
+
+ potential_msg
+ = ppWhen (not (null unifiers) && want_potential orig) $
+ potential_hdr $$
+ potentialInstancesErrMsg (PotentialInstances { matches = [], unifiers })
+
+ potential_hdr
+ = ppWhen lead_with_ambig $
+ text "Probable fix: use a type annotation to specify what"
+ <+> pprQuotedList ambig_tvs <+> text "should be."
+
+ mb_patsyn_prov :: Maybe SDoc
+ mb_patsyn_prov
+ | not lead_with_ambig
+ , ProvCtxtOrigin PSB{ psb_def = L _ pat } <- orig
+ = Just (vcat [ text "In other words, a successful match on the pattern"
+ , nest 2 $ ppr pat
+ , text "does not provide the constraint" <+> pprParendType pred ])
+ | otherwise = Nothing
+
+ extra_note | any isFunTy (filterOutInvisibleTypes (classTyCon clas) tys)
+ = text "(maybe you haven't applied a function to enough arguments?)"
+ | className clas == typeableClassName -- Avoid mysterious "No instance for (Typeable T)
+ , [_,ty] <- tys -- Look for (Typeable (k->*) (T k))
+ , Just (tc,_) <- tcSplitTyConApp_maybe ty
+ , not (isTypeFamilyTyCon tc)
+ = hang (text "GHC can't yet do polykinded")
+ 2 (text "Typeable" <+>
+ parens (ppr ty <+> dcolon <+> ppr (tcTypeKind ty)))
+ | otherwise
+ = empty
+
+ drv_fixes = case orig of
+ DerivClauseOrigin -> [drv_fix False]
+ StandAloneDerivOrigin -> [drv_fix True]
+ DerivOriginDC _ _ standalone -> [drv_fix standalone]
+ DerivOriginCoerce _ _ _ standalone -> [drv_fix standalone]
+ _ -> []
+
+ drv_fix standalone_wildcard
+ | standalone_wildcard
+ = text "fill in the wildcard constraint yourself"
+ | otherwise
+ = hang (text "use a standalone 'deriving instance' declaration,")
+ 2 (text "so you can specify the instance context yourself")
+
+pprTcReportMsg (CEC {cec_encl = implics}) (OverlappingInstances ct matches unifiers) =
+ vcat
+ [ addArising orig $
+ (text "Overlapping instances for"
+ <+> pprType (mkClassPred clas tys))
+ , ppUnless (null matching_givens) $
+ sep [text "Matching givens (or their superclasses):"
+ , nest 2 (vcat matching_givens)]
+ , potentialInstancesErrMsg
+ (PotentialInstances { matches, unifiers })
+ , ppWhen (null matching_givens && isSingleton matches && null unifiers) $
+ -- Intuitively, some given matched the wanted in their
+ -- flattened or rewritten (from given equalities) form
+ -- but the matcher can't figure that out because the
+ -- constraints are non-flat and non-rewritten so we
+ -- simply report back the whole given
+ -- context. Accelerate Smart.hs showed this problem.
+ sep [ text "There exists a (perhaps superclass) match:"
+ , nest 2 (vcat (pp_givens useful_givens))]
+
+ , ppWhen (isSingleton matches) $
+ parens (vcat [ ppUnless (null tyCoVars) $
+ text "The choice depends on the instantiation of" <+>
+ quotes (pprWithCommas ppr tyCoVars)
+ , ppUnless (null famTyCons) $
+ if (null tyCoVars)
+ then
+ text "The choice depends on the result of evaluating" <+>
+ quotes (pprWithCommas ppr famTyCons)
+ else
+ text "and the result of evaluating" <+>
+ quotes (pprWithCommas ppr famTyCons)
+ , ppWhen (null (matching_givens)) $
+ vcat [ text "To pick the first instance above, use IncoherentInstances"
+ , text "when compiling the other instance declarations"]
+ ])]
+ where
+ orig = ctOrigin ct
+ pred = ctPred ct
+ (clas, tys) = getClassPredTys pred
+ tyCoVars = tyCoVarsOfTypesList tys
+ famTyCons = filter isFamilyTyCon $ concatMap (nonDetEltsUniqSet . tyConsOfType) tys
+ useful_givens = discardProvCtxtGivens orig (getUserGivensFromImplics implics)
+ matching_givens = mapMaybe matchable useful_givens
+ matchable implic@(Implic { ic_given = evvars, ic_info = skol_info })
+ = case ev_vars_matching of
+ [] -> Nothing
+ _ -> Just $ hang (pprTheta ev_vars_matching)
+ 2 (sep [ text "bound by" <+> ppr skol_info
+ , text "at" <+>
+ ppr (getLclEnvLoc (ic_env implic)) ])
+ where ev_vars_matching = [ pred
+ | ev_var <- evvars
+ , let pred = evVarPred ev_var
+ , any can_match (pred : transSuperClasses pred) ]
+ can_match pred
+ = case getClassPredTys_maybe pred of
+ Just (clas', tys') -> clas' == clas
+ && isJust (tcMatchTys tys tys')
+ Nothing -> False
+pprTcReportMsg _ (UnsafeOverlap ct matches unsafe_overlapped) =
+ vcat [ addArising orig (text "Unsafe overlapping instances for"
+ <+> pprType (mkClassPred clas tys))
+ , sep [text "The matching instance is:",
+ nest 2 (pprInstance $ head matches)]
+ , vcat [ text "It is compiled in a Safe module and as such can only"
+ , text "overlap instances from the same module, however it"
+ , text "overlaps the following instances from different" <+>
+ text "modules:"
+ , nest 2 (vcat [pprInstances $ unsafe_overlapped])
+ ]
+ ]
+ where
+ orig = ctOrigin ct
+ pred = ctPred ct
+ (clas, tys) = getClassPredTys pred
+
+{- *********************************************************************
+* *
+ Displaying potential instances
+* *
+**********************************************************************-}
+
+-- | Directly display the given matching and unifying instances,
+-- with a header for each: `Matching instances`/`Potentially matching instances`.
+pprPotentialInstances :: (ClsInst -> SDoc) -> PotentialInstances -> SDoc
+pprPotentialInstances ppr_inst (PotentialInstances { matches, unifiers }) =
+ vcat
+ [ ppWhen (not $ null matches) $
+ text "Matching instance" <> plural matches <> colon $$
+ nest 2 (vcat (map ppr_inst matches))
+ , ppWhen (not $ null unifiers) $
+ (text "Potentially matching instance" <> plural unifiers <> colon) $$
+ nest 2 (vcat (map ppr_inst unifiers))
+ ]
+
+-- | Display a summary of available instances, omitting those involving
+-- out-of-scope types, in order to explain why we couldn't solve a particular
+-- constraint, e.g. due to instance overlap or out-of-scope types.
+--
+-- To directly display a collection of matching/unifying instances,
+-- use 'pprPotentialInstances'.
+potentialInstancesErrMsg :: PotentialInstances -> SDoc
+-- See Note [Displaying potential instances]
+potentialInstancesErrMsg potentials =
+ sdocOption sdocPrintPotentialInstances $ \print_insts ->
+ getPprStyle $ \sty ->
+ potentials_msg_with_options potentials print_insts sty
+
+-- | Display a summary of available instances, omitting out-of-scope ones.
+--
+-- Use 'potentialInstancesErrMsg' to automatically set the pretty-printing
+-- options.
+potentials_msg_with_options :: PotentialInstances
+ -> Bool -- ^ Whether to print /all/ potential instances
+ -> PprStyle
+ -> SDoc
+potentials_msg_with_options
+ (PotentialInstances { matches, unifiers })
+ show_all_potentials sty
+ | null matches && null unifiers
+ = empty
+
+ | null show_these_matches && null show_these_unifiers
+ = vcat [ not_in_scope_msg empty
+ , flag_hint ]
+
+ | otherwise
+ = vcat [ pprPotentialInstances
+ pprInstance -- print instance + location info
+ (PotentialInstances
+ { matches = show_these_matches
+ , unifiers = show_these_unifiers })
+ , overlapping_but_not_more_specific_msg sorted_matches
+ , nest 2 $ vcat
+ [ ppWhen (n_in_scope_hidden > 0) $
+ text "...plus"
+ <+> speakNOf n_in_scope_hidden (text "other")
+ , ppWhen (not_in_scopes > 0) $
+ not_in_scope_msg (text "...plus")
+ , flag_hint ] ]
+ where
+ n_show_matches, n_show_unifiers :: Int
+ n_show_matches = 3
+ n_show_unifiers = 2
+
+ (in_scope_matches, not_in_scope_matches) = partition inst_in_scope matches
+ (in_scope_unifiers, not_in_scope_unifiers) = partition inst_in_scope unifiers
+ sorted_matches = sortBy fuzzyClsInstCmp in_scope_matches
+ sorted_unifiers = sortBy fuzzyClsInstCmp in_scope_unifiers
+ (show_these_matches, show_these_unifiers)
+ | show_all_potentials = (sorted_matches, sorted_unifiers)
+ | otherwise = (take n_show_matches sorted_matches
+ ,take n_show_unifiers sorted_unifiers)
+ n_in_scope_hidden
+ = length sorted_matches + length sorted_unifiers
+ - length show_these_matches - length show_these_unifiers
+
+ -- "in scope" means that all the type constructors
+ -- are lexically in scope; these instances are likely
+ -- to be more useful
+ inst_in_scope :: ClsInst -> Bool
+ inst_in_scope cls_inst = nameSetAll name_in_scope $
+ orphNamesOfTypes (is_tys cls_inst)
+
+ name_in_scope name
+ | pretendNameIsInScope name
+ = True -- E.g. (->); see Note [pretendNameIsInScope] in GHC.Builtin.Names
+ | Just mod <- nameModule_maybe name
+ = qual_in_scope (qualName sty mod (nameOccName name))
+ | otherwise
+ = True
+
+ qual_in_scope :: QualifyName -> Bool
+ qual_in_scope NameUnqual = True
+ qual_in_scope (NameQual {}) = True
+ qual_in_scope _ = False
+
+ not_in_scopes :: Int
+ not_in_scopes = length not_in_scope_matches + length not_in_scope_unifiers
+
+ not_in_scope_msg herald =
+ hang (herald <+> speakNOf not_in_scopes (text "instance")
+ <+> text "involving out-of-scope types")
+ 2 (ppWhen show_all_potentials $
+ pprPotentialInstances
+ pprInstanceHdr -- only print the header, not the instance location info
+ (PotentialInstances
+ { matches = not_in_scope_matches
+ , unifiers = not_in_scope_unifiers
+ }))
+
+ flag_hint = ppUnless (show_all_potentials
+ || (equalLength show_these_matches matches
+ && equalLength show_these_unifiers unifiers)) $
+ text "(use -fprint-potential-instances to see them all)"
+
+-- | Compute a message informing the user of any instances that are overlapped
+-- but were not discarded because the instance overlapping them wasn't
+-- strictly more specific.
+overlapping_but_not_more_specific_msg :: [ClsInst] -> SDoc
+overlapping_but_not_more_specific_msg insts
+ -- Only print one example of "overlapping but not strictly more specific",
+ -- to avoid information overload.
+ | overlap : _ <- overlapping_but_not_more_specific
+ = overlap_header $$ ppr_overlapping overlap
+ | otherwise
+ = empty
+ where
+ overlap_header :: SDoc
+ overlap_header
+ | [_] <- overlapping_but_not_more_specific
+ = text "An overlapping instance can only be chosen when it is strictly more specific."
+ | otherwise
+ = text "Overlapping instances can only be chosen when they are strictly more specific."
+ overlapping_but_not_more_specific :: [(ClsInst, ClsInst)]
+ overlapping_but_not_more_specific
+ = nubOrdBy (comparing (is_dfun . fst))
+ [ (overlapper, overlappee)
+ | these <- groupBy ((==) `on` is_cls_nm) insts
+ -- Take all pairs of distinct instances...
+ , one:others <- tails these -- if `these = [inst_1, inst_2, ...]`
+ , other <- others -- then we get pairs `(one, other) = (inst_i, inst_j)` with `i < j`
+ -- ... such that one instance in the pair overlaps the other...
+ , let mb_overlapping
+ | hasOverlappingFlag (overlapMode $ is_flag one)
+ || hasOverlappableFlag (overlapMode $ is_flag other)
+ = [(one, other)]
+ | hasOverlappingFlag (overlapMode $ is_flag other)
+ || hasOverlappableFlag (overlapMode $ is_flag one)
+ = [(other, one)]
+ | otherwise
+ = []
+ , (overlapper, overlappee) <- mb_overlapping
+ -- ... but the overlapper is not more specific than the overlappee.
+ , not (overlapper `more_specific_than` overlappee)
+ ]
+ more_specific_than :: ClsInst -> ClsInst -> Bool
+ is1 `more_specific_than` is2
+ = isJust (tcMatchTys (is_tys is1) (is_tys is2))
+ ppr_overlapping :: (ClsInst, ClsInst) -> SDoc
+ ppr_overlapping (overlapper, overlappee)
+ = text "The first instance that follows overlaps the second, but is not more specific than it:"
+ $$ nest 2 (vcat $ map pprInstanceHdr [overlapper, overlappee])
+
+{- Note [Displaying potential instances]
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+When showing a list of instances for
+ - overlapping instances (show ones that match)
+ - no such instance (show ones that could match)
+we want to give it a bit of structure. Here's the plan
+
+* Say that an instance is "in scope" if all of the
+ type constructors it mentions are lexically in scope.
+ These are the ones most likely to be useful to the programmer.
+
+* Show at most n_show in-scope instances,
+ and summarise the rest ("plus N others")
+
+* Summarise the not-in-scope instances ("plus 4 not in scope")
+
+* Add the flag -fshow-potential-instances which replaces the
+ summary with the full list
+-}
+
+{- *********************************************************************
+* *
+ Outputting TcReportInfo
+* *
+**********************************************************************-}
+
+-- | Pretty-print an informational message, to accompany a 'TcReportMsg'.
+pprTcReportInfo :: ReportErrCtxt -> TcReportInfo -> SDoc
+pprTcReportInfo _ (Ambiguity prepend_msg (ambig_kvs, ambig_tvs)) = msg
+ where
+
+ msg | any isRuntimeUnkSkol ambig_kvs -- See Note [Runtime skolems]
+ || any isRuntimeUnkSkol ambig_tvs
+ = vcat [ text "Cannot resolve unknown runtime type"
+ <> plural ambig_tvs <+> pprQuotedList ambig_tvs
+ , text "Use :print or :force to determine these types"]
+
+ | not (null ambig_tvs)
+ = pp_ambig (text "type") ambig_tvs
+
+ | otherwise
+ = pp_ambig (text "kind") ambig_kvs
+
+ pp_ambig what tkvs
+ | prepend_msg -- "Ambiguous type variable 't0'"
+ = text "Ambiguous" <+> what <+> text "variable"
+ <> plural tkvs <+> pprQuotedList tkvs
+
+ | otherwise -- "The type variable 't0' is ambiguous"
+ = text "The" <+> what <+> text "variable" <> plural tkvs
+ <+> pprQuotedList tkvs <+> isOrAre tkvs <+> text "ambiguous"
+pprTcReportInfo ctxt (TyVarInfo tv) =
+ case tcTyVarDetails tv of
+ SkolemTv {} -> pprSkols ctxt [tv]
+ RuntimeUnk {} -> quotes (ppr tv) <+> text "is an interactive-debugger skolem"
+ MetaTv {} -> empty
+pprTcReportInfo _ (NonInjectiveTyFam tc) =
+ text "NB:" <+> quotes (ppr tc)
+ <+> text "is a non-injective type family"
+pprTcReportInfo _ (ReportCoercibleMsg msg) =
+ pprCoercibleMsg msg
+pprTcReportInfo _ (ExpectedActual { ea_expected = exp, ea_actual = act }) =
+ vcat
+ [ text "Expected:" <+> ppr exp
+ , text " Actual:" <+> ppr act ]
+pprTcReportInfo _
+ (ExpectedActualAfterTySynExpansion
+ { ea_expanded_expected = exp
+ , ea_expanded_actual = act } )
+ = vcat
+ [ text "Type synonyms expanded:"
+ , text "Expected type:" <+> ppr exp
+ , text " Actual type:" <+> ppr act ]
+pprTcReportInfo ctxt (WhenMatching cty1 cty2 sub_o mb_sub_t_or_k) =
+ sdocOption sdocPrintExplicitCoercions $ \printExplicitCoercions ->
+ if printExplicitCoercions
+ || not (cty1 `pickyEqType` cty2)
+ then vcat [ hang (text "When matching" <+> sub_whats)
+ 2 (vcat [ ppr cty1 <+> dcolon <+>
+ ppr (tcTypeKind cty1)
+ , ppr cty2 <+> dcolon <+>
+ ppr (tcTypeKind cty2) ])
+ , supplementary ]
+ else text "When matching the kind of" <+> quotes (ppr cty1)
+ where
+ sub_t_or_k = mb_sub_t_or_k `orElse` TypeLevel
+ sub_whats = text (levelString sub_t_or_k) <> char 's'
+ supplementary =
+ case mk_supplementary_ea_msg ctxt sub_t_or_k cty1 cty2 sub_o of
+ Left infos -> vcat $ map (pprTcReportInfo ctxt) infos
+ Right msg -> pprTcReportMsg ctxt msg
+pprTcReportInfo _ (SameOcc same_pkg n1 n2) =
+ text "NB:" <+> (ppr_from same_pkg n1 $$ ppr_from same_pkg n2)
+ where
+ ppr_from same_pkg nm
+ | isGoodSrcSpan loc
+ = hang (quotes (ppr nm) <+> text "is defined at")
+ 2 (ppr loc)
+ | otherwise -- Imported things have an UnhelpfulSrcSpan
+ = hang (quotes (ppr nm))
+ 2 (sep [ text "is defined in" <+> quotes (ppr (moduleName mod))
+ , ppUnless (same_pkg || pkg == mainUnit) $
+ nest 4 $ text "in package" <+> quotes (ppr pkg) ])
+ where
+ pkg = moduleUnit mod
+ mod = nameModule nm
+ loc = nameSrcSpan nm
+pprTcReportInfo ctxt (OccursCheckInterestingTyVars (tv :| tvs)) =
+ hang (text "Type variable kinds:") 2 $
+ vcat (map (tyvar_binding . tidyTyCoVarOcc (cec_tidy ctxt))
+ (tv:tvs))
+ where
+ tyvar_binding tyvar = ppr tyvar <+> dcolon <+> ppr (tyVarKind tyvar)
+
+pprCoercibleMsg :: CoercibleMsg -> SDoc
+pprCoercibleMsg (UnknownRoles ty) =
+ hang (text "NB: We cannot know what roles the parameters to" <+>
+ quotes (ppr ty) <+> text "have;")
+ 2 (text "we must assume that the role is nominal")
+pprCoercibleMsg (TyConIsAbstract tc) =
+ hsep [ text "NB: The type constructor"
+ , quotes (pprSourceTyCon tc)
+ , text "is abstract" ]
+pprCoercibleMsg (OutOfScopeNewtypeConstructor tc dc) =
+ hang (text "The data constructor" <+> quotes (ppr $ dataConName dc))
+ 2 (sep [ text "of newtype" <+> quotes (pprSourceTyCon tc)
+ , text "is not in scope" ])
+
+{- *********************************************************************
+* *
+ Outputting HoleError messages
+* *
+**********************************************************************-}
+
+pprHoleError :: ReportErrCtxt -> Hole -> HoleError -> SDoc
+pprHoleError _ (Hole { hole_ty, hole_occ = occ }) (OutOfScopeHole imp_errs)
+ = out_of_scope_msg $$ vcat (map ppr imp_errs)
+ where
+ herald | isDataOcc occ = text "Data constructor not in scope:"
+ | otherwise = text "Variable not in scope:"
+ out_of_scope_msg -- Print v :: ty only if the type has structure
+ | boring_type = hang herald 2 (ppr occ)
+ | otherwise = hang herald 2 (pp_occ_with_type occ hole_ty)
+ boring_type = isTyVarTy hole_ty
+pprHoleError ctxt (Hole { hole_ty, hole_occ }) (HoleError sort) =
+ vcat [ hole_msg
+ , tyvars_msg
+ , case sort of { ExprHole {} -> expr_hole_hint; _ -> type_hole_hint } ]
+
+ where
+
+ hole_msg = case sort of
+ ExprHole {} ->
+ hang (text "Found hole:")
+ 2 (pp_occ_with_type hole_occ hole_ty)
+ TypeHole ->
+ hang (text "Found type wildcard" <+> quotes (ppr hole_occ))
+ 2 (text "standing for" <+> quotes pp_hole_type_with_kind)
+ ConstraintHole ->
+ hang (text "Found extra-constraints wildcard standing for")
+ 2 (quotes $ pprType hole_ty) -- always kind constraint
+
+ hole_kind = tcTypeKind hole_ty
+
+ pp_hole_type_with_kind
+ | isLiftedTypeKind hole_kind
+ || isCoVarType hole_ty -- Don't print the kind of unlifted
+ -- equalities (#15039)
+ = pprType hole_ty
+ | otherwise
+ = pprType hole_ty <+> dcolon <+> pprKind hole_kind
+
+ tyvars = tyCoVarsOfTypeList hole_ty
+ tyvars_msg = ppUnless (null tyvars) $
+ text "Where:" <+> (vcat (map loc_msg other_tvs)
+ $$ pprSkols ctxt skol_tvs)
+ where
+ (skol_tvs, other_tvs) = partition is_skol tyvars
+ is_skol tv = isTcTyVar tv && isSkolemTyVar tv
+ -- Coercion variables can be free in the
+ -- hole, via kind casts
+ expr_hole_hint -- Give hint for, say, f x = _x
+ | lengthFS (occNameFS hole_occ) > 1 -- Don't give this hint for plain "_"
+ = text "Or perhaps" <+> quotes (ppr hole_occ)
+ <+> text "is mis-spelled, or not in scope"
+ | otherwise
+ = empty
+
+ type_hole_hint
+ | ErrorWithoutFlag <- cec_type_holes ctxt
+ = text "To use the inferred type, enable PartialTypeSignatures"
+ | otherwise
+ = empty
+
+ loc_msg tv
+ | isTyVar tv
+ = case tcTyVarDetails tv of
+ MetaTv {} -> quotes (ppr tv) <+> text "is an ambiguous type variable"
+ _ -> empty -- Skolems dealt with already
+ | otherwise -- A coercion variable can be free in the hole type
+ = ppWhenOption sdocPrintExplicitCoercions $
+ quotes (ppr tv) <+> text "is a coercion variable"
+
+pp_occ_with_type :: OccName -> Type -> SDoc
+pp_occ_with_type occ hole_ty = hang (pprPrefixOcc occ) 2 (dcolon <+> pprType hole_ty)
+
+{- *********************************************************************
+* *
+ Outputting ScopeError messages
+* *
+**********************************************************************-}
+
+pprScopeError :: RdrName -> NotInScopeError -> SDoc
+pprScopeError rdr_name scope_err =
+ case scope_err of
+ NotInScope {} ->
+ hang (text "Not in scope:")
+ 2 (what <+> quotes (ppr rdr_name))
+ NoExactName name ->
+ text "The Name" <+> quotes (ppr name) <+> text "is not in scope."
+ SameName gres ->
+ assertPpr (length gres >= 2) (text "pprScopeError SameName: fewer than 2 elements" $$ nest 2 (ppr gres))
+ $ hang (text "Same Name in multiple name-spaces:")
+ 2 (vcat (map pp_one sorted_names))
+ where
+ sorted_names = sortBy (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))
+ MissingBinding thing _ ->
+ sep [ text "The" <+> thing
+ <+> text "for" <+> quotes (ppr rdr_name)
+ , nest 2 $ text "lacks an accompanying binding" ]
+ NoTopLevelBinding ->
+ hang (text "No top-level binding for")
+ 2 (what <+> quotes (ppr rdr_name) <+> text "in this module")
+ UnknownSubordinate doc ->
+ quotes (ppr rdr_name) <+> text "is not a (visible)" <+> doc
+ where
+ what = pprNonVarNameSpace (occNameSpace (rdrNameOcc rdr_name))
+
+scopeErrorHints :: NotInScopeError -> [GhcHint]
+scopeErrorHints scope_err =
+ case scope_err of
+ NotInScope -> noHints
+ NoExactName {} -> [SuggestDumpSlices]
+ SameName {} -> [SuggestDumpSlices]
+ MissingBinding _ hints -> hints
+ NoTopLevelBinding -> noHints
+ UnknownSubordinate {} -> noHints
+
+{- *********************************************************************
+* *
+ Outputting ImportError messages
+* *
+**********************************************************************-}
+
+instance Outputable ImportError where
+ ppr (MissingModule mod_name) =
+ hsep
+ [ text "NB: no module named"
+ , quotes (ppr mod_name)
+ , text "is imported."
+ ]
+ ppr (ModulesDoNotExport mods occ_name)
+ | mod NE.:| [] <- mods
+ = hsep
+ [ text "NB: the module"
+ , quotes (ppr mod)
+ , text "does not export"
+ , quotes (ppr occ_name) <> dot ]
+ | otherwise
+ = hsep
+ [ text "NB: neither"
+ , quotedListWithNor (map ppr $ NE.toList mods)
+ , text "export"
+ , quotes (ppr occ_name) <> dot ]
+
+{- *********************************************************************
+* *
+ Suggested fixes for implication constraints
+* *
+**********************************************************************-}
+
+-- TODO: these functions should use GhcHint instead.
+
+show_fixes :: [SDoc] -> SDoc
+show_fixes [] = empty
+show_fixes (f:fs) = sep [ text "Possible fix:"
+ , nest 2 (vcat (f : map (text "or" <+>) fs))]
+
+ctxtFixes :: Bool -> PredType -> [Implication] -> [SDoc]
+ctxtFixes has_ambig_tvs pred implics
+ | not has_ambig_tvs
+ , isTyVarClassPred pred
+ , (skol:skols) <- usefulContext implics pred
+ , let what | null skols
+ , SigSkol (PatSynCtxt {}) _ _ <- skol
+ = text "\"required\""
+ | otherwise
+ = empty
+ = [sep [ text "add" <+> pprParendType pred
+ <+> text "to the" <+> what <+> text "context of"
+ , nest 2 $ ppr_skol skol $$
+ vcat [ text "or" <+> ppr_skol skol
+ | skol <- skols ] ] ]
+ | otherwise = []
+ where
+ ppr_skol (PatSkol (RealDataCon dc) _) = text "the data constructor" <+> quotes (ppr dc)
+ ppr_skol (PatSkol (PatSynCon ps) _) = text "the pattern synonym" <+> quotes (ppr ps)
+ ppr_skol skol_info = ppr skol_info
+
+usefulContext :: [Implication] -> PredType -> [SkolemInfo]
+-- usefulContext picks out the implications whose context
+-- the programmer might plausibly augment to solve 'pred'
+usefulContext implics pred
+ = go implics
+ where
+ pred_tvs = tyCoVarsOfType pred
+ go [] = []
+ go (ic : ics)
+ | implausible ic = rest
+ | otherwise = ic_info ic : rest
+ where
+ -- Stop when the context binds a variable free in the predicate
+ rest | any (`elemVarSet` pred_tvs) (ic_skols ic) = []
+ | otherwise = go ics
+
+ implausible ic
+ | null (ic_skols ic) = True
+ | implausible_info (ic_info ic) = True
+ | otherwise = False
+
+ implausible_info (SigSkol (InfSigCtxt {}) _ _) = True
+ implausible_info _ = False
+ -- Do not suggest adding constraints to an *inferred* type signature
+
+pp_givens :: [Implication] -> [SDoc]
+pp_givens givens
+ = case givens of
+ [] -> []
+ (g:gs) -> ppr_given (text "from the context:") g
+ : map (ppr_given (text "or from:")) gs
+ where
+ ppr_given herald implic@(Implic { ic_given = gs, ic_info = skol_info })
+ = hang (herald <+> pprEvVarTheta (mkMinimalBySCs evVarPred gs))
+ -- See Note [Suppress redundant givens during error reporting]
+ -- for why we use mkMinimalBySCs above.
+ 2 (sep [ text "bound by" <+> ppr skol_info
+ , text "at" <+> ppr (getLclEnvLoc (ic_env implic)) ])
+
+{- *********************************************************************
+* *
+ CtOrigin information
+* *
+**********************************************************************-}
+
+levelString :: TypeOrKind -> String
+levelString TypeLevel = "type"
+levelString KindLevel = "kind"
+
+pprArising :: CtOrigin -> SDoc
+-- Used for the main, top-level error message
+-- We've done special processing for TypeEq, KindEq, givens
+pprArising (TypeEqOrigin {}) = empty
+pprArising (KindEqOrigin {}) = empty
+pprArising orig | isGivenOrigin orig = empty
+ | otherwise = pprCtOrigin orig
+
+-- Add the "arising from..." part to a message
+addArising :: CtOrigin -> SDoc -> SDoc
+addArising orig msg = hang msg 2 (pprArising orig)
+
+pprWithArising :: [Ct] -> SDoc
+-- Print something like
+-- (Eq a) arising from a use of x at y
+-- (Show a) arising from a use of p at q
+-- Also return a location for the error message
+-- Works for Wanted/Derived only
+pprWithArising []
+ = panic "pprWithArising"
+pprWithArising (ct:cts)
+ | null cts
+ = addArising (ctLocOrigin loc) (pprTheta [ctPred ct])
+ | otherwise
+ = vcat (map ppr_one (ct:cts))
+ where
+ loc = ctLoc ct
+ ppr_one ct' = hang (parens (pprType (ctPred ct')))
+ 2 (pprCtLoc (ctLoc ct'))
+
+{- *********************************************************************
+* *
+ SkolemInfo
+* *
+**********************************************************************-}
+
+pprSkols :: ReportErrCtxt -> [TcTyVar] -> SDoc
+pprSkols ctxt tvs
+ = vcat (map pp_one (getSkolemInfo (cec_encl ctxt) tvs))
+ where
+ pp_one (UnkSkol, tvs)
+ = vcat [ hang (pprQuotedList tvs)
+ 2 (is_or_are tvs "a" "(rigid, skolem)")
+ , nest 2 (text "of unknown origin")
+ , nest 2 (text "bound at" <+> ppr (foldr1 combineSrcSpans (map getSrcSpan tvs)))
+ ]
+ pp_one (RuntimeUnkSkol, tvs)
+ = hang (pprQuotedList tvs)
+ 2 (is_or_are tvs "an" "unknown runtime")
+ pp_one (skol_info, tvs)
+ = vcat [ hang (pprQuotedList tvs)
+ 2 (is_or_are tvs "a" "rigid" <+> text "bound by")
+ , nest 2 (pprSkolInfo skol_info)
+ , nest 2 (text "at" <+> ppr (foldr1 combineSrcSpans (map getSrcSpan tvs))) ]
+
+ is_or_are [_] article adjective = text "is" <+> text article <+> text adjective
+ <+> text "type variable"
+ is_or_are _ _ adjective = text "are" <+> text adjective
+ <+> text "type variables"
+
+{- *********************************************************************
+* *
+ Utilities for expected/actual messages
+* *
+**********************************************************************-}
+
+mk_supplementary_ea_msg :: ReportErrCtxt -> TypeOrKind
+ -> Type -> Type -> CtOrigin -> Either [TcReportInfo] TcReportMsg
+mk_supplementary_ea_msg ctxt level ty1 ty2 orig
+ | TypeEqOrigin { uo_expected = exp, uo_actual = act } <- orig
+ , not (ea_looks_same ty1 ty2 exp act)
+ = mk_ea_msg ctxt Nothing level orig
+ | otherwise
+ = Left []
+
+ea_looks_same :: Type -> Type -> Type -> Type -> Bool
+-- True if the faulting types (ty1, ty2) look the same as
+-- the expected/actual types (exp, act).
+-- If so, we don't want to redundantly report the latter
+ea_looks_same ty1 ty2 exp act
+ = (act `looks_same` ty1 && exp `looks_same` ty2) ||
+ (exp `looks_same` ty1 && act `looks_same` ty2)
+ where
+ looks_same t1 t2 = t1 `pickyEqType` t2
+ || t1 `eqType` liftedTypeKind && t2 `eqType` liftedTypeKind
+ -- pickyEqType is sensitive to synonyms, so only replies True
+ -- when the types really look the same. However,
+ -- (TYPE 'LiftedRep) and Type both print the same way.
+
+mk_ea_msg :: ReportErrCtxt -> Maybe Ct -> TypeOrKind -> CtOrigin -> Either [TcReportInfo] TcReportMsg
+-- Constructs a "Couldn't match" message
+-- The (Maybe Ct) says whether this is the main top-level message (Just)
+-- or a supplementary message (Nothing)
+mk_ea_msg ctxt at_top level
+ (TypeEqOrigin { uo_actual = act, uo_expected = exp, uo_thing = mb_thing })
+ | Just thing <- mb_thing
+ , KindLevel <- level
+ = Right $ KindMismatch { kmismatch_what = thing
+ , kmismatch_expected = exp
+ , kmismatch_actual = act }
+ | Just ct <- at_top
+ , let mismatch =
+ Mismatch
+ { mismatch_ea = True
+ , mismatch_ct = ct
+ , mismatch_ty1 = exp
+ , mismatch_ty2 = act }
+ = Right $
+ if expanded_syns
+ then mkTcReportWithInfo mismatch [ea_expanded]
+ else mismatch
+ | otherwise
+ = Left $
+ if expanded_syns
+ then [ea,ea_expanded]
+ else [ea]
+
+ where
+ ea = ExpectedActual { ea_expected = exp, ea_actual = act }
+ ea_expanded =
+ ExpectedActualAfterTySynExpansion
+ { ea_expanded_expected = expTy1
+ , ea_expanded_actual = expTy2 }
+
+ expanded_syns = cec_expand_syns ctxt
+ && not (expTy1 `pickyEqType` exp && expTy2 `pickyEqType` act)
+ (expTy1, expTy2) = expandSynonymsToMatch exp act
+mk_ea_msg _ _ _ _ = Left []
+
+{- Note [Expanding type synonyms to make types similar]
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+In type error messages, if -fprint-expanded-types is used, we want to expand
+type synonyms to make expected and found types as similar as possible, but we
+shouldn't expand types too much to make type messages even more verbose and
+harder to understand. The whole point here is to make the difference in expected
+and found types clearer.
+
+`expandSynonymsToMatch` does this, it takes two types, and expands type synonyms
+only as much as necessary. Given two types t1 and t2:
+
+ * If they're already same, it just returns the types.
+
+ * If they're in form `C1 t1_1 .. t1_n` and `C2 t2_1 .. t2_m` (C1 and C2 are
+ type constructors), it expands C1 and C2 if they're different type synonyms.
+ Then it recursively does the same thing on expanded types. If C1 and C2 are
+ same, then it applies the same procedure to arguments of C1 and arguments of
+ C2 to make them as similar as possible.
+
+ Most important thing here is to keep number of synonym expansions at
+ minimum. For example, if t1 is `T (T3, T5, Int)` and t2 is `T (T5, T3,
+ Bool)` where T5 = T4, T4 = T3, ..., T1 = X, it returns `T (T3, T3, Int)` and
+ `T (T3, T3, Bool)`.
+
+ * Otherwise types don't have same shapes and so the difference is clearly
+ visible. It doesn't do any expansions and show these types.
+
+Note that we only expand top-layer type synonyms. Only when top-layer
+constructors are the same we start expanding inner type synonyms.
+
+Suppose top-layer type synonyms of t1 and t2 can expand N and M times,
+respectively. If their type-synonym-expanded forms will meet at some point (i.e.
+will have same shapes according to `sameShapes` function), it's possible to find
+where they meet in O(N+M) top-layer type synonym expansions and O(min(N,M))
+comparisons. We first collect all the top-layer expansions of t1 and t2 in two
+lists, then drop the prefix of the longer list so that they have same lengths.
+Then we search through both lists in parallel, and return the first pair of
+types that have same shapes. Inner types of these two types with same shapes
+are then expanded using the same algorithm.
+
+In case they don't meet, we return the last pair of types in the lists, which
+has top-layer type synonyms completely expanded. (in this case the inner types
+are not expanded at all, as the current form already shows the type error)
+-}
+
+-- | Expand type synonyms in given types only enough to make them as similar as
+-- possible. Returned types are the same in terms of used type synonyms.
+--
+-- To expand all synonyms, see 'Type.expandTypeSynonyms'.
+--
+-- See `ExpandSynsFail` tests in tests testsuite/tests/typecheck/should_fail for
+-- some examples of how this should work.
+expandSynonymsToMatch :: Type -> Type -> (Type, Type)
+expandSynonymsToMatch ty1 ty2 = (ty1_ret, ty2_ret)
+ where
+ (ty1_ret, ty2_ret) = go ty1 ty2
+
+ -- | Returns (type synonym expanded version of first type,
+ -- type synonym expanded version of second type)
+ go :: Type -> Type -> (Type, Type)
+ go t1 t2
+ | t1 `pickyEqType` t2 =
+ -- Types are same, nothing to do
+ (t1, t2)
+
+ go (TyConApp tc1 tys1) (TyConApp tc2 tys2)
+ | tc1 == tc2
+ , tys1 `equalLength` tys2 =
+ -- Type constructors are same. They may be synonyms, but we don't
+ -- expand further. The lengths of tys1 and tys2 must be equal;
+ -- for example, with type S a = a, we don't want
+ -- to zip (S Monad Int) and (S Bool).
+ let (tys1', tys2') =
+ unzip (zipWithEqual "expandSynonymsToMatch" go tys1 tys2)
+ in (TyConApp tc1 tys1', TyConApp tc2 tys2')
+
+ go (AppTy t1_1 t1_2) (AppTy t2_1 t2_2) =
+ let (t1_1', t2_1') = go t1_1 t2_1
+ (t1_2', t2_2') = go t1_2 t2_2
+ in (mkAppTy t1_1' t1_2', mkAppTy t2_1' t2_2')
+
+ go ty1@(FunTy _ w1 t1_1 t1_2) ty2@(FunTy _ w2 t2_1 t2_2) | w1 `eqType` w2 =
+ let (t1_1', t2_1') = go t1_1 t2_1
+ (t1_2', t2_2') = go t1_2 t2_2
+ in ( ty1 { ft_arg = t1_1', ft_res = t1_2' }
+ , ty2 { ft_arg = t2_1', ft_res = t2_2' })
+
+ go (ForAllTy b1 t1) (ForAllTy b2 t2) =
+ -- NOTE: We may have a bug here, but we just can't reproduce it easily.
+ -- See D1016 comments for details and our attempts at producing a test
+ -- case. Short version: We probably need RnEnv2 to really get this right.
+ let (t1', t2') = go t1 t2
+ in (ForAllTy b1 t1', ForAllTy b2 t2')
+
+ go (CastTy ty1 _) ty2 = go ty1 ty2
+ go ty1 (CastTy ty2 _) = go ty1 ty2
+
+ go t1 t2 =
+ -- See Note [Expanding type synonyms to make types similar] for how this
+ -- works
+ let
+ t1_exp_tys = t1 : tyExpansions t1
+ t2_exp_tys = t2 : tyExpansions t2
+ t1_exps = length t1_exp_tys
+ t2_exps = length t2_exp_tys
+ dif = abs (t1_exps - t2_exps)
+ in
+ followExpansions $
+ zipEqual "expandSynonymsToMatch.go"
+ (if t1_exps > t2_exps then drop dif t1_exp_tys else t1_exp_tys)
+ (if t2_exps > t1_exps then drop dif t2_exp_tys else t2_exp_tys)
+
+ -- | Expand the top layer type synonyms repeatedly, collect expansions in a
+ -- list. The list does not include the original type.
+ --
+ -- Example, if you have:
+ --
+ -- type T10 = T9
+ -- type T9 = T8
+ -- ...
+ -- type T0 = Int
+ --
+ -- `tyExpansions T10` returns [T9, T8, T7, ... Int]
+ --
+ -- This only expands the top layer, so if you have:
+ --
+ -- type M a = Maybe a
+ --
+ -- `tyExpansions (M T10)` returns [Maybe T10] (T10 is not expanded)
+ tyExpansions :: Type -> [Type]
+ tyExpansions = unfoldr (\t -> (\x -> (x, x)) `fmap` tcView t)
+
+ -- | Drop the type pairs until types in a pair look alike (i.e. the outer
+ -- constructors are the same).
+ followExpansions :: [(Type, Type)] -> (Type, Type)
+ followExpansions [] = pprPanic "followExpansions" empty
+ followExpansions [(t1, t2)]
+ | sameShapes t1 t2 = go t1 t2 -- expand subtrees
+ | otherwise = (t1, t2) -- the difference is already visible
+ followExpansions ((t1, t2) : tss)
+ -- Traverse subtrees when the outer shapes are the same
+ | sameShapes t1 t2 = go t1 t2
+ -- Otherwise follow the expansions until they look alike
+ | otherwise = followExpansions tss
+
+ sameShapes :: Type -> Type -> Bool
+ sameShapes AppTy{} AppTy{} = True
+ sameShapes (TyConApp tc1 _) (TyConApp tc2 _) = tc1 == tc2
+ sameShapes (FunTy {}) (FunTy {}) = True
+ sameShapes (ForAllTy {}) (ForAllTy {}) = True
+ sameShapes (CastTy ty1 _) ty2 = sameShapes ty1 ty2
+ sameShapes ty1 (CastTy ty2 _) = sameShapes ty1 ty2
+ sameShapes _ _ = False
diff --git a/compiler/GHC/Tc/Errors/Types.hs b/compiler/GHC/Tc/Errors/Types.hs
index f9de50f37a..8fa8e02b5e 100644
--- a/compiler/GHC/Tc/Errors/Types.hs
+++ b/compiler/GHC/Tc/Errors/Types.hs
@@ -31,22 +31,43 @@ module GHC.Tc.Errors.Types (
, associatedTyLastVarInKind
, AssociatedTyNotParamOverLastTyVar(..)
, associatedTyNotParamOverLastTyVar
+
+ , SolverReport(..), SolverReportSupplementary(..)
+ , ReportWithCtxt(..)
+ , ReportErrCtxt(..)
+ , getUserGivens, discardProvCtxtGivens, getSkolemInfo
+ , TcReportMsg(..), TcReportInfo(..)
+ , CND_Extra(..)
+ , mkTcReportWithInfo
+ , FitsMbSuppressed(..)
+ , ValidHoleFits(..), noValidHoleFits
+ , HoleFitDispConfig(..)
+ , RelevantBindings(..), pprRelevantBindings
+ , NotInScopeError(..), mkTcRnNotInScope
+ , ImportError(..)
+ , HoleError(..)
+ , CoercibleMsg(..)
+ , PotentialInstances(..)
) where
import GHC.Prelude
import GHC.Hs
import {-# SOURCE #-} GHC.Tc.Types (TcIdSigInfo)
+import {-# SOURCE #-} GHC.Tc.Errors.Hole.FitTypes (HoleFit)
import GHC.Tc.Types.Constraint
+import GHC.Tc.Types.Evidence (EvBindsVar)
+import GHC.Tc.Types.Origin (CtOrigin (ProvCtxtOrigin), TypedThing, TyVarBndrs, SkolemInfo (SigSkol, UnkSkol, RuntimeUnkSkol), FRROrigin, UserTypeCtxt (PatSynCtxt))
import GHC.Tc.Types.Rank (Rank)
-import GHC.Tc.Utils.TcType (TcType)
+import GHC.Tc.Utils.TcType (TcType, isRuntimeUnkSkol)
import GHC.Types.Error
import GHC.Types.FieldLabel (FieldLabelString)
-import GHC.Types.Name (Name, OccName)
+import GHC.Types.Name (Name, OccName, getSrcLoc)
import GHC.Types.Name.Reader
import GHC.Types.SrcLoc
import GHC.Types.TyThing (TyThing)
-import GHC.Types.Var (Id)
+import GHC.Types.Var (Id, TyCoVar, TyVar, TcTyVar)
+import GHC.Types.Var.Env (TidyEnv)
import GHC.Types.Var.Set (TyVarSet, VarSet)
import GHC.Unit.Types (Module)
import GHC.Utils.Outputable
@@ -61,10 +82,14 @@ import GHC.Core.Type (Kind, Type, ThetaType, PredType)
import GHC.Unit.State (UnitState)
import GHC.Unit.Module.Name (ModuleName)
import GHC.Types.Basic
+import GHC.Utils.Misc (filterOut)
+import GHC.Utils.Trace (pprTraceUserWarning)
import qualified GHC.LanguageExtensions as LangExt
import qualified Data.List.NonEmpty as NE
import Data.Typeable hiding (TyCon)
+import qualified Data.Semigroup as Semigroup
+import Data.List (partition)
{-
Note [Migrating TcM Messages]
@@ -138,6 +163,50 @@ data TcRnMessage where
-> !TcRnMessageDetailed
-> TcRnMessage
+ {-| TcRnSolverReport is the constructor used to report unsolved constraints
+ after constraint solving, as well as other errors such as hole fit errors.
+
+ See the documentation of the 'TcReportMsg' datatype for an overview
+ of the different errors.
+ -}
+ TcRnSolverReport :: [ReportWithCtxt]
+ -> DiagnosticReason
+ -> [GhcHint]
+ -> TcRnMessage
+ -- TODO: split up TcRnSolverReport into several components,
+ -- so that we can compute the reason and hints, as opposed
+ -- to having to pass them here.
+
+ {-| TcRnRedundantConstraints is a warning that is emitted when a binding
+ has a user-written type signature which contains superfluous constraints.
+
+ Example:
+
+ f :: (Eq a, Ord a) => a -> a -> a
+ f x y = (x < y) || x == y
+ -- `Eq a` is superfluous: the `Ord a` constraint suffices.
+
+ Test cases: T9939, T10632, T18036a, T20602, PluralS, T19296.
+ -}
+ TcRnRedundantConstraints :: [Id] -> (SkolemInfo, Bool) -> TcRnMessage
+
+ {-| TcRnInaccessibleCode is a warning that is emitted when the RHS of a pattern
+ match is inaccessible, because the constraint solver has detected a contradiction.
+
+ Example:
+
+ data B a where { MkTrue :: B True; MkFalse :: B False }
+
+ foo :: B False -> Bool
+ foo MkFalse = False
+ foo MkTrue = True -- Inaccessible: requires True ~ False
+
+ Test cases: T7293, T7294, T15558, T17646, T18572, T18610, tcfail167.
+ -}
+ TcRnInaccessibleCode :: Implication -- ^ The implication containing a contradiction.
+ -> NE.NonEmpty ReportWithCtxt -- ^ The contradiction(s).
+ -> TcRnMessage
+
{-| A type which was expected to have a fixed runtime representation
does not have a fixed runtime representation.
@@ -1416,7 +1485,7 @@ data TcRnMessage where
-}
TcRnArrowProcGADTPattern :: TcRnMessage
- {- TcRnForallIdentifier is a warning (controlled with -Wforall-identifier) that occurs
+ {-| TcRnForallIdentifier is a warning (controlled with -Wforall-identifier) that occurs
when a definition uses 'forall' as an identifier.
Example:
@@ -1435,6 +1504,60 @@ data TcRnMessage where
Test cases: T20485, T20485a
-}
TcRnGADTMonoLocalBinds :: TcRnMessage
+ {-| The TcRnNotInScope constructor is used for various not-in-scope errors.
+ See 'NotInScopeError' for more details. -}
+ TcRnNotInScope :: NotInScopeError -- ^ what the problem is
+ -> RdrName -- ^ the name that is not in scope
+ -> [ImportError] -- ^ import errors that are relevant
+ -> [GhcHint] -- ^ hints, e.g. enable DataKinds to refer to a promoted data constructor
+ -> TcRnMessage
+
+ {-| TcRnUntickedPromotedConstructor is a warning (controlled with -Wunticked-promoted-constructors
+ that is triggered by an unticked occurrence of a promoted data constructor.
+
+ Example:
+
+ data A = MkA
+ type family F (a :: A) where { F MkA = Bool }
+
+ Test case: T9778.
+ -}
+ TcRnUntickedPromotedConstructor :: Name
+ -> TcRnMessage
+
+ {-| TcRnIllegalBuiltinSyntax is an error that occurs when built-in syntax appears
+ in an unexpected location, e.g. as a data constructor or in a fixity declaration.
+
+ Examples:
+
+ infixl 5 :
+
+ data P = (,)
+
+ Test cases: rnfail042, T14907b, T15124, T15233.
+ -}
+ TcRnIllegalBuiltinSyntax :: SDoc -- ^ what kind of thing this is (a binding, fixity declaration, ...)
+ -> RdrName
+ -> TcRnMessage
+ -- TODO: remove the SDoc argument.
+
+ {-| TcRnWarnDefaulting is a warning (controlled by -Wtype-defaults)
+ that is triggered whenever a Wanted typeclass constraint
+ is solving through the defaulting of a type variable.
+
+ Example:
+
+ one = show 1
+ -- We get Wanteds Show a0, Num a0, and default a0 to Integer.
+
+ Test cases:
+ none (which are really specific to defaulting),
+ but see e.g. tcfail204.
+ -}
+ TcRnWarnDefaulting :: [Ct] -- ^ Wanted constraints in which defaulting occurred
+ -> Maybe TyVar -- ^ The type variable being defaulted
+ -> Type -- ^ The default type
+ -> TcRnMessage
{-| TcRnIncorrectNameSpace is an error that occurs when a 'Name'
is used in the incorrect 'NameSpace', e.g. a type constructor
@@ -1703,3 +1826,590 @@ data AssociatedTyNotParamOverLastTyVar
associatedTyNotParamOverLastTyVar :: Maybe TyCon -> AssociatedTyNotParamOverLastTyVar
associatedTyNotParamOverLastTyVar (Just tc) = YesAssociatedTyNotParamOverLastTyVar tc
associatedTyNotParamOverLastTyVar Nothing = NoAssociatedTyNotParamOverLastTyVar
+
+--------------------------------------------------------------------------------
+-- Errors used in GHC.Tc.Errors
+
+{- Note [Error report]
+~~~~~~~~~~~~~~~~~~~~~~
+The idea is that error msgs are divided into three parts: the main msg, the
+context block ("In the second argument of ..."), and the relevant bindings
+block, which are displayed in that order, with a mark to divide them. The
+the main msg ('report_important') varies depending on the error
+in question, but context and relevant bindings are always the same, which
+should simplify visual parsing.
+
+See 'GHC.Tc.Errors.Types.SolverReport' and 'GHC.Tc.Errors.mkErrorReport'.
+-}
+
+-- | A collection of main error messages and supplementary information.
+--
+-- In practice, we will:
+-- - display the important messages first,
+-- - then the error context (e.g. by way of a call to 'GHC.Tc.Errors.mkErrorReport'),
+-- - then the supplementary information (e.g. relevant bindings, valid hole fits),
+-- - then the hints ("Possible fix: ...").
+--
+-- So this is mostly just a way of making sure that the error context appears
+-- early on rather than at the end of the message.
+--
+-- See Note [Error report] for details.
+data SolverReport
+ = SolverReport
+ { sr_important_msgs :: [ReportWithCtxt]
+ , sr_supplementary :: [SolverReportSupplementary]
+ , sr_hints :: [GhcHint]
+ }
+
+-- | Additional information to print in a 'SolverReport', after the
+-- important messages and after the error context.
+--
+-- See Note [Error report].
+data SolverReportSupplementary
+ = SupplementaryBindings RelevantBindings
+ | SupplementaryHoleFits ValidHoleFits
+ | SupplementaryCts [(PredType, RealSrcSpan)]
+
+-- | A 'TcReportMsg', together with context (e.g. enclosing implication constraints)
+-- that are needed in order to report it.
+data ReportWithCtxt =
+ ReportWithCtxt
+ { reportContext :: ReportErrCtxt
+ -- ^ Context for what we wish to report.
+ -- This can change as we enter implications, so is
+ -- stored alongside the content.
+ , reportContent :: TcReportMsg
+ -- ^ The content of the message to report.
+ }
+
+instance Semigroup SolverReport where
+ SolverReport main1 supp1 hints1 <> SolverReport main2 supp2 hints2
+ = SolverReport (main1 ++ main2) (supp1 ++ supp2) (hints1 ++ hints2)
+
+instance Monoid SolverReport where
+ mempty = SolverReport [] [] []
+ mappend = (Semigroup.<>)
+
+-- | Context needed when reporting a 'TcReportMsg', such as
+-- the enclosing implication constraints or whether we are deferring type errors.
+data ReportErrCtxt
+ = CEC { cec_encl :: [Implication] -- | Enclosing implications
+ -- (innermost first)
+ -- ic_skols and givens are tidied, rest are not
+ , cec_tidy :: TidyEnv
+
+ , cec_binds :: EvBindsVar -- Make some errors (depending on cec_defer)
+ -- into warnings, and emit evidence bindings
+ -- into 'cec_binds' for unsolved constraints
+
+ , cec_defer_type_errors :: DiagnosticReason -- Defer type errors until runtime
+
+ -- cec_expr_holes is a union of:
+ -- cec_type_holes - a set of typed holes: '_', '_a', '_foo'
+ -- cec_out_of_scope_holes - a set of variables which are
+ -- out of scope: 'x', 'y', 'bar'
+ , cec_expr_holes :: DiagnosticReason -- Holes in expressions.
+ , cec_type_holes :: DiagnosticReason -- Holes in types.
+ , cec_out_of_scope_holes :: DiagnosticReason -- Out of scope holes.
+
+ , cec_warn_redundant :: Bool -- | True <=> -Wredundant-constraints
+ , cec_expand_syns :: Bool -- | True <=> -fprint-expanded-synonyms
+
+ , cec_suppress :: Bool -- | True <=> More important errors have occurred,
+ -- so create bindings if need be, but
+ -- don't issue any more errors/warnings
+ -- See Note [Suppressing error messages]
+ }
+
+getUserGivens :: ReportErrCtxt -> [UserGiven]
+-- One item for each enclosing implication
+getUserGivens (CEC {cec_encl = implics}) = getUserGivensFromImplics implics
+
+
+{- Note [discardProvCtxtGivens]
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+In most situations we call all enclosing implications "useful". There is one
+exception, and that is when the constraint that causes the error is from the
+"provided" context of a pattern synonym declaration:
+
+ pattern Pat :: (Num a, Eq a) => Show a => a -> Maybe a
+ -- required => provided => type
+ pattern Pat x <- (Just x, 4)
+
+When checking the pattern RHS we must check that it does actually bind all
+the claimed "provided" constraints; in this case, does the pattern (Just x, 4)
+bind the (Show a) constraint. Answer: no!
+
+But the implication we generate for this will look like
+ forall a. (Num a, Eq a) => [W] Show a
+because when checking the pattern we must make the required
+constraints available, since they are needed to match the pattern (in
+this case the literal '4' needs (Num a, Eq a)).
+
+BUT we don't want to suggest adding (Show a) to the "required" constraints
+of the pattern synonym, thus:
+ pattern Pat :: (Num a, Eq a, Show a) => Show a => a -> Maybe a
+It would then typecheck but it's silly. We want the /pattern/ to bind
+the alleged "provided" constraints, Show a.
+
+So we suppress that Implication in discardProvCtxtGivens. It's
+painfully ad-hoc but the truth is that adding it to the "required"
+constraints would work. Suppressing it solves two problems. First,
+we never tell the user that we could not deduce a "provided"
+constraint from the "required" context. Second, we never give a
+possible fix that suggests to add a "provided" constraint to the
+"required" context.
+
+For example, without this distinction the above code gives a bad error
+message (showing both problems):
+
+ error: Could not deduce (Show a) ... from the context: (Eq a)
+ ... Possible fix: add (Show a) to the context of
+ the signature for pattern synonym `Pat' ...
+-}
+
+
+discardProvCtxtGivens :: CtOrigin -> [UserGiven] -> [UserGiven]
+discardProvCtxtGivens orig givens -- See Note [discardProvCtxtGivens]
+ | ProvCtxtOrigin (PSB {psb_id = L _ name}) <- orig
+ = filterOut (discard name) givens
+ | otherwise
+ = givens
+ where
+ discard n (Implic { ic_info = SigSkol (PatSynCtxt n') _ _ }) = n == n'
+ discard _ _ = False
+
+
+getSkolemInfo :: [Implication] -> [TcTyVar]
+ -> [(SkolemInfo, [TcTyVar])] -- #14628
+-- Get the skolem info for some type variables
+-- from the implication constraints that bind them.
+--
+-- In the returned (skolem, tvs) pairs, the 'tvs' part is non-empty
+getSkolemInfo _ []
+ = []
+
+getSkolemInfo [] tvs
+ | all isRuntimeUnkSkol tvs = [(RuntimeUnkSkol, tvs)] -- #14628
+ | otherwise = -- See https://gitlab.haskell.org/ghc/ghc/-/issues?label_name[]=No%20skolem%20info
+ pprTraceUserWarning msg [(UnkSkol,tvs)]
+ where
+ msg = text "No skolem info - we could not find the origin of the following variables" <+> ppr tvs
+ $$ text "This should not happen, please report it as a bug following the instructions at:"
+ $$ text "https://gitlab.haskell.org/ghc/ghc/wikis/report-a-bug"
+
+
+getSkolemInfo (implic:implics) tvs
+ | null tvs_here = getSkolemInfo implics tvs
+ | otherwise = (ic_info implic, tvs_here) : getSkolemInfo implics tvs_other
+ where
+ (tvs_here, tvs_other) = partition (`elem` ic_skols implic) tvs
+
+-- | An error reported after constraint solving.
+-- This is usually, some sort of unsolved constraint error,
+-- but we try to be specific about the precise problem we encountered.
+data TcReportMsg
+ -- NB: this datatype is only a first step in refactoring GHC.Tc.Errors
+ -- to use the diagnostic infrastructure (TcRnMessage etc).
+ -- If you see possible improvements, please go right ahead!
+
+ -- | Wrap a message with additional information.
+ --
+ -- Prefer using the 'mkTcReportWithInfo' smart constructor
+ = TcReportWithInfo TcReportMsg (NE.NonEmpty TcReportInfo)
+
+ -- | Quantified variables appear out of dependency order.
+ --
+ -- Example:
+ --
+ -- forall (a :: k) k. ...
+ --
+ -- Test cases: BadTelescope2, T16418, T16247, T16726, T18451.
+ | BadTelescope TyVarBndrs [TyCoVar]
+
+ -- | We came across a custom type error and we have decided to report it.
+ --
+ -- Example:
+ --
+ -- type family F a where
+ -- F a = TypeError (Text "error")
+ --
+ -- err :: F ()
+ -- err = ()
+ --
+ -- Test cases: CustomTypeErrors0{1,2,3,4,5}, T12104.
+ | UserTypeError Type
+
+ -- | We want to report an out of scope variable or a typed hole.
+ -- See 'HoleError'.
+ | ReportHoleError Hole HoleError
+
+ -- | A type equality between a type variable and a polytype.
+ --
+ -- Test cases: T12427a, T2846b, T10194, ...
+ | CannotUnifyWithPolytype Ct TyVar Type
+
+ -- | Couldn't unify two types or kinds.
+ --
+ -- Example:
+ --
+ -- 3 + 3# -- can't match a lifted type with an unlifted type
+ --
+ -- Test cases: T1396, T8263, ...
+ | Mismatch
+ { mismatch_ea :: Bool -- ^ Should this be phrased in terms of expected vs actual?
+ , mismatch_ct :: Ct -- ^ The constraint in which the mismatch originated.
+ , mismatch_ty1 :: Type -- ^ First type (the expected type if if mismatch_ea is True)
+ , mismatch_ty2 :: Type -- ^ Second type (the actual type if mismatch_ea is True)
+ }
+
+ -- | A type has an unexpected kind.
+ --
+ -- Test cases: T2994, T7609, ...
+ | KindMismatch
+ { kmismatch_what :: TypedThing -- ^ What thing is 'kmismatch_actual' the kind of?
+ , kmismatch_expected :: Type
+ , kmismatch_actual :: Type
+ }
+ -- TODO: combine 'Mismatch' and 'KindMismatch' messages.
+
+ -- | A mismatch between two types, which arose from a type equality.
+ --
+ -- Test cases: T1470, tcfail212.
+ | TypeEqMismatch
+ { teq_mismatch_ppr_explicit_kinds :: Bool
+ , teq_mismatch_ct :: Ct
+ , teq_mismatch_ty1 :: Type
+ , teq_mismatch_ty2 :: Type
+ , teq_mismatch_expected :: Type -- ^ The overall expected type
+ , teq_mismatch_actual :: Type -- ^ The overall actual type
+ , teq_mismatch_what :: Maybe TypedThing -- ^ What thing is 'teq_mismatch_actual' the kind of?
+ }
+ -- TODO: combine 'Mismatch' and 'TypeEqMismatch' messages.
+
+ -- | A violation of the representation-polymorphism invariants,
+ -- i.e. an unsolved `Concrete# ty` constraint.
+ --
+ -- See 'FRROrigin' for more information.
+ | FixedRuntimeRepError [(FRROrigin, Type)]
+
+ -- | A skolem type variable escapes its scope.
+ --
+ -- Example:
+ --
+ -- data Ex where { MkEx :: a -> MkEx }
+ -- foo (MkEx x) = x
+ --
+ -- Test cases: TypeSkolEscape, T11142.
+ | SkolemEscape Ct Implication [TyVar]
+
+ -- | Trying to unify an untouchable variable, e.g. a variable from an outer scope.
+ --
+ -- Test case: Simple14
+ | UntouchableVariable TyVar Implication
+
+ -- | An equality between two types is blocked on a kind equality
+ -- beteen their kinds.
+ --
+ -- Test cases: none.
+ | BlockedEquality Ct
+
+ -- | Something was not applied to sufficiently many arguments.
+ --
+ -- Example:
+ --
+ -- instance Eq Maybe where {..}
+ --
+ -- Test case: T11563.
+ | ExpectingMoreArguments Int TypedThing
+
+ -- | Trying to use an unbound implicit parameter.
+ --
+ -- Example:
+ --
+ -- foo :: Int
+ -- foo = ?param
+ --
+ -- Test case: tcfail130.
+ | UnboundImplicitParams
+ (NE.NonEmpty Ct)
+
+ -- | Couldn't solve some Wanted constraints using the Givens.
+ -- This is the most commonly used constructor, used for generic
+ -- @"No instance for ..."@ and @"Could not deduce ... from"@ messages.
+ | CouldNotDeduce
+ { cnd_user_givens :: [Implication]
+ -- | The Wanted constraints we couldn't solve.
+ --
+ -- N.B.: the 'Ct' at the head of the list has been tidied,
+ -- perhaps not the others.
+ , cnd_wanted :: NE.NonEmpty Ct
+
+ -- | Some additional info consumed by 'mk_supplementary_ea_msg'.
+ , cnd_extra :: Maybe CND_Extra
+ }
+
+ -- | A constraint couldn't be solved because it contains
+ -- ambiguous type variables.
+ --
+ -- Example:
+ --
+ -- class C a b where
+ -- f :: (a,b)
+ --
+ -- x = fst f
+ --
+ --
+ -- Test case: T4921.
+ | AmbiguityPreventsSolvingCt
+ Ct -- ^ always a class constraint
+ ([TyVar], [TyVar]) -- ^ ambiguous kind and type variables, respectively
+
+ -- | Could not solve a constraint; there were several unifying candidate instances
+ -- but no matching instances. This is used to report as much useful information
+ -- as possible about why we couldn't choose any instance, e.g. because of
+ -- ambiguous type variables.
+ | CannotResolveInstance
+ { cannotResolve_ct :: Ct
+ , cannotResolve_unifiers :: [ClsInst]
+ , cannotResolve_candidates :: [ClsInst]
+ , cannotResolve_importErrors :: [ImportError]
+ , cannotResolve_suggestions :: [GhcHint]
+ , cannotResolve_relevant_bindings :: RelevantBindings }
+ -- TODO: remove the fields of type [GhcHint] and RelevantBindings,
+ -- in order to handle them uniformly with other diagnostic messages.
+
+ -- | Could not solve a constraint using available instances
+ -- because the instances overlap.
+ --
+ -- Test cases: tcfail118, tcfail121, tcfail218.
+ | OverlappingInstances
+ { overlappingInstances_ct :: Ct
+ , overlappingInstances_matches :: [ClsInst]
+ , overlappingInstances_unifiers :: [ClsInst] }
+
+ -- | Could not solve a constraint from instances because
+ -- instances declared in a Safe module cannot overlap instances
+ -- from other modules (with -XSafeHaskell).
+ --
+ -- Test cases: SH_Overlap{1,2,5,6,7,11}.
+ | UnsafeOverlap
+ { unsafeOverlap_ct :: Ct
+ , unsafeOverlap_matches :: [ClsInst]
+ , unsafeOverlapped :: [ClsInst] }
+
+-- | Additional information to be given in a 'CouldNotDeduce' message,
+-- which is then passed on to 'mk_supplementary_ea_msg'.
+data CND_Extra = CND_Extra TypeOrKind Type Type
+
+-- | Additional information that can be appended to an existing 'TcReportMsg'.
+data TcReportInfo
+ -- NB: this datatype is only a first step in refactoring GHC.Tc.Errors
+ -- to use the diagnostic infrastructure (TcRnMessage etc).
+ -- It would be better for these constructors to not be so closely tied
+ -- to the constructors of 'TcReportMsg'.
+ -- If you see possible improvements, please go right ahead!
+
+ -- | Some type variables remained ambiguous: print them to the user.
+ = Ambiguity
+ { lead_with_ambig_msg :: Bool -- ^ True <=> start the message with "Ambiguous type variable ..."
+ -- False <=> create a message of the form "The type variable is ambiguous."
+ , ambig_tyvars :: ([TyVar], [TyVar]) -- ^ Ambiguous kind and type variables, respectively.
+ -- Guaranteed to not both be empty.
+ }
+
+ -- | Specify some information about a type variable,
+ -- e.g. its 'SkolemInfo'.
+ | TyVarInfo TyVar
+
+ -- | Remind the user that a particular type family is not injective.
+ | NonInjectiveTyFam TyCon
+
+ -- | Explain why we couldn't coerce between two types. See 'CoercibleMsg'.
+ | ReportCoercibleMsg CoercibleMsg
+
+ -- | Display the expected and actual types.
+ | ExpectedActual
+ { ea_expected, ea_actual :: Type }
+
+ -- | Display the expected and actual types, after expanding type synonyms.
+ | ExpectedActualAfterTySynExpansion
+ { ea_expanded_expected, ea_expanded_actual :: Type }
+
+ -- | Explain how a kind equality originated.
+ | WhenMatching TcType TcType CtOrigin (Maybe TypeOrKind)
+
+ -- | Add some information to disambiguate errors in which
+ -- two 'Names' would otherwise appear to be identical.
+ --
+ -- See Note [Disambiguating (X ~ X) errors].
+ | SameOcc
+ { sameOcc_same_pkg :: Bool -- ^ Whether the two 'Name's also came from the same package.
+ , sameOcc_lhs :: Name
+ , sameOcc_rhs :: Name }
+
+ -- | Report some type variables that might be participating in an occurs-check failure.
+ | OccursCheckInterestingTyVars (NE.NonEmpty TyVar)
+
+-- | Some form of @"not in scope"@ error. See also the 'OutOfScopeHole'
+-- constructor of 'HoleError'.
+data NotInScopeError
+
+ -- | A run-of-the-mill @"not in scope"@ error.
+ = NotInScope
+
+ -- | An exact 'Name' was not in scope.
+ --
+ -- This usually indicates a problem with a Template Haskell splice.
+ --
+ -- Test cases: T5971, T18263.
+ | NoExactName Name
+
+ -- The same exact 'Name' occurs in multiple name-spaces.
+ --
+ -- This usually indicates a problem with a Template Haskell splice.
+ --
+ -- Test case: T7241.
+ | SameName [GlobalRdrElt] -- ^ always at least 2 elements
+
+ -- A type signature, fixity declaration, pragma, standalone kind signature...
+ -- is missing an associated binding.
+ | MissingBinding SDoc [GhcHint]
+ -- TODO: remove the SDoc argument.
+
+ -- | Couldn't find a top-level binding.
+ --
+ -- Happens when specifying an annotation for something that
+ -- is not in scope.
+ --
+ -- Test cases: annfail01, annfail02, annfail11.
+ | NoTopLevelBinding
+
+ -- | A class doesnt have a method with this name,
+ -- or, a class doesn't have an associated type with this name,
+ -- or, a record doesn't have a record field with this name.
+ | UnknownSubordinate SDoc
+
+-- | Create a @"not in scope"@ error message for the given 'RdrName'.
+mkTcRnNotInScope :: RdrName -> NotInScopeError -> TcRnMessage
+mkTcRnNotInScope rdr err = TcRnNotInScope err rdr [] noHints
+
+-- | Configuration for pretty-printing valid hole fits.
+data HoleFitDispConfig =
+ HFDC { showWrap, showWrapVars, showType, showProv, showMatches
+ :: Bool }
+
+-- | Report an error involving a 'Hole'.
+--
+-- This could be an out of scope data constructor or variable,
+-- a typed hole, or a wildcard in a type.
+data HoleError
+ -- | Report an out-of-scope data constructor or variable
+ -- masquerading as an expression hole.
+ --
+ -- See Note [Insoluble holes] in GHC.Tc.Types.Constraint.
+ -- See 'NotInScopeError' for other not-in-scope errors.
+ --
+ -- Test cases: T9177a.
+ = OutOfScopeHole [ImportError]
+ -- | Report a typed hole, or wildcard, with additional information.
+ | HoleError HoleSort
+
+-- | A message that aims to explain why two types couldn't be seen
+-- to be representationally equal.
+data CoercibleMsg
+ -- | Not knowing the role of a type constructor prevents us from
+ -- concluding that two types are representationally equal.
+ --
+ -- Example:
+ --
+ -- foo :: Applicative m => m (Sum Int)
+ -- foo = coerce (pure $ 1 :: Int)
+ --
+ -- We don't know what role `m` has, so we can't coerce `m Int` to `m (Sum Int)`.
+ --
+ -- Test cases: T8984, TcCoercibleFail.
+ = UnknownRoles Type
+
+ -- | The fact that a 'TyCon' is abstract prevents us from decomposing
+ -- a 'TyConApp' and deducing that two types are representationally equal.
+ --
+ -- Test cases: none.
+ | TyConIsAbstract TyCon
+
+ -- | We can't unwrap a newtype whose constructor is not in scope.
+ --
+ -- Example:
+ --
+ -- import Data.Ord (Down) -- NB: not importing the constructor
+ -- foo :: Int -> Down Int
+ -- foo = coerce
+ --
+ -- Test cases: TcCoercibleFail.
+ | OutOfScopeNewtypeConstructor TyCon DataCon
+
+-- | Explain a problem with an import.
+data ImportError
+ -- | Couldn't find a module with the requested name.
+ = MissingModule ModuleName
+ -- | The imported modules don't export what we're looking for.
+ | ModulesDoNotExport (NE.NonEmpty Module) OccName
+
+-- | This datatype collates instances that match or unifier,
+-- in order to report an error message for an unsolved typeclass constraint.
+data PotentialInstances
+ = PotentialInstances
+ { matches :: [ClsInst]
+ , unifiers :: [ClsInst]
+ }
+
+-- | Append additional information to a `TcReportMsg`.
+mkTcReportWithInfo :: TcReportMsg -> [TcReportInfo] -> TcReportMsg
+mkTcReportWithInfo msg []
+ = msg
+mkTcReportWithInfo (TcReportWithInfo msg (prev NE.:| prevs)) infos
+ = TcReportWithInfo msg (prev NE.:| prevs ++ infos)
+mkTcReportWithInfo msg (info : infos)
+ = TcReportWithInfo msg (info NE.:| infos)
+
+-- | A collection of valid hole fits or refinement fits,
+-- in which some fits might have been suppressed.
+data FitsMbSuppressed
+ = Fits
+ { fits :: [HoleFit]
+ , fitsSuppressed :: Bool -- ^ Whether we have suppressed any fits because there were too many.
+ }
+
+-- | A collection of hole fits and refinement fits.
+data ValidHoleFits
+ = ValidHoleFits
+ { holeFits :: FitsMbSuppressed
+ , refinementFits :: FitsMbSuppressed
+ }
+
+noValidHoleFits :: ValidHoleFits
+noValidHoleFits = ValidHoleFits (Fits [] False) (Fits [] False)
+
+data RelevantBindings
+ = RelevantBindings
+ { relevantBindingNamesAndTys :: [(Name, Type)]
+ , ranOutOfFuel :: Bool -- ^ Whether we ran out of fuel generating the bindings.
+ }
+
+-- | Display some relevant bindings.
+pprRelevantBindings :: RelevantBindings -> SDoc
+-- This function should be in "GHC.Tc.Errors.Ppr",
+-- but's it's here for the moment as it's needed in "GHC.Tc.Errors".
+pprRelevantBindings (RelevantBindings bds ran_out_of_fuel) =
+ ppUnless (null bds) $
+ hang (text "Relevant bindings include")
+ 2 (vcat (map ppr_binding bds) $$ ppWhen ran_out_of_fuel discardMsg)
+ where
+ ppr_binding (nm, tidy_ty) =
+ sep [ pprPrefixOcc nm <+> dcolon <+> ppr tidy_ty
+ , nest 2 (parens (text "bound at"
+ <+> ppr (getSrcLoc nm)))]
+
+discardMsg :: SDoc
+discardMsg = text "(Some bindings suppressed;" <+>
+ text "use -fmax-relevant-binds=N or -fno-max-relevant-binds)"
diff --git a/compiler/GHC/Tc/Gen/App.hs b/compiler/GHC/Tc/Gen/App.hs
index 1ee4e95753..0db2d804a8 100644
--- a/compiler/GHC/Tc/Gen/App.hs
+++ b/compiler/GHC/Tc/Gen/App.hs
@@ -862,7 +862,7 @@ tcInstFun do_ql inst_final (rn_fun, fun_ctxt) fun_sigma rn_args
go1 delta acc so_far fun_ty
(eva@(EValArg { eva_arg = ValArg arg, eva_ctxt = ctxt }) : rest_args)
= do { (wrap, arg_ty, res_ty) <- matchActualFunTySigma herald
- (Just (ppr rn_fun))
+ (Just $ HsExprRnThing rn_fun)
(n_val_args, so_far) fun_ty
; (delta', arg') <- if do_ql
then addArgCtxt ctxt arg $
@@ -1238,7 +1238,7 @@ qlUnify delta ty1 ty2
-- Passes the occurs check
= do { let ty2_kind = typeKind ty2
kappa_kind = tyVarKind kappa
- ; co <- unifyKind (Just (ppr ty2)) ty2_kind kappa_kind
+ ; co <- unifyKind (Just (TypeThing ty2)) ty2_kind kappa_kind
-- unifyKind: see Note [Actual unification in qlUnify]
; traceTc "qlUnify:update" $
diff --git a/compiler/GHC/Tc/Gen/Expr.hs b/compiler/GHC/Tc/Gen/Expr.hs
index b6573897e2..0c1d4faf24 100644
--- a/compiler/GHC/Tc/Gen/Expr.hs
+++ b/compiler/GHC/Tc/Gen/Expr.hs
@@ -781,7 +781,7 @@ tcExpr expr@(RecordUpd { rupd_expr = record_expr, rupd_flds = Left rbnds }) res_
scrut_ty = TcType.substTy scrut_subst con1_res_ty
con1_arg_tys' = map (TcType.substTy result_subst) con1_arg_tys
- ; co_scrut <- unifyType (Just (ppr record_expr)) record_rho scrut_ty
+ ; co_scrut <- unifyType (Just . HsExprRnThing $ unLoc record_expr) record_rho scrut_ty
-- NB: normal unification is OK here (as opposed to subsumption),
-- because for this to work out, both record_rho and scrut_ty have
-- to be normal datatypes -- no contravariant stuff can go on
diff --git a/compiler/GHC/Tc/Gen/Head.hs b/compiler/GHC/Tc/Gen/Head.hs
index b878a5b45b..286eec6e5c 100644
--- a/compiler/GHC/Tc/Gen/Head.hs
+++ b/compiler/GHC/Tc/Gen/Head.hs
@@ -47,7 +47,6 @@ import GHC.Tc.Utils.Instantiate
import GHC.Tc.Instance.Family ( tcLookupDataFamInst )
import GHC.Core.FamInstEnv ( FamInstEnvs )
import GHC.Core.UsageEnv ( unitUE )
-import GHC.Rename.Utils ( unknownSubordinateErr )
import GHC.Rename.Unbound ( unknownNameSuggestions, WhatLooking(..) )
import GHC.Unit.Module ( getModule )
import GHC.Tc.Errors.Types
@@ -548,8 +547,8 @@ lookupParents is_selector rdr
fieldNotInType :: RecSelParent -> RdrName -> TcRnMessage
fieldNotInType p rdr
- = TcRnUnknownMessage $ mkPlainError noHints $
- unknownSubordinateErr (text "field of type" <+> quotes (ppr p)) rdr
+ = mkTcRnNotInScope rdr $
+ UnknownSubordinate (text "field of type" <+> quotes (ppr p))
notSelector :: Name -> TcRnMessage
notSelector field
@@ -676,10 +675,10 @@ tcInferOverLit lit@(OverLit { ol_val = val
do { from_id <- tcLookupId from_name
; (wrap1, from_ty) <- topInstantiate orig (idType from_id)
- ; (wrap2, sarg_ty, res_ty) <- matchActualFunTySigma herald mb_doc
+ ; (wrap2, sarg_ty, res_ty) <- matchActualFunTySigma herald mb_thing
(1, []) from_ty
; hs_lit <- mkOverLit val
- ; co <- unifyType mb_doc (hsLitType hs_lit) (scaledThing sarg_ty)
+ ; co <- unifyType mb_thing (hsLitType hs_lit) (scaledThing sarg_ty)
; let lit_expr = L (l2l loc) $ mkHsWrapCo co $
HsLit noAnn hs_lit
@@ -691,9 +690,9 @@ tcInferOverLit lit@(OverLit { ol_val = val
, ol_type = res_ty } }
; return (HsOverLit noAnn lit', res_ty) }
where
- orig = LiteralOrigin lit
- mb_doc = Just (ppr from_name)
- herald = sep [ text "The function" <+> quotes (ppr from_name)
+ orig = LiteralOrigin lit
+ mb_thing = Just (NameThing from_name)
+ herald = sep [ text "The function" <+> quotes (ppr from_name)
, text "is applied to"]
@@ -760,25 +759,29 @@ tc_infer_id id_name
ppr thing <+> text "used where a value identifier was expected" }
where
fail_tycon tc = do
- gre <- getGlobalRdrEnv
- suggestions <- get_suggestions dataName
- unit_state <- hsc_units <$> getTopEnv
- let pprov = case lookupGRE_Name gre (tyConName tc) of
+ gre <- getGlobalRdrEnv
+ let nm = tyConName tc
+ pprov = case lookupGRE_Name gre nm of
Just gre -> nest 2 (pprNameProvenance gre)
Nothing -> empty
- info = ErrInfo { errInfoContext = pprov, errInfoSupplementary = suggestions }
- msg = TcRnMessageWithInfo unit_state
- $ TcRnMessageDetailed info (TcRnIncorrectNameSpace (tyConName tc) False)
- failWithTc msg
-
- fail_tyvar name = do
- suggestions <- get_suggestions varName
- unit_state <- hsc_units <$> getTopEnv
- let pprov = nest 2 (text "bound at" <+> ppr (getSrcLoc name))
- info = ErrInfo { errInfoContext = pprov, errInfoSupplementary = suggestions }
- msg = TcRnMessageWithInfo unit_state
- $ TcRnMessageDetailed info (TcRnIncorrectNameSpace name False)
- failWithTc msg
+ fail_with_msg dataName nm pprov
+
+ fail_tyvar nm =
+ let pprov = nest 2 (text "bound at" <+> ppr (getSrcLoc nm))
+ in fail_with_msg varName nm pprov
+
+ fail_with_msg whatName nm pprov = do
+ (import_errs, hints) <- get_suggestions whatName
+ unit_state <- hsc_units <$> getTopEnv
+ let
+ -- TODO: unfortunate to have to convert to SDoc here.
+ -- This should go away once we refactor ErrInfo.
+ hint_msg = vcat $ map ppr hints
+ import_err_msg = vcat $ map ppr import_errs
+ info = ErrInfo { errInfoContext = pprov, errInfoSupplementary = import_err_msg $$ hint_msg }
+ msg = TcRnMessageWithInfo unit_state
+ $ TcRnMessageDetailed info (TcRnIncorrectNameSpace nm False)
+ failWithTc msg
get_suggestions ns = do
let occ = mkOccNameFS ns (occNameFS (occName id_name))
diff --git a/compiler/GHC/Tc/Gen/HsType.hs b/compiler/GHC/Tc/Gen/HsType.hs
index b5386aa6a7..c9024a5cf5 100644
--- a/compiler/GHC/Tc/Gen/HsType.hs
+++ b/compiler/GHC/Tc/Gen/HsType.hs
@@ -1668,7 +1668,7 @@ tcInferTyApps_nosat mode orig_hs_ty fun orig_hs_args
(HsValArg _ : _, Nothing)
-> try_again_after_substing_or $
do { let arrows_needed = n_initial_val_args all_args
- ; co <- matchExpectedFunKind hs_ty arrows_needed substed_fun_ki
+ ; co <- matchExpectedFunKind (HsTypeRnThing $ unLoc hs_ty) arrows_needed substed_fun_ki
; fun' <- zonkTcType (fun `mkTcCastTy` co)
-- This zonk is essential, to expose the fruits
@@ -1925,7 +1925,7 @@ checkExpectedKind hs_ty ty act_kind exp_kind
; let origin = TypeEqOrigin { uo_actual = act_kind'
, uo_expected = exp_kind
- , uo_thing = Just (ppr hs_ty)
+ , uo_thing = Just (HsTypeRnThing hs_ty)
, uo_visible = True } -- the hs_ty is visible
; traceTc "checkExpectedKindX" $
@@ -2683,7 +2683,7 @@ kcCheckDeclHeader_sig kisig name flav
KindedTyVar _ _ v v_hs_ki -> do
v_ki <- tcLHsKindSig (TyVarBndrKindCtxt (unLoc v)) v_hs_ki
discardResult $ -- See Note [discardResult in kcCheckDeclHeader_sig]
- unifyKind (Just (ppr v))
+ unifyKind (Just . NameThing $ unLoc v)
(tyBinderType tb)
v_ki
@@ -3163,7 +3163,7 @@ tcExplicitTKBndrsX skol_mode bndrs thing_inside
bindExplicitTKBndrsX skol_mode bndrs $
thing_inside
- ; let skol_info = ForAllSkol (fsep (map ppr bndrs))
+ ; let skol_info = ForAllSkol (HsTyVarBndrsRn $ map unLoc bndrs)
-- Notice that we use ForAllSkol here, ignoring the enclosing
-- skol_info unlike tc_implicit_tk_bndrs, because the bad-telescope
-- test applies only to ForAllSkol
@@ -3247,7 +3247,7 @@ bindExplicitTKBndrsX skol_mode@(SM { sm_parent = check_parent, sm_kind = ctxt_ki
, Just (ATyVar _ tv) <- lookupNameEnv lcl_env name
= do { kind <- tc_lhs_kind_sig tc_ki_mode (TyVarBndrKindCtxt name) lhs_kind
; discardResult $
- unifyKind (Just (ppr name)) kind (tyVarKind tv)
+ unifyKind (Just . NameThing $ name) kind (tyVarKind tv)
-- This unify rejects:
-- class C (m :: * -> *) where
-- type F (m :: *) = ...
diff --git a/compiler/GHC/Tc/Gen/Pat.hs b/compiler/GHC/Tc/Gen/Pat.hs
index 00b2e053f8..2fbd7dcf8c 100644
--- a/compiler/GHC/Tc/Gen/Pat.hs
+++ b/compiler/GHC/Tc/Gen/Pat.hs
@@ -433,7 +433,7 @@ tc_pat pat_ty penv ps_pat thing_inside = case ps_pat of
-- Expression must be a function
; let herald = text "A view pattern expression expects"
; (expr_wrap1, Scaled _mult inf_arg_ty, inf_res_sigma)
- <- matchActualFunTySigma herald (Just (ppr expr)) (1,[]) expr_ty
+ <- matchActualFunTySigma herald (Just . HsExprRnThing $ unLoc expr) (1,[]) expr_ty
-- See Note [View patterns and polymorphism]
-- expr_wrap1 :: expr_ty "->" (inf_arg_ty -> inf_res_sigma)
diff --git a/compiler/GHC/Tc/TyCl.hs b/compiler/GHC/Tc/TyCl.hs
index 9e7dca9bd4..da6054a74f 100644
--- a/compiler/GHC/Tc/TyCl.hs
+++ b/compiler/GHC/Tc/TyCl.hs
@@ -3191,7 +3191,7 @@ checkFamTelescope tclvl hs_outer_bndrs outer_tvs
| HsOuterExplicit { hso_bndrs = bndrs } <- hs_outer_bndrs
, (b_first : _) <- bndrs
, let b_last = last bndrs
- skol_info = ForAllSkol (fsep (map ppr bndrs))
+ skol_info = ForAllSkol $ HsTyVarBndrsRn (map unLoc bndrs)
= setSrcSpan (combineSrcSpans (getLocA b_first) (getLocA b_last)) $
emitResidualTvConstraint skol_info outer_tvs tclvl emptyWC
| otherwise
diff --git a/compiler/GHC/Tc/TyCl/Instance.hs b/compiler/GHC/Tc/TyCl/Instance.hs
index 98fb149c27..ff44f1864e 100644
--- a/compiler/GHC/Tc/TyCl/Instance.hs
+++ b/compiler/GHC/Tc/TyCl/Instance.hs
@@ -898,7 +898,7 @@ tcDataFamInstHeader mb_clsinfo fam_tc outer_bndrs fixity
-- is compatible with the explicit signature (or Type, if there
-- is none)
; let hs_lhs = nlHsTyConApp fixity (getName fam_tc) hs_pats
- ; _ <- unifyKind (Just (ppr hs_lhs)) lhs_applied_kind res_kind
+ ; _ <- unifyKind (Just . HsTypeRnThing $ unLoc hs_lhs) lhs_applied_kind res_kind
; traceTc "tcDataFamInstHeader" $
vcat [ ppr fam_tc, ppr m_ksig, ppr lhs_applied_kind, ppr res_kind ]
diff --git a/compiler/GHC/Tc/Types/Constraint.hs b/compiler/GHC/Tc/Types/Constraint.hs
index 103f0744b6..955874b13f 100644
--- a/compiler/GHC/Tc/Types/Constraint.hs
+++ b/compiler/GHC/Tc/Types/Constraint.hs
@@ -25,6 +25,7 @@ module GHC.Tc.Types.Constraint (
ctEvExpr, ctEvTerm, ctEvCoercion, ctEvEvId,
tyCoVarsOfCt, tyCoVarsOfCts,
tyCoVarsOfCtList, tyCoVarsOfCtsList,
+ ambigTkvsOfCt,
CtIrredReason(..), HoleSet, isInsolubleReason,
@@ -49,6 +50,7 @@ module GHC.Tc.Types.Constraint (
Implication(..), implicationPrototype, checkTelescopeSkol,
ImplicStatus(..), isInsolubleStatus, isSolvedStatus,
+ UserGiven, getUserGivensFromImplics,
HasGivenEqs(..),
SubGoalDepth, initialSubGoalDepth, maxSubGoalDepth,
bumpSubGoalDepth, subGoalDepthExceeded,
@@ -114,7 +116,7 @@ import qualified Data.Semigroup ( (<>) )
-- these are for CheckTyEqResult
import Data.Word ( Word8 )
-import Data.List ( intersperse )
+import Data.List ( intersperse, partition )
@@ -741,6 +743,14 @@ tyCoFVsOfHole (Hole { hole_ty = ty }) = tyCoFVsOfType ty
tyCoFVsOfBag :: (a -> FV) -> Bag a -> FV
tyCoFVsOfBag tvs_of = foldr (unionFV . tvs_of) emptyFV
+ambigTkvsOfCt :: Ct -> ([Var],[Var])
+ambigTkvsOfCt ct
+ = partition (`elemVarSet` dep_tkv_set) ambig_tkvs
+ where
+ tkvs = tyCoVarsOfCtList ct
+ ambig_tkvs = filter isAmbiguousTyVar tkvs
+ dep_tkv_set = tyCoVarsOfTypes (map tyVarKind tkvs)
+
---------------------------
dropDerivedWC :: WantedConstraints -> WantedConstraints
-- See Note [Dropping derived constraints]
@@ -1386,6 +1396,12 @@ data HasGivenEqs -- See Note [HasGivenEqs]
-- is possible.
deriving Eq
+type UserGiven = Implication
+
+getUserGivensFromImplics :: [Implication] -> [UserGiven]
+getUserGivensFromImplics implics
+ = reverse (filterOut (null . ic_given) implics)
+
{- Note [HasGivenEqs]
~~~~~~~~~~~~~~~~~~~~~
The GivenEqs data type describes the Given constraints of an implication constraint:
diff --git a/compiler/GHC/Tc/Types/Origin.hs b/compiler/GHC/Tc/Types/Origin.hs
index d7c68ccd17..00f1ca10a0 100644
--- a/compiler/GHC/Tc/Types/Origin.hs
+++ b/compiler/GHC/Tc/Types/Origin.hs
@@ -1,4 +1,6 @@
-
+{-# LANGUAGE DataKinds #-}
+{-# LANGUAGE FlexibleContexts #-}
+{-# LANGUAGE GADTs #-}
{-# LANGUAGE LambdaCase #-}
{-# OPTIONS_GHC -Wno-incomplete-record-updates #-}
@@ -20,6 +22,8 @@ module GHC.Tc.Types.Origin (
isVisibleOrigin, toInvisibleOrigin,
pprCtOrigin, isGivenOrigin,
+ TypedThing(..), TyVarBndrs(..),
+
-- CtOrigin and CallStack
isPushCallStackOrigin, callStackOriginFS,
-- FixedRuntimeRep origin
@@ -212,8 +216,8 @@ data SkolemInfo
-- hence, we have less info
| ForAllSkol -- Bound by a user-written "forall".
- SDoc -- Shows just the binders, used when reporting a bad telescope
- -- See Note [Checking telescopes] in GHC.Tc.Types.Constraint
+ TyVarBndrs -- Shows just the binders, used when reporting a bad telescope
+ -- See Note [Checking telescopes] in GHC.Tc.Types.Constraint
| DerivSkol Type -- Bound by a 'deriving' clause;
-- the type is the instance we are trying to derive
@@ -264,7 +268,7 @@ pprSkolInfo :: SkolemInfo -> SDoc
-- Complete the sentence "is a rigid type variable bound by..."
pprSkolInfo (SigSkol cx ty _) = pprSigSkolInfo cx ty
pprSkolInfo (SigTypeSkol cx) = pprUserTypeCtxt cx
-pprSkolInfo (ForAllSkol tvs) = text "an explicit forall" <+> tvs
+pprSkolInfo (ForAllSkol tvs) = text "an explicit forall" <+> ppr tvs
pprSkolInfo (IPSkol ips) = text "the implicit-parameter binding" <> plural ips <+> text "for"
<+> pprWithCommas ppr ips
pprSkolInfo (DerivSkol pred) = text "the deriving clause for" <+> quotes (ppr pred)
@@ -358,6 +362,32 @@ in the right place. So we proceed as follows:
************************************************************************
-}
+-- | Some thing which has a type.
+--
+-- This datatype is used when we want to report to the user
+-- that something has an unexpected type.
+data TypedThing
+ = HsTypeRnThing (HsType GhcRn)
+ | TypeThing Type
+ | HsExprRnThing (HsExpr GhcRn)
+ | NameThing Name
+
+-- | Some kind of type variable binder.
+--
+-- Used for reporting errors, in 'SkolemInfo' and 'TcReportMsg'.
+data TyVarBndrs
+ = forall flag. OutputableBndrFlag flag 'Renamed =>
+ HsTyVarBndrsRn [HsTyVarBndr flag GhcRn]
+
+instance Outputable TypedThing where
+ ppr (HsTypeRnThing ty) = ppr ty
+ ppr (TypeThing ty) = ppr ty
+ ppr (HsExprRnThing expr) = ppr expr
+ ppr (NameThing name) = ppr name
+
+instance Outputable TyVarBndrs where
+ ppr (HsTyVarBndrsRn bndrs) = fsep (map ppr bndrs)
+
data CtOrigin
= -- | A given constraint from a user-written type signature. The
-- 'SkolemInfo' inside gives more information.
@@ -404,9 +434,10 @@ data CtOrigin
| SpecPragOrigin UserTypeCtxt -- Specialisation pragma for
-- function or instance
+
| TypeEqOrigin { uo_actual :: TcType
, uo_expected :: TcType
- , uo_thing :: Maybe SDoc
+ , uo_thing :: Maybe TypedThing
-- ^ The thing that has type "actual"
, uo_visible :: Bool
-- ^ Is at least one of the three elements above visible?
diff --git a/compiler/GHC/Tc/Utils/Unify.hs b/compiler/GHC/Tc/Utils/Unify.hs
index a0b8106a8d..aa1a753369 100644
--- a/compiler/GHC/Tc/Utils/Unify.hs
+++ b/compiler/GHC/Tc/Utils/Unify.hs
@@ -89,7 +89,7 @@ import qualified Data.Semigroup as S ( (<>) )
-- returning an uninstantiated sigma-type
matchActualFunTySigma
:: SDoc -- See Note [Herald for matchExpectedFunTys]
- -> Maybe SDoc -- The thing with type TcSigmaType
+ -> Maybe TypedThing -- The thing with type TcSigmaType
-> (Arity, [Scaled TcSigmaType]) -- Total number of value args in the call, and
-- types of values args to which function has
-- been applied already (reversed)
@@ -190,7 +190,7 @@ Ugh!
-- for example in function application
matchActualFunTysRho :: SDoc -- See Note [Herald for matchExpectedFunTys]
-> CtOrigin
- -> Maybe SDoc -- the thing with type TcSigmaType
+ -> Maybe TypedThing -- the thing with type TcSigmaType
-> Arity
-> TcSigmaType
-> TcM (HsWrapper, [Scaled TcSigmaType], TcRhoType)
@@ -523,7 +523,7 @@ tcWrapResultO :: CtOrigin -> HsExpr GhcRn -> HsExpr GhcTc -> TcSigmaType -> ExpR
tcWrapResultO orig rn_expr expr actual_ty res_ty
= do { traceTc "tcWrapResult" (vcat [ text "Actual: " <+> ppr actual_ty
, text "Expected:" <+> ppr res_ty ])
- ; wrap <- tcSubTypeNC orig GenSigCtxt (Just (ppr rn_expr)) actual_ty res_ty
+ ; wrap <- tcSubTypeNC orig GenSigCtxt (Just $ HsExprRnThing rn_expr) actual_ty res_ty
; return (mkHsWrap wrap expr) }
tcWrapResultMono :: HsExpr GhcRn -> HsExpr GhcTc
@@ -545,7 +545,7 @@ unifyExpectedType :: HsExpr GhcRn
unifyExpectedType rn_expr act_ty exp_ty
= case exp_ty of
Infer inf_res -> fillInferResult act_ty inf_res
- Check exp_ty -> unifyType (Just (ppr rn_expr)) act_ty exp_ty
+ Check exp_ty -> unifyType (Just $ HsExprRnThing rn_expr) act_ty exp_ty
------------------------
tcSubTypePat :: CtOrigin -> UserTypeCtxt
@@ -566,8 +566,8 @@ tcSubTypePat _ _ (Infer inf_res) ty_expected
---------------
tcSubType :: CtOrigin -> UserTypeCtxt
- -> TcSigmaType -- Actual
- -> ExpRhoType -- Expected
+ -> TcSigmaType -- ^ Actual
+ -> ExpRhoType -- ^ Expected
-> TcM HsWrapper
-- Checks that 'actual' is more polymorphic than 'expected'
tcSubType orig ctxt ty_actual ty_expected
@@ -575,11 +575,11 @@ tcSubType orig ctxt ty_actual ty_expected
do { traceTc "tcSubType" (vcat [pprUserTypeCtxt ctxt, ppr ty_actual, ppr ty_expected])
; tcSubTypeNC orig ctxt Nothing ty_actual ty_expected }
-tcSubTypeNC :: CtOrigin -- Used when instantiating
- -> UserTypeCtxt -- Used when skolemising
- -> Maybe SDoc -- The expression that has type 'actual' (if known)
- -> TcSigmaType -- Actual type
- -> ExpRhoType -- Expected type
+tcSubTypeNC :: CtOrigin -- ^ Used when instantiating
+ -> UserTypeCtxt -- ^ Used when skolemising
+ -> Maybe TypedThing -- ^ The expression that has type 'actual' (if known)
+ -> TcSigmaType -- ^ Actual type
+ -> ExpRhoType -- ^ Expected type
-> TcM HsWrapper
tcSubTypeNC inst_orig ctxt m_thing ty_actual res_ty
= case res_ty of
@@ -1071,7 +1071,7 @@ The exported functions are all defined as versions of some
non-exported generic functions.
-}
-unifyType :: Maybe SDoc -- ^ If present, the thing that has type ty1
+unifyType :: Maybe TypedThing -- ^ If present, the thing that has type ty1
-> TcTauType -> TcTauType -- ty1, ty2
-> TcM TcCoercionN -- :: ty1 ~# ty2
-- Actual and expected types
@@ -1081,7 +1081,7 @@ unifyType thing ty1 ty2
where
origin = TypeEqOrigin { uo_actual = ty1
, uo_expected = ty2
- , uo_thing = ppr <$> thing
+ , uo_thing = thing
, uo_visible = True }
unifyTypeET :: TcTauType -> TcTauType -> TcM CoercionN
@@ -1096,7 +1096,7 @@ unifyTypeET ty1 ty2
, uo_visible = True }
-unifyKind :: Maybe SDoc -> TcKind -> TcKind -> TcM CoercionN
+unifyKind :: Maybe TypedThing -> TcKind -> TcKind -> TcM CoercionN
unifyKind mb_thing ty1 ty2
= uType KindLevel origin ty1 ty2
where
@@ -1820,8 +1820,7 @@ causing this wibble in behavior seen here.
-- | Breaks apart a function kind into its pieces.
matchExpectedFunKind
- :: Outputable fun
- => fun -- ^ type, only for errors
+ :: TypedThing -- ^ type, only for errors
-> Arity -- ^ n: number of desired arrows
-> TcKind -- ^ fun_ kind
-> TcM Coercion -- ^ co :: fun_kind ~ (arg1 -> ... -> argn -> res)
@@ -1852,7 +1851,7 @@ matchExpectedFunKind hs_ty n k = go n k
; let new_fun = mkVisFunTysMany arg_kinds res_kind
origin = TypeEqOrigin { uo_actual = k
, uo_expected = new_fun
- , uo_thing = Just (ppr hs_ty)
+ , uo_thing = Just hs_ty
, uo_visible = True
}
; uType KindLevel origin k new_fun }
diff --git a/compiler/GHC/Tc/Utils/Unify.hs-boot b/compiler/GHC/Tc/Utils/Unify.hs-boot
index 7b4561420c..dc8bcce6e8 100644
--- a/compiler/GHC/Tc/Utils/Unify.hs-boot
+++ b/compiler/GHC/Tc/Utils/Unify.hs-boot
@@ -4,15 +4,14 @@ import GHC.Prelude
import GHC.Tc.Utils.TcType ( TcTauType )
import GHC.Tc.Types ( TcM )
import GHC.Tc.Types.Evidence ( TcCoercion, HsWrapper )
-import GHC.Tc.Types.Origin ( CtOrigin )
-import GHC.Utils.Outputable( SDoc )
+import GHC.Tc.Types.Origin ( CtOrigin, TypedThing )
import GHC.Hs.Type ( Mult )
-- This boot file exists only to tie the knot between
-- GHC.Tc.Utils.Unify and Inst
-unifyType :: Maybe SDoc -> TcTauType -> TcTauType -> TcM TcCoercion
-unifyKind :: Maybe SDoc -> TcTauType -> TcTauType -> TcM TcCoercion
+unifyType :: Maybe TypedThing -> TcTauType -> TcTauType -> TcM TcCoercion
+unifyKind :: Maybe TypedThing -> TcTauType -> TcTauType -> TcM TcCoercion
tcSubMult :: CtOrigin -> Mult -> Mult -> TcM HsWrapper
diff --git a/compiler/GHC/Types/Hint.hs b/compiler/GHC/Types/Hint.hs
index 519e55edb1..4182e40b3f 100644
--- a/compiler/GHC/Types/Hint.hs
+++ b/compiler/GHC/Types/Hint.hs
@@ -5,6 +5,10 @@ module GHC.Types.Hint (
, AvailableBindings(..)
, InstantiationSuggestion(..)
, LanguageExtensionHint(..)
+ , ImportSuggestion(..)
+ , HowInScope(..)
+ , SimilarName(..)
+ , StarIsType(..)
, suggestExtension
, suggestExtensionWithInfo
, suggestExtensions
@@ -12,6 +16,7 @@ module GHC.Types.Hint (
, suggestAnyExtension
, suggestAnyExtensionWithInfo
, useExtensionInOrderTo
+ , noStarIsTypeHints
) where
import GHC.Prelude
@@ -24,10 +29,14 @@ import Data.Typeable
import GHC.Unit.Module (ModuleName, Module)
import GHC.Hs.Extension (GhcTc)
import GHC.Core.Coercion
-import GHC.Types.Name (Name, NameSpace)
+import GHC.Types.Name (Name, NameSpace, OccName (occNameFS))
+import GHC.Types.Name.Reader (RdrName (Unqual), ImpDeclSpec)
+import GHC.Types.SrcLoc (SrcSpan)
import GHC.Types.Basic (Activation, RuleName)
import GHC.Parser.Errors.Basic
import {-# SOURCE #-} Language.Haskell.Syntax.Expr
+import GHC.Unit.Module.Imported (ImportedModsVal)
+import GHC.Data.FastString (fsLit)
-- This {-# SOURCE #-} import should be removable once
-- 'Language.Haskell.Syntax.Bind' no longer depends on 'GHC.Tc.Types.Evidence'.
@@ -237,7 +246,7 @@ data GhcHint
Test case(s): wcompat-warnings/WCompatWarningsOn.hs
-}
- | SuggestUseTypeFromDataKind
+ | SuggestUseTypeFromDataKind (Maybe RdrName)
{-| Suggests placing the 'qualified' keyword /after/ the module name.
@@ -309,9 +318,9 @@ data GhcHint
-}
| SuggestFillInWildcardConstraint
- {-| Suggests to use an identifier other than 'forall'
- Triggered by: 'GHC.Tc.Errors.Types.TcRnForallIdentifier'
- -}
+ {-| Suggests to use an identifier other than 'forall'
+ Triggered by: 'GHC.Tc.Errors.Types.TcRnForallIdentifier'
+ -}
| SuggestRenameForall
{-| Suggests to use the appropriate Template Haskell tick:
@@ -321,6 +330,59 @@ data GhcHint
Triggered by: 'GHC.Tc.Errors.Types.TcRnIncorrectNameSpace'.
-}
| SuggestAppropriateTHTick NameSpace
+ {-| Suggests enabling -ddump-splices to help debug an issue
+ when a 'Name' is not in scope or is used in multiple
+ different namespaces (e.g. both as a data constructor
+ and a type constructor).
+
+ Concomitant with 'NoExactName' or 'SameName' errors,
+ see e.g. "GHC.Rename.Env.lookupExactOcc_either".
+ Test cases: T5971, T7241, T13937.
+ -}
+ | SuggestDumpSlices
+
+ {-| Suggests adding a tick to refer to a data constructor
+ at the type level.
+
+ Test case: T9778.
+ -}
+ | SuggestAddTick Name
+
+ {-| Something is split off from its corresponding declaration.
+ For example, a datatype is given a role declaration
+ in a different module.
+
+ Test cases: T495, T8485, T2713, T5533.
+ -}
+ | SuggestMoveToDeclarationSite
+ -- TODO: remove the SDoc argument.
+ SDoc -- ^ fixity declaration, role annotation, type signature, ...
+ RdrName -- ^ the 'RdrName' for the declaration site
+
+ {-| Suggest a similar name that the user might have meant,
+ e.g. suggest 'traverse' when the user has written @travrese@.
+
+ Test case: mod73.
+ -}
+ | SuggestSimilarNames RdrName (NE.NonEmpty SimilarName)
+
+ {-| Remind the user that the field selector has been suppressed
+ because of -XNoFieldSelectors.
+
+ Test cases: NFSSuppressed, records-nofieldselectors.
+ -}
+ | RemindFieldSelectorSuppressed
+ { suppressed_selector :: RdrName
+ , suppressed_parents :: [Name] }
+
+ {-| Suggest importing from a module, removing a @hiding@ clause,
+ or explain to the user that we couldn't find a module
+ with the given 'ModuleName'.
+
+ Test cases: mod28, mod36, mod87, mod114, ...
+ -}
+ | ImportSuggestion ImportSuggestion
+
-- | An 'InstantiationSuggestion' for a '.hsig' file. This is generated
-- by GHC in case of a 'DriverUnexpectedSignature' and suggests a way
@@ -334,3 +396,101 @@ data GhcHint
-- (Try passing -instantiated-with="MyStr=<MyStr>"
-- replacing <MyStr> as necessary.)
data InstantiationSuggestion = InstantiationSuggestion !ModuleName !Module
+
+-- | Suggest how to fix an import.
+data ImportSuggestion
+ -- | Some module exports what we want, but we aren't explicitly importing it.
+ = CouldImportFrom (NE.NonEmpty (Module, ImportedModsVal)) OccName
+ -- | Some module exports what we want, but we are explicitly hiding it.
+ | CouldUnhideFrom (NE.NonEmpty (Module, ImportedModsVal)) OccName
+
+-- | Explain how something is in scope.
+data HowInScope
+ -- | It was locally bound at this particular source location.
+ = LocallyBoundAt SrcSpan
+ -- | It was imported by this particular import declaration.
+ | ImportedBy ImpDeclSpec
+
+data SimilarName
+ = SimilarName Name
+ | SimilarRdrName RdrName HowInScope
+
+--------------------------------------------------------------------------------
+
+-- | Whether '*' is a synonym for 'Data.Kind.Type'.
+data StarIsType
+ = StarIsNotType
+ | StarIsType
+
+-- | Display info about the treatment of '*' under NoStarIsType.
+--
+-- With StarIsType, three properties of '*' hold:
+--
+-- (a) it is not an infix operator
+-- (b) it is always in scope
+-- (c) it is a synonym for Data.Kind.Type
+--
+-- However, the user might not know that they are working on a module with
+-- NoStarIsType and write code that still assumes (a), (b), and (c), which
+-- actually do not hold in that module.
+--
+-- Violation of (a) shows up in the parser. For instance, in the following
+-- examples, we have '*' not applied to enough arguments:
+--
+-- data A :: *
+-- data F :: * -> *
+--
+-- Violation of (b) or (c) show up in the renamer and the typechecker
+-- respectively. For instance:
+--
+-- type K = Either * Bool
+--
+-- This will parse differently depending on whether StarIsType is enabled,
+-- but it will parse nonetheless. With NoStarIsType it is parsed as a type
+-- operator, thus we have ((*) Either Bool). Now there are two cases to
+-- consider:
+--
+-- 1. There is no definition of (*) in scope. In this case the renamer will
+-- fail to look it up. This is a violation of assumption (b).
+--
+-- 2. There is a definition of the (*) type operator in scope (for example
+-- coming from GHC.TypeNats). In this case the user will get a kind
+-- mismatch error. This is a violation of assumption (c).
+--
+-- The user might unknowingly be working on a module with NoStarIsType
+-- or use '*' as 'Data.Kind.Type' out of habit. So it is important to give a
+-- hint whenever an assumption about '*' is violated. Unfortunately, it is
+-- somewhat difficult to deal with (c), so we limit ourselves to (a) and (b).
+--
+-- 'noStarIsTypeHints' returns appropriate hints to the user depending on the
+-- extensions enabled in the module and the name that triggered the error.
+-- That is, if we have NoStarIsType and the error is related to '*' or its
+-- Unicode variant, we will suggest using 'Data.Kind.Type'; otherwise we won't
+-- suggest anything.
+noStarIsTypeHints :: StarIsType -> RdrName -> [GhcHint]
+noStarIsTypeHints is_star_type rdr_name
+ -- One might ask: if can use `sdocOption sdocStarIsType` here, why bother to
+ -- take star_is_type as input? Why not refactor?
+ --
+ -- The reason is that `sdocOption sdocStarIsType` would indicate that
+ -- StarIsType is enabled in the module that tries to load the problematic
+ -- definition, not in the module that is being loaded.
+ --
+ -- So if we have 'data T :: *' in a module with NoStarIsType, then the hint
+ -- must be displayed even if we load this definition from a module (or GHCi)
+ -- with StarIsType enabled!
+ --
+ | isUnqualStar
+ , StarIsNotType <- is_star_type
+ = [SuggestUseTypeFromDataKind (Just rdr_name)]
+ | otherwise
+ = []
+ where
+ -- Does rdr_name look like the user might have meant the '*' kind by it?
+ -- We focus on unqualified stars specifically, because qualified stars are
+ -- treated as type operators even under StarIsType.
+ isUnqualStar
+ | Unqual occName <- rdr_name
+ = let fs = occNameFS occName
+ in fs == fsLit "*" || fs == fsLit "★"
+ | otherwise = False
diff --git a/compiler/GHC/Types/Hint/Ppr.hs b/compiler/GHC/Types/Hint/Ppr.hs
index a11be60209..9fd39e2a53 100644
--- a/compiler/GHC/Types/Hint/Ppr.hs
+++ b/compiler/GHC/Types/Hint/Ppr.hs
@@ -14,7 +14,10 @@ import GHC.Types.Hint
import GHC.Hs.Expr () -- instance Outputable
import GHC.Types.Id
-import GHC.Types.Name (isValNameSpace)
+import GHC.Types.Name (NameSpace, pprDefinedAt, occNameSpace, pprNameSpace, isValNameSpace)
+import GHC.Types.Name.Reader (RdrName,ImpDeclSpec (..), rdrNameOcc, rdrNameSpace)
+import GHC.Types.SrcLoc (SrcSpan(..), srcSpanStartLine)
+import GHC.Unit.Module.Imported (ImportedModsVal(..))
import GHC.Unit.Types
import GHC.Utils.Outputable
@@ -91,9 +94,16 @@ instance Outputable GhcHint where
, whenPprDebug (ppr bad_rule) ]
SuggestIncreaseSimplifierIterations
-> text "Set limit with -fconstraint-solver-iterations=n; n=0 for no limit"
- SuggestUseTypeFromDataKind
+ SuggestUseTypeFromDataKind mb_rdr_name
-> text "Use" <+> quotes (text "Type")
- <+> text "from" <+> quotes (text "Data.Kind") <+> text "instead."
+ <+> text "from" <+> quotes (text "Data.Kind") <+> text "instead."
+ $$
+ maybe empty
+ (\rdr_name ->
+ text "NB: with NoStarIsType, " <> quotes (ppr rdr_name)
+ <+> text "is treated as a regular type operator.")
+ mb_rdr_name
+
SuggestQualifiedAfterModuleName
-> text "Place" <+> quotes (text "qualified")
<+> text "after the module name."
@@ -138,6 +148,105 @@ instance Outputable GhcHint where
how_many
| isValNameSpace ns = text "single"
| otherwise = text "double"
+ SuggestDumpSlices
+ -> vcat [ text "If you bound a unique Template Haskell name (NameU)"
+ , text "perhaps via newName,"
+ , text "then -ddump-splices might be useful." ]
+ SuggestAddTick name
+ -> hsep [ text "Use"
+ , quotes (char '\'' <> ppr name)
+ , text "instead of"
+ , quotes (ppr name) <> dot ]
+ SuggestMoveToDeclarationSite what rdr_name
+ -> text "Move the" <+> what <+> text "to the declaration site of"
+ <+> quotes (ppr rdr_name) <> dot
+ SuggestSimilarNames tried_rdr_name similar_names
+ -> case similar_names of
+ n NE.:| [] -> text "Perhaps use" <+> pp_item n
+ _ -> sep [ text "Perhaps use one of these:"
+ , nest 2 (pprWithCommas pp_item $ NE.toList similar_names) ]
+ where
+ tried_ns = occNameSpace $ rdrNameOcc tried_rdr_name
+ pp_item = pprSimilarName tried_ns
+ RemindFieldSelectorSuppressed rdr_name parents
+ -> text "Notice that" <+> quotes (ppr rdr_name)
+ <+> text "is a field selector" <+> whose
+ $$ text "that has been suppressed by NoFieldSelectors."
+ where
+ -- 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
+ ImportSuggestion import_suggestion
+ -> pprImportSuggestion import_suggestion
perhapsAsPat :: SDoc
perhapsAsPat = text "Perhaps you meant an as-pattern, which must not be surrounded by whitespace"
+
+-- | Pretty-print an 'ImportSuggestion'.
+pprImportSuggestion :: ImportSuggestion -> SDoc
+pprImportSuggestion (CouldImportFrom mods occ_name)
+ | (mod, imv) NE.:| [] <- mods
+ = 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
+ ]
+ | otherwise
+ = 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) <- NE.toList mods
+ ])
+pprImportSuggestion (CouldUnhideFrom mods occ_name)
+ | (mod, imv) NE.:| [] <- mods
+ = 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
+ ]
+ | otherwise
+ = 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) <- NE.toList mods
+ ])
+
+-- | Pretty-print a 'SimilarName'.
+pprSimilarName :: NameSpace -> SimilarName -> SDoc
+pprSimilarName _ (SimilarName name)
+ = quotes (ppr name) <+> parens (pprDefinedAt name)
+pprSimilarName tried_ns (SimilarRdrName rdr_name how_in_scope)
+ = case how_in_scope of
+ LocallyBoundAt loc ->
+ pp_ns rdr_name <+> quotes (ppr rdr_name) <+> loc'
+ where
+ loc' = case loc of
+ UnhelpfulSpan l -> parens (ppr l)
+ RealSrcSpan l _ -> parens (text "line" <+> int (srcSpanStartLine l))
+ ImportedBy is ->
+ pp_ns rdr_name <+> quotes (ppr rdr_name) <+>
+ parens (text "imported from" <+> ppr (is_mod is))
+
+ where
+ pp_ns :: RdrName -> SDoc
+ pp_ns rdr | ns /= tried_ns = pprNameSpace ns
+ | otherwise = empty
+ where ns = rdrNameSpace rdr
diff --git a/compiler/GHC/Types/Name/Reader.hs b/compiler/GHC/Types/Name/Reader.hs
index 864101e8a9..05ea5a696b 100644
--- a/compiler/GHC/Types/Name/Reader.hs
+++ b/compiler/GHC/Types/Name/Reader.hs
@@ -71,11 +71,8 @@ module GHC.Types.Name.Reader (
ImportSpec(..), ImpDeclSpec(..), ImpItemSpec(..),
importSpecLoc, importSpecModule, isExplicitItem, bestImport,
- -- * Utils for StarIsType
- starInfo,
-
-- * Utils
- opIsAt,
+ opIsAt
) where
import GHC.Prelude
@@ -1374,83 +1371,6 @@ pprLoc :: SrcSpan -> SDoc
pprLoc (RealSrcSpan s _) = text "at" <+> ppr s
pprLoc (UnhelpfulSpan {}) = empty
--- | Display info about the treatment of '*' under NoStarIsType.
---
--- With StarIsType, three properties of '*' hold:
---
--- (a) it is not an infix operator
--- (b) it is always in scope
--- (c) it is a synonym for Data.Kind.Type
---
--- However, the user might not know that they are working on a module with
--- NoStarIsType and write code that still assumes (a), (b), and (c), which
--- actually do not hold in that module.
---
--- Violation of (a) shows up in the parser. For instance, in the following
--- examples, we have '*' not applied to enough arguments:
---
--- data A :: *
--- data F :: * -> *
---
--- Violation of (b) or (c) show up in the renamer and the typechecker
--- respectively. For instance:
---
--- type K = Either * Bool
---
--- This will parse differently depending on whether StarIsType is enabled,
--- but it will parse nonetheless. With NoStarIsType it is parsed as a type
--- operator, thus we have ((*) Either Bool). Now there are two cases to
--- consider:
---
--- 1. There is no definition of (*) in scope. In this case the renamer will
--- fail to look it up. This is a violation of assumption (b).
---
--- 2. There is a definition of the (*) type operator in scope (for example
--- coming from GHC.TypeNats). In this case the user will get a kind
--- mismatch error. This is a violation of assumption (c).
---
--- The user might unknowingly be working on a module with NoStarIsType
--- or use '*' as 'Data.Kind.Type' out of habit. So it is important to give a
--- hint whenever an assumption about '*' is violated. Unfortunately, it is
--- somewhat difficult to deal with (c), so we limit ourselves to (a) and (b).
---
--- 'starInfo' generates an appropriate hint to the user depending on the
--- extensions enabled in the module and the name that triggered the error.
--- That is, if we have NoStarIsType and the error is related to '*' or its
--- Unicode variant, the resulting SDoc will contain a helpful suggestion.
--- Otherwise it is empty.
---
-starInfo :: Bool -> RdrName -> SDoc
-starInfo star_is_type rdr_name =
- -- One might ask: if can use `sdocOption sdocStarIsType` here, why bother to
- -- take star_is_type as input? Why not refactor?
- --
- -- The reason is that `sdocOption sdocStarIsType` would indicate that
- -- StarIsType is enabled in the module that tries to load the problematic
- -- definition, not in the module that is being loaded.
- --
- -- So if we have 'data T :: *' in a module with NoStarIsType, then the hint
- -- must be displayed even if we load this definition from a module (or GHCi)
- -- with StarIsType enabled!
- --
- if isUnqualStar && not star_is_type
- then text "With NoStarIsType, " <>
- quotes (ppr rdr_name) <>
- text " is treated as a regular type operator. "
- $$
- text "Did you mean to use " <> quotes (text "Type") <>
- text " from Data.Kind instead?"
- else empty
- where
- -- Does rdr_name look like the user might have meant the '*' kind by it?
- -- We focus on unqualified stars specifically, because qualified stars are
- -- treated as type operators even under StarIsType.
- isUnqualStar
- | Unqual occName <- rdr_name
- = let fs = occNameFS occName
- in fs == fsLit "*" || fs == fsLit "★"
- | otherwise = False
-
-- | Indicate if the given name is the "@" operator
opIsAt :: RdrName -> Bool
opIsAt e = e == mkUnqual varName (fsLit "@")