@@ -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 ;
@@ -467,7 +468,7 @@ impl<'a> LoweringContext<'a> {
467
468
fn visit_pat ( & mut self , p : & ' tcx Pat ) {
468
469
match p. node {
469
470
// Doesn't generate a HIR node
470
- PatKind :: Paren ( ..) => { } ,
471
+ PatKind :: Paren ( ..) | PatKind :: Rest => { } ,
471
472
_ => {
472
473
if let Some ( owner) = self . hir_id_owner {
473
474
self . lctx . lower_node_id_with_owner ( p. id , owner) ;
@@ -1156,7 +1157,7 @@ impl<'a> LoweringContext<'a> {
1156
1157
& mut self ,
1157
1158
capture_clause : CaptureBy ,
1158
1159
closure_node_id : NodeId ,
1159
- ret_ty : Option < syntax :: ptr :: P < Ty > > ,
1160
+ ret_ty : Option < AstP < Ty > > ,
1160
1161
span : Span ,
1161
1162
body : impl FnOnce ( & mut LoweringContext < ' _ > ) -> hir:: Expr ,
1162
1163
) -> hir:: ExprKind {
@@ -4171,45 +4172,20 @@ impl<'a> LoweringContext<'a> {
4171
4172
let node = match p. node {
4172
4173
PatKind :: Wild => hir:: PatKind :: Wild ,
4173
4174
PatKind :: Ident ( ref binding_mode, ident, ref sub) => {
4174
- match self . resolver . get_partial_res ( p. id ) . map ( |d| d. base_res ( ) ) {
4175
- // `None` can occur in body-less function signatures
4176
- res @ None | res @ Some ( Res :: Local ( _) ) => {
4177
- let canonical_id = match res {
4178
- Some ( Res :: Local ( id) ) => id,
4179
- _ => p. id ,
4180
- } ;
4181
-
4182
- hir:: PatKind :: Binding (
4183
- self . lower_binding_mode ( binding_mode) ,
4184
- self . lower_node_id ( canonical_id) ,
4185
- ident,
4186
- sub. as_ref ( ) . map ( |x| self . lower_pat ( x) ) ,
4187
- )
4188
- }
4189
- Some ( res) => hir:: PatKind :: Path ( hir:: QPath :: Resolved (
4190
- None ,
4191
- P ( hir:: Path {
4192
- span : ident. span ,
4193
- res : self . lower_res ( res) ,
4194
- segments : hir_vec ! [ hir:: PathSegment :: from_ident( ident) ] ,
4195
- } ) ,
4196
- ) ) ,
4197
- }
4175
+ let lower_sub = |this : & mut Self | sub. as_ref ( ) . map ( |x| this. lower_pat ( x) ) ;
4176
+ self . lower_pat_ident ( p, binding_mode, ident, lower_sub)
4198
4177
}
4199
4178
PatKind :: Lit ( ref e) => hir:: PatKind :: Lit ( P ( self . lower_expr ( e) ) ) ,
4200
- PatKind :: TupleStruct ( ref path, ref pats, ddpos ) => {
4179
+ PatKind :: TupleStruct ( ref path, ref pats) => {
4201
4180
let qpath = self . lower_qpath (
4202
4181
p. id ,
4203
4182
& None ,
4204
4183
path,
4205
4184
ParamMode :: Optional ,
4206
4185
ImplTraitContext :: disallowed ( ) ,
4207
4186
) ;
4208
- hir:: PatKind :: TupleStruct (
4209
- qpath,
4210
- pats. iter ( ) . map ( |x| self . lower_pat ( x) ) . collect ( ) ,
4211
- ddpos,
4212
- )
4187
+ let ( pats, ddpos) = self . lower_pat_tuple ( pats, "tuple struct" ) ;
4188
+ hir:: PatKind :: TupleStruct ( qpath, pats, ddpos)
4213
4189
}
4214
4190
PatKind :: Path ( ref qself, ref path) => {
4215
4191
let qpath = self . lower_qpath (
@@ -4246,8 +4222,9 @@ impl<'a> LoweringContext<'a> {
4246
4222
. collect ( ) ;
4247
4223
hir:: PatKind :: Struct ( qpath, fs, etc)
4248
4224
}
4249
- PatKind :: Tuple ( ref elts, ddpos) => {
4250
- hir:: PatKind :: Tuple ( elts. iter ( ) . map ( |x| self . lower_pat ( x) ) . collect ( ) , ddpos)
4225
+ PatKind :: Tuple ( ref pats) => {
4226
+ let ( pats, ddpos) = self . lower_pat_tuple ( pats, "tuple" ) ;
4227
+ hir:: PatKind :: Tuple ( pats, ddpos)
4251
4228
}
4252
4229
PatKind :: Box ( ref inner) => hir:: PatKind :: Box ( self . lower_pat ( inner) ) ,
4253
4230
PatKind :: Ref ( ref inner, mutbl) => {
@@ -4258,22 +4235,167 @@ impl<'a> LoweringContext<'a> {
4258
4235
P ( self . lower_expr ( e2) ) ,
4259
4236
self . lower_range_end ( end) ,
4260
4237
) ,
4261
- PatKind :: Slice ( ref before , ref slice , ref after ) => hir :: PatKind :: Slice (
4262
- before . iter ( ) . map ( |x| self . lower_pat ( x ) ) . collect ( ) ,
4263
- slice . as_ref ( ) . map ( |x| self . lower_pat ( x ) ) ,
4264
- after . iter ( ) . map ( |x| self . lower_pat ( x ) ) . collect ( ) ,
4265
- ) ,
4238
+ PatKind :: Slice ( ref pats ) => self . lower_pat_slice ( pats ) ,
4239
+ PatKind :: Rest => {
4240
+ // If we reach here the `..` pattern is not semantically allowed.
4241
+ self . ban_illegal_rest_pat ( p . span )
4242
+ }
4266
4243
PatKind :: Paren ( ref inner) => return self . lower_pat ( inner) ,
4267
4244
PatKind :: Mac ( _) => panic ! ( "Shouldn't exist here" ) ,
4268
4245
} ;
4269
4246
4247
+ self . pat_with_node_id_of ( p, node)
4248
+ }
4249
+
4250
+ fn lower_pat_tuple (
4251
+ & mut self ,
4252
+ pats : & [ AstP < Pat > ] ,
4253
+ ctx : & str ,
4254
+ ) -> ( HirVec < P < hir:: Pat > > , Option < usize > ) {
4255
+ let mut elems = Vec :: with_capacity ( pats. len ( ) ) ;
4256
+ let mut rest = None ;
4257
+
4258
+ let mut iter = pats. iter ( ) . enumerate ( ) ;
4259
+ while let Some ( ( idx, pat) ) = iter. next ( ) {
4260
+ // Interpret the first `..` pattern as a subtuple pattern.
4261
+ if pat. is_rest ( ) {
4262
+ rest = Some ( ( idx, pat. span ) ) ;
4263
+ break ;
4264
+ }
4265
+ // It was not a subslice pattern so lower it normally.
4266
+ elems. push ( self . lower_pat ( pat) ) ;
4267
+ }
4268
+
4269
+ while let Some ( ( _, pat) ) = iter. next ( ) {
4270
+ // There was a previous subtuple pattern; make sure we don't allow more.
4271
+ if pat. is_rest ( ) {
4272
+ self . ban_extra_rest_pat ( pat. span , rest. unwrap ( ) . 1 , ctx) ;
4273
+ } else {
4274
+ elems. push ( self . lower_pat ( pat) ) ;
4275
+ }
4276
+ }
4277
+
4278
+ ( elems. into ( ) , rest. map ( |( ddpos, _) | ddpos) )
4279
+ }
4280
+
4281
+ fn lower_pat_slice ( & mut self , pats : & [ AstP < Pat > ] ) -> hir:: PatKind {
4282
+ let mut before = Vec :: new ( ) ;
4283
+ let mut after = Vec :: new ( ) ;
4284
+ let mut slice = None ;
4285
+ let mut prev_rest_span = None ;
4286
+
4287
+ let mut iter = pats. iter ( ) ;
4288
+ while let Some ( pat) = iter. next ( ) {
4289
+ // Interpret the first `((ref mut?)? x @)? ..` pattern as a subslice pattern.
4290
+ match pat. node {
4291
+ PatKind :: Rest => {
4292
+ prev_rest_span = Some ( pat. span ) ;
4293
+ slice = Some ( self . pat_wild_with_node_id_of ( pat) ) ;
4294
+ break ;
4295
+ } ,
4296
+ PatKind :: Ident ( ref bm, ident, Some ( ref sub) ) if sub. is_rest ( ) => {
4297
+ prev_rest_span = Some ( sub. span ) ;
4298
+ let lower_sub = |this : & mut Self | Some ( this. pat_wild_with_node_id_of ( sub) ) ;
4299
+ let node = self . lower_pat_ident ( pat, bm, ident, lower_sub) ;
4300
+ slice = Some ( self . pat_with_node_id_of ( pat, node) ) ;
4301
+ break ;
4302
+ } ,
4303
+ _ => { }
4304
+ }
4305
+
4306
+ // It was not a subslice pattern so lower it normally.
4307
+ before. push ( self . lower_pat ( pat) ) ;
4308
+ }
4309
+
4310
+ while let Some ( pat) = iter. next ( ) {
4311
+ // There was a previous subslice pattern; make sure we don't allow more.
4312
+ let rest_span = match pat. node {
4313
+ PatKind :: Rest => Some ( pat. span ) ,
4314
+ PatKind :: Ident ( .., Some ( ref sub) ) if sub. is_rest ( ) => {
4315
+ // The `HirValidator` is merciless; add a `_` pattern to avoid ICEs.
4316
+ after. push ( self . pat_wild_with_node_id_of ( pat) ) ;
4317
+ Some ( sub. span )
4318
+ } ,
4319
+ _ => None ,
4320
+ } ;
4321
+ if let Some ( rest_span) = rest_span {
4322
+ self . ban_extra_rest_pat ( rest_span, prev_rest_span. unwrap ( ) , "slice" ) ;
4323
+ } else {
4324
+ after. push ( self . lower_pat ( pat) ) ;
4325
+ }
4326
+ }
4327
+
4328
+ hir:: PatKind :: Slice ( before. into ( ) , slice, after. into ( ) )
4329
+ }
4330
+
4331
+ fn lower_pat_ident (
4332
+ & mut self ,
4333
+ p : & Pat ,
4334
+ binding_mode : & BindingMode ,
4335
+ ident : Ident ,
4336
+ lower_sub : impl FnOnce ( & mut Self ) -> Option < P < hir:: Pat > > ,
4337
+ ) -> hir:: PatKind {
4338
+ match self . resolver . get_partial_res ( p. id ) . map ( |d| d. base_res ( ) ) {
4339
+ // `None` can occur in body-less function signatures
4340
+ res @ None | res @ Some ( Res :: Local ( _) ) => {
4341
+ let canonical_id = match res {
4342
+ Some ( Res :: Local ( id) ) => id,
4343
+ _ => p. id ,
4344
+ } ;
4345
+
4346
+ hir:: PatKind :: Binding (
4347
+ self . lower_binding_mode ( binding_mode) ,
4348
+ self . lower_node_id ( canonical_id) ,
4349
+ ident,
4350
+ lower_sub ( self ) ,
4351
+ )
4352
+ }
4353
+ Some ( res) => hir:: PatKind :: Path ( hir:: QPath :: Resolved (
4354
+ None ,
4355
+ P ( hir:: Path {
4356
+ span : ident. span ,
4357
+ res : self . lower_res ( res) ,
4358
+ segments : hir_vec ! [ hir:: PathSegment :: from_ident( ident) ] ,
4359
+ } ) ,
4360
+ ) ) ,
4361
+ }
4362
+ }
4363
+
4364
+ fn pat_wild_with_node_id_of ( & mut self , p : & Pat ) -> P < hir:: Pat > {
4365
+ self . pat_with_node_id_of ( p, hir:: PatKind :: Wild )
4366
+ }
4367
+
4368
+ /// Construct a `Pat` with the `HirId` of `p.id` lowered.
4369
+ fn pat_with_node_id_of ( & mut self , p : & Pat , node : hir:: PatKind ) -> P < hir:: Pat > {
4270
4370
P ( hir:: Pat {
4271
4371
hir_id : self . lower_node_id ( p. id ) ,
4272
4372
node,
4273
4373
span : p. span ,
4274
4374
} )
4275
4375
}
4276
4376
4377
+ /// Emit a friendly error for extra `..` patterns in a tuple/tuple struct/slice pattern.
4378
+ fn ban_extra_rest_pat ( & self , sp : Span , prev_sp : Span , ctx : & str ) {
4379
+ self . diagnostic ( )
4380
+ . struct_span_err ( sp, & format ! ( "`..` can only be used once per {} pattern" , ctx) )
4381
+ . span_label ( sp, & format ! ( "can only be used once per {} pattern" , ctx) )
4382
+ . span_label ( prev_sp, "previously used here" )
4383
+ . emit ( ) ;
4384
+ }
4385
+
4386
+ /// Used to ban the `..` pattern in places it shouldn't be semantically.
4387
+ fn ban_illegal_rest_pat ( & self , sp : Span ) -> hir:: PatKind {
4388
+ self . diagnostic ( )
4389
+ . struct_span_err ( sp, "`..` patterns are not allowed here" )
4390
+ . note ( "only allowed in tuple, tuple struct, and slice patterns" )
4391
+ . emit ( ) ;
4392
+
4393
+ // We're not in a list context so `..` can be reasonably treated
4394
+ // as `_` because it should always be valid and roughly matches the
4395
+ // intent of `..` (notice that the rest of a single slot is that slot).
4396
+ hir:: PatKind :: Wild
4397
+ }
4398
+
4277
4399
fn lower_range_end ( & mut self , e : & RangeEnd ) -> hir:: RangeEnd {
4278
4400
match * e {
4279
4401
RangeEnd :: Included ( _) => hir:: RangeEnd :: Included ,
0 commit comments