-
Notifications
You must be signed in to change notification settings - Fork 13.9k
Stabilize let chains in the 2024 edition #132833
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
|
Process-wise, we normally do the FCP on the stabilization PR, and I think that'd make the most sense here. Let us know if you need us on lang to weigh in on anything specifically, e.g. any of the open questions, to make such a stabilization PR possible. cc @rust-lang/lang for visibility. And cc @rust-lang/style given the open item on the style guide. @rustbot labels +I-style-nominated Putting on the edition hat, since this would be an edition item in some sense, we should talk about this in our next edition call. @rustbot labels +I-edition-nominated |
|
r? @fee1-dead rustbot has assigned @fee1-dead. Use |
@traviscross understood, I've converted it to a pull request using the |
|
Beautiful, thanks. Let's nominate this for lang discussion too then. @rustbot labels +I-lang-nominated |
This comment has been minimized.
This comment has been minimized.
79e1519 to
ee7488a
Compare
|
@rustbot labels -I-edition-nominated We talked this one through in the edition call. Since there's no breakage or migration here, we're happy for this one to land in Rust 2024 either ahead of or after the release of Rust 2024 itself as long as there is an edition guide chapter for it. |
aa24aa5 to
d57626e
Compare
Remove #![feature(let_chains)] from libcore PR #132833 has stabilized the let_chains feature. This PR removes the last occurrence from the library. Split out of #140966 as it caused breakage. Now we have a patch to the linux tree that fixes the build, so we update the linux tree to it. cc Rust-for-Linux/linux#1163 cc #140722
Remove #![feature(let_chains)] from libcore PR rust-lang/rust#132833 has stabilized the let_chains feature. This PR removes the last occurrence from the library. Split out of #140966 as it caused breakage. Now we have a patch to the linux tree that fixes the build, so we update the linux tree to it. cc Rust-for-Linux/linux#1163 cc rust-lang/rust#140722
Remove #![feature(let_chains)] from libcore PR rust-lang#132833 has stabilized the let_chains feature. This PR removes the last occurrence from the library. Split out of rust-lang#140966 as it caused breakage. Now we have a patch to the linux tree that fixes the build, so we update the linux tree to it. cc Rust-for-Linux/linux#1163 cc rust-lang#140722
because `let_chain` feature was stabilized on April and is available without the feature gate in Rust 2024 now. rust-lang/rust#132833
Pkgsrc changes: * Adjust patches to adapt to upstream changes and new versions. * associated checksums Upstream changes relative to 1.87.0: Version 1.88.0 (2025-06-26) ========================== Language -------- - [Stabilize `#![feature(let_chains)]` in the 2024 edition.] (rust-lang/rust#132833) This feature allows `&&`-chaining `let` statements inside `if` and `while`, allowing intermixture with boolean expressions. The patterns inside the `let` sub-expressions can be irrefutable or refutable. - [Stabilize `#![feature(naked_functions)]`.] (rust-lang/rust#134213) Naked functions allow writing functions with no compiler-generated epilogue and prologue, allowing full control over the generated assembly for a particular function. - [Stabilize `#![feature(cfg_boolean_literals)]`.] (rust-lang/rust#138632) This allows using boolean literals as `cfg` predicates, e.g. `#[cfg(true)]` and `#[cfg(false)]`. - [Fully de-stabilize the `#[bench]` attribute] (rust-lang/rust#134273). Usage of `#[bench]` without `#![feature(custom_test_frameworks)]` already triggered a deny-by-default future-incompatibility lint since Rust 1.77, but will now become a hard error. - [Add warn-by-default `dangerous_implicit_autorefs` lint against implicit autoref of raw pointer dereference.] (rust-lang/rust#123239) The lint [will be bumped to deny-by-default] (rust-lang/rust#141661) in the next version of Rust. - [Add `invalid_null_arguments` lint to prevent invalid usage of null pointers.] (rust-lang/rust#119220) This lint is uplifted from `clippy::invalid_null_ptr_usage`. - [Change trait impl candidate preference for builtin impls and trivial where-clauses.] (rust-lang/rust#138176) - [Check types of generic const parameter defaults] (rust-lang/rust#139646) Compiler -------- - [Stabilize `-Cdwarf-version` for selecting the version of DWARF debug information to generate.] (rust-lang/rust#136926) Platform Support ---------------- - [Demote `i686-pc-windows-gnu` to Tier 2.] (https://blog.rust-lang.org/2025/05/26/demoting-i686-pc-windows-gnu/) Refer to Rust's [platform support page][platform-support-doc] for more information on Rust's tiered platform support. [platform-support-doc]: https://doc.rust-lang.org/rustc/platform-support.html Libraries --------- - [Remove backticks from `#[should_panic]` test failure message.] (rust-lang/rust#136160) - [Guarantee that `[T; N]::from_fn` is generated in order of increasing indices.] (rust-lang/rust#139099), for those passing it a stateful closure. - [The libtest flag `--nocapture` is deprecated in favor of the more consistent `--no-capture` flag.] (rust-lang/rust#139224) - [Guarantee that `{float}::NAN` is a quiet NaN.] (rust-lang/rust#139483) Stabilized APIs --------------- - [`Cell::update`] (https://doc.rust-lang.org/stable/std/cell/struct.Cell.html#method.update) - [`impl Default for *const T`] (https://doc.rust-lang.org/nightly/std/primitive.pointer.html#impl-Default-for-*const+T) - [`impl Default for *mut T`] (https://doc.rust-lang.org/nightly/std/primitive.pointer.html#impl-Default-for-*mut+T) - [`HashMap::extract_if`] (https://doc.rust-lang.org/stable/std/collections/struct.HashMap.html#method.extract_if) - [`HashSet::extract_if`] (https://doc.rust-lang.org/stable/std/collections/struct.HashSet.html#method.extract_if) - [`proc_macro::Span::line`] (https://doc.rust-lang.org/stable/proc_macro/struct.Span.html#method.line) - [`proc_macro::Span::column`] (https://doc.rust-lang.org/stable/proc_macro/struct.Span.html#method.column) - [`proc_macro::Span::start`] (https://doc.rust-lang.org/stable/proc_macro/struct.Span.html#method.start) - [`proc_macro::Span::end`] (https://doc.rust-lang.org/stable/proc_macro/struct.Span.html#method.end) - [`proc_macro::Span::file`] (https://doc.rust-lang.org/stable/proc_macro/struct.Span.html#method.file) - [`proc_macro::Span::local_file`] (https://doc.rust-lang.org/stable/proc_macro/struct.Span.html#method.local_file) These previously stable APIs are now stable in const contexts: - [`NonNull<T>::replace`] (https://doc.rust-lang.org/stable/std/ptr/struct.NonNull.html#method.replace) - [`<*mut T>::replace`] (https://doc.rust-lang.org/stable/std/primitive.pointer.html#method.replace) - [`std::ptr::swap_nonoverlapping`] (rust-lang/rust#137280) - [`Cell::{replace, get, get_mut, from_mut, as_slice_of_cells}`] (rust-lang/rust#137928) Cargo ----- - [Stabilize automatic garbage collection.] (rust-lang/cargo#14287) - [use `zlib-rs` for gzip compression in rust code] (rust-lang/cargo#15417) Rustdoc ----- - [Doctests can be ignored based on target names using `ignore-*` attributes.] (rust-lang/rust#137096) - [Stabilize the `--test-runtool` and `--test-runtool-arg` CLI options to specify a program (like qemu) and its arguments to run a doctest.] (rust-lang/rust#137096) Compatibility Notes ------------------- - [Finish changing the internal representation of pasted tokens] (rust-lang/rust#124141). Certain invalid declarative macros that were previously accepted in obscure circumstances are now correctly rejected by the compiler. Use of a `tt` fragment specifier can often fix these macros. - [Fully de-stabilize the `#[bench]` attribute] (rust-lang/rust#134273). Usage of `#[bench]` without `#![feature(custom_test_frameworks)]` already triggered a deny-by-default future-incompatibility lint since Rust 1.77, but will now become a hard error. - [Fix borrow checking some always-true patterns.] (rust-lang/rust#139042) The borrow checker was overly permissive in some cases, allowing programs that shouldn't have compiled. - [Update the minimum external LLVM to 19.] (rust-lang/rust#139275) - [Make it a hard error to use a vector type with a non-Rust ABI without enabling the required target feature.] (rust-lang/rust#139309)
Pretty crazy that it just came out 3 days ago, because I am in fact
using a piece of syntax that does not compile with Rust v1.87: a `if
let` alongside an `if` statement.
if !opts.raw && let Some(grep) = &opts.grep
This is "unstable" in previous versions of Rust and will not compile, so
we _must_ use Rust v1.88.
[1]: rust-lang/rust#132833
* Make `modules.re` methods accept an already compiled pattern COPYBARA PUBLIC PR: #601 Fixes part of #581 ("Compilation failures: The user's example still produces empty files in Fusion"). Methods in `modules.re` (such as `search` and `match`) can take both a string for the initial pattern argument as well an already compiled expression. Before this change only the string variant was correctly supported: ```jinja2 {%- set pattern = '.*' -%} {%- set result = re.search(pattern, 'xyz') -%} ``` This change makes compiled patterns work as well, restoring compatibility with [pythons re](https://docs.python.org/3/library/re.html) / dbt-core / jinja2: ```jinja2 {%- set pattern = re.compile('.*') -%} {%- set result = re.search(pattern, 'xyz') -%} ``` The rust edition in the `minijinja-contrib` crate was bumped to `2024` to allow the [let chain](rust-lang/rust#132833) used here. Bumping the edition means that `cargo fmt` formats differently - the (otherwise unrelated) formatting changes are done in the second commit in this PR, while the first commit contains the actual change. GitOrigin-RevId: 99d438c * Make `modules.re` methods accept an already compiled pattern COPYBARA PUBLIC PR: #601 Fixes part of #581 ("Compilation failures: The user's example still produces empty files in Fusion"). Methods in `modules.re` (such as `search` and `match`) can take both a string for the initial pattern argument as well an already compiled expression. Before this change only the string variant was correctly supported: ```jinja2 {%- set pattern = '.*' -%} {%- set result = re.search(pattern, 'xyz') -%} ``` This change makes compiled patterns work as well, restoring compatibility with [pythons re](https://docs.python.org/3/library/re.html) / dbt-core / jinja2: ```jinja2 {%- set pattern = re.compile('.*') -%} {%- set result = re.search(pattern, 'xyz') -%} ``` The rust edition in the `minijinja-contrib` crate was bumped to `2024` to allow the [let chain](rust-lang/rust#132833) used here. Bumping the edition means that `cargo fmt` formats differently - the (otherwise unrelated) formatting changes are done in the second commit in this PR, while the first commit contains the actual change. GitOrigin-RevId: 9dd9420 * Cargo fmt * remove old changelog * Change code to avoid clippy complaint about unstable let * rename conflicting test name * update test output * Improve sdf-make-sql-functions build command Let cargo consider only the actually necessary dependencies. When `-p` is not present, cargo will do dependency feature unification across all crates first. * Remove table qualifiers in UNION plan After UNION (or other set operation), the names are no longer qualified. Keeping them qualified is incorrect (allows referencing which would be rejected by CDW) and causes planning failures in DataFusion 48. * Make `modules.re` methods accept an already compiled pattern COPYBARA PUBLIC PR: #601 Fixes part of #581 ("Compilation failures: The user's example still produces empty files in Fusion"). Methods in `modules.re` (such as `search` and `match`) can take both a string for the initial pattern argument as well an already compiled expression. Before this change only the string variant was correctly supported: ```jinja2 {%- set pattern = '.*' -%} {%- set result = re.search(pattern, 'xyz') -%} ``` This change makes compiled patterns work as well, restoring compatibility with [pythons re](https://docs.python.org/3/library/re.html) / dbt-core / jinja2: ```jinja2 {%- set pattern = re.compile('.*') -%} {%- set result = re.search(pattern, 'xyz') -%} ``` The rust edition in the `minijinja-contrib` crate was bumped to `2024` to allow the [let chain](rust-lang/rust#132833) used here. Bumping the edition means that `cargo fmt` formats differently - the (otherwise unrelated) formatting changes are done in the second commit in this PR, while the first commit contains the actual change. GitOrigin-RevId: 99d438c * Cargo fmt * fix bad merge * Update output for flaky test test_regression_tests_internal_analytics_build_selector_cloud_users_1 * Remove old changelog --------- Co-authored-by: Fredrik Fornwall <[email protected]> Co-authored-by: Gerda Shank <[email protected]> Co-authored-by: Gerda Shank <[email protected]> Co-authored-by: Piotr Findeisen <[email protected]> GitOrigin-RevId: dafcf71594623b1ce94e126eb1dd6f9a6896656a
Summary: let_chains were stabilized in 1.88.0 for edition 2024 and removed in 1.90.0 rust-lang/rust#132833 rust-lang/rust#143214 Reviewed By: dtolnay Differential Revision: D83221093
Summary: let_chains were stabilized in 1.88.0 for edition 2024 and removed in 1.90.0 rust-lang/rust#132833 rust-lang/rust#143214 Reviewed By: dtolnay Differential Revision: D83221093
Summary: let_chains were stabilized in 1.88.0 for edition 2024 and removed in 1.90.0 rust-lang/rust#132833 rust-lang/rust#143214 Reviewed By: dtolnay Differential Revision: D83221093
Summary: X-link: meta-pytorch/monarch#1388 let_chains were stabilized in 1.88.0 for edition 2024 and removed in 1.90.0 rust-lang/rust#132833 rust-lang/rust#143214 Reviewed By: dtolnay Differential Revision: D83221093 fbshipit-source-id: 6fb40aa7e1c282f453394db5b7f0dab1282c2e35
Summary: X-link: meta-pytorch/monarch#1388 let_chains were stabilized in 1.88.0 for edition 2024 and removed in 1.90.0 rust-lang/rust#132833 rust-lang/rust#143214 Reviewed By: dtolnay Differential Revision: D83221093 fbshipit-source-id: 6fb40aa7e1c282f453394db5b7f0dab1282c2e35
Summary: Pull Request resolved: #1388 let_chains were stabilized in 1.88.0 for edition 2024 and removed in 1.90.0 rust-lang/rust#132833 rust-lang/rust#143214 Reviewed By: dtolnay Differential Revision: D83221093 fbshipit-source-id: 6fb40aa7e1c282f453394db5b7f0dab1282c2e35
Summary: X-link: meta-pytorch/monarch#1388 let_chains were stabilized in 1.88.0 for edition 2024 and removed in 1.90.0 rust-lang/rust#132833 rust-lang/rust#143214 Reviewed By: dtolnay Differential Revision: D83221093 fbshipit-source-id: 6fb40aa7e1c282f453394db5b7f0dab1282c2e35
Summary: X-link: meta-pytorch/monarch#1388 let_chains were stabilized in 1.88.0 for edition 2024 and removed in 1.90.0 rust-lang/rust#132833 rust-lang/rust#143214 Test Plan: ci Reviewed By: dtolnay Differential Revision: D83221093 fbshipit-source-id: 6fb40aa7e1c282f453394db5b7f0dab1282c2e35
Stabilization report
This proposes the stabilization of
let_chains(tracking issue, RFC 2497) in the 2024 edition of Rust.What is being stabilized
The ability to
&&-chainletstatements insideifandwhileis being stabilized, allowing intermixture with boolean expressions. The patterns inside theletsub-expressions can be irrefutable or refutable.The feature will only be stabilized for the 2024 edition and future editions. Users of past editions will get an error with a hint to update the edition.
closes #53667
Why 2024 edition?
Rust generally tries to ship new features to all editions. So even the oldest editions receive the newest features. However, sometimes a feature requires a breaking change so much that offering the feature without the breaking change makes no sense. This occurs rarely, but has happened in the 2018 edition already with
asyncandawaitsyntax. It required an edition boundary in order forasync/awaitto become keywords, and the entire feature foots on those keywords.In the instance of let chains, the issue is the drop order of
if letchains. If we wantif letchains to be compatible withif let, drop order makes it hard for us to generate correct MIR. It would be strange to have different behaviour forif let ... {}andif true && let ... {}. So it's better to stay consistent withif let.In edition 2024, drop order changes have been introduced to make
if lettemporaries be lived more shortly. These changes also affectedif letchains. These changes make sense even if you don't take theif letchains MIR generation problem into account. But if we want to use them as the solution to the MIR generation problem, we need to restrict let chains to edition 2024 and beyond: for let chains, it's not just a change towards more sensible behaviour, but one required for correct function.Introduction considerations
As edition 2024 is very new, this stabilization PR only makes it possible to use let chains on 2024 without that feature gate, it doesn't mark that feature gate as stable/removed. I would propose to continue offering the
let_chainsfeature (behind a feature gate) for a limited time (maybe 3 months after stabilization?) on older editions to allow nightly users to adopt edition 2024 at their own pace. After that, the feature gate shall be marked as stabilized, not removed, and replaced by an error on editions 2021 and below.Implementation history
let_chainsin Rust 1.64 #94927let_elsedoes not interact withlet_chains#94974let_chains] Forbidletinside parentheses #95008lets in certain places #97295let_chainsblocker #98633;for;within let-chains #117743{in let-chains #117770letor==on typo'd let-chain #118191irrefutable_let_patternson leading patterns ifelse iflet-chains #129394let_chainsreferences reference#1179Adoption history
In the compiler
Outside of the compiler
Tests
Intentional restrictions
partially-macro-expanded.rs,macro-expanded.rs: it is possible to use macros to expand to both the pattern and the expression inside a let chain, but not to the entirelet pat = exproperand.parens.rs:if (let pat = expr)is not allowed in chainsensure-that-let-else-does-not-interact-with-let-chains.rs:let...elsedoesn't support chaining.Overlap with match guards
move-guard-if-let-chain.rs: test for theuse moved valueerror working well in match guards. could maybe be extended with let chains that have more than oneletshadowing.rs: shadowing in if let guards works as expectedast-validate-guards.rs: let chains in match guards require the match guards feature gateSimple cases from the early days
PR #88642 has added some tests with very simple usages of
let else, mostly as regression tests to early bugs.then-else-blocks.rsast-lowering-does-not-wrap-let-chains.rsissue-90722.rsissue-92145.rsDrop order/MIR scoping tests
issue-100276.rs: let expressions on RHS aren't terminating scopesdrop_order.rs: exhaustive temporary drop order test for various Rust constructs, including let chainsscope.rs: match guard scoping testdrop-scope.rs: another match guard scoping test, ensuring that temporaries in if-let guards live for the armdrop_order_if_let_rescope.rs: if let rescoping on edition 2024, including chainsmir_let_chains_drop_order.rs: comprehensive drop order test for let chains, distinguishes editions 2021 and 2024.issue-99938.rs,issue-99852.rsboth bad MIR ICEs fixed by #102394Linting
irrefutable-lets.rs: trailing and leading irrefutable let patterns get linted for, others don't. The lint is turned off forelse if.issue-121070-let-range.rs: regression test for false positive of the unused parens lint, precedence requires the()s hereParser: intentional restrictions
disallowed-positions.rs:letin expression context is rejected everywhere except at the top levelinvalid-let-in-a-valid-let-context.rs: nestedletis not allowed (let's are no legal expressions just because they are allowed inifandwhile).Parser: recovery
issue-103381.rs: Graceful recovery of incorrect chaining ofifandif letsemi-in-let-chain.rs: Ensure that stray;s in let chains give nice errors (if_chain!users might be accustomed to;s)deli-ident-issue-1.rs,brace-in-let-chain.rs: Ensure that stray unclosed{s in let chains give nice errors and hintsMisc
conflicting_bindings.rs: the conflicting bindings check also works in let chains. Personally, I'd extend it to chains with multiple let's as well.let-chains-attr.rs: attributes work on let chainsTangential tests with
#![feature(let_chains)]if-let.rs: MC/DC coverage tests for let chainslogical_or_in_conditional.rs: not really about let chains, more about dropping/scoping behaviour of||stringify.rs: exhaustive test of thestringifymacroexpanded-interpolation.rs,expanded-exhaustive.rs: Exhaustive test of-Zunprettydiverges-not.rs: Never type, mostly tangential to let chainsPossible future work
if let Pat(bindings) = expr {}to be written asif expr is Pat(bindings) {}(RFC 3573).if letchains are a natural extension of the already existingif letsyntax, and I'd argue orthogonal towardsissyntax.let-chains andisare not mutually exclusive lang-team#297let ... elsestatements. There is no proposed RFC for this however, nor is it implemented on nightly.ifkeyword as well, but on stable Rust, they don't supportlet. The functionality is available via an unstable feature (if_let_guardtracking issue). Stabilization of let chains affects this feature in so far as match guards containing let chains now only need theif_let_guardfeature gate be present instead of also thelet_chainsfeature (NOTE: this PR doesn't implement this simplification, it's left for future work).Open questions / blockers
let(I don't think this is a blocker): #117977move-guard-if-let-chain.rsandconflicting_bindings.rsto have chains with multiple let's: done in 133093let_else. I think we can live withlet pat = exprnot evaluating asexprfor macro_rules macros, especially given thatlet pat = expris not a legal expression anywhere except insideifandwhile.let_chainsagain reference#1740