@@ -5,7 +5,8 @@ use rustc_ast_pretty::pprust::PrintState;
55use rustc_middle:: ty:: TyCtxt ;
66use rustc_session:: parse:: ParseSess ;
77use 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 ;
910
1011/// Render a macro matcher in a format suitable for displaying to the user
1112/// as part of an item declaration.
@@ -153,7 +154,7 @@ fn print_tts(printer: &mut Printer<'_>, tts: &TokenStream) {
153154 }
154155 ( Pound , token:: Not ) => ( false , PoundBang ) ,
155156 ( _, 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 ) =>
157158 {
158159 ( true , Ident )
159160 }
@@ -177,42 +178,63 @@ fn print_tts(printer: &mut Printer<'_>, tts: &TokenStream) {
177178 }
178179}
179180
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+
184190 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 ,
217239 }
218240}
0 commit comments