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
Avoid incorrect simplifications when updating bounds in the constraint (#16410)
When combining an old and a new bound, we use `Type#&`/`Type#|` which
perform simplifications. This is usually fine, but if the new bounds
refer to the parameter currently being updated, we can run into cyclic
reasoning issues which make the simplifications invalid after the
update.
We already have logic for handling self-references in parameter bounds:
`updateEntry` calls `ensureNonCyclic` which sanitizes the type, but at
this point the simplifications have already occured. This commit simply
moves the logic out of `updateEntry` so that we can sanitize the new
bounds before simplification.
More precisely, we rename `ensureNonCyclic` to `validBoundsFor` which
calls `validBoundFor` (singular). Both are used to sanitize bounds where
needed in `addOneBound` and `unify`.
Since all calls to `updateEntry` now have sanitized bounds, we no longer
need to sanitize them in `updateEntry` itself, we document this change
by adding a pre-condition to `updateEntry`.
For the record, here's how `ConstraintsTest#validBoundsInit` used to
fail. It defines a method:
def foo[S >: T <: T | Int, T <: String]: Any
Before this commit, when `foo` was added to the current constraints, the
constraint `S <: T | Int` was propagated to the lower bound `T` of `S`.
The updated upper bound of `T` was thus set to:
String & (T | Int)
But because `Type#&` performs simplifications, this became
T | (String & Int)
by relying on the fact that at this point, `T <: String`. But in fact
this simplified bound no longer ensures that `T <: String`! The
self-reference was then replaced by `Any` in
`OrderingConstraint#ensureNonCyclic`. After this commit, the problematic
simplification no longer occurs since the new `T | Int` is sanitized to
`Any` before being intersected with the old bound.
0 commit comments