Rough matches for family instances
[ghc-hetmet.git] / compiler / iface / TcIface.lhs
index 04154ef..fa227e6 100644 (file)
@@ -6,36 +6,38 @@
 \begin{code}
 module TcIface ( 
        tcImportDecl, checkWiredInTyCon, tcHiBootIface, typecheckIface, 
-       tcIfaceDecl, tcIfaceInst, tcIfaceRule, tcIfaceGlobal, 
+       tcIfaceDecl, tcIfaceInst, tcIfaceFamInst, tcIfaceRules, tcIfaceGlobal, 
        tcExtCoreBindings
  ) where
 
 #include "HsVersions.h"
 
 import IfaceSyn
-import LoadIface       ( loadInterface, loadWiredInHomeIface,
-                         loadDecls, findAndReadIface )
+import LoadIface       ( loadInterface, loadWiredInHomeIface, findAndReadIface, loadDecls )
 import IfaceEnv                ( lookupIfaceTop, lookupIfaceExt, newGlobalBinder, 
                          extendIfaceIdEnv, extendIfaceTyVarEnv, newIPName,
                          tcIfaceTyVar, tcIfaceLclId, lookupIfaceTc, 
                          newIfaceName, newIfaceNames, ifaceExportNames )
-import BuildTyCl       ( buildSynTyCon, buildAlgTyCon, buildDataCon, buildClass,
-                         mkAbstractTyConRhs, mkDataTyConRhs, mkNewTyConRhs )
+import BuildTyCl       ( buildSynTyCon, buildAlgTyCon, buildDataCon,
+                         buildClass, 
+                         mkAbstractTyConRhs, mkOpenDataTyConRhs,
+                         mkOpenNewTyConRhs, mkDataTyConRhs, mkNewTyConRhs )
 import TcRnMonad
 import Type            ( liftedTypeKind, splitTyConApp, mkTyConApp,
                           liftedTypeKindTyCon, unliftedTypeKindTyCon, 
                           openTypeKindTyCon, argTypeKindTyCon, 
-                          ubxTupleKindTyCon,
-                         mkTyVarTys, ThetaType )
+                          ubxTupleKindTyCon, ThetaType )
 import TypeRep         ( Type(..), PredType(..) )
-import TyCon           ( TyCon, tyConName )
+import TyCon           ( TyCon, tyConName, SynTyConRhs(..), setTyConArgPoss )
 import HscTypes                ( ExternalPackageState(..), 
                          TyThing(..), tyThingClass, tyThingTyCon, 
                          ModIface(..), ModDetails(..), HomeModInfo(..),
-                         emptyModDetails, lookupTypeEnv, lookupType, typeEnvIds )
+                         emptyModDetails, lookupTypeEnv, lookupType,
+                         typeEnvIds )
 import InstEnv         ( Instance(..), mkImportedInstance )
+import FamInstEnv      ( FamInst(..), mkImportedFamInst )
 import CoreSyn
-import CoreUtils       ( exprType )
+import CoreUtils       ( exprType, dataConRepFSInstPat )
 import CoreUnfold
 import CoreLint                ( lintUnfolding )
 import WorkWrap                ( mkWrapper )
@@ -47,24 +49,27 @@ import IdInfo               ( IdInfo, CafInfo(..), WorkerInfo(..),
                          vanillaIdInfo, newStrictnessInfo )
 import Class           ( Class )
 import TyCon           ( tyConDataCons, isTupleTyCon, mkForeignTyCon )
-import DataCon         ( DataCon, dataConWorkId, dataConExTyVars, dataConInstArgTys )
+import DataCon         ( DataCon, dataConWorkId )
 import TysWiredIn      ( tupleCon, tupleTyCon, listTyCon, intTyCon, boolTyCon, charTyCon, parrTyCon )
-import Var             ( TyVar, mkTyVar, tyVarKind )
+import Var             ( TyVar, mkTyVar )
 import Name            ( Name, nameModule, nameIsLocalOrFrom, isWiredInName,
                          nameOccName, wiredInNameTyThing_maybe )
 import NameEnv
