Skip to content

fix normalizing in different ParamEnvs with the same InferCtxt#124203

Merged
bors merged 4 commits into
rust-lang:masterfrom
lukas-code:delete-deleting-caches
Apr 21, 2024
Merged

fix normalizing in different ParamEnvs with the same InferCtxt#124203
bors merged 4 commits into
rust-lang:masterfrom
lukas-code:delete-deleting-caches

Conversation

@lukas-code

Copy link
Copy Markdown
Member

This PR changes the key of the projection cache from just AliasTy to (AliasTy, ParamEnv) to allow normalizing in different ParamEnvs without resetting caches. Previously, normalizing the same alias in different param envs would always reuse the cached result from the first normalization, which is incorrect if the projection clauses in the param env have changed.

Fixing this bug allows us to get rid of InferCtxt::clear_caches, which was only used by the AutoTraitFinder, because it requires normalizing in different param envs.

r? @fmease

@rustbot rustbot added S-waiting-on-review Status: Awaiting review from the assignee but also interested parties. T-compiler Relevant to the compiler team, which will review and decide on the PR/issue. labels Apr 20, 2024
#[derive(Copy, Clone, Debug, Hash, PartialEq, Eq)]
pub struct ProjectionCacheKey<'tcx> {
ty: ty::AliasTy<'tcx>,
param_env: ty::ParamEnv<'tcx>,

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

