Skip to content

Commit ad36c2f

Browse files
committed
Auto merge of #41136 - estebank:multiline, r=jonathandturner
Always show end line of multiline annotations ```rust error[E0046]: not all trait items implemented, missing: `Item` --> $DIR/issue-23729.rs:20:9 | 20 | impl Iterator for Recurrence { | _________^ starting here... 21 | | //~^ ERROR E0046 22 | | //~| NOTE missing `Item` in implementation 23 | | //~| NOTE `Item` from trait: `type Item;` ... | 36 | | } 37 | | } | |_________^ ...ending here: missing `Item` in implementation | = note: `Item` from trait: `type Item;` ``` instead of ```rust error[E0046]: not all trait items implemented, missing: `Item` --> $DIR/issue-23729.rs:20:9 | 20 | impl Iterator for Recurrence { | ^ missing `Item` in implementation | = note: `Item` from trait: `type Item;` ```
2 parents d616f47 + 4bc7f5b commit ad36c2f

File tree

6 files changed

+269
-97
lines changed

6 files changed

+269
-97
lines changed

src/librustc_errors/emitter.rs

+119-77
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,8 @@ use std::io::prelude::*;
2121
use std::io;
2222
use std::rc::Rc;
2323
use term;
24+
use std::collections::HashMap;
25+
use std::cmp::min;
2426

