Hi all, I’m trying to build an intuition for constraint generation as the primary mode of type inference / elaboration for a compiler that I’m working on. From what I’ve read in OutsideIn(X), GHC’s mechanisms for it remain untouched so I took a look:
8.2 Brief sketch of the implementation
[…] bidirectional propagation of type information needed to support higher-rank
inference remains untouched
My high-level understanding right now is that skolemisation (through topSkolemise) may or may not emit an implication constraint depending on if there were skolemised variables or “given” constraints. I was thinking about how it would look like in a program:
runST :: forall a. (forall r. ST r a) -> a
action :: forall r. ST r Int
-- check(runST action)
runST :: (forall r. ST r ?a) -> ?a
action :: ST ?r Int
ST ?r Int < forall r. ST r ?a
-- Generates the ff. implication constraint:
∀r. [] => [ ?r ~ r, ?a ~ Int ]
-- ?a ~ Int can be promoted, thus:
?a ~ Int
∀r. [] => [ ?r ~ r ]
What I’m not sure of is how the final constraint after floating can be solved… ?r
is untouchable because its ambient level is lower than that of the implication constraint. One thought I have at the moment is that maybe I’m instantiating the r
from action
too eagerly, and that it could instead look more like:
-- Given the ambient level 1:
runST :: (forall r. ST r ?a[1]) -> ?a[1]
action :: forall r. ST r Int
-- In the following subsumption, we'll skolemise the RHS.
-- Skolemisation increases the ambient level from 1 to 2.
forall r. ST r Int < forall r. ST r ?a
-- Then, this subsumption would instantiate the LHS.
forall r. ST r Int < ST #r ?a
-- Thus, given the subsumption:
ST ?r[2] Int < ST #r ?a[1]
-- We'll generate the implication constraint:
∀r[2]. [] => [ ?r[2] ~ r, ?a[1] ~ Int ]
-- ?a[1] ~ Int can be promoted again:
?a[1] ~ Int
∀r[2]. [] => [ ?r[2] ~ r ]
The final implication constraint can be solved as is because ?r
has the same level as #r
now.