Stabilize if let guards (feature(if_let_guard))#141295
Stabilize if let guards (feature(if_let_guard))#141295rust-bors[bot] merged 1 commit intorust-lang:mainfrom
if let guards (feature(if_let_guard))#141295Conversation
|
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 |
|
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. |
|
Today I had the time to give this a closer look/load the problem space back into memory, and re-read this thread as well as the code changes. The implementation looks good to me. Since my earlier positive review, the stabilization has been held back by two issues: the reference PR as well as drop order concerns raised by @dianne . Since then, the reference PR has been approved (I found a minor issue in it but it's easy to fix), and @dianne 's concerns have been resolved. Giving the tests another look and what is being tested, there is some minor things that could get tests:
r=me with the latter two concerns addressed. |
a68ecfd to
964b63f
Compare
could you take a look on |
There was a problem hiding this comment.
nit: this should be #![deny(irrefutable_let_patterns)] - no point in only applying to the individual functions
|
@bors r=fee1-dead,est31 |
|
@bors rollup=never |
it's precisely what I wanted, thanks! |
|
Cc @rust-lang/fls on an upcoming stabilization. |
|
@bors p=2 |
This comment has been minimized.
This comment has been minimized.
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 c043085 (parent) -> e0cb264 (this PR) Test differencesShow 68 test diffsStage 1
Stage 2
Additionally, 6 doctest diffs were found. These are ignored, as they are noisy. Job group index
Test dashboardRun cargo run --manifest-path src/ci/citool/Cargo.toml -- \
test-dashboard e0cb264b814526acb82def4b5810e394a2ed294f --output-dir test-dashboardAnd 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 (e0cb264): comparison URL. Overall result: ❌ regressions - no action needed@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 2.6%, secondary 0.2%)A less reliable metric. May be of interest, but not used to determine the overall result above.
CyclesThis benchmark run did not return any relevant results for this metric. Binary sizeThis benchmark run did not return any relevant results for this metric. Bootstrap: 479.769s -> 487.064s (1.52%) |
Stabilize `if let` guards (`feature(if_let_guard)`) ## Summary This proposes the stabilization of `if let` guards (tracking issue: rust-lang/rust#51114, RFC: rust-lang/rfcs#2294). This feature allows `if 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: ```rust enum Command { Run(String), Stop, Pause, } fn process_command(cmd: Command, state: &mut String) { match cmd { Command::Run(name) if let Some(first_char) = name.chars().next() && first_char.is_ascii_alphabetic() => { // Both `name` and `first_char` are available here println!("Running command: {} (starts with '{}')", name, first_char); state.push_str(&format!("Running {}", name)); } Command::Run(name) => { println!("Cannot run command '{}'. Invalid name.", name); } Command::Stop if state.contains("running") => { println!("Stopping current process."); state.clear(); } _ => { println!("Unhandled command or state."); } } } ``` ## 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 nested `if let` statements within match arms: ```rust // Without if let guards match value { Some(x) => { if let Ok(y) = compute(x) { // Both `x` and `y` are available here println!("{}, {}", x, y); } } _ => {} } // With if let guards match value { Some(x) if let Ok(y) = compute(x) => { // Both `x` and `y` are available here println!("{}, {}", x, y); } _ => {} } ``` ## Implementation and Testing The feature has been implemented and tested comprehensively across different scenarios: ### Core Functionality Tests **Scoping and variable binding:** - [`scope.rs`](https://github.com/rust-lang/rust/blob/5796073c134eaac30475f9a19462c4e716c9119c/tests/ui/rfcs/rfc-2294-if-let-guard/scope.rs) - Verifies that bindings created in `if let` guards are properly scoped and available in match arms - [`shadowing.rs`](https://github.com/rust-lang/rust/blob/5796073c134eaac30475f9a19462c4e716c9119c/tests/ui/rfcs/rfc-2294-if-let-guard/shadowing.rs) - Tests that variable shadowing works correctly within guards - [`scoping-consistency.rs`](https://github.com/rust-lang/rust/blob/5796073c134eaac30475f9a19462c4e716c9119c/tests/ui/rfcs/rfc-2294-if-let-guard/scoping-consistency.rs) - Ensures temporaries in guards remain valid for the duration of their match arms **Type system integration:** - [`type-inference.rs`](https://github.com/rust-lang/rust/blob/5796073c134eaac30475f9a19462c4e716c9119c/tests/ui/rfcs/rfc-2294-if-let-guard/type-inference.rs) - Confirms type inference works correctly in `if let` guards - [`typeck.rs`](https://github.com/rust-lang/rust/blob/5796073c134eaac30475f9a19462c4e716c9119c/tests/ui/rfcs/rfc-2294-if-let-guard/typeck.rs) - Verifies type mismatches are caught appropriately **Pattern matching semantics:** - [`exhaustive.rs`](https://github.com/rust-lang/rust/blob/5796073c134eaac30475f9a19462c4e716c9119c/tests/ui/rfcs/rfc-2294-if-let-guard/exhaustive.rs) - Validates that `if let` guards are correctly handled in exhaustiveness analysis - [`move-guard-if-let.rs`](https://github.com/rust-lang/rust/blob/5796073c134eaac30475f9a19462c4e716c9119c/tests/ui/rfcs/rfc-2294-if-let-guard/move-guard-if-let.rs) and [`move-guard-if-let-chain.rs`](https://github.com/rust-lang/rust/blob/5796073c134eaac30475f9a19462c4e716c9119c/tests/ui/rfcs/rfc-2294-if-let-guard/move-guard-if-let-chain.rs) - Test that conditional moves in guards are tracked correctly by the borrow checker ### Error Handling and Diagnostics - [`warns.rs`](https://github.com/rust-lang/rust/blob/5796073c134eaac30475f9a19462c4e716c9119c/tests/ui/rfcs/rfc-2294-if-let-guard/warns.rs) - Tests warnings for irrefutable patterns and unreachable code in guards - [`parens.rs`](https://github.com/rust-lang/rust/blob/5796073c134eaac30475f9a19462c4e716c9119c/tests/ui/rfcs/rfc-2294-if-let-guard/parens.rs) - Ensures parentheses around `let` expressions are properly rejected - [`macro-expanded.rs`](https://github.com/rust-lang/rust/blob/5796073c134eaac30475f9a19462c4e716c9119c/tests/ui/rfcs/rfc-2294-if-let-guard/macro-expanded.rs) - Verifies macro expansions that produce invalid constructs are caught - [`guard-mutability-2.rs`](https://github.com/rust-lang/rust/blob/5796073c134eaac30475f9a19462c4e716c9119c/tests/ui/rfcs/rfc-2294-if-let-guard/guard-mutability-2.rs) - Tests mutability and ownership violations in guards - [`ast-validate-guards.rs`](https://github.com/rust-lang/rust/blob/5796073c134eaac30475f9a19462c4e716c9119c/tests/ui/rfcs/rfc-2497-if-let-chains/ast-validate-guards.rs) - Validates AST-level syntax restrictions ### Drop Order and Temporaries **Key insight:** Unlike `let_chains` in regular `if` expressions, `if let` guards do not have drop order inconsistencies because: 1. Match guards are clearly scoped to their arms 2. There is no "else block" equivalent that could cause temporal confusion - [`drop-order.rs`](https://github.com/rust-lang/rust/blob/5796073c134eaac30475f9a19462c4e716c9119c/tests/ui/rfcs/rfc-2294-if-let-guard/drop-order.rs) - Check drop order of temporaries create in match guards - [`compare-drop-order.rs`](https://github.com/rust-lang/rust/blob/aef3f5fdf052fbbc16e174aef5da6d50832ca316/tests/ui/rfcs/rfc-2294-if-let-guard/compare-drop-order.rs) - Compares drop order between `if let` guards and nested `if let` in match arms, confirming they behave identically across all editions - rust-lang/rust#140981 - A complicated drop order test involved `let chain` was made by @est31 - [`drop-order-comparisons-let-chains.rs`](https://github.com/rust-lang/rust/blob/902b4d28783e03e231d8513082cc30c4fcce5d95/tests/ui/drop/drop-order-comparisons-let-chains.rs) - Compares drop order between `let chains` in `if let guard` and regular `if` expressions - [`if-let-guards.rs`](https://github.com/rust-lang/rust/blob/5650d716e0589e2e145ce9027f35bd534e5f862a/tests/ui/drop/if-let-guards.rs) - Test correctness of drop order for bindings and temporaries - [`if-let-guards-2`](https://github.com/rust-lang/rust/blob/3a6c8c8f3d7ae654fdb6ce1255182bda21680655/tests/ui/drop/if-let-guards-2.rs) - 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 @traviscross ## Edition Compatibility This feature stabilizes on all editions, unlike `let chains` which was limited to edition 2024. This is safe because: 1. `if let` guards don't suffer from the drop order issues that affected `let chains` in regular `if` expressions 2. The scoping is unambiguous - guards are clearly tied to their match arms 3. Extensive testing confirms identical behavior across all editions ## Interactions 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 - [x] - rust-lang/rust#140981 - [x] - added tests description by @jieyouxu request - [x] - Concers from @scottmcm about stabilizing this across all editions - [x] - check if drop order in all edition when using `let chains` inside `if let` guard is the same - [x] - interactions with guard patters - [x] - pattern bindings drops before guard bindings rust-lang/rust#143376 - [x] - documentaion (rust-lang/reference#1957) - [ ] (non-blocking) add tests for [this](rust-lang/rust#145237) and [this](rust-lang/rust#141295 (comment)) --- **Related:** - Tracking Issue: rust-lang/rust#51114 - RFC: rust-lang/rfcs#2294 - Documentation PR: rust-lang/reference#1957
Summary
This proposes the stabilization of
if letguards (tracking issue: #51114, RFC: rust-lang/rfcs#2294). This feature allowsif letexpressions to be used directly within match arm guards, enabling conditional pattern matching within guard clauses.What is being stabilized
The ability to use
if letexpressions within match arm guards.Example:
Motivation
The primary motivation for
if letguards is to reduce nesting and improve readability when conditional logic depends on pattern matching. Without this feature, such logic requires nestedif letstatements 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 letguards 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 letguardstypeck.rs- Verifies type mismatches are caught appropriatelyPattern matching semantics:
exhaustive.rs- Validates thatif letguards are correctly handled in exhaustiveness analysismove-guard-if-let.rsandmove-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 aroundletexpressions 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_chainsin regularifexpressions,if letguards 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 letguards and nestedif letin match arms, confirming they behave identically across all editionslet chainwas made by @est31drop-order-comparisons-let-chains.rs- Compares drop order betweenlet chainsinif let guardand regularifexpressionsif-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 chainswhich was limited to edition 2024. This is safe because:if letguards don't suffer from the drop order issues that affectedlet chainsin regularifexpressionsInteractions with Future Features
The lang team has reviewed potential interactions with planned "guard patterns" and determined that stabilizing
if letguards 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 chainsinsideif letguard is the sameif letguard temporaries and bindings #143376if letguards with updated scoping rules reference#1957)Related:
if letguards with updated scoping rules reference#1957