module TcSimplify (
tcSimplifyInfer, tcSimplifyInferCheck,
tcSimplifyCheck, tcSimplifyRestricted,
- tcSimplifyToDicts, tcSimplifyIPs, tcSimplifyTop,
+ tcSimplifyToDicts, tcSimplifyIPs,
+ tcSimplifyTop, tcSimplifyInteractive,
tcSimplifyBracket,
tcSimplifyDeriv, tcSimplifyDefault,
import {-# SOURCE #-} TcUnify( unifyTauTy )
import TcEnv -- temp
-import HsSyn ( MonoBinds(..), HsExpr(..), andMonoBinds, andMonoBindList )
-import TcHsSyn ( TcExpr, TcId,
- TcMonoBinds, TcDictBinds
- )
+import HsSyn ( HsBind(..), LHsBinds, HsExpr(..), LHsExpr )
+import TcHsSyn ( TcId, TcDictBinds, mkHsApp, mkHsTyApp, mkHsDictApp )
import TcRnMonad
import Inst ( lookupInst, LookupInstResult(..),
isStdClassTyVarDict, isMethodFor, isMethod,
instToId, tyVarsOfInsts, cloneDict,
ipNamesOfInsts, ipNamesOfInst, dictPred,
- instBindingRequired, instCanBeGeneralised,
+ instBindingRequired,
newDictsFromOld, tcInstClassOp,
getDictClassTys, isTyVarDict,
instLoc, zonkInst, tidyInsts, tidyMoreInsts,
- Inst, pprInsts, pprInstsInFull,
- isIPDict, isInheritableInst
+ Inst, pprInsts, pprInstsInFull, tcGetInstEnvs,
+ isIPDict, isInheritableInst, pprDFuns
)
-import TcEnv ( tcGetGlobalTyVars, tcGetInstEnv, tcLookupId, findGlobals )
-import InstEnv ( lookupInstEnv, classInstEnv, InstLookupResult(..) )
+import TcEnv ( tcGetGlobalTyVars, tcLookupId, findGlobals )
+import InstEnv ( lookupInstEnv, classInstEnv )
import TcMType ( zonkTcTyVarsAndFV, tcInstTyVars, checkAmbiguity )
import TcType ( TcTyVar, TcTyVarSet, ThetaType, TyVarDetails(VanillaTv),
mkClassPred, isOverloadedTy, mkTyConApp,
mkTyVarTy, tcGetTyVar, isTyVarClassPred, mkTyVarTys,
- tyVarsOfPred )
+ tyVarsOfPred, tcEqType )
import Id ( idType, mkUserLocal )
import Var ( TyVar )
import Name ( getOccName, getSrcLoc )
import NameSet ( NameSet, mkNameSet, elemNameSet )
-import Class ( classBigSig )
+import Class ( classBigSig, classKey )
import FunDeps ( oclose, grow, improve, pprEquationDoc )
-import PrelInfo ( isNumericClass, isCreturnableClass, isCcallishClass )
-import PrelNames ( splitName, fstName, sndName )
-
+import PrelInfo ( isNumericClass )
+import PrelNames ( splitName, fstName, sndName, integerTyConName,
+ showClassKey, eqClassKey, ordClassKey )
import Subst ( mkTopTyVarSubst, substTheta, substTy )
-import TysWiredIn ( unitTy, pairTyCon )
+import TysWiredIn ( pairTyCon, doubleTy )
import ErrUtils ( Message )
import VarSet
import VarEnv ( TidyEnv )
import FiniteMap
+import Bag
import Outputable
import ListSetOps ( equivClasses )
-import Util ( zipEqual )
+import Util ( zipEqual, isSingleton )
import List ( partition )
+import SrcLoc ( Located(..) )
import CmdLineOpts
\end{code}
%************************************************************************
--------------------------------------
+ Notes on functional dependencies (a bug)
+ --------------------------------------
+
+| > class Foo a b | a->b
+| >
+| > class Bar a b | a->b
+| >
+| > data Obj = Obj
+| >
+| > instance Bar Obj Obj
+| >
+| > instance (Bar a b) => Foo a b
+| >
+| > foo:: (Foo a b) => a -> String
+| > foo _ = "works"
+| >
+| > runFoo:: (forall a b. (Foo a b) => a -> w) -> w
+| > runFoo f = f Obj
+|
+| *Test> runFoo foo
+|
+| <interactive>:1:
+| Could not deduce (Bar a b) from the context (Foo a b)
+| arising from use of `foo' at <interactive>:1
+| Probable fix:
+| Add (Bar a b) to the expected type of an expression
+| In the first argument of `runFoo', namely `foo'
+| In the definition of `it': it = runFoo foo
+|
+| Why all of the sudden does GHC need the constraint Bar a b? The
+| function foo didn't ask for that...
+
+The trouble is that to type (runFoo foo), GHC has to solve the problem:
+
+ Given constraint Foo a b
+ Solve constraint Foo a b'
+
+Notice that b and b' aren't the same. To solve this, just do
+improvement and then they are the same. But GHC currently does
+ simplify constraints
+ apply improvement
+ and loop
+
+That is usually fine, but it isn't here, because it sees that Foo a b is
+not the same as Foo a b', and so instead applies the instance decl for
+instance Bar a b => Foo a b. And that's where the Bar constraint comes
+from.
+
+The Right Thing is to improve whenever the constraint set changes at
+all. Not hard in principle, but it'll take a bit of fiddling to do.
+
+
+
+ --------------------------------------
Notes on quantification
--------------------------------------
--------------------------------------
+ The need for forall's in constraints
+ --------------------------------------
+
+[Exchange on Haskell Cafe 5/6 Dec 2000]
+
+ class C t where op :: t -> Bool
+ instance C [t] where op x = True
+
+ p y = (let f :: c -> Bool; f x = op (y >> return x) in f, y ++ [])
+ q y = (y ++ [], let f :: c -> Bool; f x = op (y >> return x) in f)
+
+The definitions of p and q differ only in the order of the components in
+the pair on their right-hand sides. And yet:
+
+ ghc and "Typing Haskell in Haskell" reject p, but accept q;
+ Hugs rejects q, but accepts p;
+ hbc rejects both p and q;
+ nhc98 ... (Malcolm, can you fill in the blank for us!).
+
+The type signature for f forces context reduction to take place, and
+the results of this depend on whether or not the type of y is known,
+which in turn depends on which component of the pair the type checker
+analyzes first.
+
+Solution: if y::m a, float out the constraints
+ Monad m, forall c. C (m c)
+When m is later unified with [], we can solve both constraints.
+
+
+ --------------------------------------
Notes on implicit parameters
--------------------------------------
= inferLoop doc (varSetElems tau_tvs)
wanted_lie `thenM` \ (qtvs, frees, binds, irreds) ->
- -- Check for non-generalisable insts
- mappM_ addCantGenErr (filter (not . instCanBeGeneralised) irreds) `thenM_`
-
extendLIEs frees `thenM_`
returnM (qtvs, binds, map instToId irreds)
| isClassDict inst = DontReduceUnlessConstant -- Dicts
| otherwise = ReduceMe -- Lits and Methods
in
+ traceTc (text "infloop" <+> vcat [ppr tau_tvs', ppr wanteds', ppr preds, ppr (grow preds tau_tvs'), ppr qtvs]) `thenM_`
-- Step 2
reduceContext doc try_me [] wanteds' `thenM` \ (no_improvement, frees, binds, irreds) ->
-- the final qtvs might be empty. See [NO TYVARS] below.
inferLoop doc tau_tvs (irreds ++ frees) `thenM` \ (qtvs1, frees1, binds1, irreds1) ->
- returnM (qtvs1, frees1, binds `AndMonoBinds` binds1, irreds1)
+ returnM (qtvs1, frees1, binds `unionBags` binds1, irreds1)
\end{code}
Example [LOOP]
= check_loop givens wanted_lie `thenM` \ (qtvs, frees, binds, irreds) ->
-- Complain about any irreducible ones
- complainCheck doc givens irreds `thenM_`
+ mappM zonkInst given_dicts_and_ips `thenM` \ givens' ->
+ groupErrs (addNoInstanceErrs (Just doc) givens') irreds `thenM_`
-- Done
- extendLIEs frees `thenM_`
+ extendLIEs frees `thenM_`
returnM (qtvs, binds)
where
+ given_dicts_and_ips = filter (not . isMethod) givens
+ -- For error reporting, filter out methods, which are
+ -- only added to the given set as an optimisation
+
ip_set = mkNameSet (ipNamesOfInsts givens)
check_loop givens wanteds
= -- Step 1
mappM zonkInst givens `thenM` \ givens' ->
mappM zonkInst wanteds `thenM` \ wanteds' ->
- get_qtvs `thenM` \ qtvs' ->
+ get_qtvs `thenM` \ qtvs' ->
-- Step 2
let
returnM (varSetElems qtvs', frees, binds, irreds)
else
check_loop givens' (irreds ++ frees) `thenM` \ (qtvs', frees1, binds1, irreds1) ->
- returnM (qtvs', frees1, binds `AndMonoBinds` binds1, irreds1)
+ returnM (qtvs', frees1, binds `unionBags` binds1, irreds1)
\end{code}
-- foo = f (3::Int)
-- We want to infer the polymorphic type
-- foo :: forall b. b -> b
- let
- try_me inst = ReduceMe -- Reduce as far as we can. Don't stop at
- -- dicts; the idea is to get rid of as many type
- -- variables as possible, and we don't want to stop
- -- at (say) Monad (ST s), because that reduces
- -- immediately, with no constraint on s.
- in
- simpleReduceLoop doc try_me wanteds `thenM` \ (_, _, constrained_dicts) ->
+
+ -- 'reduceMe': Reduce as far as we can. Don't stop at
+ -- dicts; the idea is to get rid of as many type
+ -- variables as possible, and we don't want to stop
+ -- at (say) Monad (ST s), because that reduces
+ -- immediately, with no constraint on s.
+ simpleReduceLoop doc reduceMe wanteds `thenM` \ (foo_frees, foo_binds, constrained_dicts) ->
-- Next, figure out the tyvars we will quantify over
zonkTcTyVarsAndFV (varSetElems tau_tvs) `thenM` \ tau_tvs' ->
qtvs = (tau_tvs' `minusVarSet` oclose (fdPredsOfInsts constrained_dicts) gbl_tvs)
`minusVarSet` constrained_tvs
in
+ traceTc (text "tcSimplifyRestricted" <+> vcat [
+ pprInsts wanteds, pprInsts foo_frees, pprInsts constrained_dicts,
+ ppr foo_binds,
+ ppr constrained_tvs, ppr tau_tvs', ppr qtvs ]) `thenM_`
-- The first step may have squashed more methods than
-- necessary, so try again, this time knowing the exact
-- Remember that we may need to do *some* simplification, to
-- (for example) squash {Monad (ST s)} into {}. It's not enough
-- just to float all constraints
- mappM zonkInst wanteds `thenM` \ wanteds' ->
+ restrict_loop doc qtvs wanteds
+ -- We still need a loop because improvement can take place
+ -- E.g. if we have (C (T a)) and the instance decl
+ -- instance D Int b => C (T a) where ...
+ -- and there's a functional dependency for D. Then we may improve
+ -- the tyep variable 'b'.
+
+restrict_loop doc qtvs wanteds
+ = mappM zonkInst wanteds `thenM` \ wanteds' ->
+ zonkTcTyVarsAndFV (varSetElems qtvs) `thenM` \ qtvs' ->
let
- try_me inst | isFreeWrtTyVars qtvs inst = Free
- | otherwise = ReduceMe
+ try_me inst | isFreeWrtTyVars qtvs' inst = Free
+ | otherwise = ReduceMe
in
reduceContext doc try_me [] wanteds' `thenM` \ (no_improvement, frees, binds, irreds) ->
- ASSERT( no_improvement )
- ASSERT( null irreds )
- -- No need to loop because simpleReduceLoop will have
- -- already done any improvement necessary
-
- extendLIEs frees `thenM_`
- returnM (varSetElems qtvs, binds)
+ if no_improvement then
+ ASSERT( null irreds )
+ extendLIEs frees `thenM_`
+ returnM (varSetElems qtvs', binds)
+ else
+ restrict_loop doc qtvs' (irreds ++ frees) `thenM` \ (qtvs1, binds1) ->
+ returnM (qtvs1, binds `unionBags` binds1)
\end{code}
doc = text "tcSimplifyToDicts"
-- Reduce methods and lits only; stop as soon as we get a dictionary
- try_me inst | isDict inst = DontReduce NoSCs
+ try_me inst | isDict inst = DontReduce NoSCs -- See notes above for why NoSCs
| otherwise = ReduceMe
\end{code}
\begin{code}
tcSimplifyBracket :: [Inst] -> TcM ()
tcSimplifyBracket wanteds
- = simpleReduceLoop doc try_me wanteds `thenM_`
+ = simpleReduceLoop doc reduceMe wanteds `thenM_`
returnM ()
-
where
- doc = text "tcSimplifyBracket"
- try_me inst = ReduceMe
+ doc = text "tcSimplifyBracket"
\end{code}
returnM (frees, binds)
else
simpl_loop givens' (irreds ++ frees) `thenM` \ (frees1, binds1) ->
- returnM (frees1, binds `AndMonoBinds` binds1)
+ returnM (frees1, binds `unionBags` binds1)
\end{code}
@LIE@), as well as the @HsBinds@ generated.
\begin{code}
-bindInstsOfLocalFuns :: [Inst] -> [TcId] -> TcM TcMonoBinds
+bindInstsOfLocalFuns :: [Inst] -> [TcId] -> TcM (LHsBinds TcId)
bindInstsOfLocalFuns wanteds local_ids
| null overloaded_ids
-- Common case
= extendLIEs wanteds `thenM_`
- returnM EmptyMonoBinds
+ returnM emptyBag
| otherwise
= simpleReduceLoop doc try_me wanteds `thenM` \ (frees, binds, irreds) ->
| NoRhs -- Used for Insts like (CCallable f)
-- where no witness is required.
+ -- ToDo: remove?
| Rhs -- Used when there is a RHS
- TcExpr -- The RHS
+ (LHsExpr TcId) -- The RHS
[Inst] -- Insts free in the RHS; we need these too
| Linear -- Splittable Insts only.
| LinRhss -- Splittable Insts only; this is used only internally
-- by extractResults, where a Linear
-- is turned into an LinRhss
- [TcExpr] -- A supply of suitable RHSs
+ [LHsExpr TcId] -- A supply of suitable RHSs
pprAvails avails = vcat [sep [ppr inst, nest 2 (equals <+> pprAvail avail)]
| (inst,avail) <- fmToList avails ]
extractResults :: Avails
-> [Inst] -- Wanted
-> TcM (TcDictBinds, -- Bindings
- [Inst], -- Irreducible ones
- [Inst]) -- Free ones
+ [Inst], -- Irreducible ones
+ [Inst]) -- Free ones
extractResults avails wanteds
- = go avails EmptyMonoBinds [] [] wanteds
+ = go avails emptyBag [] [] wanteds
where
go avails binds irreds frees []
= returnM (binds, irreds, frees)
Just (Given id _) -> go avails new_binds irreds frees ws
where
new_binds | id == instToId w = binds
- | otherwise = addBind binds w (HsVar id)
+ | otherwise = addBind binds w (L (instSpan w) (HsVar id))
-- The sought Id can be one of the givens, via a superclass chain
-- and then we definitely don't want to generate an x=x binding!
-> get_root irreds frees avail w `thenM` \ (irreds', frees', root_id) ->
split n (instToId split_inst) root_id w `thenM` \ (binds', rhss) ->
go (addToFM avails w (LinRhss rhss))
- (binds `AndMonoBinds` binds')
+ (binds `unionBags` binds')
irreds' frees' (split_inst : w : ws)
Just (LinRhss (rhs:rhss)) -- Consume one of the Rhss
split :: Int -> TcId -> TcId -> Inst
- -> TcM (TcDictBinds, [TcExpr])
+ -> TcM (TcDictBinds, [LHsExpr TcId])
-- (split n split_id root_id wanted) returns
-- * a list of 'n' expressions, all of which witness 'avail'
-- * a bunch of auxiliary bindings to support these expressions
id = instToId wanted
occ = getOccName id
loc = getSrcLoc id
+ span = instSpan wanted
- go 1 = returnM (EmptyMonoBinds, [HsVar root_id])
+ go 1 = returnM (emptyBag, [L span $ HsVar root_id])
go n = go ((n+1) `div` 2) `thenM` \ (binds1, rhss) ->
expand n rhss `thenM` \ (binds2, rhss') ->
- returnM (binds1 `AndMonoBinds` binds2, rhss')
+ returnM (binds1 `unionBags` binds2, rhss')
-- (expand n rhss)
-- Given ((n+1)/2) rhss, make n rhss, using auxiliary bindings
returnM (binds', head rhss : rhss')
where
go rhss = mapAndUnzipM do_one rhss `thenM` \ (binds', rhss') ->
- returnM (andMonoBindList binds', concat rhss')
+ returnM (listToBag binds', concat rhss')
do_one rhs = newUnique `thenM` \ uniq ->
tcLookupId fstName `thenM` \ fst_id ->
let
x = mkUserLocal occ uniq pair_ty loc
in
- returnM (VarMonoBind x (mk_app split_id rhs),
- [mk_fs_app fst_id ty x, mk_fs_app snd_id ty x])
+ returnM (L span (VarBind x (mk_app span split_id rhs)),
+ [mk_fs_app span fst_id ty x, mk_fs_app span snd_id ty x])
-mk_fs_app id ty var = HsVar id `TyApp` [ty,ty] `HsApp` HsVar var
+mk_fs_app span id ty var = L span (HsVar id) `mkHsTyApp` [ty,ty] `mkHsApp` (L span (HsVar var))
-mk_app id rhs = HsApp (HsVar id) rhs
+mk_app span id rhs = L span (HsApp (L span (HsVar id)) rhs)
-addBind binds inst rhs = binds `AndMonoBinds` VarMonoBind (instToId inst) rhs
+addBind binds inst rhs = binds `unionBags` unitBag (L (instLocSrcSpan (instLoc inst))
+ (VarBind (instToId inst) rhs))
+instSpan wanted = instLocSrcSpan (instLoc wanted)
\end{code}
returnM (frees, binds, irreds)
else
simpleReduceLoop doc try_me (irreds ++ frees) `thenM` \ (frees1, binds1, irreds1) ->
- returnM (frees1, binds `AndMonoBinds` binds1, irreds1)
+ returnM (frees1, binds `unionBags` binds1, irreds1)
\end{code}
returnM (no_improvement, frees, binds, irreds)
+tcImprove :: Avails -> TcM Bool -- False <=> no change
+-- Perform improvement using all the predicates in Avails
tcImprove avails
- = tcGetInstEnv `thenM` \ inst_env ->
+ = tcGetInstEnvs `thenM` \ (home_ie, pkg_ie) ->
let
preds = [ (pred, pp_loc)
| inst <- keysFM avails,
-- It does not have duplicates (good)
-- NB that (?x::t1) and (?x::t2) will be held separately in avails
-- so that improve will see them separate
- eqns = improve (classInstEnv inst_env) preds
+ eqns = improve get_insts preds
+ get_insts clas = classInstEnv home_ie clas ++ classInstEnv pkg_ie clas
in
if null eqns then
returnM True
go ws state'
-- Base case: we're done!
-reduce stack try_me wanted state
+reduce stack try_me wanted avails
-- It's the same as an existing inst, or a superclass thereof
- | Just avail <- isAvailable state wanted
+ | Just avail <- isAvailable avails wanted
= if isLinearInst wanted then
- addLinearAvailable state avail wanted `thenM` \ (state', wanteds') ->
- reduceList stack try_me wanteds' state'
+ addLinearAvailable avails avail wanted `thenM` \ (avails', wanteds') ->
+ reduceList stack try_me wanteds' avails'
else
- returnM state -- No op for non-linear things
+ returnM avails -- No op for non-linear things
| otherwise
= case try_me wanted of {
- DontReduce want_scs -> addIrred want_scs state wanted
+ DontReduce want_scs -> addIrred want_scs avails wanted
; DontReduceUnlessConstant -> -- It's irreducible (or at least should not be reduced)
-- First, see if the inst can be reduced to a constant in one step
; ReduceMe -> -- It should be reduced
lookupInst wanted `thenM` \ lookup_result ->
case lookup_result of
- GenInst wanteds' rhs -> reduceList stack try_me wanteds' state `thenM` \ state' ->
- addWanted state' wanted rhs wanteds'
- SimpleInst rhs -> addWanted state wanted rhs []
+ GenInst wanteds' rhs -> addIrred NoSCs avails wanted `thenM` \ avails1 ->
+ reduceList stack try_me wanteds' avails1 `thenM` \ avails2 ->
+ addWanted avails2 wanted rhs wanteds'
+ -- Experiment with temporarily doing addIrred *before* the reduceList,
+ -- which has the effect of adding the thing we are trying
+ -- to prove to the database before trying to prove the things it
+ -- needs. See note [RECURSIVE DICTIONARIES]
+ -- NB: we must not do an addWanted before, because that adds the
+ -- superclasses too, and thaat can lead to a spurious loop; see
+ -- the examples in [SUPERCLASS-LOOP]
+ -- So we do an addIrred before, and then overwrite it afterwards with addWanted
+
+ SimpleInst rhs -> addWanted avails wanted rhs []
NoInstance -> -- No such instance!
-- Add it and its superclasses
- addIrred AddSCs state wanted
-
+ addIrred AddSCs avails wanted
}
where
try_simple do_this_otherwise
= lookupInst wanted `thenM` \ lookup_result ->
case lookup_result of
- SimpleInst rhs -> addWanted state wanted rhs []
- other -> do_this_otherwise state wanted
+ SimpleInst rhs -> addWanted avails wanted rhs []
+ other -> do_this_otherwise avails wanted
\end{code}
--
addFree avails free = returnM (addToFM avails free IsFree)
-addWanted :: Avails -> Inst -> TcExpr -> [Inst] -> TcM Avails
+addWanted :: Avails -> Inst -> LHsExpr TcId -> [Inst] -> TcM Avails
addWanted avails wanted rhs_expr wanteds
- = ASSERT2( not (wanted `elemFM` avails), ppr wanted $$ ppr avails )
- addAvailAndSCs avails wanted avail
+ = addAvailAndSCs avails wanted avail
where
avail | instBindingRequired wanted = Rhs rhs_expr wanteds
| otherwise = ASSERT( null wanteds ) NoRhs
addGiven :: Avails -> Inst -> TcM Avails
-addGiven state given = addAvailAndSCs state given (Given (instToId given) False)
+addGiven avails given = addAvailAndSCs avails given (Given (instToId given) False)
-- No ASSERT( not (given `elemFM` 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
addAvailAndSCs :: Avails -> Inst -> Avail -> TcM Avails
addAvailAndSCs avails inst avail
| not (isClassDict inst) = returnM avails1
- | otherwise = addSCs is_loop avails1 inst
+ | otherwise = traceTc (text "addAvailAndSCs" <+> vcat [ppr inst, ppr deps]) `thenM_`
+ addSCs is_loop avails1 inst
where
- avails1 = addToFM avails inst avail
- is_loop inst = inst `elem` deps -- Note: this compares by *type*, not by Unique
- deps = findAllDeps avails avail
-
-findAllDeps :: Avails -> Avail -> [Inst]
--- Find all the Insts that this one depends on
--- See Note [SUPERCLASS-LOOP]
-findAllDeps avails (Rhs _ kids) = kids ++ concat (map (find_all_deps_help avails) kids)
-findAllDeps avails other = []
-
-find_all_deps_help :: Avails -> Inst -> [Inst]
-find_all_deps_help avails inst
- = case lookupFM avails inst of
- Just avail -> findAllDeps avails avail
- Nothing -> []
+ avails1 = addToFM avails inst avail
+ is_loop inst = any (`tcEqType` idType (instToId inst)) dep_tys
+ -- Note: this compares by *type*, not by Unique
+ deps = findAllDeps emptyVarSet avail
+ dep_tys = map idType (varSetElems deps)
+
+ findAllDeps :: IdSet -> Avail -> IdSet
+ -- Find all the Insts that this one depends on
+ -- See Note [SUPERCLASS-LOOP]
+ -- Watch out, though. Since the avails may contain loops
+ -- (see Note [RECURSIVE DICTIONARIES]), so we need to track the ones we've seen so far
+ findAllDeps so_far (Rhs _ kids)
+ = foldl findAllDeps
+ (extendVarSetList so_far (map instToId kids)) -- Add the kids to so_far
+ [a | Just a <- map (lookupFM avails) kids] -- Find the kids' Avail
+ findAllDeps so_far other = so_far
+
addSCs :: (Inst -> Bool) -> Avails -> Inst -> TcM Avails
-- Add all the superclasses of the Inst to Avails
sc_theta' = substTheta (mkTopTyVarSubst tyvars tys) sc_theta
add_sc avails (sc_dict, sc_sel) -- Add it, and its superclasses
- = case lookupFM avails sc_dict of
- Just (Given _ _) -> returnM avails -- Given is cheaper than
- -- a superclass selection
- Just other | is_loop sc_dict -> returnM avails -- See Note [SUPERCLASS-LOOP]
- | otherwise -> returnM avails' -- SCs already added
-
- Nothing -> addSCs is_loop avails' sc_dict
+ | add_me sc_dict = addSCs is_loop avails' sc_dict
+ | otherwise = returnM avails
where
- sc_sel_rhs = DictApp (TyApp (HsVar sc_sel) tys) [instToId dict]
- avail = Rhs sc_sel_rhs [dict]
- avails' = addToFM avails sc_dict avail
+ sc_sel_rhs = mkHsDictApp (mkHsTyApp (L (instSpan dict) (HsVar sc_sel)) tys) [instToId dict]
+ avails' = addToFM avails sc_dict (Rhs sc_sel_rhs [dict])
+
+ add_me :: Inst -> Bool
+ add_me sc_dict
+ | is_loop sc_dict = False -- See Note [SUPERCLASS-LOOP]
+ | otherwise = case lookupFM avails sc_dict of
+ Just (Given _ _) -> False -- Given is cheaper than superclass selection
+ other -> True
\end{code}
Note [SUPERCLASS-LOOP]: Checking for loops
for d1:Ord a (which is given) with a superclass selection or we'll just
build a loop!
+Here's another variant, immortalised in tcrun020
+ class Monad m => C1 m
+ class C1 m => C2 m x
+ instance C2 Maybe Bool
+For the instance decl we need to build (C1 Maybe), and it's no good if
+we run around and add (C2 Maybe Bool) and its superclasses to the avails
+before we search for C1 Maybe.
+
Here's another example
class Eq b => Foo a b
instance Eq a => Foo [a] a
when adding superclasses. It's a bit like the occurs check in unification.
+Note [RECURSIVE DICTIONARIES]
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+Consider
+ data D r = ZeroD | SuccD (r (D r));
+
+ instance (Eq (r (D r))) => Eq (D r) where
+ ZeroD == ZeroD = True
+ (SuccD a) == (SuccD b) = a == b
+ _ == _ = False;
+
+ equalDC :: D [] -> D [] -> Bool;
+ equalDC = (==);
+
+We need to prove (Eq (D [])). Here's how we go:
+
+ d1 : Eq (D [])
+
+by instance decl, holds if
+ d2 : Eq [D []]
+ where d1 = dfEqD d2
+
+by instance decl of Eq, holds if
+ d3 : D []
+ where d2 = dfEqList d3
+ d1 = dfEqD d2
+
+But now we can "tie the knot" to give
+
+ d3 = d1
+ d2 = dfEqList d3
+ d1 = dfEqD d2
+
+and it'll even run! The trick is to put the thing we are trying to prove
+(in this case Eq (D []) into the database before trying to prove its
+contributing clauses.
+
%************************************************************************
%* *
\begin{code}
-tcSimplifyTop :: [Inst] -> TcM TcDictBinds
+tcSimplifyTop, tcSimplifyInteractive :: [Inst] -> TcM TcDictBinds
+tcSimplifyTop wanteds = tc_simplify_top False {- Not interactive loop -} wanteds
+tcSimplifyInteractive wanteds = tc_simplify_top True {- Interactive loop -} wanteds
+
+
-- The TcLclEnv should be valid here, solely to improve
-- error message generation for the monomorphism restriction
-tcSimplifyTop wanteds
+tc_simplify_top is_interactive wanteds
= getLclEnv `thenM` \ lcl_env ->
traceTc (text "tcSimplifyTop" <+> ppr (lclEnvElts lcl_env)) `thenM_`
simpleReduceLoop (text "tcSimplTop") reduceMe wanteds `thenM` \ (frees, binds, irreds) ->
-- Collect together all the bad guys
bad_guys = non_stds ++ concat std_bads
- (tidy_env, tidy_dicts) = tidyInsts bad_guys
- (bad_ips, non_ips) = partition isIPDict tidy_dicts
+ (bad_ips, non_ips) = partition isIPDict bad_guys
(no_insts, ambigs) = partition no_inst non_ips
- no_inst d = not (isTyVarDict d) || tyVarsOfInst d `subVarSet` fixed_tvs
- fixed_tvs = oclose (fdPredsOfInsts tidy_dicts) emptyVarSet
+ no_inst d = not (isTyVarDict d)
+ -- Previously, there was a more elaborate no_inst definition:
+ -- no_inst d = not (isTyVarDict d) || tyVarsOfInst d `subVarSet` fixed_tvs
+ -- fixed_tvs = oclose (fdPredsOfInsts tidy_dicts) emptyVarSet
+ -- But that seems over-elaborate to me; it only bites for class decls with
+ -- fundeps like this: class C a b | -> b where ...
in
-- Report definite errors
- addTopInstanceErrs tidy_env no_insts `thenM_`
- addTopIPErrs tidy_env bad_ips `thenM_`
+ groupErrs (addNoInstanceErrs Nothing []) no_insts `thenM_`
+ addTopIPErrs bad_ips `thenM_`
-- Deal with ambiguity errors, but only if
-- if there has not been an error so far; errors often
-- e.g. Num (IO a) and Eq (Int -> Int)
-- and ambiguous dictionaries
-- e.g. Num a
- addTopAmbigErrs (tidy_env, ambigs) `thenM_`
+ addTopAmbigErrs ambigs `thenM_`
-- Disambiguate the ones that look feasible
- mappM disambigGroup std_oks
+ mappM (disambigGroup is_interactive) std_oks
) `thenM` \ binds_ambig ->
- returnM (binds `andMonoBinds` andMonoBindList binds_ambig)
+ returnM (binds `unionBags` unionManyBags binds_ambig)
----------------------------------
d1 `cmp_by_tyvar` d2 = get_tv d1 `compare` get_tv d2
@void@.
\begin{code}
-disambigGroup :: [Inst] -- All standard classes of form (C a)
+disambigGroup :: Bool -- True <=> simplifying at top-level interactive loop
+ -> [Inst] -- All standard classes of form (C a)
-> TcM TcDictBinds
-disambigGroup dicts
- | any isNumericClass classes -- Guaranteed all standard classes
- -- see comment at the end of function for reasons as to
- -- why the defaulting mechanism doesn't apply to groups that
- -- include CCallable or CReturnable dicts.
- && not (any isCcallishClass classes)
+disambigGroup is_interactive dicts
+ | any std_default_class classes -- Guaranteed all standard classes
= -- THE DICTS OBEY THE DEFAULTABLE CONSTRAINT
-- SO, TRY DEFAULT TYPES IN ORDER
-- default list which can satisfy all the ambiguous classes.
-- For example, if Real a is reqd, but the only type in the
-- default list is Int.
- getDefaultTys `thenM` \ default_tys ->
+ get_default_tys `thenM` \ default_tys ->
let
try_default [] -- No defaults work, so fail
= failM
in
-- See if any default works
tryM (try_default default_tys) `thenM` \ mb_ty ->
- case mb_ty of {
- Left _ -> -- If not, add an AmbigErr
- addTopAmbigErrs (tidyInsts dicts) `thenM_`
- returnM EmptyMonoBinds ;
+ case mb_ty of
+ Left _ -> bomb_out
+ Right chosen_default_ty -> choose_default chosen_default_ty
- Right chosen_default_ty ->
+ | otherwise -- No defaults
+ = bomb_out
- -- If so, bind the type variable
+ where
+ tyvar = get_tv (head dicts) -- Should be non-empty
+ classes = map get_clas dicts
+
+ std_default_class cls
+ = isNumericClass cls
+ || (is_interactive &&
+ classKey cls `elem` [showClassKey, eqClassKey, ordClassKey])
+ -- In interactive mode, we default Show a to Show ()
+ -- to avoid graututious errors on "show []"
+
+ choose_default default_ty -- Commit to tyvar = default_ty
+ = -- Bind the type variable
+ unifyTauTy default_ty (mkTyVarTy tyvar) `thenM_`
-- and reduce the context, for real this time
- unifyTauTy chosen_default_ty (mkTyVarTy tyvar) `thenM_`
- simpleReduceLoop (text "disambig" <+> ppr dicts)
+ simpleReduceLoop (text "disambig" <+> ppr dicts)
reduceMe dicts `thenM` \ (frees, binds, ambigs) ->
- WARN( not (null frees && null ambigs), ppr frees $$ ppr ambigs )
- warnDefault dicts chosen_default_ty `thenM_`
- returnM binds }
-
- | all isCreturnableClass classes
- = -- Default CCall stuff to (); we don't even both to check that () is an
- -- instance of CReturnable, because we know it is.
- unifyTauTy (mkTyVarTy tyvar) unitTy `thenM_`
- returnM EmptyMonoBinds
-
- | otherwise -- No defaults
- = addTopAmbigErrs (tidyInsts dicts) `thenM_`
- returnM EmptyMonoBinds
-
- where
- tyvar = get_tv (head dicts) -- Should be non-empty
- classes = map get_clas dicts
+ WARN( not (null frees && null ambigs), ppr frees $$ ppr ambigs )
+ warnDefault dicts default_ty `thenM_`
+ returnM binds
+
+ bomb_out = addTopAmbigErrs dicts `thenM_`
+ returnM emptyBag
+
+get_default_tys
+ = do { mb_defaults <- getDefaultTys
+ ; case mb_defaults of
+ Just tys -> return tys
+ Nothing -> -- No use-supplied default;
+ -- use [Integer, Double]
+ do { integer_ty <- tcMetaTy integerTyConName
+ ; return [integer_ty, doubleTy] } }
\end{code}
[Aside - why the defaulting mechanism is turned off when
doptM Opt_AllowUndecidableInstances `thenM` \ undecidable_ok ->
let
tv_set = mkVarSet tvs
- simpl_theta = map dictPred irreds -- reduceMe squashes all non-dicts
-
- check_pred pred
- | isEmptyVarSet pred_tyvars -- Things like (Eq T) should be rejected
- = addErrTc (noInstErr pred)
-
- | not undecidable_ok && not (isTyVarClassPred pred)
- -- Check that the returned dictionaries are all of form (C a b)
- -- (where a, b are type variables).
- -- We allow this if we had -fallow-undecidable-instances,
- -- but note that risks non-termination in the 'deriving' context-inference
- -- fixpoint loop. It is useful for situations like
- -- data Min h a = E | M a (h a)
- -- which gives the instance decl
- -- instance (Eq a, Eq (h a)) => Eq (Min h a)
- = addErrTc (noInstErr pred)
+
+ (bad_insts, ok_insts) = partition is_bad_inst irreds
+ is_bad_inst dict
+ = let pred = dictPred dict -- reduceMe squashes all non-dicts
+ in isEmptyVarSet (tyVarsOfPred pred)
+ -- Things like (Eq T) are bad
+ || (not undecidable_ok && not (isTyVarClassPred pred))
+ -- The returned dictionaries should be of form (C a b)
+ -- (where a, b are type variables).
+ -- We allow non-tyvar dicts if we had -fallow-undecidable-instances,
+ -- but note that risks non-termination in the 'deriving' context-inference
+ -- fixpoint loop. It is useful for situations like
+ -- data Min h a = E | M a (h a)
+ -- which gives the instance decl
+ -- instance (Eq a, Eq (h a)) => Eq (Min h a)
- | not (pred_tyvars `subVarSet` tv_set)
+ simpl_theta = map dictPred ok_insts
+ weird_preds = [pred | pred <- simpl_theta
+ , not (tyVarsOfPred pred `subVarSet` tv_set)]
-- Check for a bizarre corner case, when the derived instance decl should
-- have form instance C a b => D (T a) where ...
-- Note that 'b' isn't a parameter of T. This gives rise to all sorts
-- of problems; in particular, it's hard to compare solutions for
-- equality when finding the fixpoint. So I just rule it out for now.
- = addErrTc (badDerivedPred pred)
- | otherwise
- = returnM ()
- where
- pred_tyvars = tyVarsOfPred pred
-
rev_env = mkTopTyVarSubst tvs (mkTyVarTys tyvars)
-- This reverse-mapping is a Royal Pain,
-- but the result should mention TyVars not TcTyVars
in
- mappM check_pred simpl_theta `thenM_`
- checkAmbiguity tvs simpl_theta tv_set `thenM_`
+ addNoInstanceErrs Nothing [] bad_insts `thenM_`
+ mapM_ (addErrTc . badDerivedPred) weird_preds `thenM_`
+ checkAmbiguity tvs simpl_theta tv_set `thenM_`
returnM (substTheta rev_env simpl_theta)
where
doc = ptext SLIT("deriving classes for a data type")
= newDicts DataDeclOrigin theta `thenM` \ wanteds ->
simpleReduceLoop doc reduceMe wanteds `thenM` \ (frees, _, irreds) ->
ASSERT( null frees ) -- try_me never returns Free
- mappM (addErrTc . noInstErr) irreds `thenM_`
+ addNoInstanceErrs Nothing [] irreds `thenM_`
if null irreds then
returnM ()
else
plural [x] = empty
plural xs = char 's'
-
-addTopIPErrs tidy_env tidy_dicts
+addTopIPErrs dicts
= groupErrs report tidy_dicts
where
+ (tidy_env, tidy_dicts) = tidyInsts dicts
report dicts = addErrTcM (tidy_env, mk_msg dicts)
mk_msg dicts = addInstLoc dicts (ptext SLIT("Unbound implicit parameter") <>
plural tidy_dicts <+> pprInsts tidy_dicts)
--- Used for top-level irreducibles
-addTopInstanceErrs tidy_env tidy_dicts
- = groupErrs report tidy_dicts
+addNoInstanceErrs :: Maybe SDoc -- Nothing => top level
+ -- Just d => d describes the construct
+ -> [Inst] -- What is given by the context or type sig
+ -> [Inst] -- What is wanted
+ -> TcM ()
+addNoInstanceErrs mb_what givens []
+ = returnM ()
+addNoInstanceErrs mb_what givens dicts
+ = -- Some of the dicts are here because there is no instances
+ -- and some because there are too many instances (overlap)
+ -- The first thing we do is separate them
+ getDOpts `thenM` \ dflags ->
+ tcGetInstEnvs `thenM` \ inst_envs ->
+ let
+ (tidy_env1, tidy_givens) = tidyInsts givens
+ (tidy_env2, tidy_dicts) = tidyMoreInsts tidy_env1 dicts
+
+ -- Run through the dicts, generating a message for each
+ -- overlapping one, but simply accumulating all the
+ -- no-instance ones so they can be reported as a group
+ (overlap_doc, no_inst_dicts) = foldl check_overlap (empty, []) tidy_dicts
+ check_overlap (overlap_doc, no_inst_dicts) dict
+ | not (isClassDict dict) = (overlap_doc, dict : no_inst_dicts)
+ | otherwise
+ = case lookupInstEnv dflags inst_envs clas tys of
+ res@(ms, _)
+ | length ms > 1 -> (mk_overlap_msg dict res $$ overlap_doc, no_inst_dicts)
+ | otherwise -> (overlap_doc, dict : no_inst_dicts) -- No match
+ -- NB: there can be exactly one match, in the case where we have
+ -- instance C a where ...
+ -- (In this case, lookupInst doesn't bother to look up,
+ -- unless -fallow-undecidable-instances is set.)
+ -- So we report this as "no instance" rather than "overlap"; the fix is
+ -- to specify -fallow-undecidable-instances, but we leave that to the programmer!
+ where
+ (clas,tys) = getDictClassTys dict
+ in
+ mk_probable_fix tidy_env2 mb_what no_inst_dicts `thenM` \ (tidy_env3, probable_fix) ->
+ let
+ no_inst_doc | null no_inst_dicts = empty
+ | otherwise = vcat [addInstLoc no_inst_dicts heading, probable_fix]
+ heading | null givens = ptext SLIT("No instance") <> plural no_inst_dicts <+>
+ ptext SLIT("for") <+> pprInsts no_inst_dicts
+ | otherwise = sep [ptext SLIT("Could not deduce") <+> pprInsts no_inst_dicts,
+ nest 2 $ ptext SLIT("from the context") <+> pprInsts tidy_givens]
+ in
+ addErrTcM (tidy_env3, no_inst_doc $$ overlap_doc)
+
where
- report dicts = mkMonomorphismMsg tidy_env dicts `thenM` \ (tidy_env, mono_msg) ->
- addErrTcM (tidy_env, mk_msg dicts $$ mono_msg)
- mk_msg dicts = addInstLoc dicts (ptext SLIT("No instance") <> plural tidy_dicts <+>
- ptext SLIT("for") <+> pprInsts tidy_dicts)
-
+ mk_overlap_msg dict (matches, unifiers)
+ = vcat [ addInstLoc [dict] ((ptext SLIT("Overlapping instances for") <+> ppr dict)),
+ sep [ptext SLIT("Matching instances") <> colon,
+ nest 2 (pprDFuns (dfuns ++ unifiers))],
+ if null unifiers
+ then empty
+ else parens (ptext SLIT("The choice depends on the instantiation of") <+>
+ quotes (pprWithCommas ppr (varSetElems (tyVarsOfInst dict))))]
+ where
+ dfuns = [df | (_, (_,_,df)) <- matches]
+
+ mk_probable_fix tidy_env Nothing dicts -- Top level
+ = mkMonomorphismMsg tidy_env dicts
+ mk_probable_fix tidy_env (Just what) dicts -- Nested (type signatures, instance decls)
+ = returnM (tidy_env, sep [ptext SLIT("Probable fix:"), nest 2 fix1, nest 2 fix2])
+ where
+ fix1 = sep [ptext SLIT("Add") <+> pprInsts dicts,
+ ptext SLIT("to the") <+> what]
+
+ fix2 | null instance_dicts = empty
+ | otherwise = ptext SLIT("Or add an instance declaration for")
+ <+> pprInsts instance_dicts
+ instance_dicts = [d | d <- dicts, isClassDict d, not (isTyVarDict d)]
+ -- Insts for which it is worth suggesting an adding an instance declaration
+ -- Exclude implicit parameters, and tyvar dicts
-addTopAmbigErrs (tidy_env, tidy_dicts)
+
+addTopAmbigErrs dicts
-- Divide into groups that share a common set of ambiguous tyvars
= mapM report (equivClasses cmp [(d, tvs_of d) | d <- tidy_dicts])
where
+ (tidy_env, tidy_dicts) = tidyInsts dicts
+
tvs_of :: Inst -> [TcTyVar]
tvs_of d = varSetElems (tyVarsOfInst d)
cmp (_,tvs1) (_,tvs2) = tvs1 `compare` tvs2
report :: [(Inst,[TcTyVar])] -> TcM ()
- report pairs@((_,tvs) : _) -- The pairs share a common set of ambiguous tyvars
+ report pairs@((inst,tvs) : _) -- The pairs share a common set of ambiguous tyvars
= mkMonomorphismMsg tidy_env dicts `thenM` \ (tidy_env, mono_msg) ->
+ addSrcSpan (instLocSrcSpan (instLoc inst)) $
+ -- the location of the first one will do for the err message
addErrTcM (tidy_env, msg $$ mono_msg)
where
dicts = map fst pairs
msg = sep [text "Ambiguous type variable" <> plural tvs <+>
- pprQuotedList tvs <+> text "in these top-level constraint" <> plural dicts,
+ pprQuotedList tvs <+> in_msg,
nest 2 (pprInstsInFull dicts)]
+ in_msg | isSingleton dicts = text "in the top-level constraint:"
+ | otherwise = text "in these top-level constraints:"
mkMonomorphismMsg :: TidyEnv -> [Inst] -> TcM (TidyEnv, Message)
quotes (ppr default_ty),
pprInstsInFull tidy_dicts]
-complainCheck doc givens irreds
- = mappM zonkInst given_dicts_and_ips `thenM` \ givens' ->
- groupErrs (addNoInstanceErrs doc givens') irreds `thenM_`
- returnM ()
- where
- given_dicts_and_ips = filter (not . isMethod) givens
- -- Filter out methods, which are only added to
- -- the given set as an optimisation
-
-addNoInstanceErrs what_doc givens dicts
- = getDOpts `thenM` \ dflags ->
- tcGetInstEnv `thenM` \ inst_env ->
- let
- (tidy_env1, tidy_givens) = tidyInsts givens
- (tidy_env2, tidy_dicts) = tidyMoreInsts tidy_env1 dicts
-
- doc = vcat [addInstLoc dicts $
- sep [herald <+> pprInsts tidy_dicts,
- nest 4 $ ptext SLIT("from the context") <+> pprInsts tidy_givens],
- ambig_doc,
- ptext SLIT("Probable fix:"),
- nest 4 fix1,
- nest 4 fix2]
-
- herald = ptext SLIT("Could not") <+> unambig_doc <+> ptext SLIT("deduce")
- unambig_doc | ambig_overlap = ptext SLIT("unambiguously")
- | otherwise = empty
-
- -- The error message when we don't find a suitable instance
- -- is complicated by the fact that sometimes this is because
- -- there is no instance, and sometimes it's because there are
- -- too many instances (overlap). See the comments in TcEnv.lhs
- -- with the InstEnv stuff.
-
- ambig_doc
- | not ambig_overlap = empty
- | otherwise
- = vcat [ptext SLIT("The choice of (overlapping) instance declaration"),
- nest 4 (ptext SLIT("depends on the instantiation of") <+>
- quotes (pprWithCommas ppr (varSetElems (tyVarsOfInsts tidy_dicts))))]
-
- fix1 = sep [ptext SLIT("Add") <+> pprInsts tidy_dicts,
- ptext SLIT("to the") <+> what_doc]
-
- fix2 | null instance_dicts
- = empty
- | otherwise
- = ptext SLIT("Or add an instance declaration for") <+> pprInsts instance_dicts
-
- instance_dicts = [d | d <- tidy_dicts, isClassDict d, not (isTyVarDict d)]
- -- Insts for which it is worth suggesting an adding an instance declaration
- -- Exclude implicit parameters, and tyvar dicts
-
- -- Checks for the ambiguous case when we have overlapping instances
- ambig_overlap = any ambig_overlap1 dicts
- ambig_overlap1 dict
- | isClassDict dict
- = case lookupInstEnv dflags inst_env clas tys of
- NoMatch ambig -> ambig
- other -> False
- | otherwise = False
- where
- (clas,tys) = getDictClassTys dict
- in
- addErrTcM (tidy_env2, doc)
-
-- Used for the ...Thetas variants; all top level
-noInstErr pred = ptext SLIT("No instance for") <+> quotes (ppr pred)
-
badDerivedPred pred
= vcat [ptext SLIT("Can't derive instances where the instance context mentions"),
ptext SLIT("type variables that are not data type parameters"),
nest 4 (pprInstsInFull stack)]
reduceDepthMsg n stack = nest 4 (pprInstsInFull stack)
-
------------------------------------------------
-addCantGenErr inst
- = addErrTc (sep [ptext SLIT("Cannot generalise these overloadings (in a _ccall_):"),
- nest 4 (ppr inst <+> pprInstLoc (instLoc inst))])
\end{code}