Auto merge of #37369 - estebank:multiline-span, r=nikomatsakis
Show multiline spans in full if short enough When dealing with multiline spans that span few lines, show the complete span instead of restricting to the first character of the first line. For example, instead of: ``` % ./rustc file2.rs error[E0277]: the trait bound `{integer}: std::ops::Add<()>` is not satisfied --> file2.rs:13:9 | 13 | foo(1 + bar(x, | ^ trait `{integer}: std::ops::Add<()>` not satisfied | ``` show ``` % ./rustc file2.rs error[E0277]: the trait bound `{integer}: std::ops::Add<()>` is not satisfied --> file2.rs:13:9 | 13 | foo(1 + bar(x, | ________^ starting here... 14 | | y), | |_____________^ ...ending here: trait `{integer}: std::ops::Add<()>` not satisfied | ``` The [proposal in internals](https://internals.rust-lang.org/t/proposal-for-multiline-span-comments/4242/6) outlines the reasoning behind this.
This commit is contained in:
commit
b30022a1d3
@ -14,7 +14,7 @@ use syntax_pos::{COMMAND_LINE_SP, DUMMY_SP, FileMap, Span, MultiSpan, CharPos};
|
||||
|
||||
use {Level, CodeSuggestion, DiagnosticBuilder, SubDiagnostic, CodeMapper};
|
||||
use RenderSpan::*;
|
||||
use snippet::{StyledString, Style, Annotation, Line};
|
||||
use snippet::{Annotation, AnnotationType, Line, MultilineAnnotation, StyledString, Style};
|
||||
use styled_buffer::StyledBuffer;
|
||||
|
||||
use std::io::prelude::*;
|
||||
@ -65,6 +65,7 @@ pub struct EmitterWriter {
|
||||
struct FileWithAnnotatedLines {
|
||||
file: Rc<FileMap>,
|
||||
lines: Vec<Line>,
|
||||
multiline_depth: usize,
|
||||
}
|
||||
|
||||
|
||||
@ -137,10 +138,12 @@ impl EmitterWriter {
|
||||
line_index: line_index,
|
||||
annotations: vec![ann],
|
||||
}],
|
||||
multiline_depth: 0,
|
||||
});
|
||||
}
|
||||
|
||||
let mut output = vec![];
|
||||
let mut multiline_annotations = vec![];
|
||||
|
||||
if let Some(ref cm) = self.cm {
|
||||
for span_label in msp.span_labels() {
|
||||
@ -151,8 +154,9 @@ impl EmitterWriter {
|
||||
let mut hi = cm.lookup_char_pos(span_label.span.hi);
|
||||
let mut is_minimized = false;
|
||||
|
||||
// If the span is multi-line, simplify down to the span of one character
|
||||
if lo.line != hi.line {
|
||||
// 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;
|
||||
@ -163,22 +167,76 @@ impl EmitterWriter {
|
||||
// 6..7. This is degenerate input, but it's best to degrade
|
||||
// gracefully -- and the parser likes to supply a span like
|
||||
// that for EOF, in particular.
|
||||
if lo.col == hi.col {
|
||||
if lo.col == hi.col && lo.line == hi.line {
|
||||
hi.col = CharPos(lo.col.0 + 1);
|
||||
}
|
||||
|
||||
add_annotation_to_file(&mut output,
|
||||
lo.file,
|
||||
lo.line,
|
||||
Annotation {
|
||||
start_col: lo.col.0,
|
||||
end_col: hi.col.0,
|
||||
is_primary: span_label.is_primary,
|
||||
is_minimized: is_minimized,
|
||||
label: span_label.label.clone(),
|
||||
});
|
||||
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 ml = MultilineAnnotation {
|
||||
depth: 1,
|
||||
line_start: lo.line,
|
||||
line_end: hi.line,
|
||||
start_col: lo.col.0,
|
||||
end_col: hi.col.0,
|
||||
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));
|
||||
};
|
||||
|
||||
if !ann.is_multiline() {
|
||||
add_annotation_to_file(&mut output,
|
||||
lo.file,
|
||||
lo.line,
|
||||
ann);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Find overlapping multiline annotations, put them at different depths
|
||||
multiline_annotations.sort_by(|a, b| {
|
||||
(a.1.line_start, a.1.line_end).cmp(&(b.1.line_start, b.1.line_end))
|
||||
});
|
||||
for item in multiline_annotations.clone() {
|
||||
let ann = item.1;
|
||||
for item in multiline_annotations.iter_mut() {
|
||||
let ref mut a = item.1;
|
||||
// Move all other multiline annotations overlapping with this one
|
||||
// one level to the right.
|
||||
if &ann != a &&
|
||||
num_overlap(ann.line_start, ann.line_end, a.line_start, a.line_end, true)
|
||||
{
|
||||
a.increase_depth();
|
||||
} else {
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
let mut max_depth = 0; // max overlapping multiline spans
|
||||
for (file, ann) in multiline_annotations {
|
||||
if ann.depth > max_depth {
|
||||
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 {
|
||||
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() {
|
||||
file_vec.multiline_depth = max_depth;
|
||||
}
|
||||
output
|
||||
}
|
||||
|
||||
@ -186,14 +244,20 @@ impl EmitterWriter {
|
||||
buffer: &mut StyledBuffer,
|
||||
file: Rc<FileMap>,
|
||||
line: &Line,
|
||||
width_offset: usize) {
|
||||
width_offset: usize,
|
||||
multiline_depth: usize) {
|
||||
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, width_offset, &source_string, Style::Quotation);
|
||||
buffer.puts(line_offset, code_offset, &source_string, Style::Quotation);
|
||||
buffer.puts(line_offset,
|
||||
0,
|
||||
&(line.line_index.to_string()),
|
||||
@ -201,14 +265,10 @@ impl EmitterWriter {
|
||||
|
||||
draw_col_separator(buffer, line_offset, width_offset - 2);
|
||||
|
||||
if line.annotations.is_empty() {
|
||||
return;
|
||||
}
|
||||
|
||||
// We want to display like this:
|
||||
//
|
||||
// vec.push(vec.pop().unwrap());
|
||||
// --- ^^^ _ previous borrow ends here
|
||||
// --- ^^^ - previous borrow ends here
|
||||
// | |
|
||||
// | error occurs here
|
||||
// previous borrow of `vec` occurs here
|
||||
@ -227,42 +287,22 @@ impl EmitterWriter {
|
||||
// Sort the annotations by (start, end col)
|
||||
let mut annotations = line.annotations.clone();
|
||||
annotations.sort();
|
||||
annotations.reverse();
|
||||
|
||||
// Next, create the highlight line.
|
||||
for annotation in &annotations {
|
||||
for p in annotation.start_col..annotation.end_col {
|
||||
if annotation.is_primary {
|
||||
buffer.putc(line_offset + 1,
|
||||
width_offset + p,
|
||||
'^',
|
||||
Style::UnderlinePrimary);
|
||||
if !annotation.is_minimized {
|
||||
buffer.set_style(line_offset, width_offset + p, Style::UnderlinePrimary);
|
||||
}
|
||||
} else {
|
||||
buffer.putc(line_offset + 1,
|
||||
width_offset + p,
|
||||
'-',
|
||||
Style::UnderlineSecondary);
|
||||
if !annotation.is_minimized {
|
||||
buffer.set_style(line_offset, width_offset + p, Style::UnderlineSecondary);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
draw_col_separator(buffer, line_offset + 1, width_offset - 2);
|
||||
|
||||
// Now we are going to write labels in. To start, we'll exclude
|
||||
// the annotations with no labels.
|
||||
let (labeled_annotations, unlabeled_annotations): (Vec<_>, _) = annotations.into_iter()
|
||||
.partition(|a| a.label.is_some());
|
||||
|
||||
// If there are no annotations that need text, we're done.
|
||||
if labeled_annotations.is_empty() {
|
||||
return;
|
||||
}
|
||||
// Now add the text labels. We try, when possible, to stick the rightmost
|
||||
// annotation at the end of the highlight line:
|
||||
// First, figure out where each label will be positioned.
|
||||
//
|
||||
// In the case where you have the following annotations:
|
||||
//
|
||||
// vec.push(vec.pop().unwrap());
|
||||
// -------- - previous borrow ends here [C]
|
||||
// ||
|
||||
// |this makes no sense [B]
|
||||
// previous borrow of `vec` occurs here [A]
|
||||
//
|
||||
// `annotations_position` will hold [(2, A), (1, B), (0, C)].
|
||||
//
|
||||
// We try, when possible, to stick the rightmost annotation at the end
|
||||
// of the highlight line:
|
||||
//
|
||||
// vec.push(vec.pop().unwrap());
|
||||
// --- --- - previous borrow ends here
|
||||
@ -296,66 +336,251 @@ impl EmitterWriter {
|
||||
// the rightmost span overlaps with any other span, we should
|
||||
// use the "hang below" version, so we can at least make it
|
||||
// clear where the span *starts*.
|
||||
let mut labeled_annotations = &labeled_annotations[..];
|
||||
match labeled_annotations.split_last().unwrap() {
|
||||
(last, previous) => {
|
||||
if previous.iter()
|
||||
.chain(&unlabeled_annotations)
|
||||
.all(|a| !overlaps(a, last)) {
|
||||
// append the label afterwards; we keep it in a separate
|
||||
// string
|
||||
let highlight_label: String = format!(" {}", last.label.as_ref().unwrap());
|
||||
if last.is_primary {
|
||||
buffer.append(line_offset + 1, &highlight_label, Style::LabelPrimary);
|
||||
} else {
|
||||
buffer.append(line_offset + 1, &highlight_label, Style::LabelSecondary);
|
||||
}
|
||||
labeled_annotations = previous;
|
||||
let mut annotations_position = vec![];
|
||||
let mut line_len = 0;
|
||||
let mut p = 0;
|
||||
let mut ann_iter = annotations.iter().peekable();
|
||||
while let Some(annotation) = ann_iter.next() {
|
||||
let is_line = if let AnnotationType::MultilineLine(_) = annotation.annotation_type {
|
||||
true
|
||||
} else {
|
||||
false
|
||||
};
|
||||
let peek = ann_iter.peek();
|
||||
if let Some(next) = peek {
|
||||
let next_is_line = if let AnnotationType::MultilineLine(_) = next.annotation_type {
|
||||
true
|
||||
} else {
|
||||
false
|
||||
};
|
||||
|
||||
if overlaps(next, annotation) && !is_line && !next_is_line {
|
||||
p += 1;
|
||||
}
|
||||
}
|
||||
annotations_position.push((p, annotation));
|
||||
if let Some(next) = peek {
|
||||
let next_is_line = if let AnnotationType::MultilineLine(_) = next.annotation_type {
|
||||
true
|
||||
} else {
|
||||
false
|
||||
};
|
||||
let l = if let Some(ref label) = next.label {
|
||||
label.len() + 2
|
||||
} else {
|
||||
0
|
||||
};
|
||||
if (overlaps(next, annotation) || next.end_col + l > annotation.start_col)
|
||||
&& !is_line && !next_is_line
|
||||
{
|
||||
p += 1;
|
||||
}
|
||||
}
|
||||
if line_len < p {
|
||||
line_len = p;
|
||||
}
|
||||
}
|
||||
if line_len != 0 {
|
||||
line_len += 1;
|
||||
}
|
||||
|
||||
// If that's the last annotation, we're done
|
||||
if labeled_annotations.is_empty() {
|
||||
// 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
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
for (index, annotation) in labeled_annotations.iter().enumerate() {
|
||||
// Leave:
|
||||
// - 1 extra line
|
||||
// - One line for each thing that comes after
|
||||
let comes_after = labeled_annotations.len() - index - 1;
|
||||
let blank_lines = 3 + comes_after;
|
||||
for pos in 0..line_len + 1 {
|
||||
draw_col_separator(buffer, line_offset + pos + 1, width_offset - 2);
|
||||
buffer.putc(line_offset + pos + 1,
|
||||
width_offset - 2,
|
||||
'|',
|
||||
Style::LineNumber);
|
||||
}
|
||||
|
||||
// For each blank line, draw a `|` at our column. The
|
||||
// text ought to be long enough for this.
|
||||
for index in 2..blank_lines {
|
||||
if annotation.is_primary {
|
||||
buffer.putc(line_offset + index,
|
||||
width_offset + annotation.start_col,
|
||||
'|',
|
||||
Style::UnderlinePrimary);
|
||||
} else {
|
||||
buffer.putc(line_offset + index,
|
||||
width_offset + annotation.start_col,
|
||||
'|',
|
||||
Style::UnderlineSecondary);
|
||||
}
|
||||
draw_col_separator(buffer, line_offset + index, width_offset - 2);
|
||||
}
|
||||
|
||||
if annotation.is_primary {
|
||||
buffer.puts(line_offset + blank_lines,
|
||||
width_offset + annotation.start_col,
|
||||
annotation.label.as_ref().unwrap(),
|
||||
Style::LabelPrimary);
|
||||
// Write the horizontal lines for multiline annotations
|
||||
// (only the first and last lines need this).
|
||||
//
|
||||
// After this we will have:
|
||||
//
|
||||
// 2 | fn foo() {
|
||||
// | __________
|
||||
// |
|
||||
// |
|
||||
// 3 |
|
||||
// 4 | }
|
||||
// | _
|
||||
for &(pos, annotation) in &annotations_position {
|
||||
let style = if annotation.is_primary {
|
||||
Style::UnderlinePrimary
|
||||
} else {
|
||||
buffer.puts(line_offset + blank_lines,
|
||||
width_offset + annotation.start_col,
|
||||
annotation.label.as_ref().unwrap(),
|
||||
Style::LabelSecondary);
|
||||
Style::UnderlineSecondary
|
||||
};
|
||||
let pos = pos + 1;
|
||||
match annotation.annotation_type {
|
||||
AnnotationType::MultilineStart(depth) |
|
||||
AnnotationType::MultilineEnd(depth) => {
|
||||
draw_range(buffer,
|
||||
'_',
|
||||
line_offset + pos,
|
||||
width_offset + depth,
|
||||
code_offset + annotation.start_col,
|
||||
style);
|
||||
}
|
||||
_ => (),
|
||||
}
|
||||
}
|
||||
|
||||
// Write the vertical lines for multiline spans and for labels that are
|
||||
// on a different line as the underline.
|
||||
//
|
||||
// After this we will have:
|
||||
//
|
||||
// 2 | fn foo() {
|
||||
// | __________
|
||||
// | | |
|
||||
// | |
|
||||
// 3 | |
|
||||
// 4 | | }
|
||||
// | |_
|
||||
for &(pos, annotation) in &annotations_position {
|
||||
let style = if annotation.is_primary {
|
||||
Style::UnderlinePrimary
|
||||
} else {
|
||||
Style::UnderlineSecondary
|
||||
};
|
||||
let pos = pos + 1;
|
||||
if pos > 1 {
|
||||
for p in line_offset + 1..line_offset + pos + 1 {
|
||||
buffer.putc(p,
|
||||
code_offset + annotation.start_col,
|
||||
'|',
|
||||
style);
|
||||
}
|
||||
}
|
||||
match annotation.annotation_type {
|
||||
AnnotationType::MultilineStart(depth) => {
|
||||
for p in line_offset + pos + 1..line_offset + line_len + 2 {
|
||||
buffer.putc(p,
|
||||
width_offset + depth - 1,
|
||||
'|',
|
||||
style);
|
||||
}
|
||||
}
|
||||
AnnotationType::MultilineEnd(depth) => {
|
||||
for p in line_offset..line_offset + pos + 1 {
|
||||
buffer.putc(p,
|
||||
width_offset + depth - 1,
|
||||
'|',
|
||||
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);
|
||||
}
|
||||
}
|
||||
_ => (),
|
||||
}
|
||||
}
|
||||
|
||||
// Write the labels on the annotations that actually have a label.
|
||||
//
|
||||
// After this we will have:
|
||||
//
|
||||
// 2 | fn foo() {
|
||||
// | __________ starting here...
|
||||
// | | |
|
||||
// | | something about `foo`
|
||||
// 3 | |
|
||||
// 4 | | }
|
||||
// | |_ ...ending here: test
|
||||
for &(pos, annotation) in &annotations_position {
|
||||
let style = if annotation.is_primary {
|
||||
Style::LabelPrimary
|
||||
} else {
|
||||
Style::LabelSecondary
|
||||
};
|
||||
let (pos, col) = if pos == 0 {
|
||||
(pos + 1, annotation.end_col + 1)
|
||||
} else {
|
||||
(pos + 2, annotation.start_col)
|
||||
};
|
||||
if let Some(ref label) = annotation.label {
|
||||
buffer.puts(line_offset + pos,
|
||||
code_offset + col,
|
||||
&label,
|
||||
style);
|
||||
}
|
||||
}
|
||||
|
||||
// Sort from biggest span to smallest span so that smaller spans are
|
||||
// represented in the output:
|
||||
//
|
||||
// x | fn foo()
|
||||
// | ^^^---^^
|
||||
// | | |
|
||||
// | | something about `foo`
|
||||
// | something about `fn foo()`
|
||||
annotations_position.sort_by(|a, b| {
|
||||
fn len(a: &Annotation) -> usize {
|
||||
// Account for usize underflows
|
||||
if a.end_col > a.start_col {
|
||||
a.end_col - a.start_col
|
||||
} else {
|
||||
a.start_col - a.end_col
|
||||
}
|
||||
}
|
||||
// Decreasing order
|
||||
len(a.1).cmp(&len(b.1)).reverse()
|
||||
});
|
||||
|
||||
// Write the underlines.
|
||||
//
|
||||
// After this we will have:
|
||||
//
|
||||
// 2 | fn foo() {
|
||||
// | ____-_____^ starting here...
|
||||
// | | |
|
||||
// | | something about `foo`
|
||||
// 3 | |
|
||||
// 4 | | }
|
||||
// | |_^ ...ending here: test
|
||||
for &(_, annotation) in &annotations_position {
|
||||
let (underline, style) = if annotation.is_primary {
|
||||
('^', Style::UnderlinePrimary)
|
||||
} else {
|
||||
('-', Style::UnderlineSecondary)
|
||||
};
|
||||
for p in annotation.start_col..annotation.end_col {
|
||||
buffer.putc(line_offset + 1,
|
||||
code_offset + p,
|
||||
underline,
|
||||
style);
|
||||
}
|
||||
draw_col_separator(buffer, line_offset + blank_lines, width_offset - 2);
|
||||
}
|
||||
}
|
||||
|
||||
@ -577,7 +802,8 @@ impl EmitterWriter {
|
||||
self.render_source_line(&mut buffer,
|
||||
annotated_file.file.clone(),
|
||||
&annotated_file.lines[line_idx],
|
||||
3 + max_line_num_len);
|
||||
3 + max_line_num_len,
|
||||
annotated_file.multiline_depth);
|
||||
|
||||
// check to see if we need to print out or elide lines that come between
|
||||
// this annotated line and the next one
|
||||
@ -729,16 +955,38 @@ fn draw_col_separator(buffer: &mut StyledBuffer, line: usize, col: usize) {
|
||||
}
|
||||
|
||||
fn draw_col_separator_no_space(buffer: &mut StyledBuffer, line: usize, col: usize) {
|
||||
buffer.puts(line, col, "|", Style::LineNumber);
|
||||
draw_col_separator_no_space_with_style(buffer, line, col, Style::LineNumber);
|
||||
}
|
||||
|
||||
fn draw_col_separator_no_space_with_style(buffer: &mut StyledBuffer,
|
||||
line: usize,
|
||||
col: usize,
|
||||
style: Style) {
|
||||
buffer.putc(line, col, '|', style);
|
||||
}
|
||||
|
||||
fn draw_range(buffer: &mut StyledBuffer, symbol: char, line: usize,
|
||||
col_from: usize, col_to: usize, style: Style) {
|
||||
for col in col_from..col_to {
|
||||
buffer.putc(line, col, symbol, style);
|
||||
}
|
||||
}
|
||||
|
||||
fn draw_note_separator(buffer: &mut StyledBuffer, line: usize, col: usize) {
|
||||
buffer.puts(line, col, "= ", Style::LineNumber);
|
||||
}
|
||||
|
||||
fn num_overlap(a_start: usize, a_end: usize, b_start: usize, b_end:usize, inclusive: bool) -> bool {
|
||||
let extra = if inclusive {
|
||||
1
|
||||
} else {
|
||||
0
|
||||
};
|
||||
(b_start..b_end + extra).contains(a_start) ||
|
||||
(a_start..a_end + extra).contains(b_start)
|
||||
}
|
||||
fn overlaps(a1: &Annotation, a2: &Annotation) -> bool {
|
||||
(a2.start_col..a2.end_col).contains(a1.start_col) ||
|
||||
(a1.start_col..a1.end_col).contains(a2.start_col)
|
||||
num_overlap(a1.start_col, a1.end_col, a2.start_col, a2.end_col, false)
|
||||
}
|
||||
|
||||
fn emit_to_destination(rendered_buffer: &Vec<Vec<StyledString>>,
|
||||
|
@ -41,6 +41,86 @@ pub struct Line {
|
||||
pub annotations: Vec<Annotation>,
|
||||
}
|
||||
|
||||
|
||||
#[derive(Clone, Debug, PartialOrd, Ord, PartialEq, Eq)]
|
||||
pub struct MultilineAnnotation {
|
||||
pub depth: usize,
|
||||
pub line_start: usize,
|
||||
pub line_end: usize,
|
||||
pub start_col: usize,
|
||||
pub end_col: usize,
|
||||
pub is_primary: bool,
|
||||
pub label: Option<String>,
|
||||
}
|
||||
|
||||
impl MultilineAnnotation {
|
||||
pub fn increase_depth(&mut self) {
|
||||
self.depth += 1;
|
||||
}
|
||||
|
||||
pub fn as_start(&self) -> Annotation {
|
||||
Annotation {
|
||||
start_col: self.start_col,
|
||||
end_col: self.start_col + 1,
|
||||
is_primary: self.is_primary,
|
||||
label: Some("starting here...".to_owned()),
|
||||
annotation_type: AnnotationType::MultilineStart(self.depth)
|
||||
}
|
||||
}
|
||||
|
||||
pub fn as_end(&self) -> Annotation {
|
||||
Annotation {
|
||||
start_col: self.end_col - 1,
|
||||
end_col: self.end_col,
|
||||
is_primary: self.is_primary,
|
||||
label: match self.label {
|
||||
Some(ref label) => Some(format!("...ending here: {}", label)),
|
||||
None => Some("...ending here".to_owned()),
|
||||
},
|
||||
annotation_type: AnnotationType::MultilineEnd(self.depth)
|
||||
}
|
||||
}
|
||||
|
||||
pub fn as_line(&self) -> Annotation {
|
||||
Annotation {
|
||||
start_col: 0,
|
||||
end_col: 0,
|
||||
is_primary: self.is_primary,
|
||||
label: None,
|
||||
annotation_type: AnnotationType::MultilineLine(self.depth)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug, PartialOrd, Ord, PartialEq, Eq)]
|
||||
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),
|
||||
|
||||
// The Multiline type above is replaced with the following three in order
|
||||
// to reuse the current label drawing code.
|
||||
//
|
||||
// Each of these corresponds to one part of the following diagram:
|
||||
//
|
||||
// x | foo(1 + bar(x,
|
||||
// | _________^ starting here... < MultilineStart
|
||||
// x | | y), < MultilineLine
|
||||
// | |______________^ ...ending here: label < MultilineEnd
|
||||
// x | z);
|
||||
/// Annotation marking the first character of a fully shown multiline span
|
||||
MultilineStart(usize),
|
||||
/// 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
|
||||
MultilineLine(usize),
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug, PartialOrd, Ord, PartialEq, Eq)]
|
||||
pub struct Annotation {
|
||||
/// Start column, 0-based indexing -- counting *characters*, not
|
||||
@ -55,11 +135,32 @@ pub struct Annotation {
|
||||
/// Is this annotation derived from primary span
|
||||
pub is_primary: bool,
|
||||
|
||||
/// Is this a large span minimized down to a smaller span
|
||||
pub is_minimized: bool,
|
||||
|
||||
/// Optional label to display adjacent to the annotation.
|
||||
pub label: Option<String>,
|
||||
|
||||
/// Is this a single line, multiline or multiline span minimized down to a
|
||||
/// smaller span.
|
||||
pub annotation_type: AnnotationType,
|
||||
}
|
||||
|
||||
impl Annotation {
|
||||
pub fn is_minimized(&self) -> bool {
|
||||
match self.annotation_type {
|
||||
AnnotationType::Minimized => true,
|
||||
_ => false,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn is_multiline(&self) -> bool {
|
||||
match self.annotation_type {
|
||||
AnnotationType::Multiline(_) |
|
||||
AnnotationType::MultilineStart(_) |
|
||||
AnnotationType::MultilineLine(_) |
|
||||
AnnotationType::MultilineEnd(_) => true,
|
||||
_ => false,
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
|
@ -145,4 +145,7 @@ pub mod ext {
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod test_snippet;
|
||||
|
||||
// __build_diagnostic_array! { libsyntax, DIAGNOSTICS }
|
||||
|
546
src/libsyntax/test_snippet.rs
Normal file
546
src/libsyntax/test_snippet.rs
Normal file
@ -0,0 +1,546 @@
|
||||
// Copyright 2016 The Rust Project Developers. See the COPYRIGHT
|
||||
// file at the top-level directory of this distribution and at
|
||||
// http://rust-lang.org/COPYRIGHT.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
|
||||
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
|
||||
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
|
||||
// option. This file may not be copied, modified, or distributed
|
||||
// except according to those terms.
|
||||
|
||||
use codemap::CodeMap;
|
||||
use errors::Handler;
|
||||
use errors::emitter::EmitterWriter;
|
||||
use std::io;
|
||||
use std::io::prelude::*;
|
||||
use std::rc::Rc;
|
||||
use std::str;
|
||||
use std::sync::{Arc, Mutex};
|
||||
use syntax_pos::{BytePos, NO_EXPANSION, Span, MultiSpan};
|
||||
|
||||
/// Identify a position in the text by the Nth occurrence of a string.
|
||||
struct Position {
|
||||
string: &'static str,
|
||||
count: usize,
|
||||
}
|
||||
|
||||
struct SpanLabel {
|
||||
start: Position,
|
||||
end: Position,
|
||||
label: &'static str,
|
||||
}
|
||||
|
||||
struct Shared<T: Write> {
|
||||
data: Arc<Mutex<T>>,
|
||||
}
|
||||
|
||||
impl<T: Write> Write for Shared<T> {
|
||||
fn write(&mut self, buf: &[u8]) -> io::Result<usize> {
|
||||
self.data.lock().unwrap().write(buf)
|
||||
}
|
||||
|
||||
fn flush(&mut self) -> io::Result<()> {
|
||||
self.data.lock().unwrap().flush()
|
||||
}
|
||||
}
|
||||
|
||||
fn test_harness(file_text: &str, span_labels: Vec<SpanLabel>, expected_output: &str) {
|
||||
let output = Arc::new(Mutex::new(Vec::new()));
|
||||
|
||||
let code_map = Rc::new(CodeMap::new());
|
||||
code_map.new_filemap_and_lines("test.rs", None, &file_text);
|
||||
|
||||
let primary_span = make_span(&file_text, &span_labels[0].start, &span_labels[0].end);
|
||||
let mut msp = MultiSpan::from_span(primary_span);
|
||||
for span_label in span_labels {
|
||||
let span = make_span(&file_text, &span_label.start, &span_label.end);
|
||||
msp.push_span_label(span, span_label.label.to_string());
|
||||
println!("span: {:?} label: {:?}", span, span_label.label);
|
||||
println!("text: {:?}", code_map.span_to_snippet(span));
|
||||
}
|
||||
|
||||
let emitter = EmitterWriter::new(Box::new(Shared { data: output.clone() }),
|
||||
Some(code_map.clone()));
|
||||
let handler = Handler::with_emitter(true, false, Box::new(emitter));
|
||||
handler.span_err(msp, "foo");
|
||||
|
||||
assert!(expected_output.chars().next() == Some('\n'),
|
||||
"expected output should begin with newline");
|
||||
let expected_output = &expected_output[1..];
|
||||
|
||||
let bytes = output.lock().unwrap();
|
||||
let actual_output = str::from_utf8(&bytes).unwrap();
|
||||
println!("expected output:\n------\n{}------", expected_output);
|
||||
println!("actual output:\n------\n{}------", actual_output);
|
||||
|
||||
assert!(expected_output == actual_output)
|
||||
}
|
||||
|
||||
fn make_span(file_text: &str, start: &Position, end: &Position) -> Span {
|
||||
let start = make_pos(file_text, start);
|
||||
let end = make_pos(file_text, end) + end.string.len(); // just after matching thing ends
|
||||
assert!(start <= end);
|
||||
Span {
|
||||
lo: BytePos(start as u32),
|
||||
hi: BytePos(end as u32),
|
||||
expn_id: NO_EXPANSION,
|
||||
}
|
||||
}
|
||||
|
||||
fn make_pos(file_text: &str, pos: &Position) -> usize {
|
||||
let mut remainder = file_text;
|
||||
let mut offset = 0;
|
||||
for _ in 0..pos.count {
|
||||
if let Some(n) = remainder.find(&pos.string) {
|
||||
offset += n;
|
||||
remainder = &remainder[n + 1..];
|
||||
} else {
|
||||
panic!("failed to find {} instances of {:?} in {:?}",
|
||||
pos.count,
|
||||
pos.string,
|
||||
file_text);
|
||||
}
|
||||
}
|
||||
offset
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn ends_on_col0() {
|
||||
test_harness(r#"
|
||||
fn foo() {
|
||||
}
|
||||
"#,
|
||||
vec![
|
||||
SpanLabel {
|
||||
start: Position {
|
||||
string: "{",
|
||||
count: 1,
|
||||
},
|
||||
end: Position {
|
||||
string: "}",
|
||||
count: 1,
|
||||
},
|
||||
label: "test",
|
||||
},
|
||||
],
|
||||
r#"
|
||||
error: foo
|
||||
--> test.rs:2:10
|
||||
|
|
||||
2 | fn foo() {
|
||||
| __________^ starting here...
|
||||
3 | | }
|
||||
| |_^ ...ending here: test
|
||||
|
||||
"#);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn ends_on_col2() {
|
||||
test_harness(r#"
|
||||
fn foo() {
|
||||
|
||||
|
||||
}
|
||||
"#,
|
||||
vec![
|
||||
SpanLabel {
|
||||
start: Position {
|
||||
string: "{",
|
||||
count: 1,
|
||||
},
|
||||
end: Position {
|
||||
string: "}",
|
||||
count: 1,
|
||||
},
|
||||
label: "test",
|
||||
},
|
||||
],
|
||||
r#"
|
||||
error: foo
|
||||
--> test.rs:2:10
|
||||
|
|
||||
2 | fn foo() {
|
||||
| __________^ starting here...
|
||||
3 | |
|
||||
4 | |
|
||||
5 | | }
|
||||
| |___^ ...ending here: test
|
||||
|
||||
"#);
|
||||
}
|
||||
#[test]
|
||||
fn non_nested() {
|
||||
test_harness(r#"
|
||||
fn foo() {
|
||||
X0 Y0
|
||||
X1 Y1
|
||||
X2 Y2
|
||||
}
|
||||
"#,
|
||||
vec![
|
||||
SpanLabel {
|
||||
start: Position {
|
||||
string: "X0",
|
||||
count: 1,
|
||||
},
|
||||
end: Position {
|
||||
string: "X2",
|
||||
count: 1,
|
||||
},
|
||||
label: "`X` is a good letter",
|
||||
},
|
||||
SpanLabel {
|
||||
start: Position {
|
||||
string: "Y0",
|
||||
count: 1,
|
||||
},
|
||||
end: Position {
|
||||
string: "Y2",
|
||||
count: 1,
|
||||
},
|
||||
label: "`Y` is a good letter too",
|
||||
},
|
||||
],
|
||||
r#"
|
||||
error: foo
|
||||
--> test.rs:3:3
|
||||
|
|
||||
3 | X0 Y0
|
||||
| ____^__- starting here...
|
||||
| | ___|
|
||||
| || starting here...
|
||||
4 | || X1 Y1
|
||||
5 | || X2 Y2
|
||||
| ||____^__- ...ending here: `Y` is a good letter too
|
||||
| |____|
|
||||
| ...ending here: `X` is a good letter
|
||||
|
||||
"#);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn nested() {
|
||||
test_harness(r#"
|
||||
fn foo() {
|
||||
X0 Y0
|
||||
Y1 X1
|
||||
}
|
||||
"#,
|
||||
vec![
|
||||
SpanLabel {
|
||||
start: Position {
|
||||
string: "X0",
|
||||
count: 1,
|
||||
},
|
||||
end: Position {
|
||||
string: "X1",
|
||||
count: 1,
|
||||
},
|
||||
label: "`X` is a good letter",
|
||||
},
|
||||
SpanLabel {
|
||||
start: Position {
|
||||
string: "Y0",
|
||||
count: 1,
|
||||
},
|
||||
end: Position {
|
||||
string: "Y1",
|
||||
count: 1,
|
||||
},
|
||||
label: "`Y` is a good letter too",
|
||||
},
|
||||
],
|
||||
r#"
|
||||
error: foo
|
||||
--> test.rs:3:3
|
||||
|
|
||||
3 | X0 Y0
|
||||
| ____^__- starting here...
|
||||
| | ___|
|
||||
| || starting here...
|
||||
4 | || Y1 X1
|
||||
| ||____-__^ ...ending here: `X` is a good letter
|
||||
| |_____|
|
||||
| ...ending here: `Y` is a good letter too
|
||||
|
||||
"#);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn different_overlap() {
|
||||
test_harness(r#"
|
||||
fn foo() {
|
||||
X0 Y0 Z0
|
||||
X1 Y1 Z1
|
||||
X2 Y2 Z2
|
||||
X3 Y3 Z3
|
||||
}
|
||||
"#,
|
||||
vec![
|
||||
SpanLabel {
|
||||
start: Position {
|
||||
string: "Y0",
|
||||
count: 1,
|
||||
},
|
||||
end: Position {
|
||||
string: "X2",
|
||||
count: 1,
|
||||
},
|
||||
label: "`X` is a good letter",
|
||||
},
|
||||
SpanLabel {
|
||||
start: Position {
|
||||
string: "Z1",
|
||||
count: 1,
|
||||
},
|
||||
end: Position {
|
||||
string: "X3",
|
||||
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...
|
||||
5 | || X2 Y2 Z2
|
||||
| ||____^ ...ending here: `X` is a good letter
|
||||
6 | | X3 Y3 Z3
|
||||
| |_____- ...ending here: `Y` is a good letter too
|
||||
|
||||
"#);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn triple_overlap() {
|
||||
test_harness(r#"
|
||||
fn foo() {
|
||||
X0 Y0 Z0
|
||||
X1 Y1 Z1
|
||||
X2 Y2 Z2
|
||||
}
|
||||
"#,
|
||||
vec![
|
||||
SpanLabel {
|
||||
start: Position {
|
||||
string: "X0",
|
||||
count: 1,
|
||||
},
|
||||
end: Position {
|
||||
string: "X2",
|
||||
count: 1,
|
||||
},
|
||||
label: "`X` is a good letter",
|
||||
},
|
||||
SpanLabel {
|
||||
start: Position {
|
||||
string: "Y0",
|
||||
count: 1,
|
||||
},
|
||||
end: Position {
|
||||
string: "Y2",
|
||||
count: 1,
|
||||
},
|
||||
label: "`Y` is a good letter too",
|
||||
},
|
||||
SpanLabel {
|
||||
start: Position {
|
||||
string: "Z0",
|
||||
count: 1,
|
||||
},
|
||||
end: Position {
|
||||
string: "Z2",
|
||||
count: 1,
|
||||
},
|
||||
label: "`Z` label",
|
||||
},
|
||||
],
|
||||
r#"
|
||||
error: foo
|
||||
--> test.rs:3:3
|
||||
|
|
||||
3 | X0 Y0 Z0
|
||||
| _____^__-__- starting here...
|
||||
| | ____|__|
|
||||
| || ___| starting here...
|
||||
| ||| starting here...
|
||||
4 | ||| X1 Y1 Z1
|
||||
5 | ||| X2 Y2 Z2
|
||||
| |||____^__-__- ...ending here: `Z` label
|
||||
| ||____|__|
|
||||
| |____| ...ending here: `Y` is a good letter too
|
||||
| ...ending here: `X` is a good letter
|
||||
|
||||
"#);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn minimum_depth() {
|
||||
test_harness(r#"
|
||||
fn foo() {
|
||||
X0 Y0 Z0
|
||||
X1 Y1 Z1
|
||||
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: "Y1",
|
||||
count: 1,
|
||||
},
|
||||
end: Position {
|
||||
string: "Z2",
|
||||
count: 1,
|
||||
},
|
||||
label: "`Y` is a good letter too",
|
||||
},
|
||||
SpanLabel {
|
||||
start: Position {
|
||||
string: "X2",
|
||||
count: 1,
|
||||
},
|
||||
end: Position {
|
||||
string: "Y3",
|
||||
count: 1,
|
||||
},
|
||||
label: "`Z`",
|
||||
},
|
||||
],
|
||||
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 | | X2 Y2 Z2
|
||||
| |____-______- ...ending here: `Y` is a good letter too
|
||||
| ____|
|
||||
| | starting here...
|
||||
6 | | X3 Y3 Z3
|
||||
| |________- ...ending here: `Z`
|
||||
|
||||
"#);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn non_overlaping() {
|
||||
test_harness(r#"
|
||||
fn foo() {
|
||||
X0 Y0 Z0
|
||||
X1 Y1 Z1
|
||||
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: "Y2",
|
||||
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
|
||||
| |____^ ...ending here: `X` is a good letter
|
||||
5 | X2 Y2 Z2
|
||||
| ______- starting here...
|
||||
6 | | X3 Y3 Z3
|
||||
| |__________- ...ending here: `Y` is a good letter too
|
||||
|
||||
"#);
|
||||
}
|
||||
#[test]
|
||||
fn overlaping_start_and_end() {
|
||||
test_harness(r#"
|
||||
fn foo() {
|
||||
X0 Y0 Z0
|
||||
X1 Y1 Z1
|
||||
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 | | X2 Y2 Z2
|
||||
6 | | X3 Y3 Z3
|
||||
| |___________- ...ending here: `Y` is a good letter too
|
||||
|
||||
"#);
|
||||
}
|
@ -1,11 +1,15 @@
|
||||
error[E0276]: impl has stricter requirements than trait
|
||||
--> $DIR/region-extra-2.rs:19:5
|
||||
|
|
||||
15 | fn renew<'b: 'a>(self) -> &'b mut [T];
|
||||
| -------------------------------------- definition of `renew` from trait
|
||||
15 | fn renew<'b: 'a>(self) -> &'b mut [T];
|
||||
| -------------------------------------- definition of `renew` from trait
|
||||
...
|
||||
19 | fn renew<'b: 'a>(self) -> &'b mut [T] where 'a: 'b {
|
||||
| ^ impl has extra requirement `'a: 'b`
|
||||
19 | fn renew<'b: 'a>(self) -> &'b mut [T] where 'a: 'b {
|
||||
| _____^ starting here...
|
||||
20 | | //~^ ERROR E0276
|
||||
21 | | &mut self[..]
|
||||
22 | | }
|
||||
| |_____^ ...ending here: impl has extra requirement `'a: 'b`
|
||||
|
||||
error: aborting due to previous error
|
||||
|
||||
|
@ -1,11 +1,15 @@
|
||||
error[E0276]: impl has stricter requirements than trait
|
||||
--> $DIR/traits-misc-mismatch-2.rs:23:5
|
||||
|
|
||||
19 | fn zip<B, U: Iterator<U>>(self, other: U) -> ZipIterator<Self, U>;
|
||||
| ------------------------------------------------------------------ definition of `zip` from trait
|
||||
19 | fn zip<B, U: Iterator<U>>(self, other: U) -> ZipIterator<Self, U>;
|
||||
| ------------------------------------------------------------------ definition of `zip` from trait
|
||||
...
|
||||
23 | fn zip<B, U: Iterator<B>>(self, other: U) -> ZipIterator<T, U> {
|
||||
| ^ impl has extra requirement `U: Iterator<B>`
|
||||
23 | fn zip<B, U: Iterator<B>>(self, other: U) -> ZipIterator<T, U> {
|
||||
| _____^ starting here...
|
||||
24 | | //~^ ERROR E0276
|
||||
25 | | ZipIterator{a: self, b: other}
|
||||
26 | | }
|
||||
| |_____^ ...ending here: impl has extra requirement `U: Iterator<B>`
|
||||
|
||||
error: aborting due to previous error
|
||||
|
||||
|
@ -1,14 +1,26 @@
|
||||
error[E0569]: requires an `unsafe impl` declaration due to `#[may_dangle]` attribute
|
||||
--> $DIR/dropck-eyepatch-implies-unsafe-impl.rs:32:1
|
||||
|
|
||||
32 | impl<#[may_dangle] A, B: fmt::Debug> Drop for Pt<A, B> {
|
||||
| ^
|
||||
32 | impl<#[may_dangle] A, B: fmt::Debug> Drop for Pt<A, B> {
|
||||
| _^ starting here...
|
||||
33 | | //~^ ERROR requires an `unsafe impl` declaration due to `#[may_dangle]` attribute
|
||||
34 | |
|
||||
35 | | // (unsafe to access self.1 due to #[may_dangle] on A)
|
||||
36 | | fn drop(&mut self) { println!("drop {} {:?}", self.0, self.2); }
|
||||
37 | | }
|
||||
| |_^ ...ending here
|
||||
|
||||
error[E0569]: requires an `unsafe impl` declaration due to `#[may_dangle]` attribute
|
||||
--> $DIR/dropck-eyepatch-implies-unsafe-impl.rs:38:1
|
||||
|
|
||||
38 | impl<#[may_dangle] 'a, 'b, B: fmt::Debug> Drop for Pr<'a, 'b, B> {
|
||||
| ^
|
||||
38 | impl<#[may_dangle] 'a, 'b, B: fmt::Debug> Drop for Pr<'a, 'b, B> {
|
||||
| _^ starting here...
|
||||
39 | | //~^ ERROR requires an `unsafe impl` declaration due to `#[may_dangle]` attribute
|
||||
40 | |
|
||||
41 | | // (unsafe to access self.1 due to #[may_dangle] on 'a)
|
||||
42 | | fn drop(&mut self) { println!("drop {} {:?}", self.0, self.2); }
|
||||
43 | | }
|
||||
| |_^ ...ending here
|
||||
|
||||
error: aborting due to 2 previous errors
|
||||
|
||||
|
@ -15,8 +15,11 @@ error[E0495]: cannot infer an appropriate lifetime due to conflicting requiremen
|
||||
help: consider using an explicit lifetime parameter as shown: fn from_str(path: &'a str) -> Result<Self, ()>
|
||||
--> $DIR/consider-using-explicit-lifetime.rs:25:5
|
||||
|
|
||||
25 | fn from_str(path: &str) -> Result<Self, ()> {
|
||||
| ^
|
||||
25 | fn from_str(path: &str) -> Result<Self, ()> {
|
||||
| _____^ starting here...
|
||||
26 | | Ok(Foo { field: path })
|
||||
27 | | }
|
||||
| |_____^ ...ending here
|
||||
|
||||
error: aborting due to 2 previous errors
|
||||
|
||||
|
@ -1,8 +1,10 @@
|
||||
error[E0308]: mismatched types
|
||||
--> $DIR/main.rs:12:18
|
||||
|
|
||||
12 | let x: u32 = (
|
||||
| ^ expected u32, found ()
|
||||
12 | let x: u32 = (
|
||||
| __________________^ starting here...
|
||||
13 | | );
|
||||
| |_____^ ...ending here: expected u32, found ()
|
||||
|
|
||||
= note: expected type `u32`
|
||||
= note: found type `()`
|
||||
|
@ -3,8 +3,10 @@ error: main function not found
|
||||
error[E0046]: not all trait items implemented, missing: `CONSTANT`, `Type`, `method`
|
||||
--> $DIR/m2.rs:20:1
|
||||
|
|
||||
20 | impl m1::X for X {
|
||||
| ^ missing `CONSTANT`, `Type`, `method` in implementation
|
||||
20 | impl m1::X for X {
|
||||
| _^ starting here...
|
||||
21 | | }
|
||||
| |_^ ...ending here: missing `CONSTANT`, `Type`, `method` in implementation
|
||||
|
|
||||
= note: `CONSTANT` from trait: `const CONSTANT: u32;`
|
||||
= note: `Type` from trait: `type Type;`
|
||||
|
@ -10,11 +10,19 @@ error[E0323]: item `bar` is an associated const, which doesn't match its trait `
|
||||
error[E0046]: not all trait items implemented, missing: `bar`
|
||||
--> $DIR/impl-wrong-item-for-trait.rs:22:1
|
||||
|
|
||||
16 | fn bar(&self);
|
||||
| -------------- `bar` from trait
|
||||
16 | fn bar(&self);
|
||||
| -------------- `bar` from trait
|
||||
...
|
||||
22 | impl Foo for FooConstForMethod {
|
||||
| ^ missing `bar` in implementation
|
||||
22 | impl Foo for FooConstForMethod {
|
||||
| _^ starting here...
|
||||
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
|
||||
|
||||
error[E0324]: item `MY_CONST` is an associated method, which doesn't match its trait `<FooMethodForConst as Foo>`
|
||||
--> $DIR/impl-wrong-item-for-trait.rs:37:5
|
||||
@ -28,11 +36,19 @@ error[E0324]: item `MY_CONST` is an associated method, which doesn't match its t
|
||||
error[E0046]: not all trait items implemented, missing: `MY_CONST`
|
||||
--> $DIR/impl-wrong-item-for-trait.rs:33:1
|
||||
|
|
||||
17 | const MY_CONST: u32;
|
||||
| -------------------- `MY_CONST` from trait
|
||||
17 | const MY_CONST: u32;
|
||||
| -------------------- `MY_CONST` from trait
|
||||
...
|
||||
33 | impl Foo for FooMethodForConst {
|
||||
| ^ missing `MY_CONST` in implementation
|
||||
33 | impl Foo for FooMethodForConst {
|
||||
| _^ starting here...
|
||||
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
|
||||
|
||||
error[E0325]: item `bar` is an associated type, which doesn't match its trait `<FooTypeForMethod as Foo>`
|
||||
--> $DIR/impl-wrong-item-for-trait.rs:47:5
|
||||
@ -46,17 +62,27 @@ error[E0325]: item `bar` is an associated type, which doesn't match its trait `<
|
||||
error[E0046]: not all trait items implemented, missing: `bar`
|
||||
--> $DIR/impl-wrong-item-for-trait.rs:44:1
|
||||
|
|
||||
16 | fn bar(&self);
|
||||
| -------------- `bar` from trait
|
||||
16 | fn bar(&self);
|
||||
| -------------- `bar` from trait
|
||||
...
|
||||
44 | impl Foo for FooTypeForMethod {
|
||||
| ^ missing `bar` in implementation
|
||||
44 | impl Foo for FooTypeForMethod {
|
||||
| _^ starting here...
|
||||
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
|
||||
|
||||
error[E0046]: not all trait items implemented, missing: `fmt`
|
||||
--> $DIR/impl-wrong-item-for-trait.rs:53:1
|
||||
|
|
||||
53 | impl Debug for FooTypeForMethod {
|
||||
| ^ missing `fmt` in implementation
|
||||
53 | impl Debug for FooTypeForMethod {
|
||||
| _^ starting here...
|
||||
54 | | }
|
||||
| |_^ ...ending here: missing `fmt` in implementation
|
||||
|
|
||||
= note: `fmt` from trait: `fn(&Self, &mut std::fmt::Formatter<'_>) -> std::result::Result<(), std::fmt::Error>`
|
||||
|
||||
|
@ -1,8 +1,16 @@
|
||||
error[E0046]: not all trait items implemented, missing: `Output`
|
||||
--> $DIR/issue-23827.rs:36:1
|
||||
|
|
||||
36 | impl<C: Component> FnOnce<(C,)> for Prototype {
|
||||
| ^ missing `Output` in implementation
|
||||
36 | impl<C: Component> FnOnce<(C,)> for Prototype {
|
||||
| _^ starting here...
|
||||
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
|
||||
|
|
||||
= note: `Output` from trait: `type Output;`
|
||||
|
||||
|
@ -1,8 +1,14 @@
|
||||
error[E0046]: not all trait items implemented, missing: `Target`
|
||||
--> $DIR/issue-24356.rs:30:9
|
||||
|
|
||||
30 | impl Deref for Thing {
|
||||
| ^ missing `Target` in implementation
|
||||
30 | impl Deref for Thing {
|
||||
| _________^ starting here...
|
||||
31 | | //~^ ERROR E0046
|
||||
32 | | //~| NOTE missing `Target` in implementation
|
||||
33 | | //~| NOTE `Target` from trait: `type Target;`
|
||||
34 | | fn deref(&self) -> i8 { self.0 }
|
||||
35 | | }
|
||||
| |_________^ ...ending here: missing `Target` in implementation
|
||||
|
|
||||
= note: `Target` from trait: `type Target;`
|
||||
|
||||
|
30
src/test/ui/span/multiline-span-simple.rs
Normal file
30
src/test/ui/span/multiline-span-simple.rs
Normal file
@ -0,0 +1,30 @@
|
||||
// Copyright 2016 The Rust Project Developers. See the COPYRIGHT
|
||||
// file at the top-level directory of this distribution and at
|
||||
// http://rust-lang.org/COPYRIGHT.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
|
||||
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
|
||||
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
|
||||
// option. This file may not be copied, modified, or distributed
|
||||
// except according to those terms.
|
||||
|
||||
fn foo(a: u32, b: u32) {
|
||||
a + b;
|
||||
}
|
||||
|
||||
fn bar(a: u32, b: u32) {
|
||||
a + b;
|
||||
}
|
||||
|
||||
fn main() {
|
||||
let x = 1;
|
||||
let y = 2;
|
||||
let z = 3;
|
||||
foo(1 as u32 +
|
||||
|
||||
bar(x,
|
||||
|
||||
y),
|
||||
|
||||
z)
|
||||
}
|
19
src/test/ui/span/multiline-span-simple.stderr
Normal file
19
src/test/ui/span/multiline-span-simple.stderr
Normal file
@ -0,0 +1,19 @@
|
||||
error[E0277]: the trait bound `u32: std::ops::Add<()>` is not satisfied
|
||||
--> $DIR/multiline-span-simple.rs:23:9
|
||||
|
|
||||
23 | foo(1 as u32 +
|
||||
| _________^ starting here...
|
||||
24 | |
|
||||
25 | | bar(x,
|
||||
26 | |
|
||||
27 | | y),
|
||||
| |______________^ ...ending here: the trait `std::ops::Add<()>` is not implemented for `u32`
|
||||
|
|
||||
= help: the following implementations were found:
|
||||
= help: <u32 as std::ops::Add>
|
||||
= help: <&'a u32 as std::ops::Add<u32>>
|
||||
= help: <u32 as std::ops::Add<&'a u32>>
|
||||
= help: <&'b u32 as std::ops::Add<&'a u32>>
|
||||
|
||||
error: aborting due to previous error
|
||||
|
Loading…
x
Reference in New Issue
Block a user