about summary refs log tree commit diff
diff options
context:
space:
mode:
authorMatthias Krüger <matthias.krueger@famsik.de>2022-02-06 04:13:32 +0100
committerGitHub <noreply@github.com>2022-02-06 04:13:32 +0100
commit59baf4db0f73e60702d1b4b101a0789e63ddce8f (patch)
treebb4fa7ca30779a6f0a74145cfc2906c4647605e0
parent05bb32dde2289b5385373af2faaabc4b8498aa50 (diff)
parentca3057fd5595667d6eeb703b9ab80dbe73e8841c (diff)
downloadrust-59baf4db0f73e60702d1b4b101a0789e63ddce8f.tar.gz
rust-59baf4db0f73e60702d1b4b101a0789e63ddce8f.zip
Rollup merge of #93556 - dtolnay:trailingcomma, r=cjgillot
Change struct expr pretty printing to match rustfmt style

This PR backports trailing comma support from https://github.com/dtolnay/prettyplease into rustc_ast_pretty and uses it to improve the formatting of struct expressions.

Example:

```rust
macro_rules! stringify_expr {
    ($expr:expr) => {
        stringify!($expr)
    };
}

fn main() {
    println!("{}", stringify_expr!(Struct {
        a: Struct { b, c },
    }));
    println!("{}", stringify_expr!(Struct {
        aaaaaaaaaa: AAAAAAAAAA,
        bbbbbbbbbb: Struct {
            cccccccccc: CCCCCCCCCC,
            dddddddddd: DDDDDDDDDD,
            eeeeeeeeee: EEEEEEEEEE,
        },
    }));
}
```

🤮 Before:

```console
Struct{a: Struct{b, c,},}
Struct{aaaaaaaaaa: AAAAAAAAAA,
    bbbbbbbbbb:
        Struct{cccccccccc: CCCCCCCCCC,
            dddddddddd: DDDDDDDDDD,
            eeeeeeeeee: EEEEEEEEEE,},}
```

After:

```console
Struct { a: Struct { b, c } }
Struct {
    aaaaaaaaaa: AAAAAAAAAA,
    bbbbbbbbbb: Struct {
        cccccccccc: CCCCCCCCCC,
        dddddddddd: DDDDDDDDDD,
        eeeeeeeeee: EEEEEEEEEE,
    },
}
```
-rw-r--r--compiler/rustc_ast_pretty/src/pp.rs22
-rw-r--r--compiler/rustc_ast_pretty/src/pp/convenience.rs33
-rw-r--r--compiler/rustc_ast_pretty/src/pprust/state.rs5
-rw-r--r--compiler/rustc_ast_pretty/src/pprust/state/delimited.rs41
-rw-r--r--compiler/rustc_ast_pretty/src/pprust/state/expr.rs70
-rw-r--r--compiler/rustc_hir_pretty/src/lib.rs2
-rw-r--r--src/test/pretty/ast-stmt-expr-attr.rs6
-rw-r--r--src/test/pretty/issue-68710-field-attr-proc-mac-lost.rs5
-rw-r--r--src/test/pretty/stmt_expr_attributes.rs12
-rw-r--r--src/test/ui/macros/stringify.rs20
-rw-r--r--src/test/ui/rfc-2361-dbg-macro/dbg-macro-expected-behavior.run.stderr2
11 files changed, 148 insertions, 70 deletions
diff --git a/compiler/rustc_ast_pretty/src/pp.rs b/compiler/rustc_ast_pretty/src/pp.rs
index d567c8dae43..ddce86f2165 100644
--- a/compiler/rustc_ast_pretty/src/pp.rs
+++ b/compiler/rustc_ast_pretty/src/pp.rs
@@ -148,7 +148,7 @@ pub enum Breaks {
     Inconsistent,
 }
 
