Skip to content

Commit

Permalink
Rollup merge of rust-lang#93513 - dtolnay:linewidth, r=nagisa
Browse files Browse the repository at this point in the history
Allow any pretty printed line to have at least 60 chars

Follow-up to rust-lang#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 rust-lang#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
├─────────────────────────────────────┤
├─────────────────────────────────────┤
├─────────────────────────────────────┤
  ├───────────────────────────────────┤
    ├─────────────────────────────────┤
      ├───────────────────────────────┤
        ├─────────────────────────────┤
          ├───────────────────────────┤
            ├───────────────────────────┤
              ├───────────────────────────┤
            ├───────────────────────────┤
          ├───────────────────────────┤
        ├─────────────────────────────┤
      ├───────────────────────────────┤
    ├─────────────────────────────────┤
  ├───────────────────────────────────┤
├─────────────────────────────────────┤
```
  • Loading branch information
ehuss authored Feb 1, 2022
2 parents 8a70ea2 + 7739fca commit 2e39a3f
Show file tree
Hide file tree
Showing 4 changed files with 13 additions and 14 deletions.
16 changes: 9 additions & 7 deletions compiler/rustc_ast_pretty/src/pp.rs
Original file line number Diff line number Diff line change
Expand Up @@ -136,6 +136,7 @@ mod ring;

use ring::RingBuffer;
use std::borrow::Cow;
use std::cmp;
use std::collections::VecDeque;
use std::iter;

Expand Down Expand Up @@ -199,10 +200,13 @@ enum PrintFrame {

const SIZE_INFINITY: isize = 0xffff;

/// Target line width.
const MARGIN: isize = 78;
/// Every line is allowed at least this much space, even if highly indented.
const MIN_SPACE: isize = 60;

pub struct Printer {
out: String,
/// Width of lines we're constrained to
margin: isize,
/// Number of spaces left on line
space: isize,
/// Ring-buffer of tokens and calculated sizes
Expand Down Expand Up @@ -237,11 +241,9 @@ struct BufEntry {

impl Printer {
pub fn new() -> Self {
let linewidth = 78;
Printer {
out: String::new(),
margin: linewidth as isize,
space: linewidth as isize,
space: MARGIN,
buf: RingBuffer::new(),
left_total: 0,
right_total: 0,
Expand Down Expand Up @@ -395,7 +397,7 @@ impl Printer {
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::Visual => (self.margin - self.space) as usize,
IndentStyle::Visual => (MARGIN - self.space) as usize,
};
} else {
self.print_stack.push(PrintFrame::Fits);
Expand All @@ -421,7 +423,7 @@ impl Printer {
self.out.push('\n');
let indent = self.indent as isize + token.offset;
self.pending_indentation = indent;
self.space = self.margin - indent;
self.space = cmp::max(MARGIN - indent, MIN_SPACE);
}
}

Expand Down
3 changes: 1 addition & 2 deletions src/test/pretty/issue-4264.pp
Original file line number Diff line number Diff line change
Expand Up @@ -35,8 +35,7 @@
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 &str)] as [&str; 1]) as &[&str; 1]),
(&([] as [ArgumentV1; 0]) as &[ArgumentV1; 0])) as
Arguments)) as String);
(res as String)
Expand Down
5 changes: 2 additions & 3 deletions src/test/ui/match/issue-82392.stdout
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,6 @@ pub fn main() ({
({ } as
()) else if (let Some(a) =
((Some as
fn(i32) -> Option<i32> {Option::<i32>::Some})((3
as i32)) as Option<i32>) as bool) ({ } as ())
as ())
fn(i32) -> Option<i32> {Option::<i32>::Some})((3 as i32)) as
Option<i32>) as bool) ({ } as ()) as ())
} as ())
3 changes: 1 addition & 2 deletions src/test/ui/proc-macro/quote-debug.stdout
Original file line number Diff line number Diff line change
Expand Up @@ -27,8 +27,7 @@ fn main() {
crate::TokenStream::from(crate::TokenTree::Literal({
let mut iter =
"\"world\"".parse::<crate::TokenStream>().unwrap().into_iter();
if let (Some(crate::TokenTree::Literal(mut lit)),
None) =
if let (Some(crate::TokenTree::Literal(mut lit)), None) =
(iter.next(), iter.next()) {
lit.set_span(crate::Span::recover_proc_macro_span(2));
lit
Expand Down

0 comments on commit 2e39a3f

Please sign in to comment.