@@ -16,7 +16,9 @@ use lists::{format_item_list, itemize_list};
16
16
use expr:: { rewrite_unary_prefix, rewrite_pair, rewrite_tuple} ;
17
17
use types:: rewrite_path;
18
18
19
- use syntax:: ast:: { BindingMode , Pat , PatKind , FieldPat } ;
19
+ use syntax:: ast:: { self , BindingMode , Pat , PatKind , FieldPat } ;
20
+ use syntax:: ptr;
21
+ use syntax:: codemap:: { self , BytePos , Span } ;
20
22
21
23
impl Rewrite for Pat {
22
24
fn rewrite ( & self , context : & RewriteContext , width : usize , offset : Indent ) -> Option < String > {
@@ -60,49 +62,78 @@ impl Rewrite for Pat {
60
62
let prefix = format ! ( "&{}" , format_mutability( mutability) ) ;
61
63
rewrite_unary_prefix ( context, & prefix, & * * pat, width, offset)
62
64
}
63
- // FIXME(#1021): Handle `..` in tuple / tuple struct patterns (RFC 1492)
64
65
PatKind :: Tuple ( ref items, dotdot_pos) => {
65
- if dotdot_pos. is_some ( ) {
66
- return None ;
66
+ let mut pat_vec: Vec < _ > = items. into_iter ( ) . map ( |x| PatOrDotdot :: Pat ( x) ) . collect ( ) ;
67
+
68
+ if let Some ( pos) = dotdot_pos {
69
+ let snippet = context. snippet ( self . span ) ;
70
+ let lo_pos = snippet. find ( ".." ) . unwrap ( ) ;
71
+ let lo = self . span . lo + BytePos ( lo_pos as u32 ) ;
72
+ // 2 == "..".len()
73
+ let dotdot = PatOrDotdot :: Dotdot ( lo, lo + BytePos ( 2 ) ) ;
74
+
75
+ if pat_vec. is_empty ( ) {
76
+ pat_vec = vec ! [ dotdot] ;
77
+ } else {
78
+ pat_vec. insert ( pos, dotdot) ;
79
+ }
67
80
}
68
- rewrite_tuple ( context,
69
- items. iter ( ) . map ( |x| & * * x) ,
70
- self . span ,
71
- width,
72
- offset)
81
+
82
+ rewrite_tuple ( context, pat_vec. iter ( ) , self . span , width, offset)
73
83
}
74
84
PatKind :: Path ( ref path) => rewrite_path ( context, true , None , path, width, offset) ,
75
85
PatKind :: TupleStruct ( ref path, ref pat_vec, dotdot_pos) => {
76
- let path_str = try_opt ! ( rewrite_path( context, true , None , path, width, offset) ) ;
86
+ let mut pat_vec: Vec < _ > =
87
+ pat_vec. into_iter ( ) . map ( |x| PatOrDotdot :: Pat ( x) ) . collect ( ) ;
77
88
78
- // FIXME(#1021): Handle `..` in tuple / tuple struct patterns (RFC 1492)
79
- match dotdot_pos {
80
- Some ( _) => Some ( format ! ( "{}(..)" , path_str) ) ,
81
- None => {
82
- if pat_vec. is_empty ( ) {
83
- Some ( path_str)
84
- } else {
85
- // 2 = "()".len()
86
- let width = try_opt ! ( width. checked_sub( path_str. len( ) + 2 ) ) ;
87
- // 1 = "(".len()
88
- let offset = offset + path_str. len ( ) + 1 ;
89
- let items = itemize_list ( context. codemap ,
90
- pat_vec. iter ( ) ,
91
- ")" ,
92
- |item| item. span . lo ,
93
- |item| item. span . hi ,
94
- |item| item. rewrite ( context, width, offset) ,
95
- context. codemap . span_after ( self . span , "(" ) ,
96
- self . span . hi ) ;
97
- Some ( format ! ( "{}({})" ,
98
- path_str,
99
- try_opt!( format_item_list( items,
100
- width,
101
- offset,
102
- context. config) ) ) )
103
- }
89
+ if let Some ( pos) = dotdot_pos {
90
+ let snippet = context. snippet ( self . span ) ;
91
+ let lo_pos = snippet. find ( ".." ) . unwrap ( ) ;
92
+ let lo = self . span . lo + BytePos ( lo_pos as u32 ) ;
93
+ // 2 == "..".len()
94
+ let dotdot = PatOrDotdot :: Dotdot ( lo, lo + BytePos ( 2 ) ) ;
95
+
96
+ if pat_vec. is_empty ( ) {
97
+ pat_vec = vec ! [ dotdot] ;
98
+ } else {
99
+ pat_vec. insert ( pos, dotdot) ;
104
100
}
105
101
}
102
+
103
+ let path_str = try_opt ! ( rewrite_path( context, true , None , path, width, offset) ) ;
104
+
105
+ if pat_vec. is_empty ( ) {
106
+ Some ( path_str)
107
+ } else if pat_vec. len ( ) == 1 && pat_vec[ 0 ] . is_dotdot ( ) {
108
+ Some ( format ! ( "{}(..)" , path_str) )
109
+ } else {
110
+ // 2 = "()".len()
111
+ let width = try_opt ! ( width. checked_sub( path_str. len( ) + 2 ) ) ;
112
+ // 1 = "(".len()
113
+ let offset = offset + path_str. len ( ) + 1 ;
114
+ let items = itemize_list ( context. codemap ,
115
+ pat_vec. iter ( ) ,
116
+ ")" ,
117
+ |item| match * * item {
118
+ PatOrDotdot :: Pat ( ref pat) => pat. span . lo ,
119
+ PatOrDotdot :: Dotdot ( lo, _) => lo,
120
+ } ,
121
+ |item| match * * item {
122
+ PatOrDotdot :: Pat ( ref pat) => pat. span . hi ,
123
+ PatOrDotdot :: Dotdot ( _, hi) => hi,
124
+ } ,
125
+ |item| match * * item {
126
+ PatOrDotdot :: Pat ( ref pat) => {
127
+ pat. rewrite ( context, width, offset)
128
+ }
129
+ PatOrDotdot :: Dotdot ( ..) => Some ( ".." . to_string ( ) ) ,
130
+ } ,
131
+ context. codemap . span_after ( self . span , "(" ) ,
132
+ self . span . hi ) ;
133
+ Some ( format ! ( "{}({})" ,
134
+ path_str,
135
+ try_opt!( format_item_list( items, width, offset, context. config) ) ) )
136
+ }
106
137
}
107
138
PatKind :: Lit ( ref expr) => expr. rewrite ( context, width, offset) ,
108
139
PatKind :: Vec ( ref prefix, ref slice_pat, ref suffix) => {
@@ -190,3 +221,41 @@ impl Rewrite for FieldPat {
190
221
}
191
222
}
192
223
}
224
+
225
+ enum PatOrDotdot < ' a > {
226
+ Pat ( & ' a ptr:: P < ast:: Pat > ) ,
227
+ Dotdot ( BytePos , BytePos ) ,
228
+ }
229
+
230
+ impl < ' a > PatOrDotdot < ' a > {
231
+ fn is_dotdot ( & self ) -> bool {
232
+ match * self {
233
+ PatOrDotdot :: Dotdot ( ..) => true ,
234
+ _ => false ,
235
+ }
236
+ }
237
+ }
238
+
239
+ impl < ' a > Rewrite for PatOrDotdot < ' a > {
240
+ fn rewrite ( & self , context : & RewriteContext , width : usize , offset : Indent ) -> Option < String > {
241
+ match * self {
242
+ PatOrDotdot :: Pat ( ref p) => p. rewrite ( context, width, offset) ,
243
+ PatOrDotdot :: Dotdot ( ..) => Some ( ".." . to_string ( ) ) ,
244
+ }
245
+ }
246
+ }
247
+
248
+ impl < ' a > super :: Spanned for PatOrDotdot < ' a > {
249
+ fn span ( & self ) -> Span {
250
+ match * self {
251
+ PatOrDotdot :: Pat ( ref p) => p. span ( ) ,
252
+ PatOrDotdot :: Dotdot ( lo, hi) => {
253
+ Span {
254
+ lo : lo,
255
+ hi : hi,
256
+ expn_id : codemap:: NO_EXPANSION ,
257
+ }
258
+ }
259
+ }
260
+ }
261
+ }
0 commit comments