1
Fork 0

DCE and fixing some internal tests

This commit is contained in:
Jonathan Turner 2016-07-12 15:18:16 -04:00
parent f481879d2a
commit 2f2c3e1783
4 changed files with 132 additions and 1213 deletions

View file

@ -14,13 +14,12 @@ use syntax_pos::{COMMAND_LINE_SP, DUMMY_SP, FileMap, Span, MultiSpan, LineInfo,
use registry; use registry;
use check_old_skool; use check_old_skool;
use {Level, RenderSpan, CodeSuggestion, DiagnosticBuilder, CodeMapper}; use {Level, CodeSuggestion, DiagnosticBuilder, CodeMapper};
use RenderSpan::*; use RenderSpan::*;
use Level::*; use snippet::{StyledString, Style, FormatMode, Annotation, Line};
use snippet::{SnippetData, StyledString, Style, FormatMode, Annotation, Line};
use styled_buffer::StyledBuffer; use styled_buffer::StyledBuffer;
use std::{cmp, fmt}; use std::cmp;
use std::io::prelude::*; use std::io::prelude::*;
use std::io; use std::io;
use std::rc::Rc; use std::rc::Rc;
@ -73,10 +72,6 @@ pub struct EmitterWriter {
registry: Option<registry::Registry>, registry: Option<registry::Registry>,
cm: Option<Rc<CodeMapper>>, cm: Option<Rc<CodeMapper>>,
/// Is this the first error emitted thus far? If not, we emit a
/// `\n` before the top-level errors.
first: bool,
// For now, allow an old-school mode while we transition // For now, allow an old-school mode while we transition
format_mode: FormatMode format_mode: FormatMode
} }
@ -112,13 +107,11 @@ impl EmitterWriter {
EmitterWriter { dst: dst, EmitterWriter { dst: dst,
registry: registry, registry: registry,
cm: code_map, cm: code_map,
first: true,
format_mode: format_mode.clone() } format_mode: format_mode.clone() }
} else { } else {
EmitterWriter { dst: Raw(Box::new(io::stderr())), EmitterWriter { dst: Raw(Box::new(io::stderr())),
registry: registry, registry: registry,
cm: code_map, cm: code_map,
first: true,
format_mode: format_mode.clone() } format_mode: format_mode.clone() }
} }
} }
@ -131,23 +124,9 @@ impl EmitterWriter {
EmitterWriter { dst: Raw(dst), EmitterWriter { dst: Raw(dst),
registry: registry, registry: registry,
cm: code_map, cm: code_map,
first: true,
format_mode: format_mode.clone() } format_mode: format_mode.clone() }
} }
fn emit_message(&mut self,
rsp: &RenderSpan,
msg: &str,
code: Option<&str>,
lvl: Level,
is_header: bool,
show_snippet: bool) {
match self.emit_message_(rsp, msg, code, lvl, is_header, show_snippet) {
Ok(()) => { }
Err(e) => panic!("failed to emit error: {}", e)
}
}
fn preprocess_annotations(&self, msp: &MultiSpan) -> Vec<FileWithAnnotatedLines> { fn preprocess_annotations(&self, msp: &MultiSpan) -> Vec<FileWithAnnotatedLines> {
fn add_annotation_to_file(file_vec: &mut Vec<FileWithAnnotatedLines>, fn add_annotation_to_file(file_vec: &mut Vec<FileWithAnnotatedLines>,
file: Rc<FileMap>, file: Rc<FileMap>,
@ -187,7 +166,7 @@ impl EmitterWriter {
if let Some(ref cm) = self.cm { if let Some(ref cm) = self.cm {
for span_label in msp.span_labels() { for span_label in msp.span_labels() {
let mut lo = cm.lookup_char_pos(span_label.span.lo); let lo = cm.lookup_char_pos(span_label.span.lo);
let mut hi = cm.lookup_char_pos(span_label.span.hi); let mut hi = cm.lookup_char_pos(span_label.span.hi);
let mut is_minimized = false; let mut is_minimized = false;
@ -478,7 +457,7 @@ impl EmitterWriter {
if msp.primary_spans().is_empty() && msp.span_labels().is_empty() && is_secondary { if msp.primary_spans().is_empty() && msp.span_labels().is_empty() && is_secondary {
// This is a secondary message with no span info // This is a secondary message with no span info
for i in 0..max_line_num_len { for _ in 0..max_line_num_len {
buffer.prepend(0, " ", Style::NoStyle); buffer.prepend(0, " ", Style::NoStyle);
} }
draw_note_separator(&mut buffer, 0, max_line_num_len + 1); draw_note_separator(&mut buffer, 0, max_line_num_len + 1);
@ -511,7 +490,7 @@ impl EmitterWriter {
cm.lookup_char_pos(primary_span.lo) cm.lookup_char_pos(primary_span.lo)
} else { } else {
// If we don't have span information, emit and exit // If we don't have span information, emit and exit
emit_to_destination(&buffer.render(), level, &mut self.dst); emit_to_destination(&buffer.render(), level, &mut self.dst)?;
return Ok(()); return Ok(());
}; };
if let Ok(pos) = if let Ok(pos) =
@ -526,19 +505,19 @@ impl EmitterWriter {
let is_primary = primary_lo.file.name == annotated_file.file.name; let is_primary = primary_lo.file.name == annotated_file.file.name;
if is_primary { if is_primary {
// remember where we are in the output buffer for easy reference // remember where we are in the output buffer for easy reference
let mut buffer_msg_line_offset = buffer.num_lines(); let buffer_msg_line_offset = buffer.num_lines();
buffer.prepend(buffer_msg_line_offset, "--> ", Style::LineNumber); buffer.prepend(buffer_msg_line_offset, "--> ", Style::LineNumber);
let loc = primary_lo.clone(); let loc = primary_lo.clone();
buffer.append(buffer_msg_line_offset, buffer.append(buffer_msg_line_offset,
&format!("{}:{}:{}", loc.file.name, loc.line, loc.col.0 + 1), &format!("{}:{}:{}", loc.file.name, loc.line, loc.col.0 + 1),
Style::LineAndColumn); Style::LineAndColumn);
for i in 0..max_line_num_len { for _ in 0..max_line_num_len {
buffer.prepend(buffer_msg_line_offset, " ", Style::NoStyle); buffer.prepend(buffer_msg_line_offset, " ", Style::NoStyle);
} }
} else { } else {
// remember where we are in the output buffer for easy reference // remember where we are in the output buffer for easy reference
let mut buffer_msg_line_offset = buffer.num_lines(); let buffer_msg_line_offset = buffer.num_lines();
// Add spacing line // Add spacing line
draw_col_separator(&mut buffer, buffer_msg_line_offset, max_line_num_len + 1); draw_col_separator(&mut buffer, buffer_msg_line_offset, max_line_num_len + 1);
@ -548,13 +527,13 @@ impl EmitterWriter {
buffer.append(buffer_msg_line_offset + 1, buffer.append(buffer_msg_line_offset + 1,
&annotated_file.file.name, &annotated_file.file.name,
Style::LineAndColumn); Style::LineAndColumn);
for i in 0..max_line_num_len { for _ in 0..max_line_num_len {
buffer.prepend(buffer_msg_line_offset + 1, " ", Style::NoStyle); buffer.prepend(buffer_msg_line_offset + 1, " ", Style::NoStyle);
} }
} }
// Put in the spacer between the location and annotated source // Put in the spacer between the location and annotated source
let mut buffer_msg_line_offset = buffer.num_lines(); let buffer_msg_line_offset = buffer.num_lines();
draw_col_separator(&mut buffer, buffer_msg_line_offset, max_line_num_len + 1); draw_col_separator(&mut buffer, buffer_msg_line_offset, max_line_num_len + 1);
// Next, output the annotate source for this file // Next, output the annotate source for this file
@ -599,7 +578,7 @@ impl EmitterWriter {
} }
// final step: take our styled buffer, render it, then output it // final step: take our styled buffer, render it, then output it
emit_to_destination(&buffer.render(), level, &mut self.dst); emit_to_destination(&buffer.render(), level, &mut self.dst)?;
Ok(()) Ok(())
} }
@ -624,12 +603,6 @@ impl EmitterWriter {
assert!(!lines.lines.is_empty()); assert!(!lines.lines.is_empty());
let complete = suggestion.splice_lines(cm.borrow()); let complete = suggestion.splice_lines(cm.borrow());
let line_count = cmp::min(lines.lines.len(), MAX_HIGHLIGHT_LINES);
let display_lines = &lines.lines[..line_count];
let fm = &*lines.file;
// Calculate the widest number to format evenly
let max_digits = line_num_max_digits(display_lines.last().unwrap());
// print the suggestion without any line numbers, but leave // print the suggestion without any line numbers, but leave
// space for them. This helps with lining up with previous // space for them. This helps with lining up with previous
@ -646,7 +619,7 @@ impl EmitterWriter {
if let Some(_) = lines.next() { if let Some(_) = lines.next() {
buffer.append(row_num, "...", Style::NoStyle); buffer.append(row_num, "...", Style::NoStyle);
} }
emit_to_destination(&buffer.render(), level, &mut self.dst); emit_to_destination(&buffer.render(), level, &mut self.dst)?;
} }
Ok(()) Ok(())
} }
@ -664,7 +637,10 @@ impl EmitterWriter {
if !db.children.is_empty() { if !db.children.is_empty() {
let mut buffer = StyledBuffer::new(); let mut buffer = StyledBuffer::new();
draw_col_separator(&mut buffer, 0, max_line_num_len + 1); draw_col_separator(&mut buffer, 0, max_line_num_len + 1);
emit_to_destination(&buffer.render(), &db.level, &mut self.dst); match emit_to_destination(&buffer.render(), &db.level, &mut self.dst) {
Ok(()) => (),
Err(e) => panic!("failed to emit error: {}", e)
}
} }
for child in &db.children { for child in &db.children {
match child.render_span { match child.render_span {
@ -704,7 +680,10 @@ impl EmitterWriter {
} }
Err(e) => panic!("failed to emit error: {}", e) Err(e) => panic!("failed to emit error: {}", e)
} }
write!(&mut self.dst, "\n"); match write!(&mut self.dst, "\n") {
Err(e) => panic!("failed to emit error: {}", e),
_ => ()
}
} }
fn emit_message_old_school(&mut self, fn emit_message_old_school(&mut self,
msp: &MultiSpan, msp: &MultiSpan,
@ -744,7 +723,7 @@ impl EmitterWriter {
} }
if !show_snippet { if !show_snippet {
emit_to_destination(&buffer.render(), level, &mut self.dst); emit_to_destination(&buffer.render(), level, &mut self.dst)?;
return Ok(()); return Ok(());
} }
@ -752,13 +731,13 @@ impl EmitterWriter {
// print any filename or anything for those. // print any filename or anything for those.
match msp.primary_span() { match msp.primary_span() {
Some(COMMAND_LINE_SP) | Some(DUMMY_SP) => { Some(COMMAND_LINE_SP) | Some(DUMMY_SP) => {
emit_to_destination(&buffer.render(), level, &mut self.dst); emit_to_destination(&buffer.render(), level, &mut self.dst)?;
return Ok(()); return Ok(());
} }
_ => { } _ => { }
} }
let mut annotated_files = self.preprocess_annotations(msp); let annotated_files = self.preprocess_annotations(msp);
if let (Some(ref cm), Some(ann_file), Some(ref primary_span)) = if let (Some(ref cm), Some(ann_file), Some(ref primary_span)) =
(self.cm.as_ref(), annotated_files.first(), msp.primary_span().as_ref()) { (self.cm.as_ref(), annotated_files.first(), msp.primary_span().as_ref()) {
@ -781,7 +760,7 @@ impl EmitterWriter {
buffer.puts(line_offset, 0, &file_pos, Style::FileNameStyle); buffer.puts(line_offset, 0, &file_pos, Style::FileNameStyle);
buffer.puts(line_offset, file_pos_len, &source_string, Style::Quotation); buffer.puts(line_offset, file_pos_len, &source_string, Style::Quotation);
// Sort the annotations by (start, end col) // Sort the annotations by (start, end col)
let mut annotations = ann_file.lines[0].annotations.clone(); let annotations = ann_file.lines[0].annotations.clone();
// Next, create the highlight line. // Next, create the highlight line.
for annotation in &annotations { for annotation in &annotations {
@ -830,7 +809,7 @@ impl EmitterWriter {
} }
// final step: take our styled buffer, render it, then output it // final step: take our styled buffer, render it, then output it
emit_to_destination(&buffer.render(), level, &mut self.dst); emit_to_destination(&buffer.render(), level, &mut self.dst)?;
Ok(()) Ok(())
} }
fn emit_suggestion_old_school(&mut self, fn emit_suggestion_old_school(&mut self,
@ -874,7 +853,7 @@ impl EmitterWriter {
let mut row_num = 1; let mut row_num = 1;
for line in lines.by_ref().take(MAX_HIGHLIGHT_LINES) { for line in lines.by_ref().take(MAX_HIGHLIGHT_LINES) {
buffer.append(row_num, &fm.name, Style::FileNameStyle); buffer.append(row_num, &fm.name, Style::FileNameStyle);
for i in 0..max_digits+2 { for _ in 0..max_digits+2 {
buffer.append(row_num, &" ", Style::NoStyle); buffer.append(row_num, &" ", Style::NoStyle);
} }
buffer.append(row_num, line, Style::NoStyle); buffer.append(row_num, line, Style::NoStyle);
@ -885,7 +864,7 @@ impl EmitterWriter {
if let Some(_) = lines.next() { if let Some(_) = lines.next() {
buffer.append(row_num, "...", Style::NoStyle); buffer.append(row_num, "...", Style::NoStyle);
} }
emit_to_destination(&buffer.render(), level, &mut self.dst); emit_to_destination(&buffer.render(), level, &mut self.dst)?;
} }
Ok(()) Ok(())
} }
@ -905,7 +884,7 @@ impl EmitterWriter {
}; };
match child.render_span { match child.render_span {
Some(FullSpan(ref msp)) => { Some(FullSpan(_)) => {
match self.emit_message_old_school(&span, match self.emit_message_old_school(&span,
&child.message, &child.message,
&None, &None,
@ -940,235 +919,6 @@ impl EmitterWriter {
} }
} }
fn emit_message_(&mut self,
rsp: &RenderSpan,
msg: &str,
code: Option<&str>,
lvl: Level,
is_header: bool,
show_snippet: bool)
-> io::Result<()> {
let old_school = match self.format_mode {
FormatMode::NewErrorFormat => false,
FormatMode::OriginalErrorFormat => true,
FormatMode::EnvironmentSelected => check_old_skool()
};
if is_header {
if self.first {
self.first = false;
} else {
if !old_school {
write!(self.dst, "\n")?;
}
}
}
match code {
Some(code) if self.registry.as_ref()
.and_then(|registry| registry.find_description(code))
.is_some() => {
let code_with_explain = String::from("--explain ") + code;
if old_school {
let loc = match rsp.span().primary_span() {
Some(COMMAND_LINE_SP) | Some(DUMMY_SP) => "".to_string(),
Some(ps) => if let Some(ref cm) = self.cm {
cm.span_to_string(ps)
} else {
"".to_string()
},
None => "".to_string()
};
print_diagnostic(&mut self.dst, &loc, lvl, msg, Some(code))?
}
else {
print_diagnostic(&mut self.dst, "", lvl, msg, Some(&code_with_explain))?
}
}
_ => {
if old_school {
let loc = match rsp.span().primary_span() {
Some(COMMAND_LINE_SP) | Some(DUMMY_SP) => "".to_string(),
Some(ps) => if let Some(ref cm) = self.cm {
cm.span_to_string(ps)
} else {
"".to_string()
},
None => "".to_string()
};
print_diagnostic(&mut self.dst, &loc, lvl, msg, code)?
}
else {
print_diagnostic(&mut self.dst, "", lvl, msg, code)?
}
}
}
if !show_snippet {
return Ok(());
}
// Watch out for various nasty special spans; don't try to
// print any filename or anything for those.
match rsp.span().primary_span() {
Some(COMMAND_LINE_SP) | Some(DUMMY_SP) => {
return Ok(());
}
_ => { }
}
// Otherwise, print out the snippet etc as needed.
match *rsp {
FullSpan(ref msp) => {
self.highlight_lines(msp, lvl)?;
if let Some(primary_span) = msp.primary_span() {
self.print_macro_backtrace(primary_span)?;
}
}
Suggestion(ref suggestion) => {
self.highlight_suggestion(suggestion)?;
if let Some(primary_span) = rsp.span().primary_span() {
self.print_macro_backtrace(primary_span)?;
}
}
}
if old_school {
match code {
Some(code) if self.registry.as_ref()
.and_then(|registry| registry.find_description(code))
.is_some() => {
let loc = match rsp.span().primary_span() {
Some(COMMAND_LINE_SP) | Some(DUMMY_SP) => "".to_string(),
Some(ps) => if let Some(ref cm) = self.cm {
cm.span_to_string(ps)
} else {
"".to_string()
},
None => "".to_string()
};
let msg = "run `rustc --explain ".to_string() + &code.to_string() +
"` to see a detailed explanation";
print_diagnostic(&mut self.dst, &loc, Level::Help, &msg,
None)?
}
_ => ()
}
}
Ok(())
}
fn highlight_suggestion(&mut self, suggestion: &CodeSuggestion) -> io::Result<()>
{
use std::borrow::Borrow;
let primary_span = suggestion.msp.primary_span().unwrap();
if let Some(ref cm) = self.cm {
let lines = cm.span_to_lines(primary_span).unwrap();
assert!(!lines.lines.is_empty());
let complete = suggestion.splice_lines(cm.borrow());
let line_count = cmp::min(lines.lines.len(), MAX_HIGHLIGHT_LINES);
let display_lines = &lines.lines[..line_count];
let fm = &*lines.file;
// Calculate the widest number to format evenly
let max_digits = line_num_max_digits(display_lines.last().unwrap());
// print the suggestion without any line numbers, but leave
// space for them. This helps with lining up with previous
// snippets from the actual error being reported.
let mut lines = complete.lines();
for line in lines.by_ref().take(MAX_HIGHLIGHT_LINES) {
write!(&mut self.dst, "{0}:{1:2$} {3}\n",
fm.name, "", max_digits, line)?;
}
// if we elided some lines, add an ellipsis
if let Some(_) = lines.next() {
write!(&mut self.dst, "{0:1$} {0:2$} ...\n",
"", fm.name.len(), max_digits)?;
}
}
Ok(())
}
pub fn highlight_lines(&mut self,
msp: &MultiSpan,
lvl: Level)
-> io::Result<()>
{
// Check to see if we have any lines to highlight, exit early if not
match self.cm {
None => return Ok(()),
_ => ()
}
let old_school = match self.format_mode {
FormatMode::NewErrorFormat => false,
FormatMode::OriginalErrorFormat => true,
FormatMode::EnvironmentSelected => check_old_skool()
};
let mut snippet_data = SnippetData::new(self.cm.as_ref().unwrap().clone(),
msp.primary_span(),
self.format_mode.clone());
if old_school {
let mut output_vec = vec![];
for span_label in msp.span_labels() {
let mut snippet_data = SnippetData::new(self.cm.as_ref().unwrap().clone(),
Some(span_label.span),
self.format_mode.clone());
snippet_data.push(span_label.span,
span_label.is_primary,
span_label.label);
if span_label.is_primary {
output_vec.insert(0, snippet_data);
}
else {
output_vec.push(snippet_data);
}
}
for snippet_data in output_vec.iter() {
/*
let rendered_lines = snippet_data.render_lines();
for rendered_line in &rendered_lines {
for styled_string in &rendered_line.text {
self.dst.apply_style(lvl, &rendered_line.kind, styled_string.style)?;
write!(&mut self.dst, "{}", styled_string.text)?;
self.dst.reset_attrs()?;
}
write!(&mut self.dst, "\n")?;
}
*/
emit_to_destination(&snippet_data.render_lines(), &lvl, &mut self.dst);
}
}
else {
for span_label in msp.span_labels() {
snippet_data.push(span_label.span,
span_label.is_primary,
span_label.label);
}
emit_to_destination(&snippet_data.render_lines(), &lvl, &mut self.dst);
/*
let rendered_lines = snippet_data.render_lines();
for rendered_line in &rendered_lines {
for styled_string in &rendered_line.text {
self.dst.apply_style(lvl, &rendered_line.kind, styled_string.style)?;
write!(&mut self.dst, "{}", styled_string.text)?;
self.dst.reset_attrs()?;
}
write!(&mut self.dst, "\n")?;
}
*/
}
Ok(())
}
fn render_macro_backtrace_old_school(&mut self, fn render_macro_backtrace_old_school(&mut self,
sp: &Span, sp: &Span,
buffer: &mut StyledBuffer) -> io::Result<()> { buffer: &mut StyledBuffer) -> io::Result<()> {
@ -1192,24 +942,6 @@ impl EmitterWriter {
} }
Ok(()) Ok(())
} }
fn print_macro_backtrace(&mut self,
sp: Span)
-> io::Result<()> {
if let Some(ref cm) = self.cm {
for trace in cm.macro_backtrace(sp) {
let mut diag_string =
format!("in this expansion of {}", trace.macro_decl_name);
if let Some(def_site_span) = trace.def_site_span {
diag_string.push_str(
&format!(" (defined in {})",
cm.span_to_filename(def_site_span)));
}
let snippet = cm.span_to_string(trace.call_site);
print_diagnostic(&mut self.dst, &snippet, Note, &diag_string, None)?;
}
}
Ok(())
}
} }
fn draw_col_separator(buffer: &mut StyledBuffer, line: usize, col: usize) { fn draw_col_separator(buffer: &mut StyledBuffer, line: usize, col: usize) {
@ -1230,11 +962,11 @@ fn emit_to_destination(rendered_buffer: &Vec<Vec<StyledString>>,
dst: &mut Destination) -> io::Result<()> { dst: &mut Destination) -> io::Result<()> {
for line in rendered_buffer { for line in rendered_buffer {
for part in line { for part in line {
dst.apply_style(lvl.clone(), part.style); dst.apply_style(lvl.clone(), part.style)?;
write!(dst, "{}", part.text); write!(dst, "{}", part.text)?;
dst.reset_attrs()?; dst.reset_attrs()?;
} }
write!(dst, "\n"); write!(dst, "\n")?;
} }
Ok(()) Ok(())
} }
@ -1249,40 +981,6 @@ fn line_num_max_digits(line: &LineInfo) -> usize {
digits digits
} }
fn print_diagnostic(dst: &mut Destination,
topic: &str,
lvl: Level,
msg: &str,
code: Option<&str>)
-> io::Result<()> {
if !topic.is_empty() {
let old_school = check_old_skool();
if !old_school {
write!(dst, "{}: ", topic)?;
}
else {
write!(dst, "{} ", topic)?;
}
dst.reset_attrs()?;
}
dst.start_attr(term::Attr::Bold)?;
dst.start_attr(term::Attr::ForegroundColor(lvl.color()))?;
write!(dst, "{}", lvl.to_string())?;
dst.reset_attrs()?;
write!(dst, ": ")?;
dst.start_attr(term::Attr::Bold)?;
write!(dst, "{}", msg)?;
if let Some(code) = code {
let style = term::Attr::ForegroundColor(term::color::BRIGHT_MAGENTA);
print_maybe_styled!(dst, style, " [{}]", code.clone())?;
}
dst.reset_attrs()?;
write!(dst, "\n")?;
Ok(())
}
#[cfg(unix)] #[cfg(unix)]
fn stderr_isatty() -> bool { fn stderr_isatty() -> bool {
use libc; use libc;
@ -1374,46 +1072,6 @@ impl Destination {
} }
Ok(()) Ok(())
} }
fn print_maybe_styled(&mut self,
args: fmt::Arguments,
color: term::Attr,
print_newline_at_end: bool)
-> io::Result<()> {
match *self {
Terminal(ref mut t) => {
t.attr(color)?;
// If `msg` ends in a newline, we need to reset the color before
// the newline. We're making the assumption that we end up writing
// to a `LineBufferedWriter`, which means that emitting the reset
// after the newline ends up buffering the reset until we print
// another line or exit. Buffering the reset is a problem if we're
// sharing the terminal with any other programs (e.g. other rustc
// instances via `make -jN`).
//
// Note that if `msg` contains any internal newlines, this will
// result in the `LineBufferedWriter` flushing twice instead of
// once, which still leaves the opportunity for interleaved output
// to be miscolored. We assume this is rare enough that we don't
// have to worry about it.
t.write_fmt(args)?;
t.reset()?;
if print_newline_at_end {
t.write_all(b"\n")
} else {
Ok(())
}
}
Raw(ref mut w) => {
w.write_fmt(args)?;
if print_newline_at_end {
w.write_all(b"\n")
} else {
Ok(())
}
}
}
}
} }
impl Write for Destination { impl Write for Destination {

View file

@ -82,16 +82,6 @@ pub trait CodeMapper {
fn macro_backtrace(&self, span: Span) -> Vec<MacroBacktrace>; fn macro_backtrace(&self, span: Span) -> Vec<MacroBacktrace>;
} }
impl RenderSpan {
fn span(&self) -> &MultiSpan {
match *self {
FullSpan(ref msp) |
Suggestion(CodeSuggestion { ref msp, .. }) =>
msp
}
}
}
impl CodeSuggestion { impl CodeSuggestion {
/// Returns the assembled code suggestion. /// Returns the assembled code suggestion.
pub fn splice_lines(&self, cm: &CodeMapper) -> String { pub fn splice_lines(&self, cm: &CodeMapper) -> String {

View file

@ -10,13 +10,9 @@
// Code for annotating snippets. // Code for annotating snippets.
use syntax_pos::{Span, FileMap, CharPos, LineInfo}; use syntax_pos::{Span, FileMap};
use check_old_skool;
use CodeMapper; use CodeMapper;
use styled_buffer::StyledBuffer;
use std::cmp;
use std::rc::Rc; use std::rc::Rc;
use std::mem;
use {Level}; use {Level};
#[derive(Clone)] #[derive(Clone)]
@ -78,14 +74,6 @@ pub struct Annotation {
pub label: Option<String>, pub label: Option<String>,
} }
/*
#[derive(Debug)]
pub struct RenderedLine {
pub text: Vec<StyledString>,
pub kind: RenderedLineKind,
}
*/
#[derive(Debug)] #[derive(Debug)]
pub struct StyledString { pub struct StyledString {
pub text: String, pub text: String,
@ -109,720 +97,3 @@ pub enum Style {
ErrorCode, ErrorCode,
Level(Level), Level(Level),
} }
/*
#[derive(Debug, Clone)]
pub enum RenderedLineKind {
PrimaryFileName,
OtherFileName,
SourceText {
file: Rc<FileMap>,
line_index: usize,
},
Annotations,
Elision,
}
*/
impl SnippetData {
pub fn new(codemap: Rc<CodeMapper>,
primary_span: Option<Span>,
format_mode: FormatMode) // (*)
-> Self {
// (*) The primary span indicates the file that must appear
// first, and which will have a line number etc in its
// name. Outside of tests, this is always `Some`, but for many
// tests it's not relevant to test this portion of the logic,
// and it's tedious to pick a primary span (read: tedious to
// port older tests that predate the existence of a primary
// span).
debug!("SnippetData::new(primary_span={:?})", primary_span);
let mut data = SnippetData {
codemap: codemap.clone(),
files: vec![],
format_mode: format_mode.clone()
};
if let Some(primary_span) = primary_span {
let lo = codemap.lookup_char_pos(primary_span.lo);
data.files.push(
FileInfo {
file: lo.file,
primary_span: Some(primary_span),
lines: vec![],
format_mode: format_mode.clone(),
});
}
data
}
pub fn push(&mut self, span: Span, is_primary: bool, label: Option<String>) {
debug!("SnippetData::push(span={:?}, is_primary={}, label={:?})",
span, is_primary, label);
let file_lines = match self.codemap.span_to_lines(span) {
Ok(file_lines) => file_lines,
Err(_) => {
// ignore unprintable spans completely.
return;
}
};
self.file(&file_lines.file)
.push_lines(&file_lines.lines, is_primary, label);
}
fn file(&mut self, file_map: &Rc<FileMap>) -> &mut FileInfo {
let index = self.files.iter().position(|f| f.file.name == file_map.name);
if let Some(index) = index {
return &mut self.files[index];
}
self.files.push(
FileInfo {
file: file_map.clone(),
lines: vec![],
primary_span: None,
format_mode: self.format_mode.clone()
});
self.files.last_mut().unwrap()
}
pub fn render_lines(&self) -> Vec<Vec<StyledString>> {
debug!("SnippetData::render_lines()");
let mut rendered_lines: Vec<_> =
self.files.iter()
.flat_map(|f| f.render_file_lines(&self.codemap))
.collect();
//prepend_prefixes(&mut rendered_lines, &self.format_mode);
//trim_lines(&mut rendered_lines);
rendered_lines
}
}
pub trait StringSource {
fn make_string(self) -> String;
}
impl StringSource for String {
fn make_string(self) -> String {
self
}
}
impl StringSource for Vec<char> {
fn make_string(self) -> String {
self.into_iter().collect()
}
}
/*
impl<S> From<(S, Style, RenderedLineKind)> for RenderedLine
where S: StringSource
{
fn from((text, style, kind): (S, Style, RenderedLineKind)) -> Self {
RenderedLine {
text: vec![StyledString {
text: text.make_string(),
style: style,
}],
kind: kind,
}
}
}
impl<S1,S2> From<(S1, Style, S2, Style, RenderedLineKind)> for RenderedLine
where S1: StringSource, S2: StringSource
{
fn from(tuple: (S1, Style, S2, Style, RenderedLineKind)) -> Self {
let (text1, style1, text2, style2, kind) = tuple;
RenderedLine {
text: vec![
StyledString {
text: text1.make_string(),
style: style1,
},
StyledString {
text: text2.make_string(),
style: style2,
}
],
kind: kind,
}
}
}
impl RenderedLine {
fn trim_last(&mut self) {
if let Some(last_text) = self.text.last_mut() {
let len = last_text.text.trim_right().len();
last_text.text.truncate(len);
}
}
}
impl RenderedLineKind {
fn prefix(&self) -> StyledString {
match *self {
RenderedLineKind::SourceText { file: _, line_index } =>
StyledString {
text: format!("{}", line_index + 1),
style: Style::LineNumber,
},
RenderedLineKind::Elision =>
StyledString {
text: String::from("..."),
style: Style::LineNumber,
},
RenderedLineKind::PrimaryFileName |
RenderedLineKind::OtherFileName |
RenderedLineKind::Annotations =>
StyledString {
text: String::from(""),
style: Style::LineNumber,
},
}
}
}
*/
impl FileInfo {
fn get_max_line_num(&self) -> usize {
let mut max = 0;
for line in &self.lines {
if line.line_index > max {
max = line.line_index;
}
}
max
}
fn push_lines(&mut self,
lines: &[LineInfo],
is_primary: bool,
label: Option<String>) {
assert!(lines.len() > 0);
// If a span covers multiple lines, we reduce it to a single
// point at the start of the span. This means that instead
// of producing output like this:
//
// ```
// --> foo.rs:2:1
// 2 |> fn conflicting_items<'grammar>(state: &LR0State<'grammar>)
// |> ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
// 3 |> -> Set<LR0Item<'grammar>>
// |> ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
// (and so on)
// ```
//
// we produce:
//
// ```
// --> foo.rs:2:1
// 2 |> fn conflicting_items<'grammar>(state: &LR0State<'grammar>)
// ^
// ```
//
// Basically, although this loses information, multi-line spans just
// never look good.
let (line, start_col, mut end_col, is_minimized) = if lines.len() == 1 {
(lines[0].line_index, lines[0].start_col, lines[0].end_col, false)
} else {
(lines[0].line_index, lines[0].start_col, CharPos(lines[0].start_col.0 + 1), 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
// 6..7. This is degenerate input, but it's best to degrade
// gracefully -- and the parser likes to suply a span like
// that for EOF, in particular.
if start_col == end_col {
end_col.0 += 1;
}
let index = self.ensure_source_line(line);
self.lines[index].push_annotation(start_col,
end_col,
is_primary,
is_minimized,
label);
}
/// Ensure that we have a `Line` struct corresponding to
/// `line_index` in the file. If we already have some other lines,
/// then this will add the intervening lines to ensure that we
/// have a complete snippet. (Note that when we finally display,
/// some of those lines may be elided.)
fn ensure_source_line(&mut self, line_index: usize) -> usize {
if self.lines.is_empty() {
self.lines.push(Line::new(line_index));
return 0;
}
// Find the range of lines we have thus far.
let first_line_index = self.lines.first().unwrap().line_index;
let last_line_index = self.lines.last().unwrap().line_index;
assert!(first_line_index <= last_line_index);
// If the new line is lower than all the lines we have thus
// far, then insert the new line and any intervening lines at
// the front. In a silly attempt at micro-optimization, we
// don't just call `insert` repeatedly, but instead make a new
// (empty) vector, pushing the new lines onto it, and then
// appending the old vector.
if line_index < first_line_index {
let lines = mem::replace(&mut self.lines, vec![]);
self.lines.extend(
(line_index .. first_line_index)
.map(|line| Line::new(line))
.chain(lines));
return 0;
}
// If the new line comes after the ones we have so far, insert
// lines for it.
if line_index > last_line_index {
self.lines.extend(
(last_line_index+1 .. line_index+1)
.map(|line| Line::new(line)));
return self.lines.len() - 1;
}
// Otherwise it should already exist.
return line_index - first_line_index;
}
fn render_file_lines(&self, codemap: &Rc<CodeMapper>) -> Vec<Vec<StyledString>> {
let old_school = match self.format_mode {
FormatMode::OriginalErrorFormat => true,
FormatMode::NewErrorFormat => false,
FormatMode::EnvironmentSelected => check_old_skool()
};
let mut lines_iter = self.lines.iter();
let mut output = vec![];
// First insert the name of the file.
if !old_school {
match self.primary_span {
Some(span) => {
let lo = codemap.lookup_char_pos(span.lo);
output.push(vec![StyledString {
text: lo.file.name.clone(),
style: Style::FileNameStyle,
}, StyledString {
text: format!(":{}:{}", lo.line, lo.col.0 + 1),
style: Style::LineAndColumn,
}]);
output.push(vec![StyledString {
text: "".to_string(),
style: Style::FileNameStyle,
}]);
}
None => {
output.push(vec![StyledString {
text: self.file.name.clone(),
style: Style::FileNameStyle,
}]);
output.push(vec![StyledString {
text: "".to_string(),
style: Style::FileNameStyle,
}]);
}
}
}
let mut next_line = lines_iter.next();
while next_line.is_some() {
// Consume lines with annotations.
while let Some(line) = next_line {
if line.annotations.is_empty() { break; }
let mut rendered_lines = self.render_line(line);
assert!(!rendered_lines.is_empty());
if old_school {
match self.primary_span {
Some(span) => {
let lo = codemap.lookup_char_pos(span.lo);
let hi = codemap.lookup_char_pos(span.hi);
//Before each secondary line in old skool-mode, print the label
//as an old-style note
if !line.annotations[0].is_primary {
if let Some(ann) = line.annotations[0].label.clone() {
output.push(vec![StyledString {
text: lo.file.name.clone(),
style: Style::FileNameStyle,
}, StyledString {
text: format!(":{}:{}: {}:{} ", lo.line, lo.col.0 + 1,
hi.line, hi.col.0+1),
style: Style::LineAndColumn,
}, StyledString {
text: format!("note: "),
style: Style::OldSchoolNote,
}, StyledString {
text: format!("{}", ann),
style: Style::OldSchoolNoteText,
}]);
}
}
rendered_lines[0].insert(0, StyledString {
text: format!(":{} ", lo.line),
style: Style::LineAndColumn,
});
rendered_lines[0].insert(0, StyledString {
text: lo.file.name.clone(),
style: Style::FileNameStyle,
});
let gap_amount =
rendered_lines[0][0].text.len() +
rendered_lines[0][1].text.len();
assert!(rendered_lines.len() >= 2,
"no annotations resulted from: {:?}",
line);
for i in 1..rendered_lines.len() {
rendered_lines[i].insert(0, StyledString {
text: vec![" "; gap_amount].join(""),
style: Style::NoStyle
});
}
}
_ =>()
}
}
output.append(&mut rendered_lines);
next_line = lines_iter.next();
}
// Emit lines without annotations, but only if they are
// followed by a line with an annotation.
let unannotated_line = next_line;
let mut unannotated_lines = 0;
while let Some(line) = next_line {
if !line.annotations.is_empty() { break; }
unannotated_lines += 1;
next_line = lines_iter.next();
}
if unannotated_lines > 1 {
output.push(vec![StyledString{ text: String::new(), style: Style::NoStyle}]);
} else if let Some(line) = unannotated_line {
output.append(&mut self.render_line(line));
}
}
output
}
fn render_line(&self, line: &Line) -> Vec<Vec<StyledString>> {
let old_school = match self.format_mode {
FormatMode::OriginalErrorFormat => true,
FormatMode::NewErrorFormat => false,
FormatMode::EnvironmentSelected => check_old_skool()
};
let source_string = self.file.get_line(line.line_index)
.unwrap_or("");
/*
let source_kind = RenderedLineKind::SourceText {
file: self.file.clone(),
line_index: line.line_index,
};
*/
let mut styled_buffer = StyledBuffer::new();
// First create the source line we will highlight.
styled_buffer.append(0, &source_string, Style::Quotation);
if line.annotations.is_empty() {
return styled_buffer.render();
}
// We want to display like this:
//
// vec.push(vec.pop().unwrap());
// --- ^^^ _ previous borrow ends here
// | |
// | error occurs here
// previous borrow of `vec` occurs here
//
// But there are some weird edge cases to be aware of:
//
// vec.push(vec.pop().unwrap());
// -------- - previous borrow ends here
// ||
// |this makes no sense
// 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 `~`.
//let mut highlight_line = Self::whitespace(&source_string);
// Sort the annotations by (start, end col)
let mut annotations = line.annotations.clone();
annotations.sort();
// Next, create the highlight line.
for annotation in &annotations {
if old_school {
for p in annotation.start_col .. annotation.end_col {
if p == annotation.start_col {
styled_buffer.putc(1, p, '^',
if annotation.is_primary {
Style::UnderlinePrimary
} else {
Style::OldSchoolNote
});
}
else {
styled_buffer.putc(1, p, '~',
if annotation.is_primary {
Style::UnderlinePrimary
} else {
Style::OldSchoolNote
});
}
}
}
else {
for p in annotation.start_col .. annotation.end_col {
if annotation.is_primary {
styled_buffer.putc(1, p, '^', Style::UnderlinePrimary);
if !annotation.is_minimized {
styled_buffer.set_style(0, p, Style::UnderlinePrimary);
}
} else {
styled_buffer.putc(1, p, '-', Style::UnderlineSecondary);
if !annotation.is_minimized {
styled_buffer.set_style(0, p, Style::UnderlineSecondary);
}
}
}
}
}
// 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 styled_buffer.render();
}
if old_school {
return styled_buffer.render();
}
// Now add the text labels. 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
//
// But sometimes that's not possible because one of the other
// annotations overlaps it. For example, from the test
// `span_overlap_label`, we have the following annotations
// (written on distinct lines for clarity):
//
// fn foo(x: u32) {
// --------------
// -
//
// In this case, we can't stick the rightmost-most label on
// the highlight line, or we would get:
//
// fn foo(x: u32) {
// -------- x_span
// |
// fn_span
//
// which is totally weird. Instead we want:
//
// fn foo(x: u32) {
// --------------
// | |
// | x_span
// fn_span
//
// which is...less weird, at least. In fact, in general, if
// 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 {
styled_buffer.append(1, &highlight_label, Style::LabelPrimary);
} else {
styled_buffer.append(1, &highlight_label, Style::LabelSecondary);
}
labeled_annotations = previous;
}
}
}
// If that's the last annotation, we're done
if labeled_annotations.is_empty() {
return styled_buffer.render();
}
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 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 {
styled_buffer.putc(index, annotation.start_col, '|', Style::UnderlinePrimary);
} else {
styled_buffer.putc(index, annotation.start_col, '|', Style::UnderlineSecondary);
}
}
if annotation.is_primary {
styled_buffer.puts(blank_lines, annotation.start_col,
annotation.label.as_ref().unwrap(), Style::LabelPrimary);
} else {
styled_buffer.puts(blank_lines, annotation.start_col,
annotation.label.as_ref().unwrap(), Style::LabelSecondary);
}
}
styled_buffer.render()
}
}
/*
fn prepend_prefixes(rendered_lines: &mut [RenderedLine], format_mode: &FormatMode) {
let old_school = match *format_mode {
FormatMode::OriginalErrorFormat => true,
FormatMode::NewErrorFormat => false,
FormatMode::EnvironmentSelected => check_old_skool()
};
if old_school {
return;
}
let prefixes: Vec<_> =
rendered_lines.iter()
.map(|rl| rl.kind.prefix())
.collect();
// find the max amount of spacing we need; add 1 to
// p.text.len() to leave space between the prefix and the
// source text
let padding_len =
prefixes.iter()
.map(|p| if p.text.len() == 0 { 0 } else { p.text.len() + 1 })
.max()
.unwrap_or(0);
// Ensure we insert at least one character of padding, so that the
// `-->` arrows can fit etc.
let padding_len = cmp::max(padding_len, 1);
for (mut prefix, line) in prefixes.into_iter().zip(rendered_lines) {
let extra_spaces = (prefix.text.len() .. padding_len).map(|_| ' ');
prefix.text.extend(extra_spaces);
match line.kind {
RenderedLineKind::Elision => {
line.text.insert(0, prefix);
}
RenderedLineKind::PrimaryFileName => {
// --> filename
// 22 |>
// ^
// padding_len
let dashes = (0..padding_len - 1).map(|_| ' ')
.chain(Some('-'))
.chain(Some('-'))
.chain(Some('>'))
.chain(Some(' '));
line.text.insert(0, StyledString {text: dashes.collect(),
style: Style::LineNumber})
}
RenderedLineKind::OtherFileName => {
// ::: filename
// 22 |>
// ^
// padding_len
let dashes = (0..padding_len - 1).map(|_| ' ')
.chain(Some(':'))
.chain(Some(':'))
.chain(Some(':'))
.chain(Some(' '));
line.text.insert(0, StyledString {text: dashes.collect(),
style: Style::LineNumber})
}
_ => {
line.text.insert(0, prefix);
line.text.insert(1, StyledString {text: String::from("|> "),
style: Style::LineNumber})
}
}
}
}
fn trim_lines(rendered_lines: &mut [RenderedLine]) {
for line in rendered_lines {
while !line.text.is_empty() {
line.trim_last();
if line.text.last().unwrap().text.is_empty() {
line.text.pop();
} else {
break;
}
}
}
}
*/
impl Line {
fn new(line_index: usize) -> Line {
Line {
line_index: line_index,
annotations: vec![]
}
}
fn push_annotation(&mut self,
start: CharPos,
end: CharPos,
is_primary: bool,
is_minimized: bool,
label: Option<String>) {
self.annotations.push(Annotation {
start_col: start.0,
end_col: end.0,
is_primary: is_primary,
is_minimized: is_minimized,
label: label,
});
}
}
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)
}

View file

@ -1265,9 +1265,9 @@ r"blork2.rs:2:1: 2:12
println!("r#\"\n{}\"#", str); println!("r#\"\n{}\"#", str);
assert_eq!(str, &r#" assert_eq!(str, &r#"
--> dummy.txt:11:1 --> dummy.txt:11:1
|> |
11 |> e--vän 11 | e--vän
|> ^ | ^
"#[1..]); "#[1..]);
} }
@ -1333,9 +1333,9 @@ r"blork2.rs:2:1: 2:12
let expect_start = &r#" let expect_start = &r#"
--> dummy.txt:1:6 --> dummy.txt:1:6
|> |
1 |> _____aaaaaa____bbbbbb__cccccdd_ 1 | _____aaaaaa____bbbbbb__cccccdd_
|> ^^^^^^ ^^^^^^ ^^^^^^^ | ^^^^^^ ^^^^^^ ^^^^^^^
"#[1..]; "#[1..];
let span = |sp, expected| { let span = |sp, expected| {
@ -1409,28 +1409,28 @@ r"blork2.rs:2:1: 2:12
let expect0 = &r#" let expect0 = &r#"
--> dummy.txt:5:1 --> dummy.txt:5:1
|> |
5 |> ccccc 5 | ccccc
|> ^ | ^
... ...
9 |> ddd__eee_ 9 | ddd__eee_
|> ^^^ ^^^ | ^^^ ^^^
10 |> elided 10 | elided
11 |> __f_gg 11 | __f_gg
|> ^ ^^ | ^ ^^
"#[1..]; "#[1..];
let expect = &r#" let expect = &r#"
--> dummy.txt:1:1 --> dummy.txt:1:1
|> |
1 |> aaaaa 1 | aaaaa
|> ^ | ^
... ...
9 |> ddd__eee_ 9 | ddd__eee_
|> ^^^ ^^^ | ^^^ ^^^
10 |> elided 10 | elided
11 |> __f_gg 11 | __f_gg
|> ^ ^^ | ^ ^^
"#[1..]; "#[1..];
macro_rules! test { macro_rules! test {
@ -1477,9 +1477,9 @@ fn foo() {
let text = make_string(&lines); let text = make_string(&lines);
assert_eq!(&text[..], &" assert_eq!(&text[..], &"
--> foo.rs:3:2 --> foo.rs:3:2
|> |
3 |> \tbar; 3 | \tbar;
|> \t^^^ | \t^^^
"[1..]); "[1..]);
} }
@ -1510,12 +1510,12 @@ fn foo() {
println!("text=\n{}", text); println!("text=\n{}", text);
assert_eq!(&text[..], &r#" assert_eq!(&text[..], &r#"
::: foo.rs ::: foo.rs
|> |
3 |> vec.push(vec.pop().unwrap()); 3 | vec.push(vec.pop().unwrap());
|> --- --- - previous borrow ends here | --- --- - previous borrow ends here
|> | | | | |
|> | error occurs here | | error occurs here
|> previous borrow of `vec` occurs here | previous borrow of `vec` occurs here
"#[1..]); "#[1..]);
} }
@ -1577,24 +1577,24 @@ fn bar() {
println!("text=\n{}", text); println!("text=\n{}", text);
// Note that the `|>` remain aligned across both files: // Note that the `|` remain aligned across both files:
assert_eq!(&text[..], &r#" assert_eq!(&text[..], &r#"
--> foo.rs:3:14 --> foo.rs:3:14
|> |
3 |> vec.push(vec.pop().unwrap()); 3 | vec.push(vec.pop().unwrap());
|> --- ^^^ - c | --- ^^^ - c
|> | | | | |
|> | b | | b
|> a | a
::: bar.rs ::: bar.rs
|> |
17 |> vec.push(); 17 | vec.push();
|> --- - f | --- - f
|> | | |
|> d | d
... ...
21 |> vec.pop().unwrap()); 21 | vec.pop().unwrap());
|> --- e | --- e
"#[1..]); "#[1..]);
} }
@ -1632,15 +1632,15 @@ fn foo() {
println!("text=\n{}", text); println!("text=\n{}", text);
assert_eq!(&text[..], &r#" assert_eq!(&text[..], &r#"
::: foo.rs ::: foo.rs
|> |
3 |> let name = find_id(&data, 22).unwrap(); 3 | let name = find_id(&data, 22).unwrap();
|> ---- immutable borrow begins here | ---- immutable borrow begins here
... ...
6 |> data.push(Data { name: format!("Hera"), id: 66 }); 6 | data.push(Data { name: format!("Hera"), id: 66 });
|> ---- mutable borrow occurs here | ---- mutable borrow occurs here
... ...
11 |> } 11 | }
|> - immutable borrow ends here | - immutable borrow ends here
"#[1..]); "#[1..]);
} }
@ -1672,13 +1672,13 @@ fn foo() {
println!("text=r#\"\n{}\".trim_left()", text); println!("text=r#\"\n{}\".trim_left()", text);
assert_eq!(&text[..], &r#" assert_eq!(&text[..], &r#"
::: foo.rs ::: foo.rs
|> |
3 |> vec.push(vec.pop().unwrap()); 3 | vec.push(vec.pop().unwrap());
|> -------- ------ D | -------- ------ D
|> || | ||
|> |C | |C
|> A | A
|> B | B
"#[1..]); "#[1..]);
} }
@ -1709,12 +1709,12 @@ fn foo() {
println!("text=r#\"\n{}\".trim_left()", text); println!("text=r#\"\n{}\".trim_left()", text);
assert_eq!(&text[..], &r#" assert_eq!(&text[..], &r#"
::: foo.rs ::: foo.rs
|> |
3 |> vec.push(vec.pop().unwrap()); 3 | vec.push(vec.pop().unwrap());
|> --- --- - previous borrow ends here | --- --- - previous borrow ends here
|> | | | | |
|> | error occurs here | | error occurs here
|> previous borrow of `vec` occurs here | previous borrow of `vec` occurs here
"#[1..]); "#[1..]);
} }
@ -1748,12 +1748,12 @@ fn foo() {
println!("text=r#\"\n{}\".trim_left()", text); println!("text=r#\"\n{}\".trim_left()", text);
assert_eq!(&text[..], &r#" assert_eq!(&text[..], &r#"
::: foo.rs ::: foo.rs
|> |
4 |> let mut vec2 = vec; 4 | let mut vec2 = vec;
|> --- `vec` moved here because it has type `collections::vec::Vec<i32>` | --- `vec` moved here because it has type `collections::vec::Vec<i32>`
... ...
9 |> vec.push(7); 9 | vec.push(7);
|> --- use of moved value: `vec` | --- use of moved value: `vec`
"#[1..]); "#[1..]);
} }
@ -1785,11 +1785,11 @@ fn foo() {
println!("text=&r#\"\n{}\n\"#[1..]", text); println!("text=&r#\"\n{}\n\"#[1..]", text);
assert_eq!(text, &r#" assert_eq!(text, &r#"
::: foo.rs ::: foo.rs
|> |
3 |> let mut vec = vec![0, 1, 2]; 3 | let mut vec = vec![0, 1, 2];
|> --- --- | --- ---
4 |> let mut vec2 = vec; 4 | let mut vec2 = vec;
|> --- --- | --- ---
"#[1..]); "#[1..]);
} }
@ -1817,9 +1817,9 @@ impl SomeTrait for () {
println!("r#\"\n{}\"", text); println!("r#\"\n{}\"", text);
assert_eq!(text, &r#" assert_eq!(text, &r#"
::: foo.rs ::: foo.rs
|> |
3 |> fn foo(x: u32) { 3 | fn foo(x: u32) {
|> - | -
"#[1..]); "#[1..]);
} }
@ -1847,12 +1847,12 @@ impl SomeTrait for () {
println!("r#\"\n{}\"", text); println!("r#\"\n{}\"", text);
assert_eq!(text, &r#" assert_eq!(text, &r#"
::: foo.rs ::: foo.rs
|> |
2 |> fn foo(x: u32) { 2 | fn foo(x: u32) {
|> -------------- | --------------
|> | | | | |
|> | x_span | | x_span
|> fn_span | fn_span
"#[1..]); "#[1..]);
} }
@ -1882,12 +1882,12 @@ impl SomeTrait for () {
println!("r#\"\n{}\"", text); println!("r#\"\n{}\"", text);
assert_eq!(text, &r#" assert_eq!(text, &r#"
::: foo.rs ::: foo.rs
|> |
2 |> fn foo(x: u32) { 2 | fn foo(x: u32) {
|> -------------- | --------------
|> | | | | |
|> | x_span | | x_span
|> fn_span | fn_span
"#[1..]); "#[1..]);
} }
@ -1928,11 +1928,11 @@ impl SomeTrait for () {
println!("r#\"\n{}\"", text); println!("r#\"\n{}\"", text);
assert_eq!(text, &r#" assert_eq!(text, &r#"
::: foo.rs ::: foo.rs
|> |
3 |> let closure = || { 3 | let closure = || {
|> - foo | - foo
4 |> inner 4 | inner
|> ----- bar | ----- bar
"#[1..]); "#[1..]);
} }
@ -1971,9 +1971,9 @@ fn main() {
println!("r#\"\n{}\"", text); println!("r#\"\n{}\"", text);
assert_eq!(text, &r#" assert_eq!(text, &r#"
--> foo.rs:11:2 --> foo.rs:11:2
|> |
11 |> } 11 | }
|> - | -
"#[1..]); "#[1..]);
} }
} }