Conversation
|
r? @jackh726 (rust-highfive has picked a reviewer for you, use r? to override) |
This comment has been minimized.
This comment has been minimized.
9c1b8d2 to
68d46b6
Compare
This comment has been minimized.
This comment has been minimized.
68d46b6 to
f0a8446
Compare
|
This looks good to me; I'll start a T-lang FCP. |
|
Shall we stabilize @rfcbot merge |
|
Team member @joshtriplett has proposed to merge this. The next step is review by the rest of the tagged team members: Concerns:
Once a majority of reviewers approve (and at most 2 approvals are outstanding), this will enter its final comment period. If you spot a major issue that hasn't been raised at any point in this process, please speak up! See this document for info about what commands tagged team members can give me. |
This comment has been minimized.
This comment has been minimized.
|
@rfcbot concern not-while-rustfmt-breaks-on-it I remembered it not formatting last I tried using it in rustc, and sure enough it still seems to fail when I try it in playground: https://play.rust-lang.org/?version=nightly&mode=debug&edition=2021&gist=350415c3adb74101bbdc002031976b70 (There's enough people using rustfmt in CI that I think adding formatting support for it after stabilization would be impolite.) EDIT: "breaks" is not the word I should have used here. I meant "while rustfmt is unable to normalize formatting for the construct", since that's what I'd expect rustfmt to do for all stable syntax. |
It's not that rustfmt is "breaking" on it, but the formatting rules aren't established yet so rustfmt is just leaving whatever you wrote in place. You have trailing whitespace in your snippet, and rustfmt is just acknowledging the presence of what was originally written; it's not modifying what was already there/inserting trailing whitespace itself. |
I think that's my complaint. I think it's clear that we'd want rustfmt to format it, but based on https://rust-lang.github.io/rfcs/2437-rustfmt-stability.html it'd need to be a new version to add formatting support for it if we did so after stabilization. And I don't think that dance is worth it; it should just have formatting support in the release that stabilizes it. |
f0a8446 to
70a6fb4
Compare
That's not the case actually. rustfmt has always had leeway to make formatting changes for "new" syntax (we have to) until such time as the formatting has actually been stabilized. We try very hard to only do this once, which is why the "first do no harm" pattern followed for syntax that's new to rustfmt. I've never seen a case where stabilization of a feature was held up on rustfmt, and doing so would be a big mistake IMO. Throughout my time working on rustfmt it's often been an after thought where we weren't even aware of syntax changes until long after they'd been in use, and there's plenty of cases where rustfmt exhibits this same behavior on long-standing syntax (e.g. try adding comments between trait bounds). I'd think that blocking feature stabilization on style guide + formatting stabilization would either greatly elongate the lead time for feature availability on stable, or create large amounts of friction on the rustfmt side between expediency (not wanting to block) and formatting stability + quality/correctness. Also, and I say this as someone that spends a large chunk of my free time trying to maintain and improve rustfmt 😄, there's a non-zero subset of the Rust population that dislikes rustfmt and doesn't use it whatsoever. If I were one of those folks I think it would be extremely frustrating to not have access to a language feature on stable simply because of an optional tool I don't leverage. |
This comment has been minimized.
This comment has been minimized.
|
No objections since it's been being reviewed for far longer than 10 days. |
|
@bors r+ |
|
Maybe we can give it some priority if we want it to be merged before the branching. |
|
@slanterns I don't think we should get in the habit of skipping the queue; if it makes it it makes it, if not it'll make the next one. |
|
The final comment period, with a disposition to merge, as per the review above, is now complete. As the automated representative of the governance process, I would like to thank the author for their work and everyone else who contributed. This will be merged soon. |
|
Looks like this failed in a rollup. |
|
Yeah, seems the problems from earlier are plaguing us again: #101910 (comment) , which is weird as I've thought that #98147 fixed the problem. Apparently doc-tests of the rustc_macros crate are affected now. I guess those don't get the right flags passed, but need to investigate how exactly we are hitting the bug. |
|
I can reproduce it locally with |
|
I've filed #101921 to fix the issue. I've locally applied that PR to this one, the issue is resolved. |
|
@est31 Big thanks for carrying this over the finish line!! |
|
🎉 the stabilization PR has been merged 🎉 Getting let else into the language was very much a team effort, and I would like to thank everyone who was involved in their introduction and stabilization. In particular I would like to thank: Authors of the RFCs 1303 and 3137: PR authors for the implementation in the compiler: @camsteffen (lowering, tests) @compiler-errors (diagnostics, ICE fixes) @cormacrelf (initial implementation, lowering, tests) @dingxiangfei2009 (lowering, tests) @est31 (stabilization, diagnostics, tests) @JohnTitor (ICE fixes) Reviewers of those PRs: @cjgillot @petrochenkov @nagisa @matthewjasper @oli-obk @Mark-Simulacrum @pnkfelix @joshtriplett @jackh726 Everyone who tested out let-else, filed issues/bug reports, provided guidance and feedback in the RFCs, PRs and issues, including team members who approved FCPs. |

