summaryrefslogtreecommitdiff
path: root/compiler/GHC/Tc/Errors.hs
diff options
context:
space:
mode:
Diffstat (limited to 'compiler/GHC/Tc/Errors.hs')
-rw-r--r--compiler/GHC/Tc/Errors.hs1950
1 files changed, 386 insertions, 1564 deletions
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 }
{-