-
Notifications
You must be signed in to change notification settings - Fork 13.8k
Stabilize if let
guards (feature(if_let_guard)
)
#141295
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
r? @SparrowLii rustbot has assigned @SparrowLii. Use |
Some changes occurred to the CTFE machinery Some changes occurred to MIR optimizations cc @rust-lang/wg-mir-opt Some changes occurred in compiler/rustc_codegen_ssa |
6fe74d9
to
5ee8970
Compare
rust-analyzer is developed in its own repository. If possible, consider making this change to rust-lang/rust-analyzer instead. cc @rust-lang/rust-analyzer Some changes occurred in src/tools/clippy cc @rust-lang/clippy |
eb0e4b4
to
0358002
Compare
This comment has been minimized.
This comment has been minimized.
92a5204
to
ab138ce
Compare
This comment has been minimized.
This comment has been minimized.
5ceca48
to
a20c4f6
Compare
This comment has been minimized.
This comment has been minimized.
1dd9974
to
5796073
Compare
cc @Nadrieril |
This needs a fcp so I'd like to roll this to someone more familiar with this feature |
r? @est31 |
The #![feature(if_let_guard)]
use std::pin::pin;
struct LoudDrop(&'static str);
impl Drop for LoudDrop {
fn drop(&mut self) {
println!("{}", self.0);
}
}
fn main() {
match () {
_ if let x = LoudDrop("0")
&& let y = pin!(LoudDrop("1")) => {}
_ => {}
}
} This outputs My intuition is that, with regards to dropping, |
I tested this with regular let chains (outside of if-let guards) and observed the same behavior - if let x = LoudDrop("0")
&& let y = pin!(LoudDrop("1"))
{} This suggests the issue might be related to let chains in general, or specifically to the interaction between let chains and "super let". If I recall correctly, super let was implemented after let chains were stabilized, which could explain this interaction |
I did some additional testing and found that the drop order follows a predictable pattern (though this doesn't change the fact that if let x = LoudDrop("0")
&& let y = pin!(LoudDrop("1"))
&& let z = pin!(LoudDrop("2"))
&& let w = LoudDrop("3")
{}
// 3
// 0
// 2
// 1 The pattern appears to be: drops occur from bottom to top, but any pinned values are moved to the end of the drop queue |
I've filed this as #145328 |
add a scope for `if let` guard temporaries and bindings This fixes my concern with `if let` guard drop order, namely that the guard's bindings and temporaries were being dropped after their arm's pattern's bindings, instead of before (rust-lang/rust#141295 (comment)). The guard's bindings and temporaries now live in a new scope, which extends until (but not past) the end of the arm, guaranteeing they're dropped before the arm's pattern's bindings. This only introduces a new scope for match arms with guards. Perf results (rust-lang/rust#143376 (comment)) seemed to indicate there wasn't a significant hit to introduce a new scope on all match arms, but guard patterns (rust-lang/rust#129967) will likely benefit from only adding new scopes when necessary (with some patterns requiring multiple nested scopes). Tracking issue for `if_let_guard`: rust-lang/rust#51114 Tests are adapted from examples by `@traviscross,` `@est31,` and myself on rust-lang/rust#141295.
add a scope for `if let` guard temporaries and bindings This fixes my concern with `if let` guard drop order, namely that the guard's bindings and temporaries were being dropped after their arm's pattern's bindings, instead of before (rust-lang/rust#141295 (comment)). The guard's bindings and temporaries now live in a new scope, which extends until (but not past) the end of the arm, guaranteeing they're dropped before the arm's pattern's bindings. This only introduces a new scope for match arms with guards. Perf results (rust-lang/rust#143376 (comment)) seemed to indicate there wasn't a significant hit to introduce a new scope on all match arms, but guard patterns (rust-lang/rust#129967) will likely benefit from only adding new scopes when necessary (with some patterns requiring multiple nested scopes). Tracking issue for `if_let_guard`: rust-lang/rust#51114 Tests are adapted from examples by `@traviscross,` `@est31,` and myself on rust-lang/rust#141295.
add a scope for `if let` guard temporaries and bindings This fixes my concern with `if let` guard drop order, namely that the guard's bindings and temporaries were being dropped after their arm's pattern's bindings, instead of before (rust-lang/rust#141295 (comment)). The guard's bindings and temporaries now live in a new scope, which extends until (but not past) the end of the arm, guaranteeing they're dropped before the arm's pattern's bindings. This only introduces a new scope for match arms with guards. Perf results (rust-lang/rust#143376 (comment)) seemed to indicate there wasn't a significant hit to introduce a new scope on all match arms, but guard patterns (rust-lang/rust#129967) will likely benefit from only adding new scopes when necessary (with some patterns requiring multiple nested scopes). Tracking issue for `if_let_guard`: rust-lang/rust#51114 Tests are adapted from examples by `@traviscross,` `@est31,` and myself on rust-lang/rust#141295.
add a scope for `if let` guard temporaries and bindings This fixes my concern with `if let` guard drop order, namely that the guard's bindings and temporaries were being dropped after their arm's pattern's bindings, instead of before (rust-lang/rust#141295 (comment)). The guard's bindings and temporaries now live in a new scope, which extends until (but not past) the end of the arm, guaranteeing they're dropped before the arm's pattern's bindings. This only introduces a new scope for match arms with guards. Perf results (rust-lang/rust#143376 (comment)) seemed to indicate there wasn't a significant hit to introduce a new scope on all match arms, but guard patterns (rust-lang/rust#129967) will likely benefit from only adding new scopes when necessary (with some patterns requiring multiple nested scopes). Tracking issue for `if_let_guard`: rust-lang/rust#51114 Tests are adapted from examples by `@traviscross,` `@est31,` and myself on rust-lang/rust#141295.
add a scope for `if let` guard temporaries and bindings This fixes my concern with `if let` guard drop order, namely that the guard's bindings and temporaries were being dropped after their arm's pattern's bindings, instead of before (rust-lang/rust#141295 (comment)). The guard's bindings and temporaries now live in a new scope, which extends until (but not past) the end of the arm, guaranteeing they're dropped before the arm's pattern's bindings. This only introduces a new scope for match arms with guards. Perf results (rust-lang/rust#143376 (comment)) seemed to indicate there wasn't a significant hit to introduce a new scope on all match arms, but guard patterns (rust-lang/rust#129967) will likely benefit from only adding new scopes when necessary (with some patterns requiring multiple nested scopes). Tracking issue for `if_let_guard`: rust-lang/rust#51114 Tests are adapted from examples by `@traviscross,` `@est31,` and myself on rust-lang/rust#141295.
Hi everyone, It’s been a while since my last update - quite a lot has happened in the meantime, but the main thing is I'm still here I’ve noticed that many fixes, including the main concern, have already been merged - big thanks to @dianne for the help, and to @theemathas for spotting some interesting edge cases Also, the documentation (thanks again to dianne) has been created and marked as waiting-on-stabilization. Am I right in assuming that means it’s in good shape? So from what I see, the major concerns like the drop order bug and the docs are resolved I just wanted to check with the team: are there any other blockers before I start extending the test suite and working through the conflicts? |
Thanks for checking in and following up on this. Looking back over the issue, I agree that the primary blockers here have been resolved. I would indeed suggest extending the tests and rebasing the branch. We haven't yet approved the Reference PR (rust-lang/reference#1957), and that will need to happen before we merge this PR, but on a skim, it looks to be in good shape; this won't hold things up unduly. We'll probably want to see the extended tests before approving this anyway, so as to compare the behavior with what we're documenting. If you could leave a note here when the tests are extended and the branch is rebased, I'll plan to have a look, resolve the concern I had filed, restart the proposed FCP, and finish reviewing the Reference PR. |
bde3195
to
902b4d2
Compare
This PR modifies |
This PR was rebased onto a different master 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. |
This comment has been minimized.
This comment has been minimized.
902b4d2
to
54371e6
Compare
This comment has been minimized.
This comment has been minimized.
54371e6
to
725c559
Compare
The Miri subtree was changed cc @rust-lang/miri |
This comment has been minimized.
This comment has been minimized.
725c559
to
5650d71
Compare
This comment has been minimized.
This comment has been minimized.
5650d71
to
3a6c8c8
Compare
Conflicts are resolved For test part from what I see is dianne added a test for drop order which is covering the drop order fix, I updated description and specify 3 new tests in there (one of them I adopted from here #141295 (comment)) And as for tests for this and this I will add them later on if noone else will do this before, and point them in unresolved issues as non blocking |
Summary
This proposes the stabilization of
if let
guards (tracking issue: #51114, RFC: rust-lang/rfcs#2294). This feature allowsif let
expressions to be used directly within match arm guards, enabling conditional pattern matching within guard clauses.What is being stabilized
The ability to use
if let
expressions within match arm guards.Example:
Motivation
The primary motivation for
if let
guards is to reduce nesting and improve readability when conditional logic depends on pattern matching. Without this feature, such logic requires nestedif let
statements within match arms:Implementation and Testing
The feature has been implemented and tested comprehensively across different scenarios:
Core Functionality Tests
Scoping and variable binding:
scope.rs
- Verifies that bindings created inif let
guards are properly scoped and available in match armsshadowing.rs
- Tests that variable shadowing works correctly within guardsscoping-consistency.rs
- Ensures temporaries in guards remain valid for the duration of their match armsType system integration:
type-inference.rs
- Confirms type inference works correctly inif let
guardstypeck.rs
- Verifies type mismatches are caught appropriatelyPattern matching semantics:
exhaustive.rs
- Validates thatif let
guards are correctly handled in exhaustiveness analysismove-guard-if-let.rs
andmove-guard-if-let-chain.rs
- Test that conditional moves in guards are tracked correctly by the borrow checkerError Handling and Diagnostics
warns.rs
- Tests warnings for irrefutable patterns and unreachable code in guardsparens.rs
- Ensures parentheses aroundlet
expressions are properly rejectedmacro-expanded.rs
- Verifies macro expansions that produce invalid constructs are caughtguard-mutability-2.rs
- Tests mutability and ownership violations in guardsast-validate-guards.rs
- Validates AST-level syntax restrictionsDrop Order and Temporaries
Key insight: Unlike
let_chains
in regularif
expressions,if let
guards do not have drop order inconsistencies because:drop-order.rs
- Check drop order of temporaries create in match guardscompare-drop-order.rs
- Compares drop order betweenif let
guards and nestedif let
in match arms, confirming they behave identically across all editionslet chain
was made by @est31drop-order-comparisons-let-chains.rs
- Compares drop order betweenlet chains
inif let guard
and regularif
expressionsif-let-guards.rs
- Test correctness of drop order for bindings and temporariesif-let-guards-2
- The same test as above but more comprehensive and tests more interactions between different features and their drop order, checking that drop order is correct, created by @traviscrossEdition Compatibility
This feature stabilizes on all editions, unlike
let chains
which was limited to edition 2024. This is safe because:if let
guards don't suffer from the drop order issues that affectedlet chains
in regularif
expressionsInteractions with Future Features
The lang team has reviewed potential interactions with planned "guard patterns" and determined that stabilizing
if let
guards now does not create obstacles for future work. The scoping and evaluation semantics established here align with what guard patterns will need.Unresolved Issues
let chains
insideif let
guard is the sameif let
guard temporaries and bindings #143376if let
guards with updated scoping rules reference#1957)Related:
if let
guards with updated scoping rules reference#1957