You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
Create fresh type variables to keep constraints level-correct
This completes the implementation of `LevelAvoidMap` from the previous
commit: we now make sure that the nonParamBounds of a type variable does
not refer to variables of a higher level by creating fresh variables of
the appropriate level if necessary. Each fresh variable will be upper-
or lower-bounded by the existing variable it is substituted for
depending on variance (an idea that I got from [1]), in the invariant
case the existing variable will be instantiated to the fresh one (unlike
[2], we can't simply mutate the nestingLevel of the existing variable
after running avoidance on its bounds because the constraint containing
these bounds might later be retracted).
Additionally:
- When unifying two type variables, keep the one with the lowest level in
the constraint set and make sure the bounds transferred from the other
one are level-correct. This required some changes in
`Constraint#addLess` which previously assumed that `unify` would
always keep the second parameter.
- When instantiating a type variable to its full lower- or upper-bound,
we also need to avoid any type variable of a higher level among its
param bound.
This commit is necessary to avoid leaking local types in i8900a2.scala
and i8900a3.scala, these kind of leaks will become compile-time error in
the next commit.
This commit required making a type parameter explicit both in
SnippetChecker.scala and i13809/Macros_1.scala, in both situations the
problem is that the lambda passed to `map` can only be typed if the type
argument of `map` contains a wildcard, but LevelAvoidMap instead creates
a fresh type variable of a lower level at a point where we don't know
yet that this cannot work. Since this situation seems very rare in
practice, I believe this is an acceptable trade-off for soundness.
[1]: Lionel Parreaux. "The simple essence of algebraic subtyping:
principal type inference with subtyping made easy (functional pearl)."
https://dl.acm.org/doi/abs/10.1145/3409006
[2]: Oleg Kiselyov. "How OCaml type checker works -- or what
polymorphism and garbage collection have in common"
https://okmij.org/ftp/ML/generalization.html
0 commit comments