Skip to content

Commit 701dd63

Browse files
committed
gate let_chains in all places before the 2024 edition
Since `let_chains` relies on the 2024 edition drop order to be consistent, it makes sense for us to gate it in all places, even when there are unstable features such as with `if_let_guard`s in matches. This removes the need for us to pass in an enum to `CondChecker` as we can just always pass in the edition instead.
1 parent 645d0ad commit 701dd63

File tree

5 files changed

+108
-55
lines changed

5 files changed

+108
-55
lines changed

compiler/rustc_parse/src/parser/expr.rs

Lines changed: 15 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -2605,8 +2605,7 @@ impl<'a> Parser<'a> {
26052605
let lo = self.prev_token.span;
26062606
// Scoping code checks the top level edition of the `if`; let's match it here.
26072607
// The `CondChecker` also checks the edition of the `let` itself, just to make sure.
2608-
let let_chains_policy = LetChainsPolicy::EditionDependent { current_edition: lo.edition() };
2609-
let cond = self.parse_expr_cond(let_chains_policy)?;
2608+
let cond = self.parse_expr_cond(lo.edition())?;
26102609
self.parse_if_after_cond(lo, cond)
26112610
}
26122611

@@ -2716,16 +2715,16 @@ impl<'a> Parser<'a> {
27162715

27172716
/// Parses the condition of a `if` or `while` expression.
27182717
///
2719-
/// The specified `edition` in `let_chains_policy` should be that of the whole `if` construct,
2720-
/// i.e. the same span we use to later decide whether the drop behaviour should be that of
2721-
/// edition `..=2021` or that of `2024..`.
2718+
/// The specified `edition` should be that of the whole `if` construct, i.e. the same span
2719+
/// we use to later decide whether the drop behaviour should be that of edition `..=2021`
2720+
/// or that of `2024..`.
27222721
// Public because it is used in rustfmt forks such as https://github.com/tucant/rustfmt/blob/30c83df9e1db10007bdd16dafce8a86b404329b2/src/parse/macros/html.rs#L57 for custom if expressions.
2723-
pub fn parse_expr_cond(&mut self, let_chains_policy: LetChainsPolicy) -> PResult<'a, P<Expr>> {
2722+
pub fn parse_expr_cond(&mut self, edition: Edition) -> PResult<'a, P<Expr>> {
27242723
let attrs = self.parse_outer_attributes()?;
27252724
let (mut cond, _) =
27262725
self.parse_expr_res(Restrictions::NO_STRUCT_LITERAL | Restrictions::ALLOW_LET, attrs)?;
27272726

2728-
CondChecker::new(self, let_chains_policy).visit_expr(&mut cond);
2727+
CondChecker::new(self, edition).visit_expr(&mut cond);
27292728

27302729
Ok(cond)
27312730
}
@@ -3020,8 +3019,7 @@ impl<'a> Parser<'a> {
30203019

30213020
/// Parses a `while` or `while let` expression (`while` token already eaten).
30223021
fn parse_expr_while(&mut self, opt_label: Option<Label>, lo: Span) -> PResult<'a, P<Expr>> {
3023-
let policy = LetChainsPolicy::EditionDependent { current_edition: lo.edition() };
3024-
let cond = self.parse_expr_cond(policy).map_err(|mut err| {
3022+
let cond = self.parse_expr_cond(lo.edition()).map_err(|mut err| {
30253023
err.span_label(lo, "while parsing the condition of this `while` expression");
30263024
err
30273025
})?;
@@ -3426,7 +3424,8 @@ impl<'a> Parser<'a> {
34263424
let if_span = self.prev_token.span;
34273425
let mut cond = self.parse_match_guard_condition()?;
34283426

3429-
CondChecker::new(self, LetChainsPolicy::AlwaysAllowed).visit_expr(&mut cond);
3427+
// TODO explain
3428+
CondChecker::new(self, if_span.edition()).visit_expr(&mut cond);
34303429

34313430
if has_let_expr(&cond) {
34323431
let span = if_span.to(cond.span);
@@ -3455,7 +3454,7 @@ impl<'a> Parser<'a> {
34553454
unreachable!()
34563455
};
34573456
self.psess.gated_spans.ungate_last(sym::guard_patterns, cond.span);
3458-
CondChecker::new(self, LetChainsPolicy::AlwaysAllowed).visit_expr(&mut cond);
3457+
CondChecker::new(self, span.edition()).visit_expr(&mut cond);
34593458
let right = self.prev_token.span;
34603459
self.dcx().emit_err(errors::ParenthesesInMatchPat {
34613460
span: vec![left, right],
@@ -4026,13 +4025,6 @@ pub(crate) enum ForbiddenLetReason {
40264025
NotSupportedParentheses(#[primary_span] Span),
40274026
}
40284027

4029-
/// Whether let chains are allowed on all editions, or it's edition dependent (allowed only on
4030-
/// 2024 and later). In case of edition dependence, specify the currently present edition.
4031-
pub enum LetChainsPolicy {
4032-
AlwaysAllowed,
4033-
EditionDependent { current_edition: Edition },
4034-
}
4035-
40364028
/// Visitor to check for invalid use of `ExprKind::Let` that can't
40374029
/// easily be caught in parsing. For example:
40384030
///
@@ -4044,21 +4036,21 @@ pub enum LetChainsPolicy {
40444036
/// ```
40454037
struct CondChecker<'a> {
40464038
parser: &'a Parser<'a>,
4047-
let_chains_policy: LetChainsPolicy,
4039+
current_edition: Edition,
40484040
depth: u32,
40494041
forbid_let_reason: Option<ForbiddenLetReason>,
40504042
missing_let: Option<errors::MaybeMissingLet>,
40514043
comparison: Option<errors::MaybeComparison>,
40524044
}
40534045

40544046
impl<'a> CondChecker<'a> {
4055-
fn new(parser: &'a Parser<'a>, let_chains_policy: LetChainsPolicy) -> Self {
4047+
fn new(parser: &'a Parser<'a>, current_edition: Edition) -> Self {
40564048
CondChecker {
40574049
parser,
40584050
forbid_let_reason: None,
40594051
missing_let: None,
40604052
comparison: None,
4061-
let_chains_policy,
4053+
current_edition,
40624054
depth: 0,
40634055
}
40644056
}
@@ -4083,13 +4075,8 @@ impl MutVisitor for CondChecker<'_> {
40834075
));
40844076
} else if self.depth > 1 {
40854077
// Top level `let` is always allowed; only gate chains
4086-
match self.let_chains_policy {
4087-
LetChainsPolicy::AlwaysAllowed => (),
4088-
LetChainsPolicy::EditionDependent { current_edition } => {
4089-
if !current_edition.at_least_rust_2024() || !span.at_least_rust_2024() {
4090-
self.parser.psess.gated_spans.gate(sym::let_chains, span);
4091-
}
4092-
}
4078+
if !self.current_edition.at_least_rust_2024() || !span.at_least_rust_2024() {
4079+
self.parser.psess.gated_spans.gate(sym::let_chains, span);
40934080
}
40944081
}
40954082
}

tests/ui/rfcs/rfc-2294-if-let-guard/feature-gate.rs

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,9 +15,11 @@ fn _if_let_guard() {
1515

1616
() if true && let 0 = 1 => {}
1717
//~^ ERROR `if let` guards are experimental
18+
//~| ERROR `let` expressions in this position are unstable
1819

1920
() if let 0 = 1 && true => {}
2021
//~^ ERROR `if let` guards are experimental
22+
//~| ERROR `let` expressions in this position are unstable
2123

2224
() if (let 0 = 1) && true => {}
2325
//~^ ERROR expected expression, found `let` statement
@@ -31,13 +33,16 @@ fn _if_let_guard() {
3133

3234
() if let 0 = 1 && let 1 = 2 && (let 2 = 3 && let 3 = 4 && let 4 = 5) => {}
3335
//~^ ERROR `if let` guards are experimental
36+
//~| ERROR `let` expressions in this position are unstable
37+
//~| ERROR `let` expressions in this position are unstable
3438
//~| ERROR expected expression, found `let` statement
3539
//~| ERROR expected expression, found `let` statement
3640
//~| ERROR expected expression, found `let` statement
3741

3842

3943
() if let Range { start: _, end: _ } = (true..true) && false => {}
4044
//~^ ERROR `if let` guards are experimental
45+
//~| ERROR `let` expressions in this position are unstable
4146

4247
_ => {}
4348
}

tests/ui/rfcs/rfc-2294-if-let-guard/feature-gate.stderr

Lines changed: 75 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -25,106 +25,106 @@ LL | () if (((let 0 = 1))) => {}
2525
| ^^^^^^^^^
2626

2727
error: expected expression, found `let` statement
28-
--> $DIR/feature-gate.rs:22:16
28+
--> $DIR/feature-gate.rs:24:16
2929
|
3030
LL | () if (let 0 = 1) && true => {}
3131
| ^^^^^^^^^
3232
|
3333
= note: only supported directly in conditions of `if` and `while` expressions
3434
note: `let`s wrapped in parentheses are not supported in a context with let chains
35-
--> $DIR/feature-gate.rs:22:16
35+
--> $DIR/feature-gate.rs:24:16
3636
|
3737
LL | () if (let 0 = 1) && true => {}
3838
| ^^^^^^^^^
3939

4040
error: expected expression, found `let` statement
41-
--> $DIR/feature-gate.rs:25:24
41+
--> $DIR/feature-gate.rs:27:24
4242
|
4343
LL | () if true && (let 0 = 1) => {}
4444
| ^^^^^^^^^
4545
|
4646
= note: only supported directly in conditions of `if` and `while` expressions
4747
note: `let`s wrapped in parentheses are not supported in a context with let chains
48-
--> $DIR/feature-gate.rs:25:24
48+
--> $DIR/feature-gate.rs:27:24
4949
|
5050
LL | () if true && (let 0 = 1) => {}
5151
| ^^^^^^^^^
5252

5353
error: expected expression, found `let` statement
54-
--> $DIR/feature-gate.rs:28:16
54+
--> $DIR/feature-gate.rs:30:16
5555
|
5656
LL | () if (let 0 = 1) && (let 0 = 1) => {}
5757
| ^^^^^^^^^
5858
|
5959
= note: only supported directly in conditions of `if` and `while` expressions
6060
note: `let`s wrapped in parentheses are not supported in a context with let chains
61-
--> $DIR/feature-gate.rs:28:16
61+
--> $DIR/feature-gate.rs:30:16
6262
|
6363
LL | () if (let 0 = 1) && (let 0 = 1) => {}
6464
| ^^^^^^^^^
6565

6666
error: expected expression, found `let` statement
67-
--> $DIR/feature-gate.rs:28:31
67+
--> $DIR/feature-gate.rs:30:31
6868
|
6969
LL | () if (let 0 = 1) && (let 0 = 1) => {}
7070
| ^^^^^^^^^
7171
|
7272
= note: only supported directly in conditions of `if` and `while` expressions
7373
note: `let`s wrapped in parentheses are not supported in a context with let chains
74-
--> $DIR/feature-gate.rs:28:31
74+
--> $DIR/feature-gate.rs:30:31
7575
|
7676
LL | () if (let 0 = 1) && (let 0 = 1) => {}
7777
| ^^^^^^^^^
7878

7979
error: expected expression, found `let` statement
80-
--> $DIR/feature-gate.rs:32:42
80+
--> $DIR/feature-gate.rs:34:42
8181
|
8282
LL | () if let 0 = 1 && let 1 = 2 && (let 2 = 3 && let 3 = 4 && let 4 = 5) => {}
8383
| ^^^^^^^^^
8484
|
8585
= note: only supported directly in conditions of `if` and `while` expressions
8686
note: `let`s wrapped in parentheses are not supported in a context with let chains
87-
--> $DIR/feature-gate.rs:32:42
87+
--> $DIR/feature-gate.rs:34:42
8888
|
8989
LL | () if let 0 = 1 && let 1 = 2 && (let 2 = 3 && let 3 = 4 && let 4 = 5) => {}
9090
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
9191

9292
error: expected expression, found `let` statement
93-
--> $DIR/feature-gate.rs:32:55
93+
--> $DIR/feature-gate.rs:34:55
9494
|
9595
LL | () if let 0 = 1 && let 1 = 2 && (let 2 = 3 && let 3 = 4 && let 4 = 5) => {}
9696
| ^^^^^^^^^
9797
|
9898
= note: only supported directly in conditions of `if` and `while` expressions
9999
note: `let`s wrapped in parentheses are not supported in a context with let chains
100-
--> $DIR/feature-gate.rs:32:42
100+
--> $DIR/feature-gate.rs:34:42
101101
|
102102
LL | () if let 0 = 1 && let 1 = 2 && (let 2 = 3 && let 3 = 4 && let 4 = 5) => {}
103103
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
104104

105105
error: expected expression, found `let` statement
106-
--> $DIR/feature-gate.rs:32:68
106+
--> $DIR/feature-gate.rs:34:68
107107
|
108108
LL | () if let 0 = 1 && let 1 = 2 && (let 2 = 3 && let 3 = 4 && let 4 = 5) => {}
109109
| ^^^^^^^^^
110110
|
111111
= note: only supported directly in conditions of `if` and `while` expressions
112112
note: `let`s wrapped in parentheses are not supported in a context with let chains
113-
--> $DIR/feature-gate.rs:32:42
113+
--> $DIR/feature-gate.rs:34:42
114114
|
115115
LL | () if let 0 = 1 && let 1 = 2 && (let 2 = 3 && let 3 = 4 && let 4 = 5) => {}
116116
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
117117

118118
error: expected expression, found `let` statement
119-
--> $DIR/feature-gate.rs:55:16
119+
--> $DIR/feature-gate.rs:60:16
120120
|
121121
LL | use_expr!((let 0 = 1 && 0 == 0));
122122
| ^^^
123123
|
124124
= note: only supported directly in conditions of `if` and `while` expressions
125125

126126
error: expected expression, found `let` statement
127-
--> $DIR/feature-gate.rs:55:16
127+
--> $DIR/feature-gate.rs:60:16
128128
|
129129
LL | use_expr!((let 0 = 1 && 0 == 0));
130130
| ^^^
@@ -133,15 +133,15 @@ LL | use_expr!((let 0 = 1 && 0 == 0));
133133
= note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no`
134134

135135
error: expected expression, found `let` statement
136-
--> $DIR/feature-gate.rs:58:16
136+
--> $DIR/feature-gate.rs:63:16
137137
|
138138
LL | use_expr!((let 0 = 1));
139139
| ^^^
140140
|
141141
= note: only supported directly in conditions of `if` and `while` expressions
142142

143143
error: expected expression, found `let` statement
144-
--> $DIR/feature-gate.rs:58:16
144+
--> $DIR/feature-gate.rs:63:16
145145
|
146146
LL | use_expr!((let 0 = 1));
147147
| ^^^
@@ -150,7 +150,7 @@ LL | use_expr!((let 0 = 1));
150150
= note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no`
151151

152152
error: no rules expected keyword `let`
153-
--> $DIR/feature-gate.rs:67:15
153+
--> $DIR/feature-gate.rs:72:15
154154
|
155155
LL | macro_rules! use_expr {
156156
| --------------------- when calling this macro
@@ -159,7 +159,7 @@ LL | use_expr!(let 0 = 1);
159159
| ^^^ no rules expected this token in macro call
160160
|
161161
note: while trying to match meta-variable `$e:expr`
162-
--> $DIR/feature-gate.rs:48:10
162+
--> $DIR/feature-gate.rs:53:10
163163
|
164164
LL | ($e:expr) => {
165165
| ^^^^^^^
@@ -187,7 +187,7 @@ LL | () if true && let 0 = 1 => {}
187187
= help: you can write `if matches!(<expr>, <pattern>)` instead of `if let <pattern> = <expr>`
188188

189189
error[E0658]: `if let` guards are experimental
190-
--> $DIR/feature-gate.rs:19:12
190+
--> $DIR/feature-gate.rs:20:12
191191
|
192192
LL | () if let 0 = 1 && true => {}
193193
| ^^^^^^^^^^^^^^^^^^^^
@@ -198,7 +198,7 @@ LL | () if let 0 = 1 && true => {}
198198
= help: you can write `if matches!(<expr>, <pattern>)` instead of `if let <pattern> = <expr>`
199199

200200
error[E0658]: `if let` guards are experimental
201-
--> $DIR/feature-gate.rs:32:12
201+
--> $DIR/feature-gate.rs:34:12
202202
|
203203
LL | () if let 0 = 1 && let 1 = 2 && (let 2 = 3 && let 3 = 4 && let 4 = 5) => {}
204204
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -209,7 +209,7 @@ LL | () if let 0 = 1 && let 1 = 2 && (let 2 = 3 && let 3 = 4 && let 4 =
209209
= help: you can write `if matches!(<expr>, <pattern>)` instead of `if let <pattern> = <expr>`
210210

211211
error[E0658]: `if let` guards are experimental
212-
--> $DIR/feature-gate.rs:39:12
212+
--> $DIR/feature-gate.rs:43:12
213213
|
214214
LL | () if let Range { start: _, end: _ } = (true..true) && false => {}
215215
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -220,7 +220,7 @@ LL | () if let Range { start: _, end: _ } = (true..true) && false => {}
220220
= help: you can write `if matches!(<expr>, <pattern>)` instead of `if let <pattern> = <expr>`
221221

222222
error[E0658]: `if let` guards are experimental
223-
--> $DIR/feature-gate.rs:63:12
223+
--> $DIR/feature-gate.rs:68:12
224224
|
225225
LL | () if let 0 = 1 => {}
226226
| ^^^^^^^^^^^^
@@ -230,6 +230,56 @@ LL | () if let 0 = 1 => {}
230230
= note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date
231231
= help: you can write `if matches!(<expr>, <pattern>)` instead of `if let <pattern> = <expr>`
232232

233-
error: aborting due to 20 previous errors
233+
error[E0658]: `let` expressions in this position are unstable
234+
--> $DIR/feature-gate.rs:16:23
235+
|
236+
LL | () if true && let 0 = 1 => {}
237+
| ^^^^^^^^^
238+
|
239+
= note: see issue #53667 <https://github.com/rust-lang/rust/issues/53667> for more information
240+
= help: add `#![feature(let_chains)]` to the crate attributes to enable
241+
= note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date
242+
243+
error[E0658]: `let` expressions in this position are unstable
244+
--> $DIR/feature-gate.rs:20:15
245+
|
246+
LL | () if let 0 = 1 && true => {}
247+
| ^^^^^^^^^
248+
|
249+
= note: see issue #53667 <https://github.com/rust-lang/rust/issues/53667> for more information
250+
= help: add `#![feature(let_chains)]` to the crate attributes to enable
251+
= note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date
252+
253+
error[E0658]: `let` expressions in this position are unstable
254+
--> $DIR/feature-gate.rs:34:15
255+
|
256+
LL | () if let 0 = 1 && let 1 = 2 && (let 2 = 3 && let 3 = 4 && let 4 = 5) => {}
257+
| ^^^^^^^^^
258+
|
259+
= note: see issue #53667 <https://github.com/rust-lang/rust/issues/53667> for more information
260+
= help: add `#![feature(let_chains)]` to the crate attributes to enable
261+
= note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date
262+
263+
error[E0658]: `let` expressions in this position are unstable
264+
--> $DIR/feature-gate.rs:34:28
265+
|
266+
LL | () if let 0 = 1 && let 1 = 2 && (let 2 = 3 && let 3 = 4 && let 4 = 5) => {}
267+
| ^^^^^^^^^
268+
|
269+
= note: see issue #53667 <https://github.com/rust-lang/rust/issues/53667> for more information
270+
= help: add `#![feature(let_chains)]` to the crate attributes to enable
271+
= note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date
272+
273+
error[E0658]: `let` expressions in this position are unstable
274+
--> $DIR/feature-gate.rs:43:15
275+
|
276+
LL | () if let Range { start: _, end: _ } = (true..true) && false => {}
277+
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
278+
|
279+
= note: see issue #53667 <https://github.com/rust-lang/rust/issues/53667> for more information
280+
= help: add `#![feature(let_chains)]` to the crate attributes to enable
281+
= note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date
282+
283+
error: aborting due to 25 previous errors
234284

235285
For more information about this error, try `rustc --explain E0658`.

0 commit comments

Comments
 (0)