relaxed instance termination test
[ghc-hetmet.git] / ghc / compiler / typecheck / TcInstDcls.lhs
index 8366dad..3fec58d 100644 (file)
@@ -9,11 +9,12 @@ module TcInstDcls ( tcInstDecls1, tcInstDecls2 ) where
 #include "HsVersions.h"
 
 import HsSyn
-import TcBinds         ( tcSpecSigs, badBootDeclErr )
+import TcBinds         ( mkPragFun, tcPrags, badBootDeclErr )
 import TcClassDcl      ( tcMethodBind, mkMethodBind, badMethodErr, 
                          tcClassDecl2, getGenericInstances )
 import TcRnMonad       
-import TcMType         ( tcSkolSigType, checkValidTheta, checkValidInstHead, instTypeErr, 
+import TcMType         ( tcSkolSigType, checkValidTheta, checkValidInstHead,
+                         checkInstTermination, instTypeErr, 
                          checkAmbiguity, SourceTyCtxt(..) )
 import TcType          ( mkClassPred, tyVarsOfType, 
                          tcSplitSigmaTy, tcSplitDFunHead, mkTyVarTys,
@@ -22,8 +23,7 @@ import Inst           ( tcInstClassOp, newDicts, instToId, showLIE,
                          getOverlapFlag, tcExtendLocalInstEnv )
 import InstEnv         ( mkLocalInstance, instanceDFunId )
 import TcDeriv         ( tcDeriving )
-import TcEnv           ( tcExtendGlobalValEnv, tcExtendTyVarEnv,
-                         InstInfo(..), InstBindings(..), 
+import TcEnv           ( InstInfo(..), InstBindings(..), 
                          newDFunName, tcExtendIdEnv
                        )
 import TcHsType                ( kcHsSigType, tcHsKindedType )
@@ -36,13 +36,12 @@ import Var          ( Id, idName, idType )
 import MkId            ( mkDictFunId, rUNTIME_ERROR_ID )
 import FunDeps         ( checkInstFDs )
 import Name            ( Name, getSrcLoc )
-import NameSet         ( unitNameSet, emptyNameSet )
-import UnicodeUtil     ( stringToUtf8 )
 import Maybe           ( catMaybes )
 import SrcLoc          ( srcLocSpan, unLoc, noLoc, Located(..), srcSpanStart )
 import ListSetOps      ( minusList )
 import Outputable
 import Bag
+import BasicTypes      ( Activation( AlwaysActive ), InlineSpec(..) )
 import FastString
 \end{code}
 
@@ -135,7 +134,7 @@ tcInstDecls1        -- Deal with both source-code and imported instance decls
    -> TcM (TcGblEnv,           -- The full inst env
           [InstInfo],          -- Source-code instance decls to process; 
                                -- contains all dfuns for this module
-          [HsBindGroup Name])  -- Supporting bindings for derived instances
+          HsValBinds Name)     -- Supporting bindings for derived instances
 
 tcInstDecls1 tycl_decls inst_decls
   = checkNoErrs $
@@ -181,10 +180,6 @@ tcLocalInstDecl1 :: LInstDecl Name
        -- Type-check all the stuff before the "where"
        --
        -- We check for respectable instance type, and context
-       -- but only do this for non-imported instance decls.
-       -- Imported ones should have been checked already, and may indeed
-       -- contain something illegal in normal Haskell, notably
-       --      instance CCallable [Char] 
 tcLocalInstDecl1 decl@(L loc (InstDecl poly_ty binds uprags))
   =    -- Prime error recovery, set source location
     recoverM (returnM Nothing)         $
@@ -201,6 +196,7 @@ tcLocalInstDecl1 decl@(L loc (InstDecl poly_ty binds uprags))
     checkValidTheta InstThetaCtxt theta                        `thenM_`
     checkAmbiguity tyvars theta (tyVarsOfType tau)     `thenM_`
     checkValidInstHead tau                             `thenM` \ (clas,inst_tys) ->
+    checkInstTermination theta inst_tys                        `thenM_`
     checkTc (checkInstFDs theta clas inst_tys)
            (instTypeErr (pprClassPred clas inst_tys) msg)      `thenM_`
     newDFunName clas inst_tys (srcSpanStart loc)               `thenM` \ dfun_name ->
@@ -370,27 +366,21 @@ tcInstDecl2 (InstInfo { iSpec = ispec, iBinds = binds })
        -- of the inst_tyavars' with something in the envt
     checkSigTyVars inst_tyvars'        `thenM_`
 
-       -- Deal with 'SPECIALISE instance' pragmas by making them
-       -- look like SPECIALISE pragmas for the dfun
+       -- Deal with 'SPECIALISE instance' pragmas 
     let
-       uprags = case binds of
-                      VanillaInst _ uprags -> uprags
-                      other                -> []
-       spec_prags = [ L loc (SpecSig (L loc (idName dfun_id)) ty)
-                    | L loc (SpecInstSig ty) <- uprags ]
+       specs = case binds of
+                 VanillaInst _ prags -> filter isSpecInstLSig prags
+                 other               -> []
     in
-    tcExtendGlobalValEnv [dfun_id] (
-       tcExtendTyVarEnv inst_tyvars'   $
-       tcSpecSigs spec_prags
-    )                                  `thenM` \ prag_binds ->
-
+    tcPrags dfun_id specs                      `thenM` \ prags -> 
+    
        -- Create the result bindings
     let
         dict_constr   = classDataCon clas
        scs_and_meths = map instToId sc_dicts ++ meth_ids
        this_dict_id  = instToId this_dict
-       inlines       | null dfun_arg_dicts = emptyNameSet
-                     | otherwise           = unitNameSet (idName dfun_id)
+       inline_prag | null dfun_arg_dicts = []
+                   | otherwise = [InlinePrag (Inline AlwaysActive True)]
                -- 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
@@ -403,18 +393,6 @@ tcInstDecl2 (InstInfo { iSpec = ispec, iBinds = binds })
                --      See Note [Inline dfuns] below
 
        dict_rhs
-         | null scs_and_meths
-         =     -- Blatant special case for CCallable, CReturnable
-               -- If the dictionary is empty then we should never
-               -- select anything from it, so we make its RHS just
-               -- emit an error message.  This in turn means that we don't
-               -- mention the constructor, which doesn't exist for CCallable, CReturnable
-               -- Hardly beautiful, but only three extra lines.
-           nlHsApp (noLoc $ TyApp (nlHsVar rUNTIME_ERROR_ID) 
-                                  [idType this_dict_id])
-                 (nlHsLit (HsStringPrim (mkFastString (stringToUtf8 msg))))
-
-         | otherwise   -- The common case
          = mkHsConApp dict_constr inst_tys' (map HsVar scs_and_meths)
                -- We don't produce a binding for the dict_constr; instead we
                -- rely on the simplifier to unfold this saturated application
@@ -432,12 +410,12 @@ tcInstDecl2 (InstInfo { iSpec = ispec, iBinds = binds })
        main_bind = noLoc $ AbsBinds
                            inst_tyvars'
                            (map instToId dfun_arg_dicts)
-                           [(inst_tyvars', dfun_id, this_dict_id)] 
-                           inlines all_binds
+                           [(inst_tyvars', dfun_id, this_dict_id, 
+                                           inline_prag ++ prags)] 
+                           all_binds
     in
     showLIE (text "instance")          `thenM_`
-    returnM (unitBag main_bind `unionBags` 
-            prag_binds )
+    returnM (unitBag main_bind)
 
 
 tcMethods origin clas inst_tyvars' dfun_theta' inst_tys' 
@@ -485,8 +463,9 @@ tcMethods origin clas inst_tyvars' dfun_theta' inst_tys'
        -- The trouble is that the 'meth_inst' for op, which is 'available', also
        -- looks like 'op at Int'.  But they are not the same.
     let
+       prag_fn        = mkPragFun uprags
        all_insts      = avail_insts ++ catMaybes meth_insts
-       tc_method_bind = tcMethodBind inst_tyvars' dfun_theta' all_insts uprags 
+       tc_method_bind = tcMethodBind inst_tyvars' dfun_theta' all_insts prag_fn
        meth_ids       = [meth_id | (_,meth_id,_) <- meth_infos]
     in