@@ -58,6 +58,7 @@ use std::mem;
58
58
use smallvec:: SmallVec ;
59
59
use syntax:: attr;
60
60
use syntax:: ast;
61
+ use syntax:: ptr:: P as AstP ;
61
62
use syntax:: ast:: * ;
62
63
use syntax:: errors;
63
64
use syntax:: ext:: hygiene:: ExpnId ;
@@ -468,7 +469,7 @@ impl<'a> LoweringContext<'a> {
468
469
fn visit_pat ( & mut self , p : & ' tcx Pat ) {
469
470
match p. node {
470
471
// Doesn't generate a HIR node
471
- PatKind :: Paren ( ..) => { } ,
472
+ PatKind :: Paren ( ..) | PatKind :: Rest => { } ,
472
473
_ => {
473
474
if let Some ( owner) = self . hir_id_owner {
474
475
self . lctx . lower_node_id_with_owner ( p. id , owner) ;
@@ -4198,19 +4199,16 @@ impl<'a> LoweringContext<'a> {
4198
4199
}
4199
4200
}
4200
4201
PatKind :: Lit ( ref e) => hir:: PatKind :: Lit ( P ( self . lower_expr ( e) ) ) ,
4201
- PatKind :: TupleStruct ( ref path, ref pats, ddpos ) => {
4202
+ PatKind :: TupleStruct ( ref path, ref pats) => {
4202
4203
let qpath = self . lower_qpath (
4203
4204
p. id ,
4204
4205
& None ,
4205
4206
path,
4206
4207
ParamMode :: Optional ,
4207
4208
ImplTraitContext :: disallowed ( ) ,
4208
4209
) ;
4209
- hir:: PatKind :: TupleStruct (
4210
- qpath,
4211
- pats. iter ( ) . map ( |x| self . lower_pat ( x) ) . collect ( ) ,
4212
- ddpos,
4213
- )
4210
+ let ( pats, ddpos) = self . lower_pat_tuple ( & * pats, "tuple struct" ) ;
4211
+ hir:: PatKind :: TupleStruct ( qpath, pats, ddpos)
4214
4212
}
4215
4213
PatKind :: Path ( ref qself, ref path) => {
4216
4214
let qpath = self . lower_qpath (
@@ -4247,8 +4245,9 @@ impl<'a> LoweringContext<'a> {
4247
4245
. collect ( ) ;
4248
4246
hir:: PatKind :: Struct ( qpath, fs, etc)
4249
4247
}
4250
- PatKind :: Tuple ( ref elts, ddpos) => {
4251
- hir:: PatKind :: Tuple ( elts. iter ( ) . map ( |x| self . lower_pat ( x) ) . collect ( ) , ddpos)
4248
+ PatKind :: Tuple ( ref pats) => {
4249
+ let ( pats, ddpos) = self . lower_pat_tuple ( & * pats, "tuple" ) ;
4250
+ hir:: PatKind :: Tuple ( pats, ddpos)
4252
4251
}
4253
4252
PatKind :: Box ( ref inner) => hir:: PatKind :: Box ( self . lower_pat ( inner) ) ,
4254
4253
PatKind :: Ref ( ref inner, mutbl) => {
@@ -4279,6 +4278,46 @@ impl<'a> LoweringContext<'a> {
4279
4278
} )
4280
4279
}
4281
4280
4281
+ fn lower_pat_tuple (
4282
+ & mut self ,
4283
+ pats : & [ AstP < Pat > ] ,
4284
+ ctx : & str ,
4285
+ ) -> ( HirVec < P < hir:: Pat > > , Option < usize > ) {
4286
+ let mut elems = Vec :: with_capacity ( pats. len ( ) ) ;
4287
+ let mut rest = None ;
4288
+
4289
+ let mut iter = pats. iter ( ) . enumerate ( ) ;
4290
+ while let Some ( ( idx, pat) ) = iter. next ( ) {
4291
+ // Interpret the first `..` pattern as a subtuple pattern.
4292
+ if pat. is_rest ( ) {
4293
+ rest = Some ( ( idx, pat. span ) ) ;
4294
+ break ;
4295
+ }
4296
+ // It was not a subslice pattern so lower it normally.
4297
+ elems. push ( self . lower_pat ( pat) ) ;
4298
+ }
4299
+
4300
+ while let Some ( ( _, pat) ) = iter. next ( ) {
4301
+ // There was a previous subtuple pattern; make sure we don't allow more.
4302
+ if pat. is_rest ( ) {
4303
+ self . ban_extra_rest_pat ( pat. span , rest. unwrap ( ) . 1 , ctx) ;
4304
+ } else {
4305
+ elems. push ( self . lower_pat ( pat) ) ;
4306
+ }
4307
+ }
4308
+
4309
+ ( elems. into ( ) , rest. map ( |( ddpos, _) | ddpos) )
4310
+ }
4311
+
4312
+ /// Emit a friendly error for extra `..` patterns in a tuple/tuple struct/slice pattern.
4313
+ fn ban_extra_rest_pat ( & self , sp : Span , prev_sp : Span , ctx : & str ) {
4314
+ self . diagnostic ( )
4315
+ . struct_span_err ( sp, & format ! ( "`..` can only be used once per {} pattern" , ctx) )
4316
+ . span_label ( sp, & format ! ( "can only be used once per {} pattern" , ctx) )
4317
+ . span_label ( prev_sp, "previously used here" )
4318
+ . emit ( ) ;
4319
+ }
4320
+
4282
4321
/// Used to ban the `..` pattern in places it shouldn't be semantically.
4283
4322
fn ban_illegal_rest_pat ( & self , sp : Span ) -> hir:: PatKind {
4284
4323
self . diagnostic ( )
0 commit comments