Skip to content

Add support for elision in structured error messages #1

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
75 changes: 72 additions & 3 deletions src/libsyntax/errors/snippet/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -55,6 +55,7 @@ pub struct RenderedLine {
pub enum RenderedLineKind {
SourceText,
Highlights,
Elision,
}
use self::RenderedLineKind::*;

Expand Down Expand Up @@ -98,9 +99,77 @@ impl SnippetData {
}

pub fn render_lines(&self) -> Vec<RenderedLine> {
self.lines.iter()
.flat_map(|line| self.render_line(line))
.collect()
let mut line_groups = vec![];

//Group our lines by those with annotations and those without
let mut lines_iter = self.lines.iter().peekable();

loop {
match lines_iter.next() {
None => break,
Some(line) if line.annotations.is_empty() => {
// Collect unannotated group
let mut unannotated_group : Vec<&Line> = vec![];

unannotated_group.push(line);

loop {
let next_line =
match lines_iter.peek() {
None => break,
Some(x) if !x.annotations.is_empty() => break,
Some(x) => x.clone()
};

unannotated_group.push(next_line);
lines_iter.next();
}

line_groups.push((false, unannotated_group));
}
Some(line) => {
// Collect annotated group
let mut annotated_group : Vec<&Line> = vec![];

annotated_group.push(line);

loop {
let next_line =
match lines_iter.peek() {
None => break,
Some(x) if x.annotations.is_empty() => break,
Some(x) => x.clone()
};

annotated_group.push(next_line);
lines_iter.next();
}

line_groups.push((true, annotated_group));
}
}
}

let mut output = vec![];
for &(is_annotated, ref group) in line_groups.iter() {
if is_annotated {
let mut v: Vec<RenderedLine> =
group.iter().flat_map(|line| self.render_line(line)).collect();
output.append(&mut v);
}
else {
if group.len() > 1 {
output.push(RenderedLine::from((String::from("..."), Elision)));
}
else {
let mut v: Vec<RenderedLine> =
group.iter().flat_map(|line| self.render_line(line)).collect();
output.append(&mut v);
}
}
}

output
}

fn render_line(&self, line: &Line) -> Vec<RenderedLine> {
Expand Down
73 changes: 53 additions & 20 deletions src/libsyntax/errors/snippet/test.rs
Original file line number Diff line number Diff line change
Expand Up @@ -128,12 +128,8 @@ fn foo() {
kind: Highlights
},
RenderedLine {
text: "",
kind: SourceText
},
RenderedLine {
text: " // Add one more item we forgot to the vector. Silly us.",
kind: SourceText
text: "...",
kind: Elision
},
RenderedLine {
text: " data.push(Data { name: format!(\"Hera\"), id: 66 });",
Expand All @@ -144,20 +140,8 @@ fn foo() {
kind: Highlights
},
RenderedLine {
text: "",
kind: SourceText
},
RenderedLine {
text: " // Print everything out.",
kind: SourceText
},
RenderedLine {
text: " println!(\"Name: {:?}\", name);",
kind: SourceText
},
RenderedLine {
text: " println!(\"Data: {:?}\", data);",
kind: SourceText
text: "...",
kind: Elision
},
RenderedLine {
text: "}",
Expand Down Expand Up @@ -269,3 +253,52 @@ fn foo() {
]"#);
}

#[test]
fn elide_unnecessary_lines() {
let file_text = r#"
fn foo() {
let mut vec = vec![0, 1, 2];
let mut vec2 = vec;
vec2.push(3);
vec2.push(4);
vec2.push(5);
vec2.push(6);
vec.push(7);
}
"#;

let cm = Rc::new(CodeMap::new());
cm.new_filemap_and_lines("foo.rs", file_text);
let span_vec0 = cm.span_substr(file_text, "vec", 3);
let span_vec1 = cm.span_substr(file_text, "vec", 8);

let mut snippet = SnippetData::new(cm);
snippet.push(span_vec0, Some(format!("`vec` moved here because it has type `collections::vec::Vec<i32>`, which is moved by default")));
snippet.push(span_vec1, Some(format!("use of moved value: `vec`")));

let lines = snippet.render_lines();
println!("{:#?}", lines);
assert_eq!(format!("\n{:#?}", lines), r#"
[
RenderedLine {
text: " let mut vec2 = vec;",
kind: SourceText
},
RenderedLine {
text: " ~~~ `vec` moved here because it has type `collections::vec::Vec<i32>`, which is moved by default",
kind: Highlights
},
RenderedLine {
text: "...",
kind: Elision
},
RenderedLine {
text: " vec.push(7);",
kind: SourceText
},
RenderedLine {
text: " ~~~ use of moved value: `vec`",
kind: Highlights
}
]"#);
}