%
-% (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}
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 Outputable ( Outputable(..) )
+import Maybes ( catMaybes )
+import Name ( isLocallyDefined, getSrcLoc, Name{-instance NamedThing-} )
+import Outputable ( Outputable(..){-instance * []-} )
import PprCore
import PprStyle ( PprStyle(..) )
import PprType ( GenType, GenTyVar, TyCon )
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,isVisibleDataTyCon )
-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`
ppStr ("*** Core Lint Errors: in " ++ whoDunnit ++ " ***"),
msg sty,
ppStr "*** Offending Program ***",
- ppAboves
- (map (pprCoreBinding sty (pprBigCoreBinder sty) (pprTypedCoreBinder sty) (ppr sty))
- binds),
+ ppAboves (map (pprCoreBinding sty) binds),
ppStr "*** End of Offense ***"
])
where
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 ->
(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)
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}
%************************************************************************
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}
%************************************************************************
%************************************************************************
\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}
\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 (AlgAlts alts deflt) ty tycon
- = panic "CoreLint.lintCoreAlts"
-{- LATER:
- WDP: can't tell what type DNT wants here
+lintCoreAlts whole_alts@(AlgAlts alts deflt) ty --tycon
= -- Check tycon is not a primitive tycon
- addErrIfL (isPrimTyCon tycon) (mkCasePrimMsg tycon)
- `seqL`
- -- Check we have a non-abstract data tycon
- addErrIfL (not (isVisibleDataTyCon tycon)) (mkCaseAbstractMsg 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`
lintDeflt deflt ty
`thenL` \maybe_deflt_ty ->
- mapL (lintAlgAlt ty tycon) alts
+ mapL (lintAlgAlt ty {-tycon-}) alts
`thenL` \maybe_alt_tys ->
- returnL (maybe_deflt_ty : maybe_alt_tys)
+ -- Check the result types
+ case catMaybes (maybe_deflt_ty : maybe_alt_tys) of
+ [] -> returnL Nothing
-lintCoreAlts (PrimAlts alts deflt) ty tycon
+ (first_ty:tys) -> mapL check tys `seqL`
+ returnL (Just first_ty)
+ where
+ check ty = checkTys first_ty ty (mkCaseAltMsg whole_alts)
+
+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
`thenL` \maybe_deflt_ty ->
- returnL (maybe_deflt_ty : maybe_alt_tys)
-- Check the result types
--}
-{-
- `thenL` \ maybe_result_tys ->
- case catMaybes (maybe_result_tys) of
+ case catMaybes (maybe_deflt_ty : maybe_alt_tys) of
[] -> returnL Nothing
(first_ty:tys) -> mapL check tys `seqL`
returnL (Just first_ty)
where
- check ty = checkTys first_ty ty (mkCaseAltMsg alts)
--}
+ check ty = checkTys first_ty ty (mkCaseAltMsg whole_alts)
-lintAlgAlt scrut_ty (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 (
\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)
\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
-- 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)
mkCaseAbstractMsg :: TyCon -> ErrMsg
mkCaseAbstractMsg tycon sty
- = ppAbove (ppStr "An algebraic case on an abstract type:")
+ = ppAbove (ppStr "An algebraic case on some weird type:")
(ppr sty tycon)
mkDefltMsg :: CoreCaseDefault -> ErrMsg
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
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