[project @ 2003-06-20 11:14:18 by simonpj]
[ghc-hetmet.git] / ghc / compiler / typecheck / TcSimplify.lhs
index 758659a..999d390 100644 (file)
@@ -19,7 +19,7 @@ module TcSimplify (
 #include "HsVersions.h"
 
 import {-# SOURCE #-} TcUnify( unifyTauTy )
-
+import TcEnv           -- temp
 import HsSyn           ( MonoBinds(..), HsExpr(..), andMonoBinds, andMonoBindList )
 import TcHsSyn         ( TcExpr, TcId,
                          TcMonoBinds, TcDictBinds
@@ -35,11 +35,11 @@ import Inst         ( lookupInst, LookupInstResult(..),
                          instBindingRequired, instCanBeGeneralised,
                          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),
@@ -57,11 +57,13 @@ 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}
@@ -567,6 +569,7 @@ inferLoop doc tau_tvs wanteds
          | 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) ->
 
@@ -739,7 +742,7 @@ tcSimplCheck doc get_qtvs givens wanted_lie
       =                -- Step 1
        mappM zonkInst givens   `thenM` \ givens' ->
        mappM zonkInst wanteds  `thenM` \ wanteds' ->
-       get_qtvs                        `thenM` \ qtvs' ->
+       get_qtvs                `thenM` \ qtvs' ->
 
                    -- Step 2
        let
@@ -783,14 +786,13 @@ tcSimplifyRestricted doc tau_tvs wanteds
        --      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' ->
@@ -800,6 +802,10 @@ tcSimplifyRestricted doc tau_tvs wanteds
        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
@@ -814,19 +820,28 @@ tcSimplifyRestricted doc tau_tvs wanteds
        -- 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}
 
 
@@ -905,12 +920,10 @@ this bracket again at its usage site.
 \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}
 
 
@@ -1606,8 +1619,12 @@ It's OK: the final zonking stage should zap y to (), which is fine.
 
 \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
@@ -1634,8 +1651,8 @@ tcSimplifyTop wanteds
     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
@@ -1648,7 +1665,7 @@ tcSimplifyTop wanteds
        --      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
@@ -1731,7 +1748,7 @@ disambigGroup dicts
     tryM (try_default default_tys)     `thenM` \ mb_ty ->
     case mb_ty of {
        Left _ ->       -- If not, add an AmbigErr
-                 addAmbigErrs dicts    `thenM_`
+                 addTopAmbigErrs (tidyInsts dicts)     `thenM_`
                  returnM EmptyMonoBinds ;
 
        Right chosen_default_ty ->
@@ -1748,11 +1765,11 @@ disambigGroup dicts
   | 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
@@ -1901,61 +1918,109 @@ from the insts, or just whatever seems to be around in the monad just
 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
@@ -1969,7 +2034,8 @@ addNoInstanceErrs what_doc givens dicts
        (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:"),
@@ -2016,7 +2082,7 @@ addNoInstanceErrs what_doc givens dicts
                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)