@@ -187,8 +187,18 @@ impl<'hir> LoweringContext<'_, 'hir> {
187187 }
188188 ExprKind :: InlineAsm ( ref asm) => self . lower_expr_asm ( e. span , asm) ,
189189 ExprKind :: LlvmInlineAsm ( ref asm) => self . lower_expr_llvm_asm ( asm) ,
190- ExprKind :: Struct ( ref path, ref fields, ref maybe_expr) => {
191- let maybe_expr = maybe_expr. as_ref ( ) . map ( |x| self . lower_expr ( x) ) ;
190+ ExprKind :: Struct ( ref path, ref fields, ref rest) => {
191+ let rest = match rest {
192+ StructRest :: Base ( e) => Some ( self . lower_expr ( e) ) ,
193+ StructRest :: Rest ( sp) => {
194+ self . sess
195+ . struct_span_err ( * sp, "base expression required after `..`" )
196+ . span_label ( * sp, "add a base expression here" )
197+ . emit ( ) ;
198+ Some ( & * self . arena . alloc ( self . expr_err ( * sp) ) )
199+ }
200+ StructRest :: None => None ,
201+ } ;
192202 hir:: ExprKind :: Struct (
193203 self . arena . alloc ( self . lower_qpath (
194204 e. id ,
@@ -198,7 +208,7 @@ impl<'hir> LoweringContext<'_, 'hir> {
198208 ImplTraitContext :: disallowed ( ) ,
199209 ) ) ,
200210 self . arena . alloc_from_iter ( fields. iter ( ) . map ( |x| self . lower_field ( x) ) ) ,
201- maybe_expr ,
211+ rest ,
202212 )
203213 }
204214 ExprKind :: Yield ( ref opt_expr) => self . lower_expr_yield ( e. span , opt_expr. as_deref ( ) ) ,
@@ -851,20 +861,22 @@ impl<'hir> LoweringContext<'_, 'hir> {
851861 whole_span : Span ,
852862 ) -> hir:: ExprKind < ' hir > {
853863 // Return early in case of an ordinary assignment.
854- fn is_ordinary ( lhs : & Expr ) -> bool {
864+ fn is_ordinary ( lower_ctx : & mut LoweringContext < ' _ , ' _ > , lhs : & Expr ) -> bool {
855865 match & lhs. kind {
856- ExprKind :: Tup ( ..) => false ,
866+ ExprKind :: Array ( ..) | ExprKind :: Struct ( ..) | ExprKind :: Tup ( ..) => false ,
867+ // Check for tuple struct constructor.
868+ ExprKind :: Call ( callee, ..) => lower_ctx. extract_tuple_struct_path ( callee) . is_none ( ) ,
857869 ExprKind :: Paren ( e) => {
858870 match e. kind {
859871 // We special-case `(..)` for consistency with patterns.
860872 ExprKind :: Range ( None , None , RangeLimits :: HalfOpen ) => false ,
861- _ => is_ordinary ( e) ,
873+ _ => is_ordinary ( lower_ctx , e) ,
862874 }
863875 }
864876 _ => true ,
865877 }
866878 }
867- if is_ordinary ( lhs) {
879+ if is_ordinary ( self , lhs) {
868880 return hir:: ExprKind :: Assign ( self . lower_expr ( lhs) , self . lower_expr ( rhs) , eq_sign_span) ;
869881 }
870882 if !self . sess . features_untracked ( ) . destructuring_assignment {
@@ -902,6 +914,26 @@ impl<'hir> LoweringContext<'_, 'hir> {
902914 hir:: ExprKind :: Block ( & self . block_all ( whole_span, stmts, None ) , None )
903915 }
904916
917+ /// If the given expression is a path to a tuple struct, returns that path.
918+ /// It is not a complete check, but just tries to reject most paths early
919+ /// if they are not tuple structs.
920+ /// Type checking will take care of the full validation later.
921+ fn extract_tuple_struct_path < ' a > ( & mut self , expr : & ' a Expr ) -> Option < & ' a Path > {
922+ // For tuple struct destructuring, it must be a non-qualified path (like in patterns).
923+ if let ExprKind :: Path ( None , path) = & expr. kind {
924+ // Does the path resolves to something disallowed in a tuple struct/variant pattern?
925+ if let Some ( partial_res) = self . resolver . get_partial_res ( expr. id ) {
926+ if partial_res. unresolved_segments ( ) == 0
927+ && !partial_res. base_res ( ) . expected_in_tuple_struct_pat ( )
928+ {
929+ return None ;
930+ }
931+ }
932+ return Some ( path) ;
933+ }
934+ None
935+ }
936+
905937 /// Convert the LHS of a destructuring assignment to a pattern.
906938 /// Each sub-assignment is recorded in `assignments`.
907939 fn destructure_assign (
@@ -911,6 +943,86 @@ impl<'hir> LoweringContext<'_, 'hir> {
911943 assignments : & mut Vec < hir:: Stmt < ' hir > > ,
912944 ) -> & ' hir hir:: Pat < ' hir > {
913945 match & lhs. kind {
946+ // Slice patterns.
947+ ExprKind :: Array ( elements) => {
948+ let ( pats, rest) =
949+ self . destructure_sequence ( elements, "slice" , eq_sign_span, assignments) ;
950+ let slice_pat = if let Some ( ( i, span) ) = rest {
951+ let ( before, after) = pats. split_at ( i) ;
952+ hir:: PatKind :: Slice (
953+ before,
954+ Some ( self . pat_without_dbm ( span, hir:: PatKind :: Wild ) ) ,
955+ after,
956+ )
957+ } else {
958+ hir:: PatKind :: Slice ( pats, None , & [ ] )
959+ } ;
960+ return self . pat_without_dbm ( lhs. span , slice_pat) ;
961+ }
962+ // Tuple structs.
963+ ExprKind :: Call ( callee, args) => {
964+ if let Some ( path) = self . extract_tuple_struct_path ( callee) {
965+ let ( pats, rest) = self . destructure_sequence (
966+ args,
967+ "tuple struct or variant" ,
968+ eq_sign_span,
969+ assignments,
970+ ) ;
971+ let qpath = self . lower_qpath (
972+ callee. id ,
973+ & None ,
974+ path,
975+ ParamMode :: Optional ,
976+ ImplTraitContext :: disallowed ( ) ,
977+ ) ;
978+ // Destructure like a tuple struct.
979+ let tuple_struct_pat =
980+ hir:: PatKind :: TupleStruct ( qpath, pats, rest. map ( |r| r. 0 ) ) ;
981+ return self . pat_without_dbm ( lhs. span , tuple_struct_pat) ;
982+ }
983+ }
984+ // Structs.
985+ ExprKind :: Struct ( path, fields, rest) => {
986+ let field_pats = self . arena . alloc_from_iter ( fields. iter ( ) . map ( |f| {
987+ let pat = self . destructure_assign ( & f. expr , eq_sign_span, assignments) ;
988+ hir:: FieldPat {
989+ hir_id : self . next_id ( ) ,
990+ ident : f. ident ,
991+ pat,
992+ is_shorthand : f. is_shorthand ,
993+ span : f. span ,
994+ }
995+ } ) ) ;
996+ let qpath = self . lower_qpath (
997+ lhs. id ,
998+ & None ,
999+ path,
1000+ ParamMode :: Optional ,
1001+ ImplTraitContext :: disallowed ( ) ,
1002+ ) ;
1003+ let fields_omitted = match rest {
1004+ StructRest :: Base ( e) => {
1005+ self . sess
1006+ . struct_span_err (
1007+ e. span ,
1008+ "functional record updates are not allowed in destructuring \
1009+ assignments",
1010+ )
1011+ . span_suggestion (
1012+ e. span ,
1013+ "consider removing the trailing pattern" ,
1014+ String :: new ( ) ,
1015+ rustc_errors:: Applicability :: MachineApplicable ,
1016+ )
1017+ . emit ( ) ;
1018+ true
1019+ }
1020+ StructRest :: Rest ( _) => true ,
1021+ StructRest :: None => false ,
1022+ } ;
1023+ let struct_pat = hir:: PatKind :: Struct ( qpath, field_pats, fields_omitted) ;
1024+ return self . pat_without_dbm ( lhs. span , struct_pat) ;
1025+ }
9141026 // Tuples.
9151027 ExprKind :: Tup ( elements) => {
9161028 let ( pats, rest) =
0 commit comments