Skip to content

Commit

Permalink
Browse files Browse the repository at this point in the history
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;`
```
  • Loading branch information
estebank committed Apr 9, 2017
1 parent 9e84bf8 commit 4bc7f5b
Show file tree
Hide file tree
Showing 6 changed files with 269 additions and 97 deletions.
196 changes: 119 additions & 77 deletions src/librustc_errors/emitter.rs
Expand Up @@ -21,6 +21,8 @@ use std::io::prelude::*;
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 {
Expand Down Expand Up @@ -156,15 +158,6 @@ impl EmitterWriter {
}
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
Expand All @@ -175,16 +168,7 @@ impl EmitterWriter {
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,
Expand All @@ -194,8 +178,17 @@ impl EmitterWriter {
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() {
Expand Down Expand Up @@ -233,9 +226,15 @@ impl EmitterWriter {
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() {
Expand All @@ -249,16 +248,11 @@ impl EmitterWriter {
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);
Expand Down Expand Up @@ -286,7 +280,7 @@ impl EmitterWriter {
// 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();
Expand Down Expand Up @@ -410,25 +404,9 @@ impl EmitterWriter {
// 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.
Expand Down Expand Up @@ -483,16 +461,15 @@ impl EmitterWriter {
}
}

// 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:
//
// 2 | fn foo() {
// | __________
// | | |
// | |
// 3 | |
// 3 |
// 4 | | }
// | |_
for &(pos, annotation) in &annotations_position {
Expand Down Expand Up @@ -528,16 +505,6 @@ impl EmitterWriter {
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);
}
}
_ => (),
}
}
Expand All @@ -548,11 +515,11 @@ impl EmitterWriter {
//
// 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
Expand Down Expand Up @@ -591,11 +558,11 @@ impl EmitterWriter {
//
// 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)
Expand All @@ -609,6 +576,20 @@ impl EmitterWriter {
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 {
Expand Down Expand Up @@ -902,22 +883,64 @@ impl EmitterWriter {
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)
Expand All @@ -932,11 +955,21 @@ impl EmitterWriter {
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);
}
}

Expand Down Expand Up @@ -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
Expand Down
13 changes: 3 additions & 10 deletions src/librustc_errors/snippet.rs
Expand Up @@ -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),

Expand All @@ -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),
}

Expand All @@ -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 {
Expand Down

0 comments on commit 4bc7f5b

Please sign in to comment.