Skip to content

Commit 1cb22e4

Browse files
authored
Rollup merge of #93155 - dtolnay:blockindent, r=nagisa
Switch pretty printer to block-based indentation This PR backports dtolnay/prettyplease@401d60c from the `prettyplease` crate into `rustc_ast_pretty`. A before and after: ```diff - let res = - ((::alloc::fmt::format as - for<'r> fn(Arguments<'r>) -> String {format})(((::core::fmt::Arguments::new_v1 - as - fn(&[&'static str], &[ArgumentV1]) -> Arguments {Arguments::new_v1})((&([("test" - as - &str)] - as - [&str; 1]) - as - &[&str; 1]), - (&([] - as - [ArgumentV1; 0]) - as - &[ArgumentV1; 0])) - as - Arguments)) - as String); + let res = + ((::alloc::fmt::format as + for<'r> fn(Arguments<'r>) -> String {format})(((::core::fmt::Arguments::new_v1 + as + fn(&[&'static str], &[ArgumentV1]) -> Arguments {Arguments::new_v1})((&([("test" + as &str)] as [&str; 1]) as + &[&str; 1]), + (&([] as [ArgumentV1; 0]) as &[ArgumentV1; 0])) as + Arguments)) as String); ``` Previously the pretty printer would compute indentation always relative to whatever column a block begins at, like this: ```rust fn demo(arg1: usize, arg2: usize); ``` This is never the thing to do in the dominant contemporary Rust style. Rustfmt's default and the style used by the vast majority of Rust codebases is block indentation: ```rust fn demo( arg1: usize, arg2: usize, ); ``` where every indentation level is a multiple of 4 spaces and each level is indented relative to the indentation of the previous line, not the position that the block starts in. By itself this PR doesn't get perfect formatting in all cases, but it is the smallest possible step in clearly the right direction. More backports from `prettyplease` to tune the ibox/cbox indent levels around various AST node types are upcoming.
2 parents 71efe90 + 125c729 commit 1cb22e4

22 files changed

+276
-263
lines changed

compiler/rustc_ast_pretty/src/pp.rs

+49-20
Original file line numberDiff line numberDiff line change
@@ -146,6 +146,22 @@ pub enum Breaks {
146146
Inconsistent,
147147
}
148148

