[project @ 2003-05-14 09:13:52 by simonmar]
[ghc-hetmet.git] / ghc / compiler / stgSyn / StgLint.lhs
index d844e9d..28b02a9 100644 (file)
@@ -10,19 +10,20 @@ module StgLint ( lintStgBindings ) where
 
 import StgSyn
 
-import Bag             ( Bag, emptyBag, isEmptyBag, snocBag, foldBag )
-import Id              ( Id, idType )
+import Bag             ( Bag, emptyBag, isEmptyBag, snocBag, bagToList )
+import Id              ( Id, idType, isLocalId )
 import VarSet
-import DataCon         ( DataCon, dataConArgTys, dataConType )
-import Const           ( literalType, conType, Literal )
+import DataCon         ( DataCon, dataConArgTys, dataConRepType )
+import PrimOp          ( primOpType )
+import Literal         ( literalType, Literal )
 import Maybes          ( catMaybes )
-import Name            ( isLocallyDefined, getSrcLoc )
-import ErrUtils                ( ErrMsg, Message, addErrLocHdrLine, pprBagOfErrors, dontAddErrLoc )
-import Type            ( mkFunTys, splitFunTys, splitAlgTyConApp_maybe, 
-                         isUnLiftedType, isTyVarTy, Type
+import Name            ( getSrcLoc )
+import ErrUtils                ( Message, addErrLocHdrLine )
+import Type            ( mkFunTys, splitFunTys, splitTyConApp_maybe,
+                         isUnLiftedType, isTyVarTy, dropForAlls, Type
                        )
-import TyCon           ( TyCon, isDataTyCon )
-import Util            ( zipEqual )
+import TyCon           ( TyCon, isAlgTyCon, isNewTyCon, tyConDataCons )
+import Util            ( zipEqual, equalLength )
 import Outputable
 
 infixr 9 `thenL`, `thenL_`, `thenMaybeL`, `thenMaybeL_`
@@ -32,6 +33,18 @@ Checks for
        (a) *some* type errors
        (b) locally-defined variables used but not defined
 
+
+Note: unless -dverbose-stg is on, display of lint errors will result
+in "panic: bOGUS_LVs".
+
+WARNING: 
+~~~~~~~~
+
+This module has suffered bit-rot; it is likely to yield lint errors
+for Stg code that is currently perfectly acceptable for code
+generation.  Solution: don't use it!  (KSW 2000-05).
+
+
 %************************************************************************
 %*                                                                     *
 \subsection{``lint'' for various constructs}
@@ -67,7 +80,7 @@ lintStgBindings whodunnit binds
 
 \begin{code}
 lintStgArg :: StgArg -> LintM (Maybe Type)
-lintStgArg (StgConArg con) = returnL (Just (conType con))
+lintStgArg (StgLitArg lit) = returnL (Just (literalType lit))
 lintStgArg (StgVarArg v)   = lintStgVar v
 
 lintStgVar v  = checkInScope v `thenL_`
@@ -114,6 +127,9 @@ lint_binds_help (binder, rhs)
 \begin{code}
 lintStgRhs :: StgRhs -> LintM (Maybe Type)
 
+lintStgRhs (StgRhsClosure _ _ _ _ _ [] expr)
+  = lintStgExpr expr
+
 lintStgRhs (StgRhsClosure _ _ _ _ _ binders expr)
   = addLoc (LambdaBodyOf binders) (
     addInScopeVars binders (
@@ -127,12 +143,14 @@ lintStgRhs (StgRhsCon _ con args)
       Nothing      -> returnL Nothing
       Just arg_tys  -> checkFunApp con_ty arg_tys (mkRhsConMsg con_ty arg_tys)
   where
-    con_ty = dataConType con
+    con_ty = dataConRepType con
 \end{code}
 
 \begin{code}
 lintStgExpr :: StgExpr -> LintM (Maybe Type)   -- Nothing if error found
 
+lintStgExpr (StgLit l) = returnL (Just (literalType l))
+
 lintStgExpr e@(StgApp fun args)
   = lintStgVar fun             `thenMaybeL` \ fun_ty  ->
     mapMaybeL lintStgArg args  `thenL`      \ maybe_arg_tys ->
@@ -140,13 +158,27 @@ lintStgExpr e@(StgApp fun args)
       Nothing      -> returnL Nothing
       Just arg_tys  -> checkFunApp fun_ty arg_tys (mkFunAppMsg fun_ty arg_tys e)
 
-lintStgExpr e@(StgCon con args _)
+lintStgExpr e@(StgConApp con args)
   = mapMaybeL lintStgArg args  `thenL` \ maybe_arg_tys ->
     case maybe_arg_tys of
       Nothing      -> returnL Nothing
       Just arg_tys  -> checkFunApp con_ty arg_tys (mkFunAppMsg con_ty arg_tys e)
   where
-    con_ty = conType con
+    con_ty = dataConRepType con
+
+lintStgExpr e@(StgOpApp (StgFCallOp _ _) args res_ty)
+  =    -- We don't have enough type information to check
+       -- the application; ToDo
+    mapMaybeL lintStgArg args  `thenL` \ maybe_arg_tys ->
+    returnL (Just res_ty)
+
+lintStgExpr e@(StgOpApp (StgPrimOp op) args _)
+  = mapMaybeL lintStgArg args  `thenL` \ maybe_arg_tys ->
+    case maybe_arg_tys of
+      Nothing      -> returnL Nothing
+      Just arg_tys  -> checkFunApp op_ty arg_tys (mkFunAppMsg op_ty arg_tys e)
+  where
+    op_ty = primOpType op
 
 lintStgExpr (StgLam _ bndrs _)
   = addErrL (ptext SLIT("Unexpected StgLam") <+> ppr bndrs)    `thenL_`
@@ -170,28 +202,36 @@ lintStgExpr (StgSCC _ expr)       = lintStgExpr expr
 
 lintStgExpr e@(StgCase scrut _ _ bndr _ alts)
   = lintStgExpr scrut          `thenMaybeL` \ _ ->
-    checkTys (idType bndr) scrut_ty (mkDefltMsg bndr) `thenL_`
-
-       -- Check that it is a data type
-    case (splitAlgTyConApp_maybe scrut_ty) of
-      Just (tycon, _, _) | isDataTyCon tycon
-             -> addInScopeVars [bndr] (lintStgAlts alts scrut_ty tycon)
-      other   -> addErrL (mkCaseDataConMsg e)  `thenL_`
-                returnL Nothing
-  where
-    scrut_ty = get_ty alts
 
-    get_ty (StgAlgAlts  ty _ _) = ty
-    get_ty (StgPrimAlts ty _ _) = ty
+    (case alts of
+       StgPrimAlts tc _ _       -> check_bndr tc
+       StgAlgAlts (Just tc) _ _ -> check_bndr tc
+       StgAlgAlts Nothing   _ _ -> returnL ()
+    )                                                  `thenL_`
+       
+    (trace (showSDoc (ppr e)) $ 
+       -- we only allow case of tail-call or primop.
+    (case scrut of
+       StgApp _ _    -> returnL ()
+       StgConApp _ _ -> returnL ()
+       other -> addErrL (mkCaseOfCaseMsg e))   `thenL_`
+
+    addInScopeVars [bndr] (lintStgAlts alts scrut_ty)
+    )
+  where
+    scrut_ty     = idType bndr
+    bad_bndr      = mkDefltMsg bndr
+    check_bndr tc = case splitTyConApp_maybe scrut_ty of
+                       Just (bndr_tc, _) -> checkL (tc == bndr_tc) bad_bndr
+                       Nothing           -> addErrL bad_bndr
 \end{code}
 
 \begin{code}
 lintStgAlts :: StgCaseAlts
             -> Type            -- Type of scrutinee
-            -> TyCon                   -- TyCon pinned on the case
             -> LintM (Maybe Type)      -- Type of alternatives
 
-lintStgAlts alts scrut_ty case_tycon
+lintStgAlts alts scrut_ty
   = (case alts of
         StgAlgAlts _ alg_alts deflt ->
           mapL (lintAlgAlt scrut_ty) alg_alts  `thenL` \ maybe_alt_tys ->
@@ -213,18 +253,21 @@ lintStgAlts alts scrut_ty case_tycon
          check ty = checkTys first_ty ty (mkCaseAltMsg alts)
 
 lintAlgAlt scrut_ty (con, args, _, rhs)
-  = (case splitAlgTyConApp_maybe scrut_ty of
-      Nothing ->
-        addErrL (mkAlgAltMsg1 scrut_ty)
-      Just (tycon, tys_applied, cons) ->
+  = (case splitTyConApp_maybe scrut_ty of
+      Just (tycon, tys_applied) | isAlgTyCon tycon && 
+                                 not (isNewTyCon tycon) ->
         let
+          cons    = tyConDataCons tycon
           arg_tys = dataConArgTys con tys_applied
+               -- This almost certainly does not work for existential constructors
         in
         checkL (con `elem` cons) (mkAlgAltMsg2 scrut_ty con) `thenL_`
-        checkL (length arg_tys == length args) (mkAlgAltMsg3 con args)
+        checkL (equalLength arg_tys args) (mkAlgAltMsg3 con args)
                                                                 `thenL_`
         mapL check (zipEqual "lintAlgAlt:stg" arg_tys args)     `thenL_`
         returnL ()
+      other ->
+        addErrL (mkAlgAltMsg1 scrut_ty)
     )                                                           `thenL_`
     addInScopeVars args        (
         lintStgExpr rhs
@@ -256,8 +299,8 @@ lintDeflt deflt@(StgBindDefault rhs) scrut_ty = lintStgExpr rhs
 \begin{code}
 type LintM a = [LintLocInfo]   -- Locations
            -> IdSet            -- Local vars in scope
-           -> Bag ErrMsg       -- Error messages so far
-           -> (a, Bag ErrMsg)  -- Result and error messages (if any)
+           -> Bag Message      -- Error messages so far
+           -> (a, Bag Message) -- Result and error messages (if any)
 
 data LintLocInfo
   = RhsOf Id           -- The variable bound
@@ -288,7 +331,7 @@ initL m
     if isEmptyBag errs then
        Nothing
     else
-       Just (pprBagOfErrors errs)
+       Just (vcat (punctuate (text "") (bagToList errs)))
     }
 
 returnL :: a -> LintM a
@@ -340,13 +383,14 @@ checkL False msg loc scope errs = ((), addErr errs msg loc)
 addErrL :: Message -> LintM ()
 addErrL msg loc scope errs = ((), addErr errs msg loc)
 
-addErr :: Bag ErrMsg -> Message -> [LintLocInfo] -> Bag ErrMsg
+addErr :: Bag Message -> Message -> [LintLocInfo] -> Bag Message
 
 addErr errs_so_far msg locs
   = errs_so_far `snocBag` mk_msg locs
   where
-    mk_msg (loc:_) = let (l,hdr) = dumpLoc loc in addErrLocHdrLine l hdr msg
-    mk_msg []      = dontAddErrLoc "" msg
+    mk_msg (loc:_) = let (l,hdr) = dumpLoc loc 
+                    in addErrLocHdrLine l hdr msg
+    mk_msg []      = msg
 
 addLoc :: LintLocInfo -> LintM a -> LintM a
 addLoc extra_loc m loc scope errs
@@ -360,8 +404,6 @@ addInScopeVars ids m loc scope errs
     -- a real error out of it...
     let
        new_set = mkVarSet ids
-
-       shadowed = scope `intersectVarSet` new_set
     in
 --  After adding -fliberate-case, Simon decided he likes shadowed
 --  names after all.  WDP 94/07
@@ -371,6 +413,12 @@ addInScopeVars ids m loc scope errs
     m loc (scope `unionVarSet` new_set) errs
 \end{code}
 
+Checking function applications: we only check that the type has the
+right *number* of arrows, we don't actually compare the types.  This
+is because we can't expect the types to be equal - the type
+applications and type lambdas that we use to calculate accurate types
+have long since disappeared.
+
 \begin{code}
 checkFunApp :: Type                -- The function type
            -> [Type]               -- The arg type(s)
@@ -380,7 +428,7 @@ checkFunApp :: Type                     -- The function type
 checkFunApp fun_ty arg_tys msg loc scope errs
   = cfa res_ty expected_arg_tys arg_tys
   where
-    (expected_arg_tys, res_ty) = splitFunTys fun_ty
+    (expected_arg_tys, res_ty) = splitFunTys (dropForAlls fun_ty)
 
     cfa res_ty expected []     -- Args have run out; that's fine
       = (Just (mkFunTys expected res_ty), errs)
@@ -397,37 +445,29 @@ checkFunApp fun_ty arg_tys msg loc scope errs
          (new_expected, new_res) -> cfa new_res new_expected arg_tys
 
     cfa res_ty (expected_arg_ty:expected_arg_tys) (arg_ty:arg_tys)
-      = if (expected_arg_ty == arg_ty)
-       then cfa res_ty expected_arg_tys arg_tys
-       else (Nothing, addErr errs msg loc) -- Arg mis-match
+      = cfa res_ty expected_arg_tys arg_tys
 \end{code}
 
 \begin{code}
 checkInScope :: Id -> LintM ()
 checkInScope id loc scope errs
-  = if isLocallyDefined id && not (id `elemVarSet` scope) then
+  = if isLocalId id && not (id `elemVarSet` scope) then
        ((), addErr errs (hsep [ppr id, ptext SLIT("is out of scope")]) loc)
     else
        ((), errs)
 
 checkTys :: Type -> Type -> Message -> LintM ()
 checkTys ty1 ty2 msg loc scope errs
-  = if (ty1 == ty2)
-    then ((), errs)
-    else ((), addErr errs msg loc)
+  = -- if (ty1 == ty2) then
+    ((), errs)
+    -- else ((), addErr errs msg loc)
 \end{code}
 
 \begin{code}
 mkCaseAltMsg :: StgCaseAlts -> Message
 mkCaseAltMsg alts
   = ($$) (text "In some case alternatives, type of alternatives not all same:")
-           -- LATER: (ppr alts)
-           (panic "mkCaseAltMsg")
-
-mkCaseDataConMsg :: StgExpr -> Message
-mkCaseDataConMsg expr
-  = ($$) (ptext SLIT("A case scrutinee not a type-constructor type:"))
-           (ppr expr)
+           (empty) -- LATER: ppr alts
 
 mkCaseAbstractMsg :: TyCon -> Message
 mkCaseAbstractMsg tycon
@@ -492,6 +532,10 @@ mkPrimAltMsg alt
   = text "In a primitive case alternative, type of literal doesn't match type of scrutinee:"
     $$ ppr alt
 
+mkCaseOfCaseMsg :: StgExpr -> Message
+mkCaseOfCaseMsg e
+  = text "Case of non-tail-call:" $$ ppr e
+
 mkRhsMsg :: Id -> Type -> Message
 mkRhsMsg binder ty
   = vcat [hsep [ptext SLIT("The type of this binder doesn't match the type of its RHS:"),