about summary refs log tree commit diff
path: root/compiler/rustc_parse/src/parser/expr.rs
diff options
context:
space:
mode:
authorbors <bors@rust-lang.org>2023-11-29 11:42:03 +0000
committerbors <bors@rust-lang.org>2023-11-29 11:42:03 +0000
commitce4727f723144aea42d66c09a0a7e75f8c51b8fd (patch)
treedea63ac4b1c641a0b2da8eb142fe4fb31877b441 /compiler/rustc_parse/src/parser/expr.rs
parentec1f21cb0483c40329b54c10b19c0e6220f5e51d (diff)
parent6094cb5d3635b17b51e0f1cfe83e5532eada064e (diff)
downloadrust-ce4727f723144aea42d66c09a0a7e75f8c51b8fd.tar.gz
rust-ce4727f723144aea42d66c09a0a7e75f8c51b8fd.zip
Auto merge of #118443 - matthiaskrgr:rollup-mp8o3m4, r=matthiaskrgr
Rollup of 7 pull requests

Successful merges:

 - #118157 (Add `never_patterns` feature gate)
 - #118191 (Suggest `let` or `==` on typo'd let-chain)
 - #118231 (also add is_empty to const raw slices)
 - #118333 (Print list of missing target features when calling a function with target features outside an unsafe block)
 - #118426 (ConstProp: Correctly remove const if unknown value assigned to it.)
 - #118428 (rustdoc: Move `AssocItemRender` and `RenderMode` to `html::render`.)
 - #118438 (Update nto-qnx.md)

Failed merges:

 - #118268 (Pretty print `Fn<(..., ...)>` trait refs with parentheses (almost) always)

r? `@ghost`
`@rustbot` modify labels: rollup
Diffstat (limited to 'compiler/rustc_parse/src/parser/expr.rs')
-rw-r--r--compiler/rustc_parse/src/parser/expr.rs48
1 files changed, 40 insertions, 8 deletions
diff --git a/compiler/rustc_parse/src/parser/expr.rs b/compiler/rustc_parse/src/parser/expr.rs
index 79567eb3898..e334837c1d4 100644
--- a/compiler/rustc_parse/src/parser/expr.rs
+++ b/compiler/rustc_parse/src/parser/expr.rs
@@ -1,3 +1,4 @@
+// ignore-tidy-filelength
 use super::diagnostics::SnapshotParser;
 use super::pat::{CommaRecoveryMode, Expected, RecoverColon, RecoverComma};
 use super::ty::{AllowPlus, RecoverQPath, RecoverReturnSign};
@@ -2477,7 +2478,7 @@ impl<'a> Parser<'a> {
         let mut cond =
             self.parse_expr_res(Restrictions::NO_STRUCT_LITERAL | Restrictions::ALLOW_LET, None)?;
 
-        CondChecker { parser: self, forbid_let_reason: None }.visit_expr(&mut cond);
+        CondChecker::new(self).visit_expr(&mut cond);
 
         if let ExprKind::Let(_, _, _, None) = cond.kind {
             // Remove the last feature gating of a `let` expression since it's stable.
@@ -2493,6 +2494,8 @@ impl<'a> Parser<'a> {
             let err = errors::ExpectedExpressionFoundLet {
                 span: self.token.span,
                 reason: ForbiddenLetReason::OtherForbidden,
+                missing_let: None,
+                comparison: None,
             };
             if self.prev_token.kind == token::BinOp(token::Or) {
                 // This was part of a closure, the that part of the parser recover.
@@ -2876,7 +2879,7 @@ impl<'a> Parser<'a> {
                 let if_span = this.prev_token.span;
                 let mut cond = this.parse_match_guard_condition()?;
 
-                CondChecker { parser: this, forbid_let_reason: None }.visit_expr(&mut cond);
+                CondChecker::new(this).visit_expr(&mut cond);
 
                 let (has_let_expr, does_not_have_bin_op) = check_let_expr(&cond);
                 if has_let_expr {
@@ -3552,6 +3555,14 @@ pub(crate) enum ForbiddenLetReason {
 struct CondChecker<'a> {
     parser: &'a Parser<'a>,
     forbid_let_reason: Option<ForbiddenLetReason>,
+    missing_let: Option<errors::MaybeMissingLet>,
+    comparison: Option<errors::MaybeComparison>,
+}
+
+impl<'a> CondChecker<'a> {
+    fn new(parser: &'a Parser<'a>) -> Self {
+        CondChecker { parser, forbid_let_reason: None, missing_let: None, comparison: None }
+    }
 }
 
 impl MutVisitor for CondChecker<'_> {
@@ -3562,11 +3573,13 @@ impl MutVisitor for CondChecker<'_> {
         match e.kind {
             ExprKind::Let(_, _, _, ref mut is_recovered @ None) => {
                 if let Some(reason) = self.forbid_let_reason {
-                    *is_recovered = Some(
-                        self.parser
-                            .sess
-                            .emit_err(errors::ExpectedExpressionFoundLet { span, reason }),
-                    );
+                    *is_recovered =
+                        Some(self.parser.sess.emit_err(errors::ExpectedExpressionFoundLet {
+                            span,
+                            reason,
+                            missing_let: self.missing_let,
+                            comparison: self.comparison,
+                        }));
                 } else {
                     self.parser.sess.gated_spans.gate(sym::let_chains, span);
                 }
@@ -3590,9 +3603,28 @@ impl MutVisitor for CondChecker<'_> {
                 noop_visit_expr(e, self);
                 self.forbid_let_reason = forbid_let_reason;
             }
+            ExprKind::Assign(ref lhs, _, span) => {
+                let forbid_let_reason = self.forbid_let_reason;
+                self.forbid_let_reason = Some(OtherForbidden);
+                let missing_let = self.missing_let;
+                if let ExprKind::Binary(_, _, rhs) = &lhs.kind
+                    && let ExprKind::Path(_, _)
+                    | ExprKind::Struct(_)
+                    | ExprKind::Call(_, _)
+                    | ExprKind::Array(_) = rhs.kind
+                {
+                    self.missing_let =
+                        Some(errors::MaybeMissingLet { span: rhs.span.shrink_to_lo() });
+                }
+                let comparison = self.comparison;
+                self.comparison = Some(errors::MaybeComparison { span: span.shrink_to_hi() });
+                noop_visit_expr(e, self);
+                self.forbid_let_reason = forbid_let_reason;
+                self.missing_let = missing_let;
+                self.comparison = comparison;
+            }
             ExprKind::Unary(_, _)
             | ExprKind::Await(_, _)
-            | ExprKind::Assign(_, _, _)
             | ExprKind::AssignOp(_, _, _)
             | ExprKind::Range(_, _, _)
             | ExprKind::Try(_)