\begin{code}
module TcErrors(
- reportUnsolved, reportUnsolvedImplication, reportUnsolvedDeriv,
- reportUnsolvedWantedEvVars, warnDefaulting, typeExtraInfoMsg,
+ reportUnsolved, reportUnsolvedDeriv,
+ reportUnsolvedWantedEvVars, warnDefaulting,
+ unifyCtxt, typeExtraInfoMsg,
kindErrorTcS, misMatchErrorTcS, flattenForAllErrorTcS,
occursCheckErrorTcS, solverDepthErrorTcS
) where
import Bag
import ListSetOps( equivClasses )
import Util
-import Unique
import FastString
import Outputable
import DynFlags
import StaticFlags( opt_PprStyle_Debug )
import Data.List( partition )
-import Control.Monad( unless )
+import Control.Monad( when, unless )
\end{code}
%************************************************************************
| isEmptyBag unsolved
= return ()
| otherwise
- = do { env0 <- tcInitTidyEnv
+ = do { unsolved <- mapBagM zonkWanted unsolved
+ -- Zonk to un-flatten any flatten-skols
+ ; env0 <- tcInitTidyEnv
; let tidy_env = tidyFreeTyVars env0 (tyVarsOfWanteds unsolved)
tidy_unsolved = tidyWanteds tidy_env unsolved
err_ctxt = CEC { cec_encl = []
where
unsolved = mkWantedConstraints unsolved_flats unsolved_implics
+
reportUnsolvedWantedEvVars :: Bag WantedEvVar -> TcM ()
reportUnsolvedWantedEvVars wanteds
| isEmptyBag wanteds
= return ()
| otherwise
- = do { env0 <- tcInitTidyEnv
+ = do { wanteds <- mapBagM zonkWantedEvVar wanteds
+ ; env0 <- tcInitTidyEnv
; let tidy_env = tidyFreeTyVars env0 (tyVarsOfWantedEvVars wanteds)
tidy_unsolved = tidyWantedEvVars tidy_env wanteds
err_ctxt = CEC { cec_encl = []
| null unsolved
= return ()
| otherwise
- = do { env0 <- tcInitTidyEnv
+ = setCtLoc loc $
+ do { unsolved <- zonkTcThetaType unsolved
+ ; env0 <- tcInitTidyEnv
; let tidy_env = tidyFreeTyVars env0 (tyVarsOfTheta unsolved)
tidy_unsolved = map (tidyPred tidy_env) unsolved
err_ctxt = CEC { cec_encl = []
, cec_extra = alt_fix
, cec_tidy = tidy_env }
- ; reportFlat err_ctxt tidy_unsolved loc }
+ ; reportFlat err_ctxt tidy_unsolved (ctLocOrigin loc) }
where
alt_fix = vcat [ptext (sLit "Alternatively, use a standalone 'deriving instance' declaration,"),
nest 2 $ ptext (sLit "so you can specify the instance context yourself")]
-reportUnsolvedImplication :: Implication -> TcM ()
-reportUnsolvedImplication implic
- = do { env0 <- tcInitTidyEnv
- ; let tidy_env = tidyFreeTyVars env0 (tyVarsOfImplication implic)
- tidy_implic = tidyImplication tidy_env implic
- new_tidy_env = foldNameEnv add tidy_env (ic_env implic)
- err_ctxt = CEC { cec_encl = [tidy_implic]
- , cec_extra = empty
- , cec_tidy = new_tidy_env }
- ; reportTidyWanteds err_ctxt (ic_wanted tidy_implic) }
- where
- -- Extend the tidy env with a mapping from tyvars to the
- -- names the user originally used. At the moment we do this
- -- from the type env, but it might be better to record the
- -- scoped type variable in the Implication. Urgh.
- add (ATyVar name ty) (occ_env, var_env)
- | Just tv <- tcGetTyVar_maybe ty
- , not (getUnique name `elemVarEnvByKey` var_env)
- = case tidyOccName occ_env (nameOccName name) of
- (occ_env', occ') -> (occ_env', extendVarEnv var_env tv tv')
- where
- tv' = setTyVarName tv name'
- name' = tidyNameOcc name occ'
- add _ tidy_env = tidy_env
+--------------------------------------------
+-- Internal functions
+--------------------------------------------
data ReportErrCtxt
= CEC { cec_encl :: [Implication] -- Enclosing implications
reportTidyWanteds :: ReportErrCtxt -> WantedConstraints -> TcM ()
reportTidyWanteds ctxt unsolved
- = do { let (flats, implics) = splitWanteds unsolved
- (ambigs, others) = partition is_ambiguous (bagToList flats)
- ; groupErrs (reportFlat ctxt) others
- ; mapBagM_ (reportTidyImplic ctxt) implics
- ; ifErrsM (return ()) $
- -- Only report ambiguity if no other errors happened
- -- See Note [Avoiding spurious errors]
- reportAmbigErrs ctxt skols ambigs }
+ = do { let (flats, implics) = splitWanteds unsolved
+ (ambigs, non_ambigs) = partition is_ambiguous (bagToList flats)
+ (tv_eqs, others) = partition is_tv_eq non_ambigs
+
+ ; groupErrs (reportEqErrs ctxt) tv_eqs
+ ; when (null tv_eqs) $ groupErrs (reportFlat ctxt) others
+ ; when (null tv_eqs) $ mapBagM_ (reportTidyImplic ctxt) implics
+
+ -- Only report ambiguity if no other errors (at all) happened
+ -- See Note [Avoiding spurious errors] in TcSimplify
+ ; ifErrsM (return ()) $ reportAmbigErrs ctxt skols ambigs }
where
skols = foldr (unionVarSet . ic_skols) emptyVarSet (cec_encl ctxt)
+ -- Report equalities of form (a~ty) first. They are usually
+ -- skolem-equalities, and they cause confusing knock-on
+ -- effects in other errors; see test T4093b.
+ is_tv_eq c | EqPred ty1 ty2 <- wantedEvVarPred c
+ = tcIsTyVarTy ty1 || tcIsTyVarTy ty2
+ | otherwise = False
+
-- Treat it as "ambiguous" if
-- (a) it is a class constraint
-- (b) it constrains only type variables
where
pred = wantedEvVarPred d
-reportFlat :: ReportErrCtxt -> [PredType] -> WantedLoc -> TcM ()
-reportFlat ctxt flats loc
- = do { unless (null dicts) $ reportDictErrs ctxt dicts loc
- ; unless (null eqs) $ reportEqErrs ctxt eqs loc
- ; unless (null ips) $ reportIPErrs ctxt ips loc
+reportFlat :: ReportErrCtxt -> [PredType] -> CtOrigin -> TcM ()
+reportFlat ctxt flats origin
+ = do { unless (null dicts) $ reportDictErrs ctxt dicts origin
+ ; unless (null eqs) $ reportEqErrs ctxt eqs origin
+ ; unless (null ips) $ reportIPErrs ctxt ips origin
; ASSERT( null others ) return () }
where
(dicts, non_dicts) = partition isClassPred flats
-- Support code
--------------------------------------------
-groupErrs :: ([PredType] -> WantedLoc -> TcM ()) -- Deal with one group
- -> [WantedEvVar] -- Unsolved wanteds
+groupErrs :: ([PredType] -> CtOrigin -> TcM ()) -- Deal with one group
+ -> [WantedEvVar] -- Unsolved wanteds
-> TcM ()
-- Group together insts with the same origin
-- We want to report them together in error messages
groupErrs _ []
= return ()
groupErrs report_err (wanted : wanteds)
- = do { setCtLoc the_loc $ report_err the_vars the_loc
+ = do { setCtLoc the_loc $
+ report_err the_vars (ctLocOrigin the_loc)
; groupErrs report_err others }
where
the_loc = wantedEvVarLoc wanted
-- and it avoids need equality on InstLocs.
-- Add the "arising from..." part to a message about bunch of dicts
-addArising :: WantedLoc -> SDoc -> SDoc
-addArising loc msg = msg $$ nest 2 (pprArising loc)
+addArising :: CtOrigin -> SDoc -> SDoc
+addArising orig msg = msg $$ nest 2 (pprArising orig)
pprWithArising :: [WantedEvVar] -> (WantedLoc, SDoc)
-- Print something like
pprWithArising []
= panic "pprWithArising"
pprWithArising [WantedEvVar ev loc]
- = (loc, pprEvVarTheta [ev] <+> pprArising loc)
+ = (loc, pprEvVarTheta [ev] <+> pprArising (ctLocOrigin loc))
pprWithArising ev_vars
= (first_loc, vcat (map ppr_one ev_vars))
where
%************************************************************************
\begin{code}
-reportIPErrs :: ReportErrCtxt -> [PredType] -> WantedLoc -> TcM ()
-reportIPErrs ctxt ips loc
- = addErrorReport ctxt $ addArising loc msg
+reportIPErrs :: ReportErrCtxt -> [PredType] -> CtOrigin -> TcM ()
+reportIPErrs ctxt ips orig
+ = addErrorReport ctxt $ addArising orig msg
where
msg | Just givens <- getUserGivens ctxt
= couldNotDeduce givens ips
%************************************************************************
\begin{code}
-reportEqErrs :: ReportErrCtxt -> [PredType] -> WantedLoc -> TcM ()
-reportEqErrs ctxt eqs loc = mapM_ (reportEqErr ctxt loc) eqs
-
-reportEqErr :: ReportErrCtxt -> WantedLoc -> PredType -> TcM ()
-reportEqErr ctxt loc pred@(EqPred ty1 ty2)
- | Just tv1 <- tcGetTyVar_maybe ty1 = reportTyVarEqErr ctxt loc tv1 ty2
- | Just tv2 <- tcGetTyVar_maybe ty2 = reportTyVarEqErr ctxt loc tv2 ty1
+reportEqErrs :: ReportErrCtxt -> [PredType] -> CtOrigin -> TcM ()
+reportEqErrs ctxt eqs orig
+ = mapM_ report_one eqs
+ where
+ env0 = cec_tidy ctxt
+ report_one (EqPred ty1 ty2)
+ = do { (env1, extra) <- getWantedEqExtra emptyTvSubst env0 orig ty1 ty2
+ ; let ctxt' = ctxt { cec_tidy = env1
+ , cec_extra = cec_extra ctxt $$ extra }
+ ; reportEqErr ctxt' ty1 ty2 }
+ report_one pred
+ = pprPanic "reportEqErrs" (ppr pred)
+
+reportEqErr :: ReportErrCtxt -> TcType -> TcType -> TcM ()
+reportEqErr ctxt ty1 ty2
+ | Just tv1 <- tcGetTyVar_maybe ty1 = reportTyVarEqErr ctxt tv1 ty2
+ | Just tv2 <- tcGetTyVar_maybe ty2 = reportTyVarEqErr ctxt tv2 ty1
| otherwise -- Neither side is a type variable
-- Since the unsolved constraint is canonical,
-- it must therefore be of form (F tys ~ ty)
= addErrorReport ctxt (msg $$ mkTyFunInfoMsg ty1 ty2)
where
msg = case getUserGivens ctxt of
- Just givens -> couldNotDeduce givens [pred]
+ Just givens -> couldNotDeduce givens [EqPred ty1 ty2]
Nothing -> misMatchMsg ty1 ty2
-reportEqErr _ _ _ = panic "reportEqErr" -- Must be equality pred
-
-reportTyVarEqErr :: ReportErrCtxt -> WantedLoc
- -> TcTyVar -> TcType -> TcM ()
-reportTyVarEqErr ctxt loc tv1 ty2
+reportTyVarEqErr :: ReportErrCtxt -> TcTyVar -> TcType -> TcM ()
+reportTyVarEqErr ctxt tv1 ty2
| not is_meta1
, Just tv2 <- tcGetTyVar_maybe ty2
, isMetaTyVar tv2
= -- sk ~ alpha: swap
- reportTyVarEqErr ctxt loc tv2 ty1
+ reportTyVarEqErr ctxt tv2 ty1
| not is_meta1
= -- sk ~ ty, where ty isn't a meta-tyvar: mis-match
| Just tv <- tcGetTyVar_maybe ty
, isTcTyVar tv
, isSkolemTyVar tv || isSigTyVar tv
- , not (isUnk tv)
+ , not (isUnkSkol tv)
, let (env1, tv1) = tidySkolemTyVar env tv
= (env1, pprSkolTvBinding tv1)
where
typeExtraInfoMsg env _ty = (env, empty) -- Normal case
+
+--------------------
+unifyCtxt :: EqOrigin -> TidyEnv -> TcM (TidyEnv, SDoc)
+unifyCtxt (UnifyOrigin { uo_actual = act_ty, uo_expected = exp_ty }) tidy_env
+ = do { act_ty' <- zonkTcType act_ty
+ ; exp_ty' <- zonkTcType exp_ty
+ ; let (env1, exp_ty'') = tidyOpenType tidy_env exp_ty'
+ (env2, act_ty'') = tidyOpenType env1 act_ty'
+ ; return (env2, mkExpectedActualMsg act_ty'' exp_ty'') }
+
+mkExpectedActualMsg :: Type -> Type -> SDoc
+mkExpectedActualMsg act_ty exp_ty
+ = vcat [ text "Expected type" <> colon <+> ppr exp_ty
+ , text " Actual type" <> colon <+> ppr act_ty ]
\end{code}
Note [Non-injective type functions]
%************************************************************************
\begin{code}
-reportDictErrs :: ReportErrCtxt -> [PredType] -> WantedLoc -> TcM ()
-reportDictErrs ctxt wanteds loc
+reportDictErrs :: ReportErrCtxt -> [PredType] -> CtOrigin -> TcM ()
+reportDictErrs ctxt wanteds orig
= do { inst_envs <- tcGetInstEnvs
; let (others, overlaps) = partitionWith (check_overlap inst_envs) wanteds
; unless (null others) $
mk_overlap_msg pred (matches, unifiers)
= ASSERT( not (null matches) )
- vcat [ addArising loc (ptext (sLit "Overlapping instances for")
+ vcat [ addArising orig (ptext (sLit "Overlapping instances for")
<+> pprPred pred)
, sep [ptext (sLit "Matching instances") <> colon,
nest 2 (vcat [pprInstances ispecs, pprInstances unifiers])]
mk_no_inst_err :: [PredType] -> SDoc
mk_no_inst_err wanteds
| Just givens <- getUserGivens ctxt
- = vcat [ addArising loc $ couldNotDeduce givens wanteds
+ = vcat [ addArising orig $ couldNotDeduce givens wanteds
, show_fixes (fix1 : fixes2) ]
| otherwise -- Top level
- = vcat [ addArising loc $
+ = vcat [ addArising orig $
ptext (sLit "No instance") <> plural wanteds
<+> ptext (sLit "for") <+> pprTheta wanteds
, show_fixes fixes2 ]
-- ASSUMPTION: the Insts are fully zonked
mkMonomorphismMsg ctxt inst_tvs
= do { dflags <- getDOpts
- ; (tidy_env, docs) <- findGlobals ctxt (mkVarSet inst_tvs)
+ ; traceTc "Mono" (vcat (map pprSkolTvBinding inst_tvs))
+ ; (tidy_env, docs) <- findGlobals ctxt (mkVarSet inst_tvs)
; return (tidy_env, mk_msg dflags docs) }
where
- mk_msg _ _ | any isRuntimeUnk inst_tvs
+ mk_msg _ _ | any isRuntimeUnkSkol inst_tvs -- See Note [Runtime skolems]
= vcat [ptext (sLit "Cannot resolve unknown runtime types:") <+>
(pprWithCommas ppr inst_tvs),
ptext (sLit "Use :print or :force to determine these types")]
monomorphism_fix dflags
= ptext (sLit "Probable fix:") <+> vcat
[ptext (sLit "give these definition(s) an explicit type signature"),
- if dopt Opt_MonomorphismRestriction dflags
+ if xopt Opt_MonomorphismRestriction dflags
then ptext (sLit "or use -XNoMonomorphismRestriction")
else empty] -- Only suggest adding "-XNoMonomorphismRestriction"
-- if it is not already set!
(loc, ppr_wanteds) = pprWithArising wanteds
\end{code}
+Note [Runtime skolems]
+~~~~~~~~~~~~~~~~~~~~~~
+We want to give a reasonably helpful error message for ambiguity
+arising from *runtime* skolems in the debugger. These
+are created by in RtClosureInspect.zonkRTTIType.
+
+
%************************************************************************
%* *
Error from the canonicaliser
+ These ones are called *during* constraint simplification
%* *
%************************************************************************
\begin{code}
kindErrorTcS :: CtFlavor -> TcType -> TcType -> TcS a
+-- If there's a kind error, we don't want to blindly say "kind error"
+-- We might, say, be unifying a skolem 'a' with a type 'Int',
+-- in which case that's the error to report. So we set things
+-- up to call reportEqErr, which does the business properly
kindErrorTcS fl ty1 ty2
- = wrapErrTcS $
- setCtFlavorLoc fl $
- do { env0 <- tcInitTidyEnv
- ; let (env1, ty1') = tidyOpenType env0 ty1
- (env2, ty2') = tidyOpenType env1 ty2
- ; failWithTcM (env2, kindErrorMsg ty1' ty2') }
+ = wrapEqErrTcS fl ty1 ty2 $ \ env0 ty1 ty2 extra ->
+ do { let ctxt = CEC { cec_encl = []
+ , cec_extra = extra
+ , cec_tidy = env0 }
+ ; reportEqErr ctxt ty1 ty2
+ ; failM
+ }
misMatchErrorTcS :: CtFlavor -> TcType -> TcType -> TcS a
misMatchErrorTcS fl ty1 ty2
- = wrapErrTcS $
- setCtFlavorLoc fl $
- do { env0 <- tcInitTidyEnv
- ; let (env1, ty1') = tidyOpenType env0 ty1
- (env2, ty2') = tidyOpenType env1 ty2
- (env3, msg) = misMatchMsgWithExtras env2 ty1' ty2'
- ; failWithTcM (env3, inaccessible_msg $$ msg) }
+ = wrapEqErrTcS fl ty1 ty2 $ \ env0 ty1 ty2 extra ->
+ do { let (env1, msg) = misMatchMsgWithExtras env0 ty1 ty2
+ ; failWithTcM (env1, inaccessible_msg $$ msg $$ extra) }
where
inaccessible_msg
= case fl of
occursCheckErrorTcS :: CtFlavor -> TcTyVar -> TcType -> TcS a
occursCheckErrorTcS fl tv ty
- = wrapErrTcS $
- setCtFlavorLoc fl $
- do { env0 <- tcInitTidyEnv
- ; let (env1, tv') = tidyOpenTyVar env0 tv
- (env2, ty') = tidyOpenType env1 ty
- extra = sep [ppr tv', char '=', ppr ty']
- ; failWithTcM (env2, hang msg 2 extra) }
+ = wrapEqErrTcS fl (mkTyVarTy tv) ty $ \ env0 ty1 ty2 extra2 ->
+ do { let extra1 = sep [ppr ty1, char '=', ppr ty2]
+ ; failWithTcM (env0, hang msg 2 (extra1 $$ extra2)) }
where
msg = text $ "Occurs check: cannot construct the infinite type:"
-setCtFlavorLoc :: CtFlavor -> TcM a -> TcM a
-setCtFlavorLoc (Wanted loc) thing = setCtLoc loc thing
-setCtFlavorLoc (Derived loc) thing = setCtLoc loc thing
-setCtFlavorLoc (Given loc) thing = setCtLoc loc thing
-
solverDepthErrorTcS :: Int -> [CanonicalCt] -> TcS a
solverDepthErrorTcS depth stack
| null stack -- Shouldn't happen unless you say -fcontext-stack=0
flattenForAllErrorTcS :: CtFlavor -> TcType -> Bag CanonicalCt -> TcS a
flattenForAllErrorTcS fl ty _bad_eqs
- = wrapErrTcS $
+ = wrapErrTcS $
setCtFlavorLoc fl $
do { env0 <- tcInitTidyEnv
; let (env1, ty') = tidyOpenType env0 ty
, ppr ty' ]
; failWithTcM (env1, msg) }
\end{code}
+
+%************************************************************************
+%* *
+ Setting the context
+%* *
+%************************************************************************
+
+\begin{code}
+setCtFlavorLoc :: CtFlavor -> TcM a -> TcM a
+setCtFlavorLoc (Wanted loc) thing = setCtLoc loc thing
+setCtFlavorLoc (Derived loc _) thing = setCtLoc loc thing
+setCtFlavorLoc (Given loc) thing = setCtLoc loc thing
+
+wrapEqErrTcS :: CtFlavor -> TcType -> TcType
+ -> (TidyEnv -> TcType -> TcType -> SDoc -> TcM a)
+ -> TcS a
+wrapEqErrTcS fl ty1 ty2 thing_inside
+ = do { ty_binds_var <- getTcSTyBinds
+ ; wrapErrTcS $ setCtFlavorLoc fl $
+ do { -- Apply the current substitition
+ -- and zonk to get rid of flatten-skolems
+ ; ty_binds_map <- readTcRef ty_binds_var
+ ; let subst = mkOpenTvSubst (mapVarEnv snd ty_binds_map)
+ ; env0 <- tcInitTidyEnv
+ ; (env1, ty1) <- zonkSubstTidy env0 subst ty1
+ ; (env2, ty2) <- zonkSubstTidy env1 subst ty2
+ ; let do_wanted loc = do { (env3, extra) <- getWantedEqExtra subst env2
+ (ctLocOrigin loc) ty1 ty2
+ ; thing_inside env3 ty1 ty2 extra }
+ ; case fl of
+ Wanted loc -> do_wanted loc
+ Derived loc _ -> do_wanted loc
+ Given {} -> thing_inside env2 ty1 ty2 empty
+ -- We could print more info, but it
+ -- seems to be coming out already
+ } }
+ where
+
+getWantedEqExtra :: TvSubst -> TidyEnv -> CtOrigin -> TcType -> TcType
+ -> TcM (TidyEnv, SDoc)
+getWantedEqExtra subst env0 (TypeEqOrigin item) ty1 ty2
+ -- If the types in the error message are the same
+ -- as the types we are unifying (remember to zonk the latter)
+ -- don't add the extra expected/actual message
+ --
+ -- The complication is that the types in the TypeEqOrigin must
+ -- (a) be zonked
+ -- (b) have any TcS-monad pending equalities applied to them
+ -- (hence the passed-in substitution)
+ = do { (env1, act) <- zonkSubstTidy env0 subst (uo_actual item)
+ ; (env2, exp) <- zonkSubstTidy env1 subst (uo_expected item)
+ ; if (act `tcEqType` ty1 && exp `tcEqType` ty2)
+ || (exp `tcEqType` ty1 && act `tcEqType` ty2)
+ then
+ return (env0, empty)
+ else
+ return (env2, mkExpectedActualMsg act exp) }
+
+getWantedEqExtra _ env0 orig _ _
+ = return (env0, pprArising orig)
+
+zonkSubstTidy :: TidyEnv -> TvSubst -> TcType -> TcM (TidyEnv, TcType)
+-- In general, becore printing a type, we want to
+-- a) Zonk it. Even during constraint simplification this is
+-- is important, to un-flatten the flatten skolems in a type
+-- b) Substitute any solved unification variables. This is
+-- only important *during* solving, becuase after solving
+-- the substitution is expressed in the mutable type variables
+-- But during solving there may be constraint (F xi ~ ty)
+-- where the substitution has not been applied to the RHS
+zonkSubstTidy env subst ty
+ = do { ty' <- zonkTcTypeAndSubst subst ty
+ ; return (tidyOpenType env ty') }
+\end{code}