@@ -5,7 +5,8 @@ use rustc_ast_pretty::pprust::PrintState;
5
5
use rustc_middle:: ty:: TyCtxt ;
6
6
use rustc_session:: parse:: ParseSess ;
7
7
use rustc_span:: source_map:: FilePathMapping ;
8
- use rustc_span:: symbol:: { kw, Symbol } ;
8
+ use rustc_span:: symbol:: { kw, Ident , Symbol } ;
9
+ use rustc_span:: Span ;
9
10
10
11
/// Render a macro matcher in a format suitable for displaying to the user
11
12
/// as part of an item declaration.
@@ -153,7 +154,7 @@ fn print_tts(printer: &mut Printer<'_>, tts: &TokenStream) {
153
154
}
154
155
( Pound , token:: Not ) => ( false , PoundBang ) ,
155
156
( _, token:: Ident ( symbol, /* is_raw */ false ) )
156
- if !usually_needs_space_between_keyword_and_open_delim ( * symbol) =>
157
+ if !usually_needs_space_between_keyword_and_open_delim ( * symbol, tt . span ) =>
157
158
{
158
159
( true , Ident )
159
160
}
@@ -177,42 +178,63 @@ fn print_tts(printer: &mut Printer<'_>, tts: &TokenStream) {
177
178
}
178
179
}
179
180
180
- // This rough subset of keywords is listed here to distinguish tokens resembling
181
- // `f(0)` (no space between ident and paren) from tokens resembling `if let (0,
182
- // 0) = x` (space between ident and paren).
183
- fn usually_needs_space_between_keyword_and_open_delim ( symbol : Symbol ) -> bool {
181
+ fn usually_needs_space_between_keyword_and_open_delim ( symbol : Symbol , span : Span ) -> bool {
182
+ let ident = Ident { name : symbol, span } ;
183
+ let is_keyword = ident. is_used_keyword ( ) || ident. is_unused_keyword ( ) ;
184
+ if !is_keyword {
185
+ // An identifier that is not a keyword usually does not need a space
186
+ // before an open delim. For example: `f(0)` or `f[0]`.
187
+ return false ;
188
+ }
189
+
184
190
match symbol {
185
- kw:: As
186
- | kw:: Box
187
- | kw:: Break
188
- | kw:: Const
189
- | kw:: Continue
190
- | kw:: Crate
191
- | kw:: Else
192
- | kw:: Enum
193
- | kw:: Extern
194
- | kw:: For
195
- | kw:: If
196
- | kw:: Impl
197
- | kw:: In
198
- | kw:: Let
199
- | kw:: Loop
200
- | kw:: Macro
201
- | kw:: Match
202
- | kw:: Mod
203
- | kw:: Move
204
- | kw:: Mut
205
- | kw:: Ref
206
- | kw:: Return
207
- | kw:: Static
208
- | kw:: Struct
209
- | kw:: Trait
210
- | kw:: Type
211
- | kw:: Unsafe
212
- | kw:: Use
213
- | kw:: Where
214
- | kw:: While
215
- | kw:: Yield => true ,
216
- _ => false ,
191
+ // No space after keywords that are syntactically an expression. For
192
+ // example: a tuple struct created with `let _ = Self(0, 0)`, or if
193
+ // someone has `impl Index<MyStruct> for bool` then `true[MyStruct]`.
194
+ kw:: False | kw:: SelfLower | kw:: SelfUpper | kw:: True => false ,
195
+
196
+ // No space, as in `let _: fn();`
197
+ kw:: Fn => false ,
198
+
199
+ // No space, as in `pub(crate) type T;`
200
+ kw:: Pub => false ,
201
+
202
+ // No space for keywords that can end an expression, as in `fut.await()`
203
+ // where fut's Output type is `fn()`.
204
+ kw:: Await => false ,
205
+
206
+ // Otherwise space after keyword. Some examples:
207
+ //
208
+ // `expr as [T; 2]`
209
+ // ^
210
+ // `box (tuple,)`
211
+ // ^
212
+ // `break (tuple,)`
213
+ // ^
214
+ // `type T = dyn (Fn() -> dyn Trait) + Send;`
215
+ // ^
216
+ // `for (tuple,) in iter {}`
217
+ // ^
218
+ // `if (tuple,) == v {}`
219
+ // ^
220
+ // `impl [T] {}`
221
+ // ^
222
+ // `for x in [..] {}`
223
+ // ^
224
+ // `let () = unit;`
225
+ // ^
226
+ // `match [x, y] {...}`
227
+ // ^
228
+ // `&mut (x as T)`
229
+ // ^
230
+ // `return [];`
231
+ // ^
232
+ // `fn f<T>() where (): Into<T>`
233
+ // ^
234
+ // `while (a + b).what() {}`
235
+ // ^
236
+ // `yield [];`
237
+ // ^
238
+ _ => true ,
217
239
}
218
240
}
0 commit comments