Skip to content

Commit 86b900a

Browse files
authored
Rollup merge of #79757 - jryans:long-line-tab-handling-early-expand, r=estebank
Replace tabs earlier in diagnostics This replaces tabs earlier in the diagnostics emitting process, which allows various margin calculations to ignore the existence of tabs. It does add a string copy for the source lines that are emitted. Fixes #78438 r? `@estebank`
2 parents 467f5e9 + 3537bd8 commit 86b900a

File tree

4 files changed

+48
-29
lines changed

4 files changed

+48
-29
lines changed

compiler/rustc_errors/src/emitter.rs

+20-5
Original file line numberDiff line numberDiff line change
@@ -644,6 +644,8 @@ impl EmitterWriter {
644644
code_offset: usize,
645645
margin: Margin,
646646
) {
647+
// Tabs are assumed to have been replaced by spaces in calling code.
648+
assert!(!source_string.contains('\t'));
647649
let line_len = source_string.len();
648650
// Create the source line we will highlight.
649651
let left = margin.left(line_len);
@@ -707,7 +709,7 @@ impl EmitterWriter {
707709
}
708710

709711
let source_string = match file.get_line(line.line_index - 1) {
710-
Some(s) => s,
712+
Some(s) => replace_tabs(&*s),
711713
None => return Vec::new(),
712714
};
713715

@@ -1376,8 +1378,17 @@ impl EmitterWriter {
13761378
let file = annotated_file.file.clone();
13771379
let line = &annotated_file.lines[line_idx];
13781380
if let Some(source_string) = file.get_line(line.line_index - 1) {
1379-
let leading_whitespace =
1380-
source_string.chars().take_while(|c| c.is_whitespace()).count();
1381+
let leading_whitespace = source_string
1382+
.chars()
1383+
.take_while(|c| c.is_whitespace())
1384+
.map(|c| {
1385+
match c {
1386+
// Tabs are displayed as 4 spaces
1387+
'\t' => 4,
1388+
_ => 1,
1389+
}
1390+
})
1391+
.sum();
13811392
if source_string.chars().any(|c| !c.is_whitespace()) {
13821393
whitespace_margin = min(whitespace_margin, leading_whitespace);
13831394
}
@@ -1502,7 +1513,7 @@ impl EmitterWriter {
15021513

15031514
self.draw_line(
15041515
&mut buffer,
1505-
&unannotated_line,
1516+
&replace_tabs(&unannotated_line),
15061517
annotated_file.lines[line_idx + 1].line_index - 1,
15071518
last_buffer_line_num,
15081519
width_offset,
@@ -1598,7 +1609,7 @@ impl EmitterWriter {
15981609
);
15991610
// print the suggestion
16001611
draw_col_separator(&mut buffer, row_num, max_line_num_len + 1);
1601-
buffer.append(row_num, line, Style::NoStyle);
1612+
buffer.append(row_num, &replace_tabs(line), Style::NoStyle);
16021613
row_num += 1;
16031614
}
16041615

@@ -1930,6 +1941,10 @@ impl FileWithAnnotatedLines {
19301941
}
19311942
}
19321943

1944+
fn replace_tabs(str: &str) -> String {
1945+
str.replace('\t', " ")
1946+
}
1947+
19331948
fn draw_col_separator(buffer: &mut StyledBuffer, line: usize, col: usize) {
19341949
buffer.puts(line, col, "| ", Style::LineNumber);
19351950
}

compiler/rustc_errors/src/styled_buffer.rs

+3-24
Original file line numberDiff line numberDiff line change
@@ -13,34 +13,13 @@ impl StyledBuffer {
1313
StyledBuffer { text: vec![], styles: vec![] }
1414
}
1515

16-
fn replace_tabs(&mut self) {
17-
for (line_pos, line) in self.text.iter_mut().enumerate() {
18-
let mut tab_pos = vec![];
19-
for (pos, c) in line.iter().enumerate() {
20-
if *c == '\t' {
21-
tab_pos.push(pos);
22-
}
23-
}
24-
// start with the tabs at the end of the line to replace them with 4 space chars
25-
for pos in tab_pos.iter().rev() {
26-
assert_eq!(line.remove(*pos), '\t');
27-
// fix the position of the style to match up after replacing the tabs
28-
let s = self.styles[line_pos].remove(*pos);
29-
for _ in 0..4 {
30-
line.insert(*pos, ' ');
31-
self.styles[line_pos].insert(*pos, s);
32-
}
33-
}
34-
}
35-
}
16+
pub fn render(&self) -> Vec<Vec<StyledString>> {
17+
// Tabs are assumed to have been replaced by spaces in calling code.
18+
assert!(self.text.iter().all(|r| !r.contains(&'\t')));
3619

37-
pub fn render(&mut self) -> Vec<Vec<StyledString>> {
3820
let mut output: Vec<Vec<StyledString>> = vec![];
3921
let mut styled_vec: Vec<StyledString> = vec![];
4022

41-
// before we render, replace tabs with spaces
42-
self.replace_tabs();
43-
4423
for (row, row_style) in self.text.iter().zip(&self.styles) {
4524
let mut current_style = Style::NoStyle;
4625
let mut current_text = String::new();
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
// Test for #78438: ensure underline alignment with many tabs on the left, long line on the right
2+
3+
// ignore-tidy-linelength
4+
// ignore-tidy-tab
5+
6+
fn main() {
7+
let money = 42i32;
8+
match money {
9+
v @ 1 | 2 | 3 => panic!("You gave me too little money {}", v), // Long text here: TTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTT
10+
//~^ ERROR variable `v` is not bound in all patterns
11+
v => println!("Enough money {}", v),
12+
}
13+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
error[E0408]: variable `v` is not bound in all patterns
2+
--> $DIR/tabs-trimming.rs:9:16
3+
|
4+
LL | ... v @ 1 | 2 | 3 => panic!("You gave me too little money {}", v), // Long text here: TTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTT...
5+
| - ^ ^ pattern doesn't bind `v`
6+
| | |
7+
| | pattern doesn't bind `v`
8+
| variable not in all patterns
9+
10+
error: aborting due to previous error
11+
12+
For more information about this error, try `rustc --explain E0408`.

0 commit comments

Comments
 (0)