Basic set up for global family instance environment
[ghc-hetmet.git] / compiler / typecheck / TcInstDcls.lhs
index 1aa126f..6135ca2 100644 (file)
@@ -11,39 +11,54 @@ module TcInstDcls ( tcInstDecls1, tcInstDecls2 ) where
 import HsSyn
 import TcBinds         ( mkPragFun, tcPrags, badBootDeclErr )
 import TcTyClsDecls     ( tcIdxTyInstDecl )
-import TcClassDcl      ( tcMethodBind, mkMethodBind, badMethodErr, 
-                         tcClassDecl2, getGenericInstances )
+import TcClassDcl      ( tcMethodBind, mkMethodBind, badMethodErr, badATErr,
+                         omittedATWarn, tcClassDecl2, getGenericInstances )
 import TcRnMonad       
-import TcMType         ( tcSkolSigType, checkValidInstance, checkValidInstHead )
-import TcType          ( mkClassPred, tcSplitSigmaTy, tcSplitDFunHead, 
-                          SkolemInfo(InstSkol), tcSplitDFunTy, mkFunTy )
+import TcMType         ( tcSkolSigType, checkValidInstance,
+                         checkValidInstHead )
+import TcType          ( TcType, mkClassPred, tcSplitSigmaTy,
+                         tcSplitDFunHead,  SkolemInfo(InstSkol),
+                         tcSplitDFunTy, mkFunTy ) 
 import Inst            ( newDictBndr, newDictBndrs, instToId, showLIE, 
                          getOverlapFlag, tcExtendLocalInstEnv )
 import InstEnv         ( mkLocalInstance, instanceDFunId )
+import FamInst         ( tcExtendLocalFamInstEnv )
+import FamInstEnv      ( extractFamInsts )
 import TcDeriv         ( tcDeriving )
 import TcEnv           ( InstInfo(..), InstBindings(..), 
-                         newDFunName, tcExtendIdEnv
+                         newDFunName, tcExtendIdEnv, tcExtendGlobalEnv
                        )
 import TcHsType                ( kcHsSigType, tcHsKindedType )
 import TcUnify         ( checkSigTyVars )
 import TcSimplify      ( tcSimplifySuperClasses )
 import Type            ( zipOpenTvSubst, substTheta, mkTyConApp, mkTyVarTy,
-                          splitFunTys )
+                          splitFunTys, TyThing(ATyCon), isTyVarTy, tcEqType,
+                          substTys, emptyTvSubst, extendTvSubst )
 import Coercion         ( mkSymCoercion )
-import TyCon            ( TyCon, newTyConCo, tyConTyVars )
+import TyCon            ( TyCon, tyConName, newTyConCo_maybe, tyConTyVars,
+                         isTyConAssoc, tyConFamInst_maybe,
+                         assocTyConArgPoss_maybe )
 import DataCon         ( classDataCon, dataConTyCon, dataConInstArgTys )
-import Class           ( classBigSig )
-import Var             ( TyVar, Id, idName, idType, tyVarKind )
+import Class           ( Class, classBigSig, classATs )
+import Var             ( TyVar, Id, idName, idType, tyVarKind, tyVarName )
+import VarEnv           ( rnBndrs2, mkRnEnv2, emptyInScopeSet )
 import Id               ( mkSysLocal )
 import UniqSupply       ( uniqsFromSupply, splitUniqSupply )
 import MkId            ( mkDictFunId )
-import Name            ( Name, getSrcLoc )
-import Maybe           ( catMaybes )
-import SrcLoc          ( srcLocSpan, unLoc, noLoc, Located(..), srcSpanStart )
+import Name            ( Name, getSrcLoc, nameOccName )
+import NameSet         ( addListToNameSet, emptyNameSet, minusNameSet,
+                         nameSetToList ) 
+import Maybe           ( isNothing, fromJust, catMaybes )
+import Monad           ( when )
+import List            ( find )
+import DynFlags                ( DynFlag(Opt_WarnMissingMethods) )
+import SrcLoc          ( srcLocSpan, unLoc, noLoc, Located(..), srcSpanStart,
+                         getLoc)
 import ListSetOps      ( minusList )
 import Outputable
 import Bag
 import BasicTypes      ( Activation( AlwaysActive ), InlineSpec(..) )