-import OccName         ( OccName, mkVarOccFS, mkTyVarOccoccNameSpace, pprNameSpace  )
-import FastString       ( FastString )
+import OccName         ( OccName, mkVarOccFS, mkTyVarOcc, occNameSpace, 
+                         pprNameSpace, occNameFS  )
 import Module          ( Module, moduleName )
 import UniqFM          ( lookupUFM )
-import UniqSupply      ( initUs_ )
+import UniqSupply      ( initUs_, uniqsFromSupply )
 import Outputable      
 import ErrUtils                ( Message )
 import Maybes          ( MaybeErr(..) )
 import SrcLoc          ( noSrcLoc )
-import Util            ( zipWithEqual, equalLength, splitAtList )
+import Util            ( zipWithEqual )
 import DynFlags                ( DynFlag(..), isOneShot )
+import Control.Monad   ( unless )
 
+import List            ( elemIndex)
+import Maybe           ( catMaybes )
 \end{code}
 
 This module takes
@@ -133,12 +138,11 @@ checkWiredInTyCon tc
   = return ()
   | otherwise
   = do { mod <- getModule
-       ; if nameIsLocalOrFrom mod tc_name then
+       ; unless (mod == nameModule tc_name)
+                (initIfaceTcRn (loadWiredInHomeIface tc_name))
                -- Don't look for (non-existent) Float.hi when
                -- compiling Float.lhs, which mentions Float of course
-               return ()
-         else  -- A bit yukky to call initIfaceTcRn here
-               initIfaceTcRn (loadWiredInHomeIface tc_name) 
+               -- A bit yukky to call initIfaceTcRn here
        }
   where
     tc_name = tyConName tc
@@ -198,28 +202,31 @@ typecheckIface iface
                -- to handle unboxed tuples, so it must not see unfoldings.
          ignore_prags <- doptM Opt_IgnoreInterfacePragmas
 
-               -- Load & typecheck the decls
-       ; decl_things <- loadDecls ignore_prags (mi_decls iface)
-
-       ; let type_env = mkNameEnv decl_things
+               -- Typecheck the decls.  This is done lazily, so that the knot-tying
+               -- within this single module work out right.  In the If monad there is
+               -- no global envt for the current interface; instead, the knot is tied
+               -- through the if_rec_types field of IfGblEnv
+       ; names_w_things <- loadDecls ignore_prags (mi_decls iface)
+       ; let type_env = mkNameEnv names_w_things
        ; writeMutVar tc_env_var type_env
 
                -- Now do those rules and instances
-       ; let { rules | ignore_prags = []
-                     | otherwise    = mi_rules iface
-             ; dfuns = mi_insts iface
-             } 
-       ; dfuns <- mapM tcIfaceInst dfuns
-       ; rules <- mapM tcIfaceRule rules
+       ; insts     <- mapM tcIfaceInst    (mi_insts     iface)
+       ; fam_insts <- mapM tcIfaceFamInst (mi_fam_insts iface)
+       ; rules     <- tcIfaceRules ignore_prags (mi_rules iface)
 
                -- Exports
-       ; exports <-  ifaceExportNames (mi_exports iface)
+       ; exports <- ifaceExportNames (mi_exports iface)
 
                -- Finished
-       ; return (ModDetails {  md_types = type_env, 
-                               md_insts = dfuns,
-                               md_rules = rules,
-                               md_exports = exports }) 
+       ; traceIf (vcat [text "Finished typechecking interface for" <+> ppr (mi_module iface),
+                        text "Type envt:" <+> ppr type_env])
+       ; return $ ModDetails { md_types     = type_env
+                             , md_insts     = insts
+                             , md_fam_insts = fam_insts
+                             , md_rules     = rules
+                             , md_exports   = exports 
+                             }
     }
 \end{code}
 
@@ -342,43 +349,60 @@ the forkM stuff.
 
 
 \begin{code}
