[project @ 1996-07-25 20:43:49 by partain]
[ghc-hetmet.git] / ghc / compiler / coreSyn / CoreLint.lhs
index e31af01..99afabc 100644 (file)
@@ -1,5 +1,5 @@
 %
-% (c) The GRASP/AQUA Project, Glasgow University, 1993-1995
+% (c) The GRASP/AQUA Project, Glasgow University, 1993-1996
 %
 \section[CoreLint]{A ``lint'' pass to check for Core correctness}
 
@@ -11,18 +11,21 @@ module CoreLint (
        lintUnfolding
     ) where
 
-import Ubiq
+IMP_Ubiq()
 
 import CoreSyn
 
 import Bag
-import Kind            ( Kind{-instance-} )
+import Kind            ( hasMoreBoxityInfo, Kind{-instance-} )
 import Literal         ( literalType, Literal{-instance-} )
-import Id              ( idType, isBottomingId,
-                         getInstantiatedDataConSig, GenId{-instances-}
+import Id              ( idType, isBottomingId, dataConRepType,
+                         dataConArgTys, GenId{-instances-},
+                         emptyIdSet, mkIdSet, intersectIdSets,
+                         unionIdSets, elementOfIdSet, SYN_IE(IdSet)
                        )
 import Maybes          ( catMaybes )
-import Outputable      ( Outputable(..) )
+import Name            ( isLocallyDefined, getSrcLoc, Name{-instance NamedThing-} )
+import Outputable      ( Outputable(..){-instance * []-} )
 import PprCore
 import PprStyle                ( PprStyle(..) )
 import PprType         ( GenType, GenTyVar, TyCon )
@@ -30,18 +33,18 @@ import Pretty
 import PrimOp          ( primOpType, PrimOp(..) )
 import PrimRep         ( PrimRep(..) )
 import SrcLoc          ( SrcLoc )
-import Type            ( mkFunTy,getFunTy_maybe,mkForAllTy,getForAllTy_maybe,
-                         isPrimType,getTypeKind,instantiateTy,
+import Type            ( mkFunTy,getFunTy_maybe,mkForAllTy,mkForAllTys,getForAllTy_maybe,
+                         getFunTyExpandingDicts_maybe,
+                         getForAllTyExpandingDicts_maybe,
+                         isPrimType,typeKind,instantiateTy,splitSigmaTy,
                          mkForAllUsageTy,getForAllUsageTy,instantiateUsage,
-                         maybeAppDataTyCon, eqTy
-                       )
-import TyCon           ( isPrimTyCon, tyConFamilySize )
-import TyVar           ( getTyVarKind, GenTyVar{-instances-} )
-import UniqSet         ( emptyUniqSet, mkUniqSet, intersectUniqSets,
-                         unionUniqSets, elementOfUniqSet, UniqSet(..)
+                         maybeAppDataTyConExpandingDicts, eqTy
+--                       ,expandTy -- ToDo:rm
                        )
+import TyCon           ( isPrimTyCon )
+import TyVar           ( tyVarKind, GenTyVar{-instances-} )
 import Unique          ( Unique )
-import Usage           ( GenUsage )
+import Usage           ( GenUsage, SYN_IE(Usage) )
 import Util            ( zipEqual, pprTrace, pprPanic, assertPanic, panic )
 
 infixr 9 `thenL`, `seqL`, `thenMaybeL`, `seqMaybeL`
@@ -183,6 +186,8 @@ lintCoreExpr :: CoreExpr -> LintM (Maybe Type)      -- Nothing if error found
 lintCoreExpr (Var var) = checkInScope var `seqL` returnL (Just (idType var))
 lintCoreExpr (Lit lit) = returnL (Just (literalType lit))
 lintCoreExpr (SCC _ expr) = lintCoreExpr expr
+lintCoreExpr (Coerce _ ty expr)
+  = lintCoreExpr expr `seqL` returnL (Just ty)
 
 lintCoreExpr (Let binds body)
   = lintCoreBinding binds `thenL` \binders ->
@@ -193,19 +198,19 @@ lintCoreExpr (Let binds body)
        (addInScopeVars binders (lintCoreExpr body))
 
 lintCoreExpr e@(Con con args)
-  = lintCoreArgs False e (idType con) args
+  = lintCoreArgs {-False-} e (dataConRepType con) args
     -- Note: we don't check for primitive types in these arguments
 
 lintCoreExpr e@(Prim op args)
-  = lintCoreArgs True e (primOpType op) args
+  = lintCoreArgs {-True-} e (primOpType op) args
     -- Note: we do check for primitive types in these arguments
 
 lintCoreExpr e@(App fun@(Var v) arg) | isBottomingId v
-  = lintCoreExpr fun `thenMaybeL` \ ty -> lintCoreArg False e ty arg
+  = lintCoreExpr fun `thenMaybeL` \ ty -> lintCoreArg {-False-} e ty arg
     -- Note: we don't check for primitive types in argument to 'error'
 
 lintCoreExpr e@(App fun arg)
-  = lintCoreExpr fun `thenMaybeL` \ty -> lintCoreArg True e ty arg
+  = lintCoreExpr fun `thenMaybeL` \ty -> lintCoreArg {-True-} e ty arg
     -- Note: we do check for primitive types in this argument
 
 lintCoreExpr (Lam (ValBinder var) expr)
@@ -217,14 +222,11 @@ lintCoreExpr (Lam (ValBinder var) expr)
 lintCoreExpr (Lam (TyBinder tyvar) expr)
   = lintCoreExpr expr `thenMaybeL` \ty ->
     returnL (Just(mkForAllTy tyvar ty))
-    -- TODO: Should add in-scope type variable at this point
+    -- ToDo: Should add in-scope type variable at this point
 
 lintCoreExpr e@(Case scrut alts)
  = lintCoreExpr scrut `thenMaybeL` \ty ->
-   -- Check that it is a data type
-   case maybeAppDataTyCon ty of
-     Nothing -> addErrL (mkCaseDataConMsg e) `seqL` returnL Nothing
-     Just(tycon, _, _) -> lintCoreAlts alts ty tycon
+   lintCoreAlts alts ty
 \end{code}
 
 %************************************************************************
@@ -237,12 +239,12 @@ The boolean argument indicates whether we should flag type
 applications to primitive types as being errors.
 
 \begin{code}
-lintCoreArgs :: Bool -> CoreExpr -> Type -> [CoreArg] -> LintM (Maybe Type)
+lintCoreArgs :: {-Bool ->-} CoreExpr -> Type -> [CoreArg] -> LintM (Maybe Type)
 
-lintCoreArgs _          _ ty [] = returnL (Just ty)
-lintCoreArgs checkTyApp e ty (a : args)
-  = lintCoreArg  checkTyApp e ty  a `thenMaybeL` \ res ->
-    lintCoreArgs checkTyApp e res args
+lintCoreArgs _ ty [] = returnL (Just ty)
+lintCoreArgs e ty (a : args)
+  = lintCoreArg  e ty  a `thenMaybeL` \ res ->
+    lintCoreArgs e res args
 \end{code}
 
 %************************************************************************
@@ -252,36 +254,54 @@ lintCoreArgs checkTyApp e ty (a : args)
 %************************************************************************
 
 \begin{code}
-lintCoreArg :: Bool -> CoreExpr -> Type -> CoreArg -> LintM (Maybe Type)
+lintCoreArg :: {-Bool ->-} CoreExpr -> Type -> CoreArg -> LintM (Maybe Type)
 
-lintCoreArg _ e ty (LitArg lit)
+lintCoreArg e ty (LitArg lit)
   = -- Make sure function type matches argument
-    case (getFunTy_maybe ty) of
-      Just (arg,res) | (literalType lit `eqTy` arg) -> returnL(Just res)
-      _ -> addErrL (mkAppMsg ty (literalType lit) e) `seqL` returnL Nothing
+    case (getFunTyExpandingDicts_maybe False{-no peeking in newtypes-} ty) of
+      Just (arg,res) | (lit_ty `eqTy` arg) -> returnL(Just res)
+      _ -> addErrL (mkAppMsg ty lit_ty e) `seqL` returnL Nothing
+  where
+    lit_ty = literalType lit
 
-lintCoreArg _ e ty (VarArg v)
+lintCoreArg e ty (VarArg v)
   = -- Make sure variable is bound
     checkInScope v `seqL`
     -- Make sure function type matches argument
-    case (getFunTy_maybe ty) of
-      Just (arg,res) | (idType v `eqTy` arg) -> returnL(Just res)
-      _ -> addErrL (mkAppMsg ty (idType v) e) `seqL` returnL Nothing
+    case (getFunTyExpandingDicts_maybe False{-as above-} ty) of
+      Just (arg,res) | (var_ty `eqTy` arg) -> returnL(Just res)
+      _ -> addErrL (mkAppMsg ty var_ty e) `seqL` returnL Nothing
+  where
+    var_ty = idType v
 
-lintCoreArg checkTyApp e ty a@(TyArg arg_ty)
-  = -- TODO: Check that ty is well-kinded and has no unbound tyvars
+lintCoreArg e ty a@(TyArg arg_ty)
+  = -- ToDo: Check that ty is well-kinded and has no unbound tyvars
     checkIfSpecDoneL (not (isPrimType arg_ty)) (mkSpecTyAppMsg a)
     `seqL`
-    case (getForAllTy_maybe ty) of
-      Just (tyvar,body) | (getTyVarKind tyvar == getTypeKind arg_ty) ->
-       returnL(Just(instantiateTy [(tyvar,arg_ty)] body))
-      _ -> addErrL (mkTyAppMsg ty arg_ty e) `seqL` returnL Nothing
+    case (getForAllTyExpandingDicts_maybe ty) of
+      Nothing -> addErrL (mkTyAppMsg SLIT("Illegal") ty arg_ty e) `seqL` returnL Nothing
+
+      Just (tyvar,body) ->
+       let
+           tyvar_kind = tyVarKind tyvar
+           argty_kind = typeKind arg_ty
+       in
+       if argty_kind `hasMoreBoxityInfo` tyvar_kind
+               -- Arg type might be boxed for a function with an uncommitted
+               -- tyvar; notably this is used so that we can give
+               --      error :: forall a:*. String -> a
+               -- and then apply it to both boxed and unboxed types.
+        then
+           returnL(Just(instantiateTy [(tyvar,arg_ty)] body))
+       else
+           pprTrace "lintCoreArg:kinds:" (ppCat [ppr PprDebug tyvar_kind, ppr PprDebug argty_kind]) $
+           addErrL (mkTyAppMsg SLIT("Kinds not right in") ty arg_ty e) `seqL` returnL Nothing
        
-lintCoreArg _ e ty (UsageArg u)
-  = -- TODO: Check that usage has no unbound usage variables
+lintCoreArg e ty (UsageArg u)
+  = -- ToDo: Check that usage has no unbound usage variables
     case (getForAllUsageTy ty) of
       Just (uvar,bounds,body) ->
-        -- TODO Check argument satisfies bounds
+        -- ToDo: Check argument satisfies bounds
         returnL(Just(panic "lintCoreArg:instantiateUsage uvar u body"))
       _ -> addErrL (mkUsageAppMsg ty u e) `seqL` returnL Nothing
 \end{code}
@@ -295,20 +315,20 @@ lintCoreArg _ e ty (UsageArg u)
 \begin{code}
 lintCoreAlts :: CoreCaseAlts
             -> Type                    -- Type of scrutinee
-            -> TyCon                   -- TyCon pinned on the case
+--          -> TyCon                   -- TyCon pinned on the case
             -> LintM (Maybe Type)      -- Type of alternatives
 
-lintCoreAlts whole_alts@(AlgAlts alts deflt) ty tycon
+lintCoreAlts whole_alts@(AlgAlts alts deflt) ty --tycon
   = -- Check tycon is not a primitive tycon
-    addErrIfL (isPrimTyCon tycon) (mkCasePrimMsg tycon)
-    `seqL`
+--    addErrIfL (isPrimTyCon tycon) (mkCasePrimMsg tycon)
+--    `seqL`
     -- Check we are scrutinising a proper datatype
     -- (ToDo: robustify)
-    addErrIfL (not (tyConFamilySize tycon >= 1)) (mkCaseAbstractMsg tycon)
-    `seqL`
+--    addErrIfL (not (tyConFamilySize tycon >= 1)) (mkCaseAbstractMsg tycon)
+--    `seqL`
     lintDeflt deflt ty
     `thenL` \maybe_deflt_ty ->
-    mapL (lintAlgAlt ty tycon) alts
+    mapL (lintAlgAlt ty {-tycon-}) alts
     `thenL` \maybe_alt_tys ->
     -- Check the result types
     case catMaybes (maybe_deflt_ty : maybe_alt_tys) of
@@ -319,10 +339,10 @@ lintCoreAlts whole_alts@(AlgAlts alts deflt) ty tycon
        where
          check ty = checkTys first_ty ty (mkCaseAltMsg whole_alts)
 
-lintCoreAlts whole_alts@(PrimAlts alts deflt) ty tycon
+lintCoreAlts whole_alts@(PrimAlts alts deflt) ty --tycon
   = -- Check tycon is a primitive tycon
-    addErrIfL (not (isPrimTyCon tycon)) (mkCaseNotPrimMsg tycon)
-    `seqL`
+--    addErrIfL (not (isPrimTyCon tycon)) (mkCaseNotPrimMsg tycon)
+--    `seqL`
     mapL (lintPrimAlt ty) alts
     `thenL` \maybe_alt_tys ->
     lintDeflt deflt ty
@@ -336,18 +356,18 @@ lintCoreAlts whole_alts@(PrimAlts alts deflt) ty tycon
        where
          check ty = checkTys first_ty ty (mkCaseAltMsg whole_alts)
 
-lintAlgAlt scrut_ty tycon{-ToDo: use it!-} (con,args,rhs)
-  = (case maybeAppDataTyCon scrut_ty of
+lintAlgAlt scrut_ty {-tycon-ToDo: use it!-} (con,args,rhs)
+  = (case maybeAppDataTyConExpandingDicts scrut_ty of
       Nothing ->
         addErrL (mkAlgAltMsg1 scrut_ty)
       Just (tycon, tys_applied, cons) ->
         let
-          (_, arg_tys, _) = getInstantiatedDataConSig con tys_applied
+          arg_tys = dataConArgTys con tys_applied
         in
         checkL (con `elem` cons) (mkAlgAltMsg2 scrut_ty con) `seqL`
         checkL (length arg_tys == length args) (mkAlgAltMsg3 con args)
                                                                 `seqL`
-        mapL check (arg_tys `zipEqual` args)                    `seqL`
+        mapL check (zipEqual "lintAlgAlt" arg_tys args)         `seqL`
         returnL ()
     )                                                           `seqL`
     addInScopeVars args        (
@@ -381,7 +401,7 @@ lintDeflt deflt@(BindDefault binder rhs) ty
 \begin{code}
 type LintM a = Bool            -- True <=> specialisation has been done
            -> [LintLocInfo]    -- Locations
-           -> UniqSet Id       -- Local vars in scope
+           -> IdSet            -- Local vars in scope
            -> Bag ErrMsg       -- Error messages so far
            -> (a, Bag ErrMsg)  -- Result and error messages (if any)
 
@@ -418,7 +438,7 @@ pp_binder sty b = ppCat [ppr sty b, ppStr "::", ppr sty (idType b)]
 \begin{code}
 initL :: LintM a -> Bool -> Maybe ErrMsg
 initL m spec_done
-  = case (m spec_done [] emptyUniqSet emptyBag) of { (_, errs) ->
+  = case (m spec_done [] emptyIdSet emptyBag) of { (_, errs) ->
     if isEmptyBag errs then
        Nothing
     else
@@ -503,24 +523,27 @@ addInScopeVars ids m spec loc scope errs
     -- For now, it's just a "trace"; we may make
     -- a real error out of it...
     let
-       new_set = mkUniqSet ids
+       new_set = mkIdSet ids
 
-       shadowed = scope `intersectUniqSets` new_set
+--     shadowed = scope `intersectIdSets` new_set
     in
 --  After adding -fliberate-case, Simon decided he likes shadowed
 --  names after all.  WDP 94/07
 --  (if isEmptyUniqSet shadowed
 --  then id
 --  else pprTrace "Shadowed vars:" (ppr PprDebug (uniqSetToList shadowed))) (
-    m spec loc (scope `unionUniqSets` new_set) errs
+    m spec loc (scope `unionIdSets` new_set) errs
 --  )
 \end{code}
 
 \begin{code}
 checkInScope :: Id -> LintM ()
 checkInScope id spec loc scope errs
-  = if isLocallyDefined id && not (id `elementOfUniqSet` scope) then
-      ((),addErr errs (\sty -> ppCat [ppr sty id,ppStr "is out of scope"]) loc)
+  = let
+       id_name = getName id
+    in
+    if isLocallyDefined id_name && not (id `elementOfIdSet` scope) then
+      ((),addErr errs (\sty -> ppCat [ppr sty id, ppStr "is out of scope"]) loc)
     else
       ((),errs)
 
@@ -562,20 +585,17 @@ mkDefltMsg deflt sty
 
 mkAppMsg :: Type -> Type -> CoreExpr -> ErrMsg
 mkAppMsg fun arg expr sty
-  = ppAboves [ppStr "Argument values doesn't match argument type:",
+  = ppAboves [ppStr "Argument value doesn't match argument type:",
              ppHang (ppStr "Fun type:") 4 (ppr sty fun),
              ppHang (ppStr "Arg type:") 4 (ppr sty arg),
              ppHang (ppStr "Expression:") 4 (pp_expr sty expr)]
 
-mkTyAppMsg :: Type -> Type -> CoreExpr -> ErrMsg
-mkTyAppMsg ty arg expr sty
-  = panic "mkTyAppMsg"
-{-
-  = ppAboves [ppStr "Illegal type application:",
-             ppHang (ppStr "Exp type:") 4 (ppr sty exp),
-             ppHang (ppStr "Arg type:") 4 (ppr sty arg),
+mkTyAppMsg :: FAST_STRING -> Type -> Type -> CoreExpr -> ErrMsg
+mkTyAppMsg msg ty arg expr sty
+  = ppAboves [ppCat [ppPStr msg, ppStr "type application:"],
+             ppHang (ppStr "Exp type:")   4 (ppr sty ty),
+             ppHang (ppStr "Arg type:")   4 (ppr sty arg),
              ppHang (ppStr "Expression:") 4 (pp_expr sty expr)]
--}
 
 mkUsageAppMsg :: Type -> Usage -> CoreExpr -> ErrMsg
 mkUsageAppMsg ty u expr sty
@@ -588,6 +608,7 @@ mkAlgAltMsg1 :: Type -> ErrMsg
 mkAlgAltMsg1 ty sty
   = ppAbove (ppStr "In some case statement, type of scrutinee is not a data type:")
            (ppr sty ty)
+--         (ppAbove (ppr sty ty) (ppr sty (expandTy ty))) -- ToDo: rm
 
 mkAlgAltMsg2 :: Type -> Id -> ErrMsg
 mkAlgAltMsg2 ty con sty