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