Skip to content

Commit 59baf4d

Browse files
authored
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, }, } ```
2 parents 05bb32d + ca3057f commit 59baf4d

File tree

11 files changed

+148
-70
lines changed

11 files changed

+148
-70
lines changed

compiler/rustc_ast_pretty/src/pp.rs

+17-5
Original file line numberDiff line numberDiff line change
@@ -148,7 +148,7 @@ pub enum Breaks {
148148
Inconsistent,
149149
}
150150

151-
#[derive(Clone, Copy)]
151+
#[derive(Clone, Copy, PartialEq)]
152152
enum IndentStyle {
153153
/// Vertically aligned under whatever column this block begins at.
154154
///
@@ -164,19 +164,20 @@ enum IndentStyle {
164164
Block { offset: isize },
165165
}
166166

167-
#[derive(Clone, Copy)]
167+
#[derive(Clone, Copy, Default, PartialEq)]
168168
pub struct BreakToken {
169169
offset: isize,
170170
blank_space: isize,
171+
pre_break: Option<char>,
171172
}
172173

173-
#[derive(Clone, Copy)]
174+
#[derive(Clone, Copy, PartialEq)]
174175
pub struct BeginToken {
175176
indent: IndentStyle,
176177
breaks: Breaks,
177178
}
178179

179-
#[derive(Clone)]
180+
#[derive(Clone, PartialEq)]
180181
pub enum Token {
181182
// In practice a string token contains either a `&'static str` or a
182183
// `String`. `Cow` is overkill for this because we never modify the data,
@@ -313,6 +314,12 @@ impl Printer {
313314
}
314315
}
315316

