summaryrefslogtreecommitdiff
path: root/compiler/GHC/HsToCore/Utils.hs
diff options
context:
space:
mode:
Diffstat (limited to 'compiler/GHC/HsToCore/Utils.hs')
-rw-r--r--compiler/GHC/HsToCore/Utils.hs65
1 files changed, 64 insertions, 1 deletions
diff --git a/compiler/GHC/HsToCore/Utils.hs b/compiler/GHC/HsToCore/Utils.hs
index 5c68525f12..333929c956 100644
--- a/compiler/GHC/HsToCore/Utils.hs
+++ b/compiler/GHC/HsToCore/Utils.hs
@@ -30,7 +30,7 @@ module GHC.HsToCore.Utils (
wrapBind, wrapBinds,
mkErrorAppDs, mkCoreAppDs, mkCoreAppsDs, mkCastDs,
- mkFailExpr,
+ mkFailExpr, dsWhenNoErrs,
seqVar,
@@ -982,6 +982,69 @@ mk_fail_msg dflags ctx pat
= showPpr dflags $ text "Pattern match failure in" <+> pprStmtContext ctx
<+> text "at" <+> ppr (getLocA pat)
+{- Note [Desugaring representation-polymorphic applications]
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+To desugar a function application
+
+> HsApp _ f e :: HsExpr GhcTc
+
+into Core, we need to know whether the argument e is lifted or unlifted,
+in order to respect the let/app invariant.
+ (See Note [Core let/app invariant] in GHC.Core)
+
+This causes a problem when e is representation-polymorphic, as we aren't able
+to determine whether to build a Core application
+
+> f_desugared e_desugared
+
+or a strict binding:
+
+> case e_desugared of { x -> f_desugared x }
+
+See GHC.Core.Make.mkValApp, which will call isUnliftedType, which panics
+on a representation-polymorphic type.
+
+These representation-polymorphic applications are disallowed in source Haskell,
+but we might want to continue desugaring as much as possible instead of
+aborting as soon as we see such a problematic function application.
+
+When desugaring an expression which might have problems (such as disallowed
+representation polymorphism as above), we check for errors first, and then:
+
+ - if no problems were detected, desugar normally,
+ - if errors were found, we want to avoid desugaring, so we instead return
+ a runtime error Core expression which has the right type.
+
+This is what the function dsWhenNoErrs achieves:
+
+> dsWhenNoErrs result_ty thing_inside mk_expr
+
+We run thing_inside to check for errors. If there are no errors, we apply
+mk_expr to desugar; otherwise, we construct a runtime error at type result_ty.
+
+Note that result_ty is only used when there is an error, and isn't inspected
+otherwise; this means it's OK to pass something that can be a bit expensive
+to compute.
+
+See #12709 for an example of why this machinery is necessary.
+See also #14765 and #18149 for why it is important to return an expression
+that has the proper type in case of an error.
+-}
+
+-- | Runs the thing_inside. If there are no errors, use the provided
+-- function to construct a Core expression, and return it.
+-- Otherwise, return a runtime error, of the given type.
+-- This is useful for doing a bunch of representation polymorphism checks
+-- and then avoiding making a Core App.
+-- See Note [Desugaring representation-polymorphic applications]
+dsWhenNoErrs :: Type -> DsM a -> (a -> CoreExpr) -> DsM CoreExpr
+dsWhenNoErrs result_ty thing_inside mk_expr
+ = do { (result, no_errs) <- askNoErrsDs thing_inside
+ ; if no_errs
+ then return $ mk_expr result
+ else mkErrorAppDs rUNTIME_ERROR_ID result_ty
+ (text "dsWhenNoErrs found errors") }
+
{- *********************************************************************
* *
Ticks