-
Notifications
You must be signed in to change notification settings - Fork 13.5k
de-duplicate condition scoping logic between AST→HIR lowering and ScopeTree
construction
#143213
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
Conversation
rustbot has assigned @WaffleLapkin. Use |
This comment has been minimized.
This comment has been minimized.
This comment was marked as resolved.
This comment was marked as resolved.
686da48
to
13c796b
Compare
Some changes occurred in coverage tests. cc @Zalathar |
13c796b
to
be191a0
Compare
actually, I've convinced myself it's cleanest to get rid of
edit: I just noticed that I've left @rustbot author |
Some changes occurred in src/tools/clippy cc @rust-lang/clippy |
Reminder, once the PR becomes ready for a review, use |
alright, I've removed
all of this predates me contributing to the compiler, but I guess putting @rustbot ready |
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.
This looks good. A few nits and questions.
}) | ||
.is_some(), | ||
); | ||
err.emit(); |
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.
Can this be moved into demand_suptype_with_origin
?
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.
There are other still other uses of demand_suptype_with_origin
that augment the error in some way before emitting. There's a variant that emits the error, demand_suptype
, but it uses a misc obligation cause rather than ObligationCauseCode::Pattern
. One possible alternative would be to define a demand_suptype_pat
like we do for demand_eqtype_pat
, but that would be the only use of it.
let cond = self.lower_expr(cond); | ||
let reason = DesugaringKind::CondTemporary; | ||
let span_block = self.mark_span_with_reason(reason, cond.span, None); | ||
self.expr_drop_temps(span_block, cond) |
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.
Do you have ideas how to remove DropTemps
completely? In a follow-up pr ofc.
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.
In short, no. It could easily be removed from for
loop desugaring, but afaict it can only easily be removed from async desugaring in Editions 2024 and newer.
- For desugaring
for pat in expr { .. }
, it's to keep theexpr
's temps from living into the enclosing expression (which means an even longer lifetime forfor
in block tail expressions in old Editions). The difference can be seen here. If we wanted to removeDropTemps
in a cross-Edition-compatible way without a breaking change, we could use a block with one statement and no tail expression, since for loops always return()
. That said, as long asDropTemps
still exists, it's probably the easiest way to get the current behavior. - For async desugaring, it's to make sure the body's temporaries are dropped before the parameters. Currently, it's lowered into the tail expression of a block, which ensures its temporaries are dropped in Edition 2024, but tail expressions aren't terminating scopes in old Editions. I don't have a good answer for this other than keeping
DropTemps
around for it, but I'm admittedly not too familiar with async desugaring.
// Temporaries for `let` expressions must live into the success branch. | ||
hir::ExprKind::Let(_) => false, | ||
// Logical operator chains are handled in `resolve_expr`. The operators themselves have no | ||
// intermediate value to drop, and operands will be wrapped in terminating scopes. |
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.
This comment needs to be elaborated a bit. It took me some time to convince myself that resolve_expr
does the right thing.
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've added some more details: diff. If that doesn't fully clarify it, are there any things in particular that you think need accounting for or mentioning?
I noticed a comment that I'd missed that references |
r? cjgillot |
Thanks! |
de-duplicate condition scoping logic between AST→HIR lowering and `ScopeTree` construction There was some overlap between `rustc_ast_lowering::LoweringContext::lower_cond` and `rustc_hir_analysis::check::region::resolve_expr`, so I've removed the former and migrated its logic to the latter, with some simplifications. Consequences: - For `while` and `if` expressions' `let`-chains, this changes the `HirId`s for the `&&`s to properly correspond to their AST nodes. This is how guards were handled already. - This makes match guards share previously-duplicated logic with `if`/`while` expressions. This will also be used by guard pattern[^1] guards. - Aside from legacy syntax extensions (e.g. some builtin macros) that directly feed AST to the compiler, it's currently impossible to put attributes directly on `&&` operators in `let` chains[^2]. Nonetheless, attributes on `&&` operators in `let` chains in `if`/`while` expression conditions are no longer silently ignored and will be lowered. - This no longer wraps conditions in `DropTemps`, so the HIR and THIR will be slightly smaller. - `DesugaringKind::CondTemporary` is now gone. It's no longer applied to any spans, and all uses of it were dead since they were made to account for `if` and `while` being desugared to `match` on a boolean scrutinee. - Should be a marginal perf improvement beyond that due to leveraging [`ScopeTree` construction](https://github.com/rust-lang/rust/blob/5e749eb66f93ee998145399fbdde337e57cd72ef/compiler/rustc_hir_analysis/src/check/region.rs#L312-L355)'s clever handling of `&&` and `||`: - This removes some unnecessary terminating scopes that were placed around top-level `&&` and `||` operators in conditions. When lowered to MIR, logical operator chains don't create intermediate boolean temporaries, so there's no temporary to drop. The linked snippet handles wrapping the operands in terminating scopes as necessary, in case they create temporaries. - The linked snippet takes care of letting `let` temporaries live and terminating other operands, so we don't need separate traversals of `&&` chains for that. [^1]: rust-lang#129967 [^2]: Case-by-case, here's my justification: `#[attr] e1 && e2` applies the attribute to `e1`. In `#[attr] (e1 && e2)` , the attribute is on the parentheses in the AST, plus it'd fail to parse if `e1` or `e2` contains a `let`. In `#[attr] expands_to_let_chain!()`, the attribute would already be ignored (rust-lang#63221) and it'd fail to parse anyway; even if the expansion site is a condition, the expansion wouldn't be parsed with `Restrictions::ALLOW_LET`. If it *was* allowed, the notion of a "reparse context" from rust-lang#61733 (comment) would be necessary in order to make `let`-chains left-associative; multiple places in the compiler assume they are.
Rollup of 9 pull requests Successful merges: - #143213 (de-duplicate condition scoping logic between AST→HIR lowering and `ScopeTree` construction) - #143461 (make `cfg_select` a builtin macro) - #143519 (Check assoc consts and tys later like assoc fns) - #143554 (slice: Mark `rotate_left`, `rotate_right` unstably const) - #143704 (Be a bit more careful around exotic cycles in in the inliner) - #143774 (constify `From` and `Into`) - #143786 (Fix fallback for CI_JOB_NAME) - #143796 (Fix ICE for parsed attributes with longer path not handled by CheckAttribute) - #143798 (Remove format short command trait) r? `@ghost` `@rustbot` modify labels: rollup
☀️ Test successful - checks-actions |
What is this?This is an experimental post-merge analysis report that shows differences in test outcomes between the merged PR and its parent PR.Comparing b1d2f2c (parent) -> d2baa49 (this PR) Test differencesShow 12 test diffs12 doctest diffs were found. These are ignored, as they are noisy. Test dashboardRun cargo run --manifest-path src/ci/citool/Cargo.toml -- \
test-dashboard d2baa49a106fad06fbf6202fb6ea8a0b3d2767cc --output-dir test-dashboard And then open Job duration changes
How to interpret the job duration changes?Job durations can vary a lot, based on the actual runner instance |
Finished benchmarking commit (d2baa49): comparison URL. Overall result: ❌✅ regressions and improvements - please read the text belowOur benchmarks found a performance regression caused by this PR. Next Steps:
@rustbot label: +perf-regression 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 0.7%)A less reliable metric. May be of interest, but not used to determine the overall result above.
CyclesResults (primary -2.8%, secondary 1.5%)A less reliable metric. May be of interest, but not used to determine the overall result above.
Binary sizeResults (primary -0.1%, secondary -0.1%)A less reliable metric. May be of interest, but not used to determine the overall result above.
Bootstrap: 466.487s -> 464.852s (-0.35%) |
There was some overlap between
rustc_ast_lowering::LoweringContext::lower_cond
andrustc_hir_analysis::check::region::resolve_expr
, so I've removed the former and migrated its logic to the latter, with some simplifications.Consequences:
while
andif
expressions'let
-chains, this changes theHirId
s for the&&
s to properly correspond to their AST nodes. This is how guards were handled already.if
/while
expressions. This will also be used by guard pattern1 guards.&&
operators inlet
chains2. Nonetheless, attributes on&&
operators inlet
chains inif
/while
expression conditions are no longer silently ignored and will be lowered.DropTemps
, so the HIR and THIR will be slightly smaller.DesugaringKind::CondTemporary
is now gone. It's no longer applied to any spans, and all uses of it were dead since they were made to account forif
andwhile
being desugared tomatch
on a boolean scrutinee.ScopeTree
construction's clever handling of&&
and||
:&&
and||
operators in conditions. When lowered to MIR, logical operator chains don't create intermediate boolean temporaries, so there's no temporary to drop. The linked snippet handles wrapping the operands in terminating scopes as necessary, in case they create temporaries.let
temporaries live and terminating other operands, so we don't need separate traversals of&&
chains for that.Footnotes
Tracking issue for RFC 3637: Guard patterns #129967 ↩
Case-by-case, here's my justification:
#[attr] e1 && e2
applies the attribute toe1
. In#[attr] (e1 && e2)
, the attribute is on the parentheses in the AST, plus it'd fail to parse ife1
ore2
contains alet
. In#[attr] expands_to_let_chain!()
, the attribute would already be ignored (How to treat inert attributes on macro invocations? #63221) and it'd fail to parse anyway; even if the expansion site is a condition, the expansion wouldn't be parsed withRestrictions::ALLOW_LET
. If it was allowed, the notion of a "reparse context" from https://github.com/rust-lang/rust/issues/61733#issuecomment-509626449 would be necessary in order to makelet
-chains left-associative; multiple places in the compiler assume they are. ↩