Note [fillInferResult]
When inferring, we use fillInferResult to "fill in" the hole in InferResult
data InferResult = IR { ir_uniq :: Unique
, ir_lvl :: TcLevel
, ir_ref :: IORef (Maybe TcType) }
There are two things to worry about:
1. What if it is under a GADT or existential pattern match?
- GADTs: a unification variable (and Infer's hole is similar) is untouchable
- Existentials: be careful about skolem-escape
2. What if it is filled in more than once? E.g. multiple branches of a case
case e of
T1 -> e1
T2 -> e2
Our typing rules are:
* The RHS of a existential or GADT alternative must always be a
monotype, regardless of the number of alternatives.
* Multiple non-existential/GADT branches can have (the same)
higher rank type (#18412). E.g. this is OK:
case e of
True -> hr
False -> hr
where hr:: (forall a. a->a) -> Int
c.f. Section 7.1 of "Practical type inference for arbitrary-rank types"
We use choice (2) in that Section.
(GHC 8.10 and earlier used choice (1).)
But note that
case e of
True -> hr
False -> \x -> hr x
will fail, because we still /infer/ both branches, so the \x will get
a (monotype) unification variable, which will fail to unify with
(forall a. a->a)
For (1) we can detect the GADT/existential situation by seeing that
the current TcLevel is greater than that stored in ir_lvl of the Infer
ExpType. We bump the level whenever we go past a GADT/existential match.
Then, before filling the hole use promoteTcType to promote the type
to the outer ir_lvl. promoteTcType does this
- create a fresh unification variable alpha at level ir_lvl
- emits an equality alpha[ir_lvl] ~ ty
- fills the hole with alpha
That forces the type to be a monotype (since unification variables can
only unify with monotypes); and catches skolem-escapes because the
alpha is untouchable until the equality floats out.
For (2), we simply look to see if the hole is filled already.
- if not, we promote (as above) and fill the hole
- if it is filled, we simply unify with the type that is
already there
(FIR1) There is one wrinkle. Suppose we have
case e of
T1 -> e1 :: (forall a. a->a) -> Int
G2 -> e2
where T1 is not GADT or existential, but G2 is a GADT. Then suppose the
T1 alternative fills the hole with (forall a. a->a) -> Int, which is fine.
But now the G2 alternative must not *just* unify with that else we'd risk
allowing through (e2 :: (forall a. a->a) -> Int). If we'd checked G2 first
we'd have filled the hole with a unification variable, which enforces a
monotype.
So if we check G2 second, we still want to emit a constraint that restricts
the RHS to be a monotype. This is done by ensureMonoType, and it works
by simply generating a constraint (alpha ~ ty), where alpha is a fresh
unification variable. We discard the evidence. References 0
This Note does not link to any other.
Referenced by 3
- TcLevel of ExpType GHC.Tc.Utils.TcMType
- inferResultToType GHC.Tc.Utils.TcMType
- GHC.Tc.Utils.TcMType call site