From a20ee76b56c46a593238ce7ac9b9f70a99c43ff4 Mon Sep 17 00:00:00 2001 From: Niko Matsakis Date: Wed, 20 Apr 2016 14:52:31 -0400 Subject: [PATCH 01/40] revamp MultiSpan and introduce new snippet code MultiSpan model is now: - set of primary spans - set of span+label pairs Primary spans render with `^^^`, secondary spans with `---`. Labels are placed next to the `^^^` or `---` marker as appropriate. --- src/libsyntax/codemap.rs | 218 +++---- src/libsyntax/errors/snippet/mod.rs | 821 +++++++++++++++++++++++++++ src/libsyntax/errors/snippet/test.rs | 524 +++++++++++++++++ 3 files changed, 1428 insertions(+), 135 deletions(-) create mode 100644 src/libsyntax/errors/snippet/mod.rs create mode 100644 src/libsyntax/errors/snippet/test.rs diff --git a/src/libsyntax/codemap.rs b/src/libsyntax/codemap.rs index 35aa827782ddf..228af27f4b10a 100644 --- a/src/libsyntax/codemap.rs +++ b/src/libsyntax/codemap.rs @@ -32,8 +32,6 @@ use serialize::{Encodable, Decodable, Encoder, Decoder}; use ast::Name; -use errors::emitter::MAX_HIGHLIGHT_LINES; - // _____________________________________________________________________________ // Pos, BytePos, CharPos // @@ -51,7 +49,7 @@ pub struct BytePos(pub u32); /// A character offset. Because of multibyte utf8 characters, a byte offset /// is not equivalent to a character offset. The CodeMap will convert BytePos /// values to CharPos values as necessary. -#[derive(Copy, Clone, PartialEq, Eq, Hash, PartialOrd, Debug)] +#[derive(Copy, Clone, PartialEq, Eq, Hash, PartialOrd, Ord, Debug)] pub struct CharPos(pub usize); // FIXME: Lots of boilerplate in these impls, but so far my attempts to fix @@ -132,13 +130,29 @@ pub struct Span { pub expn_id: ExpnId } -/// Spans are converted to MultiSpans just before error reporting, either automatically, -/// generated by line grouping, or manually constructed. -/// In the latter case care should be taken to ensure that spans are ordered, disjoint, -/// and point into the same FileMap. +/// A collection of spans. Spans have two orthogonal attributes: +/// +/// - they can be *primary spans*. In this case they are the locus of +/// the error, and would be rendered with `^^^`. +/// - they can have a *label*. In this case, the label is written next +/// to the mark in the snippet when we render. #[derive(Clone)] pub struct MultiSpan { - pub spans: Vec + primary_spans: Vec, + span_labels: Vec<(Span, String)>, +} + +#[derive(Clone, Debug)] +pub struct SpanLabel { + /// the span we are going to include in the final snippet + pub span: Span, + + /// is this a primary span? This is the "locus" of the message, + /// and is indicated with a `^^^^` underline, versus `----` + pub is_primary: bool, + + /// what label should we attach to this span (if any)? + pub label: Option, } pub const DUMMY_SP: Span = Span { lo: BytePos(0), hi: BytePos(0), expn_id: NO_EXPANSION }; @@ -276,97 +290,76 @@ pub fn original_sp(cm: &CodeMap, sp: Span, enclosing_sp: Span) -> Span { impl MultiSpan { pub fn new() -> MultiSpan { - MultiSpan { spans: Vec::new() } + MultiSpan { + primary_spans: vec![], + span_labels: vec![] + } } - pub fn to_span_bounds(&self) -> Span { - assert!(!self.spans.is_empty()); - let Span { lo, expn_id, .. } = *self.spans.first().unwrap(); - let Span { hi, .. } = *self.spans.last().unwrap(); - Span { lo: lo, hi: hi, expn_id: expn_id } + pub fn from_span(primary_span: Span) -> MultiSpan { + MultiSpan { + primary_spans: vec![primary_span], + span_labels: vec![] + } } - /// Merges or inserts the given span into itself. - pub fn push_merge(&mut self, mut sp: Span) { - let mut idx_merged = None; - - for idx in 0.. { - let cur = match self.spans.get(idx) { - Some(s) => *s, - None => break, - }; - // Try to merge with a contained Span - if let Some(union) = cur.merge(sp) { - self.spans[idx] = union; - sp = union; - idx_merged = Some(idx); - break; - } - // Or insert into the first sorted position - if sp.hi <= cur.lo { - self.spans.insert(idx, sp); - idx_merged = Some(idx); - break; - } - } - if let Some(idx) = idx_merged { - // Merge with spans trailing the insertion/merging position - while (idx + 1) < self.spans.len() { - if let Some(union) = self.spans[idx + 1].merge(sp) { - self.spans[idx] = union; - self.spans.remove(idx + 1); - } else { - break; - } - } - } else { - self.spans.push(sp); + pub fn from_spans(vec: Vec) -> MultiSpan { + MultiSpan { + primary_spans: vec, + span_labels: vec![] } } - /// Inserts the given span into itself, for use with `end_highlight_lines`. - pub fn push_trim(&mut self, mut sp: Span) { - let mut prev = mk_sp(BytePos(0), BytePos(0)); + pub fn push_primary_span(&mut self, span: Span) { + self.primary_spans.push(span); + } - if let Some(first) = self.spans.get_mut(0) { - if first.lo > sp.lo { - // Prevent us here from spanning fewer lines - // because of trimming the start of the span - // (this should not be visible, because this method ought - // to not be used in conjunction with `highlight_lines`) - first.lo = sp.lo; - } + pub fn push_span_label(&mut self, span: Span, label: String) { + self.span_labels.push((span, label)); + } + + /// Selects the first primary span (if any) + pub fn primary_span(&self) -> Option { + self.primary_spans.first().cloned() + } + + /// Returns all primary spans. + pub fn primary_spans(&self) -> &[Span] { + &self.primary_spans + } + + /// Returns the strings to highlight. If we have an explicit set, + /// return those, otherwise just give back an (unlabeled) version + /// of the primary span. + pub fn span_labels(&self) -> Vec { + let is_primary = |span| self.primary_spans.contains(&span); + let mut span_labels = vec![]; + + for &(span, ref label) in &self.span_labels { + span_labels.push(SpanLabel { + span: span, + is_primary: is_primary(span), + label: Some(label.clone()) + }); } - for idx in 0.. { - if let Some(sp_trim) = sp.trim_start(prev) { - // Implies `sp.hi > prev.hi` - let cur = match self.spans.get(idx) { - Some(s) => *s, - None => { - sp = sp_trim; - break; - } - }; - // `cur` may overlap with `sp_trim` - if let Some(cur_trim) = cur.trim_start(sp_trim) { - // Implies `sp.hi < cur.hi` - self.spans.insert(idx, sp_trim); - self.spans[idx + 1] = cur_trim; - return; - } else if sp.hi == cur.hi { - return; - } - prev = cur; + for &span in &self.primary_spans { + if !span_labels.iter().any(|sl| sl.span == span) { + span_labels.push(SpanLabel { + span: span, + is_primary: true, + label: None + }); } } - self.spans.push(sp); + + span_labels } } impl From for MultiSpan { fn from(span: Span) -> MultiSpan { - MultiSpan { spans: vec![span] } + MultiSpan::from_span(span) } } @@ -929,6 +922,10 @@ impl CodeMap { } pub fn span_to_string(&self, sp: Span) -> String { + if sp == COMMAND_LINE_SP { + return "".to_string(); + } + if self.files.borrow().is_empty() && sp.source_equal(&DUMMY_SP) { return "no-location".to_string(); } @@ -1099,12 +1096,16 @@ impl CodeMap { } pub fn span_to_lines(&self, sp: Span) -> FileLinesResult { + debug!("span_to_lines(sp={:?})", sp); + if sp.lo > sp.hi { return Err(SpanLinesError::IllFormedSpan(sp)); } let lo = self.lookup_char_pos(sp.lo); + debug!("span_to_lines: lo={:?}", lo); let hi = self.lookup_char_pos(sp.hi); + debug!("span_to_lines: hi={:?}", hi); if lo.file.start_pos != hi.file.start_pos { return Err(SpanLinesError::DistinctSources(DistinctSources { @@ -1184,59 +1185,6 @@ impl CodeMap { } } - /// Groups and sorts spans by lines into `MultiSpan`s, where `push` adds them to their group, - /// specifying the unification behaviour for overlapping spans. - /// Spans overflowing a line are put into their own one-element-group. - pub fn custom_group_spans(&self, mut spans: Vec, push: F) -> Vec - where F: Fn(&mut MultiSpan, Span) - { - spans.sort_by(|a, b| a.lo.cmp(&b.lo)); - let mut groups = Vec::::new(); - let mut overflowing = vec![]; - let mut prev_expn = ExpnId(!2u32); - let mut prev_file = !0usize; - let mut prev_line = !0usize; - let mut err_size = 0; - - for sp in spans { - let line = self.lookup_char_pos(sp.lo).line; - let line_hi = self.lookup_char_pos(sp.hi).line; - if line != line_hi { - overflowing.push(sp.into()); - continue - } - let file = self.lookup_filemap_idx(sp.lo); - - if err_size < MAX_HIGHLIGHT_LINES && sp.expn_id == prev_expn && file == prev_file { - // `push` takes care of sorting, trimming, and merging - push(&mut groups.last_mut().unwrap(), sp); - if line != prev_line { - err_size += 1; - } - } else { - groups.push(sp.into()); - err_size = 1; - } - prev_expn = sp.expn_id; - prev_file = file; - prev_line = line; - } - groups.extend(overflowing); - groups - } - - /// Groups and sorts spans by lines into `MultiSpan`s, merging overlapping spans. - /// Spans overflowing a line are put into their own one-element-group. - pub fn group_spans(&self, spans: Vec) -> Vec { - self.custom_group_spans(spans, |msp, sp| msp.push_merge(sp)) - } - - /// Like `group_spans`, but trims overlapping spans instead of - /// merging them (for use with `end_highlight_lines`) - pub fn end_group_spans(&self, spans: Vec) -> Vec { - self.custom_group_spans(spans, |msp, sp| msp.push_trim(sp)) - } - pub fn get_filemap(&self, filename: &str) -> Rc { for fm in self.files.borrow().iter() { if filename == fm.name { diff --git a/src/libsyntax/errors/snippet/mod.rs b/src/libsyntax/errors/snippet/mod.rs new file mode 100644 index 0000000000000..cd8f705ab2e5f --- /dev/null +++ b/src/libsyntax/errors/snippet/mod.rs @@ -0,0 +1,821 @@ +// Copyright 2012-2015 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 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +// Code for annotating snippets. + +use codemap::{CharPos, CodeMap, FileMap, LineInfo, Span}; +use std::cmp; +use std::rc::Rc; +use std::mem; +use std::ops::Range; + +#[cfg(test)] +mod test; + +pub struct SnippetData { + codemap: Rc, + files: Vec, +} + +pub struct FileInfo { + file: Rc, + + /// The "primary file", if any, gets a `-->` marker instead of + /// `>>>`, and has a line-number/column printed and not just a + /// filename. It appears first in the listing. It is known to + /// contain at least one primary span, though primary spans (which + /// are designated with `^^^`) may also occur in other files. + primary_span: Option, + + lines: Vec, +} + +struct Line { + line_index: usize, + annotations: Vec, +} + +#[derive(Clone, PartialOrd, Ord, PartialEq, Eq)] +struct Annotation { + /// Start column, 0-based indexing -- counting *characters*, not + /// utf-8 bytes. Note that it is important that this field goes + /// first, so that when we sort, we sort orderings by start + /// column. + start_col: usize, + + /// End column within the line. + end_col: usize, + + /// Is this annotation derived from primary span + is_primary: bool, + + /// Optional label to display adjacent to the annotation. + label: Option, +} + +#[derive(Debug)] +pub struct RenderedLine { + pub text: Vec, + pub kind: RenderedLineKind, +} + +#[derive(Debug)] +pub struct StyledString { + pub text: String, + pub style: Style, +} + +#[derive(Debug)] +pub struct StyledBuffer { + text: Vec>, + styles: Vec> +} + +#[derive(Copy, Clone, Debug, PartialEq)] +pub enum Style { + FileNameStyle, + LineAndColumn, + LineNumber, + Quotation, + UnderlinePrimary, + UnderlineSecondary, + LabelPrimary, + LabelSecondary, + NoStyle, +} +use self::Style::*; + +#[derive(Debug, Clone)] +pub enum RenderedLineKind { + PrimaryFileName, + OtherFileName, + SourceText { + file: Rc, + line_index: usize, + }, + Annotations, + Elision, +} +use self::RenderedLineKind::*; + +impl SnippetData { + pub fn new(codemap: Rc, + primary_span: Option) // (*) + -> 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![] + }; + 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![], + }); + } + data + } + + pub fn push(&mut self, span: Span, is_primary: bool, label: Option) { + 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) -> &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, + }); + self.files.last_mut().unwrap() + } + + pub fn render_lines(&self) -> Vec { + 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); + 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 { + fn make_string(self) -> String { + self.into_iter().collect() + } +} + +impl 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 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 !self.text.is_empty() { + let last_text = &mut self.text.last_mut().unwrap().text; + let len = last_text.trim_right().len(); + last_text.truncate(len); + } + } +} + +impl RenderedLineKind { + fn prefix(&self) -> StyledString { + match *self { + SourceText { file: _, line_index } => + StyledString { + text: format!("{}", line_index + 1), + style: LineNumber, + }, + Elision => + StyledString { + text: String::from("..."), + style: LineNumber, + }, + PrimaryFileName | + OtherFileName | + Annotations => + StyledString { + text: String::from(""), + style: LineNumber, + }, + } + } +} + +impl StyledBuffer { + fn new() -> StyledBuffer { + StyledBuffer { text: vec![], styles: vec![] } + } + + fn render(&self, source_kind: RenderedLineKind) -> Vec { + let mut output: Vec = vec![]; + let mut styled_vec: Vec = vec![]; + + for (row, row_style) in self.text.iter().zip(&self.styles) { + let mut current_style = NoStyle; + let mut current_text = String::new(); + + for (&c, &s) in row.iter().zip(row_style) { + if s != current_style { + if !current_text.is_empty() { + styled_vec.push(StyledString { text: current_text, style: current_style }); + } + current_style = s; + current_text = String::new(); + } + current_text.push(c); + } + if !current_text.is_empty() { + styled_vec.push(StyledString { text: current_text, style: current_style }); + } + + if output.is_empty() { + //We know our first output line is source and the rest are highlights and labels + output.push(RenderedLine { text: styled_vec, kind: source_kind.clone() }); + } else { + output.push(RenderedLine { text: styled_vec, kind: Annotations }); + } + styled_vec = vec![]; + } + + output + } + + fn putc(&mut self, line: usize, col: usize, chr: char, style: Style) { + while line >= self.text.len() { + self.text.push(vec![]); + self.styles.push(vec![]); + } + + if col < self.text[line].len() { + self.text[line][col] = chr; + self.styles[line][col] = style; + } else { + while self.text[line].len() < col { + self.text[line].push(' '); + self.styles[line].push(NoStyle); + } + self.text[line].push(chr); + self.styles[line].push(style); + } + } + + fn puts(&mut self, line: usize, col: usize, string: &str, style: Style) { + let mut n = col; + for c in string.chars() { + self.putc(line, n, c, style); + n += 1; + } + } + + fn set_style(&mut self, line: usize, col: usize, style: Style) { + if self.styles.len() > line && self.styles[line].len() > col { + self.styles[line][col] = style; + } + } + + fn append(&mut self, line: usize, string: &str, style: Style) { + if line >= self.text.len() { + self.puts(line, 0, string, style); + } else { + let col = self.text[line].len(); + self.puts(line, col, string, style); + } + } +} + +impl FileInfo { + fn push_lines(&mut self, + lines: &[LineInfo], + is_primary: bool, + label: Option) { + assert!(lines.len() > 0); + + // If a span covers multiple lines, just put the label on the + // first one. This is a sort of arbitrary choice and not + // obviously correct. + let (line0, remaining_lines) = lines.split_first().unwrap(); + let index = self.ensure_source_line(line0.line_index); + self.lines[index].push_annotation(line0.start_col, + line0.end_col, + is_primary, + label); + for line in remaining_lines { + if line.end_col > line.start_col { + let index = self.ensure_source_line(line.line_index); + self.lines[index].push_annotation(line.start_col, + line.end_col, + is_primary, + None); + } + } + } + + /// 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) -> Vec { + // Group our lines by those with annotations and those without + let mut lines_iter = self.lines.iter().peekable(); + + let mut line_groups = vec![]; + + 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![]; + + // First insert the name of the file. + match self.primary_span { + Some(span) => { + let lo = codemap.lookup_char_pos(span.lo); + output.push(RenderedLine { + text: vec![StyledString { + text: lo.file.name.clone(), + style: FileNameStyle, + }, StyledString { + text: format!(":{}:{}", lo.line, lo.col.0 + 1), + style: LineAndColumn, + }], + kind: PrimaryFileName, + }); + } + None => { + output.push(RenderedLine { + text: vec![StyledString { + text: self.file.name.clone(), + style: FileNameStyle, + }], + kind: OtherFileName, + }); + } + } + + for &(is_annotated, ref group) in line_groups.iter() { + if is_annotated { + let mut annotation_ends_at_eol = false; + let mut prev_ends_at_eol = false; + let mut elide_unlabeled_region = false; + + for group_line in group.iter() { + let source_string_len = + self.file.get_line(group_line.line_index) + .map(|s| s.len()) + .unwrap_or(0); + + for annotation in &group_line.annotations { + if annotation.end_col == source_string_len { + annotation_ends_at_eol = true; + } + } + + let is_single_unlabeled_annotated_line = + if group_line.annotations.len() == 1 { + if let Some(annotation) = group_line.annotations.first() { + match annotation.label { + Some(_) => false, + None => annotation.start_col == 0 && + annotation.end_col == source_string_len + } + } else { + false + } + } else { + false + }; + + if prev_ends_at_eol && is_single_unlabeled_annotated_line { + if !elide_unlabeled_region { + output.push(RenderedLine::from((String::new(), + NoStyle, Elision))); + elide_unlabeled_region = true; + prev_ends_at_eol = true; + } + continue; + } + + let mut v = self.render_line(group_line); + output.append(&mut v); + + prev_ends_at_eol = annotation_ends_at_eol; + } + } else { + if group.len() > 1 { + output.push(RenderedLine::from((String::new(), NoStyle, Elision))); + } else { + let mut v: Vec = + group.iter().flat_map(|line| self.render_line(line)).collect(); + output.append(&mut v); + } + } + } + + output + } + + fn render_line(&self, line: &Line) -> Vec { + let source_string = self.file.get_line(line.line_index) + .unwrap_or(""); + let source_kind = 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, Quotation); + + if line.annotations.is_empty() { + return styled_buffer.render(source_kind); + } + + // 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 { + for p in annotation.start_col .. annotation.end_col { + if annotation.is_primary { + styled_buffer.putc(1, p, '^', UnderlinePrimary); + styled_buffer.set_style(0, p, UnderlinePrimary); + } else { + styled_buffer.putc(1, p, '-', 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(source_kind); + } + + // 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, LabelPrimary); + } else { + styled_buffer.append(1, &highlight_label, LabelSecondary); + } + labeled_annotations = previous; + } + } + } + + // If that's the last annotation, we're done + if labeled_annotations.is_empty() { + return styled_buffer.render(source_kind); + } + + 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, '|', UnderlinePrimary); + } else { + styled_buffer.putc(index, annotation.start_col, '|', UnderlineSecondary); + } + } + + if annotation.is_primary { + styled_buffer.puts(blank_lines, annotation.start_col, + annotation.label.as_ref().unwrap(), LabelPrimary); + } else { + styled_buffer.puts(blank_lines, annotation.start_col, + annotation.label.as_ref().unwrap(), LabelSecondary); + } + } + + styled_buffer.render(source_kind) + } +} + +fn prepend_prefixes(rendered_lines: &mut [RenderedLine]) { + 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: LineNumber}) + } + RenderedLineKind::OtherFileName => { + // >>>>> filename + // 22 |> + // ^ + // padding_len + let dashes = (0..padding_len + 2).map(|_| '>') + .chain(Some(' ')); + line.text.insert(0, StyledString {text: dashes.collect(), + style: LineNumber}) + } + _ => { + line.text.insert(0, prefix); + line.text.insert(1, StyledString {text: String::from("|> "), + 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, + label: Option) { + self.annotations.push(Annotation { + start_col: start.0, + end_col: end.0, + is_primary: is_primary, + label: label, + }); + } +} + +fn overlaps(a1: &Annotation, + a2: &Annotation) + -> bool +{ + between(a1.start_col, a2.start_col .. a2.end_col) || + between(a2.start_col, a1.start_col .. a1.end_col) +} + +fn between(v: usize, range: Range) -> bool { + v >= range.start && v < range.end +} diff --git a/src/libsyntax/errors/snippet/test.rs b/src/libsyntax/errors/snippet/test.rs new file mode 100644 index 0000000000000..44ece285b1b23 --- /dev/null +++ b/src/libsyntax/errors/snippet/test.rs @@ -0,0 +1,524 @@ +// Copyright 2012-2015 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 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +// Code for testing annotated snippets. + +use codemap::{BytePos, CodeMap, FileMap, NO_EXPANSION, Span}; +use std::rc::Rc; +use super::{RenderedLine, SnippetData}; + +/// Returns the span corresponding to the `n`th occurrence of +/// `substring` in `source_text`. +trait CodeMapExtension { + fn span_substr(&self, + file: &Rc, + source_text: &str, + substring: &str, + n: usize) + -> Span; +} + +impl CodeMapExtension for CodeMap { + fn span_substr(&self, + file: &Rc, + source_text: &str, + substring: &str, + n: usize) + -> Span + { + println!("span_substr(file={:?}/{:?}, substring={:?}, n={})", + file.name, file.start_pos, substring, n); + let mut i = 0; + let mut hi = 0; + loop { + let offset = source_text[hi..].find(substring).unwrap_or_else(|| { + panic!("source_text `{}` does not have {} occurrences of `{}`, only {}", + source_text, n, substring, i); + }); + let lo = hi + offset; + hi = lo + substring.len(); + if i == n { + let span = Span { + lo: BytePos(lo as u32 + file.start_pos.0), + hi: BytePos(hi as u32 + file.start_pos.0), + expn_id: NO_EXPANSION, + }; + assert_eq!(&self.span_to_snippet(span).unwrap()[..], + substring); + return span; + } + i += 1; + } + } +} + +fn splice(start: Span, end: Span) -> Span { + Span { + lo: start.lo, + hi: end.hi, + expn_id: NO_EXPANSION, + } +} + +fn make_string(lines: &[RenderedLine]) -> String { + lines.iter() + .flat_map(|rl| { + rl.text.iter() + .map(|s| &s.text[..]) + .chain(Some("\n")) + }) + .collect() +} + +#[test] +fn one_line() { + let file_text = r#" +fn foo() { + vec.push(vec.pop().unwrap()); +} +"#; + + let cm = Rc::new(CodeMap::new()); + let foo = cm.new_filemap_and_lines("foo.rs", file_text); + let span_vec0 = cm.span_substr(&foo, file_text, "vec", 0); + let span_vec1 = cm.span_substr(&foo, file_text, "vec", 1); + let span_semi = cm.span_substr(&foo, file_text, ";", 0); + + let mut snippet = SnippetData::new(cm, None); + snippet.push(span_vec0, false, Some(format!("previous borrow of `vec` occurs here"))); + snippet.push(span_vec1, false, Some(format!("error occurs here"))); + snippet.push(span_semi, false, Some(format!("previous borrow ends here"))); + + let lines = snippet.render_lines(); + println!("{:#?}", lines); + + let text: String = make_string(&lines); + + println!("text=\n{}", text); + assert_eq!(&text[..], &r#" +>>>> foo.rs +3 |> vec.push(vec.pop().unwrap()); + |> --- --- - previous borrow ends here + |> | | + |> | error occurs here + |> previous borrow of `vec` occurs here +"#[1..]); +} + +#[test] +fn two_files() { + let file_text_foo = r#" +fn foo() { + vec.push(vec.pop().unwrap()); +} +"#; + + let file_text_bar = r#" +fn bar() { + // these blank links here + // serve to ensure that the line numbers + // from bar.rs + // require more digits + + + + + + + + + + + vec.push(); + + // this line will get elided + + vec.pop().unwrap()); +} +"#; + + let cm = Rc::new(CodeMap::new()); + let foo_map = cm.new_filemap_and_lines("foo.rs", file_text_foo); + let span_foo_vec0 = cm.span_substr(&foo_map, file_text_foo, "vec", 0); + let span_foo_vec1 = cm.span_substr(&foo_map, file_text_foo, "vec", 1); + let span_foo_semi = cm.span_substr(&foo_map, file_text_foo, ";", 0); + + let bar_map = cm.new_filemap_and_lines("bar.rs", file_text_bar); + let span_bar_vec0 = cm.span_substr(&bar_map, file_text_bar, "vec", 0); + let span_bar_vec1 = cm.span_substr(&bar_map, file_text_bar, "vec", 1); + let span_bar_semi = cm.span_substr(&bar_map, file_text_bar, ";", 0); + + let mut snippet = SnippetData::new(cm, Some(span_foo_vec1)); + snippet.push(span_foo_vec0, false, Some(format!("a"))); + snippet.push(span_foo_vec1, true, Some(format!("b"))); + snippet.push(span_foo_semi, false, Some(format!("c"))); + snippet.push(span_bar_vec0, false, Some(format!("d"))); + snippet.push(span_bar_vec1, false, Some(format!("e"))); + snippet.push(span_bar_semi, false, Some(format!("f"))); + + let lines = snippet.render_lines(); + println!("{:#?}", lines); + + let text: String = make_string(&lines); + + println!("text=\n{}", text); + + // Note that the `|>` remain aligned across both files: + assert_eq!(&text[..], &r#" + --> foo.rs:3:14 +3 |> vec.push(vec.pop().unwrap()); + |> --- ^^^ - c + |> | | + |> | b + |> a +>>>>>> bar.rs +17 |> vec.push(); + |> --- - f + |> | + |> d +... +21 |> vec.pop().unwrap()); + |> --- e +"#[1..]); +} + +#[test] +fn multi_line() { + let file_text = r#" +fn foo() { + let name = find_id(&data, 22).unwrap(); + + // Add one more item we forgot to the vector. Silly us. + data.push(Data { name: format!("Hera"), id: 66 }); + + // Print everything out. + println!("Name: {:?}", name); + println!("Data: {:?}", data); +} +"#; + + let cm = Rc::new(CodeMap::new()); + let foo = cm.new_filemap_and_lines("foo.rs", file_text); + let span_data0 = cm.span_substr(&foo, file_text, "data", 0); + let span_data1 = cm.span_substr(&foo, file_text, "data", 1); + let span_rbrace = cm.span_substr(&foo, file_text, "}", 3); + + let mut snippet = SnippetData::new(cm, None); + snippet.push(span_data0, false, Some(format!("immutable borrow begins here"))); + snippet.push(span_data1, false, Some(format!("mutable borrow occurs here"))); + snippet.push(span_rbrace, false, Some(format!("immutable borrow ends here"))); + + let lines = snippet.render_lines(); + println!("{:#?}", lines); + + let text: String = make_string(&lines); + + println!("text=\n{}", text); + assert_eq!(&text[..], &r#" +>>>>>> foo.rs +3 |> let name = find_id(&data, 22).unwrap(); + |> ---- immutable borrow begins here +... +6 |> data.push(Data { name: format!("Hera"), id: 66 }); + |> ---- mutable borrow occurs here +... +11 |> } + |> - immutable borrow ends here +"#[1..]); +} + +#[test] +fn overlapping() { + let file_text = r#" +fn foo() { + vec.push(vec.pop().unwrap()); +} +"#; + + let cm = Rc::new(CodeMap::new()); + let foo = cm.new_filemap_and_lines("foo.rs", file_text); + let span0 = cm.span_substr(&foo, file_text, "vec.push", 0); + let span1 = cm.span_substr(&foo, file_text, "vec", 0); + let span2 = cm.span_substr(&foo, file_text, "ec.push", 0); + let span3 = cm.span_substr(&foo, file_text, "unwrap", 0); + + let mut snippet = SnippetData::new(cm, None); + snippet.push(span0, false, Some(format!("A"))); + snippet.push(span1, false, Some(format!("B"))); + snippet.push(span2, false, Some(format!("C"))); + snippet.push(span3, false, Some(format!("D"))); + + let lines = snippet.render_lines(); + println!("{:#?}", lines); + let text: String = make_string(&lines); + + println!("text=r#\"\n{}\".trim_left()", text); + assert_eq!(&text[..], &r#" +>>>> foo.rs +3 |> vec.push(vec.pop().unwrap()); + |> -------- ------ D + |> || + |> |C + |> A + |> B +"#[1..]); +} + +#[test] +fn one_line_out_of_order() { + let file_text = r#" +fn foo() { + vec.push(vec.pop().unwrap()); +} +"#; + + let cm = Rc::new(CodeMap::new()); + let foo = cm.new_filemap_and_lines("foo.rs", file_text); + let span_vec0 = cm.span_substr(&foo, file_text, "vec", 0); + let span_vec1 = cm.span_substr(&foo, file_text, "vec", 1); + let span_semi = cm.span_substr(&foo, file_text, ";", 0); + + // intentionally don't push the snippets left to right + let mut snippet = SnippetData::new(cm, None); + snippet.push(span_vec1, false, Some(format!("error occurs here"))); + snippet.push(span_vec0, false, Some(format!("previous borrow of `vec` occurs here"))); + snippet.push(span_semi, false, Some(format!("previous borrow ends here"))); + + let lines = snippet.render_lines(); + println!("{:#?}", lines); + let text: String = make_string(&lines); + + println!("text=r#\"\n{}\".trim_left()", text); + assert_eq!(&text[..], &r#" +>>>> foo.rs +3 |> vec.push(vec.pop().unwrap()); + |> --- --- - previous borrow ends here + |> | | + |> | error occurs here + |> previous borrow of `vec` occurs here +"#[1..]); +} + +#[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()); + let foo = cm.new_filemap_and_lines("foo.rs", file_text); + let span_vec0 = cm.span_substr(&foo, file_text, "vec", 3); + let span_vec1 = cm.span_substr(&foo, file_text, "vec", 8); + + let mut snippet = SnippetData::new(cm, None); + snippet.push(span_vec0, false, Some(format!("`vec` moved here because it \ + has type `collections::vec::Vec`"))); + snippet.push(span_vec1, false, Some(format!("use of moved value: `vec`"))); + + let lines = snippet.render_lines(); + println!("{:#?}", lines); + let text: String = make_string(&lines); + println!("text=r#\"\n{}\".trim_left()", text); + assert_eq!(&text[..], &r#" +>>>>>> foo.rs +4 |> let mut vec2 = vec; + |> --- `vec` moved here because it has type `collections::vec::Vec` +... +9 |> vec.push(7); + |> --- use of moved value: `vec` +"#[1..]); +} + +#[test] +fn spans_without_labels() { + 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()); + let foo = cm.new_filemap_and_lines("foo.rs", file_text); + + let mut snippet = SnippetData::new(cm.clone(), None); + for i in 0..4 { + let span_veci = cm.span_substr(&foo, file_text, "vec", i); + snippet.push(span_veci, false, None); + } + + let lines = snippet.render_lines(); + let text: String = make_string(&lines); + println!("text=&r#\"\n{}\n\"#[1..]", text); + assert_eq!(text, &r#" +>>>> foo.rs +3 |> let mut vec = vec![0, 1, 2]; + |> --- --- +4 |> let mut vec2 = vec; + |> --- --- +"#[1..]); +} + +#[test] +fn span_long_selection() { + let file_text = r#" +impl SomeTrait for () { + fn foo(x: u32) { + // impl 1 + // impl 2 + // impl 3 + } +} +"#; + + let cm = Rc::new(CodeMap::new()); + let foo = cm.new_filemap_and_lines("foo.rs", file_text); + + let mut snippet = SnippetData::new(cm.clone(), None); + let fn_span = cm.span_substr(&foo, file_text, "fn", 0); + let rbrace_span = cm.span_substr(&foo, file_text, "}", 0); + snippet.push(splice(fn_span, rbrace_span), false, None); + let lines = snippet.render_lines(); + let text: String = make_string(&lines); + println!("r#\"\n{}\"", text); + assert_eq!(text, &r#" +>>>>>> foo.rs +3 |> fn foo(x: u32) { + |> ---------------- +... +"#[1..]); +} + +#[test] +fn span_overlap_label() { + // Test that we don't put `x_span` to the right of its highlight, + // since there is another highlight that overlaps it. + + let file_text = r#" + fn foo(x: u32) { + } +} +"#; + + let cm = Rc::new(CodeMap::new()); + let foo = cm.new_filemap_and_lines("foo.rs", file_text); + + let mut snippet = SnippetData::new(cm.clone(), None); + let fn_span = cm.span_substr(&foo, file_text, "fn foo(x: u32)", 0); + let x_span = cm.span_substr(&foo, file_text, "x", 0); + snippet.push(fn_span, false, Some(format!("fn_span"))); + snippet.push(x_span, false, Some(format!("x_span"))); + let lines = snippet.render_lines(); + let text: String = make_string(&lines); + println!("r#\"\n{}\"", text); + assert_eq!(text, &r#" +>>>> foo.rs +2 |> fn foo(x: u32) { + |> -------------- + |> | | + |> | x_span + |> fn_span +"#[1..]); +} + +#[test] +fn span_overlap_label2() { + // Test that we don't put `x_span` to the right of its highlight, + // since there is another highlight that overlaps it. In this + // case, the overlap is only at the beginning, but it's still + // better to show the beginning more clearly. + + let file_text = r#" + fn foo(x: u32) { + } +} +"#; + + let cm = Rc::new(CodeMap::new()); + let foo = cm.new_filemap_and_lines("foo.rs", file_text); + + let mut snippet = SnippetData::new(cm.clone(), None); + let fn_span = cm.span_substr(&foo, file_text, "fn foo(x", 0); + let x_span = cm.span_substr(&foo, file_text, "x: u32)", 0); + snippet.push(fn_span, false, Some(format!("fn_span"))); + snippet.push(x_span, false, Some(format!("x_span"))); + let lines = snippet.render_lines(); + let text: String = make_string(&lines); + println!("r#\"\n{}\"", text); + assert_eq!(text, &r#" +>>>> foo.rs +2 |> fn foo(x: u32) { + |> -------------- + |> | | + |> | x_span + |> fn_span +"#[1..]); +} + +#[test] +fn span_overlap_label3() { + // Test that we don't put `x_span` to the right of its highlight, + // since there is another highlight that overlaps it. In this + // case, the overlap is only at the beginning, but it's still + // better to show the beginning more clearly. + + let file_text = r#" + fn foo() { + let closure = || { + inner + }; + } +} +"#; + + let cm = Rc::new(CodeMap::new()); + let foo = cm.new_filemap_and_lines("foo.rs", file_text); + + let mut snippet = SnippetData::new(cm.clone(), None); + + let closure_span = { + let closure_start_span = cm.span_substr(&foo, file_text, "||", 0); + let closure_end_span = cm.span_substr(&foo, file_text, "}", 0); + splice(closure_start_span, closure_end_span) + }; + + let inner_span = cm.span_substr(&foo, file_text, "inner", 0); + + snippet.push(closure_span, false, Some(format!("foo"))); + snippet.push(inner_span, false, Some(format!("bar"))); + + let lines = snippet.render_lines(); + let text: String = make_string(&lines); + println!("r#\"\n{}\"", text); + assert_eq!(text, &r#" +>>>> foo.rs +3 |> let closure = || { + |> ---- foo +4 |> inner + |> ---------------- + |> | + |> bar +5 |> }; + |> -------- +"#[1..]); +} From e7c7a18d94cf672d6a031455d091e0bebe1a6b7c Mon Sep 17 00:00:00 2001 From: Niko Matsakis Date: Wed, 20 Apr 2016 14:57:20 -0400 Subject: [PATCH 02/40] adapt JSON to new model Each Span now carries a `is_primary` boolean along with an optional label. If there are multiple labels for a span, it will appear multiple times. --- src/libsyntax/errors/json.rs | 202 ++++++++++++------------------ src/tools/compiletest/src/json.rs | 47 +++++-- 2 files changed, 119 insertions(+), 130 deletions(-) diff --git a/src/libsyntax/errors/json.rs b/src/libsyntax/errors/json.rs index 821617bfe89df..b343c3f3fbbc5 100644 --- a/src/libsyntax/errors/json.rs +++ b/src/libsyntax/errors/json.rs @@ -20,7 +20,7 @@ // FIXME spec the JSON output properly. -use codemap::{self, Span, MacroBacktrace, MultiSpan, CodeMap}; +use codemap::{self, MacroBacktrace, Span, SpanLabel, MultiSpan, CodeMap}; use diagnostics::registry::Registry; use errors::{Level, DiagnosticBuilder, SubDiagnostic, RenderSpan, CodeSuggestion}; use errors::emitter::Emitter; @@ -53,20 +53,13 @@ impl JsonEmitter { } impl Emitter for JsonEmitter { - fn emit(&mut self, span: Option<&MultiSpan>, msg: &str, code: Option<&str>, level: Level) { + fn emit(&mut self, span: &MultiSpan, msg: &str, code: Option<&str>, level: Level) { let data = Diagnostic::new(span, msg, code, level, self); if let Err(e) = writeln!(&mut self.dst, "{}", as_json(&data)) { panic!("failed to print diagnostics: {:?}", e); } } - fn custom_emit(&mut self, sp: &RenderSpan, msg: &str, level: Level) { - let data = Diagnostic::from_render_span(sp, msg, level, self); - if let Err(e) = writeln!(&mut self.dst, "{}", as_json(&data)) { - panic!("failed to print diagnostics: {:?}", e); - } - } - fn emit_struct(&mut self, db: &DiagnosticBuilder) { let data = Diagnostic::from_diagnostic_builder(db, self); if let Err(e) = writeln!(&mut self.dst, "{}", as_json(&data)) { @@ -104,8 +97,13 @@ struct DiagnosticSpan { /// 1-based, character offset. column_start: usize, column_end: usize, + /// Is this a "primary" span -- meaning the point, or one of the points, + /// where the error occurred? + is_primary: bool, /// Source text from the start of line_start to the end of line_end. text: Vec, + /// Label that should be placed at this location (if any) + label: Option, /// If we are suggesting a replacement, this will contain text /// that should be sliced in atop this span. You may prefer to /// load the fully rendered version from the parent `Diagnostic`, @@ -148,7 +146,7 @@ struct DiagnosticCode { } impl<'a> Diagnostic<'a> { - fn new(msp: Option<&MultiSpan>, + fn new(msp: &MultiSpan, msg: &'a str, code: Option<&str>, level: Level, @@ -158,27 +156,12 @@ impl<'a> Diagnostic<'a> { message: msg, code: DiagnosticCode::map_opt_string(code.map(|c| c.to_owned()), je), level: level.to_str(), - spans: msp.map_or(vec![], |msp| DiagnosticSpan::from_multispan(msp, je)), + spans: DiagnosticSpan::from_multispan(msp, je), children: vec![], rendered: None, } } - fn from_render_span(span: &RenderSpan, - msg: &'a str, - level: Level, - je: &JsonEmitter) - -> Diagnostic<'a> { - Diagnostic { - message: msg, - code: None, - level: level.to_str(), - spans: DiagnosticSpan::from_render_span(span, je), - children: vec![], - rendered: je.render(span), - } - } - fn from_diagnostic_builder<'c>(db: &'c DiagnosticBuilder, je: &JsonEmitter) -> Diagnostic<'c> { @@ -186,7 +169,7 @@ impl<'a> Diagnostic<'a> { message: &db.message, code: DiagnosticCode::map_opt_string(db.code.clone(), je), level: db.level.to_str(), - spans: db.span.as_ref().map_or(vec![], |sp| DiagnosticSpan::from_multispan(sp, je)), + spans: DiagnosticSpan::from_multispan(&db.span, je), children: db.children.iter().map(|c| { Diagnostic::from_sub_diagnostic(c, je) }).collect(), @@ -201,8 +184,7 @@ impl<'a> Diagnostic<'a> { level: db.level.to_str(), spans: db.render_span.as_ref() .map(|sp| DiagnosticSpan::from_render_span(sp, je)) - .or_else(|| db.span.as_ref().map(|s| DiagnosticSpan::from_multispan(s, je))) - .unwrap_or(vec![]), + .unwrap_or_else(|| DiagnosticSpan::from_multispan(&db.span, je)), children: vec![], rendered: db.render_span.as_ref() .and_then(|rsp| je.render(rsp)), @@ -211,44 +193,68 @@ impl<'a> Diagnostic<'a> { } impl DiagnosticSpan { - fn from_span(span: Span, suggestion: Option<&String>, je: &JsonEmitter) - -> DiagnosticSpan { + fn from_span_label(span: SpanLabel, + suggestion: Option<&String>, + je: &JsonEmitter) + -> DiagnosticSpan { + Self::from_span_etc(span.span, + span.is_primary, + span.label, + suggestion, + je) + } + + fn from_span_etc(span: Span, + is_primary: bool, + label: Option, + suggestion: Option<&String>, + je: &JsonEmitter) + -> DiagnosticSpan { // obtain the full backtrace from the `macro_backtrace` // helper; in some ways, it'd be better to expand the // backtrace ourselves, but the `macro_backtrace` helper makes // some decision, such as dropping some frames, and I don't // want to duplicate that logic here. let backtrace = je.cm.macro_backtrace(span).into_iter(); - DiagnosticSpan::from_span_and_backtrace(span, suggestion, backtrace, je) + DiagnosticSpan::from_span_full(span, + is_primary, + label, + suggestion, + backtrace, + je) } - fn from_span_and_backtrace(span: Span, - suggestion: Option<&String>, - mut backtrace: vec::IntoIter, - je: &JsonEmitter) - -> DiagnosticSpan { + fn from_span_full(span: Span, + is_primary: bool, + label: Option, + suggestion: Option<&String>, + mut backtrace: vec::IntoIter, + je: &JsonEmitter) + -> DiagnosticSpan { let start = je.cm.lookup_char_pos(span.lo); let end = je.cm.lookup_char_pos(span.hi); - let backtrace_step = - backtrace.next() - .map(|bt| { - let call_site = - Self::from_span_and_backtrace(bt.call_site, - None, - backtrace, - je); - let def_site_span = bt.def_site_span.map(|sp| { - Self::from_span_and_backtrace(sp, - None, - vec![].into_iter(), - je) - }); - Box::new(DiagnosticSpanMacroExpansion { - span: call_site, - macro_decl_name: bt.macro_decl_name, - def_site_span: def_site_span, - }) - }); + let backtrace_step = backtrace.next().map(|bt| { + let call_site = + Self::from_span_full(bt.call_site, + false, + None, + None, + backtrace, + je); + let def_site_span = bt.def_site_span.map(|sp| { + Self::from_span_full(sp, + false, + None, + None, + vec![].into_iter(), + je) + }); + Box::new(DiagnosticSpanMacroExpansion { + span: call_site, + macro_decl_name: bt.macro_decl_name, + def_site_span: def_site_span, + }) + }); DiagnosticSpan { file_name: start.file.name.clone(), byte_start: span.lo.0, @@ -257,53 +263,42 @@ impl DiagnosticSpan { line_end: end.line, column_start: start.col.0 + 1, column_end: end.col.0 + 1, + is_primary: is_primary, text: DiagnosticSpanLine::from_span(span, je), suggested_replacement: suggestion.cloned(), expansion: backtrace_step, + label: label, } } fn from_multispan(msp: &MultiSpan, je: &JsonEmitter) -> Vec { - msp.spans.iter().map(|&span| Self::from_span(span, None, je)).collect() + msp.span_labels() + .into_iter() + .map(|span_str| Self::from_span_label(span_str, None, je)) + .collect() } fn from_suggestion(suggestion: &CodeSuggestion, je: &JsonEmitter) -> Vec { - assert_eq!(suggestion.msp.spans.len(), suggestion.substitutes.len()); - suggestion.msp.spans.iter() - .zip(&suggestion.substitutes) - .map(|(&span, suggestion)| { - DiagnosticSpan::from_span(span, Some(suggestion), je) - }) - .collect() + assert_eq!(suggestion.msp.span_labels().len(), suggestion.substitutes.len()); + suggestion.msp.span_labels() + .into_iter() + .zip(&suggestion.substitutes) + .map(|(span_label, suggestion)| { + DiagnosticSpan::from_span_label(span_label, + Some(suggestion), + je) + }) + .collect() } fn from_render_span(rsp: &RenderSpan, je: &JsonEmitter) -> Vec { match *rsp { RenderSpan::FileLine(ref msp) | - RenderSpan::FullSpan(ref msp) => { - DiagnosticSpan::from_multispan(msp, je) - } - RenderSpan::Suggestion(ref suggestion) => { - DiagnosticSpan::from_suggestion(suggestion, je) - } - RenderSpan::EndSpan(ref msp) => { - msp.spans.iter().map(|&span| { - let end = je.cm.lookup_char_pos(span.hi); - DiagnosticSpan { - file_name: end.file.name.clone(), - byte_start: span.hi.0, - byte_end: span.hi.0, - line_start: end.line, - line_end: end.line, - column_start: end.col.0 + 1, - column_end: end.col.0 + 1, - text: DiagnosticSpanLine::from_span_end(span, je), - suggested_replacement: None, - expansion: None, - } - }).collect() - } + RenderSpan::FullSpan(ref msp) => + DiagnosticSpan::from_multispan(msp, je), + RenderSpan::Suggestion(ref suggestion) => + DiagnosticSpan::from_suggestion(suggestion, je), } } } @@ -340,34 +335,6 @@ impl DiagnosticSpanLine { }) .unwrap_or(vec![]) } - - /// Create a list of DiagnosticSpanLines from span - the result covers all - /// of `span`, but the highlight is zero-length and at the end of `span`. - fn from_span_end(span: Span, je: &JsonEmitter) -> Vec { - je.cm.span_to_lines(span) - .map(|lines| { - let fm = &*lines.file; - lines.lines.iter() - .enumerate() - .map(|(i, line)| { - // Invariant - CodeMap::span_to_lines - // will not return extra context lines - // - the last line returned is the last - // line of `span`. - let highlight = if i == lines.lines.len() - 1 { - (line.end_col.0 + 1, line.end_col.0 + 1) - } else { - (0, 0) - }; - DiagnosticSpanLine::line_from_filemap(fm, - line.line_index, - highlight.0, - highlight.1) - }) - .collect() - }) - .unwrap_or(vec![]) - } } impl DiagnosticCode { @@ -396,9 +363,6 @@ impl JsonEmitter { RenderSpan::Suggestion(ref suggestion) => { Some(suggestion.splice_lines(&self.cm)) } - RenderSpan::EndSpan(_) => { - None - } } } } diff --git a/src/tools/compiletest/src/json.rs b/src/tools/compiletest/src/json.rs index 073b5e57cc7c5..3501b335205ed 100644 --- a/src/tools/compiletest/src/json.rs +++ b/src/tools/compiletest/src/json.rs @@ -33,6 +33,8 @@ struct DiagnosticSpan { line_end: usize, column_start: usize, column_end: usize, + is_primary: bool, + label: Option, expansion: Option>, } @@ -66,7 +68,7 @@ fn parse_line(file_name: &str, line: &str) -> Vec { match json::decode::(line) { Ok(diagnostic) => { let mut expected_errors = vec![]; - push_expected_errors(&mut expected_errors, &diagnostic, file_name); + push_expected_errors(&mut expected_errors, &diagnostic, &[], file_name); expected_errors } Err(error) => { @@ -80,12 +82,24 @@ fn parse_line(file_name: &str, line: &str) -> Vec { fn push_expected_errors(expected_errors: &mut Vec, diagnostic: &Diagnostic, + default_spans: &[&DiagnosticSpan], file_name: &str) { - // We only consider messages pertaining to the current file. - let matching_spans = || { - diagnostic.spans.iter().filter(|span| { - Path::new(&span.file_name) == Path::new(&file_name) - }) + let spans_in_this_file: Vec<_> = + diagnostic.spans.iter() + .filter(|span| Path::new(&span.file_name) == Path::new(&file_name)) + .collect(); + + let primary_spans: Vec<_> = + spans_in_this_file.iter() + .cloned() + .filter(|span| span.is_primary) + .collect(); + let primary_spans = if primary_spans.is_empty() { + // subdiagnostics often don't have a span of their own; + // inherit the span from the parent in that case + default_spans + } else { + &primary_spans }; // We break the output into multiple lines, and then append the @@ -124,7 +138,7 @@ fn push_expected_errors(expected_errors: &mut Vec, // more structured shortly anyhow. let mut message_lines = diagnostic.message.lines(); if let Some(first_line) = message_lines.next() { - for span in matching_spans() { + for span in primary_spans { let msg = with_code(span, first_line); let kind = ErrorKind::from_str(&diagnostic.level).ok(); expected_errors.push( @@ -137,7 +151,7 @@ fn push_expected_errors(expected_errors: &mut Vec, } } for next_line in message_lines { - for span in matching_spans() { + for span in primary_spans { expected_errors.push( Error { line_num: span.line_start, @@ -150,7 +164,7 @@ fn push_expected_errors(expected_errors: &mut Vec, // If the message has a suggestion, register that. if let Some(ref rendered) = diagnostic.rendered { - let start_line = matching_spans().map(|s| s.line_start).min().expect("\ + let start_line = primary_spans.iter().map(|s| s.line_start).min().expect("\ every suggestion should have at least one span"); for (index, line) in rendered.lines().enumerate() { expected_errors.push( @@ -164,7 +178,7 @@ fn push_expected_errors(expected_errors: &mut Vec, } // Add notes for the backtrace - for span in matching_spans() { + for span in primary_spans { for frame in &span.expansion { push_backtrace(expected_errors, frame, @@ -172,9 +186,20 @@ fn push_expected_errors(expected_errors: &mut Vec, } } + // Add notes for any labels that appear in the message. + for span in spans_in_this_file.iter() + .filter(|span| span.label.is_some()) + { + expected_errors.push(Error { + line_num: span.line_start, + kind: Some(ErrorKind::Note), + msg: span.label.clone().unwrap() + }); + } + // Flatten out the children. for child in &diagnostic.children { - push_expected_errors(expected_errors, child, file_name); + push_expected_errors(expected_errors, child, primary_spans, file_name); } } From 5b150cf0ca2145c7d03a2b5ed92d9f65cc0ebcca Mon Sep 17 00:00:00 2001 From: Niko Matsakis Date: Wed, 20 Apr 2016 14:45:28 -0400 Subject: [PATCH 03/40] add borrowck info inline in main snippet This uses the new `span_label` APIs --- src/librustc/diagnostics.rs | 2 +- src/librustc_borrowck/borrowck/check_loans.rs | 142 +++++++------ src/librustc_borrowck/borrowck/mod.rs | 188 ++++++------------ src/librustc_borrowck/diagnostics.rs | 1 + 4 files changed, 146 insertions(+), 187 deletions(-) diff --git a/src/librustc/diagnostics.rs b/src/librustc/diagnostics.rs index e230836ef4515..efef259dcad9b 100644 --- a/src/librustc/diagnostics.rs +++ b/src/librustc/diagnostics.rs @@ -1569,5 +1569,5 @@ register_diagnostics! { E0490, // a value of type `..` is borrowed for too long E0491, // in type `..`, reference has a longer lifetime than the data it... E0495, // cannot infer an appropriate lifetime due to conflicting requirements - E0524, // expected a closure that implements `..` but this closure only implements `..` + E0525, // expected a closure that implements `..` but this closure only implements `..` } diff --git a/src/librustc_borrowck/borrowck/check_loans.rs b/src/librustc_borrowck/borrowck/check_loans.rs index d79ba213aca14..bbd9cd4526d95 100644 --- a/src/librustc_borrowck/borrowck/check_loans.rs +++ b/src/librustc_borrowck/borrowck/check_loans.rs @@ -447,22 +447,24 @@ impl<'a, 'tcx> CheckLoanCtxt<'a, 'tcx> { // borrow ends let common = new_loan.loan_path.common(&old_loan.loan_path); - let (nl, ol, new_loan_msg, old_loan_msg) = + let (nl, ol, new_loan_msg, old_loan_msg) = { if new_loan.loan_path.has_fork(&old_loan.loan_path) && common.is_some() { let nl = self.bccx.loan_path_to_string(&common.unwrap()); let ol = nl.clone(); - let new_loan_msg = format!(" (here through borrowing `{}`)", + let new_loan_msg = format!(" (via `{}`)", self.bccx.loan_path_to_string( &new_loan.loan_path)); - let old_loan_msg = format!(" (through borrowing `{}`)", + let old_loan_msg = format!(" (via `{}`)", self.bccx.loan_path_to_string( &old_loan.loan_path)); (nl, ol, new_loan_msg, old_loan_msg) } else { (self.bccx.loan_path_to_string(&new_loan.loan_path), self.bccx.loan_path_to_string(&old_loan.loan_path), - String::new(), String::new()) - }; + String::new(), + String::new()) + } + }; let ol_pronoun = if new_loan.loan_path == old_loan.loan_path { "it".to_string() @@ -470,12 +472,48 @@ impl<'a, 'tcx> CheckLoanCtxt<'a, 'tcx> { format!("`{}`", ol) }; + // We want to assemble all the relevant locations for the error. + // + // 1. Where did the new loan occur. + // - if due to closure creation, where was the variable used in closure? + // 2. Where did old loan occur. + // 3. Where does old loan expire. + + let previous_end_span = + self.tcx().map.span(old_loan.kill_scope.node_id(&self.tcx().region_maps)) + .end_point(); + let mut err = match (new_loan.kind, old_loan.kind) { (ty::MutBorrow, ty::MutBorrow) => { struct_span_err!(self.bccx, new_loan.span, E0499, "cannot borrow `{}`{} as mutable \ more than once at a time", nl, new_loan_msg) + .span_label( + old_loan.span, + &format!("first mutable borrow occurs here{}", old_loan_msg)) + .span_label( + new_loan.span, + &format!("second mutable borrow occurs here{}", new_loan_msg)) + .span_label( + previous_end_span, + &format!("first borrow ends here")) + } + + (ty::UniqueImmBorrow, ty::UniqueImmBorrow) => { + struct_span_err!(self.bccx, new_loan.span, E0524, + "two closures require unique access to `{}` \ + at the same time", + nl) + .span_label( + old_loan.span, + &format!("first closure is constructed here")) + .span_label( + new_loan.span, + &format!("second closure is constructed here")) + .span_label( + previous_end_span, + &format!("borrow from first closure ends here")) } (ty::UniqueImmBorrow, _) => { @@ -483,6 +521,15 @@ impl<'a, 'tcx> CheckLoanCtxt<'a, 'tcx> { "closure requires unique access to `{}` \ but {} is already borrowed{}", nl, ol_pronoun, old_loan_msg) + .span_label( + new_loan.span, + &format!("closure construction occurs here{}", new_loan_msg)) + .span_label( + old_loan.span, + &format!("borrow occurs here{}", old_loan_msg)) + .span_label( + previous_end_span, + &format!("borrow ends here")) } (_, ty::UniqueImmBorrow) => { @@ -490,6 +537,15 @@ impl<'a, 'tcx> CheckLoanCtxt<'a, 'tcx> { "cannot borrow `{}`{} as {} because \ previous closure requires unique access", nl, new_loan_msg, new_loan.kind.to_user_str()) + .span_label( + new_loan.span, + &format!("borrow occurs here{}", new_loan_msg)) + .span_label( + old_loan.span, + &format!("closure construction occurs here{}", old_loan_msg)) + .span_label( + previous_end_span, + &format!("borrow from closure ends here")) } (_, _) => { @@ -502,70 +558,42 @@ impl<'a, 'tcx> CheckLoanCtxt<'a, 'tcx> { ol_pronoun, old_loan.kind.to_user_str(), old_loan_msg) + .span_label( + new_loan.span, + &format!("{} borrow occurs here{}", + new_loan.kind.to_user_str(), + new_loan_msg)) + .span_label( + old_loan.span, + &format!("{} borrow occurs here{}", + old_loan.kind.to_user_str(), + old_loan_msg)) + .span_label( + previous_end_span, + &format!("{} borrow ends here", + old_loan.kind.to_user_str())) } }; match new_loan.cause { euv::ClosureCapture(span) => { - err.span_note( + err = err.span_label( span, - &format!("borrow occurs due to use of `{}` in closure", - nl)); + &format!("borrow occurs due to use of `{}` in closure", nl)); } _ => { } } - let rule_summary = match old_loan.kind { - ty::MutBorrow => { - format!("the mutable borrow prevents subsequent \ - moves, borrows, or modification of `{0}` \ - until the borrow ends", - ol) - } - - ty::ImmBorrow => { - format!("the immutable borrow prevents subsequent \ - moves or mutable borrows of `{0}` \ - until the borrow ends", - ol) - } - - ty::UniqueImmBorrow => { - format!("the unique capture prevents subsequent \ - moves or borrows of `{0}` \ - until the borrow ends", - ol) - } - }; - - let borrow_summary = match old_loan.cause { - euv::ClosureCapture(_) => { - format!("previous borrow of `{}` occurs here{} due to \ - use in closure", - ol, old_loan_msg) - } - - euv::OverloadedOperator | - euv::AddrOf | - euv::AutoRef | - euv::AutoUnsafe | - euv::ClosureInvocation | - euv::ForLoop | - euv::RefBinding | - euv::MatchDiscriminant => { - format!("previous borrow of `{}` occurs here{}", - ol, old_loan_msg) + match old_loan.cause { + euv::ClosureCapture(span) => { + err = err.span_label( + span, + &format!("previous borrow occurs due to use of `{}` in closure", + ol)); } - }; - - err.span_note( - old_loan.span, - &format!("{}; {}", borrow_summary, rule_summary)); + _ => { } + } - let old_loan_span = self.tcx().map.span( - old_loan.kill_scope.node_id(&self.tcx().region_maps)); - err.span_end_note(old_loan_span, - "previous borrow ends here"); err.emit(); return false; } diff --git a/src/librustc_borrowck/borrowck/mod.rs b/src/librustc_borrowck/borrowck/mod.rs index 15db356b1ba95..87000749598a7 100644 --- a/src/librustc_borrowck/borrowck/mod.rs +++ b/src/librustc_borrowck/borrowck/mod.rs @@ -34,14 +34,14 @@ use rustc::middle::free_region::FreeRegionMap; use rustc::middle::mem_categorization as mc; use rustc::middle::mem_categorization::Categorization; use rustc::middle::region; -use rustc::ty::{self, Ty, TyCtxt}; +use rustc::ty::{self, TyCtxt}; use std::fmt; use std::mem; use std::rc::Rc; use syntax::ast; use syntax::attr::AttrMetaMethods; -use syntax::codemap::Span; +use syntax::codemap::{MultiSpan, Span}; use syntax::errors::DiagnosticBuilder; use rustc::hir; @@ -633,23 +633,22 @@ impl<'a, 'tcx> BorrowckCtxt<'a, 'tcx> { lp: &LoanPath<'tcx>, the_move: &move_data::Move, moved_lp: &LoanPath<'tcx>, - param_env: &ty::ParameterEnvironment<'b,'tcx>) { - let verb = match use_kind { - MovedInUse => "use", - MovedInCapture => "capture", + _param_env: &ty::ParameterEnvironment<'b,'tcx>) { + let (verb, verb_participle) = match use_kind { + MovedInUse => ("use", "used"), + MovedInCapture => ("capture", "captured"), }; - let (ol, moved_lp_msg, mut err) = match the_move.kind { + let (_ol, _moved_lp_msg, mut err) = match the_move.kind { move_data::Declared => { - let err = struct_span_err!( + // If this is an uninitialized variable, just emit a simple warning + // and return. + struct_span_err!( self.tcx.sess, use_span, E0381, "{} of possibly uninitialized variable: `{}`", verb, - self.loan_path_to_string(lp)); - - (self.loan_path_to_string(moved_lp), - String::new(), - err) + self.loan_path_to_string(lp)).emit(); + return; } _ => { // If moved_lp is something like `x.a`, and lp is something like `x.b`, we would @@ -688,122 +687,52 @@ impl<'a, 'tcx> BorrowckCtxt<'a, 'tcx> { self.tcx.sess, use_span, E0382, "{} of {}moved value: `{}`", verb, msg, nl); - (ol, moved_lp_msg, err) + (ol, moved_lp_msg, err)} + }; + + // Get type of value and span where it was previously + // moved. + let (move_span, move_note) = match the_move.kind { + move_data::Declared => { + unreachable!(); } + + move_data::MoveExpr | + move_data::MovePat => + (self.tcx.map.span(the_move.id), ""), + + move_data::Captured => + (match self.tcx.map.expect_expr(the_move.id).node { + hir::ExprClosure(_, _, _, fn_decl_span) => fn_decl_span, + ref r => bug!("Captured({}) maps to non-closure: {:?}", + the_move.id, r), + }, " (into closure)"), }; - match the_move.kind { - move_data::Declared => {} + // Annotate the use and the move in the span. Watch out for + // the case where the use and the move are the same. This + // means the use is in a loop. + err = if use_span == move_span { + err.span_label( + use_span, + &format!("value moved{} here in previous iteration of loop", + move_note)) + } else { + err.span_label(use_span, &format!("value {} here after move", verb_participle)) + .span_label(move_span, &format!("value moved{} here", move_note)) + }; - move_data::MoveExpr => { - let (expr_ty, expr_span) = match self.tcx - .map - .find(the_move.id) { - Some(hir_map::NodeExpr(expr)) => { - (self.tcx.expr_ty_adjusted(&expr), expr.span) - } - r => { - bug!("MoveExpr({}) maps to {:?}, not Expr", - the_move.id, - r) - } - }; - let (suggestion, _) = - move_suggestion(param_env, expr_span, expr_ty, ("moved by default", "")); - // If the two spans are the same, it's because the expression will be evaluated - // multiple times. Avoid printing the same span and adjust the wording so it makes - // more sense that it's from multiple evalutations. - if expr_span == use_span { - err.note( - &format!("`{}` was previously moved here{} because it has type `{}`, \ - which is {}", - ol, - moved_lp_msg, - expr_ty, - suggestion)); - } else { - err.span_note( - expr_span, - &format!("`{}` moved here{} because it has type `{}`, which is {}", - ol, - moved_lp_msg, - expr_ty, - suggestion)); - } - } + err.note(&format!("move occurs because `{}` has type `{}`, \ + which does not implement the `Copy` trait", + self.loan_path_to_string(moved_lp), + moved_lp.ty)); - move_data::MovePat => { - let pat_ty = self.tcx.node_id_to_type(the_move.id); - let span = self.tcx.map.span(the_move.id); - err.span_note(span, - &format!("`{}` moved here{} because it has type `{}`, \ - which is moved by default", - ol, - moved_lp_msg, - pat_ty)); - match self.tcx.sess.codemap().span_to_snippet(span) { - Ok(string) => { - err.span_suggestion( - span, - &format!("if you would like to borrow the value instead, \ - use a `ref` binding as shown:"), - format!("ref {}", string)); - }, - Err(_) => { - err.fileline_help(span, - "use `ref` to override"); - }, - } - } + // Note: we used to suggest adding a `ref binding` or calling + // `clone` but those suggestions have been removed because + // they are often not what you actually want to do, and were + // not considered particularly helpful. - move_data::Captured => { - let (expr_ty, expr_span) = match self.tcx - .map - .find(the_move.id) { - Some(hir_map::NodeExpr(expr)) => { - (self.tcx.expr_ty_adjusted(&expr), expr.span) - } - r => { - bug!("Captured({}) maps to {:?}, not Expr", - the_move.id, - r) - } - }; - let (suggestion, help) = - move_suggestion(param_env, - expr_span, - expr_ty, - ("moved by default", - "make a copy and capture that instead to override")); - err.span_note( - expr_span, - &format!("`{}` moved into closure environment here{} because it \ - has type `{}`, which is {}", - ol, - moved_lp_msg, - moved_lp.ty, - suggestion)); - err.fileline_help(expr_span, help); - } - } err.emit(); - - fn move_suggestion<'a,'tcx>(param_env: &ty::ParameterEnvironment<'a,'tcx>, - span: Span, - ty: Ty<'tcx>, - default_msgs: (&'static str, &'static str)) - -> (&'static str, &'static str) { - match ty.sty { - _ => { - if ty.moves_by_default(param_env, span) { - ("non-copyable", - "perhaps you meant to use `clone()`?") - } else { - default_msgs - } - } - } - } } pub fn report_partial_reinitialization_of_uninitialized_structure( @@ -833,19 +762,20 @@ impl<'a, 'tcx> BorrowckCtxt<'a, 'tcx> { self.tcx.sess.span_err(s, m); } - pub fn struct_span_err(&self, s: Span, m: &str) -> DiagnosticBuilder<'a> { + pub fn struct_span_err>(&self, s: S, m: &str) + -> DiagnosticBuilder<'a> { self.tcx.sess.struct_span_err(s, m) } - pub fn struct_span_err_with_code(&self, - s: Span, - msg: &str, - code: &str) - -> DiagnosticBuilder<'a> { + pub fn struct_span_err_with_code>(&self, + s: S, + msg: &str, + code: &str) + -> DiagnosticBuilder<'a> { self.tcx.sess.struct_span_err_with_code(s, msg, code) } - pub fn span_err_with_code(&self, s: Span, msg: &str, code: &str) { + pub fn span_err_with_code>(&self, s: S, msg: &str, code: &str) { self.tcx.sess.span_err_with_code(s, msg, code); } diff --git a/src/librustc_borrowck/diagnostics.rs b/src/librustc_borrowck/diagnostics.rs index 7f6fd9de3d294..c7ad0b6a6c606 100644 --- a/src/librustc_borrowck/diagnostics.rs +++ b/src/librustc_borrowck/diagnostics.rs @@ -444,4 +444,5 @@ register_diagnostics! { E0506, // cannot assign to `..` because it is borrowed E0508, // cannot move out of type `..`, a non-copy fixed-size array E0509, // cannot move out of type `..`, which defines the `Drop` trait + E0524, // two closures require unique access to `..` at the same time } From 11dc974a38fd533aa692cea213305056cd3a6902 Mon Sep 17 00:00:00 2001 From: Niko Matsakis Date: Wed, 20 Apr 2016 14:56:01 -0400 Subject: [PATCH 04/40] refactor to use new snippet code and model Major changes: - Remove old snippet rendering code and use the new stuff. - Introduce `span_label` method to add a label - Remove EndSpan mode and replace with a fn to get the last character of a span. - Stop using `Option` and just use an empty `MultiSpan` - and probably a bunch of other stuff :) --- src/librustc/session/mod.rs | 4 +- src/librustc_driver/lib.rs | 16 +- src/librustc_driver/test.rs | 4 - src/librustc_trans/back/write.rs | 19 +- src/libsyntax/codemap.rs | 87 +--- src/libsyntax/errors/emitter.rs | 796 +++++++++---------------------- src/libsyntax/errors/mod.rs | 175 ++++--- 7 files changed, 357 insertions(+), 744 deletions(-) diff --git a/src/librustc/session/mod.rs b/src/librustc/session/mod.rs index 5b78e4de18b57..edb1c4530c240 100644 --- a/src/librustc/session/mod.rs +++ b/src/librustc/session/mod.rs @@ -567,7 +567,7 @@ pub fn early_error(output: config::ErrorOutputType, msg: &str) -> ! { } config::ErrorOutputType::Json => Box::new(JsonEmitter::basic()), }; - emitter.emit(None, msg, None, errors::Level::Fatal); + emitter.emit(&MultiSpan::new(), msg, None, errors::Level::Fatal); panic!(errors::FatalError); } @@ -578,7 +578,7 @@ pub fn early_warn(output: config::ErrorOutputType, msg: &str) { } config::ErrorOutputType::Json => Box::new(JsonEmitter::basic()), }; - emitter.emit(None, msg, None, errors::Level::Warning); + emitter.emit(&MultiSpan::new(), msg, None, errors::Level::Warning); } // Err(0) means compilation was stopped, but no errors were found. diff --git a/src/librustc_driver/lib.rs b/src/librustc_driver/lib.rs index 2d3363507d06c..52306e388e235 100644 --- a/src/librustc_driver/lib.rs +++ b/src/librustc_driver/lib.rs @@ -91,8 +91,9 @@ use std::thread; use rustc::session::early_error; -use syntax::{ast, errors, diagnostics}; -use syntax::codemap::{CodeMap, FileLoader, RealFileLoader}; +use syntax::{ast, errors, diagnostic}; +use syntax::codemap::MultiSpan; +use syntax::parse::{self, PResult}; use syntax::errors::emitter::Emitter; use syntax::feature_gate::{GatedCfg, UnstableFeatures}; use syntax::parse::{self, PResult, token}; @@ -136,7 +137,8 @@ pub fn run(args: Vec) -> isize { None => { let mut emitter = errors::emitter::BasicEmitter::stderr(errors::ColorConfig::Auto); - emitter.emit(None, &abort_msg(err_count), None, errors::Level::Fatal); + emitter.emit(&MultiSpan::new(), &abort_msg(err_count), None, + errors::Level::Fatal); exit_on_err(); } } @@ -379,7 +381,7 @@ fn check_cfg(sopts: &config::Options, match item.node { ast::MetaItemKind::List(ref pred, _) => { saw_invalid_predicate = true; - emitter.emit(None, + emitter.emit(&MultiSpan::new(), &format!("invalid predicate in --cfg command line argument: `{}`", pred), None, @@ -1028,19 +1030,19 @@ pub fn monitor(f: F) { // a .span_bug or .bug call has already printed what // it wants to print. if !value.is::() { - emitter.emit(None, "unexpected panic", None, errors::Level::Bug); + emitter.emit(&MultiSpan::new(), "unexpected panic", None, errors::Level::Bug); } let xs = ["the compiler unexpectedly panicked. this is a bug.".to_string(), format!("we would appreciate a bug report: {}", BUG_REPORT_URL)]; for note in &xs { - emitter.emit(None, ¬e[..], None, errors::Level::Note) + emitter.emit(&MultiSpan::new(), ¬e[..], None, errors::Level::Note) } if match env::var_os("RUST_BACKTRACE") { Some(val) => &val != "0", None => false, } { - emitter.emit(None, + emitter.emit(&MultiSpan::new(), "run with `RUST_BACKTRACE=1` for a backtrace", None, errors::Level::Note); diff --git a/src/librustc_driver/test.rs b/src/librustc_driver/test.rs index ce92dd158c969..60f4ab1c95f2b 100644 --- a/src/librustc_driver/test.rs +++ b/src/librustc_driver/test.rs @@ -86,10 +86,6 @@ impl Emitter for ExpectErrorEmitter { lvl: Level) { remove_message(self, msg, lvl); } - - fn custom_emit(&mut self, _sp: &RenderSpan, msg: &str, lvl: Level) { - remove_message(self, msg, lvl); - } } fn errors(msgs: &[&str]) -> (Box, usize) { diff --git a/src/librustc_trans/back/write.rs b/src/librustc_trans/back/write.rs index 8a915f044053a..50fd039276253 100644 --- a/src/librustc_trans/back/write.rs +++ b/src/librustc_trans/back/write.rs @@ -19,7 +19,7 @@ use llvm::SMDiagnosticRef; use {CrateTranslation, ModuleTranslation}; use util::common::time; use util::common::path2cstr; -use syntax::codemap; +use syntax::codemap::{self, MultiSpan}; use syntax::errors::{self, Handler, Level}; use syntax::errors::emitter::Emitter; @@ -84,13 +84,13 @@ impl SharedEmitter { for diag in &*buffer { match diag.code { Some(ref code) => { - handler.emit_with_code(None, + handler.emit_with_code(&MultiSpan::new(), &diag.msg, &code[..], diag.lvl); }, None => { - handler.emit(None, + handler.emit(&MultiSpan::new(), &diag.msg, diag.lvl); }, @@ -101,9 +101,12 @@ impl SharedEmitter { } impl Emitter for SharedEmitter { - fn emit(&mut self, sp: Option<&codemap::MultiSpan>, - msg: &str, code: Option<&str>, lvl: Level) { - assert!(sp.is_none(), "SharedEmitter doesn't support spans"); + fn emit(&mut self, + sp: &codemap::MultiSpan, + msg: &str, + code: Option<&str>, + lvl: Level) { + assert!(sp.primary_span().is_none(), "SharedEmitter doesn't support spans"); self.buffer.lock().unwrap().push(Diagnostic { msg: msg.to_string(), @@ -112,8 +115,8 @@ impl Emitter for SharedEmitter { }); } - fn custom_emit(&mut self, _sp: &errors::RenderSpan, _msg: &str, _lvl: Level) { - bug!("SharedEmitter doesn't support custom_emit"); + fn emit_struct(&mut self, _db: &errors::DiagnosticBuilder) { + bug!("SharedEmitter doesn't support emit_struct"); } } diff --git a/src/libsyntax/codemap.rs b/src/libsyntax/codemap.rs index 228af27f4b10a..5862538de2e04 100644 --- a/src/libsyntax/codemap.rs +++ b/src/libsyntax/codemap.rs @@ -163,6 +163,12 @@ pub const COMMAND_LINE_SP: Span = Span { lo: BytePos(0), expn_id: COMMAND_LINE_EXPN }; impl Span { + /// Returns a new span representing just the end-point of this span + pub fn end_point(self) -> Span { + let lo = cmp::max(self.hi.0 - 1, self.lo.0); + Span { lo: BytePos(lo), hi: self.hi, expn_id: self.expn_id} + } + /// Returns `self` if `self` is not the dummy span, and `other` otherwise. pub fn substitute_dummy(self, other: Span) -> Span { if self.source_equal(&DUMMY_SP) { other } else { self } @@ -794,7 +800,7 @@ impl CodeMap { /// Creates a new filemap and sets its line information. pub fn new_filemap_and_lines(&self, filename: &str, src: &str) -> Rc { let fm = self.new_filemap(filename.to_string(), src.to_owned()); - let mut byte_pos: u32 = 0; + let mut byte_pos: u32 = fm.start_pos.0; for line in src.lines() { // register the start of this line fm.next_line(BytePos(byte_pos)); @@ -1126,7 +1132,9 @@ impl CodeMap { // numbers in Loc are 1-based, so we subtract 1 to get 0-based // lines. for line_index in lo.line-1 .. hi.line-1 { - let line_len = lo.file.get_line(line_index).map(|s| s.len()).unwrap_or(0); + let line_len = lo.file.get_line(line_index) + .map(|s| s.chars().count()) + .unwrap_or(0); lines.push(LineInfo { line_index: line_index, start_col: start_col, end_col: CharPos::from_usize(line_len) }); @@ -1584,13 +1592,13 @@ mod tests { assert_eq!(file_lines.lines[0].line_index, 1); } - /// Given a string like " ^~~~~~~~~~~~ ", produces a span + /// Given a string like " ~~~~~~~~~~~~ ", produces a span /// coverting that range. The idea is that the string has the same /// length as the input, and we uncover the byte positions. Note /// that this can span lines and so on. fn span_from_selection(input: &str, selection: &str) -> Span { assert_eq!(input.len(), selection.len()); - let left_index = selection.find('^').unwrap() as u32; + let left_index = selection.find('~').unwrap() as u32; let right_index = selection.rfind('~').map(|x|x as u32).unwrap_or(left_index); Span { lo: BytePos(left_index), hi: BytePos(right_index + 1), expn_id: NO_EXPANSION } } @@ -1601,7 +1609,7 @@ mod tests { fn span_to_snippet_and_lines_spanning_multiple_lines() { let cm = CodeMap::new(); let inputtext = "aaaaa\nbbbbBB\nCCC\nDDDDDddddd\neee\n"; - let selection = " \n ^~\n~~~\n~~~~~ \n \n"; + let selection = " \n ~~\n~~~\n~~~~~ \n \n"; cm.new_filemap_and_lines("blork.rs", inputtext); let span = span_from_selection(inputtext, selection); @@ -1751,73 +1759,4 @@ r"blork2.rs:2:1: 2:12 "; assert_eq!(sstr, res_str); } - - #[test] - fn t13() { - // Test that collecting multiple spans into line-groups works correctly - let cm = CodeMap::new(); - let inp = "_aaaaa__bbb\nvv\nw\nx\ny\nz\ncccccc__ddddee__"; - let sp1 = " ^~~~~ \n \n \n \n \n \n "; - let sp2 = " \n \n \n \n \n^\n "; - let sp3 = " ^~~\n~~\n \n \n \n \n "; - let sp4 = " \n \n \n \n \n \n^~~~~~ "; - let sp5 = " \n \n \n \n \n \n ^~~~ "; - let sp6 = " \n \n \n \n \n \n ^~~~ "; - let sp_trim = " \n \n \n \n \n \n ^~ "; - let sp_merge = " \n \n \n \n \n \n ^~~~~~ "; - let sp7 = " \n ^\n \n \n \n \n "; - let sp8 = " \n \n^\n \n \n \n "; - let sp9 = " \n \n \n^\n \n \n "; - let sp10 = " \n \n \n \n^\n \n "; - - let span = |sp, expected| { - let sp = span_from_selection(inp, sp); - assert_eq!(&cm.span_to_snippet(sp).unwrap(), expected); - sp - }; - - cm.new_filemap_and_lines("blork.rs", inp); - let sp1 = span(sp1, "aaaaa"); - let sp2 = span(sp2, "z"); - let sp3 = span(sp3, "bbb\nvv"); - let sp4 = span(sp4, "cccccc"); - let sp5 = span(sp5, "dddd"); - let sp6 = span(sp6, "ddee"); - let sp7 = span(sp7, "v"); - let sp8 = span(sp8, "w"); - let sp9 = span(sp9, "x"); - let sp10 = span(sp10, "y"); - let sp_trim = span(sp_trim, "ee"); - let sp_merge = span(sp_merge, "ddddee"); - - let spans = vec![sp5, sp2, sp4, sp9, sp10, sp7, sp3, sp8, sp1, sp6]; - - macro_rules! check_next { - ($groups: expr, $expected: expr) => ({ - let actual = $groups.next().map(|g|&g.spans[..]); - let expected = $expected; - println!("actual:\n{:?}\n", actual); - println!("expected:\n{:?}\n", expected); - assert_eq!(actual, expected.as_ref().map(|x|&x[..])); - }); - } - - let _groups = cm.group_spans(spans.clone()); - let it = &mut _groups.iter(); - - check_next!(it, Some([sp1, sp7, sp8, sp9, sp10, sp2])); - // New group because we're exceeding MAX_HIGHLIGHT_LINES - check_next!(it, Some([sp4, sp_merge])); - check_next!(it, Some([sp3])); - check_next!(it, None::<[Span; 0]>); - - let _groups = cm.end_group_spans(spans); - let it = &mut _groups.iter(); - - check_next!(it, Some([sp1, sp7, sp8, sp9, sp10, sp2])); - // New group because we're exceeding MAX_HIGHLIGHT_LINES - check_next!(it, Some([sp4, sp5, sp_trim])); - check_next!(it, Some([sp3])); - check_next!(it, None::<[Span; 0]>); - } } diff --git a/src/libsyntax/errors/emitter.rs b/src/libsyntax/errors/emitter.rs index 0b5234769b219..e963a5f794cb6 100644 --- a/src/libsyntax/errors/emitter.rs +++ b/src/libsyntax/errors/emitter.rs @@ -16,6 +16,7 @@ use diagnostics; use errors::{Level, RenderSpan, CodeSuggestion, DiagnosticBuilder}; use errors::RenderSpan::*; use errors::Level::*; +use errors::snippet::{RenderedLineKind, SnippetData, Style}; use std::{cmp, fmt}; use std::io::prelude::*; @@ -24,27 +25,15 @@ use std::rc::Rc; use term; pub trait Emitter { - fn emit(&mut self, span: Option<&MultiSpan>, msg: &str, code: Option<&str>, lvl: Level); - fn custom_emit(&mut self, sp: &RenderSpan, msg: &str, lvl: Level); + fn emit(&mut self, span: &MultiSpan, msg: &str, code: Option<&str>, lvl: Level); /// Emit a structured diagnostic. - fn emit_struct(&mut self, db: &DiagnosticBuilder) { - self.emit(db.span.as_ref(), &db.message, db.code.as_ref().map(|s| &**s), db.level); - for child in &db.children { - match child.render_span { - Some(ref sp) => self.custom_emit(sp, &child.message, child.level), - None => self.emit(child.span.as_ref(), &child.message, None, child.level), - } - } - } + fn emit_struct(&mut self, db: &DiagnosticBuilder); } /// maximum number of lines we will print for each error; arbitrary. pub const MAX_HIGHLIGHT_LINES: usize = 6; -/// maximum number of lines we will print for each span; arbitrary. -const MAX_SP_LINES: usize = 6; - #[derive(Clone, Copy, Debug, PartialEq, Eq)] pub enum ColorConfig { Auto, @@ -70,19 +59,23 @@ pub struct BasicEmitter { impl Emitter for BasicEmitter { fn emit(&mut self, - msp: Option<&MultiSpan>, + msp: &MultiSpan, msg: &str, code: Option<&str>, lvl: Level) { - assert!(msp.is_none(), "BasicEmitter can't handle spans"); + assert!(msp.primary_span().is_none(), "BasicEmitter can't handle spans"); + if let Err(e) = print_diagnostic(&mut self.dst, "", lvl, msg, code) { panic!("failed to print diagnostics: {:?}", e); } - } - fn custom_emit(&mut self, _: &RenderSpan, _: &str, _: Level) { - panic!("BasicEmitter can't handle custom_emit"); + fn emit_struct(&mut self, db: &DiagnosticBuilder) { + self.emit(&db.span, &db.message, db.code.as_ref().map(|s| &**s), db.level); + for child in &db.children { + assert!(child.render_span.is_none(), "BasicEmitter can't handle spans"); + self.emit(&child.span, &child.message, None, child.level); + } } } @@ -101,33 +94,31 @@ pub struct EmitterWriter { dst: Destination, registry: Option, cm: Rc, + first: bool, } impl Emitter for EmitterWriter { fn emit(&mut self, - msp: Option<&MultiSpan>, + msp: &MultiSpan, msg: &str, code: Option<&str>, lvl: Level) { - let error = match msp.map(|s|(s.to_span_bounds(), s)) { - Some((COMMAND_LINE_SP, msp)) => { - self.emit_(&FileLine(msp.clone()), msg, code, lvl) - }, - Some((DUMMY_SP, _)) | None => print_diagnostic(&mut self.dst, "", lvl, msg, code), - Some((_, msp)) => self.emit_(&FullSpan(msp.clone()), msg, code, lvl), - }; - - if let Err(e) = error { - panic!("failed to print diagnostics: {:?}", e); - } + self.emit_multispan(msp, msg, code, lvl, true); } - fn custom_emit(&mut self, - rsp: &RenderSpan, - msg: &str, - lvl: Level) { - if let Err(e) = self.emit_(rsp, msg, None, lvl) { - panic!("failed to print diagnostics: {:?}", e); + fn emit_struct(&mut self, db: &DiagnosticBuilder) { + self.emit_multispan(&db.span, &db.message, + db.code.as_ref().map(|s| &**s), db.level, true); + + for child in &db.children { + match child.render_span { + Some(ref sp) => + self.emit_renderspan(sp, &child.message, + child.level), + None => + self.emit_multispan(&child.span, + &child.message, None, child.level, false), + } } } } @@ -153,9 +144,10 @@ impl EmitterWriter { -> EmitterWriter { if color_config.use_color() { let dst = Destination::from_stderr(); - EmitterWriter { dst: dst, registry: registry, cm: code_map } + EmitterWriter { dst: dst, registry: registry, cm: code_map, first: true } } else { - EmitterWriter { dst: Raw(Box::new(io::stderr())), registry: registry, cm: code_map } + EmitterWriter { dst: Raw(Box::new(io::stderr())), + registry: registry, cm: code_map, first: true } } } @@ -163,7 +155,49 @@ impl EmitterWriter { registry: Option, code_map: Rc) -> EmitterWriter { - EmitterWriter { dst: Raw(dst), registry: registry, cm: code_map } + EmitterWriter { dst: Raw(dst), registry: registry, cm: code_map, first: true } + } + + fn emit_multispan(&mut self, + span: &MultiSpan, + msg: &str, + code: Option<&str>, + lvl: Level, + is_header: bool) { + if is_header { + if self.first { + self.first = false; + } else { + match write!(self.dst, "\n") { + Ok(_) => { } + Err(e) => { + panic!("failed to print diagnostics: {:?}", e) + } + } + } + } + + let error = match span.primary_span() { + Some(COMMAND_LINE_SP) => { + self.emit_(&FileLine(span.clone()), msg, code, lvl) + } + Some(DUMMY_SP) | None => { + print_diagnostic(&mut self.dst, "", lvl, msg, code) + } + Some(_) => { + self.emit_(&FullSpan(span.clone()), msg, code, lvl) + } + }; + + if let Err(e) = error { + panic!("failed to print diagnostics: {:?}", e); + } + } + + fn emit_renderspan(&mut self, sp: &RenderSpan, msg: &str, lvl: Level) { + if let Err(e) = self.emit_(sp, msg, None, lvl) { + panic!("failed to print diagnostics: {:?}", e); + } } fn emit_(&mut self, @@ -173,51 +207,43 @@ impl EmitterWriter { lvl: Level) -> io::Result<()> { let msp = rsp.span(); - let bounds = msp.to_span_bounds(); - - let ss = if bounds == COMMAND_LINE_SP { - "".to_string() - } else if let EndSpan(_) = *rsp { - let span_end = Span { lo: bounds.hi, hi: bounds.hi, expn_id: bounds.expn_id}; - self.cm.span_to_string(span_end) - } else { - self.cm.span_to_string(bounds) - }; - - print_diagnostic(&mut self.dst, &ss[..], lvl, msg, code)?; + let primary_span = msp.primary_span(); + + 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; + print_diagnostic(&mut self.dst, "", lvl, msg, Some(&code_with_explain))? + } + _ => print_diagnostic(&mut self.dst, "", lvl, msg, code)? + } match *rsp { FullSpan(_) => { self.highlight_lines(msp, lvl)?; - self.print_macro_backtrace(bounds)?; - } - EndSpan(_) => { - self.end_highlight_lines(msp, lvl)?; - self.print_macro_backtrace(bounds)?; + if let Some(primary_span) = primary_span { + self.print_macro_backtrace(primary_span)?; + } } Suggestion(ref suggestion) => { self.highlight_suggestion(suggestion)?; - self.print_macro_backtrace(bounds)?; + if let Some(primary_span) = primary_span { + self.print_macro_backtrace(primary_span)?; + } } FileLine(..) => { // no source text in this case! } } - if let Some(code) = code { - if let Some(_) = self.registry.as_ref() - .and_then(|registry| registry.find_description(code)) { - print_diagnostic(&mut self.dst, &ss[..], Help, - &format!("run `rustc --explain {}` to see a \ - detailed explanation", code), None)?; - } - } Ok(()) } fn highlight_suggestion(&mut self, suggestion: &CodeSuggestion) -> io::Result<()> { - let lines = self.cm.span_to_lines(suggestion.msp.to_span_bounds()).unwrap(); + let primary_span = suggestion.msp.primary_span().unwrap(); + let lines = self.cm.span_to_lines(primary_span).unwrap(); assert!(!lines.lines.is_empty()); let complete = suggestion.splice_lines(&self.cm); @@ -251,325 +277,21 @@ impl EmitterWriter { lvl: Level) -> io::Result<()> { - let lines = match self.cm.span_to_lines(msp.to_span_bounds()) { - Ok(lines) => lines, - Err(_) => { - write!(&mut self.dst, "(internal compiler error: unprintable span)\n")?; - return Ok(()); - } - }; - - let fm = &*lines.file; - if let None = fm.src { - return Ok(()); - } - - let display_line_infos = &lines.lines[..]; - assert!(display_line_infos.len() > 0); - - // Calculate the widest number to format evenly and fix #11715 - let digits = line_num_max_digits(display_line_infos.last().unwrap()); - let first_line_index = display_line_infos.first().unwrap().line_index; - - let skip = fm.name.chars().count() + digits + 2; - - let mut spans = msp.spans.iter().peekable(); - let mut lines = display_line_infos.iter(); - let mut prev_line_index = first_line_index.wrapping_sub(1); - - // Display at most MAX_HIGHLIGHT_LINES lines. - let mut remaining_err_lines = MAX_HIGHLIGHT_LINES; - - // To emit a overflowed spans code-lines *AFTER* the rendered spans - let mut overflowed_buf = String::new(); - let mut overflowed = false; - - // FIXME (#8706) - 'l: loop { - if remaining_err_lines <= 0 { - break; - } - let line = match lines.next() { - Some(l) => l, - None => break, - }; - - // Skip is the number of characters we need to skip because they are - // part of the 'filename:line ' part of the code line. - let mut s: String = ::std::iter::repeat(' ').take(skip).collect(); - let mut col = skip; - let mut lastc = ' '; - - let cur_line_str = fm.get_line(line.line_index).unwrap(); - let mut line_chars = cur_line_str.chars().enumerate().peekable(); - let mut line_spans = 0; - - // Assemble spans for this line - loop { - // Peek here to preserve the span if it doesn't belong to this line - let sp = match spans.peek() { - Some(sp) => **sp, - None => break, - }; - let lo = self.cm.lookup_char_pos(sp.lo); - let hi = self.cm.lookup_char_pos(sp.hi); - let line_num = line.line_index + 1; - - if !(lo.line <= line_num && hi.line >= line_num) { - // This line is not contained in the span - if overflowed { - // Never elide the final line of an overflowed span - prev_line_index = line.line_index - 1; - overflowed = false; - break; - } - - if line_spans == 0 { - continue 'l; - } else { - // This line is finished, now render the spans we've assembled - break; - } - } - spans.next(); - line_spans += 1; - - if lo.line != hi.line { - // Assemble extra code lines to be emitted after this lines spans - // (substract `2` because the first and last line are rendered normally) - let max_lines = cmp::min(remaining_err_lines, MAX_SP_LINES) - 2; - prev_line_index = line.line_index; - let count = cmp::min((hi.line - lo.line - 1), max_lines); - for _ in 0..count { - let line = match lines.next() { - Some(l) => l, - None => break, - }; - let line_str = fm.get_line(line.line_index).unwrap(); - overflowed_buf.push_str(&format!("{}:{:>width$} {}\n", - fm.name, - line.line_index + 1, - line_str, - width=digits)); - remaining_err_lines -= 1; - prev_line_index += 1 - } - // Remember that the span overflowed to ensure - // that we emit its last line exactly once - // (other spans may, or may not, start on it) - overflowed = true; - break; - } - - for (pos, ch) in line_chars.by_ref() { - lastc = ch; - if pos >= lo.col.to_usize() { break; } - // Whenever a tab occurs on the code line, we insert one on - // the error-point-squiggly-line as well (instead of a space). - // That way the squiggly line will usually appear in the correct - // position. - match ch { - '\t' => { - col += 8 - col%8; - s.push('\t'); - }, - _ => { - col += 1; - s.push(' '); - }, - } - } - - s.push('^'); - let col_ptr = col; - let count = match lastc { - // Most terminals have a tab stop every eight columns by default - '\t' => 8 - col%8, - _ => 1, - }; - col += count; - s.extend(::std::iter::repeat('~').take(count)); - - let hi = self.cm.lookup_char_pos(sp.hi); - if hi.col != lo.col { - let mut chars = line_chars.by_ref(); - loop { - // We peek here to preserve the value for the next span - let (pos, ch) = match chars.peek() { - Some(elem) => *elem, - None => break, - }; - if pos >= hi.col.to_usize() { break; } - let count = match ch { - '\t' => 8 - col%8, - _ => 1, - }; - col += count; - s.extend(::std::iter::repeat('~').take(count)); - - chars.next(); - } - } - if (col - col_ptr) > 0 { - // One extra squiggly is replaced by a "^" - s.pop(); - } - } - - // If we elided something put an ellipsis. - if prev_line_index != line.line_index.wrapping_sub(1) && !overflowed { - write!(&mut self.dst, "{0:1$}...\n", "", skip)?; - } - - // Print offending code-line - remaining_err_lines -= 1; - write!(&mut self.dst, "{}:{:>width$} {}\n", - fm.name, - line.line_index + 1, - cur_line_str, - width=digits)?; - - if s.len() > skip { - // Render the spans we assembled previously (if any). - println_maybe_styled!(&mut self.dst, term::Attr::ForegroundColor(lvl.color()), - "{}", s)?; - } - - if !overflowed_buf.is_empty() { - // Print code-lines trailing the rendered spans (when a span overflows) - write!(&mut self.dst, "{}", &overflowed_buf)?; - overflowed_buf.clear(); - } else { - prev_line_index = line.line_index; - } - } - - // If we elided something, put an ellipsis. - if lines.next().is_some() { - write!(&mut self.dst, "{0:1$}...\n", "", skip)?; - } - Ok(()) - } - - /// Here are the differences between this and the normal `highlight_lines`: - /// `end_highlight_lines` will always put arrow on the last byte of each - /// span (instead of the first byte). Also, when a span is too long (more - /// than 6 lines), `end_highlight_lines` will print the first line, then - /// dot dot dot, then last line, whereas `highlight_lines` prints the first - /// six lines. - #[allow(deprecated)] - fn end_highlight_lines(&mut self, - msp: &MultiSpan, - lvl: Level) - -> io::Result<()> { - let lines = match self.cm.span_to_lines(msp.to_span_bounds()) { - Ok(lines) => lines, - Err(_) => { - write!(&mut self.dst, "(internal compiler error: unprintable span)\n")?; - return Ok(()); - } - }; - - let fm = &*lines.file; - if let None = fm.src { - return Ok(()); + let mut snippet_data = SnippetData::new(self.cm.clone(), + msp.primary_span()); + for span_label in msp.span_labels() { + snippet_data.push(span_label.span, + span_label.is_primary, + span_label.label); } - - let lines = &lines.lines[..]; - - // Calculate the widest number to format evenly - let first_line = lines.first().unwrap(); - let last_line = lines.last().unwrap(); - let digits = line_num_max_digits(last_line); - - let skip = fm.name.chars().count() + digits + 2; - - let mut spans = msp.spans.iter().peekable(); - let mut lines = lines.iter(); - let mut prev_line_index = first_line.line_index.wrapping_sub(1); - - // Display at most MAX_HIGHLIGHT_LINES lines. - let mut remaining_err_lines = MAX_HIGHLIGHT_LINES; - - 'l: loop { - if remaining_err_lines <= 0 { - break; - } - let line = match lines.next() { - Some(line) => line, - None => break, - }; - - // Skip is the number of characters we need to skip because they are - // part of the 'filename:line ' part of the previous line. - let mut s: String = ::std::iter::repeat(' ').take(skip).collect(); - - let line_str = fm.get_line(line.line_index).unwrap(); - let mut line_chars = line_str.chars().enumerate(); - let mut line_spans = 0; - - loop { - // Peek here to preserve the span if it doesn't belong to this line - let sp = match spans.peek() { - Some(sp) => **sp, - None => break, - }; - let lo = self.cm.lookup_char_pos(sp.lo); - let hi = self.cm.lookup_char_pos(sp.hi); - let elide_sp = (hi.line - lo.line) >= MAX_SP_LINES; - - let line_num = line.line_index + 1; - if !(lo.line <= line_num && hi.line >= line_num) { - // This line is not contained in the span - if line_spans == 0 { - continue 'l; - } else { - // This line is finished, now render the spans we've assembled - break - } - } else if hi.line > line_num { - if elide_sp && lo.line < line_num { - // This line is inbetween the first and last line of the span, - // so we may want to elide it. - continue 'l; - } else { - break - } - } - line_spans += 1; - spans.next(); - - for (pos, ch) in line_chars.by_ref() { - // Span seems to use half-opened interval, so subtract 1 - if pos >= hi.col.to_usize() - 1 { break; } - // Whenever a tab occurs on the previous line, we insert one on - // the error-point-squiggly-line as well (instead of a space). - // That way the squiggly line will usually appear in the correct - // position. - match ch { - '\t' => s.push('\t'), - _ => s.push(' '), - } - } - s.push('^'); + 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()?; } - - if prev_line_index != line.line_index.wrapping_sub(1) { - // If we elided something, put an ellipsis. - write!(&mut self.dst, "{0:1$}...\n", "", skip)?; - } - - // Print offending code-lines - write!(&mut self.dst, "{}:{:>width$} {}\n", fm.name, - line.line_index + 1, line_str, width=digits)?; - remaining_err_lines -= 1; - - if s.len() > skip { - // Render the spans we assembled previously (if any) - println_maybe_styled!(&mut self.dst, term::Attr::ForegroundColor(lvl.color()), - "{}", s)?; - } - prev_line_index = line.line_index; + write!(&mut self.dst, "\n")?; } Ok(()) } @@ -602,6 +324,7 @@ fn line_num_max_digits(line: &codemap::LineInfo) -> usize { digits } + fn print_diagnostic(dst: &mut Destination, topic: &str, lvl: Level, @@ -609,17 +332,22 @@ fn print_diagnostic(dst: &mut Destination, code: Option<&str>) -> io::Result<()> { if !topic.is_empty() { - write!(dst, "{} ", topic)?; - } - - print_maybe_styled!(dst, term::Attr::ForegroundColor(lvl.color()), - "{}: ", lvl.to_string())?; - print_maybe_styled!(dst, term::Attr::Bold, "{}", msg)?; - + dst.start_attr(term::Attr::ForegroundColor(lvl.color()))?; + 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(()) } @@ -660,6 +388,52 @@ impl Destination { } } + fn apply_style(&mut self, + lvl: Level, + _kind: &RenderedLineKind, + style: Style) + -> io::Result<()> { + match style { + Style::FileNameStyle => { + } + Style::LineAndColumn => { + } + Style::LineNumber => { + self.start_attr(term::Attr::Bold)?; + self.start_attr(term::Attr::ForegroundColor(term::color::BRIGHT_BLUE))?; + } + Style::Quotation => { + } + Style::UnderlinePrimary | Style::LabelPrimary => { + self.start_attr(term::Attr::Bold)?; + self.start_attr(term::Attr::ForegroundColor(lvl.color()))?; + } + Style::UnderlineSecondary | Style::LabelSecondary => { + self.start_attr(term::Attr::Bold)?; + self.start_attr(term::Attr::ForegroundColor(term::color::BRIGHT_BLUE))?; + } + Style::NoStyle => { + } + } + Ok(()) + } + + fn start_attr(&mut self, attr: term::Attr) -> io::Result<()> { + match *self { + Terminal(ref mut t) => { t.attr(attr)?; } + Raw(_) => { } + } + Ok(()) + } + + fn reset_attrs(&mut self) -> io::Result<()> { + match *self { + Terminal(ref mut t) => { t.reset()?; } + Raw(_) => { } + } + Ok(()) + } + fn print_maybe_styled(&mut self, args: fmt::Arguments, color: term::Attr, @@ -741,7 +515,7 @@ mod test { /// that this can span lines and so on. fn span_from_selection(input: &str, selection: &str) -> Span { assert_eq!(input.len(), selection.len()); - let left_index = selection.find('^').unwrap() as u32; + let left_index = selection.find('~').unwrap() as u32; let right_index = selection.rfind('~').map(|x|x as u32).unwrap_or(left_index); Span { lo: BytePos(left_index), hi: BytePos(right_index + 1), expn_id: NO_EXPANSION } } @@ -777,12 +551,15 @@ mod test { let vec = data.lock().unwrap().clone(); let vec: &[u8] = &vec; let str = from_utf8(vec).unwrap(); - println!("{}", str); - assert_eq!(str, "dummy.txt: 8 line8\n\ - dummy.txt: 9 line9\n\ - dummy.txt:10 line10\n\ - dummy.txt:11 e-lä-vän\n\ - dummy.txt:12 tolv\n"); + println!("r#\"\n{}\"#", str); + assert_eq!(str, &r#" + --> dummy.txt:8:1 +8 |> line8 + |> ^^^^^^^^^^^^^ +... +11 |> e-lä-vän + |> ^^^^^^^^^^^^^^^^ +"#[1..]); } #[test] @@ -790,7 +567,7 @@ mod test { // Test that a `MultiSpan` containing a single span splices a substition correctly let cm = CodeMap::new(); let inputtext = "aaaaa\nbbbbBB\nCCC\nDDDDDddddd\neee\n"; - let selection = " \n ^~\n~~~\n~~~~~ \n \n"; + let selection = " \n ~~\n~~~\n~~~~~ \n \n"; cm.new_filemap_and_lines("blork.rs", inputtext); let sp = span_from_selection(inputtext, selection); let msp: MultiSpan = sp.into(); @@ -808,51 +585,25 @@ mod test { } #[test] - fn test_multiple_span_splice() { - // Test that a `MultiSpan` containing multiple spans splices substitions on - // several lines correctly + fn test_multi_span_splice() { + // Test that a `MultiSpan` containing multiple spans splices a substition correctly let cm = CodeMap::new(); - let inp = "aaaaabbbbBB\nZZ\nZZ\nCCCDDDDDdddddeee"; - let sp1 = " ^~~~~~\n \n \n "; - let sp2 = " \n \n \n^~~~~~ "; - let sp3 = " \n \n \n ^~~ "; - let sp4 = " \n \n \n ^~~~ "; - - let span_eq = |sp, eq| assert_eq!(&cm.span_to_snippet(sp).unwrap(), eq); - - cm.new_filemap_and_lines("blork.rs", inp); - let sp1 = span_from_selection(inp, sp1); - let sp2 = span_from_selection(inp, sp2); - let sp3 = span_from_selection(inp, sp3); - let sp4 = span_from_selection(inp, sp4); - span_eq(sp1, "bbbbBB"); - span_eq(sp2, "CCCDDD"); - span_eq(sp3, "ddd"); - span_eq(sp4, "ddee"); - - let substitutes: Vec = ["1", "2", "3", "4"].iter().map(|x|x.to_string()).collect(); - let expected = "aaaaa1\nZZ\nZZ\n2DD34e"; - - let test = |msp| { - let suggest = CodeSuggestion { - msp: msp, - substitutes: substitutes.clone(), - }; - let actual = suggest.splice_lines(&cm); - assert_eq!(actual, expected); + let inputtext = "aaaaa\nbbbbBB\nCCC\nDDDDDddddd\neee\n"; + let selection1 = " \n \n \n \n ~ \n"; // intentionally out of order + let selection2 = " \n ~~\n~~~\n~~~~~ \n \n"; + cm.new_filemap_and_lines("blork.rs", inputtext); + let sp1 = span_from_selection(inputtext, selection1); + let sp2 = span_from_selection(inputtext, selection2); + let msp: MultiSpan = MultiSpan::from_spans(vec![sp1, sp2]); + + let expected = "bbbbZZZZZZddddd\neXYZe"; + let suggest = CodeSuggestion { + msp: msp, + substitutes: vec!["ZZZZZZ".to_owned(), + "XYZ".to_owned()] }; - test(MultiSpan { spans: vec![sp1, sp2, sp3, sp4] }); - - // Test ordering and merging by `MultiSpan::push` - let mut msp = MultiSpan::new(); - msp.push_merge(sp2); - msp.push_merge(sp1); - assert_eq!(&msp.spans, &[sp1, sp2]); - msp.push_merge(sp4); - assert_eq!(&msp.spans, &[sp1, sp2, sp4]); - msp.push_merge(sp3); - assert_eq!(&msp.spans, &[sp1, sp2, sp3, sp4]); - test(msp); + + assert_eq!(suggest.splice_lines(&cm), expected); } #[test] @@ -862,17 +613,17 @@ mod test { let mut diag = EmitterWriter::new(Box::new(Sink(data.clone())), None, cm.clone()); let inp = "_____aaaaaa____bbbbbb__cccccdd_"; - let sp1 = " ^~~~~~ "; - let sp2 = " ^~~~~~ "; - let sp3 = " ^~~~~ "; - let sp4 = " ^~~~ "; - let sp34 = " ^~~~~~~ "; - let sp4_end = " ^~ "; - - let expect_start = "dummy.txt:1 _____aaaaaa____bbbbbb__cccccdd_\n\ - \x20 ^~~~~~ ^~~~~~ ^~~~~~~\n"; - let expect_end = "dummy.txt:1 _____aaaaaa____bbbbbb__cccccdd_\n\ - \x20 ^ ^ ^ ^\n"; + let sp1 = " ~~~~~~ "; + let sp2 = " ~~~~~~ "; + let sp3 = " ~~~~~ "; + let sp4 = " ~~~~ "; + let sp34 = " ~~~~~~~ "; + + let expect_start = &r#" + --> dummy.txt:1:6 +1 |> _____aaaaaa____bbbbbb__cccccdd_ + |> ^^^^^^ ^^^^^^ ^^^^^^^ +"#[1..]; let span = |sp, expected| { let sp = span_from_selection(inp, sp); @@ -885,7 +636,6 @@ mod test { let sp3 = span(sp3, "ccccc"); let sp4 = span(sp4, "ccdd"); let sp34 = span(sp34, "cccccdd"); - let sp4_end = span(sp4_end, "dd"); let spans = vec![sp1, sp2, sp3, sp4]; @@ -894,26 +644,17 @@ mod test { highlight(); let vec = data.lock().unwrap().clone(); let actual = from_utf8(&vec[..]).unwrap(); + println!("actual=\n{}", actual); assert_eq!(actual, expected); }; - let msp = MultiSpan { spans: vec![sp1, sp2, sp34] }; - let msp_end = MultiSpan { spans: vec![sp1, sp2, sp3, sp4_end] }; + let msp = MultiSpan::from_spans(vec![sp1, sp2, sp34]); test(expect_start, &mut || { diag.highlight_lines(&msp, Level::Error).unwrap(); }); - test(expect_end, &mut || { - diag.end_highlight_lines(&msp_end, Level::Error).unwrap(); - }); test(expect_start, &mut || { - for msp in cm.group_spans(spans.clone()) { - diag.highlight_lines(&msp, Level::Error).unwrap(); - } - }); - test(expect_end, &mut || { - for msp in cm.end_group_spans(spans.clone()) { - diag.end_highlight_lines(&msp, Level::Error).unwrap(); - } + let msp = MultiSpan::from_spans(spans.clone()); + diag.highlight_lines(&msp, Level::Error).unwrap(); }); } @@ -950,75 +691,31 @@ mod test { let sp4 = span(10, 10, (2, 3)); let sp5 = span(10, 10, (4, 6)); - let expect0 = "dummy.txt: 5 ccccc\n\ - dummy.txt: 6 xxxxx\n\ - dummy.txt: 7 yyyyy\n\ - \x20 ...\n\ - dummy.txt: 9 ddd__eee_\n\ - \x20 ^~~ ^~~\n\ - \x20 ...\n\ - dummy.txt:11 __f_gg\n\ - \x20 ^ ^~\n"; - - let expect = "dummy.txt: 1 aaaaa\n\ - dummy.txt: 2 aaaaa\n\ - dummy.txt: 3 aaaaa\n\ - dummy.txt: 4 bbbbb\n\ - dummy.txt: 5 ccccc\n\ - dummy.txt: 6 xxxxx\n\ - \x20 ...\n"; - - let expect_g1 = "dummy.txt:1 aaaaa\n\ - dummy.txt:2 aaaaa\n\ - dummy.txt:3 aaaaa\n\ - dummy.txt:4 bbbbb\n\ - dummy.txt:5 ccccc\n\ - dummy.txt:6 xxxxx\n\ - \x20 ...\n"; - - let expect2 = "dummy.txt: 9 ddd__eee_\n\ - \x20 ^~~ ^~~\n\ - \x20 ...\n\ - dummy.txt:11 __f_gg\n\ - \x20 ^ ^~\n"; - - - let expect_end = "dummy.txt: 1 aaaaa\n\ - \x20 ...\n\ - dummy.txt: 7 yyyyy\n\ - \x20 ^\n\ - \x20 ...\n\ - dummy.txt: 9 ddd__eee_\n\ - \x20 ^ ^\n\ - \x20 ...\n\ - dummy.txt:11 __f_gg\n\ - \x20 ^ ^\n"; - - let expect0_end = "dummy.txt: 5 ccccc\n\ - dummy.txt: 6 xxxxx\n\ - dummy.txt: 7 yyyyy\n\ - \x20 ^\n\ - \x20 ...\n\ - dummy.txt: 9 ddd__eee_\n\ - \x20 ^ ^\n\ - \x20 ...\n\ - dummy.txt:11 __f_gg\n\ - \x20 ^ ^\n"; - - let expect_end_g1 = "dummy.txt:1 aaaaa\n\ - \x20 ...\n\ - dummy.txt:7 yyyyy\n\ - \x20 ^\n"; - - let expect2_end = "dummy.txt: 9 ddd__eee_\n\ - \x20 ^ ^\n\ - \x20 ...\n\ - dummy.txt:11 __f_gg\n\ - \x20 ^ ^\n"; - - let expect_groups = [expect2, expect_g1]; - let expect_end_groups = [expect2_end, expect_end_g1]; - let spans = vec![sp3, sp1, sp4, sp2, sp5]; + let expect0 = &r#" + --> dummy.txt:5:1 +5 |> ccccc + |> ^^^^^ +... +8 |> _____ +9 |> ddd__eee_ + |> ^^^ ^^^ +10 |> elided +11 |> __f_gg + |> ^ ^^ +"#[1..]; + + let expect = &r#" + --> dummy.txt:1:1 +1 |> aaaaa + |> ^^^^^ +... +8 |> _____ +9 |> ddd__eee_ + |> ^^^ ^^^ +10 |> elided +11 |> __f_gg + |> ^ ^^ +"#[1..]; macro_rules! test { ($expected: expr, $highlight: expr) => ({ @@ -1034,37 +731,14 @@ mod test { }); } - let msp0 = MultiSpan { spans: vec![sp0, sp2, sp3, sp4, sp5] }; - let msp = MultiSpan { spans: vec![sp1, sp2, sp3, sp4, sp5] }; - let msp2 = MultiSpan { spans: vec![sp2, sp3, sp4, sp5] }; + let msp0 = MultiSpan::from_spans(vec![sp0, sp2, sp3, sp4, sp5]); + let msp = MultiSpan::from_spans(vec![sp1, sp2, sp3, sp4, sp5]); test!(expect0, || { diag.highlight_lines(&msp0, Level::Error).unwrap(); }); - test!(expect0_end, || { - diag.end_highlight_lines(&msp0, Level::Error).unwrap(); - }); test!(expect, || { diag.highlight_lines(&msp, Level::Error).unwrap(); }); - test!(expect_end, || { - diag.end_highlight_lines(&msp, Level::Error).unwrap(); - }); - test!(expect2, || { - diag.highlight_lines(&msp2, Level::Error).unwrap(); - }); - test!(expect2_end, || { - diag.end_highlight_lines(&msp2, Level::Error).unwrap(); - }); - for (msp, expect) in cm.group_spans(spans.clone()).iter().zip(expect_groups.iter()) { - test!(expect, || { - diag.highlight_lines(&msp, Level::Error).unwrap(); - }); - } - for (msp, expect) in cm.group_spans(spans.clone()).iter().zip(expect_end_groups.iter()) { - test!(expect, || { - diag.end_highlight_lines(&msp, Level::Error).unwrap(); - }); - } } } diff --git a/src/libsyntax/errors/mod.rs b/src/libsyntax/errors/mod.rs index 792828b3054e9..abbc4eef7bf81 100644 --- a/src/libsyntax/errors/mod.rs +++ b/src/libsyntax/errors/mod.rs @@ -13,7 +13,7 @@ pub use errors::emitter::ColorConfig; use self::Level::*; use self::RenderSpan::*; -use codemap::{self, CodeMap, MultiSpan}; +use codemap::{self, CodeMap, MultiSpan, NO_EXPANSION, Span}; use diagnostics; use errors::emitter::{Emitter, EmitterWriter}; @@ -24,6 +24,7 @@ use term; pub mod emitter; pub mod json; +pub mod snippet; #[derive(Clone)] pub enum RenderSpan { @@ -32,13 +33,6 @@ pub enum RenderSpan { /// the source code covered by the span. FullSpan(MultiSpan), - /// Similar to a FullSpan, but the cited position is the end of - /// the span, instead of the start. Used, at least, for telling - /// compiletest/runtest to look at the last line of the span - /// (since `end_highlight_lines` displays an arrow to the end - /// of the span). - EndSpan(MultiSpan), - /// A suggestion renders with both with an initial line for the /// message, prefixed by file:linenum, followed by a summary /// of hypothetical source code, where each `String` is spliced @@ -61,7 +55,6 @@ impl RenderSpan { match *self { FullSpan(ref msp) | Suggestion(CodeSuggestion { ref msp, .. }) | - EndSpan(ref msp) | FileLine(ref msp) => msp } @@ -88,12 +81,24 @@ impl CodeSuggestion { } } } - let bounds = self.msp.to_span_bounds(); - let lines = cm.span_to_lines(bounds).unwrap(); - assert!(!lines.lines.is_empty()); - // This isn't strictly necessary, but would in all likelyhood be an error - assert_eq!(self.msp.spans.len(), self.substitutes.len()); + let mut primary_spans = self.msp.primary_spans().to_owned(); + + assert_eq!(primary_spans.len(), self.substitutes.len()); + if primary_spans.is_empty() { + return format!(""); + } + + // Assumption: all spans are in the same file, and all spans + // are disjoint. Sort in ascending order. + primary_spans.sort_by_key(|sp| sp.lo); + + // Find the bounding span. + let lo = primary_spans.iter().map(|sp| sp.lo).min().unwrap(); + let hi = primary_spans.iter().map(|sp| sp.hi).min().unwrap(); + let bounding_span = Span { lo: lo, hi: hi, expn_id: NO_EXPANSION }; + let lines = cm.span_to_lines(bounding_span).unwrap(); + assert!(!lines.lines.is_empty()); // To build up the result, we do this for each span: // - push the line segment trailing the previous span @@ -105,13 +110,13 @@ impl CodeSuggestion { // // Finally push the trailing line segment of the last span let fm = &lines.file; - let mut prev_hi = cm.lookup_char_pos(bounds.lo); + let mut prev_hi = cm.lookup_char_pos(bounding_span.lo); prev_hi.col = CharPos::from_usize(0); let mut prev_line = fm.get_line(lines.lines[0].line_index); let mut buf = String::new(); - for (sp, substitute) in self.msp.spans.iter().zip(self.substitutes.iter()) { + for (sp, substitute) in primary_spans.iter().zip(self.substitutes.iter()) { let cur_lo = cm.lookup_char_pos(sp.lo); if prev_hi.line == cur_lo.line { push_trailing(&mut buf, prev_line, &prev_hi, Some(&cur_lo)); @@ -183,7 +188,7 @@ pub struct DiagnosticBuilder<'a> { level: Level, message: String, code: Option, - span: Option, + span: MultiSpan, children: Vec, } @@ -192,7 +197,7 @@ pub struct DiagnosticBuilder<'a> { struct SubDiagnostic { level: Level, message: String, - span: Option, + span: MultiSpan, render_span: Option, } @@ -228,37 +233,61 @@ impl<'a> DiagnosticBuilder<'a> { self.level == Level::Fatal } - pub fn note(&mut self , msg: &str) -> &mut DiagnosticBuilder<'a> { - self.sub(Level::Note, msg, None, None); + /// Add a span/label to be included in the resulting snippet. + /// This is pushed onto the `MultiSpan` that was created when the + /// diagnostic was first built. If you don't call this function at + /// all, and you just supplied a `Span` to create the diagnostic, + /// then the snippet will just include that `Span`, which is + /// called the primary span. + pub fn span_label(mut self, span: Span, label: &fmt::Display) + -> DiagnosticBuilder<'a> { + self.span.push_span_label(span, format!("{}", label)); + self + } + + pub fn note_expected_found(mut self, + label: &fmt::Display, + expected: &fmt::Display, + found: &fmt::Display) + -> DiagnosticBuilder<'a> + { + // For now, just attach these as notes + self.note(&format!("expected {} `{}`", label, expected)); + self.note(&format!(" found {} `{}`", label, found)); + self + } + + pub fn note(&mut self, msg: &str) -> &mut DiagnosticBuilder<'a> { + self.sub(Level::Note, msg, MultiSpan::new(), None); self } pub fn span_note>(&mut self, sp: S, msg: &str) -> &mut DiagnosticBuilder<'a> { - self.sub(Level::Note, msg, Some(sp.into()), None); + self.sub(Level::Note, msg, sp.into(), None); self } pub fn warn(&mut self, msg: &str) -> &mut DiagnosticBuilder<'a> { - self.sub(Level::Warning, msg, None, None); + self.sub(Level::Warning, msg, MultiSpan::new(), None); self } pub fn span_warn>(&mut self, sp: S, msg: &str) -> &mut DiagnosticBuilder<'a> { - self.sub(Level::Warning, msg, Some(sp.into()), None); + self.sub(Level::Warning, msg, sp.into(), None); self } pub fn help(&mut self , msg: &str) -> &mut DiagnosticBuilder<'a> { - self.sub(Level::Help, msg, None, None); + self.sub(Level::Help, msg, MultiSpan::new(), None); self } pub fn span_help>(&mut self, sp: S, msg: &str) -> &mut DiagnosticBuilder<'a> { - self.sub(Level::Help, msg, Some(sp.into()), None); + self.sub(Level::Help, msg, sp.into(), None); self } /// Prints out a message with a suggested edit of the code. @@ -269,43 +298,15 @@ impl<'a> DiagnosticBuilder<'a> { msg: &str, suggestion: String) -> &mut DiagnosticBuilder<'a> { - self.sub(Level::Help, msg, None, Some(Suggestion(CodeSuggestion { + self.sub(Level::Help, msg, MultiSpan::new(), Some(Suggestion(CodeSuggestion { msp: sp.into(), substitutes: vec![suggestion], }))); self } - pub fn span_end_note>(&mut self, - sp: S, - msg: &str) - -> &mut DiagnosticBuilder<'a> { - self.sub(Level::Note, msg, None, Some(EndSpan(sp.into()))); - self - } - pub fn fileline_warn>(&mut self, - sp: S, - msg: &str) - -> &mut DiagnosticBuilder<'a> { - self.sub(Level::Warning, msg, None, Some(FileLine(sp.into()))); - self - } - pub fn fileline_note>(&mut self, - sp: S, - msg: &str) - -> &mut DiagnosticBuilder<'a> { - self.sub(Level::Note, msg, None, Some(FileLine(sp.into()))); - self - } - pub fn fileline_help>(&mut self, - sp: S, - msg: &str) - -> &mut DiagnosticBuilder<'a> { - self.sub(Level::Help, msg, None, Some(FileLine(sp.into()))); - self - } - pub fn span>(&mut self, sp: S) -> &mut Self { - self.span = Some(sp.into()); + pub fn set_span>(&mut self, sp: S) -> &mut Self { + self.span = sp.into(); self } @@ -324,7 +325,7 @@ impl<'a> DiagnosticBuilder<'a> { level: level, message: message.to_owned(), code: None, - span: None, + span: MultiSpan::new(), children: vec![], } } @@ -334,7 +335,7 @@ impl<'a> DiagnosticBuilder<'a> { fn sub(&mut self, level: Level, message: &str, - span: Option, + span: MultiSpan, render_span: Option) { let sub = SubDiagnostic { level: level, @@ -357,7 +358,10 @@ impl<'a> fmt::Debug for DiagnosticBuilder<'a> { impl<'a> Drop for DiagnosticBuilder<'a> { fn drop(&mut self) { if !self.cancelled() { - self.emitter.borrow_mut().emit(None, "Error constructed but not emitted", None, Bug); + self.emitter.borrow_mut().emit(&MultiSpan::new(), + "Error constructed but not emitted", + None, + Bug); panic!(); } } @@ -412,7 +416,7 @@ impl Handler { msg: &str) -> DiagnosticBuilder<'a> { let mut result = DiagnosticBuilder::new(&self.emit, Level::Warning, msg); - result.span(sp); + result.set_span(sp); if !self.can_emit_warnings { result.cancel(); } @@ -424,7 +428,7 @@ impl Handler { code: &str) -> DiagnosticBuilder<'a> { let mut result = DiagnosticBuilder::new(&self.emit, Level::Warning, msg); - result.span(sp); + result.set_span(sp); result.code(code.to_owned()); if !self.can_emit_warnings { result.cancel(); @@ -444,7 +448,7 @@ impl Handler { -> DiagnosticBuilder<'a> { self.bump_err_count(); let mut result = DiagnosticBuilder::new(&self.emit, Level::Error, msg); - result.span(sp); + result.set_span(sp); result } pub fn struct_span_err_with_code<'a, S: Into>(&'a self, @@ -454,7 +458,7 @@ impl Handler { -> DiagnosticBuilder<'a> { self.bump_err_count(); let mut result = DiagnosticBuilder::new(&self.emit, Level::Error, msg); - result.span(sp); + result.set_span(sp); result.code(code.to_owned()); result } @@ -468,7 +472,7 @@ impl Handler { -> DiagnosticBuilder<'a> { self.bump_err_count(); let mut result = DiagnosticBuilder::new(&self.emit, Level::Fatal, msg); - result.span(sp); + result.set_span(sp); result } pub fn struct_span_fatal_with_code<'a, S: Into>(&'a self, @@ -478,7 +482,7 @@ impl Handler { -> DiagnosticBuilder<'a> { self.bump_err_count(); let mut result = DiagnosticBuilder::new(&self.emit, Level::Fatal, msg); - result.span(sp); + result.set_span(sp); result.code(code.to_owned()); result } @@ -499,7 +503,7 @@ impl Handler { if self.treat_err_as_bug { self.span_bug(sp, msg); } - self.emit(Some(&sp.into()), msg, Fatal); + self.emit(&sp.into(), msg, Fatal); self.bump_err_count(); return FatalError; } @@ -508,7 +512,7 @@ impl Handler { if self.treat_err_as_bug { self.span_bug(sp, msg); } - self.emit_with_code(Some(&sp.into()), msg, code, Fatal); + self.emit_with_code(&sp.into(), msg, code, Fatal); self.bump_err_count(); return FatalError; } @@ -516,24 +520,24 @@ impl Handler { if self.treat_err_as_bug { self.span_bug(sp, msg); } - self.emit(Some(&sp.into()), msg, Error); + self.emit(&sp.into(), msg, Error); self.bump_err_count(); } pub fn span_err_with_code>(&self, sp: S, msg: &str, code: &str) { if self.treat_err_as_bug { self.span_bug(sp, msg); } - self.emit_with_code(Some(&sp.into()), msg, code, Error); + self.emit_with_code(&sp.into(), msg, code, Error); self.bump_err_count(); } pub fn span_warn>(&self, sp: S, msg: &str) { - self.emit(Some(&sp.into()), msg, Warning); + self.emit(&sp.into(), msg, Warning); } pub fn span_warn_with_code>(&self, sp: S, msg: &str, code: &str) { - self.emit_with_code(Some(&sp.into()), msg, code, Warning); + self.emit_with_code(&sp.into(), msg, code, Warning); } pub fn span_bug>(&self, sp: S, msg: &str) -> ! { - self.emit(Some(&sp.into()), msg, Bug); + self.emit(&sp.into(), msg, Bug); panic!(ExplicitBug); } pub fn delay_span_bug>(&self, sp: S, msg: &str) { @@ -541,11 +545,11 @@ impl Handler { *delayed = Some((sp.into(), msg.to_string())); } pub fn span_bug_no_panic>(&self, sp: S, msg: &str) { - self.emit(Some(&sp.into()), msg, Bug); + self.emit(&sp.into(), msg, Bug); self.bump_err_count(); } pub fn span_note_without_error>(&self, sp: S, msg: &str) { - self.emit.borrow_mut().emit(Some(&sp.into()), msg, None, Note); + self.emit.borrow_mut().emit(&sp.into(), msg, None, Note); } pub fn span_unimpl>(&self, sp: S, msg: &str) -> ! { self.span_bug(sp, &format!("unimplemented {}", msg)); @@ -554,7 +558,7 @@ impl Handler { if self.treat_err_as_bug { self.bug(msg); } - self.emit.borrow_mut().emit(None, msg, None, Fatal); + self.emit.borrow_mut().emit(&MultiSpan::new(), msg, None, Fatal); self.bump_err_count(); FatalError } @@ -562,17 +566,17 @@ impl Handler { if self.treat_err_as_bug { self.bug(msg); } - self.emit.borrow_mut().emit(None, msg, None, Error); + self.emit.borrow_mut().emit(&MultiSpan::new(), msg, None, Error); self.bump_err_count(); } pub fn warn(&self, msg: &str) { - self.emit.borrow_mut().emit(None, msg, None, Warning); + self.emit.borrow_mut().emit(&MultiSpan::new(), msg, None, Warning); } pub fn note_without_error(&self, msg: &str) { - self.emit.borrow_mut().emit(None, msg, None, Note); + self.emit.borrow_mut().emit(&MultiSpan::new(), msg, None, Note); } pub fn bug(&self, msg: &str) -> ! { - self.emit.borrow_mut().emit(None, msg, None, Bug); + self.emit.borrow_mut().emit(&MultiSpan::new(), msg, None, Bug); panic!(ExplicitBug); } pub fn unimpl(&self, msg: &str) -> ! { @@ -614,25 +618,20 @@ impl Handler { panic!(self.fatal(&s)); } pub fn emit(&self, - msp: Option<&MultiSpan>, + msp: &MultiSpan, msg: &str, lvl: Level) { if lvl == Warning && !self.can_emit_warnings { return } - self.emit.borrow_mut().emit(msp, msg, None, lvl); + self.emit.borrow_mut().emit(&msp, msg, None, lvl); if !self.continue_after_error.get() { self.abort_if_errors(); } } pub fn emit_with_code(&self, - msp: Option<&MultiSpan>, + msp: &MultiSpan, msg: &str, code: &str, lvl: Level) { if lvl == Warning && !self.can_emit_warnings { return } - self.emit.borrow_mut().emit(msp, msg, Some(code), lvl); - if !self.continue_after_error.get() { self.abort_if_errors(); } - } - pub fn custom_emit(&self, rsp: RenderSpan, msg: &str, lvl: Level) { - if lvl == Warning && !self.can_emit_warnings { return } - self.emit.borrow_mut().custom_emit(&rsp, msg, lvl); + self.emit.borrow_mut().emit(&msp, msg, Some(code), lvl); if !self.continue_after_error.get() { self.abort_if_errors(); } } } From d9a947ce8fd4f53b7a273b39a84a7af0fe34d2c5 Mon Sep 17 00:00:00 2001 From: Niko Matsakis Date: Wed, 20 Apr 2016 15:00:05 -0400 Subject: [PATCH 05/40] use new `note_expected_found` API This API pulls the "expected type foo, found type bar" out after the main snippet. There are some other places where it makes sense, but this is a start. --- src/librustc/infer/error_reporting.rs | 38 ++++++++++++------------ src/librustc_typeck/check/_match.rs | 4 +-- src/librustc_typeck/check/intrinsic.rs | 5 +--- src/librustc_typeck/check/wfcheck.rs | 3 +- src/librustc_typeck/collect.rs | 5 ++-- src/librustc_typeck/lib.rs | 40 ++++++++++++++------------ 6 files changed, 46 insertions(+), 49 deletions(-) diff --git a/src/librustc/infer/error_reporting.rs b/src/librustc/infer/error_reporting.rs index abc6ff4a294e3..88972beb31b09 100644 --- a/src/librustc/infer/error_reporting.rs +++ b/src/librustc/infer/error_reporting.rs @@ -249,12 +249,12 @@ pub trait ErrorReporting<'tcx> { terr: &TypeError<'tcx>) -> DiagnosticBuilder<'tcx>; - fn values_str(&self, values: &ValuePairs<'tcx>) -> Option; + fn values_str(&self, values: &ValuePairs<'tcx>) -> Option<(String, String)>; fn expected_found_str + TypeFoldable<'tcx>>( &self, exp_found: &ty::error::ExpectedFound) - -> Option; + -> Option<(String, String)>; fn report_concrete_failure(&self, origin: SubregionOrigin<'tcx>, @@ -535,7 +535,7 @@ impl<'a, 'tcx> ErrorReporting<'tcx> for InferCtxt<'a, 'tcx> { trace: TypeTrace<'tcx>, terr: &TypeError<'tcx>) -> DiagnosticBuilder<'tcx> { - let expected_found_str = match self.values_str(&trace.values) { + let (expected, found) = match self.values_str(&trace.values) { Some(v) => v, None => { return self.tcx.sess.diagnostic().struct_dummy(); /* derived error */ @@ -548,18 +548,17 @@ impl<'a, 'tcx> ErrorReporting<'tcx> for InferCtxt<'a, 'tcx> { false }; - let expected_found_str = if is_simple_error { - expected_found_str - } else { - format!("{} ({})", expected_found_str, terr) - }; - let mut err = struct_span_err!(self.tcx.sess, trace.origin.span(), E0308, - "{}: {}", - trace.origin, - expected_found_str); + "{}", + trace.origin); + + if !is_simple_error { + err = err.note_expected_found(&"type", &expected, &found); + } + + err = err.span_label(trace.origin.span(), &terr); self.check_and_note_conflicting_crates(&mut err, terr, trace.origin.span()); @@ -574,6 +573,7 @@ impl<'a, 'tcx> ErrorReporting<'tcx> for InferCtxt<'a, 'tcx> { }, _ => () } + err } @@ -631,7 +631,7 @@ impl<'a, 'tcx> ErrorReporting<'tcx> for InferCtxt<'a, 'tcx> { /// Returns a string of the form "expected `{}`, found `{}`", or None if this is a derived /// error. - fn values_str(&self, values: &ValuePairs<'tcx>) -> Option { + fn values_str(&self, values: &ValuePairs<'tcx>) -> Option<(String, String)> { match *values { infer::Types(ref exp_found) => self.expected_found_str(exp_found), infer::TraitRefs(ref exp_found) => self.expected_found_str(exp_found), @@ -642,7 +642,7 @@ impl<'a, 'tcx> ErrorReporting<'tcx> for InferCtxt<'a, 'tcx> { fn expected_found_str + TypeFoldable<'tcx>>( &self, exp_found: &ty::error::ExpectedFound) - -> Option + -> Option<(String, String)> { let expected = exp_found.expected.resolve(self); if expected.references_error() { @@ -654,9 +654,7 @@ impl<'a, 'tcx> ErrorReporting<'tcx> for InferCtxt<'a, 'tcx> { return None; } - Some(format!("expected `{}`, found `{}`", - expected, - found)) + Some((format!("{}", expected), format!("{}", found))) } fn report_generic_bound_failure(&self, @@ -1751,11 +1749,11 @@ impl<'a, 'tcx> ErrorReportingHelpers<'tcx> for InferCtxt<'a, 'tcx> { }; match self.values_str(&trace.values) { - Some(values_str) => { + Some((expected, found)) => { err.span_note( trace.origin.span(), - &format!("...so that {} ({})", - desc, values_str)); + &format!("...so that {} (expected {}, found {})", + desc, expected, found)); } None => { // Really should avoid printing this error at diff --git a/src/librustc_typeck/check/_match.rs b/src/librustc_typeck/check/_match.rs index a7a04f4a85fe8..544fb117f3614 100644 --- a/src/librustc_typeck/check/_match.rs +++ b/src/librustc_typeck/check/_match.rs @@ -116,8 +116,8 @@ pub fn check_pat<'a, 'tcx>(pcx: &pat_ctxt<'a, 'tcx>, // Check that the types of the end-points can be unified. let types_unify = require_same_types( - tcx, Some(fcx.infcx()), false, pat.span, rhs_ty, lhs_ty, - || "mismatched types in range".to_string() + tcx, Some(fcx.infcx()), false, pat.span, rhs_ty, lhs_ty, + "mismatched types in range", ); // It's ok to return without a message as `require_same_types` prints an error. diff --git a/src/librustc_typeck/check/intrinsic.rs b/src/librustc_typeck/check/intrinsic.rs index eae0cfb0f2267..b71ee8722ab60 100644 --- a/src/librustc_typeck/check/intrinsic.rs +++ b/src/librustc_typeck/check/intrinsic.rs @@ -61,10 +61,7 @@ fn equate_intrinsic_type<'a, 'tcx>(tcx: &TyCtxt<'tcx>, it: &hir::ForeignItem, it.span, i_ty.ty, fty, - || { - format!("intrinsic has wrong type: expected `{}`", - fty) - }); + "intrinsic has wrong type"); } } diff --git a/src/librustc_typeck/check/wfcheck.rs b/src/librustc_typeck/check/wfcheck.rs index 3bfd53ceadae8..492dbce9bdf45 100644 --- a/src/librustc_typeck/check/wfcheck.rs +++ b/src/librustc_typeck/check/wfcheck.rs @@ -418,8 +418,7 @@ impl<'ccx, 'tcx> CheckTypeWellFormedVisitor<'ccx, 'tcx> { let _ = ::require_same_types( fcx.tcx(), Some(fcx.infcx()), false, span, sig.inputs[0], rcvr_ty, - || "mismatched method receiver".to_owned() - ); + "mismatched method receiver"); } fn check_variances_for_type_defn(&self, diff --git a/src/librustc_typeck/collect.rs b/src/librustc_typeck/collect.rs index ffcf427715667..51534a46ddac3 100644 --- a/src/librustc_typeck/collect.rs +++ b/src/librustc_typeck/collect.rs @@ -1044,8 +1044,9 @@ fn convert_enum_def<'tcx>(tcx: &TyCtxt<'tcx>, -> ty::AdtDefMaster<'tcx> { fn print_err(tcx: &TyCtxt, span: Span, ty: ty::Ty, cv: ConstVal) { - span_err!(tcx.sess, span, E0079, "mismatched types: expected `{}` got `{}`", - ty, cv.description()); + struct_span_err!(tcx.sess, span, E0079, "mismatched types") + .note_expected_found(&"type", &ty, &format!("{}", cv.description())) + .emit(); } fn evaluate_disr_expr<'tcx>(tcx: &TyCtxt<'tcx>, repr_ty: attr::IntType, diff --git a/src/librustc_typeck/lib.rs b/src/librustc_typeck/lib.rs index 7f27d10ce1ec3..c51304120a89c 100644 --- a/src/librustc_typeck/lib.rs +++ b/src/librustc_typeck/lib.rs @@ -185,15 +185,14 @@ fn require_c_abi_if_variadic(tcx: &TyCtxt, } } -fn require_same_types<'a, 'tcx, M>(tcx: &TyCtxt<'tcx>, - maybe_infcx: Option<&infer::InferCtxt<'a, 'tcx>>, - t1_is_expected: bool, - span: Span, - t1: Ty<'tcx>, - t2: Ty<'tcx>, - msg: M) - -> bool where - M: FnOnce() -> String, +fn require_same_types<'a, 'tcx>(tcx: &TyCtxt<'tcx>, + maybe_infcx: Option<&infer::InferCtxt<'a, 'tcx>>, + t1_is_expected: bool, + span: Span, + t1: Ty<'tcx>, + t2: Ty<'tcx>, + msg: &str) + -> bool { let result = match maybe_infcx { None => { @@ -208,7 +207,17 @@ fn require_same_types<'a, 'tcx, M>(tcx: &TyCtxt<'tcx>, match result { Ok(_) => true, Err(ref terr) => { - let mut err = struct_span_err!(tcx.sess, span, E0211, "{}: {}", msg(), terr); + let mut err = struct_span_err!(tcx.sess, span, E0211, "{}", msg); + err = err.span_label(span, &terr); + let (mut expected_ty, mut found_ty) = + if t1_is_expected {(t1, t2)} else {(t2, t1)}; + if let Some(infcx) = maybe_infcx { + expected_ty = infcx.resolve_type_vars_if_possible(&expected_ty); + found_ty = infcx.resolve_type_vars_if_possible(&found_ty); + } + err = err.note_expected_found(&"type", + &expected_ty, + &found_ty); tcx.note_and_explain_type_err(&mut err, terr, span); err.emit(); false @@ -250,10 +259,7 @@ fn check_main_fn_ty(ccx: &CrateCtxt, }); require_same_types(tcx, None, false, main_span, main_t, se_ty, - || { - format!("main function expects type: `{}`", - se_ty) - }); + "main function has wrong type"); } _ => { span_bug!(main_span, @@ -301,11 +307,7 @@ fn check_start_fn_ty(ccx: &CrateCtxt, }); require_same_types(tcx, None, false, start_span, start_t, se_ty, - || { - format!("start function expects type: `{}`", - se_ty) - }); - + "start function has wrong type"); } _ => { span_bug!(start_span, From e416518e6862335a9c99f4c9dfe23192bac3cab8 Mon Sep 17 00:00:00 2001 From: Niko Matsakis Date: Wed, 20 Apr 2016 14:42:13 -0400 Subject: [PATCH 06/40] update test cases to reflect new messages --- src/test/compile-fail/array-not-vector.rs | 14 +-- .../compile-fail/associated-types-eq-3.rs | 7 +- .../compile-fail/associated-types-path-2.rs | 6 +- .../compile-fail/augmented-assignments.rs | 4 +- src/test/compile-fail/bad-const-type.rs | 7 +- src/test/compile-fail/bad-main.rs | 2 +- src/test/compile-fail/binop-move-semantics.rs | 2 + .../block-must-not-have-result-while.rs | 7 +- .../borrowck/borrowck-box-insensitivity.rs | 46 +++++--- .../borrowck/borrowck-closures-mut-of-imm.rs | 2 +- .../borrowck/borrowck-closures-unique.rs | 2 +- .../borrowck/borrowck-lend-flow-loop.rs | 1 + .../borrowck-mut-borrow-linear-errors.rs | 1 + .../borrowck-report-with-custom-diagnostic.rs | 15 ++- src/test/compile-fail/closure-wrong-kind.rs | 2 +- src/test/compile-fail/coerce-mut.rs | 4 +- src/test/compile-fail/coercion-slice.rs | 7 +- src/test/compile-fail/cross-borrow-trait.rs | 7 +- .../compile-fail/default_ty_param_conflict.rs | 3 + .../default_ty_param_conflict_cross_crate.rs | 6 +- .../compile-fail/destructure-trait-ref.rs | 21 ++-- src/test/compile-fail/dst-bad-assign.rs | 7 +- src/test/compile-fail/dst-bad-coerce4.rs | 7 +- .../explicit-self-lifetime-mismatch.rs | 8 +- src/test/compile-fail/extern-main-fn.rs | 2 +- src/test/compile-fail/fn-item-type.rs | 20 ++-- src/test/compile-fail/fn-trait-formatting.rs | 21 ++-- .../fully-qualified-type-name1.rs | 7 +- .../fully-qualified-type-name2.rs | 7 +- .../fully-qualified-type-name4.rs | 7 +- .../generic-type-params-name-repr.rs | 42 +++---- src/test/compile-fail/if-branch-types.rs | 3 +- src/test/compile-fail/if-let-arm-types.rs | 3 + .../compile-fail/if-without-else-result.rs | 7 +- .../integer-literal-suffix-inference.rs | 108 ++++++------------ .../integral-variable-unification-error.rs | 7 +- src/test/compile-fail/issue-10176.rs | 7 +- src/test/compile-fail/issue-11319.rs | 9 +- src/test/compile-fail/issue-12997-2.rs | 7 +- src/test/compile-fail/issue-13359.rs | 6 +- src/test/compile-fail/issue-13466.rs | 14 +-- src/test/compile-fail/issue-13482-2.rs | 7 +- src/test/compile-fail/issue-13482.rs | 4 +- src/test/compile-fail/issue-13624.rs | 14 +-- src/test/compile-fail/issue-14091.rs | 7 +- src/test/compile-fail/issue-14541.rs | 7 +- src/test/compile-fail/issue-15783.rs | 7 +- src/test/compile-fail/issue-15896.rs | 7 +- src/test/compile-fail/issue-16338.rs | 7 +- src/test/compile-fail/issue-16401.rs | 7 +- src/test/compile-fail/issue-17033.rs | 7 +- src/test/compile-fail/issue-17263.rs | 14 ++- src/test/compile-fail/issue-17283.rs | 21 ++-- src/test/compile-fail/issue-17728.rs | 3 + src/test/compile-fail/issue-17740.rs | 8 +- src/test/compile-fail/issue-19109.rs | 9 +- src/test/compile-fail/issue-19991.rs | 7 +- src/test/compile-fail/issue-24036.rs | 6 + src/test/compile-fail/issue-24357.rs | 4 +- src/test/compile-fail/issue-24446.rs | 2 +- src/test/compile-fail/issue-26480.rs | 1 + src/test/compile-fail/issue-27008.rs | 7 +- src/test/compile-fail/issue-29084.rs | 5 +- src/test/compile-fail/issue-2951.rs | 7 +- src/test/compile-fail/issue-3477.rs | 3 +- src/test/compile-fail/issue-3680.rs | 7 +- src/test/compile-fail/issue-4201.rs | 7 +- src/test/compile-fail/issue-4517.rs | 7 +- src/test/compile-fail/issue-4968.rs | 7 +- src/test/compile-fail/issue-5100.rs | 40 +++---- src/test/compile-fail/issue-5358-1.rs | 7 +- src/test/compile-fail/issue-5500.rs | 7 +- src/test/compile-fail/issue-7061.rs | 7 +- src/test/compile-fail/issue-7092.rs | 9 +- src/test/compile-fail/issue-7867.rs | 21 ++-- src/test/compile-fail/issue-9575.rs | 2 +- src/test/compile-fail/main-wrong-type-2.rs | 2 +- src/test/compile-fail/main-wrong-type.rs | 2 +- src/test/compile-fail/match-range-fail.rs | 3 +- src/test/compile-fail/match-struct.rs | 7 +- src/test/compile-fail/match-vec-mismatch-2.rs | 7 +- src/test/compile-fail/method-self-arg-1.rs | 14 +-- ...ased-on-type-distribute-copy-over-paren.rs | 8 +- .../moves-based-on-type-match-bindings.rs | 2 + .../compile-fail/mut-pattern-mismatched.rs | 8 +- src/test/compile-fail/noexporttypeexe.rs | 7 +- src/test/compile-fail/occurs-check-2.rs | 4 +- src/test/compile-fail/occurs-check.rs | 4 +- .../compile-fail/pattern-error-continue.rs | 10 +- src/test/compile-fail/pptypedef.rs | 6 +- src/test/compile-fail/ptr-coercion.rs | 12 +- src/test/compile-fail/ref-suggestion.rs | 6 - src/test/compile-fail/regions-bounds.rs | 8 +- .../regions-early-bound-error-method.rs | 4 +- .../regions-fn-subtyping-return-static.rs | 7 +- .../compile-fail/regions-infer-not-param.rs | 8 +- .../regions-infer-paramd-indirect.rs | 4 +- .../reject-specialized-drops-8142.rs | 4 +- src/test/compile-fail/repeat_count.rs | 41 +++---- .../compile-fail/shift-various-bad-types.rs | 3 +- src/test/compile-fail/slice-mut.rs | 4 +- .../slightly-nice-generic-literal-messages.rs | 7 +- .../compile-fail/struct-base-wrong-type-2.rs | 14 +-- .../compile-fail/struct-base-wrong-type.rs | 14 +-- .../structure-constructor-type-mismatch.rs | 18 +-- src/test/compile-fail/substs-ppaux.rs | 32 +++--- src/test/compile-fail/suppressed-error.rs | 7 +- .../tag-that-dare-not-speak-its-name.rs | 7 +- src/test/compile-fail/terr-in-field.rs | 7 +- src/test/compile-fail/terr-sorts.rs | 7 +- .../compile-fail/token-error-correct-3.rs | 3 + .../compile-fail/trait-bounds-cant-coerce.rs | 7 +- src/test/compile-fail/tuple-arity-mismatch.rs | 14 +-- .../tutorial-suffix-inference-test.rs | 9 +- .../compile-fail/type-mismatch-multiple.rs | 10 +- .../type-mismatch-same-crate-name.rs | 16 ++- src/test/compile-fail/type-parameter-names.rs | 7 +- .../type-params-in-different-spaces-1.rs | 7 +- .../typeck_type_placeholder_mismatch.rs | 14 +-- .../compile-fail/ufcs-explicit-self-bad.rs | 8 +- src/test/compile-fail/variadic-ffi-3.rs | 14 +-- 121 files changed, 534 insertions(+), 630 deletions(-) diff --git a/src/test/compile-fail/array-not-vector.rs b/src/test/compile-fail/array-not-vector.rs index 6c9b8f81b2faf..1bbccae53a44d 100644 --- a/src/test/compile-fail/array-not-vector.rs +++ b/src/test/compile-fail/array-not-vector.rs @@ -11,16 +11,14 @@ fn main() { let _x: i32 = [1, 2, 3]; //~^ ERROR mismatched types - //~| expected `i32` - //~| found `[_; 3]` - //~| expected i32 - //~| found array of 3 elements + //~| expected type `i32` + //~| found type `[_; 3]` + //~| expected i32, found array of 3 elements let x: &[i32] = &[1, 2, 3]; let _y: &i32 = x; //~^ ERROR mismatched types - //~| expected `&i32` - //~| found `&[i32]` - //~| expected i32 - //~| found slice + //~| expected type `&i32` + //~| found type `&[i32]` + //~| expected i32, found slice } diff --git a/src/test/compile-fail/associated-types-eq-3.rs b/src/test/compile-fail/associated-types-eq-3.rs index f01f2b111c5c1..8c66160e8a36f 100644 --- a/src/test/compile-fail/associated-types-eq-3.rs +++ b/src/test/compile-fail/associated-types-eq-3.rs @@ -32,10 +32,9 @@ fn foo1>(x: I) { fn foo2(x: I) { let _: Bar = x.boo(); //~^ ERROR mismatched types - //~| expected `Bar` - //~| found `::A` - //~| expected struct `Bar` - //~| found associated type + //~| expected type `Bar` + //~| found type `::A` + //~| expected struct `Bar`, found associated type } diff --git a/src/test/compile-fail/associated-types-path-2.rs b/src/test/compile-fail/associated-types-path-2.rs index 68fba56427cc5..cdb7dff692c14 100644 --- a/src/test/compile-fail/associated-types-path-2.rs +++ b/src/test/compile-fail/associated-types-path-2.rs @@ -28,8 +28,7 @@ pub fn f2(a: T) -> T::A { pub fn f1_int_int() { f1(2i32, 4i32); //~^ ERROR mismatched types - //~| expected `u32` - //~| found `i32` + //~| expected u32, found i32 } pub fn f1_int_uint() { @@ -49,8 +48,7 @@ pub fn f1_uint_int() { pub fn f2_int() { let _: i32 = f2(2i32); //~^ ERROR mismatched types - //~| expected `i32` - //~| found `u32` + //~| expected i32, found u32 } pub fn main() { } diff --git a/src/test/compile-fail/augmented-assignments.rs b/src/test/compile-fail/augmented-assignments.rs index 221015d512062..8ac6b419295ee 100644 --- a/src/test/compile-fail/augmented-assignments.rs +++ b/src/test/compile-fail/augmented-assignments.rs @@ -21,8 +21,10 @@ impl AddAssign for Int { fn main() { let mut x = Int(1); x //~ error: use of moved value: `x` + //~^ value used here after move + //~| note: move occurs because `x` has type `Int` += - x; //~ note: `x` moved here because it has type `Int`, which is non-copyable + x; //~ value moved here let y = Int(2); y //~ error: cannot borrow immutable local variable `y` as mutable diff --git a/src/test/compile-fail/bad-const-type.rs b/src/test/compile-fail/bad-const-type.rs index f05c8c31f1024..ee6ac33072792 100644 --- a/src/test/compile-fail/bad-const-type.rs +++ b/src/test/compile-fail/bad-const-type.rs @@ -10,8 +10,7 @@ static i: String = 10; //~^ ERROR mismatched types -//~| expected `std::string::String` -//~| found `_` -//~| expected struct `std::string::String` -//~| found integral variable +//~| expected type `std::string::String` +//~| found type `_` +//~| expected struct `std::string::String`, found integral variable fn main() { println!("{}", i); } diff --git a/src/test/compile-fail/bad-main.rs b/src/test/compile-fail/bad-main.rs index 321dca8989134..1253f7569e7e8 100644 --- a/src/test/compile-fail/bad-main.rs +++ b/src/test/compile-fail/bad-main.rs @@ -8,4 +8,4 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -fn main(x: isize) { } //~ ERROR: main function expects type +fn main(x: isize) { } //~ ERROR: main function has wrong type diff --git a/src/test/compile-fail/binop-move-semantics.rs b/src/test/compile-fail/binop-move-semantics.rs index cff0064497aff..0cc6ea3e984d9 100644 --- a/src/test/compile-fail/binop-move-semantics.rs +++ b/src/test/compile-fail/binop-move-semantics.rs @@ -62,6 +62,7 @@ fn mut_plus_immut() { &mut f + &f; //~ ERROR: cannot borrow `f` as immutable because it is also borrowed as mutable + //~^ cannot borrow `f` as immutable because it is also borrowed as mutable } fn immut_plus_mut() { @@ -70,6 +71,7 @@ fn immut_plus_mut() { &f + &mut f; //~ ERROR: cannot borrow `f` as mutable because it is also borrowed as immutable + //~^ cannot borrow `f` as mutable because it is also borrowed as immutable } fn main() {} diff --git a/src/test/compile-fail/block-must-not-have-result-while.rs b/src/test/compile-fail/block-must-not-have-result-while.rs index ba6340ed395ee..a0fb470e1e4d0 100644 --- a/src/test/compile-fail/block-must-not-have-result-while.rs +++ b/src/test/compile-fail/block-must-not-have-result-while.rs @@ -11,9 +11,8 @@ fn main() { while true { true //~ ERROR mismatched types - //~| expected `()` - //~| found `bool` - //~| expected () - //~| found bool + //~| expected type `()` + //~| found type `bool` + //~| expected (), found bool } } diff --git a/src/test/compile-fail/borrowck/borrowck-box-insensitivity.rs b/src/test/compile-fail/borrowck/borrowck-box-insensitivity.rs index 7c3d632078fe2..bde3212c5bc63 100644 --- a/src/test/compile-fail/borrowck/borrowck-box-insensitivity.rs +++ b/src/test/compile-fail/borrowck/borrowck-box-insensitivity.rs @@ -33,22 +33,28 @@ struct D { fn copy_after_move() { let a: Box<_> = box A { x: box 0, y: 1 }; let _x = a.x; + //~^ value moved here let _y = a.y; //~ ERROR use of moved - //~^^ NOTE `a` moved here (through moving `a.x`) + //~^ move occurs because `a.x` has type `Box` + //~| value used here after move } fn move_after_move() { let a: Box<_> = box B { x: box 0, y: box 1 }; let _x = a.x; + //~^ value moved here let _y = a.y; //~ ERROR use of moved - //~^^ NOTE `a` moved here (through moving `a.x`) + //~^ move occurs because `a.x` has type `Box` + //~| value used here after move } fn borrow_after_move() { let a: Box<_> = box A { x: box 0, y: 1 }; let _x = a.x; + //~^ value moved here let _y = &a.y; //~ ERROR use of moved - //~^^ NOTE `a` moved here (through moving `a.x`) + //~^ move occurs because `a.x` has type `Box` + //~| value used here after move } fn move_after_borrow() { @@ -75,44 +81,52 @@ fn move_after_mut_borrow() { fn borrow_after_mut_borrow() { let mut a: Box<_> = box A { x: box 0, y: 1 }; let _x = &mut a.x; - //~^ NOTE previous borrow of `a` occurs here (through borrowing `a.x`); + //~^ NOTE mutable borrow occurs here (via `a.x`) let _y = &a.y; //~ ERROR cannot borrow + //~^ immutable borrow occurs here (via `a.y`) } -//~^ NOTE previous borrow ends here +//~^ NOTE mutable borrow ends here fn mut_borrow_after_borrow() { let mut a: Box<_> = box A { x: box 0, y: 1 }; let _x = &a.x; - //~^ NOTE previous borrow of `a` occurs here (through borrowing `a.x`) + //~^ NOTE immutable borrow occurs here (via `a.x`) let _y = &mut a.y; //~ ERROR cannot borrow + //~^ mutable borrow occurs here (via `a.y`) } -//~^ NOTE previous borrow ends here +//~^ NOTE immutable borrow ends here fn copy_after_move_nested() { let a: Box<_> = box C { x: box A { x: box 0, y: 1 }, y: 2 }; let _x = a.x.x; - //~^ NOTE `a.x.x` moved here because it has type `Box`, which is moved by default + //~^ value moved here let _y = a.y; //~ ERROR use of collaterally moved + //~^ NOTE move occurs because `a.x.x` has type `Box` + //~| value used here after move } fn move_after_move_nested() { let a: Box<_> = box D { x: box A { x: box 0, y: 1 }, y: box 2 }; let _x = a.x.x; - //~^ NOTE `a.x.x` moved here because it has type `Box`, which is moved by default + //~^ value moved here let _y = a.y; //~ ERROR use of collaterally moved + //~^ NOTE move occurs because `a.x.x` has type `Box` + //~| value used here after move } fn borrow_after_move_nested() { let a: Box<_> = box C { x: box A { x: box 0, y: 1 }, y: 2 }; let _x = a.x.x; - //~^ NOTE `a.x.x` moved here because it has type `Box`, which is moved by default + //~^ value moved here let _y = &a.y; //~ ERROR use of collaterally moved + //~^ NOTE move occurs because `a.x.x` has type `Box` + //~| value used here after move } fn move_after_borrow_nested() { let a: Box<_> = box D { x: box A { x: box 0, y: 1 }, y: box 2 }; let _x = &a.x.x; - //~^ NOTE borrow of `a.x.x` occurs here + //~^ borrow of `a.x.x` occurs here let _y = a.y; //~ ERROR cannot move } @@ -133,18 +147,20 @@ fn move_after_mut_borrow_nested() { fn borrow_after_mut_borrow_nested() { let mut a: Box<_> = box C { x: box A { x: box 0, y: 1 }, y: 2 }; let _x = &mut a.x.x; - //~^ NOTE previous borrow of `a.x.x` occurs here; the mutable borrow prevents + //~^ mutable borrow occurs here let _y = &a.y; //~ ERROR cannot borrow + //~^ immutable borrow occurs here } -//~^ NOTE previous borrow ends here +//~^ NOTE mutable borrow ends here fn mut_borrow_after_borrow_nested() { let mut a: Box<_> = box C { x: box A { x: box 0, y: 1 }, y: 2 }; let _x = &a.x.x; - //~^ NOTE previous borrow of `a.x.x` occurs here; the immutable borrow prevents + //~^ immutable borrow occurs here let _y = &mut a.y; //~ ERROR cannot borrow + //~^ mutable borrow occurs here } -//~^ NOTE previous borrow ends here +//~^ NOTE immutable borrow ends here fn main() { copy_after_move(); diff --git a/src/test/compile-fail/borrowck/borrowck-closures-mut-of-imm.rs b/src/test/compile-fail/borrowck/borrowck-closures-mut-of-imm.rs index 40f9be2dd8230..dc2f0e8395f08 100644 --- a/src/test/compile-fail/borrowck/borrowck-closures-mut-of-imm.rs +++ b/src/test/compile-fail/borrowck/borrowck-closures-mut-of-imm.rs @@ -24,7 +24,7 @@ fn a(x: &isize) { //~^ ERROR cannot borrow let c2 = || set(&mut *x); //~^ ERROR cannot borrow - //~| ERROR closure requires unique access + //~| ERROR two closures require unique access to `x` at the same time } fn main() { diff --git a/src/test/compile-fail/borrowck/borrowck-closures-unique.rs b/src/test/compile-fail/borrowck/borrowck-closures-unique.rs index 3646a68f06fd7..1b22dc4d2c6af 100644 --- a/src/test/compile-fail/borrowck/borrowck-closures-unique.rs +++ b/src/test/compile-fail/borrowck/borrowck-closures-unique.rs @@ -39,7 +39,7 @@ fn c(x: &mut isize) { fn d(x: &mut isize) { let c1 = || set(x); - let c2 = || set(x); //~ ERROR closure requires unique access to `x` + let c2 = || set(x); //~ ERROR two closures require unique access to `x` at the same time } fn e(x: &mut isize) { diff --git a/src/test/compile-fail/borrowck/borrowck-lend-flow-loop.rs b/src/test/compile-fail/borrowck/borrowck-lend-flow-loop.rs index f09e7ffd7e4b7..56cbe0b187867 100644 --- a/src/test/compile-fail/borrowck/borrowck-lend-flow-loop.rs +++ b/src/test/compile-fail/borrowck/borrowck-lend-flow-loop.rs @@ -109,6 +109,7 @@ fn while_aliased_mut_cond(cond: bool, cond2: bool) { borrow(&*v); //~ ERROR cannot borrow if cond2 { x = &mut v; //~ ERROR cannot borrow + //~^ ERROR cannot borrow } } } diff --git a/src/test/compile-fail/borrowck/borrowck-mut-borrow-linear-errors.rs b/src/test/compile-fail/borrowck/borrowck-mut-borrow-linear-errors.rs index 38e0e27a7b98e..f789d44016eb1 100644 --- a/src/test/compile-fail/borrowck/borrowck-mut-borrow-linear-errors.rs +++ b/src/test/compile-fail/borrowck/borrowck-mut-borrow-linear-errors.rs @@ -19,6 +19,7 @@ fn main() { match 1 { 1 => { addr = &mut x; } //~^ ERROR cannot borrow `x` as mutable more than once at a time + //~| ERROR cannot borrow `x` as mutable more than once at a time 2 => { addr = &mut x; } //~^ ERROR cannot borrow `x` as mutable more than once at a time _ => { addr = &mut x; } diff --git a/src/test/compile-fail/borrowck/borrowck-report-with-custom-diagnostic.rs b/src/test/compile-fail/borrowck/borrowck-report-with-custom-diagnostic.rs index 2b1ff47ee3d94..3ca8cc431e098 100644 --- a/src/test/compile-fail/borrowck/borrowck-report-with-custom-diagnostic.rs +++ b/src/test/compile-fail/borrowck/borrowck-report-with-custom-diagnostic.rs @@ -13,10 +13,11 @@ fn main() { // Original borrow ends at end of function let mut x = 1; let y = &mut x; - //~^ previous borrow of `x` occurs here; the mutable borrow prevents + //~^ mutable borrow occurs here let z = &x; //~ ERROR cannot borrow + //~^ immutable borrow occurs here } -//~^ NOTE previous borrow ends here +//~^ NOTE mutable borrow ends here fn foo() { match true { @@ -24,10 +25,11 @@ fn foo() { // Original borrow ends at end of match arm let mut x = 1; let y = &x; - //~^ previous borrow of `x` occurs here; the immutable borrow prevents + //~^ immutable borrow occurs here let z = &mut x; //~ ERROR cannot borrow + //~^ mutable borrow occurs here } - //~^ NOTE previous borrow ends here + //~^ NOTE immutable borrow ends here false => () } } @@ -37,8 +39,9 @@ fn bar() { || { let mut x = 1; let y = &mut x; - //~^ previous borrow of `x` occurs here; the mutable borrow prevents + //~^ first mutable borrow occurs here let z = &mut x; //~ ERROR cannot borrow + //~^ second mutable borrow occurs here }; - //~^ NOTE previous borrow ends here + //~^ NOTE first borrow ends here } diff --git a/src/test/compile-fail/closure-wrong-kind.rs b/src/test/compile-fail/closure-wrong-kind.rs index 6792414c36790..a387e4c5ece11 100644 --- a/src/test/compile-fail/closure-wrong-kind.rs +++ b/src/test/compile-fail/closure-wrong-kind.rs @@ -17,6 +17,6 @@ fn bar(_: T) {} fn main() { let x = X; - let closure = |_| foo(x); //~ ERROR E0524 + let closure = |_| foo(x); //~ ERROR E0525 bar(closure); } diff --git a/src/test/compile-fail/coerce-mut.rs b/src/test/compile-fail/coerce-mut.rs index 30c1b66a7b81f..634d12441a120 100644 --- a/src/test/compile-fail/coerce-mut.rs +++ b/src/test/compile-fail/coerce-mut.rs @@ -14,7 +14,7 @@ fn main() { let x = 0; f(&x); //~^ ERROR mismatched types - //~| expected `&mut i32` - //~| found `&_` + //~| expected type `&mut i32` + //~| found type `&_` //~| values differ in mutability } diff --git a/src/test/compile-fail/coercion-slice.rs b/src/test/compile-fail/coercion-slice.rs index bb4d1693af7e3..bd7e6c2a2131d 100644 --- a/src/test/compile-fail/coercion-slice.rs +++ b/src/test/compile-fail/coercion-slice.rs @@ -13,8 +13,7 @@ fn main() { let _: &[i32] = [0]; //~^ ERROR mismatched types - //~| expected `&[i32]` - //~| found `[_; 1]` - //~| expected &-ptr - //~| found array of 1 elements + //~| expected type `&[i32]` + //~| found type `[_; 1]` + //~| expected &-ptr, found array of 1 elements } diff --git a/src/test/compile-fail/cross-borrow-trait.rs b/src/test/compile-fail/cross-borrow-trait.rs index d60fb1d5d1966..ea9a29c0e2ae5 100644 --- a/src/test/compile-fail/cross-borrow-trait.rs +++ b/src/test/compile-fail/cross-borrow-trait.rs @@ -19,8 +19,7 @@ pub fn main() { // FIXME (#22405): Replace `Box::new` with `box` here when/if possible. let x: Box = Box::new(Foo); let _y: &Trait = x; //~ ERROR mismatched types - //~| expected `&Trait` - //~| found `Box` - //~| expected &-ptr - //~| found box + //~| expected type `&Trait` + //~| found type `Box` + //~| expected &-ptr, found box } diff --git a/src/test/compile-fail/default_ty_param_conflict.rs b/src/test/compile-fail/default_ty_param_conflict.rs index 48c5cd1ff7706..4702b504f157d 100644 --- a/src/test/compile-fail/default_ty_param_conflict.rs +++ b/src/test/compile-fail/default_ty_param_conflict.rs @@ -23,6 +23,9 @@ fn main() { // Here, F is instantiated with $0=uint let x = foo(); //~^ ERROR: mismatched types + //~| expected type `usize` + //~| found type `isize` + //~| NOTE: conflicting type parameter defaults `usize` and `isize` //~| NOTE: conflicting type parameter defaults `usize` and `isize` //~| NOTE: ...that was applied to an unconstrained type variable here diff --git a/src/test/compile-fail/default_ty_param_conflict_cross_crate.rs b/src/test/compile-fail/default_ty_param_conflict_cross_crate.rs index fc2c49d65affe..b608c6c99be89 100644 --- a/src/test/compile-fail/default_ty_param_conflict_cross_crate.rs +++ b/src/test/compile-fail/default_ty_param_conflict_cross_crate.rs @@ -24,7 +24,11 @@ fn main() { //~^ NOTE: ...that also applies to the same type variable here meh(foo); - //~^ ERROR: mismatched types: + //~^ ERROR: mismatched types //~| NOTE: conflicting type parameter defaults `bool` and `char` + //~| NOTE: conflicting type parameter defaults `bool` and `char` + //~| a second default is defined on `default_param_test::bleh` //~| NOTE: ...that was applied to an unconstrained type variable here + //~| expected type `bool` + //~| found type `char` } diff --git a/src/test/compile-fail/destructure-trait-ref.rs b/src/test/compile-fail/destructure-trait-ref.rs index 68d9795710245..d0a31fbce91ed 100644 --- a/src/test/compile-fail/destructure-trait-ref.rs +++ b/src/test/compile-fail/destructure-trait-ref.rs @@ -40,20 +40,17 @@ fn main() { // n > m let &&x = &1isize as &T; //~^ ERROR mismatched types - //~| expected `T` - //~| found `&_` - //~| expected trait T - //~| found &-ptr + //~| expected type `T` + //~| found type `&_` + //~| expected trait T, found &-ptr let &&&x = &(&1isize as &T); //~^ ERROR mismatched types - //~| expected `T` - //~| found `&_` - //~| expected trait T - //~| found &-ptr + //~| expected type `T` + //~| found type `&_` + //~| expected trait T, found &-ptr let box box x = box 1isize as Box; //~^ ERROR mismatched types - //~| expected `T` - //~| found `Box<_>` - //~| expected trait T - //~| found box + //~| expected type `T` + //~| found type `Box<_>` + //~| expected trait T, found box } diff --git a/src/test/compile-fail/dst-bad-assign.rs b/src/test/compile-fail/dst-bad-assign.rs index 2d21d0ebc760b..9e71ad2417792 100644 --- a/src/test/compile-fail/dst-bad-assign.rs +++ b/src/test/compile-fail/dst-bad-assign.rs @@ -45,9 +45,8 @@ pub fn main() { let z: Box = Box::new(Bar1 {f: 36}); f5.ptr = Bar1 {f: 36}; //~^ ERROR mismatched types - //~| expected `ToBar` - //~| found `Bar1` - //~| expected trait ToBar - //~| found struct `Bar1` + //~| expected type `ToBar` + //~| found type `Bar1` + //~| expected trait ToBar, found struct `Bar1` //~| ERROR `ToBar: std::marker::Sized` is not satisfied } diff --git a/src/test/compile-fail/dst-bad-coerce4.rs b/src/test/compile-fail/dst-bad-coerce4.rs index c1443bdbb309d..9d4d56cf79190 100644 --- a/src/test/compile-fail/dst-bad-coerce4.rs +++ b/src/test/compile-fail/dst-bad-coerce4.rs @@ -19,8 +19,7 @@ pub fn main() { let f1: &Fat<[isize]> = &Fat { ptr: [1, 2, 3] }; let f2: &Fat<[isize; 3]> = f1; //~^ ERROR mismatched types - //~| expected `&Fat<[isize; 3]>` - //~| found `&Fat<[isize]>` - //~| expected array of 3 elements - //~| found slice + //~| expected type `&Fat<[isize; 3]>` + //~| found type `&Fat<[isize]>` + //~| expected array of 3 elements, found slice } diff --git a/src/test/compile-fail/explicit-self-lifetime-mismatch.rs b/src/test/compile-fail/explicit-self-lifetime-mismatch.rs index 922e58698dd75..b5432fafb1b85 100644 --- a/src/test/compile-fail/explicit-self-lifetime-mismatch.rs +++ b/src/test/compile-fail/explicit-self-lifetime-mismatch.rs @@ -16,12 +16,12 @@ struct Foo<'a,'b> { impl<'a,'b> Foo<'a,'b> { fn bar(self: Foo<'b,'a>) {} //~^ ERROR mismatched types - //~| expected `Foo<'a, 'b>` - //~| found `Foo<'b, 'a>` + //~| expected type `Foo<'a, 'b>` + //~| found type `Foo<'b, 'a>` //~| lifetime mismatch //~| ERROR mismatched types - //~| expected `Foo<'a, 'b>` - //~| found `Foo<'b, 'a>` + //~| expected type `Foo<'a, 'b>` + //~| found type `Foo<'b, 'a>` //~| lifetime mismatch } diff --git a/src/test/compile-fail/extern-main-fn.rs b/src/test/compile-fail/extern-main-fn.rs index 05ce3eefda86c..11f299acefa87 100644 --- a/src/test/compile-fail/extern-main-fn.rs +++ b/src/test/compile-fail/extern-main-fn.rs @@ -8,4 +8,4 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -extern fn main() {} //~ ERROR: main function expects type +extern fn main() {} //~ ERROR: main function has wrong type diff --git a/src/test/compile-fail/fn-item-type.rs b/src/test/compile-fail/fn-item-type.rs index c90a7113f1b41..6217a9f16b935 100644 --- a/src/test/compile-fail/fn-item-type.rs +++ b/src/test/compile-fail/fn-item-type.rs @@ -22,26 +22,22 @@ impl Foo for T { /* `foo` is still default here */ } fn main() { eq(foo::, bar::); //~^ ERROR mismatched types - //~| expected `fn(isize) -> isize {foo::}` - //~| found `fn(isize) -> isize {bar::}` - //~| expected fn item - //~| found a different fn item + //~| expected type `fn(isize) -> isize {foo::}` + //~| found type `fn(isize) -> isize {bar::}` + //~| expected fn item, found a different fn item eq(foo::, foo::); //~^ ERROR mismatched types - //~| expected `fn(isize) -> isize {foo::}` - //~| found `fn(isize) -> isize {foo::}` + //~| expected u8, found i8 eq(bar::, bar::>); //~^ ERROR mismatched types - //~| expected `fn(isize) -> isize {bar::}` - //~| found `fn(isize) -> isize {bar::>}` - //~| expected struct `std::string::String` - //~| found struct `std::vec::Vec` + //~| expected type `fn(isize) -> isize {bar::}` + //~| found type `fn(isize) -> isize {bar::>}` + //~| expected struct `std::string::String`, found struct `std::vec::Vec` // Make sure we distinguish between trait methods correctly. eq(::foo, ::foo); //~^ ERROR mismatched types - //~| expected `fn() {::foo}` - //~| found `fn() {::foo}` + //~| expected u8, found u16 } diff --git a/src/test/compile-fail/fn-trait-formatting.rs b/src/test/compile-fail/fn-trait-formatting.rs index 8cbfc520ff449..fd140cd1d391a 100644 --- a/src/test/compile-fail/fn-trait-formatting.rs +++ b/src/test/compile-fail/fn-trait-formatting.rs @@ -16,22 +16,19 @@ fn needs_fn(x: F) where F: Fn(isize) -> isize {} fn main() { let _: () = (box |_: isize| {}) as Box; //~^ ERROR mismatched types - //~| expected `()` - //~| found `Box` - //~| expected () - //~| found box + //~| expected type `()` + //~| found type `Box` + //~| expected (), found box let _: () = (box |_: isize, isize| {}) as Box; //~^ ERROR mismatched types - //~| expected `()` - //~| found `Box` - //~| expected () - //~| found box + //~| expected type `()` + //~| found type `Box` + //~| expected (), found box let _: () = (box || -> isize { unimplemented!() }) as Box isize>; //~^ ERROR mismatched types - //~| expected `()` - //~| found `Box isize>` - //~| expected () - //~| found box + //~| expected type `()` + //~| found type `Box isize>` + //~| expected (), found box needs_fn(1); //~^ ERROR : std::ops::Fn<(isize,)>` diff --git a/src/test/compile-fail/fully-qualified-type-name1.rs b/src/test/compile-fail/fully-qualified-type-name1.rs index fb787e8572c20..5ea8ce2264438 100644 --- a/src/test/compile-fail/fully-qualified-type-name1.rs +++ b/src/test/compile-fail/fully-qualified-type-name1.rs @@ -14,8 +14,7 @@ fn main() { let x: Option; x = 5; //~^ ERROR mismatched types - //~| expected `std::option::Option` - //~| found `_` - //~| expected enum `std::option::Option` - //~| found integral variable + //~| expected type `std::option::Option` + //~| found type `_` + //~| expected enum `std::option::Option`, found integral variable } diff --git a/src/test/compile-fail/fully-qualified-type-name2.rs b/src/test/compile-fail/fully-qualified-type-name2.rs index ab542d90800b2..9ba8a11d536be 100644 --- a/src/test/compile-fail/fully-qualified-type-name2.rs +++ b/src/test/compile-fail/fully-qualified-type-name2.rs @@ -21,10 +21,9 @@ mod y { fn bar(x: x::foo) -> y::foo { return x; //~^ ERROR mismatched types - //~| expected `y::foo` - //~| found `x::foo` - //~| expected enum `y::foo` - //~| found enum `x::foo` + //~| expected type `y::foo` + //~| found type `x::foo` + //~| expected enum `y::foo`, found enum `x::foo` } fn main() { diff --git a/src/test/compile-fail/fully-qualified-type-name4.rs b/src/test/compile-fail/fully-qualified-type-name4.rs index 9242849efc746..3c8fde751f123 100644 --- a/src/test/compile-fail/fully-qualified-type-name4.rs +++ b/src/test/compile-fail/fully-qualified-type-name4.rs @@ -15,10 +15,9 @@ use std::option::Option; fn bar(x: usize) -> Option { return x; //~^ ERROR mismatched types - //~| expected `std::option::Option` - //~| found `usize` - //~| expected enum `std::option::Option` - //~| found usize + //~| expected type `std::option::Option` + //~| found type `usize` + //~| expected enum `std::option::Option`, found usize } fn main() { diff --git a/src/test/compile-fail/generic-type-params-name-repr.rs b/src/test/compile-fail/generic-type-params-name-repr.rs index adf9a98a05c2d..71d7cf792e475 100644 --- a/src/test/compile-fail/generic-type-params-name-repr.rs +++ b/src/test/compile-fail/generic-type-params-name-repr.rs @@ -22,46 +22,40 @@ fn main() { // Ensure that the printed type doesn't include the default type params... let _: Foo = (); //~^ ERROR mismatched types - //~| expected `Foo` - //~| found `()` - //~| expected struct `Foo` - //~| found () + //~| expected type `Foo` + //~| found type `()` + //~| expected struct `Foo`, found () // ...even when they're present, but the same types as the defaults. let _: Foo = (); //~^ ERROR mismatched types - //~| expected `Foo` - //~| found `()` - //~| expected struct `Foo` - //~| found () + //~| expected type `Foo` + //~| found type `()` + //~| expected struct `Foo`, found () // Including cases where the default is using previous type params. let _: HashMap = (); //~^ ERROR mismatched types - //~| expected `HashMap` - //~| found `()` - //~| expected struct `HashMap` - //~| found () + //~| expected type `HashMap` + //~| found type `()` + //~| expected struct `HashMap`, found () let _: HashMap> = (); //~^ ERROR mismatched types - //~| expected `HashMap` - //~| found `()` - //~| expected struct `HashMap` - //~| found () + //~| expected type `HashMap` + //~| found type `()` + //~| expected struct `HashMap`, found () // But not when there's a different type in between. let _: Foo = (); //~^ ERROR mismatched types - //~| expected `Foo` - //~| found `()` - //~| expected struct `Foo` - //~| found () + //~| expected type `Foo` + //~| found type `()` + //~| expected struct `Foo`, found () // And don't print <> at all when there's just defaults. let _: Foo = (); //~^ ERROR mismatched types - //~| expected `Foo` - //~| found `()` - //~| expected struct `Foo` - //~| found () + //~| expected type `Foo` + //~| found type `()` + //~| expected struct `Foo`, found () } diff --git a/src/test/compile-fail/if-branch-types.rs b/src/test/compile-fail/if-branch-types.rs index 2c730531b823a..ca9803f66b20d 100644 --- a/src/test/compile-fail/if-branch-types.rs +++ b/src/test/compile-fail/if-branch-types.rs @@ -11,6 +11,5 @@ fn main() { let x = if true { 10i32 } else { 10u32 }; //~^ ERROR if and else have incompatible types - //~| expected `i32` - //~| found `u32` + //~| expected i32, found u32 } diff --git a/src/test/compile-fail/if-let-arm-types.rs b/src/test/compile-fail/if-let-arm-types.rs index d179ec015d231..c7b1e1a62c209 100644 --- a/src/test/compile-fail/if-let-arm-types.rs +++ b/src/test/compile-fail/if-let-arm-types.rs @@ -10,6 +10,9 @@ fn main() { if let Some(b) = None { //~ ERROR: `if let` arms have incompatible types + //~^ expected (), found integral variable + //~| expected type `()` + //~| found type `_` () } else { //~ NOTE: `if let` arm with an incompatible type 1 diff --git a/src/test/compile-fail/if-without-else-result.rs b/src/test/compile-fail/if-without-else-result.rs index a9567f4272f50..e8aa1f70ea1dc 100644 --- a/src/test/compile-fail/if-without-else-result.rs +++ b/src/test/compile-fail/if-without-else-result.rs @@ -11,9 +11,8 @@ fn main() { let a = if true { true }; //~^ ERROR if may be missing an else clause - //~| expected `()` - //~| found `bool` - //~| expected () - //~| found bool + //~| expected type `()` + //~| found type `bool` + //~| expected (), found bool println!("{}", a); } diff --git a/src/test/compile-fail/integer-literal-suffix-inference.rs b/src/test/compile-fail/integer-literal-suffix-inference.rs index a01db18a34a7f..7a850d90a8747 100644 --- a/src/test/compile-fail/integer-literal-suffix-inference.rs +++ b/src/test/compile-fail/integer-literal-suffix-inference.rs @@ -41,168 +41,132 @@ fn main() { id_i8(a8); // ok id_i8(a16); //~^ ERROR mismatched types - //~| expected `i8` - //~| found `i16` + //~| expected i8, found i16 id_i8(a32); //~^ ERROR mismatched types - //~| expected `i8` - //~| found `i32` + //~| expected i8, found i32 id_i8(a64); //~^ ERROR mismatched types - //~| expected `i8` - //~| found `i64` + //~| expected i8, found i64 id_i16(a8); //~^ ERROR mismatched types - //~| expected `i16` - //~| found `i8` + //~| expected i16, found i8 id_i16(a16); // ok id_i16(a32); //~^ ERROR mismatched types - //~| expected `i16` - //~| found `i32` + //~| expected i16, found i32 id_i16(a64); //~^ ERROR mismatched types - //~| expected `i16` - //~| found `i64` + //~| expected i16, found i64 id_i32(a8); //~^ ERROR mismatched types - //~| expected `i32` - //~| found `i8` + //~| expected i32, found i8 id_i32(a16); //~^ ERROR mismatched types - //~| expected `i32` - //~| found `i16` + //~| expected i32, found i16 id_i32(a32); // ok id_i32(a64); //~^ ERROR mismatched types - //~| expected `i32` - //~| found `i64` + //~| expected i32, found i64 id_i64(a8); //~^ ERROR mismatched types - //~| expected `i64` - //~| found `i8` + //~| expected i64, found i8 id_i64(a16); //~^ ERROR mismatched types - //~| expected `i64` - //~| found `i16` + //~| expected i64, found i16 id_i64(a32); //~^ ERROR mismatched types - //~| expected `i64` - //~| found `i32` + //~| expected i64, found i32 id_i64(a64); // ok id_i8(c8); // ok id_i8(c16); //~^ ERROR mismatched types - //~| expected `i8` - //~| found `i16` + //~| expected i8, found i16 id_i8(c32); //~^ ERROR mismatched types - //~| expected `i8` - //~| found `i32` + //~| expected i8, found i32 id_i8(c64); //~^ ERROR mismatched types - //~| expected `i8` - //~| found `i64` + //~| expected i8, found i64 id_i16(c8); //~^ ERROR mismatched types - //~| expected `i16` - //~| found `i8` + //~| expected i16, found i8 id_i16(c16); // ok id_i16(c32); //~^ ERROR mismatched types - //~| expected `i16` - //~| found `i32` + //~| expected i16, found i32 id_i16(c64); //~^ ERROR mismatched types - //~| expected `i16` - //~| found `i64` + //~| expected i16, found i64 id_i32(c8); //~^ ERROR mismatched types - //~| expected `i32` - //~| found `i8` + //~| expected i32, found i8 id_i32(c16); //~^ ERROR mismatched types - //~| expected `i32` - //~| found `i16` + //~| expected i32, found i16 id_i32(c32); // ok id_i32(c64); //~^ ERROR mismatched types - //~| expected `i32` - //~| found `i64` + //~| expected i32, found i64 id_i64(a8); //~^ ERROR mismatched types - //~| expected `i64` - //~| found `i8` + //~| expected i64, found i8 id_i64(a16); //~^ ERROR mismatched types - //~| expected `i64` - //~| found `i16` + //~| expected i64, found i16 id_i64(a32); //~^ ERROR mismatched types - //~| expected `i64` - //~| found `i32` + //~| expected i64, found i32 id_i64(a64); // ok id_u8(b8); // ok id_u8(b16); //~^ ERROR mismatched types - //~| expected `u8` - //~| found `u16` + //~| expected u8, found u16 id_u8(b32); //~^ ERROR mismatched types - //~| expected `u8` - //~| found `u32` + //~| expected u8, found u32 id_u8(b64); //~^ ERROR mismatched types - //~| expected `u8` - //~| found `u64` + //~| expected u8, found u64 id_u16(b8); //~^ ERROR mismatched types - //~| expected `u16` - //~| found `u8` + //~| expected u16, found u8 id_u16(b16); // ok id_u16(b32); //~^ ERROR mismatched types - //~| expected `u16` - //~| found `u32` + //~| expected u16, found u32 id_u16(b64); //~^ ERROR mismatched types - //~| expected `u16` - //~| found `u64` + //~| expected u16, found u64 id_u32(b8); //~^ ERROR mismatched types - //~| expected `u32` - //~| found `u8` + //~| expected u32, found u8 id_u32(b16); //~^ ERROR mismatched types - //~| expected `u32` - //~| found `u16` + //~| expected u32, found u16 id_u32(b32); // ok id_u32(b64); //~^ ERROR mismatched types - //~| expected `u32` - //~| found `u64` + //~| expected u32, found u64 id_u64(b8); //~^ ERROR mismatched types - //~| expected `u64` - //~| found `u8` + //~| expected u64, found u8 id_u64(b16); //~^ ERROR mismatched types - //~| expected `u64` - //~| found `u16` + //~| expected u64, found u16 id_u64(b32); //~^ ERROR mismatched types - //~| expected `u64` - //~| found `u32` + //~| expected u64, found u32 id_u64(b64); // ok } diff --git a/src/test/compile-fail/integral-variable-unification-error.rs b/src/test/compile-fail/integral-variable-unification-error.rs index 3374f715917c2..99f2d25166891 100644 --- a/src/test/compile-fail/integral-variable-unification-error.rs +++ b/src/test/compile-fail/integral-variable-unification-error.rs @@ -12,8 +12,7 @@ fn main() { let mut x = 2; x = 5.0; //~^ ERROR mismatched types - //~| expected `_` - //~| found `_` - //~| expected integral variable - //~| found floating-point variable + //~| expected type `_` + //~| found type `_` + //~| expected integral variable, found floating-point variable } diff --git a/src/test/compile-fail/issue-10176.rs b/src/test/compile-fail/issue-10176.rs index 6e84e777898b6..434b795ff31f5 100644 --- a/src/test/compile-fail/issue-10176.rs +++ b/src/test/compile-fail/issue-10176.rs @@ -11,10 +11,9 @@ fn f() -> isize { (return 1, return 2) //~^ ERROR mismatched types -//~| expected `isize` -//~| found `(_, _)` -//~| expected isize -//~| found tuple +//~| expected type `isize` +//~| found type `(_, _)` +//~| expected isize, found tuple } fn main() {} diff --git a/src/test/compile-fail/issue-11319.rs b/src/test/compile-fail/issue-11319.rs index d3e44b71b1c89..8242fa1c2e979 100644 --- a/src/test/compile-fail/issue-11319.rs +++ b/src/test/compile-fail/issue-11319.rs @@ -10,11 +10,10 @@ fn main() { match Some(10) { - //~^ ERROR match arms have incompatible types: - //~| expected `bool` - //~| found `()` - //~| expected bool - //~| found () + //~^ ERROR match arms have incompatible types + //~| expected type `bool` + //~| found type `()` + //~| expected bool, found () Some(5) => false, Some(2) => true, None => (), //~ NOTE match arm with an incompatible type diff --git a/src/test/compile-fail/issue-12997-2.rs b/src/test/compile-fail/issue-12997-2.rs index 8b467c2ba11f9..436d9e91dc72f 100644 --- a/src/test/compile-fail/issue-12997-2.rs +++ b/src/test/compile-fail/issue-12997-2.rs @@ -15,7 +15,6 @@ #[bench] fn bar(x: isize) { } //~^ ERROR mismatched types -//~| expected `fn(&mut __test::test::Bencher)` -//~| found `fn(isize) {bar}` -//~| expected &-ptr -//~| found isize +//~| expected type `fn(&mut __test::test::Bencher)` +//~| found type `fn(isize) {bar}` +//~| expected &-ptr, found isize diff --git a/src/test/compile-fail/issue-13359.rs b/src/test/compile-fail/issue-13359.rs index 775412a12ca6a..e33859e8c19a3 100644 --- a/src/test/compile-fail/issue-13359.rs +++ b/src/test/compile-fail/issue-13359.rs @@ -15,11 +15,9 @@ fn bar(_s: u32) { } fn main() { foo(1*(1 as isize)); //~^ ERROR mismatched types - //~| expected `i16` - //~| found `isize` + //~| expected i16, found isize bar(1*(1 as usize)); //~^ ERROR mismatched types - //~| expected `u32` - //~| found `usize` + //~| expected u32, found usize } diff --git a/src/test/compile-fail/issue-13466.rs b/src/test/compile-fail/issue-13466.rs index d2c8b679ff69f..17b96411603ef 100644 --- a/src/test/compile-fail/issue-13466.rs +++ b/src/test/compile-fail/issue-13466.rs @@ -17,16 +17,14 @@ pub fn main() { let _x: usize = match Some(1) { Ok(u) => u, //~^ ERROR mismatched types - //~| expected `std::option::Option<_>` - //~| found `std::result::Result<_, _>` - //~| expected enum `std::option::Option` - //~| found enum `std::result::Result` + //~| expected type `std::option::Option<_>` + //~| found type `std::result::Result<_, _>` + //~| expected enum `std::option::Option`, found enum `std::result::Result` Err(e) => panic!(e) //~^ ERROR mismatched types - //~| expected `std::option::Option<_>` - //~| found `std::result::Result<_, _>` - //~| expected enum `std::option::Option` - //~| found enum `std::result::Result` + //~| expected type `std::option::Option<_>` + //~| found type `std::result::Result<_, _>` + //~| expected enum `std::option::Option`, found enum `std::result::Result` }; } diff --git a/src/test/compile-fail/issue-13482-2.rs b/src/test/compile-fail/issue-13482-2.rs index e1fe2d06993d5..fe03373a45d9f 100644 --- a/src/test/compile-fail/issue-13482-2.rs +++ b/src/test/compile-fail/issue-13482-2.rs @@ -17,10 +17,9 @@ fn main() { let y = match x { [] => None, //~^ ERROR mismatched types -//~| expected `[_#1i; 2]` -//~| found `[_#7t; 0]` -//~| expected an array with a fixed size of 2 elements -//~| found one with 0 elements +//~| expected type `[_#1i; 2]` +//~| found type `[_#7t; 0]` +//~| expected an array with a fixed size of 2 elements, found one with 0 elements [a,_] => Some(a) }; } diff --git a/src/test/compile-fail/issue-13482.rs b/src/test/compile-fail/issue-13482.rs index 8d98fe313349b..7ed7f5898b1b7 100644 --- a/src/test/compile-fail/issue-13482.rs +++ b/src/test/compile-fail/issue-13482.rs @@ -15,8 +15,8 @@ fn main() { let y = match x { [] => None, //~^ ERROR mismatched types - //~| expected `[_; 2]` - //~| found `[_; 0]` + //~| expected type `[_; 2]` + //~| found type `[_; 0]` //~| expected an array with a fixed size of 2 elements [a,_] => Some(a) }; diff --git a/src/test/compile-fail/issue-13624.rs b/src/test/compile-fail/issue-13624.rs index 2a5805790a742..e4ed87c3cb0cd 100644 --- a/src/test/compile-fail/issue-13624.rs +++ b/src/test/compile-fail/issue-13624.rs @@ -16,10 +16,9 @@ mod a { pub fn get_enum_struct_variant() -> () { Enum::EnumStructVariant { x: 1, y: 2, z: 3 } //~^ ERROR mismatched types - //~| expected `()` - //~| found `a::Enum` - //~| expected () - //~| found enum `a::Enum` + //~| expected type `()` + //~| found type `a::Enum` + //~| expected (), found enum `a::Enum` } } @@ -32,10 +31,9 @@ mod b { match enum_struct_variant { a::Enum::EnumStructVariant { x, y, z } => { //~^ ERROR mismatched types - //~| expected `()` - //~| found `a::Enum` - //~| expected () - // found enum `a::Enum` + //~| expected type `()` + //~| found type `a::Enum` + //~| expected (), found enum `a::Enum` } } } diff --git a/src/test/compile-fail/issue-14091.rs b/src/test/compile-fail/issue-14091.rs index 3ceb465cb4b23..ccaeeab8b4789 100644 --- a/src/test/compile-fail/issue-14091.rs +++ b/src/test/compile-fail/issue-14091.rs @@ -9,9 +9,8 @@ // except according to those terms. // error-pattern:mismatched types -// error-pattern:expected `bool` -// error-pattern:found `_` -// error-pattern:expected bool -// error-pattern:found integral variable +// error-pattern:expected bool, found integral variable +// error-pattern:expected type `bool` +// error-pattern:found type `_` fn main(){assert!(1,1);} diff --git a/src/test/compile-fail/issue-14541.rs b/src/test/compile-fail/issue-14541.rs index deb8f00cd01c9..84c600d2201e3 100644 --- a/src/test/compile-fail/issue-14541.rs +++ b/src/test/compile-fail/issue-14541.rs @@ -14,10 +14,9 @@ struct vec3 { y: f32, z: f32 } fn make(v: vec2) { let vec3 { y: _, z: _ } = v; //~^ ERROR mismatched types - //~| expected `vec2` - //~| found `vec3` - //~| expected struct `vec2` - //~| found struct `vec3` + //~| expected type `vec2` + //~| found type `vec3` + //~| expected struct `vec2`, found struct `vec3` } fn main() { } diff --git a/src/test/compile-fail/issue-15783.rs b/src/test/compile-fail/issue-15783.rs index 9a139021e4c6d..37a2f1582bf08 100644 --- a/src/test/compile-fail/issue-15783.rs +++ b/src/test/compile-fail/issue-15783.rs @@ -17,9 +17,8 @@ fn main() { let x = Some(&[name]); let msg = foo(x); //~^ ERROR mismatched types -//~| expected `std::option::Option<&[&str]>` -//~| found `std::option::Option<&[&str; 1]>` -//~| expected slice -//~| found array of 1 elements +//~| expected type `std::option::Option<&[&str]>` +//~| found type `std::option::Option<&[&str; 1]>` +//~| expected slice, found array of 1 elements assert_eq!(msg, 3); } diff --git a/src/test/compile-fail/issue-15896.rs b/src/test/compile-fail/issue-15896.rs index 7381ade263b20..35ef9ba2b4bea 100644 --- a/src/test/compile-fail/issue-15896.rs +++ b/src/test/compile-fail/issue-15896.rs @@ -20,10 +20,9 @@ fn main() { E::B( Tau{t: x}, //~^ ERROR mismatched types - //~| expected `main::R` - //~| found `main::Tau` - //~| expected enum `main::R` - //~| found struct `main::Tau` + //~| expected type `main::R` + //~| found type `main::Tau` + //~| expected enum `main::R`, found struct `main::Tau` _) => x, }; } diff --git a/src/test/compile-fail/issue-16338.rs b/src/test/compile-fail/issue-16338.rs index 30775a958b57d..da6d081a7acb5 100644 --- a/src/test/compile-fail/issue-16338.rs +++ b/src/test/compile-fail/issue-16338.rs @@ -13,8 +13,7 @@ use std::raw::Slice; fn main() { let Slice { data: data, len: len } = "foo"; //~^ ERROR mismatched types - //~| expected `&str` - //~| found `std::raw::Slice<_>` - //~| expected &-ptr - //~| found struct `std::raw::Slice` + //~| expected type `&str` + //~| found type `std::raw::Slice<_>` + //~| expected &-ptr, found struct `std::raw::Slice` } diff --git a/src/test/compile-fail/issue-16401.rs b/src/test/compile-fail/issue-16401.rs index a90f9fe26e48c..df272a71cee4f 100644 --- a/src/test/compile-fail/issue-16401.rs +++ b/src/test/compile-fail/issue-16401.rs @@ -14,10 +14,9 @@ fn main() { match () { Slice { data: data, len: len } => (), //~^ ERROR mismatched types - //~| expected `()` - //~| found `std::raw::Slice<_>` - //~| expected () - //~| found struct `std::raw::Slice` + //~| expected type `()` + //~| found type `std::raw::Slice<_>` + //~| expected (), found struct `std::raw::Slice` _ => unreachable!() } } diff --git a/src/test/compile-fail/issue-17033.rs b/src/test/compile-fail/issue-17033.rs index 6010e206920e5..f0fe01b415970 100644 --- a/src/test/compile-fail/issue-17033.rs +++ b/src/test/compile-fail/issue-17033.rs @@ -12,10 +12,9 @@ fn f<'r>(p: &'r mut fn(p: &mut ())) { (*p)(()) //~ ERROR mismatched types - //~| expected `&mut ()` - //~| found `()` - //~| expected &-ptr - //~| found () + //~| expected type `&mut ()` + //~| found type `()` + //~| expected &-ptr, found () } fn main() {} diff --git a/src/test/compile-fail/issue-17263.rs b/src/test/compile-fail/issue-17263.rs index 2320bc02baf5e..063afe285fad3 100644 --- a/src/test/compile-fail/issue-17263.rs +++ b/src/test/compile-fail/issue-17263.rs @@ -15,13 +15,15 @@ struct Foo { a: isize, b: isize } fn main() { let mut x: Box<_> = box Foo { a: 1, b: 2 }; let (a, b) = (&mut x.a, &mut x.b); - //~^ ERROR cannot borrow `x` (here through borrowing `x.b`) as mutable more than once at a time - //~^^ NOTE previous borrow of `x` occurs here (through borrowing `x.a`) + //~^ ERROR cannot borrow `x` (via `x.b`) as mutable more than once at a time + //~| NOTE first mutable borrow occurs here (via `x.a`) + //~| NOTE second mutable borrow occurs here (via `x.b`) let mut foo: Box<_> = box Foo { a: 1, b: 2 }; let (c, d) = (&mut foo.a, &foo.b); - //~^ ERROR cannot borrow `foo` (here through borrowing `foo.b`) as immutable - //~^^ NOTE previous borrow of `foo` occurs here (through borrowing `foo.a`) + //~^ ERROR cannot borrow `foo` (via `foo.b`) as immutable + //~| NOTE mutable borrow occurs here (via `foo.a`) + //~| NOTE immutable borrow occurs here (via `foo.b`) } -//~^ NOTE previous borrow ends here -//~^^ NOTE previous borrow ends here +//~^ NOTE first borrow ends here +//~^^ NOTE mutable borrow ends here diff --git a/src/test/compile-fail/issue-17283.rs b/src/test/compile-fail/issue-17283.rs index c7d6443663241..98208bcfdbdee 100644 --- a/src/test/compile-fail/issue-17283.rs +++ b/src/test/compile-fail/issue-17283.rs @@ -24,28 +24,25 @@ fn main() { // `x { ... }` should not be interpreted as a struct literal here if x = x { //~^ ERROR mismatched types - //~| expected `bool` - //~| found `()` - //~| expected bool - //~| found () + //~| expected type `bool` + //~| found type `()` + //~| expected bool, found () println!("{}", x); } // Explicit parentheses on the left should match behavior of above if (x = x) { //~^ ERROR mismatched types - //~| expected `bool` - //~| found `()` - //~| expected bool - //~| found () + //~| expected type `bool` + //~| found type `()` + //~| expected bool, found () println!("{}", x); } // The struct literal interpretation is fine with explicit parentheses on the right if y = (Foo { foo: x }) { //~^ ERROR mismatched types - //~| expected `bool` - //~| found `()` - //~| expected bool - //~| found () + //~| expected type `bool` + //~| found type `()` + //~| expected bool, found () println!("{}", x); } } diff --git a/src/test/compile-fail/issue-17728.rs b/src/test/compile-fail/issue-17728.rs index 787eb7a3b8878..f508d7123d88f 100644 --- a/src/test/compile-fail/issue-17728.rs +++ b/src/test/compile-fail/issue-17728.rs @@ -108,6 +108,9 @@ impl Debug for Player { fn str_to_direction(to_parse: &str) -> RoomDirection { match to_parse { //~ ERROR match arms have incompatible types + //~^ expected enum `RoomDirection`, found enum `std::option::Option` + //~| expected type `RoomDirection` + //~| found type `std::option::Option<_>` "w" | "west" => RoomDirection::West, "e" | "east" => RoomDirection::East, "n" | "north" => RoomDirection::North, diff --git a/src/test/compile-fail/issue-17740.rs b/src/test/compile-fail/issue-17740.rs index 4381bf22e2ace..6b9294b2038f1 100644 --- a/src/test/compile-fail/issue-17740.rs +++ b/src/test/compile-fail/issue-17740.rs @@ -15,12 +15,12 @@ struct Foo<'a> { impl <'a> Foo<'a>{ fn bar(self: &mut Foo) { //~^ mismatched types - //~| expected `&mut Foo<'a>` - //~| found `&mut Foo<'_>` + //~| expected type `&mut Foo<'a>` + //~| found type `&mut Foo<'_>` //~| lifetime mismatch //~| mismatched types - //~| expected `&mut Foo<'a>` - //~| found `&mut Foo<'_>` + //~| expected type `&mut Foo<'a>` + //~| found type `&mut Foo<'_>` //~| lifetime mismatch } } diff --git a/src/test/compile-fail/issue-19109.rs b/src/test/compile-fail/issue-19109.rs index 1ffffa9fc748e..580684e2e140b 100644 --- a/src/test/compile-fail/issue-19109.rs +++ b/src/test/compile-fail/issue-19109.rs @@ -12,11 +12,10 @@ trait Trait { } fn function(t: &mut Trait) { t as *mut Trait - //~^ ERROR: mismatched types: - //~| expected `()`, - //~| found `*mut Trait` - //~| (expected (), - //~| found *-ptr) [E0308] + //~^ ERROR: mismatched types + //~| NOTE: expected type `()` + //~| NOTE: found type `*mut Trait` + //~| NOTE: expected (), found *-ptr } fn main() { } diff --git a/src/test/compile-fail/issue-19991.rs b/src/test/compile-fail/issue-19991.rs index 6c9b0004f7754..b368daaaf587c 100644 --- a/src/test/compile-fail/issue-19991.rs +++ b/src/test/compile-fail/issue-19991.rs @@ -13,10 +13,9 @@ fn main() { if let Some(homura) = Some("madoka") { //~ ERROR missing an else clause - //~| expected `()` - //~| found `_` - //~| expected () - //~| found integral variable + //~| expected type `()` + //~| found type `_` + //~| expected (), found integral variable 765 }; } diff --git a/src/test/compile-fail/issue-24036.rs b/src/test/compile-fail/issue-24036.rs index 06b058cbfe179..ac7e0f2e9a867 100644 --- a/src/test/compile-fail/issue-24036.rs +++ b/src/test/compile-fail/issue-24036.rs @@ -14,6 +14,9 @@ fn closure_to_loc() { //~^ ERROR mismatched types //~| NOTE no two closures, even if identical, have the same type //~| HELP consider boxing your closure and/or using it as a trait object + //~| expected closure, found a different closure + //~| expected type `[closure + //~| found type `[closure } fn closure_from_match() { @@ -26,6 +29,9 @@ fn closure_from_match() { //~^^^^^^ ERROR match arms have incompatible types //~| NOTE no two closures, even if identical, have the same type //~| HELP consider boxing your closure and/or using it as a trait object + //~| expected closure, found a different closure + //~| expected type `[closure + //~| found type `[closure } fn main() { } diff --git a/src/test/compile-fail/issue-24357.rs b/src/test/compile-fail/issue-24357.rs index f193a07b85af9..5d6b989fc968a 100644 --- a/src/test/compile-fail/issue-24357.rs +++ b/src/test/compile-fail/issue-24357.rs @@ -12,7 +12,9 @@ struct NoCopy; fn main() { let x = NoCopy; let f = move || { let y = x; }; - //~^ NOTE `x` moved into closure environment here because it has type `NoCopy` + //~^ value moved (into closure) here let z = x; //~^ ERROR use of moved value: `x` + //~| value used here after move + //~| move occurs because `x` has type `NoCopy` } diff --git a/src/test/compile-fail/issue-24446.rs b/src/test/compile-fail/issue-24446.rs index a2831fd2b5ac8..cbeac77479811 100644 --- a/src/test/compile-fail/issue-24446.rs +++ b/src/test/compile-fail/issue-24446.rs @@ -10,7 +10,7 @@ fn main() { static foo: Fn() -> u32 = || -> u32 { - //~^ ERROR: mismatched types: + //~^ ERROR: mismatched types 0 }; } diff --git a/src/test/compile-fail/issue-26480.rs b/src/test/compile-fail/issue-26480.rs index 23e4ffb1f3076..adcf8484f7828 100644 --- a/src/test/compile-fail/issue-26480.rs +++ b/src/test/compile-fail/issue-26480.rs @@ -25,6 +25,7 @@ macro_rules! write { write(stdout, $arr.as_ptr() as *const i8, $arr.len() * size_of($arr[0])); //~^ ERROR mismatched types + //~| expected u64, found usize } }} } diff --git a/src/test/compile-fail/issue-27008.rs b/src/test/compile-fail/issue-27008.rs index 2a4b98563ab9f..bdcbaf09177fe 100644 --- a/src/test/compile-fail/issue-27008.rs +++ b/src/test/compile-fail/issue-27008.rs @@ -13,9 +13,8 @@ struct S; fn main() { let b = [0; S]; //~^ ERROR mismatched types - //~| expected `usize` - //~| found `S` - //~| expected usize - //~| found struct `S` + //~| expected type `usize` + //~| found type `S` + //~| expected usize, found struct `S` //~| ERROR expected positive integer for repeat count, found struct } diff --git a/src/test/compile-fail/issue-29084.rs b/src/test/compile-fail/issue-29084.rs index 78913e759a1cc..00d2969a0f67d 100644 --- a/src/test/compile-fail/issue-29084.rs +++ b/src/test/compile-fail/issue-29084.rs @@ -13,10 +13,13 @@ macro_rules! foo { fn bar(d: u8) { } bar(&mut $d); //~^ ERROR mismatched types + //~| expected u8, found &-ptr + //~| expected type `u8` + //~| found type `&mut u8` }} } fn main() { foo!(0u8); - //~^ NOTE in this expansion of foo! + //~^ in this expansion of foo! } diff --git a/src/test/compile-fail/issue-2951.rs b/src/test/compile-fail/issue-2951.rs index d0781b5658087..11ff7ab2476b9 100644 --- a/src/test/compile-fail/issue-2951.rs +++ b/src/test/compile-fail/issue-2951.rs @@ -12,10 +12,9 @@ fn foo(x: T, y: U) { let mut xx = x; xx = y; //~^ ERROR mismatched types - //~| expected `T` - //~| found `U` - //~| expected type parameter - //~| found a different type parameter + //~| expected type `T` + //~| found type `U` + //~| expected type parameter, found a different type parameter } fn main() { diff --git a/src/test/compile-fail/issue-3477.rs b/src/test/compile-fail/issue-3477.rs index 43ef1b59ccf27..0bad7372a12d9 100644 --- a/src/test/compile-fail/issue-3477.rs +++ b/src/test/compile-fail/issue-3477.rs @@ -11,6 +11,5 @@ fn main() { let _p: char = 100; //~^ ERROR mismatched types - //~| expected `char` - //~| found `u8` + //~| expected char, found u8 } diff --git a/src/test/compile-fail/issue-3680.rs b/src/test/compile-fail/issue-3680.rs index fc918c278ef5d..e698e6da5294e 100644 --- a/src/test/compile-fail/issue-3680.rs +++ b/src/test/compile-fail/issue-3680.rs @@ -12,9 +12,8 @@ fn main() { match None { Err(_) => () //~^ ERROR mismatched types - //~| expected `std::option::Option<_>` - //~| found `std::result::Result<_, _>` - //~| expected enum `std::option::Option` - //~| found enum `std::result::Result` + //~| expected type `std::option::Option<_>` + //~| found type `std::result::Result<_, _>` + //~| expected enum `std::option::Option`, found enum `std::result::Result` } } diff --git a/src/test/compile-fail/issue-4201.rs b/src/test/compile-fail/issue-4201.rs index b5af1f03b635b..58423341cc6f0 100644 --- a/src/test/compile-fail/issue-4201.rs +++ b/src/test/compile-fail/issue-4201.rs @@ -13,10 +13,9 @@ fn main() { 0 } else if false { //~^ ERROR if may be missing an else clause -//~| expected `()` -//~| found `_` -//~| expected () -//~| found integral variable +//~| expected type `()` +//~| found type `_` +//~| expected (), found integral variable 1 }; } diff --git a/src/test/compile-fail/issue-4517.rs b/src/test/compile-fail/issue-4517.rs index a1804b5a2689d..fbd8972cbfaa6 100644 --- a/src/test/compile-fail/issue-4517.rs +++ b/src/test/compile-fail/issue-4517.rs @@ -14,8 +14,7 @@ fn main() { let foo: [u8; 4] = [1; 4]; bar(foo); //~^ ERROR mismatched types - //~| expected `usize` - //~| found `[u8; 4]` - //~| expected usize - //~| found array of 4 elements + //~| expected type `usize` + //~| found type `[u8; 4]` + //~| expected usize, found array of 4 elements } diff --git a/src/test/compile-fail/issue-4968.rs b/src/test/compile-fail/issue-4968.rs index e7cd20f38a1d2..7c0905873df89 100644 --- a/src/test/compile-fail/issue-4968.rs +++ b/src/test/compile-fail/issue-4968.rs @@ -14,8 +14,7 @@ const A: (isize,isize) = (4,2); fn main() { match 42 { A => () } //~^ ERROR mismatched types - //~| expected `_` - //~| found `(isize, isize)` - //~| expected integral variable - //~| found tuple + //~| expected type `_` + //~| found type `(isize, isize)` + //~| expected integral variable, found tuple } diff --git a/src/test/compile-fail/issue-5100.rs b/src/test/compile-fail/issue-5100.rs index 304b6f185fe36..9e78b7b947f98 100644 --- a/src/test/compile-fail/issue-5100.rs +++ b/src/test/compile-fail/issue-5100.rs @@ -16,48 +16,43 @@ enum A { B, C } fn main() { match (true, false) { A::B => (), -//~^ ERROR mismatched types: -//~| expected `(bool, bool)` -//~| found `A` -//~| expected tuple -//~| found enum `A` +//~^ ERROR mismatched types +//~| expected type `(bool, bool)` +//~| found type `A` +//~| expected tuple, found enum `A` _ => () } match (true, false) { (true, false, false) => () //~^ ERROR mismatched types -//~| expected `(bool, bool)` -//~| found `(_, _, _)` -//~| expected a tuple with 2 elements -//~| found one with 3 elements +//~| expected type `(bool, bool)` +//~| found type `(_, _, _)` +//~| expected a tuple with 2 elements, found one with 3 elements } match (true, false) { (true, false, false) => () //~^ ERROR mismatched types -//~| expected `(bool, bool)` -//~| found `(_, _, _)` -//~| expected a tuple with 2 elements -//~| found one with 3 elements +//~| expected type `(bool, bool)` +//~| found type `(_, _, _)` +//~| expected a tuple with 2 elements, found one with 3 elements } match (true, false) { box (true, false) => () //~^ ERROR mismatched types -//~| expected `(bool, bool)` -//~| found `Box<_>` -//~| expected tuple -//~| found box +//~| expected type `(bool, bool)` +//~| found type `Box<_>` +//~| expected tuple, found box } match (true, false) { &(true, false) => () //~^ ERROR mismatched types -//~| expected `(bool, bool)` -//~| found `&_` -//~| expected tuple -//~| found &-ptr +//~| expected type `(bool, bool)` +//~| found type `&_` +//~| expected tuple, found &-ptr } @@ -69,6 +64,5 @@ fn main() { // Make sure none of the errors above were fatal let x: char = true; //~ ERROR mismatched types - //~| expected `char` - //~| found `bool` + //~| expected char, found bool } diff --git a/src/test/compile-fail/issue-5358-1.rs b/src/test/compile-fail/issue-5358-1.rs index 32702d3e2f6fe..d8aad54fd3ee9 100644 --- a/src/test/compile-fail/issue-5358-1.rs +++ b/src/test/compile-fail/issue-5358-1.rs @@ -15,10 +15,9 @@ fn main() { match S(Either::Left(5)) { Either::Right(_) => {} //~^ ERROR mismatched types - //~| expected `S` - //~| found `Either<_, _>` - //~| expected struct `S` - //~| found enum `Either` + //~| expected type `S` + //~| found type `Either<_, _>` + //~| expected struct `S`, found enum `Either` _ => {} } } diff --git a/src/test/compile-fail/issue-5500.rs b/src/test/compile-fail/issue-5500.rs index 565634191be9a..cacbf7656def2 100644 --- a/src/test/compile-fail/issue-5500.rs +++ b/src/test/compile-fail/issue-5500.rs @@ -11,8 +11,7 @@ fn main() { &panic!() //~^ ERROR mismatched types - //~| expected `()` - //~| found `&_` - //~| expected () - //~| found &-ptr + //~| expected type `()` + //~| found type `&_` + //~| expected (), found &-ptr } diff --git a/src/test/compile-fail/issue-7061.rs b/src/test/compile-fail/issue-7061.rs index e261249bc998e..1519d71dd3be2 100644 --- a/src/test/compile-fail/issue-7061.rs +++ b/src/test/compile-fail/issue-7061.rs @@ -13,10 +13,9 @@ struct BarStruct; impl<'a> BarStruct { fn foo(&'a mut self) -> Box { self } //~^ ERROR mismatched types - //~| expected `Box` - //~| found `&'a mut BarStruct` - //~| expected box - //~| found &-ptr + //~| expected type `Box` + //~| found type `&'a mut BarStruct` + //~| expected box, found &-ptr } fn main() {} diff --git a/src/test/compile-fail/issue-7092.rs b/src/test/compile-fail/issue-7092.rs index 4acbcb165ff08..638f45cd35776 100644 --- a/src/test/compile-fail/issue-7092.rs +++ b/src/test/compile-fail/issue-7092.rs @@ -15,11 +15,10 @@ fn foo(x: Whatever) { match x { Some(field) => //~^ ERROR mismatched types -//~| expected `Whatever` -//~| found `std::option::Option<_>` -//~| expected enum `Whatever` -//~| found enum `std::option::Option` - field.access(), +//~| expected type `Whatever` +//~| found type `std::option::Option<_>` +//~| expected enum `Whatever`, found enum `std::option::Option` + field.access(), } } diff --git a/src/test/compile-fail/issue-7867.rs b/src/test/compile-fail/issue-7867.rs index 95513860b084f..e0de860b0eac3 100644 --- a/src/test/compile-fail/issue-7867.rs +++ b/src/test/compile-fail/issue-7867.rs @@ -16,25 +16,22 @@ fn main() { match (true, false) { A::B => (), //~^ ERROR mismatched types - //~| expected `(bool, bool)` - //~| found `A` - //~| expected tuple - //~| found enum `A` + //~| expected type `(bool, bool)` + //~| found type `A` + //~| expected tuple, found enum `A` _ => () } match &Some(42) { Some(x) => (), //~^ ERROR mismatched types - //~| expected `&std::option::Option<_>` - //~| found `std::option::Option<_>` - //~| expected &-ptr - //~| found enum `std::option::Option` + //~| expected type `&std::option::Option<_>` + //~| found type `std::option::Option<_>` + //~| expected &-ptr, found enum `std::option::Option` None => () //~^ ERROR mismatched types - //~| expected `&std::option::Option<_>` - //~| found `std::option::Option<_>` - //~| expected &-ptr - //~| found enum `std::option::Option` + //~| expected type `&std::option::Option<_>` + //~| found type `std::option::Option<_>` + //~| expected &-ptr, found enum `std::option::Option` } } diff --git a/src/test/compile-fail/issue-9575.rs b/src/test/compile-fail/issue-9575.rs index 94dd787f08635..9295eeb1779b0 100644 --- a/src/test/compile-fail/issue-9575.rs +++ b/src/test/compile-fail/issue-9575.rs @@ -12,6 +12,6 @@ #[start] fn start(argc: isize, argv: *const *const u8, crate_map: *const u8) -> isize { - //~^ ERROR incorrect number of function parameters + //~^ start function has wrong type 0 } diff --git a/src/test/compile-fail/main-wrong-type-2.rs b/src/test/compile-fail/main-wrong-type-2.rs index 09d5765a80f3f..7434a6c960b2d 100644 --- a/src/test/compile-fail/main-wrong-type-2.rs +++ b/src/test/compile-fail/main-wrong-type-2.rs @@ -9,5 +9,5 @@ // except according to those terms. fn main() -> char { -//~^ ERROR: main function expects type +//~^ ERROR: main function has wrong type } diff --git a/src/test/compile-fail/main-wrong-type.rs b/src/test/compile-fail/main-wrong-type.rs index d9c617a71720e..431b855d51773 100644 --- a/src/test/compile-fail/main-wrong-type.rs +++ b/src/test/compile-fail/main-wrong-type.rs @@ -14,5 +14,5 @@ struct S { } fn main(foo: S) { -//~^ ERROR: main function expects type +//~^ ERROR: main function has wrong type } diff --git a/src/test/compile-fail/match-range-fail.rs b/src/test/compile-fail/match-range-fail.rs index 05b870b8f41cc..526aa83dec7fd 100644 --- a/src/test/compile-fail/match-range-fail.rs +++ b/src/test/compile-fail/match-range-fail.rs @@ -28,6 +28,5 @@ fn main() { _ => { } }; //~^^^ ERROR mismatched types in range - //~| expected char - //~| found integral variable + //~| expected char, found integral variable } diff --git a/src/test/compile-fail/match-struct.rs b/src/test/compile-fail/match-struct.rs index 5bda37896879b..0dbdda1f9ba1e 100644 --- a/src/test/compile-fail/match-struct.rs +++ b/src/test/compile-fail/match-struct.rs @@ -16,10 +16,9 @@ fn main() { match (S { a: 1 }) { E::C(_) => (), //~^ ERROR mismatched types - //~| expected `S` - //~| found `E` - //~| expected struct `S` - //~| found enum `E` + //~| expected type `S` + //~| found type `E` + //~| expected struct `S`, found enum `E` _ => () } } diff --git a/src/test/compile-fail/match-vec-mismatch-2.rs b/src/test/compile-fail/match-vec-mismatch-2.rs index 0bbba8861217d..2831499c73d87 100644 --- a/src/test/compile-fail/match-vec-mismatch-2.rs +++ b/src/test/compile-fail/match-vec-mismatch-2.rs @@ -14,9 +14,8 @@ fn main() { match () { [()] => { } //~^ ERROR mismatched types - //~| expected `()` - //~| found `&[_]` - //~| expected () - //~| found &-ptr + //~| expected type `()` + //~| found type `&[_]` + //~| expected (), found &-ptr } } diff --git a/src/test/compile-fail/method-self-arg-1.rs b/src/test/compile-fail/method-self-arg-1.rs index 57a96bb9a26ea..ffa5287d4b2c3 100644 --- a/src/test/compile-fail/method-self-arg-1.rs +++ b/src/test/compile-fail/method-self-arg-1.rs @@ -19,13 +19,11 @@ impl Foo { fn main() { let x = Foo; Foo::bar(x); //~ ERROR mismatched types - //~| expected `&Foo` - //~| found `Foo` - //~| expected &-ptr - //~| found struct `Foo` + //~| expected type `&Foo` + //~| found type `Foo` + //~| expected &-ptr, found struct `Foo` Foo::bar(&42); //~ ERROR mismatched types - //~| expected `&Foo` - //~| found `&_` - //~| expected struct `Foo` - //~| found integral variable + //~| expected type `&Foo` + //~| found type `&_` + //~| expected struct `Foo`, found integral variable } diff --git a/src/test/compile-fail/moves-based-on-type-distribute-copy-over-paren.rs b/src/test/compile-fail/moves-based-on-type-distribute-copy-over-paren.rs index f30360af46eb4..02c09aa7d69a2 100644 --- a/src/test/compile-fail/moves-based-on-type-distribute-copy-over-paren.rs +++ b/src/test/compile-fail/moves-based-on-type-distribute-copy-over-paren.rs @@ -16,13 +16,17 @@ fn touch(_a: &A) {} fn f00() { let x = "hi".to_string(); - let _y = Foo { f:x }; //~ NOTE `x` moved here + let _y = Foo { f:x }; + //~^ value moved here touch(&x); //~ ERROR use of moved value: `x` + //~^ value used here after move + //~| move occurs because `x` has type `std::string::String` } fn f05() { let x = "hi".to_string(); - let _y = Foo { f:(((x))) }; //~ NOTE `x` moved here + let _y = Foo { f:(((x))) }; + //~^ value moved here touch(&x); //~ ERROR use of moved value: `x` } diff --git a/src/test/compile-fail/moves-based-on-type-match-bindings.rs b/src/test/compile-fail/moves-based-on-type-match-bindings.rs index 7d209467caf2a..bcbb8dbfad121 100644 --- a/src/test/compile-fail/moves-based-on-type-match-bindings.rs +++ b/src/test/compile-fail/moves-based-on-type-match-bindings.rs @@ -24,6 +24,8 @@ fn f10() { }; touch(&x); //~ ERROR use of partially moved value: `x` + //~^ value used here after move + //~| move occurs because `x.f` has type `std::string::String` } fn main() {} diff --git a/src/test/compile-fail/mut-pattern-mismatched.rs b/src/test/compile-fail/mut-pattern-mismatched.rs index 9eb24c81960ca..63e7dbd30def2 100644 --- a/src/test/compile-fail/mut-pattern-mismatched.rs +++ b/src/test/compile-fail/mut-pattern-mismatched.rs @@ -14,8 +14,8 @@ fn main() { // (separate lines to ensure the spans are accurate) let &_ //~ ERROR mismatched types - //~| expected `&mut _` - //~| found `&_` + //~| expected type `&mut _` + //~| found type `&_` //~| values differ in mutability = foo; let &mut _ = foo; @@ -23,8 +23,8 @@ fn main() { let bar = &1; let &_ = bar; let &mut _ //~ ERROR mismatched types - //~| expected `&_` - //~| found `&mut _` + //~| expected type `&_` + //~| found type `&mut _` //~| values differ in mutability = bar; } diff --git a/src/test/compile-fail/noexporttypeexe.rs b/src/test/compile-fail/noexporttypeexe.rs index 687e1e49ee844..c950ef5b68002 100644 --- a/src/test/compile-fail/noexporttypeexe.rs +++ b/src/test/compile-fail/noexporttypeexe.rs @@ -19,8 +19,7 @@ fn main() { // not convertible to a path. let x: isize = noexporttypelib::foo(); //~^ ERROR mismatched types - //~| expected `isize` - //~| found `std::option::Option` - //~| expected isize - //~| found enum `std::option::Option` + //~| expected type `isize` + //~| found type `std::option::Option` + //~| expected isize, found enum `std::option::Option` } diff --git a/src/test/compile-fail/occurs-check-2.rs b/src/test/compile-fail/occurs-check-2.rs index fd2903a85ddb0..5cb60079fa4b8 100644 --- a/src/test/compile-fail/occurs-check-2.rs +++ b/src/test/compile-fail/occurs-check-2.rs @@ -16,7 +16,7 @@ fn main() { g = f; f = box g; //~^ ERROR mismatched types - //~| expected `_` - //~| found `Box<_>` + //~| expected type `_` + //~| found type `Box<_>` //~| cyclic type of infinite size } diff --git a/src/test/compile-fail/occurs-check.rs b/src/test/compile-fail/occurs-check.rs index 036fcc1b9d779..499124cb0573b 100644 --- a/src/test/compile-fail/occurs-check.rs +++ b/src/test/compile-fail/occurs-check.rs @@ -14,7 +14,7 @@ fn main() { let f; f = box f; //~^ ERROR mismatched types - //~| expected `_` - //~| found `Box<_>` + //~| expected type `_` + //~| found type `Box<_>` //~| cyclic type of infinite size } diff --git a/src/test/compile-fail/pattern-error-continue.rs b/src/test/compile-fail/pattern-error-continue.rs index 9b67595800320..d9f3bb3c40f8d 100644 --- a/src/test/compile-fail/pattern-error-continue.rs +++ b/src/test/compile-fail/pattern-error-continue.rs @@ -31,17 +31,15 @@ fn main() { match 'c' { S { .. } => (), //~^ ERROR mismatched types - //~| expected `char` - //~| found `S` - //~| expected char - //~| found struct `S` + //~| expected type `char` + //~| found type `S` + //~| expected char, found struct `S` _ => () } f(true); //~^ ERROR mismatched types - //~| expected `char` - //~| found `bool` + //~| expected char, found bool match () { E::V => {} //~ ERROR failed to resolve. Use of undeclared type or module `E` diff --git a/src/test/compile-fail/pptypedef.rs b/src/test/compile-fail/pptypedef.rs index 1a1c87ff47d46..7ece52e753786 100644 --- a/src/test/compile-fail/pptypedef.rs +++ b/src/test/compile-fail/pptypedef.rs @@ -13,11 +13,9 @@ fn let_in(x: T, f: F) where F: FnOnce(T) {} fn main() { let_in(3u32, |i| { assert!(i == 3i32); }); //~^ ERROR mismatched types - //~| expected `u32` - //~| found `i32` + //~| expected u32, found i32 let_in(3i32, |i| { assert!(i == 3u32); }); //~^ ERROR mismatched types - //~| expected `i32` - //~| found `u32` + //~| expected i32, found u32 } diff --git a/src/test/compile-fail/ptr-coercion.rs b/src/test/compile-fail/ptr-coercion.rs index 18e210076cb55..ff627e69d4c58 100644 --- a/src/test/compile-fail/ptr-coercion.rs +++ b/src/test/compile-fail/ptr-coercion.rs @@ -15,19 +15,19 @@ pub fn main() { // *const -> *mut let x: *const isize = &42; let x: *mut isize = x; //~ ERROR mismatched types - //~| expected `*mut isize` - //~| found `*const isize` + //~| expected type `*mut isize` + //~| found type `*const isize` //~| values differ in mutability // & -> *mut let x: *mut isize = &42; //~ ERROR mismatched types - //~| expected `*mut isize` - //~| found `&isize` + //~| expected type `*mut isize` + //~| found type `&isize` //~| values differ in mutability let x: *const isize = &42; let x: *mut isize = x; //~ ERROR mismatched types - //~| expected `*mut isize` - //~| found `*const isize` + //~| expected type `*mut isize` + //~| found type `*const isize` //~| values differ in mutability } diff --git a/src/test/compile-fail/ref-suggestion.rs b/src/test/compile-fail/ref-suggestion.rs index 815f752663223..0a0867195d976 100644 --- a/src/test/compile-fail/ref-suggestion.rs +++ b/src/test/compile-fail/ref-suggestion.rs @@ -11,22 +11,16 @@ fn main() { let x = vec![1]; let y = x; - //~^ HELP use a `ref` binding as shown - //~| SUGGESTION let ref y = x; x; //~ ERROR use of moved value let x = vec![1]; let mut y = x; - //~^ HELP use a `ref` binding as shown - //~| SUGGESTION let ref mut y = x; x; //~ ERROR use of moved value let x = (Some(vec![1]), ()); match x { (Some(y), ()) => {}, - //~^ HELP use a `ref` binding as shown - //~| SUGGESTION (Some(ref y), ()) => {}, _ => {}, } x; //~ ERROR use of partially moved value diff --git a/src/test/compile-fail/regions-bounds.rs b/src/test/compile-fail/regions-bounds.rs index 7f2889a327be0..64dbf27b78e48 100644 --- a/src/test/compile-fail/regions-bounds.rs +++ b/src/test/compile-fail/regions-bounds.rs @@ -17,15 +17,15 @@ struct a_class<'a> { x:&'a isize } fn a_fn1<'a,'b>(e: an_enum<'a>) -> an_enum<'b> { return e; //~ ERROR mismatched types - //~| expected `an_enum<'b>` - //~| found `an_enum<'a>` + //~| expected type `an_enum<'b>` + //~| found type `an_enum<'a>` //~| lifetime mismatch } fn a_fn3<'a,'b>(e: a_class<'a>) -> a_class<'b> { return e; //~ ERROR mismatched types - //~| expected `a_class<'b>` - //~| found `a_class<'a>` + //~| expected type `a_class<'b>` + //~| found type `a_class<'a>` //~| lifetime mismatch } diff --git a/src/test/compile-fail/regions-early-bound-error-method.rs b/src/test/compile-fail/regions-early-bound-error-method.rs index 8cc35272282c4..f6a0c86de6626 100644 --- a/src/test/compile-fail/regions-early-bound-error-method.rs +++ b/src/test/compile-fail/regions-early-bound-error-method.rs @@ -29,8 +29,8 @@ impl<'a> Box<'a> { fn or<'b,G:GetRef<'b>>(&self, g2: G) -> &'a isize { g2.get() //~^ ERROR mismatched types - //~| expected `&'a isize` - //~| found `&'b isize` + //~| expected type `&'a isize` + //~| found type `&'b isize` //~| lifetime mismatch } diff --git a/src/test/compile-fail/regions-fn-subtyping-return-static.rs b/src/test/compile-fail/regions-fn-subtyping-return-static.rs index ebf7ca289f889..c0116b21166e0 100644 --- a/src/test/compile-fail/regions-fn-subtyping-return-static.rs +++ b/src/test/compile-fail/regions-fn-subtyping-return-static.rs @@ -55,10 +55,9 @@ fn supply_G() { want_G(bar); want_G(baz); //~^ ERROR mismatched types - //~| expected `fn(&'cx S) -> &'static S` - //~| found `fn(&S) -> &S {baz}` - //~| expected concrete lifetime - //~| found bound lifetime parameter 'cx + //~| expected type `fn(&'cx S) -> &'static S` + //~| found type `fn(&S) -> &S {baz}` + //~| expected concrete lifetime, found bound lifetime parameter 'cx } pub fn main() { diff --git a/src/test/compile-fail/regions-infer-not-param.rs b/src/test/compile-fail/regions-infer-not-param.rs index 83b9d4633dcf3..131b7170951f6 100644 --- a/src/test/compile-fail/regions-infer-not-param.rs +++ b/src/test/compile-fail/regions-infer-not-param.rs @@ -27,10 +27,10 @@ fn take_direct<'a,'b>(p: direct<'a>) -> direct<'b> { p } //~ ERROR mismatched ty fn take_indirect1(p: indirect1) -> indirect1 { p } fn take_indirect2<'a,'b>(p: indirect2<'a>) -> indirect2<'b> { p } //~ ERROR mismatched types -//~| expected `indirect2<'b>` -//~| found `indirect2<'a>` +//~| expected type `indirect2<'b>` +//~| found type `indirect2<'a>` //~| ERROR mismatched types -//~| expected `indirect2<'b>` -//~| found `indirect2<'a>` +//~| expected type `indirect2<'b>` +//~| found type `indirect2<'a>` fn main() {} diff --git a/src/test/compile-fail/regions-infer-paramd-indirect.rs b/src/test/compile-fail/regions-infer-paramd-indirect.rs index 1d32e8fe7b250..fad115c2aedf8 100644 --- a/src/test/compile-fail/regions-infer-paramd-indirect.rs +++ b/src/test/compile-fail/regions-infer-paramd-indirect.rs @@ -32,8 +32,8 @@ impl<'a> set_f<'a> for c<'a> { fn set_f_bad(&mut self, b: Box) { self.f = b; //~^ ERROR mismatched types - //~| expected `Box>` - //~| found `Box>` + //~| expected type `Box>` + //~| found type `Box>` //~| lifetime mismatch } } diff --git a/src/test/compile-fail/reject-specialized-drops-8142.rs b/src/test/compile-fail/reject-specialized-drops-8142.rs index adc8702240378..1ea956bbd5489 100644 --- a/src/test/compile-fail/reject-specialized-drops-8142.rs +++ b/src/test/compile-fail/reject-specialized-drops-8142.rs @@ -38,8 +38,8 @@ impl<'ml> Drop for M<'ml> { fn drop(&mut self) { } } // AC impl Drop for N<'static> { fn drop(&mut self) { } } // REJECT //~^ ERROR mismatched types -//~| expected `N<'n>` -//~| found `N<'static>` +//~| expected type `N<'n>` +//~| found type `N<'static>` impl Drop for O { fn drop(&mut self) { } } // ACCEPT diff --git a/src/test/compile-fail/repeat_count.rs b/src/test/compile-fail/repeat_count.rs index 10b722946a8a8..ab5af64d95c13 100644 --- a/src/test/compile-fail/repeat_count.rs +++ b/src/test/compile-fail/repeat_count.rs @@ -16,52 +16,45 @@ fn main() { //~^ ERROR expected constant integer for repeat count, found variable [E0307] let b = [0; ()]; //~^ ERROR mismatched types - //~| expected `usize` - //~| found `()` - //~| expected usize - //~| found ()) [E0308] + //~| expected type `usize` + //~| found type `()` + //~| expected usize, found () //~| ERROR expected positive integer for repeat count, found tuple [E0306] let c = [0; true]; //~^ ERROR mismatched types - //~| expected `usize` - //~| found `bool` + //~| expected usize, found bool //~| ERROR expected positive integer for repeat count, found boolean [E0306] let d = [0; 0.5]; //~^ ERROR mismatched types - //~| expected `usize` - //~| found `_` - //~| expected usize - //~| found floating-point variable) [E0308] + //~| expected type `usize` + //~| found type `_` + //~| expected usize, found floating-point variable //~| ERROR expected positive integer for repeat count, found float [E0306] let e = [0; "foo"]; //~^ ERROR mismatched types - //~| expected `usize` - //~| found `&'static str` - //~| expected usize - //~| found &-ptr) [E0308] + //~| expected type `usize` + //~| found type `&'static str` + //~| expected usize, found &-ptr //~| ERROR expected positive integer for repeat count, found string literal [E0306] let f = [0; -4_isize]; //~^ ERROR mismatched types //~| expected `usize` - //~| found `isize` [E0308] + //~| found `isize` //~| ERROR mismatched types: - //~| expected `usize`, - //~| found `isize` [E0307] + //~| expected usize, found isize let f = [0_usize; -1_isize]; //~^ ERROR mismatched types //~| expected `usize` - //~| found `isize` [E0308] + //~| found `isize` //~| ERROR mismatched types - //~| expected `usize` - //~| found `isize` [E0307] + //~| expected usize, found isize struct G { g: (), } let g = [0; G { g: () }]; //~^ ERROR mismatched types - //~| expected `usize` - //~| found `main::G` - //~| expected usize - //~| found struct `main::G`) [E0308] + //~| expected type `usize` + //~| found type `main::G` + //~| expected usize, found struct `main::G` //~| ERROR expected positive integer for repeat count, found struct [E0306] } diff --git a/src/test/compile-fail/shift-various-bad-types.rs b/src/test/compile-fail/shift-various-bad-types.rs index 560af9193b35e..2d06161111ef1 100644 --- a/src/test/compile-fail/shift-various-bad-types.rs +++ b/src/test/compile-fail/shift-various-bad-types.rs @@ -34,8 +34,7 @@ fn foo(p: &Panolpy) { // Type of the result follows the LHS, not the RHS: let _: i32 = 22_i64 >> 1_i32; //~^ ERROR mismatched types - //~| expected `i32` - //~| found `i64` + //~| expected i32, found i64 } fn main() { diff --git a/src/test/compile-fail/slice-mut.rs b/src/test/compile-fail/slice-mut.rs index e6acc32545178..874cca8cb3fd0 100644 --- a/src/test/compile-fail/slice-mut.rs +++ b/src/test/compile-fail/slice-mut.rs @@ -16,7 +16,7 @@ fn main() { let y: &mut[_] = &x[2..4]; //~^ ERROR mismatched types - //~| expected `&mut [_]` - //~| found `&[isize]` + //~| expected type `&mut [_]` + //~| found type `&[isize]` //~| values differ in mutability } diff --git a/src/test/compile-fail/slightly-nice-generic-literal-messages.rs b/src/test/compile-fail/slightly-nice-generic-literal-messages.rs index 3c1c3796a246f..3140bb6e5731d 100644 --- a/src/test/compile-fail/slightly-nice-generic-literal-messages.rs +++ b/src/test/compile-fail/slightly-nice-generic-literal-messages.rs @@ -16,10 +16,9 @@ fn main() { match Foo(1.1, marker::PhantomData) { 1 => {} //~^ ERROR mismatched types - //~| expected `Foo<_, _>` - //~| found `_` - //~| expected struct `Foo` - //~| found integral variable + //~| expected type `Foo<_, _>` + //~| found type `_` + //~| expected struct `Foo`, found integral variable } } diff --git a/src/test/compile-fail/struct-base-wrong-type-2.rs b/src/test/compile-fail/struct-base-wrong-type-2.rs index 83e73b6bc3ef4..1250d0dabcd9a 100644 --- a/src/test/compile-fail/struct-base-wrong-type-2.rs +++ b/src/test/compile-fail/struct-base-wrong-type-2.rs @@ -19,13 +19,11 @@ struct Bar { x: isize } fn main() { let b = Bar { x: 5 }; let f = Foo { a: 2, ..b }; //~ ERROR mismatched types - //~| expected `Foo` - //~| found `Bar` - //~| expected struct `Foo` - //~| found struct `Bar` + //~| expected type `Foo` + //~| found type `Bar` + //~| expected struct `Foo`, found struct `Bar` let f__isize = Foo { a: 2, ..4 }; //~ ERROR mismatched types - //~| expected `Foo` - //~| found `_` - //~| expected struct `Foo` - //~| found integral variable + //~| expected type `Foo` + //~| found type `_` + //~| expected struct `Foo`, found integral variable } diff --git a/src/test/compile-fail/struct-base-wrong-type.rs b/src/test/compile-fail/struct-base-wrong-type.rs index c98131560d486..4503e465840fe 100644 --- a/src/test/compile-fail/struct-base-wrong-type.rs +++ b/src/test/compile-fail/struct-base-wrong-type.rs @@ -18,15 +18,13 @@ struct Bar { x: isize } static bar: Bar = Bar { x: 5 }; static foo: Foo = Foo { a: 2, ..bar }; //~ ERROR mismatched types - //~| expected `Foo` - //~| found `Bar` - //~| expected struct `Foo` - //~| found struct `Bar` + //~| expected type `Foo` + //~| found type `Bar` + //~| expected struct `Foo`, found struct `Bar` static foo_i: Foo = Foo { a: 2, ..4 }; //~ ERROR mismatched types - //~| expected `Foo` - //~| found `_` - //~| expected struct `Foo` - //~| found integral variable + //~| expected type `Foo` + //~| found type `_` + //~| expected struct `Foo`, found integral variable fn main() { let b = Bar { x: 5 }; diff --git a/src/test/compile-fail/structure-constructor-type-mismatch.rs b/src/test/compile-fail/structure-constructor-type-mismatch.rs index 7a6b8ff662240..87fc5ba93aeb3 100644 --- a/src/test/compile-fail/structure-constructor-type-mismatch.rs +++ b/src/test/compile-fail/structure-constructor-type-mismatch.rs @@ -26,38 +26,32 @@ fn main() { let pt = PointF { x: 1, //~^ ERROR mismatched types - //~| expected f32 - //~| found integral variable + //~| expected f32, found integral variable y: 2, //~^ ERROR mismatched types - //~| expected f32 - //~| found integral variable + //~| expected f32, found integral variable }; let pt2 = Point:: { x: 3, //~^ ERROR mismatched types - //~| expected f32 - //~| found integral variable + //~| expected f32, found integral variable y: 4, //~^ ERROR mismatched types - //~| expected f32 - //~| found integral variable + //~| expected f32, found integral variable }; let pair = PairF { x: 5, //~^ ERROR mismatched types - //~| expected f32 - //~| found integral variable + //~| expected f32, found integral variable y: 6, }; let pair2 = PairF:: { x: 7, //~^ ERROR mismatched types - //~| expected f32 - //~| found integral variable + //~| expected f32, found integral variable y: 8, }; diff --git a/src/test/compile-fail/substs-ppaux.rs b/src/test/compile-fail/substs-ppaux.rs index 8dd9994b234ba..c857790e342d0 100644 --- a/src/test/compile-fail/substs-ppaux.rs +++ b/src/test/compile-fail/substs-ppaux.rs @@ -24,36 +24,36 @@ fn main() {} fn foo<'z>() where &'z (): Sized { let x: () = >::bar::<'static, char>; //[verbose]~^ ERROR mismatched types - //[verbose]~| expected `()` - //[verbose]~| found `fn() {>::bar::}` + //[verbose]~| expected type `()` + //[verbose]~| found type `fn() {>::bar::}` //[normal]~^^^^ ERROR mismatched types - //[normal]~| expected `()` - //[normal]~| found `fn() {>::bar::<'static, char>}` + //[normal]~| expected type `()` + //[normal]~| found type `fn() {>::bar::<'static, char>}` let x: () = >::bar::<'static, char>; //[verbose]~^ ERROR mismatched types - //[verbose]~| expected `()` - //[verbose]~| found `fn() {>::bar::}` + //[verbose]~| expected type `()` + //[verbose]~| found type `fn() {>::bar::}` //[normal]~^^^^ ERROR mismatched types - //[normal]~| expected `()` - //[normal]~| found `fn() {>::bar::<'static, char>}` + //[normal]~| expected type `()` + //[normal]~| found type `fn() {>::bar::<'static, char>}` let x: () = >::baz; //[verbose]~^ ERROR mismatched types - //[verbose]~| expected `()` - //[verbose]~| found `fn() {>::baz}` + //[verbose]~| expected type `()` + //[verbose]~| found type `fn() {>::baz}` //[normal]~^^^^ ERROR mismatched types - //[normal]~| expected `()` - //[normal]~| found `fn() {>::baz}` + //[normal]~| expected type `()` + //[normal]~| found type `fn() {>::baz}` let x: () = foo::<'static>; //[verbose]~^ ERROR mismatched types - //[verbose]~| expected `()` - //[verbose]~| found `fn() {foo::}` + //[verbose]~| expected type `()` + //[verbose]~| found type `fn() {foo::}` //[normal]~^^^^ ERROR mismatched types - //[normal]~| expected `()` - //[normal]~| found `fn() {foo::<'static>}` + //[normal]~| expected type `()` + //[normal]~| found type `fn() {foo::<'static>}` >::bar; //[verbose]~^ ERROR `str: std::marker::Sized` is not satisfied diff --git a/src/test/compile-fail/suppressed-error.rs b/src/test/compile-fail/suppressed-error.rs index 44de5d8cfe353..9a4a52ced2008 100644 --- a/src/test/compile-fail/suppressed-error.rs +++ b/src/test/compile-fail/suppressed-error.rs @@ -11,9 +11,8 @@ fn main() { let (x, y) = (); //~^ ERROR mismatched types -//~| expected `()` -//~| found `(_, _)` -//~| expected () -//~| found tuple +//~| expected type `()` +//~| found type `(_, _)` +//~| expected (), found tuple return x; } diff --git a/src/test/compile-fail/tag-that-dare-not-speak-its-name.rs b/src/test/compile-fail/tag-that-dare-not-speak-its-name.rs index 725234dfeab56..8f420f1ce4b0d 100644 --- a/src/test/compile-fail/tag-that-dare-not-speak-its-name.rs +++ b/src/test/compile-fail/tag-that-dare-not-speak-its-name.rs @@ -21,8 +21,7 @@ fn main() { let y; let x : char = last(y); //~^ ERROR mismatched types - //~| expected `char` - //~| found `std::option::Option<_>` - //~| expected char - //~| found enum `std::option::Option` + //~| expected type `char` + //~| found type `std::option::Option<_>` + //~| expected char, found enum `std::option::Option` } diff --git a/src/test/compile-fail/terr-in-field.rs b/src/test/compile-fail/terr-in-field.rs index 60db35b879f57..4a21e1339811e 100644 --- a/src/test/compile-fail/terr-in-field.rs +++ b/src/test/compile-fail/terr-in-field.rs @@ -21,10 +21,9 @@ struct bar { fn want_foo(f: foo) {} fn have_bar(b: bar) { want_foo(b); //~ ERROR mismatched types - //~| expected `foo` - //~| found `bar` - //~| expected struct `foo` - //~| found struct `bar` + //~| expected type `foo` + //~| found type `bar` + //~| expected struct `foo`, found struct `bar` } fn main() {} diff --git a/src/test/compile-fail/terr-sorts.rs b/src/test/compile-fail/terr-sorts.rs index 231d2366b48a8..592d7b3929bfc 100644 --- a/src/test/compile-fail/terr-sorts.rs +++ b/src/test/compile-fail/terr-sorts.rs @@ -19,10 +19,9 @@ type bar = Box; fn want_foo(f: foo) {} fn have_bar(b: bar) { want_foo(b); //~ ERROR mismatched types - //~| expected `foo` - //~| found `Box` - //~| expected struct `foo` - //~| found box + //~| expected type `foo` + //~| found type `Box` + //~| expected struct `foo`, found box } fn main() {} diff --git a/src/test/compile-fail/token-error-correct-3.rs b/src/test/compile-fail/token-error-correct-3.rs index f42c8d09a9c09..24627e9420874 100644 --- a/src/test/compile-fail/token-error-correct-3.rs +++ b/src/test/compile-fail/token-error-correct-3.rs @@ -22,6 +22,9 @@ pub mod raw { callback(path.as_ref(); //~ NOTE: unclosed delimiter //~^ ERROR: expected one of fs::create_dir_all(path.as_ref()).map(|()| true) //~ ERROR: mismatched types + //~^ expected (), found enum `std::result::Result` + //~| expected type `()` + //~| found type `std::result::Result` } else { //~ ERROR: incorrect close delimiter: `}` //~^ ERROR: expected one of Ok(false); diff --git a/src/test/compile-fail/trait-bounds-cant-coerce.rs b/src/test/compile-fail/trait-bounds-cant-coerce.rs index 836f08d0e78bb..1fff812af5b8d 100644 --- a/src/test/compile-fail/trait-bounds-cant-coerce.rs +++ b/src/test/compile-fail/trait-bounds-cant-coerce.rs @@ -22,10 +22,9 @@ fn c(x: Box) { fn d(x: Box) { a(x); //~ ERROR mismatched types - //~| expected `Box` - //~| found `Box` - //~| expected bounds `Send` - //~| found no bounds + //~| expected type `Box` + //~| found type `Box` + //~| expected bounds `Send`, found no bounds } fn main() { } diff --git a/src/test/compile-fail/tuple-arity-mismatch.rs b/src/test/compile-fail/tuple-arity-mismatch.rs index 8ad9ca50e3042..e62255a4e77d4 100644 --- a/src/test/compile-fail/tuple-arity-mismatch.rs +++ b/src/test/compile-fail/tuple-arity-mismatch.rs @@ -15,15 +15,13 @@ fn first((value, _): (isize, f64)) -> isize { value } fn main() { let y = first ((1,2.0,3)); //~^ ERROR mismatched types - //~| expected `(isize, f64)` - //~| found `(isize, f64, _)` - //~| expected a tuple with 2 elements - //~| found one with 3 elements + //~| expected type `(isize, f64)` + //~| found type `(isize, f64, _)` + //~| expected a tuple with 2 elements, found one with 3 elements let y = first ((1,)); //~^ ERROR mismatched types - //~| expected `(isize, f64)` - //~| found `(isize,)` - //~| expected a tuple with 2 elements - //~| found one with 1 elements + //~| expected type `(isize, f64)` + //~| found type `(isize,)` + //~| expected a tuple with 2 elements, found one with 1 elements } diff --git a/src/test/compile-fail/tutorial-suffix-inference-test.rs b/src/test/compile-fail/tutorial-suffix-inference-test.rs index 99d6437c02ed4..dadf7eb91d8f4 100644 --- a/src/test/compile-fail/tutorial-suffix-inference-test.rs +++ b/src/test/compile-fail/tutorial-suffix-inference-test.rs @@ -18,12 +18,10 @@ fn main() { identity_u8(x); // after this, `x` is assumed to have type `u8` identity_u16(x); //~^ ERROR mismatched types - //~| expected `u16` - //~| found `u8` + //~| expected u16, found u8 identity_u16(y); //~^ ERROR mismatched types - //~| expected `u16` - //~| found `i32` + //~| expected u16, found i32 let a = 3; @@ -32,6 +30,5 @@ fn main() { identity_i(a); // ok identity_u16(a); //~^ ERROR mismatched types - //~| expected `u16` - //~| found `isize` + //~| expected u16, found isize } diff --git a/src/test/compile-fail/type-mismatch-multiple.rs b/src/test/compile-fail/type-mismatch-multiple.rs index dd8f54cdabb8f..0f174d99fefcb 100644 --- a/src/test/compile-fail/type-mismatch-multiple.rs +++ b/src/test/compile-fail/type-mismatch-multiple.rs @@ -12,11 +12,9 @@ fn main() { let a: bool = 1; let b: i32 = true; } //~^ ERROR mismatched types -//~| expected `bool` -//~| found `_` -//~| expected bool -//~| found integral variable +//~| expected type `bool` +//~| found type `_` +//~| expected bool, found integral variable //~| ERROR mismatched types -//~| expected `i32` -//~| found `bool` +//~| expected i32, found bool diff --git a/src/test/compile-fail/type-mismatch-same-crate-name.rs b/src/test/compile-fail/type-mismatch-same-crate-name.rs index e81ae5d743939..e74acaa71b0f3 100644 --- a/src/test/compile-fail/type-mismatch-same-crate-name.rs +++ b/src/test/compile-fail/type-mismatch-same-crate-name.rs @@ -23,9 +23,17 @@ fn main() { let bar2 = {extern crate crate_a2 as a; a::bar()}; { extern crate crate_a1 as a; - a::try_foo(foo2); //~ ERROR mismatched types - //~^ NOTE Perhaps two different versions of crate `crate_a1` - a::try_bar(bar2); //~ ERROR mismatched types - //~^ NOTE Perhaps two different versions of crate `crate_a1` + a::try_foo(foo2); + //~^ ERROR mismatched types + //~| Perhaps two different versions of crate `crate_a1` + //~| expected struct `main::a::Foo` + //~| expected type `main::a::Foo` + //~| found type `main::a::Foo` + a::try_bar(bar2); + //~^ ERROR mismatched types + //~| Perhaps two different versions of crate `crate_a1` + //~| expected trait `main::a::Bar` + //~| expected type `Box` + //~| found type `Box` } } diff --git a/src/test/compile-fail/type-parameter-names.rs b/src/test/compile-fail/type-parameter-names.rs index 408bf72e97c87..11a2fc2665ca4 100644 --- a/src/test/compile-fail/type-parameter-names.rs +++ b/src/test/compile-fail/type-parameter-names.rs @@ -14,10 +14,9 @@ fn foo(x: Foo) -> Bar { x //~^ ERROR mismatched types -//~| expected `Bar` -//~| found `Foo` -//~| expected type parameter -//~| found a different type parameter +//~| expected type `Bar` +//~| found type `Foo` +//~| expected type parameter, found a different type parameter } fn main() {} diff --git a/src/test/compile-fail/type-params-in-different-spaces-1.rs b/src/test/compile-fail/type-params-in-different-spaces-1.rs index 155b835bbc6e0..26eac6adde221 100644 --- a/src/test/compile-fail/type-params-in-different-spaces-1.rs +++ b/src/test/compile-fail/type-params-in-different-spaces-1.rs @@ -13,10 +13,9 @@ use std::ops::Add; trait BrokenAdd: Copy + Add { fn broken_add(&self, rhs: T) -> Self { *self + rhs //~ ERROR mismatched types - //~| expected `Self` - //~| found `T` - //~| expected Self - //~| found type parameter + //~| expected type `Self` + //~| found type `T` + //~| expected Self, found type parameter } } diff --git a/src/test/compile-fail/typeck_type_placeholder_mismatch.rs b/src/test/compile-fail/typeck_type_placeholder_mismatch.rs index 1daea8f915b3f..91e3c38322e47 100644 --- a/src/test/compile-fail/typeck_type_placeholder_mismatch.rs +++ b/src/test/compile-fail/typeck_type_placeholder_mismatch.rs @@ -22,18 +22,16 @@ pub fn main() { fn test1() { let x: Foo<_> = Bar::(PhantomData); //~^ ERROR mismatched types - //~| expected `Foo<_>` - //~| found `Bar` - //~| expected struct `Foo` - //~| found struct `Bar` + //~| expected type `Foo<_>` + //~| found type `Bar` + //~| expected struct `Foo`, found struct `Bar` let y: Foo = x; } fn test2() { let x: Foo<_> = Bar::(PhantomData); //~^ ERROR mismatched types - //~| expected `Foo<_>` - //~| found `Bar` - //~| expected struct `Foo` - //~| found struct `Bar` + //~| expected type `Foo<_>` + //~| found type `Bar` + //~| expected struct `Foo`, found struct `Bar` } diff --git a/src/test/compile-fail/ufcs-explicit-self-bad.rs b/src/test/compile-fail/ufcs-explicit-self-bad.rs index e54a7623cb0c3..f14a3505cdeb4 100644 --- a/src/test/compile-fail/ufcs-explicit-self-bad.rs +++ b/src/test/compile-fail/ufcs-explicit-self-bad.rs @@ -45,12 +45,12 @@ impl<'a, T> SomeTrait for &'a Bar { //~^ ERROR mismatched types fn dummy3(self: &&Bar) {} //~^ ERROR mismatched types - //~| expected `&&'a Bar` - //~| found `&&Bar` + //~| expected type `&&'a Bar` + //~| found type `&&Bar` //~| lifetime mismatch //~| ERROR mismatched types - //~| expected `&&'a Bar` - //~| found `&&Bar` + //~| expected type `&&'a Bar` + //~| found type `&&Bar` //~| lifetime mismatch } diff --git a/src/test/compile-fail/variadic-ffi-3.rs b/src/test/compile-fail/variadic-ffi-3.rs index 6e60562da6749..b43159b0d96b0 100644 --- a/src/test/compile-fail/variadic-ffi-3.rs +++ b/src/test/compile-fail/variadic-ffi-3.rs @@ -21,17 +21,15 @@ fn main() { let x: unsafe extern "C" fn(f: isize, x: u8) = foo; //~^ ERROR: mismatched types - //~| expected `unsafe extern "C" fn(isize, u8)` - //~| found `unsafe extern "C" fn(isize, u8, ...) {foo}` - //~| expected non-variadic fn - //~| found variadic function + //~| expected type `unsafe extern "C" fn(isize, u8)` + //~| found type `unsafe extern "C" fn(isize, u8, ...) {foo}` + //~| NOTE: expected non-variadic fn, found variadic function let y: extern "C" fn(f: isize, x: u8, ...) = bar; //~^ ERROR: mismatched types - //~| expected `extern "C" fn(isize, u8, ...)` - //~| found `extern "C" fn(isize, u8) {bar}` - //~| expected variadic fn - //~| found non-variadic function + //~| expected type `extern "C" fn(isize, u8, ...)` + //~| found type `extern "C" fn(isize, u8) {bar}` + //~| NOTE: expected variadic fn, found non-variadic function foo(1, 2, 3f32); //~ ERROR: can't pass an `f32` to variadic function, cast to `c_double` foo(1, 2, true); //~ ERROR: can't pass `bool` to variadic function, cast to `c_int` From 1ff1887cc9537cf45c2bc405ce0b026ef9a2246a Mon Sep 17 00:00:00 2001 From: Niko Matsakis Date: Wed, 20 Apr 2016 14:44:07 -0400 Subject: [PATCH 07/40] thread tighter span for closures around Track the span corresponding to the `|...|` part of the closure. --- src/libsyntax/ext/expand.rs | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/libsyntax/ext/expand.rs b/src/libsyntax/ext/expand.rs index 63d9a699944ea..65df379781ecd 100644 --- a/src/libsyntax/ext/expand.rs +++ b/src/libsyntax/ext/expand.rs @@ -222,7 +222,7 @@ fn expand_mac_invoc(mac: ast::Mac, pth.span, &format!("macro undefined: '{}!'", &extname)); - fld.cx.suggest_macro_name(&extname.as_str(), pth.span, &mut err); + fld.cx.suggest_macro_name(&extname.as_str(), &mut err); err.emit(); // let compilation continue @@ -355,8 +355,8 @@ fn contains_macro_use(fld: &mut MacroExpander, attrs: &[ast::Attribute]) -> bool "macro_escape is a deprecated synonym for macro_use"); is_use = true; if let ast::AttrStyle::Inner = attr.node.style { - err.fileline_help(attr.span, "consider an outer attribute, \ - #[macro_use] mod ...").emit(); + err.help("consider an outer attribute, \ + #[macro_use] mod ...").emit(); } else { err.emit(); } From 489a6c95bf747059b28472efc17d39795c6adcad Mon Sep 17 00:00:00 2001 From: Niko Matsakis Date: Wed, 20 Apr 2016 14:49:16 -0400 Subject: [PATCH 08/40] replace fileline_{help,note} with {help,note} The extra filename and line was mainly there to keep the indentation relative to the main snippet; now that this doesn't include filename/line-number as a prefix, it is distracted. --- src/librustc/infer/error_reporting.rs | 19 +- src/librustc/lint/context.rs | 14 +- src/librustc/traits/error_reporting.rs | 165 ++++++------------ .../borrowck/gather_loans/move_error.rs | 3 +- src/librustc_borrowck/borrowck/mod.rs | 3 +- src/librustc_const_eval/check_match.rs | 2 +- src/librustc_lint/builtin.rs | 4 +- src/librustc_metadata/creader.rs | 4 +- src/librustc_metadata/loader.rs | 26 ++- src/librustc_passes/consts.rs | 3 +- src/librustc_resolve/lib.rs | 29 ++- src/librustc_typeck/astconv.rs | 45 +++-- src/librustc_typeck/check/callee.rs | 4 +- src/librustc_typeck/check/cast.rs | 7 +- src/librustc_typeck/check/method/suggest.rs | 28 ++- src/librustc_typeck/check/mod.rs | 6 +- src/librustc_typeck/check/wfcheck.rs | 3 +- src/librustc_typeck/coherence/mod.rs | 3 +- src/librustc_typeck/collect.rs | 9 +- src/libsyntax/diagnostics/macros.rs | 6 +- src/libsyntax/ext/base.rs | 7 +- src/libsyntax/feature_gate.rs | 6 +- src/libsyntax/parse/attr.rs | 5 +- src/libsyntax/parse/mod.rs | 10 +- src/libsyntax/parse/parser.rs | 21 ++- 25 files changed, 172 insertions(+), 260 deletions(-) diff --git a/src/librustc/infer/error_reporting.rs b/src/librustc/infer/error_reporting.rs index 88972beb31b09..11d92f8585489 100644 --- a/src/librustc/infer/error_reporting.rs +++ b/src/librustc/infer/error_reporting.rs @@ -682,10 +682,9 @@ impl<'a, 'tcx> ErrorReporting<'tcx> for InferCtxt<'a, 'tcx> { E0309, "{} may not live long enough", labeled_user_string); - err.fileline_help(origin.span(), - &format!("consider adding an explicit lifetime bound `{}: {}`...", - bound_kind, - sub)); + err.help(&format!("consider adding an explicit lifetime bound `{}: {}`...", + bound_kind, + sub)); err } @@ -696,10 +695,9 @@ impl<'a, 'tcx> ErrorReporting<'tcx> for InferCtxt<'a, 'tcx> { E0310, "{} may not live long enough", labeled_user_string); - err.fileline_help(origin.span(), - &format!("consider adding an explicit lifetime \ - bound `{}: 'static`...", - bound_kind)); + err.help(&format!("consider adding an explicit lifetime \ + bound `{}: 'static`...", + bound_kind)); err } @@ -710,9 +708,8 @@ impl<'a, 'tcx> ErrorReporting<'tcx> for InferCtxt<'a, 'tcx> { E0311, "{} may not live long enough", labeled_user_string); - err.fileline_help(origin.span(), - &format!("consider adding an explicit lifetime bound for `{}`", - bound_kind)); + err.help(&format!("consider adding an explicit lifetime bound for `{}`", + bound_kind)); self.tcx.note_and_explain_region( &mut err, &format!("{} must be valid for ", labeled_user_string), diff --git a/src/librustc/lint/context.rs b/src/librustc/lint/context.rs index 684cfbea3f5da..4ea6845b3c4f4 100644 --- a/src/librustc/lint/context.rs +++ b/src/librustc/lint/context.rs @@ -456,17 +456,13 @@ pub fn raw_struct_lint<'a>(sess: &'a Session, it will become a hard error in a future release!"); let citation = format!("for more information, see {}", future_incompatible.reference); - if let Some(sp) = span { - err.fileline_warn(sp, &explanation); - err.fileline_note(sp, &citation); - } else { - err.warn(&explanation); - err.note(&citation); - } + err.warn(&explanation); + err.note(&citation); } if let Some(span) = def { - err.span_note(span, "lint level defined here"); + let explanation = "lint level defined here"; + err = err.span_label(span, &explanation); } err @@ -542,7 +538,7 @@ pub trait LintContext: Sized { let mut err = self.lookup(lint, Some(span), msg); if self.current_level(lint) != Level::Allow { if note_span == span { - err.fileline_note(note_span, note); + err.note(note); } else { err.span_note(note_span, note); } diff --git a/src/librustc/traits/error_reporting.rs b/src/librustc/traits/error_reporting.rs index d7ddfc9f1a6d0..531a4fbf8beba 100644 --- a/src/librustc/traits/error_reporting.rs +++ b/src/librustc/traits/error_reporting.rs @@ -206,18 +206,17 @@ fn find_similar_impl_candidates<'a, 'tcx>( impl_candidates } -fn report_similar_impl_candidates(span: Span, - err: &mut DiagnosticBuilder, +fn report_similar_impl_candidates(err: &mut DiagnosticBuilder, impl_candidates: &[ty::TraitRef]) { - err.fileline_help(span, &format!("the following implementations were found:")); + err.help(&format!("the following implementations were found:")); let end = cmp::min(4, impl_candidates.len()); for candidate in &impl_candidates[0..end] { - err.fileline_help(span, &format!(" {:?}", candidate)); + err.help(&format!(" {:?}", candidate)); } if impl_candidates.len() > 4 { - err.fileline_help(span, &format!("and {} others", impl_candidates.len()-4)); + err.help(&format!("and {} others", impl_candidates.len()-4)); } } @@ -240,7 +239,7 @@ pub fn report_overflow_error<'a, 'tcx, T>(infcx: &InferCtxt<'a, 'tcx>, predicate); if suggest_increasing_limit { - suggest_new_overflow_limit(infcx.tcx, &mut err, obligation.cause.span); + suggest_new_overflow_limit(infcx.tcx, &mut err); } note_obligation_cause(infcx, &mut err, obligation); @@ -353,19 +352,15 @@ pub fn try_report_overflow_error_type_of_infinite_size<'a, 'tcx>( let mut err = recursive_type_with_infinite_size_error(tcx, main_def_id); let len = struct_enum_tys.len(); if len > 2 { - let span = tcx.map.span_if_local(main_def_id).unwrap(); - err.fileline_note(span, - &format!("type `{}` is embedded within `{}`...", - struct_enum_tys[0], - struct_enum_tys[1])); + err.note(&format!("type `{}` is embedded within `{}`...", + struct_enum_tys[0], + struct_enum_tys[1])); for &next_ty in &struct_enum_tys[1..len-1] { - err.fileline_note(span, - &format!("...which in turn is embedded within `{}`...", next_ty)); + err.note(&format!("...which in turn is embedded within `{}`...", next_ty)); } - err.fileline_note(span, - &format!("...which in turn is embedded within `{}`, \ - completing the cycle.", - struct_enum_tys[len-1])); + err.note(&format!("...which in turn is embedded within `{}`, \ + completing the cycle.", + struct_enum_tys[len-1])); } err.emit(); infcx.tcx.sess.abort_if_errors(); @@ -380,9 +375,9 @@ pub fn recursive_type_with_infinite_size_error<'tcx>(tcx: &TyCtxt<'tcx>, let span = tcx.map.span_if_local(type_def_id).unwrap(); let mut err = struct_span_err!(tcx.sess, span, E0072, "recursive type `{}` has infinite size", tcx.item_path_str(type_def_id)); - err.fileline_help(span, &format!("insert indirection (e.g., a `Box`, `Rc`, or `&`) \ - at some point to make `{}` representable", - tcx.item_path_str(type_def_id))); + err.help(&format!("insert indirection (e.g., a `Box`, `Rc`, or `&`) \ + at some point to make `{}` representable", + tcx.item_path_str(type_def_id))); err } @@ -423,15 +418,14 @@ pub fn report_selection_error<'a, 'tcx>(infcx: &InferCtxt<'a, 'tcx>, // these notes will often be of the form // "the type `T` can't be frobnicated" // which is somewhat confusing. - err.fileline_help(obligation.cause.span, &format!( - "consider adding a `where {}` bound", + err.help(&format!("consider adding a `where {}` bound", trait_ref.to_predicate() )); } else if let Some(s) = on_unimplemented_note(infcx, trait_ref, obligation.cause.span) { // Otherwise, if there is an on-unimplemented note, // display it. - err.fileline_note(obligation.cause.span, &s); + err.note(&s); } else { // If we can't show anything useful, try to find // similar impls. @@ -439,8 +433,7 @@ pub fn report_selection_error<'a, 'tcx>(infcx: &InferCtxt<'a, 'tcx>, let impl_candidates = find_similar_impl_candidates(infcx, trait_ref); if impl_candidates.len() > 0 { - report_similar_impl_candidates(obligation.cause.span, - &mut err, &impl_candidates); + report_similar_impl_candidates(&mut err, &impl_candidates); } } note_obligation_cause(infcx, &mut err, obligation); @@ -499,7 +492,7 @@ pub fn report_selection_error<'a, 'tcx>(infcx: &InferCtxt<'a, 'tcx>, let found_kind = infcx.closure_kind(closure_def_id).unwrap(); let closure_span = infcx.tcx.map.span_if_local(closure_def_id).unwrap(); let mut err = struct_span_err!( - infcx.tcx.sess, closure_span, E0524, + infcx.tcx.sess, closure_span, E0525, "expected a closure that implements the `{}` trait, but this closure \ only implements `{}`", kind, @@ -570,41 +563,31 @@ pub fn report_object_safety_error<'tcx>(tcx: &TyCtxt<'tcx>, } match violation { ObjectSafetyViolation::SizedSelf => { - err.fileline_note( - span, - "the trait cannot require that `Self : Sized`"); + err.note("the trait cannot require that `Self : Sized`"); } ObjectSafetyViolation::SupertraitSelf => { - err.fileline_note( - span, - "the trait cannot use `Self` as a type parameter \ - in the supertrait listing"); + err.note("the trait cannot use `Self` as a type parameter \ + in the supertrait listing"); } ObjectSafetyViolation::Method(method, MethodViolationCode::StaticMethod) => { - err.fileline_note( - span, - &format!("method `{}` has no receiver", - method.name)); + err.note(&format!("method `{}` has no receiver", + method.name)); } ObjectSafetyViolation::Method(method, MethodViolationCode::ReferencesSelf) => { - err.fileline_note( - span, - &format!("method `{}` references the `Self` type \ - in its arguments or return type", - method.name)); + err.note(&format!("method `{}` references the `Self` type \ + in its arguments or return type", + method.name)); } ObjectSafetyViolation::Method(method, MethodViolationCode::Generic) => { - err.fileline_note( - span, - &format!("method `{}` has generic type parameters", - method.name)); + err.note(&format!("method `{}` has generic type parameters", + method.name)); } } } @@ -766,14 +749,12 @@ fn note_obligation_cause<'a, 'tcx, T>(infcx: &InferCtxt<'a, 'tcx>, note_obligation_cause_code(infcx, err, &obligation.predicate, - obligation.cause.span, &obligation.cause.code); } fn note_obligation_cause_code<'a, 'tcx, T>(infcx: &InferCtxt<'a, 'tcx>, err: &mut DiagnosticBuilder, predicate: &T, - cause_span: Span, cause_code: &ObligationCauseCode<'tcx>) where T: fmt::Display { @@ -781,101 +762,71 @@ fn note_obligation_cause_code<'a, 'tcx, T>(infcx: &InferCtxt<'a, 'tcx>, match *cause_code { ObligationCauseCode::MiscObligation => { } ObligationCauseCode::SliceOrArrayElem => { - err.fileline_note( - cause_span, - "slice and array elements must have `Sized` type"); + err.note("slice and array elements must have `Sized` type"); } ObligationCauseCode::ProjectionWf(data) => { - err.fileline_note( - cause_span, - &format!("required so that the projection `{}` is well-formed", - data)); + err.note(&format!("required so that the projection `{}` is well-formed", + data)); } ObligationCauseCode::ReferenceOutlivesReferent(ref_ty) => { - err.fileline_note( - cause_span, - &format!("required so that reference `{}` does not outlive its referent", - ref_ty)); + err.note(&format!("required so that reference `{}` does not outlive its referent", + ref_ty)); } ObligationCauseCode::ItemObligation(item_def_id) => { let item_name = tcx.item_path_str(item_def_id); - err.fileline_note( - cause_span, - &format!("required by `{}`", item_name)); + err.note(&format!("required by `{}`", item_name)); } ObligationCauseCode::ObjectCastObligation(object_ty) => { - err.fileline_note( - cause_span, - &format!( - "required for the cast to the object type `{}`", - infcx.ty_to_string(object_ty))); + err.note(&format!("required for the cast to the object type `{}`", + infcx.ty_to_string(object_ty))); } ObligationCauseCode::RepeatVec => { - err.fileline_note( - cause_span, - "the `Copy` trait is required because the \ - repeated element will be copied"); + err.note("the `Copy` trait is required because the \ + repeated element will be copied"); } ObligationCauseCode::VariableType(_) => { - err.fileline_note( - cause_span, - "all local variables must have a statically known size"); + err.note("all local variables must have a statically known size"); } ObligationCauseCode::ReturnType => { - err.fileline_note( - cause_span, - "the return type of a function must have a \ - statically known size"); + err.note("the return type of a function must have a \ + statically known size"); } ObligationCauseCode::AssignmentLhsSized => { - err.fileline_note( - cause_span, - "the left-hand-side of an assignment must have a statically known size"); + err.note("the left-hand-side of an assignment must have a statically known size"); } ObligationCauseCode::StructInitializerSized => { - err.fileline_note( - cause_span, - "structs must have a statically known size to be initialized"); + err.note("structs must have a statically known size to be initialized"); } ObligationCauseCode::ClosureCapture(var_id, _, builtin_bound) => { let def_id = tcx.lang_items.from_builtin_kind(builtin_bound).unwrap(); let trait_name = tcx.item_path_str(def_id); let name = tcx.local_var_name_str(var_id); - err.fileline_note( - cause_span, + err.note( &format!("the closure that captures `{}` requires that all captured variables \ implement the trait `{}`", name, trait_name)); } ObligationCauseCode::FieldSized => { - err.fileline_note( - cause_span, - "only the last field of a struct or enum variant \ - may have a dynamically sized type"); + err.note("only the last field of a struct or enum variant \ + may have a dynamically sized type"); } ObligationCauseCode::SharedStatic => { - err.fileline_note( - cause_span, - "shared static variables must have a type that implements `Sync`"); + err.note("shared static variables must have a type that implements `Sync`"); } ObligationCauseCode::BuiltinDerivedObligation(ref data) => { let parent_trait_ref = infcx.resolve_type_vars_if_possible(&data.parent_trait_ref); - err.fileline_note( - cause_span, - &format!("required because it appears within the type `{}`", - parent_trait_ref.0.self_ty())); + err.note(&format!("required because it appears within the type `{}`", + parent_trait_ref.0.self_ty())); let parent_predicate = parent_trait_ref.to_predicate(); note_obligation_cause_code(infcx, err, &parent_predicate, - cause_span, &data.parent_code); } ObligationCauseCode::ImplDerivedObligation(ref data) => { let parent_trait_ref = infcx.resolve_type_vars_if_possible(&data.parent_trait_ref); - err.fileline_note( - cause_span, + err.note( &format!("required because of the requirements on the impl of `{}` for `{}`", parent_trait_ref, parent_trait_ref.0.self_ty())); @@ -883,12 +834,10 @@ fn note_obligation_cause_code<'a, 'tcx, T>(infcx: &InferCtxt<'a, 'tcx>, note_obligation_cause_code(infcx, err, &parent_predicate, - cause_span, &data.parent_code); } ObligationCauseCode::CompareImplMethodObligation => { - err.fileline_note( - cause_span, + err.note( &format!("the requirement `{}` appears on the impl method \ but not on the corresponding trait method", predicate)); @@ -896,12 +845,10 @@ fn note_obligation_cause_code<'a, 'tcx, T>(infcx: &InferCtxt<'a, 'tcx>, } } -fn suggest_new_overflow_limit(tcx: &TyCtxt, err:&mut DiagnosticBuilder, span: Span) { +fn suggest_new_overflow_limit(tcx: &TyCtxt, err:&mut DiagnosticBuilder) { let current_limit = tcx.sess.recursion_limit.get(); let suggested_limit = current_limit * 2; - err.fileline_note( - span, - &format!( - "consider adding a `#![recursion_limit=\"{}\"]` attribute to your crate", - suggested_limit)); + err.note(&format!( + "consider adding a `#![recursion_limit=\"{}\"]` attribute to your crate", + suggested_limit)); } diff --git a/src/librustc_borrowck/borrowck/gather_loans/move_error.rs b/src/librustc_borrowck/borrowck/gather_loans/move_error.rs index 3d94f5b186f0f..5768a441c51b7 100644 --- a/src/librustc_borrowck/borrowck/gather_loans/move_error.rs +++ b/src/librustc_borrowck/borrowck/gather_loans/move_error.rs @@ -167,8 +167,7 @@ fn note_move_destination(err: &mut DiagnosticBuilder, err.span_note( move_to_span, "attempting to move value to here"); - err.fileline_help( - move_to_span, + err.help( &format!("to prevent the move, \ use `ref {0}` or `ref mut {0}` to capture value by \ reference", diff --git a/src/librustc_borrowck/borrowck/mod.rs b/src/librustc_borrowck/borrowck/mod.rs index 87000749598a7..f65e694939bfc 100644 --- a/src/librustc_borrowck/borrowck/mod.rs +++ b/src/librustc_borrowck/borrowck/mod.rs @@ -912,8 +912,7 @@ impl<'a, 'tcx> BorrowckCtxt<'a, 'tcx> { }; if is_closure { - err.fileline_help(span, - "closures behind references must be called via `&mut`"); + err.help("closures behind references must be called via `&mut`"); } err.emit(); } diff --git a/src/librustc_const_eval/check_match.rs b/src/librustc_const_eval/check_match.rs index 5883013ac72f2..ead6ab099a88b 100644 --- a/src/librustc_const_eval/check_match.rs +++ b/src/librustc_const_eval/check_match.rs @@ -255,7 +255,7 @@ fn check_for_bindings_named_the_same_as_variants(cx: &MatchCheckCtxt, pat: &Pat) "pattern binding `{}` is named the same as one \ of the variants of the type `{}`", ident.node, ty_path); - fileline_help!(err, p.span, + help!(err, "if you meant to match on a variant, \ consider making the path in the pattern qualified: `{}::{}`", ty_path, ident.node); diff --git a/src/librustc_lint/builtin.rs b/src/librustc_lint/builtin.rs index 5e3a47701ebbf..4bdd926869a5a 100644 --- a/src/librustc_lint/builtin.rs +++ b/src/librustc_lint/builtin.rs @@ -764,8 +764,8 @@ impl LateLintPass for UnconditionalRecursion { for call in &self_call_spans { db.span_note(*call, "recursive call site"); } - db.fileline_help(sp, "a `loop` may express intention \ - better if this is on purpose"); + db.help("a `loop` may express intention \ + better if this is on purpose"); } db.emit(); } diff --git a/src/librustc_metadata/creader.rs b/src/librustc_metadata/creader.rs index 635ef4ab35836..de0de219db2f1 100644 --- a/src/librustc_metadata/creader.rs +++ b/src/librustc_metadata/creader.rs @@ -241,8 +241,8 @@ impl<'a> CrateReader<'a> { crate_rustc_version .as_ref().map(|s| &**s) .unwrap_or("an old version of rustc")); - err.fileline_help(span, "consider removing the compiled binaries and recompiling \ - with your current version of rustc"); + err.help("consider removing the compiled binaries and recompiling \ + with your current version of rustc"); err.emit(); } } diff --git a/src/librustc_metadata/loader.rs b/src/librustc_metadata/loader.rs index 28e0e5746a3ee..2316a67d9d3e3 100644 --- a/src/librustc_metadata/loader.rs +++ b/src/librustc_metadata/loader.rs @@ -346,39 +346,33 @@ impl<'a> Context<'a> { if !self.rejected_via_triple.is_empty() { let mismatches = self.rejected_via_triple.iter(); for (i, &CrateMismatch{ ref path, ref got }) in mismatches.enumerate() { - err.fileline_note(self.span, - &format!("crate `{}`, path #{}, triple {}: {}", - self.ident, i+1, got, path.display())); + err.note(&format!("crate `{}`, path #{}, triple {}: {}", + self.ident, i+1, got, path.display())); } } if !self.rejected_via_hash.is_empty() { - err.span_note(self.span, "perhaps this crate needs \ - to be recompiled?"); + err.note("perhaps this crate needs to be recompiled?"); let mismatches = self.rejected_via_hash.iter(); for (i, &CrateMismatch{ ref path, .. }) in mismatches.enumerate() { - err.fileline_note(self.span, - &format!("crate `{}` path #{}: {}", - self.ident, i+1, path.display())); + err.note(&format!("crate `{}` path #{}: {}", + self.ident, i+1, path.display())); } match self.root { &None => {} &Some(ref r) => { for (i, path) in r.paths().iter().enumerate() { - err.fileline_note(self.span, - &format!("crate `{}` path #{}: {}", - r.ident, i+1, path.display())); + err.note(&format!("crate `{}` path #{}: {}", + r.ident, i+1, path.display())); } } } } if !self.rejected_via_kind.is_empty() { - err.fileline_help(self.span, "please recompile this crate using \ - --crate-type lib"); + err.help("please recompile this crate using --crate-type lib"); let mismatches = self.rejected_via_kind.iter(); for (i, &CrateMismatch { ref path, .. }) in mismatches.enumerate() { - err.fileline_note(self.span, - &format!("crate `{}` path #{}: {}", - self.ident, i+1, path.display())); + err.note(&format!("crate `{}` path #{}: {}", + self.ident, i+1, path.display())); } } diff --git a/src/librustc_passes/consts.rs b/src/librustc_passes/consts.rs index 1f9c40856fd19..dede4d2a42a53 100644 --- a/src/librustc_passes/consts.rs +++ b/src/librustc_passes/consts.rs @@ -198,9 +198,8 @@ impl<'a, 'tcx> CheckCrateVisitor<'a, 'tcx> { let mut err = self.tcx.sess.struct_span_err( expr.span, "const fns are an unstable feature"); - fileline_help!( + help!( &mut err, - expr.span, "in Nightly builds, add `#![feature(const_fn)]` to the crate \ attributes to enable"); err.emit(); diff --git a/src/librustc_resolve/lib.rs b/src/librustc_resolve/lib.rs index b83d6e9363e9c..1bb99eb1a5e0e 100644 --- a/src/librustc_resolve/lib.rs +++ b/src/librustc_resolve/lib.rs @@ -244,7 +244,7 @@ fn resolve_struct_error<'b, 'a: 'b, 'tcx: 'a>(resolver: &'b Resolver<'a, 'tcx>, E0405, "trait `{}` is not in scope", name); - show_candidates(&mut err, span, &candidates); + show_candidates(&mut err, &candidates); err } ResolutionError::UndeclaredAssociatedType => { @@ -312,7 +312,7 @@ fn resolve_struct_error<'b, 'a: 'b, 'tcx: 'a>(resolver: &'b Resolver<'a, 'tcx>, "{} `{}` is undefined or not in scope", kind, name); - show_candidates(&mut err, span, &candidates); + show_candidates(&mut err, &candidates); err } ResolutionError::DeclarationShadowsEnumVariantOrUnitLikeStruct(name) => { @@ -420,7 +420,7 @@ fn resolve_struct_error<'b, 'a: 'b, 'tcx: 'a>(resolver: &'b Resolver<'a, 'tcx>, match context { UnresolvedNameContext::Other => { } // no help available UnresolvedNameContext::PathIsMod(parent) => { - err.fileline_help(span, &match parent.map(|parent| &parent.node) { + err.help(&match parent.map(|parent| &parent.node) { Some(&ExprField(_, ident)) => { format!("To reference an item from the `{module}` module, \ use `{module}::{ident}`", @@ -1784,8 +1784,8 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> { // If it's a typedef, give a note if let Def::TyAlias(..) = path_res.base_def { - err.fileline_note(trait_path.span, - "`type` aliases cannot be used for traits"); + err.note(trait_path.span, + "`type` aliases cannot be used for traits"); let definition_site = { let segments = &trait_path.segments; @@ -2880,7 +2880,7 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> { let msg = format!("did you mean to write: `{} {{ /* fields */ }}`?", path_name); if self.emit_errors { - err.fileline_help(expr.span, &msg); + err.help(&msg); } else { err.span_help(expr.span, &msg); } @@ -2922,7 +2922,7 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> { path_name); if self.emit_errors { - err.fileline_help(expr.span, &msg); + err.help(&msg); } else { err.span_help(expr.span, &msg); } @@ -3420,7 +3420,6 @@ fn path_names_to_string(path: &Path, depth: usize) -> String { /// entities with that name in all crates. This method allows outputting the /// results of this search in a programmer-friendly way fn show_candidates(session: &mut DiagnosticBuilder, - span: syntax::codemap::Span, candidates: &SuggestedCandidates) { let paths = &candidates.candidates; @@ -3440,26 +3439,23 @@ fn show_candidates(session: &mut DiagnosticBuilder, // behave differently based on how many candidates we have: if !paths.is_empty() { if paths.len() == 1 { - session.fileline_help( - span, + session.help( &format!("you can import it into scope: `use {};`.", &path_strings[0]), ); } else { - session.fileline_help(span, "you can import several candidates \ + session.help("you can import several candidates \ into scope (`use ...;`):"); let count = path_strings.len() as isize - MAX_CANDIDATES as isize + 1; for (idx, path_string) in path_strings.iter().enumerate() { if idx == MAX_CANDIDATES - 1 && count > 1 { - session.fileline_help( - span, + session.help( &format!(" and {} other candidates", count).to_string(), ); break; } else { - session.fileline_help( - span, + session.help( &format!(" `{}`", path_string).to_string(), ); } @@ -3468,8 +3464,7 @@ fn show_candidates(session: &mut DiagnosticBuilder, } } else { // nothing found: - session.fileline_help( - span, + session.help( &format!("no candidates by the name of `{}` found in your \ project; maybe you misspelled the name or forgot to import \ an external crate?", candidates.name.to_string()), diff --git a/src/librustc_typeck/astconv.rs b/src/librustc_typeck/astconv.rs index 1110e193e579b..ac7745985e6af 100644 --- a/src/librustc_typeck/astconv.rs +++ b/src/librustc_typeck/astconv.rs @@ -206,7 +206,6 @@ pub fn ast_region_to_region(tcx: &TyCtxt, lifetime: &hir::Lifetime) fn report_elision_failure( db: &mut DiagnosticBuilder, - default_span: Span, params: Vec) { let mut m = String::new(); @@ -243,29 +242,29 @@ fn report_elision_failure( } if len == 0 { - fileline_help!(db, default_span, - "this function's return type contains a borrowed value, but \ - there is no value for it to be borrowed from"); - fileline_help!(db, default_span, - "consider giving it a 'static lifetime"); + help!(db, + "this function's return type contains a borrowed value, but \ + there is no value for it to be borrowed from"); + help!(db, + "consider giving it a 'static lifetime"); } else if !any_lifetimes { - fileline_help!(db, default_span, - "this function's return type contains a borrowed value with \ - an elided lifetime, but the lifetime cannot be derived from \ - the arguments"); - fileline_help!(db, default_span, - "consider giving it an explicit bounded or 'static \ - lifetime"); + help!(db, + "this function's return type contains a borrowed value with \ + an elided lifetime, but the lifetime cannot be derived from \ + the arguments"); + help!(db, + "consider giving it an explicit bounded or 'static \ + lifetime"); } else if len == 1 { - fileline_help!(db, default_span, - "this function's return type contains a borrowed value, but \ - the signature does not say which {} it is borrowed from", - m); + help!(db, + "this function's return type contains a borrowed value, but \ + the signature does not say which {} it is borrowed from", + m); } else { - fileline_help!(db, default_span, - "this function's return type contains a borrowed value, but \ - the signature does not say whether it is borrowed from {}", - m); + help!(db, + "this function's return type contains a borrowed value, but \ + the signature does not say whether it is borrowed from {}", + m); } } @@ -286,7 +285,7 @@ pub fn opt_ast_region_to_region<'tcx>( let mut err = struct_span_err!(this.tcx().sess, default_span, E0106, "missing lifetime specifier"); if let Some(params) = params { - report_elision_failure(&mut err, default_span, params); + report_elision_failure(&mut err, params); } err.emit(); ty::ReStatic @@ -1087,7 +1086,7 @@ fn ast_ty_to_trait_ref<'tcx>(this: &AstConv<'tcx>, } _ => { - fileline_help!(&mut err, ty.span, + help!(&mut err, "perhaps you forgot parentheses? (per RFC 438)"); } } diff --git a/src/librustc_typeck/check/callee.rs b/src/librustc_typeck/check/callee.rs index 21800d91d9458..a96b739ebcf99 100644 --- a/src/librustc_typeck/check/callee.rs +++ b/src/librustc_typeck/check/callee.rs @@ -64,8 +64,8 @@ pub fn check_legal_trait_for_method_call(ccx: &CrateCtxt, span: Span, trait_id: struct_span_err!(tcx.sess, span, E0174, "explicit use of unboxed closure method `{}` is experimental", method) - .fileline_help(span, "add `#![feature(unboxed_closures)]` to the crate \ - attributes to enable") + .help("add `#![feature(unboxed_closures)]` to the crate \ + attributes to enable") .emit(); } } diff --git a/src/librustc_typeck/check/cast.rs b/src/librustc_typeck/check/cast.rs index 922c411ce8cd8..249ab27ec5956 100644 --- a/src/librustc_typeck/check/cast.rs +++ b/src/librustc_typeck/check/cast.rs @@ -155,8 +155,7 @@ impl<'tcx> CastCheck<'tcx> { actual, fcx.infcx().ty_to_string(self.cast_ty)) }, self.expr_ty, None) - .fileline_help(self.span, - &format!("cast through {} first", match e { + .help(&format!("cast through {} first", match e { CastError::NeedViaPtr => "a raw pointer", CastError::NeedViaThinPtr => "a thin pointer", CastError::NeedViaInt => "an integer", @@ -167,7 +166,7 @@ impl<'tcx> CastCheck<'tcx> { } CastError::CastToBool => { struct_span_err!(fcx.tcx().sess, self.span, E0054, "cannot cast as `bool`") - .fileline_help(self.span, "compare with zero instead") + .help("compare with zero instead") .emit(); } CastError::CastToChar => { @@ -202,7 +201,7 @@ impl<'tcx> CastCheck<'tcx> { actual, fcx.infcx().ty_to_string(self.cast_ty)) }, self.expr_ty, None) - .fileline_note(self.span, "vtable kinds may not match") + .note("vtable kinds may not match") .emit(); } } diff --git a/src/librustc_typeck/check/method/suggest.rs b/src/librustc_typeck/check/method/suggest.rs index c5195cf8787da..b541ca151c856 100644 --- a/src/librustc_typeck/check/method/suggest.rs +++ b/src/librustc_typeck/check/method/suggest.rs @@ -148,9 +148,7 @@ pub fn report_error<'a, 'tcx>(fcx: &FnCtxt<'a, 'tcx>, if is_fn_ty(&rcvr_ty, &fcx, span) { macro_rules! report_function { ($span:expr, $name:expr) => { - err.fileline_note( - $span, - &format!("{} is a function, perhaps you wish to call it", + err.note(&format!("{} is a function, perhaps you wish to call it", $name)); } } @@ -172,8 +170,7 @@ pub fn report_error<'a, 'tcx>(fcx: &FnCtxt<'a, 'tcx>, } if !static_sources.is_empty() { - err.fileline_note( - span, + err.note( "found the following associated functions; to be used as \ methods, functions must have a `self` parameter"); @@ -187,8 +184,7 @@ pub fn report_error<'a, 'tcx>(fcx: &FnCtxt<'a, 'tcx>, p)) .collect::>() .join(", "); - err.fileline_note( - span, + err.note( &format!("the method `{}` exists but the \ following trait bounds were not satisfied: {}", item_name, @@ -306,13 +302,12 @@ fn suggest_traits_to_import<'a, 'tcx>(fcx: &FnCtxt<'a, 'tcx>, traits_are = if candidates.len() == 1 {"trait is"} else {"traits are"}, one_of_them = if candidates.len() == 1 {"it"} else {"one of them"}); - err.fileline_help(span, &msg[..]); + err.help(&msg[..]); for (i, trait_did) in candidates.iter().enumerate() { - err.fileline_help(span, - &format!("candidate #{}: `use {}`", - i + 1, - fcx.tcx().item_path_str(*trait_did))); + err.help(&format!("candidate #{}: `use {}`", + i + 1, + fcx.tcx().item_path_str(*trait_did))); } return } @@ -351,13 +346,12 @@ fn suggest_traits_to_import<'a, 'tcx>(fcx: &FnCtxt<'a, 'tcx>, one_of_them = if candidates.len() == 1 {"it"} else {"one of them"}, name = item_name); - err.fileline_help(span, &msg[..]); + err.help(&msg[..]); for (i, trait_info) in candidates.iter().enumerate() { - err.fileline_help(span, - &format!("candidate #{}: `{}`", - i + 1, - fcx.tcx().item_path_str(trait_info.def_id))); + err.help(&format!("candidate #{}: `{}`", + i + 1, + fcx.tcx().item_path_str(trait_info.def_id))); } } } diff --git a/src/librustc_typeck/check/mod.rs b/src/librustc_typeck/check/mod.rs index 2d0505d9347d5..385f04b8564f5 100644 --- a/src/librustc_typeck/check/mod.rs +++ b/src/librustc_typeck/check/mod.rs @@ -2955,9 +2955,9 @@ fn check_expr_with_expectation_and_lvalue_pref<'a, 'tcx>(fcx: &FnCtxt<'a, 'tcx>, `{}`", field.node, actual) }, expr_t, None) - .fileline_help(field.span, - "maybe a `()` to call it is missing? \ - If not, try an anonymous function") + .help( + "maybe a `()` to call it is missing? \ + If not, try an anonymous function") .emit(); fcx.write_error(expr.id); } else { diff --git a/src/librustc_typeck/check/wfcheck.rs b/src/librustc_typeck/check/wfcheck.rs index 492dbce9bdf45..25a37b6810e44 100644 --- a/src/librustc_typeck/check/wfcheck.rs +++ b/src/librustc_typeck/check/wfcheck.rs @@ -501,8 +501,7 @@ impl<'ccx, 'tcx> CheckTypeWellFormedVisitor<'ccx, 'tcx> { let suggested_marker_id = self.tcx().lang_items.phantom_data(); match suggested_marker_id { Some(def_id) => { - err.fileline_help( - span, + err.help( &format!("consider removing `{}` or using a marker such as `{}`", param_name, self.tcx().item_path_str(def_id))); diff --git a/src/librustc_typeck/coherence/mod.rs b/src/librustc_typeck/coherence/mod.rs index 859fbd974fedc..bfb371be663b5 100644 --- a/src/librustc_typeck/coherence/mod.rs +++ b/src/librustc_typeck/coherence/mod.rs @@ -510,8 +510,7 @@ fn enforce_trait_manually_implementable(tcx: &TyCtxt, sp: Span, trait_def_id: De E0183, "manual implementations of `{}` are experimental", trait_name); - fileline_help!(&mut err, sp, - "add `#![feature(unboxed_closures)]` to the crate attributes to enable"); + help!(&mut err, "add `#![feature(unboxed_closures)]` to the crate attributes to enable"); err.emit(); } diff --git a/src/librustc_typeck/collect.rs b/src/librustc_typeck/collect.rs index 51534a46ddac3..c10488a03ef68 100644 --- a/src/librustc_typeck/collect.rs +++ b/src/librustc_typeck/collect.rs @@ -1258,9 +1258,9 @@ fn trait_def_of_item<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>, it.span, "the `#[rustc_paren_sugar]` attribute is a temporary means of controlling \ which traits can use parenthetical notation"); - fileline_help!(&mut err, it.span, - "add `#![feature(unboxed_closures)]` to \ - the crate attributes to use it"); + help!(&mut err, + "add `#![feature(unboxed_closures)]` to \ + the crate attributes to use it"); err.emit(); } @@ -2196,8 +2196,7 @@ fn compute_type_scheme_of_foreign_fn_decl<'a, 'tcx>( &format!("use of SIMD type `{}` in FFI is highly experimental and \ may result in invalid code", pprust::ty_to_string(ast_ty))) - .fileline_help(ast_ty.span, - "add #![feature(simd_ffi)] to the crate attributes to enable") + .help("add #![feature(simd_ffi)] to the crate attributes to enable") .emit(); } }; diff --git a/src/libsyntax/diagnostics/macros.rs b/src/libsyntax/diagnostics/macros.rs index 95a74d875545f..25e0428248df4 100644 --- a/src/libsyntax/diagnostics/macros.rs +++ b/src/libsyntax/diagnostics/macros.rs @@ -101,9 +101,9 @@ macro_rules! span_help { } #[macro_export] -macro_rules! fileline_help { - ($err:expr, $span:expr, $($message:tt)*) => ({ - ($err).fileline_help($span, &format!($($message)*)); +macro_rules! help { + ($err:expr, $($message:tt)*) => ({ + ($err).help(&format!($($message)*)); }) } diff --git a/src/libsyntax/ext/base.rs b/src/libsyntax/ext/base.rs index c0306b8494be2..303187aeba87d 100644 --- a/src/libsyntax/ext/base.rs +++ b/src/libsyntax/ext/base.rs @@ -764,15 +764,14 @@ impl<'a> ExtCtxt<'a> { pub fn suggest_macro_name(&mut self, name: &str, - span: Span, err: &mut DiagnosticBuilder<'a>) { let names = &self.syntax_env.names; if let Some(suggestion) = find_best_match_for_name(names.iter(), name, None) { if suggestion != name { - err.fileline_help(span, &format!("did you mean `{}!`?", suggestion)); + err.help(&format!("did you mean `{}!`?", suggestion)); } else { - err.fileline_help(span, &format!("have you added the `#[macro_use]` on the \ - module/import?")); + err.help(&format!("have you added the `#[macro_use]` on the \ + module/import?")); } } } diff --git a/src/libsyntax/feature_gate.rs b/src/libsyntax/feature_gate.rs index ed2371fc34823..e269475d1e2c5 100644 --- a/src/libsyntax/feature_gate.rs +++ b/src/libsyntax/feature_gate.rs @@ -770,9 +770,9 @@ pub fn emit_feature_err(diag: &Handler, feature: &str, span: Span, issue: GateIs err.emit(); return; } - err.fileline_help(span, &format!("add #![feature({})] to the \ - crate attributes to enable", - feature)); + err.help(&format!("add #![feature({})] to the \ + crate attributes to enable", + feature)); err.emit(); } diff --git a/src/libsyntax/parse/attr.rs b/src/libsyntax/parse/attr.rs index b8e320e36e9b4..3aac12d76ffdf 100644 --- a/src/libsyntax/parse/attr.rs +++ b/src/libsyntax/parse/attr.rs @@ -69,9 +69,8 @@ impl<'a> Parser<'a> { self.diagnostic() .struct_span_err(span, "an inner attribute is not permitted in this context") - .fileline_help(span, - "place inner attribute at the top of the module or \ - block") + .help("place inner attribute at the top of the module or \ + block") .emit() } ast::AttrStyle::Inner diff --git a/src/libsyntax/parse/mod.rs b/src/libsyntax/parse/mod.rs index c2050d2a8f48b..2a9bcfd658c18 100644 --- a/src/libsyntax/parse/mod.rs +++ b/src/libsyntax/parse/mod.rs @@ -445,11 +445,11 @@ fn filtered_float_lit(data: token::InternedString, suffix: Option<&str>, if suf.len() >= 2 && looks_like_width_suffix(&['f'], suf) { // if it looks like a width, lets try to be helpful. sd.struct_span_err(sp, &format!("invalid width `{}` for float literal", &suf[1..])) - .fileline_help(sp, "valid widths are 32 and 64") + .help("valid widths are 32 and 64") .emit(); } else { sd.struct_span_err(sp, &format!("invalid suffix `{}` for float literal", suf)) - .fileline_help(sp, "valid suffixes are `f32` and `f64`") + .help("valid suffixes are `f32` and `f64`") .emit(); } @@ -621,12 +621,12 @@ pub fn integer_lit(s: &str, if looks_like_width_suffix(&['i', 'u'], suf) { sd.struct_span_err(sp, &format!("invalid width `{}` for integer literal", &suf[1..])) - .fileline_help(sp, "valid widths are 8, 16, 32 and 64") + .help("valid widths are 8, 16, 32 and 64") .emit(); } else { sd.struct_span_err(sp, &format!("invalid suffix `{}` for numeric literal", suf)) - .fileline_help(sp, "the suffix must be one of the integral types \ - (`u32`, `isize`, etc)") + .help("the suffix must be one of the integral types \ + (`u32`, `isize`, etc)") .emit(); } diff --git a/src/libsyntax/parse/parser.rs b/src/libsyntax/parse/parser.rs index 671a11b57dec1..b9188f5101d3f 100644 --- a/src/libsyntax/parse/parser.rs +++ b/src/libsyntax/parse/parser.rs @@ -583,7 +583,7 @@ impl<'a> Parser<'a> { let mut err = self.fatal(&format!("expected identifier, found `{}`", self.this_token_to_string())); if self.token == token::Underscore { - err.fileline_note(self.span, "`_` is a wildcard pattern, not an identifier"); + err.note("`_` is a wildcard pattern, not an identifier"); } Err(err) } @@ -1082,7 +1082,7 @@ impl<'a> Parser<'a> { } pub fn span_fatal_help(&self, sp: Span, m: &str, help: &str) -> DiagnosticBuilder<'a> { let mut err = self.sess.span_diagnostic.struct_span_fatal(sp, m); - err.fileline_help(sp, help); + err.help(help); err } pub fn bug(&self, m: &str) -> ! { @@ -2622,10 +2622,9 @@ impl<'a> Parser<'a> { Some(f) => f, None => continue, }; - err.fileline_help(last_span, - &format!("try parenthesizing the first index; e.g., `(foo.{}){}`", - float.trunc() as usize, - format!(".{}", fstr.splitn(2, ".").last().unwrap()))); + err.help(&format!("try parenthesizing the first index; e.g., `(foo.{}){}`", + float.trunc() as usize, + format!(".{}", fstr.splitn(2, ".").last().unwrap()))); } return Err(err); @@ -3134,7 +3133,7 @@ impl<'a> Parser<'a> { let mut err = self.diagnostic().struct_span_err(op_span, "chained comparison operators require parentheses"); if op.node == BinOpKind::Lt && *outer_op == AssocOp::Greater { - err.fileline_help(op_span, + err.help( "use `::<...>` instead of `<...>` if you meant to specify type arguments"); } err.emit(); @@ -4951,13 +4950,13 @@ impl<'a> Parser<'a> { if is_macro_rules { self.diagnostic().struct_span_err(span, "can't qualify macro_rules \ invocation with `pub`") - .fileline_help(span, "did you mean #[macro_export]?") + .help("did you mean #[macro_export]?") .emit(); } else { self.diagnostic().struct_span_err(span, "can't qualify macro \ invocation with `pub`") - .fileline_help(span, "try adjusting the macro to put `pub` \ - inside the invocation") + .help("try adjusting the macro to put `pub` \ + inside the invocation") .emit(); } } @@ -5857,7 +5856,7 @@ impl<'a> Parser<'a> { if self.eat_keyword(keywords::Mut) { let last_span = self.last_span; self.diagnostic().struct_span_err(last_span, "const globals cannot be mutable") - .fileline_help(last_span, "did you mean to declare a static?") + .help("did you mean to declare a static?") .emit(); } let (ident, item_, extra_attrs) = self.parse_item_const(None)?; From 41a652e0948d6cbcffa89a219b37a1e39ae619d4 Mon Sep 17 00:00:00 2001 From: Niko Matsakis Date: Wed, 20 Apr 2016 15:52:52 -0400 Subject: [PATCH 09/40] WIP factor out RudimentaryEmitter --- src/librustc_trans/back/write.rs | 21 +++++--------- src/libsyntax/errors/emitter.rs | 47 +++++++++++++++++++++----------- 2 files changed, 38 insertions(+), 30 deletions(-) diff --git a/src/librustc_trans/back/write.rs b/src/librustc_trans/back/write.rs index 50fd039276253..ffd8c261b6055 100644 --- a/src/librustc_trans/back/write.rs +++ b/src/librustc_trans/back/write.rs @@ -19,9 +19,9 @@ use llvm::SMDiagnosticRef; use {CrateTranslation, ModuleTranslation}; use util::common::time; use util::common::path2cstr; -use syntax::codemap::{self, MultiSpan}; +use syntax::codemap::MultiSpan; use syntax::errors::{self, Handler, Level}; -use syntax::errors::emitter::Emitter; +use syntax::errors::emitter::RudimentaryEmitter; use std::collections::HashMap; use std::ffi::{CStr, CString}; @@ -100,24 +100,17 @@ impl SharedEmitter { } } -impl Emitter for SharedEmitter { - fn emit(&mut self, - sp: &codemap::MultiSpan, - msg: &str, - code: Option<&str>, - lvl: Level) { - assert!(sp.primary_span().is_none(), "SharedEmitter doesn't support spans"); - +impl RudimentaryEmitter for SharedEmitter { + fn emit_rudimentary(&mut self, + msg: &str, + code: Option<&str>, + lvl: Level) { self.buffer.lock().unwrap().push(Diagnostic { msg: msg.to_string(), code: code.map(|s| s.to_string()), lvl: lvl, }); } - - fn emit_struct(&mut self, _db: &errors::DiagnosticBuilder) { - bug!("SharedEmitter doesn't support emit_struct"); - } } diff --git a/src/libsyntax/errors/emitter.rs b/src/libsyntax/errors/emitter.rs index e963a5f794cb6..f851937d82bc0 100644 --- a/src/libsyntax/errors/emitter.rs +++ b/src/libsyntax/errors/emitter.rs @@ -25,12 +25,38 @@ use std::rc::Rc; use term; pub trait Emitter { + /// Emit a standalone diagnostic message. fn emit(&mut self, span: &MultiSpan, msg: &str, code: Option<&str>, lvl: Level); /// Emit a structured diagnostic. fn emit_struct(&mut self, db: &DiagnosticBuilder); } +/// A core trait that can only handle very simple messages: those +/// without spans or any real structure. Used only in specific contexts. +pub trait RudimentaryEmitter { + fn emit_rudimentary(&mut self, msg: &str, code: Option<&str>, lvl: Level); +} + +impl Emitter for T { + fn emit(&mut self, + msp: &MultiSpan, + msg: &str, + code: Option<&str>, + lvl: Level) { + assert!(msp.primary_span().is_none(), "Rudimenatry emitters can't handle spans"); + self.emit_rudimentary(msg, code, lvl); + } + + fn emit_struct(&mut self, db: &DiagnosticBuilder) { + self.emit(&db.span, &db.message, db.code.as_ref().map(|s| &**s), db.level); + for child in &db.children { + assert!(child.render_span.is_none(), "Rudimentary emitters can't handle render spans"); + self.emit(&child.span, &child.message, None, child.level); + } + } +} + /// maximum number of lines we will print for each error; arbitrary. pub const MAX_HIGHLIGHT_LINES: usize = 6; @@ -57,26 +83,15 @@ pub struct BasicEmitter { dst: Destination, } -impl Emitter for BasicEmitter { - fn emit(&mut self, - msp: &MultiSpan, - msg: &str, - code: Option<&str>, - lvl: Level) { - assert!(msp.primary_span().is_none(), "BasicEmitter can't handle spans"); - +impl RudimentaryEmitter for BasicEmitter { + fn emit_rudimentary(&mut self, + msg: &str, + code: Option<&str>, + lvl: Level) { if let Err(e) = print_diagnostic(&mut self.dst, "", lvl, msg, code) { panic!("failed to print diagnostics: {:?}", e); } } - - fn emit_struct(&mut self, db: &DiagnosticBuilder) { - self.emit(&db.span, &db.message, db.code.as_ref().map(|s| &**s), db.level); - for child in &db.children { - assert!(child.render_span.is_none(), "BasicEmitter can't handle spans"); - self.emit(&child.span, &child.message, None, child.level); - } - } } impl BasicEmitter { From 71c6f813098a4e51344b7968022bbd946bad37be Mon Sep 17 00:00:00 2001 From: Niko Matsakis Date: Wed, 20 Apr 2016 16:08:51 -0400 Subject: [PATCH 10/40] change errors from Yellow to Magenta The Yellow text is very hard to read with a white background. --- src/libsyntax/errors/mod.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/libsyntax/errors/mod.rs b/src/libsyntax/errors/mod.rs index abbc4eef7bf81..0de2e067802e2 100644 --- a/src/libsyntax/errors/mod.rs +++ b/src/libsyntax/errors/mod.rs @@ -661,7 +661,7 @@ impl Level { fn color(self) -> term::color::Color { match self { Bug | Fatal | PhaseFatal | Error => term::color::BRIGHT_RED, - Warning => term::color::BRIGHT_YELLOW, + Warning => term::color::BRIGHT_MAGENTA, Note => term::color::BRIGHT_GREEN, Help => term::color::BRIGHT_CYAN, Cancelled => unreachable!(), From 47143945cc3bc8ec67f67609df13ccd4bb1a3bf5 Mon Sep 17 00:00:00 2001 From: Niko Matsakis Date: Wed, 20 Apr 2016 17:35:32 -0400 Subject: [PATCH 11/40] delete the json-errors test It's primary purpose was to check that json worked at all, but compiletest does that now. --- src/test/run-make/json-errors/Makefile | 9 --------- src/test/run-make/json-errors/foo.json | 4 ---- src/test/run-make/json-errors/foo.rs | 15 --------------- 3 files changed, 28 deletions(-) delete mode 100644 src/test/run-make/json-errors/Makefile delete mode 100644 src/test/run-make/json-errors/foo.json delete mode 100644 src/test/run-make/json-errors/foo.rs diff --git a/src/test/run-make/json-errors/Makefile b/src/test/run-make/json-errors/Makefile deleted file mode 100644 index 30bcafd104945..0000000000000 --- a/src/test/run-make/json-errors/Makefile +++ /dev/null @@ -1,9 +0,0 @@ --include ../tools.mk - -LOG := $(TMPDIR)/foo.log - -all: - cp foo.rs $(TMPDIR) - cd $(TMPDIR) - -$(RUSTC) -Z unstable-options --error-format=json foo.rs 2>$(LOG) - diff foo.json $(LOG) diff --git a/src/test/run-make/json-errors/foo.json b/src/test/run-make/json-errors/foo.json deleted file mode 100644 index bde669ab0f7f9..0000000000000 --- a/src/test/run-make/json-errors/foo.json +++ /dev/null @@ -1,4 +0,0 @@ -{"message":"unresolved name `y`","code":{"code":"E0425","explanation":"\nAn unresolved name was used. Example of erroneous codes:\n\n```compile_fail\nsomething_that_doesnt_exist::foo;\n// error: unresolved name `something_that_doesnt_exist::foo`\n\n// or:\n\ntrait Foo {\n fn bar() {\n Self; // error: unresolved name `Self`\n }\n}\n\n// or:\n\nlet x = unknown_variable; // error: unresolved name `unknown_variable`\n```\n\nPlease verify that the name wasn't misspelled and ensure that the\nidentifier being referred to is valid for the given situation. Example:\n\n```\nenum something_that_does_exist {\n Foo,\n}\n```\n\nOr:\n\n```\nmod something_that_does_exist {\n pub static foo : i32 = 0i32;\n}\n\nsomething_that_does_exist::foo; // ok!\n```\n\nOr:\n\n```\nlet unknown_variable = 12u32;\nlet x = unknown_variable; // ok!\n```\n"},"level":"error","spans":[{"file_name":"foo.rs","byte_start":496,"byte_end":497,"line_start":12,"line_end":12,"column_start":18,"column_end":19,"text":[{"text":" let x = 42 + y;","highlight_start":18,"highlight_end":19}],"suggested_replacement":null,"expansion":null}],"children":[],"rendered":null} -{"message":"mismatched types:\n expected `u8`,\n found `i32`","code":{"code":"E0308","explanation":"\nThis error occurs when the compiler was unable to infer the concrete type of a\nvariable. It can occur for several cases, the most common of which is a\nmismatch in the expected type that the compiler inferred for a variable's\ninitializing expression, and the actual type explicitly assigned to the\nvariable.\n\nFor example:\n\n```compile_fail\nlet x: i32 = \"I am not a number!\";\n// ~~~ ~~~~~~~~~~~~~~~~~~~~\n// | |\n// | initializing expression;\n// | compiler infers type `&str`\n// |\n// type `i32` assigned to variable `x`\n```\n\nAnother situation in which this occurs is when you attempt to use the `try!`\nmacro inside a function that does not return a `Result`:\n\n```compile_fail\nuse std::fs::File;\n\nfn main() {\n let mut f = try!(File::create(\"foo.txt\"));\n}\n```\n\nThis code gives an error like this:\n\n```text\n:5:8: 6:42 error: mismatched types:\n expected `()`,\n found `core::result::Result<_, _>`\n (expected (),\n found enum `core::result::Result`) [E0308]\n```\n\n`try!` returns a `Result`, and so the function must. But `main()` has\n`()` as its return type, hence the error.\n"},"level":"error","spans":[{"file_name":"foo.rs","byte_start":511,"byte_end":516,"line_start":14,"line_end":14,"column_start":12,"column_end":17,"text":[{"text":" 42u8 + 42i32;","highlight_start":12,"highlight_end":17}],"suggested_replacement":null,"expansion":null}],"children":[],"rendered":null} -{"message":"the trait bound `u8: std::ops::Add` is not satisfied","code":{"code":"E0277","explanation":"\nYou tried to use a type which doesn't implement some trait in a place which\nexpected that trait. Erroneous code example:\n\n```compile_fail\n// here we declare the Foo trait with a bar method\ntrait Foo {\n fn bar(&self);\n}\n\n// we now declare a function which takes an object implementing the Foo trait\nfn some_func(foo: T) {\n foo.bar();\n}\n\nfn main() {\n // we now call the method with the i32 type, which doesn't implement\n // the Foo trait\n some_func(5i32); // error: the trait bound `i32 : Foo` is not satisfied\n}\n```\n\nIn order to fix this error, verify that the type you're using does implement\nthe trait. Example:\n\n```\ntrait Foo {\n fn bar(&self);\n}\n\nfn some_func(foo: T) {\n foo.bar(); // we can now use this method since i32 implements the\n // Foo trait\n}\n\n// we implement the trait on the i32 type\nimpl Foo for i32 {\n fn bar(&self) {}\n}\n\nfn main() {\n some_func(5i32); // ok!\n}\n```\n\nOr in a generic context, an erroneous code example would look like:\n```compile_fail\nfn some_func(foo: T) {\n println!(\"{:?}\", foo); // error: the trait `core::fmt::Debug` is not\n // implemented for the type `T`\n}\n\nfn main() {\n // We now call the method with the i32 type,\n // which *does* implement the Debug trait.\n some_func(5i32);\n}\n```\n\nNote that the error here is in the definition of the generic function: Although\nwe only call it with a parameter that does implement `Debug`, the compiler\nstill rejects the function: It must work with all possible input types. In\norder to make this example compile, we need to restrict the generic type we're\naccepting:\n```\nuse std::fmt;\n\n// Restrict the input type to types that implement Debug.\nfn some_func(foo: T) {\n println!(\"{:?}\", foo);\n}\n\nfn main() {\n // Calling the method is still fine, as i32 implements Debug.\n some_func(5i32);\n\n // This would fail to compile now:\n // struct WithoutDebug;\n // some_func(WithoutDebug);\n}\n\nRust only looks at the signature of the called function, as such it must\nalready specify all requirements that will be used for every type parameter.\n```\n\n"},"level":"error","spans":[{"file_name":"foo.rs","byte_start":504,"byte_end":516,"line_start":14,"line_end":14,"column_start":5,"column_end":17,"text":[{"text":" 42u8 + 42i32;","highlight_start":5,"highlight_end":17}],"suggested_replacement":null,"expansion":null}],"children":[{"message":"the following implementations were found:","code":null,"level":"help","spans":[{"file_name":"foo.rs","byte_start":504,"byte_end":516,"line_start":14,"line_end":14,"column_start":5,"column_end":17,"text":[{"text":" 42u8 + 42i32;","highlight_start":5,"highlight_end":17}],"suggested_replacement":null,"expansion":null}],"children":[],"rendered":null},{"message":" ","code":null,"level":"help","spans":[{"file_name":"foo.rs","byte_start":504,"byte_end":516,"line_start":14,"line_end":14,"column_start":5,"column_end":17,"text":[{"text":" 42u8 + 42i32;","highlight_start":5,"highlight_end":17}],"suggested_replacement":null,"expansion":null}],"children":[],"rendered":null},{"message":" <&'a u8 as std::ops::Add>","code":null,"level":"help","spans":[{"file_name":"foo.rs","byte_start":504,"byte_end":516,"line_start":14,"line_end":14,"column_start":5,"column_end":17,"text":[{"text":" 42u8 + 42i32;","highlight_start":5,"highlight_end":17}],"suggested_replacement":null,"expansion":null}],"children":[],"rendered":null},{"message":" >","code":null,"level":"help","spans":[{"file_name":"foo.rs","byte_start":504,"byte_end":516,"line_start":14,"line_end":14,"column_start":5,"column_end":17,"text":[{"text":" 42u8 + 42i32;","highlight_start":5,"highlight_end":17}],"suggested_replacement":null,"expansion":null}],"children":[],"rendered":null},{"message":" <&'b u8 as std::ops::Add<&'a u8>>","code":null,"level":"help","spans":[{"file_name":"foo.rs","byte_start":504,"byte_end":516,"line_start":14,"line_end":14,"column_start":5,"column_end":17,"text":[{"text":" 42u8 + 42i32;","highlight_start":5,"highlight_end":17}],"suggested_replacement":null,"expansion":null}],"children":[],"rendered":null}],"rendered":null} -{"message":"aborting due to 2 previous errors","code":null,"level":"error","spans":[],"children":[],"rendered":null} diff --git a/src/test/run-make/json-errors/foo.rs b/src/test/run-make/json-errors/foo.rs deleted file mode 100644 index 4db33940d8843..0000000000000 --- a/src/test/run-make/json-errors/foo.rs +++ /dev/null @@ -1,15 +0,0 @@ -// Copyright 2015 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 or the MIT license -// , at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - -fn main() { - let x = 42 + y; - - 42u8 + 42i32; -} From 9d022f299359c341d2f57ab5425855556fc83937 Mon Sep 17 00:00:00 2001 From: Niko Matsakis Date: Wed, 20 Apr 2016 17:47:42 -0400 Subject: [PATCH 12/40] rewrite span-length to include strings It is way easier to copy-and-paste strings from the output than to figure out how to reproduce them from first principles. --- .../run-make/unicode-input/span_length.rs | 32 ++++++++++--------- 1 file changed, 17 insertions(+), 15 deletions(-) diff --git a/src/test/run-make/unicode-input/span_length.rs b/src/test/run-make/unicode-input/span_length.rs index 3963d20df8873..f3bfe083016e7 100644 --- a/src/test/run-make/unicode-input/span_length.rs +++ b/src/test/run-make/unicode-input/span_length.rs @@ -65,8 +65,8 @@ fn main() { let err = String::from_utf8_lossy(&result.stderr); - // the span should end the line (e.g no extra ~'s) - let expected_span = format!("^{}\n", repeat("~").take(n - 1) + // the span should end the line (e.g no extra ^'s) + let expected_span = format!("^{}\n", repeat("^").take(n - 1) .collect::()); assert!(err.contains(&expected_span)); } @@ -91,17 +91,19 @@ fn main() { // Test both the length of the snake and the leading spaces up to it - // First snake is 8 ~s long, with 7 preceding spaces (excluding file name/line offset) - let expected_span = format!("\n{}^{}\n", - repeat(" ").take(offset + 7).collect::(), - repeat("~").take(8).collect::()); - assert!(err.contains(&expected_span)); - // Second snake is only 7 ~s long, with 36 preceding spaces, - // because rustc counts chars() now rather than width(). This - // is because width() functions are to be removed from - // librustc_unicode - let expected_span = format!("\n{}^{}\n", - repeat(" ").take(offset + 36).collect::(), - repeat("~").take(7).collect::()); - assert!(err.contains(&expected_span)); + // First snake is 9 ^s long. + let expected_1 = r#" +1 |> extern "路濫狼á́́" fn foo() {} extern "路濫狼á́" fn bar() {} + |> ^^^^^^^^^ +"#; + assert!(err.contains(&expected_1)); + + // Second snake is only 8 ^s long, because rustc counts chars() + // now rather than width(). This is because width() functions are + // to be removed from librustc_unicode + let expected_2 = r#" +1 |> extern "路濫狼á́́" fn foo() {} extern "路濫狼á́" fn bar() {} + |> ^^^^^^^^ +"#; + assert!(err.contains(&expected_2)); } From 1067850e6a8664eaabd59c3893aa5a762bdf2339 Mon Sep 17 00:00:00 2001 From: Niko Matsakis Date: Wed, 20 Apr 2016 20:00:25 -0400 Subject: [PATCH 13/40] refactor the Emitter trait There is now a CoreEmitter that everything desugars to, but without losing any information. Also remove RenderSpan::FileLine. This lets the rustc_driver tests build. --- src/librustc_driver/test.rs | 17 ++-- src/librustc_trans/back/write.rs | 16 +-- src/libsyntax/errors/emitter.rs | 163 ++++++++++++++----------------- src/libsyntax/errors/json.rs | 2 - src/libsyntax/errors/mod.rs | 7 +- 5 files changed, 92 insertions(+), 113 deletions(-) diff --git a/src/librustc_driver/test.rs b/src/librustc_driver/test.rs index 60f4ab1c95f2b..f2448d50b22bc 100644 --- a/src/librustc_driver/test.rs +++ b/src/librustc_driver/test.rs @@ -34,9 +34,9 @@ use std::cell::RefCell; use std::rc::Rc; use syntax::ast; use syntax::abi::Abi; -use syntax::codemap::{MultiSpan, CodeMap, DUMMY_SP}; +use syntax::codemap::{CodeMap, DUMMY_SP}; use syntax::errors; -use syntax::errors::emitter::Emitter; +use syntax::errors::emitter::{CoreEmitter, Emitter}; use syntax::errors::{Level, RenderSpan}; use syntax::parse::token; use syntax::feature_gate::UnstableFeatures; @@ -78,12 +78,13 @@ fn remove_message(e: &mut ExpectErrorEmitter, msg: &str, lvl: Level) { } } -impl Emitter for ExpectErrorEmitter { - fn emit(&mut self, - _sp: Option<&MultiSpan>, - msg: &str, - _: Option<&str>, - lvl: Level) { +impl CoreEmitter for ExpectErrorEmitter { + fn emit_message(&mut self, + _sp: &RenderSpan, + msg: &str, + _: Option<&str>, + lvl: Level, + _is_header: bool) { remove_message(self, msg, lvl); } } diff --git a/src/librustc_trans/back/write.rs b/src/librustc_trans/back/write.rs index ffd8c261b6055..a35048f89c114 100644 --- a/src/librustc_trans/back/write.rs +++ b/src/librustc_trans/back/write.rs @@ -20,8 +20,8 @@ use {CrateTranslation, ModuleTranslation}; use util::common::time; use util::common::path2cstr; use syntax::codemap::MultiSpan; -use syntax::errors::{self, Handler, Level}; -use syntax::errors::emitter::RudimentaryEmitter; +use syntax::errors::{self, Handler, Level, RenderSpan}; +use syntax::errors::emitter::CoreEmitter; use std::collections::HashMap; use std::ffi::{CStr, CString}; @@ -100,11 +100,13 @@ impl SharedEmitter { } } -impl RudimentaryEmitter for SharedEmitter { - fn emit_rudimentary(&mut self, - msg: &str, - code: Option<&str>, - lvl: Level) { +impl CoreEmitter for SharedEmitter { + fn emit_message(&mut self, + _rsp: &RenderSpan, + msg: &str, + code: Option<&str>, + lvl: Level, + _is_header: bool) { self.buffer.lock().unwrap().push(Diagnostic { msg: msg.to_string(), code: code.map(|s| s.to_string()), diff --git a/src/libsyntax/errors/emitter.rs b/src/libsyntax/errors/emitter.rs index f851937d82bc0..2b29de7fd7135 100644 --- a/src/libsyntax/errors/emitter.rs +++ b/src/libsyntax/errors/emitter.rs @@ -24,6 +24,8 @@ use std::io; use std::rc::Rc; use term; +/// Emitter trait for emitting errors. Do not implement this directly: +/// implement `CoreEmitter` instead. pub trait Emitter { /// Emit a standalone diagnostic message. fn emit(&mut self, span: &MultiSpan, msg: &str, code: Option<&str>, lvl: Level); @@ -32,27 +34,44 @@ pub trait Emitter { fn emit_struct(&mut self, db: &DiagnosticBuilder); } -/// A core trait that can only handle very simple messages: those -/// without spans or any real structure. Used only in specific contexts. -pub trait RudimentaryEmitter { - fn emit_rudimentary(&mut self, msg: &str, code: Option<&str>, lvl: Level); +pub trait CoreEmitter { + fn emit_message(&mut self, + rsp: &RenderSpan, + msg: &str, + code: Option<&str>, + lvl: Level, + is_header: bool); } -impl Emitter for T { +impl Emitter for T { fn emit(&mut self, msp: &MultiSpan, msg: &str, code: Option<&str>, lvl: Level) { - assert!(msp.primary_span().is_none(), "Rudimenatry emitters can't handle spans"); - self.emit_rudimentary(msg, code, lvl); + self.emit_message(&FullSpan(msp.clone()), + msg, + code, + lvl, + true); } fn emit_struct(&mut self, db: &DiagnosticBuilder) { - self.emit(&db.span, &db.message, db.code.as_ref().map(|s| &**s), db.level); + self.emit_message(&FullSpan(db.span.clone()), + &db.message, + db.code.as_ref().map(|s| &**s), + db.level, + true); for child in &db.children { - assert!(child.render_span.is_none(), "Rudimentary emitters can't handle render spans"); - self.emit(&child.span, &child.message, None, child.level); + let render_span = child.render_span + .clone() + .unwrap_or_else( + || FullSpan(child.span.clone())); + self.emit_message(&render_span, + &child.message, + None, + child.level, + false); } } } @@ -83,11 +102,14 @@ pub struct BasicEmitter { dst: Destination, } -impl RudimentaryEmitter for BasicEmitter { - fn emit_rudimentary(&mut self, - msg: &str, - code: Option<&str>, - lvl: Level) { +impl CoreEmitter for BasicEmitter { + fn emit_message(&mut self, + _rsp: &RenderSpan, + msg: &str, + code: Option<&str>, + lvl: Level, + _is_header: bool) { + // we ignore the span as we have no access to a codemap at this point if let Err(e) = print_diagnostic(&mut self.dst, "", lvl, msg, code) { panic!("failed to print diagnostics: {:?}", e); } @@ -112,28 +134,16 @@ pub struct EmitterWriter { first: bool, } -impl Emitter for EmitterWriter { - fn emit(&mut self, - msp: &MultiSpan, - msg: &str, - code: Option<&str>, - lvl: Level) { - self.emit_multispan(msp, msg, code, lvl, true); - } - - fn emit_struct(&mut self, db: &DiagnosticBuilder) { - self.emit_multispan(&db.span, &db.message, - db.code.as_ref().map(|s| &**s), db.level, true); - - for child in &db.children { - match child.render_span { - Some(ref sp) => - self.emit_renderspan(sp, &child.message, - child.level), - None => - self.emit_multispan(&child.span, - &child.message, None, child.level, false), - } +impl CoreEmitter for EmitterWriter { + fn emit_message(&mut self, + rsp: &RenderSpan, + msg: &str, + code: Option<&str>, + lvl: Level, + is_header: bool) { + match self.emit_message_(rsp, msg, code, lvl, is_header) { + Ok(()) => { } + Err(e) => panic!("failed to emit error: {}", e) } } } @@ -173,83 +183,56 @@ impl EmitterWriter { EmitterWriter { dst: Raw(dst), registry: registry, cm: code_map, first: true } } - fn emit_multispan(&mut self, - span: &MultiSpan, - msg: &str, - code: Option<&str>, - lvl: Level, - is_header: bool) { + fn emit_message_(&mut self, + rsp: &RenderSpan, + msg: &str, + code: Option<&str>, + lvl: Level, + is_header: bool) + -> io::Result<()> { if is_header { if self.first { self.first = false; } else { - match write!(self.dst, "\n") { - Ok(_) => { } - Err(e) => { - panic!("failed to print diagnostics: {:?}", e) - } - } + write!(self.dst, "\n")?; } } - let error = match span.primary_span() { - Some(COMMAND_LINE_SP) => { - self.emit_(&FileLine(span.clone()), msg, code, lvl) - } - Some(DUMMY_SP) | None => { - print_diagnostic(&mut self.dst, "", lvl, msg, code) - } - Some(_) => { - self.emit_(&FullSpan(span.clone()), msg, code, lvl) - } - }; - - if let Err(e) = error { - panic!("failed to print diagnostics: {:?}", e); - } - } - - fn emit_renderspan(&mut self, sp: &RenderSpan, msg: &str, lvl: Level) { - if let Err(e) = self.emit_(sp, msg, None, lvl) { - panic!("failed to print diagnostics: {:?}", e); - } - } - - fn emit_(&mut self, - rsp: &RenderSpan, - msg: &str, - code: Option<&str>, - lvl: Level) - -> io::Result<()> { - let msp = rsp.span(); - let primary_span = msp.primary_span(); - match code { Some(code) if self.registry.as_ref() - .and_then(|registry| registry.find_description(code)).is_some() => - { + .and_then(|registry| registry.find_description(code)) + .is_some() => { let code_with_explain = String::from("--explain ") + code; print_diagnostic(&mut self.dst, "", lvl, msg, Some(&code_with_explain))? } - _ => print_diagnostic(&mut self.dst, "", lvl, msg, code)? + _ => { + print_diagnostic(&mut self.dst, "", lvl, msg, code)? + } } + // 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(_) => { + FullSpan(ref msp) => { self.highlight_lines(msp, lvl)?; - if let Some(primary_span) = primary_span { + 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) = primary_span { + if let Some(primary_span) = rsp.span().primary_span() { self.print_macro_backtrace(primary_span)?; } } - FileLine(..) => { - // no source text in this case! - } } Ok(()) diff --git a/src/libsyntax/errors/json.rs b/src/libsyntax/errors/json.rs index b343c3f3fbbc5..93c6268ccaea1 100644 --- a/src/libsyntax/errors/json.rs +++ b/src/libsyntax/errors/json.rs @@ -294,7 +294,6 @@ impl DiagnosticSpan { fn from_render_span(rsp: &RenderSpan, je: &JsonEmitter) -> Vec { match *rsp { - RenderSpan::FileLine(ref msp) | RenderSpan::FullSpan(ref msp) => DiagnosticSpan::from_multispan(msp, je), RenderSpan::Suggestion(ref suggestion) => @@ -356,7 +355,6 @@ impl DiagnosticCode { impl JsonEmitter { fn render(&self, render_span: &RenderSpan) -> Option { match *render_span { - RenderSpan::FileLine(_) | RenderSpan::FullSpan(_) => { None } diff --git a/src/libsyntax/errors/mod.rs b/src/libsyntax/errors/mod.rs index 0de2e067802e2..d533ffb981a6b 100644 --- a/src/libsyntax/errors/mod.rs +++ b/src/libsyntax/errors/mod.rs @@ -38,10 +38,6 @@ pub enum RenderSpan { /// of hypothetical source code, where each `String` is spliced /// into the lines in place of the code covered by each span. Suggestion(CodeSuggestion), - - /// A FileLine renders with just a line for the message prefixed - /// by file:linenum. - FileLine(MultiSpan), } #[derive(Clone)] @@ -54,8 +50,7 @@ impl RenderSpan { fn span(&self) -> &MultiSpan { match *self { FullSpan(ref msp) | - Suggestion(CodeSuggestion { ref msp, .. }) | - FileLine(ref msp) => + Suggestion(CodeSuggestion { ref msp, .. }) => msp } } From 8013eebf2c77b7756b6a99aee2c38ef417c60e19 Mon Sep 17 00:00:00 2001 From: Niko Matsakis Date: Thu, 21 Apr 2016 04:47:01 -0400 Subject: [PATCH 14/40] fix error message in librustc_driver tests --- src/librustc_driver/test.rs | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/librustc_driver/test.rs b/src/librustc_driver/test.rs index f2448d50b22bc..c6a0e0feff12a 100644 --- a/src/librustc_driver/test.rs +++ b/src/librustc_driver/test.rs @@ -73,6 +73,7 @@ fn remove_message(e: &mut ExpectErrorEmitter, msg: &str, lvl: Level) { e.messages.remove(i); } None => { + debug!("Unexpected error: {} Expected: {:?}", msg, e.messages); panic!("Unexpected error: {} Expected: {:?}", msg, e.messages); } } @@ -446,7 +447,7 @@ fn contravariant_region_ptr_ok() { #[test] fn contravariant_region_ptr_err() { - test_env(EMPTY_SOURCE_STR, errors(&["lifetime mismatch"]), |env| { + test_env(EMPTY_SOURCE_STR, errors(&["mismatched types"]), |env| { env.create_simple_region_hierarchy(); let t_rptr1 = env.t_rptr_scope(1); let t_rptr10 = env.t_rptr_scope(10); From 5adfe5bffedf0e98864d93381ca2ff2213d8fc88 Mon Sep 17 00:00:00 2001 From: Niko Matsakis Date: Tue, 26 Apr 2016 12:48:54 -0400 Subject: [PATCH 15/40] Nit: comments should be uppercase letter --- src/libsyntax/codemap.rs | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/libsyntax/codemap.rs b/src/libsyntax/codemap.rs index 5862538de2e04..93025c5833294 100644 --- a/src/libsyntax/codemap.rs +++ b/src/libsyntax/codemap.rs @@ -144,14 +144,14 @@ pub struct MultiSpan { #[derive(Clone, Debug)] pub struct SpanLabel { - /// the span we are going to include in the final snippet + /// The span we are going to include in the final snippet. pub span: Span, - /// is this a primary span? This is the "locus" of the message, - /// and is indicated with a `^^^^` underline, versus `----` + /// Is this a primary span? This is the "locus" of the message, + /// and is indicated with a `^^^^` underline, versus `----`. pub is_primary: bool, - /// what label should we attach to this span (if any)? + /// What label should we attach to this span (if any)? pub label: Option, } From 9a9c9afbe265b1fc9dbb1ed8bdb9b82523badf9c Mon Sep 17 00:00:00 2001 From: Niko Matsakis Date: Tue, 26 Apr 2016 12:49:05 -0400 Subject: [PATCH 16/40] Fix whitespace --- src/test/compile-fail/issue-7092.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/test/compile-fail/issue-7092.rs b/src/test/compile-fail/issue-7092.rs index 638f45cd35776..26e1597b1db4b 100644 --- a/src/test/compile-fail/issue-7092.rs +++ b/src/test/compile-fail/issue-7092.rs @@ -18,7 +18,7 @@ fn foo(x: Whatever) { //~| expected type `Whatever` //~| found type `std::option::Option<_>` //~| expected enum `Whatever`, found enum `std::option::Option` - field.access(), + field.access(), } } From e56121c584893d8b46af5e4cd5d580d30f221d9f Mon Sep 17 00:00:00 2001 From: Niko Matsakis Date: Tue, 26 Apr 2016 12:49:10 -0400 Subject: [PATCH 17/40] Do not import variants from RenderedLineKind --- src/libsyntax/errors/snippet/mod.rs | 24 ++++++++++++------------ 1 file changed, 12 insertions(+), 12 deletions(-) diff --git a/src/libsyntax/errors/snippet/mod.rs b/src/libsyntax/errors/snippet/mod.rs index cd8f705ab2e5f..0018667e67b65 100644 --- a/src/libsyntax/errors/snippet/mod.rs +++ b/src/libsyntax/errors/snippet/mod.rs @@ -103,7 +103,7 @@ pub enum RenderedLineKind { Annotations, Elision, } -use self::RenderedLineKind::*; +use self::RenderedLineKind as RLK; impl SnippetData { pub fn new(codemap: Rc, @@ -244,19 +244,19 @@ impl RenderedLine { impl RenderedLineKind { fn prefix(&self) -> StyledString { match *self { - SourceText { file: _, line_index } => + RLK::SourceText { file: _, line_index } => StyledString { text: format!("{}", line_index + 1), style: LineNumber, }, - Elision => + RLK::Elision => StyledString { text: String::from("..."), style: LineNumber, }, - PrimaryFileName | - OtherFileName | - Annotations => + RLK::PrimaryFileName | + RLK::OtherFileName | + RLK::Annotations => StyledString { text: String::from(""), style: LineNumber, @@ -296,7 +296,7 @@ impl StyledBuffer { //We know our first output line is source and the rest are highlights and labels output.push(RenderedLine { text: styled_vec, kind: source_kind.clone() }); } else { - output.push(RenderedLine { text: styled_vec, kind: Annotations }); + output.push(RenderedLine { text: styled_vec, kind: RLK::Annotations }); } styled_vec = vec![]; } @@ -484,7 +484,7 @@ impl FileInfo { text: format!(":{}:{}", lo.line, lo.col.0 + 1), style: LineAndColumn, }], - kind: PrimaryFileName, + kind: RLK::PrimaryFileName, }); } None => { @@ -493,7 +493,7 @@ impl FileInfo { text: self.file.name.clone(), style: FileNameStyle, }], - kind: OtherFileName, + kind: RLK::OtherFileName, }); } } @@ -534,7 +534,7 @@ impl FileInfo { if prev_ends_at_eol && is_single_unlabeled_annotated_line { if !elide_unlabeled_region { output.push(RenderedLine::from((String::new(), - NoStyle, Elision))); + NoStyle, RLK::Elision))); elide_unlabeled_region = true; prev_ends_at_eol = true; } @@ -548,7 +548,7 @@ impl FileInfo { } } else { if group.len() > 1 { - output.push(RenderedLine::from((String::new(), NoStyle, Elision))); + output.push(RenderedLine::from((String::new(), NoStyle, RLK::Elision))); } else { let mut v: Vec = group.iter().flat_map(|line| self.render_line(line)).collect(); @@ -563,7 +563,7 @@ impl FileInfo { fn render_line(&self, line: &Line) -> Vec { let source_string = self.file.get_line(line.line_index) .unwrap_or(""); - let source_kind = SourceText { + let source_kind = RLK::SourceText { file: self.file.clone(), line_index: line.line_index, }; From d58a4becf3943c02b9815f3d3875fe8817e41c7b Mon Sep 17 00:00:00 2001 From: Niko Matsakis Date: Tue, 26 Apr 2016 12:52:28 -0400 Subject: [PATCH 18/40] Nit: do not import variants from Style --- src/libsyntax/errors/snippet/mod.rs | 47 ++++++++++++++--------------- 1 file changed, 23 insertions(+), 24 deletions(-) diff --git a/src/libsyntax/errors/snippet/mod.rs b/src/libsyntax/errors/snippet/mod.rs index 0018667e67b65..f86d4bdb147a6 100644 --- a/src/libsyntax/errors/snippet/mod.rs +++ b/src/libsyntax/errors/snippet/mod.rs @@ -90,7 +90,6 @@ pub enum Style { LabelSecondary, NoStyle, } -use self::Style::*; #[derive(Debug, Clone)] pub enum RenderedLineKind { @@ -247,19 +246,19 @@ impl RenderedLineKind { RLK::SourceText { file: _, line_index } => StyledString { text: format!("{}", line_index + 1), - style: LineNumber, + style: Style::LineNumber, }, RLK::Elision => StyledString { text: String::from("..."), - style: LineNumber, + style: Style::LineNumber, }, RLK::PrimaryFileName | RLK::OtherFileName | RLK::Annotations => StyledString { text: String::from(""), - style: LineNumber, + style: Style::LineNumber, }, } } @@ -275,7 +274,7 @@ impl StyledBuffer { let mut styled_vec: Vec = vec![]; for (row, row_style) in self.text.iter().zip(&self.styles) { - let mut current_style = NoStyle; + let mut current_style = Style::NoStyle; let mut current_text = String::new(); for (&c, &s) in row.iter().zip(row_style) { @@ -316,7 +315,7 @@ impl StyledBuffer { } else { while self.text[line].len() < col { self.text[line].push(' '); - self.styles[line].push(NoStyle); + self.styles[line].push(Style::NoStyle); } self.text[line].push(chr); self.styles[line].push(style); @@ -479,10 +478,10 @@ impl FileInfo { output.push(RenderedLine { text: vec![StyledString { text: lo.file.name.clone(), - style: FileNameStyle, + style: Style::FileNameStyle, }, StyledString { text: format!(":{}:{}", lo.line, lo.col.0 + 1), - style: LineAndColumn, + style: Style::LineAndColumn, }], kind: RLK::PrimaryFileName, }); @@ -491,7 +490,7 @@ impl FileInfo { output.push(RenderedLine { text: vec![StyledString { text: self.file.name.clone(), - style: FileNameStyle, + style: Style::FileNameStyle, }], kind: RLK::OtherFileName, }); @@ -534,7 +533,7 @@ impl FileInfo { if prev_ends_at_eol && is_single_unlabeled_annotated_line { if !elide_unlabeled_region { output.push(RenderedLine::from((String::new(), - NoStyle, RLK::Elision))); + Style::NoStyle, RLK::Elision))); elide_unlabeled_region = true; prev_ends_at_eol = true; } @@ -548,7 +547,7 @@ impl FileInfo { } } else { if group.len() > 1 { - output.push(RenderedLine::from((String::new(), NoStyle, RLK::Elision))); + output.push(RenderedLine::from((String::new(), Style::NoStyle, RLK::Elision))); } else { let mut v: Vec = group.iter().flat_map(|line| self.render_line(line)).collect(); @@ -571,7 +570,7 @@ impl FileInfo { let mut styled_buffer = StyledBuffer::new(); // First create the source line we will highlight. - styled_buffer.append(0, &source_string, Quotation); + styled_buffer.append(0, &source_string, Style::Quotation); if line.annotations.is_empty() { return styled_buffer.render(source_kind); @@ -606,10 +605,10 @@ impl FileInfo { for annotation in &annotations { for p in annotation.start_col .. annotation.end_col { if annotation.is_primary { - styled_buffer.putc(1, p, '^', UnderlinePrimary); - styled_buffer.set_style(0, p, UnderlinePrimary); + styled_buffer.putc(1, p, '^', Style::UnderlinePrimary); + styled_buffer.set_style(0, p, Style::UnderlinePrimary); } else { - styled_buffer.putc(1, p, '-', UnderlineSecondary); + styled_buffer.putc(1, p, '-', Style::UnderlineSecondary); } } } @@ -671,9 +670,9 @@ impl FileInfo { // string let highlight_label: String = format!(" {}", last.label.as_ref().unwrap()); if last.is_primary { - styled_buffer.append(1, &highlight_label, LabelPrimary); + styled_buffer.append(1, &highlight_label, Style::LabelPrimary); } else { - styled_buffer.append(1, &highlight_label, LabelSecondary); + styled_buffer.append(1, &highlight_label, Style::LabelSecondary); } labeled_annotations = previous; } @@ -696,18 +695,18 @@ impl FileInfo { // 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, '|', UnderlinePrimary); + styled_buffer.putc(index, annotation.start_col, '|', Style::UnderlinePrimary); } else { - styled_buffer.putc(index, annotation.start_col, '|', UnderlineSecondary); + 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(), LabelPrimary); + annotation.label.as_ref().unwrap(), Style::LabelPrimary); } else { styled_buffer.puts(blank_lines, annotation.start_col, - annotation.label.as_ref().unwrap(), LabelSecondary); + annotation.label.as_ref().unwrap(), Style::LabelSecondary); } } @@ -752,7 +751,7 @@ fn prepend_prefixes(rendered_lines: &mut [RenderedLine]) { .chain(Some('>')) .chain(Some(' ')); line.text.insert(0, StyledString {text: dashes.collect(), - style: LineNumber}) + style: Style::LineNumber}) } RenderedLineKind::OtherFileName => { // >>>>> filename @@ -762,12 +761,12 @@ fn prepend_prefixes(rendered_lines: &mut [RenderedLine]) { let dashes = (0..padding_len + 2).map(|_| '>') .chain(Some(' ')); line.text.insert(0, StyledString {text: dashes.collect(), - style: LineNumber}) + style: Style::LineNumber}) } _ => { line.text.insert(0, prefix); line.text.insert(1, StyledString {text: String::from("|> "), - style: LineNumber}) + style: Style::LineNumber}) } } } From d5529f000da43fe2e9f2aad03f747b0144da9354 Mon Sep 17 00:00:00 2001 From: Niko Matsakis Date: Tue, 26 Apr 2016 12:53:20 -0400 Subject: [PATCH 19/40] Nit: do not use RLK --- src/libsyntax/errors/snippet/mod.rs | 26 ++++++++++++++------------ 1 file changed, 14 insertions(+), 12 deletions(-) diff --git a/src/libsyntax/errors/snippet/mod.rs b/src/libsyntax/errors/snippet/mod.rs index f86d4bdb147a6..4d9a3eb24860d 100644 --- a/src/libsyntax/errors/snippet/mod.rs +++ b/src/libsyntax/errors/snippet/mod.rs @@ -102,7 +102,6 @@ pub enum RenderedLineKind { Annotations, Elision, } -use self::RenderedLineKind as RLK; impl SnippetData { pub fn new(codemap: Rc, @@ -243,19 +242,19 @@ impl RenderedLine { impl RenderedLineKind { fn prefix(&self) -> StyledString { match *self { - RLK::SourceText { file: _, line_index } => + RenderedLineKind::SourceText { file: _, line_index } => StyledString { text: format!("{}", line_index + 1), style: Style::LineNumber, }, - RLK::Elision => + RenderedLineKind::Elision => StyledString { text: String::from("..."), style: Style::LineNumber, }, - RLK::PrimaryFileName | - RLK::OtherFileName | - RLK::Annotations => + RenderedLineKind::PrimaryFileName | + RenderedLineKind::OtherFileName | + RenderedLineKind::Annotations => StyledString { text: String::from(""), style: Style::LineNumber, @@ -295,7 +294,7 @@ impl StyledBuffer { //We know our first output line is source and the rest are highlights and labels output.push(RenderedLine { text: styled_vec, kind: source_kind.clone() }); } else { - output.push(RenderedLine { text: styled_vec, kind: RLK::Annotations }); + output.push(RenderedLine { text: styled_vec, kind: RenderedLineKind::Annotations }); } styled_vec = vec![]; } @@ -483,7 +482,7 @@ impl FileInfo { text: format!(":{}:{}", lo.line, lo.col.0 + 1), style: Style::LineAndColumn, }], - kind: RLK::PrimaryFileName, + kind: RenderedLineKind::PrimaryFileName, }); } None => { @@ -492,7 +491,7 @@ impl FileInfo { text: self.file.name.clone(), style: Style::FileNameStyle, }], - kind: RLK::OtherFileName, + kind: RenderedLineKind::OtherFileName, }); } } @@ -533,7 +532,8 @@ impl FileInfo { if prev_ends_at_eol && is_single_unlabeled_annotated_line { if !elide_unlabeled_region { output.push(RenderedLine::from((String::new(), - Style::NoStyle, RLK::Elision))); + Style::NoStyle, + RenderedLineKind::Elision))); elide_unlabeled_region = true; prev_ends_at_eol = true; } @@ -547,7 +547,9 @@ impl FileInfo { } } else { if group.len() > 1 { - output.push(RenderedLine::from((String::new(), Style::NoStyle, RLK::Elision))); + output.push(RenderedLine::from((String::new(), + Style::NoStyle, + RenderedLineKind::Elision))); } else { let mut v: Vec = group.iter().flat_map(|line| self.render_line(line)).collect(); @@ -562,7 +564,7 @@ impl FileInfo { fn render_line(&self, line: &Line) -> Vec { let source_string = self.file.get_line(line.line_index) .unwrap_or(""); - let source_kind = RLK::SourceText { + let source_kind = RenderedLineKind::SourceText { file: self.file.clone(), line_index: line.line_index, }; From f6496cd3700a9a4e3dc1a6d3245287066f4b99e4 Mon Sep 17 00:00:00 2001 From: Niko Matsakis Date: Tue, 26 Apr 2016 13:06:28 -0400 Subject: [PATCH 20/40] Nit: address various style nits --- src/libsyntax/errors/emitter.rs | 7 ++++++- src/libsyntax/errors/snippet/mod.rs | 4 +--- src/libsyntax/errors/snippet/test.rs | 4 +++- 3 files changed, 10 insertions(+), 5 deletions(-) diff --git a/src/libsyntax/errors/emitter.rs b/src/libsyntax/errors/emitter.rs index 2b29de7fd7135..7cad1714625bb 100644 --- a/src/libsyntax/errors/emitter.rs +++ b/src/libsyntax/errors/emitter.rs @@ -131,6 +131,9 @@ pub struct EmitterWriter { dst: Destination, registry: Option, cm: Rc, + + /// Is this the first error emitted thus far? If not, we emit a + /// `\n` before the top-level errors. first: bool, } @@ -172,7 +175,9 @@ impl EmitterWriter { EmitterWriter { dst: dst, registry: registry, cm: code_map, first: true } } else { EmitterWriter { dst: Raw(Box::new(io::stderr())), - registry: registry, cm: code_map, first: true } + registry: registry, + cm: code_map, + first: true } } } diff --git a/src/libsyntax/errors/snippet/mod.rs b/src/libsyntax/errors/snippet/mod.rs index 4d9a3eb24860d..ada336b29a48a 100644 --- a/src/libsyntax/errors/snippet/mod.rs +++ b/src/libsyntax/errors/snippet/mod.rs @@ -16,7 +16,6 @@ use std::rc::Rc; use std::mem; use std::ops::Range; -#[cfg(test)] mod test; pub struct SnippetData { @@ -210,8 +209,7 @@ impl From<(S, Style, RenderedLineKind)> for RenderedLine impl From<(S1, Style, S2, Style, RenderedLineKind)> for RenderedLine where S1: StringSource, S2: StringSource { - fn from(tuple: (S1, Style, S2, Style, RenderedLineKind)) - -> Self { + fn from(tuple: (S1, Style, S2, Style, RenderedLineKind)) -> Self { let (text1, style1, text2, style2, kind) = tuple; RenderedLine { text: vec![ diff --git a/src/libsyntax/errors/snippet/test.rs b/src/libsyntax/errors/snippet/test.rs index 44ece285b1b23..ccf50536adbab 100644 --- a/src/libsyntax/errors/snippet/test.rs +++ b/src/libsyntax/errors/snippet/test.rs @@ -1,4 +1,4 @@ -// Copyright 2012-2015 The Rust Project Developers. See the COPYRIGHT +// 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. // @@ -10,6 +10,8 @@ // Code for testing annotated snippets. +#![cfg(test)] + use codemap::{BytePos, CodeMap, FileMap, NO_EXPANSION, Span}; use std::rc::Rc; use super::{RenderedLine, SnippetData}; From 94841bea7b5753ba29655ce60a99f329e8eb8f24 Mon Sep 17 00:00:00 2001 From: Niko Matsakis Date: Tue, 26 Apr 2016 13:36:19 -0400 Subject: [PATCH 21/40] Nit: in emitter.rs --- src/libsyntax/errors/emitter.rs | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/src/libsyntax/errors/emitter.rs b/src/libsyntax/errors/emitter.rs index 7cad1714625bb..07dafb0b7dff0 100644 --- a/src/libsyntax/errors/emitter.rs +++ b/src/libsyntax/errors/emitter.rs @@ -397,8 +397,7 @@ impl Destination { style: Style) -> io::Result<()> { match style { - Style::FileNameStyle => { - } + Style::FileNameStyle | Style::LineAndColumn => { } Style::LineNumber => { From 24f4b151b11b22b66ac0128f76c1e12cca45b178 Mon Sep 17 00:00:00 2001 From: Niko Matsakis Date: Tue, 26 Apr 2016 13:36:30 -0400 Subject: [PATCH 22/40] Nit: use last_mut better --- src/libsyntax/errors/snippet/mod.rs | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/src/libsyntax/errors/snippet/mod.rs b/src/libsyntax/errors/snippet/mod.rs index ada336b29a48a..0c8b4f2046a49 100644 --- a/src/libsyntax/errors/snippet/mod.rs +++ b/src/libsyntax/errors/snippet/mod.rs @@ -229,10 +229,9 @@ impl From<(S1, Style, S2, Style, RenderedLineKind)> for RenderedLine impl RenderedLine { fn trim_last(&mut self) { - if !self.text.is_empty() { - let last_text = &mut self.text.last_mut().unwrap().text; - let len = last_text.trim_right().len(); - last_text.truncate(len); + if let Some(last_text) = self.text.last_mut() { + let len = last_text.text.trim_right().len(); + last_text.text.truncate(len); } } } From 1fdbfcdbd0a6a63317872fef24222533bbc8cfaf Mon Sep 17 00:00:00 2001 From: Niko Matsakis Date: Tue, 26 Apr 2016 09:33:38 -0700 Subject: [PATCH 23/40] only emit `^` at the start of a multi-line error as a result, simplify elision code --- src/libsyntax/errors/emitter.rs | 15 +-- src/libsyntax/errors/snippet/mod.rs | 184 +++++++++------------------ src/libsyntax/errors/snippet/test.rs | 11 +- 3 files changed, 67 insertions(+), 143 deletions(-) diff --git a/src/libsyntax/errors/emitter.rs b/src/libsyntax/errors/emitter.rs index 07dafb0b7dff0..eaa973db2b8c7 100644 --- a/src/libsyntax/errors/emitter.rs +++ b/src/libsyntax/errors/emitter.rs @@ -543,7 +543,7 @@ mod test { dreizehn "; let file = cm.new_filemap_and_lines("dummy.txt", content); - let start = file.lines.borrow()[7]; + let start = file.lines.borrow()[10]; let end = file.lines.borrow()[11]; let sp = mk_sp(start, end); let lvl = Level::Error; @@ -555,12 +555,9 @@ mod test { let str = from_utf8(vec).unwrap(); println!("r#\"\n{}\"#", str); assert_eq!(str, &r#" - --> dummy.txt:8:1 -8 |> line8 - |> ^^^^^^^^^^^^^ -... + --> dummy.txt:11:1 11 |> e-lä-vän - |> ^^^^^^^^^^^^^^^^ + |> ^ "#[1..]); } @@ -696,9 +693,8 @@ mod test { let expect0 = &r#" --> dummy.txt:5:1 5 |> ccccc - |> ^^^^^ + |> ^ ... -8 |> _____ 9 |> ddd__eee_ |> ^^^ ^^^ 10 |> elided @@ -709,9 +705,8 @@ mod test { let expect = &r#" --> dummy.txt:1:1 1 |> aaaaa - |> ^^^^^ + |> ^ ... -8 |> _____ 9 |> ddd__eee_ |> ^^^ ^^^ 10 |> elided diff --git a/src/libsyntax/errors/snippet/mod.rs b/src/libsyntax/errors/snippet/mod.rs index 0c8b4f2046a49..643b5c3c5f236 100644 --- a/src/libsyntax/errors/snippet/mod.rs +++ b/src/libsyntax/errors/snippet/mod.rs @@ -49,7 +49,7 @@ struct Annotation { /// column. start_col: usize, - /// End column within the line. + /// End column within the line (exclusive) end_col: usize, /// Is this annotation derived from primary span @@ -349,24 +349,40 @@ impl FileInfo { label: Option) { assert!(lines.len() > 0); - // If a span covers multiple lines, just put the label on the - // first one. This is a sort of arbitrary choice and not - // obviously correct. - let (line0, remaining_lines) = lines.split_first().unwrap(); - let index = self.ensure_source_line(line0.line_index); - self.lines[index].push_annotation(line0.start_col, - line0.end_col, + // 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> + // |> ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + // (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, end_col) = if lines.len() == 1 { + (lines[0].line_index, lines[0].start_col, lines[0].end_col) + } else { + (lines[0].line_index, lines[0].start_col, CharPos(lines[0].start_col.0 + 1)) + }; + let index = self.ensure_source_line(line); + self.lines[index].push_annotation(start_col, + end_col, is_primary, label); - for line in remaining_lines { - if line.end_col > line.start_col { - let index = self.ensure_source_line(line.line_index); - self.lines[index].push_annotation(line.start_col, - line.end_col, - is_primary, - None); - } - } } /// Ensure that we have a `Line` struct corresponding to @@ -414,57 +430,10 @@ impl FileInfo { } fn render_file_lines(&self, codemap: &Rc) -> Vec { - // Group our lines by those with annotations and those without - let mut lines_iter = self.lines.iter().peekable(); - - let mut line_groups = vec![]; - - 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)); - } - } - } + // As a first step, we elide any instance of more than one + // continuous unannotated line. + let mut lines_iter = self.lines.iter(); let mut output = vec![]; // First insert the name of the file. @@ -493,65 +462,30 @@ impl FileInfo { } } - for &(is_annotated, ref group) in line_groups.iter() { - if is_annotated { - let mut annotation_ends_at_eol = false; - let mut prev_ends_at_eol = false; - let mut elide_unlabeled_region = false; - - for group_line in group.iter() { - let source_string_len = - self.file.get_line(group_line.line_index) - .map(|s| s.len()) - .unwrap_or(0); - - for annotation in &group_line.annotations { - if annotation.end_col == source_string_len { - annotation_ends_at_eol = true; - } - } - - let is_single_unlabeled_annotated_line = - if group_line.annotations.len() == 1 { - if let Some(annotation) = group_line.annotations.first() { - match annotation.label { - Some(_) => false, - None => annotation.start_col == 0 && - annotation.end_col == source_string_len - } - } else { - false - } - } else { - false - }; - - if prev_ends_at_eol && is_single_unlabeled_annotated_line { - if !elide_unlabeled_region { - output.push(RenderedLine::from((String::new(), - Style::NoStyle, - RenderedLineKind::Elision))); - elide_unlabeled_region = true; - prev_ends_at_eol = true; - } - continue; - } - - let mut v = self.render_line(group_line); - output.append(&mut v); + 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; } + output.append(&mut self.render_line(line)); + next_line = lines_iter.next(); + } - prev_ends_at_eol = annotation_ends_at_eol; - } - } else { - if group.len() > 1 { - output.push(RenderedLine::from((String::new(), - Style::NoStyle, - RenderedLineKind::Elision))); - } else { - let mut v: Vec = - group.iter().flat_map(|line| self.render_line(line)).collect(); - output.append(&mut v); - } + // 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(RenderedLine::from((String::new(), + Style::NoStyle, + RenderedLineKind::Elision))); + } else if let Some(line) = unannotated_line { + output.append(&mut self.render_line(line)); } } diff --git a/src/libsyntax/errors/snippet/test.rs b/src/libsyntax/errors/snippet/test.rs index ccf50536adbab..d995d828bc727 100644 --- a/src/libsyntax/errors/snippet/test.rs +++ b/src/libsyntax/errors/snippet/test.rs @@ -406,8 +406,7 @@ impl SomeTrait for () { assert_eq!(text, &r#" >>>>>> foo.rs 3 |> fn foo(x: u32) { - |> ---------------- -... + |> - "#[1..]); } @@ -515,12 +514,8 @@ fn span_overlap_label3() { assert_eq!(text, &r#" >>>> foo.rs 3 |> let closure = || { - |> ---- foo + |> - foo 4 |> inner - |> ---------------- - |> | - |> bar -5 |> }; - |> -------- + |> ---- bar "#[1..]); } From 883b9699098e43453c0f4b9c3fd2a6fa16afcb35 Mon Sep 17 00:00:00 2001 From: Niko Matsakis Date: Tue, 26 Apr 2016 21:06:53 -0400 Subject: [PATCH 24/40] Nit: add comment --- src/libsyntax/codemap.rs | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/src/libsyntax/codemap.rs b/src/libsyntax/codemap.rs index 93025c5833294..1efd415685cc6 100644 --- a/src/libsyntax/codemap.rs +++ b/src/libsyntax/codemap.rs @@ -334,9 +334,11 @@ impl MultiSpan { &self.primary_spans } - /// Returns the strings to highlight. If we have an explicit set, - /// return those, otherwise just give back an (unlabeled) version - /// of the primary span. + /// Returns the strings to highlight. We always ensure that there + /// is an entry for each of the primary spans -- for each primary + /// span P, if there is at least one label with span P, we return + /// those labels (marked as primary). But otherwise we return + /// `SpanLabel` instances with empty labels. pub fn span_labels(&self) -> Vec { let is_primary = |span| self.primary_spans.contains(&span); let mut span_labels = vec![]; From 5db4d620f2727113dfd5dd16fdb9417b9afda9d2 Mon Sep 17 00:00:00 2001 From: Niko Matsakis Date: Tue, 26 Apr 2016 21:08:54 -0400 Subject: [PATCH 25/40] Nit: remove push_primary_span, which was never called --- src/libsyntax/codemap.rs | 4 ---- 1 file changed, 4 deletions(-) diff --git a/src/libsyntax/codemap.rs b/src/libsyntax/codemap.rs index 1efd415685cc6..ca8708fdc8326 100644 --- a/src/libsyntax/codemap.rs +++ b/src/libsyntax/codemap.rs @@ -316,10 +316,6 @@ impl MultiSpan { } } - pub fn push_primary_span(&mut self, span: Span) { - self.primary_spans.push(span); - } - pub fn push_span_label(&mut self, span: Span, label: String) { self.span_labels.push((span, label)); } From ba12ed06edf119c1d543158b8d0ac7d7ec503d82 Mon Sep 17 00:00:00 2001 From: Niko Matsakis Date: Tue, 26 Apr 2016 22:52:56 -0400 Subject: [PATCH 26/40] fix tests better --- src/libsyntax/errors/emitter.rs | 4 ++-- src/libsyntax/errors/snippet/test.rs | 6 +++--- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/src/libsyntax/errors/emitter.rs b/src/libsyntax/errors/emitter.rs index eaa973db2b8c7..cea6dbb75d981 100644 --- a/src/libsyntax/errors/emitter.rs +++ b/src/libsyntax/errors/emitter.rs @@ -556,8 +556,8 @@ mod test { println!("r#\"\n{}\"#", str); assert_eq!(str, &r#" --> dummy.txt:11:1 -11 |> e-lä-vän - |> ^ +11 |> e-lä-vän + |> ^ "#[1..]); } diff --git a/src/libsyntax/errors/snippet/test.rs b/src/libsyntax/errors/snippet/test.rs index d995d828bc727..286a3e3d40715 100644 --- a/src/libsyntax/errors/snippet/test.rs +++ b/src/libsyntax/errors/snippet/test.rs @@ -405,8 +405,8 @@ impl SomeTrait for () { println!("r#\"\n{}\"", text); assert_eq!(text, &r#" >>>>>> foo.rs -3 |> fn foo(x: u32) { - |> - +3 |> fn foo(x: u32) { + |> - "#[1..]); } @@ -516,6 +516,6 @@ fn span_overlap_label3() { 3 |> let closure = || { |> - foo 4 |> inner - |> ---- bar + |> ----- bar "#[1..]); } From 8a9ad72c1d67261049aac1d067529da48adcc644 Mon Sep 17 00:00:00 2001 From: Niko Matsakis Date: Tue, 26 Apr 2016 22:59:15 -0400 Subject: [PATCH 27/40] Nit: use Range::contains --- src/libsyntax/errors/snippet/mod.rs | 9 ++------- src/libsyntax/lib.rs | 1 + 2 files changed, 3 insertions(+), 7 deletions(-) diff --git a/src/libsyntax/errors/snippet/mod.rs b/src/libsyntax/errors/snippet/mod.rs index 643b5c3c5f236..feaf48352db86 100644 --- a/src/libsyntax/errors/snippet/mod.rs +++ b/src/libsyntax/errors/snippet/mod.rs @@ -14,7 +14,6 @@ use codemap::{CharPos, CodeMap, FileMap, LineInfo, Span}; use std::cmp; use std::rc::Rc; use std::mem; -use std::ops::Range; mod test; @@ -744,10 +743,6 @@ fn overlaps(a1: &Annotation, a2: &Annotation) -> bool { - between(a1.start_col, a2.start_col .. a2.end_col) || - between(a2.start_col, a1.start_col .. a1.end_col) -} - -fn between(v: usize, range: Range) -> bool { - v >= range.start && v < range.end + (a2.start_col .. a2.end_col).contains(a1.start_col) || + (a1.start_col .. a1.end_col).contains(a2.start_col) } diff --git a/src/libsyntax/lib.rs b/src/libsyntax/lib.rs index 6cfa1e9847b88..420a41e03b914 100644 --- a/src/libsyntax/lib.rs +++ b/src/libsyntax/lib.rs @@ -33,6 +33,7 @@ #![feature(str_escape)] #![feature(unicode)] #![feature(question_mark)] +#![feature(range_contains)] extern crate serialize; extern crate term; From 790043b44e0c078c0f80b16cd03d1aeac6ef242b Mon Sep 17 00:00:00 2001 From: Niko Matsakis Date: Wed, 27 Apr 2016 10:45:35 -0400 Subject: [PATCH 28/40] fix snippet tests MORE! --- src/libsyntax/errors/emitter.rs | 2 +- src/libsyntax/errors/snippet/test.rs | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/libsyntax/errors/emitter.rs b/src/libsyntax/errors/emitter.rs index cea6dbb75d981..b5be0fa16dd45 100644 --- a/src/libsyntax/errors/emitter.rs +++ b/src/libsyntax/errors/emitter.rs @@ -555,7 +555,7 @@ mod test { let str = from_utf8(vec).unwrap(); println!("r#\"\n{}\"#", str); assert_eq!(str, &r#" - --> dummy.txt:11:1 + --> dummy.txt:11:1 11 |> e-lä-vän |> ^ "#[1..]); diff --git a/src/libsyntax/errors/snippet/test.rs b/src/libsyntax/errors/snippet/test.rs index 286a3e3d40715..56c891daa12fb 100644 --- a/src/libsyntax/errors/snippet/test.rs +++ b/src/libsyntax/errors/snippet/test.rs @@ -404,7 +404,7 @@ impl SomeTrait for () { let text: String = make_string(&lines); println!("r#\"\n{}\"", text); assert_eq!(text, &r#" ->>>>>> foo.rs +>>>> foo.rs 3 |> fn foo(x: u32) { |> - "#[1..]); From 89d086be74d5ddf21d67f2a3c27a29cca2631bba Mon Sep 17 00:00:00 2001 From: Niko Matsakis Date: Wed, 27 Apr 2016 19:51:12 -0400 Subject: [PATCH 29/40] change color of warning to YELLOW --- src/libsyntax/errors/mod.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/libsyntax/errors/mod.rs b/src/libsyntax/errors/mod.rs index d533ffb981a6b..feac8aadc1e05 100644 --- a/src/libsyntax/errors/mod.rs +++ b/src/libsyntax/errors/mod.rs @@ -656,7 +656,7 @@ impl Level { fn color(self) -> term::color::Color { match self { Bug | Fatal | PhaseFatal | Error => term::color::BRIGHT_RED, - Warning => term::color::BRIGHT_MAGENTA, + Warning => term::color::YELLOW, Note => term::color::BRIGHT_GREEN, Help => term::color::BRIGHT_CYAN, Cancelled => unreachable!(), From 49dfac487267b574c802e0bdf5a66c5ff0624340 Mon Sep 17 00:00:00 2001 From: Niko Matsakis Date: Wed, 27 Apr 2016 19:59:57 -0400 Subject: [PATCH 30/40] move "lint level defined here" into secondary note It does not help you to understand the error, just explains why you are seeing it, so it is clearly secondary. --- src/librustc/lint/context.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/librustc/lint/context.rs b/src/librustc/lint/context.rs index 4ea6845b3c4f4..43c0e197e16bc 100644 --- a/src/librustc/lint/context.rs +++ b/src/librustc/lint/context.rs @@ -462,7 +462,7 @@ pub fn raw_struct_lint<'a>(sess: &'a Session, if let Some(span) = def { let explanation = "lint level defined here"; - err = err.span_label(span, &explanation); + err.span_note(span, &explanation); } err From 84cb56f8ee11ba89914462e478f06e9c1e8e7971 Mon Sep 17 00:00:00 2001 From: Jonathan Turner Date: Thu, 28 Apr 2016 16:39:59 -0700 Subject: [PATCH 31/40] Add back in a 'old school' error format --- src/libsyntax/errors/emitter.rs | 116 ++++++++++++++++++++---- src/libsyntax/errors/snippet/mod.rs | 135 +++++++++++++++++++++------- 2 files changed, 201 insertions(+), 50 deletions(-) diff --git a/src/libsyntax/errors/emitter.rs b/src/libsyntax/errors/emitter.rs index b5be0fa16dd45..7f4d1a9dc349a 100644 --- a/src/libsyntax/errors/emitter.rs +++ b/src/libsyntax/errors/emitter.rs @@ -135,6 +135,9 @@ pub struct EmitterWriter { /// 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 + old_school: bool, } impl CoreEmitter for EmitterWriter { @@ -170,14 +173,23 @@ impl EmitterWriter { registry: Option, code_map: Rc) -> EmitterWriter { + let old_school = match ::std::env::var("RUST_NEW_ERROR_FORMAT") { + Ok(_) => false, + Err(_) => true, + }; if color_config.use_color() { let dst = Destination::from_stderr(); - EmitterWriter { dst: dst, registry: registry, cm: code_map, first: true } + EmitterWriter { dst: dst, + registry: registry, + cm: code_map, + first: true, + old_school: old_school } } else { EmitterWriter { dst: Raw(Box::new(io::stderr())), registry: registry, cm: code_map, - first: true } + first: true, + old_school: old_school } } } @@ -185,7 +197,15 @@ impl EmitterWriter { registry: Option, code_map: Rc) -> EmitterWriter { - EmitterWriter { dst: Raw(dst), registry: registry, cm: code_map, first: true } + let old_school = match ::std::env::var("RUST_NEW_ERROR_FORMAT") { + Ok(_) => false, + Err(_) => true, + }; + EmitterWriter { dst: Raw(dst), + registry: registry, + cm: code_map, + first: true, + old_school: old_school } } fn emit_message_(&mut self, @@ -199,7 +219,9 @@ impl EmitterWriter { if self.first { self.first = false; } else { - write!(self.dst, "\n")?; + if !self.old_school { + write!(self.dst, "\n")?; + } } } @@ -208,7 +230,17 @@ impl EmitterWriter { .and_then(|registry| registry.find_description(code)) .is_some() => { let code_with_explain = String::from("--explain ") + code; - print_diagnostic(&mut self.dst, "", lvl, msg, Some(&code_with_explain))? + if self.old_school { + let loc = match rsp.span().primary_span() { + Some(COMMAND_LINE_SP) | Some(DUMMY_SP) => "".to_string(), + Some(ps) => self.cm.span_to_string(ps), + 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))? + } } _ => { print_diagnostic(&mut self.dst, "", lvl, msg, code)? @@ -239,7 +271,24 @@ impl EmitterWriter { } } } - + if self.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) => self.cm.span_to_string(ps), + 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(()) } @@ -282,19 +331,48 @@ impl EmitterWriter { { let mut snippet_data = SnippetData::new(self.cm.clone(), msp.primary_span()); - for span_label in msp.span_labels() { - snippet_data.push(span_label.span, - span_label.is_primary, - span_label.label); + if self.old_school { + let mut output_vec = vec![]; + for span_label in msp.span_labels() { + let mut snippet_data = snippet_data.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")?; + } + } } - 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()?; + else { + for span_label in msp.span_labels() { + snippet_data.push(span_label.span, + span_label.is_primary, + span_label.label); + } + 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")?; } - write!(&mut self.dst, "\n")?; } Ok(()) } @@ -327,7 +405,6 @@ fn line_num_max_digits(line: &codemap::LineInfo) -> usize { digits } - fn print_diagnostic(dst: &mut Destination, topic: &str, lvl: Level, @@ -335,7 +412,6 @@ fn print_diagnostic(dst: &mut Destination, code: Option<&str>) -> io::Result<()> { if !topic.is_empty() { - dst.start_attr(term::Attr::ForegroundColor(lvl.color()))?; write!(dst, "{}: ", topic)?; dst.reset_attrs()?; } @@ -346,10 +422,12 @@ fn print_diagnostic(dst: &mut Destination, 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(()) diff --git a/src/libsyntax/errors/snippet/mod.rs b/src/libsyntax/errors/snippet/mod.rs index feaf48352db86..18a64cc399c42 100644 --- a/src/libsyntax/errors/snippet/mod.rs +++ b/src/libsyntax/errors/snippet/mod.rs @@ -17,11 +17,13 @@ use std::mem; mod test; +#[derive(Clone)] pub struct SnippetData { codemap: Rc, files: Vec, } +#[derive(Clone)] pub struct FileInfo { file: Rc, @@ -35,6 +37,7 @@ pub struct FileInfo { lines: Vec, } +#[derive(Clone)] struct Line { line_index: usize, annotations: Vec, @@ -429,6 +432,10 @@ impl FileInfo { } fn render_file_lines(&self, codemap: &Rc) -> Vec { + let old_school = match ::std::env::var("RUST_NEW_ERROR_FORMAT") { + Ok(_) => false, + Err(_) => true, + }; // As a first step, we elide any instance of more than one // continuous unannotated line. @@ -436,28 +443,30 @@ impl FileInfo { let mut output = vec![]; // First insert the name of the file. - match self.primary_span { - Some(span) => { - let lo = codemap.lookup_char_pos(span.lo); - output.push(RenderedLine { - text: vec![StyledString { - text: lo.file.name.clone(), - style: Style::FileNameStyle, - }, StyledString { - text: format!(":{}:{}", lo.line, lo.col.0 + 1), - style: Style::LineAndColumn, - }], - kind: RenderedLineKind::PrimaryFileName, - }); - } - None => { - output.push(RenderedLine { - text: vec![StyledString { - text: self.file.name.clone(), - style: Style::FileNameStyle, - }], - kind: RenderedLineKind::OtherFileName, - }); + if !old_school { + match self.primary_span { + Some(span) => { + let lo = codemap.lookup_char_pos(span.lo); + output.push(RenderedLine { + text: vec![StyledString { + text: lo.file.name.clone(), + style: Style::FileNameStyle, + }, StyledString { + text: format!(":{}:{}", lo.line, lo.col.0 + 1), + style: Style::LineAndColumn, + }], + kind: RenderedLineKind::PrimaryFileName, + }); + } + None => { + output.push(RenderedLine { + text: vec![StyledString { + text: self.file.name.clone(), + style: Style::FileNameStyle, + }], + kind: RenderedLineKind::OtherFileName, + }); + } } } @@ -466,7 +475,31 @@ impl FileInfo { // Consume lines with annotations. while let Some(line) = next_line { if line.annotations.is_empty() { break; } - output.append(&mut self.render_line(line)); + + let mut rendered_line = self.render_line(line); + if old_school { + match self.primary_span { + Some(span) => { + let lo = codemap.lookup_char_pos(span.lo); + rendered_line[0].text.insert(0, StyledString { + text: format!(":{} ", lo.line), + style: Style::LineAndColumn, + }); + rendered_line[0].text.insert(0, StyledString { + text: lo.file.name.clone(), + style: Style::FileNameStyle, + }); + let gap_amount = rendered_line[0].text[0].text.len() + + rendered_line[0].text[1].text.len(); + rendered_line[1].text.insert(0, StyledString { + text: vec![" "; gap_amount].join(""), + style: Style::NoStyle + }); + } + _ =>() + } + } + output.append(&mut rendered_line); next_line = lines_iter.next(); } @@ -492,6 +525,10 @@ impl FileInfo { } fn render_line(&self, line: &Line) -> Vec { + let old_school = match ::std::env::var("RUST_NEW_ERROR_FORMAT") { + Ok(_) => false, + Err(_) => true, + }; let source_string = self.file.get_line(line.line_index) .unwrap_or(""); let source_kind = RenderedLineKind::SourceText { @@ -535,12 +572,34 @@ impl FileInfo { // Next, create the highlight line. for annotation in &annotations { - for p in annotation.start_col .. annotation.end_col { - if annotation.is_primary { - styled_buffer.putc(1, p, '^', Style::UnderlinePrimary); - styled_buffer.set_style(0, p, Style::UnderlinePrimary); - } else { - styled_buffer.putc(1, p, '-', Style::UnderlineSecondary); + 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::UnderlineSecondary + }); + } + else { + styled_buffer.putc(1, p, '~', + if annotation.is_primary { + Style::UnderlinePrimary + } else { + Style::UnderlineSecondary + }); + } + } + } + else { + for p in annotation.start_col .. annotation.end_col { + if annotation.is_primary { + styled_buffer.putc(1, p, '^', Style::UnderlinePrimary); + styled_buffer.set_style(0, p, Style::UnderlinePrimary); + } else { + styled_buffer.putc(1, p, '-', Style::UnderlineSecondary); + } } } } @@ -555,6 +614,9 @@ impl FileInfo { if labeled_annotations.is_empty() { return styled_buffer.render(source_kind); } + if old_school { + return styled_buffer.render(source_kind); + } // Now add the text labels. We try, when possible, to stick the rightmost // annotation at the end of the highlight line: @@ -647,6 +709,14 @@ impl FileInfo { } fn prepend_prefixes(rendered_lines: &mut [RenderedLine]) { + let old_school = match ::std::env::var("RUST_NEW_ERROR_FORMAT") { + Ok(_) => false, + Err(_) => true, + }; + if old_school { + return; + } + let prefixes: Vec<_> = rendered_lines.iter() .map(|rl| rl.kind.prefix()) @@ -686,11 +756,14 @@ fn prepend_prefixes(rendered_lines: &mut [RenderedLine]) { style: Style::LineNumber}) } RenderedLineKind::OtherFileName => { - // >>>>> filename + // ::: filename // 22 |> // ^ // padding_len - let dashes = (0..padding_len + 2).map(|_| '>') + 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}) From 79f61a45328e534e52cf705452b33ae4b8ae474d Mon Sep 17 00:00:00 2001 From: Jonathan Turner Date: Fri, 29 Apr 2016 13:27:40 -0700 Subject: [PATCH 32/40] Finish up with 'old school' error mode --- src/librustc_trans/back/write.rs | 3 +- src/libsyntax/errors/emitter.rs | 75 +++++++++++++++++++++++++++----- 2 files changed, 65 insertions(+), 13 deletions(-) diff --git a/src/librustc_trans/back/write.rs b/src/librustc_trans/back/write.rs index a35048f89c114..10bcf83d7556f 100644 --- a/src/librustc_trans/back/write.rs +++ b/src/librustc_trans/back/write.rs @@ -106,7 +106,8 @@ impl CoreEmitter for SharedEmitter { msg: &str, code: Option<&str>, lvl: Level, - _is_header: bool) { + _is_header: bool, + _show_snippet: bool) { self.buffer.lock().unwrap().push(Diagnostic { msg: msg.to_string(), code: code.map(|s| s.to_string()), diff --git a/src/libsyntax/errors/emitter.rs b/src/libsyntax/errors/emitter.rs index 7f4d1a9dc349a..769f6b0539706 100644 --- a/src/libsyntax/errors/emitter.rs +++ b/src/libsyntax/errors/emitter.rs @@ -40,7 +40,8 @@ pub trait CoreEmitter { msg: &str, code: Option<&str>, lvl: Level, - is_header: bool); + is_header: bool, + show_snippet: bool); } impl Emitter for T { @@ -53,25 +54,47 @@ impl Emitter for T { msg, code, lvl, + true, true); } fn emit_struct(&mut self, db: &DiagnosticBuilder) { + let old_school = match ::std::env::var("RUST_NEW_ERROR_FORMAT") { + Ok(_) => false, + Err(_) => true, + }; + let db_span = FullSpan(db.span.clone()); self.emit_message(&FullSpan(db.span.clone()), &db.message, db.code.as_ref().map(|s| &**s), db.level, + true, true); for child in &db.children { let render_span = child.render_span .clone() .unwrap_or_else( || FullSpan(child.span.clone())); - self.emit_message(&render_span, - &child.message, - None, - child.level, - false); + + if !old_school { + self.emit_message(&render_span, + &child.message, + None, + child.level, + false, + true); + } else { + let (render_span, show_snippet) = match render_span.span().primary_span() { + None => (db_span.clone(), false), + _ => (render_span, true) + }; + self.emit_message(&render_span, + &child.message, + None, + child.level, + false, + show_snippet); + } } } } @@ -108,7 +131,8 @@ impl CoreEmitter for BasicEmitter { msg: &str, code: Option<&str>, lvl: Level, - _is_header: bool) { + _is_header: bool, + _show_snippet: bool) { // we ignore the span as we have no access to a codemap at this point if let Err(e) = print_diagnostic(&mut self.dst, "", lvl, msg, code) { panic!("failed to print diagnostics: {:?}", e); @@ -146,8 +170,9 @@ impl CoreEmitter for EmitterWriter { msg: &str, code: Option<&str>, lvl: Level, - is_header: bool) { - match self.emit_message_(rsp, msg, code, lvl, is_header) { + 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) } @@ -213,7 +238,8 @@ impl EmitterWriter { msg: &str, code: Option<&str>, lvl: Level, - is_header: bool) + is_header: bool, + show_snippet: bool) -> io::Result<()> { if is_header { if self.first { @@ -243,10 +269,24 @@ impl EmitterWriter { } } _ => { - print_diagnostic(&mut self.dst, "", lvl, msg, code)? + if self.old_school { + let loc = match rsp.span().primary_span() { + Some(COMMAND_LINE_SP) | Some(DUMMY_SP) => "".to_string(), + Some(ps) => self.cm.span_to_string(ps), + 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() { @@ -333,8 +373,10 @@ impl EmitterWriter { msp.primary_span()); if self.old_school { let mut output_vec = vec![]; + for span_label in msp.span_labels() { let mut snippet_data = snippet_data.clone(); + snippet_data.push(span_label.span, span_label.is_primary, span_label.label); @@ -412,7 +454,16 @@ fn print_diagnostic(dst: &mut Destination, code: Option<&str>) -> io::Result<()> { if !topic.is_empty() { - write!(dst, "{}: ", topic)?; + let old_school = match ::std::env::var("RUST_NEW_ERROR_FORMAT") { + Ok(_) => false, + Err(_) => true, + }; + if !old_school { + write!(dst, "{}: ", topic)?; + } + else { + write!(dst, "{} ", topic)?; + } dst.reset_attrs()?; } dst.start_attr(term::Attr::Bold)?; From 5974e5b294ee3b67054a31eae2a4b9bab950a119 Mon Sep 17 00:00:00 2001 From: Jonathan Turner Date: Fri, 29 Apr 2016 14:06:20 -0700 Subject: [PATCH 33/40] Fix up error-pattern style test --- src/test/compile-fail/issue-14091.rs | 3 --- 1 file changed, 3 deletions(-) diff --git a/src/test/compile-fail/issue-14091.rs b/src/test/compile-fail/issue-14091.rs index ccaeeab8b4789..9c594ef485fd7 100644 --- a/src/test/compile-fail/issue-14091.rs +++ b/src/test/compile-fail/issue-14091.rs @@ -9,8 +9,5 @@ // except according to those terms. // error-pattern:mismatched types -// error-pattern:expected bool, found integral variable -// error-pattern:expected type `bool` -// error-pattern:found type `_` fn main(){assert!(1,1);} From 2ba5fac1a460de9936b85f9459668b0992f21f06 Mon Sep 17 00:00:00 2001 From: Niko Matsakis Date: Fri, 29 Apr 2016 18:08:02 -0400 Subject: [PATCH 34/40] fix rebase flaws --- src/librustc_driver/lib.rs | 5 ++--- src/librustc_resolve/lib.rs | 3 +-- src/libsyntax_ext/deriving/mod.rs | 6 +++--- 3 files changed, 6 insertions(+), 8 deletions(-) diff --git a/src/librustc_driver/lib.rs b/src/librustc_driver/lib.rs index 52306e388e235..d03ae45e83fe8 100644 --- a/src/librustc_driver/lib.rs +++ b/src/librustc_driver/lib.rs @@ -91,9 +91,8 @@ use std::thread; use rustc::session::early_error; -use syntax::{ast, errors, diagnostic}; -use syntax::codemap::MultiSpan; -use syntax::parse::{self, PResult}; +use syntax::{ast, errors, diagnostics}; +use syntax::codemap::{CodeMap, FileLoader, RealFileLoader, MultiSpan}; use syntax::errors::emitter::Emitter; use syntax::feature_gate::{GatedCfg, UnstableFeatures}; use syntax::parse::{self, PResult, token}; diff --git a/src/librustc_resolve/lib.rs b/src/librustc_resolve/lib.rs index 1bb99eb1a5e0e..e747ed1526061 100644 --- a/src/librustc_resolve/lib.rs +++ b/src/librustc_resolve/lib.rs @@ -1784,8 +1784,7 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> { // If it's a typedef, give a note if let Def::TyAlias(..) = path_res.base_def { - err.note(trait_path.span, - "`type` aliases cannot be used for traits"); + err.note("`type` aliases cannot be used for traits"); let definition_site = { let segments = &trait_path.segments; diff --git a/src/libsyntax_ext/deriving/mod.rs b/src/libsyntax_ext/deriving/mod.rs index 4ca3196b9c5ec..91c272c59c4a6 100644 --- a/src/libsyntax_ext/deriving/mod.rs +++ b/src/libsyntax_ext/deriving/mod.rs @@ -204,9 +204,9 @@ macro_rules! derive_traits { sp, feature_gate::EXPLAIN_DERIVE_UNDERSCORE, ); if option_env!("CFG_DISABLE_UNSTABLE_FEATURES").is_none() { - w.fileline_help( - sp, &format!("add #![feature(custom_derive)] to \ - the crate attributes to enable") + w.help( + &format!("add #![feature(custom_derive)] to \ + the crate attributes to enable") ); } w.emit(); From 95576b8ec40538fc311029dd838d2a22c0e9af7f Mon Sep 17 00:00:00 2001 From: Niko Matsakis Date: Fri, 29 Apr 2016 21:13:42 -0400 Subject: [PATCH 35/40] update unit tests --- src/libsyntax/errors/emitter.rs | 21 +++++---------------- src/libsyntax/errors/mod.rs | 17 +++++++++++++++++ src/libsyntax/errors/snippet/mod.rs | 17 +++++------------ src/libsyntax/errors/snippet/test.rs | 22 +++++++++++----------- 4 files changed, 38 insertions(+), 39 deletions(-) diff --git a/src/libsyntax/errors/emitter.rs b/src/libsyntax/errors/emitter.rs index 769f6b0539706..486e2ace0876a 100644 --- a/src/libsyntax/errors/emitter.rs +++ b/src/libsyntax/errors/emitter.rs @@ -13,6 +13,7 @@ use self::Destination::*; use codemap::{self, COMMAND_LINE_SP, DUMMY_SP, Pos, Span, MultiSpan}; use diagnostics; +use errors::check_old_skool; use errors::{Level, RenderSpan, CodeSuggestion, DiagnosticBuilder}; use errors::RenderSpan::*; use errors::Level::*; @@ -59,10 +60,7 @@ impl Emitter for T { } fn emit_struct(&mut self, db: &DiagnosticBuilder) { - let old_school = match ::std::env::var("RUST_NEW_ERROR_FORMAT") { - Ok(_) => false, - Err(_) => true, - }; + let old_school = check_old_skool(); let db_span = FullSpan(db.span.clone()); self.emit_message(&FullSpan(db.span.clone()), &db.message, @@ -198,10 +196,7 @@ impl EmitterWriter { registry: Option, code_map: Rc) -> EmitterWriter { - let old_school = match ::std::env::var("RUST_NEW_ERROR_FORMAT") { - Ok(_) => false, - Err(_) => true, - }; + let old_school = check_old_skool(); if color_config.use_color() { let dst = Destination::from_stderr(); EmitterWriter { dst: dst, @@ -222,10 +217,7 @@ impl EmitterWriter { registry: Option, code_map: Rc) -> EmitterWriter { - let old_school = match ::std::env::var("RUST_NEW_ERROR_FORMAT") { - Ok(_) => false, - Err(_) => true, - }; + let old_school = check_old_skool(); EmitterWriter { dst: Raw(dst), registry: registry, cm: code_map, @@ -454,10 +446,7 @@ fn print_diagnostic(dst: &mut Destination, code: Option<&str>) -> io::Result<()> { if !topic.is_empty() { - let old_school = match ::std::env::var("RUST_NEW_ERROR_FORMAT") { - Ok(_) => false, - Err(_) => true, - }; + let old_school = check_old_skool(); if !old_school { write!(dst, "{}: ", topic)?; } diff --git a/src/libsyntax/errors/mod.rs b/src/libsyntax/errors/mod.rs index feac8aadc1e05..4ade537c8ce04 100644 --- a/src/libsyntax/errors/mod.rs +++ b/src/libsyntax/errors/mod.rs @@ -683,3 +683,20 @@ pub fn expect(diag: &Handler, opt: Option, msg: M) -> T where None => diag.bug(&msg()), } } + +/// True if we should use the old-skool error format style. This is +/// the default setting until the new errors are deemed stable enough +/// for general use. +/// +/// FIXME(#33240) +#[cfg(not(test))] +fn check_old_skool() -> bool { + use std::env; + env::var("RUST_NEW_ERROR_FORMAT").is_err() +} + +/// For unit tests, use the new format. +#[cfg(test)] +fn check_old_skool() -> bool { + false +} diff --git a/src/libsyntax/errors/snippet/mod.rs b/src/libsyntax/errors/snippet/mod.rs index 18a64cc399c42..6c90bfd08186b 100644 --- a/src/libsyntax/errors/snippet/mod.rs +++ b/src/libsyntax/errors/snippet/mod.rs @@ -11,6 +11,7 @@ // Code for annotating snippets. use codemap::{CharPos, CodeMap, FileMap, LineInfo, Span}; +use errors::check_old_skool; use std::cmp; use std::rc::Rc; use std::mem; @@ -432,10 +433,8 @@ impl FileInfo { } fn render_file_lines(&self, codemap: &Rc) -> Vec { - let old_school = match ::std::env::var("RUST_NEW_ERROR_FORMAT") { - Ok(_) => false, - Err(_) => true, - }; + let old_school = check_old_skool(); + // As a first step, we elide any instance of more than one // continuous unannotated line. @@ -525,10 +524,7 @@ impl FileInfo { } fn render_line(&self, line: &Line) -> Vec { - let old_school = match ::std::env::var("RUST_NEW_ERROR_FORMAT") { - Ok(_) => false, - Err(_) => true, - }; + let old_school = check_old_skool(); let source_string = self.file.get_line(line.line_index) .unwrap_or(""); let source_kind = RenderedLineKind::SourceText { @@ -709,10 +705,7 @@ impl FileInfo { } fn prepend_prefixes(rendered_lines: &mut [RenderedLine]) { - let old_school = match ::std::env::var("RUST_NEW_ERROR_FORMAT") { - Ok(_) => false, - Err(_) => true, - }; + let old_school = check_old_skool(); if old_school { return; } diff --git a/src/libsyntax/errors/snippet/test.rs b/src/libsyntax/errors/snippet/test.rs index 56c891daa12fb..569d11199190c 100644 --- a/src/libsyntax/errors/snippet/test.rs +++ b/src/libsyntax/errors/snippet/test.rs @@ -105,7 +105,7 @@ fn foo() { println!("text=\n{}", text); assert_eq!(&text[..], &r#" ->>>> foo.rs + ::: foo.rs 3 |> vec.push(vec.pop().unwrap()); |> --- --- - previous borrow ends here |> | | @@ -180,7 +180,7 @@ fn bar() { |> | | |> | b |> a ->>>>>> bar.rs + ::: bar.rs 17 |> vec.push(); |> --- - f |> | @@ -224,7 +224,7 @@ fn foo() { println!("text=\n{}", text); assert_eq!(&text[..], &r#" ->>>>>> foo.rs + ::: foo.rs 3 |> let name = find_id(&data, 22).unwrap(); |> ---- immutable borrow begins here ... @@ -263,7 +263,7 @@ fn foo() { println!("text=r#\"\n{}\".trim_left()", text); assert_eq!(&text[..], &r#" ->>>> foo.rs + ::: foo.rs 3 |> vec.push(vec.pop().unwrap()); |> -------- ------ D |> || @@ -299,7 +299,7 @@ fn foo() { println!("text=r#\"\n{}\".trim_left()", text); assert_eq!(&text[..], &r#" ->>>> foo.rs + ::: foo.rs 3 |> vec.push(vec.pop().unwrap()); |> --- --- - previous borrow ends here |> | | @@ -337,7 +337,7 @@ fn foo() { let text: String = make_string(&lines); println!("text=r#\"\n{}\".trim_left()", text); assert_eq!(&text[..], &r#" ->>>>>> foo.rs + ::: foo.rs 4 |> let mut vec2 = vec; |> --- `vec` moved here because it has type `collections::vec::Vec` ... @@ -373,7 +373,7 @@ fn foo() { let text: String = make_string(&lines); println!("text=&r#\"\n{}\n\"#[1..]", text); assert_eq!(text, &r#" ->>>> foo.rs + ::: foo.rs 3 |> let mut vec = vec![0, 1, 2]; |> --- --- 4 |> let mut vec2 = vec; @@ -404,7 +404,7 @@ impl SomeTrait for () { let text: String = make_string(&lines); println!("r#\"\n{}\"", text); assert_eq!(text, &r#" ->>>> foo.rs + ::: foo.rs 3 |> fn foo(x: u32) { |> - "#[1..]); @@ -433,7 +433,7 @@ fn span_overlap_label() { let text: String = make_string(&lines); println!("r#\"\n{}\"", text); assert_eq!(text, &r#" ->>>> foo.rs + ::: foo.rs 2 |> fn foo(x: u32) { |> -------------- |> | | @@ -467,7 +467,7 @@ fn span_overlap_label2() { let text: String = make_string(&lines); println!("r#\"\n{}\"", text); assert_eq!(text, &r#" ->>>> foo.rs + ::: foo.rs 2 |> fn foo(x: u32) { |> -------------- |> | | @@ -512,7 +512,7 @@ fn span_overlap_label3() { let text: String = make_string(&lines); println!("r#\"\n{}\"", text); assert_eq!(text, &r#" ->>>> foo.rs + ::: foo.rs 3 |> let closure = || { |> - foo 4 |> inner From 64e0819fc2681be7d3f0e61f8b0f61eca67ad3fb Mon Sep 17 00:00:00 2001 From: Niko Matsakis Date: Sat, 30 Apr 2016 09:54:48 -0400 Subject: [PATCH 36/40] patch travis failure --- src/librustc_driver/test.rs | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/librustc_driver/test.rs b/src/librustc_driver/test.rs index c6a0e0feff12a..37f7b31b69cf2 100644 --- a/src/librustc_driver/test.rs +++ b/src/librustc_driver/test.rs @@ -85,7 +85,8 @@ impl CoreEmitter for ExpectErrorEmitter { msg: &str, _: Option<&str>, lvl: Level, - _is_header: bool) { + _is_header: bool, + _show_snippet: bool) { remove_message(self, msg, lvl); } } From f359aa276216aa74868b4ead5fea9a83a8397b27 Mon Sep 17 00:00:00 2001 From: jonathandturner Date: Sat, 30 Apr 2016 09:06:01 -0700 Subject: [PATCH 37/40] Fix unicode test to use original error format --- .../run-make/unicode-input/span_length.rs | 32 +++++++++---------- 1 file changed, 15 insertions(+), 17 deletions(-) diff --git a/src/test/run-make/unicode-input/span_length.rs b/src/test/run-make/unicode-input/span_length.rs index f3bfe083016e7..3963d20df8873 100644 --- a/src/test/run-make/unicode-input/span_length.rs +++ b/src/test/run-make/unicode-input/span_length.rs @@ -65,8 +65,8 @@ fn main() { let err = String::from_utf8_lossy(&result.stderr); - // the span should end the line (e.g no extra ^'s) - let expected_span = format!("^{}\n", repeat("^").take(n - 1) + // the span should end the line (e.g no extra ~'s) + let expected_span = format!("^{}\n", repeat("~").take(n - 1) .collect::()); assert!(err.contains(&expected_span)); } @@ -91,19 +91,17 @@ fn main() { // Test both the length of the snake and the leading spaces up to it - // First snake is 9 ^s long. - let expected_1 = r#" -1 |> extern "路濫狼á́́" fn foo() {} extern "路濫狼á́" fn bar() {} - |> ^^^^^^^^^ -"#; - assert!(err.contains(&expected_1)); - - // Second snake is only 8 ^s long, because rustc counts chars() - // now rather than width(). This is because width() functions are - // to be removed from librustc_unicode - let expected_2 = r#" -1 |> extern "路濫狼á́́" fn foo() {} extern "路濫狼á́" fn bar() {} - |> ^^^^^^^^ -"#; - assert!(err.contains(&expected_2)); + // First snake is 8 ~s long, with 7 preceding spaces (excluding file name/line offset) + let expected_span = format!("\n{}^{}\n", + repeat(" ").take(offset + 7).collect::(), + repeat("~").take(8).collect::()); + assert!(err.contains(&expected_span)); + // Second snake is only 7 ~s long, with 36 preceding spaces, + // because rustc counts chars() now rather than width(). This + // is because width() functions are to be removed from + // librustc_unicode + let expected_span = format!("\n{}^{}\n", + repeat(" ").take(offset + 36).collect::(), + repeat("~").take(7).collect::()); + assert!(err.contains(&expected_span)); } From 9d151a71c032b655ca457521730044237c9e130e Mon Sep 17 00:00:00 2001 From: Niko Matsakis Date: Mon, 2 May 2016 11:37:59 -0400 Subject: [PATCH 38/40] do not fail if len(rendered_lines) is == 1 also handle more rendered-lines --- src/libsyntax/errors/snippet/mod.rs | 24 ++++++++++++++---------- 1 file changed, 14 insertions(+), 10 deletions(-) diff --git a/src/libsyntax/errors/snippet/mod.rs b/src/libsyntax/errors/snippet/mod.rs index 6c90bfd08186b..1ec4a0157426a 100644 --- a/src/libsyntax/errors/snippet/mod.rs +++ b/src/libsyntax/errors/snippet/mod.rs @@ -475,30 +475,34 @@ impl FileInfo { while let Some(line) = next_line { if line.annotations.is_empty() { break; } - let mut rendered_line = self.render_line(line); + 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); - rendered_line[0].text.insert(0, StyledString { + rendered_lines[0].text.insert(0, StyledString { text: format!(":{} ", lo.line), style: Style::LineAndColumn, }); - rendered_line[0].text.insert(0, StyledString { + rendered_lines[0].text.insert(0, StyledString { text: lo.file.name.clone(), style: Style::FileNameStyle, }); - let gap_amount = rendered_line[0].text[0].text.len() + - rendered_line[0].text[1].text.len(); - rendered_line[1].text.insert(0, StyledString { - text: vec![" "; gap_amount].join(""), - style: Style::NoStyle - }); + let gap_amount = + rendered_lines[0].text[0].text.len() + + rendered_lines[0].text[1].text.len(); + for i in 1..rendered_lines.len() { + rendered_lines[i].text.insert(0, StyledString { + text: vec![" "; gap_amount].join(""), + style: Style::NoStyle + }); + } } _ =>() } } - output.append(&mut rendered_line); + output.append(&mut rendered_lines); next_line = lines_iter.next(); } From db8a9a92b3dafcd5a8d7207096c8cbb90db0b013 Mon Sep 17 00:00:00 2001 From: Niko Matsakis Date: Mon, 2 May 2016 11:44:25 -0400 Subject: [PATCH 39/40] avoid double panic --- src/libsyntax/errors/mod.rs | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/libsyntax/errors/mod.rs b/src/libsyntax/errors/mod.rs index 4ade537c8ce04..f0c665bcb3cdb 100644 --- a/src/libsyntax/errors/mod.rs +++ b/src/libsyntax/errors/mod.rs @@ -20,6 +20,7 @@ use errors::emitter::{Emitter, EmitterWriter}; use std::cell::{RefCell, Cell}; use std::{error, fmt}; use std::rc::Rc; +use std::thread::panicking; use term; pub mod emitter; @@ -352,7 +353,7 @@ impl<'a> fmt::Debug for DiagnosticBuilder<'a> { /// we emit a bug. impl<'a> Drop for DiagnosticBuilder<'a> { fn drop(&mut self) { - if !self.cancelled() { + if !panicking() && !self.cancelled() { self.emitter.borrow_mut().emit(&MultiSpan::new(), "Error constructed but not emitted", None, From 9355a91224a6f715b94342c074e5bac1f9e820f3 Mon Sep 17 00:00:00 2001 From: Niko Matsakis Date: Mon, 2 May 2016 13:05:14 -0400 Subject: [PATCH 40/40] assert we get at least two rendered lines back --- src/libsyntax/errors/snippet/mod.rs | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/src/libsyntax/errors/snippet/mod.rs b/src/libsyntax/errors/snippet/mod.rs index 1ec4a0157426a..e213f623ab85d 100644 --- a/src/libsyntax/errors/snippet/mod.rs +++ b/src/libsyntax/errors/snippet/mod.rs @@ -38,13 +38,13 @@ pub struct FileInfo { lines: Vec, } -#[derive(Clone)] +#[derive(Clone, Debug)] struct Line { line_index: usize, annotations: Vec, } -#[derive(Clone, PartialOrd, Ord, PartialEq, Eq)] +#[derive(Clone, Debug, PartialOrd, Ord, PartialEq, Eq)] struct Annotation { /// Start column, 0-based indexing -- counting *characters*, not /// utf-8 bytes. Note that it is important that this field goes @@ -492,6 +492,9 @@ impl FileInfo { let gap_amount = rendered_lines[0].text[0].text.len() + rendered_lines[0].text[1].text.len(); + assert!(rendered_lines.len() >= 2, + "no annotations resulted from: {:?}", + line); for i in 1..rendered_lines.len() { rendered_lines[i].text.insert(0, StyledString { text: vec![" "; gap_amount].join(""),