]> git.lizzy.rs Git - rust.git/commitdiff
Rollup merge of #67538 - varkor:lhs-assign-diagnostics, r=Centril
authorMazdak Farrokhzad <twingoow@gmail.com>
Mon, 23 Dec 2019 14:16:29 +0000 (15:16 +0100)
committerGitHub <noreply@github.com>
Mon, 23 Dec 2019 14:16:29 +0000 (15:16 +0100)
Improve diagnostics for invalid assignment

- Improve wording and span information for invalid assignment diagnostics.
- Link to https://github.com/rust-lang/rfcs/issues/372 when it appears the user is trying a destructuring assignment.
- Make the equality constraint in `where` clauses error consistent with the invalid assignment error.

37 files changed:
src/librustc/hir/intravisit.rs
src/librustc/hir/lowering/expr.rs
src/librustc/hir/mod.rs
src/librustc/hir/print.rs
src/librustc_lint/unused.rs
src/librustc_mir/hair/cx/expr.rs
src/librustc_parse/parser/expr.rs
src/librustc_passes/ast_validation.rs
src/librustc_passes/liveness.rs
src/librustc_privacy/lib.rs
src/librustc_typeck/check/demand.rs
src/librustc_typeck/check/expr.rs
src/librustc_typeck/check/op.rs
src/librustc_typeck/expr_use_visitor.rs
src/libsyntax/ast.rs
src/libsyntax/mut_visit.rs
src/libsyntax/print/pprust.rs
src/libsyntax/util/parser.rs
src/libsyntax/visit.rs
src/test/ui-fulldeps/pprust-expr-roundtrip.rs
src/test/ui/bad/bad-expr-lhs.rs
src/test/ui/bad/bad-expr-lhs.stderr
src/test/ui/destructuring-assignment/note-unsupported.rs [new file with mode: 0644]
src/test/ui/destructuring-assignment/note-unsupported.stderr [new file with mode: 0644]
src/test/ui/error-codes/E0067.stderr
src/test/ui/error-codes/E0070.stderr
src/test/ui/issues/issue-13407.rs
src/test/ui/issues/issue-13407.stderr
src/test/ui/issues/issue-26093.rs
src/test/ui/issues/issue-26093.stderr
src/test/ui/issues/issue-34334.rs
src/test/ui/issues/issue-34334.stderr
src/test/ui/type/type-check/assignment-expected-bool.rs
src/test/ui/type/type-check/assignment-expected-bool.stderr
src/test/ui/type/type-check/assignment-in-if.rs
src/test/ui/where-clauses/where-equality-constraints.rs
src/test/ui/where-clauses/where-equality-constraints.stderr

index dc2008fdd9743f706750b0b9a2f91e77bd6ed935..a7a8673d49eb1d020796907592ea9ce0be2299c8 100644 (file)
@@ -1043,9 +1043,9 @@ pub fn walk_expr<'v, V: Visitor<'v>>(visitor: &mut V, expression: &'v Expr) {
             walk_list!(visitor, visit_label, opt_label);
             visitor.visit_block(block);
         }
