[project @ 1999-06-24 12:27:58 by simonmar]
[ghc-hetmet.git] / ghc / compiler / stgSyn / StgLint.lhs
index 6c7fb4a..631218a 100644 (file)
@@ -17,12 +17,12 @@ import DataCon              ( DataCon, dataConArgTys, dataConType )
 import Const           ( literalType, conType, Literal )
 import Maybes          ( catMaybes )
 import Name            ( isLocallyDefined, getSrcLoc )
-import ErrUtils                ( ErrMsg )
+import ErrUtils                ( ErrMsg, Message, addErrLocHdrLine, pprBagOfErrors, dontAddErrLoc )
 import Type            ( mkFunTys, splitFunTys, splitAlgTyConApp_maybe, 
-                         isUnLiftedType, isTyVarTy, Type
+                         isUnLiftedType, isTyVarTy, splitForAllTys, Type
                        )
 import TyCon           ( TyCon, isDataTyCon )
-import Util            ( zipEqual, trace )
+import Util            ( zipEqual )
 import Outputable
 
 infixr 9 `thenL`, `thenL_`, `thenMaybeL`, `thenMaybeL_`
@@ -114,6 +114,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 (
@@ -148,6 +151,10 @@ lintStgExpr e@(StgCon con args _)
   where
     con_ty = conType con
 
+lintStgExpr (StgLam _ bndrs _)
+  = addErrL (ptext SLIT("Unexpected StgLam") <+> ppr bndrs)    `thenL_`
+    returnL Nothing
+
 lintStgExpr (StgLet binds body)
   = lintStgBinds binds         `thenL` \ binders ->
     addLoc (BodyOfLetRec binders) (
@@ -168,12 +175,15 @@ 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
+    (trace (showSDoc (ppr e)) $ 
+       -- we only allow case of tail-call or primop.
+    (case scrut of
+       StgApp _ _ -> returnL ()
+       StgCon _ _ _ -> returnL ()
+       other -> addErrL (mkCaseOfCaseMsg e))   `thenL_`
+
+    addInScopeVars [bndr] (lintStgAlts alts scrut_ty)
+  )
   where
     scrut_ty = get_ty alts
 
@@ -184,10 +194,9 @@ lintStgExpr e@(StgCase scrut _ _ bndr _ alts)
 \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 ->
@@ -260,33 +269,31 @@ data LintLocInfo
   | LambdaBodyOf [Id]  -- The lambda-binder
   | BodyOfLetRec [Id]  -- One of the binders
 
-instance Outputable LintLocInfo where
-    ppr (RhsOf v)
-      = hcat [ppr (getSrcLoc v), ptext SLIT(": [RHS of "), pp_binders [v], char ']']
+dumpLoc (RhsOf v) =
+  (getSrcLoc v, ptext SLIT(" [RHS of ") <> pp_binders [v] <> char ']' )
+dumpLoc (LambdaBodyOf bs) =
+  (getSrcLoc (head bs), ptext SLIT(" [in body of lambda with binders ") <> pp_binders bs <> char ']' )
 
-    ppr (LambdaBodyOf bs)
-      = hcat [ptext SLIT(": [in body of lambda with binders "), pp_binders bs, char ']']
+dumpLoc (BodyOfLetRec bs) =
+  (getSrcLoc (head bs), ptext SLIT(" [in body of letrec with binders ") <> pp_binders bs <> char ']' )
 
-    ppr (BodyOfLetRec bs)
-      = hcat [ppr (getSrcLoc (head bs)),
-               ptext SLIT(": [in body of letrec with binders "), pp_binders bs, char ']']
 
 pp_binders :: [Id] -> SDoc
 pp_binders bs
   = sep (punctuate comma (map pp_binder bs))
   where
     pp_binder b
-      = hsep [ppr b, ptext SLIT("::"), ppr (idType b)]
+      = hsep [ppr b, dcolon, ppr (idType b)]
 \end{code}
 
 \begin{code}
-initL :: LintM a -> Maybe ErrMsg
+initL :: LintM a -> Maybe Message
 initL m
   = case (m [] emptyVarSet emptyBag) of { (_, errs) ->
     if isEmptyBag errs then
        Nothing
     else
-       Just (foldBag ($$) (\ msg -> msg) empty errs)
+       Just (pprBagOfErrors errs)
     }
 
 returnL :: a -> LintM a
@@ -331,20 +338,20 @@ mapMaybeL f (x:xs)
 \end{code}
 
 \begin{code}
-checkL :: Bool -> ErrMsg -> LintM ()
+checkL :: Bool -> Message -> LintM ()
 checkL True  msg loc scope errs = ((), errs)
 checkL False msg loc scope errs = ((), addErr errs msg loc)
 
-addErrL :: ErrMsg -> LintM ()
+addErrL :: Message -> LintM ()
 addErrL msg loc scope errs = ((), addErr errs msg loc)
 
-addErr :: Bag ErrMsg -> ErrMsg -> [LintLocInfo] -> Bag ErrMsg
+addErr :: Bag ErrMsg -> Message -> [LintLocInfo] -> Bag ErrMsg
 
 addErr errs_so_far msg locs
   = errs_so_far `snocBag` mk_msg locs
   where
-    mk_msg (loc:_) = hang (ppr loc) 4 msg
-    mk_msg []      = msg
+    mk_msg (loc:_) = let (l,hdr) = dumpLoc loc in addErrLocHdrLine l hdr msg
+    mk_msg []      = dontAddErrLoc "" msg
 
 addLoc :: LintLocInfo -> LintM a -> LintM a
 addLoc extra_loc m loc scope errs
@@ -369,16 +376,23 @@ 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)
-           -> ErrMsg           -- Error messgae
-           -> LintM (Maybe Type)       -- The result type
+checkFunApp :: Type                -- The function type
+           -> [Type]               -- The arg type(s)
+           -> Message              -- Error messgae
+           -> LintM (Maybe Type)   -- The result 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
+    (_, de_forall_ty)   = splitForAllTys fun_ty
+    (expected_arg_tys, res_ty) = splitFunTys de_forall_ty
 
     cfa res_ty expected []     -- Args have run out; that's fine
       = (Just (mkFunTys expected res_ty), errs)
@@ -395,9 +409,7 @@ 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}
@@ -408,60 +420,54 @@ checkInScope id loc scope errs
     else
        ((), errs)
 