-tcIfaceDecl :: IfaceDecl -> IfL TyThing
+tcIfaceDecl :: Bool    -- True <=> discard IdInfo on IfaceId bindings
+           -> IfaceDecl
+           -> IfL TyThing
 
-tcIfaceDecl (IfaceId {ifName = occ_name, ifType = iface_type, ifIdInfo = info})
+tcIfaceDecl ignore_prags (IfaceId {ifName = occ_name, ifType = iface_type, ifIdInfo = info})
   = do { name <- lookupIfaceTop occ_name
        ; ty <- tcIfaceType iface_type
-       ; info <- tcIdInfo name ty info
+       ; info <- tcIdInfo ignore_prags name ty info
        ; return (AnId (mkVanillaGlobal name ty info)) }
 
-tcIfaceDecl (IfaceData {ifName = occ_name, 
+tcIfaceDecl ignore_prags 
+           (IfaceData {ifName = occ_name, 
                        ifTyVars = tv_bndrs, 
                        ifCtxt = ctxt, ifGadtSyntax = gadt_syn,
                        ifCons = rdr_cons, 
                        ifRec = is_rec, 
-                       ifGeneric = want_generic })
+                       ifGeneric = want_generic,
+                       ifFamInst = mb_family })
   = do { tc_name <- lookupIfaceTop occ_name
        ; bindIfaceTyVars tv_bndrs $ \ tyvars -> do
 
        { tycon <- fixM ( \ tycon -> do
            { stupid_theta <- tcIfaceCtxt ctxt
-           ; cons  <- tcIfaceDataCons tc_name tycon tyvars rdr_cons
+           ; famInst <- 
+               case mb_family of
+                 Nothing         -> return Nothing
+                 Just (fam, tys) -> 
+                   do { famTyCon <- tcIfaceTyCon fam
+                      ; insttys <- mapM tcIfaceType tys
+                      ; return $ Just (famTyCon, insttys)
+                      }
+           ; cons <- tcIfaceDataCons tc_name tycon tyvars rdr_cons
            ; buildAlgTyCon tc_name tyvars stupid_theta
-                           cons is_rec want_generic gadt_syn
+                           cons is_rec want_generic gadt_syn famInst
            })
         ; traceIf (text "tcIfaceDecl4" <+> ppr tycon)
        ; return (ATyCon tycon)
     }}
 
-tcIfaceDecl (IfaceSyn {ifName = occ_name, ifTyVars = tv_bndrs, 
-                      ifSynRhs = rdr_rhs_ty})
+tcIfaceDecl ignore_prags 
+           (IfaceSyn {ifName = occ_name, ifTyVars = tv_bndrs, 
+                      ifOpenSyn = isOpen, ifSynRhs = rdr_rhs_ty})
    = bindIfaceTyVars tv_bndrs $ \ tyvars -> do
      { tc_name <- lookupIfaceTop occ_name
-     ; rhs_ty <- tcIfaceType rdr_rhs_ty
-     ; return (ATyCon (buildSynTyCon tc_name tyvars rhs_ty))
+     ; rhs_tyki <- tcIfaceType rdr_rhs_ty
+     ; let rhs = if isOpen then OpenSynTyCon rhs_tyki 
+                          else SynonymTyCon rhs_tyki
+     ; return (ATyCon (buildSynTyCon tc_name tyvars rhs))
      }
 
