@@ -58,6 +58,7 @@ use std::mem;
5858use smallvec:: SmallVec ;
5959use syntax:: attr;
6060use syntax:: ast;
61+ use syntax:: ptr:: P as AstP ;
6162use syntax:: ast:: * ;
6263use syntax:: errors;
6364use syntax:: ext:: hygiene:: ExpnId ;
@@ -467,7 +468,7 @@ impl<'a> LoweringContext<'a> {
467468 fn visit_pat ( & mut self , p : & ' tcx Pat ) {
468469 match p. node {
469470 // Doesn't generate a HIR node
470- PatKind :: Paren ( ..) => { } ,
471+ PatKind :: Paren ( ..) | PatKind :: Rest => { } ,
471472 _ => {
472473 if let Some ( owner) = self . hir_id_owner {
473474 self . lctx . lower_node_id_with_owner ( p. id , owner) ;
@@ -1156,7 +1157,7 @@ impl<'a> LoweringContext<'a> {
11561157 & mut self ,
11571158 capture_clause : CaptureBy ,
11581159 closure_node_id : NodeId ,
1159- ret_ty : Option < syntax :: ptr :: P < Ty > > ,
1160+ ret_ty : Option < AstP < Ty > > ,
11601161 span : Span ,
11611162 body : impl FnOnce ( & mut LoweringContext < ' _ > ) -> hir:: Expr ,
11621163 ) -> hir:: ExprKind {
@@ -4171,45 +4172,20 @@ impl<'a> LoweringContext<'a> {
41714172 let node = match p. node {
41724173 PatKind :: Wild => hir:: PatKind :: Wild ,
41734174 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)
41984177 }
41994178 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) => {
42014180 let qpath = self . lower_qpath (
42024181 p. id ,
42034182 & None ,
42044183 path,
42054184 ParamMode :: Optional ,
42064185 ImplTraitContext :: disallowed ( ) ,
42074186 ) ;
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)
42134189 }
42144190 PatKind :: Path ( ref qself, ref path) => {
42154191 let qpath = self . lower_qpath (
@@ -4246,8 +4222,9 @@ impl<'a> LoweringContext<'a> {
42464222 . collect ( ) ;
42474223 hir:: PatKind :: Struct ( qpath, fs, etc)
42484224 }
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)
42514228 }
42524229 PatKind :: Box ( ref inner) => hir:: PatKind :: Box ( self . lower_pat ( inner) ) ,
42534230 PatKind :: Ref ( ref inner, mutbl) => {
@@ -4258,22 +4235,167 @@ impl<'a> LoweringContext<'a> {
42584235 P ( self . lower_expr ( e2) ) ,
42594236 self . lower_range_end ( end) ,
42604237 ) ,
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+ }
42664243 PatKind :: Paren ( ref inner) => return self . lower_pat ( inner) ,
42674244 PatKind :: Mac ( _) => panic ! ( "Shouldn't exist here" ) ,
42684245 } ;
42694246
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 > {
42704370 P ( hir:: Pat {
42714371 hir_id : self . lower_node_id ( p. id ) ,
42724372 node,
42734373 span : p. span ,
42744374 } )
42754375 }
42764376
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+
42774399 fn lower_range_end ( & mut self , e : & RangeEnd ) -> hir:: RangeEnd {
42784400 match * e {
42794401 RangeEnd :: Included ( _) => hir:: RangeEnd :: Included ,
0 commit comments