#include "HsVersions.h"
import {-# SOURCE #-} TcUnify( unifyTauTy )
-
+import TcEnv -- temp
import HsSyn ( MonoBinds(..), HsExpr(..), andMonoBinds, andMonoBindList )
import TcHsSyn ( TcExpr, TcId,
TcMonoBinds, TcDictBinds
instToId, tyVarsOfInsts, cloneDict,
ipNamesOfInsts, ipNamesOfInst, dictPred,
instBindingRequired, instCanBeGeneralised,
- newDictsFromOld, newMethodAtLoc,
+ newDictsFromOld, tcInstClassOp,
getDictClassTys, isTyVarDict,
- instLoc, pprInst, zonkInst, tidyInsts, tidyMoreInsts,
+ instLoc, zonkInst, tidyInsts, tidyMoreInsts,
Inst, pprInsts, pprInstsInFull,
isIPDict, isInheritableInst
)
-import TcEnv ( tcGetGlobalTyVars, tcGetInstEnv, tcLookupId )
+import TcEnv ( tcGetGlobalTyVars, tcGetInstEnv, tcLookupId, findGlobals )
import InstEnv ( lookupInstEnv, classInstEnv, InstLookupResult(..) )
import TcMType ( zonkTcTyVarsAndFV, tcInstTyVars, checkAmbiguity )
import TcType ( TcTyVar, TcTyVarSet, ThetaType, TyVarDetails(VanillaTv),
import NameSet ( NameSet, mkNameSet, elemNameSet )
import Class ( classBigSig )
import FunDeps ( oclose, grow, improve, pprEquationDoc )
-import PrelInfo ( isNumericClass, isCreturnableClass, isCcallishClass,
- splitName, fstName, sndName )
+import PrelInfo ( isNumericClass, isCreturnableClass, isCcallishClass )
+import PrelNames ( splitName, fstName, sndName )
import Subst ( mkTopTyVarSubst, substTheta, substTy )
import TysWiredIn ( unitTy, pairTyCon )
+import ErrUtils ( Message )
import VarSet
+import VarEnv ( TidyEnv )
import FiniteMap
import Outputable
import ListSetOps ( equivClasses )
-import Util ( zipEqual )
+import Util ( zipEqual, isSingleton )
import List ( partition )
import CmdLineOpts
\end{code}
| 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) ->
= -- Step 1
mappM zonkInst givens `thenM` \ givens' ->
mappM zonkInst wanteds `thenM` \ wanteds' ->
- get_qtvs `thenM` \ qtvs' ->
+ get_qtvs `thenM` \ qtvs' ->
-- Step 2
let
-- 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 `AndMonoBinds` binds1)
\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}
| otherwise
= tcLookupId splitName `thenM` \ split_id ->
- newMethodAtLoc (instLoc wanted) split_id
- [linearInstType wanted] `thenM` \ split_inst ->
+ tcInstClassOp (instLoc wanted) split_id
+ [linearInstType wanted] `thenM` \ split_inst ->
returnM (addToFM avails wanted (Linear 2 split_inst avail), [split_inst])
where
\begin{code}
tcSimplifyTop :: [Inst] -> TcM TcDictBinds
+-- The TcLclEnv should be valid here, solely to improve
+-- error message generation for the monomorphism restriction
tcSimplifyTop wanteds
- = simpleReduceLoop (text "tcSimplTop") reduceMe wanteds `thenM` \ (frees, binds, irreds) ->
+ = getLclEnv `thenM` \ lcl_env ->
+ traceTc (text "tcSimplifyTop" <+> ppr (lclEnvElts lcl_env)) `thenM_`
+ simpleReduceLoop (text "tcSimplTop") reduceMe wanteds `thenM` \ (frees, binds, irreds) ->
ASSERT( null frees )
let
in
-- Report definite errors
- mappM (addTopInstanceErrs tidy_env) (groupInsts no_insts) `thenM_`
- mappM (addTopIPErrs tidy_env) (groupInsts bad_ips) `thenM_`
+ addTopInstanceErrs tidy_env no_insts `thenM_`
+ addTopIPErrs tidy_env 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
- mappM (addAmbigErr tidy_env) ambigs `thenM_`
+ addTopAmbigErrs (tidy_env, ambigs) `thenM_`
-- Disambiguate the ones that look feasible
mappM disambigGroup std_oks
= failM
try_default (default_ty : default_tys)
- = tryTc_ (try_default default_tys) $ -- If default_ty fails, we try
+ = tryTcLIE_ (try_default default_tys) $ -- If default_ty fails, we try
-- default_tys instead
tcSimplifyDefault theta `thenM` \ _ ->
returnM default_ty
where
theta = [mkClassPred clas [default_ty] | clas <- classes]
in
- -- See if any default works, and if so bind the type variable to it
- -- If not, add an AmbigErr
- recoverM (addAmbigErrs dicts `thenM_`
- returnM EmptyMonoBinds) $
+ -- 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 ;
- try_default default_tys `thenM` \ chosen_default_ty ->
+ Right chosen_default_ty ->
- -- Bind the type variable and reduce the context, for real this time
+ -- If so, bind the type variable
+ -- and reduce the context, for real this time
unifyTauTy chosen_default_ty (mkTyVarTy tyvar) `thenM_`
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
+ 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_`
+ unifyTauTy (mkTyVarTy tyvar) unitTy `thenM_`
returnM EmptyMonoBinds
| otherwise -- No defaults
- = addAmbigErrs dicts `thenM_`
+ = addTopAmbigErrs (tidyInsts dicts) `thenM_`
returnM EmptyMonoBinds
where
now?
\begin{code}
-groupInsts :: [Inst] -> [[Inst]]
+groupErrs :: ([Inst] -> TcM ()) -- Deal with one group
+ -> [Inst] -- The offending Insts
+ -> TcM ()
-- Group together insts with the same origin
-- We want to report them together in error messages
-groupInsts [] = []
-groupInsts (inst:insts) = (inst:friends) : groupInsts others
- where
- -- (It may seem a bit crude to compare the error messages,
- -- but it makes sure that we combine just what the user sees,
- -- and it avoids need equality on InstLocs.)
- (friends, others) = partition is_friend insts
- loc_msg = showSDoc (pprInstLoc (instLoc inst))
- is_friend friend = showSDoc (pprInstLoc (instLoc friend)) == loc_msg
+
+groupErrs report_err []
+ = returnM ()
+groupErrs report_err (inst:insts)
+ = do_one (inst:friends) `thenM_`
+ groupErrs report_err others
+
+ where
+ -- (It may seem a bit crude to compare the error messages,
+ -- but it makes sure that we combine just what the user sees,
+ -- and it avoids need equality on InstLocs.)
+ (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)
+ -- Add location and context information derived from the Insts
+
+-- Add the "arising from..." part to a message about bunch of dicts
+addInstLoc :: [Inst] -> Message -> Message
+addInstLoc insts msg = msg $$ nest 2 (pprInstLoc (instLoc (head insts)))
plural [x] = empty
plural xs = char 's'
+
addTopIPErrs tidy_env tidy_dicts
- = addInstErrTcM (instLoc (head tidy_dicts))
- (tidy_env,
- ptext SLIT("Unbound implicit parameter") <> plural tidy_dicts <+> pprInsts tidy_dicts)
+ = groupErrs report tidy_dicts
+ where
+ 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
- = addInstErrTcM (instLoc (head tidy_dicts))
- (tidy_env,
- ptext SLIT("No instance") <> plural tidy_dicts <+>
- ptext SLIT("for") <+> pprInsts tidy_dicts)
-
-addAmbigErrs dicts
- = mappM (addAmbigErr tidy_env) tidy_dicts
+ = groupErrs report tidy_dicts
where
- (tidy_env, tidy_dicts) = tidyInsts dicts
-
-addAmbigErr tidy_env tidy_dict
- = addInstErrTcM (instLoc tidy_dict)
- (tidy_env,
- sep [text "Ambiguous type variable(s)" <+> pprQuotedList ambig_tvs,
- nest 4 (text "in the constraint" <+> quotes (pprInst tidy_dict))])
+ 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)
+
+
+addTopAmbigErrs (tidy_env, tidy_dicts)
+-- Divide into groups that share a common set of ambiguous tyvars
+ = mapM report (equivClasses cmp [(d, tvs_of d) | d <- tidy_dicts])
where
- ambig_tvs = varSetElems (tyVarsOfInst tidy_dict)
+ 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
+ = mkMonomorphismMsg tidy_env dicts `thenM` \ (tidy_env, mono_msg) ->
+ addErrTcM (tidy_env, msg $$ mono_msg)
+ where
+ dicts = map fst pairs
+ msg = sep [text "Ambiguous type variable" <> plural tvs <+>
+ 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)
+-- There's an error with these Insts; if they have free type variables
+-- it's probably caused by the monomorphism restriction.
+-- Try to identify the offending variable
+-- ASSUMPTION: the Insts are fully zonked
+mkMonomorphismMsg tidy_env insts
+ | isEmptyVarSet inst_tvs
+ = returnM (tidy_env, empty)
+ | otherwise
+ = findGlobals inst_tvs tidy_env `thenM` \ (tidy_env, docs) ->
+ returnM (tidy_env, mk_msg docs)
+ where
+ inst_tvs = tyVarsOfInsts insts
+
+ mk_msg [] = empty -- This happens in things like
+ -- f x = show (read "foo")
+ -- whre monomorphism doesn't play any role
+ mk_msg docs = vcat [ptext SLIT("Possible cause: the monomorphism restriction applied to the following:"),
+ nest 2 (vcat docs),
+ ptext SLIT("Probable fix: give these definition(s) an explicit type signature")]
+
warnDefault dicts default_ty
= doptM Opt_WarnTypeDefaults `thenM` \ warn_flag ->
- addSrcLoc (get_loc (head dicts)) (warnTc warn_flag warn_msg)
+ addInstCtxt (instLoc (head dicts)) (warnTc warn_flag warn_msg)
where
-- Tidy them first
(_, tidy_dicts) = tidyInsts dicts
- get_loc i = case instLoc i of { (_,loc,_) -> loc }
warn_msg = vcat [ptext SLIT("Defaulting the following constraint(s) to type") <+>
quotes (ppr default_ty),
pprInstsInFull tidy_dicts]
complainCheck doc givens irreds
- = mappM zonkInst given_dicts_and_ips `thenM` \ givens' ->
- mappM (addNoInstanceErrs doc givens') (groupInsts irreds) `thenM_`
+ = mappM zonkInst given_dicts_and_ips `thenM` \ givens' ->
+ groupErrs (addNoInstanceErrs doc givens') irreds `thenM_`
returnM ()
where
given_dicts_and_ips = filter (not . isMethod) givens
(tidy_env1, tidy_givens) = tidyInsts givens
(tidy_env2, tidy_dicts) = tidyMoreInsts tidy_env1 dicts
- doc = vcat [sep [herald <+> pprInsts tidy_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:"),
where
(clas,tys) = getDictClassTys dict
in
- addInstErrTcM (instLoc (head dicts)) (tidy_env2, doc)
+ addErrTcM (tidy_env2, doc)
-- Used for the ...Thetas variants; all top level
noInstErr pred = ptext SLIT("No instance for") <+> quotes (ppr pred)