[project @ 2002-04-02 13:21:36 by simonpj]
[ghc-hetmet.git] / ghc / compiler / typecheck / Inst.lhs
index 2d46001..6b25d8a 100644 (file)
@@ -9,19 +9,20 @@ module Inst (
        plusLIEs, mkLIE, isEmptyLIE, lieToList, listToLIE,
 
        Inst, 
-       pprInst, pprInsts, pprInstsInFull, tidyInsts,
+       pprInst, pprInsts, pprInstsInFull, tidyInsts, tidyMoreInsts,
 
-       newDictsFromOld, newDicts, 
-       newMethod, newMethodWithGivenTy, newOverloadedLit,
-       newIPDict, tcInstId,
+       newDictsFromOld, newDicts, cloneDict,
+       newMethod, newMethodWithGivenTy, newMethodAtLoc,
+       newOverloadedLit, newIPDict, tcInstCall, tcInstDataCon,
 
-       tyVarsOfInst, tyVarsOfInsts, tyVarsOfLIE, instLoc, getDictClassTys,
-       getIPs,
-       predsOfInsts, predsOfInst,
+       tyVarsOfInst, tyVarsOfInsts, tyVarsOfLIE, 
+       ipNamesOfInst, ipNamesOfInsts, predsOfInst, predsOfInsts,
+       instLoc, getDictClassTys, dictPred,
 
        lookupInst, lookupSimpleInst, LookupInstResult(..),
 
-       isDict, isClassDict, isMethod, instMentionsIPs,
+       isDict, isClassDict, isMethod, 
+       isLinearInst, linearInstType,
        isTyVarDict, isStdClassTyVarDict, isMethodFor, 
        instBindingRequired, instCanBeGeneralised,
 
@@ -33,36 +34,35 @@ module Inst (
 
 #include "HsVersions.h"
 
-import CmdLineOpts ( opt_NoMethodSharing )
 import HsSyn   ( HsLit(..), HsOverLit(..), HsExpr(..) )
-import TcHsSyn ( TcExpr, TcId, 
+import TcHsSyn ( TcExpr, TcId, TypecheckedHsExpr,
                  mkHsTyApp, mkHsDictApp, mkHsConApp, zonkId
                )
 import TcMonad
 import TcEnv   ( TcIdSet, tcGetInstEnv, tcLookupId )
 import InstEnv ( InstLookupResult(..), lookupInstEnv )
-import TcMType ( zonkTcType, zonkTcTypes, zonkTcPredType,
-                 zonkTcThetaType, tcInstTyVar, tcInstType,
+import TcMType ( zonkTcType, zonkTcTypes, zonkTcPredType, zapToType,
+                 zonkTcThetaType, tcInstTyVar, tcInstType, tcInstTyVars
                )
-import TcType  ( Type, 
-                 SourceType(..), PredType, ThetaType,
-                 tcSplitForAllTys, tcSplitForAllTys, 
-                 tcSplitMethodTy, tcSplitRhoTy, tcFunArgTy,
+import TcType  ( Type, TcType, TcThetaType, TcPredType, TcTauType, TcTyVarSet,
+                 SourceType(..), PredType, ThetaType, TyVarDetails(VanillaTv),
+                 tcSplitForAllTys, tcSplitForAllTys, mkTyConApp,
+                 tcSplitMethodTy, tcSplitPhiTy, tcFunArgTy,
                  isIntTy,isFloatTy, isIntegerTy, isDoubleTy,
                  tcIsTyVarTy, mkPredTy, mkTyVarTy, mkTyVarTys,
                  tyVarsOfType, tyVarsOfTypes, tyVarsOfPred, tidyPred,
-                 predMentionsIPs, isClassPred, isTyVarClassPred, 
+                 isClassPred, isTyVarClassPred, isLinearPred,
                  getClassPredTys, getClassPredTys_maybe, mkPredName,
                  tidyType, tidyTypes, tidyFreeTyVars,
                  tcCmpType, tcCmpTypes, tcCmpPred
                )
 import CoreFVs ( idFreeTyVars )
 import Class   ( Class )
-import Id      ( Id, idName, idType, mkUserLocal, mkSysLocal, mkLocalId )
+import DataCon ( dataConSig )
+import Id      ( Id, idName, idType, mkUserLocal, mkSysLocal, mkLocalId, setIdUnique )
 import PrelInfo        ( isStandardClass, isCcallishClass, isNoDictClass )
 import Name    ( Name, mkMethodOcc, getOccName )
-import NameSet ( NameSet )
-import PprType ( pprPred )     
+import PprType ( pprPred, pprParendType )      
 import Subst   ( emptyInScopeSet, mkSubst, 
                  substTy, substTyWith, substTheta, mkTyVarSubst, mkTopTyVarSubst
                )
@@ -71,7 +71,9 @@ import VarEnv ( TidyEnv, lookupSubstEnv, SubstResult(..) )
 import VarSet  ( elemVarSet, emptyVarSet, unionVarSet )
 import TysWiredIn ( floatDataCon, doubleDataCon )
 import PrelNames( fromIntegerName, fromRationalName )
-import Util    ( thenCmp )
+import Util    ( thenCmp, equalLength )
+import BasicTypes( IPName(..), mapIPName, ipNameName )
+
 import Bag
 import Outputable
 \end{code}
@@ -99,7 +101,7 @@ zonkLIE :: LIE -> NF_TcM LIE
 zonkLIE lie = mapBagNF_Tc zonkInst lie
 
 pprInsts :: [Inst] -> SDoc
-pprInsts insts = parens (sep (punctuate comma (map pprInst insts)))
+pprInsts insts  = parens (sep (punctuate comma (map pprInst insts)))
 
 
 pprInstsInFull insts
@@ -204,6 +206,9 @@ instLoc (Dict _ _         loc) = loc
 instLoc (Method _ _ _ _ _ loc) = loc
 instLoc (LitInst _ _ _    loc) = loc
 
+dictPred (Dict _ pred _ ) = pred
+dictPred inst            = pprPanic "dictPred" (ppr inst)
+
 getDictClassTys (Dict _ pred _) = getClassPredTys pred
 
 predsOfInsts :: [Inst] -> [PredType]
@@ -217,9 +222,16 @@ predsOfInst (LitInst _ _ _ _)           = []
        -- But Num and Fractional have only one parameter and no functional
        -- dependencies, so I think no caller of predsOfInst will care.
 
-ipsOfPreds theta = [(n,ty) | IParam n ty <- theta]
+ipNamesOfInsts :: [Inst] -> [Name]
+ipNamesOfInst  :: Inst   -> [Name]
+-- Get the implicit parameters mentioned by these Insts
+-- NB: ?x and %x get different Names
 
-getIPs inst = ipsOfPreds (predsOfInst inst)
+ipNamesOfInsts insts = [n | inst <- insts, n <- ipNamesOfInst inst]
+
+ipNamesOfInst (Dict _ (IParam n _) _)  = [ipNameName n]
+ipNamesOfInst (Method _ _ _ theta _ _) = [ipNameName n | IParam n _ <- theta]
+ipNamesOfInst other                   = []
 
 tyVarsOfInst :: Inst -> TcTyVarSet
 tyVarsOfInst (LitInst _ _ ty _)      = tyVarsOfType  ty
@@ -255,12 +267,17 @@ isMethodFor :: TcIdSet -> Inst -> Bool
 isMethodFor ids (Method uniq id tys _ _ loc) = id `elemVarSet` ids
 isMethodFor ids inst                        = False
 
-instMentionsIPs :: Inst -> NameSet -> Bool
-  -- True if the Inst mentions any of the implicit
-  -- parameters in the supplied set of names
-instMentionsIPs (Dict _ pred _)          ip_names = pred `predMentionsIPs` ip_names
-instMentionsIPs (Method _ _ _ theta _ _) ip_names = any (`predMentionsIPs` ip_names) theta
-instMentionsIPs other                   ip_names = False
+isLinearInst :: Inst -> Bool
+isLinearInst (Dict _ pred _) = isLinearPred pred
+isLinearInst other          = False
+       -- We never build Method Insts that have
+       -- linear implicit paramters in them.
+       -- Hence no need to look for Methods
+       -- See TcExpr.tcId 
+
+linearInstType :: Inst -> TcType       -- %x::t  -->  t
+linearInstType (Dict _ (IParam _ ty) _) = ty
+
 
 isStdClassTyVarDict (Dict _ pred _) = case getClassPredTys_maybe pred of
                                        Just (clas, [ty]) -> isStandardClass clas && tcIsTyVarTy ty
@@ -275,7 +292,6 @@ must be witnessed by an actual binding; the second tells whether an
 \begin{code}
 instBindingRequired :: Inst -> Bool
 instBindingRequired (Dict _ (ClassP clas _) _) = not (isNoDictClass clas)
-instBindingRequired (Dict _ (IParam _ _) _)    = False
 instBindingRequired other                     = True
 
 instCanBeGeneralised :: Inst -> Bool
@@ -298,6 +314,10 @@ newDicts orig theta
   = tcGetInstLoc orig          `thenNF_Tc` \ loc ->
     newDictsAtLoc loc theta
 
+cloneDict :: Inst -> NF_TcM Inst
+cloneDict (Dict id ty loc) = tcGetUnique       `thenNF_Tc` \ uniq ->
+                            returnNF_Tc (Dict (setIdUnique id uniq) ty loc)
+
 newDictsFromOld :: Inst -> TcThetaType -> NF_TcM [Inst]
 newDictsFromOld (Dict _ _ loc) theta = newDictsAtLoc loc theta
 
@@ -312,12 +332,20 @@ newDictsAtLoc inst_loc@(_,loc,_) theta
   where
     mk_dict uniq pred = Dict (mkLocalId (mkPredName uniq loc pred) (mkPredTy pred)) pred inst_loc
 
--- For implicit parameters, since there is only one in scope
--- at any time, we use the name of the implicit parameter itself
-newIPDict orig name ty
-  = tcGetInstLoc orig                  `thenNF_Tc` \ inst_loc ->
-    returnNF_Tc (Dict (mkLocalId name (mkPredTy pred)) pred inst_loc)
-  where pred = IParam name ty
+-- For vanilla implicit parameters, there is only one in scope
+-- at any time, so we used to use the name of the implicit parameter itself
+-- But with splittable implicit parameters there may be many in 
+-- scope, so we make up a new name.
+newIPDict :: InstOrigin -> IPName Name -> Type 
+         -> NF_TcM (IPName Id, Inst)
+newIPDict orig ip_name ty
+  = tcGetInstLoc orig                  `thenNF_Tc` \ inst_loc@(_,loc,_) ->
+    tcGetUnique                                `thenNF_Tc` \ uniq ->
+    let
+       pred = IParam ip_name ty
+       id   = mkLocalId (mkPredName uniq loc pred) (mkPredTy pred)
+    in
+    returnNF_Tc (mapIPName (\n -> id) ip_name, Dict id pred inst_loc)
 \end{code}
 
 
@@ -327,60 +355,40 @@ newIPDict orig name ty
 %*                                                                     *
 %************************************************************************
 
-tcInstId instantiates an occurrence of an Id.
-The instantiate_it loop runs round instantiating the Id.
-It has to be a loop because we are now prepared to entertain
-types like
-       f:: forall a. Eq a => forall b. Baz b => tau
-We want to instantiate this to
-       f2::tau         {f2 = f1 b (Baz b), f1 = f a (Eq a)}
-
-The -fno-method-sharing flag controls what happens so far as the LIE
-is concerned.  The default case is that for an overloaded function we 
-generate a "method" Id, and add the Method Inst to the LIE.  So you get
-something like
-       f :: Num a => a -> a
-       f = /\a (d:Num a) -> let m = (+) a d in \ (x:a) -> m x x
-If you specify -fno-method-sharing, the dictionary application 
-isn't shared, so we get
-       f :: Num a => a -> a
-       f = /\a (d:Num a) (x:a) -> (+) a d x x
-This gets a bit less sharing, but
-       a) it's better for RULEs involving overloaded functions
-       b) perhaps fewer separated lambdas
-
 
 \begin{code}
-tcInstId :: Id -> NF_TcM (TcExpr, LIE, TcType)
-tcInstId fun
-  | opt_NoMethodSharing  = loop_noshare (HsVar fun) (idType fun)
-  | otherwise           = loop_share fun
-  where
-    orig = OccurrenceOf fun
-    loop_noshare fun fun_ty
-      = tcInstType fun_ty              `thenNF_Tc` \ (tyvars, theta, tau) ->
-       let 
-           ty_app = mkHsTyApp fun (mkTyVarTys tyvars)
-       in
-        if null theta then             -- Is it overloaded?
-           returnNF_Tc (ty_app, emptyLIE, tau)
-       else
-           newDicts orig theta                                         `thenNF_Tc` \ dicts ->
-           loop_noshare (mkHsDictApp ty_app (map instToId dicts)) tau  `thenNF_Tc` \ (expr, lie, final_tau) ->
-           returnNF_Tc (expr, mkLIE dicts `plusLIE` lie, final_tau)
-
-    loop_share fun
-      = tcInstType (idType fun)                `thenNF_Tc` \ (tyvars, theta, tau) ->
-       let 
-           arg_tys = mkTyVarTys tyvars
-       in
-        if null theta then             -- Is it overloaded?
-           returnNF_Tc (mkHsTyApp (HsVar fun) arg_tys, emptyLIE, tau)
-       else
-               -- Yes, it's overloaded
-           newMethodWithGivenTy orig fun arg_tys theta tau     `thenNF_Tc` \ meth ->
-           loop_share (instToId meth)                          `thenNF_Tc` \ (expr, lie, final_tau) ->
-           returnNF_Tc (expr, unitLIE meth `plusLIE` lie, final_tau)
+tcInstCall :: InstOrigin  -> TcType -> NF_TcM (TypecheckedHsExpr -> TypecheckedHsExpr, LIE, TcType)
+tcInstCall orig fun_ty -- fun_ty is usually a sigma-type
+  = tcInstType VanillaTv fun_ty        `thenNF_Tc` \ (tyvars, theta, tau) ->
+    newDicts orig theta                `thenNF_Tc` \ dicts ->
+    let
+       inst_fn e = mkHsDictApp (mkHsTyApp e (mkTyVarTys tyvars)) (map instToId dicts)
+    in
+    returnNF_Tc (inst_fn, mkLIE dicts, tau)
+
+tcInstDataCon orig data_con
+  = let 
+       (tvs, stupid_theta, ex_tvs, ex_theta, arg_tys, tycon) = dataConSig data_con
+            -- We generate constraints for the stupid theta even when 
+            -- pattern matching (as the Report requires)
+    in
+    tcInstTyVars VanillaTv (ex_tvs ++ tvs)     `thenNF_Tc` \ (all_tvs', ty_args', tenv) ->
+    let
+       stupid_theta' = substTheta tenv stupid_theta
+       ex_theta'     = substTheta tenv ex_theta
+       arg_tys'      = map (substTy tenv) arg_tys
+
+       n_ex_tvs  = length ex_tvs
+       ex_tvs'   = take n_ex_tvs all_tvs'
+       result_ty = mkTyConApp tycon (drop n_ex_tvs ty_args')
+    in
+    newDicts orig stupid_theta'        `thenNF_Tc` \ stupid_dicts ->
+    newDicts orig ex_theta'    `thenNF_Tc` \ ex_dicts ->
+
+       -- Note that we return the stupid theta *only* in the LIE;
+       -- we don't otherwise use it at all
+    returnNF_Tc (ty_args', map instToId ex_dicts, arg_tys', result_ty,
+                mkLIE stupid_dicts, mkLIE ex_dicts, ex_tvs')
 
 
 newMethod :: InstOrigin
@@ -415,9 +423,9 @@ newMethodAtLoc inst_loc real_id tys
   =    -- Get the Id type and instantiate it at the specified types
     let
        (tyvars,rho)  = tcSplitForAllTys (idType real_id)
-       rho_ty        = ASSERT( length tyvars == length tys )
+       rho_ty        = ASSERT( equalLength tyvars tys )
                        substTy (mkTopTyVarSubst tyvars tys) rho
-       (theta, tau)  = tcSplitRhoTy rho_ty
+       (theta, tau)  = tcSplitPhiTy rho_ty
     in
     newMethodWith inst_loc real_id tys theta tau       `thenNF_Tc` \ meth_inst ->
     returnNF_Tc (meth_inst, instToId meth_inst)
@@ -433,16 +441,19 @@ newOverloadedLit :: InstOrigin
                 -> HsOverLit
                 -> TcType
                 -> NF_TcM (TcExpr, LIE)
-newOverloadedLit orig lit ty
-  | Just expr <- shortCutLit lit ty
+newOverloadedLit orig lit expected_ty
+  | Just expr <- shortCutLit lit expected_ty
   = returnNF_Tc (expr, emptyLIE)
 
   | otherwise
   = tcGetInstLoc orig          `thenNF_Tc` \ loc ->
     tcGetUnique                        `thenNF_Tc` \ new_uniq ->
+    zapToType expected_ty      `thenNF_Tc_` 
+       -- The expected type might be a 'hole' type variable, 
+       -- in which case we must zap it to an ordinary type variable
     let
-       lit_inst = LitInst lit_id lit ty loc
-       lit_id   = mkSysLocal SLIT("lit") new_uniq ty
+       lit_inst = LitInst lit_id lit expected_ty loc
+       lit_id   = mkSysLocal FSLIT("lit") new_uniq expected_ty
     in
     returnNF_Tc (HsVar (instToId lit_inst), unitLIE lit_inst)
 
@@ -519,7 +530,7 @@ pprInst (Dict u pred loc) = pprPred pred <+> show_uniq u
 
 pprInst m@(Method u id tys theta tau loc)
   = hsep [ppr id, ptext SLIT("at"), 
-         brackets (interppSP tys) {- ,
+         brackets (sep (map pprParendType tys)) {- ,
          ptext SLIT("theta"), ppr theta,
          ptext SLIT("tau"), ppr tau
          show_uniq u,
@@ -532,13 +543,16 @@ tidyInst env (LitInst u lit ty loc)            = LitInst u lit (tidyType env ty) loc
 tidyInst env (Dict u pred loc)              = Dict u (tidyPred env pred) loc
 tidyInst env (Method u id tys theta tau loc) = Method u id (tidyTypes env tys) theta tau loc
 
-tidyInsts :: [Inst] -> (TidyEnv, [Inst])
+tidyMoreInsts :: TidyEnv -> [Inst] -> (TidyEnv, [Inst])
 -- This function doesn't assume that the tyvars are in scope
 -- so it works like tidyOpenType, returning a TidyEnv
-tidyInsts insts 
-  = (env, map (tidyInst env) insts)
+tidyMoreInsts env insts
+  = (env', map (tidyInst env') insts)
   where
-    env = tidyFreeTyVars emptyTidyEnv (tyVarsOfInsts insts)
+    env' = tidyFreeTyVars env (tyVarsOfInsts insts)
+
+tidyInsts :: [Inst] -> (TidyEnv, [Inst])
+tidyInsts insts = tidyMoreInsts emptyTidyEnv insts
 \end{code}
 
 
@@ -560,23 +574,28 @@ lookupInst :: Inst
 -- Dictionaries
 
 lookupInst dict@(Dict _ (ClassP clas tys) loc)
-  = tcGetInstEnv               `thenNF_Tc` \ inst_env ->
-    case lookupInstEnv inst_env clas tys of
+  = getDOptsTc                 `thenNF_Tc` \ dflags ->
+    tcGetInstEnv               `thenNF_Tc` \ inst_env ->
+    case lookupInstEnv dflags inst_env clas tys of
 
       FoundInst tenv dfun_id
-       -> let
+       ->      -- It's possible that not all the tyvars are in
+               -- the substitution, tenv. For example:
+               --      instance C X a => D X where ...
+               -- (presumably there's a functional dependency in class C)
+               -- Hence the mk_ty_arg to instantiate any un-substituted tyvars.        
+          let
                (tyvars, rho) = tcSplitForAllTys (idType dfun_id)
                mk_ty_arg tv  = case lookupSubstEnv tenv tv of
                                   Just (DoneTy ty) -> returnNF_Tc ty
-                                  Nothing          -> tcInstTyVar tv   `thenNF_Tc` \ tc_tv ->
+                                  Nothing          -> tcInstTyVar VanillaTv tv `thenNF_Tc` \ tc_tv ->
                                                       returnTc (mkTyVarTy tc_tv)
           in
           mapNF_Tc mk_ty_arg tyvars    `thenNF_Tc` \ ty_args ->
           let
-               subst         = mkTyVarSubst tyvars ty_args
-               dfun_rho      = substTy subst rho
-               (theta, _)    = tcSplitRhoTy dfun_rho
-               ty_app        = mkHsTyApp (HsVar dfun_id) ty_args
+               dfun_rho   = substTy (mkTyVarSubst tyvars ty_args) rho
+               (theta, _) = tcSplitPhiTy dfun_rho
+               ty_app     = mkHsTyApp (HsVar dfun_id) ty_args
           in
           if null theta then
                returnNF_Tc (SimpleInst ty_app)
@@ -638,15 +657,14 @@ lookupSimpleInst :: Class
                 -> NF_TcM (Maybe ThetaType)    -- Here are the needed (c,t)s
 
 lookupSimpleInst clas tys
-  = tcGetInstEnv               `thenNF_Tc` \ inst_env -> 
-    case lookupInstEnv inst_env clas tys of
+  = getDOptsTc                 `thenNF_Tc` \ dflags ->
+    tcGetInstEnv               `thenNF_Tc` \ inst_env -> 
+    case lookupInstEnv dflags inst_env clas tys of
       FoundInst tenv dfun
        -> returnNF_Tc (Just (substTheta (mkSubst emptyInScopeSet tenv) theta))
         where
           (_, rho)  = tcSplitForAllTys (idType dfun)
-          (theta,_) = tcSplitRhoTy rho
+          (theta,_) = tcSplitPhiTy rho
 
       other  -> returnNF_Tc Nothing
 \end{code}
-
-