Don't emit alias-relate goal if projections are structurally equal after resolving vars #109617
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
Before emitting an alias-relate goal in
super_combine_tys
, first check that the projections are not equal after callingresolve_vars_if_possible
.This is because we don't eagerly resolve infer vars in the solver, so we may equate
<?0 as Trait>::Projection == <Rigid as Trait>::Projection
even though we already know that?0 = Rigid
, and end up spitting out trivial alias-relate goals that become non-trivial after canonicalization (since each var is canonicalized separately).This is mostly problematic when
Rigid
mentioned above has region vars (or type vars, for that matter, but I couldn't think of a test exercising this that doesn't already end up with ambiguity), because we canonicalize all region variables separately, and alias-relate goals have 3 separate branches that can be used to satisfy it, and these branches may all be true but return different sets of region constraints.We can fix this by resolving vars before checking if types are equal, and only emitting an alias-relate goal if the projections are not exactly equal.
A more detailed explanation motivated by a failing test is below.
r? @lcnr
See the UI test. For brevity,
Filter
isstd::iter::Filter
andIter
isstd::slice::Iter
.Filter<Iter<'?0r, Attr>, for<'a, 'b> fn(&'a &'b Attr) -> bool> normalizes-to &'?1r Attr
.Filter<Iter<'?0r, Attr>, for<'a, 'b> fn(&'a &'b Attr) -> bool> normalizes-to ?2t
. Canonicalize that, etc. Not super relevant.Iterator for Filter
impl instd::iter
:Filter<Iter<'?0r, Attr>, for<'a, 'b> fn(&'a &'b Attr) -> bool>: Iterator
, and we instantiate a fresh impl trait ref:Filter<?3t, ?4t>: Iterator
?3t = Iter<'?0r, Attr>
and?4t = for<'a, 'b> fn(&'a &'b Attr) -> bool
.<?3t as Iterator>::Item
.?1t = <?3t as Iterator>::Item
.CombineFields::instantiate
.<?3t as Iterator>::Item
. This is not really relevant to the bug here -- generalization doesn't actually do anything meaningful because?1t
can name the region'?0r
, but...?3t
resolved toIter<'?0r, Attr>
.<Iter<'?0r, Attr> as Iterator>::Item
and<?3t as Iterator>::Item
respectively. This ends up emitting an alias-relate goal, even though the resolved LHS is structurally equal to the RHS after resolving vars...rust/compiler/rustc_infer/src/infer/equate.rs
Lines 81 to 84 in 2d429f3
<Iter<'^0r, Attr> as Iterator>::Item == <Iter<'^1r, Attr> as Iterator>::Item
, which ends up being ambiguous because the different alias-relate branches (RHS normalizes-to LHS, LHS normalizes-to RHS, and LHS equate-substs RHS) end up having different region constraints... :/Perhaps if we processed region constraints before canonicalization (or compressed and "normalized" them in some way), that canonicalized alias-relate goal
<Iter<'^0r, Attr> as Iterator>::Item == <Iter<'^1r, Attr> as Iterator>::Item
may not end up being ambiguous, but for now it does.Footnotes
And this shouldn't matter for correctness in general, since all we're doing is equating things and evaluating nested goals. ↩