tcSimplifyDeriv, tcSimplifyDefault,
bindInstsOfLocalFuns,
-
+
misMatchMsg
) where
import FunDeps
import PrelInfo
import PrelNames
-import Type
import TysWiredIn
import ErrUtils
import BasicTypes
import FiniteMap
import Bag
import Outputable
-import Maybes
import ListSetOps
import Util
import SrcLoc
import DynFlags
import FastString
+
import Control.Monad
import Data.List
\end{code}
; gbl_tvs <- tcGetGlobalTyVars
; let preds1 = fdPredsOfInsts wanted'
gbl_tvs1 = oclose preds1 gbl_tvs
- qtvs = grow preds1 tau_tvs1 `minusVarSet` gbl_tvs1
+ qtvs = growInstsTyVars wanted' tau_tvs1 `minusVarSet` gbl_tvs1
-- See Note [Choosing which variables to quantify]
-- To maximise sharing, remove from consideration any
; extendLIEs free
-- To make types simple, reduce as much as possible
- ; traceTc (text "infer" <+> (ppr preds1 $$ ppr (grow preds1 tau_tvs1) $$ ppr gbl_tvs $$
+ ; traceTc (text "infer" <+> (ppr preds1 $$ ppr (growInstsTyVars wanted' tau_tvs1) $$ ppr gbl_tvs $$
ppr gbl_tvs1 $$ ppr free $$ ppr bound))
; (irreds1, binds1) <- tryHardCheckLoop doc bound
-- Then b is fixed by gbl_tvs, so (C a b) will be in free, and
-- irreds2 will be empty. But we don't want to generalise over b!
; let preds2 = fdPredsOfInsts irreds2 -- irreds2 is zonked
- qtvs = grow preds2 tau_tvs2 `minusVarSet` oclose preds2 gbl_tvs2
+ qtvs = growInstsTyVars irreds2 tau_tvs2 `minusVarSet` oclose preds2 gbl_tvs2
+ ---------------------------------------------------
+ -- BUG WARNING: there's a nasty bug lurking here
+ -- fdPredsOfInsts may return preds that mention variables quantified in
+ -- one of the implication constraints in irreds2; and that is clearly wrong:
+ -- we might quantify over too many variables through accidental capture
+ ---------------------------------------------------
; let (free, irreds3) = partition (isFreeWhenInferring qtvs) irreds2
; extendLIEs free
The excitement comes when simplifying the bindings for h. Initially
try to simplify {y @ [[t1]] t2, 0 @ t1}, with initial qtvs = {t2}.
-From this we get t1:=:t2, but also various bindings. We can't forget
+From this we get t1~t2, but also various bindings. We can't forget
the bindings (because of [LOOP]), but in fact t1 is what g is
polymorphic in.
-- (ir1, .., irn) = f qtvs givens
-- where f is (evidence for) the new implication constraint
-- f :: forall qtvs. givens => (ir1, .., irn)
--- qtvs includes coercion variables.
+-- qtvs includes coercion variables
--
-- This binding must line up the 'rhs' in reduceImplication
makeImplicationBind loc all_tvs
name = mkInternalName uniq (mkVarOcc "ic") span
implic_inst = ImplicInst { tci_name = name,
tci_tyvars = all_tvs,
- tci_given = (eq_givens ++ dict_givens),
+ tci_given = eq_givens ++ dict_givens,
-- same order as binders
tci_wanted = irreds,
tci_loc = loc }
<.> mkWpTyApps eq_cotvs
<.> mkWpTyApps (mkTyVarTys all_tvs)
bind | [dict_irred_id] <- dict_irred_ids
- = VarBind dict_irred_id rhs
+ = mkVarBind dict_irred_id rhs
| otherwise
- = PatBind { pat_lhs = lpat
+ = L span $
+ PatBind { pat_lhs = lpat
, pat_rhs = unguardedGRHSs rhs
, pat_rhs_ty = hsLPatType lpat
, bind_fvs = placeHolderNames
}
; traceTc $ text "makeImplicationBind" <+> ppr implic_inst
- ; return ([implic_inst], unitBag (L span bind))
+ ; return ([implic_inst], unitBag bind)
}
-----------------------------------------------------------
; env' <- zonkRedEnv env
; wanteds' <- zonkInsts wanteds
- ; (improved, binds, irreds) <- reduceContext env' wanteds'
+ ; (improved, tybinds, binds, irreds)
+ <- reduceContext env' wanteds'
+ ; execTcTyVarBinds tybinds
; if null irreds || not improved then
return (irreds, binds)
Conclusion: in the very special case of tcSimplifySuperClasses
we have one 'given' (namely the "this" dictionary) whose superclasses
-must not be added to 'givens' by addGiven. That is the *whole* reason
-for the red_given_scs field in RedEnv, and the function argument to
-addGiven.
+must not be added to 'givens' by addGiven.
+
+There is a complication though. Suppose there are equalities
+ instance (Eq a, a~b) => Num (a,b)
+Then we normalise the 'givens' wrt the equalities, so the original
+given "this" dictionary is cast to one of a different type. So it's a
+bit trickier than before to identify the "special" dictionary whose
+superclasses must not be added. See test
+ indexed-types/should_run/EqInInstance
+
+We need a persistent property of the dictionary to record this
+special-ness. Current I'm using the InstLocOrigin (a bit of a hack,
+but cool), which is maintained by dictionary normalisation.
+Specifically, the InstLocOrigin is
+ NoScOrigin
+then the no-superclass thing kicks in. WATCH OUT if you fiddle
+with InstLocOrigin!
\begin{code}
tcSimplifySuperClasses
-> TcM TcDictBinds
tcSimplifySuperClasses loc this givens sc_wanteds
= do { traceTc (text "tcSimplifySuperClasses")
+
+ -- Note [Recursive instances and superclases]
+ ; no_sc_loc <- getInstLoc NoScOrigin
+ ; let no_sc_this = setInstLoc this no_sc_loc
+
+ ; let env = RedEnv { red_doc = pprInstLoc loc,
+ red_try_me = try_me,
+ red_givens = no_sc_this : givens,
+ red_stack = (0,[]),
+ red_improve = False } -- No unification vars
+
+
; (irreds,binds1) <- checkLoop env sc_wanteds
; let (tidy_env, tidy_irreds) = tidyInsts irreds
- ; reportNoInstances tidy_env (Just (loc, givens)) tidy_irreds
+ ; reportNoInstances tidy_env (Just (loc, givens)) [] tidy_irreds
; return binds1 }
where
- env = RedEnv { red_doc = pprInstLoc loc,
- red_try_me = try_me,
- red_givens = this:givens,
- red_given_scs = add_scs,
- red_stack = (0,[]),
- red_improve = False } -- No unification vars
- add_scs g | g==this = NoSCs
- | otherwise = AddSCs
-
try_me _ = ReduceMe -- Try hard, so we completely solve the superclass
-- constraints right here. See Note [SUPERCLASS-LOOP 1]
\end{code}
tcSimplifyRestricted doc top_lvl bndrs tau_tvs wanteds
-- Zonk everything in sight
= do { traceTc (text "tcSimplifyRestricted")
- ; wanteds' <- zonkInsts wanteds
+ ; wanteds_z <- zonkInsts wanteds
-- 'ReduceMe': Reduce as far as we can. Don't stop at
-- dicts; the idea is to get rid of as many type
-- HOWEVER, some unification may take place, if we instantiate
-- a method Inst with an equality constraint
; let env = mkNoImproveRedEnv doc (\_ -> ReduceMe)
- ; (_imp, _binds, constrained_dicts) <- reduceContext env wanteds'
+ ; (_imp, _tybinds, _binds, constrained_dicts)
+ <- reduceContext env wanteds_z
-- Next, figure out the tyvars we will quantify over
; tau_tvs' <- zonkTcTyVarsAndFV (varSetElems tau_tvs)
-- (for example) squash {Monad (ST s)} into {}. It's not enough
-- just to float all constraints
--
- -- At top level, we *do* squash methods becuase we want to
+ -- At top level, we *do* squash methods because we want to
-- expose implicit parameters to the test that follows
; let is_nested_group = isNotTopLevel top_lvl
try_me inst | isFreeWrtTyVars qtvs inst,
(is_nested_group || isDict inst) = Stop
| otherwise = ReduceMe
env = mkNoImproveRedEnv doc try_me
- ; (_imp, binds, irreds) <- reduceContext env wanteds'
+ ; (_imp, tybinds, binds, irreds) <- reduceContext env wanteds_z
+ ; execTcTyVarBinds tybinds
-- See "Notes on implicit parameters, Question 4: top level"
; ASSERT( all (isFreeWrtTyVars qtvs) irreds ) -- None should be captured
tcSimplifyRuleLhs :: [Inst] -> TcM ([Inst], TcDictBinds)
tcSimplifyRuleLhs wanteds
= do { wanteds' <- zonkInsts wanteds
- ; (irreds, binds) <- go [] emptyBag wanteds'
+
+ -- Simplify equalities
+ -- It's important to do this: Trac #3346 for example
+ ; (_, wanteds'', tybinds, binds1) <- tcReduceEqs [] wanteds'
+ ; execTcTyVarBinds tybinds
+
+ -- Simplify other constraints
+ ; (irreds, binds2) <- go [] emptyBag wanteds''
+
+ -- Report anything that is left
; let (dicts, bad_irreds) = partition isDict irreds
; traceTc (text "tcSimplifyrulelhs" <+> pprInsts bad_irreds)
; addNoInstanceErrs (nub bad_irreds)
-- The nub removes duplicates, which has
-- not happened otherwise (see notes above)
- ; return (dicts, binds) }
+
+ ; return (dicts, binds1 `unionBags` binds2) }
where
go :: [Inst] -> TcDictBinds -> [Inst] -> TcM ([Inst], TcDictBinds)
go irreds binds []
\begin{code}
tcSimplifyBracket :: [Inst] -> TcM ()
tcSimplifyBracket wanteds
- = do { tryHardCheckLoop doc wanteds
+ = do { _ <- tryHardCheckLoop doc wanteds
; return () }
where
doc = text "tcSimplifyBracket"
-- Unusually for checking, we *must* zonk the given_ips
; let env = mkRedEnv doc try_me given_ips'
- ; (improved, binds, irreds) <- reduceContext env wanteds'
+ ; (improved, tybinds, binds, irreds) <- reduceContext env wanteds'
+ ; execTcTyVarBinds tybinds
; if null irreds || not improved then
ASSERT( all is_free irreds )
-- Always dicts & equalities
-- but see Note [Rigidity]
- , red_given_scs :: Inst -> WantSCs -- See Note [Recursive instances and superclases]
-
, red_stack :: (Int, [Inst]) -- Recursion stack (for err msg)
-- See Note [RedStack]
}
mkRedEnv doc try_me givens
= RedEnv { red_doc = doc, red_try_me = try_me,
red_givens = givens,
- red_given_scs = const AddSCs,
red_stack = (0,[]),
red_improve = True }
mkInferRedEnv doc try_me
= RedEnv { red_doc = doc, red_try_me = try_me,
red_givens = [],
- red_given_scs = const AddSCs,
red_stack = (0,[]),
red_improve = True }
mkNoImproveRedEnv doc try_me
= RedEnv { red_doc = doc, red_try_me = try_me,
red_givens = [],
- red_given_scs = const AddSCs,
red_stack = (0,[]),
red_improve = True }
reduceContext :: RedEnv
-> [Inst] -- Wanted
-> TcM (ImprovementDone,
+ TcTyVarBinds, -- Type variable bindings
TcDictBinds, -- Dictionary bindings
[Inst]) -- Irreducible
givens = red_givens env
; (givens',
wanteds',
- normalise_binds,
- eq_improved) <- tcReduceEqs givens wanteds
+ tybinds,
+ normalise_binds) <- tcReduceEqs givens wanteds
; traceTc $ text "reduceContext: tcReduceEqs result" <+> vcat
- [ppr givens', ppr wanteds', ppr normalise_binds]
+ [ppr givens', ppr wanteds', ppr tybinds,
+ ppr normalise_binds]
-- Build the Avail mapping from "given_dicts"
; (init_state, _) <- getLIE $ do
- { init_state <- foldlM (addGiven (red_given_scs env))
- emptyAvails givens'
+ { init_state <- foldlM addGiven emptyAvails givens'
; return init_state
}
-- Collect all irreducible instances, and determine whether we should
-- go round again. We do so in either of two cases:
-- (1) If dictionary reduction or equality solving led to
- -- improvement (i.e., instantiated type variables).
- -- (2) If we uncovered extra equalities. We will try to solve them
- -- in the next iteration.
- -- (3) If we reduced dictionaries (i.e., got dictionary bindings),
+ -- improvement (i.e., bindings for type variables).
+ -- (2) If we reduced dictionaries (i.e., got dictionary bindings),
-- they may have exposed further opportunities to normalise
-- family applications. See Note [Dictionary Improvement]
+ --
+ -- NB: We do *not* go around for new extra_eqs. Morally, we should,
+ -- but we can't without risking non-termination (see #2688). By
+ -- not going around, we miss some legal programs mixing FDs and
+ -- TFs, but we never claimed to support such programs in the
+ -- current implementation anyway.
; let all_irreds = dict_irreds ++ implic_irreds ++ extra_eqs
avails_improved = availsImproved avails
+ eq_improved = anyBag (not . isCoVarBind) tybinds
improvedFlexible = avails_improved || eq_improved
- extraEqs = (not . null) extra_eqs
reduced_dicts = not (isEmptyBag dict_binds)
- improved = improvedFlexible || extraEqs || reduced_dicts
+ improved = improvedFlexible || reduced_dicts
--
improvedHint = (if avails_improved then " [AVAILS]" else "") ++
- (if eq_improved then " [EQ]" else "") ++
- (if extraEqs then " [EXTRA EQS]" else "")
+ (if eq_improved then " [EQ]" else "")
; traceTc (text "reduceContext end" <+> (vcat [
text "----------------------",
text "given" <+> ppr givens,
text "wanted" <+> ppr wanteds0,
text "----",
+ text "tybinds" <+> ppr tybinds,
text "avails" <+> pprAvails avails,
text "improved =" <+> ppr improved <+> text improvedHint,
text "(all) irreds = " <+> ppr all_irreds,
]))
; return (improved,
+ tybinds,
normalise_binds `unionBags` dict_binds
`unionBags` implic_binds,
all_irreds)
}
+ where
+ isCoVarBind (TcTyVarBind tv _) = isCoVar tv
tcImproveOne :: Avails -> Inst -> TcM ImprovementDone
tcImproveOne avails inst
eq_cotvs = map instToVar extra_eq_givens
dict_ids = map instToId extra_dict_givens
- -- Note [Always inline implication constraints]
- wrap_inline | null dict_ids = idHsWrapper
- | otherwise = WpInline
- co = wrap_inline
- <.> mkWpTyLams tvs
+ co = mkWpTyLams tvs
<.> mkWpTyLams eq_cotvs
<.> mkWpLams dict_ids
<.> WpLet (binds `unionBags` bind)
. filter (not . isEqInst)
$ wanteds
payload = mkBigLHsTup dict_bndrs
-
; traceTc (vcat [text "reduceImplication" <+> ppr name,
ppr simpler_implic_insts,
text "->" <+> ppr rhs])
- ; return (unitBag (L loc (VarBind (instToId orig_implic) rhs)),
+ ; return (unitBag (L loc (VarBind { var_id= instToId orig_implic
+ , var_rhs = rhs
+ , var_inline = notNull dict_ids }
+ -- See Note [Always inline implication constraints]
+ )),
simpler_implic_insts)
}
}
where
avail = Rhs rhs_expr wanteds
-addGiven :: (Inst -> WantSCs) -> Avails -> Inst -> TcM Avails
-addGiven want_scs avails given = addAvailAndSCs (want_scs given) avails given (Given given)
- -- Conditionally add superclasses for 'givens'
+addGiven :: Avails -> Inst -> TcM Avails
+addGiven avails given
+ = addAvailAndSCs want_scs avails given (Given given)
+ where
+ want_scs = case instLocOrigin (instLoc given) of
+ NoScOrigin -> NoSCs
+ _other -> AddSCs
+ -- Conditionally add superclasses for 'given'
-- See Note [Recursive instances and superclases]
- --
- -- No ASSERT( not (given `elemAvails` avails) ) because in an instance
- -- decl for Ord t we can add both Ord t and Eq t as 'givens',
- -- so the assert isn't true
+
+ -- No ASSERT( not (given `elemAvails` avails) ) because in an
+ -- instance decl for Ord t we can add both Ord t and Eq t as
+ -- 'givens', so the assert isn't true
\end{code}
\begin{code}
where
extended_defaulting = interactive || dopt Opt_ExtendedDefaultRules dflags
+ -- See also Trac #1974
ovl_strings = dopt Opt_OverloadedStrings dflags
unaries :: [(Inst, Class, TcTyVar)] -- (C tv) constraints
-> TcM () -- Just does unification, to fix the default types
disambigGroup default_tys dicts
- = try_default default_tys
+ = do { mb_chosen_ty <- try_default default_tys
+ ; case mb_chosen_ty of
+ Nothing -> return ()
+ Just chosen_ty -> do { _ <- unifyType chosen_ty (mkTyVarTy tyvar)
+ ; warnDefault dicts chosen_ty } }
where
(_,_,tyvar) = ASSERT(not (null dicts)) head dicts -- Should be non-empty
classes = [c | (_,c,_) <- dicts]
- try_default [] = return ()
+ try_default [] = return Nothing
try_default (default_ty : default_tys)
= tryTcLIE_ (try_default default_tys) $
do { tcSimplifyDefault [mkClassPred clas [default_ty] | clas <- classes]
-- For example, if Real a is reqd, but the only type in the
-- default list is Int.
- -- After this we can't fail
- ; warnDefault dicts default_ty
- ; unifyType default_ty (mkTyVarTy tyvar)
- ; return () -- TOMDO: do something with the coercion
+ ; return (Just default_ty) -- TOMDO: do something with the coercion
}
; (irreds, _) <- tryHardCheckLoop doc wanteds
; let (tv_dicts, others) = partition ok irreds
- ; addNoInstanceErrs others
+ (tidy_env, tidy_insts) = tidyInsts others
+ ; reportNoInstances tidy_env Nothing [alt_fix] tidy_insts
-- See Note [Exotic derived instance contexts] in TcMType
; let rev_env = zipTopTvSubst tvs (mkTyVarTys tyvars)
ok dict | isDict dict = validDerivPred (dictPred dict)
| otherwise = False
+ alt_fix = vcat [ptext (sLit "use a standalone 'deriving instance' declaration instead,"),
+ ptext (sLit "so you can specify the instance context yourself")]
\end{code}
tcSimplifyDefault theta = do
wanteds <- newDictBndrsO DefaultOrigin theta
(irreds, _) <- tryHardCheckLoop doc wanteds
- addNoInstanceErrs irreds
+ addNoInstanceErrs irreds
if null irreds then
return ()
else
\end{code}
+
%************************************************************************
%* *
\section{Errors and contexts}
(friends, others) = partition is_friend insts
loc_msg = showSDoc (pprInstLoc (instLoc inst))
is_friend friend = showSDoc (pprInstLoc (instLoc friend)) == loc_msg
- do_one insts = addInstCtxt (instLoc (head insts)) (report_err insts)
+ do_one insts = setInstCtxt (instLoc (head insts)) (report_err insts)
-- Add location and context information derived from the Insts
-- Add the "arising from..." part to a message about bunch of dicts
-> TcM ()
addNoInstanceErrs insts
= do { let (tidy_env, tidy_insts) = tidyInsts insts
- ; reportNoInstances tidy_env Nothing tidy_insts }
+ ; reportNoInstances tidy_env Nothing [] tidy_insts }
reportNoInstances
:: TidyEnv
-- Nothing => top level
-- Just (d,g) => d describes the construct
-- with givens g
+ -> [SDoc] -- Alternative fix for no-such-instance
-> [Inst] -- What is wanted (can include implications)
-> TcM ()
-reportNoInstances tidy_env mb_what insts
- = groupErrs (report_no_instances tidy_env mb_what) insts
+reportNoInstances tidy_env mb_what alt_fix insts
+ = groupErrs (report_no_instances tidy_env mb_what alt_fix) insts
-report_no_instances :: TidyEnv -> Maybe (InstLoc, [Inst]) -> [Inst] -> TcM ()
-report_no_instances tidy_env mb_what insts
+report_no_instances :: TidyEnv -> Maybe (InstLoc, [Inst]) -> [SDoc] -> [Inst] -> TcM ()
+report_no_instances tidy_env mb_what alt_fixes insts
= do { inst_envs <- tcGetInstEnvs
; let (implics, insts1) = partition isImplicInst insts
(insts2, overlaps) = partitionWith (check_overlap inst_envs) insts1
complain_implic inst -- Recurse!
= reportNoInstances tidy_env
(Just (tci_loc inst, tci_given inst))
- (tci_wanted inst)
+ alt_fixes (tci_wanted inst)
check_overlap :: (InstEnv,InstEnv) -> Inst -> Either Inst SDoc
-- Right msg => overlap message
= vcat [ addInstLoc insts $
sep [ ptext (sLit "Could not deduce") <+> pprDictsTheta insts
, nest 2 $ ptext (sLit "from the context") <+> pprDictsTheta givens]
- , show_fixes (fix1 loc : fixes2) ]
+ , show_fixes (fix1 loc : fixes2 ++ alt_fixes) ]
| otherwise -- Top level
= vcat [ addInstLoc insts $
ptext (sLit "No instance") <> plural insts
<+> ptext (sLit "for") <+> pprDictsTheta insts
- , show_fixes fixes2 ]
+ , show_fixes (fixes2 ++ alt_fixes) ]
where
fix1 loc = sep [ ptext (sLit "add") <+> pprDictsTheta insts
warnDefault :: [(Inst, Class, Var)] -> Type -> TcM ()
warnDefault ups default_ty = do
warn_flag <- doptM Opt_WarnTypeDefaults
- addInstCtxt (instLoc (head (dicts))) (warnTc warn_flag warn_msg)
+ setInstCtxt (instLoc (head (dicts))) (warnTc warn_flag warn_msg)
where
dicts = [d | (d,_,_) <- ups]