+import HscTypes                ( implicitTyThings )
 import FastString
 \end{code}
 
@@ -143,27 +158,37 @@ tcInstDecls1 tycl_decls inst_decls
                -- (they recover, so that we get more than one error each
                -- round) 
 
-               -- (1) Do the ordinary instance declarations and instances of
-               --     indexed types
+               -- (1) Do class instance declarations and instances of indexed
+               --     types 
        ; let { idxty_decls = filter (isIdxTyDecl . unLoc) tycl_decls }
-       ; local_inst_infos <- mappM tcLocalInstDecl1 inst_decls
-       ; idxty_inst_infos <- mappM tcIdxTyInstDecl idxty_decls
-
-       ; let { local_inst_info = concat local_inst_infos ++ 
-                                catMaybes idxty_inst_infos
-            ; clas_decls      = filter (isClassDecl.unLoc) tycl_decls }
-
-               -- (2) Instances from generic class declarations
+       ; local_info_tycons <- mappM tcLocalInstDecl1  inst_decls
+       ; idx_tycons        <- mappM tcIdxTyInstDeclTL idxty_decls
+
+       ; let { (local_infos,
+               at_tycons)     = unzip local_info_tycons
+            ; local_info      = concat local_infos
+            ; at_idx_tycon    = concat at_tycons ++ catMaybes idx_tycons
+            ; clas_decls      = filter (isClassDecl.unLoc) tycl_decls 
+            ; implicit_things = concatMap implicitTyThings at_idx_tycon
+            }
+
+               -- (2) Add the tycons of indexed types and their implicit
+               --     tythings to the global environment
+       ; tcExtendGlobalEnv (at_idx_tycon ++ implicit_things) $ do {
+
+               -- (3) Instances from generic class declarations
        ; generic_inst_info <- getGenericInstances clas_decls
 
                -- Next, construct the instance environment so far, consisting
                -- of 
                --   a) local instance decls
                --   b) generic instances
-       ; addInsts local_inst_info   $ do {
-       ; addInsts generic_inst_info $ do {
+               --   c) local family instance decls
+       ; addInsts local_info         $ do {
+       ; addInsts generic_inst_info  $ do {
+       ; addFamInsts at_idx_tycon    $ do {
 
-               -- (3) Compute instances from "deriving" clauses; 
+               -- (4) Compute instances from "deriving" clauses; 
                -- This stuff computes a context for the derived instance
                -- decl, so it needs to know about all the instances possible
        ; (deriv_inst_info, deriv_binds) <- tcDeriving tycl_decls
@@ -171,25 +196,50 @@ tcInstDecls1 tycl_decls inst_decls
 
        ; gbl_env <- getGblEnv
        ; returnM (gbl_env, 
-                 generic_inst_info ++ deriv_inst_info ++ local_inst_info,
+                 generic_inst_info ++ deriv_inst_info ++ local_info,
                  deriv_binds) 
-    }}}}
+    }}}}}}
+  where
+    -- Make sure that toplevel type instance are not for associated types.
+    -- !!!TODO: Need to perform this check for the TyThing of type functions,
+    --         too.
+    tcIdxTyInstDeclTL ldecl@(L loc decl) =
+      do { tything <- tcIdxTyInstDecl ldecl
+        ; setSrcSpan loc $
+            when (isAssocFamily tything) $
+              addErr $ assocInClassErr (tcdName decl)
+        ; return tything
+        }
+    isAssocFamily (Just (ATyCon tycon)) =
+      case tyConFamInst_maybe tycon of
+        Nothing       -> panic "isAssocFamily: no family?!?"
+       Just (fam, _) -> isTyConAssoc fam
+    isAssocFamily (Just _            ) = panic "isAssocFamily: no tycon?!?"
+    isAssocFamily Nothing               = False
+
+assocInClassErr name = 
+  ptext SLIT("Associated type") <+> quotes (ppr name) <+> 
+  ptext SLIT("must be inside a class instance")
 
 addInsts :: [InstInfo] -> TcM a -> TcM a
 addInsts infos thing_inside
   = tcExtendLocalInstEnv (map iSpec infos) thing_inside
+
+addFamInsts :: [TyThing] -> TcM a -> TcM a
+addFamInsts tycons thing_inside
+  = tcExtendLocalFamInstEnv (extractFamInsts tycons) thing_inside
 \end{code} 
 
 \begin{code}
 tcLocalInstDecl1 :: LInstDecl Name 