🎉 Stabilizes the
let elsefeature, added by RFC 3137. 🎉Reference PR: rust-lang/reference#1156
closes #87335 (
let elsetracking issue)FCP: #93628 (comment)
Stabilization report
Summary
The feature allows refutable patterns in
letstatements if the expression isfollowed by a diverging
else:Differences from the RFC / Desugaring
Outside of desugaring I'm not aware of any differences between the implementation and the RFC. The chosen desugaring has been changed from the RFC's original. You can read a detailed discussion of the implementation history of it in @cormacrelf 's summary in this thread, as well as the followup. Since that followup, further changes have happened to the desugaring, in #98574, #99518, #99954. The later changes were mostly about the drop order: On match, temporaries drop in the same order as they would for a
letdeclaration. On mismatch, temporaries drop before theelseblock.Test cases
In chronological order as they were merged.
Added by df9a2e0 (#87688):
ui/pattern/usefulness/top-level-alternation.rsto ensure the unreachable pattern lint visits patterns insidelet else.Added by 5b95df4 (#87688):
ui/let-else/let-else-bool-binop-init.rsto ensure that no lazy boolean expressions (using&&or||) are allowed in the expression, as the RFC mandates.ui/let-else/let-else-brace-before-else.rsto ensure that no}directly preceding theelseis allowed in the expression, as the RFC mandates.ui/let-else/let-else-check.rsto ensure that#[allow(...)]attributes added to the entireletstatement apply for theelseblock.ui/let-else/let-else-irrefutable.rsto ensure that theirrefutable_let_patternslint fires.ui/let-else/let-else-missing-semicolon.rsto ensure the presence of semicolons at the end of theletstatement.ui/let-else/let-else-non-diverging.rsto ensure theelseblock diverges.ui/let-else/let-else-run-pass.rsto ensure the feature works in some simple test case settings.ui/let-else/let-else-scope.rsto ensure the bindings created by the outerletexpression are not available in theelseblock of it.Added by bf7c32a (#89965):
ui/let-else/issue-89960.rsas a regression test for the ICE-on-error bug Erroneous 'ref mut' in let-else binding causes ICE #89960 . Later in 102b912 this got removed in favour of more comprehensive tests.Added by 8565419 (#89974):
ui/let-else/let-else-if.rsto test for the improved error message that points out thatlet else ifis not possible.Added by 9b45713:
ui/let-else/let-else-allow-unused.rsas a regression test for let-else: linting forunusedbindings is not handled correctly #89807, to ensure that#[allow(...)]attributes added to the entireletstatement apply for bindings created by thelet elsepattern.Added by 61bcd8d (#89841):
ui/let-else/let-else-non-copy.rsto ensure that a copy is performed out of non-copy wrapper types. This mirrorsif letbehaviour. The test case bases on rustc internal changes originally meant for Adopt let_else across the compiler #89933 but then removed from the PR due to the error prior to the improvements of Implement let-else type annotations natively #89841.ui/let-else/let-else-source-expr-nomove-pass.rsto ensure that while there is a move of the binding in the successful case, theelsecase can still access the non-matching value. This mirrorsif letbehaviour.Added by 102b912 (#89841):
ui/let-else/let-else-ref-bindings.rsandui/let-else/let-else-ref-bindings-pass.rsto checkrefandref mutkeywords in the pattern work correctly and error when needed.Added by 2715c5f (#89841):
rfc2005test suite.Added by fec8a50 (#89841):
ui/let-else/let-else-deref-coercion-annotated.rsandui/let-else/let-else-deref-coercion.rsto check deref coercions.Added since this stabilization report was originally written (2022-02-09)
Added by 76ea566 (#94211):
ui/let-else/let-else-destructuring.rsto give a nice error message if an user tries to do an assignment with a (possibly refutable) pattern and anelseblock, like asked for in destructuring assignment and let else #93995.Added by e7730dc (#94208):
ui/let-else/let-else-allow-in-expr.rsto test whether#[allow(unused_variables)]works in the expr, as well as its non presence, as well as putting it on the entirelet elseaffects the expr, too. This was adding a missing test as pointed out by the stabilization report.ui/let-else/let-else-allow-unused.rsandui/let-else/let-else-check.rsto ensure that non-presence of#[allow(unused)]does issue the unused lint. This was adding a missing test case as pointed out by the stabilization report.Added by 5bd7106 (#94208):
ui/let-else/let-else-slicing-error.rs, a regression test for Wrong suggestion for slice patterns when using let-else statement #92069, which got fixed without addition of a regression test. This resolves a missing test as pointed out by the stabilization report.Added by 5374688 (#98574):
src/test/ui/async-await/async-await-let-else.rsto test the interaction of async/await withlet elseAdded by 6c529de (#98574):
src/test/ui/let-else/let-else-temporary-lifetime.rsas a (partial) regression test for Let-else does not drop temporaries at the end of the statement #98672Added by 9b56640 (#99518):
src/test/ui/let-else/let-else-temp-borrowck.rsas a regression test forlet_elsereturns in surprising borrowck errors with impl trait #93951src/test/ui/let-else/let-else-temporary-lifetime.rsto include a partial regression test for Let-else does not drop temporaries at the end of the statement #98672 (especially regardingelsedrop order)Added by baf9a7c (#99518):
src/test/ui/let-else/let-else-temporary-lifetime.rsto include a partial regression test forlet_elsereturns in surprising borrowck errors with impl trait #93951, similar tolet-else-temp-borrowck.rsAdded by 60be2de (#99518):
src/test/ui/let-else/let-else-temporary-lifetime.rsto include a program that can now be compiled thanks to borrow checker implications of Let-else: break out scopes when a let-else pattern fails to match #99518Added by 47a7a91 (#100132):
src/test/ui/let-else/issue-100103.rs, as a regression test for ICE trying to useErr(1)?withlet_elsein atryblock #100103, to ensure that there is no ICE when doingErr(...)?inside else blocks.Added by e3c5bd6 (#100443):
src/test/ui/let-else/let-else-then-diverge.rs, to verify that there is no unreachable code error with the current desugaring.Added by 9818526 (#100443):
src/test/ui/let-else/issue-94176.rs, to make sure that a correct span is emitted for a missing trailing expression error. Regression test for Missing trailing expression in block withlet elseyields incorrectly spanned error message #94176.Added by e182d12 (#100434):
let else(this bug surfaced in many different ways)Added by e262856 (#99954):
src/test/ui/let-else/let-else-temporary-lifetime.rsextended to contain & borrows as well, as this was identified as an earlier issue with the desugaring: Let-else does not drop temporaries at the end of the statement #98672 (comment)Added by 2d8460e (#99291):
src/test/ui/let-else/let-else-drop-order.rsa matrix based test for various drop order behaviour oflet else. Especially, it verifies equality ofletandlet elsedrop orders, resolving a stabilization blocker.Added by 1b87ce0 (#101410):
src/test/ui/let-else/let-else-temporary-lifetime.rsto add the-Zvalidate-mirflag, as a regression test for ICE: broken mir with let-else, -Zvalidate-mir #99228Added by af591eb (#101410):
src/test/ui/let-else/issue-99975.rsas a regression test for the ICE Internal Compiler Error: Broken MIR in Item(...) Withlet_elseUsage #99975.Added by this PR:
ui/let-else/let-else.rs, a simple run-pass check, similar toui/let-else/let-else-run-pass.rs.Things not currently tested
The→ test added by e7730dc#[allow(...)]tests check whether allow works, but they don't check whether the non-presence of allow causes a lint to fire.There is no→ test added by e7730dc#[allow(...)]test for the expression, as there are tests for the pattern and the else block.→ test added by e7730dclet-else-brace-before-else.rsforbids thelet ... = {} else {}pattern and there is a rustfix to obtainlet ... = ({}) else {}. I'm not sure whether the.fixedfiles are checked by the tooling that they compile. But if there is no such check, it would be neat to make sure thatlet ... = ({}) else {}compiles.Wrong suggestion for slice patterns when using let-else statement #92069 got closed as fixed, but no regression test was added. Not sure it's worth to add one.→ test added by 5bd7106consistency between→ test added by 2d8460elet elseandif letregarding lifetimes and drop order: Stabilizelet else#93628 (comment)Edit: they are all tested now.
Possible future work / Refutable destructuring assignments
RFC 2909 specifies destructuring assignment, allowing statements like
FooBar { a, b, c } = foo();.As it was stabilized, destructuring assignment only allows irrefutable patterns, which before the advent of
let elsewere the only patterns thatletsupported.So the combination of
let elseand destructuring assignments gives reason to think about extensions of the destructuring assignments feature that allow refutable patterns, discussed in #93995.A naive mapping of
let elseto destructuring assignments in the form ofSome(v) = foo() else { ... };might not be the ideal way.let elseneeds a divergingelseclause as it introduces new bindings, while assignments have a default behaviour to fall back to if the pattern does not match, in the form of not performing the assignment. Thus, there is no good case to require divergence, or even anelseclause at all, beyond the need for having some introducer syntax so that it is clear to readers that the assignment is not a given (enums and structs look similar). There are better candidates for introducer syntax however than an emptyelse {}clause, likemaybewhich could be added as a keyword on an edition boundary:Further design discussion is left to an RFC, or the linked issue.