won't that lead to tons of cache misses?

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Almost all code that isn't the AutoTraitFinder will always use the same ParamEnv for a single InferCtxt, so I don't expect there to be many cache misses if any at all. But maybe start a perf run just to confirm? (I don't have permission)

@fmease

fmease commented Apr 20, 2024

Copy link
Copy Markdown
Member

@bors try @rust-timer queue

@rust-timer

This comment has been minimized.

@rustbot rustbot added the S-waiting-on-perf Status: Waiting on a perf run to be completed. label Apr 20, 2024
@bors

bors commented Apr 20, 2024

Copy link
Copy Markdown
Collaborator

⌛ Trying commit 31a05a2 with merge ceb60ad...

bors added a commit to rust-lang-ci/rust that referenced this pull request Apr 20, 2024
…=<try>

fix normalizing in different `ParamEnv`s with the same `InferCtxt`

This PR changes the key of the projection cache from just `AliasTy` to `(AliasTy, ParamEnv)` to allow normalizing in different `ParamEnv`s without resetting caches. Previously, normalizing the same alias in different param envs would always reuse the cached result from the first normalization, which is incorrect if the projection clauses in the param env have changed.

Fixing this bug allows us to get rid of `InferCtxt::clear_caches`, which was only used by the `AutoTraitFinder`, because it requires normalizing in different param envs.

r? `@fmease`
@bors

bors commented Apr 20, 2024

Copy link
Copy Markdown
Collaborator

☀️ Try build successful - checks-actions
Build commit: ceb60ad (ceb60ade6b48a31fc13ac63893178917b3fcd1a8)

@rust-timer

This comment has been minimized.

@compiler-errors

Copy link
Copy Markdown
Contributor

I thought I tried this before and the perf regression was really bad 🤔

@rust-timer

Copy link
Copy Markdown
Collaborator

Finished benchmarking commit (ceb60ad): comparison URL.

Overall result: ✅ improvements - no action needed

Benchmarking 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.

@bors rollup=never
@rustbot label: -S-waiting-on-perf -perf-regression

Instruction count

This is a highly reliable metric that was used to determine the overall result at the top of this comment.

mean range count
Regressions ❌
(primary)
0.3% [0.3%, 0.3%] 1
Regressions ❌
(secondary)
- - 0
Improvements ✅
(primary)
-0.7% [-2.4%, -0.2%] 10
Improvements ✅
(secondary)
-0.9% [-0.9%, -0.9%] 1
All ❌✅ (primary) -0.6% [-2.4%, 0.3%] 11

Max RSS (memory usage)

Results

This 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.

mean range count
Regressions ❌
(primary)
3.3% [3.3%, 3.3%] 1
Regressions ❌
(secondary)
- - 0
Improvements ✅
(primary)
- - 0
Improvements ✅
(secondary)
- - 0
All ❌✅ (primary) 3.3% [3.3%, 3.3%] 1

Cycles

Results

This 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.

mean range count
Regressions ❌
(primary)
- - 0
Regressions ❌
(secondary)
6.3% [5.3%, 7.3%] 5
Improvements ✅
(primary)
-1.8% [-1.8%, -1.8%] 1
Improvements ✅
(secondary)
- - 0
All ❌✅ (primary) -1.8% [-1.8%, -1.8%] 1

Binary size

This benchmark run did not return any relevant results for this metric.

Bootstrap: 672.886s -> 671.734s (-0.17%)
Artifact size: 315.23 MiB -> 315.25 MiB (0.01%)

@rustbot rustbot removed the S-waiting-on-perf Status: Waiting on a perf run to be completed. label Apr 20, 2024

@compiler-errors compiler-errors left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Awesome. Glad to see this leads to a doc perf win, too.

@compiler-errors

Copy link
Copy Markdown
Contributor

@bors r+

@bors

bors commented Apr 21, 2024

Copy link
Copy Markdown
Collaborator

📌 Commit 31a05a2 has been approved by compiler-errors

It is now in the queue for this repository.

@bors bors added S-waiting-on-bors Status: Waiting on bors to run and complete tests. Bors will change the label on completion. and removed S-waiting-on-review Status: Awaiting review from the assignee but also interested parties. labels Apr 21, 2024
@bors

bors commented Apr 21, 2024

Copy link
Copy Markdown
Collaborator

⌛ Testing commit 31a05a2 with merge b6bd939...

bors added a commit to rust-lang-ci/rust that referenced this pull request Apr 21, 2024
…=compiler-errors

fix normalizing in different `ParamEnv`s with the same `InferCtxt`

This PR changes the key of the projection cache from just `AliasTy` to `(AliasTy, ParamEnv)` to allow normalizing in different `ParamEnv`s without resetting caches. Previously, normalizing the same alias in different param envs would always reuse the cached result from the first normalization, which is incorrect if the projection clauses in the param env have changed.

Fixing this bug allows us to get rid of `InferCtxt::clear_caches`, which was only used by the `AutoTraitFinder`, because it requires normalizing in different param envs.

r? `@fmease`
@rust-log-analyzer

This comment has been minimized.

@bors

bors commented Apr 21, 2024

Copy link
Copy Markdown
Collaborator

💔 Test failed - checks-actions

@bors bors added S-waiting-on-review Status: Awaiting review from the assignee but also interested parties. and removed S-waiting-on-bors Status: Waiting on bors to run and complete tests. Bors will change the label on completion. labels Apr 21, 2024
@fmease fmease added S-waiting-on-author Status: This is awaiting some action (such as code changes or more information) from the author. and removed S-waiting-on-review Status: Awaiting review from the assignee but also interested parties. labels Apr 21, 2024
@compiler-errors

compiler-errors commented Apr 21, 2024

Copy link
Copy Markdown
Contributor

Ugh. See #117131 and #117542.

Here's a minimal-ish example:

use std::future::Future;

struct Size<T>(T);

trait Foo {
    fn foo<K, V>() -> impl Future<Output = Size<impl Sized>> {
        async {
            Size(())
        }
    }
}

fn main() {}

We can no longer rely on the RPITIT -> opaque tys having been stashed in the projection cache, so we need to use the normalize_param_env everywhere in check_type_bounds. Not certain if that will regress behavior due to incompleteness of choosing certain predicates over others in the old trait solver.

@lukas-code

Copy link
Copy Markdown
Member Author

We can no longer rely on the RPITIT -> opaque tys having been stashed in the projection cache

It's actually the opposite happening here: assumed_wf_types is will attempt to normalize the RPITIT in the normal param_env first, so we end up with RPITIT -> RPITIT in the projection cache.

let assumed_wf_types = ocx.assumed_wf_types_and_report_errors(param_env, impl_ty_def_id)?;

When normalizing the obligation in the normalize_param_env later, we pick up the RPITIT -> RPITIT from the cache, so we don't normalize RPITIT -> opaque type at all.

let normalize_param_env = param_env_with_gat_bounds(tcx, impl_ty, impl_trait_ref);
for mut obligation in util::elaborate(tcx, obligations) {
let normalized_predicate =
ocx.normalize(&normalize_cause, normalize_param_env, obligation.predicate);
debug!("compare_projection_bounds: normalized predicate = {:?}", normalized_predicate);
obligation.predicate = normalized_predicate;
ocx.register_obligation(obligation);
}


This makes me think that maybe we shouldn't normalize the RPITITs in default method implementations at all, because AFAICT there is not additional type information to be gained. Because it's impossible for a default method to specify a return type that's more concrete than the RPITIT that it's defining.

@compiler-errors

compiler-errors commented Apr 21, 2024

Copy link
Copy Markdown
Contributor

This makes me think that maybe we shouldn't normalize the RPITITs in default method implementations at all, because AFAICT there is not additional type information to be gained. Because it's impossible for a default method to specify a return type that's more concrete than the RPITIT that it's defining.

I'm not certain what you mean -- RPITITs can specify default method bodies that constrain the opaque:

trait RPITIT {
    fn test() -> impl Sized { 0 }
}

@compiler-errors

Copy link
Copy Markdown
Contributor

Oh, do you mean just in param_env_with_gat_bounds? I mean, if it works then sure. It's too early in the morning for me to consider the implications of not doing so though.

@lukas-code

lukas-code commented Apr 21, 2024

Copy link
Copy Markdown
Member Author

I'm not certain what you mean -- RPITITs can specify default method bodies that constrain the opaque:

Yeah but type checking will only see impl Sized and doesn't know that it's actually i32.

Opposed to this, wich actually knows the concrete type for <i32 as RPITIT>::test:

trait RPITIT {
    fn test() -> impl Sized;
}

impl RPITIT for i32 {
    fn test() -> i32 { 0 }
}

Oh, do you mean just in param_env_with_gat_bounds?

Yes, exactly. RevealAll etc still have to normalize the RPITIT of course.

@lukas-code

Copy link
Copy Markdown
Member Author

Alright, I found the actual problem. It was a missing super_fold_with.

@compiler-errors

compiler-errors commented Apr 21, 2024

Copy link
Copy Markdown
Contributor

Oh that's incredibly embarrassing but also i'm unsurprised that normalization usually hides this from being an issue. Thanks for looking into this.

@bors r+

@bors

bors commented Apr 21, 2024

Copy link
Copy Markdown
Collaborator

📌 Commit 5a2b335 has been approved by compiler-errors

It is now in the queue for this repository.

@bors bors added S-waiting-on-bors Status: Waiting on bors to run and complete tests. Bors will change the label on completion. and removed S-waiting-on-author Status: This is awaiting some action (such as code changes or more information) from the author. labels Apr 21, 2024
@bors

bors commented Apr 21, 2024

Copy link
Copy Markdown
Collaborator

⌛ Testing commit 5a2b335 with merge 1b3fba0...

@bors

bors commented Apr 21, 2024

Copy link
Copy Markdown
Collaborator

☀️ Test successful - checks-actions
Approved by: compiler-errors
Pushing 1b3fba0 to master...

@bors bors added the merged-by-bors This PR was explicitly merged by bors. label Apr 21, 2024
@bors bors merged commit 1b3fba0 into rust-lang:master Apr 21, 2024
@rustbot rustbot added this to the 1.79.0 milestone Apr 21, 2024
@lukas-code lukas-code deleted the delete-deleting-caches branch April 21, 2024 21:07
@rust-timer

Copy link
Copy Markdown
Collaborator

Finished benchmarking commit (1b3fba0): comparison URL.

Overall result: ❌✅ regressions and improvements - ACTION NEEDED

Next Steps: If you can justify the regressions found in this perf run, please indicate this with @rustbot label: +perf-regression-triaged along with sufficient written justification. If you cannot justify the regressions please open an issue or create a new PR that fixes the regressions, add a comment linking to the newly created issue or PR, and then add the perf-regression-triaged label to this PR.

@rustbot label: +perf-regression
cc @rust-lang/wg-compiler-performance

Instruction count

This is a highly reliable metric that was used to determine the overall result at the top of this comment.

mean range count
Regressions ❌
(primary)
- - 0
Regressions ❌
(secondary)
4.1% [4.1%, 4.1%] 1
Improvements ✅
(primary)
-0.7% [-2.4%, -0.2%] 9
Improvements ✅
(secondary)
-0.9% [-0.9%, -0.9%] 1
All ❌✅ (primary) -0.7% [-2.4%, -0.2%] 9

Max RSS (memory usage)

Results

This 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.

mean range count
Regressions ❌
(primary)
2.1% [2.1%, 2.1%] 1
Regressions ❌
(secondary)
- - 0
Improvements ✅
(primary)
- - 0
Improvements ✅
(secondary)
- - 0
All ❌✅ (primary) 2.1% [2.1%, 2.1%] 1

Cycles

Results

This 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.

mean range count
Regressions ❌
(primary)
- - 0
Regressions ❌
(secondary)
3.9% [3.9%, 3.9%] 1
Improvements ✅
(primary)
-1.4% [-1.9%, -0.9%] 2
Improvements ✅
(secondary)
- - 0
All ❌✅ (primary) -1.4% [-1.9%, -0.9%] 2

Binary size

This benchmark run did not return any relevant results for this metric.

Bootstrap: 669.682s -> 674.072s (0.66%)
Artifact size: 315.52 MiB -> 315.57 MiB (0.02%)

@rustbot rustbot added the perf-regression Performance regression. label Apr 21, 2024
@lukas-code

Copy link
Copy Markdown
Member Author

The regression is likely noise, it went back down in the following merge: #124241 (comment) / #124241 (comment).

perf graph

@rustbot label perf-regression-triaged

@rustbot rustbot added the perf-regression-triaged The performance regression has been triaged. label Apr 22, 2024
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

merged-by-bors This PR was explicitly merged by bors. perf-regression Performance regression. perf-regression-triaged The performance regression has been triaged. S-waiting-on-bors Status: Waiting on bors to run and complete tests. Bors will change the label on completion. T-compiler Relevant to the compiler team, which will review and decide on the PR/issue.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

7 participants