..and a bit more
[ghc-hetmet.git] / compiler / typecheck / TcInstDcls.lhs
index 45338d0..b05b551 100644 (file)
@@ -51,7 +51,6 @@ pass, when the class-instance envs and GVE contain all the info from
 all the instance and value decls.  Indeed that's the reason we need
 two passes over the instance decls.
 
 all the instance and value decls.  Indeed that's the reason we need
 two passes over the instance decls.
 
-
 Here is the overall algorithm.
 Assume that we have an instance declaration
 
 Here is the overall algorithm.
 Assume that we have an instance declaration
 
@@ -176,7 +175,8 @@ tcLocalInstDecl1 :: LInstDecl Name
        -- Type-check all the stuff before the "where"
        --
        -- We check for respectable instance type, and context
        -- 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))
+tcLocalInstDecl1 decl@(L loc (InstDecl poly_ty binds uprags ats))
+  -- !!!TODO: Handle the `ats' parameter!!! -=chak
   =    -- Prime error recovery, set source location
     recoverM (returnM Nothing)         $
     setSrcSpan loc                     $
   =    -- Prime error recovery, set source location
     recoverM (returnM Nothing)         $
     setSrcSpan loc                     $
@@ -303,8 +303,103 @@ First comes the easy case of a non-local instance decl.
 
 \begin{code}
 tcInstDecl2 :: InstInfo -> TcM (LHsBinds Id)
 
 \begin{code}
 tcInstDecl2 :: InstInfo -> TcM (LHsBinds Id)
+-- Returns a binding for the dfun
+
+--
+-- Derived newtype instances
+--
+-- We need to make a copy of the dictionary we are deriving from
+-- because we may need to change some of the superclass dictionaries
+-- see Note [Newtype deriving superclasses] in TcDeriv.lhs
+--
+-- In the case of a newtype, things are rather easy
+--     class Show a => Foo a b where ...
+--     newtype T a = MkT (Tree [a]) deriving( Foo Int )
+-- The newtype gives an FC axiom looking like
+--     axiom CoT a :: Tree [a] = T a
+--
+-- So all need is to generate a binding looking like
+--     dfunFooT :: forall a. (Foo Int (Tree [a], Show (T a)) => Foo Int (T a)
+--     dfunFooT = /\a. \(ds:Show (T a)) (df:Foo (Tree [a])).
+--               case df `cast` (Foo Int (CoT a)) of
+--                  Foo _ op1 .. opn -> Foo ds op1 .. opn
+
+tcInstDecl2 (InstInfo { iSpec = ispec, 
+                       iBinds = NewTypeDerived tycon rep_tys })
+  = do { let dfun_id      = instanceDFunId ispec 
+             rigid_info   = InstSkol dfun_id
+             origin       = SigOrigin rigid_info
+             inst_ty      = idType dfun_id
+              maybe_co_con = newTyConCo tycon
+       ; (tvs, theta, inst_head) <- tcSkolSigType rigid_info inst_ty
+       ; dicts <- newDicts origin theta
+       ; uniqs <- newUniqueSupply
+       ; let (rep_dict_id:sc_dict_ids) = map instToId dicts
+               -- (Here, wee are relying on the order of dictionary 
+               -- arguments built by NewTypeDerived in TcDeriv.)
+
+              wrap_fn = CoTyLams tvs <.> CoLams dict_ids
+        
+             coerced_rep_dict = mkHsCoerce co_fn (HsVar rep_dict_id)
+
+             body | null sc_dicts = coerced_rep_dict
+                  | otherwise = HsCase coerced_rep_dict $
+                                MatchGroup [the_match] inst_head
+             the_match = mkSimpleMatch [the_pat] the_rhs
+             op_ids = zipWith (mkSysLocal FSLIT("op"))
+                              (uniqsFromSupply uniqs) op_tys
+             the_pat = ConPatOut { pat_con = cls_data_con, pat_tvs = [],
+                                   pat_dicts = map (WildPat . idType) sc_dict_ids,
+                                   pat_binds = emptyDictBinds,
+                                   pat_args = PrefixCon (map VarPat op_ids), 
+                                   pat_ty = <type of pattern> }
+             the_rhs = mkHsApps (dataConWrapId cls_data_con) types sc_dict_ids (map HsVar op_ids)
+
+        ; return (unitBag (VarBind dfun_id (mkHsCoerce wrap_fn body))) }
+  where
+    co_fn :: ExprCoFn
+    co_fn | Just co_con <- newTyConCo tycon
+         = ExprCoFn (mkAppCoercion (mkAppsCoercion tycon rep_tys) 
+                                           (mkTyConApp co_con tvs))
+         | otherwise
+         = idCoerecion
+
+tcMethods origin clas inst_tyvars' dfun_theta' inst_tys' 
+         avail_insts op_items (NewTypeDerived rep_tys)
+  = getInstLoc origin                          `thenM` \ inst_loc ->
+    mapAndUnzip3M (do_one inst_loc) op_items   `thenM` \ (meth_ids, meth_binds, rhs_insts) ->
+    
+    tcSimplifyCheck
+        (ptext SLIT("newtype derived instance"))
+        inst_tyvars' avail_insts rhs_insts     `thenM` \ lie_binds ->
+
+       -- I don't think we have to do the checkSigTyVars thing
+
+    returnM (meth_ids, lie_binds `unionBags` listToBag meth_binds)
+
+  where
+    do_one inst_loc (sel_id, _)
+       = -- The binding is like "op @ NewTy = op @ RepTy"
+               -- Make the *binder*, like in mkMethodBind
+         tcInstClassOp inst_loc sel_id inst_tys'       `thenM` \ meth_inst ->
+
+               -- Make the *occurrence on the rhs*
+         tcInstClassOp inst_loc sel_id rep_tys'        `thenM` \ rhs_inst ->
+         let
+            meth_id = instToId meth_inst
+         in
+         return (meth_id, noLoc (VarBind meth_id (nlHsVar (instToId rhs_inst))), rhs_inst)
+
+       -- Instantiate rep_tys with the relevant type variables
+       -- This looks a bit odd, because inst_tyvars' are the skolemised version
+       -- of the type variables in the instance declaration; but rep_tys doesn't
+       -- have the skolemised version, so we substitute them in here
+    rep_tys' = substTys subst rep_tys
+    subst    = zipOpenTvSubst inst_tyvars' (mkTyVarTys inst_tyvars')
+
 
 
-tcInstDecl2 (InstInfo { iSpec = ispec, iBinds = binds })
+
+tcInstDecl2 (InstInfo { iSpec = ispec, iBinds = VanillaInst monobinds uprags })
   = let 
        dfun_id    = instanceDFunId ispec
        rigid_info = InstSkol dfun_id
   = let 
        dfun_id    = instanceDFunId ispec
        rigid_info = InstSkol dfun_id
@@ -341,7 +436,7 @@ tcInstDecl2 (InstInfo { iSpec = ispec, iBinds = binds })
     in
     tcMethods origin clas inst_tyvars' 
              dfun_theta' inst_tys' avail_insts 
     in
     tcMethods origin clas inst_tyvars' 
              dfun_theta' inst_tys' avail_insts 
-             op_items binds            `thenM` \ (meth_ids, meth_binds) ->
+             op_items monobinds uprags         `thenM` \ (meth_ids, meth_binds) ->
 
        -- Figure out bindings for the superclass context
        -- Don't include this_dict in the 'givens', else
 
        -- Figure out bindings for the superclass context
        -- Don't include this_dict in the 'givens', else
@@ -356,12 +451,7 @@ tcInstDecl2 (InstInfo { iSpec = ispec, iBinds = binds })
     checkSigTyVars inst_tyvars'        `thenM_`
 
        -- Deal with 'SPECIALISE instance' pragmas 
     checkSigTyVars inst_tyvars'        `thenM_`
 
        -- Deal with 'SPECIALISE instance' pragmas 
-    let
-       specs = case binds of
-                 VanillaInst _ prags -> filter isSpecInstLSig prags
-                 other               -> []
-    in
-    tcPrags dfun_id specs                      `thenM` \ prags -> 
+    tcPrags dfun_id (filter isSpecInstLSig prags)      `thenM` \ prags -> 
     
        -- Create the result bindings
     let
     
        -- Create the result bindings
     let
@@ -405,7 +495,7 @@ tcInstDecl2 (InstInfo { iSpec = ispec, iBinds = binds })
 
 
 tcMethods origin clas inst_tyvars' dfun_theta' inst_tys' 
 
 
 tcMethods origin clas inst_tyvars' dfun_theta' inst_tys' 
-         avail_insts op_items (VanillaInst monobinds uprags)
+         avail_insts op_items monobinds uprags
   =    -- Check that all the method bindings come from this class
     let
        sel_names = [idName sel_id | (sel_id, _) <- op_items]
   =    -- Check that all the method bindings come from this class
     let
        sel_names = [idName sel_id | (sel_id, _) <- op_items]
@@ -451,48 +541,16 @@ tcMethods origin clas inst_tyvars' dfun_theta' inst_tys'
     let
        prag_fn        = mkPragFun uprags
        all_insts      = avail_insts ++ catMaybes meth_insts
     let
        prag_fn        = mkPragFun uprags
        all_insts      = avail_insts ++ catMaybes meth_insts
-       tc_method_bind = tcMethodBind inst_tyvars' dfun_theta' all_insts prag_fn
+       sig_fn n       = Just []        -- No scoped type variables, but every method has
+                                       -- a type signature, in effect, so that we check
+                                       -- the method has the right type
+       tc_method_bind = tcMethodBind inst_tyvars' dfun_theta' all_insts sig_fn prag_fn
        meth_ids       = [meth_id | (_,meth_id,_) <- meth_infos]
     in
 
     mapM tc_method_bind meth_infos             `thenM` \ meth_binds_s ->
    
     returnM (meth_ids, unionManyBags meth_binds_s)
        meth_ids       = [meth_id | (_,meth_id,_) <- meth_infos]
     in
 
     mapM tc_method_bind meth_infos             `thenM` \ meth_binds_s ->
    
     returnM (meth_ids, unionManyBags meth_binds_s)
-
-
--- Derived newtype instances
-tcMethods origin clas inst_tyvars' dfun_theta' inst_tys' 
-         avail_insts op_items (NewTypeDerived rep_tys)
-  = getInstLoc origin                          `thenM` \ inst_loc ->
-    mapAndUnzip3M (do_one inst_loc) op_items   `thenM` \ (meth_ids, meth_binds, rhs_insts) ->
-    
-    tcSimplifyCheck
-        (ptext SLIT("newtype derived instance"))
-        inst_tyvars' avail_insts rhs_insts     `thenM` \ lie_binds ->
-
-       -- I don't think we have to do the checkSigTyVars thing
-
-    returnM (meth_ids, lie_binds `unionBags` listToBag meth_binds)
-
-  where
-    do_one inst_loc (sel_id, _)
-       = -- The binding is like "op @ NewTy = op @ RepTy"
-               -- Make the *binder*, like in mkMethodBind
-         tcInstClassOp inst_loc sel_id inst_tys'       `thenM` \ meth_inst ->
-
-               -- Make the *occurrence on the rhs*
-         tcInstClassOp inst_loc sel_id rep_tys'        `thenM` \ rhs_inst ->
-         let
-            meth_id = instToId meth_inst
-         in
-         return (meth_id, noLoc (VarBind meth_id (nlHsVar (instToId rhs_inst))), rhs_inst)
-
-       -- Instantiate rep_tys with the relevant type variables
-       -- This looks a bit odd, because inst_tyvars' are the skolemised version
-       -- of the type variables in the instance declaration; but rep_tys doesn't
-       -- have the skolemised version, so we substitute them in here
-    rep_tys' = substTys subst rep_tys
-    subst    = zipOpenTvSubst inst_tyvars' (mkTyVarTys inst_tyvars')
 \end{code}
 
 
 \end{code}