@@ -187,8 +187,18 @@ impl<'hir> LoweringContext<'_, 'hir> {
187
187
}
188
188
ExprKind :: InlineAsm ( ref asm) => self . lower_expr_asm ( e. span , asm) ,
189
189
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
+ } ;
192
202
hir:: ExprKind :: Struct (
193
203
self . arena . alloc ( self . lower_qpath (
194
204
e. id ,
@@ -198,7 +208,7 @@ impl<'hir> LoweringContext<'_, 'hir> {
198
208
ImplTraitContext :: disallowed ( ) ,
199
209
) ) ,
200
210
self . arena . alloc_from_iter ( fields. iter ( ) . map ( |x| self . lower_field ( x) ) ) ,
201
- maybe_expr ,
211
+ rest ,
202
212
)
203
213
}
204
214
ExprKind :: Yield ( ref opt_expr) => self . lower_expr_yield ( e. span , opt_expr. as_deref ( ) ) ,
@@ -851,20 +861,22 @@ impl<'hir> LoweringContext<'_, 'hir> {
851
861
whole_span : Span ,
852
862
) -> hir:: ExprKind < ' hir > {
853
863
// 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 {
855
865
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 ( ) ,
857
869
ExprKind :: Paren ( e) => {
858
870
match e. kind {
859
871
// We special-case `(..)` for consistency with patterns.
860
872
ExprKind :: Range ( None , None , RangeLimits :: HalfOpen ) => false ,
861
- _ => is_ordinary ( e) ,
873
+ _ => is_ordinary ( lower_ctx , e) ,
862
874
}
863
875
}
864
876
_ => true ,
865
877
}
866
878
}
867
- if is_ordinary ( lhs) {
879
+ if is_ordinary ( self , lhs) {
868
880
return hir:: ExprKind :: Assign ( self . lower_expr ( lhs) , self . lower_expr ( rhs) , eq_sign_span) ;
869
881
}
870
882
if !self . sess . features_untracked ( ) . destructuring_assignment {
@@ -902,6 +914,26 @@ impl<'hir> LoweringContext<'_, 'hir> {
902
914
hir:: ExprKind :: Block ( & self . block_all ( whole_span, stmts, None ) , None )
903
915
}
904
916
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
+
905
937
/// Convert the LHS of a destructuring assignment to a pattern.
906
938
/// Each sub-assignment is recorded in `assignments`.
907
939
fn destructure_assign (
@@ -911,6 +943,86 @@ impl<'hir> LoweringContext<'_, 'hir> {
911
943
assignments : & mut Vec < hir:: Stmt < ' hir > > ,
912
944
) -> & ' hir hir:: Pat < ' hir > {
913
945
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
+ }
914
1026
// Tuples.
915
1027
ExprKind :: Tup ( elements) => {
916
1028
let ( pats, rest) =
0 commit comments