-                -> TcM [InstInfo]      -- [] if there was an error
+                -> TcM ([InstInfo], [TyThing]) -- [] if there was an error
        -- A source-file instance declaration
        -- Type-check all the stuff before the "where"
        --
        -- We check for respectable instance type, and context
 tcLocalInstDecl1 decl@(L loc (InstDecl poly_ty binds uprags ats))
   =    -- Prime error recovery, set source location
-    recoverM (returnM [])              $
+    recoverM (returnM ([], []))                $
     setSrcSpan loc                     $
     addErrCtxt (instDeclCtxt1 poly_ty) $
 
@@ -203,23 +253,118 @@ tcLocalInstDecl1 decl@(L loc (InstDecl poly_ty binds uprags ats))
        ; poly_ty'  <- tcHsKindedType kinded_ty
        ; let (tyvars, theta, tau) = tcSplitSigmaTy poly_ty'
        
+       -- Next, process any associated types.
+       ; idx_tycons <- mappM tcIdxTyInstDecl ats
+
        -- Now, check the validity of the instance.
        ; (clas, inst_tys) <- checkValidInstHead tau
        ; checkValidInstance tyvars theta clas inst_tys
-
-       -- Next, process any associated types.
-       ; idxty_inst_info <- mappM tcIdxTyInstDecl ats
+       ; checkValidAndMissingATs clas (tyvars, inst_tys) 
+                                 (zip ats idx_tycons)
 
        -- Finally, construct the Core representation of the instance.
        -- (This no longer includes the associated types.)
        ; dfun_name <- newDFunName clas inst_tys (srcSpanStart loc)
        ; overlap_flag <- getOverlapFlag
-       ; let dfun  = mkDictFunId dfun_name tyvars theta clas inst_tys
-             ispec = mkLocalInstance dfun overlap_flag
+       ; let dfun           = mkDictFunId dfun_name tyvars theta clas inst_tys
+             ispec          = mkLocalInstance dfun overlap_flag
 
