summaryrefslogtreecommitdiff
path: root/compiler/GHC/Core/Lint.hs
diff options
context:
space:
mode:
Diffstat (limited to 'compiler/GHC/Core/Lint.hs')
-rw-r--r--compiler/GHC/Core/Lint.hs109
1 files changed, 80 insertions, 29 deletions
diff --git a/compiler/GHC/Core/Lint.hs b/compiler/GHC/Core/Lint.hs
index fdd7da96c0..cf094619b3 100644
--- a/compiler/GHC/Core/Lint.hs
+++ b/compiler/GHC/Core/Lint.hs
@@ -34,6 +34,7 @@ import GHC.Driver.Ppr
import GHC.Driver.Env
import GHC.Core
+import GHC.Core.FamInstEnv
import GHC.Core.FVs
import GHC.Core.Utils
import GHC.Core.Stats ( coreBindsStats )
@@ -83,6 +84,8 @@ import GHC.Core.Coercion.Opt ( checkAxInstCo )
import GHC.Core.Opt.Arity ( typeArity )
import GHC.Types.Demand ( splitDmdSig, isDeadEndDiv )
import GHC.Types.TypeEnv
+import GHC.Tc.Solver.Monad ( stepsWithEvidence )
+import GHC.Unit.External
import GHC.Unit.Module.ModGuts
import GHC.Runtime.Context
@@ -283,19 +286,20 @@ be, and it makes a convenient place for them. They print out stuff
before and after core passes, and do Core Lint when necessary.
-}
-endPass :: CoreToDo -> CoreProgram -> [CoreRule] -> CoreM ()
-endPass pass binds rules
+endPass :: CoreToDo -> CoreProgram -> [CoreRule] -> [FamInst] -> CoreM ()
+endPass pass binds rules fam_insts
= do { hsc_env <- getHscEnv
; print_unqual <- getPrintUnqualified
- ; liftIO $ endPassIO hsc_env print_unqual pass binds rules }
+ ; liftIO $ endPassIO hsc_env print_unqual pass binds rules fam_insts }
endPassIO :: HscEnv -> PrintUnqualified
- -> CoreToDo -> CoreProgram -> [CoreRule] -> IO ()
+ -> CoreToDo -> CoreProgram -> [CoreRule] -> [FamInst] -> IO ()
-- Used by the IO-is CorePrep too
-endPassIO hsc_env print_unqual pass binds rules
+endPassIO hsc_env print_unqual pass binds rules fam_insts
= do { dumpPassResult logger dflags print_unqual mb_flag
(ppr pass) (pprPassDetails pass) binds rules
- ; lintPassResult hsc_env pass binds }
+ ; fam_envs <- getFamInstEnvsIO hsc_env fam_insts
+ ; lintPassResult hsc_env fam_envs pass binds }
where
logger = hsc_logger hsc_env
dflags = hsc_dflags hsc_env
@@ -304,6 +308,17 @@ endPassIO hsc_env print_unqual pass binds rules
| dopt Opt_D_verbose_core2core dflags -> Just flag
_ -> Nothing
+-- AMG TODO: it's far from clear this is right
+getFamInstEnvsIO :: HscEnv -> [FamInst] -> IO FamInstEnvs
+getFamInstEnvsIO hsc_env this_module_fam_insts
+ = do { let (_home_insts, home_fam_inst_list) = hptInstances hsc_env (\_ -> True)
+ ; let home_fam_insts = extendFamInstEnvList emptyFamInstEnv home_fam_inst_list
+ ; let (_, ic_fam_insts) = ic_instances (hsc_IC hsc_env)
+ ; let all_home_fam_insts = extendFamInstEnvList home_fam_insts (this_module_fam_insts ++ ic_fam_insts)
+ ; eps_fam_insts <- eps_fam_inst_env <$> hscEPS hsc_env
+ ; return (eps_fam_insts, all_home_fam_insts)
+ }
+
dumpIfSet :: Logger -> DynFlags -> Bool -> CoreToDo -> SDoc -> SDoc -> IO ()
dumpIfSet logger dflags dump_me pass extra_info doc
= Logger.dumpIfSet logger dflags dump_me (showSDoc dflags (ppr pass <+> extra_info)) doc
@@ -376,12 +391,12 @@ coreDumpFlag (CoreDoPasses {}) = Nothing
************************************************************************
-}
-lintPassResult :: HscEnv -> CoreToDo -> CoreProgram -> IO ()
-lintPassResult hsc_env pass binds
+lintPassResult :: HscEnv -> FamInstEnvs -> CoreToDo -> CoreProgram -> IO ()
+lintPassResult hsc_env fam_envs pass binds
| not (gopt Opt_DoCoreLinting dflags)
= return ()
| otherwise
- = do { let warns_and_errs = lintCoreBindings dflags pass (interactiveInScope $ hsc_IC hsc_env) binds
+ = do { let warns_and_errs = lintCoreBindings dflags fam_envs pass (interactiveInScope $ hsc_IC hsc_env) binds
; Err.showPass logger dflags ("Core Linted result of " ++ showPpr dflags pass)
; displayLintResults logger dflags (showLintWarnings pass) (ppr pass)
(pprCoreBindings binds) warns_and_errs }
@@ -434,10 +449,12 @@ lintInteractiveExpr :: SDoc -- ^ The source of the linted expression
lintInteractiveExpr what hsc_env expr
| not (gopt Opt_DoCoreLinting dflags)
= return ()
- | Just err <- lintExpr dflags (interactiveInScope $ hsc_IC hsc_env) expr
- = displayLintResults logger dflags False what (pprCoreExpr expr) (emptyBag, err)
| otherwise
- = return ()
+ = do { fam_envs <- getFamInstEnvsIO hsc_env [] -- AMG TODO: is empty list right?
+ ; case lintExpr dflags fam_envs (interactiveInScope $ hsc_IC hsc_env) expr of
+ Just err -> displayLintResults logger dflags False what (pprCoreExpr expr) (emptyBag, err)
+ Nothing -> return ()
+ }
where
dflags = hsc_dflags hsc_env
logger = hsc_logger hsc_env
@@ -469,12 +486,12 @@ interactiveInScope ictxt
-- where t is a RuntimeUnk (see TcType)
-- | Type-check a 'CoreProgram'. See Note [Core Lint guarantee].
-lintCoreBindings :: DynFlags -> CoreToDo -> [Var] -> CoreProgram -> WarnsAndErrs
+lintCoreBindings :: DynFlags -> FamInstEnvs -> CoreToDo -> [Var] -> CoreProgram -> WarnsAndErrs
-- Returns (warnings, errors)
-- If you edit this function, you may need to update the GHC formalism
-- See Note [GHC Formalism]
-lintCoreBindings dflags pass local_in_scope binds
- = initL dflags flags local_in_scope $
+lintCoreBindings dflags fam_envs pass local_in_scope binds
+ = initL dflags flags fam_envs local_in_scope $
addLoc TopLevelBindings $
do { checkL (null dups) (dupVars dups)
; checkL (null ext_dups) (dupExtVars ext_dups)
@@ -554,17 +571,18 @@ hence the `TopLevelFlag` on `tcPragExpr` in GHC.IfaceToCore.
lintUnfolding :: Bool -- True <=> is a compulsory unfolding
-> DynFlags
+ -> FamInstEnvs
-> SrcLoc
-> VarSet -- Treat these as in scope
-> CoreExpr
-> Maybe (Bag SDoc) -- Nothing => OK
-lintUnfolding is_compulsory dflags locn var_set expr
+lintUnfolding is_compulsory dflags fam_envs locn var_set expr
| isEmptyBag errs = Nothing
| otherwise = Just errs
where
vars = nonDetEltsUniqSet var_set
- (_warns, errs) = initL dflags (defaultLintFlags dflags) vars $
+ (_warns, errs) = initL dflags (defaultLintFlags dflags) fam_envs vars $
if is_compulsory
-- See Note [Checking for levity polymorphism]
then noLPChecks linter
@@ -573,15 +591,16 @@ lintUnfolding is_compulsory dflags locn var_set expr
lintCoreExpr expr
lintExpr :: DynFlags
+ -> FamInstEnvs
-> [Var] -- Treat these as in scope
-> CoreExpr
-> Maybe (Bag SDoc) -- Nothing => OK
-lintExpr dflags vars expr
+lintExpr dflags fam_envs vars expr
| isEmptyBag errs = Nothing
| otherwise = Just errs
where
- (_warns, errs) = initL dflags (defaultLintFlags dflags) vars linter
+ (_warns, errs) = initL dflags (defaultLintFlags dflags) fam_envs vars linter
linter = addLoc TopLevelBindings $
lintCoreExpr expr
@@ -2095,7 +2114,7 @@ lintCoercion co@(UnivCo prov r ty1 ty2)
; ty2' <- lintType ty2
; let k1 = typeKind ty1'
k2 = typeKind ty2'
- ; prov' <- lint_prov k1 k2 prov
+ ; prov' <- lint_prov k1 ty1' k2 ty2' prov
; when (r /= Phantom && classifiesTypeWithValues k1
&& classifiesTypeWithValues k2)
@@ -2144,22 +2163,47 @@ lintCoercion co@(UnivCo prov r ty1 ty2)
_ -> return ()
}
- lint_prov k1 k2 (PhantomProv kco)
+ lint_prov k1 _ k2 _ (PhantomProv kco)
= do { kco' <- lintStarCoercion kco
; lintRole co Phantom r
; check_kinds kco' k1 k2
; return (PhantomProv kco') }
- lint_prov k1 k2 (ProofIrrelProv kco)
+ lint_prov k1 _ k2 _ (ProofIrrelProv kco)
= do { lintL (isCoercionTy ty1) (mkBadProofIrrelMsg ty1 co)
; lintL (isCoercionTy ty2) (mkBadProofIrrelMsg ty2 co)
; kco' <- lintStarCoercion kco
; check_kinds kco k1 k2
; return (ProofIrrelProv kco') }
- lint_prov _ _ prov@(PluginProv _) = return prov
-
- lint_prov _ _ prov@(StepsProv _ _) = return prov -- AMG TODO: actually lint this
+ lint_prov _ _ _ _ prov@(PluginProv _) = return prov
+
+ lint_prov _ ty1' _ ty2' prov@(StepsProv m n)
+ = do { fam_envs <- getFamInstEnvs
+ ; let mb1 = stepsWithEvidence m fam_envs ty1'
+ ; let mb2 = stepsWithEvidence n fam_envs ty2'
+ ; case (mb1, mb2) of
+ (Just (u, co1), Just (v, co2)) -> do { checkL (u `eqType` v) (report mb1 mb2 "inputs do not reduce to equal types")
+ ; lco <- lintCoercion (mkSymCo co1 `mkTransCo` co2)
+ ; checkL (coercionLKind lco `eqType` ty1')
+ (report mb1 mb2 "coercion left type wrong")
+ ; checkL (coercionRKind lco `eqType` ty2')
+ (report mb1 mb2 "coercion right type wrong")
+ ; return ()
+ }
+ _ -> addWarnL (report mb1 mb2 "could not reduce")
+ ; return prov
+ }
+ where
+ report u v s =
+ hang (text $ "Invalid steps coercion: " ++ s)
+ 2 (vcat [ text "LHS:" <+> ppr ty1'
+ , text "Expected" <+> ppr m <+> text "steps"
+ , text "Reduced LHS:" <+> ppr u
+ , text "RHS:" <+> ppr ty2'
+ , text "Expected" <+> ppr n <+> text "steps"
+ , text "Reduced RHS:" <+> ppr v
+ ])
check_kinds kco k1 k2
= do { let Pair k1' k2' = coercionKind kco
@@ -2335,12 +2379,13 @@ lintCoercion (HoleCo h)
lintAxioms :: Logger
-> DynFlags
+ -> FamInstEnvs
-> SDoc -- ^ The source of the linted axioms
-> [CoAxiom Branched]
-> IO ()
-lintAxioms logger dflags what axioms =
+lintAxioms logger dflags fam_envs what axioms =
displayLintResults logger dflags True what (vcat $ map pprCoAxiom axioms) $
- initL dflags (defaultLintFlags dflags) [] $
+ initL dflags (defaultLintFlags dflags) fam_envs [] $
do { mapM_ lint_axiom axioms
; let axiom_groups = groupWith coAxiomTyCon axioms
; mapM_ lint_axiom_group axiom_groups }
@@ -2498,6 +2543,7 @@ compatible_branches (CoAxBranch { cab_tvs = tvs1
substTy unifying_subst rhs2'
Nothing -> True
+
{-
************************************************************************
* *
@@ -2532,6 +2578,7 @@ data LintEnv
-- See Note [Join points]
, le_dynflags :: DynFlags -- DynamicFlags
+ , le_fam_envs :: FamInstEnvs
, le_ue_aliases :: NameEnv UsageEnv -- Assigns usage environments to the
-- alias-like binders, as found in
-- non-recursive lets.
@@ -2697,9 +2744,9 @@ data LintLocInfo
| InCo Coercion -- Inside a coercion
| InAxiom (CoAxiom Branched) -- Inside a CoAxiom
-initL :: DynFlags -> LintFlags -> [Var]
+initL :: DynFlags -> LintFlags -> FamInstEnvs -> [Var]
-> LintM a -> WarnsAndErrs -- Warnings and errors
-initL dflags flags vars m
+initL dflags flags fam_envs vars m
= case unLintM m env (emptyBag, emptyBag) of
(Just _, errs) -> errs
(Nothing, errs@(_, e)) | not (isEmptyBag e) -> errs
@@ -2713,6 +2760,7 @@ initL dflags flags vars m
, le_joins = emptyVarSet
, le_loc = []
, le_dynflags = dflags
+ , le_fam_envs = fam_envs
, le_ue_aliases = emptyNameEnv }
setReportUnsat :: Bool -> LintM a -> LintM a
@@ -2826,6 +2874,9 @@ getValidJoins = LintM (\ env errs -> (Just (le_joins env), errs))
getTCvSubst :: LintM TCvSubst
getTCvSubst = LintM (\ env errs -> (Just (le_subst env), errs))
+getFamInstEnvs :: LintM FamInstEnvs
+getFamInstEnvs = LintM (\ env errs -> (Just (le_fam_envs env), errs))
+
getUEAliases :: LintM (NameEnv UsageEnv)
getUEAliases = LintM (\ env errs -> (Just (le_ue_aliases env), errs))