-
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
base: master
Are you sure you want to change the base?
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 |
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. ↩