@@ -900,35 +900,40 @@ impl<'hir> LoweringContext<'_, 'hir> {
900
900
eq_sign_span : Span ,
901
901
assignments : & mut Vec < hir:: Stmt < ' hir > > ,
902
902
) -> & ' hir hir:: Pat < ' hir > {
903
- // TODO: Handle `..` and `_`
903
+ // TODO: Handle `_`, requires changes to the parser
904
904
match & lhs. kind {
905
905
// slices:
906
906
ExprKind :: Array ( elements) => {
907
- let pats = self . arena . alloc_from_iter (
908
- elements. iter ( ) . map ( |e| self . destructure_assign ( e, eq_sign_span, assignments) ) ,
909
- ) ;
910
- let slice_pat = hir:: PatKind :: Slice ( pats, None , & [ ] ) ;
907
+ let ( pats, rest) =
908
+ self . destructure_sequence ( elements, "slice" , eq_sign_span, assignments) ;
909
+ let slice_pat = if let Some ( ( i, span) ) = rest {
910
+ let ( before, after) = pats. split_at ( i) ;
911
+ hir:: PatKind :: Slice ( before, Some ( self . pat ( span, hir:: PatKind :: Wild ) ) , after)
912
+ } else {
913
+ hir:: PatKind :: Slice ( pats, None , & [ ] )
914
+ } ;
911
915
return self . pat ( lhs. span , slice_pat) ;
912
916
}
913
917
// tuple structs:
914
918
ExprKind :: Call ( callee, args) => {
915
919
if let ExprKind :: Path ( qself, path) = & callee. kind {
916
- let pats = self . arena . alloc_from_iter (
917
- args. iter ( ) . map ( |e| self . destructure_assign ( e, eq_sign_span, assignments) ) ,
918
- ) ;
920
+ let ( pats, rest) =
921
+ self . destructure_sequence ( args, "tuple struct" , eq_sign_span, assignments) ;
919
922
let qpath = self . lower_qpath (
920
923
callee. id ,
921
924
qself,
922
925
path,
923
926
ParamMode :: Optional ,
924
927
ImplTraitContext :: disallowed ( ) ,
925
928
) ;
926
- let tuple_struct_pat = hir:: PatKind :: TupleStruct ( qpath, pats, None ) ;
929
+ let tuple_struct_pat =
930
+ hir:: PatKind :: TupleStruct ( qpath, pats, rest. map ( |r| r. 0 ) ) ;
927
931
return self . pat ( lhs. span , tuple_struct_pat) ;
928
932
}
929
933
}
930
934
// structs:
931
- ExprKind :: Struct ( path, fields, _rest) => {
935
+ // TODO: support `..` here, requires changes to the parser
936
+ ExprKind :: Struct ( path, fields, rest) => {
932
937
let field_pats = self . arena . alloc_from_iter ( fields. iter ( ) . map ( |f| {
933
938
let pat = self . destructure_assign ( & f. expr , eq_sign_span, assignments) ;
934
939
hir:: FieldPat {
@@ -951,10 +956,9 @@ impl<'hir> LoweringContext<'_, 'hir> {
951
956
}
952
957
// tuples:
953
958
ExprKind :: Tup ( elements) => {
954
- let pats = self . arena . alloc_from_iter (
955
- elements. iter ( ) . map ( |e| self . destructure_assign ( e, eq_sign_span, assignments) ) ,
956
- ) ;
957
- let tuple_pat = hir:: PatKind :: Tuple ( pats, None ) ;
959
+ let ( pats, rest) =
960
+ self . destructure_sequence ( elements, "tuple" , eq_sign_span, assignments) ;
961
+ let tuple_pat = hir:: PatKind :: Tuple ( pats, rest. map ( |r| r. 0 ) ) ;
958
962
return self . pat ( lhs. span , tuple_pat) ;
959
963
}
960
964
_ => { }
@@ -969,6 +973,35 @@ impl<'hir> LoweringContext<'_, 'hir> {
969
973
pat
970
974
}
971
975
976
+ /// Destructure a sequence of expressions occurring on the LHS of an assignment.
977
+ /// Such a sequence occurs in a tuple (struct)/slice.
978
+ /// Return a sequence of corresponding patterns and the index and span of `..`, if any.
979
+ /// Along the way, introduce additional assignments in the parameter `assignments`.
980
+ fn destructure_sequence (
981
+ & mut self ,
982
+ elements : & [ AstP < Expr > ] ,
983
+ ctx : & str ,
984
+ eq_sign_span : Span ,
985
+ assignments : & mut Vec < hir:: Stmt < ' hir > > ,
986
+ ) -> ( & ' hir [ & ' hir hir:: Pat < ' hir > ] , Option < ( usize , Span ) > ) {
987
+ let mut rest = None ;
988
+ let elements =
989
+ self . arena . alloc_from_iter ( elements. iter ( ) . enumerate ( ) . filter_map ( |( i, e) | {
990
+ // Check for `..` pattern.
991
+ if let ExprKind :: Range ( None , None , RangeLimits :: HalfOpen ) = e. kind {
992
+ if let Some ( ( _, prev_span) ) = rest {
993
+ self . ban_extra_rest_pat ( e. span , prev_span, ctx) ;
994
+ } else {
995
+ rest = Some ( ( i, e. span ) ) ;
996
+ }
997
+ None
998
+ } else {
999
+ Some ( self . destructure_assign ( e, eq_sign_span, assignments) )
1000
+ }
1001
+ } ) ) ;
1002
+ ( elements, rest)
1003
+ }
1004
+
972
1005
/// Desugar `<start>..=<end>` into `std::ops::RangeInclusive::new(<start>, <end>)`.
973
1006
fn lower_expr_range_closed ( & mut self , span : Span , e1 : & Expr , e2 : & Expr ) -> hir:: ExprKind < ' hir > {
974
1007
let e1 = self . lower_expr_mut ( e1) ;
0 commit comments