-       ; return $ [InstInfo { iSpec  = ispec, 
-                              iBinds = VanillaInst binds uprags }] ++
-                   catMaybes idxty_inst_info }
+       ; return ([InstInfo { iSpec  = ispec, 
+                             iBinds = VanillaInst binds uprags }],
+                 catMaybes idx_tycons)
+        }
+  where
+    -- We pass in the source form and the type checked form of the ATs.  We
+    -- really need the source form only to be able to produce more informative
+    -- error messages.
+    checkValidAndMissingATs :: Class
+                           -> ([TyVar], [TcType])     -- instance types
+                           -> [(LTyClDecl Name,       -- source form of AT
+                                Maybe TyThing)]       -- Core form of AT
+                           -> TcM ()
+    checkValidAndMissingATs clas inst_tys ats
+      = do { -- Issue a warning for each class AT that is not defined in this
+            -- instance.
+          ; let classDefATs = listToNameSet . map tyConName . classATs $ clas
+                 definedATs  = listToNameSet . map (tcdName.unLoc.fst)  $ ats
+                omitted     = classDefATs `minusNameSet` definedATs
+          ; warn <- doptM Opt_WarnMissingMethods
+          ; mapM_ (warnTc warn . omittedATWarn) (nameSetToList omitted)
+          
+            -- Ensure that all AT indexes that correspond to class parameters
+            -- coincide with the types in the instance head.  All remaining
+            -- AT arguments must be variables.  Also raise an error for any
+            -- type instances that are not associated with this class.
+          ; mapM_ (checkIndexes clas inst_tys) ats
+          }
+
+    checkIndexes _    _        (hsAT, Nothing)             = 
+      return ()           -- skip, we already had an error here
+    checkIndexes clas inst_tys (hsAT, Just (ATyCon tycon)) = 
+-- !!!TODO: check that this does the Right Thing for indexed synonyms, too!
+      checkIndexes' clas inst_tys hsAT 
+                   (tyConTyVars tycon, 
+                    snd . fromJust . tyConFamInst_maybe $ tycon)
+    checkIndexes _ _ _ = panic "checkIndexes"
+
+    checkIndexes' clas (instTvs, instTys) hsAT (atTvs, atTys)
+      = let atName = tcdName . unLoc $ hsAT
+       in
+       setSrcSpan (getLoc hsAT)       $
+       addErrCtxt (atInstCtxt atName) $
+       case find ((atName ==) . tyConName) (classATs clas) of
+         Nothing     -> addErrTc $ badATErr clas atName  -- not in this class
+         Just atDecl -> 
+           case assocTyConArgPoss_maybe atDecl of
+             Nothing   -> panic "checkIndexes': AT has no args poss?!?"
+             Just poss -> 
+
+               -- The following is tricky!  We need to deal with three
+               -- complications: (1) The AT possibly only uses a subset of
+               -- the class parameters as indexes and those it uses may be in
+               -- a different order; (2) the AT may have extra arguments,
+               -- which must be type variables; and (3) variables in AT and
+               -- instance head will be different `Name's even if their
+               -- source lexemes are identical.
+               --
+               -- Re (1), `poss' contains a permutation vector to extract the
+               -- class parameters in the right order.
+               --
+               -- Re (2), we wrap the (permuted) class parameters in a Maybe
+               -- type and use Nothing for any extra AT arguments.  (First
+               -- equation of `checkIndex' below.)
+               --
+               -- Re (3), we replace any type variable in the AT parameters
+               -- that has the same source lexeme as some variable in the
+               -- instance types with the instance type variable sharing its
+               -- source lexeme.
+               --
+               let relevantInstTys = map (instTys !!) poss
+                   instArgs        = map Just relevantInstTys ++ 
+                                     repeat Nothing  -- extra arguments
+                   renaming        = substSameTyVar atTvs instTvs
+               in
+               zipWithM_ checkIndex (substTys renaming atTys) instArgs
+
+    checkIndex ty Nothing 
+      | isTyVarTy ty         = return ()
+      | otherwise            = addErrTc $ mustBeVarArgErr ty
+    checkIndex ty (Just instTy) 
+      | ty `tcEqType` instTy = return ()
+      | otherwise            = addErrTc $ wrongATArgErr ty instTy
+
+    listToNameSet = addListToNameSet emptyNameSet 
+
+    substSameTyVar []       _            = emptyTvSubst
+    substSameTyVar (tv:tvs) replacingTvs = 
+      let replacement = case find (tv `sameLexeme`) replacingTvs of
+                         Nothing  -> mkTyVarTy tv
+                         Just rtv -> mkTyVarTy rtv
+          --
+          tv1 `sameLexeme` tv2 = 
+           nameOccName (tyVarName tv1) == nameOccName (tyVarName tv2)
+      in
+      extendTvSubst (substSameTyVar tvs replacingTvs) tv replacement
 \end{code}
 
 
@@ -405,7 +550,7 @@ tcInstDecl2 (InstInfo { iSpec = ispec,
   where
        -- For newtype T a = MkT <ty>
        -- The returned coercion has kind :: C (T a):=:C <ty>
-    co_fn tvs cls_tycon cls_inst_tys | Just co_con <- newTyConCo tycon
+    co_fn tvs cls_tycon cls_inst_tys | Just co_con <- newTyConCo_maybe tycon
           = ExprCoFn (mkTyConApp cls_tycon (drop_tail 1 cls_inst_tys ++
                       [mkSymCoercion (mkTyConApp co_con (map mkTyVarTy tvs))]))
           | otherwise
@@ -683,4 +828,19 @@ instDeclCtxt2 dfun_ty
 inst_decl_ctxt doc = ptext SLIT("In the instance declaration for") <+> quotes doc
 
 superClassCtxt = ptext SLIT("When checking the super-classes of an instance declaration")
+
+atInstCtxt name = ptext SLIT("In the associated type instance for") <+> 
+                 quotes (ppr name)
+
+mustBeVarArgErr ty = 
+  sep [ ptext SLIT("Arguments that do not correspond to a class parameter") <+>
+        ptext SLIT("must be variables")
+      , ptext SLIT("Instead of a variable, found") <+> ppr ty
+      ]
+
+wrongATArgErr ty instTy =
+  sep [ ptext SLIT("Type indexes must match class instance head")
+      , ptext SLIT("Found") <+> ppr ty <+> ptext SLIT("but expected") <+>
+         ppr instTy
+      ]
 \end{code}