Skip to content
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

Stabilize let chains in the 2024 edition #132833

Open
wants to merge 5 commits into
base: master
Choose a base branch
from

Conversation

est31
Copy link
Member

@est31 est31 commented Nov 10, 2024

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 &&-chain let statements inside if and while is being stabilized, allowing intermixture with boolean expressions. The patterns inside the let sub-expressions can be irrefutable or refutable.

struct FnCall<'a> {
    fn_name: &'a str,
    args: Vec<i32>,
}

fn is_legal_ident(s: &str) -> bool {
    s.chars()
        .all(|c| ('a'..='z').contains(&c) || ('A'..='Z').contains(&c))
}

impl<'a> FnCall<'a> {
    fn parse(s: &'a str) -> Option<Self> {
        if let Some((fn_name, after_name)) = s.split_once("(")
            && !fn_name.is_empty()
            && is_legal_ident(fn_name)
            && let Some((args_str, "")) = after_name.rsplit_once(")")
        {
            let args = args_str
                .split(',')
                .map(|arg| arg.parse())
                .collect::<Result<Vec<_>, _>>();
            args.ok().map(|args| FnCall { fn_name, args })
        } else {
            None
        }
    }
    fn exec(&self) -> Option<i32> {
        let iter = self.args.iter().copied();
        match self.fn_name {
            "sum" => Some(iter.sum()),
            "max" => iter.max(),
            "min" => iter.min(),
            _ => None,
        }
    }
}

fn main() {
    println!("{:?}", FnCall::parse("sum(1,2,3)").unwrap().exec());
    println!("{:?}", FnCall::parse("max(4,5)").unwrap().exec());
}

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 async and await syntax. It required an edition boundary in order for async/await to become keywords, and the entire feature foots on those keywords.

In the instance of let chains, the issue is the drop order of if let chains. If we want if let chains to be compatible with if let, drop order makes it hard for us to generate correct MIR. It would be strange to have different behaviour for if let ... {} and if true && let ... {}. So it's better to stay consistent with if let.

In edition 2024, drop order changes have been introduced to make if let temporaries be lived more shortly. These changes also affected if let chains. These changes make sense even if you don't take the if let chains 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_chains feature (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

Adoption 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 entire let pat = expr operand.
parens.rs: if (let pat = expr) is not allowed in chains
ensure-that-let-else-does-not-interact-with-let-chains.rs: let...else doesn't support chaining.

Overlap with match guards

move-guard-if-let-chain.rs: test for the use moved value error working well in match guards. could maybe be extended with let chains that have more than one let
shadowing.rs: shadowing in if let guards works as expected
ast-validate-guards.rs: let chains in match guards require the match guards feature gate

Simple 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.rs
ast-lowering-does-not-wrap-let-chains.rs
issue-90722.rs
issue-92145.rs

Drop order/MIR scoping tests

issue-100276.rs: let expressions on RHS aren't terminating scopes
drop_order.rs: exhaustive temporary drop order test for various Rust constructs, including let chains
scope.rs: match guard scoping test
drop-scope.rs: another match guard scoping test, ensuring that temporaries in if-let guards live for the arm
drop_order_if_let_rescope.rs: if let rescoping on edition 2024, including chains
mir_let_chains_drop_order.rs: comprehensive drop order test for let chains, distinguishes editions 2021 and 2024.
issue-99938.rs, issue-99852.rs both bad MIR ICEs fixed by #102394

Linting

irrefutable-lets.rs: trailing and leading irrefutable let patterns get linted for, others don't. The lint is turned off for else if.
issue-121070-let-range.rs: regression test for false positive of the unused parens lint, precedence requires the ()s here

Parser: intentional restrictions

