-
Notifications
You must be signed in to change notification settings - Fork 12.8k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Combine three generalizer implementations #111221
Conversation
} | ||
} | ||
} | ||
ty::ConstKind::Unevaluated(ty::UnevaluatedConst { def, substs }) => { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The old behavior of the NLL generalizer did this:
ty::ConstKind::Unevaluated(..) if self.tcx().lazy_normalization() => Ok(a),
Not exactly sure what's more correct here. I guess we probably shouldn't be generalizing aliases? But in that case, we need to be emitting a const vid and an alias relate (or const equate) here, right?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
We should only get ConstKind::Unevaluated
with subst if generic_const_exprs
is enabled afaik so this shouldnt affect stable I think. Generalizing alias substs seems wrong but I think creating an infer var is also wrong since if the alias is underneath a binder the infer var would not be able to name any of its placeholders when we later relate the original ty with the generalised ty. Probably just doesn't matter to try and make generalizing aliases work correctly in this PR since its already not great and doing it correctly seems hard xd
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Specifically if we have:
for<'a> fn(<?0.0 as Trait<'a>>::Assoc) <: ?1.0
we generalize the fn ptr to get for<'a> fn(?2.0)
and then we end up relating for<'a> fn(<?0.0 as Trait<'a>>::Assoc) eq for<'a> fn(?2.0)
once the binders are instantiated we'll end up with fn(<?0.0 as Trait<'!a.1>>::Assoc) eq fn(?2.0)
the alias-relate(<?0.0 as Trait<'!a.1>>::Assoc, eq, ?2.0)
is kinda messed up,
- we cant instantiate
?2.0
with'!a.1
if the alias ends up normalizing to the trait argument because of universe checks - we cant just Err(NoSolution) as that's unsound in coherence since
for<'a> fn(<?0.0 as Trait<'a>>::Assoc) eq ?1.0
should be allowed to end up successful with inferring?1.0 = for<'a> fn(Foo<'a>)
if that's how the alias ends up normalizing (not actually sure if the fact that this is lifetimes means this would play out differently, just sub it all for type placeholders I guess if so lol)
This whole thing just reminds me of the current "replace aliases with infer vars" hack in project
and how it doesn't work for projections under binders.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'm pretty sure that this just fundamentally cant work because of universes and actually we would need to be generalizing types with binders to an infer var (didnt realise this til lcnr said it, had just thought everything was doomed) and emitting a general relate obligation not alias relate, so that we'd have relate(for<'a> fn(<?0.0 as Trait<'a>>::Assoc, <:, ?1.0)
. We need alias-relate
to be general purpose relate anyway to correctly handle occurs check and projections not being unsound in coherence (Foo<<?0 as Trait>::Assoc> eq ?0>
would emit a relate
instead of a Err(NoSolution)
)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
converting types with binders (trait objects and fn ptrs) into infer vars during generalization would inhibit inference probably in ways that are backwards incompatible, no idea to what extent this would be backwards compatible (or put another way: if its realistically something that can be broken). So it may be that its not a viable solution and actually we just want to accept generalization being incomplete and make occurs check and universe check into ambiguity during coherence instead of NoSolution
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think we shouldn't change this behavior in this PR even if it's incomplete.
However, similar to the opaque branch above, super_relate_consts
is already purely structural, so we can remove that match arm as its equivalent to super_relate_consts
.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
super_relate_consts
is unfortuantely not structural. We are eagerly evaluating ty::UnevaluatedConst
there. But I agree, it should be made purely structural.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
super_relate_consts
has a bunch of weird stuff going on that it probably shouldnt be doing. I'd be in favor of renaming to structurally_relate_consts
even though super_relate_consts
isnt very structural right now, it would also make it a bit more obvious that what super_relate_consts
is doing is weird.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Renamed to structurally_relate_{tys,consts}
but left a FIXME on structurally_relate_consts
that says that it's not currently structural and that should be fixed.
Ok(g) | ||
} | ||
|
||
fn regions( |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The old implementation of the NLL generalizer always generalized regions -- there was some comment:
// For now, we just always create a fresh region variable to
// replace all the regions in the source type. In the main
// type checker, we special case the case where the ambient
// variance is `Invariant` and try to avoid creating a fresh
// region variable, but since this comes up so much less in
// NLL (only when users use `_` etc) it is much less
// important.
//
// As an aside, since these new variables are created in
// `self.universe` universe, this also serves to enforce the
// universe scoping rules.
//
// FIXME(#54105) -- if the ambient variance is bivariant,
// though, we may however need to check well-formedness or
// risk a problem like #41677 again.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Also comment about bivariance, perhaps we should be setting needs_wf
here too?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
needs_wf
is kind of a mess and mostly there to guide type inference during hir typeck. It is probably also necessary when equating user type annotations during nll typeck, but given that this happens inside of a query, the nll generalizer does not need add special wf obligations.
I believe that we should instead check that all locals in the mir body are well formed. But well 🤷 i guess lets keep the status quo in this PR.
☔ The latest upstream changes (presumably #111231) made this pull request unmergeable. Please resolve the merge conflicts. |
964ca17
to
8d2ae13
Compare
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
realized that nll relate does not explicitly generalize const inference vars but instead relies on super_combine_consts
which then generalizes const inference vars using the ordinary typeck generalizer which feels like it should cause bugs if that code is ever reachable?
a few nits then r=me.
Ok(g) | ||
} | ||
|
||
fn regions( |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
needs_wf
is kind of a mess and mostly there to guide type inference during hir typeck. It is probably also necessary when equating user type annotations during nll typeck, but given that this happens inside of a query, the nll generalizer does not need add special wf obligations.
I believe that we should instead check that all locals in the mir body are well formed. But well 🤷 i guess lets keep the status quo in this PR.
} | ||
} | ||
} | ||
ty::ConstKind::Unevaluated(ty::UnevaluatedConst { def, substs }) => { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think we shouldn't change this behavior in this PR even if it's incomplete.
However, similar to the opaque branch above, super_relate_consts
is already purely structural, so we can remove that match arm as its equivalent to super_relate_consts
.
@bors rollup=never this change is complex enough that i can imagine us missing something, so let's make this easier to bisect. @bors try @rust-timer queue |
This comment has been minimized.
This comment has been minimized.
?bors @bors try |
⌛ Trying commit 8d2ae13f8353f50f00a300d64124d3f26c5fc426 with merge 971d96e4613fd0cf06584ae3654679cbb360969e... |
☀️ Try build successful - checks-actions |
This comment has been minimized.
This comment has been minimized.
Finished benchmarking commit (971d96e4613fd0cf06584ae3654679cbb360969e): comparison URL. Overall result: ❌ regressions - ACTION NEEDEDBenchmarking this pull request likely means that it is perf-sensitive, so we're automatically marking it as not fit for rolling up. While you can manually mark this PR as fit for rollup, we strongly recommend not doing so since this PR may lead to changes in compiler perf. Next Steps: If you can justify the regressions found in this try perf run, please indicate this with @bors rollup=never Instruction countThis is a highly reliable metric that was used to determine the overall result at the top of this comment.
Max RSS (memory usage)This benchmark run did not return any relevant results for this metric. CyclesThis benchmark run did not return any relevant results for this metric. Binary sizeThis benchmark run did not return any relevant results for this metric. Bootstrap: 658.646s -> 659.139s (0.07%) |
i think perf is good enough. 3 minimal regressions to |
65d6ccf
to
97fedf1
Compare
I think I addressed all the nits? I won't r=@lcnr until they take another quick look at the final diff, though no rush! 😄 |
☔ The latest upstream changes (presumably #109732) made this pull request unmergeable. Please resolve the merge conflicts. |
97fedf1
to
26db751
Compare
This comment has been minimized.
This comment has been minimized.
26db751
to
bd1b41c
Compare
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
some nits, r=me
@@ -456,11 +442,11 @@ impl<'infcx, 'tcx> CombineFields<'infcx, 'tcx> { | |||
/// - `for_vid` is a "root vid" | |||
#[instrument(skip(self), level = "trace", ret)] | |||
fn generalize( |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
does that method still make sense? might be easier to just inline that into instantiate
. Also I am not sure whether RelationDir
is particularily useful, so maybe just using Variance
is easier?
or well said differently, why do we prefer RelationDir
over variance here but still use Variance
in other parts of the code?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'm just gonna remove RelationDir
lol
bd1b41c
to
a2678e1
Compare
@bors r=lcnr |
☀️ Test successful - checks-actions |
Finished benchmarking commit (ea54255): comparison URL. Overall result: ❌ regressions - ACTION NEEDEDNext Steps: If you can justify the regressions found in this perf run, please indicate this with @rustbot label: +perf-regression Instruction countThis is a highly reliable metric that was used to determine the overall result at the top of this comment.
Max RSS (memory usage)This benchmark run did not return any relevant results for this metric. CyclesResultsThis is a less reliable metric that may be of interest but was not used to determine the overall result at the top of this comment.
Binary sizeThis benchmark run did not return any relevant results for this metric. Bootstrap: 644.092s -> 642.928s (-0.18%) |
@compiler-errors: any idea what happened with |
No, I didn't really do anything functional in the nits/changes that lcnr requested. Just some renames and moving things around mostly. |
Fixes #111092
Fixes #109505
This code is a bit delicate and there were subtle changes between them, so I'll leave inline comments where further inspection is needed.
Regarding this comment from #109813 -- "add tests triggering all codepaths: at least the combine and the const generalizer", can't really do that now, and I don't really know how we'd get a higher-ranked const error since non-lifetime binders doesn't really support
for<const ..>
(it errors out when you try to use it).r? @lcnr