[project @ 2002-05-23 15:51:26 by simonpj]
[ghc-hetmet.git] / ghc / compiler / typecheck / TcModule.lhs
index e799f09..6b76101 100644 (file)
@@ -6,7 +6,7 @@
 \begin{code}
 module TcModule (
        typecheckModule, typecheckIface, typecheckStmt, typecheckExpr,
-       typecheckExtraDecls,
+       typecheckExtraDecls, typecheckCoreModule,
        TcResults(..)
     ) where
 
@@ -15,55 +15,59 @@ module TcModule (
 import CmdLineOpts     ( DynFlag(..), DynFlags, dopt )
 import HsSyn           ( HsBinds(..), MonoBinds(..), HsDecl(..), HsExpr(..),
                          Stmt(..), InPat(..), HsMatchContext(..), HsDoContext(..), RuleDecl(..),
-                         isIfaceRuleDecl, nullBinds, andMonoBindList, mkSimpleMatch, placeHolderType
+                         isSourceInstDecl, mkSimpleMatch, placeHolderType, isCoreDecl
                        )
-import PrelNames       ( mAIN_Name, mainName, ioTyConName, printName,
-                         returnIOName, bindIOName, failIOName, 
-                         itName
+import PrelNames       ( ioTyConName, printName,
+                         returnIOName, bindIOName, failIOName, thenIOName, runMainName, 
+                         dollarMainName, itName
                        )
 import MkId            ( unsafeCoerceId )
-import RnHsSyn         ( RenamedHsBinds, RenamedHsDecl, RenamedStmt,
-                         RenamedHsExpr )
+import RnHsSyn         ( RenamedHsDecl, RenamedStmt, RenamedHsExpr, 
+                         RenamedRuleDecl, RenamedTyClDecl, RenamedInstDecl )
 import TcHsSyn         ( TypecheckedMonoBinds, TypecheckedHsExpr,
                          TypecheckedForeignDecl, TypecheckedRuleDecl,
+                         TypecheckedCoreBind,
                          zonkTopBinds, zonkForeignExports, zonkRules, mkHsLet,
                          zonkExpr, zonkIdBndr
                        )
 
+import Rename          ( RnResult(..) )
 import MkIface         ( pprModDetails )
 import TcExpr          ( tcMonoExpr )
 import TcMonad
-import TcMType         ( unifyTauTy, newTyVarTy, zonkTcType, tcInstType )
+import TcMType         ( newTyVarTy, zonkTcType )
 import TcType          ( Type, liftedTypeKind, openTypeKind,
-                         tyVarsOfType, tidyType, tcFunResultTy,
-                         mkForAllTys, mkFunTys, mkTyConApp, tcSplitForAllTys
+                         tyVarsOfType, tcFunResultTy,
+                         mkForAllTys, mkFunTys, mkTyConApp, tcSplitForAllTys,
+                         tcSplitTyConApp_maybe, isUnitTy
                        )
 import TcMatches       ( tcStmtsAndThen )
-import Inst            ( emptyLIE, plusLIE )
+import Inst            ( LIE, emptyLIE, plusLIE )
 import TcBinds         ( tcTopBinds )
 import TcClassDcl      ( tcClassDecls2 )
 import TcDefaults      ( tcDefaults, defaultDefaultTys )
-import TcEnv           ( TcEnv, RecTcEnv, InstInfo(iDFunId), tcExtendGlobalValEnv, tcLookup_maybe,
+import TcEnv           ( TcEnv, RecTcEnv, InstInfo(iDFunId), tcExtendGlobalValEnv, 
                          isLocalThing, tcSetEnv, tcSetInstEnv, initTcEnv, getTcGEnv,
-                         tcExtendGlobalTypeEnv, tcLookupGlobalId, tcLookupTyCon,
-                         TcTyThing(..), tcLookupId 
+                         tcExtendGlobalEnv, tcExtendGlobalTypeEnv, 
+                         tcLookupGlobalId, tcLookupTyCon,
+                         TyThing(..), tcLookupId 
                        )
 import TcRules         ( tcIfaceRules, tcSourceRules )
 import TcForeign       ( tcForeignImports, tcForeignExports )
-import TcIfaceSig      ( tcInterfaceSigs )
-import TcInstDcls      ( tcInstDecls1, tcInstDecls2 )
+import TcIfaceSig      ( tcInterfaceSigs, tcCoreBinds )
+import TcInstDcls      ( tcInstDecls1, tcIfaceInstDecls1, addInstDFuns, initInstEnv, tcInstDecls2 )
 import TcSimplify      ( tcSimplifyTop, tcSimplifyInfer )
 import TcTyClsDecls    ( tcTyAndClassDecls )
-import CoreUnfold      ( unfoldingTemplate, hasUnfolding )
+import CoreUnfold      ( unfoldingTemplate )
 import TysWiredIn      ( mkListTy, unitTy )
 import ErrUtils                ( printErrorsAndWarnings, errorsFound, 
                          dumpIfSet_dyn, dumpIfSet_dyn_or, showPass )
-import Id              ( Id, idType, idUnfolding )
-import Module           ( Module, moduleName )
-import Name            ( Name )
-import NameEnv         ( lookupNameEnv )
+import Rules           ( extendRuleBase )
+import Id              ( Id, mkLocalId, idType, idUnfolding, setIdLocalExported )
+import Module           ( Module )
+import Name            ( Name, getName, getSrcLoc )
 import TyCon           ( tyConGenInfo )
-import BasicTypes       ( EP(..), Fixity, RecFlag(..) )
+import BasicTypes       ( EP(..), RecFlag(..) )
 import SrcLoc          ( noSrcLoc )
 import Outputable
 import IO              ( stdout )
@@ -71,9 +75,9 @@ import HscTypes               ( PersistentCompilerState(..), HomeSymbolTable,
                          PackageTypeEnv, ModIface(..),
                          ModDetails(..), DFunId,
                          TypeEnv, extendTypeEnvList, typeEnvTyCons, typeEnvElts,
-                         TyThing(..), 
                          mkTypeEnv
                        )
+import List            ( partition )
 \end{code}
 
 
@@ -108,10 +112,7 @@ typecheckStmt dflags pcs hst ic_type_env unqual this_mod names (stmt, iface_decl
     tcSetDefaultTys defaultDefaultTys $
 
        -- Typecheck the extra declarations
-    fixTc (\ ~(unf_env, _, _, _, _) ->
-       tcImports unf_env pcs hst get_fixity this_mod iface_decls
-    )                  `thenTc` \ (env, new_pcs, local_inst_info, deriv_binds, local_rules) ->
-    ASSERT( null local_inst_info && nullBinds deriv_binds && null local_rules )
+    tcExtraDecls pcs hst this_mod iface_decls  `thenTc` \ (new_pcs, env) ->
 
     tcSetEnv env                               $
     tcExtendGlobalTypeEnv ic_type_env          $
@@ -127,10 +128,6 @@ typecheckStmt dflags pcs hst ic_type_env unqual this_mod names (stmt, iface_decl
     ioToTc (dumpIfSet_dyn dflags Opt_D_dump_tc "Typechecked" (ppr zonked_expr))                `thenNF_Tc_`
 
     returnTc (new_pcs, zonked_expr, zonked_ids, error "typecheckStmt: no type")
-
-  where
-    get_fixity :: Name -> Maybe Fixity
-    get_fixity n = pprPanic "typecheckStmt" (ppr n)
 \end{code}
 
 Here is the grand plan, implemented in tcUserStmt
@@ -178,12 +175,13 @@ tcUserStmt names stmt
     
 
 tc_stmts names stmts
-  = tcLookupGlobalId returnIOName      `thenNF_Tc` \ return_id ->
-    tcLookupGlobalId bindIOName                `thenNF_Tc` \ bind_id ->
-    tcLookupGlobalId failIOName                `thenNF_Tc` \ fail_id ->
+  = mapNF_Tc tcLookupGlobalId 
+       [returnIOName, failIOName, bindIOName, thenIOName]      `thenNF_Tc` \ io_ids ->
     tcLookupTyCon ioTyConName          `thenNF_Tc` \ ioTyCon ->
     newTyVarTy liftedTypeKind          `thenNF_Tc` \ res_ty ->
     let
+       return_id  = head io_ids        -- Rather gruesome
+
        io_ty = (\ ty -> mkTyConApp ioTyCon [ty], res_ty)
 
                -- mk_return builds the expression
@@ -215,7 +213,7 @@ tc_stmts names stmts
     traceTc (text "tcs 4") `thenNF_Tc_`
 
     returnTc (mkHsLet const_binds $
-             HsDoOut DoExpr tc_stmts return_id bind_id fail_id 
+             HsDoOut DoExpr tc_stmts io_ids
                      (mkTyConApp ioTyCon [mkListTy unitTy]) noSrcLoc,
              ids)
   where
@@ -249,10 +247,7 @@ typecheckExpr dflags pcs hst ic_type_env unqual this_mod (expr, decls)
     tcSetDefaultTys defaultDefaultTys $
 
        -- Typecheck the extra declarations
-    fixTc (\ ~(unf_env, _, _, _, _) ->
-       tcImports unf_env pcs hst get_fixity this_mod decls
-    )                  `thenTc` \ (env, new_pcs, local_inst_info, deriv_binds, local_rules) ->
-    ASSERT( null local_inst_info && nullBinds deriv_binds && null local_rules )
+    tcExtraDecls pcs hst this_mod decls        `thenTc` \ (new_pcs, env) ->
 
        -- Now typecheck the expression
     tcSetEnv env                       $
@@ -282,9 +277,6 @@ typecheckExpr dflags pcs hst ic_type_env unqual this_mod (expr, decls)
     returnTc (new_pcs, zonked_expr, [], zonked_ty) 
 
   where
-    get_fixity :: Name -> Maybe Fixity
-    get_fixity n = pprPanic "typecheckExpr" (ppr n)
-
     smpl_doc = ptext SLIT("main expression")
 \end{code}
 
@@ -304,17 +296,40 @@ typecheckExtraDecls
    -> [RenamedHsDecl]     -- extra decls sucked in from interface files
    -> IO (Maybe PersistentCompilerState)
 
-typecheckExtraDecls  dflags pcs hst unqual this_mod decls
+typecheckExtraDecls dflags pcs hst unqual this_mod decls
  = typecheck dflags pcs hst unqual $
-     fixTc (\ ~(unf_env, _, _, _, _) ->
-         tcImports unf_env pcs hst get_fixity this_mod decls
-     ) `thenTc` \ (env, new_pcs, local_inst_info, deriv_binds, local_rules) ->
-     ASSERT( null local_inst_info && nullBinds deriv_binds && null local_rules )
-     returnTc new_pcs
- where
-    get_fixity n = pprPanic "typecheckExpr" (ppr n)
+   tcExtraDecls pcs hst this_mod decls `thenTc` \ (new_pcs, _) ->
+   returnTc new_pcs
+
+tcExtraDecls :: PersistentCompilerState
+            -> HomeSymbolTable
+            -> Module          
+            -> [RenamedHsDecl] 
+            -> TcM (PersistentCompilerState, TcEnv)
+       -- Returned environment includes instances
+
+tcExtraDecls pcs hst this_mod decls
+  = tcIfaceImports this_mod decls      `thenTc` \ (env, all_things, dfuns, rules) ->
+    addInstDFuns (pcs_insts pcs) dfuns `thenNF_Tc` \ new_pcs_insts ->
+    let
+        new_pcs_pte   = extendTypeEnvList (pcs_PTE pcs) all_things
+       new_pcs_rules = addIfaceRules (pcs_rules pcs) rules
+        
+       new_pcs :: PersistentCompilerState
+       new_pcs = pcs { pcs_PTE   = new_pcs_pte,
+                       pcs_insts = new_pcs_insts,
+                       pcs_rules = new_pcs_rules
+                 }
+    in
+       -- Initialise the instance environment
+    tcSetEnv env (
+       initInstEnv new_pcs hst         `thenNF_Tc` \ inst_env ->
+       tcSetInstEnv inst_env tcGetEnv
+    )                                  `thenNF_Tc` \ new_env ->
+    returnTc (new_pcs, new_env)
 \end{code}
 
+
 %************************************************************************
 %*                                                                     *
 \subsection{Typechecking a module}
@@ -326,9 +341,8 @@ typecheckModule
        :: DynFlags
        -> PersistentCompilerState
        -> HomeSymbolTable
-       -> ModIface             -- Iface for this module
        -> PrintUnqualified     -- For error printing
-       -> [RenamedHsDecl]
+       -> RnResult
        -> IO (Maybe (PersistentCompilerState, TcResults))
                        -- The new PCS is Augmented with imported information,
                                                -- (but not stuff from this module)
@@ -344,27 +358,19 @@ data TcResults
     }
 
 
-typecheckModule dflags pcs hst mod_iface unqual decls
+typecheckModule dflags pcs hst unqual rn_result
   = do { maybe_tc_result <- typecheck dflags pcs hst unqual $
-                            tcModule pcs hst get_fixity this_mod decls
+                            tcModule pcs hst rn_result
        ; printTcDump dflags unqual maybe_tc_result
        ; return maybe_tc_result }
-  where
-    this_mod   = mi_module   mod_iface
-    fixity_env = mi_fixities mod_iface
-
-    get_fixity :: Name -> Maybe Fixity
-    get_fixity nm = lookupNameEnv fixity_env nm
-
 
 tcModule :: PersistentCompilerState
         -> HomeSymbolTable
-        -> (Name -> Maybe Fixity)
-        -> Module
-        -> [RenamedHsDecl]
+        -> RnResult
         -> TcM (PersistentCompilerState, TcResults)
 
-tcModule pcs hst get_fixity this_mod decls
+tcModule pcs hst (RnResult { rr_decls = decls, rr_mod = this_mod, 
+                            rr_fixities = fix_env, rr_main = maybe_main_name })
   = fixTc (\ ~(unf_env, _, _) ->
                -- Loop back the final environment, including the fully zonked
                -- versions of bindings from this module.  In the presence of mutual
@@ -372,10 +378,17 @@ tcModule pcs hst get_fixity this_mod decls
                -- in this module, which is why the knot is so big
 
                -- Type-check the type and class decls, and all imported decls
-       tcImports unf_env pcs hst get_fixity this_mod decls     
-                               `thenTc` \ (env, new_pcs, local_insts, deriv_binds, local_rules) ->
+       tcImports unf_env pcs hst this_mod 
+                 tycl_decls iface_inst_decls iface_rule_decls     `thenTc` \ (env1, new_pcs) ->
+
+       tcSetEnv env1                           $
 
-       tcSetEnv env                            $
+               -- Do the source-language instances, including derivings
+       initInstEnv new_pcs hst                 `thenNF_Tc` \ inst_env1 ->
+       tcInstDecls1 (pcs_PRS new_pcs) inst_env1
+                    fix_env this_mod 
+                    tycl_decls src_inst_decls  `thenTc` \ (inst_env2, inst_info, deriv_binds) ->
+       tcSetInstEnv inst_env2                  $
 
         -- Foreign import declarations next
         traceTc (text "Tc4")                   `thenNF_Tc_`
@@ -390,19 +403,25 @@ tcModule pcs hst get_fixity this_mod decls
        -- We also typecheck any extra binds that came out of the "deriving" process
        traceTc (text "Default types" <+> ppr defaulting_tys)   `thenNF_Tc_`
         traceTc (text "Tc5")                           `thenNF_Tc_`
-       tcTopBinds (val_binds `ThenBinds` deriv_binds)  `thenTc` \ ((val_binds, env), lie_valdecls) ->
+       tcTopBinds (val_binds `ThenBinds` deriv_binds)  `thenTc` \ ((val_binds, env2), lie_valdecls) ->
        
        -- Second pass over class and instance declarations, 
        -- plus rules and foreign exports, to generate bindings
-       tcSetEnv env                            $
-       tcInstDecls2  local_insts               `thenNF_Tc` \ (lie_instdecls, inst_binds) ->
-       tcClassDecls2 this_mod tycl_decls       `thenNF_Tc` \ (lie_clasdecls, cls_dm_binds) ->
-       tcForeignExports decls                  `thenTc`    \ (lie_fodecls,   foe_binds, foe_decls) ->
-       tcSourceRules source_rules              `thenNF_Tc` \ (lie_rules,     more_local_rules) ->
+       tcSetEnv env2                           $
+        traceTc (text "Tc6")                   `thenNF_Tc_`
+       traceTc (ppr (getTcGEnv env2))          `thenNF_Tc_`
+       tcClassDecls2 this_mod tycl_decls       `thenNF_Tc` \ (lie_clasdecls, cls_dm_binds, dm_ids) ->
+       tcExtendGlobalValEnv dm_ids             $
+        traceTc (text "Tc7")                   `thenNF_Tc_`
+       tcInstDecls2 inst_info                  `thenNF_Tc` \ (lie_instdecls, inst_binds) ->
+        traceTc (text "Tc8")                   `thenNF_Tc_`
+       tcForeignExports this_mod decls         `thenTc`    \ (lie_fodecls,   foe_binds, foe_decls) ->
+        traceTc (text "Tc9")                   `thenNF_Tc_`
+       tcSourceRules src_rule_decls            `thenNF_Tc` \ (lie_rules,     src_rules) ->
        
                -- CHECK THAT main IS DEFINED WITH RIGHT TYPE, IF REQUIRED
-        traceTc (text "Tc6")                   `thenNF_Tc_`
-       tcCheckMain this_mod                    `thenTc_`
+        traceTc (text "Tc10")                  `thenNF_Tc_`
+       tcCheckMain maybe_main_name             `thenTc` \ (main_bind, lie_main) ->
 
             -- Deal with constant or ambiguous InstIds.  How could
             -- there be ambiguous ones?  They can only arise if a
@@ -423,19 +442,22 @@ tcModule pcs hst get_fixity this_mod decls
                           lie_instdecls `plusLIE`
                           lie_clasdecls `plusLIE`
                           lie_fodecls   `plusLIE`
-                          lie_rules
+                          lie_rules     `plusLIE`
+                          lie_main
        in
-       tcSimplifyTop lie_alldecls      `thenTc` \ const_inst_binds ->
-        traceTc (text "endsimpltop") `thenTc_`
+       tcSimplifyTop lie_alldecls              `thenTc` \ const_inst_binds ->
+        traceTc (text "endsimpltop")           `thenTc_`
+       
        
            -- Backsubstitution.    This must be done last.
            -- Even tcSimplifyTop may do some unification.
        let
-           all_binds = val_binds               `AndMonoBinds`
-                           inst_binds          `AndMonoBinds`
-                           cls_dm_binds        `AndMonoBinds`
-                           const_inst_binds    `AndMonoBinds`
-                           foe_binds
+           all_binds = val_binds        `AndMonoBinds`
+                       inst_binds       `AndMonoBinds`
+                       cls_dm_binds     `AndMonoBinds`
+                       const_inst_binds `AndMonoBinds`
+                       foe_binds        `AndMonoBinds`
+                       main_bind
        in
        traceTc (text "Tc7")            `thenNF_Tc_`
        zonkTopBinds all_binds          `thenNF_Tc` \ (all_binds', final_env)  ->
@@ -444,32 +466,35 @@ tcModule pcs hst get_fixity this_mod decls
        traceTc (text "Tc8")            `thenNF_Tc_`
        zonkForeignExports foe_decls    `thenNF_Tc` \ foe_decls' ->
        traceTc (text "Tc9")            `thenNF_Tc_`
-       zonkRules more_local_rules      `thenNF_Tc` \ more_local_rules' ->
-       
+       zonkRules src_rules             `thenNF_Tc` \ src_rules' ->
        
-       let     local_things = filter (isLocalThing this_mod) (typeEnvElts (getTcGEnv final_env))
        
-               local_type_env :: TypeEnv
-               local_type_env = mkTypeEnv local_things
-                   
-               all_local_rules = local_rules ++ more_local_rules'
+       let     src_things = filter (isLocalThing this_mod) (typeEnvElts (getTcGEnv final_env))
+                               -- This is horribly crude; the env might be jolly big
        in  
        traceTc (text "Tc10")           `thenNF_Tc_`
        returnTc (final_env,
                  new_pcs,
-                 TcResults { tc_env     = local_type_env,
-                             tc_insts   = map iDFunId local_insts,
+                 TcResults { tc_env     = mkTypeEnv src_things,
+                             tc_insts   = map iDFunId inst_info,
                              tc_binds   = all_binds', 
                              tc_fords   = foi_decls ++ foe_decls',
-                             tc_rules   = all_local_rules
+                             tc_rules   = src_rules'
                            }
        )
     )                  `thenTc` \ (_, pcs, tc_result) ->
     returnTc (pcs, tc_result)
   where
-    tycl_decls   = [d | TyClD d <- decls]
-    val_binds    = foldr ThenBinds EmptyBinds [binds | ValD binds <- decls]
-    source_rules = [d | RuleD d <- decls, not (isIfaceRuleDecl d)]
+    tycl_decls = [d | TyClD d <- decls]
+    rule_decls = [d | RuleD d <- decls]
+    inst_decls = [d | InstD d <- decls]
+    val_decls  = [d | ValD d  <- decls]
+    
+    core_binds = [d | d <- tycl_decls, isCoreDecl d]
+
+    (src_inst_decls, iface_inst_decls) = partition isSourceInstDecl           inst_decls
+    (src_rule_decls, iface_rule_decls) = partition (isSourceRuleDecl this_mod) rule_decls
+    val_binds                         = foldr ThenBinds EmptyBinds val_decls
 \end{code}
 
 
@@ -492,51 +517,96 @@ typecheckIface
 
 typecheckIface dflags pcs hst mod_iface decls
   = do { maybe_tc_stuff <- typecheck dflags pcs hst alwaysQualify $
-                           tcIfaceImports pcs hst get_fixity this_mod decls
+                           tcIface pcs this_mod decls
        ; printIfaceDump dflags maybe_tc_stuff
        ; return maybe_tc_stuff }
   where
-    this_mod   = mi_module   mod_iface
-    fixity_env = mi_fixities mod_iface
-
-    get_fixity :: Name -> Maybe Fixity
-    get_fixity nm = lookupNameEnv fixity_env nm
-
-    tcIfaceImports pcs hst get_fixity this_mod decls
-       = fixTc (\ ~(unf_env, _, _, _, _) ->
-             tcImports unf_env pcs hst get_fixity this_mod decls
-          )    `thenTc` \ (env, new_pcs, local_inst_info, 
-                           deriv_binds, local_rules) ->
-         ASSERT(nullBinds deriv_binds)
-         let 
-             local_things = filter (isLocalThing this_mod) (typeEnvElts (getTcGEnv env))
-
-             mod_details = ModDetails { md_types = mkTypeEnv local_things,
-                                        md_insts = map iDFunId local_inst_info,
-                                        md_rules = [(id,rule) | IfaceRuleOut id rule <- local_rules],
-                                        md_binds = [] }
+    this_mod = mi_module mod_iface
+
+tcIface pcs this_mod decls
+-- The decls are coming from this_mod's interface file, together
+-- with imported interface decls that belong in the "package" stuff.
+-- (With GHCi, all the home modules have already been processed.)
+-- That is why we need to do the partitioning below.
+  = tcIfaceImports this_mod decls      `thenTc` \ (_, all_things, dfuns, rules) ->
+
+    let 
+       -- Do the partitioning (see notes above)
+       (local_things, imported_things) = partition (isLocalThing this_mod) all_things
+       (local_rules,  imported_rules)  = partition is_local_rule rules
+       (local_dfuns,  imported_dfuns)  = partition (isLocalThing this_mod) dfuns
+       is_local_rule (IfaceRuleOut n _) = isLocalThing this_mod n
+    in
+    addInstDFuns (pcs_insts pcs) imported_dfuns                `thenNF_Tc` \ new_pcs_insts ->
+    let
+       new_pcs_pte :: PackageTypeEnv
+        new_pcs_pte   = extendTypeEnvList (pcs_PTE pcs) imported_things
+       new_pcs_rules = addIfaceRules (pcs_rules pcs) imported_rules
+        
+       new_pcs :: PersistentCompilerState
+       new_pcs = pcs { pcs_PTE   = new_pcs_pte,
+                       pcs_insts = new_pcs_insts,
+                       pcs_rules = new_pcs_rules
+                 }
+
+       mod_details = ModDetails { md_types = mkTypeEnv local_things,
+                                  md_insts = local_dfuns,
+                                  md_rules = [(id,rule) | IfaceRuleOut id rule <- local_rules],
+                                  md_binds = [] }
                        -- All the rules from an interface are of the IfaceRuleOut form
-         in
-          returnTc (new_pcs, mod_details)
+    in
+    returnTc (new_pcs, mod_details)
+
+
+tcIfaceImports :: Module 
+              -> [RenamedHsDecl]       -- All interface-file decls
+              -> TcM (TcEnv, [TyThing], [DFunId], [TypecheckedRuleDecl])
+tcIfaceImports this_mod decls
+-- The decls are all interface-file declarations
+  = let
+       inst_decls = [d | InstD d <- decls]
+       tycl_decls = [d | TyClD d <- decls]
+       rule_decls = [d | RuleD d <- decls]
+    in
+    fixTc (\ ~(unf_env, _, _, _) ->
+       -- This fixTc follows the same general plan as tcImports,
+       -- which is better commented (below)
+       tcTyAndClassDecls this_mod tycl_decls           `thenTc` \ tycl_things ->
+       tcExtendGlobalEnv tycl_things                   $
+       tcInterfaceSigs unf_env this_mod tycl_decls     `thenTc` \ sig_ids ->
+       tcExtendGlobalValEnv sig_ids                    $
+       tcIfaceInstDecls1 inst_decls                    `thenTc` \ dfuns ->
+       tcIfaceRules rule_decls                         `thenTc` \ rules ->
+       tcGetEnv                                        `thenTc` \ env ->
+       let
+         all_things = map AnId sig_ids ++ tycl_things
+       in
+       returnTc (env, all_things, dfuns, rules)
+    )
+
 
 tcImports :: RecTcEnv
          -> PersistentCompilerState
          -> HomeSymbolTable
-         -> (Name -> Maybe Fixity)
          -> Module
-         -> [RenamedHsDecl]
-         -> TcM (TcEnv, PersistentCompilerState, [InstInfo], 
-                        RenamedHsBinds, [TypecheckedRuleDecl])
+         -> [RenamedTyClDecl]
+         -> [RenamedInstDecl]
+         -> [RenamedRuleDecl]
+         -> TcM (TcEnv, PersistentCompilerState)
 
 -- tcImports is a slight mis-nomer.  
 -- It deals with everything that could be an import:
---     type and class decls
+--     type and class decls (some source, some imported)
 --     interface signatures (checked lazily)
---     instance decls
---     rule decls
+--     instance decls (some source, some imported)
+--     rule decls (all imported)
 -- These can occur in source code too, of course
+--
+-- tcImports is only called when processing source code,
+-- so that any interface-file declarations are for other modules, not this one
 
-tcImports unf_env pcs hst get_fixity this_mod decls
+tcImports unf_env pcs hst this_mod 
+         tycl_decls inst_decls rule_decls
          -- (unf_env :: RecTcEnv) is used for type-checking interface pragmas
          -- which is done lazily [ie failure just drops the pragma
          -- without having any global-failure effect].
@@ -548,58 +618,127 @@ tcImports unf_env pcs hst get_fixity this_mod decls
        -- tcImports recovers internally, but if anything gave rise to
        -- an error we'd better stop now, to avoid a cascade
        
-    traceTc (text "Tc1")                               `thenNF_Tc_`
-    tcTyAndClassDecls unf_env this_mod tycl_decls      `thenTc` \ env ->
-    tcSetEnv env                                       $
-    
-       -- Typecheck the instance decls, includes deriving
-    traceTc (text "Tc2")       `thenNF_Tc_`
-    tcInstDecls1 (pcs_insts pcs) (pcs_PRS pcs) 
-            hst unf_env get_fixity this_mod 
-            decls                      `thenTc` \ (new_pcs_insts, inst_env, local_insts, deriv_binds) ->
-    tcSetInstEnv inst_env                      $
+    traceTc (text "Tc1")                       `thenNF_Tc_`
+    tcTyAndClassDecls  this_mod tycl_decls     `thenTc` \ tycl_things ->
+    tcExtendGlobalEnv tycl_things              $
     
-    -- Interface type signatures
-    -- We tie a knot so that the Ids read out of interfaces are in scope
-    --   when we read their pragmas.
-    -- What we rely on is that pragmas are typechecked lazily; if
-    --   any type errors are found (ie there's an inconsistency)
-    --   we silently discard the pragma
-    traceTc (text "Tc3")                       `thenNF_Tc_`
+       -- Interface type signatures
+       -- We tie a knot so that the Ids read out of interfaces are in scope
+       --   when we read their pragmas.
+       -- What we rely on is that pragmas are typechecked lazily; if
+       --   any type errors are found (ie there's an inconsistency)
+       --   we silently discard the pragma
+    traceTc (text "Tc2")                       `thenNF_Tc_`
     tcInterfaceSigs unf_env this_mod tycl_decls        `thenTc` \ sig_ids ->
     tcExtendGlobalValEnv sig_ids               $
     
+       -- Typecheck the instance decls, includes deriving
+       -- Note that imported dictionary functions are already
+       -- in scope from the preceding tcInterfaceSigs
+    traceTc (text "Tc3")               `thenNF_Tc_`
+    tcIfaceInstDecls1 inst_decls       `thenTc` \ dfuns ->
+    tcIfaceRules rule_decls            `thenNF_Tc` \ rules ->
     
-    tcIfaceRules unf_env (pcs_rules pcs) this_mod iface_rules  `thenNF_Tc` \ (new_pcs_rules, local_rules) ->
-       -- When relinking this module from its interface-file decls
-       -- we'll have IfaceRules that are in fact local to this module
-       -- That's the reason we we get any local_rules out here
-    
-    tcGetEnv                                           `thenTc` \ unf_env ->
+    addInstDFuns (pcs_insts pcs) dfuns `thenNF_Tc` \ new_pcs_insts ->
+    tcGetEnv                           `thenTc` \ unf_env ->
     let
-        all_things = typeEnvElts (getTcGEnv unf_env)
-    
          -- sometimes we're compiling in the context of a package module
          -- (on the GHCi command line, for example).  In this case, we
          -- want to treat everything we pulled in as an imported thing.
-        imported_things
-                 = filter (not . isLocalThing this_mod) all_things
+        imported_things = map AnId sig_ids ++  -- All imported
+                         filter (not . isLocalThing this_mod) tycl_things
         
         new_pte :: PackageTypeEnv
         new_pte = extendTypeEnvList (pcs_PTE pcs) imported_things
         
+       new_pcs_rules = addIfaceRules (pcs_rules pcs) rules
+
         new_pcs :: PersistentCompilerState
         new_pcs = pcs { pcs_PTE   = new_pte,
                        pcs_insts = new_pcs_insts,
                        pcs_rules = new_pcs_rules
                  }
     in
-    returnTc (unf_env, new_pcs, local_insts, deriv_binds, local_rules)
+    returnTc (unf_env, new_pcs)
+
+isSourceRuleDecl :: Module -> RenamedRuleDecl -> Bool
+-- This is a bit gruesome.  
+-- Usually, HsRules come only from source files; IfaceRules only from interface files
+-- But built-in rules appear as an IfaceRuleOut... and when compiling
+-- the source file for that built-in rule, we want to treat it as a source
+-- rule, so it gets put with the other rules for that module.
+isSourceRuleDecl this_mod (HsRule _ _ _ _ _ _)       = True
+isSourceRuleDecl this_mod (IfaceRule  _ _ _ n _ _ _) = False
+isSourceRuleDecl this_mod (IfaceRuleOut name _)      = isLocalThing this_mod name 
+
+addIfaceRules rule_base rules
+  = foldl add_rule rule_base rules
   where
-    tycl_decls  = [d | TyClD d <- decls]
-    iface_rules = [d | RuleD d <- decls, isIfaceRuleDecl d]
+    add_rule rule_base (IfaceRuleOut id rule) = extendRuleBase rule_base (id, rule)
 \end{code}    
 
+\begin{code}
+typecheckCoreModule
+       :: DynFlags
+       -> PersistentCompilerState
+       -> HomeSymbolTable
+       -> ModIface             -- Iface for this module (just module & fixities)
+       -> [RenamedHsDecl]
+       -> IO (Maybe (PersistentCompilerState, (TypeEnv, [TypecheckedCoreBind], [TypecheckedRuleDecl])))
+typecheckCoreModule dflags pcs hst mod_iface decls
+  = do { maybe_tc_stuff <- typecheck dflags pcs hst alwaysQualify $
+                            tcCoreDecls this_mod decls
+
+--     ; printIfaceDump dflags maybe_tc_stuff
+
+           -- Q: Is it OK not to extend PCS here?
+          -- (in the event that it needs to be, I'm returning the PCS passed in.)
+        ; case maybe_tc_stuff of
+           Nothing -> return Nothing
+           Just result -> return (Just (pcs, result)) }
+  where
+    this_mod = mi_module mod_iface
+    core_decls = [d | (TyClD d) <- decls, isCoreDecl d]
+
+
+tcCoreDecls :: Module 
+           -> [RenamedHsDecl]  -- All interface-file decls
+           -> TcM (TypeEnv, [TypecheckedCoreBind], [TypecheckedRuleDecl])
+tcCoreDecls this_mod decls
+-- The decls are all TyClD declarations coming from External Core input.
+  = let
+       tycl_decls = [d | TyClD d <- decls]
+       rule_decls = [d | RuleD d <- decls]
+       core_decls = filter isCoreDecl tycl_decls
+    in
+    fixTc (\ ~(unf_env, _) ->
+       -- This fixTc follows the same general plan as tcImports,
+       -- which is better commented.
+       -- [ Q: do we need to tie a knot for External Core? ]
+       tcTyAndClassDecls this_mod tycl_decls           `thenTc` \ tycl_things ->
+       tcExtendGlobalEnv tycl_things                   $
+
+        tcInterfaceSigs unf_env this_mod tycl_decls    `thenTc` \ sig_ids ->
+        tcExtendGlobalValEnv sig_ids                   $
+
+       tcCoreBinds core_decls                          `thenTc` \ core_prs ->
+       let
+          local_ids = map fst core_prs
+       in
+       tcExtendGlobalValEnv local_ids                  $
+
+       tcIfaceRules rule_decls                         `thenTc` \ rules ->
+
+       let     
+          src_things = filter (isLocalThing this_mod) tycl_things
+                       ++ map AnId local_ids
+       in
+       tcGetEnv                                        `thenNF_Tc` \ env ->    
+       returnTc (env, (mkTypeEnv src_things, core_prs, rules))
+    )                                                  `thenTc` \ (_, result) ->
+    returnTc result
+\end{code}
+
 
 %************************************************************************
 %*                                                                     *
@@ -608,48 +747,43 @@ tcImports unf_env pcs hst get_fixity this_mod decls
 %************************************************************************
 
 We must check that in module Main,
-       a) main is defined
-       b) main :: forall a1...an. IO t,  for some type t
+       a) Main.main is in scope
+       b) Main.main :: forall a1...an. IO t,  for some type t
 
-If we have
-       main = error "Urk"
-then the type of main will be 
-       main :: forall a. a
-and that should pass the test too.  
+Then we build
+       $main = PrelTopHandler.runMain Main.main
 
-So we just instantiate the type and unify with IO t, and declare 
-victory if doing so succeeds.
+The function
+  PrelTopHandler :: IO a -> IO ()
+catches the top level exceptions.  
+It accepts a Main.main of any type (IO a).
 
 \begin{code}
-tcCheckMain :: Module -> TcM ()
-tcCheckMain this_mod
-  | not (moduleName this_mod == mAIN_Name )
-  = returnTc ()
-
-  | otherwise
-  =    -- First unify the main_id with IO t, for any old t
-    tcLookup_maybe mainName            `thenNF_Tc` \ maybe_thing ->
-    case maybe_thing of
-       Just (ATcId main_id) -> check_main_ty (idType main_id)
-       other                -> addErrTc noMainErr      
+tcCheckMain :: Maybe Name -> TcM (TypecheckedMonoBinds, LIE)
+tcCheckMain Nothing = returnTc (EmptyMonoBinds, emptyLIE)
+
+tcCheckMain (Just main_name)
+  = tcLookupId main_name               `thenNF_Tc` \ main_id ->
+       -- If it is not Nothing, it should be in the env
+    tcAddSrcLoc (getSrcLoc main_id)    $
+    tcAddErrCtxt mainCtxt              $
+    newTyVarTy liftedTypeKind          `thenNF_Tc` \ ty ->
+    tcMonoExpr rhs ty                  `thenTc` \ (main_expr, lie) ->
+    zonkTcType ty                      `thenNF_Tc` \ ty ->
+    ASSERT( is_io_unit ty )
+    let
+       dollar_main_id = setIdLocalExported (mkLocalId dollarMainName ty)
+    in
+    returnTc (VarMonoBind dollar_main_id main_expr, lie)
   where
-    check_main_ty main_ty
-      = tcInstType main_ty             `thenNF_Tc` \ (tvs, theta, main_tau) ->
-       newTyVarTy liftedTypeKind       `thenNF_Tc` \ arg_ty ->
-       tcLookupTyCon ioTyConName       `thenNF_Tc` \ ioTyCon ->
-       tcAddErrCtxtM (mainTypeCtxt main_ty)    $
-       if not (null theta) then 
-               failWithTc empty        -- Context has the error message
-       else
-       unifyTauTy main_tau (mkTyConApp ioTyCon [arg_ty])
-
-mainTypeCtxt main_ty tidy_env 
-  = zonkTcType main_ty         `thenNF_Tc` \ main_ty' ->
-    returnNF_Tc (tidy_env, ptext SLIT("`main' has the illegal type") <+> 
-                                quotes (ppr (tidyType tidy_env main_ty')))
-
-noMainErr = hsep [ptext SLIT("Module") <+> quotes (ppr mAIN_Name), 
-                 ptext SLIT("must include a definition for") <+> quotes (ptext SLIT("main"))]
+    rhs = HsApp (HsVar runMainName) (HsVar main_name)
+
+is_io_unit :: Type -> Bool     -- True for IO ()
+is_io_unit tau = case tcSplitTyConApp_maybe tau of
+                  Just (tc, [arg]) -> getName tc == ioTyConName && isUnitTy arg
+                  other            -> False
+
+mainCtxt = ptext SLIT("When checking the type of 'main'")
 \end{code}
 
 
@@ -697,7 +831,8 @@ printTcDump dflags unqual (Just (_, results))
           else return ()
 
        dumpIfSet_dyn dflags Opt_D_dump_tc    
-                     "Typechecked" (ppr (tc_binds results))
+       -- foreign x-d's have undefined's in their types; hence can't show the tc_fords
+                     "Typechecked" (ppr (tc_binds results) {- $$ ppr (tc_fords results)-})
 
          
 printIfaceDump dflags Nothing = return ()