[project @ 2001-05-24 13:59:09 by simonpj]
[ghc-hetmet.git] / ghc / compiler / typecheck / TcInstDcls.lhs
index 324ee71..d2132a5 100644 (file)
@@ -12,7 +12,7 @@ module TcInstDcls ( tcInstDecls1, tcInstDecls2, tcAddDeclCtxt ) where
 import CmdLineOpts     ( DynFlag(..), dopt )
 
 import HsSyn           ( HsDecl(..), InstDecl(..), TyClDecl(..), HsType(..),
-                         MonoBinds(..), HsExpr(..),  HsLit(..), Sig(..), 
+                         MonoBinds(..), HsExpr(..),  HsLit(..), Sig(..), HsTyVarBndr(..),
                          andMonoBindList, collectMonoBinders, isClassDecl, toHsType
                        )
 import RnHsSyn         ( RenamedHsBinds, RenamedInstDecl, RenamedHsDecl, 
@@ -32,11 +32,11 @@ import TcEnv                ( TcEnv, tcExtendGlobalValEnv,
                          tcExtendTyVarEnvForMeths, 
                          tcAddImportedIdInfo, tcLookupClass,
                          InstInfo(..), pprInstInfo, simpleInstInfoTyCon, 
-                         simpleInstInfoTy, newDFunName, tcExtendTyVarEnv,
+                         simpleInstInfoTy, newDFunName,
                          isLocalThing,
                        )
 import InstEnv         ( InstEnv, extendInstEnv )
-import TcMonoType      ( tcTyVars, tcHsSigType, kcHsSigType, checkSigTyVars )
+import TcMonoType      ( tcHsTyVars, tcHsSigType, kcHsSigType, checkSigTyVars )
 import TcSimplify      ( tcSimplifyCheck )
 import HscTypes                ( HomeSymbolTable, DFunId,
                          ModDetails(..), PackageInstEnv, PersistentRenamerState
@@ -52,7 +52,7 @@ import FunDeps                ( checkInstFDs )
 import Generics                ( validGenericInstanceType )
 import Module          ( Module, foldModuleEnv )
 import Name            ( getSrcLoc )
-import NameSet         ( emptyNameSet, unitNameSet, nameSetToList )
+import NameSet         ( unitNameSet, nameSetToList )
 import PrelInfo                ( eRROR_ID )
 import PprType         ( pprClassPred, pprPred )
 import TyCon           ( TyCon, isSynTyCon )
@@ -65,6 +65,7 @@ import Type           ( splitDFunTy, isTyVarTy,
 import Subst           ( mkTopTyVarSubst, substTheta )
 import VarSet          ( varSetElems )
 import TysWiredIn      ( genericTyCons, isFFIArgumentTy, isFFIImportResultTy )
+import ForeignCall     ( Safety(..) )
 import PrelNames       ( cCallableClassKey, cReturnableClassKey, hasKey )
 import Name             ( Name )
 import SrcLoc           ( SrcLoc )
@@ -395,9 +396,10 @@ mkGenericInstance clas loc (hs_ty, binds)
   -- For example:      instance (C a, C b) => C (a+b) where { binds }
 
   =    -- Extract the universally quantified type variables
-    tcTyVars (nameSetToList (extractHsTyVars hs_ty)) 
-            (kcHsSigType hs_ty)                `thenTc` \ tyvars ->
-    tcExtendTyVarEnv tyvars                                    $
+    let
+       sig_tvs = map UserTyVar (nameSetToList (extractHsTyVars hs_ty))
+    in
+    tcHsTyVars sig_tvs (kcHsSigType hs_ty)     $ \ tyvars ->
 
        -- Type-check the instance type, and check its form
     tcHsSigType hs_ty                          `thenTc` \ inst_ty ->
@@ -606,7 +608,7 @@ tcInstDecl2 (InstInfo { iDFunId = dfun_id,
                -- Always inline the dfun; this is an experimental decision
                -- because it makes a big performance difference sometimes.
                -- Often it means we can do the method selection, and then
-               -- inline the method as well.  Marcin's idea.
+               -- inline the method as well.  Marcin's idea; see comments below.
 
        dict_rhs
          | null scs_and_meths
@@ -649,6 +651,96 @@ tcInstDecl2 (InstInfo { iDFunId = dfun_id,
              main_bind `AndMonoBinds` prag_binds)
 \end{code}
 
+               ------------------------------
+               Inlining dfuns unconditionally
+               ------------------------------
+
+The code above unconditionally inlines dict funs.  Here's why.
+Consider this program:
+
+    test :: Int -> Int -> Bool
+    test x y = (x,y) == (y,x) || test y x
+    -- Recursive to avoid making it inline.
+
+This needs the (Eq (Int,Int)) instance.  If we inline that dfun
+the code we end up with is good:
+
+    Test.$wtest =
+       \r -> case ==# [ww ww1] of wild {
+               PrelBase.False -> Test.$wtest ww1 ww;
+               PrelBase.True ->
+                 case ==# [ww1 ww] of wild1 {
+                   PrelBase.False -> Test.$wtest ww1 ww;
+                   PrelBase.True -> PrelBase.True [];
+                 };
+           };
+    Test.test = \r [w w1]
+           case w of w2 {
+             PrelBase.I# ww ->
+                 case w1 of w3 { PrelBase.I# ww1 -> Test.$wtest ww ww1; };
+           };
+
+If we don't inline the dfun, the code is not nearly as good:
+
+    (==) = case PrelTup.$fEq(,) PrelBase.$fEqInt PrelBase.$fEqInt of tpl {
+             PrelBase.:DEq tpl1 tpl2 -> tpl2;
+           };
+    
+    Test.$wtest =
+       \r [ww ww1]
+           let { y = PrelBase.I#! [ww1]; } in
+           let { x = PrelBase.I#! [ww]; } in
+           let { sat_slx = PrelTup.(,)! [y x]; } in
+           let { sat_sly = PrelTup.(,)! [x y];
+           } in
+             case == sat_sly sat_slx of wild {
+               PrelBase.False -> Test.$wtest ww1 ww;
+               PrelBase.True -> PrelBase.True [];
+             };
+    
+    Test.test =
+       \r [w w1]
+           case w of w2 {
+             PrelBase.I# ww ->
+                 case w1 of w3 { PrelBase.I# ww1 -> Test.$wtest ww ww1; };
+           };
+
+Why doesn't GHC inline $fEq?  Because it looks big:
+
+    PrelTup.zdfEqZ1T{-rcX-}
+       = \ @ a{-reT-} :: * @ b{-reS-} :: *
+            zddEq{-rf6-} _Ks :: {PrelBase.Eq{-23-} a{-reT-}}
+            zddEq1{-rf7-} _Ks :: {PrelBase.Eq{-23-} b{-reS-}} ->
+            let {
+              zeze{-rf0-} _Kl :: (b{-reS-} -> b{-reS-} -> PrelBase.Bool{-3c-})
+              zeze{-rf0-} = PrelBase.zeze{-01L-}@ b{-reS-} zddEq1{-rf7-} } in
+            let {
+              zeze1{-rf3-} _Kl :: (a{-reT-} -> a{-reT-} -> PrelBase.Bool{-3c-})
+              zeze1{-rf3-} = PrelBase.zeze{-01L-} @ a{-reT-} zddEq{-rf6-} } in
+            let {
+              zeze2{-reN-} :: ((a{-reT-}, b{-reS-}) -> (a{-reT-}, b{-reS-})-> PrelBase.Bool{-3c-})
+              zeze2{-reN-} = \ ds{-rf5-} _Ks :: (a{-reT-}, b{-reS-})
+                              ds1{-rf4-} _Ks :: (a{-reT-}, b{-reS-}) ->
+                            case ds{-rf5-}
+                            of wild{-reW-} _Kd { (a1{-rf2-} _Ks, a2{-reZ-} _Ks) ->
+                            case ds1{-rf4-}
+                            of wild1{-reX-} _Kd { (b1{-rf1-} _Ks, b2{-reY-} _Ks) ->
+                            PrelBase.zaza{-r4e-}
+                              (zeze1{-rf3-} a1{-rf2-} b1{-rf1-})
+                              (zeze{-rf0-} a2{-reZ-} b2{-reY-})
+                            }
+                            } } in     
+            let {
+              a1{-reR-} :: ((a{-reT-}, b{-reS-})-> (a{-reT-}, b{-reS-})-> PrelBase.Bool{-3c-})
+              a1{-reR-} = \ a2{-reV-} _Ks :: (a{-reT-}, b{-reS-})
+                           b1{-reU-} _Ks :: (a{-reT-}, b{-reS-}) ->
+                         PrelBase.not{-r6I-} (zeze2{-reN-} a2{-reV-} b1{-reU-})
+            } in
+              PrelBase.zdwZCDEq{-r8J-} @ (a{-reT-}, b{-reS-}) a1{-reR-} zeze2{-reN-})
+
+and it's not as bad as it seems, because it's further dramatically
+simplified: only zeze2 is extracted and its body is simplified.
+
 
 %************************************************************************
 %*                                                                     *
@@ -723,7 +815,7 @@ checkInstHead dflags theta clas inst_taus
     maybe_tycon_app      = splitTyConApp_maybe first_inst_tau
     Just (tycon, arg_tys) = maybe_tycon_app
 
-    ccallable_type   dflags ty = isFFIArgumentTy dflags False {- Not safe call -} ty
+    ccallable_type   dflags ty = isFFIArgumentTy dflags PlayRisky ty
     creturnable_type        ty = isFFIImportResultTy dflags ty
        
 check_tyvars dflags clas inst_taus