@@ -17,7 +17,7 @@ use crate::check::TupleArgumentsFlag::DontTupleArguments;
17
17
use crate :: util:: common:: ErrorReported ;
18
18
use crate :: util:: nodemap:: FxHashMap ;
19
19
20
- use errors:: { pluralize, Applicability , DiagnosticBuilder } ;
20
+ use errors:: { pluralize, Applicability , DiagnosticBuilder , DiagnosticId } ;
21
21
use rustc:: hir;
22
22
use rustc:: hir:: def:: { CtorKind , DefKind , Res } ;
23
23
use rustc:: hir:: def_id:: DefId ;
@@ -219,6 +219,9 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
219
219
ExprKind :: Box ( ref subexpr) => self . check_expr_box ( subexpr, expected) ,
220
220
ExprKind :: Lit ( ref lit) => self . check_lit ( & lit, expected) ,
221
221
ExprKind :: Binary ( op, ref lhs, ref rhs) => self . check_binop ( expr, op, lhs, rhs) ,
222
+ ExprKind :: Assign ( ref lhs, ref rhs, ref span) => {
223
+ self . check_expr_assign ( expr, expected, lhs, rhs, span)
224
+ }
222
225
ExprKind :: AssignOp ( op, ref lhs, ref rhs) => self . check_binop_assign ( expr, op, lhs, rhs) ,
223
226
ExprKind :: Unary ( unop, ref oprnd) => {
224
227
self . check_expr_unary ( unop, oprnd, expected, needs, expr)
@@ -245,7 +248,6 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
245
248
}
246
249
}
247
250
ExprKind :: Ret ( ref expr_opt) => self . check_expr_return ( expr_opt. as_deref ( ) , expr) ,
248
- ExprKind :: Assign ( ref lhs, ref rhs) => self . check_expr_assign ( expr, expected, lhs, rhs) ,
249
251
ExprKind :: Loop ( ref body, _, source) => {
250
252
self . check_expr_loop ( body, source, expected, expr)
251
253
}
@@ -723,6 +725,40 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
723
725
) ;
724
726
}
725
727
728
+ fn is_destructuring_place_expr ( & self , expr : & ' tcx hir:: Expr ) -> bool {
729
+ match & expr. kind {
730
+ ExprKind :: Array ( comps) | ExprKind :: Tup ( comps) => {
731
+ comps. iter ( ) . all ( |e| self . is_destructuring_place_expr ( e) )
732
+ }
733
+ ExprKind :: Struct ( _path, fields, rest) => {
734
+ rest. as_ref ( ) . map ( |e| self . is_destructuring_place_expr ( e) ) . unwrap_or ( true )
735
+ && fields. iter ( ) . all ( |f| self . is_destructuring_place_expr ( & f. expr ) )
736
+ }
737
+ _ => expr. is_syntactic_place_expr ( ) ,
738
+ }
739
+ }
740
+
741
+ pub ( crate ) fn check_lhs_assignable (
742
+ & self ,
743
+ lhs : & ' tcx hir:: Expr ,
744
+ err_code : & ' static str ,
745
+ expr_span : & Span ,
746
+ ) {
747
+ if !lhs. is_syntactic_place_expr ( ) {
748
+ let mut err = self . tcx . sess . struct_span_err_with_code (
749
+ * expr_span,
750
+ "invalid left-hand side of assignment" ,
751
+ DiagnosticId :: Error ( err_code. into ( ) ) ,
752
+ ) ;
753
+ err. span_label ( lhs. span , "cannot assign to this expression" ) ;
754
+ if self . is_destructuring_place_expr ( lhs) {
755
+ err. note ( "destructuring assignments are not currently supported" ) ;
756
+ err. note ( "for more information, see https://github.com/rust-lang/rfcs/issues/372" ) ;
757
+ }
758
+ err. emit ( ) ;
759
+ }
760
+ }
761
+
726
762
/// Type check assignment expression `expr` of form `lhs = rhs`.
727
763
/// The expected type is `()` and is passsed to the function for the purposes of diagnostics.
728
764
fn check_expr_assign (
@@ -731,6 +767,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
731
767
expected : Expectation < ' tcx > ,
732
768
lhs : & ' tcx hir:: Expr ,
733
769
rhs : & ' tcx hir:: Expr ,
770
+ span : & Span ,
734
771
) -> Ty < ' tcx > {
735
772
let lhs_ty = self . check_expr_with_needs ( & lhs, Needs :: MutPlace ) ;
736
773
let rhs_ty = self . check_expr_coercable_to_type ( & rhs, lhs_ty) ;
@@ -752,10 +789,8 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
752
789
err. help ( msg) ;
753
790
}
754
791
err. emit ( ) ;
755
- } else if !lhs. is_syntactic_place_expr ( ) {
756
- struct_span_err ! ( self . tcx. sess, expr. span, E0070 , "invalid left-hand side expression" )
757
- . span_label ( expr. span , "left-hand of expression not valid" )
758
- . emit ( ) ;
792
+ } else {
793
+ self . check_lhs_assignable ( lhs, "E0070" , span) ;
759
794
}
760
795
761
796
self . require_type_is_sized ( lhs_ty, lhs. span , traits:: AssignmentLhsSized ) ;
0 commit comments