@@ -681,22 +681,40 @@ pub trait PrintState<'a>: std::ops::Deref<Target = pp::Printer> + std::ops::Dere
681681 }
682682 }
683683
684+ // The easiest way to implement token stream pretty printing would be to
685+ // print each token followed by a single space. But that would produce ugly
686+ // output, so we go to some effort to do better.
687+ //
688+ // First, we track whether each token that appears in source code is
689+ // followed by a space, with `Spacing`, and reproduce that in the output.
690+ // This works well in a lot of cases. E.g. `stringify!(x + y)` produces
691+ // "x + y" and `stringify!(x+y)` produces "x+y".
692+ //
693+ // But this doesn't work for code produced by proc macros (which have no
694+ // original source text representation) nor for code produced by decl
695+ // macros (which are tricky because the whitespace after tokens appearing
696+ // in macro rules isn't always what you want in the produced output). For
697+ // these we mostly use `Spacing::Alone`, which is the conservative choice.
698+ //
699+ // So we have a backup mechanism for when `Spacing::Alone` occurs between a
700+ // pair of tokens: we check if that pair of tokens can obviously go
701+ // together without a space between them. E.g. token `x` followed by token
702+ // `,` is better printed as `x,` than `x ,`. (Even if the original source
703+ // code was `x ,`.)
704+ //
705+ // Finally, we must be careful about changing the output. Token pretty
706+ // printing is used by `stringify!` and `impl Display for
707+ // proc_macro::TokenStream`, and some programs rely on the output having a
708+ // particular form, even though they shouldn't. In particular, some proc
709+ // macros do `format!({stream})` on a token stream and then "parse" the
710+ // output with simple string matching that can't handle whitespace changes.
711+ // E.g. we have seen cases where a proc macro can handle `a :: b` but not
712+ // `a::b`. See #117433 for some examples.
684713 fn print_tts ( & mut self , tts : & TokenStream , convert_dollar_crate : bool ) {
685714 let mut iter = tts. trees ( ) . peekable ( ) ;
686715 while let Some ( tt) = iter. next ( ) {
687716 let spacing = self . print_tt ( tt, convert_dollar_crate) ;
688717 if let Some ( next) = iter. peek ( ) {
689- // Should we print a space after `tt`? There are two guiding
690- // factors.
691- // - `spacing` is the more important and accurate one. Most
692- // tokens have good spacing information, and
693- // `Joint`/`JointHidden` get used a lot.
694- // - `space_between` is the backup. Code produced by proc
695- // macros has worse spacing information, with no
696- // `JointHidden` usage and too much `Alone` usage, which
697- // would result in over-spaced output such as
698- // `( x () , y . z )`. `space_between` avoids some of the
699- // excess whitespace.
700718 if spacing == Spacing :: Alone && space_between ( tt, next) {
701719 self . space ( ) ;
702720 }
0 commit comments