summaryrefslogtreecommitdiff
path: root/compiler/coreSyn/CoreLint.hs
diff options
context:
space:
mode:
Diffstat (limited to 'compiler/coreSyn/CoreLint.hs')
-rw-r--r--compiler/coreSyn/CoreLint.hs55
1 files changed, 42 insertions, 13 deletions
diff --git a/compiler/coreSyn/CoreLint.hs b/compiler/coreSyn/CoreLint.hs
index c81d754131..aa31aed0b5 100644
--- a/compiler/coreSyn/CoreLint.hs
+++ b/compiler/coreSyn/CoreLint.hs
@@ -84,7 +84,7 @@ Core Lint is the type-checker for Core. Using it, we get the following guarantee
If all of:
1. Core Lint passes,
-2. there are no unsafe coercions (i.e. UnsafeCoerceProv),
+2. there are no unsafe coercions (i.e. unsafeEqualityProof),
3. all plugin-supplied coercions (i.e. PluginProv) are valid, and
4. all case-matches are complete
then running the compiled program will not seg-fault, assuming no bugs downstream
@@ -494,18 +494,23 @@ hence the `TopLevelFlag` on `tcPragExpr` in GHC.IfaceToCore.
-}
-lintUnfolding :: DynFlags
+lintUnfolding :: Bool -- True <=> is a compulsory unfolding
+ -> DynFlags
-> SrcLoc
-> VarSet -- Treat these as in scope
-> CoreExpr
-> Maybe MsgDoc -- Nothing => OK
-lintUnfolding dflags locn vars expr
+lintUnfolding is_compulsory dflags locn vars expr
| isEmptyBag errs = Nothing
| otherwise = Just (pprMessageBag errs)
where
in_scope = mkInScopeSet vars
- (_warns, errs) = initL dflags defaultLintFlags in_scope linter
+ (_warns, errs) = initL dflags defaultLintFlags in_scope $
+ if is_compulsory
+ -- See Note [Checking for levity polymorphism]
+ then noLPChecks linter
+ else linter
linter = addLoc (ImportedUnfolding locn) $
lintCoreExpr expr
@@ -683,7 +688,10 @@ lintIdUnfolding :: Id -> Type -> Unfolding -> LintM ()
lintIdUnfolding bndr bndr_ty uf
| isStableUnfolding uf
, Just rhs <- maybeUnfoldingTemplate uf
- = do { ty <- lintRhs bndr rhs
+ = do { ty <- if isCompulsoryUnfolding uf
+ then noLPChecks $ lintRhs bndr rhs
+ -- See Note [Checking for levity polymorphism]
+ else lintRhs bndr rhs
; ensureEqTys bndr_ty ty (mkRhsMsg bndr (text "unfolding") ty) }
lintIdUnfolding _ _ _
= return () -- Do not Lint unstable unfoldings, because that leads
@@ -699,6 +707,23 @@ that form a mutually recursive group. Only after a round of
simplification are they unravelled. So we suppress the test for
the desugarer.
+Note [Checking for levity polymorphism]
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+We ordinarily want to check for bad levity polymorphism. See
+Note [Levity polymorphism invariants] in CoreSyn. However, we do *not*
+want to do this in a compulsory unfolding. Compulsory unfoldings arise
+only internally, for things like newtype wrappers, dictionaries, and
+(notably) unsafeCoerce#. These might legitimately be levity-polymorphic;
+indeed levity-polyorphic unfoldings are a primary reason for the
+very existence of compulsory unfoldings (we can't compile code for
+the original, levity-poly, binding).
+
+It is vitally important that we do levity-polymorphism checks *after*
+performing the unfolding, but not beforehand. This is all safe because
+we will check any unfolding after it has been unfolded; checking the
+unfolding beforehand is merely an optimization, and one that actively
+hurts us here.
+
************************************************************************
* *
\subsection[lintCoreExpr]{lintCoreExpr}
@@ -997,7 +1022,8 @@ lintCoreArg fun_ty (Type arg_ty)
lintCoreArg fun_ty arg
= do { arg_ty <- markAllJoinsBad $ lintCoreExpr arg
-- See Note [Levity polymorphism invariants] in CoreSyn
- ; lintL (not (isTypeLevPoly arg_ty))
+ ; flags <- getLintFlags
+ ; lintL (not (lf_check_levity_poly flags) || not (isTypeLevPoly arg_ty))
(text "Levity-polymorphic argument:" <+>
(ppr arg <+> dcolon <+> parens (ppr arg_ty <+> dcolon <+> ppr (typeKind arg_ty))))
-- check for levity polymorphism first, because otherwise isUnliftedType panics
@@ -1055,10 +1081,6 @@ lintTyKind :: OutTyVar -> OutType -> LintM ()
-- If you edit this function, you may need to update the GHC formalism
-- See Note [GHC Formalism]
lintTyKind tyvar arg_ty
- -- 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.
= do { arg_kind <- lintType arg_ty
; unless (arg_kind `eqType` tyvar_kind)
(addErrL (mkKindErrMsg tyvar arg_ty $$ (text "Linted Arg kind:" <+> ppr arg_kind))) }
@@ -1286,7 +1308,7 @@ lintIdBndr top_lvl bind_site id linterF
lintInTy (idType id)
-- See Note [Levity polymorphism invariants] in CoreSyn
- ; lintL (isJoinId id || not (isKindLevPoly k))
+ ; lintL (isJoinId id || not (lf_check_levity_poly flags) || not (isKindLevPoly k))
(text "Levity-polymorphic binder:" <+>
(ppr id <+> dcolon <+> parens (ppr ty <+> dcolon <+> ppr k)))
@@ -1819,8 +1841,6 @@ lintCoercion co@(UnivCo prov r ty1 ty2)
= do { k1 <- lintType ty1
; k2 <- lintType ty2
; case prov of
- UnsafeCoerceProv -> return () -- no extra checks
-
PhantomProv kco -> do { lintRole co Phantom r
; check_kinds kco k1 k2 }
@@ -2095,6 +2115,7 @@ data LintFlags
, lf_check_inline_loop_breakers :: Bool -- See Note [Checking for INLINE loop breakers]
, lf_check_static_ptrs :: StaticPtrCheck -- ^ See Note [Checking StaticPtrs]
, lf_report_unsat_syns :: Bool -- ^ See Note [Linting type synonym applications]
+ , lf_check_levity_poly :: Bool -- See Note [Checking for levity polymorphism]
}
-- See Note [Checking StaticPtrs]
@@ -2112,6 +2133,7 @@ defaultLintFlags = LF { lf_check_global_ids = False
, lf_check_inline_loop_breakers = True
, lf_check_static_ptrs = AllowAnywhere
, lf_report_unsat_syns = True
+ , lf_check_levity_poly = True
}
newtype LintM a =
@@ -2248,6 +2270,13 @@ setReportUnsat ru thing_inside
let env' = env { le_flags = (le_flags env) { lf_report_unsat_syns = ru } }
in unLintM thing_inside env' errs
+-- See Note [Checking for levity polymorphism]
+noLPChecks :: LintM a -> LintM a
+noLPChecks thing_inside
+ = LintM $ \env errs ->
+ let env' = env { le_flags = (le_flags env) { lf_check_levity_poly = False } }
+ in unLintM thing_inside env' errs
+
getLintFlags :: LintM LintFlags
getLintFlags = LintM $ \ env errs -> (Just (le_flags env), errs)