{- (c) The University of Glasgow 2006 (c) The GRASP/AQUA Project, Glasgow University, 1993-1998 A ``lint'' pass to check for Core correctness -} {-# LANGUAGE CPP #-} {-# OPTIONS_GHC -fprof-auto #-} module CoreLint ( lintCoreBindings, lintUnfolding, lintPassResult, lintInteractiveExpr, lintExpr, lintAnnots, -- ** Debug output CoreLint.showPass, showPassIO, endPass, endPassIO, dumpPassResult, CoreLint.dumpIfSet, ) where #include "HsVersions.h" import CoreSyn import CoreFVs import CoreUtils import CoreMonad import Bag import Literal import DataCon import TysWiredIn import TysPrim import Var import VarEnv import VarSet import Name import Id import PprCore import ErrUtils import Coercion import SrcLoc import Kind import Type import TypeRep import TyCon import CoAxiom import BasicTypes import ErrUtils as Err import StaticFlags import ListSetOps import PrelNames import Outputable import FastString import Util import InstEnv ( instanceDFunId ) import OptCoercion ( checkAxInstCo ) import UniqSupply import HscTypes import DynFlags import Control.Monad import MonadUtils import Data.Maybe import Pair {- Note [GHC Formalism] ~~~~~~~~~~~~~~~~~~~~ This file implements the type-checking algorithm for System FC, the "official" name of the Core language. Type safety of FC is heart of the claim that executables produced by GHC do not have segmentation faults. Thus, it is useful to be able to reason about System FC independently of reading the code. To this purpose, there is a document ghc.pdf built in docs/core-spec that contains a formalism of the types and functions dealt with here. If you change just about anything in this file or you change other types/functions throughout the Core language (all signposted to this note), you should update that formalism. See docs/core-spec/README for more info about how to do so. Summary of checks ~~~~~~~~~~~~~~~~~ Checks that a set of core bindings is well-formed. The PprStyle and String just control what we print in the event of an error. The Bool value indicates whether we have done any specialisation yet (in which case we do some extra checks). We check for (a) type errors (b) Out-of-scope type variables (c) Out-of-scope local variables (d) Ill-kinded types If we have done specialisation the we check that there are (a) No top-level bindings of primitive (unboxed type) Outstanding issues: -- Things are *not* OK if: -- -- * Unsaturated type app before specialisation has been done; -- -- * Oversaturated type app after specialisation (eta reduction -- may well be happening...); Note [Linting type lets] ~~~~~~~~~~~~~~~~~~~~~~~~ In the desugarer, it's very very convenient to be able to say (in effect) let a = Type Int in
That is, use a type let. See Note [Type let] in CoreSyn. However, when linting we need to remember that a=Int, else we might reject a correct program. So we carry a type substitution (in this example [a -> Int]) and apply this substitution before comparing types. The functin lintInTy :: Type -> LintM Type returns a substituted type; that's the only reason it returns anything. When we encounter a binder (like x::a) we must apply the substitution to the type of the binding variable. lintBinders does this. For Ids, the type-substituted Id is added to the in_scope set (which itself is part of the TvSubst we are carrying down), and when we find an occurrence of an Id, we fetch it from the in-scope set. ************************************************************************ * * Beginning and ending passes * * ************************************************************************ These functions are not CoreM monad stuff, but they probably ought to be, and it makes a conveneint place. place for them. They print out stuff before and after core passes, and do Core Lint when necessary. -} showPass :: CoreToDo -> CoreM () showPass pass = do { dflags <- getDynFlags ; liftIO $ showPassIO dflags pass } showPassIO :: DynFlags -> CoreToDo -> IO () showPassIO dflags pass = Err.showPass dflags (showPpr dflags pass) endPass :: CoreToDo -> CoreProgram -> [CoreRule] -> CoreM () endPass pass binds rules = do { hsc_env <- getHscEnv ; print_unqual <- getPrintUnqualified ; liftIO $ endPassIO hsc_env print_unqual pass binds rules } endPassIO :: HscEnv -> PrintUnqualified -> CoreToDo -> CoreProgram -> [CoreRule] -> IO () -- Used by the IO-is CorePrep too endPassIO hsc_env print_unqual pass binds rules = do { dumpPassResult dflags print_unqual mb_flag (ppr pass) (pprPassDetails pass) binds rules ; lintPassResult hsc_env pass binds } where dflags = hsc_dflags hsc_env mb_flag = case coreDumpFlag pass of Just flag | dopt flag dflags -> Just flag | dopt Opt_D_verbose_core2core dflags -> Just flag _ -> Nothing dumpIfSet :: DynFlags -> Bool -> CoreToDo -> SDoc -> SDoc -> IO () dumpIfSet dflags dump_me pass extra_info doc = Err.dumpIfSet dflags dump_me (showSDoc dflags (ppr pass <+> extra_info)) doc dumpPassResult :: DynFlags -> PrintUnqualified -> Maybe DumpFlag -- Just df => show details in a file whose -- name is specified by df -> SDoc -- Header -> SDoc -- Extra info to appear after header -> CoreProgram -> [CoreRule] -> IO () dumpPassResult dflags unqual mb_flag hdr extra_info binds rules | Just flag <- mb_flag = Err.dumpSDoc dflags unqual flag (showSDoc dflags hdr) dump_doc | otherwise = Err.debugTraceMsg dflags 2 size_doc -- Report result size -- This has the side effect of forcing the intermediate to be evaluated where size_doc = sep [text "Result size of" <+> hdr, nest 2 (equals <+> ppr (coreBindsStats binds))] dump_doc = vcat [ nest 2 extra_info , size_doc , blankLine , pprCoreBindings binds , ppUnless (null rules) pp_rules ] pp_rules = vcat [ blankLine , ptext (sLit "------ Local rules for imported ids --------") , pprRules rules ] coreDumpFlag :: CoreToDo -> Maybe DumpFlag coreDumpFlag (CoreDoSimplify {}) = Just Opt_D_verbose_core2core coreDumpFlag (CoreDoPluginPass {}) = Just Opt_D_verbose_core2core coreDumpFlag CoreDoFloatInwards = Just Opt_D_verbose_core2core coreDumpFlag (CoreDoFloatOutwards {}) = Just Opt_D_verbose_core2core coreDumpFlag CoreLiberateCase = Just Opt_D_verbose_core2core coreDumpFlag CoreDoStaticArgs = Just Opt_D_verbose_core2core coreDumpFlag CoreDoCallArity = Just Opt_D_dump_call_arity coreDumpFlag CoreDoStrictness = Just Opt_D_dump_stranal coreDumpFlag CoreDoWorkerWrapper = Just Opt_D_dump_worker_wrapper coreDumpFlag CoreDoSpecialising = Just Opt_D_dump_spec coreDumpFlag CoreDoSpecConstr = Just Opt_D_dump_spec coreDumpFlag CoreCSE = Just Opt_D_dump_cse coreDumpFlag CoreDoVectorisation = Just Opt_D_dump_vect coreDumpFlag CoreDesugar = Just Opt_D_dump_ds coreDumpFlag CoreDesugarOpt = Just Opt_D_dump_ds coreDumpFlag CoreTidy = Just Opt_D_dump_simpl coreDumpFlag CorePrep = Just Opt_D_dump_prep coreDumpFlag CoreDoPrintCore = Nothing coreDumpFlag (CoreDoRuleCheck {}) = Nothing coreDumpFlag CoreDoNothing = Nothing coreDumpFlag (CoreDoPasses {}) = Nothing {- ************************************************************************ * * Top-level interfaces * * ************************************************************************ -} lintPassResult :: HscEnv -> CoreToDo -> CoreProgram -> IO () lintPassResult hsc_env pass binds | not (gopt Opt_DoCoreLinting dflags) = return () | otherwise = do { let (warns, errs) = lintCoreBindings pass (interactiveInScope hsc_env) binds ; Err.showPass dflags ("Core Linted result of " ++ showPpr dflags pass) ; displayLintResults dflags pass warns errs binds } where dflags = hsc_dflags hsc_env displayLintResults :: DynFlags -> CoreToDo -> Bag Err.MsgDoc -> Bag Err.MsgDoc -> CoreProgram -> IO () displayLintResults dflags pass warns errs binds | not (isEmptyBag errs) = do { log_action dflags dflags Err.SevDump noSrcSpan defaultDumpStyle (vcat [ lint_banner "errors" (ppr pass), Err.pprMessageBag errs , ptext (sLit "*** Offending Program ***") , pprCoreBindings binds , ptext (sLit "*** End of Offense ***") ]) ; Err.ghcExit dflags 1 } | not (isEmptyBag warns) , not opt_NoDebugOutput , showLintWarnings pass = log_action dflags dflags Err.SevDump noSrcSpan defaultDumpStyle (lint_banner "warnings" (ppr pass) $$ Err.pprMessageBag warns) | otherwise = return () where lint_banner :: String -> SDoc -> SDoc lint_banner string pass = ptext (sLit "*** Core Lint") <+> text string <+> ptext (sLit ": in result of") <+> pass <+> ptext (sLit "***") showLintWarnings :: CoreToDo -> Bool -- Disable Lint warnings on the first simplifier pass, because -- there may be some INLINE knots still tied, which is tiresomely noisy showLintWarnings (CoreDoSimplify _ (SimplMode { sm_phase = InitialPhase })) = False showLintWarnings _ = True lintInteractiveExpr :: String -> HscEnv -> CoreExpr -> IO () lintInteractiveExpr what hsc_env expr | not (gopt Opt_DoCoreLinting dflags) = return () | Just err <- lintExpr (interactiveInScope hsc_env) expr = do { display_lint_err err ; Err.ghcExit dflags 1 } | otherwise = return () where dflags = hsc_dflags hsc_env display_lint_err err = do { log_action dflags dflags Err.SevDump noSrcSpan defaultDumpStyle (vcat [ lint_banner "errors" (text what) , err , ptext (sLit "*** Offending Program ***") , pprCoreExpr expr , ptext (sLit "*** End of Offense ***") ]) ; Err.ghcExit dflags 1 } interactiveInScope :: HscEnv -> [Var] -- In GHCi we may lint expressions, or bindings arising from 'deriving' -- clauses, that mention variables bound in the interactive context. -- These are Local things (see Note [Interactively-bound Ids in GHCi] in HscTypes). -- So we have to tell Lint about them, lest it reports them as out of scope. -- -- We do this by find local-named things that may appear free in interactive -- context. This function is pretty revolting and quite possibly not quite right. -- When we are not in GHCi, the interactive context (hsc_IC hsc_env) is empty -- so this is a (cheap) no-op. -- -- See Trac #8215 for an example interactiveInScope hsc_env = varSetElems tyvars ++ ids where -- C.f. TcRnDriver.setInteractiveContext, Desugar.deSugarExpr ictxt = hsc_IC hsc_env (cls_insts, _fam_insts) = ic_instances ictxt te1 = mkTypeEnvWithImplicits (ic_tythings ictxt) te = extendTypeEnvWithIds te1 (map instanceDFunId cls_insts) ids = typeEnvIds te tyvars = mapUnionVarSet (tyVarsOfType . idType) ids -- Why the type variables? How can the top level envt have free tyvars? -- I think it's because of the GHCi debugger, which can bind variables -- f :: [t] -> [t] -- where t is a RuntimeUnk (see TcType) lintCoreBindings :: CoreToDo -> [Var] -> CoreProgram -> (Bag MsgDoc, Bag MsgDoc) -- Returns (warnings, errors) -- If you edit this function, you may need to update the GHC formalism -- See Note [GHC Formalism] lintCoreBindings pass local_in_scope binds = initL flags $ addLoc TopLevelBindings $ addInScopeVars local_in_scope $ addInScopeVars binders $ -- Put all the top-level binders in scope at the start -- This is because transformation rules can bring something -- into use 'unexpectedly' do { checkL (null dups) (dupVars dups) ; checkL (null ext_dups) (dupExtVars ext_dups) ; mapM lint_bind binds } where flags = LF { lf_check_global_ids = check_globals , lf_check_inline_loop_breakers = check_lbs } -- See Note [Checking for global Ids] check_globals = case pass of CoreTidy -> False CorePrep -> False _ -> True -- See Note [Checking for INLINE loop breakers] check_lbs = case pass of CoreDesugar -> False CoreDesugarOpt -> False _ -> True binders = bindersOfBinds binds (_, dups) = removeDups compare binders -- dups_ext checks for names with different uniques -- but but the same External name M.n. We don't -- allow this at top level: -- M.n{r3} = ... -- M.n{r29} = ... -- because they both get the same linker symbol ext_dups = snd (removeDups ord_ext (map Var.varName binders)) ord_ext n1 n2 | Just m1 <- nameModule_maybe n1 , Just m2 <- nameModule_maybe n2 = compare (m1, nameOccName n1) (m2, nameOccName n2) | otherwise = LT -- If you edit this function, you may need to update the GHC formalism -- See Note [GHC Formalism] lint_bind (Rec prs) = mapM_ (lintSingleBinding TopLevel Recursive) prs lint_bind (NonRec bndr rhs) = lintSingleBinding TopLevel NonRecursive (bndr,rhs) {- ************************************************************************ * * \subsection[lintUnfolding]{lintUnfolding} * * ************************************************************************ We use this to check all unfoldings that come in from interfaces (it is very painful to catch errors otherwise): -} lintUnfolding :: SrcLoc -> [Var] -- Treat these as in scope -> CoreExpr -> Maybe MsgDoc -- Nothing => OK lintUnfolding locn vars expr | isEmptyBag errs = Nothing | otherwise = Just (pprMessageBag errs) where (_warns, errs) = initL defaultLintFlags linter linter = addLoc (ImportedUnfolding locn) $ addInScopeVars vars $ lintCoreExpr expr lintExpr :: [Var] -- Treat these as in scope -> CoreExpr -> Maybe MsgDoc -- Nothing => OK lintExpr vars expr | isEmptyBag errs = Nothing | otherwise = Just (pprMessageBag errs) where (_warns, errs) = initL defaultLintFlags linter linter = addLoc TopLevelBindings $ addInScopeVars vars $ lintCoreExpr expr {- ************************************************************************ * * \subsection[lintCoreBinding]{lintCoreBinding} * * ************************************************************************ Check a core binding, returning the list of variables bound. -} lintSingleBinding :: TopLevelFlag -> RecFlag -> (Id, CoreExpr) -> LintM () -- If you edit this function, you may need to update the GHC formalism -- See Note [GHC Formalism] lintSingleBinding top_lvl_flag rec_flag (binder,rhs) = addLoc (RhsOf binder) $ -- Check the rhs do { ty <- lintCoreExpr rhs ; lintBinder binder -- Check match to RHS type ; binder_ty <- applySubstTy binder_ty ; checkTys binder_ty ty (mkRhsMsg binder (ptext (sLit "RHS")) ty) -- Check the let/app invariant -- See Note [CoreSyn let/app invariant] in CoreSyn ; checkL (not (isUnLiftedType binder_ty) || (isNonRec rec_flag && exprOkForSpeculation rhs)) (mkRhsPrimMsg binder rhs) -- Check that if the binder is top-level or recursive, it's not demanded ; checkL (not (isStrictId binder) || (isNonRec rec_flag && not (isTopLevel top_lvl_flag))) (mkStrictMsg binder) -- Check that if the binder is local, it is not marked as exported ; checkL (not (isExportedId binder) || isTopLevel top_lvl_flag) (mkNonTopExportedMsg binder) -- Check that if the binder is local, it does not have an external name ; checkL (not (isExternalName (Var.varName binder)) || isTopLevel top_lvl_flag) (mkNonTopExternalNameMsg binder) -- Check whether binder's specialisations contain any out-of-scope variables ; mapM_ (checkBndrIdInScope binder) bndr_vars ; flags <- getLintFlags ; when (lf_check_inline_loop_breakers flags && isStrongLoopBreaker (idOccInfo binder) && isInlinePragma (idInlinePragma binder)) (addWarnL (ptext (sLit "INLINE binder is (non-rule) loop breaker:") <+> ppr binder)) -- Only non-rule loop breakers inhibit inlining -- Check whether arity and demand type are consistent (only if demand analysis -- already happened) -- -- Note (Apr 2014): this is actually ok. See Note [Demand analysis for trivial right-hand sides] -- in DmdAnal. After eta-expansion in CorePrep the rhs is no longer trivial. -- ; let dmdTy = idStrictness binder -- ; checkL (case dmdTy of -- StrictSig dmd_ty -> idArity binder >= dmdTypeDepth dmd_ty || exprIsTrivial rhs) -- (mkArityMsg binder) ; lintIdUnfolding binder binder_ty (idUnfolding binder) } -- We should check the unfolding, if any, but this is tricky because -- the unfolding is a SimplifiableCoreExpr. Give up for now. where binder_ty = idType binder bndr_vars = varSetElems (idFreeVars binder) -- If you edit this function, you may need to update the GHC formalism -- See Note [GHC Formalism] lintBinder var | isId var = lintIdBndr var $ \_ -> (return ()) | otherwise = return () lintIdUnfolding :: Id -> Type -> Unfolding -> LintM () lintIdUnfolding bndr bndr_ty (CoreUnfolding { uf_tmpl = rhs, uf_src = src }) | isStableSource src = do { ty <- lintCoreExpr rhs ; checkTys bndr_ty ty (mkRhsMsg bndr (ptext (sLit "unfolding")) ty) } lintIdUnfolding _ _ _ = return () -- We could check more {- Note [Checking for INLINE loop breakers] ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ It's very suspicious if a strong loop breaker is marked INLINE. However, the desugarer generates instance methods with INLINE pragmas that form a mutually recursive group. Only after a round of simplification are they unravelled. So we suppress the test for the desugarer. ************************************************************************ * * \subsection[lintCoreExpr]{lintCoreExpr} * * ************************************************************************ -} --type InKind = Kind -- Substitution not yet applied type InType = Type type InCoercion = Coercion type InVar = Var type InTyVar = TyVar type OutKind = Kind -- Substitution has been applied to this, -- but has not been linted yet type LintedKind = Kind -- Substitution applied, and type is linted type OutType = Type -- Substitution has been applied to this, -- but has not been linted yet type LintedType = Type -- Substitution applied, and type is linted type OutCoercion = Coercion type OutVar = Var type OutTyVar = TyVar lintCoreExpr :: CoreExpr -> LintM OutType -- The returned type has the substitution from the monad -- already applied to it: -- lintCoreExpr e subst = exprType (subst e) -- -- The returned "type" can be a kind, if the expression is (Type ty) -- If you edit this function, you may need to update the GHC formalism -- See Note [GHC Formalism] lintCoreExpr (Var var) = do { checkL (not (var == oneTupleDataConId)) (ptext (sLit "Illegal one-tuple")) ; checkL (isId var && not (isCoVar var)) (ptext (sLit "Non term variable") <+> ppr var) ; checkDeadIdOcc var ; var' <- lookupIdInScope var ; return (idType var') } lintCoreExpr (Lit lit) = return (literalType lit) lintCoreExpr (Cast expr co) = do { expr_ty <- lintCoreExpr expr ; co' <- applySubstCo co ; (_, from_ty, to_ty, r) <- lintCoercion co' ; checkRole co' Representational r ; checkTys from_ty expr_ty (mkCastErr expr co' from_ty expr_ty) ; return to_ty } lintCoreExpr (Tick (Breakpoint _ ids) expr) = do forM_ ids $ \id -> do checkDeadIdOcc id lookupIdInScope id lintCoreExpr expr lintCoreExpr (Tick _other_tickish expr) = lintCoreExpr expr lintCoreExpr (Let (NonRec tv (Type ty)) body) | isTyVar tv = -- See Note [Linting type lets] do { ty' <- applySubstTy ty ; lintTyBndr tv $ \ tv' -> do { addLoc (RhsOf tv) $ checkTyKind tv' ty' -- Now extend the substitution so we -- take advantage of it in the body ; extendSubstL tv' ty' $ addLoc (BodyOfLetRec [tv]) $ lintCoreExpr body } } lintCoreExpr (Let (NonRec bndr rhs) body) | isId bndr = do { lintSingleBinding NotTopLevel NonRecursive (bndr,rhs) ; addLoc (BodyOfLetRec [bndr]) (lintAndScopeId bndr $ \_ -> (lintCoreExpr body)) } | otherwise = failWithL (mkLetErr bndr rhs) -- Not quite accurate lintCoreExpr (Let (Rec pairs) body) = lintAndScopeIds bndrs $ \_ -> do { checkL (null dups) (dupVars dups) ; mapM_ (lintSingleBinding NotTopLevel Recursive) pairs ; addLoc (BodyOfLetRec bndrs) (lintCoreExpr body) } where bndrs = map fst pairs (_, dups) = removeDups compare bndrs lintCoreExpr e@(App _ _) = do { fun_ty <- lintCoreExpr fun ; addLoc (AnExpr e) $ foldM lintCoreArg fun_ty args } where (fun, args) = collectArgs e lintCoreExpr (Lam var expr) = addLoc (LambdaBodyOf var) $ lintBinder var $ \ var' -> do { body_ty <- lintCoreExpr expr ; if isId var' then return (mkFunTy (idType var') body_ty) else return (mkForAllTy var' body_ty) } -- The applySubstTy is needed to apply the subst to var lintCoreExpr e@(Case scrut var alt_ty alts) = -- Check the scrutinee do { scrut_ty <- lintCoreExpr scrut ; alt_ty <- lintInTy alt_ty ; var_ty <- lintInTy (idType var) ; case tyConAppTyCon_maybe (idType var) of Just tycon | debugIsOn && isAlgTyCon tycon && not (isFamilyTyCon tycon || isAbstractTyCon tycon) && null (tyConDataCons tycon) -> pprTrace "Lint warning: case binder's type has no constructors" (ppr var <+> ppr (idType var)) -- This can legitimately happen for type families $ return () _otherwise -> return () -- Don't use lintIdBndr on var, because unboxed tuple is legitimate ; subst <- getTvSubst ; checkTys var_ty scrut_ty (mkScrutMsg var var_ty scrut_ty subst) ; lintAndScopeId var $ \_ -> do { -- Check the alternatives mapM_ (lintCoreAlt scrut_ty alt_ty) alts ; checkCaseAlts e scrut_ty alts ; return alt_ty } } -- This case can't happen; linting types in expressions gets routed through -- lintCoreArgs lintCoreExpr (Type ty) = pprPanic "lintCoreExpr" (ppr ty) lintCoreExpr (Coercion co) = do { (_kind, ty1, ty2, role) <- lintInCo co ; return (mkCoercionType role ty1 ty2) } {- Note [Kind instantiation in coercions] ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ Consider the following coercion axiom: ax_co [(k_ag :: BOX), (f_aa :: k_ag -> Constraint)] :: T k_ag f_aa ~ f_aa Consider the following instantiation: ax_co <* -> *>