317+
pub fn offset(&mut self, offset: isize) {
318+
if let Some(BufEntry { token: Token::Break(token), .. }) = &mut self.buf.last_mut() {
319+
token.offset += offset;
320+
}
321+
}
322+
316323
fn check_stream(&mut self) {
317324
while self.right_total - self.left_total > self.space {
318325
if *self.scan_stack.front().unwrap() == self.buf.index_of_first() {
@@ -391,7 +398,9 @@ impl Printer {
391398
if size > self.space {
392399
self.print_stack.push(PrintFrame::Broken { indent: self.indent, breaks: token.breaks });
393400
self.indent = match token.indent {
394-
IndentStyle::Block { offset } => (self.indent as isize + offset) as usize,
401+
IndentStyle::Block { offset } => {
402+
usize::try_from(self.indent as isize + offset).unwrap()
403+
}
395404
IndentStyle::Visual => (MARGIN - self.space) as usize,
396405
};
397406
} else {
@@ -415,6 +424,9 @@ impl Printer {
415424
self.pending_indentation += token.blank_space;
416425
self.space -= token.blank_space;
417426
} else {
427+
if let Some(pre_break) = token.pre_break {
428+
self.out.push(pre_break);
429+
}
418430
self.out.push('\n');
419431
let indent = self.indent as isize + token.offset;
420432
self.pending_indentation = indent;

compiler/rustc_ast_pretty/src/pp/convenience.rs

+23-10
Original file line numberDiff line numberDiff line change
@@ -3,20 +3,17 @@ use std::borrow::Cow;
33

44
impl Printer {
55
/// "raw box"
6-
pub fn rbox(&mut self, indent: usize, breaks: Breaks) {
7-
self.scan_begin(BeginToken {
8-
indent: IndentStyle::Block { offset: indent as isize },
9-
breaks,
10-
})
6+
pub fn rbox(&mut self, indent: isize, breaks: Breaks) {
7+
self.scan_begin(BeginToken { indent: IndentStyle::Block { offset: indent }, breaks })
118
}
129

1310
/// Inconsistent breaking box
14-
pub fn ibox(&mut self, indent: usize) {
11+
pub fn ibox(&mut self, indent: isize) {
1512
self.rbox(indent, Breaks::Inconsistent)
1613
}
1714

1815
/// Consistent breaking box
19-
pub fn cbox(&mut self, indent: usize) {
16+
pub fn cbox(&mut self, indent: isize) {
2017
self.rbox(indent, Breaks::Consistent)
2118
}
2219

@@ -25,7 +22,11 @@ impl Printer {
2522
}
2623

2724
pub fn break_offset(&mut self, n: usize, off: isize) {
28-
self.scan_break(BreakToken { offset: off, blank_space: n as isize })
25+
self.scan_break(BreakToken {
26+
offset: off,
27+
blank_space: n as isize,
28+
..BreakToken::default()
29+
});
2930
}
3031

3132
pub fn end(&mut self) {
@@ -66,12 +67,24 @@ impl Printer {
6667
}
6768

6869
pub fn hardbreak_tok_offset(off: isize) -> Token {
69-
Token::Break(BreakToken { offset: off, blank_space: SIZE_INFINITY })
70+
Token::Break(BreakToken {
71+
offset: off,
72+
blank_space: SIZE_INFINITY,
73+
..BreakToken::default()
74+
})
75+
}
76+
77+
pub fn trailing_comma(&mut self) {
78+
self.scan_break(BreakToken {
79+
blank_space: 1,
80+
pre_break: Some(','),
81+
..BreakToken::default()
82+
});
7083
}
7184
}
7285

7386
impl Token {
7487
pub fn is_hardbreak_tok(&self) -> bool {
75-
matches!(self, Token::Break(BreakToken { offset: 0, blank_space: SIZE_INFINITY }))
88+
*self == Printer::hardbreak_tok_offset(0)
7689
}
7790
}

compiler/rustc_ast_pretty/src/pprust/state.rs

+4-1
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
1+
mod delimited;
12
mod expr;
23
mod item;
34

@@ -23,6 +24,8 @@ use rustc_span::{BytePos, FileName, Span};
2324

2425
use std::borrow::Cow;
2526

27+
pub use self::delimited::IterDelimited;
28+
2629
pub enum MacHeader<'a> {
2730
Path(&'a ast::Path),
2831
Keyword(&'static str),
@@ -92,7 +95,7 @@ pub struct State<'a> {
9295
ann: &'a (dyn PpAnn + 'a),
9396
}
9497

95-
crate const INDENT_UNIT: usize = 4;
98+
crate const INDENT_UNIT: isize = 4;
9699

97100
/// Requires you to pass an input filename and reader so that
98101
/// it can scan the input text for comments to copy forward.
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,41 @@
1+
use std::iter::Peekable;
2+
use std::mem;
3+
use std::ops::Deref;
4+
5+
pub struct Delimited<I: Iterator> {
6+
is_first: bool,
7+
iter: Peekable<I>,
8+
}
9+
10+
pub trait IterDelimited: Iterator + Sized {
11+
fn delimited(self) -> Delimited<Self> {
12+
Delimited { is_first: true, iter: self.peekable() }
13+
}
14+
}
15+
16+
impl<I: Iterator> IterDelimited for I {}
17+
18+
pub struct IteratorItem<T> {
19+
value: T,
20+
pub is_first: bool,
21+
pub is_last: bool,
22+
}
23+
24+
impl<I: Iterator> Iterator for Delimited<I> {
25+
type Item = IteratorItem<I::Item>;
26+
27+
fn next(&mut self) -> Option<Self::Item> {
28+
let value = self.iter.next()?;
29+
let is_first = mem::replace(&mut self.is_first, false);
30+
let is_last = self.iter.peek().is_none();
31+
Some(IteratorItem { value, is_first, is_last })
32+
}
33+
}
34+
35+
impl<T> Deref for IteratorItem<T> {
36+
type Target = T;
37+
38+
fn deref(&self) -> &Self::Target {
39+
&self.value
40+
}
41+
}

compiler/rustc_ast_pretty/src/pprust/state/expr.rs

+39-31
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
1-
use crate::pp::Breaks::{Consistent, Inconsistent};
2-
use crate::pprust::state::{AnnNode, PrintState, State, INDENT_UNIT};
1+
use crate::pp::Breaks::Inconsistent;
2+
use crate::pprust::state::{AnnNode, IterDelimited, PrintState, State, INDENT_UNIT};
33

44
use rustc_ast::ptr::P;
55
use rustc_ast::util::parser::{self, AssocOp, Fixity};
@@ -117,38 +117,46 @@ impl<'a> State<'a> {
117117
} else {
118118
self.print_path(path, true, 0);
119119
}
120+
self.nbsp();
120121
self.word("{");
121-
self.commasep_cmnt(
122-
Consistent,
123-
fields,
124-
|s, field| {
125-
s.print_outer_attributes(&field.attrs);
126-
s.ibox(INDENT_UNIT);
127-
if !field.is_shorthand {
128-
s.print_ident(field.ident);
129-
s.word_space(":");
130-
}
131-
s.print_expr(&field.expr);
132-
s.end();
133-
},
134-
|f| f.span,
135-
);
136-
match rest {
137-
ast::StructRest::Base(_) | ast::StructRest::Rest(_) => {
138-
self.ibox(INDENT_UNIT);
139-
if !fields.is_empty() {
140-
self.word(",");
141-
self.space();
142-
}
143-
self.word("..");
144-
if let ast::StructRest::Base(ref expr) = *rest {
145-
self.print_expr(expr);
146-
}
147-
self.end();
122+
let has_rest = match rest {
123+
ast::StructRest::Base(_) | ast::StructRest::Rest(_) => true,
124+
ast::StructRest::None => false,
125+
};
126+
if fields.is_empty() && !has_rest {
127+
self.word("}");
128+
return;
129+
}
130+
self.cbox(0);
131+
for field in fields.iter().delimited() {
132+
self.maybe_print_comment(field.span.hi());
133+
self.print_outer_attributes(&field.attrs);
134+
if field.is_first {
135+
self.space_if_not_bol();
136+
}
137+
if !field.is_shorthand {
138+
self.print_ident(field.ident);
139+
self.word_nbsp(":");
140+
}
141+
self.print_expr(&field.expr);
142+
if !field.is_last || has_rest {
143+
self.word_space(",");
144+
} else {
145+
self.trailing_comma();
148146
}
149-
ast::StructRest::None if !fields.is_empty() => self.word(","),
150-
_ => {}
151147
}
148+
if has_rest {
149+
if fields.is_empty() {
150+
self.space();
151+
}
152+
self.word("..");
153+
if let ast::StructRest::Base(expr) = rest {
154+
self.print_expr(expr);
155+
}
156+
self.space();
157+
}
158+
self.offset(-INDENT_UNIT);
159+
self.end();
152160
self.word("}");
153161
}
154162

compiler/rustc_hir_pretty/src/lib.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -139,7 +139,7 @@ impl<'a> PrintState<'a> for State<'a> {
139139
}
140140
}
141141

142-
pub const INDENT_UNIT: usize = 4;
142+
pub const INDENT_UNIT: isize = 4;
143143

144144
/// Requires you to pass an input filename and reader so that
145145
/// it can scan the input text for comments to copy forward.

src/test/pretty/ast-stmt-expr-attr.rs

+3-3
Original file line numberDiff line numberDiff line change
@@ -119,9 +119,9 @@ fn syntax() {
119119
let _ = #[attr] foo![#! [attr]];
120120
let _ = #[attr] foo! {};
121121
let _ = #[attr] foo! { #! [attr] };
122-
let _ = #[attr] Foo{bar: baz,};
123-
let _ = #[attr] Foo{..foo};
124-
let _ = #[attr] Foo{bar: baz, ..foo};
122+
let _ = #[attr] Foo { bar: baz };
123+
let _ = #[attr] Foo { ..foo };
124+
let _ = #[attr] Foo { bar: baz, ..foo };
125125
let _ = #[attr] (0);
126126

127127
{

src/test/pretty/issue-68710-field-attr-proc-mac-lost.rs

+3-2
Original file line numberDiff line numberDiff line change
@@ -8,9 +8,10 @@ struct C {
88

99
#[allow()]
1010
const C: C =
11-
C{
11+
C {
1212
#[cfg(debug_assertions)]
1313
field: 0,
1414

1515
#[cfg(not(debug_assertions))]
16-
field: 1,};
16+
field: 1,
17+
};

src/test/pretty/stmt_expr_attributes.rs

+6-6
Original file line numberDiff line numberDiff line change
@@ -90,9 +90,9 @@ struct Bar(());
9090
fn _7() {
9191

9292
#[rustc_dummy]
93-
Foo{data: (),};
93+
Foo { data: () };
9494

95-
let _ = #[rustc_dummy] Foo{data: (),};
95+
let _ = #[rustc_dummy] Foo { data: () };
9696
}
9797

9898
fn _8() {
@@ -209,7 +209,7 @@ fn _11() {
209209
let mut x = 0;
210210
let _ = #[rustc_dummy] x = 15;
211211
let _ = #[rustc_dummy] x += 15;
212-
let s = Foo{data: (),};
212+
let s = Foo { data: () };
213213
let _ = #[rustc_dummy] s.data;
214214
let _ = (#[rustc_dummy] s).data;
215215
let t = Bar(());
@@ -235,9 +235,9 @@ fn _11() {
235235
let _ = #[rustc_dummy] expr_mac!();
236236
let _ = #[rustc_dummy] expr_mac![];
237237
let _ = #[rustc_dummy] expr_mac! {};
238-
let _ = #[rustc_dummy] Foo{data: (),};
239-
let _ = #[rustc_dummy] Foo{..s};
240-
let _ = #[rustc_dummy] Foo{data: (), ..s};
238+
let _ = #[rustc_dummy] Foo { data: () };
239+
let _ = #[rustc_dummy] Foo { ..s };
240+
let _ = #[rustc_dummy] Foo { data: (), ..s };
241241
let _ = #[rustc_dummy] (0);
242242
}
243243

src/test/ui/macros/stringify.rs

+10-10
Original file line numberDiff line numberDiff line change
@@ -315,17 +315,17 @@ fn test_expr() {
315315
assert_eq!(stringify_expr!(mac! { ... }), "mac! { ... }");
316316

317317
// ExprKind::Struct
318-
assert_eq!(stringify_expr!(Struct {}), "Struct{}"); // FIXME
318+
assert_eq!(stringify_expr!(Struct {}), "Struct {}");
319319
#[rustfmt::skip] // https://github.com/rust-lang/rustfmt/issues/5151
320-
assert_eq!(stringify_expr!(<Struct as Trait>::Type {}), "<Struct as Trait>::Type{}");
321-
assert_eq!(stringify_expr!(Struct { .. }), "Struct{..}"); // FIXME
322-
assert_eq!(stringify_expr!(Struct { ..base }), "Struct{..base}"); // FIXME
323-
assert_eq!(stringify_expr!(Struct { x }), "Struct{x,}");
324-
assert_eq!(stringify_expr!(Struct { x, .. }), "Struct{x, ..}");
325-
assert_eq!(stringify_expr!(Struct { x, ..base }), "Struct{x, ..base}");
326-
assert_eq!(stringify_expr!(Struct { x: true }), "Struct{x: true,}");
327-
assert_eq!(stringify_expr!(Struct { x: true, .. }), "Struct{x: true, ..}");
328-
assert_eq!(stringify_expr!(Struct { x: true, ..base }), "Struct{x: true, ..base}");
320+
assert_eq!(stringify_expr!(<Struct as Trait>::Type {}), "<Struct as Trait>::Type {}");
321+
assert_eq!(stringify_expr!(Struct { .. }), "Struct { .. }");
322+
assert_eq!(stringify_expr!(Struct { ..base }), "Struct { ..base }");
323+
assert_eq!(stringify_expr!(Struct { x }), "Struct { x }");
324+
assert_eq!(stringify_expr!(Struct { x, .. }), "Struct { x, .. }");
325+
assert_eq!(stringify_expr!(Struct { x, ..base }), "Struct { x, ..base }");
326+
assert_eq!(stringify_expr!(Struct { x: true }), "Struct { x: true }");
327+
assert_eq!(stringify_expr!(Struct { x: true, .. }), "Struct { x: true, .. }");
328+
assert_eq!(stringify_expr!(Struct { x: true, ..base }), "Struct { x: true, ..base }");
329329

330330
// ExprKind::Repeat
331331
assert_eq!(stringify_expr!([(); 0]), "[(); 0]");

src/test/ui/rfc-2361-dbg-macro/dbg-macro-expected-behavior.run.stderr

+1-1
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
[$DIR/dbg-macro-expected-behavior.rs:20] Unit = Unit
22
[$DIR/dbg-macro-expected-behavior.rs:21] a = Unit
3-
[$DIR/dbg-macro-expected-behavior.rs:27] Point{x: 42, y: 24,} = Point {
3+
[$DIR/dbg-macro-expected-behavior.rs:27] Point { x: 42, y: 24 } = Point {
44
x: 42,
55
y: 24,
66
}

0 commit comments

Comments
 (0)