149+
#[derive(Clone, Copy)]
150+
enum IndentStyle {
151+
/// Vertically aligned under whatever column this block begins at.
152+
///
153+
/// fn demo(arg1: usize,
154+
/// arg2: usize);
155+
Visual,
156+
/// Indented relative to the indentation level of the previous line.
157+
///
158+
/// fn demo(
159+
/// arg1: usize,
160+
/// arg2: usize,
161+
/// );
162+
Block { offset: isize },
163+
}
164+
149165
#[derive(Clone, Copy)]
150166
pub struct BreakToken {
151167
offset: isize,
@@ -154,7 +170,7 @@ pub struct BreakToken {
154170

155171
#[derive(Clone, Copy)]
156172
pub struct BeginToken {
157-
offset: isize,
173+
indent: IndentStyle,
158174
breaks: Breaks,
159175
}
160176

@@ -178,7 +194,7 @@ impl Token {
178194
#[derive(Copy, Clone)]
179195
enum PrintFrame {
180196
Fits,
181-
Broken { offset: isize, breaks: Breaks },
197+
Broken { indent: usize, breaks: Breaks },
182198
}
183199

184200
const SIZE_INFINITY: isize = 0xffff;
@@ -204,6 +220,8 @@ pub struct Printer {
204220
scan_stack: VecDeque<usize>,
205221
/// Stack of blocks-in-progress being flushed by print
206222
print_stack: Vec<PrintFrame>,
223+
/// Level of indentation of current line
224+
indent: usize,
207225
/// Buffered indentation to avoid writing trailing whitespace
208226
pending_indentation: isize,
209227
/// The token most recently popped from the left boundary of the
@@ -229,6 +247,7 @@ impl Printer {
229247
right_total: 0,
230248
scan_stack: VecDeque::new(),
231249
print_stack: Vec::new(),
250+
indent: 0,
232251
pending_indentation: 0,
233252
last_printed: None,
234253
}
@@ -368,38 +387,41 @@ impl Printer {
368387
*self
369388
.print_stack
370389
.last()
371-
.unwrap_or(&PrintFrame::Broken { offset: 0, breaks: Breaks::Inconsistent })
390+
.unwrap_or(&PrintFrame::Broken { indent: 0, breaks: Breaks::Inconsistent })
372391
}
373392

374393
fn print_begin(&mut self, token: BeginToken, size: isize) {
375394
if size > self.space {
376-
let col = self.margin - self.space + token.offset;
377-
self.print_stack.push(PrintFrame::Broken { offset: col, breaks: token.breaks });
395+
self.print_stack.push(PrintFrame::Broken { indent: self.indent, breaks: token.breaks });
396+
self.indent = match token.indent {
397+
IndentStyle::Block { offset } => (self.indent as isize + offset) as usize,
398+
IndentStyle::Visual => (self.margin - self.space) as usize,
399+
};
378400
} else {
379401
self.print_stack.push(PrintFrame::Fits);
380402
}
381403
}
382404

383405
fn print_end(&mut self) {
384-
self.print_stack.pop().unwrap();
406+
if let PrintFrame::Broken { indent, .. } = self.print_stack.pop().unwrap() {
407+
self.indent = indent;
408+
}
385409
}
386410

387411
fn print_break(&mut self, token: BreakToken, size: isize) {
388-
let break_offset =
389-
match self.get_top() {
390-
PrintFrame::Fits => None,
391-
PrintFrame::Broken { offset, breaks: Breaks::Consistent } => Some(offset),
392-
PrintFrame::Broken { offset, breaks: Breaks::Inconsistent } => {
393-
if size > self.space { Some(offset) } else { None }
394-
}
395-
};
396-
if let Some(offset) = break_offset {
397-
self.out.push('\n');
398-
self.pending_indentation = offset + token.offset;
399-
self.space = self.margin - (offset + token.offset);
400-
} else {
412+
let fits = match self.get_top() {
413+
PrintFrame::Fits => true,
414+
PrintFrame::Broken { breaks: Breaks::Consistent, .. } => false,
415+
PrintFrame::Broken { breaks: Breaks::Inconsistent, .. } => size <= self.space,
416+
};
417+
if fits {
401418
self.pending_indentation += token.blank_space;
402419
self.space -= token.blank_space;
420+
} else {
421+
self.out.push('\n');
422+
let indent = self.indent as isize + token.offset;
423+
self.pending_indentation = indent;
424+
self.space = self.margin - indent;
403425
}
404426
}
405427

@@ -422,7 +444,10 @@ impl Printer {
422444

423445
/// "raw box"
424446
pub fn rbox(&mut self, indent: usize, breaks: Breaks) {
425-
self.scan_begin(BeginToken { offset: indent as isize, breaks })
447+
self.scan_begin(BeginToken {
448+
indent: IndentStyle::Block { offset: indent as isize },
449+
breaks,
450+
})
426451
}
427452

428453
/// Inconsistent breaking box
@@ -435,6 +460,10 @@ impl Printer {
435460
self.rbox(indent, Breaks::Consistent)
436461
}
437462

463+
pub fn visual_align(&mut self) {
464+
self.scan_begin(BeginToken { indent: IndentStyle::Visual, breaks: Breaks::Consistent });
465+
}
466+
438467
pub fn break_offset(&mut self, n: usize, off: isize) {
439468
self.scan_break(BreakToken { offset: off, blank_space: n as isize })
440469
}

compiler/rustc_ast_pretty/src/pprust/state.rs

+2-2
Original file line numberDiff line numberDiff line change
@@ -315,7 +315,7 @@ pub trait PrintState<'a>: std::ops::Deref<Target = pp::Printer> + std::ops::Dere
315315
self.word(cmnt.lines[0].clone());
316316
self.hardbreak()
317317
} else {
318-
self.ibox(0);
318+
self.visual_align();
319319
for line in &cmnt.lines {
320320
if !line.is_empty() {
321321
self.word(line.clone());
@@ -655,7 +655,7 @@ pub trait PrintState<'a>: std::ops::Deref<Target = pp::Printer> + std::ops::Dere
655655
// Outer-box is consistent.
656656
self.cbox(INDENT_UNIT);
657657
// Head-box is inconsistent.
658-
self.ibox(w.len() + 1);
658+
self.ibox(0);
659659
// Keyword that starts the head.
660660
if !w.is_empty() {
661661
self.word_nbsp(w);

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

+16-8
Original file line numberDiff line numberDiff line change
@@ -320,7 +320,9 @@ impl<'a> State<'a> {
320320
self.print_ident(label.ident);
321321
self.word_space(":");
322322
}
323-
self.head("while");
323+
self.cbox(0);
324+
self.ibox(0);
325+
self.word_nbsp("while");
324326
self.print_expr_as_cond(test);
325327
self.space();
326328
self.print_block_with_attrs(blk, attrs);
@@ -330,7 +332,9 @@ impl<'a> State<'a> {
330332
self.print_ident(label.ident);
331333
self.word_space(":");
332334
}
333-
self.head("for");
335+
self.cbox(0);
336+
self.ibox(0);
337+
self.word_nbsp("for");
334338
self.print_pat(pat);
335339
self.space();
336340
self.word_space("in");
@@ -343,12 +347,14 @@ impl<'a> State<'a> {
343347
self.print_ident(label.ident);
344348
self.word_space(":");
345349
}
346-
self.head("loop");
350+
self.cbox(0);
351+
self.ibox(0);
352+
self.word_nbsp("loop");
347353
self.print_block_with_attrs(blk, attrs);
348354
}
349355
ast::ExprKind::Match(ref expr, ref arms) => {
350-
self.cbox(INDENT_UNIT);
351-
self.ibox(INDENT_UNIT);
356+
self.cbox(0);
357+
self.ibox(0);
352358
self.word_nbsp("match");
353359
self.print_expr_as_cond(expr);
354360
self.space();
@@ -388,7 +394,7 @@ impl<'a> State<'a> {
388394
self.word_space(":");
389395
}
390396
// containing cbox, will be closed by print-block at }
391-
self.cbox(INDENT_UNIT);
397+
self.cbox(0);
392398
// head-box, will be closed by print-block after {
393399
self.ibox(0);
394400
self.print_block_with_attrs(blk, attrs);
@@ -397,7 +403,7 @@ impl<'a> State<'a> {
397403
self.word_nbsp("async");
398404
self.print_capture_clause(capture_clause);
399405
// cbox/ibox in analogy to the `ExprKind::Block` arm above
400-
self.cbox(INDENT_UNIT);
406+
self.cbox(0);
401407
self.ibox(0);
402408
self.print_block_with_attrs(blk, attrs);
403409
}
@@ -500,7 +506,9 @@ impl<'a> State<'a> {
500506
self.word("?")
501507
}
502508
ast::ExprKind::TryBlock(ref blk) => {
503-
self.head("try");
509+
self.cbox(0);
510+
self.ibox(0);
511+
self.word_nbsp("try");
504512
self.print_block_with_attrs(blk, attrs)
505513
}
506514
ast::ExprKind::Err => {

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

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

44
use rustc_ast as ast;
55
use rustc_ast::GenericBound;
@@ -377,7 +377,7 @@ impl<'a> State<'a> {
377377
self.space_if_not_bol();
378378
self.maybe_print_comment(v.span.lo());
379379
self.print_outer_attributes(&v.attrs);
380-
self.ibox(INDENT_UNIT);
380+
self.ibox(0);
381381
self.print_variant(v);
382382
self.word(",");
383383
self.end();

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

+37-37
Original file line numberDiff line numberDiff line change
@@ -28,67 +28,67 @@ fn syntax() {
2828
let _ = #[attr] (x as Y);
2929
let _ =
3030
#[attr] while true {
31-
#![attr]
32-
};
31+
#![attr]
32+
};
3333
let _ =
3434
#[attr] while let Some(false) = true {
35-
#![attr]
36-
};
35+
#![attr]
36+
};
3737
let _ =
3838
#[attr] for x in y {
39-
#![attr]
40-
};
39+
#![attr]
40+
};
4141
let _ =
4242
#[attr] loop {
43-
#![attr]
44-
};
43+
#![attr]
44+
};
4545
let _ =
4646
#[attr] match true {
47-
#![attr]
48-
#[attr]
49-
_ => false,
50-
};
47+
#![attr]
48+
#[attr]
49+
_ => false,
50+
};
5151
let _ = #[attr] || #[attr] foo;
5252
let _ = #[attr] move || #[attr] foo;
5353
let _ =
5454
#[attr] ||
55-
#[attr] {
56-
#![attr]
57-
foo
58-
};
55+
#[attr] {
56+
#![attr]
57+
foo
58+
};
5959
let _ =
6060
#[attr] move ||
61-
#[attr] {
62-
#![attr]
63-
foo
64-
};
61+
#[attr] {
62+
#![attr]
63+
foo
64+
};
6565
let _ =
6666
#[attr] ||
67-
{
68-
#![attr]
69-
foo
70-
};
67+
{
68+
#![attr]
69+
foo
70+
};
7171
let _ =
7272
#[attr] move ||
73-
{
74-
#![attr]
75-
foo
76-
};
73+
{
74+
#![attr]
75+
foo
76+
};
7777
let _ =
7878
#[attr] {
79-
#![attr]
80-
};
79+
#![attr]
80+
};
8181
let _ =
8282
#[attr] {
83-
#![attr]
84-
let _ = ();
85-
};
83+
#![attr]
84+
let _ = ();
85+
};
8686
let _ =
8787
#[attr] {
88-
#![attr]
89-
let _ = ();
90-
foo
91-
};
88+
#![attr]
89+
let _ = ();
90+
foo
91+
};
9292
let _ = #[attr] x = y;
9393
let _ = #[attr] (x = y);
9494
let _ = #[attr] x += y;

src/test/pretty/block-comment-wchar.pp

+4-4
Original file line numberDiff line numberDiff line change
@@ -93,9 +93,9 @@
9393
// Taken from https://www.unicode.org/Public/UNIDATA/PropList.txt
9494
let chars =
9595
['\x0A', '\x0B', '\x0C', '\x0D', '\x20', '\u{85}', '\u{A0}',
96-
'\u{1680}', '\u{2000}', '\u{2001}', '\u{2002}', '\u{2003}',
97-
'\u{2004}', '\u{2005}', '\u{2006}', '\u{2007}', '\u{2008}',
98-
'\u{2009}', '\u{200A}', '\u{2028}', '\u{2029}', '\u{202F}',
99-
'\u{205F}', '\u{3000}'];
96+
'\u{1680}', '\u{2000}', '\u{2001}', '\u{2002}', '\u{2003}',
97+
'\u{2004}', '\u{2005}', '\u{2006}', '\u{2007}', '\u{2008}',
98+
'\u{2009}', '\u{200A}', '\u{2028}', '\u{2029}', '\u{202F}',
99+
'\u{205F}', '\u{3000}'];
100100
for c in &chars { let ws = c.is_whitespace(); println!("{} {}", c, ws); }
101101
}

0 commit comments

Comments
 (0)