-        ExprKind::Assign(ref left_hand_expression, ref right_hand_expression) => {
-            visitor.visit_expr(right_hand_expression);
-            visitor.visit_expr(left_hand_expression)
+        ExprKind::Assign(ref lhs, ref rhs, _) => {
+            visitor.visit_expr(rhs);
+            visitor.visit_expr(lhs)
         }
         ExprKind::AssignOp(_, ref left_expression, ref right_expression) => {
             visitor.visit_expr(right_expression);
index 8939b5eef266062f3c32ece766a9baf0400c3a49..8311b9168e4553b0c6ac84381c7903ac1599b469 100644 (file)
@@ -122,8 +122,8 @@ pub(super) fn lower_expr(&mut self, e: &Expr) -> hir::Expr {
                 self.lower_block(blk, opt_label.is_some()),
                 self.lower_label(opt_label),
             ),
-            ExprKind::Assign(ref el, ref er) => {
-                hir::ExprKind::Assign(P(self.lower_expr(el)), P(self.lower_expr(er)))
+            ExprKind::Assign(ref el, ref er, span) => {
+                hir::ExprKind::Assign(P(self.lower_expr(el)), P(self.lower_expr(er)), span)
             }
             ExprKind::AssignOp(op, ref el, ref er) => hir::ExprKind::AssignOp(
                 self.lower_binop(op),
@@ -994,8 +994,11 @@ fn lower_expr_for(
             let (val_pat, val_pat_hid) = self.pat_ident(pat.span, val_ident);
             let val_expr = P(self.expr_ident(pat.span, val_ident, val_pat_hid));
             let next_expr = P(self.expr_ident(pat.span, next_ident, next_pat_hid));
-            let assign =
-                P(self.expr(pat.span, hir::ExprKind::Assign(next_expr, val_expr), ThinVec::new()));
+            let assign = P(self.expr(
+                pat.span,
+                hir::ExprKind::Assign(next_expr, val_expr, pat.span),
+                ThinVec::new(),
+            ));
             let some_pat = self.pat_some(pat.span, val_pat);
             self.arm(some_pat, assign)
         };
index 915b0afc48fcb0b3f4d55d35676aea622312ef5e..bf95324d776dc12fe0d87b1368781237f3b0eeb6 100644 (file)
@@ -1690,7 +1690,8 @@ pub enum ExprKind {
     Block(P<Block>, Option<Label>),
 
     /// An assignment (e.g., `a = foo()`).
-    Assign(P<Expr>, P<Expr>),
+    /// The `Span` argument is the span of the `=` token.
+    Assign(P<Expr>, P<Expr>, Span),
     /// An assignment with an operator.
     ///
     /// E.g., `a += 1`.
index 767e53f9519013173f736b81ea4fe8c934d9087f..2f3b6f82ee5ee206e22cf3b2a3453c26fefd7668 100644 (file)
@@ -1289,7 +1289,7 @@ pub fn print_expr(&mut self, expr: &hir::Expr) {
                 self.ibox(0);
                 self.print_block(&blk);
             }
-            hir::ExprKind::Assign(ref lhs, ref rhs) => {
+            hir::ExprKind::Assign(ref lhs, ref rhs, _) => {
                 let prec = AssocOp::Assign.precedence() as i8;
                 self.print_expr_maybe_paren(&lhs, prec + 1);
                 self.s.space();
@@ -2265,7 +2265,7 @@ fn contains_exterior_struct_lit(value: &hir::Expr) -> bool {
     match value.kind {
         hir::ExprKind::Struct(..) => true,
 
-        hir::ExprKind::Assign(ref lhs, ref rhs)
+        hir::ExprKind::Assign(ref lhs, ref rhs, _)
         | hir::ExprKind::AssignOp(_, ref lhs, ref rhs)
         | hir::ExprKind::Binary(_, ref lhs, ref rhs) => {
             // `X { y: 1 } + X { y: 2 }`
index 6bdb77bb804f46536138630577d4eabfa22ce46f..5f57aabe8d426bc53e9ea28d88d44c2235d3a85a 100644 (file)
@@ -490,7 +490,7 @@ fn check_expr(&mut self, cx: &EarlyContext<'_>, e: &ast::Expr) {
                 (value, "`return` value", false, Some(left), None)
             }
 
-            Assign(_, ref value) => (value, "assigned value", false, None, None),
+            Assign(_, ref value, _) => (value, "assigned value", false, None, None),
             AssignOp(.., ref value) => (value, "assigned value", false, None, None),
             // either function/method call, or something this lint doesn't care about
             ref call_or_other => {
index bfeb3c40e28e8789abd27f01ab0c314db05b5166..b5cd24bebc33ab2921f369fe710a0aa4deb122e5 100644 (file)
@@ -227,7 +227,7 @@ fn make_mirror_unadjusted<'a, 'tcx>(cx: &mut Cx<'a, 'tcx>, expr: &'tcx hir::Expr
 
         hir::ExprKind::Block(ref blk, _) => ExprKind::Block { body: &blk },
 
-        hir::ExprKind::Assign(ref lhs, ref rhs) => {
+        hir::ExprKind::Assign(ref lhs, ref rhs, _) => {
             ExprKind::Assign { lhs: lhs.to_ref(), rhs: rhs.to_ref() }
         }
 
index fa68ddf272a84ab8963e8afd6c93a1f8f864ef61..e0eb841f2c0cfd17e99417446125d2fc05b956e0 100644 (file)
@@ -281,7 +281,9 @@ pub(super) fn parse_assoc_expr_with(
                     let binary = self.mk_binary(source_map::respan(cur_op_span, ast_op), lhs, rhs);
                     self.mk_expr(span, binary, AttrVec::new())
                 }
-                AssocOp::Assign => self.mk_expr(span, ExprKind::Assign(lhs, rhs), AttrVec::new()),
+                AssocOp::Assign => {
+                    self.mk_expr(span, ExprKind::Assign(lhs, rhs, cur_op_span), AttrVec::new())
+                }
                 AssocOp::AssignOp(k) => {
                     let aop = match k {
                         token::Plus => BinOpKind::Add,
index ee6a67802ade38237ee305cb972dbf822e797f3b..1d5e65c6d27cd39f35cbc918339bdf0248b90105 100644 (file)
@@ -737,8 +737,14 @@ fn visit_generics(&mut self, generics: &'a Generics) {
         for predicate in &generics.where_clause.predicates {
             if let WherePredicate::EqPredicate(ref predicate) = *predicate {
                 self.err_handler()
-                    .span_err(predicate.span, "equality constraints are not yet \
-                                               supported in where clauses (see #20041)");
+                    .struct_span_err(
+                        predicate.span,
+                        "equality constraints are not yet supported in `where` clauses",
+                    )
+                    .note(
+                        "for more information, see https://github.com/rust-lang/rust/issues/20041",
+                    )
+                    .emit();
             }
         }
 
index de532421bfb032680b8a82970db7083a5d671c9b..1a8abeb7abcdc34a310ea7fee43380b423b45942 100644 (file)
@@ -1079,7 +1079,7 @@ fn propagate_through_expr(&mut self, expr: &Expr, succ: LiveNode) -> LiveNode {
                     .unwrap_or_else(|| span_bug!(expr.span, "continue to unknown label"))
             }
 
-            hir::ExprKind::Assign(ref l, ref r) => {
+            hir::ExprKind::Assign(ref l, ref r, _) => {
                 // see comment on places in
                 // propagate_through_place_components()
                 let succ = self.write_place(&l, succ, ACC_WRITE);
@@ -1373,7 +1373,7 @@ fn visit_arm(&mut self, arm: &'tcx hir::Arm) {
 
 fn check_expr<'tcx>(this: &mut Liveness<'_, 'tcx>, expr: &'tcx Expr) {
     match expr.kind {
-        hir::ExprKind::Assign(ref l, _) => {
+        hir::ExprKind::Assign(ref l, ..) => {
             this.check_place(&l);
         }
 
index f7e48907e0141257af96fe784e082cb3d81637eb..cdfcb8090e65ee2318832935492e5031e7c84f56 100644 (file)
@@ -1251,7 +1251,7 @@ fn visit_expr(&mut self, expr: &'tcx hir::Expr) {
             return;
         }
         match expr.kind {
-            hir::ExprKind::Assign(.., ref rhs) | hir::ExprKind::Match(ref rhs, ..) => {
+            hir::ExprKind::Assign(_, ref rhs, _) | hir::ExprKind::Match(ref rhs, ..) => {
                 // Do not report duplicate errors for `x = y` and `match x { ... }`.
                 if self.check_expr_pat_type(rhs.hir_id, rhs.span) {
                     return;
index 3a25786365b483d26dcee63c93ac7bbde45171a8..9a14b75ca2f4dc4ec66be06434e117e04ba1efe4 100644 (file)
@@ -490,7 +490,7 @@ pub fn check_ref(
                             String::new()
                         };
                         if let Some(hir::Node::Expr(hir::Expr {
-                            kind: hir::ExprKind::Assign(left_expr, _),
+                            kind: hir::ExprKind::Assign(left_expr, ..),
                             ..
                         })) = self.tcx.hir().find(self.tcx.hir().get_parent_node(expr.hir_id))
                         {
index 6ecf3ccd6e7ed65abf470a985cfad859cb201a75..5c602ad76cd32d05090fdd36e54d31f0f5bf6239 100644 (file)
@@ -17,7 +17,7 @@
 use crate::util::common::ErrorReported;
 use crate::util::nodemap::FxHashMap;
 
-use errors::{pluralize, Applicability, DiagnosticBuilder};
+use errors::{pluralize, Applicability, DiagnosticBuilder, DiagnosticId};
 use rustc::hir;
 use rustc::hir::def::{CtorKind, DefKind, Res};
 use rustc::hir::def_id::DefId;
@@ -219,6 +219,9 @@ fn check_expr_kind(
             ExprKind::Box(ref subexpr) => self.check_expr_box(subexpr, expected),
             ExprKind::Lit(ref lit) => self.check_lit(&lit, expected),
             ExprKind::Binary(op, ref lhs, ref rhs) => self.check_binop(expr, op, lhs, rhs),
+            ExprKind::Assign(ref lhs, ref rhs, ref span) => {
+                self.check_expr_assign(expr, expected, lhs, rhs, span)
+            }
             ExprKind::AssignOp(op, ref lhs, ref rhs) => self.check_binop_assign(expr, op, lhs, rhs),
             ExprKind::Unary(unop, ref oprnd) => {
                 self.check_expr_unary(unop, oprnd, expected, needs, expr)
@@ -245,7 +248,6 @@ fn check_expr_kind(
                 }
             }
             ExprKind::Ret(ref expr_opt) => self.check_expr_return(expr_opt.as_deref(), expr),
-            ExprKind::Assign(ref lhs, ref rhs) => self.check_expr_assign(expr, expected, lhs, rhs),
             ExprKind::Loop(ref body, _, source) => {
                 self.check_expr_loop(body, source, expected, expr)
             }
@@ -723,6 +725,40 @@ pub(super) fn check_return_expr(&self, return_expr: &'tcx hir::Expr) {
         );
     }
 
+    fn is_destructuring_place_expr(&self, expr: &'tcx hir::Expr) -> bool {
+        match &expr.kind {
+            ExprKind::Array(comps) | ExprKind::Tup(comps) => {
+                comps.iter().all(|e| self.is_destructuring_place_expr(e))
+            }
+            ExprKind::Struct(_path, fields, rest) => {
+                rest.as_ref().map(|e| self.is_destructuring_place_expr(e)).unwrap_or(true)
+                    && fields.iter().all(|f| self.is_destructuring_place_expr(&f.expr))
+            }
+            _ => expr.is_syntactic_place_expr(),
+        }
+    }
+
+    pub(crate) fn check_lhs_assignable(
+        &self,
+        lhs: &'tcx hir::Expr,
+        err_code: &'static str,
+        expr_span: &Span,
+    ) {
+        if !lhs.is_syntactic_place_expr() {
+            let mut err = self.tcx.sess.struct_span_err_with_code(
+                *expr_span,
+                "invalid left-hand side of assignment",
+                DiagnosticId::Error(err_code.into()),
+            );
+            err.span_label(lhs.span, "cannot assign to this expression");
+            if self.is_destructuring_place_expr(lhs) {
+                err.note("destructuring assignments are not currently supported");
+                err.note("for more information, see https://github.com/rust-lang/rfcs/issues/372");
+            }
+            err.emit();
+        }
+    }
+
     /// Type check assignment expression `expr` of form `lhs = rhs`.
     /// The expected type is `()` and is passsed to the function for the purposes of diagnostics.
     fn check_expr_assign(
@@ -731,6 +767,7 @@ fn check_expr_assign(
         expected: Expectation<'tcx>,
         lhs: &'tcx hir::Expr,
         rhs: &'tcx hir::Expr,
+        span: &Span,
     ) -> Ty<'tcx> {
         let lhs_ty = self.check_expr_with_needs(&lhs, Needs::MutPlace);
         let rhs_ty = self.check_expr_coercable_to_type(&rhs, lhs_ty);
@@ -752,10 +789,8 @@ fn check_expr_assign(
                 err.help(msg);
             }
             err.emit();
-        } else if !lhs.is_syntactic_place_expr() {
-            struct_span_err!(self.tcx.sess, expr.span, E0070, "invalid left-hand side expression")
-                .span_label(expr.span, "left-hand of expression not valid")
-                .emit();
+        } else {
+            self.check_lhs_assignable(lhs, "E0070", span);
         }
 
         self.require_type_is_sized(lhs_ty, lhs.span, traits::AssignmentLhsSized);
index 53475569b2c3f37e7198c1a185c9709efe378594..c5d3aac136bcbd64ca94c84956b8ffd7fd139eec 100644 (file)
@@ -19,30 +19,22 @@ pub fn check_binop_assign(
         &self,
         expr: &'tcx hir::Expr,
         op: hir::BinOp,
-        lhs_expr: &'tcx hir::Expr,
-        rhs_expr: &'tcx hir::Expr,
+        lhs: &'tcx hir::Expr,
+        rhs: &'tcx hir::Expr,
     ) -> Ty<'tcx> {
         let (lhs_ty, rhs_ty, return_ty) =
-            self.check_overloaded_binop(expr, lhs_expr, rhs_expr, op, IsAssign::Yes);
+            self.check_overloaded_binop(expr, lhs, rhs, op, IsAssign::Yes);
 
         let ty =
             if !lhs_ty.is_ty_var() && !rhs_ty.is_ty_var() && is_builtin_binop(lhs_ty, rhs_ty, op) {
-                self.enforce_builtin_binop_types(lhs_expr, lhs_ty, rhs_expr, rhs_ty, op);
+                self.enforce_builtin_binop_types(lhs, lhs_ty, rhs, rhs_ty, op);
                 self.tcx.mk_unit()
             } else {
                 return_ty
             };
 
-        if !lhs_expr.is_syntactic_place_expr() {
-            struct_span_err!(
-                self.tcx.sess,
-                lhs_expr.span,
-                E0067,
-                "invalid left-hand side expression"
-            )
-            .span_label(lhs_expr.span, "invalid expression for left-hand side")
-            .emit();
-        }
+        self.check_lhs_assignable(lhs, "E0067", &op.span);
+
         ty
     }
 
index 58baf24438bd05f3529926481b017ab0d7b04905..6c7e3658365a060e5989b8e0971826b5f3c3f017 100644 (file)
@@ -286,7 +286,7 @@ pub fn walk_expr(&mut self, expr: &hir::Expr) {
                 }
             }
 
-            hir::ExprKind::Assign(ref lhs, ref rhs) => {
+            hir::ExprKind::Assign(ref lhs, ref rhs, _) => {
                 self.mutate_expr(lhs);
                 self.consume_expr(rhs);
             }
index 9009faa544004ba87c590d6ce1d216aab9adf8f6..c98942abaf3c2ae26ec390c1add4ca09d856acc9 100644 (file)
@@ -1216,7 +1216,8 @@ pub enum ExprKind {
     TryBlock(P<Block>),
 
     /// An assignment (`a = foo()`).
-    Assign(P<Expr>, P<Expr>),
+    /// The `Span` argument is the span of the `=` token.
+    Assign(P<Expr>, P<Expr>, Span),
     /// An assignment with an operator.
     ///
     /// E.g., `a += 1`.
index 780323d114eda374cc0730297df066b7c218fd45..f6817c713a4a66f20bf4690a8db3d217436f3cb8 100644 (file)
@@ -1168,7 +1168,7 @@ pub fn noop_visit_expr<T: MutVisitor>(Expr { kind, id, span, attrs }: &mut Expr,
             vis.visit_block(body);
         }
         ExprKind::Await(expr) => vis.visit_expr(expr),
-        ExprKind::Assign(el, er) => {
+        ExprKind::Assign(el, er, _) => {
             vis.visit_expr(el);
             vis.visit_expr(er);
         }
index dc01f2472b7f0899441e8d4489ed567fe1474201..b1b667f03bee2be489ebc4628e5cd0481161edc0 100644 (file)
@@ -2041,7 +2041,7 @@ fn print_expr_outer_attr_style(&mut self, expr: &ast::Expr, is_inline: bool) {
                 self.print_expr_maybe_paren(expr, parser::PREC_POSTFIX);
                 self.s.word(".await");
             }
-            ast::ExprKind::Assign(ref lhs, ref rhs) => {
+            ast::ExprKind::Assign(ref lhs, ref rhs, _) => {
                 let prec = AssocOp::Assign.precedence() as i8;
                 self.print_expr_maybe_paren(lhs, prec + 1);
                 self.s.space();
index 88e3d8daf70478842683eb41267d2afa4c175ac6..98af382efb0838672460775b8cc2a5b4c0ffb913 100644 (file)
@@ -378,7 +378,7 @@ pub fn contains_exterior_struct_lit(value: &ast::Expr) -> bool {
     match value.kind {
         ast::ExprKind::Struct(..) => true,
 
-        ast::ExprKind::Assign(ref lhs, ref rhs)
+        ast::ExprKind::Assign(ref lhs, ref rhs, _)
         | ast::ExprKind::AssignOp(_, ref lhs, ref rhs)
         | ast::ExprKind::Binary(_, ref lhs, ref rhs) => {
             // X { y: 1 } + X { y: 2 }
index d6573a06647d157f354823dd32419a4ed03b2173..fbc5d1332490fc8e70399201fe04bdb17341c84c 100644 (file)
@@ -766,9 +766,9 @@ pub fn walk_expr<'a, V: Visitor<'a>>(visitor: &mut V, expression: &'a Expr) {
             visitor.visit_block(body);
         }
         ExprKind::Await(ref expr) => visitor.visit_expr(expr),
-        ExprKind::Assign(ref left_hand_expression, ref right_hand_expression) => {
-            visitor.visit_expr(left_hand_expression);
-            visitor.visit_expr(right_hand_expression);
+        ExprKind::Assign(ref lhs, ref rhs, _) => {
+            visitor.visit_expr(lhs);
+            visitor.visit_expr(rhs);
         }
         ExprKind::AssignOp(_, ref left_expression, ref right_expression) => {
             visitor.visit_expr(left_expression);
index 0c050e314133e49e84865c08ff8abf02568a683f..36d47cea13b07cd4d2ff1d3cad2d0d32a853f0eb 100644 (file)
@@ -126,8 +126,8 @@ fn iter_exprs(depth: usize, f: &mut dyn FnMut(P<Expr>)) {
                                           DUMMY_SP)));
             },
             12 => {
-                iter_exprs(depth - 1, &mut |e| g(ExprKind::Assign(e, make_x())));
-                iter_exprs(depth - 1, &mut |e| g(ExprKind::Assign(make_x(), e)));
+                iter_exprs(depth - 1, &mut |e| g(ExprKind::Assign(e, make_x(), DUMMY_SP)));
+                iter_exprs(depth - 1, &mut |e| g(ExprKind::Assign(make_x(), e, DUMMY_SP)));
             },
             13 => {
                 iter_exprs(depth - 1, &mut |e| g(ExprKind::Field(e, Ident::from_str("f"))));
index 2cd8bc9d47333c42fce1880a62cea2d95eea0859..d7cf1b77005145bd74e9ae31b847ebdcb1b5934a 100644 (file)
@@ -1,10 +1,10 @@
 fn main() {
-    1 = 2; //~ ERROR invalid left-hand side expression
-    1 += 2; //~ ERROR invalid left-hand side expression
-    (1, 2) = (3, 4); //~ ERROR invalid left-hand side expression
+    1 = 2; //~ ERROR invalid left-hand side of assignment
+    1 += 2; //~ ERROR invalid left-hand side of assignment
+    (1, 2) = (3, 4); //~ ERROR invalid left-hand side of assignment
 
     let (a, b) = (1, 2);
-    (a, b) = (3, 4); //~ ERROR invalid left-hand side expression
+    (a, b) = (3, 4); //~ ERROR invalid left-hand side of assignment
 
-    None = Some(3); //~ ERROR invalid left-hand side expression
+    None = Some(3); //~ ERROR invalid left-hand side of assignment
 }
index a0de6a73797e280dfe0fa1018df2f7981aa9c73c..a195e1054d099e7b4211df6e3be396951cdbbfbd 100644 (file)
@@ -1,32 +1,45 @@
-error[E0070]: invalid left-hand side expression
-  --> $DIR/bad-expr-lhs.rs:2:5
+error[E0070]: invalid left-hand side of assignment
+  --> $DIR/bad-expr-lhs.rs:2:7
    |
 LL |     1 = 2;
-   |     ^^^^^ left-hand of expression not valid
+   |     - ^
+   |     |
+   |     cannot assign to this expression
 
-error[E0067]: invalid left-hand side expression
-  --> $DIR/bad-expr-lhs.rs:3:5
+error[E0067]: invalid left-hand side of assignment
+  --> $DIR/bad-expr-lhs.rs:3:7
    |
 LL |     1 += 2;
-   |     ^ invalid expression for left-hand side
+   |     - ^^
+   |     |
+   |     cannot assign to this expression
 
-error[E0070]: invalid left-hand side expression
-  --> $DIR/bad-expr-lhs.rs:4:5
+error[E0070]: invalid left-hand side of assignment
+  --> $DIR/bad-expr-lhs.rs:4:12
    |
 LL |     (1, 2) = (3, 4);
-   |     ^^^^^^^^^^^^^^^ left-hand of expression not valid
+   |     ------ ^
+   |     |
+   |     cannot assign to this expression
 
-error[E0070]: invalid left-hand side expression
-  --> $DIR/bad-expr-lhs.rs:7:5
+error[E0070]: invalid left-hand side of assignment
+  --> $DIR/bad-expr-lhs.rs:7:12
    |
 LL |     (a, b) = (3, 4);
-   |     ^^^^^^^^^^^^^^^ left-hand of expression not valid
+   |     ------ ^
+   |     |
+   |     cannot assign to this expression
+   |
+   = note: destructuring assignments are not currently supported
+   = note: for more information, see https://github.com/rust-lang/rfcs/issues/372
 
-error[E0070]: invalid left-hand side expression
-  --> $DIR/bad-expr-lhs.rs:9:5
+error[E0070]: invalid left-hand side of assignment
+  --> $DIR/bad-expr-lhs.rs:9:10
    |
 LL |     None = Some(3);
-   |     ^^^^^^^^^^^^^^ left-hand of expression not valid
+   |     ---- ^
+   |     |
+   |     cannot assign to this expression
 
 error: aborting due to 5 previous errors
 
diff --git a/src/test/ui/destructuring-assignment/note-unsupported.rs b/src/test/ui/destructuring-assignment/note-unsupported.rs
new file mode 100644 (file)
index 0000000..876c9ef
--- /dev/null
@@ -0,0 +1,25 @@
+struct S { x: u8, y: u8 }
+
+fn main() {
+    let (a, b) = (1, 2);
+
+    (a, b) = (3, 4); //~ ERROR invalid left-hand side of assignment
+    (a, b) += (3, 4); //~ ERROR invalid left-hand side of assignment
+    //~^ ERROR binary assignment operation `+=` cannot be applied
+
+    [a, b] = [3, 4]; //~ ERROR invalid left-hand side of assignment
+    [a, b] += [3, 4]; //~ ERROR invalid left-hand side of assignment
+    //~^ ERROR binary assignment operation `+=` cannot be applied
+
+    let s = S { x: 3, y: 4 };
+
+    S { x: a, y: b } = s; //~ ERROR invalid left-hand side of assignment
+    S { x: a, y: b } += s; //~ ERROR invalid left-hand side of assignment
+    //~^ ERROR binary assignment operation `+=` cannot be applied
+
+    S { x: a, ..s } = S { x: 3, y: 4 }; //~ ERROR invalid left-hand side of assignment
+
+    let c = 3;
+
+    ((a, b), c) = ((3, 4), 5); //~ ERROR invalid left-hand side of assignment
+}
diff --git a/src/test/ui/destructuring-assignment/note-unsupported.stderr b/src/test/ui/destructuring-assignment/note-unsupported.stderr
new file mode 100644 (file)
index 0000000..a6805c3
--- /dev/null
@@ -0,0 +1,122 @@
+error[E0070]: invalid left-hand side of assignment
+  --> $DIR/note-unsupported.rs:6:12
+   |
+LL |     (a, b) = (3, 4);
+   |     ------ ^
+   |     |
+   |     cannot assign to this expression
+   |
+   = note: destructuring assignments are not currently supported
+   = note: for more information, see https://github.com/rust-lang/rfcs/issues/372
+
+error[E0368]: binary assignment operation `+=` cannot be applied to type `({integer}, {integer})`
+  --> $DIR/note-unsupported.rs:7:5
+   |
+LL |     (a, b) += (3, 4);
+   |     ------^^^^^^^^^^
+   |     |
+   |     cannot use `+=` on type `({integer}, {integer})`
+   |
+   = note: an implementation of `std::ops::AddAssign` might be missing for `({integer}, {integer})`
+
+error[E0067]: invalid left-hand side of assignment
+  --> $DIR/note-unsupported.rs:7:12
+   |
+LL |     (a, b) += (3, 4);
+   |     ------ ^^
+   |     |
+   |     cannot assign to this expression
+   |
+   = note: destructuring assignments are not currently supported
+   = note: for more information, see https://github.com/rust-lang/rfcs/issues/372
+
+error[E0070]: invalid left-hand side of assignment
+  --> $DIR/note-unsupported.rs:10:12
+   |
+LL |     [a, b] = [3, 4];
+   |     ------ ^
+   |     |
+   |     cannot assign to this expression
+   |
+   = note: destructuring assignments are not currently supported
+   = note: for more information, see https://github.com/rust-lang/rfcs/issues/372
+
+error[E0368]: binary assignment operation `+=` cannot be applied to type `[{integer}; 2]`
+  --> $DIR/note-unsupported.rs:11:5
+   |
+LL |     [a, b] += [3, 4];
+   |     ------^^^^^^^^^^
+   |     |
+   |     cannot use `+=` on type `[{integer}; 2]`
+   |
+   = note: an implementation of `std::ops::AddAssign` might be missing for `[{integer}; 2]`
+
+error[E0067]: invalid left-hand side of assignment
+  --> $DIR/note-unsupported.rs:11:12
+   |
+LL |     [a, b] += [3, 4];
+   |     ------ ^^
+   |     |
+   |     cannot assign to this expression
+   |
+   = note: destructuring assignments are not currently supported
+   = note: for more information, see https://github.com/rust-lang/rfcs/issues/372
+
+error[E0070]: invalid left-hand side of assignment
+  --> $DIR/note-unsupported.rs:16:22
+   |
+LL |     S { x: a, y: b } = s;
+   |     ---------------- ^
+   |     |
+   |     cannot assign to this expression
+   |
+   = note: destructuring assignments are not currently supported
+   = note: for more information, see https://github.com/rust-lang/rfcs/issues/372
+
+error[E0368]: binary assignment operation `+=` cannot be applied to type `S`
+  --> $DIR/note-unsupported.rs:17:5
+   |
+LL |     S { x: a, y: b } += s;
+   |     ----------------^^^^^
+   |     |
+   |     cannot use `+=` on type `S`
+   |
+   = note: an implementation of `std::ops::AddAssign` might be missing for `S`
+
+error[E0067]: invalid left-hand side of assignment
+  --> $DIR/note-unsupported.rs:17:22
+   |
+LL |     S { x: a, y: b } += s;
+   |     ---------------- ^^
+   |     |
+   |     cannot assign to this expression
+   |
+   = note: destructuring assignments are not currently supported
+   = note: for more information, see https://github.com/rust-lang/rfcs/issues/372
+
+error[E0070]: invalid left-hand side of assignment
+  --> $DIR/note-unsupported.rs:20:21
+   |
+LL |     S { x: a, ..s } = S { x: 3, y: 4 };
+   |     --------------- ^
+   |     |
+   |     cannot assign to this expression
+   |
+   = note: destructuring assignments are not currently supported
+   = note: for more information, see https://github.com/rust-lang/rfcs/issues/372
+
+error[E0070]: invalid left-hand side of assignment
+  --> $DIR/note-unsupported.rs:24:17
+   |
+LL |     ((a, b), c) = ((3, 4), 5);
+   |     ----------- ^
+   |     |
+   |     cannot assign to this expression
+   |
+   = note: destructuring assignments are not currently supported
+   = note: for more information, see https://github.com/rust-lang/rfcs/issues/372
+
+error: aborting due to 11 previous errors
+
+Some errors have detailed explanations: E0067, E0070, E0368.
+For more information about an error, try `rustc --explain E0067`.
index 0334565840f833b0193d924f7d9af24f0da74505..526503798b3d47d203fffa9b768b5b9301bf9bff 100644 (file)
@@ -8,11 +8,13 @@ LL |     LinkedList::new() += 1;
    |
    = note: an implementation of `std::ops::AddAssign` might be missing for `std::collections::LinkedList<_>`
 
-error[E0067]: invalid left-hand side expression
-  --> $DIR/E0067.rs:4:5
+error[E0067]: invalid left-hand side of assignment
+  --> $DIR/E0067.rs:4:23
    |
 LL |     LinkedList::new() += 1;
-   |     ^^^^^^^^^^^^^^^^^ invalid expression for left-hand side
+   |     ----------------- ^^
+   |     |
+   |     cannot assign to this expression
 
 error: aborting due to 2 previous errors
 
index 845833bc82f70e1eb0ab2f5f5d8476af5005b278..d809bb18dee16a0fc75d5fa86247711f6921eddb 100644 (file)
@@ -1,14 +1,18 @@
-error[E0070]: invalid left-hand side expression
-  --> $DIR/E0070.rs:6:5
+error[E0070]: invalid left-hand side of assignment
+  --> $DIR/E0070.rs:6:16
    |
 LL |     SOME_CONST = 14;
-   |     ^^^^^^^^^^^^^^^ left-hand of expression not valid
+   |     ---------- ^
+   |     |
+   |     cannot assign to this expression
 
-error[E0070]: invalid left-hand side expression
-  --> $DIR/E0070.rs:7:5
+error[E0070]: invalid left-hand side of assignment
+  --> $DIR/E0070.rs:7:7
    |
 LL |     1 = 3;
-   |     ^^^^^ left-hand of expression not valid
+   |     - ^
+   |     |
+   |     cannot assign to this expression
 
 error[E0308]: mismatched types
   --> $DIR/E0070.rs:8:25
@@ -16,11 +20,13 @@ error[E0308]: mismatched types
 LL |     some_other_func() = 4;
    |                         ^ expected `()`, found integer
 
-error[E0070]: invalid left-hand side expression
-  --> $DIR/E0070.rs:8:5
+error[E0070]: invalid left-hand side of assignment
+  --> $DIR/E0070.rs:8:23
    |
 LL |     some_other_func() = 4;
-   |     ^^^^^^^^^^^^^^^^^^^^^ left-hand of expression not valid
+   |     ----------------- ^
+   |     |
+   |     cannot assign to this expression
 
 error: aborting due to 4 previous errors
 
index 322e67cc131802f629084e4ab96694ef628ba26b..fa53d55f5b3d7240b7dc9a97224ee00976c38c2c 100644 (file)
@@ -4,7 +4,7 @@ mod A {
 
 fn main() {
     A::C = 1;
-    //~^ ERROR: invalid left-hand side expression
+    //~^ ERROR: invalid left-hand side of assignment
     //~| ERROR: mismatched types
     //~| ERROR: struct `C` is private
 }
index 5a465cc533bb7004fdcc2b9f8375412d934443e7..b280de3158fede7567b64391c728f6464b685e13 100644 (file)
@@ -10,11 +10,13 @@ error[E0308]: mismatched types
 LL |     A::C = 1;
    |            ^ expected struct `A::C`, found integer
 
-error[E0070]: invalid left-hand side expression
-  --> $DIR/issue-13407.rs:6:5
+error[E0070]: invalid left-hand side of assignment
+  --> $DIR/issue-13407.rs:6:10
    |
 LL |     A::C = 1;
-   |     ^^^^^^^^ left-hand of expression not valid
+   |     ---- ^
+   |     |
+   |     cannot assign to this expression
 
 error: aborting due to 3 previous errors
 
index 7895c90068fe2ebf4e7393c24b840ca4ed32ff4a..c838515caf997e6f6a8ba6ad2a06ea124256354a 100644 (file)
@@ -1,7 +1,9 @@
 macro_rules! not_a_place {
     ($thing:expr) => {
         $thing = 42;
-        //~^ ERROR invalid left-hand side expression
+        //~^ ERROR invalid left-hand side of assignment
+        $thing += 42;
+        //~^ ERROR invalid left-hand side of assignment
     }
 }
 
index 947c52f08d2e6c794d25f8758ea1b283f4fca4be..c96228b518a853bf59eeebdeda607a447622ca04 100644 (file)
@@ -1,12 +1,28 @@
-error[E0070]: invalid left-hand side expression
-  --> $DIR/issue-26093.rs:3:9
+error[E0070]: invalid left-hand side of assignment
+  --> $DIR/issue-26093.rs:3:16
    |
 LL |         $thing = 42;
-   |         ^^^^^^^^^^^ left-hand of expression not valid
+   |                ^
 ...
 LL |     not_a_place!(99);
-   |     ----------------- in this macro invocation
+   |     -----------------
+   |     |            |
+   |     |            cannot assign to this expression
+   |     in this macro invocation
 
-error: aborting due to previous error
+error[E0067]: invalid left-hand side of assignment
+  --> $DIR/issue-26093.rs:5:16
+   |
+LL |         $thing += 42;
+   |                ^^
+...
+LL |     not_a_place!(99);
+   |     -----------------
+   |     |            |
+   |     |            cannot assign to this expression
+   |     in this macro invocation
+
+error: aborting due to 2 previous errors
 
-For more information about this error, try `rustc --explain E0070`.
+Some errors have detailed explanations: E0067, E0070.
+For more information about an error, try `rustc --explain E0067`.
index 4457d71cbb4a7b132df872e73bf31f5ba56cecf7..e34b5c9a0f47e3a7b84a3902ce756769ce4808d1 100644 (file)
@@ -3,7 +3,7 @@ fn main () {
     //~^ ERROR expected one of `,` or `>`, found `=`
     //~| ERROR expected value, found struct `Vec`
     //~| ERROR mismatched types
-    //~| ERROR invalid left-hand side expression
+    //~| ERROR invalid left-hand side of assignment
     //~| ERROR expected expression, found reserved identifier `_`
     //~| ERROR expected expression, found reserved identifier `_`
     let sr2: Vec<(u32, _, _)> = sr.iter().map(|(faction, th_sender, th_receiver)| {}).collect();
index fc90e0674cf55d2f7f9ed327e7b73d1defc8054d..3055e316a082a381197317e563b7dc2601956aca 100644 (file)
@@ -35,11 +35,13 @@ LL |     let sr: Vec<(u32, _, _) = vec![];
             found struct `std::vec::Vec<_>`
    = note: this error originates in a macro outside of the current crate (in Nightly builds, run with -Z external-macro-backtrace for more info)
 
-error[E0070]: invalid left-hand side expression
-  --> $DIR/issue-34334.rs:2:13
+error[E0070]: invalid left-hand side of assignment
+  --> $DIR/issue-34334.rs:2:29
    |
 LL |     let sr: Vec<(u32, _, _) = vec![];
-   |             ^^^^^^^^^^^^^^^^^^^^^^^^ left-hand of expression not valid
+   |             --------------- ^
+   |             |
+   |             cannot assign to this expression
 
 error[E0599]: no method named `iter` found for type `()` in the current scope
   --> $DIR/issue-34334.rs:9:36
index 03830fea062cf7d660f63c0da91af450a45d703b..191939bdb705b4d09d02df1d8ca3ea056db351cf 100644 (file)
@@ -30,5 +30,5 @@ fn main() {
     // A test to check that not expecting `bool` behaves well:
     let _: usize = 0 = 0;
     //~^ ERROR mismatched types [E0308]
-    //~| ERROR invalid left-hand side expression [E0070]
+    //~| ERROR invalid left-hand side of assignment [E0070]
 }
index 9a1cf5b25625ccb6df818b5a4e011d242801b4c2..3f1caddf728cbead005a00cd44e78c3b8d66ac54 100644 (file)
@@ -97,11 +97,13 @@ LL |         || (0 = 0);
    |            expected `bool`, found `()`
    |            help: try comparing for equality: `0 == 0`
 
-error[E0070]: invalid left-hand side expression
-  --> $DIR/assignment-expected-bool.rs:31:20
+error[E0070]: invalid left-hand side of assignment
+  --> $DIR/assignment-expected-bool.rs:31:22
    |
 LL |     let _: usize = 0 = 0;
-   |                    ^^^^^ left-hand of expression not valid
+   |                    - ^
+   |                    |
+   |                    cannot assign to this expression
 
 error[E0308]: mismatched types
   --> $DIR/assignment-expected-bool.rs:31:20
index 77b122b0a794a779c22dad1ebd69379973c86833..8da7b32b47b14ca21f015c09dc69251041aea895 100644 (file)
@@ -26,7 +26,7 @@ fn main() {
         //~^ ERROR mismatched types
         println!("{}", x);
     }
-    // "invalid left-hand side expression" error is suppresed
+    // "invalid left-hand side of assignment" error is suppresed
     if 3 = x {
         //~^ ERROR mismatched types
         println!("{}", x);
index f2349144b88ae7042edfd52551eeb29483fb450f..8828f09d92d333d548a320d148ca66140dce8f51 100644 (file)
@@ -1,6 +1,6 @@
 fn f() where u8 = u16 {}
-//~^ ERROR equality constraints are not yet supported in where clauses
+//~^ ERROR equality constraints are not yet supported in `where` clauses
 fn g() where for<'a> &'static (u8,) == u16, {}
-//~^ ERROR equality constraints are not yet supported in where clauses
+//~^ ERROR equality constraints are not yet supported in `where` clauses
 
 fn main() {}
index 220447079c629f88ed84f6d0d838963c312abbca..c0241fe708f6451e0aaaec7e76b5153c53fe3171 100644 (file)
@@ -1,14 +1,18 @@
-error: equality constraints are not yet supported in where clauses (see #20041)
+error: equality constraints are not yet supported in `where` clauses
   --> $DIR/where-equality-constraints.rs:1:14
    |
 LL | fn f() where u8 = u16 {}
    |              ^^^^^^^^
+   |
+   = note: for more information, see https://github.com/rust-lang/rust/issues/20041
 
-error: equality constraints are not yet supported in where clauses (see #20041)
+error: equality constraints are not yet supported in `where` clauses
   --> $DIR/where-equality-constraints.rs:3:14
    |
 LL | fn g() where for<'a> &'static (u8,) == u16, {}
    |              ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |
+   = note: for more information, see https://github.com/rust-lang/rust/issues/20041
 
 error: aborting due to 2 previous errors