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;` ```
This commit is contained in:
parent
9e84bf8096
commit
4bc7f5b52c
@ -21,6 +21,8 @@
|
||||
use std::io;
|
||||
use std::rc::Rc;
|
||||
use term;
|
||||
use std::collections::HashMap;
|
||||
use std::cmp::min;
|
||||
|
||||
/// Emitter trait for emitting errors.
|
||||
pub trait Emitter {
|
||||
@ -156,15 +158,6 @@ fn add_annotation_to_file(file_vec: &mut Vec<FileWithAnnotatedLines>,
|
||||
}
|
||||
let lo = cm.lookup_char_pos(span_label.span.lo);
|
||||
let mut hi = cm.lookup_char_pos(span_label.span.hi);
|
||||
let mut is_minimized = false;
|
||||
|
||||
// If the span is long multi-line, simplify down to the span of one character
|
||||
let max_multiline_span_length = 8;
|
||||
if lo.line != hi.line && (hi.line - lo.line) > max_multiline_span_length {
|
||||
hi.line = lo.line;
|
||||
hi.col = CharPos(lo.col.0 + 1);
|
||||
is_minimized = true;
|
||||
}
|
||||
|
||||
// Watch out for "empty spans". If we get a span like 6..6, we
|
||||
// want to just display a `^` at 6, so convert that to
|
||||
@ -175,16 +168,7 @@ fn add_annotation_to_file(file_vec: &mut Vec<FileWithAnnotatedLines>,
|
||||
hi.col = CharPos(lo.col.0 + 1);
|
||||
}
|
||||
|
||||
let mut ann = Annotation {
|
||||
start_col: lo.col.0,
|
||||
end_col: hi.col.0,
|
||||
is_primary: span_label.is_primary,
|
||||
label: span_label.label.clone(),
|
||||
annotation_type: AnnotationType::Singleline,
|
||||
};
|
||||
if is_minimized {
|
||||
ann.annotation_type = AnnotationType::Minimized;
|
||||
} else if lo.line != hi.line {
|
||||
let ann_type = if lo.line != hi.line {
|
||||
let ml = MultilineAnnotation {
|
||||
depth: 1,
|
||||
line_start: lo.line,
|
||||
@ -194,8 +178,17 @@ fn add_annotation_to_file(file_vec: &mut Vec<FileWithAnnotatedLines>,
|
||||
is_primary: span_label.is_primary,
|
||||
label: span_label.label.clone(),
|
||||
};
|
||||
ann.annotation_type = AnnotationType::Multiline(ml.clone());
|
||||
multiline_annotations.push((lo.file.clone(), ml));
|
||||
multiline_annotations.push((lo.file.clone(), ml.clone()));
|
||||
AnnotationType::Multiline(ml)
|
||||
} else {
|
||||
AnnotationType::Singleline
|
||||
};
|
||||
let ann = Annotation {
|
||||
start_col: lo.col.0,
|
||||
end_col: hi.col.0,
|
||||
is_primary: span_label.is_primary,
|
||||
label: span_label.label.clone(),
|
||||
annotation_type: ann_type,
|
||||
};
|
||||
|
||||
if !ann.is_multiline() {
|
||||
@ -233,9 +226,15 @@ fn add_annotation_to_file(file_vec: &mut Vec<FileWithAnnotatedLines>,
|
||||
max_depth = ann.depth;
|
||||
}
|
||||
add_annotation_to_file(&mut output, file.clone(), ann.line_start, ann.as_start());
|
||||
for line in ann.line_start + 1..ann.line_end {
|
||||
let middle = min(ann.line_start + 4, ann.line_end);
|
||||
for line in ann.line_start + 1..middle {
|
||||
add_annotation_to_file(&mut output, file.clone(), line, ann.as_line());
|
||||
}
|
||||
if middle < ann.line_end - 1 {
|
||||
for line in ann.line_end - 1..ann.line_end {
|
||||
add_annotation_to_file(&mut output, file.clone(), line, ann.as_line());
|
||||
}
|
||||
}
|
||||
add_annotation_to_file(&mut output, file, ann.line_end, ann.as_end());
|
||||
}
|
||||
for file_vec in output.iter_mut() {
|
||||
@ -249,16 +248,11 @@ fn render_source_line(&self,
|
||||
file: Rc<FileMap>,
|
||||
line: &Line,
|
||||
width_offset: usize,
|
||||
multiline_depth: usize) {
|
||||
code_offset: usize) -> Vec<(usize, Style)> {
|
||||
let source_string = file.get_line(line.line_index - 1)
|
||||
.unwrap_or("");
|
||||
|
||||
let line_offset = buffer.num_lines();
|
||||
let code_offset = if multiline_depth == 0 {
|
||||
width_offset
|
||||
} else {
|
||||
width_offset + multiline_depth + 1
|
||||
};
|
||||
|
||||
// First create the source line we will highlight.
|
||||
buffer.puts(line_offset, code_offset, &source_string, Style::Quotation);
|
||||
@ -286,7 +280,7 @@ fn render_source_line(&self,
|
||||
// previous borrow of `vec` occurs here
|
||||
//
|
||||
// For this reason, we group the lines into "highlight lines"
|
||||
// and "annotations lines", where the highlight lines have the `~`.
|
||||
// and "annotations lines", where the highlight lines have the `^`.
|
||||
|
||||
// Sort the annotations by (start, end col)
|
||||
let mut annotations = line.annotations.clone();
|
||||
@ -410,25 +404,9 @@ fn render_source_line(&self,
|
||||
// If there are no annotations or the only annotations on this line are
|
||||
// MultilineLine, then there's only code being shown, stop processing.
|
||||
if line.annotations.is_empty() || line.annotations.iter()
|
||||
.filter(|a| {
|
||||
// Set the multiline annotation vertical lines to the left of
|
||||
// the code in this line.
|
||||
if let AnnotationType::MultilineLine(depth) = a.annotation_type {
|
||||
buffer.putc(line_offset,
|
||||
width_offset + depth - 1,
|
||||
'|',
|
||||
if a.is_primary {
|
||||
Style::UnderlinePrimary
|
||||
} else {
|
||||
Style::UnderlineSecondary
|
||||
});
|
||||
false
|
||||
} else {
|
||||
true
|
||||
}
|
||||
}).collect::<Vec<_>>().len() == 0
|
||||
.filter(|a| !a.is_line()).collect::<Vec<_>>().len() == 0
|
||||
{
|
||||
return;
|
||||
return vec![];
|
||||
}
|
||||
|
||||
// Write the colunmn separator.
|
||||
@ -483,8 +461,7 @@ fn render_source_line(&self,
|
||||
}
|
||||
}
|
||||
|
||||
// Write the vertical lines for multiline spans and for labels that are
|
||||
// on a different line as the underline.
|
||||
// Write the vertical lines for labels that are on a different line as the underline.
|
||||
//
|
||||
// After this we will have:
|
||||
//
|
||||
@ -492,7 +469,7 @@ fn render_source_line(&self,
|
||||
// | __________
|
||||
// | | |
|
||||
// | |
|
||||
// 3 | |
|
||||
// 3 |
|
||||
// 4 | | }
|
||||
// | |_
|
||||
for &(pos, annotation) in &annotations_position {
|
||||
@ -528,16 +505,6 @@ fn render_source_line(&self,
|
||||
style);
|
||||
}
|
||||
}
|
||||
AnnotationType::MultilineLine(depth) => {
|
||||
// the first line will have already be filled when we checked
|
||||
// wether there were any annotations for this line.
|
||||
for p in line_offset + 1..line_offset + line_len + 2 {
|
||||
buffer.putc(p,
|
||||
width_offset + depth - 1,
|
||||
'|',
|
||||
style);
|
||||
}
|
||||
}
|
||||
_ => (),
|
||||
}
|
||||
}
|
||||
@ -548,11 +515,11 @@ fn render_source_line(&self,
|
||||
//
|
||||
// 2 | fn foo() {
|
||||
// | __________ starting here...
|
||||
// | | |
|
||||
// | | something about `foo`
|
||||
// 3 | |
|
||||
// 4 | | }
|
||||
// | |_ ...ending here: test
|
||||
// | |
|
||||
// | something about `foo`
|
||||
// 3 |
|
||||
// 4 | }
|
||||
// | _ ...ending here: test
|
||||
for &(pos, annotation) in &annotations_position {
|
||||
let style = if annotation.is_primary {
|
||||
Style::LabelPrimary
|
||||
@ -591,11 +558,11 @@ fn render_source_line(&self,
|
||||
//
|
||||
// 2 | fn foo() {
|
||||
// | ____-_____^ starting here...
|
||||
// | | |
|
||||
// | | something about `foo`
|
||||
// 3 | |
|
||||
// 4 | | }
|
||||
// | |_^ ...ending here: test
|
||||
// | |
|
||||
// | something about `foo`
|
||||
// 3 |
|
||||
// 4 | }
|
||||
// | _^ ...ending here: test
|
||||
for &(_, annotation) in &annotations_position {
|
||||
let (underline, style) = if annotation.is_primary {
|
||||
('^', Style::UnderlinePrimary)
|
||||
@ -609,6 +576,20 @@ fn render_source_line(&self,
|
||||
style);
|
||||
}
|
||||
}
|
||||
annotations_position.iter().filter_map(|&(_, annotation)| {
|
||||
match annotation.annotation_type {
|
||||
AnnotationType::MultilineStart(p) | AnnotationType::MultilineEnd(p) => {
|
||||
let style = if annotation.is_primary {
|
||||
Style::LabelPrimary
|
||||
} else {
|
||||
Style::LabelSecondary
|
||||
};
|
||||
Some((p, style))
|
||||
},
|
||||
_ => None
|
||||
}
|
||||
|
||||
}).collect::<Vec<_>>()
|
||||
}
|
||||
|
||||
fn get_multispan_max_line_num(&mut self, msp: &MultiSpan) -> usize {
|
||||
@ -902,22 +883,64 @@ fn emit_message_default(&mut self,
|
||||
let buffer_msg_line_offset = buffer.num_lines();
|
||||
draw_col_separator_no_space(&mut buffer, buffer_msg_line_offset, max_line_num_len + 1);
|
||||
|
||||
// Contains the vertical lines' positions for active multiline annotations
|
||||
let mut multilines = HashMap::new();
|
||||
|
||||
// Next, output the annotate source for this file
|
||||
for line_idx in 0..annotated_file.lines.len() {
|
||||
self.render_source_line(&mut buffer,
|
||||
annotated_file.file.clone(),
|
||||
&annotated_file.lines[line_idx],
|
||||
3 + max_line_num_len,
|
||||
annotated_file.multiline_depth);
|
||||
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(),
|
||||
&annotated_file.lines[line_idx],
|
||||
width_offset,
|
||||
code_offset);
|
||||
|
||||
let mut to_add = HashMap::new();
|
||||
|
||||
for (depth, style) in depths {
|
||||
if multilines.get(&depth).is_some() {
|
||||
multilines.remove(&depth);
|
||||
} else {
|
||||
to_add.insert(depth, style);
|
||||
}
|
||||
}
|
||||
|
||||
// Set the multiline annotation vertical lines to the left of
|
||||
// the code in this line.
|
||||
for (depth, style) in &multilines {
|
||||
for line in previous_buffer_line..buffer.num_lines() {
|
||||
draw_multiline_line(&mut buffer,
|
||||
line,
|
||||
width_offset,
|
||||
*depth,
|
||||
*style);
|
||||
}
|
||||
}
|
||||
// check to see if we need to print out or elide lines that come between
|
||||
// this annotated line and the next one
|
||||
// this annotated line and the next one.
|
||||
if line_idx < (annotated_file.lines.len() - 1) {
|
||||
let line_idx_delta = annotated_file.lines[line_idx + 1].line_index -
|
||||
annotated_file.lines[line_idx].line_index;
|
||||
if line_idx_delta > 2 {
|
||||
let last_buffer_line_num = buffer.num_lines();
|
||||
buffer.puts(last_buffer_line_num, 0, "...", Style::LineNumber);
|
||||
|
||||
// Set the multiline annotation vertical lines on `...` bridging line.
|
||||
for (depth, style) in &multilines {
|
||||
draw_multiline_line(&mut buffer,
|
||||
last_buffer_line_num,
|
||||
width_offset,
|
||||
*depth,
|
||||
*style);
|
||||
}
|
||||
} else if line_idx_delta == 2 {
|
||||
let unannotated_line = annotated_file.file
|
||||
.get_line(annotated_file.lines[line_idx].line_index)
|
||||
@ -932,11 +955,21 @@ fn emit_message_default(&mut self,
|
||||
Style::LineNumber);
|
||||
draw_col_separator(&mut buffer, last_buffer_line_num, 1 + max_line_num_len);
|
||||
buffer.puts(last_buffer_line_num,
|
||||
3 + max_line_num_len,
|
||||
code_offset,
|
||||
&unannotated_line,
|
||||
Style::Quotation);
|
||||
|
||||
for (depth, style) in &multilines {
|
||||
draw_multiline_line(&mut buffer,
|
||||
last_buffer_line_num,
|
||||
width_offset,
|
||||
*depth,
|
||||
*style);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
multilines.extend(&to_add);
|
||||
}
|
||||
}
|
||||
|
||||
@ -1085,6 +1118,15 @@ fn draw_note_separator(buffer: &mut StyledBuffer, line: usize, col: usize) {
|
||||
buffer.puts(line, col, "= ", Style::LineNumber);
|
||||
}
|
||||
|
||||
fn draw_multiline_line(buffer: &mut StyledBuffer,
|
||||
line: usize,
|
||||
offset: usize,
|
||||
depth: usize,
|
||||
style: Style)
|
||||
{
|
||||
buffer.putc(line, offset + depth - 1, '|', style);
|
||||
}
|
||||
|
||||
fn num_overlap(a_start: usize, a_end: usize, b_start: usize, b_end:usize, inclusive: bool) -> bool {
|
||||
let extra = if inclusive {
|
||||
1
|
||||
|
@ -97,9 +97,6 @@ pub enum AnnotationType {
|
||||
/// Annotation under a single line of code
|
||||
Singleline,
|
||||
|
||||
/// Annotation under the first character of a multiline span
|
||||
Minimized,
|
||||
|
||||
/// Annotation enclosing the first and last character of a multiline span
|
||||
Multiline(MultilineAnnotation),
|
||||
|
||||
@ -118,6 +115,9 @@ pub enum AnnotationType {
|
||||
/// Annotation marking the last character of a fully shown multiline span
|
||||
MultilineEnd(usize),
|
||||
/// Line at the left enclosing the lines of a fully shown multiline span
|
||||
// Just a placeholder for the drawing algorithm, to know that it shouldn't skip the first 4
|
||||
// and last 2 lines of code. The actual line is drawn in `emit_message_default` and not in
|
||||
// `draw_multiline_line`.
|
||||
MultilineLine(usize),
|
||||
}
|
||||
|
||||
@ -144,13 +144,6 @@ pub struct Annotation {
|
||||
}
|
||||
|
||||
impl Annotation {
|
||||
pub fn is_minimized(&self) -> bool {
|
||||
match self.annotation_type {
|
||||
AnnotationType::Minimized => true,
|
||||
_ => false,
|
||||
}
|
||||
}
|
||||
|
||||
/// Wether this annotation is a vertical line placeholder.
|
||||
pub fn is_line(&self) -> bool {
|
||||
if let AnnotationType::MultilineLine(_) = self.annotation_type {
|
||||
|
@ -932,3 +932,137 @@ fn foo() {
|
||||
|
||||
"#);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn long_snippet() {
|
||||
test_harness(r#"
|
||||
fn foo() {
|
||||
X0 Y0 Z0
|
||||
X1 Y1 Z1
|
||||
1
|
||||
2
|
||||
3
|
||||
4
|
||||
5
|
||||
6
|
||||
7
|
||||
8
|
||||
9
|
||||
10
|
||||
X2 Y2 Z2
|
||||
X3 Y3 Z3
|
||||
}
|
||||
"#,
|
||||
vec![
|
||||
SpanLabel {
|
||||
start: Position {
|
||||
string: "Y0",
|
||||
count: 1,
|
||||
},
|
||||
end: Position {
|
||||
string: "X1",
|
||||
count: 1,
|
||||
},
|
||||
label: "`X` is a good letter",
|
||||
},
|
||||
SpanLabel {
|
||||
start: Position {
|
||||
string: "Z1",
|
||||
count: 1,
|
||||
},
|
||||
end: Position {
|
||||
string: "Z3",
|
||||
count: 1,
|
||||
},
|
||||
label: "`Y` is a good letter too",
|
||||
},
|
||||
],
|
||||
r#"
|
||||
error: foo
|
||||
--> test.rs:3:6
|
||||
|
|
||||
3 | X0 Y0 Z0
|
||||
| ______^ starting here...
|
||||
4 | | X1 Y1 Z1
|
||||
| |____^____- starting here...
|
||||
| ||____|
|
||||
| | ...ending here: `X` is a good letter
|
||||
5 | | 1
|
||||
6 | | 2
|
||||
7 | | 3
|
||||
... |
|
||||
15 | | X2 Y2 Z2
|
||||
16 | | X3 Y3 Z3
|
||||
| |___________- ...ending here: `Y` is a good letter too
|
||||
|
||||
"#);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn long_snippet_multiple_spans() {
|
||||
test_harness(r#"
|
||||
fn foo() {
|
||||
X0 Y0 Z0
|
||||
1
|
||||
2
|
||||
3
|
||||
X1 Y1 Z1
|
||||
4
|
||||
5
|
||||
6
|
||||
X2 Y2 Z2
|
||||
7
|
||||
8
|
||||
9
|
||||
10
|
||||
X3 Y3 Z3
|
||||
}
|
||||
"#,
|
||||
vec![
|
||||
SpanLabel {
|
||||
start: Position {
|
||||
string: "Y0",
|
||||
count: 1,
|
||||
},
|
||||
end: Position {
|
||||
string: "Y3",
|
||||
count: 1,
|
||||
},
|
||||
label: "`Y` is a good letter",
|
||||
},
|
||||
SpanLabel {
|
||||
start: Position {
|
||||
string: "Z1",
|
||||
count: 1,
|
||||
},
|
||||
end: Position {
|
||||
string: "Z2",
|
||||
count: 1,
|
||||
},
|
||||
label: "`Z` is a good letter too",
|
||||
},
|
||||
],
|
||||
r#"
|
||||
error: foo
|
||||
--> test.rs:3:6
|
||||
|
|
||||
3 | X0 Y0 Z0
|
||||
| ______^ starting here...
|
||||
4 | | 1
|
||||
5 | | 2
|
||||
6 | | 3
|
||||
7 | | X1 Y1 Z1
|
||||
| |_________- starting here...
|
||||
8 | || 4
|
||||
9 | || 5
|
||||
10 | || 6
|
||||
11 | || X2 Y2 Z2
|
||||
| ||__________- ...ending here: `Z` is a good letter too
|
||||
... |
|
||||
15 | | 10
|
||||
16 | | X3 Y3 Z3
|
||||
| |_______^ ...ending here: `Y` is a good letter
|
||||
|
||||
"#);
|
||||
}
|
||||
|
||||
|
@ -24,8 +24,7 @@ error[E0046]: not all trait items implemented, missing: `bar`
|
||||
23 | | //~^ ERROR E0046
|
||||
24 | | //~| NOTE missing `bar` in implementation
|
||||
25 | | const bar: u64 = 1;
|
||||
26 | | //~^ ERROR E0323
|
||||
27 | | //~| NOTE does not match trait
|
||||
... |
|
||||
28 | | const MY_CONST: u32 = 1;
|
||||
29 | | }
|
||||
| |_^ ...ending here: missing `bar` in implementation
|
||||
@ -50,8 +49,7 @@ error[E0046]: not all trait items implemented, missing: `MY_CONST`
|
||||
34 | | //~^ ERROR E0046
|
||||
35 | | //~| NOTE missing `MY_CONST` in implementation
|
||||
36 | | fn bar(&self) {}
|
||||
37 | | fn MY_CONST() {}
|
||||
38 | | //~^ ERROR E0324
|
||||
... |
|
||||
39 | | //~| NOTE does not match trait
|
||||
40 | | }
|
||||
| |_^ ...ending here: missing `MY_CONST` in implementation
|
||||
@ -76,8 +74,7 @@ error[E0046]: not all trait items implemented, missing: `bar`
|
||||
45 | | //~^ ERROR E0046
|
||||
46 | | //~| NOTE missing `bar` in implementation
|
||||
47 | | type bar = u64;
|
||||
48 | | //~^ ERROR E0325
|
||||
49 | | //~| NOTE does not match trait
|
||||
... |
|
||||
50 | | const MY_CONST: u32 = 1;
|
||||
51 | | }
|
||||
| |_^ ...ending here: missing `bar` in implementation
|
||||
|
@ -1,8 +1,15 @@
|
||||
error[E0046]: not all trait items implemented, missing: `Item`
|
||||
--> $DIR/issue-23729.rs:20:9
|
||||
|
|
||||
20 | impl Iterator for Recurrence {
|
||||
| ^ missing `Item` in implementation
|
||||
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;`
|
||||
|
||||
|
@ -6,8 +6,7 @@ error[E0046]: not all trait items implemented, missing: `Output`
|
||||
37 | | //~^ ERROR E0046
|
||||
38 | | //~| NOTE missing `Output` in implementation
|
||||
39 | | //~| NOTE `Output` from trait: `type Output;`
|
||||
40 | | extern "rust-call" fn call_once(self, (comp,): (C,)) -> Prototype {
|
||||
41 | | Fn::call(&self, (comp,))
|
||||
... |
|
||||
42 | | }
|
||||
43 | | }
|
||||
| |_^ ...ending here: missing `Output` in implementation
|
||||
|
Loading…
Reference in New Issue
Block a user