diff options
author | Simon Peyton Jones <simon.peytonjones@gmail.com> | 2023-01-12 22:21:40 +0000 |
---|---|---|
committer | Simon Peyton Jones <simon.peytonjones@gmail.com> | 2023-01-31 08:54:52 +0000 |
commit | ae22d1096df1bd83b5ce9ef5d8c2bd8c00e20bad (patch) | |
tree | dc345c52cefcb688e3be7447551cb0a0bedfb492 /compiler/GHC/Core.hs | |
parent | b69461a06166d2b1c600df87b87656d09122fb7c (diff) | |
download | haskell-wip/T22745.tar.gz |
Improve exprOkForSpeculation for classopswip/T22745
This patch fixes #22745 and #15205, which are about GHC's
failure to discard unnecessary superclass selections that
yield coercions. See
GHC.Core.Utils Note [exprOkForSpeculation and type classes]
The main changes are:
* Write new Note [NON-BOTTOM_DICTS invariant] in GHC.Core, and
refer to it
* Define new function isTerminatingType, to identify those
guaranteed-terminating dictionary types.
* exprOkForSpeculation has a new (very simple) case for ClassOpId
* ClassOpId has a new field that says if the return type is
an unlifted type, or a terminating type.
This was surprisingly tricky to get right. In particular note
that unlifted types are not terminating types; you can write an
expression of unlifted type, that diverges. Not so for dictionaries
(or, more precisely, for the dictionaries that GHC constructs).
Metric Decrease:
LargeRecord
Diffstat (limited to 'compiler/GHC/Core.hs')
-rw-r--r-- | compiler/GHC/Core.hs | 51 |
1 files changed, 40 insertions, 11 deletions
diff --git a/compiler/GHC/Core.hs b/compiler/GHC/Core.hs index b18ec7acda..809332d395 100644 --- a/compiler/GHC/Core.hs +++ b/compiler/GHC/Core.hs @@ -292,7 +292,7 @@ data AltCon -- This instance is a bit shady. It can only be used to compare AltCons for -- a single type constructor. Fortunately, it seems quite unlikely that we'll -- ever need to compare AltCons for different type constructors. --- The instance adheres to the order described in [Core case invariants] +-- The instance adheres to the order described in Note [Case expression invariants] instance Ord AltCon where compare (DataAlt con1) (DataAlt con2) = assert (dataConTyCon con1 == dataConTyCon con2) $ @@ -466,6 +466,45 @@ we need to allow lots of things in the arguments of a call. TL;DR: we relaxed the let/app invariant to become the let-can-float invariant. +Note [NON-BOTTOM-DICTS invariant] +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +It is a global invariant (not checkable by Lint) that + + every non-newtype dictionary-typed expression is non-bottom. + +These conditions are captured by GHC.Core.Type.isTerminatingType. + +How are we so sure about this? Dictionaries are built by GHC in only two ways: + +* A dictionary function (DFun), arising from an instance declaration. + DFuns do no computation: they always return a data constructor immediately. + See DFunUnfolding in GHC.Core. So the result of a call to a DFun is always + non-bottom. + + Exception: newtype dictionaries. + + Plus: see the Very Nasty Wrinkle in Note [Speculative evaluation] + in GHC.CoreToStg.Prep + +* A superclass selection from some other dictionary. This is harder to guarantee: + see Note [Recursive superclasses] and Note [Solving superclass constraints] + in GHC.Tc.TyCl.Instance. + +A bad Core-to-Core pass could invalidate this reasoning, but that's too bad. +It's still an invariant of Core programs generated by GHC from Haskell, and +Core-to-Core passes maintain it. + +Why is it useful to know that dictionaries are non-bottom? + +1. It justifies the use of `-XDictsStrict`; + see `GHC.Core.Types.Demand.strictifyDictDmd` + +2. It means that (eq_sel d) is ok-for-speculation and thus + case (eq_sel d) of _ -> blah + can be discarded by the Simplifier. See these Notes: + Note [exprOkForSpeculation and type classes] in GHC.Core.Utils + Note[Speculative evaluation] in GHC.CoreToStg.Prep + Note [Case expression invariants] ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ Case expressions are one of the more complicated elements of the Core @@ -556,10 +595,6 @@ substitutions until the next run of the simplifier. Note [Equality superclasses in quantified constraints] in GHC.Tc.Solver.Canonical -Note [Core case invariants] -~~~~~~~~~~~~~~~~~~~~~~~~~~~ -See Note [Case expression invariants] - Note [Representation polymorphism invariants] ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ GHC allows us to abstract over calling conventions using **representation polymorphism**. @@ -627,12 +662,6 @@ representation: we check whether bound variables and function arguments have a See Note [Representation polymorphism checking] in GHC.Tc.Utils.Concrete for an overview of how we enforce these invariants in the typechecker. -Note [Core let goal] -~~~~~~~~~~~~~~~~~~~~ -* The simplifier tries to ensure that if the RHS of a let is a constructor - application, its arguments are trivial, so that the constructor can be - inlined vigorously. - Note [Empty case alternatives] ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ The alternatives of a case expression should be exhaustive. But |