-checkTys :: Type -> Type -> ErrMsg -> LintM ()
+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 -> ErrMsg
+mkCaseAltMsg :: StgCaseAlts -> Message
 mkCaseAltMsg alts
   = ($$) (text "In some case alternatives, type of alternatives not all same:")
-           -- LATER: (ppr alts)
-           (panic "mkCaseAltMsg")
-
-mkCaseDataConMsg :: StgExpr -> ErrMsg
-mkCaseDataConMsg expr
-  = ($$) (ptext SLIT("A case scrutinee not a type-constructor type:"))
-           (ppr expr)
+           (empty) -- LATER: ppr alts
 
-mkCaseAbstractMsg :: TyCon -> ErrMsg
+mkCaseAbstractMsg :: TyCon -> Message
 mkCaseAbstractMsg tycon
   = ($$) (ptext SLIT("An algebraic case on an abstract type:"))
            (ppr tycon)
 
-mkDefltMsg :: Id -> ErrMsg
+mkDefltMsg :: Id -> Message
 mkDefltMsg bndr
   = ($$) (ptext SLIT("Binder of a case expression doesn't match type of scrutinee:"))
            (panic "mkDefltMsg")
 
-mkFunAppMsg :: Type -> [Type] -> StgExpr -> ErrMsg
+mkFunAppMsg :: Type -> [Type] -> StgExpr -> Message
 mkFunAppMsg fun_ty arg_tys expr
   = vcat [text "In a function application, function type doesn't match arg types:",
              hang (ptext SLIT("Function type:")) 4 (ppr fun_ty),
              hang (ptext SLIT("Arg types:")) 4 (vcat (map (ppr) arg_tys)),
              hang (ptext SLIT("Expression:")) 4 (ppr expr)]
 
-mkRhsConMsg :: Type -> [Type] -> ErrMsg
+mkRhsConMsg :: Type -> [Type] -> Message
 mkRhsConMsg fun_ty arg_tys
   = vcat [text "In a RHS constructor application, con type doesn't match arg types:",
              hang (ptext SLIT("Constructor type:")) 4 (ppr fun_ty),
              hang (ptext SLIT("Arg types:")) 4 (vcat (map (ppr) arg_tys))]
 
-mkUnappTyMsg :: Id -> Type -> ErrMsg
+mkUnappTyMsg :: Id -> Type -> Message
 mkUnappTyMsg var ty
   = vcat [text "Variable has a for-all type, but isn't applied to any types.",
              (<>) (ptext SLIT("Var:      ")) (ppr var),
              (<>) (ptext SLIT("Its type: ")) (ppr ty)]
 
-mkAlgAltMsg1 :: Type -> ErrMsg
+mkAlgAltMsg1 :: Type -> Message
 mkAlgAltMsg1 ty
   = ($$) (text "In some case statement, type of scrutinee is not a data type:")
            (ppr ty)
 
-mkAlgAltMsg2 :: Type -> DataCon -> ErrMsg
+mkAlgAltMsg2 :: Type -> DataCon -> Message
 mkAlgAltMsg2 ty con
   = vcat [
        text "In some algebraic case alternative, constructor is not a constructor of scrutinee type:",
@@ -469,7 +475,7 @@ mkAlgAltMsg2 ty con
        ppr con
     ]
 
-mkAlgAltMsg3 :: DataCon -> [Id] -> ErrMsg
+mkAlgAltMsg3 :: DataCon -> [Id] -> Message
 mkAlgAltMsg3 con alts
   = vcat [
        text "In some algebraic case alternative, number of arguments doesn't match constructor:",
@@ -477,7 +483,7 @@ mkAlgAltMsg3 con alts
        ppr alts
     ]
 
-mkAlgAltMsg4 :: Type -> Id -> ErrMsg
+mkAlgAltMsg4 :: Type -> Id -> Message
 mkAlgAltMsg4 ty arg
   = vcat [
        text "In some algebraic case alternative, type of argument doesn't match data constructor:",
@@ -485,12 +491,16 @@ mkAlgAltMsg4 ty arg
        ppr arg
     ]
 
-mkPrimAltMsg :: (Literal, StgExpr) -> ErrMsg
+mkPrimAltMsg :: (Literal, StgExpr) -> Message
 mkPrimAltMsg alt
   = text "In a primitive case alternative, type of literal doesn't match type of scrutinee:"
     $$ ppr alt
 
-mkRhsMsg :: Id -> Type -> ErrMsg
+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:"),
                     ppr binder],