Pre-Stabilization: `if let` guards

it might make more sense to start with a review and see what the team thinks first rather than rushing stabilization PR, but (!) this is finish line to be stablizied

I went through the full set of tests and also studied #132833, which stabilized let_chains and includes a some of discussion and evidence that if let guards behave correctly

My conclusion is that the feature appears sound and well-tested, and I believe it’s ready for stabilization (for 2024 edition for now). If I missed anything, please let me know

I'm wondering if we should enable if let guards only for edition 2024 and later. I tried removing the edition checks and applying the IfLetRescope behavior in edition 2021, but it led to MIR issues (e.g., ICE related to drop scopes). Given that let_chains were also stabilized only for edition 2024 to avoid similar backward compatibility pitfalls, maybe it makes sense to take the same approach here?

We could open an issue later if compatibility between editions becomes essential, but for now, it seems reasonable to restrict this feature to edition 2024. After all, it is stable (at least in 2024 edition), and thanks to if let rescope, it is now highly predictable and stable, especially for things like move and drop semantics

Since development seems to have stalled, and the test suite already covers a wide range of interactions (including drop order, temporaries, mutability, macros and a LOT more), I believe this would be a productive and low-risk step toward stabilization

If this direction looks good to everyone, I’d be happy to try opening a proper stabilization PR — not sure how tricky it’ll be, but I’d love to gain the experience :D

Reference adding documentaion for if let rust-lang/reference#1823

Here my my write-up explaining this feature and how it works in details

kivooeo.github.io/if-let-guard-feature/

Current stabilization checklist (feel free to ask add/fix something here)

  • Tests cover drop order, move, async, const, bindings, temporaries, mutability, macros, and a lot more (see tests for if let guard)
  • est31: irrefutable_let_patterns lint works as expected
  • Verify other lints (unused_variables, unreachable_patterns, etc.)
  • Documentation updated in src/doc/if-let-guard-review.md and rust-lang/reference#1823 (The if-let-guard-review.md document is a comprehensive write-up summarizing the state of the if let guards feature, including tests, drop semantics, and stabilization considerations. Since it’s more of a review and discussion document rather than final documentation, I don’t think it belongs in src/doc)
  • Check and confirm rustfmt support for if let guards
  • Confirm 2024-only stabilization with team
  • Make this work on all editions
  • Open stabilization PR after team approval
5 Likes

I think we should try to stabilize it on all editions, not just 2024. But we should do the rescoping on all editions as well. In my initial testing, I don't see any difference though between editions, all the stuff behaves as if it's on edition 2024. Not sure. In any case, it's simple to add rescoping to all editions for if let guards, see this branch.

Is the branch you shared a complete fix for adapting rescoping across all editions?

For if let guards, yes. Other places that can have let chains, like while let are not affected. So we can ship this without breaking anything for existing stable users. But I'm not sure if there is any observable difference, i.e. if there is a test where different behaviour shows up.

I will test this locally, thanks, if this work and pass tests for both 2021 and 2024 editions then I will open stabilization PR

@est31 can you please review this changes here

all tests are passed for both editions with your fix, and i replaced #![feature(if_let_guard)] with #![cfg_attr(bootstrap, feature(if_let_guard))]

is there anything i should change as well to submit stabilization PR?

We should probably figure out if there is any externally observable difference between rescoping vs no rescoping: changes in drop order, whether something compiles now or doesn't compile now, etc. For example, we could check if different MIR is generated or if it's the same. Such stuff would be useful for building regression tests of that rescoping behaviour.

Correct me if I misunderstood, but you’re suggesting to check and compare the MIR output with and without this patch, right? Especially for cases that test scoping or drop order — that way we can see whether rescoping actually makes a difference or not, and if it’s something we really need to rely on?

2025-05-13T14:38:04.682 [INFO] Comparing C:\Users\Kivooeo\Desktop\drop_order_mir_dump_patch\ with C:\Users\Kivooeo\Desktop\drop_order_mir_dump_no_patch\
2025-05-13T14:38:04.858 [INFO] Comparison completed: Identical

I compared both editions pre patched to both editions after your patch and they are the same, i got MIR output with this flags on rustc -Zdump-mir=all -Zmir-opt-level=0 --edition=202x

Is there i'm missing? Or this it's expected behaviour?

Ok, maybe it was better to test not a drop_order but drop_scope

Drop scope test actually gives the identical results as well

Can you tell me which tool you used for the comparison? And which rust snippet did you use?

I used WinMerge since there is no diff in windows

drop_order test and drop_scope test

In second I've added main body like this

fn main() {
    for &num in &[1, 2, 3, 4] {
        let_guard(num);
    }

    for &num in &[5, 6, 7, 8] {
        let_let_chain_guard(num);
    }

    for &num in &[9, 10, 11, 12] {
        let_cond_chain_guard(num);
    }
}

So after generation four folders (for both pre-patch (current) and patch and both editions in each)

I just compared with this tool (this is diff analogue from unix) folder to folder

thanks. I had a look at the tests and they don't really exercise let chains well. So I have made a PR to adapt the existing let chains tests to match guards: Add match guard let chain drop order and scoping tests by est31 · Pull Request #140981 · rust-lang/rust · GitHub

That’s quite a thorough test!

Just to clarify — the tests were run without enabling rescoping on all editions, right? So if we decide to apply the same rescoping logic to all editions, then the warnings like:

  • "if let assigns a shorter lifetime since Edition 2024"
  • "this changes meaning in Rust 2024"

…would no longer be necessary, since the behavior would be consistent across editions? That would mean we’re aiming to unify the rescoping behavior across editions as well — right?

Yeah the tests were run without the edition specific rescoping. In other words, according to all snippets I see, if let guards behave as if rescoping existed on all editions already.

This is a bit surprising to me. Does that mean that the current implementation of if let guards already behaves as if rescoping applies to all editions, even though the actual patch for that hasn’t landed yet?

Or is it possible that the effect of rescoping was introduced in some earlier change that already affects all editions?

Because I ran tests for both edidtions without your fix that adapt if let rescope for all editions and all tests are passed for both edition