-tcIfaceDecl (IfaceClass {ifCtxt = rdr_ctxt, ifName = occ_name, ifTyVars = tv_bndrs, 
-                        ifFDs = rdr_fds, ifSigs = rdr_sigs, 
+tcIfaceDecl ignore_prags
+           (IfaceClass {ifCtxt = rdr_ctxt, ifName = occ_name, 
+                        ifTyVars = tv_bndrs, ifFDs = rdr_fds, 
+                        ifATs = rdr_ats, ifSigs = rdr_sigs, 
                         ifRec = tc_isrec })
 -- ToDo: in hs-boot files we should really treat abstract classes specially,
 --      as we do abstract tycons
@@ -387,7 +411,9 @@ tcIfaceDecl (IfaceClass {ifCtxt = rdr_ctxt, ifName = occ_name, ifTyVars = tv_bnd
     ; ctxt <- tcIfaceCtxt rdr_ctxt
     ; sigs <- mappM tc_sig rdr_sigs
     ; fds  <- mappM tc_fd rdr_fds
-    ; cls  <- buildClass cls_name tyvars ctxt fds sigs tc_isrec
+    ; ats'  <- mappM (tcIfaceDecl ignore_prags) rdr_ats
+    ; let ats = zipWith setTyThingPoss ats' (map ifTyVars rdr_ats)
+    ; cls  <- buildClass cls_name tyvars ctxt fds ats sigs tc_isrec
     ; return (AClass cls) }
   where
    tc_sig (IfaceClassOp occ dm rdr_ty)
@@ -404,7 +430,20 @@ tcIfaceDecl (IfaceClass {ifCtxt = rdr_ctxt, ifName = occ_name, ifTyVars = tv_bnd
                           ; tvs2' <- mappM tcIfaceTyVar tvs2
                           ; return (tvs1', tvs2') }
 
-tcIfaceDecl (IfaceForeign {ifName = rdr_name, ifExtName = ext_name})
+   -- For each AT argument compute the position of the corresponding class
+   -- parameter in the class head.  This will later serve as a permutation
+   -- vector when checking the validity of instance declarations.
+   setTyThingPoss (ATyCon tycon) atTyVars = 
+     let classTyVars = map fst tv_bndrs
+        poss        =   catMaybes 
+                      . map ((`elemIndex` classTyVars) . fst) 
+                      $ atTyVars
+                   -- There will be no Nothing, as we already passed renaming
+     in 
+     ATyCon (setTyConArgPoss tycon poss)
+   setTyThingPoss _              _ = panic "TcIface.setTyThingPoss"
+
+tcIfaceDecl ignore_prags (IfaceForeign {ifName = rdr_name, ifExtName = ext_name})
   = do { name <- lookupIfaceTop rdr_name
        ; return (ATyCon (mkForeignTyCon name ext_name 
                                         liftedTypeKind 0)) }
@@ -412,6 +451,8 @@ tcIfaceDecl (IfaceForeign {ifName = rdr_name, ifExtName = ext_name})
 tcIfaceDataCons tycon_name tycon tc_tyvars if_cons
   = case if_cons of
        IfAbstractTyCon  -> return mkAbstractTyConRhs
+       IfOpenDataTyCon  -> return mkOpenDataTyConRhs
+       IfOpenNewTyCon   -> return mkOpenNewTyConRhs
        IfDataTyCon cons -> do  { data_cons <- mappM tc_con_decl cons
                                ; return (mkDataTyConRhs data_cons) }
        IfNewTyCon con   -> do  { data_con <- tc_con_decl con
@@ -452,7 +493,7 @@ tcIfaceDataCons tycon_name tycon tc_tyvars if_cons
 tcIfaceEqSpec spec
   = mapM do_item spec
   where
-    do_item (occ, if_ty) = do { tv <- tcIfaceTyVar occ
+    do_item (occ, if_ty) = do { tv <- tcIfaceTyVar (occNameFS occ)
                               ; ty <- tcIfaceType if_ty
                               ; return (tv,ty) }
 \end{code}     
@@ -472,11 +513,22 @@ tcIfaceInst (IfaceInst { ifDFun = dfun_occ, ifOFlag = oflag,
   = do { dfun    <- forkM (ptext SLIT("Dict fun") <+> ppr dfun_occ) $
                     tcIfaceExtId (LocalTop dfun_occ)
        ; cls'    <- lookupIfaceExt cls
-       ; mb_tcs' <- mapM do_tc mb_tcs
+       ; mb_tcs' <- mapM tc_rough mb_tcs
        ; return (mkImportedInstance cls' mb_tcs' orph dfun oflag) }
-  where
-    do_tc Nothing   = return Nothing
-    do_tc (Just tc) = do { tc' <- lookupIfaceTc tc; return (Just tc') }
+
+tcIfaceFamInst :: IfaceFamInst -> IfL FamInst
+tcIfaceFamInst (IfaceFamInst { ifFamInstTyCon = tycon, 
+                              ifFamInstFam = fam, ifFamInstTys = mb_tcs })
+--  = do       { tycon'  <- forkM (ptext SLIT("Inst tycon") <+> ppr tycon) $
+-- ^^^this line doesn't work, but vvv this does => CPP in Haskell = evil!
+  = do { tycon'  <- forkM (text ("Inst tycon") <+> ppr tycon) $
+                    tcIfaceTyCon tycon
+       ; fam'    <- lookupIfaceExt fam
+       ; mb_tcs' <- mapM tc_rough mb_tcs
+       ; return (mkImportedFamInst fam' mb_tcs' tycon') }
+
+tc_rough Nothing   = return Nothing
+tc_rough (Just tc) = do { tc' <- lookupIfaceTc tc; return (Just tc') }
 \end{code}
 
 
@@ -491,6 +543,13 @@ are in the type environment.  However, remember that typechecking a Rule may
 (as a side effect) augment the type envt, and so we may need to iterate the process.
 
 \begin{code}
+tcIfaceRules :: Bool           -- True <=> ignore rules
+            -> [IfaceRule]
+            -> IfL [CoreRule]
+tcIfaceRules ignore_prags if_rules
+  | ignore_prags = return []
+  | otherwise    = mapM tcIfaceRule if_rules
+
 tcIfaceRule :: IfaceRule -> IfL CoreRule
 tcIfaceRule (IfaceRule {ifRuleName = name, ifActivation = act, ifRuleBndrs = bndrs,
                        ifRuleHead = fn, ifRuleArgs = args, ifRuleRhs = rhs,
@@ -678,21 +737,16 @@ tcIfaceAlt (tycon, inst_tys) (IfaceTupleAlt boxity, arg_occs, rhs)
        ; tcIfaceDataAlt data_con inst_tys arg_occs rhs }
 
 tcIfaceDataAlt con inst_tys arg_strs rhs
-  = do { arg_names <- newIfaceNames (map mkVarOccFS arg_strs)
-        ; let (tyvar_strs, id_strs) = splitAtList (dataConTyVars con) arg_strs
-        ; tyvar_names <- mapM (newIfaceName . mkTyVarOcc) tyvar_strs
-        ; id_names    <- mapM (newIfaceName . mkVarOccFS) id_strs
-       ; let   ex_tvs  = [ mkTyVar name (tyVarKind tv) 
-                          | (name,tv) <- tyvar_names `zip` dataConExTyVars con ]
-               arg_tys  = dataConInstArgTys con (inst_tys ++ mkTyVarTys ex_tvs)
-               arg_ids  = ASSERT2( equalLength id_names arg_tys,
-                                   ppr (con, tyvar_names++id_names, rhs) $$ ppr ex_tvs $$ ppr arg_tys )
-                          zipWith mkLocalId id_names arg_tys
-               
-       ; rhs' <- extendIfaceTyVarEnv ex_tvs    $
+  = do { us <- newUniqueSupply
+       ; let uniqs = uniqsFromSupply us
+       ; let (ex_tvs, co_tvs, arg_ids)
+                     = dataConRepFSInstPat arg_strs uniqs con inst_tys
+              all_tvs = ex_tvs ++ co_tvs
+
+       ; rhs' <- extendIfaceTyVarEnv all_tvs   $
                  extendIfaceIdEnv arg_ids      $
                  tcIfaceExpr rhs
-       ; return (DataAlt con, ex_tvs ++ arg_ids, rhs') }
+       ; return (DataAlt con, all_tvs ++ arg_ids, rhs') }
 \end{code}
 
 
@@ -727,9 +781,12 @@ do_one (IfaceRec pairs) thing_inside
 %************************************************************************
 
 \begin{code}
-tcIdInfo :: Name -> Type -> IfaceIdInfo -> IfL IdInfo
-tcIdInfo name ty NoInfo                = return vanillaIdInfo
-tcIdInfo name ty (HasInfo info) = foldlM tcPrag init_info info
+tcIdInfo :: Bool -> Name -> Type -> IfaceIdInfo -> IfL IdInfo
+tcIdInfo ignore_prags name ty info 
+  | ignore_prags = return vanillaIdInfo
+  | otherwise    = case info of
+                       NoInfo       -> return vanillaIdInfo
+                       HasInfo info -> foldlM tcPrag init_info info
   where
     -- Set the CgInfo to something sensible but uninformative before
     -- we start; default assumption is that it has CAFs
@@ -797,7 +854,7 @@ tcPragExpr name expr
        get_in_scope_ids                        `thenM` \ in_scope -> 
        case lintUnfolding noSrcLoc in_scope core_expr' of
          Nothing       -> returnM ()
-         Just fail_msg -> pprPanic "Iface Lint failure" (doc <+> fail_msg)
+         Just fail_msg -> pprPanic "Iface Lint failure" (hang doc 2 fail_msg)
     )                          `thenM_`
 
    returnM core_expr'  
@@ -826,10 +883,7 @@ tcIfaceGlobal :: Name -> IfL TyThing
 tcIfaceGlobal name
   | Just thing <- wiredInNameTyThing_maybe name
        -- Wired-in things include TyCons, DataCons, and Ids
-  = do { loadWiredInHomeIface name; return thing }
-       -- Even though we are in an interface file, we want to make
-       -- sure its instances are loaded (imagine f :: Double -> Double)
-       -- and its RULES are loaded too
+  = do { ifCheckWiredInThing name; return thing }
   | otherwise
   = do { (eps,hpt) <- getEpsAndHpt
        ; dflags <- getDOpts
@@ -856,6 +910,20 @@ tcIfaceGlobal name
            Succeeded thing -> return thing
     }}}}}
 
+ifCheckWiredInThing :: Name -> IfL ()
+-- Even though we are in an interface file, we want to make
+-- sure the instances of a wired-in thing are loaded (imagine f :: Double -> Double)
+-- Ditto want to ensure that RULES are loaded too
+ifCheckWiredInThing name 
+  = do { mod <- getIfModule
+               -- Check whether we are typechecking the interface for this
+               -- very module.  E.g when compiling the base library in --make mode
+               -- we may typecheck GHC.Base.hi. At that point, GHC.Base is not in
+               -- the HPT, so without the test we'll demand-load it into the PIT!
+               -- C.f. the same test in checkWiredInTyCon above
+       ; unless (mod == nameModule name)
+                (loadWiredInHomeIface name) }
+
 tcIfaceTyCon :: IfaceTyCon -> IfL TyCon
 tcIfaceTyCon IfaceIntTc        = tcWiredInTyCon intTyCon
 tcIfaceTyCon IfaceBoolTc       = tcWiredInTyCon boolTyCon
@@ -885,7 +953,7 @@ tcIfaceTyCon IfaceUbxTupleKindTc     = return ubxTupleKindTyCon
 -- sure the instances and RULES of this tycon are loaded 
 -- Imagine: f :: Double -> Double
 tcWiredInTyCon :: TyCon -> IfL TyCon
-tcWiredInTyCon tc = do { loadWiredInHomeIface (tyConName tc)
+tcWiredInTyCon tc = do { ifCheckWiredInThing (tyConName tc)
                       ; return tc }
 
 tcIfaceClass :: IfaceExtName -> IfL Class
@@ -973,7 +1041,5 @@ mk_iface_tyvar :: Name -> IfaceKind -> IfL TyVar
 mk_iface_tyvar name ifKind = do { kind <- tcIfaceType ifKind
                                 ; return (mkTyVar name kind)
                                 }
-
-mk_iface_tyvar name kind = mkTyVar name kind
 \end{code}