-Znext-solver Less normalizes-to janks#156619
Conversation
|
Some changes occurred to the core trait solver cc @rust-lang/initiative-trait-system-refactor changes to cc @lcnr This PR modifies |
|
@bors try @rust-timer queue |
This comment has been minimized.
This comment has been minimized.
This comment has been minimized.
This comment has been minimized.
`-Znext-solver` Less normalizes-to janks
|
I haven't done the nested goals' recursion depth part yet 😅 I'm gonna work on it if the overall design here pan out to be feasible |
This comment has been minimized.
This comment has been minimized.
|
Finished benchmarking commit (d4c528b): comparison URL. Overall result: ❌✅ regressions and improvements - please read:Benchmarking means the PR may be perf-sensitive. It's automatically marked not fit for rolling up. Overriding is possible but disadvised: it risks changing compiler perf. Next, please: If you can, justify the regressions found in this try perf run in writing along with @bors rollup=never Instruction countOur most reliable metric. Used to determine the overall result above. However, even this metric can be noisy.
Max RSS (memory usage)Results (primary 1.5%, secondary 8.5%)A less reliable metric. May be of interest, but not used to determine the overall result above.
CyclesResults (secondary 26.9%)A less reliable metric. May be of interest, but not used to determine the overall result above.
Binary sizeThis perf run didn't have relevant results for this metric. Bootstrap: 510.626s -> 509.733s (-0.17%) |
|
Oh, the perf regressions are insane 😅 I'll look into them |
|
@bors try @rust-timer queue |
This comment has been minimized.
This comment has been minimized.
This comment has been minimized.
This comment has been minimized.
`-Znext-solver` Less normalizes-to janks
This comment has been minimized.
This comment has been minimized.
|
Finished benchmarking commit (52311d2): comparison URL. Overall result: ❌✅ regressions and improvements - please read:Benchmarking means the PR may be perf-sensitive. It's automatically marked not fit for rolling up. Overriding is possible but disadvised: it risks changing compiler perf. Next, please: If you can, justify the regressions found in this try perf run in writing along with @bors rollup=never Instruction countOur most reliable metric. Used to determine the overall result above. However, even this metric can be noisy.
Max RSS (memory usage)Results (primary 1.7%, secondary 8.4%)A less reliable metric. May be of interest, but not used to determine the overall result above.
CyclesResults (primary 2.3%, secondary 22.5%)A less reliable metric. May be of interest, but not used to determine the overall result above.
Binary sizeThis perf run didn't have relevant results for this metric. Bootstrap: 513.812s -> 509.975s (-0.75%) |
6bd6498 to
5927eca
Compare
This comment has been minimized.
This comment has been minimized.
|
If my observation is correct, this would fix the perf regression 🤔 |
This comment has been minimized.
This comment has been minimized.
`-Znext-solver` Less normalizes-to janks
This comment has been minimized.
This comment has been minimized.
|
Finished benchmarking commit (4d1f2a6): comparison URL. Overall result: ❌✅ regressions and improvements - please read:Benchmarking means the PR may be perf-sensitive. It's automatically marked not fit for rolling up. Overriding is possible but disadvised: it risks changing compiler perf. Next, please: If you can, justify the regressions found in this try perf run in writing along with @bors rollup=never Instruction countOur most reliable metric. Used to determine the overall result above. However, even this metric can be noisy.
Max RSS (memory usage)Results (secondary -1.9%)A less reliable metric. May be of interest, but not used to determine the overall result above.
CyclesResults (secondary -4.4%)A less reliable metric. May be of interest, but not used to determine the overall result above.
Binary sizeThis perf run didn't have relevant results for this metric. Bootstrap: 523.273s -> 517.628s (-1.08%) |
| /// Because of this we return any ambiguous nested goals from `NormalizesTo` to the | ||
| /// caller when then adds these to its own context. The caller is always an `AliasRelate` | ||
| /// caller when then adds these to its own context. The caller is always an `Projection` | ||
| /// goal so this never leaks out of the solver. |
There was a problem hiding this comment.
can you more completely rewrite this comment and also state that NormalizesTo is just an implementation detail of Projection for associated terms
I feel like NormalizesTois just somewhat of a bad name xx
It should be something like
ProjectionComputeAssocTermCandidate or NormalizeAssocTermInternal or whatever :>
There was a problem hiding this comment.
Sure. Would you like to change both this variant and the NormalizesTo goal's names into one of those more proper ones?
There was a problem hiding this comment.
I just changed the name of CurrentGoalKind::NormalizesTo for now and left PredicateKind::NormalizesTo as a FIXME for now 😅
| self.normalization_goal_source, | ||
| Goal::new(self.cx(), self.param_env, normalizes_to), | ||
| Goal::new(self.cx(), self.param_env, projection), | ||
| false, |
There was a problem hiding this comment.
hmm, I guess it's fine for now. Can you add a FIXME that this whole folder should be removed in favor of proper normalization, cc #156742
| normalizes_to, | ||
| None, | ||
| IncreaseDepthForNested::No, | ||
| )?; |
There was a problem hiding this comment.
comments please :3
- why do we use a separate goal only for associated terms
- why do we not increase the depth for nested goals
- edge case that we don't reevaluate the
NormalizesToif equating theunconstrained_termafterwards reesults in inference constraints in the impl headerl, and how that should be fine as we will reevaluate the outerProjectiongoal in that case
There was a problem hiding this comment.
I added comments but I'm not totally sure my understandings on those questions are correct 😅
44d974b to
ed986a6
Compare
This comment has been minimized.
This comment has been minimized.
1dad181 to
8cdfcda
Compare
| // In the new solver, nested goals are evaluated eagerly and the ambiguous nested | ||
| // goals aren't propagated back to the caller but discarded. | ||
| // | ||
| // This behavior made some unfortunate regressions when proving some associated | ||
| // projection goal, as we may lose the nested goals from the impl candidate's | ||
| // header which were preserved in the old solver. (See #122687) | ||
| // | ||
| // To avoid this, we create a `NormalizesTo` whose expected term is fully | ||
| // unconstrained and evaluate it as if we are calling a function rather than | ||
| // evaluating a nested goal, and register its ambiguous nested goals to the | ||
| // caller's context instead of discarding them. | ||
| // | ||
| // This may feel incorrect as we don't reevaluate the ambiguous `NormalizesTo` goal | ||
| // like other ordinary nested goals. Will we be in trouble if equating | ||
| // `unconstrained_term` with the expected term results in inference constraints in | ||
| // the impl header, which should be result in `Certainty::Yes` if we reevaluate it? | ||
| // Hopefully not, because we apply the certainty of nested `NormalizesTo` goal as | ||
| // the shallow certainty of the outer associated projection goal. If `NormalizesTo` | ||
| // returns ambiguity, the caller will do so as well and it and its `NormalizesTo` | ||
| // will be evaluated again by the caller's outer context. |
There was a problem hiding this comment.
I think this explanation is not as clear as it could be.
The chain of reasoning here is as follows:
- we don't want candidate selection when normalizing associated terms to be impacted by the expected term. normalization should behave like a function of just the alias being normalized
- because of this, we use an internal
NormalizesTogoal for which the expected term is always fully unconstrained and then equate that to the actual expected term afterwards - this results in weaker type inference if there's a nested where-clause when normalizing which we can actually make progress on based on the expected term. That's what
NormalizesTo: return nested goals to caller #122687 is for
And then (imo slightly separately) we don't reevaluate the NormalizesTo goal here even though equating the expected term with the normalization result could add inference constraints to the alias term. This is fine as these inference constraints should cause the caller to reevaluate the current Projection goal, which will then also reevaluate the NormalizesTo goal
There was a problem hiding this comment.
can you move all of this into a normalize_associated_term function or whatever?
| @@ -39,19 +34,12 @@ where | |||
| ty::AliasTermKind::ProjectionTy { .. } | ty::AliasTermKind::ProjectionConst { .. } => { | |||
| self.normalize_associated_term(goal) | |||
There was a problem hiding this comment.
and here you can keep this match as a debug_assert and just inline normalize_associated_term below it :3
This comment has been minimized.
This comment has been minimized.
We had never stepped into recursive replacement with `AliasRelate` goals when replacing aliases because `AliasRelate` goals don't allow normalization
8cdfcda to
54875bf
Compare
|
This PR was rebased onto a different main commit. Here's a range-diff highlighting what actually changed. Rebasing is a normal part of keeping PRs up to date, so no action is needed—this note is just to help reviewers. |
|
@bors r=lcnr |
View all comments
cc rust-lang/trait-system-refactor-initiative#223 (comment)
r? lcnr