@@ -17,7 +17,7 @@ use crate::util::common::ErrorReported;
17
17
use crate :: util:: nodemap:: FxHashMap ;
18
18
use crate :: astconv:: AstConv as _;
19
19
20
- use errors:: { Applicability , DiagnosticBuilder , pluralize} ;
20
+ use errors:: { Applicability , DiagnosticBuilder , DiagnosticId , pluralize} ;
21
21
use syntax_pos:: hygiene:: DesugaringKind ;
22
22
use syntax:: ast;
23
23
use syntax:: symbol:: { Symbol , kw, sym} ;
@@ -230,6 +230,9 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
230
230
ExprKind :: Binary ( op, ref lhs, ref rhs) => {
231
231
self . check_binop ( expr, op, lhs, rhs)
232
232
}
233
+ ExprKind :: Assign ( ref lhs, ref rhs, ref span) => {
234
+ self . check_expr_assign ( expr, expected, lhs, rhs, span)
235
+ }
233
236
ExprKind :: AssignOp ( op, ref lhs, ref rhs) => {
234
237
self . check_binop_assign ( expr, op, lhs, rhs)
235
238
}
@@ -262,9 +265,6 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
262
265
ExprKind :: Ret ( ref expr_opt) => {
263
266
self . check_expr_return ( expr_opt. as_deref ( ) , expr)
264
267
}
265
- ExprKind :: Assign ( ref lhs, ref rhs) => {
266
- self . check_expr_assign ( expr, expected, lhs, rhs)
267
- }
268
268
ExprKind :: Loop ( ref body, _, source) => {
269
269
self . check_expr_loop ( body, source, expected, expr)
270
270
}
@@ -759,6 +759,42 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
759
759
) ;
760
760
}
761
761
762
+ fn is_destructuring_place_expr ( & self , expr : & ' tcx hir:: Expr ) -> bool {
763
+ match & expr. kind {
764
+ ExprKind :: Array ( comps) | ExprKind :: Tup ( comps) => {
765
+ comps. iter ( ) . all ( |e| self . is_destructuring_place_expr ( e) )
766
+ }
767
+ ExprKind :: Struct ( _path, fields, rest) => {
768
+ rest. as_ref ( ) . map ( |e| self . is_destructuring_place_expr ( e) ) . unwrap_or ( true ) &&
769
+ fields. iter ( ) . all ( |f| self . is_destructuring_place_expr ( & f. expr ) )
770
+ }
771
+ _ => expr. is_syntactic_place_expr ( ) ,
772
+ }
773
+ }
774
+
775
+ pub ( crate ) fn check_lhs_assignable (
776
+ & self ,
777
+ lhs : & ' tcx hir:: Expr ,
778
+ err_code : & ' static str ,
779
+ expr_span : & Span ,
780
+ ) {
781
+ if !lhs. is_syntactic_place_expr ( ) {
782
+ let mut err = self . tcx . sess . struct_span_err_with_code (
783
+ * expr_span,
784
+ "invalid left-hand side of assignment" ,
785
+ DiagnosticId :: Error ( err_code. into ( ) ) ,
786
+ ) ;
787
+ err. span_label ( lhs. span , "cannot assign to this expression" ) ;
788
+ if self . is_destructuring_place_expr ( lhs) {
789
+ err. note ( "destructuring assignments are not currently supported" ) ;
790
+ err. note (
791
+ "for more information, see https://github.com/rust-lang/rfcs/issues/372" ,
792
+ ) ;
793
+ }
794
+ err. emit ( ) ;
795
+ }
796
+ }
797
+
762
798
/// Type check assignment expression `expr` of form `lhs = rhs`.
763
799
/// The expected type is `()` and is passsed to the function for the purposes of diagnostics.
764
800
fn check_expr_assign (
@@ -767,6 +803,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
767
803
expected : Expectation < ' tcx > ,
768
804
lhs : & ' tcx hir:: Expr ,
769
805
rhs : & ' tcx hir:: Expr ,
806
+ span : & Span ,
770
807
) -> Ty < ' tcx > {
771
808
let lhs_ty = self . check_expr_with_needs ( & lhs, Needs :: MutPlace ) ;
772
809
let rhs_ty = self . check_expr_coercable_to_type ( & rhs, lhs_ty) ;
@@ -788,11 +825,8 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
788
825
err. help ( msg) ;
789
826
}
790
827
err. emit ( ) ;
791
- } else if !lhs. is_syntactic_place_expr ( ) {
792
- struct_span_err ! ( self . tcx. sess, expr. span, E0070 ,
793
- "invalid left-hand side expression" )
794
- . span_label ( expr. span , "left-hand of expression not valid" )
795
- . emit ( ) ;
828
+ } else {
829
+ self . check_lhs_assignable ( lhs, "E0070" , span) ;
796
830
}
797
831
798
832
self . require_type_is_sized ( lhs_ty, lhs. span , traits:: AssignmentLhsSized ) ;
0 commit comments