2527
/// Emitter trait for emitting errors.
2628
pub trait Emitter {
@@ -156,15 +158,6 @@ impl EmitterWriter {
156158
}
157159
let lo = cm.lookup_char_pos(span_label.span.lo);
158160
let mut hi = cm.lookup_char_pos(span_label.span.hi);
159-
let mut is_minimized = false;
160-
161-
// If the span is long multi-line, simplify down to the span of one character
162-
let max_multiline_span_length = 8;
163-
if lo.line != hi.line && (hi.line - lo.line) > max_multiline_span_length {
164-
hi.line = lo.line;
165-
hi.col = CharPos(lo.col.0 + 1);
166-
is_minimized = true;
167-
}
168161

169162
// Watch out for "empty spans". If we get a span like 6..6, we
170163
// want to just display a `^` at 6, so convert that to
@@ -175,16 +168,7 @@ impl EmitterWriter {
175168
hi.col = CharPos(lo.col.0 + 1);
176169
}
177170

178-
let mut ann = Annotation {
179-
start_col: lo.col.0,
180-
end_col: hi.col.0,
181-
is_primary: span_label.is_primary,
182-
label: span_label.label.clone(),
183-
annotation_type: AnnotationType::Singleline,
184-
};
185-
if is_minimized {
186-
ann.annotation_type = AnnotationType::Minimized;
187-
} else if lo.line != hi.line {
171+
let ann_type = if lo.line != hi.line {
188172
let ml = MultilineAnnotation {
189173
depth: 1,
190174
line_start: lo.line,
@@ -194,8 +178,17 @@ impl EmitterWriter {
194178
is_primary: span_label.is_primary,
195179
label: span_label.label.clone(),
196180
};
197-
ann.annotation_type = AnnotationType::Multiline(ml.clone());
198-
multiline_annotations.push((lo.file.clone(), ml));
181+
multiline_annotations.push((lo.file.clone(), ml.clone()));
182+
AnnotationType::Multiline(ml)
183+
} else {
184+
AnnotationType::Singleline
185+
};
186+
let ann = Annotation {
187+
start_col: lo.col.0,
188+
end_col: hi.col.0,
189+
is_primary: span_label.is_primary,
190+
label: span_label.label.clone(),
191+
annotation_type: ann_type,
199192
};
200193

201194
if !ann.is_multiline() {
@@ -233,9 +226,15 @@ impl EmitterWriter {
233226
max_depth = ann.depth;
234227
}
235228
add_annotation_to_file(&mut output, file.clone(), ann.line_start, ann.as_start());
236-
for line in ann.line_start + 1..ann.line_end {
229+
let middle = min(ann.line_start + 4, ann.line_end);
230+
for line in ann.line_start + 1..middle {
237231
add_annotation_to_file(&mut output, file.clone(), line, ann.as_line());
238232
}
233+
if middle < ann.line_end - 1 {
234+
for line in ann.line_end - 1..ann.line_end {
235+
add_annotation_to_file(&mut output, file.clone(), line, ann.as_line());
236+
}
237+
}
239238
add_annotation_to_file(&mut output, file, ann.line_end, ann.as_end());
240239
}
241240
for file_vec in output.iter_mut() {
@@ -249,16 +248,11 @@ impl EmitterWriter {
249248
file: Rc<FileMap>,
250249
line: &Line,
251250
width_offset: usize,
252-
multiline_depth: usize) {
251+
code_offset: usize) -> Vec<(usize, Style)> {
253252
let source_string = file.get_line(line.line_index - 1)
254253
.unwrap_or("");
255254

256255
let line_offset = buffer.num_lines();
257-
let code_offset = if multiline_depth == 0 {
258-
width_offset
259-
} else {
260-
width_offset + multiline_depth + 1
261-
};
262256

263257
// First create the source line we will highlight.
264258
buffer.puts(line_offset, code_offset, &source_string, Style::Quotation);
@@ -286,7 +280,7 @@ impl EmitterWriter {
286280
// previous borrow of `vec` occurs here
287281
//
288282
// For this reason, we group the lines into "highlight lines"
289-
// and "annotations lines", where the highlight lines have the `~`.
283+
// and "annotations lines", where the highlight lines have the `^`.
290284

291285
// Sort the annotations by (start, end col)
292286
let mut annotations = line.annotations.clone();
@@ -410,25 +404,9 @@ impl EmitterWriter {
410404
// If there are no annotations or the only annotations on this line are
411405
// MultilineLine, then there's only code being shown, stop processing.
412406
if line.annotations.is_empty() || line.annotations.iter()
413-
.filter(|a| {
414-
// Set the multiline annotation vertical lines to the left of
415-
// the code in this line.
416-
if let AnnotationType::MultilineLine(depth) = a.annotation_type {
417-
buffer.putc(line_offset,
418-
width_offset + depth - 1,
419-
'|',
420-
if a.is_primary {
421-
Style::UnderlinePrimary
422-
} else {
423-
Style::UnderlineSecondary
424-
});
425-
false
426-
} else {
427-
true
428-
}
429-
}).collect::<Vec<_>>().len() == 0
407+
.filter(|a| !a.is_line()).collect::<Vec<_>>().len() == 0
430408
{
431-
return;
409+
return vec![];
432410
}
433411

434412
// Write the colunmn separator.
@@ -483,16 +461,15 @@ impl EmitterWriter {
483461
}
484462
}
485463

486-
// Write the vertical lines for multiline spans and for labels that are
487-
// on a different line as the underline.
464+
// Write the vertical lines for labels that are on a different line as the underline.
488465
//
489466
// After this we will have:
490467
//
491468
// 2 | fn foo() {
492469
// | __________
493470
// | | |
494471
// | |
495-
// 3 | |
472+
// 3 |
496473
// 4 | | }
497474
// | |_
498475
for &(pos, annotation) in &annotations_position {
@@ -528,16 +505,6 @@ impl EmitterWriter {
528505
style);
529506
}
530507
}
531-
AnnotationType::MultilineLine(depth) => {
532-
// the first line will have already be filled when we checked
533-
// wether there were any annotations for this line.
534-
for p in line_offset + 1..line_offset + line_len + 2 {
535-
buffer.putc(p,
536-
width_offset + depth - 1,
537-
'|',
538-
style);
539-
}
540-
}
541508
_ => (),
542509
}
543510
}
@@ -548,11 +515,11 @@ impl EmitterWriter {
548515
//
549516
// 2 | fn foo() {
550517
// | __________ starting here...
551-
// | | |
552-
// | | something about `foo`
553-
// 3 | |
554-
// 4 | | }
555-
// | |_ ...ending here: test
518+
// | |
519+
// | something about `foo`
520+
// 3 |
521+
// 4 | }
522+
// | _ ...ending here: test
556523
for &(pos, annotation) in &annotations_position {
557524
let style = if annotation.is_primary {
558525
Style::LabelPrimary
@@ -591,11 +558,11 @@ impl EmitterWriter {
591558
//
592559
// 2 | fn foo() {
593560
// | ____-_____^ starting here...
594-
// | | |
595-
// | | something about `foo`
596-
// 3 | |
597-
// 4 | | }
598-
// | |_^ ...ending here: test
561+
// | |
562+
// | something about `foo`
563+
// 3 |
564+
// 4 | }
565+
// | _^ ...ending here: test
599566
for &(_, annotation) in &annotations_position {
600567
let (underline, style) = if annotation.is_primary {
601568
('^', Style::UnderlinePrimary)
@@ -609,6 +576,20 @@ impl EmitterWriter {
609576
style);
610577
}
611578
}
579+
annotations_position.iter().filter_map(|&(_, annotation)| {
580+
match annotation.annotation_type {
581+
AnnotationType::MultilineStart(p) | AnnotationType::MultilineEnd(p) => {
582+
let style = if annotation.is_primary {
583+
Style::LabelPrimary
584+
} else {
585+
Style::LabelSecondary
586+
};
587+
Some((p, style))
588+
},
589+
_ => None
590+
}
591+
592+
}).collect::<Vec<_>>()
612593
}
613594

614595
fn get_multispan_max_line_num(&mut self, msp: &MultiSpan) -> usize {
@@ -902,22 +883,64 @@ impl EmitterWriter {
902883
let buffer_msg_line_offset = buffer.num_lines();
903884
draw_col_separator_no_space(&mut buffer, buffer_msg_line_offset, max_line_num_len + 1);
904885

886+
// Contains the vertical lines' positions for active multiline annotations
887+
let mut multilines = HashMap::new();
888+
905889
// Next, output the annotate source for this file
906890
for line_idx in 0..annotated_file.lines.len() {
907-
self.render_source_line(&mut buffer,
908-
annotated_file.file.clone(),
909-
&annotated_file.lines[line_idx],
910-
3 + max_line_num_len,
911-
annotated_file.multiline_depth);
891+
let previous_buffer_line = buffer.num_lines();
892+
893+
let width_offset = 3 + max_line_num_len;
894+
let code_offset = if annotated_file.multiline_depth == 0 {
895+
width_offset
896+
} else {
897+
width_offset + annotated_file.multiline_depth + 1
898+
};
899+
900+
let depths = self.render_source_line(&mut buffer,
901+
annotated_file.file.clone(),
902+
&annotated_file.lines[line_idx],
903+
width_offset,
904+
code_offset);
912905

906+
let mut to_add = HashMap::new();
907+
908+
for (depth, style) in depths {
909+
if multilines.get(&depth).is_some() {
910+
multilines.remove(&depth);
911+
} else {
912+
to_add.insert(depth, style);
913+
}
914+
}
915+
916+
// Set the multiline annotation vertical lines to the left of
917+
// the code in this line.
918+
for (depth, style) in &multilines {
919+
for line in previous_buffer_line..buffer.num_lines() {
920+
draw_multiline_line(&mut buffer,
921+
line,
922+
width_offset,
923+
*depth,
924+
*style);
925+
}
926+
}
913927
// check to see if we need to print out or elide lines that come between
914-
// this annotated line and the next one
928+
// this annotated line and the next one.
915929
if line_idx < (annotated_file.lines.len() - 1) {
916930
let line_idx_delta = annotated_file.lines[line_idx + 1].line_index -
917931
annotated_file.lines[line_idx].line_index;
918932
if line_idx_delta > 2 {
919933
let last_buffer_line_num = buffer.num_lines();
920934
buffer.puts(last_buffer_line_num, 0, "...", Style::LineNumber);
935+
936+
// Set the multiline annotation vertical lines on `...` bridging line.
937+
for (depth, style) in &multilines {
938+
draw_multiline_line(&mut buffer,
939+
last_buffer_line_num,
940+
width_offset,
941+
*depth,
942+
*style);
943+
}
921944
} else if line_idx_delta == 2 {
922945
let unannotated_line = annotated_file.file
923946
.get_line(annotated_file.lines[line_idx].line_index)
@@ -932,11 +955,21 @@ impl EmitterWriter {
932955
Style::LineNumber);
933956
draw_col_separator(&mut buffer, last_buffer_line_num, 1 + max_line_num_len);
934957
buffer.puts(last_buffer_line_num,
935-
3 + max_line_num_len,
958+
code_offset,
936959
&unannotated_line,
937960
Style::Quotation);
961+
962+
for (depth, style) in &multilines {
963+
draw_multiline_line(&mut buffer,
964+
last_buffer_line_num,
965+
width_offset,
966+
*depth,
967+
*style);
968+
}
938969
}
939970
}
971+
972+
multilines.extend(&to_add);
940973
}
941974
}
942975

@@ -1085,6 +1118,15 @@ fn draw_note_separator(buffer: &mut StyledBuffer, line: usize, col: usize) {
10851118
buffer.puts(line, col, "= ", Style::LineNumber);
10861119
}
10871120

1121+
fn draw_multiline_line(buffer: &mut StyledBuffer,
1122+
line: usize,
1123+
offset: usize,
1124+
depth: usize,
1125+
style: Style)
1126+
{
1127+
buffer.putc(line, offset + depth - 1, '|', style);
1128+
}
1129+
10881130
fn num_overlap(a_start: usize, a_end: usize, b_start: usize, b_end:usize, inclusive: bool) -> bool {
10891131
let extra = if inclusive {
10901132
1

src/librustc_errors/snippet.rs

+3-10
Original file line numberDiff line numberDiff line change
@@ -97,9 +97,6 @@ pub enum AnnotationType {
9797
/// Annotation under a single line of code
9898
Singleline,
9999

100-
/// Annotation under the first character of a multiline span
101-
Minimized,
102-
103100
/// Annotation enclosing the first and last character of a multiline span
104101
Multiline(MultilineAnnotation),
105102

@@ -118,6 +115,9 @@ pub enum AnnotationType {
118115
/// Annotation marking the last character of a fully shown multiline span
119116
MultilineEnd(usize),
120117
/// Line at the left enclosing the lines of a fully shown multiline span
118+
// Just a placeholder for the drawing algorithm, to know that it shouldn't skip the first 4
119+
// and last 2 lines of code. The actual line is drawn in `emit_message_default` and not in
120+
// `draw_multiline_line`.
121121
MultilineLine(usize),
122122
}
123123

@@ -144,13 +144,6 @@ pub struct Annotation {
144144
}
145145

146146
impl Annotation {
147-
pub fn is_minimized(&self) -> bool {
148-
match self.annotation_type {
149-
AnnotationType::Minimized => true,
150-
_ => false,
151-
}
152-
}
153-
154147
/// Wether this annotation is a vertical line placeholder.
155148
pub fn is_line(&self) -> bool {
156149
if let AnnotationType::MultilineLine(_) = self.annotation_type {

0 commit comments

Comments
 (0)