-#[derive(Clone, Copy)]
+#[derive(Clone, Copy, PartialEq)]
 enum IndentStyle {
     /// Vertically aligned under whatever column this block begins at.
     ///
@@ -164,19 +164,20 @@ enum IndentStyle {
     Block { offset: isize },
 }
 
-#[derive(Clone, Copy)]
+#[derive(Clone, Copy, Default, PartialEq)]
 pub struct BreakToken {
     offset: isize,
     blank_space: isize,
+    pre_break: Option<char>,
 }
 
-#[derive(Clone, Copy)]
+#[derive(Clone, Copy, PartialEq)]
 pub struct BeginToken {
     indent: IndentStyle,
     breaks: Breaks,
 }
 
-#[derive(Clone)]
+#[derive(Clone, PartialEq)]
 pub enum Token {
     // In practice a string token contains either a `&'static str` or a
     // `String`. `Cow` is overkill for this because we never modify the data,
@@ -313,6 +314,12 @@ impl Printer {
         }
     }
 
+    pub fn offset(&mut self, offset: isize) {
+        if let Some(BufEntry { token: Token::Break(token), .. }) = &mut self.buf.last_mut() {
+            token.offset += offset;
+        }
+    }
+
     fn check_stream(&mut self) {
         while self.right_total - self.left_total > self.space {
             if *self.scan_stack.front().unwrap() == self.buf.index_of_first() {
@@ -391,7 +398,9 @@ impl Printer {
         if size > self.space {
             self.print_stack.push(PrintFrame::Broken { indent: self.indent, breaks: token.breaks });
             self.indent = match token.indent {
-                IndentStyle::Block { offset } => (self.indent as isize + offset) as usize,
+                IndentStyle::Block { offset } => {
+                    usize::try_from(self.indent as isize + offset).unwrap()
+                }
                 IndentStyle::Visual => (MARGIN - self.space) as usize,
             };
         } else {
@@ -415,6 +424,9 @@ impl Printer {
             self.pending_indentation += token.blank_space;
             self.space -= token.blank_space;
         } else {
+            if let Some(pre_break) = token.pre_break {
+                self.out.push(pre_break);
+            }
             self.out.push('\n');
             let indent = self.indent as isize + token.offset;
             self.pending_indentation = indent;
diff --git a/compiler/rustc_ast_pretty/src/pp/convenience.rs b/compiler/rustc_ast_pretty/src/pp/convenience.rs
index 1b9ac705883..785e6886d8a 100644
--- a/compiler/rustc_ast_pretty/src/pp/convenience.rs
+++ b/compiler/rustc_ast_pretty/src/pp/convenience.rs
@@ -3,20 +3,17 @@ use std::borrow::Cow;
 
 impl Printer {
     /// "raw box"
-    pub fn rbox(&mut self, indent: usize, breaks: Breaks) {
-        self.scan_begin(BeginToken {
-            indent: IndentStyle::Block { offset: indent as isize },
-            breaks,
-        })
+    pub fn rbox(&mut self, indent: isize, breaks: Breaks) {
+        self.scan_begin(BeginToken { indent: IndentStyle::Block { offset: indent }, breaks })
     }
 
     /// Inconsistent breaking box
-    pub fn ibox(&mut self, indent: usize) {
+    pub fn ibox(&mut self, indent: isize) {
         self.rbox(indent, Breaks::Inconsistent)
     }
 
     /// Consistent breaking box
-    pub fn cbox(&mut self, indent: usize) {
+    pub fn cbox(&mut self, indent: isize) {
         self.rbox(indent, Breaks::Consistent)
     }
 
@@ -25,7 +22,11 @@ impl Printer {
     }
 
     pub fn break_offset(&mut self, n: usize, off: isize) {
-        self.scan_break(BreakToken { offset: off, blank_space: n as isize })
+        self.scan_break(BreakToken {
+            offset: off,
+            blank_space: n as isize,
+            ..BreakToken::default()
+        });
     }
 
     pub fn end(&mut self) {
@@ -66,12 +67,24 @@ impl Printer {
     }
 
     pub fn hardbreak_tok_offset(off: isize) -> Token {
-        Token::Break(BreakToken { offset: off, blank_space: SIZE_INFINITY })
+        Token::Break(BreakToken {
+            offset: off,
+            blank_space: SIZE_INFINITY,
+            ..BreakToken::default()
+        })
+    }
+
+    pub fn trailing_comma(&mut self) {
+        self.scan_break(BreakToken {
+            blank_space: 1,
+            pre_break: Some(','),
+            ..BreakToken::default()
+        });
     }
 }
 
 impl Token {
     pub fn is_hardbreak_tok(&self) -> bool {
-        matches!(self, Token::Break(BreakToken { offset: 0, blank_space: SIZE_INFINITY }))
+        *self == Printer::hardbreak_tok_offset(0)
     }
 }
diff --git a/compiler/rustc_ast_pretty/src/pprust/state.rs b/compiler/rustc_ast_pretty/src/pprust/state.rs
index b575dc21961..b2c62383fb6 100644
--- a/compiler/rustc_ast_pretty/src/pprust/state.rs
+++ b/compiler/rustc_ast_pretty/src/pprust/state.rs
@@ -1,3 +1,4 @@
+mod delimited;
 mod expr;
 mod item;
 
@@ -23,6 +24,8 @@ use rustc_span::{BytePos, FileName, Span};
 
 use std::borrow::Cow;
 
+pub use self::delimited::IterDelimited;
+
 pub enum MacHeader<'a> {
     Path(&'a ast::Path),
     Keyword(&'static str),
@@ -92,7 +95,7 @@ pub struct State<'a> {
     ann: &'a (dyn PpAnn + 'a),
 }
 
-crate const INDENT_UNIT: usize = 4;
+crate const INDENT_UNIT: isize = 4;
 
 /// Requires you to pass an input filename and reader so that
 /// it can scan the input text for comments to copy forward.
diff --git a/compiler/rustc_ast_pretty/src/pprust/state/delimited.rs b/compiler/rustc_ast_pretty/src/pprust/state/delimited.rs
new file mode 100644
index 00000000000..fe0640baaa1
--- /dev/null
+++ b/compiler/rustc_ast_pretty/src/pprust/state/delimited.rs
@@ -0,0 +1,41 @@
+use std::iter::Peekable;
+use std::mem;
+use std::ops::Deref;
+
+pub struct Delimited<I: Iterator> {
+    is_first: bool,
+    iter: Peekable<I>,
+}
+
+pub trait IterDelimited: Iterator + Sized {
+    fn delimited(self) -> Delimited<Self> {
+        Delimited { is_first: true, iter: self.peekable() }
+    }
+}
+
+impl<I: Iterator> IterDelimited for I {}
+
+pub struct IteratorItem<T> {
+    value: T,
+    pub is_first: bool,
+    pub is_last: bool,
+}
+
+impl<I: Iterator> Iterator for Delimited<I> {
+    type Item = IteratorItem<I::Item>;
+
+    fn next(&mut self) -> Option<Self::Item> {
+        let value = self.iter.next()?;
+        let is_first = mem::replace(&mut self.is_first, false);
+        let is_last = self.iter.peek().is_none();
+        Some(IteratorItem { value, is_first, is_last })
+    }
+}
+
+impl<T> Deref for IteratorItem<T> {
+    type Target = T;
+
+    fn deref(&self) -> &Self::Target {
+        &self.value
+    }
+}
diff --git a/compiler/rustc_ast_pretty/src/pprust/state/expr.rs b/compiler/rustc_ast_pretty/src/pprust/state/expr.rs
index 6a5bba30b8b..44116fa76a0 100644
--- a/compiler/rustc_ast_pretty/src/pprust/state/expr.rs
+++ b/compiler/rustc_ast_pretty/src/pprust/state/expr.rs
@@ -1,5 +1,5 @@
-use crate::pp::Breaks::{Consistent, Inconsistent};
-use crate::pprust::state::{AnnNode, PrintState, State, INDENT_UNIT};
+use crate::pp::Breaks::Inconsistent;
+use crate::pprust::state::{AnnNode, IterDelimited, PrintState, State, INDENT_UNIT};
 
 use rustc_ast::ptr::P;
 use rustc_ast::util::parser::{self, AssocOp, Fixity};
@@ -117,38 +117,46 @@ impl<'a> State<'a> {
         } else {
             self.print_path(path, true, 0);
         }
+        self.nbsp();
         self.word("{");
-        self.commasep_cmnt(
-            Consistent,
-            fields,
-            |s, field| {
-                s.print_outer_attributes(&field.attrs);
-                s.ibox(INDENT_UNIT);
-                if !field.is_shorthand {
-                    s.print_ident(field.ident);
-                    s.word_space(":");
-                }
-                s.print_expr(&field.expr);
-                s.end();
-            },
-            |f| f.span,
-        );
-        match rest {
-            ast::StructRest::Base(_) | ast::StructRest::Rest(_) => {
-                self.ibox(INDENT_UNIT);
-                if !fields.is_empty() {
-                    self.word(",");
-                    self.space();
-                }
-                self.word("..");
-                if let ast::StructRest::Base(ref expr) = *rest {
-                    self.print_expr(expr);
-                }
-                self.end();
+        let has_rest = match rest {
+            ast::StructRest::Base(_) | ast::StructRest::Rest(_) => true,
+            ast::StructRest::None => false,
+        };
+        if fields.is_empty() && !has_rest {
+            self.word("}");
+            return;
+        }
+        self.cbox(0);
+        for field in fields.iter().delimited() {
+            self.maybe_print_comment(field.span.hi());
+            self.print_outer_attributes(&field.attrs);
+            if field.is_first {
+                self.space_if_not_bol();
+            }
+            if !field.is_shorthand {
+                self.print_ident(field.ident);
+                self.word_nbsp(":");
+            }
+            self.print_expr(&field.expr);
+            if !field.is_last || has_rest {
+                self.word_space(",");
+            } else {
+                self.trailing_comma();
             }
-            ast::StructRest::None if !fields.is_empty() => self.word(","),
-            _ => {}
         }
+        if has_rest {
+            if fields.is_empty() {
+                self.space();
+            }
+            self.word("..");
+            if let ast::StructRest::Base(expr) = rest {
+                self.print_expr(expr);
+            }
+            self.space();
+        }
+        self.offset(-INDENT_UNIT);
+        self.end();
         self.word("}");
     }
 
diff --git a/compiler/rustc_hir_pretty/src/lib.rs b/compiler/rustc_hir_pretty/src/lib.rs
index a47ebaf1237..13008a83379 100644
--- a/compiler/rustc_hir_pretty/src/lib.rs
+++ b/compiler/rustc_hir_pretty/src/lib.rs
@@ -139,7 +139,7 @@ impl<'a> PrintState<'a> for State<'a> {
     }
 }
 
-pub const INDENT_UNIT: usize = 4;
+pub const INDENT_UNIT: isize = 4;
 
 /// Requires you to pass an input filename and reader so that
 /// it can scan the input text for comments to copy forward.
diff --git a/src/test/pretty/ast-stmt-expr-attr.rs b/src/test/pretty/ast-stmt-expr-attr.rs
index 2404b321942..27c86ec22b8 100644
--- a/src/test/pretty/ast-stmt-expr-attr.rs
+++ b/src/test/pretty/ast-stmt-expr-attr.rs
@@ -119,9 +119,9 @@ fn syntax() {
     let _ = #[attr] foo![#! [attr]];
     let _ = #[attr] foo! {};
     let _ = #[attr] foo! { #! [attr] };
-    let _ = #[attr] Foo{bar: baz,};
-    let _ = #[attr] Foo{..foo};
-    let _ = #[attr] Foo{bar: baz, ..foo};
+    let _ = #[attr] Foo { bar: baz };
+    let _ = #[attr] Foo { ..foo };
+    let _ = #[attr] Foo { bar: baz, ..foo };
     let _ = #[attr] (0);
 
     {
diff --git a/src/test/pretty/issue-68710-field-attr-proc-mac-lost.rs b/src/test/pretty/issue-68710-field-attr-proc-mac-lost.rs
index 87f525a6178..80f739f4f9e 100644
--- a/src/test/pretty/issue-68710-field-attr-proc-mac-lost.rs
+++ b/src/test/pretty/issue-68710-field-attr-proc-mac-lost.rs
@@ -8,9 +8,10 @@ struct C {
 
 #[allow()]
 const C: C =
-    C{
+    C {
         #[cfg(debug_assertions)]
         field: 0,
 
         #[cfg(not(debug_assertions))]
-        field: 1,};
+        field: 1,
+    };
diff --git a/src/test/pretty/stmt_expr_attributes.rs b/src/test/pretty/stmt_expr_attributes.rs
index 96bde96200a..7ab22f1960c 100644
--- a/src/test/pretty/stmt_expr_attributes.rs
+++ b/src/test/pretty/stmt_expr_attributes.rs
@@ -90,9 +90,9 @@ struct Bar(());
 fn _7() {
 
     #[rustc_dummy]
-    Foo{data: (),};
+    Foo { data: () };
 
-    let _ = #[rustc_dummy] Foo{data: (),};
+    let _ = #[rustc_dummy] Foo { data: () };
 }
 
 fn _8() {
@@ -209,7 +209,7 @@ fn _11() {
     let mut x = 0;
     let _ = #[rustc_dummy] x = 15;
     let _ = #[rustc_dummy] x += 15;
-    let s = Foo{data: (),};
+    let s = Foo { data: () };
     let _ = #[rustc_dummy] s.data;
     let _ = (#[rustc_dummy] s).data;
     let t = Bar(());
@@ -235,9 +235,9 @@ fn _11() {
     let _ = #[rustc_dummy] expr_mac!();
     let _ = #[rustc_dummy] expr_mac![];
     let _ = #[rustc_dummy] expr_mac! {};
-    let _ = #[rustc_dummy] Foo{data: (),};
-    let _ = #[rustc_dummy] Foo{..s};
-    let _ = #[rustc_dummy] Foo{data: (), ..s};
+    let _ = #[rustc_dummy] Foo { data: () };
+    let _ = #[rustc_dummy] Foo { ..s };
+    let _ = #[rustc_dummy] Foo { data: (), ..s };
     let _ = #[rustc_dummy] (0);
 }
 
diff --git a/src/test/ui/macros/stringify.rs b/src/test/ui/macros/stringify.rs
index 004ab386b3f..57e5ab42f79 100644
--- a/src/test/ui/macros/stringify.rs
+++ b/src/test/ui/macros/stringify.rs
@@ -315,17 +315,17 @@ fn test_expr() {
     assert_eq!(stringify_expr!(mac! { ... }), "mac! { ... }");
 
     // ExprKind::Struct
-    assert_eq!(stringify_expr!(Struct {}), "Struct{}"); // FIXME
+    assert_eq!(stringify_expr!(Struct {}), "Struct {}");
     #[rustfmt::skip] // https://github.com/rust-lang/rustfmt/issues/5151
-    assert_eq!(stringify_expr!(<Struct as Trait>::Type {}), "<Struct as Trait>::Type{}");
-    assert_eq!(stringify_expr!(Struct { .. }), "Struct{..}"); // FIXME
-    assert_eq!(stringify_expr!(Struct { ..base }), "Struct{..base}"); // FIXME
-    assert_eq!(stringify_expr!(Struct { x }), "Struct{x,}");
-    assert_eq!(stringify_expr!(Struct { x, .. }), "Struct{x, ..}");
-    assert_eq!(stringify_expr!(Struct { x, ..base }), "Struct{x, ..base}");
-    assert_eq!(stringify_expr!(Struct { x: true }), "Struct{x: true,}");
-    assert_eq!(stringify_expr!(Struct { x: true, .. }), "Struct{x: true, ..}");
-    assert_eq!(stringify_expr!(Struct { x: true, ..base }), "Struct{x: true, ..base}");
+    assert_eq!(stringify_expr!(<Struct as Trait>::Type {}), "<Struct as Trait>::Type {}");
+    assert_eq!(stringify_expr!(Struct { .. }), "Struct { .. }");
+    assert_eq!(stringify_expr!(Struct { ..base }), "Struct { ..base }");
+    assert_eq!(stringify_expr!(Struct { x }), "Struct { x }");
+    assert_eq!(stringify_expr!(Struct { x, .. }), "Struct { x, .. }");
+    assert_eq!(stringify_expr!(Struct { x, ..base }), "Struct { x, ..base }");
+    assert_eq!(stringify_expr!(Struct { x: true }), "Struct { x: true }");
+    assert_eq!(stringify_expr!(Struct { x: true, .. }), "Struct { x: true, .. }");
+    assert_eq!(stringify_expr!(Struct { x: true, ..base }), "Struct { x: true, ..base }");
 
     // ExprKind::Repeat
     assert_eq!(stringify_expr!([(); 0]), "[(); 0]");
diff --git a/src/test/ui/rfc-2361-dbg-macro/dbg-macro-expected-behavior.run.stderr b/src/test/ui/rfc-2361-dbg-macro/dbg-macro-expected-behavior.run.stderr
index 707b38cf37a..49d72158e92 100644
--- a/src/test/ui/rfc-2361-dbg-macro/dbg-macro-expected-behavior.run.stderr
+++ b/src/test/ui/rfc-2361-dbg-macro/dbg-macro-expected-behavior.run.stderr
@@ -1,6 +1,6 @@
 [$DIR/dbg-macro-expected-behavior.rs:20] Unit = Unit
 [$DIR/dbg-macro-expected-behavior.rs:21] a = Unit
-[$DIR/dbg-macro-expected-behavior.rs:27] Point{x: 42, y: 24,} = Point {
+[$DIR/dbg-macro-expected-behavior.rs:27] Point { x: 42, y: 24 } = Point {
     x: 42,
     y: 24,
 }