Don't call ungate_last
This commit is contained in:
parent
162daaa2fa
commit
5258cb76a5
1 changed files with 45 additions and 54 deletions
|
@ -2606,7 +2606,10 @@ impl<'a> Parser<'a> {
|
||||||
/// Parses an `if` expression (`if` token already eaten).
|
/// Parses an `if` expression (`if` token already eaten).
|
||||||
fn parse_expr_if(&mut self) -> PResult<'a, P<Expr>> {
|
fn parse_expr_if(&mut self) -> PResult<'a, P<Expr>> {
|
||||||
let lo = self.prev_token.span;
|
let lo = self.prev_token.span;
|
||||||
let cond = self.parse_expr_cond(lo.edition())?;
|
// Scoping code checks the top level edition of the `if`; let's match it here.
|
||||||
|
// The `CondChecker` also checks the edition of the `let` itself, just to make sure.
|
||||||
|
let let_chains_policy = LetChainsPolicy::EditionDependent { current_edition: lo.edition() };
|
||||||
|
let cond = self.parse_expr_cond(let_chains_policy)?;
|
||||||
self.parse_if_after_cond(lo, cond)
|
self.parse_if_after_cond(lo, cond)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -2716,41 +2719,16 @@ impl<'a> Parser<'a> {
|
||||||
|
|
||||||
/// Parses the condition of a `if` or `while` expression.
|
/// Parses the condition of a `if` or `while` expression.
|
||||||
///
|
///
|
||||||
/// The specified `edition` should be that of the whole `if` or `while` construct: the same
|
/// The specified `edition` in `let_chains_policy` should be that of the whole `if` construct,
|
||||||
/// span that we later decide the drop behaviour on (editions ..=2021 vs 2024..)
|
/// i.e. the same span we use to later decide whether the drop behaviour should be that of
|
||||||
|
/// edition `..=2021` or that of `2024..`.
|
||||||
// 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.
|
// 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.
|
||||||
pub fn parse_expr_cond(&mut self, edition: Edition) -> PResult<'a, P<Expr>> {
|
pub fn parse_expr_cond(&mut self, let_chains_policy: LetChainsPolicy) -> PResult<'a, P<Expr>> {
|
||||||
let attrs = self.parse_outer_attributes()?;
|
let attrs = self.parse_outer_attributes()?;
|
||||||
let (mut cond, _) =
|
let (mut cond, _) =
|
||||||
self.parse_expr_res(Restrictions::NO_STRUCT_LITERAL | Restrictions::ALLOW_LET, attrs)?;
|
self.parse_expr_res(Restrictions::NO_STRUCT_LITERAL | Restrictions::ALLOW_LET, attrs)?;
|
||||||
|
|
||||||
CondChecker::new(self).visit_expr(&mut cond);
|
CondChecker::new(self, let_chains_policy).visit_expr(&mut cond);
|
||||||
|
|
||||||
if let ExprKind::Let(_, _, _, Recovered::No) = cond.kind {
|
|
||||||
// Remove the last feature gating of a `let` expression since it's stable.
|
|
||||||
self.psess.gated_spans.ungate_last(sym::let_chains, cond.span);
|
|
||||||
} else {
|
|
||||||
fn ungate_let_exprs(this: &mut Parser<'_>, expr: &Expr) {
|
|
||||||
if !expr.span.at_least_rust_2024() {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
match &expr.kind {
|
|
||||||
ExprKind::Binary(BinOp { node: BinOpKind::And, .. }, lhs, rhs) => {
|
|
||||||
ungate_let_exprs(this, rhs);
|
|
||||||
ungate_let_exprs(this, lhs);
|
|
||||||
}
|
|
||||||
ExprKind::Let(..) => {
|
|
||||||
this.psess.gated_spans.ungate_last(sym::let_chains, expr.span)
|
|
||||||
}
|
|
||||||
_ => (),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if edition.at_least_rust_2024() {
|
|
||||||
// Scoping code checks the top level edition of the `if`: let's match it here.
|
|
||||||
// Also check all editions in between, just to make sure.
|
|
||||||
ungate_let_exprs(self, &cond);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
Ok(cond)
|
Ok(cond)
|
||||||
}
|
}
|
||||||
|
@ -3045,7 +3023,8 @@ impl<'a> Parser<'a> {
|
||||||
|
|
||||||
/// Parses a `while` or `while let` expression (`while` token already eaten).
|
/// Parses a `while` or `while let` expression (`while` token already eaten).
|
||||||
fn parse_expr_while(&mut self, opt_label: Option<Label>, lo: Span) -> PResult<'a, P<Expr>> {
|
fn parse_expr_while(&mut self, opt_label: Option<Label>, lo: Span) -> PResult<'a, P<Expr>> {
|
||||||
let cond = self.parse_expr_cond(lo.edition()).map_err(|mut err| {
|
let policy = LetChainsPolicy::EditionDependent { current_edition: lo.edition() };
|
||||||
|
let cond = self.parse_expr_cond(policy).map_err(|mut err| {
|
||||||
err.span_label(lo, "while parsing the condition of this `while` expression");
|
err.span_label(lo, "while parsing the condition of this `while` expression");
|
||||||
err
|
err
|
||||||
})?;
|
})?;
|
||||||
|
@ -3429,7 +3408,7 @@ impl<'a> Parser<'a> {
|
||||||
}
|
}
|
||||||
|
|
||||||
fn parse_match_arm_guard(&mut self) -> PResult<'a, Option<P<Expr>>> {
|
fn parse_match_arm_guard(&mut self) -> PResult<'a, Option<P<Expr>>> {
|
||||||
// Used to check the `let_chains` and `if_let_guard` features mostly by scanning
|
// Used to check the `if_let_guard` feature mostly by scanning
|
||||||
// `&&` tokens.
|
// `&&` tokens.
|
||||||
fn has_let_expr(expr: &Expr) -> bool {
|
fn has_let_expr(expr: &Expr) -> bool {
|
||||||
match &expr.kind {
|
match &expr.kind {
|
||||||
|
@ -3450,23 +3429,9 @@ impl<'a> Parser<'a> {
|
||||||
let if_span = self.prev_token.span;
|
let if_span = self.prev_token.span;
|
||||||
let mut cond = self.parse_match_guard_condition()?;
|
let mut cond = self.parse_match_guard_condition()?;
|
||||||
|
|
||||||
CondChecker::new(self).visit_expr(&mut cond);
|
CondChecker::new(self, LetChainsPolicy::AlwaysAllowed).visit_expr(&mut cond);
|
||||||
|
|
||||||
if has_let_expr(&cond) {
|
if has_let_expr(&cond) {
|
||||||
// Let chains are allowed in match guards, but only there
|
|
||||||
fn ungate_let_exprs(this: &mut Parser<'_>, expr: &Expr) {
|
|
||||||
match &expr.kind {
|
|
||||||
ExprKind::Binary(BinOp { node: BinOpKind::And, .. }, lhs, rhs) => {
|
|
||||||
ungate_let_exprs(this, rhs);
|
|
||||||
ungate_let_exprs(this, lhs);
|
|
||||||
}
|
|
||||||
ExprKind::Let(..) => {
|
|
||||||
this.psess.gated_spans.ungate_last(sym::let_chains, expr.span)
|
|
||||||
}
|
|
||||||
_ => (),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
ungate_let_exprs(self, &cond);
|
|
||||||
let span = if_span.to(cond.span);
|
let span = if_span.to(cond.span);
|
||||||
self.psess.gated_spans.gate(sym::if_let_guard, span);
|
self.psess.gated_spans.gate(sym::if_let_guard, span);
|
||||||
}
|
}
|
||||||
|
@ -3493,7 +3458,7 @@ impl<'a> Parser<'a> {
|
||||||
unreachable!()
|
unreachable!()
|
||||||
};
|
};
|
||||||
self.psess.gated_spans.ungate_last(sym::guard_patterns, cond.span);
|
self.psess.gated_spans.ungate_last(sym::guard_patterns, cond.span);
|
||||||
CondChecker::new(self).visit_expr(&mut cond);
|
CondChecker::new(self, LetChainsPolicy::AlwaysAllowed).visit_expr(&mut cond);
|
||||||
let right = self.prev_token.span;
|
let right = self.prev_token.span;
|
||||||
self.dcx().emit_err(errors::ParenthesesInMatchPat {
|
self.dcx().emit_err(errors::ParenthesesInMatchPat {
|
||||||
span: vec![left, right],
|
span: vec![left, right],
|
||||||
|
@ -4072,7 +4037,14 @@ pub(crate) enum ForbiddenLetReason {
|
||||||
NotSupportedParentheses(#[primary_span] Span),
|
NotSupportedParentheses(#[primary_span] Span),
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Visitor to check for invalid/unstable use of `ExprKind::Let` that can't
|
/// Whether let chains are allowed on all editions, or it's edition dependent (allowed only on
|
||||||
|
/// 2024 and later). In case of edition dependence, specify the currently present edition.
|
||||||
|
pub enum LetChainsPolicy {
|
||||||
|
AlwaysAllowed,
|
||||||
|
EditionDependent { current_edition: Edition },
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Visitor to check for invalid use of `ExprKind::Let` that can't
|
||||||
/// easily be caught in parsing. For example:
|
/// easily be caught in parsing. For example:
|
||||||
///
|
///
|
||||||
/// ```rust,ignore (example)
|
/// ```rust,ignore (example)
|
||||||
|
@ -4083,19 +4055,29 @@ pub(crate) enum ForbiddenLetReason {
|
||||||
/// ```
|
/// ```
|
||||||
struct CondChecker<'a> {
|
struct CondChecker<'a> {
|
||||||
parser: &'a Parser<'a>,
|
parser: &'a Parser<'a>,
|
||||||
|
let_chains_policy: LetChainsPolicy,
|
||||||
|
depth: u32,
|
||||||
forbid_let_reason: Option<ForbiddenLetReason>,
|
forbid_let_reason: Option<ForbiddenLetReason>,
|
||||||
missing_let: Option<errors::MaybeMissingLet>,
|
missing_let: Option<errors::MaybeMissingLet>,
|
||||||
comparison: Option<errors::MaybeComparison>,
|
comparison: Option<errors::MaybeComparison>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'a> CondChecker<'a> {
|
impl<'a> CondChecker<'a> {
|
||||||
fn new(parser: &'a Parser<'a>) -> Self {
|
fn new(parser: &'a Parser<'a>, let_chains_policy: LetChainsPolicy) -> Self {
|
||||||
CondChecker { parser, forbid_let_reason: None, missing_let: None, comparison: None }
|
CondChecker {
|
||||||
|
parser,
|
||||||
|
forbid_let_reason: None,
|
||||||
|
missing_let: None,
|
||||||
|
comparison: None,
|
||||||
|
let_chains_policy,
|
||||||
|
depth: 0,
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl MutVisitor for CondChecker<'_> {
|
impl MutVisitor for CondChecker<'_> {
|
||||||
fn visit_expr(&mut self, e: &mut P<Expr>) {
|
fn visit_expr(&mut self, e: &mut P<Expr>) {
|
||||||
|
self.depth += 1;
|
||||||
use ForbiddenLetReason::*;
|
use ForbiddenLetReason::*;
|
||||||
|
|
||||||
let span = e.span;
|
let span = e.span;
|
||||||
|
@ -4110,8 +4092,16 @@ impl MutVisitor for CondChecker<'_> {
|
||||||
comparison: self.comparison,
|
comparison: self.comparison,
|
||||||
},
|
},
|
||||||
));
|
));
|
||||||
} else {
|
} else if self.depth > 1 {
|
||||||
self.parser.psess.gated_spans.gate(sym::let_chains, span);
|
// Top level `let` is always allowed; only gate chains
|
||||||
|
match self.let_chains_policy {
|
||||||
|
LetChainsPolicy::AlwaysAllowed => (),
|
||||||
|
LetChainsPolicy::EditionDependent { current_edition } => {
|
||||||
|
if !current_edition.at_least_rust_2024() || !span.at_least_rust_2024() {
|
||||||
|
self.parser.psess.gated_spans.gate(sym::let_chains, span);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
ExprKind::Binary(Spanned { node: BinOpKind::And, .. }, _, _) => {
|
ExprKind::Binary(Spanned { node: BinOpKind::And, .. }, _, _) => {
|
||||||
|
@ -4213,5 +4203,6 @@ impl MutVisitor for CondChecker<'_> {
|
||||||
// These would forbid any let expressions they contain already.
|
// These would forbid any let expressions they contain already.
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
self.depth -= 1;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue