Skip to content

Commit 2e39a3f

Browse files
authored
Rollup merge of #93513 - dtolnay:linewidth, r=nagisa
Allow any pretty printed line to have at least 60 chars Follow-up to #93155. The rustc AST pretty printer has a tendency to get stuck in "vertical smear mode" when formatting highly nested code, where it puts a linebreak at *every possible* linebreak opportunity once the indentation goes beyond the pretty printer's target line width: ```rust ... ((&([("test" as &str)] as [&str; 1]) as &[&str; 1]), (&([] as [ArgumentV1; 0]) as &[ArgumentV1; 0])) ... ``` ```rust ... [(1 as i32), (2 as i32), (3 as i32)] as [i32; 3] ... ``` This is less common after #93155 because that PR greatly reduced the total amount of indentation, but the "vertical smear mode" failure mode is still just as present when you have deeply nested modules, functions, or trait impls, such as in the case of macro-expanded code from `-Zunpretty=expanded`. Vertical smear mode is never the best way to format highly indented code though. It does not prevent the target line width from being exceeded, and it produces output that is less readable than just a longer line. This PR makes the pretty printing algorithm allow a minimum of 60 chars on every line independent of indentation. So as code gets more indented, the right margin eventually recedes to make room for formatting without vertical smear. ```console ├─────────────────────────────────────┤ ├─────────────────────────────────────┤ ├─────────────────────────────────────┤ ├───────────────────────────────────┤ ├─────────────────────────────────┤ ├───────────────────────────────┤ ├─────────────────────────────┤ ├───────────────────────────┤ ├───────────────────────────┤ ├───────────────────────────┤ ├───────────────────────────┤ ├───────────────────────────┤ ├─────────────────────────────┤ ├───────────────────────────────┤ ├─────────────────────────────────┤ ├───────────────────────────────────┤ ├─────────────────────────────────────┤ ```
2 parents 8a70ea2 + 7739fca commit 2e39a3f

File tree

4 files changed

+13
-14
lines changed

4 files changed

+13
-14
lines changed

compiler/rustc_ast_pretty/src/pp.rs

+9-7
Original file line numberDiff line numberDiff line change
@@ -136,6 +136,7 @@ mod ring;
136136

137137
use ring::RingBuffer;
138138
use std::borrow::Cow;
139+
use std::cmp;
139140
use std::collections::VecDeque;
140141
use std::iter;
141142

@@ -199,10 +200,13 @@ enum PrintFrame {
199200

200201
const SIZE_INFINITY: isize = 0xffff;
201202

203+
/// Target line width.
204+
const MARGIN: isize = 78;
205+
/// Every line is allowed at least this much space, even if highly indented.
206+
const MIN_SPACE: isize = 60;
207+
202208
pub struct Printer {
203209
out: String,
204-
/// Width of lines we're constrained to
205-
margin: isize,
206210
/// Number of spaces left on line
207211
space: isize,
208212
/// Ring-buffer of tokens and calculated sizes
@@ -237,11 +241,9 @@ struct BufEntry {
237241

238242
impl Printer {
239243
pub fn new() -> Self {
240-
let linewidth = 78;
241244
Printer {
242245
out: String::new(),
243-
margin: linewidth as isize,
244-
space: linewidth as isize,
246+
space: MARGIN,
245247
buf: RingBuffer::new(),
246248
left_total: 0,
247249
right_total: 0,
@@ -395,7 +397,7 @@ impl Printer {
395397
self.print_stack.push(PrintFrame::Broken { indent: self.indent, breaks: token.breaks });
396398
self.indent = match token.indent {
397399
IndentStyle::Block { offset } => (self.indent as isize + offset) as usize,
398-
IndentStyle::Visual => (self.margin - self.space) as usize,
400+
IndentStyle::Visual => (MARGIN - self.space) as usize,
399401
};
400402
} else {
401403
self.print_stack.push(PrintFrame::Fits);
@@ -421,7 +423,7 @@ impl Printer {
421423
self.out.push('\n');
422424
let indent = self.indent as isize + token.offset;
423425
self.pending_indentation = indent;
424-
self.space = self.margin - indent;
426+
self.space = cmp::max(MARGIN - indent, MIN_SPACE);
425427
}
426428
}
427429

src/test/pretty/issue-4264.pp

+1-2
Original file line numberDiff line numberDiff line change
@@ -35,8 +35,7 @@
3535
for<'r> fn(Arguments<'r>) -> String {format})(((::core::fmt::Arguments::new_v1
3636
as
3737
fn(&[&'static str], &[ArgumentV1]) -> Arguments {Arguments::new_v1})((&([("test"
38-
as &str)] as [&str; 1]) as
39-
&[&str; 1]),
38+
as &str)] as [&str; 1]) as &[&str; 1]),
4039
(&([] as [ArgumentV1; 0]) as &[ArgumentV1; 0])) as
4140
Arguments)) as String);
4241
(res as String)

src/test/ui/match/issue-82392.stdout

+2-3
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,6 @@ pub fn main() ({
1111
({ } as
1212
()) else if (let Some(a) =
1313
((Some as
14-
fn(i32) -> Option<i32> {Option::<i32>::Some})((3
15-
as i32)) as Option<i32>) as bool) ({ } as ())
16-
as ())
14+
fn(i32) -> Option<i32> {Option::<i32>::Some})((3 as i32)) as
15+
Option<i32>) as bool) ({ } as ()) as ())
1716
} as ())

src/test/ui/proc-macro/quote-debug.stdout

+1-2
Original file line numberDiff line numberDiff line change
@@ -27,8 +27,7 @@ fn main() {
2727
crate::TokenStream::from(crate::TokenTree::Literal({
2828
let mut iter =
2929
"\"world\"".parse::<crate::TokenStream>().unwrap().into_iter();
30-
if let (Some(crate::TokenTree::Literal(mut lit)),
31-
None) =
30+
if let (Some(crate::TokenTree::Literal(mut lit)), None) =
3231
(iter.next(), iter.next()) {
3332
lit.set_span(crate::Span::recover_proc_macro_span(2));
3433
lit

0 commit comments

Comments
 (0)