module GHC.Tc.Errors(
reportUnsolved, reportAllUnsolved, warnAllUnsolved,
warnDefaulting,
solverDepthErrorTcS
) where
#include "HsVersions.h"
import GHC.Prelude
import GHC.Tc.Types
import GHC.Tc.Utils.Monad
import GHC.Tc.Types.Constraint
import GHC.Core.Predicate
import GHC.Tc.Utils.TcMType
import GHC.Tc.Utils.Unify( occCheckForErrors, CheckTyEqResult(..) )
import GHC.Tc.Utils.Env( tcInitTidyEnv )
import GHC.Tc.Utils.TcType
import GHC.Tc.Types.Origin
import GHC.Rename.Unbound ( unknownNameSuggestions )
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, flattenTys )
import GHC.Unit.Module
import GHC.Tc.Instance.Family
import GHC.Tc.Utils.Instantiate
import GHC.Core.InstEnv
import GHC.Core.TyCon
import GHC.Core.Class
import GHC.Core.DataCon
import GHC.Tc.Types.Evidence
import GHC.Tc.Types.EvTerm
import GHC.Hs.Binds ( PatSynBind(..) )
import GHC.Types.Name
import GHC.Types.Name.Reader ( lookupGRE_Name, GlobalRdrEnv, mkRdrUnqual )
import GHC.Builtin.Names ( typeableClassName )
import GHC.Types.Id
import GHC.Types.Var
import GHC.Types.Var.Set
import GHC.Types.Var.Env
import GHC.Types.Name.Set
import GHC.Data.Bag
import GHC.Utils.Error ( pprLocMsgEnvelope )
import GHC.Types.Basic
import GHC.Types.Error
import GHC.Core.ConLike ( ConLike(..))
import GHC.Utils.Misc
import GHC.Data.FastString
import GHC.Utils.Outputable as O
import GHC.Utils.Panic
import GHC.Types.SrcLoc
import GHC.Driver.Session
import GHC.Driver.Ppr
import GHC.Data.List.SetOps ( equivClasses )
import GHC.Data.Maybe
import qualified GHC.LanguageExtensions as LangExt
import GHC.Utils.FV ( fvVarList, unionFV )
import Control.Monad ( when, unless )
import Data.Foldable ( toList )
import Data.List ( partition, mapAccumL, sortBy, unfoldr )
import GHC.Tc.Errors.Hole ( findValidHoleFits )
import qualified Data.Semigroup as Semigroup
reportUnsolved :: WantedConstraints -> TcM (Bag EvBind)
reportUnsolved wanted
= do { binds_var <- newTcEvBinds
; defer_errors <- goptM Opt_DeferTypeErrors
; warn_errors <- woptM Opt_WarnDeferredTypeErrors
; let type_errors | not defer_errors = TypeError
| warn_errors = TypeWarn (Reason Opt_WarnDeferredTypeErrors)
| otherwise = TypeDefer
; defer_holes <- goptM Opt_DeferTypedHoles
; warn_holes <- woptM Opt_WarnTypedHoles
; let expr_holes | not defer_holes = HoleError
| warn_holes = HoleWarn
| otherwise = HoleDefer
; partial_sigs <- xoptM LangExt.PartialTypeSignatures
; warn_partial_sigs <- woptM Opt_WarnPartialTypeSignatures
; let type_holes | not partial_sigs = HoleError
| warn_partial_sigs = HoleWarn
| otherwise = HoleDefer
; defer_out_of_scope <- goptM Opt_DeferOutOfScopeVariables
; warn_out_of_scope <- woptM Opt_WarnDeferredOutOfScopeVariables
; let out_of_scope_holes | not defer_out_of_scope = HoleError
| warn_out_of_scope = HoleWarn
| otherwise = HoleDefer
; report_unsolved type_errors expr_holes
type_holes out_of_scope_holes
binds_var wanted
; ev_binds <- getTcEvBindsMap binds_var
; return (evBindMapBinds ev_binds)}
reportAllUnsolved :: WantedConstraints -> TcM ()
reportAllUnsolved wanted
= do { ev_binds <- newNoTcEvBinds
; partial_sigs <- xoptM LangExt.PartialTypeSignatures
; warn_partial_sigs <- woptM Opt_WarnPartialTypeSignatures
; let type_holes | not partial_sigs = HoleError
| warn_partial_sigs = HoleWarn
| otherwise = HoleDefer
; report_unsolved TypeError HoleError type_holes HoleError
ev_binds wanted }
warnAllUnsolved :: WantedConstraints -> TcM ()
warnAllUnsolved wanted
= do { ev_binds <- newTcEvBinds
; report_unsolved (TypeWarn NoReason) HoleWarn HoleWarn HoleWarn
ev_binds wanted }
report_unsolved :: TypeErrorChoice
-> HoleChoice
-> HoleChoice
-> HoleChoice
-> EvBindsVar
-> WantedConstraints -> TcM ()
report_unsolved type_errors expr_holes
type_holes out_of_scope_holes binds_var wanted
| isEmptyWC wanted
= return ()
| otherwise
= do { traceTc "reportUnsolved {" $
vcat [ text "type errors:" <+> ppr type_errors
, text "expr holes:" <+> ppr expr_holes
, text "type holes:" <+> ppr type_holes
, text "scope holes:" <+> ppr out_of_scope_holes ]
; traceTc "reportUnsolved (before zonking and tidying)" (ppr wanted)
; wanted <- zonkWC wanted
; let tidy_env = tidyFreeTyCoVars emptyTidyEnv free_tvs
free_tvs = filterOut isCoVar $
tyCoVarsOfWCList wanted
; traceTc "reportUnsolved (after zonking):" $
vcat [ text "Free tyvars:" <+> pprTyVars free_tvs
, text "Tidy env:" <+> ppr tidy_env
, text "Wanted:" <+> ppr wanted ]
; warn_redundant <- woptM Opt_WarnRedundantConstraints
; exp_syns <- goptM Opt_PrintExpandedSynonyms
; let err_ctxt = CEC { cec_encl = []
, cec_tidy = tidy_env
, cec_defer_type_errors = type_errors
, cec_expr_holes = expr_holes
, cec_type_holes = type_holes
, cec_out_of_scope_holes = out_of_scope_holes
, cec_suppress = insolubleWC wanted
, cec_warn_redundant = warn_redundant
, cec_expand_syns = exp_syns
, cec_binds = binds_var }
; tc_lvl <- getTcLevel
; reportWanteds err_ctxt tc_lvl wanted
; traceTc "reportUnsolved }" empty }
data Report
= Report { report_important :: [SDoc]
, report_relevant_bindings :: [SDoc]
, report_valid_hole_fits :: [SDoc]
}
instance Outputable Report where
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 ]
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.<>)
important :: SDoc -> Report
important doc = mempty { report_important = [doc] }
mk_relevant_bindings :: SDoc -> Report
mk_relevant_bindings doc = mempty { report_relevant_bindings = [doc] }
valid_hole_fits :: SDoc -> Report
valid_hole_fits docs = mempty { report_valid_hole_fits = [docs] }
data TypeErrorChoice
= TypeError
| TypeWarn WarnReason
| TypeDefer
data HoleChoice
= HoleError
| HoleWarn
| HoleDefer
instance Outputable HoleChoice where
ppr HoleError = text "HoleError"
ppr HoleWarn = text "HoleWarn"
ppr HoleDefer = text "HoleDefer"
instance Outputable TypeErrorChoice where
ppr TypeError = text "TypeError"
ppr (TypeWarn reason) = text "TypeWarn" <+> ppr reason
ppr TypeDefer = text "TypeDefer"
data ReportErrCtxt
= CEC { cec_encl :: [Implication]
, cec_tidy :: TidyEnv
, cec_binds :: EvBindsVar
, cec_defer_type_errors :: TypeErrorChoice
, cec_expr_holes :: HoleChoice
, cec_type_holes :: HoleChoice
, cec_out_of_scope_holes :: HoleChoice
, cec_warn_redundant :: Bool
, cec_expand_syns :: Bool
, cec_suppress :: Bool
}
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 ])
deferringAnyBindings :: ReportErrCtxt -> Bool
deferringAnyBindings (CEC { cec_defer_type_errors = TypeError
, cec_expr_holes = HoleError
, cec_out_of_scope_holes = HoleError }) = False
deferringAnyBindings _ = True
maybeSwitchOffDefer :: EvBindsVar -> ReportErrCtxt -> ReportErrCtxt
maybeSwitchOffDefer evb ctxt
| CoEvBindsVar{} <- evb
= ctxt { cec_defer_type_errors = TypeError
, cec_expr_holes = HoleError
, cec_out_of_scope_holes = HoleError }
| otherwise
= ctxt
reportImplic :: ReportErrCtxt -> Implication -> TcM ()
reportImplic ctxt implic@(Implic { ic_skols = tvs
, ic_given = given
, ic_wanted = wanted, ic_binds = evb
, ic_status = status, ic_info = info
, ic_tclvl = tc_lvl })
| BracketSkol <- info
, not insoluble
= return ()
| otherwise
= do { traceTc "reportImplic" (ppr implic')
; when bad_telescope $ reportBadTelescope ctxt tcl_env info tvs
; reportWanteds ctxt' tc_lvl wanted
; when (cec_warn_redundant ctxt) $
warnRedundantConstraints ctxt' tcl_env info' dead_givens }
where
tcl_env = ic_env implic
insoluble = isInsolubleStatus status
(env1, tvs') = mapAccumL tidyVarBndr (cec_tidy ctxt) $
scopedSort tvs
info' = tidySkolemInfo env1 info
implic' = implic { ic_skols = tvs'
, ic_given = map (tidyEvVar env1) given
, ic_info = info' }
ctxt1 = maybeSwitchOffDefer evb ctxt
ctxt' = ctxt1 { cec_tidy = env1
, cec_encl = implic' : cec_encl ctxt
, cec_suppress = insoluble || cec_suppress ctxt
, cec_binds = evb }
dead_givens = case status of
IC_Solved { ics_dead = dead } -> dead
_ -> []
bad_telescope = case status of
IC_BadTelescope -> True
_ -> False
warnRedundantConstraints :: ReportErrCtxt -> TcLclEnv -> SkolemInfo -> [EvVar] -> TcM ()
warnRedundantConstraints ctxt env info ev_vars
| null redundant_evs
= return ()
| SigSkol {} <- info
= setLclEnv env $
addErrCtxt (text "In" <+> ppr info) $
do { env <- getLclEnv
; msg <- mkErrorReport ctxt env (important doc)
; reportWarning (Reason Opt_WarnRedundantConstraints) msg }
| otherwise
= do { msg <- mkErrorReport ctxt env (important doc)
; reportWarning (Reason Opt_WarnRedundantConstraints) msg }
where
doc = text "Redundant constraint" <> plural redundant_evs <> colon
<+> pprEvVarTheta redundant_evs
redundant_evs =
filterOut is_type_error $
case info of
InstSkol -> filterOut (improving . idType) ev_vars
_ -> ev_vars
is_type_error = isJust . userTypeError_maybe . idType
improving pred
= any isImprovementPred (pred : transSuperClasses pred)
reportBadTelescope :: ReportErrCtxt -> TcLclEnv -> SkolemInfo -> [TcTyVar] -> TcM ()
reportBadTelescope ctxt env (ForAllSkol telescope) skols
= do { msg <- mkErrorReport ctxt env (important doc)
; reportError 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
reportBadTelescope _ _ skol_info skols
= pprPanic "reportBadTelescope" (ppr skol_info $$ ppr skols)
reportWanteds :: ReportErrCtxt -> TcLevel -> WantedConstraints -> TcM ()
reportWanteds ctxt tc_lvl (WC { wc_simple = simples, wc_impl = implics
, wc_holes = holes })
= do { traceTc "reportWanteds" (vcat [ text "Simples =" <+> ppr simples
, text "Suppress =" <+> ppr (cec_suppress ctxt)
, text "tidy_cts =" <+> ppr tidy_cts
, text "tidy_holes = " <+> ppr tidy_holes ])
; let (out_of_scope, other_holes) = partition isOutOfScopeHole tidy_holes
ctxt_for_scope_errs = ctxt { cec_suppress = False }
; (_, no_out_of_scope) <- askNoErrs $
reportHoles tidy_cts ctxt_for_scope_errs out_of_scope
; let ctxt_for_insols = ctxt { cec_suppress = not no_out_of_scope }
; reportHoles tidy_cts ctxt_for_insols other_holes
; (ctxt1, cts1) <- tryReporters ctxt_for_insols report1 tidy_cts
; let ctxt2 = ctxt { cec_suppress = cec_suppress ctxt || cec_suppress ctxt1 }
; (_, leftovers) <- tryReporters ctxt2 report2 cts1
; MASSERT2( null leftovers, ppr leftovers )
; mapBagM_ (reportImplic ctxt2) implics }
where
env = cec_tidy ctxt
tidy_cts = bagToList (mapBag (tidyCt env) simples)
tidy_holes = bagToList (mapBag (tidyHole env) holes)
report1 = [ ("custom_error", unblocked is_user_type_error, True, mkUserTypeErrorReporter)
, given_eq_spec
, ("insoluble2", unblocked utterly_wrong, True, mkGroupReporter mkEqErr)
, ("skolem eq1", unblocked very_wrong, True, mkSkolReporter)
, ("skolem eq2", unblocked skolem_eq, True, mkSkolReporter)
, ("non-tv eq", unblocked non_tv_eq, True, mkSkolReporter)
, ("Homo eqs", unblocked is_homo_equality, True, mkGroupReporter mkEqErr)
, ("Other eqs", unblocked is_equality, True, mkGroupReporter mkEqErr)
, ("Blocked eqs", is_equality, False, mkSuppressReporter mkBlockedEqErr)]
report2 = [ ("Implicit params", is_ip, False, mkGroupReporter mkIPErr)
, ("Irreds", is_irred, False, mkGroupReporter mkIrredErr)
, ("Dicts", is_dict, False, mkGroupReporter mkDictErr) ]
unblocked :: (Ct -> Pred -> Bool) -> Ct -> Pred -> Bool
unblocked _ (CIrredCan { cc_status = BlockedCIS {}}) _ = False
unblocked checker ct pred = checker ct pred
is_dict, is_equality, is_ip, is_irred :: Ct -> Pred -> Bool
is_given_eq ct pred
| EqPred {} <- pred = arisesFromGivens ct
| otherwise = False
utterly_wrong _ (EqPred NomEq ty1 ty2) = isRigidTy ty1 && isRigidTy ty2
utterly_wrong _ _ = False
very_wrong _ (EqPred NomEq ty1 ty2) = isSkolemTy tc_lvl ty1 && isRigidTy ty2
very_wrong _ _ = False
skolem_eq _ (EqPred NomEq ty1 _) = isSkolemTy tc_lvl ty1
skolem_eq _ _ = False
non_tv_eq _ (EqPred NomEq ty1 _) = not (isTyVarTy ty1)
non_tv_eq _ _ = False
is_user_type_error ct _ = isUserTypeErrorCt ct
is_homo_equality _ (EqPred _ ty1 ty2) = tcTypeKind ty1 `tcEqType` tcTypeKind ty2
is_homo_equality _ _ = False
is_equality _ (EqPred {}) = True
is_equality _ _ = False
is_dict _ (ClassPred {}) = True
is_dict _ _ = False
is_ip _ (ClassPred cls _) = isIPClass cls
is_ip _ _ = False
is_irred _ (IrredPred {}) = True
is_irred _ _ = False
given_eq_spec
| has_gadt_match (cec_encl ctxt)
= ("insoluble1a", is_given_eq, True, mkGivenErrorReporter)
| otherwise
= ("insoluble1b", is_given_eq, False, ignoreErrorReporter)
has_gadt_match [] = False
has_gadt_match (implic : implics)
| PatSkol {} <- ic_info implic
, ic_given_eqs implic /= NoGivenEqs
, ic_warn_inaccessible implic
= True
| otherwise
= has_gadt_match implics
isSkolemTy :: TcLevel -> Type -> Bool
isSkolemTy tc_lvl ty
| Just tv <- getTyVar_maybe ty
= isSkolemTyVar tv
|| (isTyVarTyVar tv && isTouchableMetaTyVar tc_lvl tv)
| otherwise
= False
isTyFun_maybe :: Type -> Maybe TyCon
isTyFun_maybe ty = case tcSplitTyConApp_maybe ty of
Just (tc,_) | isTypeFamilyTyCon tc -> Just tc
_ -> Nothing
type Reporter
= ReportErrCtxt -> [Ct] -> TcM ()
type ReporterSpec
= ( String
, Ct -> Pred -> Bool
, Bool
, Reporter)
mkSkolReporter :: Reporter
mkSkolReporter ctxt cts
= mapM_ (reportGroup mkEqErr ctxt) (group cts)
where
group [] = []
group (ct:cts) = (ct : yeses) : group noes
where
(yeses, noes) = partition (group_with ct) cts
group_with ct1 ct2
| EQ <- cmp_loc ct1 ct2 = True
| eq_lhs_type ct1 ct2 = True
| otherwise = False
reportHoles :: [Ct]
-> ReportErrCtxt -> [Hole] -> TcM ()
reportHoles tidy_cts ctxt
= mapM_ $ \hole -> unless (ignoreThisHole ctxt hole) $
do { err <- mkHoleError tidy_cts ctxt hole
; maybeReportHoleError ctxt hole err
; maybeAddDeferredHoleBinding ctxt err hole }
ignoreThisHole :: ReportErrCtxt -> Hole -> Bool
ignoreThisHole ctxt hole
= case hole_sort hole of
ExprHole {} -> False
TypeHole -> ignore_type_hole
ConstraintHole -> ignore_type_hole
where
ignore_type_hole = case cec_type_holes ctxt of
HoleDefer -> True
_ -> False
mkUserTypeErrorReporter :: Reporter
mkUserTypeErrorReporter ctxt
= mapM_ $ \ct -> do { err <- mkUserTypeError ctxt ct
; maybeReportError ctxt err
; addDeferredBinding ctxt err ct }
mkUserTypeError :: ReportErrCtxt -> Ct -> TcM (MsgEnvelope DecoratedSDoc)
mkUserTypeError ctxt ct = mkErrorMsgFromCt ctxt ct
$ important
$ pprUserTypeErrorTy
$ case getUserTypeErrorMsg ct of
Just msg -> msg
Nothing -> pprPanic "mkUserTypeError" (ppr ct)
mkGivenErrorReporter :: Reporter
mkGivenErrorReporter ctxt cts
= do { (ctxt, binds_msg, ct) <- relevantBindings True ctxt ct
; dflags <- getDynFlags
; let (implic:_) = cec_encl ctxt
ct' = setCtLoc ct (setCtLocEnv (ctLoc ct) (ic_env implic))
inaccessible_msg = hang (text "Inaccessible code in")
2 (ppr (ic_info implic))
report = important inaccessible_msg `mappend`
mk_relevant_bindings binds_msg
; err <- mkEqErr_help dflags ctxt report ct' ty1 ty2
; traceTc "mkGivenErrorReporter" (ppr ct)
; reportWarning (Reason Opt_WarnInaccessibleCode) err }
where
(ct : _ ) = cts
(ty1, ty2) = getEqPredTys (ctPred ct)
ignoreErrorReporter :: Reporter
ignoreErrorReporter ctxt cts
= do { traceTc "mkGivenErrorReporter no" (ppr cts $$ ppr (cec_encl ctxt))
; return () }
mkGroupReporter :: (ReportErrCtxt -> [Ct] -> TcM (MsgEnvelope DecoratedSDoc))
-> Reporter
mkGroupReporter mk_err ctxt cts
= mapM_ (reportGroup mk_err ctxt . toList) (equivClasses cmp_loc cts)
mkSuppressReporter :: (ReportErrCtxt -> [Ct] -> TcM (MsgEnvelope DecoratedSDoc)) -> Reporter
mkSuppressReporter mk_err ctxt cts
= mapM_ (suppressGroup mk_err ctxt . toList) (equivClasses cmp_loc cts)
eq_lhs_type :: Ct -> Ct -> Bool
eq_lhs_type ct1 ct2
= case (classifyPredType (ctPred ct1), classifyPredType (ctPred ct2)) of
(EqPred eq_rel1 ty1 _, EqPred eq_rel2 ty2 _) ->
(eq_rel1 == eq_rel2) && (ty1 `eqType` ty2)
_ -> pprPanic "mkSkolReporter" (ppr ct1 $$ ppr ct2)
cmp_loc :: Ct -> Ct -> Ordering
cmp_loc ct1 ct2 = get ct1 `compare` get ct2
where
get ct = realSrcSpanStart (ctLocSpan (ctLoc ct))
reportGroup :: (ReportErrCtxt -> [Ct] -> TcM (MsgEnvelope DecoratedSDoc)) -> Reporter
reportGroup mk_err ctxt cts =
ASSERT( not (null cts))
do { err <- mk_err ctxt cts
; traceTc "About to maybeReportErr" $
vcat [ text "Constraint:" <+> ppr cts
, text "cec_suppress =" <+> ppr (cec_suppress ctxt)
, text "cec_defer_type_errors =" <+> ppr (cec_defer_type_errors ctxt) ]
; maybeReportError ctxt err
; traceTc "reportGroup" (ppr cts)
; mapM_ (addDeferredBinding ctxt err) cts }
suppressGroup :: (ReportErrCtxt -> [Ct] -> TcM (MsgEnvelope DecoratedSDoc)) -> Reporter
suppressGroup mk_err ctxt cts
= do { err <- mk_err ctxt cts
; traceTc "Suppressing errors for" (ppr cts)
; mapM_ (addDeferredBinding ctxt err) cts }
maybeReportHoleError :: ReportErrCtxt -> Hole -> MsgEnvelope DecoratedSDoc -> TcM ()
maybeReportHoleError ctxt hole err
| isOutOfScopeHole hole
=
case cec_out_of_scope_holes ctxt of
HoleError -> reportError err
HoleWarn ->
reportWarning (Reason Opt_WarnDeferredOutOfScopeVariables) err
HoleDefer -> return ()
maybeReportHoleError ctxt (Hole { hole_sort = hole_sort }) err
| case hole_sort of TypeHole -> True
ConstraintHole -> True
_ -> False
=
case cec_type_holes ctxt of
HoleError -> reportError err
HoleWarn -> reportWarning (Reason Opt_WarnPartialTypeSignatures) err
HoleDefer -> return ()
maybeReportHoleError ctxt hole err
=
ASSERT( not (isOutOfScopeHole hole) )
case cec_expr_holes ctxt of
HoleError -> reportError err
HoleWarn -> reportWarning (Reason Opt_WarnTypedHoles) err
HoleDefer -> return ()
maybeReportError :: ReportErrCtxt -> MsgEnvelope DecoratedSDoc -> TcM ()
maybeReportError ctxt err
| cec_suppress ctxt
= return ()
| otherwise
= case cec_defer_type_errors ctxt of
TypeDefer -> return ()
TypeWarn reason -> reportWarning reason err
TypeError -> reportError err
addDeferredBinding :: ReportErrCtxt -> MsgEnvelope DecoratedSDoc -> Ct -> TcM ()
addDeferredBinding ctxt err ct
| deferringAnyBindings ctxt
, CtWanted { ctev_pred = pred, ctev_dest = dest } <- ctEvidence ct
= do { dflags <- getDynFlags
; let err_tm = mkErrorTerm dflags pred err
ev_binds_var = cec_binds ctxt
; case dest of
EvVarDest evar
-> addTcEvBind ev_binds_var $ mkWantedEvBind evar err_tm
HoleDest hole
-> do {
let co_var = coHoleCoVar hole
; addTcEvBind ev_binds_var $ mkWantedEvBind co_var err_tm
; fillCoercionHole hole (mkTcCoVarCo co_var) }}
| otherwise
= return ()
mkErrorTerm :: DynFlags -> Type
-> MsgEnvelope DecoratedSDoc -> EvTerm
mkErrorTerm dflags ty err = evDelayedError ty err_fs
where
err_msg = pprLocMsgEnvelope err
err_fs = mkFastString $ showSDoc dflags $
err_msg $$ text "(deferred type error)"
maybeAddDeferredHoleBinding :: ReportErrCtxt -> MsgEnvelope DecoratedSDoc -> Hole -> TcM ()
maybeAddDeferredHoleBinding ctxt err (Hole { hole_sort = ExprHole (HER ref ref_ty _) })
| deferringAnyBindings ctxt
= do { dflags <- getDynFlags
; let err_tm = mkErrorTerm dflags ref_ty err
; writeMutVar ref err_tm }
| otherwise
= return ()
maybeAddDeferredHoleBinding _ _ (Hole { hole_sort = TypeHole })
= return ()
maybeAddDeferredHoleBinding _ _ (Hole { hole_sort = ConstraintHole })
= return ()
tryReporters :: ReportErrCtxt -> [ReporterSpec] -> [Ct] -> TcM (ReportErrCtxt, [Ct])
tryReporters ctxt reporters cts
= do { let (vis_cts, invis_cts) = partition (isVisibleOrigin . ctOrigin) cts
; traceTc "tryReporters {" (ppr vis_cts $$ ppr invis_cts)
; (ctxt', cts') <- go ctxt reporters vis_cts invis_cts
; traceTc "tryReporters }" (ppr cts')
; return (ctxt', cts') }
where
go ctxt [] vis_cts invis_cts
= return (ctxt, vis_cts ++ invis_cts)
go ctxt (r : rs) vis_cts invis_cts
= do { (ctxt', vis_cts') <- tryReporter ctxt r vis_cts
; (ctxt'', invis_cts') <- tryReporter ctxt' r invis_cts
; go ctxt'' rs vis_cts' invis_cts' }
tryReporter :: ReportErrCtxt -> ReporterSpec -> [Ct] -> TcM (ReportErrCtxt, [Ct])
tryReporter ctxt (str, keep_me, suppress_after, reporter) cts
| null yeses
= return (ctxt, cts)
| otherwise
= do { traceTc "tryReporter{ " (text str <+> ppr yeses)
; (_, no_errs) <- askNoErrs (reporter ctxt yeses)
; let suppress_now = not no_errs && suppress_after
ctxt' = ctxt { cec_suppress = suppress_now || cec_suppress ctxt }
; traceTc "tryReporter end }" (text str <+> ppr (cec_suppress ctxt) <+> ppr suppress_after)
; return (ctxt', nos) }
where
(yeses, nos) = partition (\ct -> keep_me ct (classifyPredType (ctPred ct))) cts
pprArising :: CtOrigin -> SDoc
pprArising (TypeEqOrigin {}) = empty
pprArising (KindEqOrigin {}) = empty
pprArising (GivenOrigin {}) = empty
pprArising orig = pprCtOrigin orig
addArising :: CtOrigin -> SDoc -> SDoc
addArising orig msg = hang msg 2 (pprArising orig)
pprWithArising :: [Ct] -> (CtLoc, SDoc)
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'))
mkErrorMsgFromCt :: ReportErrCtxt -> Ct -> Report -> TcM (MsgEnvelope DecoratedSDoc)
mkErrorMsgFromCt ctxt ct report
= mkErrorReport ctxt (ctLocEnv (ctLoc ct)) report
mkErrorReport :: ReportErrCtxt -> TcLclEnv -> Report -> TcM (MsgEnvelope DecoratedSDoc)
mkErrorReport ctxt tcl_env (Report important relevant_bindings valid_subs)
= do { context <- mkErrInfo (cec_tidy ctxt) (tcl_ctxt tcl_env)
; mkDecoratedSDocAt (RealSrcSpan (tcl_loc tcl_env) Nothing)
(vcat important)
context
(vcat $ relevant_bindings ++ valid_subs)
}
type UserGiven = Implication
getUserGivens :: ReportErrCtxt -> [UserGiven]
getUserGivens (CEC {cec_encl = implics}) = getUserGivensFromImplics implics
getUserGivensFromImplics :: [Implication] -> [UserGiven]
getUserGivensFromImplics implics
= reverse (filterOut (null . ic_given) implics)
mkIrredErr :: ReportErrCtxt -> [Ct] -> TcM (MsgEnvelope DecoratedSDoc)
mkIrredErr ctxt cts
= do { (ctxt, binds_msg, ct1) <- relevantBindings True ctxt ct1
; let orig = ctOrigin ct1
msg = couldNotDeduce (getUserGivens ctxt) (map ctPred cts, orig)
; mkErrorMsgFromCt ctxt ct1 $
msg `mappend` mk_relevant_bindings binds_msg }
where
(ct1:_) = cts
mkHoleError :: [Ct] -> ReportErrCtxt -> Hole -> TcM (MsgEnvelope DecoratedSDoc)
mkHoleError _tidy_simples _ctxt hole@(Hole { hole_occ = occ
, hole_ty = hole_ty
, hole_loc = ct_loc })
| isOutOfScopeHole hole
= do { dflags <- getDynFlags
; rdr_env <- getGlobalRdrEnv
; imp_info <- getImports
; curr_mod <- getModule
; hpt <- getHpt
; mkDecoratedSDocAt (RealSrcSpan (tcl_loc lcl_env) Nothing)
out_of_scope_msg O.empty
(unknownNameSuggestions dflags hpt curr_mod rdr_env
(tcl_rdr lcl_env) imp_info (mkRdrUnqual occ)) }
where
herald | isDataOcc occ = text "Data constructor not in scope:"
| otherwise = text "Variable not in scope:"
out_of_scope_msg
| 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
mkHoleError tidy_simples ctxt hole@(Hole { hole_occ = occ
, hole_ty = hole_ty
, hole_sort = sort
, hole_loc = ct_loc })
= do { (ctxt, binds_msg)
<- relevant_bindings False ctxt lcl_env (tyCoVarsOfType hole_ty)
; show_hole_constraints <- goptM Opt_ShowHoleConstraints
; let constraints_msg
| ExprHole _ <- sort, show_hole_constraints
= givenConstraintsMsg 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)
; mkErrorReport ctxt lcl_env $
important hole_msg `mappend`
mk_relevant_bindings (binds_msg $$ constraints_msg) `mappend`
valid_hole_fits sub_msg }
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)
, tyvars_msg, type_hole_hint ]
pp_hole_type_with_kind
| isLiftedTypeKind hole_kind
|| isCoVarType hole_ty
= 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
type_hole_hint
| HoleError <- cec_type_holes ctxt
= text "To use the inferred type, enable PartialTypeSignatures"
| otherwise
= empty
expr_hole_hint
| lengthFS (occNameFS occ) > 1
= 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
| otherwise
= ppWhenOption sdocPrintExplicitCoercions $
quotes (ppr tv) <+> text "is a coercion variable"
pp_occ_with_type :: OccName -> Type -> SDoc
pp_occ_with_type occ hole_ty = hang (pprPrefixOcc occ) 2 (dcolon <+> pprType hole_ty)
validHoleFits :: ReportErrCtxt
-> [Ct]
-> Hole
-> TcM (ReportErrCtxt, SDoc)
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) }
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)
mkIPErr :: ReportErrCtxt -> [Ct] -> TcM (MsgEnvelope DecoratedSDoc)
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)
; mkErrorMsgFromCt ctxt ct1 $
msg `mappend` mk_relevant_bindings binds_msg }
where
(ct1:_) = cts
mkEqErr :: ReportErrCtxt -> [Ct] -> TcM (MsgEnvelope DecoratedSDoc)
mkEqErr ctxt (ct:_) = mkEqErr1 ctxt ct
mkEqErr _ [] = panic "mkEqErr"
mkEqErr1 :: ReportErrCtxt -> Ct -> TcM (MsgEnvelope DecoratedSDoc)
mkEqErr1 ctxt ct
= 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
; dflags <- getDynFlags
; traceTc "mkEqErr1" (ppr ct $$ pprCtOrigin (ctOrigin ct))
; let report = mconcat [ important coercible_msg
, mk_relevant_bindings binds_msg]
; mkEqErr_help dflags ctxt report ct ty1 ty2 }
where
(ty1, ty2) = getEqPredTys (ctPred ct)
mkCoercibleExplanation :: GlobalRdrEnv -> FamInstEnvs
-> TcType -> TcType -> SDoc
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 (tc, tys) <- splitTyConApp_maybe ty2
, (rep_tc, _, _) <- tcLookupDataFamInst fam_envs tc tys
, Just msg <- coercible_msg_for_tycon rep_tc
= 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")
| otherwise
= empty
where
coercible_msg_for_tycon tc
| isAbstractTyCon tc
= Just $ hsep [ text "NB: The type constructor"
, quotes (pprSourceTyCon tc)
, text "is abstract" ]
| 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" ])
| otherwise = Nothing
has_unknown_roles ty
| Just (tc, tys) <- tcSplitTyConApp_maybe ty
= tys `lengthAtLeast` tyConArity tc
| Just (s, _) <- tcSplitAppTy_maybe ty
= has_unknown_roles s
| isTyVarTy ty
= True
| otherwise
= False
mkEqErr_help :: DynFlags -> ReportErrCtxt -> Report
-> Ct
-> TcType -> TcType -> TcM (MsgEnvelope DecoratedSDoc)
mkEqErr_help dflags ctxt report ct ty1 ty2
| Just (tv1, _) <- tcGetCastedTyVar_maybe ty1
= mkTyVarEqErr dflags ctxt report ct tv1 ty2
| Just (tv2, _) <- tcGetCastedTyVar_maybe ty2
= mkTyVarEqErr dflags ctxt report ct tv2 ty1
| otherwise
= reportEqErr ctxt report ct ty1 ty2
reportEqErr :: ReportErrCtxt -> Report
-> Ct
-> TcType -> TcType -> TcM (MsgEnvelope DecoratedSDoc)
reportEqErr ctxt report ct ty1 ty2
= mkErrorMsgFromCt ctxt ct (mconcat [misMatch, report, eqInfo])
where
misMatch = misMatchOrCND False ctxt ct ty1 ty2
eqInfo = mkEqInfoMsg ct ty1 ty2
mkTyVarEqErr, mkTyVarEqErr'
:: DynFlags -> ReportErrCtxt -> Report -> Ct
-> TcTyVar -> TcType -> TcM (MsgEnvelope DecoratedSDoc)
mkTyVarEqErr dflags ctxt report ct tv1 ty2
= do { traceTc "mkTyVarEqErr" (ppr ct $$ ppr tv1 $$ ppr ty2)
; mkTyVarEqErr' dflags ctxt report ct tv1 ty2 }
mkTyVarEqErr' dflags ctxt report ct tv1 ty2
| isSkolemTyVar tv1
|| isTyVarTyVar tv1 && not (isTyVarTy ty2)
|| ctEqRel ct == ReprEq
= mkErrorMsgFromCt ctxt ct $ mconcat
[ headline_msg
, extraTyVarEqInfo ctxt tv1 ty2
, suggestAddSig ctxt ty1 ty2
, report
]
| CTE_Occurs <- occ_check_expand
= do { let extra2 = mkEqInfoMsg 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)
; mkErrorMsgFromCt ctxt ct $
mconcat [headline_msg, extra2, extra3, report] }
| CTE_Bad <- occ_check_expand
= do { let msg = vcat [ text "Cannot instantiate unification variable"
<+> quotes (ppr tv1)
, hang (text "with a" <+> what <+> text "involving polytypes:") 2 (ppr ty2) ]
; mkErrorMsgFromCt ctxt ct $ mconcat [ headline_msg, important msg, report ] }
| (implic:_) <- cec_encl ctxt
, Implic { ic_skols = skols } <- implic
, tv1 `elem` skols
= mkErrorMsgFromCt ctxt ct $ mconcat
[ misMatchMsg ctxt ct ty1 ty2
, extraTyVarEqInfo ctxt tv1 ty2
, report
]
| (implic:_) <- cec_encl ctxt
, Implic { ic_skols = skols, ic_info = skol_info } <- implic
, let esc_skols = filter (`elemVarSet` (tyCoVarsOfType ty2)) skols
, not (null esc_skols)
= do { 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)) ] ]
; mkErrorMsgFromCt ctxt ct (mconcat [msg, tv_extra, report]) }
| (implic:_) <- cec_encl ctxt
, Implic { ic_given = given, ic_tclvl = lvl, ic_info = skol_info } <- implic
= ASSERT2( not (isTouchableMetaTyVar lvl tv1)
, ppr tv1 $$ ppr lvl )
do { 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
; mkErrorMsgFromCt ctxt ct $ mconcat
[msg, tclvl_extra, tv_extra, add_sig, report] }
| otherwise
= reportEqErr ctxt report ct (mkTyVarTy tv1) ty2
where
headline_msg = misMatchOrCND insoluble_occurs_check ctxt ct ty1 ty2
ty1 = mkTyVarTy tv1
occ_check_expand = occCheckForErrors dflags tv1 ty2
insoluble_occurs_check = isInsolubleOccursCheck (ctEqRel ct) tv1 ty2
what = text $ levelString $
ctLocTypeOrKind_maybe (ctLoc ct) `orElse` TypeLevel
levelString :: TypeOrKind -> String
levelString TypeLevel = "type"
levelString KindLevel = "kind"
mkEqInfoMsg :: Ct -> TcType -> TcType -> Report
mkEqInfoMsg ct ty1 ty2
= important (tyfun_msg $$ ambig_msg)
where
mb_fun1 = isTyFun_maybe ty1
mb_fun2 = isTyFun_maybe ty2
ambig_msg | isJust mb_fun1 || isJust mb_fun2
= snd (mkAmbigMsg False ct)
| otherwise = empty
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
misMatchOrCND :: Bool -> ReportErrCtxt -> Ct
-> TcType -> TcType -> Report
misMatchOrCND insoluble_occurs_check ctxt ct ty1 ty2
| insoluble_occurs_check
|| (isRigidTy ty1 && isRigidTy ty2)
|| isGivenCt ct
|| null givens
=
misMatchMsg ctxt ct ty1 ty2
| otherwise
= mconcat [ couldNotDeduce givens ([eq_pred], orig)
, important $ mk_supplementary_ea_msg ctxt level ty1 ty2 orig ]
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 ]
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))
2 (sep [ text "bound by" <+> ppr skol_info
, text "at" <+> ppr (tcl_loc (ic_env implic)) ])
mkBlockedEqErr :: ReportErrCtxt -> [Ct] -> TcM (MsgEnvelope DecoratedSDoc)
mkBlockedEqErr ctxt (ct:_) = mkErrorMsgFromCt ctxt ct report
where
report = important msg
msg = vcat [ hang (text "Cannot use equality for substitution:")
2 (ppr (ctPred ct))
, text "Doing so would be ill-kinded." ]
mkBlockedEqErr _ [] = panic "mkBlockedEqErr no constraints"
extraTyVarEqInfo :: ReportErrCtxt -> TcTyVar -> TcType -> Report
extraTyVarEqInfo ctxt tv1 ty2
= important (extraTyVarInfo ctxt 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
= ASSERT2( 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
suggestAddSig ctxt ty1 _ty2
| null inferred_bndrs
= mempty
| [bndr] <- inferred_bndrs
= important $ text "Possible fix: add a type signature for" <+> quotes (ppr bndr)
| otherwise
= important $ text "Possible fix: add type signatures for some or all of" <+> (ppr inferred_bndrs)
where
inferred_bndrs = case tcGetTyVar_maybe ty1 of
Just tv | isSkolemTyVar tv -> find (cec_encl ctxt) False tv
_ -> []
find [] _ _ = []
find (implic:implics) seen_eqs tv
| tv `elem` ic_skols implic
, InferSkol prs <- ic_info implic
, seen_eqs
= map fst prs
| otherwise
= find implics (seen_eqs || ic_given_eqs implic /= NoGivenEqs) tv
misMatchMsg :: ReportErrCtxt -> Ct -> TcType -> TcType -> Report
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
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
=
sep [ text herald1 <+> quotes (ppr ty1)
, nest padding $
text herald2 <+> quotes (ppr ty2) ]
| otherwise
=
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 })
| 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
|
ea_looks_same ty1 ty2 exp act
= mk_ea_msg ctxt (Just ct) level orig
| otherwise
= 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)
-> let n_act = count_args act
n_exp = count_args exp in
case n_act n_exp of
n | n > 0
, 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"
_ -> 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'
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
ea_looks_same ty1 ty2 exp act
= (act `looks_same` ty1 && exp `looks_same` ty2) ||
(exp `looks_same` ty1 && act `looks_same` ty2)
where
looks_same t1 t2 = t1 `pickyEqType` t2
|| t1 `eqType` liftedTypeKind && t2 `eqType` liftedTypeKind
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
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
, 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
pprWithExplicitKindsWhenMismatch :: Type -> Type -> CtOrigin
-> SDoc -> SDoc
pprWithExplicitKindsWhenMismatch ty1 ty2 ct
= pprWithExplicitKindsWhen show_kinds
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
expandSynonymsToMatch :: Type -> Type -> (Type, Type)
expandSynonymsToMatch ty1 ty2 = (ty1_ret, ty2_ret)
where
(ty1_ret, ty2_ret) = go ty1 ty2
go :: Type -> Type -> (Type, Type)
go t1 t2
| t1 `pickyEqType` t2 =
(t1, t2)
go (TyConApp tc1 tys1) (TyConApp tc2 tys2)
| tc1 == tc2
, tys1 `equalLength` tys2 =
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) =
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 =
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)
tyExpansions :: Type -> [Type]
tyExpansions = unfoldr (\t -> (\x -> (x, x)) `fmap` tcView t)
followExpansions :: [(Type, Type)] -> (Type, Type)
followExpansions [] = pprPanic "followExpansions" empty
followExpansions [(t1, t2)]
| sameShapes t1 t2 = go t1 t2
| otherwise = (t1, t2)
followExpansions ((t1, t2) : tss)
| sameShapes t1 t2 = go t1 t2
| 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
sameOccExtra ty1 ty2
| Just (tc1, _) <- tcSplitTyConApp_maybe ty1
, Just (tc2, _) <- tcSplitTyConApp_maybe ty2
, let n1 = tyConName tc1
n2 = tyConName tc2
same_occ = nameOccName n1 == nameOccName n2
same_pkg = moduleUnit (nameModule n1) == moduleUnit (nameModule n2)
, n1 /= n2
, same_occ
= text "NB:" <+> (ppr_from same_pkg n1 $$ ppr_from same_pkg n2)
| otherwise
= empty
where
ppr_from same_pkg nm
| isGoodSrcSpan loc
= hang (quotes (ppr nm) <+> text "is defined at")
2 (ppr loc)
| otherwise
= 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
mkDictErr :: ReportErrCtxt -> [Ct] -> TcM (MsgEnvelope DecoratedSDoc)
mkDictErr ctxt cts
= ASSERT( not (null cts) )
do { inst_envs <- tcGetInstEnvs
; let (ct1:_) = cts
min_cts = elim_superclasses cts
lookups = map (lookup_cls_inst inst_envs) min_cts
(no_inst_cts, overlap_cts) = partition is_no_inst lookups
; (ctxt, err) <- mk_dict_err ctxt (head (no_inst_cts ++ overlap_cts))
; mkErrorMsgFromCt ctxt ct1 (important err) }
where
no_givens = null (getUserGivens ctxt)
is_no_inst (ct, (matches, unifiers, _))
= no_givens
&& null matches
&& (null unifiers || all (not . isAmbiguousTyVar) (tyCoVarsOfCtList ct))
lookup_cls_inst inst_envs ct
= (ct, lookupInstEnv True inst_envs clas (flattenTys emptyInScopeSet tys))
where
(clas, tys) = getClassPredTys (ctPred ct)
elim_superclasses cts = mkMinimalBySCs ctPred cts
mk_dict_err :: ReportErrCtxt -> (Ct, ClsInstLookupResult)
-> TcM (ReportErrCtxt, SDoc)
mk_dict_err ctxt@(CEC {cec_encl = implics}) (ct, (matches, unifiers, unsafe_overlapped))
| null matches
= do { (ctxt, binds_msg, ct) <- relevantBindings True ctxt ct
; candidate_insts <- get_candidate_instances
; return (ctxt, cannot_resolve_msg ct candidate_insts binds_msg) }
| null unsafe_overlapped
= return (ctxt, overlap_msg)
| otherwise
= return (ctxt, 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)
get_candidate_instances :: TcM [ClsInst]
get_candidate_instances
| [ty] <- tys
= do { instEnvs <- tcGetInstEnvs
; return (filter (is_candidate_inst ty)
(classInstances instEnvs clas)) }
| otherwise = return []
is_candidate_inst ty inst
| [other_ty] <- is_tys inst
, Just (tc1, _) <- tcSplitTyConApp_maybe ty
, Just (tc2, _) <- tcSplitTyConApp_maybe other_ty
= let n1 = tyConName tc1
n2 = tyConName tc2
different_names = n1 /= n2
same_occ_names = nameOccName n1 == nameOccName n2
in different_names && same_occ_names
| otherwise = False
cannot_resolve_msg :: Ct -> [ClsInst] -> SDoc -> SDoc
cannot_resolve_msg ct candidate_insts binds_msg
= 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) $
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))) ]
where
orig = ctOrigin ct
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) $
sdocOption sdocPrintPotentialInstances $ \print_insts ->
getPprStyle $ \sty ->
pprPotentials (PrintPotentialInstances print_insts) sty potential_hdr unifiers
potential_hdr
= vcat [ ppWhen lead_with_ambig $
text "Probable fix: use a type annotation to specify what"
<+> pprQuotedList ambig_tvs <+> text "should be."
, text "These potential instance" <> plural unifiers
<+> text "exist:"]
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
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
, [_,ty] <- tys
, 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")
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)]
, sdocOption sdocPrintPotentialInstances $ \print_insts ->
getPprStyle $ \sty ->
pprPotentials (PrintPotentialInstances print_insts) sty (text "Matching instances:") $
ispecs ++ unifiers
, ppWhen (null matching_givens && isSingleton matches && null unifiers) $
sep [ text "There exists a (perhaps superclass) match:"
, nest 2 (vcat (pp_givens useful_givens))]
, ppWhen (isSingleton matches) $
parens (vcat [ text "The choice depends on the instantiation of" <+>
quotes (pprWithCommas ppr (tyCoVarsOfTypesList tys))
, ppWhen (null (matching_givens)) $
vcat [ text "To pick the first instance above, use IncoherentInstances"
, text "when compiling the other instance declarations"]
])]
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
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
| 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 implics pred
= go implics
where
pred_tvs = tyCoVarsOfType pred
go [] = []
go (ic : ics)
| implausible ic = rest
| otherwise = ic_info ic : rest
where
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
show_fixes :: [SDoc] -> SDoc
show_fixes [] = empty
show_fixes (f:fs) = sep [ text "Possible fix:"
, nest 2 (vcat (f : map (text "or" <+>) fs))]
newtype PrintPotentialInstances = PrintPotentialInstances Bool
pprPotentials :: PrintPotentialInstances -> PprStyle -> SDoc -> [ClsInst] -> SDoc
pprPotentials (PrintPotentialInstances show_potentials) sty herald insts
| null insts
= empty
| null show_these
= hang herald
2 (vcat [ not_in_scope_msg empty
, flag_hint ])
| otherwise
= hang herald
2 (vcat [ pprInstances show_these
, ppWhen (n_in_scope_hidden > 0) $
text "...plus"
<+> speakNOf n_in_scope_hidden (text "other")
, not_in_scope_msg (text "...plus")
, flag_hint ])
where
n_show = 3 :: Int
(in_scope, not_in_scope) = partition inst_in_scope insts
sorted = sortBy fuzzyClsInstCmp in_scope
show_these | show_potentials = sorted
| otherwise = take n_show sorted
n_in_scope_hidden = length sorted length show_these
inst_in_scope :: ClsInst -> Bool
inst_in_scope cls_inst = nameSetAll name_in_scope $
orphNamesOfTypes (is_tys cls_inst)
name_in_scope name
| isBuiltInSyntax name
= True
| 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_scope_msg herald
| null not_in_scope
= empty
| otherwise
= hang (herald <+> speakNOf (length not_in_scope) (text "instance")
<+> text "involving out-of-scope types")
2 (ppWhen show_potentials (pprInstances not_in_scope))
flag_hint = ppUnless (show_potentials || equalLength show_these insts) $
text "(use -fprint-potential-instances to see them all)"
mkAmbigMsg :: Bool
-> 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
|| 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
= text "Ambiguous" <+> what <+> text "variable"
<> plural tkvs <+> pprQuotedList tkvs
| otherwise
= 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)
= hang (pprQuotedList tvs)
2 (is_or_are tvs "an" "unknown")
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
where
tkvs = tyCoVarsOfCtList ct
ambig_tkvs = filter isAmbiguousTyVar tkvs
dep_tkv_set = tyCoVarsOfTypes (map tyVarKind tkvs)
getSkolemInfo :: [Implication] -> [TcTyVar]
-> [(SkolemInfo, [TcTyVar])]
getSkolemInfo _ []
= []
getSkolemInfo [] tvs
| all isRuntimeUnkSkol tvs = [(RuntimeUnkSkol, tvs)]
| otherwise = pprPanic "No skolem info:" (ppr tvs)
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 :: Bool
-> ReportErrCtxt -> Ct
-> TcM (ReportErrCtxt, SDoc, Ct)
relevantBindings want_filtering ctxt ct
= do { traceTc "relevantBindings" (ppr ct)
; (env1, tidy_orig) <- zonkTidyOrigin (cec_tidy ctxt) (ctLocOrigin loc)
; let extra_tvs = case tidy_orig of
KindEqOrigin t1 t2 _ _ -> tyCoVarsOfTypes [t1,t2]
_ -> emptyVarSet
ct_fvs = tyCoVarsOfCt ct `unionVarSet` extra_tvs
loc' = setCtLocOrigin loc tidy_orig
ct' = setCtLoc ct loc'
ctxt1 = ctxt { cec_tidy = env1 }
; (ctxt2, doc) <- relevant_bindings want_filtering ctxt1 lcl_env ct_fvs
; return (ctxt2, doc, ct') }
where
loc = ctLoc ct
lcl_env = ctLocEnv loc
relevant_bindings :: Bool
-> ReportErrCtxt
-> TcLclEnv
-> TyCoVarSet
-> TcM (ReportErrCtxt, SDoc)
relevant_bindings want_filtering ctxt lcl_env ct_tvs
= do { dflags <- getDynFlags
; traceTc "relevant_bindings" $
vcat [ ppr ct_tvs
, pprWithCommas id [ ppr id <+> dcolon <+> ppr (idType id)
| TcIdBndr id _ <- tcl_bndrs lcl_env ]
, pprWithCommas id
[ ppr id | TcIdBndr_ExpType id _ _ <- tcl_bndrs lcl_env ] ]
; (tidy_env', docs, discards)
<- go dflags (cec_tidy ctxt) (maxRelevantBinds dflags)
emptyVarSet [] False
(removeBindingShadowing $ tcl_bndrs lcl_env)
; let doc = ppUnless (null docs) $
hang (text "Relevant bindings include")
2 (vcat docs $$ ppWhen discards discardMsg)
ctxt' = ctxt { cec_tidy = tidy_env' }
; return (ctxt', doc) }
where
run_out :: Maybe Int -> Bool
run_out Nothing = False
run_out (Just n) = n <= 0
dec_max :: Maybe Int -> Maybe Int
dec_max = fmap (\n -> n 1)
go :: DynFlags -> TidyEnv -> Maybe Int -> TcTyVarSet -> [SDoc]
-> Bool
-> [TcBinder]
-> TcM (TidyEnv, [SDoc], Bool)
go _ tidy_env _ _ docs discards []
= return (tidy_env, reverse docs, discards)
go dflags tidy_env n_left tvs_seen docs discards (tc_bndr : tc_bndrs)
= case tc_bndr of
TcTvBndr {} -> discard_it
TcIdBndr id top_lvl -> go2 (idName id) (idType id) top_lvl
TcIdBndr_ExpType name et top_lvl ->
do { mb_ty <- readExpType_maybe et
; case mb_ty of
Just ty -> go2 name ty top_lvl
Nothing -> discard_it
}
where
discard_it = go dflags tidy_env n_left tvs_seen docs
discards tc_bndrs
go2 id_name id_type top_lvl
= do { (tidy_env', tidy_ty) <- zonkTidyTcType tidy_env id_type
; 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)))]
new_seen = tvs_seen `unionVarSet` id_tvs
; if (want_filtering && not (hasPprDebug dflags)
&& id_tvs `disjointVarSet` ct_tvs)
then discard_it
else if isTopLevel top_lvl && not (isNothing n_left)
then discard_it
else if run_out n_left && id_tvs `subVarSet` tvs_seen
then go dflags tidy_env n_left tvs_seen docs
True
tc_bndrs
else go dflags tidy_env' (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)"
warnDefaulting :: [Ct] -> Type -> TcM ()
warnDefaulting wanteds 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
(loc, ppr_wanteds) = pprWithArising tidy_wanteds
warn_msg =
hang (hsep [ text "Defaulting the following"
, text "constraint" <> plural tidy_wanteds
, text "to type"
, quotes (ppr default_ty) ])
2
ppr_wanteds
; setCtLocM loc $ warnTc (Reason Opt_WarnTypeDefaults) warn_default warn_msg }
solverDepthErrorTcS :: CtLoc -> TcType -> TcM a
solverDepthErrorTcS loc ty
= setCtLocM loc $
do { ty <- zonkTcType ty
; env0 <- tcInitTidyEnv
; let tidy_env = tidyFreeTyCoVars env0 (tyCoVarsOfTypeList ty)
tidy_ty = tidyType tidy_env ty
msg
= vcat [ text "Reduction stack overflow; size =" <+> ppr depth
, hang (text "When simplifying the following type:")
2 (ppr tidy_ty)
, note ]
; failWithTcM (tidy_env, msg) }
where
depth = ctLocDepth loc
note = vcat
[ text "Use -freduction-depth=0 to disable this check"
, text "(any upper bound you could choose might fail unpredictably with"
, text " minor updates to GHC, so disabling the check is recommended if"
, text " you're sure that type checking should terminate)" ]