Skip to content

Commit 5258cb7

Browse files
committed
Don't call ungate_last
1 parent 162daaa commit 5258cb7

File tree

1 file changed

+45
-54
lines changed
  • compiler/rustc_parse/src/parser

1 file changed

+45
-54
lines changed

Diff for: compiler/rustc_parse/src/parser/expr.rs

+45-54
Original file line numberDiff line numberDiff line change
@@ -2606,7 +2606,10 @@ impl<'a> Parser<'a> {
26062606
/// Parses an `if` expression (`if` token already eaten).
26072607
fn parse_expr_if(&mut self) -> PResult<'a, P<Expr>> {
26082608
let lo = self.prev_token.span;
2609-
let cond = self.parse_expr_cond(lo.edition())?;
2609+
// Scoping code checks the top level edition of the `if`; let's match it here.
2610+
// The `CondChecker` also checks the edition of the `let` itself, just to make sure.
2611+
let let_chains_policy = LetChainsPolicy::EditionDependent { current_edition: lo.edition() };
2612+
let cond = self.parse_expr_cond(let_chains_policy)?;
26102613
self.parse_if_after_cond(lo, cond)
26112614
}
26122615

@@ -2716,41 +2719,16 @@ impl<'a> Parser<'a> {
27162719

27172720
/// Parses the condition of a `if` or `while` expression.
27182721
///
2719-
/// The specified `edition` should be that of the whole `if` or `while` construct: the same
2720-
/// span that we later decide the drop behaviour on (editions ..=2021 vs 2024..)
2722+
/// The specified `edition` in `let_chains_policy` should be that of the whole `if` construct,
2723+
/// i.e. the same span we use to later decide whether the drop behaviour should be that of
2724+
/// edition `..=2021` or that of `2024..`.
27212725
// 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.
2722-
pub fn parse_expr_cond(&mut self, edition: Edition) -> PResult<'a, P<Expr>> {
2726+
pub fn parse_expr_cond(&mut self, let_chains_policy: LetChainsPolicy) -> PResult<'a, P<Expr>> {
27232727
let attrs = self.parse_outer_attributes()?;
27242728
let (mut cond, _) =
27252729
self.parse_expr_res(Restrictions::NO_STRUCT_LITERAL | Restrictions::ALLOW_LET, attrs)?;
27262730

2727-
CondChecker::new(self).visit_expr(&mut cond);
2728-
2729-
if let ExprKind::Let(_, _, _, Recovered::No) = cond.kind {
2730-
// Remove the last feature gating of a `let` expression since it's stable.
2731-
self.psess.gated_spans.ungate_last(sym::let_chains, cond.span);
2732-
} else {
2733-
fn ungate_let_exprs(this: &mut Parser<'_>, expr: &Expr) {
2734-
if !expr.span.at_least_rust_2024() {
2735-
return;
2736-
}
2737-
match &expr.kind {
2738-
ExprKind::Binary(BinOp { node: BinOpKind::And, .. }, lhs, rhs) => {
2739-
ungate_let_exprs(this, rhs);
2740-
ungate_let_exprs(this, lhs);
2741-
}
2742-
ExprKind::Let(..) => {
2743-
this.psess.gated_spans.ungate_last(sym::let_chains, expr.span)
2744-
}
2745-
_ => (),
2746-
}
2747-
}
2748-
if edition.at_least_rust_2024() {
2749-
// Scoping code checks the top level edition of the `if`: let's match it here.
2750-
// Also check all editions in between, just to make sure.
2751-
ungate_let_exprs(self, &cond);
2752-
}
2753-
}
2731+
CondChecker::new(self, let_chains_policy).visit_expr(&mut cond);
27542732

27552733
Ok(cond)
27562734
}
@@ -3045,7 +3023,8 @@ impl<'a> Parser<'a> {
30453023

30463024
/// Parses a `while` or `while let` expression (`while` token already eaten).
30473025
fn parse_expr_while(&mut self, opt_label: Option<Label>, lo: Span) -> PResult<'a, P<Expr>> {
3048-
let cond = self.parse_expr_cond(lo.edition()).map_err(|mut err| {
3026+
let policy = LetChainsPolicy::EditionDependent { current_edition: lo.edition() };
3027+
let cond = self.parse_expr_cond(policy).map_err(|mut err| {
30493028
err.span_label(lo, "while parsing the condition of this `while` expression");
30503029
err
30513030
})?;
@@ -3429,7 +3408,7 @@ impl<'a> Parser<'a> {
34293408
}
34303409

34313410
fn parse_match_arm_guard(&mut self) -> PResult<'a, Option<P<Expr>>> {
3432-
// Used to check the `let_chains` and `if_let_guard` features mostly by scanning
3411+
// Used to check the `if_let_guard` feature mostly by scanning
34333412
// `&&` tokens.
34343413
fn has_let_expr(expr: &Expr) -> bool {
34353414
match &expr.kind {
@@ -3450,23 +3429,9 @@ impl<'a> Parser<'a> {
34503429
let if_span = self.prev_token.span;
34513430
let mut cond = self.parse_match_guard_condition()?;
34523431

3453-
CondChecker::new(self).visit_expr(&mut cond);
3432+
CondChecker::new(self, LetChainsPolicy::AlwaysAllowed).visit_expr(&mut cond);
34543433

34553434
if has_let_expr(&cond) {
3456-
// Let chains are allowed in match guards, but only there
3457-
fn ungate_let_exprs(this: &mut Parser<'_>, expr: &Expr) {
3458-
match &expr.kind {
3459-
ExprKind::Binary(BinOp { node: BinOpKind::And, .. }, lhs, rhs) => {
3460-
ungate_let_exprs(this, rhs);
3461-
ungate_let_exprs(this, lhs);
3462-
}
3463-
ExprKind::Let(..) => {
3464-
this.psess.gated_spans.ungate_last(sym::let_chains, expr.span)
3465-
}
3466-
_ => (),
3467-
}
3468-
}
3469-
ungate_let_exprs(self, &cond);
34703435
let span = if_span.to(cond.span);
34713436
self.psess.gated_spans.gate(sym::if_let_guard, span);
34723437
}
@@ -3493,7 +3458,7 @@ impl<'a> Parser<'a> {
34933458
unreachable!()
34943459
};
34953460
self.psess.gated_spans.ungate_last(sym::guard_patterns, cond.span);
3496-
CondChecker::new(self).visit_expr(&mut cond);
3461+
CondChecker::new(self, LetChainsPolicy::AlwaysAllowed).visit_expr(&mut cond);
34973462
let right = self.prev_token.span;
34983463
self.dcx().emit_err(errors::ParenthesesInMatchPat {
34993464
span: vec![left, right],
@@ -4072,7 +4037,14 @@ pub(crate) enum ForbiddenLetReason {
40724037
NotSupportedParentheses(#[primary_span] Span),
40734038
}
40744039

4075-
/// Visitor to check for invalid/unstable use of `ExprKind::Let` that can't
4040+
/// Whether let chains are allowed on all editions, or it's edition dependent (allowed only on
4041+
/// 2024 and later). In case of edition dependence, specify the currently present edition.
4042+
pub enum LetChainsPolicy {
4043+
AlwaysAllowed,
4044+
EditionDependent { current_edition: Edition },
4045+
}
4046+
4047+
/// Visitor to check for invalid use of `ExprKind::Let` that can't
40764048
/// easily be caught in parsing. For example:
40774049
///
40784050
/// ```rust,ignore (example)
@@ -4083,19 +4055,29 @@ pub(crate) enum ForbiddenLetReason {
40834055
/// ```
40844056
struct CondChecker<'a> {
40854057
parser: &'a Parser<'a>,
4058+
let_chains_policy: LetChainsPolicy,
4059+
depth: u32,
40864060
forbid_let_reason: Option<ForbiddenLetReason>,
40874061
missing_let: Option<errors::MaybeMissingLet>,
40884062
comparison: Option<errors::MaybeComparison>,
40894063
}
40904064

40914065
impl<'a> CondChecker<'a> {
4092-
fn new(parser: &'a Parser<'a>) -> Self {
4093-
CondChecker { parser, forbid_let_reason: None, missing_let: None, comparison: None }
4066+
fn new(parser: &'a Parser<'a>, let_chains_policy: LetChainsPolicy) -> Self {
4067+
CondChecker {
4068+
parser,
4069+
forbid_let_reason: None,
4070+
missing_let: None,
4071+
comparison: None,
4072+
let_chains_policy,
4073+
depth: 0,
4074+
}
40944075
}
40954076
}
40964077

40974078
impl MutVisitor for CondChecker<'_> {
40984079
fn visit_expr(&mut self, e: &mut P<Expr>) {
4080+
self.depth += 1;
40994081
use ForbiddenLetReason::*;
41004082

41014083
let span = e.span;
@@ -4110,8 +4092,16 @@ impl MutVisitor for CondChecker<'_> {
41104092
comparison: self.comparison,
41114093
},
41124094
));
4113-
} else {
4114-
self.parser.psess.gated_spans.gate(sym::let_chains, span);
4095+
} else if self.depth > 1 {
4096+
// Top level `let` is always allowed; only gate chains
4097+
match self.let_chains_policy {
4098+
LetChainsPolicy::AlwaysAllowed => (),
4099+
LetChainsPolicy::EditionDependent { current_edition } => {
4100+
if !current_edition.at_least_rust_2024() || !span.at_least_rust_2024() {
4101+
self.parser.psess.gated_spans.gate(sym::let_chains, span);
4102+
}
4103+
}
4104+
}
41154105
}
41164106
}
41174107
ExprKind::Binary(Spanned { node: BinOpKind::And, .. }, _, _) => {
@@ -4213,5 +4203,6 @@ impl MutVisitor for CondChecker<'_> {
42134203
// These would forbid any let expressions they contain already.
42144204
}
42154205
}
4206+
self.depth -= 1;
42164207
}
42174208
}

0 commit comments

Comments
 (0)