disallowed-positions.rs: let in expression context is rejected everywhere except at the top level
invalid-let-in-a-valid-let-context.rs: nested let is not allowed (let's are no legal expressions just because they are allowed in if and while).

Parser: recovery

issue-103381.rs: Graceful recovery of incorrect chaining of if and if let
semi-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 hints

Misc

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 chains

Tangential tests with #![feature(let_chains)]

if-let.rs: MC/DC coverage tests for let chains
logical_or_in_conditional.rs: not really about let chains, more about dropping/scoping behaviour of ||
stringify.rs: exhaustive test of the stringify macro
expanded-interpolation.rs, expanded-exhaustive.rs: Exhaustive test of -Zunpretty
diverges-not.rs: Never type, mostly tangential to let chains

Possible future work

  • There is proposals to allow if let Pat(bindings) = expr {} to be written as if expr is Pat(bindings) {} (RFC 3573). if let chains are a natural extension of the already existing if let syntax, and I'd argue orthogonal towards is syntax.
  • One could have similar chaining inside let ... else statements. There is no proposed RFC for this however, nor is it implemented on nightly.
  • Match guards have the if keyword as well, but on stable Rust, they don't support let. The functionality is available via an unstable feature (if_let_guard tracking issue). Stabilization of let chains affects this feature in so far as match guards containing let chains now only need the if_let_guard feature gate be present instead of also the let_chains feature (NOTE: this PR doesn't implement this simplification, it's left for future work).

Open questions / blockers

@est31 est31 added the F-let_chains `#![feature(let_chains)]` label Nov 10, 2024
@rustbot rustbot added the needs-triage This issue may need triage. Remove it if it has been sufficiently triaged. label Nov 10, 2024
@jieyouxu jieyouxu added T-lang Relevant to the language team, which will review and decide on the PR/issue. C-tracking-issue Category: An issue tracking the progress of sth. like the implementation of an RFC A-edition-2024 Area: The 2024 edition and removed needs-triage This issue may need triage. Remove it if it has been sufficiently triaged. labels Nov 10, 2024
@traviscross
Copy link
Contributor

traviscross commented Nov 10, 2024

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

@rustbot rustbot added I-style-nominated Nominated for discussion during a style team meeting. I-edition-nominated Nominated for discussion during an edition team meeting. labels Nov 10, 2024
@rustbot
Copy link
Collaborator

rustbot commented Nov 10, 2024

r? @fee1-dead

rustbot has assigned @fee1-dead.
They will have a look at your PR within the next two weeks and either review your PR or reassign to another reviewer.

Use r? to explicitly pick a reviewer

@rustbot rustbot added the S-waiting-on-review Status: Awaiting review from the assignee but also interested parties. label Nov 10, 2024
@est31 est31 removed the C-tracking-issue Category: An issue tracking the progress of sth. like the implementation of an RFC label Nov 10, 2024
@est31
Copy link
Member Author

est31 commented Nov 10, 2024

Process-wise, we normally do the FCP on the stabilization PR, and I think that'd make the most sense here.

@traviscross understood, I've converted it to a pull request using the gh cli. Thanks for cc'ing the relevant teams.

@traviscross
Copy link
Contributor

Beautiful, thanks. Let's nominate this for lang discussion too then.

@rustbot labels +I-lang-nominated

@rustbot rustbot added the I-lang-nominated Nominated for discussion during a lang team meeting. label Nov 10, 2024
@rust-log-analyzer

This comment has been minimized.

@fee1-dead fee1-dead self-assigned this Nov 11, 2024
@compiler-errors compiler-errors added the S-waiting-on-fcp Status: PR is in FCP and is awaiting for FCP to complete. label Nov 11, 2024
@compiler-errors compiler-errors removed their assignment Nov 11, 2024
@fee1-dead fee1-dead added S-waiting-on-author Status: This is awaiting some action (such as code changes or more information) from the author. and removed S-waiting-on-review Status: Awaiting review from the assignee but also interested parties. labels Nov 12, 2024
@traviscross
Copy link
Contributor

@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.

@rustbot rustbot removed the I-edition-nominated Nominated for discussion during an edition team meeting. label Nov 13, 2024
@est31 est31 force-pushed the stabilize_let_chains branch from aa24aa5 to d57626e Compare November 13, 2024 09:55
@est31 est31 force-pushed the stabilize_let_chains branch from 1689804 to 17f4621 Compare March 16, 2025 05:51
@rust-log-analyzer

This comment has been minimized.

@est31 est31 force-pushed the stabilize_let_chains branch from ba6be5f to 2ba5942 Compare March 17, 2025 01:45
@rust-log-analyzer

This comment has been minimized.

@fee1-dead
Copy link
Member

fee1-dead commented Apr 1, 2025

Has there been any precedent/writings elsewhere that new language features require style RFCs/modifications to the style guide before getting stabilized? I don't really think that that should block this, so I believe the resolve-open-items concern should be marked as resolved and this should go into fcp.

I'll take another look at the compiler implementation once fcp is completed.

@traviscross
Copy link
Contributor

It's in the nightly style procedure document from the style team, which they added here and FCPed here, and then on lang we FCPed acceptance of this blocker here.

@VorpalBlade
Copy link

VorpalBlade commented Apr 1, 2025

Given that nothing has happened for the style guide since 2023 regarding led chains if I'm reading this correctly it doesn't seem sensible to continue blocking on that. Is that really the up-to-date issue on this?

The style team should be asked to prioritise making a decision on this. In the 2024 survey, let chains is one of the top wanted unstable features (first if you look at "would improve my code", near the top if you look at "unblock use case").

@traviscross
Copy link
Contributor

The style team knows this is a priority.

@bors
Copy link
Collaborator

bors commented Apr 2, 2025

☔ The latest upstream changes (presumably #138478) made this pull request unmergeable. Please resolve the merge conflicts.

@calebcartwright
Copy link
Member

I've checked the box on style/formatting and included the link to the PR (#139456)

The work required of the style team on the matter, i.e. discussing and making the decision, has been done for quite a long time. I know there's some separate threads to discuss ways of potentially avoiding any style-related delays in the future, but I will share two thoughts now before I forget them:

  • The final exercise of updating the text in the style guide is work that can be done by anyone (PR does not have to be authored by a member of the 2-3 person style team), just like much of the other work involved in feature development and stabilization. Within the style team we should discuss how we could make it easier/more clear for others to contribute to the style guide, especially as it relates to new syntax and stabilization.
  • I don't know if this final style PR really needed to be a hard blocker at this point, especially if everything was fully ready to be shipped 3-4 weeks ago.

The big motivation for incorporating style into the stabilization process was to alleviate previous situations where new, stable syntax didn't have any style prescriptions and large nested chunks of code were often not being formatted at all. That made for a bad developer experience and could risk some developers not adopting those new constructs as a result.

However, that wouldn't have been the situation in this case, as the lengthy style discussions and feedback loops were long done, decisions were finalized, and rustfmt had already implemented them.

@traviscross
Copy link
Contributor

@rfcbot resolve resolve-open-items

OK. Thanks to @est31 and to @calebcartwright for knocking off all the items here. Time to start the last call.

@rfcbot rfcbot added the final-comment-period In the final comment period and will be merged soon unless new substantive objections are raised. label Apr 7, 2025
@rfcbot
Copy link
Collaborator

rfcbot commented Apr 7, 2025

🔔 This is now entering its final comment period, as per the review above. 🔔

@rfcbot rfcbot removed the proposed-final-comment-period Proposed to merge/close by relevant subteam, see T-<team> label. Will enter FCP once signed off. label Apr 7, 2025
Kobzol added a commit to Kobzol/rust that referenced this pull request Apr 7, 2025
…inal, r=joshtriplett

style guide: add let-chain rules

Reopens rust-lang#110568

refs rust-lang#53667 and I suppose rust-lang#132833 as well

This reflects the style rules that the style team had already agreed upon back in 2023, with the addition of literals in the lhs being permissible for single line formatting, and the removal of unnecessary language/example snippets around non-`&&` operators that was a small hiccup in the original PR.

It also reflects current formatting behavior implemented in rustfmt (though note that the adjustment to include literals has been implemented & merged, but is still pending a sync to nightly)
rust-timer added a commit to rust-lang-ci/rust that referenced this pull request Apr 7, 2025
Rollup merge of rust-lang#139456 - calebcartwright:style-let-chains-final, r=joshtriplett

style guide: add let-chain rules

Reopens rust-lang#110568

refs rust-lang#53667 and I suppose rust-lang#132833 as well

This reflects the style rules that the style team had already agreed upon back in 2023, with the addition of literals in the lhs being permissible for single line formatting, and the removal of unnecessary language/example snippets around non-`&&` operators that was a small hiccup in the original PR.

It also reflects current formatting behavior implemented in rustfmt (though note that the adjustment to include literals has been implemented & merged, but is still pending a sync to nightly)
@camsteffen
Copy link
Contributor

The work required of the style team on the matter, i.e. discussing and making the decision, has been done for quite a long time...The final exercise of updating the text in the style guide is work that can be done by anyone

@calebcartwright I've been trying to follow along and I don't know that it was ever clearly communicated to the community that the style team had made a final decision, and that the next step was for someone to open a PR. Maybe I missed something? Also it would have been nice to receive an update in the discussion thread (I linked above) with some rationale and perhaps an opportunity for folks to have final comments. To be clear, I'm not advocating for any further delay, but maybe better transparency in the future.

est31 added 4 commits April 7, 2025 18:08
The edition gate is a bit stricter than the drop behaviour,
which is fine. The cases we want to avoid are the opposite:
not gated but 2021 drop behaviour.
@est31 est31 force-pushed the stabilize_let_chains branch from bfaf497 to 77c404c Compare April 7, 2025 16:17
@est31
Copy link
Member Author

est31 commented Apr 7, 2025

Thanks @calebcartwright for filing the style guide pull request and guiding the PR towards merging. It's really great news that this feature is (again) doing the last steps towards stabilization.

I have rebased the pull request. @fee1-dead if you want you can already take a look now.

@camsteffen

I've been trying to follow along and I don't know that it was ever clearly communicated to the community that the style team had made a final decision, and that the next step was for someone to open a PR. Maybe I missed something?

There has been a msg in the zulip thread here in January, so I've been aware of that since that point of time. That thread had been in the "Open questions / blockers" section of the pull request description since a long time.

In February I've listed the open blockers and also asked for someone to file a PR. I should probably have responded to your msg a week later on March 7 about formatting, probably my msg above hasn't been clear enough.

In the end we were one month hard blocked on formatting, which isn't that much in the grand scheme of things (note that this PR is open for 6 months at this point). People have been busy with the edition 2024 release earlier this year which had priority also for the style team. Many of us are free time contributors who don't have this as a day job, me included.

@rust-log-analyzer

This comment has been minimized.

@est31 est31 force-pushed the stabilize_let_chains branch from 77c404c to c373f03 Compare April 7, 2025 16:57
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
A-edition-2024 Area: The 2024 edition disposition-merge This issue / PR is in PFCP or FCP with a disposition to merge it. F-let_chains `#![feature(let_chains)]` final-comment-period In the final comment period and will be merged soon unless new substantive objections are raised. I-lang-nominated Nominated for discussion during a lang team meeting. I-style-nominated Nominated for discussion during a style team meeting. S-waiting-on-author Status: This is awaiting some action (such as code changes or more information) from the author. S-waiting-on-fcp Status: PR is in FCP and is awaiting for FCP to complete. T-lang Relevant to the language team, which will review and decide on the PR/issue.
Projects
None yet
Development

Successfully merging this pull request may close these issues.

Tracking issue for eRFC 2497, "if- and while-let-chains, take 2"