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