From 0e668e0496fcc13fa042be416b64ba6823669cca Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Esteban=20K=C3=BCber?= Date: Wed, 24 Jul 2019 17:58:29 -0700 Subject: [PATCH 1/9] Strip code to the left and right in diagnostics for long lines --- src/librustc_errors/emitter.rs | 150 ++++++++++++++---- src/test/ui/inline-asm-bad-operand.stderr | 4 +- ...0-unused-variable-in-struct-pattern.stderr | 4 +- .../ui/methods/method-missing-call.stderr | 4 +- ...-on-type-no-recursive-stack-closure.stderr | 10 +- .../ui/regions/regions-name-undeclared.stderr | 8 +- 6 files changed, 133 insertions(+), 47 deletions(-) diff --git a/src/librustc_errors/emitter.rs b/src/librustc_errors/emitter.rs index 361b5cd9357..007c6369c7b 100644 --- a/src/librustc_errors/emitter.rs +++ b/src/librustc_errors/emitter.rs @@ -179,6 +179,7 @@ pub struct EmitterWriter { sm: Option>, short_message: bool, teach: bool, + strip_margin: bool, ui_testing: bool, } @@ -201,6 +202,7 @@ impl EmitterWriter { sm: source_map, short_message, teach, + strip_margin: false, ui_testing: false, } } @@ -217,6 +219,7 @@ impl EmitterWriter { sm: source_map, short_message, teach, + strip_margin: false, ui_testing: false, } } @@ -234,12 +237,29 @@ impl EmitterWriter { } } - fn render_source_line(&self, - buffer: &mut StyledBuffer, - file: Lrc, - line: &Line, - width_offset: usize, - code_offset: usize) -> Vec<(usize, Style)> { + fn render_source_line( + &self, + buffer: &mut StyledBuffer, + file: Lrc, + line: &Line, + width_offset: usize, + code_offset: usize, + margin: usize, + right_span_margin: usize + ) -> Vec<(usize, Style)> { + // Draw: + // + // LL | ... code ... + // | ^^-^ span label + // | | + // | secondary span label + // + // ^^ ^ ^^^ ^^^^ ^^^ we don't care about code too far to the right of a span, we trim it + // | | | | + // | | | actual code found in your source code and the spans we use to mark it + // | | when there's too much wasted space to the left, we trim it to focus where it matters + // | vertical divider between the column number and the code + // column number if line.line_index == 0 { return Vec::new(); } @@ -251,12 +271,28 @@ impl EmitterWriter { let line_offset = buffer.num_lines(); - // First create the source line we will highlight. - buffer.puts(line_offset, code_offset, &source_string, Style::Quotation); - buffer.puts(line_offset, - 0, - &self.maybe_anonymized(line.line_index), - Style::LineNumber); + let left_margin = std::cmp::min(margin, source_string.len()); + let right_margin = if source_string.len() > right_span_margin + 120 { + right_span_margin + 120 + } else { + source_string.len() + }; + // Create the source line we will highlight. + buffer.puts( + line_offset, + code_offset, + &source_string[left_margin..right_margin], // On long lines, we strip the source line + Style::Quotation, + ); + if margin > 0 { // We have stripped some code/whitespace from the beginning, make it clear. + buffer.puts(line_offset, code_offset, "...", Style::LineNumber); + } + if right_margin != source_string.len() { + // We have stripped some code after the right-most span end, make it clear we did so. + let offset = code_offset + right_margin - left_margin; + buffer.puts(line_offset, offset, "...", Style::LineNumber); + } + buffer.puts(line_offset, 0, &self.maybe_anonymized(line.line_index), Style::LineNumber); draw_col_separator(buffer, line_offset, width_offset - 2); @@ -279,18 +315,13 @@ impl EmitterWriter { if line.annotations.len() == 1 { if let Some(ref ann) = line.annotations.get(0) { if let AnnotationType::MultilineStart(depth) = ann.annotation_type { - if source_string.chars() - .take(ann.start_col) - .all(|c| c.is_whitespace()) { + if source_string.chars().take(ann.start_col).all(|c| c.is_whitespace()) { let style = if ann.is_primary { Style::UnderlinePrimary } else { Style::UnderlineSecondary }; - buffer.putc(line_offset, - width_offset + depth - 1, - '/', - style); + buffer.putc(line_offset, width_offset + depth - 1, '/', style); return vec![(depth, style)]; } } @@ -515,13 +546,13 @@ impl EmitterWriter { '_', line_offset + pos, width_offset + depth, - code_offset + annotation.start_col, + code_offset + annotation.start_col - margin, style); } _ if self.teach => { buffer.set_style_range(line_offset, - code_offset + annotation.start_col, - code_offset + annotation.end_col, + code_offset + annotation.start_col - margin, + code_offset + annotation.end_col - margin, style, annotation.is_primary); } @@ -551,7 +582,7 @@ impl EmitterWriter { if pos > 1 && (annotation.has_label() || annotation.takes_space()) { for p in line_offset + 1..=line_offset + pos { buffer.putc(p, - code_offset + annotation.start_col, + code_offset + annotation.start_col - margin, '|', style); } @@ -595,9 +626,9 @@ impl EmitterWriter { Style::LabelSecondary }; let (pos, col) = if pos == 0 { - (pos + 1, annotation.end_col + 1) + (pos + 1, annotation.end_col + 1 - margin) } else { - (pos + 2, annotation.start_col) + (pos + 2, annotation.start_col - margin) }; if let Some(ref label) = annotation.label { buffer.puts(line_offset + pos, @@ -639,7 +670,7 @@ impl EmitterWriter { }; for p in annotation.start_col..annotation.end_col { buffer.putc(line_offset + 1, - code_offset + p, + code_offset + p - margin, underline, style); } @@ -1037,6 +1068,51 @@ impl EmitterWriter { // Contains the vertical lines' positions for active multiline annotations let mut multilines = FxHashMap::default(); + // Get the left-side margin to remove it + let mut margin = std::usize::MAX; + for line_idx in 0..annotated_file.lines.len() { + let file = annotated_file.file.clone(); + let line = &annotated_file.lines[line_idx]; + if let Some(source_string) = file.get_line(line.line_index - 1) { + let leading_whitespace = source_string + .chars() + .take_while(|c| c.is_whitespace()) + .count(); + if source_string.chars().any(|c| !c.is_whitespace()) { + margin = std::cmp::min(margin, leading_whitespace); + } + } + } + if margin >= 20 { // On errors with generous margins, trim it + margin = margin - 16; // Keep at least 4 spaces margin + } else if margin == std::usize::MAX || !self.strip_margin { + margin = 0; + } + + // Left-most column any visible span points at. + let mut span_left_margin = std::usize::MAX; + for line in &annotated_file.lines { + for ann in &line.annotations { + span_left_margin = std::cmp::min(span_left_margin, ann.start_col); + span_left_margin = std::cmp::min(span_left_margin, ann.end_col); + } + } + if span_left_margin == std::usize::MAX { + span_left_margin = 0; + } + if span_left_margin > 160 { + margin = std::cmp::max(margin, span_left_margin - 100); + } + + // Right-most column any visible span points at. + let mut span_right_margin = 0; + for line in &annotated_file.lines { + for ann in &line.annotations { + span_right_margin = std::cmp::max(span_right_margin, ann.start_col); + span_right_margin = std::cmp::max(span_right_margin, ann.end_col); + } + } + // Next, output the annotate source for this file for line_idx in 0..annotated_file.lines.len() { let previous_buffer_line = buffer.num_lines(); @@ -1048,11 +1124,15 @@ impl EmitterWriter { width_offset + annotated_file.multiline_depth + 1 }; - let depths = self.render_source_line(&mut buffer, - annotated_file.file.clone(), - &annotated_file.lines[line_idx], - width_offset, - code_offset); + let depths = self.render_source_line( + &mut buffer, + annotated_file.file.clone(), + &annotated_file.lines[line_idx], + width_offset, + code_offset, + margin, + span_right_margin, + ); let mut to_add = FxHashMap::default(); @@ -1107,9 +1187,15 @@ impl EmitterWriter { draw_col_separator(&mut buffer, last_buffer_line_num, 1 + max_line_num_len); + let left_margin = std::cmp::min(margin, unannotated_line.len()); + let right_margin = if unannotated_line.len() > span_right_margin + 120 { + span_right_margin + 120 + } else { + unannotated_line.len() + }; buffer.puts(last_buffer_line_num, code_offset, - &unannotated_line, + &unannotated_line[left_margin..right_margin], Style::Quotation); for (depth, style) in &multilines { diff --git a/src/test/ui/inline-asm-bad-operand.stderr b/src/test/ui/inline-asm-bad-operand.stderr index 4554da7b798..d5c1cf51daf 100644 --- a/src/test/ui/inline-asm-bad-operand.stderr +++ b/src/test/ui/inline-asm-bad-operand.stderr @@ -37,8 +37,8 @@ LL | asm!("mov sp, $0"::"r"(addr), error[E0669]: invalid value for constraint in inline assembly --> $DIR/inline-asm-bad-operand.rs:56:32 | -LL | "r"("hello e0669")); - | ^^^^^^^^^^^^^ +LL | ... "r"("hello e0669")); + | ^^^^^^^^^^^^^ error: aborting due to 7 previous errors diff --git a/src/test/ui/lint/issue-47390-unused-variable-in-struct-pattern.stderr b/src/test/ui/lint/issue-47390-unused-variable-in-struct-pattern.stderr index a0b34d220c8..3262662a2a5 100644 --- a/src/test/ui/lint/issue-47390-unused-variable-in-struct-pattern.stderr +++ b/src/test/ui/lint/issue-47390-unused-variable-in-struct-pattern.stderr @@ -38,8 +38,8 @@ LL | if let SoulHistory { corridors_of_light, warning: variable `hours_are_suns` is assigned to, but never used --> $DIR/issue-47390-unused-variable-in-struct-pattern.rs:38:30 | -LL | mut hours_are_suns, - | ^^^^^^^^^^^^^^ +LL | ... mut hours_are_suns, + | ^^^^^^^^^^^^^^ | = note: consider using `_hours_are_suns` instead diff --git a/src/test/ui/methods/method-missing-call.stderr b/src/test/ui/methods/method-missing-call.stderr index 3ab5f66a0c3..fe44d3a29da 100644 --- a/src/test/ui/methods/method-missing-call.stderr +++ b/src/test/ui/methods/method-missing-call.stderr @@ -1,8 +1,8 @@ error[E0615]: attempted to take value of method `get_x` on type `Point` --> $DIR/method-missing-call.rs:22:26 | -LL | .get_x; - | ^^^^^ help: use parentheses to call the method: `get_x()` +LL | ... .get_x; + | ^^^^^ help: use parentheses to call the method: `get_x()` error[E0615]: attempted to take value of method `filter_map` on type `std::iter::Filter, [closure@$DIR/method-missing-call.rs:27:20: 27:25]>, [closure@$DIR/method-missing-call.rs:28:23: 28:35]>` --> $DIR/method-missing-call.rs:29:16 diff --git a/src/test/ui/moves/moves-based-on-type-no-recursive-stack-closure.stderr b/src/test/ui/moves/moves-based-on-type-no-recursive-stack-closure.stderr index 483c364752b..6eff7b06d53 100644 --- a/src/test/ui/moves/moves-based-on-type-no-recursive-stack-closure.stderr +++ b/src/test/ui/moves/moves-based-on-type-no-recursive-stack-closure.stderr @@ -1,11 +1,11 @@ error[E0499]: cannot borrow `*f` as mutable more than once at a time --> $DIR/moves-based-on-type-no-recursive-stack-closure.rs:20:27 | -LL | (f.c)(f, true); - | ----- ^ second mutable borrow occurs here - | | - | first mutable borrow occurs here - | first borrow later used by call +LL | ... (f.c)(f, true); + | ----- ^ second mutable borrow occurs here + | | + | first mutable borrow occurs here + | first borrow later used by call error[E0382]: borrow of moved value: `f` --> $DIR/moves-based-on-type-no-recursive-stack-closure.rs:32:5 diff --git a/src/test/ui/regions/regions-name-undeclared.stderr b/src/test/ui/regions/regions-name-undeclared.stderr index 4840d751f7f..fe0345c3a38 100644 --- a/src/test/ui/regions/regions-name-undeclared.stderr +++ b/src/test/ui/regions/regions-name-undeclared.stderr @@ -49,14 +49,14 @@ LL | fn fn_types(a: &'a isize, error[E0261]: use of undeclared lifetime name `'b` --> $DIR/regions-name-undeclared.rs:42:36 | -LL | &'b isize, - | ^^ undeclared lifetime +LL | ... &'b isize, + | ^^ undeclared lifetime error[E0261]: use of undeclared lifetime name `'b` --> $DIR/regions-name-undeclared.rs:45:36 | -LL | &'b isize)>, - | ^^ undeclared lifetime +LL | ... &'b isize)>, + | ^^ undeclared lifetime error[E0261]: use of undeclared lifetime name `'a` --> $DIR/regions-name-undeclared.rs:46:17 From 266b878334cecce3a0636ddbb95318f7a5669f45 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Esteban=20K=C3=BCber?= Date: Tue, 13 Aug 2019 19:09:28 -0700 Subject: [PATCH 2/9] clean up --- src/librustc_errors/emitter.rs | 220 +++++++++++++----- ...-on-type-no-recursive-stack-closure.stderr | 10 +- 2 files changed, 162 insertions(+), 68 deletions(-) diff --git a/src/librustc_errors/emitter.rs b/src/librustc_errors/emitter.rs index 007c6369c7b..b7615fef049 100644 --- a/src/librustc_errors/emitter.rs +++ b/src/librustc_errors/emitter.rs @@ -57,6 +57,80 @@ impl HumanReadableErrorType { } } +#[derive(Clone, Copy, Debug)] +struct Margin { + pub whitespace_left: usize, + pub span_left: usize, + pub span_right: usize, + pub line_len: usize, + pub computed_left: usize, + pub computed_right: usize, + pub column_width: usize, + pub label_right: usize, +} + +impl Margin { + fn new( + whitespace_left: usize, + span_left: usize, + span_right: usize, + label_right: usize, + ) -> Self { + Margin { + whitespace_left, + span_left, + span_right, + line_len: 0, + computed_left: 0, + computed_right: 0, + column_width: 140, + label_right, + } + } + + fn was_cut_left(&self) -> bool { + self.computed_left > 0 + } + + fn was_cut_right(&self) -> bool { + self.computed_right < self.line_len + } + + fn compute(&mut self) { + self.computed_left = if self.whitespace_left > 20 { + self.whitespace_left - 16 // We want some padding. + } else { + 0 + }; + self.computed_right = self.column_width + self.computed_left; + + if self.computed_right - self.computed_left > self.column_width { + // Trimming only whitespace isn't enough, let's get craftier. + if self.label_right - self.whitespace_left <= self.column_width { + self.computed_left = self.whitespace_left; + self.computed_right = self.computed_left + self.column_width; + } else if self.label_right - self.span_left - 20 <= self.column_width { + self.computed_left = self.span_left - 20; + self.computed_right = self.computed_left + self.column_width; + } else if self.label_right - self.span_left <= self.column_width { + self.computed_left = self.span_left; + self.computed_right = self.computed_left + self.column_width; + } else if self.span_right - self.span_left <= self.column_width { + self.computed_left = self.span_left; + self.computed_right = self.computed_left + self.column_width; + } else { // mostly give up but still don't show the full line + self.computed_left = self.span_left; + self.computed_right = self.span_right; + } + } + self.computed_left = std::cmp::min(self.computed_left, self.line_len); + if self.computed_right > self.line_len { + self.computed_right = self.line_len; + } + self.computed_right = std::cmp::min(self.computed_right, self.line_len); + } +} + const ANONYMIZED_LINE_NUM: &str = "LL"; /// Emitter trait for emitting errors. @@ -179,7 +253,6 @@ pub struct EmitterWriter { sm: Option>, short_message: bool, teach: bool, - strip_margin: bool, ui_testing: bool, } @@ -202,7 +275,6 @@ impl EmitterWriter { sm: source_map, short_message, teach, - strip_margin: false, ui_testing: false, } } @@ -219,7 +291,6 @@ impl EmitterWriter { sm: source_map, short_message, teach, - strip_margin: false, ui_testing: false, } } @@ -244,8 +315,7 @@ impl EmitterWriter { line: &Line, width_offset: usize, code_offset: usize, - margin: usize, - right_span_margin: usize + mut margin: Margin, ) -> Vec<(usize, Style)> { // Draw: // @@ -260,6 +330,7 @@ impl EmitterWriter { // | | when there's too much wasted space to the left, we trim it to focus where it matters // | vertical divider between the column number and the code // column number + if line.line_index == 0 { return Vec::new(); } @@ -271,26 +342,27 @@ impl EmitterWriter { let line_offset = buffer.num_lines(); - let left_margin = std::cmp::min(margin, source_string.len()); - let right_margin = if source_string.len() > right_span_margin + 120 { - right_span_margin + 120 - } else { - source_string.len() - }; + margin.line_len = source_string.len(); + margin.compute(); // Create the source line we will highlight. buffer.puts( line_offset, code_offset, - &source_string[left_margin..right_margin], // On long lines, we strip the source line + // On long lines, we strip the source line + &source_string[margin.computed_left..margin.computed_right], Style::Quotation, ); - if margin > 0 { // We have stripped some code/whitespace from the beginning, make it clear. + if margin.was_cut_left() { // We have stripped some code/whitespace from the beginning, make it clear. buffer.puts(line_offset, code_offset, "...", Style::LineNumber); } - if right_margin != source_string.len() { + if margin.was_cut_right() { // We have stripped some code after the right-most span end, make it clear we did so. - let offset = code_offset + right_margin - left_margin; - buffer.puts(line_offset, offset, "...", Style::LineNumber); + buffer.puts( + line_offset, + margin.computed_right - margin.computed_left + code_offset, + "...", + Style::LineNumber, + ); } buffer.puts(line_offset, 0, &self.maybe_anonymized(line.line_index), Style::LineNumber); @@ -546,13 +618,13 @@ impl EmitterWriter { '_', line_offset + pos, width_offset + depth, - code_offset + annotation.start_col - margin, + code_offset + annotation.start_col - margin.computed_left, style); } _ if self.teach => { buffer.set_style_range(line_offset, - code_offset + annotation.start_col - margin, - code_offset + annotation.end_col - margin, + code_offset + annotation.start_col - margin.computed_left, + code_offset + annotation.end_col - margin.computed_left, style, annotation.is_primary); } @@ -582,7 +654,7 @@ impl EmitterWriter { if pos > 1 && (annotation.has_label() || annotation.takes_space()) { for p in line_offset + 1..=line_offset + pos { buffer.putc(p, - code_offset + annotation.start_col - margin, + code_offset + annotation.start_col - margin.computed_left, '|', style); } @@ -626,9 +698,9 @@ impl EmitterWriter { Style::LabelSecondary }; let (pos, col) = if pos == 0 { - (pos + 1, annotation.end_col + 1 - margin) + (pos + 1, annotation.end_col + 1 - margin.computed_left) } else { - (pos + 2, annotation.start_col - margin) + (pos + 2, annotation.start_col - margin.computed_left) }; if let Some(ref label) = annotation.label { buffer.puts(line_offset + pos, @@ -670,7 +742,7 @@ impl EmitterWriter { }; for p in annotation.start_col..annotation.end_col { buffer.putc(line_offset + 1, - code_offset + p - margin, + code_offset + p - margin.computed_left, underline, style); } @@ -1010,22 +1082,30 @@ impl EmitterWriter { let buffer_msg_line_offset = buffer.num_lines(); buffer.prepend(buffer_msg_line_offset, "--> ", Style::LineNumber); - buffer.append(buffer_msg_line_offset, - &format!("{}:{}:{}", - loc.file.name, - sm.doctest_offset_line(&loc.file.name, loc.line), - loc.col.0 + 1), - Style::LineAndColumn); + buffer.append( + buffer_msg_line_offset, + &format!( + "{}:{}:{}", + loc.file.name, + sm.doctest_offset_line(&loc.file.name, loc.line), + loc.col.0 + 1, + ), + Style::LineAndColumn, + ); for _ in 0..max_line_num_len { buffer.prepend(buffer_msg_line_offset, " ", Style::NoStyle); } } else { - buffer.prepend(0, - &format!("{}:{}:{}: ", - loc.file.name, - sm.doctest_offset_line(&loc.file.name, loc.line), - loc.col.0 + 1), - Style::LineAndColumn); + buffer.prepend( + 0, + &format!( + "{}:{}:{}: ", + loc.file.name, + sm.doctest_offset_line(&loc.file.name, loc.line), + loc.col.0 + 1, + ), + Style::LineAndColumn, + ); } } else if !self.short_message { // remember where we are in the output buffer for easy reference @@ -1069,7 +1149,7 @@ impl EmitterWriter { let mut multilines = FxHashMap::default(); // Get the left-side margin to remove it - let mut margin = std::usize::MAX; + let mut whitespace_margin = std::usize::MAX; for line_idx in 0..annotated_file.lines.len() { let file = annotated_file.file.clone(); let line = &annotated_file.lines[line_idx]; @@ -1079,14 +1159,15 @@ impl EmitterWriter { .take_while(|c| c.is_whitespace()) .count(); if source_string.chars().any(|c| !c.is_whitespace()) { - margin = std::cmp::min(margin, leading_whitespace); + whitespace_margin = std::cmp::min( + whitespace_margin, + leading_whitespace, + ); } } } - if margin >= 20 { // On errors with generous margins, trim it - margin = margin - 16; // Keep at least 4 spaces margin - } else if margin == std::usize::MAX || !self.strip_margin { - margin = 0; + if whitespace_margin == std::usize::MAX { + whitespace_margin = 0; } // Left-most column any visible span points at. @@ -1100,18 +1181,27 @@ impl EmitterWriter { if span_left_margin == std::usize::MAX { span_left_margin = 0; } - if span_left_margin > 160 { - margin = std::cmp::max(margin, span_left_margin - 100); - } // Right-most column any visible span points at. let mut span_right_margin = 0; + let mut label_right_margin = 0; for line in &annotated_file.lines { for ann in &line.annotations { span_right_margin = std::cmp::max(span_right_margin, ann.start_col); span_right_margin = std::cmp::max(span_right_margin, ann.end_col); + label_right_margin = std::cmp::max( + label_right_margin, + // TODO: account for labels not in the same line + ann.end_col + ann.label.as_ref().map(|l| l.len() + 1).unwrap_or(0), + ); } } + let margin = Margin::new( + whitespace_margin, + span_left_margin, + span_right_margin, + label_right_margin, + ); // Next, output the annotate source for this file for line_idx in 0..annotated_file.lines.len() { @@ -1131,7 +1221,6 @@ impl EmitterWriter { width_offset, code_offset, margin, - span_right_margin, ); let mut to_add = FxHashMap::default(); @@ -1179,24 +1268,29 @@ impl EmitterWriter { let last_buffer_line_num = buffer.num_lines(); - buffer.puts(last_buffer_line_num, - 0, - &self.maybe_anonymized(annotated_file.lines[line_idx + 1] - .line_index - 1), - Style::LineNumber); - draw_col_separator(&mut buffer, - last_buffer_line_num, - 1 + max_line_num_len); - let left_margin = std::cmp::min(margin, unannotated_line.len()); - let right_margin = if unannotated_line.len() > span_right_margin + 120 { - span_right_margin + 120 - } else { - unannotated_line.len() - }; - buffer.puts(last_buffer_line_num, - code_offset, - &unannotated_line[left_margin..right_margin], - Style::Quotation); + buffer.puts( + last_buffer_line_num, + 0, + &self.maybe_anonymized( + annotated_file.lines[line_idx + 1].line_index - 1, + ), + Style::LineNumber, + ); + draw_col_separator( + &mut buffer, + last_buffer_line_num, + 1 + max_line_num_len, + ); + + let mut margin = margin; + margin.line_len = unannotated_line.len(); + margin.compute(); + buffer.puts( + last_buffer_line_num, + code_offset, + &unannotated_line[margin.computed_left..margin.computed_right], + Style::Quotation, + ); for (depth, style) in &multilines { draw_multiline_line(&mut buffer, diff --git a/src/test/ui/moves/moves-based-on-type-no-recursive-stack-closure.stderr b/src/test/ui/moves/moves-based-on-type-no-recursive-stack-closure.stderr index 6eff7b06d53..483c364752b 100644 --- a/src/test/ui/moves/moves-based-on-type-no-recursive-stack-closure.stderr +++ b/src/test/ui/moves/moves-based-on-type-no-recursive-stack-closure.stderr @@ -1,11 +1,11 @@ error[E0499]: cannot borrow `*f` as mutable more than once at a time --> $DIR/moves-based-on-type-no-recursive-stack-closure.rs:20:27 | -LL | ... (f.c)(f, true); - | ----- ^ second mutable borrow occurs here - | | - | first mutable borrow occurs here - | first borrow later used by call +LL | (f.c)(f, true); + | ----- ^ second mutable borrow occurs here + | | + | first mutable borrow occurs here + | first borrow later used by call error[E0382]: borrow of moved value: `f` --> $DIR/moves-based-on-type-no-recursive-stack-closure.rs:32:5 From f08b036cc78ca225a8d3e25fc138ed3a210c611f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Esteban=20K=C3=BCber?= Date: Wed, 14 Aug 2019 09:34:09 -0700 Subject: [PATCH 3/9] Introduce `term-size` dependency and consider term width when trimming --- Cargo.lock | 12 + src/librustc_errors/Cargo.toml | 1 + src/librustc_errors/emitter.rs | 252 +++++++++++------- src/test/ui/inline-asm-bad-operand.stderr | 4 +- ...0-unused-variable-in-struct-pattern.stderr | 4 +- .../ui/lint/lint-stability-deprecated.stderr | 36 +-- .../ui/methods/method-missing-call.stderr | 4 +- .../ui/regions/regions-name-undeclared.stderr | 8 +- .../non-whitespace-trimming-2.rs | 6 + .../non-whitespace-trimming-2.stderr | 12 + .../terminal-width/non-whitespace-trimming.rs | 6 + .../non-whitespace-trimming.stderr | 12 + .../terminal-width/whitespace-trimming-2.rs | 8 + .../whitespace-trimming-2.stderr | 14 + .../ui/terminal-width/whitespace-trimming.rs | 6 + .../terminal-width/whitespace-trimming.stderr | 12 + src/tools/tidy/src/deps.rs | 1 + 17 files changed, 277 insertions(+), 121 deletions(-) create mode 100644 src/test/ui/terminal-width/non-whitespace-trimming-2.rs create mode 100644 src/test/ui/terminal-width/non-whitespace-trimming-2.stderr create mode 100644 src/test/ui/terminal-width/non-whitespace-trimming.rs create mode 100644 src/test/ui/terminal-width/non-whitespace-trimming.stderr create mode 100644 src/test/ui/terminal-width/whitespace-trimming-2.rs create mode 100644 src/test/ui/terminal-width/whitespace-trimming-2.stderr create mode 100644 src/test/ui/terminal-width/whitespace-trimming.rs create mode 100644 src/test/ui/terminal-width/whitespace-trimming.stderr diff --git a/Cargo.lock b/Cargo.lock index 06c455b3c91..16baa7436cb 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -3219,6 +3219,7 @@ dependencies = [ "rustc_data_structures", "serialize", "syntax_pos", + "term_size", "termcolor", "unicode-width", ] @@ -4090,6 +4091,17 @@ dependencies = [ "winapi 0.3.6", ] +[[package]] +name = "term_size" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9e5b9a66db815dcfd2da92db471106457082577c3c278d4138ab3e3b4e189327" +dependencies = [ + "kernel32-sys", + "libc", + "winapi 0.2.8", +] + [[package]] name = "termcolor" version = "1.0.4" diff --git a/src/librustc_errors/Cargo.toml b/src/librustc_errors/Cargo.toml index 32f121f18f6..1541845bb55 100644 --- a/src/librustc_errors/Cargo.toml +++ b/src/librustc_errors/Cargo.toml @@ -18,3 +18,4 @@ unicode-width = "0.1.4" atty = "0.2" termcolor = "1.0" annotate-snippets = "0.6.1" +term_size = "0.3.1" diff --git a/src/librustc_errors/emitter.rs b/src/librustc_errors/emitter.rs index b7615fef049..6bb151d19b3 100644 --- a/src/librustc_errors/emitter.rs +++ b/src/librustc_errors/emitter.rs @@ -24,7 +24,7 @@ use rustc_data_structures::sync::Lrc; use std::borrow::Cow; use std::io::prelude::*; use std::io; -use std::cmp::{min, Reverse}; +use std::cmp::{min, max, Reverse}; use std::path::Path; use termcolor::{StandardStream, ColorChoice, ColorSpec, BufferWriter, Ansi}; use termcolor::{WriteColor, Color, Buffer}; @@ -59,13 +59,20 @@ impl HumanReadableErrorType { #[derive(Clone, Copy, Debug)] struct Margin { + /// The available whitespace in the left that can be consumed when centering. pub whitespace_left: usize, + /// The column of the beginning of left-most span. pub span_left: usize, + /// The column of the end of right-most span. pub span_right: usize, - pub line_len: usize, + /// The beginning of the line to be displayed. pub computed_left: usize, + /// The end of the line to be displayed. pub computed_right: usize, + /// The current width of the terminal. 140 by default and in tests. pub column_width: usize, + /// The end column of a span label, including the span. Doesn't account for labels not in the + /// same line as the span. pub label_right: usize, } @@ -75,59 +82,92 @@ impl Margin { span_left: usize, span_right: usize, label_right: usize, + column_width: usize, + max_line_len: usize, ) -> Self { - Margin { - whitespace_left, - span_left, - span_right, - line_len: 0, + // The 6 is padding to give a bit of room for `...` when displaying: + // ``` + // error: message + // --> file.rs:16:58 + // | + // 16 | ... fn foo(self) -> Self::Bar { + // | ^^^^^^^^^ + // ``` + + let mut m = Margin { + whitespace_left: if whitespace_left >= 6 { whitespace_left - 6 } else { 0 }, + span_left: if span_left >= 6 { span_left - 6 } else { 0 }, + span_right: span_right + 6, computed_left: 0, computed_right: 0, - column_width: 140, - label_right, - } + column_width, + label_right: label_right + 6, + }; + m.compute(max_line_len); + m } fn was_cut_left(&self) -> bool { self.computed_left > 0 } - fn was_cut_right(&self) -> bool { - self.computed_right < self.line_len + fn was_cut_right(&self, line_len: usize) -> bool { + let right = if self.computed_right == self.span_right || + self.computed_right == self.label_right + { + // Account for the "..." padding given above. Otherwise we end up with code lines that + // do fit but end in "..." as if they were trimmed. + self.computed_right - 6 + } else { + self.computed_right + }; + right < line_len && line_len > self.computed_left + self.column_width } - fn compute(&mut self) { + fn compute(&mut self, max_line_len: usize) { + // When there's a lot of whitespace (>20), we want to trim it as it is useless. self.computed_left = if self.whitespace_left > 20 { self.whitespace_left - 16 // We want some padding. } else { 0 }; - self.computed_right = self.column_width + self.computed_left; + // We want to show as much as possible, max_line_len is the right-most boundary for the + // relevant code. + self.computed_right = max(max_line_len, self.computed_left); if self.computed_right - self.computed_left > self.column_width { // Trimming only whitespace isn't enough, let's get craftier. if self.label_right - self.whitespace_left <= self.column_width { + // Attempt to fit the code window only trimming whitespace. self.computed_left = self.whitespace_left; self.computed_right = self.computed_left + self.column_width; - } else if self.label_right - self.span_left - 20 <= self.column_width { - self.computed_left = self.span_left - 20; - self.computed_right = self.computed_left + self.column_width; } else if self.label_right - self.span_left <= self.column_width { + // Attempt to fit the code window considering only the spans and labels. self.computed_left = self.span_left; self.computed_right = self.computed_left + self.column_width; } else if self.span_right - self.span_left <= self.column_width { + // Attempt to fit the code window considering the spans and labels plus padding. self.computed_left = self.span_left; self.computed_right = self.computed_left + self.column_width; - } else { // mostly give up but still don't show the full line + } else { // Mostly give up but still don't show the full line. self.computed_left = self.span_left; self.computed_right = self.span_right; } } - self.computed_left = std::cmp::min(self.computed_left, self.line_len); - if self.computed_right > self.line_len { - self.computed_right = self.line_len; + } + + fn left(&self, line_len: usize) -> usize { + min(self.computed_left, line_len) + } + + fn right(&self, line_len: usize) -> usize { + if max(line_len, self.computed_left) - self.computed_left <= self.column_width { + line_len + } else if self.computed_right > line_len { + line_len + } else { + self.computed_right } - self.computed_right = std::cmp::min(self.computed_right, self.line_len); } } @@ -308,6 +348,42 @@ impl EmitterWriter { } } + fn draw_line( + &self, + buffer: &mut StyledBuffer, + source_string: &str, + line_index: usize, + line_offset: usize, + width_offset: usize, + code_offset: usize, + margin: Margin, + ) { + let line_len = source_string.len(); + // Create the source line we will highlight. + buffer.puts( + line_offset, + code_offset, + // On long lines, we strip the source line + &source_string[margin.left(line_len)..margin.right(line_len)], + Style::Quotation, + ); + if margin.was_cut_left() { // We have stripped some code/whitespace from the beginning, make it clear. + buffer.puts(line_offset, code_offset, "...", Style::LineNumber); + } + if margin.was_cut_right(line_len) { + // We have stripped some code after the right-most span end, make it clear we did so. + buffer.puts( + line_offset, + margin.right(line_len) - margin.left(line_len) + code_offset - 3, + "...", + Style::LineNumber, + ); + } + buffer.puts(line_offset, 0, &self.maybe_anonymized(line_index), Style::LineNumber); + + draw_col_separator(buffer, line_offset, width_offset - 2); + } + fn render_source_line( &self, buffer: &mut StyledBuffer, @@ -315,7 +391,7 @@ impl EmitterWriter { line: &Line, width_offset: usize, code_offset: usize, - mut margin: Margin, + margin: Margin, ) -> Vec<(usize, Style)> { // Draw: // @@ -342,31 +418,15 @@ impl EmitterWriter { let line_offset = buffer.num_lines(); - margin.line_len = source_string.len(); - margin.compute(); - // Create the source line we will highlight. - buffer.puts( + self.draw_line( + buffer, + &source_string, + line.line_index, line_offset, + width_offset, code_offset, - // On long lines, we strip the source line - &source_string[margin.computed_left..margin.computed_right], - Style::Quotation, + margin, ); - if margin.was_cut_left() { // We have stripped some code/whitespace from the beginning, make it clear. - buffer.puts(line_offset, code_offset, "...", Style::LineNumber); - } - if margin.was_cut_right() { - // We have stripped some code after the right-most span end, make it clear we did so. - buffer.puts( - line_offset, - margin.computed_right - margin.computed_left + code_offset, - "...", - Style::LineNumber, - ); - } - buffer.puts(line_offset, 0, &self.maybe_anonymized(line.line_index), Style::LineNumber); - - draw_col_separator(buffer, line_offset, width_offset - 2); // Special case when there's only one annotation involved, it is the start of a multiline // span and there's no text at the beginning of the code line. Instead of doing the whole @@ -614,19 +674,23 @@ impl EmitterWriter { match annotation.annotation_type { AnnotationType::MultilineStart(depth) | AnnotationType::MultilineEnd(depth) => { - draw_range(buffer, - '_', - line_offset + pos, - width_offset + depth, - code_offset + annotation.start_col - margin.computed_left, - style); + draw_range( + buffer, + '_', + line_offset + pos, + width_offset + depth, + code_offset + annotation.start_col - margin.computed_left, + style, + ); } _ if self.teach => { - buffer.set_style_range(line_offset, - code_offset + annotation.start_col - margin.computed_left, - code_offset + annotation.end_col - margin.computed_left, - style, - annotation.is_primary); + buffer.set_style_range( + line_offset, + code_offset + annotation.start_col - margin.computed_left, + code_offset + annotation.end_col - margin.computed_left, + style, + annotation.is_primary, + ); } _ => {} } @@ -1159,7 +1223,7 @@ impl EmitterWriter { .take_while(|c| c.is_whitespace()) .count(); if source_string.chars().any(|c| !c.is_whitespace()) { - whitespace_margin = std::cmp::min( + whitespace_margin = min( whitespace_margin, leading_whitespace, ); @@ -1174,8 +1238,8 @@ impl EmitterWriter { let mut span_left_margin = std::usize::MAX; for line in &annotated_file.lines { for ann in &line.annotations { - span_left_margin = std::cmp::min(span_left_margin, ann.start_col); - span_left_margin = std::cmp::min(span_left_margin, ann.end_col); + span_left_margin = min(span_left_margin, ann.start_col); + span_left_margin = min(span_left_margin, ann.end_col); } } if span_left_margin == std::usize::MAX { @@ -1185,35 +1249,49 @@ impl EmitterWriter { // Right-most column any visible span points at. let mut span_right_margin = 0; let mut label_right_margin = 0; + let mut max_line_len = 0; for line in &annotated_file.lines { + max_line_len = max( + max_line_len, + annotated_file.file.get_line(line.line_index - 1).map(|s| s.len()).unwrap_or(0), + ); for ann in &line.annotations { - span_right_margin = std::cmp::max(span_right_margin, ann.start_col); - span_right_margin = std::cmp::max(span_right_margin, ann.end_col); - label_right_margin = std::cmp::max( + span_right_margin = max(span_right_margin, ann.start_col); + span_right_margin = max(span_right_margin, ann.end_col); + label_right_margin = max( label_right_margin, // TODO: account for labels not in the same line ann.end_col + ann.label.as_ref().map(|l| l.len() + 1).unwrap_or(0), ); } } + + let width_offset = 3 + max_line_num_len; + let code_offset = if annotated_file.multiline_depth == 0 { + width_offset + } else { + width_offset + annotated_file.multiline_depth + 1 + }; + + let column_width = if self.ui_testing { + 140 + } else { + term_size::dimensions().map(|(w, _)| w - code_offset).unwrap_or(140) + }; + let margin = Margin::new( whitespace_margin, span_left_margin, span_right_margin, label_right_margin, + column_width, + max_line_len, ); // Next, output the annotate source for this file for line_idx in 0..annotated_file.lines.len() { let previous_buffer_line = buffer.num_lines(); - let width_offset = 3 + max_line_num_len; - let code_offset = if annotated_file.multiline_depth == 0 { - width_offset - } else { - width_offset + annotated_file.multiline_depth + 1 - }; - let depths = self.render_source_line( &mut buffer, annotated_file.file.clone(), @@ -1268,36 +1346,24 @@ impl EmitterWriter { let last_buffer_line_num = buffer.num_lines(); - buffer.puts( - last_buffer_line_num, - 0, - &self.maybe_anonymized( - annotated_file.lines[line_idx + 1].line_index - 1, - ), - Style::LineNumber, - ); - draw_col_separator( + self.draw_line( &mut buffer, + &unannotated_line, + annotated_file.lines[line_idx + 1].line_index - 1, last_buffer_line_num, - 1 + max_line_num_len, - ); - - let mut margin = margin; - margin.line_len = unannotated_line.len(); - margin.compute(); - buffer.puts( - last_buffer_line_num, + width_offset, code_offset, - &unannotated_line[margin.computed_left..margin.computed_right], - Style::Quotation, + margin, ); for (depth, style) in &multilines { - draw_multiline_line(&mut buffer, - last_buffer_line_num, - width_offset, - *depth, - *style); + draw_multiline_line( + &mut buffer, + last_buffer_line_num, + width_offset, + *depth, + *style, + ); } } } diff --git a/src/test/ui/inline-asm-bad-operand.stderr b/src/test/ui/inline-asm-bad-operand.stderr index d5c1cf51daf..55523bad6c5 100644 --- a/src/test/ui/inline-asm-bad-operand.stderr +++ b/src/test/ui/inline-asm-bad-operand.stderr @@ -37,8 +37,8 @@ LL | asm!("mov sp, $0"::"r"(addr), error[E0669]: invalid value for constraint in inline assembly --> $DIR/inline-asm-bad-operand.rs:56:32 | -LL | ... "r"("hello e0669")); - | ^^^^^^^^^^^^^ +LL | ... "r"("hello e0669")); + | ^^^^^^^^^^^^^ error: aborting due to 7 previous errors diff --git a/src/test/ui/lint/issue-47390-unused-variable-in-struct-pattern.stderr b/src/test/ui/lint/issue-47390-unused-variable-in-struct-pattern.stderr index 3262662a2a5..a0b34d220c8 100644 --- a/src/test/ui/lint/issue-47390-unused-variable-in-struct-pattern.stderr +++ b/src/test/ui/lint/issue-47390-unused-variable-in-struct-pattern.stderr @@ -38,8 +38,8 @@ LL | if let SoulHistory { corridors_of_light, warning: variable `hours_are_suns` is assigned to, but never used --> $DIR/issue-47390-unused-variable-in-struct-pattern.rs:38:30 | -LL | ... mut hours_are_suns, - | ^^^^^^^^^^^^^^ +LL | mut hours_are_suns, + | ^^^^^^^^^^^^^^ | = note: consider using `_hours_are_suns` instead diff --git a/src/test/ui/lint/lint-stability-deprecated.stderr b/src/test/ui/lint/lint-stability-deprecated.stderr index 8132a66df8a..62380135b33 100644 --- a/src/test/ui/lint/lint-stability-deprecated.stderr +++ b/src/test/ui/lint/lint-stability-deprecated.stderr @@ -67,14 +67,14 @@ LL | deprecated_unstable_text(); warning: use of deprecated item 'lint_stability::Trait::trait_deprecated_unstable_text': text --> $DIR/lint-stability-deprecated.rs:57:9 | -LL | Trait::trait_deprecated_unstable_text(&foo); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +LL | ... Trait::trait_deprecated_unstable_text(&foo); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ warning: use of deprecated item 'lint_stability::Trait::trait_deprecated_unstable_text': text --> $DIR/lint-stability-deprecated.rs:59:9 | -LL | ::trait_deprecated_unstable_text(&foo); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +LL | ... ::trait_deprecated_unstable_text(&foo); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ warning: use of deprecated item 'lint_stability::DeprecatedStruct': text --> $DIR/lint-stability-deprecated.rs:106:17 @@ -181,14 +181,14 @@ LL | ::trait_deprecated_unstable(&foo); warning: use of deprecated item 'lint_stability::Trait::trait_deprecated_unstable_text': text --> $DIR/lint-stability-deprecated.rs:155:9 | -LL | Trait::trait_deprecated_unstable_text(&foo); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +LL | ... Trait::trait_deprecated_unstable_text(&foo); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ warning: use of deprecated item 'lint_stability::Trait::trait_deprecated_unstable_text': text --> $DIR/lint-stability-deprecated.rs:157:9 | -LL | ::trait_deprecated_unstable_text(&foo); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +LL | ... ::trait_deprecated_unstable_text(&foo); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ warning: use of deprecated item 'lint_stability::DeprecatedTrait': text --> $DIR/lint-stability-deprecated.rs:185:10 @@ -421,20 +421,20 @@ LL | ::trait_deprecated_unstable(&foo); warning: use of deprecated item 'lint_stability::MethodTester::method_deprecated_unstable_text': text --> $DIR/lint-stability-deprecated.rs:53:13 | -LL | foo.method_deprecated_unstable_text(); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +LL | ... foo.method_deprecated_unstable_text(); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ warning: use of deprecated item 'lint_stability::MethodTester::method_deprecated_unstable_text': text --> $DIR/lint-stability-deprecated.rs:54:9 | -LL | Foo::method_deprecated_unstable_text(&foo); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +LL | ... Foo::method_deprecated_unstable_text(&foo); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ warning: use of deprecated item 'lint_stability::MethodTester::method_deprecated_unstable_text': text --> $DIR/lint-stability-deprecated.rs:55:9 | -LL | ::method_deprecated_unstable_text(&foo); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +LL | ... ::method_deprecated_unstable_text(&foo); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ warning: use of deprecated item 'lint_stability::Trait::trait_deprecated_unstable_text': text --> $DIR/lint-stability-deprecated.rs:56:13 @@ -445,8 +445,8 @@ LL | foo.trait_deprecated_unstable_text(); warning: use of deprecated item 'lint_stability::Trait::trait_deprecated_unstable_text': text --> $DIR/lint-stability-deprecated.rs:58:9 | -LL | ::trait_deprecated_unstable_text(&foo); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +LL | ... ::trait_deprecated_unstable_text(&foo); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ warning: use of deprecated item 'lint_stability::DeprecatedStruct::i': text --> $DIR/lint-stability-deprecated.rs:107:13 @@ -505,8 +505,8 @@ LL | foo.trait_deprecated_unstable_text(); warning: use of deprecated item 'lint_stability::Trait::trait_deprecated_unstable_text': text --> $DIR/lint-stability-deprecated.rs:156:9 | -LL | ::trait_deprecated_unstable_text(&foo); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +LL | ... ::trait_deprecated_unstable_text(&foo); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ warning: use of deprecated item 'lint_stability::Trait::trait_deprecated': text --> $DIR/lint-stability-deprecated.rs:173:13 diff --git a/src/test/ui/methods/method-missing-call.stderr b/src/test/ui/methods/method-missing-call.stderr index fe44d3a29da..3ab5f66a0c3 100644 --- a/src/test/ui/methods/method-missing-call.stderr +++ b/src/test/ui/methods/method-missing-call.stderr @@ -1,8 +1,8 @@ error[E0615]: attempted to take value of method `get_x` on type `Point` --> $DIR/method-missing-call.rs:22:26 | -LL | ... .get_x; - | ^^^^^ help: use parentheses to call the method: `get_x()` +LL | .get_x; + | ^^^^^ help: use parentheses to call the method: `get_x()` error[E0615]: attempted to take value of method `filter_map` on type `std::iter::Filter, [closure@$DIR/method-missing-call.rs:27:20: 27:25]>, [closure@$DIR/method-missing-call.rs:28:23: 28:35]>` --> $DIR/method-missing-call.rs:29:16 diff --git a/src/test/ui/regions/regions-name-undeclared.stderr b/src/test/ui/regions/regions-name-undeclared.stderr index fe0345c3a38..5f6a48a35f3 100644 --- a/src/test/ui/regions/regions-name-undeclared.stderr +++ b/src/test/ui/regions/regions-name-undeclared.stderr @@ -49,14 +49,14 @@ LL | fn fn_types(a: &'a isize, error[E0261]: use of undeclared lifetime name `'b` --> $DIR/regions-name-undeclared.rs:42:36 | -LL | ... &'b isize, - | ^^ undeclared lifetime +LL | ... &'b isize, + | ^^ undeclared lifetime error[E0261]: use of undeclared lifetime name `'b` --> $DIR/regions-name-undeclared.rs:45:36 | -LL | ... &'b isize)>, - | ^^ undeclared lifetime +LL | ... &'b isize)>, + | ^^ undeclared lifetime error[E0261]: use of undeclared lifetime name `'a` --> $DIR/regions-name-undeclared.rs:46:17 diff --git a/src/test/ui/terminal-width/non-whitespace-trimming-2.rs b/src/test/ui/terminal-width/non-whitespace-trimming-2.rs new file mode 100644 index 00000000000..31e979702ff --- /dev/null +++ b/src/test/ui/terminal-width/non-whitespace-trimming-2.rs @@ -0,0 +1,6 @@ +// ignore-tidy-length + +fn main() { + let _: () = (); let _: () = (); let _: () = (); let _: () = (); let _: () = (); let _: () = (); let _: () = (); let _: () = (); let _: () = (); let _: () = (); let _: () = (); let _: () = (); let _: () = (); let _: () = (); let _: () = 42; let _: () = (); let _: () = (); let _: () = (); let _: () = (); let _: () = (); let _: () = (); let _: () = (); let _: () = (); let _: () = (); let _: () = (); let _: () = (); let _: () = (); let _: () = (); let _: () = (); let _: () = (); let _: () = (); let _: () = (); let _: () = (); let _: () = (); let _: () = (); let _: () = (); let _: () = (); let _: () = (); let _: () = (); +//~^ ERROR mismatched types +} diff --git a/src/test/ui/terminal-width/non-whitespace-trimming-2.stderr b/src/test/ui/terminal-width/non-whitespace-trimming-2.stderr new file mode 100644 index 00000000000..3821d86e23a --- /dev/null +++ b/src/test/ui/terminal-width/non-whitespace-trimming-2.stderr @@ -0,0 +1,12 @@ +error[E0308]: mismatched types + --> $DIR/non-whitespace-trimming-2.rs:4:241 + | +LL | ... = 42; let _: () = (); let _: () = (); let _: () = (); let _: () = (); let _: () = (); let _: () = (); let _: () = (); let _: () = ();... + | ^^ expected (), found integer + | + = note: expected type `()` + found type `{integer}` + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0308`. diff --git a/src/test/ui/terminal-width/non-whitespace-trimming.rs b/src/test/ui/terminal-width/non-whitespace-trimming.rs new file mode 100644 index 00000000000..791e8a592d1 --- /dev/null +++ b/src/test/ui/terminal-width/non-whitespace-trimming.rs @@ -0,0 +1,6 @@ +// ignore-tidy-length + +fn main() { + let _: () = (); let _: () = (); let _: () = (); let _: () = (); let _: () = (); let _: () = (); let _: () = (); let _: () = (); let _: () = (); let _: () = (); let _: () = (); let _: () = (); let _: () = (); let _: () = (); let _: () = 42; let _: () = (); let _: () = (); let _: () = (); let _: () = (); let _: () = (); let _: () = (); let _: () = (); let _: () = (); +//~^ ERROR mismatched types +} diff --git a/src/test/ui/terminal-width/non-whitespace-trimming.stderr b/src/test/ui/terminal-width/non-whitespace-trimming.stderr new file mode 100644 index 00000000000..36e6d8045a8 --- /dev/null +++ b/src/test/ui/terminal-width/non-whitespace-trimming.stderr @@ -0,0 +1,12 @@ +error[E0308]: mismatched types + --> $DIR/non-whitespace-trimming.rs:4:241 + | +LL | ... = 42; let _: () = (); let _: () = (); let _: () = (); let _: () = (); let _: () = (); let _: () = (); let _: () = (); let _: () = (); + | ^^ expected (), found integer + | + = note: expected type `()` + found type `{integer}` + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0308`. diff --git a/src/test/ui/terminal-width/whitespace-trimming-2.rs b/src/test/ui/terminal-width/whitespace-trimming-2.rs new file mode 100644 index 00000000000..bc02c685dc9 --- /dev/null +++ b/src/test/ui/terminal-width/whitespace-trimming-2.rs @@ -0,0 +1,8 @@ +// ignore-tidy-length + +fn foo() -> usize { + () +//~^ ERROR mismatched types +} + +fn main() {} diff --git a/src/test/ui/terminal-width/whitespace-trimming-2.stderr b/src/test/ui/terminal-width/whitespace-trimming-2.stderr new file mode 100644 index 00000000000..38df5a9e9a0 --- /dev/null +++ b/src/test/ui/terminal-width/whitespace-trimming-2.stderr @@ -0,0 +1,14 @@ +error[E0308]: mismatched types + --> $DIR/whitespace-trimming-2.rs:4:187 + | +LL | ...-> usize { + | ----- expected `usize` because of return type +LL | ... () + | ^^ expected usize, found () + | + = note: expected type `usize` + found type `()` + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0308`. diff --git a/src/test/ui/terminal-width/whitespace-trimming.rs b/src/test/ui/terminal-width/whitespace-trimming.rs new file mode 100644 index 00000000000..427ed1e72e4 --- /dev/null +++ b/src/test/ui/terminal-width/whitespace-trimming.rs @@ -0,0 +1,6 @@ +// ignore-tidy-length + +fn main() { + let _: () = 42; +//~^ ERROR mismatched types +} diff --git a/src/test/ui/terminal-width/whitespace-trimming.stderr b/src/test/ui/terminal-width/whitespace-trimming.stderr new file mode 100644 index 00000000000..45a804b9f6a --- /dev/null +++ b/src/test/ui/terminal-width/whitespace-trimming.stderr @@ -0,0 +1,12 @@ +error[E0308]: mismatched types + --> $DIR/whitespace-trimming.rs:4:193 + | +LL | ... let _: () = 42; + | ^^ expected (), found integer + | + = note: expected type `()` + found type `{integer}` + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0308`. diff --git a/src/tools/tidy/src/deps.rs b/src/tools/tidy/src/deps.rs index de54eb8f573..92f60b2ddab 100644 --- a/src/tools/tidy/src/deps.rs +++ b/src/tools/tidy/src/deps.rs @@ -159,6 +159,7 @@ const WHITELIST: &[Crate<'_>] = &[ Crate("termcolor"), Crate("terminon"), Crate("termion"), + Crate("term_size"), Crate("thread_local"), Crate("ucd-util"), Crate("unicode-width"), From 45a6be545891f4a8f19f0dce801b67fdccf435ee Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Esteban=20K=C3=BCber?= Date: Wed, 14 Aug 2019 11:44:56 -0700 Subject: [PATCH 4/9] Fix tidy --- src/librustc_errors/emitter.rs | 21 +++++++++---------- .../non-whitespace-trimming-2.rs | 2 +- .../terminal-width/non-whitespace-trimming.rs | 2 +- .../terminal-width/whitespace-trimming-2.rs | 2 +- .../ui/terminal-width/whitespace-trimming.rs | 2 +- 5 files changed, 14 insertions(+), 15 deletions(-) diff --git a/src/librustc_errors/emitter.rs b/src/librustc_errors/emitter.rs index 6bb151d19b3..a78a4365633 100644 --- a/src/librustc_errors/emitter.rs +++ b/src/librustc_errors/emitter.rs @@ -367,7 +367,8 @@ impl EmitterWriter { &source_string[margin.left(line_len)..margin.right(line_len)], Style::Quotation, ); - if margin.was_cut_left() { // We have stripped some code/whitespace from the beginning, make it clear. + if margin.was_cut_left() { + // We have stripped some code/whitespace from the beginning, make it clear. buffer.puts(line_offset, code_offset, "...", Style::LineNumber); } if margin.was_cut_right(line_len) { @@ -403,7 +404,7 @@ impl EmitterWriter { // ^^ ^ ^^^ ^^^^ ^^^ we don't care about code too far to the right of a span, we trim it // | | | | // | | | actual code found in your source code and the spans we use to mark it - // | | when there's too much wasted space to the left, we trim it to focus where it matters + // | | when there's too much wasted space to the left, trim it // | vertical divider between the column number and the code // column number @@ -1251,18 +1252,16 @@ impl EmitterWriter { let mut label_right_margin = 0; let mut max_line_len = 0; for line in &annotated_file.lines { - max_line_len = max( - max_line_len, - annotated_file.file.get_line(line.line_index - 1).map(|s| s.len()).unwrap_or(0), - ); + max_line_len = max(max_line_len, annotated_file.file + .get_line(line.line_index - 1) + .map(|s| s.len()) + .unwrap_or(0)); for ann in &line.annotations { span_right_margin = max(span_right_margin, ann.start_col); span_right_margin = max(span_right_margin, ann.end_col); - label_right_margin = max( - label_right_margin, - // TODO: account for labels not in the same line - ann.end_col + ann.label.as_ref().map(|l| l.len() + 1).unwrap_or(0), - ); + // FIXME: account for labels not in the same line + let label_right = ann.label.as_ref().map(|l| l.len() + 1).unwrap_or(0); + label_right_margin = max(label_right_margin, ann.end_col + label_right); } } diff --git a/src/test/ui/terminal-width/non-whitespace-trimming-2.rs b/src/test/ui/terminal-width/non-whitespace-trimming-2.rs index 31e979702ff..b1ef6b95f25 100644 --- a/src/test/ui/terminal-width/non-whitespace-trimming-2.rs +++ b/src/test/ui/terminal-width/non-whitespace-trimming-2.rs @@ -1,4 +1,4 @@ -// ignore-tidy-length +// ignore-tidy-linelength fn main() { let _: () = (); let _: () = (); let _: () = (); let _: () = (); let _: () = (); let _: () = (); let _: () = (); let _: () = (); let _: () = (); let _: () = (); let _: () = (); let _: () = (); let _: () = (); let _: () = (); let _: () = 42; let _: () = (); let _: () = (); let _: () = (); let _: () = (); let _: () = (); let _: () = (); let _: () = (); let _: () = (); let _: () = (); let _: () = (); let _: () = (); let _: () = (); let _: () = (); let _: () = (); let _: () = (); let _: () = (); let _: () = (); let _: () = (); let _: () = (); let _: () = (); let _: () = (); let _: () = (); let _: () = (); let _: () = (); diff --git a/src/test/ui/terminal-width/non-whitespace-trimming.rs b/src/test/ui/terminal-width/non-whitespace-trimming.rs index 791e8a592d1..f6c8d345c65 100644 --- a/src/test/ui/terminal-width/non-whitespace-trimming.rs +++ b/src/test/ui/terminal-width/non-whitespace-trimming.rs @@ -1,4 +1,4 @@ -// ignore-tidy-length +// ignore-tidy-linelength fn main() { let _: () = (); let _: () = (); let _: () = (); let _: () = (); let _: () = (); let _: () = (); let _: () = (); let _: () = (); let _: () = (); let _: () = (); let _: () = (); let _: () = (); let _: () = (); let _: () = (); let _: () = 42; let _: () = (); let _: () = (); let _: () = (); let _: () = (); let _: () = (); let _: () = (); let _: () = (); let _: () = (); diff --git a/src/test/ui/terminal-width/whitespace-trimming-2.rs b/src/test/ui/terminal-width/whitespace-trimming-2.rs index bc02c685dc9..c68f678aab3 100644 --- a/src/test/ui/terminal-width/whitespace-trimming-2.rs +++ b/src/test/ui/terminal-width/whitespace-trimming-2.rs @@ -1,4 +1,4 @@ -// ignore-tidy-length +// ignore-tidy-linelength fn foo() -> usize { () diff --git a/src/test/ui/terminal-width/whitespace-trimming.rs b/src/test/ui/terminal-width/whitespace-trimming.rs index 427ed1e72e4..f747bcf17e0 100644 --- a/src/test/ui/terminal-width/whitespace-trimming.rs +++ b/src/test/ui/terminal-width/whitespace-trimming.rs @@ -1,4 +1,4 @@ -// ignore-tidy-length +// ignore-tidy-linelength fn main() { let _: () = 42; From de2e9fe2c476021c7589d840a3b3ae870e0a75d9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Esteban=20K=C3=BCber?= Date: Wed, 14 Aug 2019 14:09:37 -0700 Subject: [PATCH 5/9] Center trim on the span labels and handle unicode --- src/librustc_errors/emitter.rs | 57 ++++++++++++------- .../non-whitespace-trimming-2.rs | 2 +- .../non-whitespace-trimming-2.stderr | 6 +- .../non-whitespace-trimming.stderr | 4 +- 4 files changed, 41 insertions(+), 28 deletions(-) diff --git a/src/librustc_errors/emitter.rs b/src/librustc_errors/emitter.rs index a78a4365633..d20e700b355 100644 --- a/src/librustc_errors/emitter.rs +++ b/src/librustc_errors/emitter.rs @@ -143,11 +143,13 @@ impl Margin { self.computed_right = self.computed_left + self.column_width; } else if self.label_right - self.span_left <= self.column_width { // Attempt to fit the code window considering only the spans and labels. - self.computed_left = self.span_left; + let padding_left = (self.column_width - (self.label_right - self.span_left)) / 2; + self.computed_left = self.span_left - padding_left; self.computed_right = self.computed_left + self.column_width; } else if self.span_right - self.span_left <= self.column_width { // Attempt to fit the code window considering the spans and labels plus padding. - self.computed_left = self.span_left; + let padding_left = (self.column_width - (self.span_right - self.span_left)) / 2; + self.computed_left = self.span_left - padding_left; self.computed_right = self.computed_left + self.column_width; } else { // Mostly give up but still don't show the full line. self.computed_left = self.span_left; @@ -360,13 +362,11 @@ impl EmitterWriter { ) { let line_len = source_string.len(); // Create the source line we will highlight. - buffer.puts( - line_offset, - code_offset, - // On long lines, we strip the source line - &source_string[margin.left(line_len)..margin.right(line_len)], - Style::Quotation, - ); + let left = margin.left(line_len); + let right = margin.right(line_len); + // On long lines, we strip the source line, accounting for unicode. + let code: String = source_string.chars().skip(left).take(right - left).collect(); + buffer.puts(line_offset, code_offset, &code, Style::Quotation); if margin.was_cut_left() { // We have stripped some code/whitespace from the beginning, make it clear. buffer.puts(line_offset, code_offset, "...", Style::LineNumber); @@ -419,6 +419,8 @@ impl EmitterWriter { let line_offset = buffer.num_lines(); + let left = margin.left(source_string.len()); // Left trim + self.draw_line( buffer, &source_string, @@ -680,15 +682,15 @@ impl EmitterWriter { '_', line_offset + pos, width_offset + depth, - code_offset + annotation.start_col - margin.computed_left, + code_offset + annotation.start_col - left, style, ); } _ if self.teach => { buffer.set_style_range( line_offset, - code_offset + annotation.start_col - margin.computed_left, - code_offset + annotation.end_col - margin.computed_left, + code_offset + annotation.start_col - left, + code_offset + annotation.end_col - left, style, annotation.is_primary, ); @@ -763,15 +765,20 @@ impl EmitterWriter { Style::LabelSecondary }; let (pos, col) = if pos == 0 { - (pos + 1, annotation.end_col + 1 - margin.computed_left) + (pos + 1, if annotation.end_col + 1 > left { + annotation.end_col + 1 - left + } else { + 0 + }) } else { - (pos + 2, annotation.start_col - margin.computed_left) + (pos + 2, if annotation.start_col > left { + annotation.start_col - left + } else { + 0 + }) }; if let Some(ref label) = annotation.label { - buffer.puts(line_offset + pos, - code_offset + col, - &label, - style); + buffer.puts(line_offset + pos, code_offset + col, &label, style); } } @@ -806,10 +813,16 @@ impl EmitterWriter { ('-', Style::UnderlineSecondary) }; for p in annotation.start_col..annotation.end_col { - buffer.putc(line_offset + 1, - code_offset + p - margin.computed_left, - underline, - style); + buffer.putc( + line_offset + 1, + if code_offset + p > left { + code_offset + p - left + } else { + 0 + }, + underline, + style, + ); } } annotations_position.iter().filter_map(|&(_, annotation)| { diff --git a/src/test/ui/terminal-width/non-whitespace-trimming-2.rs b/src/test/ui/terminal-width/non-whitespace-trimming-2.rs index b1ef6b95f25..abd9e189a75 100644 --- a/src/test/ui/terminal-width/non-whitespace-trimming-2.rs +++ b/src/test/ui/terminal-width/non-whitespace-trimming-2.rs @@ -1,6 +1,6 @@ // ignore-tidy-linelength fn main() { - let _: () = (); let _: () = (); let _: () = (); let _: () = (); let _: () = (); let _: () = (); let _: () = (); let _: () = (); let _: () = (); let _: () = (); let _: () = (); let _: () = (); let _: () = (); let _: () = (); let _: () = 42; let _: () = (); let _: () = (); let _: () = (); let _: () = (); let _: () = (); let _: () = (); let _: () = (); let _: () = (); let _: () = (); let _: () = (); let _: () = (); let _: () = (); let _: () = (); let _: () = (); let _: () = (); let _: () = (); let _: () = (); let _: () = (); let _: () = (); let _: () = (); let _: () = (); let _: () = (); let _: () = (); let _: () = (); + let _: usize = 0; let _: usize = 1; let _: usize = 2; let _: usize = 3; let _: usize = 4; let _: usize = 5; let _: usize = 6; let _: usize = 7; let _: usize = 8; let _: usize = 9; let _: usize = 10; let _: usize = 11; let _: usize = 12; let _: usize = 13; let _: usize = 14; let _: usize = 15; let _: () = 42; let _: usize = 0; let _: usize = 1; let _: usize = 2; let _: usize = 3; let _: usize = 4; let _: usize = 5; let _: usize = 6; let _: usize = 7; let _: usize = 8; let _: usize = 9; let _: usize = 10; let _: usize = 11; let _: usize = 12; let _: usize = 13; let _: usize = 14; let _: usize = 15; //~^ ERROR mismatched types } diff --git a/src/test/ui/terminal-width/non-whitespace-trimming-2.stderr b/src/test/ui/terminal-width/non-whitespace-trimming-2.stderr index 3821d86e23a..bf1699f5cab 100644 --- a/src/test/ui/terminal-width/non-whitespace-trimming-2.stderr +++ b/src/test/ui/terminal-width/non-whitespace-trimming-2.stderr @@ -1,8 +1,8 @@ error[E0308]: mismatched types - --> $DIR/non-whitespace-trimming-2.rs:4:241 + --> $DIR/non-whitespace-trimming-2.rs:4:311 | -LL | ... = 42; let _: () = (); let _: () = (); let _: () = (); let _: () = (); let _: () = (); let _: () = (); let _: () = (); let _: () = ();... - | ^^ expected (), found integer +LL | ...; let _: usize = 14; let _: usize = 15; let _: () = 42; let _: usize = 0; let _: usize = 1; let _: usize = 2; let _: usize = 3; let _:... + | ^^ expected (), found integer | = note: expected type `()` found type `{integer}` diff --git a/src/test/ui/terminal-width/non-whitespace-trimming.stderr b/src/test/ui/terminal-width/non-whitespace-trimming.stderr index 36e6d8045a8..622713eb5f6 100644 --- a/src/test/ui/terminal-width/non-whitespace-trimming.stderr +++ b/src/test/ui/terminal-width/non-whitespace-trimming.stderr @@ -1,8 +1,8 @@ error[E0308]: mismatched types --> $DIR/non-whitespace-trimming.rs:4:241 | -LL | ... = 42; let _: () = (); let _: () = (); let _: () = (); let _: () = (); let _: () = (); let _: () = (); let _: () = (); let _: () = (); - | ^^ expected (), found integer +LL | ...) = (); let _: () = (); let _: () = (); let _: () = 42; let _: () = (); let _: () = (); let _: () = (); let _: () = (); let _: () = ()... + | ^^ expected (), found integer | = note: expected type `()` found type `{integer}` From 9980796d6d29f532e9a49a5b3767285e2a5e2d02 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Esteban=20K=C3=BCber?= Date: Wed, 14 Aug 2019 17:06:09 -0700 Subject: [PATCH 6/9] Further unicode checks --- src/librustc_errors/emitter.rs | 30 ++++++++++++------- .../non-whitespace-trimming-unicode.rs | 6 ++++ .../non-whitespace-trimming-unicode.stderr | 12 ++++++++ 3 files changed, 38 insertions(+), 10 deletions(-) create mode 100644 src/test/ui/terminal-width/non-whitespace-trimming-unicode.rs create mode 100644 src/test/ui/terminal-width/non-whitespace-trimming-unicode.stderr diff --git a/src/librustc_errors/emitter.rs b/src/librustc_errors/emitter.rs index d20e700b355..83c55c0da2b 100644 --- a/src/librustc_errors/emitter.rs +++ b/src/librustc_errors/emitter.rs @@ -148,7 +148,7 @@ impl Margin { self.computed_right = self.computed_left + self.column_width; } else if self.span_right - self.span_left <= self.column_width { // Attempt to fit the code window considering the spans and labels plus padding. - let padding_left = (self.column_width - (self.span_right - self.span_left)) / 2; + let padding_left = (self.column_width - (self.span_right - self.span_left)) / 5 * 2; self.computed_left = self.span_left - padding_left; self.computed_right = self.computed_left + self.column_width; } else { // Mostly give up but still don't show the full line. @@ -365,7 +365,18 @@ impl EmitterWriter { let left = margin.left(line_len); let right = margin.right(line_len); // On long lines, we strip the source line, accounting for unicode. - let code: String = source_string.chars().skip(left).take(right - left).collect(); + let mut taken = 0; + let code: String = source_string.chars().skip(left).take_while(|ch| { + // Make sure that the trimming on the right will fall within the terminal width. + // FIXME: `unicode_width` sometimes disagrees with terminals on how wide a `char` is. + // For now, just accept that sometimes the code line will be longer than desired. + let next = unicode_width::UnicodeWidthChar::width(*ch).unwrap_or(1); + if taken + next > right - left { + return false; + } + taken += next; + true + }).collect(); buffer.puts(line_offset, code_offset, &code, Style::Quotation); if margin.was_cut_left() { // We have stripped some code/whitespace from the beginning, make it clear. @@ -373,12 +384,7 @@ impl EmitterWriter { } if margin.was_cut_right(line_len) { // We have stripped some code after the right-most span end, make it clear we did so. - buffer.puts( - line_offset, - margin.right(line_len) - margin.left(line_len) + code_offset - 3, - "...", - Style::LineNumber, - ); + buffer.puts(line_offset, code_offset + taken - 3, "...", Style::LineNumber); } buffer.puts(line_offset, 0, &self.maybe_anonymized(line_index), Style::LineNumber); @@ -420,6 +426,10 @@ impl EmitterWriter { let line_offset = buffer.num_lines(); let left = margin.left(source_string.len()); // Left trim + // Account for unicode characters of width !=0 that were removed. + let left = source_string.chars().take(left).fold(0, |acc, ch| { + acc + unicode_width::UnicodeWidthChar::width(ch).unwrap_or(1) + }); self.draw_line( buffer, @@ -1465,7 +1475,7 @@ impl EmitterWriter { // ...or trailing spaces. Account for substitutions containing unicode // characters. let sub_len = part.snippet.trim().chars().fold(0, |acc, ch| { - acc + unicode_width::UnicodeWidthChar::width(ch).unwrap_or(0) + acc + unicode_width::UnicodeWidthChar::width(ch).unwrap_or(1) }); let underline_start = (span_start_pos + start) as isize + offset; @@ -1488,7 +1498,7 @@ impl EmitterWriter { // length of the code after substitution let full_sub_len = part.snippet.chars().fold(0, |acc, ch| { - acc + unicode_width::UnicodeWidthChar::width(ch).unwrap_or(0) as isize + acc + unicode_width::UnicodeWidthChar::width(ch).unwrap_or(1) as isize }); // length of the code to be substituted diff --git a/src/test/ui/terminal-width/non-whitespace-trimming-unicode.rs b/src/test/ui/terminal-width/non-whitespace-trimming-unicode.rs new file mode 100644 index 00000000000..8d4d1b16279 --- /dev/null +++ b/src/test/ui/terminal-width/non-whitespace-trimming-unicode.rs @@ -0,0 +1,6 @@ +// ignore-tidy-linelength + +fn main() { + let _: &str = "🦀☀☁☂☃☄★☆☇☈☉☊☋☌☍☎☏☐☑☒☓ ☖☗☘☙☚☛☜☝☞☟☠☡☢☣☤☥☦☧☨☩☪☫☬☭☮☯☰☱☲☳☴☵☶☷☸☹☺☻☼☽☾☿♀♁♂♃♄♅♆♇♏♔♕♖♗♘♙♚♛♜♝♞♟♠♡♢♣♤♥♦♧♨♩♪♫♬♭♮♯♰♱♲♳♴♵♶♷♸♹♺♻♼♽♾♿⚀⚁⚂⚃⚄⚅⚆⚈⚉4🦀☀☁☂☃☄★☆☇☈☉☊☋☌☍☎☏☐☑☒☓☖☗☘☙☚☛☜☝☞☟☠☡☢☣☤☥☦☧☨☩☪☫☬☭☮☯☰☱☲☳☴☵☶☷☸☹☺☻☼☽☾☿♀♁♂♃♄♅♆♇♏♔♕♖♗♘♙♚♛♜♝♞♟♠♡♢♣♤♥♦♧♨♩♪♫♬♭♮♯♰♱♲♳♴♵♶♷♸♹♺♻♼♽♾♿⚀⚁⚂⚃⚄⚅⚆⚈⚉4🦀🦀☁☂☃☄★☆☇☈☉☊☋☌☍☎☏☐☑☒☓☖☗☘☙☚☛☜☝☞☟☠☡☢☣☤☥☦☧☨☩☪☫☬☭☮☯☰☱☲☳☴☵☶☷☸☹☺☻☼☽☾☿♀♁♂♃♄♅♆♇♏♔♕♖♗♘♙♚♛♜♝♞♟♠♡♢♣♤♥♦♧♨♩♪♫♬♭♮♯♰♱♲♳♴♵♶♷♸♹♺♻♼♽♾♿⚀⚁⚂⚃⚄⚅⚆⚈⚉4"; let _: () = 42; let _: &str = "🦀☀☁☂☃☄★☆☇☈☉☊☋☌☍☎☏☐☑☒☓ ☖☗☘☙☚☛☜☝☞☟☠☡☢☣☤☥☦☧☨☩☪☫☬☭☮☯☰☱☲☳☴☵☶☷☸☹☺☻☼☽☾☿♀♁♂♃♄♅♆♇♏♔♕♖♗♘♙♚♛♜♝♞♟♠♡♢♣♤♥♦♧♨♩♪♫♬♭♮♯♰♱♲♳♴♵♶♷♸♹♺♻♼♽♾♿⚀⚁⚂⚃⚄⚅⚆⚈⚉4🦀☀☁☂☃☄★☆☇☈☉☊☋☌☍☎☏☐☑☒☓☖☗☘☙☚☛☜☝☞☟☠☡☢☣☤☥☦☧☨☩☪☫☬☭☮☯☰☱☲☳☴☵☶☷☸☹☺☻☼☽☾☿♀♁♂♃♄♅♆♇♏♔♕♖♗♘♙♚♛♜♝♞♟♠♡♢♣♤♥♦♧♨♩♪♫♬♭♮♯♰♱♲♳♴♵♶♷♸♹♺♻♼♽♾♿⚀⚁⚂⚃⚄⚅⚆⚈⚉4🦀🦀☁☂☃☄★☆☇☈☉☊☋☌☍☎☏☐☑☒☓☖☗☘☙☚☛☜☝☞☟☠☡☢☣☤☥☦☧☨☩☪☫☬☭☮☯☰☱☲☳☴☵☶☷☸☹☺☻☼☽☾☿♀♁♂♃♄♅♆♇♏♔♕♖♗♘♙♚♛♜♝♞♟♠♡♢♣♤♥♦♧♨♩♪♫♬♭♮♯♰♱♲♳♴♵♶♷♸♹♺♻♼♽♾♿⚀⚁⚂⚃⚄⚅⚆⚈⚉4"; +//~^ ERROR mismatched types +} diff --git a/src/test/ui/terminal-width/non-whitespace-trimming-unicode.stderr b/src/test/ui/terminal-width/non-whitespace-trimming-unicode.stderr new file mode 100644 index 00000000000..b56b1948d9e --- /dev/null +++ b/src/test/ui/terminal-width/non-whitespace-trimming-unicode.stderr @@ -0,0 +1,12 @@ +error[E0308]: mismatched types + --> $DIR/non-whitespace-trimming-unicode.rs:4:415 + | +LL | ...♯♰♱♲♳♴♵♶♷♸♹♺♻♼♽♾♿⚀⚁⚂⚃⚄⚅⚆⚈⚉4"; let _: () = 42; let _: &str = "🦀☀☁☂☃☄★☆☇☈☉☊☋☌☍☎☏☐☑☒☓ ☖☗☘☙☚☛☜☝☞☟☠☡☢☣☤☥☦☧☨☩☪☫☬☭☮☯☰☱☲☳☴☵☶☷☸☹☺☻☼☽☾☿♀♁♂♃♄♅♆... + | ^^ expected (), found integer + | + = note: expected type `()` + found type `{integer}` + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0308`. From 21f2e9334567b64436f4e6525c5c98adafd16ca2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Esteban=20K=C3=BCber?= Date: Wed, 14 Aug 2019 17:57:28 -0700 Subject: [PATCH 7/9] Add terminal_width debugging flag --- src/librustc/session/config.rs | 2 ++ src/librustc/session/mod.rs | 6 ++++-- src/librustc_driver/lib.rs | 12 +++++++----- src/librustc_errors/emitter.rs | 24 +++++++++++++++++------- src/librustc_errors/lib.rs | 2 +- src/librustdoc/core.rs | 1 + src/librustdoc/test.rs | 2 +- src/libsyntax/json.rs | 2 +- src/libsyntax/parse/lexer/tests.rs | 9 ++++++++- src/libsyntax/tests.rs | 13 ++++++++----- 10 files changed, 50 insertions(+), 23 deletions(-) diff --git a/src/librustc/session/config.rs b/src/librustc/session/config.rs index 8e3b910e0da..89481e9eafd 100644 --- a/src/librustc/session/config.rs +++ b/src/librustc/session/config.rs @@ -1292,6 +1292,8 @@ options! {DebuggingOptions, DebuggingSetter, basic_debugging_options, "show macro backtraces even for non-local macros"), teach: bool = (false, parse_bool, [TRACKED], "show extended diagnostic help"), + terminal_width: Option = (None, parse_opt_uint, [UNTRACKED], + "set the current terminal width"), continue_parse_after_error: bool = (false, parse_bool, [TRACKED], "attempt to recover from parse errors (experimental)"), dep_tasks: bool = (false, parse_bool, [UNTRACKED], diff --git a/src/librustc/session/mod.rs b/src/librustc/session/mod.rs index 61dac678912..f01883d9634 100644 --- a/src/librustc/session/mod.rs +++ b/src/librustc/session/mod.rs @@ -1055,6 +1055,7 @@ fn default_emitter( Some(source_map.clone()), short, sopts.debugging_opts.teach, + sopts.debugging_opts.terminal_width, ), Some(dst) => EmitterWriter::new( dst, @@ -1062,6 +1063,7 @@ fn default_emitter( short, false, // no teach messages when writing to a buffer false, // no colors when writing to a buffer + None, // no terminal width ), }; Box::new(emitter.ui_testing(sopts.debugging_opts.ui_testing)) @@ -1375,7 +1377,7 @@ pub fn early_error(output: config::ErrorOutputType, msg: &str) -> ! { let emitter: Box = match output { config::ErrorOutputType::HumanReadable(kind) => { let (short, color_config) = kind.unzip(); - Box::new(EmitterWriter::stderr(color_config, None, short, false)) + Box::new(EmitterWriter::stderr(color_config, None, short, false, None)) } config::ErrorOutputType::Json { pretty, json_rendered } => Box::new(JsonEmitter::basic(pretty, json_rendered)), @@ -1389,7 +1391,7 @@ pub fn early_warn(output: config::ErrorOutputType, msg: &str) { let emitter: Box = match output { config::ErrorOutputType::HumanReadable(kind) => { let (short, color_config) = kind.unzip(); - Box::new(EmitterWriter::stderr(color_config, None, short, false)) + Box::new(EmitterWriter::stderr(color_config, None, short, false, None)) } config::ErrorOutputType::Json { pretty, json_rendered } => Box::new(JsonEmitter::basic(pretty, json_rendered)), diff --git a/src/librustc_driver/lib.rs b/src/librustc_driver/lib.rs index b19ea513b75..3d94d51f17e 100644 --- a/src/librustc_driver/lib.rs +++ b/src/librustc_driver/lib.rs @@ -1135,11 +1135,13 @@ pub fn report_ices_to_stderr_if_any R, R>(f: F) -> Result, source_map: Option>, teach: bool, + terminal_width: Option, ) -> EmitterWriter { let (short, color_config) = self.unzip(); - EmitterWriter::new(dst, source_map, short, teach, color_config.suggests_using_colors()) + let color = color_config.suggests_using_colors(); + EmitterWriter::new(dst, source_map, short, teach, color, terminal_width) } } @@ -296,6 +298,7 @@ pub struct EmitterWriter { short_message: bool, teach: bool, ui_testing: bool, + terminal_width: Option, } #[derive(Debug)] @@ -306,11 +309,13 @@ pub struct FileWithAnnotatedLines { } impl EmitterWriter { - pub fn stderr(color_config: ColorConfig, - source_map: Option>, - short_message: bool, - teach: bool) - -> EmitterWriter { + pub fn stderr( + color_config: ColorConfig, + source_map: Option>, + short_message: bool, + teach: bool, + terminal_width: Option, + ) -> EmitterWriter { let dst = Destination::from_stderr(color_config); EmitterWriter { dst, @@ -318,6 +323,7 @@ impl EmitterWriter { short_message, teach, ui_testing: false, + terminal_width, } } @@ -327,6 +333,7 @@ impl EmitterWriter { short_message: bool, teach: bool, colored: bool, + terminal_width: Option, ) -> EmitterWriter { EmitterWriter { dst: Raw(dst, colored), @@ -334,6 +341,7 @@ impl EmitterWriter { short_message, teach, ui_testing: false, + terminal_width, } } @@ -1295,7 +1303,9 @@ impl EmitterWriter { width_offset + annotated_file.multiline_depth + 1 }; - let column_width = if self.ui_testing { + let column_width = if let Some(width) = self.terminal_width { + width + } else if self.ui_testing { 140 } else { term_size::dimensions().map(|(w, _)| w - code_offset).unwrap_or(140) diff --git a/src/librustc_errors/lib.rs b/src/librustc_errors/lib.rs index 4018a667bf2..6585633e00a 100644 --- a/src/librustc_errors/lib.rs +++ b/src/librustc_errors/lib.rs @@ -383,7 +383,7 @@ impl Handler { cm: Option>, flags: HandlerFlags) -> Handler { - let emitter = Box::new(EmitterWriter::stderr(color_config, cm, false, false)); + let emitter = Box::new(EmitterWriter::stderr(color_config, cm, false, false, None)); Handler::with_emitter_and_flags(emitter, flags) } diff --git a/src/librustdoc/core.rs b/src/librustdoc/core.rs index 87381f224d0..98362464771 100644 --- a/src/librustdoc/core.rs +++ b/src/librustdoc/core.rs @@ -193,6 +193,7 @@ pub fn new_handler(error_format: ErrorOutputType, source_map.map(|cm| cm as _), short, sessopts.debugging_opts.teach, + sessopts.debugging_opts.terminal_width, ).ui_testing(ui_testing) ) }, diff --git a/src/librustdoc/test.rs b/src/librustdoc/test.rs index 83a8d3fc109..8db0eb15929 100644 --- a/src/librustdoc/test.rs +++ b/src/librustdoc/test.rs @@ -427,7 +427,7 @@ pub fn make_test(s: &str, // Any errors in parsing should also appear when the doctest is compiled for real, so just // send all the errors that libsyntax emits directly into a `Sink` instead of stderr. let cm = Lrc::new(SourceMap::new(FilePathMapping::empty())); - let emitter = EmitterWriter::new(box io::sink(), None, false, false, false); + let emitter = EmitterWriter::new(box io::sink(), None, false, false, false, None); // FIXME(misdreavus): pass `-Z treat-err-as-bug` to the doctest parser let handler = Handler::with_emitter(false, None, box emitter); let sess = ParseSess::with_span_handler(handler, cm); diff --git a/src/libsyntax/json.rs b/src/libsyntax/json.rs index 83c9c692bd3..ada46f7bc5a 100644 --- a/src/libsyntax/json.rs +++ b/src/libsyntax/json.rs @@ -219,7 +219,7 @@ impl Diagnostic { } let buf = BufWriter::default(); let output = buf.clone(); - je.json_rendered.new_emitter(Box::new(buf), Some(je.sm.clone()), false) + je.json_rendered.new_emitter(Box::new(buf), Some(je.sm.clone()), false, None) .ui_testing(je.ui_testing).emit_diagnostic(db); let output = Arc::try_unwrap(output.0).unwrap().into_inner().unwrap(); let output = String::from_utf8(output).unwrap(); diff --git a/src/libsyntax/parse/lexer/tests.rs b/src/libsyntax/parse/lexer/tests.rs index a915aa42fd1..963ad2c0b8f 100644 --- a/src/libsyntax/parse/lexer/tests.rs +++ b/src/libsyntax/parse/lexer/tests.rs @@ -10,7 +10,14 @@ use errors::{Handler, emitter::EmitterWriter}; use syntax_pos::{BytePos, Span}; fn mk_sess(sm: Lrc) -> ParseSess { - let emitter = EmitterWriter::new(Box::new(io::sink()), Some(sm.clone()), false, false, false); + let emitter = errors::emitter::EmitterWriter::new( + Box::new(io::sink()), + Some(sm.clone()), + false, + false, + false, + None, + ); ParseSess::with_span_handler(Handler::with_emitter(true, None, Box::new(emitter)), sm) } diff --git a/src/libsyntax/tests.rs b/src/libsyntax/tests.rs index 4c0e1e3704d..c472212bc20 100644 --- a/src/libsyntax/tests.rs +++ b/src/libsyntax/tests.rs @@ -144,11 +144,14 @@ fn test_harness(file_text: &str, span_labels: Vec, expected_output: & println!("text: {:?}", source_map.span_to_snippet(span)); } - let emitter = EmitterWriter::new(Box::new(Shared { data: output.clone() }), - Some(source_map.clone()), - false, - false, - false); + let emitter = EmitterWriter::new( + Box::new(Shared { data: output.clone() }), + Some(source_map.clone()), + false, + false, + false, + None, + ); let handler = Handler::with_emitter(true, None, Box::new(emitter)); handler.span_err(msp, "foo"); From cc2272fe879f662bc2623fe6d96b358ed011e382 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Esteban=20K=C3=BCber?= Date: Wed, 21 Aug 2019 12:00:36 -0700 Subject: [PATCH 8/9] Formatting --- src/libsyntax/parse/lexer/tests.rs | 69 +++++++++++++++++++----------- 1 file changed, 45 insertions(+), 24 deletions(-) diff --git a/src/libsyntax/parse/lexer/tests.rs b/src/libsyntax/parse/lexer/tests.rs index 963ad2c0b8f..6faaa01321d 100644 --- a/src/libsyntax/parse/lexer/tests.rs +++ b/src/libsyntax/parse/lexer/tests.rs @@ -35,10 +35,11 @@ fn t1() { with_default_globals(|| { let sm = Lrc::new(SourceMap::new(FilePathMapping::empty())); let sh = mk_sess(sm.clone()); - let mut string_reader = setup(&sm, - &sh, - "/* my source file */ fn main() { println!(\"zebra\"); }\n" - .to_string()); + let mut string_reader = setup( + &sm, + &sh, + "/* my source file */ fn main() { println!(\"zebra\"); }\n".to_string(), + ); assert_eq!(string_reader.next_token(), token::Comment); assert_eq!(string_reader.next_token(), token::Whitespace); let tok1 = string_reader.next_token(); @@ -134,8 +135,10 @@ fn character_a() { with_default_globals(|| { let sm = Lrc::new(SourceMap::new(FilePathMapping::empty())); let sh = mk_sess(sm.clone()); - assert_eq!(setup(&sm, &sh, "'a'".to_string()).next_token(), - mk_lit(token::Char, "a", None)); + assert_eq!( + setup(&sm, &sh, "'a'".to_string()).next_token(), + mk_lit(token::Char, "a", None), + ); }) } @@ -144,8 +147,10 @@ fn character_space() { with_default_globals(|| { let sm = Lrc::new(SourceMap::new(FilePathMapping::empty())); let sh = mk_sess(sm.clone()); - assert_eq!(setup(&sm, &sh, "' '".to_string()).next_token(), - mk_lit(token::Char, " ", None)); + assert_eq!( + setup(&sm, &sh, "' '".to_string()).next_token(), + mk_lit(token::Char, " ", None), + ); }) } @@ -154,8 +159,10 @@ fn character_escaped() { with_default_globals(|| { let sm = Lrc::new(SourceMap::new(FilePathMapping::empty())); let sh = mk_sess(sm.clone()); - assert_eq!(setup(&sm, &sh, "'\\n'".to_string()).next_token(), - mk_lit(token::Char, "\\n", None)); + assert_eq!( + setup(&sm, &sh, "'\\n'".to_string()).next_token(), + mk_lit(token::Char, "\\n", None), + ); }) } @@ -164,8 +171,10 @@ fn lifetime_name() { with_default_globals(|| { let sm = Lrc::new(SourceMap::new(FilePathMapping::empty())); let sh = mk_sess(sm.clone()); - assert_eq!(setup(&sm, &sh, "'abc".to_string()).next_token(), - token::Lifetime(Symbol::intern("'abc"))); + assert_eq!( + setup(&sm, &sh, "'abc".to_string()).next_token(), + token::Lifetime(Symbol::intern("'abc")), + ); }) } @@ -174,8 +183,10 @@ fn raw_string() { with_default_globals(|| { let sm = Lrc::new(SourceMap::new(FilePathMapping::empty())); let sh = mk_sess(sm.clone()); - assert_eq!(setup(&sm, &sh, "r###\"\"#a\\b\x00c\"\"###".to_string()).next_token(), - mk_lit(token::StrRaw(3), "\"#a\\b\x00c\"", None)); + assert_eq!( + setup(&sm, &sh, "r###\"\"#a\\b\x00c\"\"###".to_string()).next_token(), + mk_lit(token::StrRaw(3), "\"#a\\b\x00c\"", None), + ); }) } @@ -186,11 +197,15 @@ fn literal_suffixes() { let sh = mk_sess(sm.clone()); macro_rules! test { ($input: expr, $tok_type: ident, $tok_contents: expr) => {{ - assert_eq!(setup(&sm, &sh, format!("{}suffix", $input)).next_token(), - mk_lit(token::$tok_type, $tok_contents, Some("suffix"))); + assert_eq!( + setup(&sm, &sh, format!("{}suffix", $input)).next_token(), + mk_lit(token::$tok_type, $tok_contents, Some("suffix")), + ); // with a whitespace separator: - assert_eq!(setup(&sm, &sh, format!("{} suffix", $input)).next_token(), - mk_lit(token::$tok_type, $tok_contents, None)); + assert_eq!( + setup(&sm, &sh, format!("{} suffix", $input)).next_token(), + mk_lit(token::$tok_type, $tok_contents, None), + ); }} } @@ -204,12 +219,18 @@ fn literal_suffixes() { test!("1.0", Float, "1.0"); test!("1.0e10", Float, "1.0e10"); - assert_eq!(setup(&sm, &sh, "2us".to_string()).next_token(), - mk_lit(token::Integer, "2", Some("us"))); - assert_eq!(setup(&sm, &sh, "r###\"raw\"###suffix".to_string()).next_token(), - mk_lit(token::StrRaw(3), "raw", Some("suffix"))); - assert_eq!(setup(&sm, &sh, "br###\"raw\"###suffix".to_string()).next_token(), - mk_lit(token::ByteStrRaw(3), "raw", Some("suffix"))); + assert_eq!( + setup(&sm, &sh, "2us".to_string()).next_token(), + mk_lit(token::Integer, "2", Some("us")), + ); + assert_eq!( + setup(&sm, &sh, "r###\"raw\"###suffix".to_string()).next_token(), + mk_lit(token::StrRaw(3), "raw", Some("suffix")), + ); + assert_eq!( + setup(&sm, &sh, "br###\"raw\"###suffix".to_string()).next_token(), + mk_lit(token::ByteStrRaw(3), "raw", Some("suffix")), + ); }) } From aaf4dc35e33eea8b658b82a307b81e63e8b214f4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Esteban=20K=C3=BCber?= Date: Wed, 21 Aug 2019 14:26:52 -0700 Subject: [PATCH 9/9] fix rebase --- src/libsyntax/parse/lexer/tests.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/libsyntax/parse/lexer/tests.rs b/src/libsyntax/parse/lexer/tests.rs index 6faaa01321d..652ae95c853 100644 --- a/src/libsyntax/parse/lexer/tests.rs +++ b/src/libsyntax/parse/lexer/tests.rs @@ -10,7 +10,7 @@ use errors::{Handler, emitter::EmitterWriter}; use syntax_pos::{BytePos, Span}; fn mk_sess(sm: Lrc) -> ParseSess { - let emitter = errors::emitter::EmitterWriter::new( + let emitter = EmitterWriter::new( Box::new(io::sink()), Some(sm.clone()), false,