diff options
author | Simon Peyton Jones <simonpj@microsoft.com> | 2018-09-13 11:23:53 +0100 |
---|---|---|
committer | Simon Peyton Jones <simonpj@microsoft.com> | 2018-09-13 11:35:00 +0100 |
commit | bd76875ae6ad0cdd734564dddfb9ab88a6de9579 (patch) | |
tree | dddaeaf707a06f3e4b34d462978a20f89c12b0f6 /compiler/coreSyn/CoreSyn.hs | |
parent | 291b0f89703f28631a381549e1838aa06195d011 (diff) | |
download | haskell-bd76875ae6ad0cdd734564dddfb9ab88a6de9579.tar.gz |
Allow (~) in the head of a quantified constraints
Since the introduction of quantified constraints, GHC has rejected
a quantified constraint with (~) in the head, thus
f :: (forall a. blah => a ~ ty) => stuff
I am frankly dubious that this is ever useful. But /is/ necessary for
Coercible (representation equality version of (~)) and it does no harm
to allow it for (~) as well. Plus, our users are asking for it
(Trac #15359, #15625).
It was really only excluded by accident, so
this patch lifts the restriction. See TcCanonical
Note [Equality superclasses in quantified constraints]
There are a number of wrinkles:
* If the context of the quantified constraint is empty, we
can get trouble when we get down to unboxed equality (a ~# b)
or (a ~R# b), as Trac #15625 showed. This is even more of
a corner case, but it produced an outright crash, so I elaborated
the superclass machinery in TcCanonical.makeStrictSuperClasses
to add a void argument in this case. See
Note [Equality superclasses in quantified constraints]
* The restriction on (~) was in TcValidity.checkValidInstHead.
In lifting the restriction I discovered an old special case for
(~), namely
| clas_nm `elem` [ heqTyConName, eqTyConName]
, nameModule clas_nm /= this_mod
This was (solely) to support the strange instance
instance a ~~ b => a ~ b
in Data.Type.Equality. But happily that is no longer
with us, since
commit f265008fb6f70830e7e92ce563f6d83833cef071
Refactor (~) to reduce the suerpclass stack
So I removed the special case.
* I found that the Core invariants on when we could have
co = <expr>
were entirely not written down. (Getting this wrong ws
the proximate source of the crash in Trac #15625. So
- Documented them better in CoreSyn
Note [CoreSyn type and coercion invariant],
- Modified CoreOpt and CoreLint to match
- Modified CoreUtils.bindNonRec to match
- Made MkCore.mkCoreLet use bindNonRec, rather
than duplicate its logic
- Made Simplify.rebuildCase case-to-let respect
Note [CoreSyn type and coercion invariant],
Diffstat (limited to 'compiler/coreSyn/CoreSyn.hs')
-rw-r--r-- | compiler/coreSyn/CoreSyn.hs | 71 |
1 files changed, 46 insertions, 25 deletions
diff --git a/compiler/coreSyn/CoreSyn.hs b/compiler/coreSyn/CoreSyn.hs index 025c19e3ca..aa27d7a7fb 100644 --- a/compiler/coreSyn/CoreSyn.hs +++ b/compiler/coreSyn/CoreSyn.hs @@ -46,7 +46,7 @@ module CoreSyn ( exprToType, exprToCoercion_maybe, applyTypeToArg, - isValArg, isTypeArg, isTyCoArg, valArgCount, valBndrCount, + isValArg, isTypeArg, isCoArg, isTyCoArg, valArgCount, valBndrCount, isRuntimeArg, isRuntimeVar, -- * Tick-related functions @@ -173,6 +173,7 @@ These data types are the heart of the compiler -- The language consists of the following elements: -- -- * Variables +-- See Note [Variable occurrences in Core] -- -- * Primitive literals -- @@ -187,29 +188,10 @@ These data types are the heart of the compiler -- this corresponds to allocating a thunk for the things -- bound and then executing the sub-expression. -- --- #top_level_invariant# --- #letrec_invariant# --- --- The right hand sides of all top-level and recursive @let@s --- /must/ be of lifted type (see "Type#type_classification" for --- the meaning of /lifted/ vs. /unlifted/). There is one exception --- to this rule, top-level @let@s are allowed to bind primitive --- string literals, see Note [CoreSyn top-level string literals]. --- +-- See Note [CoreSyn letrec invariant] -- See Note [CoreSyn let/app invariant] -- See Note [Levity polymorphism invariants] --- --- #type_let# --- We allow a /non-recursive/ let to bind a type variable, thus: --- --- > Let (NonRec tv (Type ty)) body --- --- This can be very convenient for postponing type substitutions until --- the next run of the simplifier. --- --- At the moment, the rest of the compiler only deals with type-let --- in a Let expression, rather than at top level. We may want to revist --- this choice. +-- See Note [CoreSyn type and coercion invariant] -- -- * Case expression. Operationally this corresponds to evaluating -- the scrutinee (expression examined) to weak head normal form @@ -371,13 +353,25 @@ PrelRules for the rationale for this restriction. -------------------------- CoreSyn INVARIANTS --------------------------- -Note [CoreSyn top-level invariant] +Note [Variable occurrences in Core] ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -See #toplevel_invariant# +Variable /occurrences/ are never CoVars, though /bindings/ can be. +All CoVars appear in Coercions. + +For example + \(c :: Age~#Int) (d::Int). d |> (sym c) +Here 'c' is a CoVar, which is lambda-bound, but it /occurs/ in +a Coercion, (sym c). Note [CoreSyn letrec invariant] ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -See #letrec_invariant# +The right hand sides of all top-level and recursive @let@s +/must/ be of lifted type (see "Type#type_classification" for +the meaning of /lifted/ vs. /unlifted/). + +There is one exception to this rule, top-level @let@s are +allowed to bind primitive string literals: see +Note [CoreSyn top-level string literals]. Note [CoreSyn top-level string literals] ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ @@ -451,6 +445,27 @@ which will generate a @case@ if necessary The let/app invariant is initially enforced by mkCoreLet and mkCoreApp in coreSyn/MkCore. +Note [CoreSyn type and coercion invariant] +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +We allow a /non-recursive/, /non-top-level/ let to bind type and +coercion variables. These can be very convenient for postponing type +substitutions until the next run of the simplifier. + +* A type variable binding must have a RHS of (Type ty) + +* A coercion variable binding must have a RHS of (Coercion co) + + It is possible to have terms that return a coercion, but we use + case-binding for those; e.g. + case (eq_sel d) of (co :: a ~# b) -> blah + where eq_sel :: (a~b) -> (a~#b) + + Or even even + case (df @Int) of (co :: a ~# b) -> blah + Which is very exotic, and I think never encountered; but see + Note [Equality superclasses in quantified constraints] + in TcCanonical + Note [CoreSyn case invariants] ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ See #case_invariants# @@ -2102,6 +2117,12 @@ isTyCoArg (Type {}) = True isTyCoArg (Coercion {}) = True isTyCoArg _ = False +-- | Returns @True@ iff the expression is a 'Coercion' +-- expression at its top level +isCoArg :: Expr b -> Bool +isCoArg (Coercion {}) = True +isCoArg _ = False + -- | Returns @True@ iff the expression is a 'Type' expression at its -- top level. Note this does NOT include 'Coercion's. isTypeArg :: Expr b -> Bool |