From 8f044fae36b73ec4593c127ec2a7c28716208591 Mon Sep 17 00:00:00 2001 From: Jonathan Turner Date: Tue, 5 Jul 2016 15:24:23 -0400 Subject: [PATCH 01/19] Remove BasicEmitter --- src/librustc/session/mod.rs | 15 +++- src/librustc_driver/lib.rs | 17 +++- src/librustc_errors/emitter.rs | 136 ++++++++++++++----------------- src/librustc_errors/lib.rs | 2 +- src/librustdoc/core.rs | 2 +- src/librustdoc/test.rs | 4 +- src/libsyntax/codemap.rs | 6 +- src/libsyntax/parse/lexer/mod.rs | 2 +- src/libsyntax/parse/mod.rs | 6 +- 9 files changed, 101 insertions(+), 89 deletions(-) diff --git a/src/librustc/session/mod.rs b/src/librustc/session/mod.rs index 0e516bdc21194..3939f5f5880a9 100644 --- a/src/librustc/session/mod.rs +++ b/src/librustc/session/mod.rs @@ -22,7 +22,8 @@ use mir::transform as mir_pass; use syntax::ast::{NodeId, Name}; use errors::{self, DiagnosticBuilder}; -use errors::emitter::{Emitter, BasicEmitter, EmitterWriter}; +use errors::emitter::{Emitter, EmitterWriter}; +use errors::snippet::FormatMode; use syntax::json::JsonEmitter; use syntax::feature_gate; use syntax::parse; @@ -439,7 +440,7 @@ pub fn build_session_with_codemap(sopts: config::Options, config::ErrorOutputType::HumanReadable(color_config) => { Box::new(EmitterWriter::stderr(color_config, Some(registry), - codemap.clone(), + Some(codemap.clone()), errors::snippet::FormatMode::EnvironmentSelected)) } config::ErrorOutputType::Json => { @@ -577,7 +578,10 @@ unsafe fn configure_llvm(sess: &Session) { pub fn early_error(output: config::ErrorOutputType, msg: &str) -> ! { let mut emitter: Box = match output { config::ErrorOutputType::HumanReadable(color_config) => { - Box::new(BasicEmitter::stderr(color_config)) + Box::new(EmitterWriter::stderr(color_config, + None, + None, + FormatMode::EnvironmentSelected)) } config::ErrorOutputType::Json => Box::new(JsonEmitter::basic()), }; @@ -588,7 +592,10 @@ pub fn early_error(output: config::ErrorOutputType, msg: &str) -> ! { pub fn early_warn(output: config::ErrorOutputType, msg: &str) { let mut emitter: Box = match output { config::ErrorOutputType::HumanReadable(color_config) => { - Box::new(BasicEmitter::stderr(color_config)) + Box::new(EmitterWriter::stderr(color_config, + None, + None, + FormatMode::EnvironmentSelected)) } config::ErrorOutputType::Json => Box::new(JsonEmitter::basic()), }; diff --git a/src/librustc_driver/lib.rs b/src/librustc_driver/lib.rs index 84e0403192317..695e9062db334 100644 --- a/src/librustc_driver/lib.rs +++ b/src/librustc_driver/lib.rs @@ -100,6 +100,7 @@ use syntax::feature_gate::{GatedCfg, UnstableFeatures}; use syntax::parse::{self, PResult}; use syntax_pos::MultiSpan; use errors::emitter::Emitter; +use errors::snippet::FormatMode; #[cfg(test)] pub mod test; @@ -139,7 +140,10 @@ pub fn run(args: Vec) -> isize { Some(sess) => sess.fatal(&abort_msg(err_count)), None => { let mut emitter = - errors::emitter::BasicEmitter::stderr(errors::ColorConfig::Auto); + errors::emitter::EmitterWriter::stderr(errors::ColorConfig::Auto, + None, + None, + FormatMode::EnvironmentSelected); emitter.emit(&MultiSpan::new(), &abort_msg(err_count), None, errors::Level::Fatal); exit_on_err(); @@ -375,7 +379,10 @@ fn check_cfg(sopts: &config::Options, output: ErrorOutputType) { let mut emitter: Box = match output { config::ErrorOutputType::HumanReadable(color_config) => { - Box::new(errors::emitter::BasicEmitter::stderr(color_config)) + Box::new(errors::emitter::EmitterWriter::stderr(color_config, + None, + None, + FormatMode::EnvironmentSelected)) } config::ErrorOutputType::Json => Box::new(json::JsonEmitter::basic()), }; @@ -1046,7 +1053,11 @@ pub fn monitor(f: F) { if let Err(value) = thread.unwrap().join() { // Thread panicked without emitting a fatal diagnostic if !value.is::() { - let mut emitter = errors::emitter::BasicEmitter::stderr(errors::ColorConfig::Auto); + let mut emitter = + errors::emitter::EmitterWriter::stderr(errors::ColorConfig::Auto, + None, + None, + FormatMode::EnvironmentSelected); // a .span_bug or .bug call has already printed what // it wants to print. diff --git a/src/librustc_errors/emitter.rs b/src/librustc_errors/emitter.rs index a7c68e3a87b31..75c35869e9e9d 100644 --- a/src/librustc_errors/emitter.rs +++ b/src/librustc_errors/emitter.rs @@ -117,42 +117,10 @@ impl ColorConfig { } } -/// A basic emitter for when we don't have access to a codemap or registry. Used -/// for reporting very early errors, etc. -pub struct BasicEmitter { - dst: Destination, -} - -impl CoreEmitter for BasicEmitter { - fn emit_message(&mut self, - _rsp: &RenderSpan, - msg: &str, - code: Option<&str>, - lvl: Level, - _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); - } - } -} - -impl BasicEmitter { - pub fn stderr(color_config: ColorConfig) -> BasicEmitter { - if color_config.use_color() { - let dst = Destination::from_stderr(); - BasicEmitter { dst: dst } - } else { - BasicEmitter { dst: Raw(Box::new(io::stderr())) } - } - } -} - pub struct EmitterWriter { dst: Destination, registry: Option, - cm: Rc, + cm: Option>, /// Is this the first error emitted thus far? If not, we emit a /// `\n` before the top-level errors. @@ -194,7 +162,7 @@ macro_rules! println_maybe_styled { impl EmitterWriter { pub fn stderr(color_config: ColorConfig, registry: Option, - code_map: Rc, + code_map: Option>, format_mode: FormatMode) -> EmitterWriter { if color_config.use_color() { @@ -215,7 +183,7 @@ impl EmitterWriter { pub fn new(dst: Box, registry: Option, - code_map: Rc, + code_map: Option>, format_mode: FormatMode) -> EmitterWriter { EmitterWriter { dst: Raw(dst), @@ -257,7 +225,11 @@ impl EmitterWriter { if 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), + Some(ps) => if let Some(ref cm) = self.cm { + cm.span_to_string(ps) + } else { + "".to_string() + }, None => "".to_string() }; print_diagnostic(&mut self.dst, &loc, lvl, msg, Some(code))? @@ -270,7 +242,11 @@ impl EmitterWriter { if 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), + Some(ps) => if let Some(ref cm) = self.cm { + cm.span_to_string(ps) + } else { + "".to_string() + }, None => "".to_string() }; print_diagnostic(&mut self.dst, &loc, lvl, msg, code)? @@ -316,7 +292,11 @@ impl EmitterWriter { .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), + Some(ps) => if let Some(ref cm) = self.cm { + cm.span_to_string(ps) + } else { + "".to_string() + }, None => "".to_string() }; let msg = "run `rustc --explain ".to_string() + &code.to_string() + @@ -335,32 +315,34 @@ impl EmitterWriter { use std::borrow::Borrow; 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.borrow()); - let line_count = cmp::min(lines.lines.len(), MAX_HIGHLIGHT_LINES); - let display_lines = &lines.lines[..line_count]; - - let fm = &*lines.file; - // Calculate the widest number to format evenly - let max_digits = line_num_max_digits(display_lines.last().unwrap()); - - // print the suggestion without any line numbers, but leave - // space for them. This helps with lining up with previous - // snippets from the actual error being reported. - let mut lines = complete.lines(); - for line in lines.by_ref().take(MAX_HIGHLIGHT_LINES) { - write!(&mut self.dst, "{0}:{1:2$} {3}\n", - fm.name, "", max_digits, line)?; - } + if let Some(ref cm) = self.cm { + let lines = cm.span_to_lines(primary_span).unwrap(); + + assert!(!lines.lines.is_empty()); + + let complete = suggestion.splice_lines(cm.borrow()); + let line_count = cmp::min(lines.lines.len(), MAX_HIGHLIGHT_LINES); + let display_lines = &lines.lines[..line_count]; + + let fm = &*lines.file; + // Calculate the widest number to format evenly + let max_digits = line_num_max_digits(display_lines.last().unwrap()); + + // print the suggestion without any line numbers, but leave + // space for them. This helps with lining up with previous + // snippets from the actual error being reported. + let mut lines = complete.lines(); + for line in lines.by_ref().take(MAX_HIGHLIGHT_LINES) { + write!(&mut self.dst, "{0}:{1:2$} {3}\n", + fm.name, "", max_digits, line)?; + } - // if we elided some lines, add an ellipsis - if let Some(_) = lines.next() { - write!(&mut self.dst, "{0:1$} {0:2$} ...\n", - "", fm.name.len(), max_digits)?; + // if we elided some lines, add an ellipsis + if let Some(_) = lines.next() { + write!(&mut self.dst, "{0:1$} {0:2$} ...\n", + "", fm.name.len(), max_digits)?; + } } - Ok(()) } @@ -369,20 +351,26 @@ impl EmitterWriter { lvl: Level) -> io::Result<()> { + // Check to see if we have any lines to highlight, exit early if not + match self.cm { + None => return Ok(()), + _ => () + } + let old_school = match self.format_mode { FormatMode::NewErrorFormat => false, FormatMode::OriginalErrorFormat => true, FormatMode::EnvironmentSelected => check_old_skool() }; - let mut snippet_data = SnippetData::new(self.cm.clone(), + let mut snippet_data = SnippetData::new(self.cm.as_ref().unwrap().clone(), msp.primary_span(), self.format_mode.clone()); if old_school { let mut output_vec = vec![]; for span_label in msp.span_labels() { - let mut snippet_data = SnippetData::new(self.cm.clone(), + let mut snippet_data = SnippetData::new(self.cm.as_ref().unwrap().clone(), Some(span_label.span), self.format_mode.clone()); @@ -431,16 +419,18 @@ impl EmitterWriter { fn print_macro_backtrace(&mut self, sp: Span) -> io::Result<()> { - for trace in self.cm.macro_backtrace(sp) { - let mut diag_string = - format!("in this expansion of {}", trace.macro_decl_name); - if let Some(def_site_span) = trace.def_site_span { - diag_string.push_str( - &format!(" (defined in {})", - self.cm.span_to_filename(def_site_span))); + if let Some(ref cm) = self.cm { + for trace in cm.macro_backtrace(sp) { + let mut diag_string = + format!("in this expansion of {}", trace.macro_decl_name); + if let Some(def_site_span) = trace.def_site_span { + diag_string.push_str( + &format!(" (defined in {})", + cm.span_to_filename(def_site_span))); + } + let snippet = cm.span_to_string(trace.call_site); + print_diagnostic(&mut self.dst, &snippet, Note, &diag_string, None)?; } - let snippet = self.cm.span_to_string(trace.call_site); - print_diagnostic(&mut self.dst, &snippet, Note, &diag_string, None)?; } Ok(()) } diff --git a/src/librustc_errors/lib.rs b/src/librustc_errors/lib.rs index 18fc826f9aa4b..100e79b1954d5 100644 --- a/src/librustc_errors/lib.rs +++ b/src/librustc_errors/lib.rs @@ -423,7 +423,7 @@ impl Handler { registry: Option, can_emit_warnings: bool, treat_err_as_bug: bool, - cm: Rc) + cm: Option>) -> Handler { let emitter = Box::new(EmitterWriter::stderr(color_config, registry, cm, snippet::FormatMode::EnvironmentSelected)); diff --git a/src/librustdoc/core.rs b/src/librustdoc/core.rs index 49a3991ecbe0b..fc9ae73f5ce7e 100644 --- a/src/librustdoc/core.rs +++ b/src/librustdoc/core.rs @@ -131,7 +131,7 @@ pub fn run_core(search_paths: SearchPaths, None, true, false, - codemap.clone()); + Some(codemap.clone())); let dep_graph = DepGraph::new(false); let _ignore = dep_graph.in_ignore(); diff --git a/src/librustdoc/test.rs b/src/librustdoc/test.rs index bb69ba6e568d5..f9d0df9981a1d 100644 --- a/src/librustdoc/test.rs +++ b/src/librustdoc/test.rs @@ -77,7 +77,7 @@ pub fn run(input: &str, None, true, false, - codemap.clone()); + Some(codemap.clone())); let dep_graph = DepGraph::new(false); let _ignore = dep_graph.in_ignore(); @@ -229,7 +229,7 @@ fn runtest(test: &str, cratename: &str, cfgs: Vec, libs: SearchPaths, let codemap = Rc::new(CodeMap::new()); let emitter = errors::emitter::EmitterWriter::new(box Sink(data.clone()), None, - codemap.clone(), + Some(codemap.clone()), errors::snippet::FormatMode::EnvironmentSelected); let old = io::set_panic(box Sink(data.clone())); let _bomb = Bomb(data.clone(), old.unwrap_or(box io::stdout())); diff --git a/src/libsyntax/codemap.rs b/src/libsyntax/codemap.rs index 743f96d737e2d..3b93dc0c4d37f 100644 --- a/src/libsyntax/codemap.rs +++ b/src/libsyntax/codemap.rs @@ -1235,7 +1235,7 @@ r"blork2.rs:2:1: 2:12 let cm = Rc::new(CodeMap::new()); let mut ew = EmitterWriter::new(Box::new(Sink(data.clone())), None, - cm.clone(), + Some(cm.clone()), FormatMode::NewErrorFormat); let content = "abcdefg koksi @@ -1321,7 +1321,7 @@ r"blork2.rs:2:1: 2:12 let cm = Rc::new(CodeMap::new()); let mut diag = EmitterWriter::new(Box::new(Sink(data.clone())), None, - cm.clone(), + Some(cm.clone()), FormatMode::NewErrorFormat); let inp = "_____aaaaaa____bbbbbb__cccccdd_"; @@ -1377,7 +1377,7 @@ r"blork2.rs:2:1: 2:12 let cm = Rc::new(CodeMap::new()); let mut diag = EmitterWriter::new(Box::new(Sink(data.clone())), None, - cm.clone(), + Some(cm.clone()), FormatMode::NewErrorFormat); let inp = "aaaaa\n\ diff --git a/src/libsyntax/parse/lexer/mod.rs b/src/libsyntax/parse/lexer/mod.rs index 77b5c10899a3d..5ea1d6be9fec9 100644 --- a/src/libsyntax/parse/lexer/mod.rs +++ b/src/libsyntax/parse/lexer/mod.rs @@ -1686,7 +1686,7 @@ mod tests { // FIXME (#22405): Replace `Box::new` with `box` here when/if possible. let emitter = errors::emitter::EmitterWriter::new(Box::new(io::sink()), None, - cm, + Some(cm), errors::snippet::FormatMode::EnvironmentSelected); errors::Handler::with_emitter(true, false, Box::new(emitter)) } diff --git a/src/libsyntax/parse/mod.rs b/src/libsyntax/parse/mod.rs index 9502bc48a3e11..6af4d95e888ac 100644 --- a/src/libsyntax/parse/mod.rs +++ b/src/libsyntax/parse/mod.rs @@ -50,7 +50,11 @@ pub struct ParseSess { impl ParseSess { pub fn new() -> ParseSess { let cm = Rc::new(CodeMap::new()); - let handler = Handler::with_tty_emitter(ColorConfig::Auto, None, true, false, cm.clone()); + let handler = Handler::with_tty_emitter(ColorConfig::Auto, + None, + true, + false, + Some(cm.clone())); ParseSess::with_span_handler(handler, cm) } From 55f06883b83bb652d7a8f036c15136abeb933048 Mon Sep 17 00:00:00 2001 From: Jonathan Turner Date: Wed, 6 Jul 2016 12:08:16 -0400 Subject: [PATCH 02/19] Remove emit from emitter, leaving emit_struct --- src/librustc/session/mod.rs | 10 +++--- src/librustc_driver/lib.rs | 34 +++++++++++--------- src/librustc_errors/emitter.rs | 16 ---------- src/librustc_errors/lib.rs | 57 ++++++++++++++++++++++++++-------- src/libsyntax/json.rs | 25 +-------------- 5 files changed, 71 insertions(+), 71 deletions(-) diff --git a/src/librustc/session/mod.rs b/src/librustc/session/mod.rs index 3939f5f5880a9..fa9bc7c83680c 100644 --- a/src/librustc/session/mod.rs +++ b/src/librustc/session/mod.rs @@ -576,7 +576,7 @@ unsafe fn configure_llvm(sess: &Session) { } pub fn early_error(output: config::ErrorOutputType, msg: &str) -> ! { - let mut emitter: Box = match output { + let emitter: Box = match output { config::ErrorOutputType::HumanReadable(color_config) => { Box::new(EmitterWriter::stderr(color_config, None, @@ -585,12 +585,13 @@ pub fn early_error(output: config::ErrorOutputType, msg: &str) -> ! { } config::ErrorOutputType::Json => Box::new(JsonEmitter::basic()), }; - emitter.emit(&MultiSpan::new(), msg, None, errors::Level::Fatal); + let handler = errors::Handler::with_emitter(true, false, emitter); + handler.emit(&MultiSpan::new(), msg, errors::Level::Fatal); panic!(errors::FatalError); } pub fn early_warn(output: config::ErrorOutputType, msg: &str) { - let mut emitter: Box = match output { + let emitter: Box = match output { config::ErrorOutputType::HumanReadable(color_config) => { Box::new(EmitterWriter::stderr(color_config, None, @@ -599,7 +600,8 @@ pub fn early_warn(output: config::ErrorOutputType, msg: &str) { } config::ErrorOutputType::Json => Box::new(JsonEmitter::basic()), }; - emitter.emit(&MultiSpan::new(), msg, None, errors::Level::Warning); + let handler = errors::Handler::with_emitter(true, false, emitter); + handler.emit(&MultiSpan::new(), msg, 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 695e9062db334..0a8df923b846b 100644 --- a/src/librustc_driver/lib.rs +++ b/src/librustc_driver/lib.rs @@ -139,13 +139,15 @@ pub fn run(args: Vec) -> isize { match session { Some(sess) => sess.fatal(&abort_msg(err_count)), None => { - let mut emitter = + let emitter = errors::emitter::EmitterWriter::stderr(errors::ColorConfig::Auto, None, None, FormatMode::EnvironmentSelected); - emitter.emit(&MultiSpan::new(), &abort_msg(err_count), None, - errors::Level::Fatal); + let handler = errors::Handler::with_emitter(true, false, Box::new(emitter)); + handler.emit(&MultiSpan::new(), + &abort_msg(err_count), + errors::Level::Fatal); exit_on_err(); } } @@ -377,7 +379,7 @@ fn handle_explain(code: &str, fn check_cfg(sopts: &config::Options, output: ErrorOutputType) { - let mut emitter: Box = match output { + let emitter: Box = match output { config::ErrorOutputType::HumanReadable(color_config) => { Box::new(errors::emitter::EmitterWriter::stderr(color_config, None, @@ -386,17 +388,17 @@ fn check_cfg(sopts: &config::Options, } config::ErrorOutputType::Json => Box::new(json::JsonEmitter::basic()), }; + let handler = errors::Handler::with_emitter(true, false, emitter); let mut saw_invalid_predicate = false; for item in sopts.cfg.iter() { match item.node { ast::MetaItemKind::List(ref pred, _) => { saw_invalid_predicate = true; - emitter.emit(&MultiSpan::new(), + handler.emit(&MultiSpan::new(), &format!("invalid predicate in --cfg command line argument: `{}`", pred), - None, - errors::Level::Fatal); + errors::Level::Fatal); } _ => {}, } @@ -1053,30 +1055,34 @@ pub fn monitor(f: F) { if let Err(value) = thread.unwrap().join() { // Thread panicked without emitting a fatal diagnostic if !value.is::() { - let mut emitter = - errors::emitter::EmitterWriter::stderr(errors::ColorConfig::Auto, + let emitter = + Box::new(errors::emitter::EmitterWriter::stderr(errors::ColorConfig::Auto, None, None, - FormatMode::EnvironmentSelected); + FormatMode::EnvironmentSelected)); + let handler = errors::Handler::with_emitter(true, false, emitter); // a .span_bug or .bug call has already printed what // it wants to print. if !value.is::() { - emitter.emit(&MultiSpan::new(), "unexpected panic", None, errors::Level::Bug); + handler.emit(&MultiSpan::new(), + "unexpected panic", + 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(&MultiSpan::new(), ¬e[..], None, errors::Level::Note) + handler.emit(&MultiSpan::new(), + ¬e[..], + errors::Level::Note); } if match env::var_os("RUST_BACKTRACE") { Some(val) => &val != "0", None => false, } { - emitter.emit(&MultiSpan::new(), + handler.emit(&MultiSpan::new(), "run with `RUST_BACKTRACE=1` for a backtrace", - None, errors::Level::Note); } diff --git a/src/librustc_errors/emitter.rs b/src/librustc_errors/emitter.rs index 75c35869e9e9d..ab331239cdbaf 100644 --- a/src/librustc_errors/emitter.rs +++ b/src/librustc_errors/emitter.rs @@ -28,9 +28,6 @@ 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); - /// Emit a structured diagnostic. fn emit_struct(&mut self, db: &DiagnosticBuilder); } @@ -46,19 +43,6 @@ pub trait CoreEmitter { } impl Emitter for T { - fn emit(&mut self, - msp: &MultiSpan, - msg: &str, - code: Option<&str>, - lvl: Level) { - self.emit_message(&FullSpan(msp.clone()), - msg, - code, - lvl, - true, - true); - } - fn emit_struct(&mut self, db: &DiagnosticBuilder) { let old_school = check_old_skool(); let db_span = FullSpan(db.span.clone()); diff --git a/src/librustc_errors/lib.rs b/src/librustc_errors/lib.rs index 100e79b1954d5..e3e63341ee906 100644 --- a/src/librustc_errors/lib.rs +++ b/src/librustc_errors/lib.rs @@ -359,11 +359,20 @@ impl<'a> DiagnosticBuilder<'a> { fn new(handler: &'a Handler, level: Level, message: &str) -> DiagnosticBuilder<'a> { + DiagnosticBuilder::new_with_code(handler, level, None, message) + } + + /// Convenience function for internal use, clients should use one of the + /// struct_* methods on Handler. + fn new_with_code(handler: &'a Handler, + level: Level, + code: Option, + message: &str) -> DiagnosticBuilder<'a> { DiagnosticBuilder { handler: handler, level: level, message: message.to_owned(), - code: None, + code: code, span: MultiSpan::new(), children: vec![], } @@ -397,10 +406,10 @@ impl<'a> fmt::Debug for DiagnosticBuilder<'a> { impl<'a> Drop for DiagnosticBuilder<'a> { fn drop(&mut self) { if !panicking() && !self.cancelled() { - self.handler.emit.borrow_mut().emit(&MultiSpan::new(), - "Error constructed but not emitted", - None, - Bug); + let mut db = DiagnosticBuilder::new(self.handler, + Bug, + "Error constructed but not emitted"); + db.emit(); panic!(); } } @@ -588,7 +597,7 @@ impl Handler { self.bump_err_count(); } pub fn span_note_without_error>(&self, sp: S, msg: &str) { - self.emit.borrow_mut().emit(&sp.into(), msg, None, Note); + self.emit(&sp.into(), msg, Note); } pub fn span_unimpl>(&self, sp: S, msg: &str) -> ! { self.span_bug(sp, &format!("unimplemented {}", msg)); @@ -597,7 +606,10 @@ impl Handler { if self.treat_err_as_bug { self.bug(msg); } - self.emit.borrow_mut().emit(&MultiSpan::new(), msg, None, Fatal); + let mut db = DiagnosticBuilder::new(self, + Fatal, + msg); + db.emit(); self.bump_err_count(); FatalError } @@ -605,17 +617,29 @@ impl Handler { if self.treat_err_as_bug { self.bug(msg); } - self.emit.borrow_mut().emit(&MultiSpan::new(), msg, None, Error); + let mut db = DiagnosticBuilder::new(self, + Error, + msg); + db.emit(); self.bump_err_count(); } pub fn warn(&self, msg: &str) { - self.emit.borrow_mut().emit(&MultiSpan::new(), msg, None, Warning); + let mut db = DiagnosticBuilder::new(self, + Warning, + msg); + db.emit(); } pub fn note_without_error(&self, msg: &str) { - self.emit.borrow_mut().emit(&MultiSpan::new(), msg, None, Note); + let mut db = DiagnosticBuilder::new(self, + Note, + msg); + db.emit(); } pub fn bug(&self, msg: &str) -> ! { - self.emit.borrow_mut().emit(&MultiSpan::new(), msg, None, Bug); + let mut db = DiagnosticBuilder::new(self, + Bug, + msg); + db.emit(); panic!(ExplicitBug); } pub fn unimpl(&self, msg: &str) -> ! { @@ -661,7 +685,9 @@ impl Handler { msg: &str, lvl: Level) { if lvl == Warning && !self.can_emit_warnings { return } - self.emit.borrow_mut().emit(&msp, msg, None, lvl); + let mut db = DiagnosticBuilder::new(self, lvl, msg); + db.set_span(msp.clone()); + db.emit(); if !self.continue_after_error.get() { self.abort_if_errors(); } } pub fn emit_with_code(&self, @@ -670,7 +696,12 @@ impl Handler { code: &str, lvl: Level) { if lvl == Warning && !self.can_emit_warnings { return } - self.emit.borrow_mut().emit(&msp, msg, Some(code), lvl); + let mut db = DiagnosticBuilder::new_with_code(self, + lvl, + Some(code.to_owned()), + msg); + db.set_span(msp.clone()); + db.emit(); if !self.continue_after_error.get() { self.abort_if_errors(); } } } diff --git a/src/libsyntax/json.rs b/src/libsyntax/json.rs index dc9a5ee46645f..20908453e73e0 100644 --- a/src/libsyntax/json.rs +++ b/src/libsyntax/json.rs @@ -22,7 +22,7 @@ use codemap::CodeMap; use syntax_pos::{self, MacroBacktrace, Span, SpanLabel, MultiSpan}; use errors::registry::Registry; -use errors::{Level, DiagnosticBuilder, SubDiagnostic, RenderSpan, CodeSuggestion, CodeMapper}; +use errors::{DiagnosticBuilder, SubDiagnostic, RenderSpan, CodeSuggestion, CodeMapper}; use errors::emitter::Emitter; use std::rc::Rc; @@ -53,13 +53,6 @@ impl JsonEmitter { } impl Emitter for JsonEmitter { - 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 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)) { @@ -146,22 +139,6 @@ struct DiagnosticCode { } impl<'a> Diagnostic<'a> { - fn new(msp: &MultiSpan, - msg: &'a str, - code: Option<&str>, - level: Level, - je: &JsonEmitter) - -> Diagnostic<'a> { - Diagnostic { - message: msg, - code: DiagnosticCode::map_opt_string(code.map(|c| c.to_owned()), je), - level: level.to_str(), - spans: DiagnosticSpan::from_multispan(msp, je), - children: vec![], - rendered: None, - } - } - fn from_diagnostic_builder<'c>(db: &'c DiagnosticBuilder, je: &JsonEmitter) -> Diagnostic<'c> { From a6e7239e7b5db3a96fb6b84c41ecbced64b0ad2e Mon Sep 17 00:00:00 2001 From: Jonathan Turner Date: Thu, 7 Jul 2016 07:50:49 -0400 Subject: [PATCH 03/19] Rename emit_struct->emit --- src/librustc_errors/emitter.rs | 4 ++-- src/librustc_errors/lib.rs | 6 +++--- src/libsyntax/json.rs | 2 +- 3 files changed, 6 insertions(+), 6 deletions(-) diff --git a/src/librustc_errors/emitter.rs b/src/librustc_errors/emitter.rs index ab331239cdbaf..697f9687b0a15 100644 --- a/src/librustc_errors/emitter.rs +++ b/src/librustc_errors/emitter.rs @@ -29,7 +29,7 @@ use term; /// implement `CoreEmitter` instead. pub trait Emitter { /// Emit a structured diagnostic. - fn emit_struct(&mut self, db: &DiagnosticBuilder); + fn emit(&mut self, db: &DiagnosticBuilder); } pub trait CoreEmitter { @@ -43,7 +43,7 @@ pub trait CoreEmitter { } impl Emitter for T { - fn emit_struct(&mut self, db: &DiagnosticBuilder) { + fn emit(&mut self, db: &DiagnosticBuilder) { let old_school = check_old_skool(); let db_span = FullSpan(db.span.clone()); self.emit_message(&FullSpan(db.span.clone()), diff --git a/src/librustc_errors/lib.rs b/src/librustc_errors/lib.rs index e3e63341ee906..7c14c132382e7 100644 --- a/src/librustc_errors/lib.rs +++ b/src/librustc_errors/lib.rs @@ -238,7 +238,7 @@ impl<'a> DiagnosticBuilder<'a> { return; } - self.handler.emit.borrow_mut().emit_struct(&self); + self.handler.emitter.borrow_mut().emit(&self); self.cancel(); self.handler.panic_if_treat_err_as_bug(); @@ -420,7 +420,7 @@ impl<'a> Drop for DiagnosticBuilder<'a> { /// others log errors for later reporting. pub struct Handler { err_count: Cell, - emit: RefCell>, + emitter: RefCell>, pub can_emit_warnings: bool, treat_err_as_bug: bool, continue_after_error: Cell, @@ -444,7 +444,7 @@ impl Handler { e: Box) -> Handler { Handler { err_count: Cell::new(0), - emit: RefCell::new(e), + emitter: RefCell::new(e), can_emit_warnings: can_emit_warnings, treat_err_as_bug: treat_err_as_bug, continue_after_error: Cell::new(true), diff --git a/src/libsyntax/json.rs b/src/libsyntax/json.rs index 20908453e73e0..a40c30b3e3397 100644 --- a/src/libsyntax/json.rs +++ b/src/libsyntax/json.rs @@ -53,7 +53,7 @@ impl JsonEmitter { } impl Emitter for JsonEmitter { - fn emit_struct(&mut self, db: &DiagnosticBuilder) { + fn emit(&mut self, db: &DiagnosticBuilder) { let data = Diagnostic::from_diagnostic_builder(db, self); if let Err(e) = writeln!(&mut self.dst, "{}", as_json(&data)) { panic!("failed to print diagnostics: {:?}", e); From a019c2c6bad2bae7e0f5c527ea8a11615acc037f Mon Sep 17 00:00:00 2001 From: Jonathan Turner Date: Thu, 7 Jul 2016 14:57:09 -0400 Subject: [PATCH 04/19] Remove CoreEmitter and focus on Emitter --- src/librustc_driver/test.rs | 19 ++++---- src/librustc_errors/emitter.rs | 79 +++++++++++++++----------------- src/librustc_trans/back/write.rs | 28 +++++------ 3 files changed, 58 insertions(+), 68 deletions(-) diff --git a/src/librustc_driver/test.rs b/src/librustc_driver/test.rs index 911becd3f569b..ace469680df27 100644 --- a/src/librustc_driver/test.rs +++ b/src/librustc_driver/test.rs @@ -33,8 +33,8 @@ use syntax::ast; use syntax::abi::Abi; use syntax::codemap::CodeMap; use errors; -use errors::emitter::{CoreEmitter, Emitter}; -use errors::{Level, RenderSpan}; +use errors::emitter::Emitter; +use errors::{Level, RenderSpan, DiagnosticBuilder}; use syntax::parse::token; use syntax::feature_gate::UnstableFeatures; use syntax_pos::DUMMY_SP; @@ -76,15 +76,12 @@ fn remove_message(e: &mut ExpectErrorEmitter, msg: &str, lvl: Level) { } } -impl CoreEmitter for ExpectErrorEmitter { - fn emit_message(&mut self, - _sp: &RenderSpan, - msg: &str, - _: Option<&str>, - lvl: Level, - _is_header: bool, - _show_snippet: bool) { - remove_message(self, msg, lvl); +impl Emitter for ExpectErrorEmitter { + fn emit(&mut self, db: &DiagnosticBuilder) { + remove_message(self, db.message, lvl); + for child in &db.children { + remove_message(self, &child.message, child.level); + } } } diff --git a/src/librustc_errors/emitter.rs b/src/librustc_errors/emitter.rs index 697f9687b0a15..a0d7120dd4f46 100644 --- a/src/librustc_errors/emitter.rs +++ b/src/librustc_errors/emitter.rs @@ -25,47 +25,29 @@ use std::io; use std::rc::Rc; use term; -/// Emitter trait for emitting errors. Do not implement this directly: -/// implement `CoreEmitter` instead. +/// Emitter trait for emitting errors. pub trait Emitter { /// Emit a structured diagnostic. fn emit(&mut self, db: &DiagnosticBuilder); } -pub trait CoreEmitter { - fn emit_message(&mut self, - rsp: &RenderSpan, - msg: &str, - code: Option<&str>, - lvl: Level, - is_header: bool, - show_snippet: bool); -} - -impl Emitter for T { +impl Emitter for EmitterWriter { fn emit(&mut self, db: &DiagnosticBuilder) { - let old_school = check_old_skool(); - 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())); - if !old_school { - self.emit_message(&render_span, - &child.message, - None, - child.level, - false, - true); - } else { + if check_old_skool() { + let db_span = FullSpan(db.span.clone()); + + for child in &db.children { + let render_span = child.render_span + .clone() + .unwrap_or_else( + || FullSpan(child.span.clone())); let (render_span, show_snippet) = match render_span.span().primary_span() { None => (db_span.clone(), false), _ => (render_span, true) @@ -77,6 +59,19 @@ impl Emitter for T { false, show_snippet); } + } else { + 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, + true); + } } } } @@ -114,21 +109,6 @@ pub struct EmitterWriter { format_mode: FormatMode } -impl CoreEmitter for EmitterWriter { - fn emit_message(&mut self, - rsp: &RenderSpan, - msg: &str, - code: Option<&str>, - lvl: Level, - is_header: bool, - show_snippet: bool) { - match self.emit_message_(rsp, msg, code, lvl, is_header, show_snippet) { - Ok(()) => { } - Err(e) => panic!("failed to emit error: {}", e) - } - } -} - /// Do not use this for messages that end in `\n` – use `println_maybe_styled` instead. See /// `EmitterWriter::print_maybe_styled` for details. macro_rules! print_maybe_styled { @@ -177,6 +157,19 @@ impl EmitterWriter { format_mode: format_mode.clone() } } + fn emit_message(&mut self, + rsp: &RenderSpan, + msg: &str, + code: Option<&str>, + lvl: Level, + is_header: bool, + show_snippet: bool) { + match self.emit_message_(rsp, msg, code, lvl, is_header, show_snippet) { + Ok(()) => { } + Err(e) => panic!("failed to emit error: {}", e) + } + } + fn emit_message_(&mut self, rsp: &RenderSpan, msg: &str, diff --git a/src/librustc_trans/back/write.rs b/src/librustc_trans/back/write.rs index 071960f1944cf..33cffa8a48013 100644 --- a/src/librustc_trans/back/write.rs +++ b/src/librustc_trans/back/write.rs @@ -19,8 +19,8 @@ use llvm::SMDiagnosticRef; use {CrateTranslation, ModuleTranslation}; use util::common::time; use util::common::path2cstr; -use errors::{self, Handler, Level, RenderSpan}; -use errors::emitter::CoreEmitter; +use errors::{self, Handler, Level, DiagnosticBuilder}; +use errors::emitter::Emitter; use syntax_pos::MultiSpan; use std::collections::HashMap; @@ -100,23 +100,23 @@ impl SharedEmitter { } } -impl CoreEmitter for SharedEmitter { - fn emit_message(&mut self, - _rsp: &RenderSpan, - msg: &str, - code: Option<&str>, - lvl: Level, - _is_header: bool, - _show_snippet: bool) { +impl Emitter for SharedEmitter { + fn emit(&mut self, db: &DiagnosticBuilder) { self.buffer.lock().unwrap().push(Diagnostic { - msg: msg.to_string(), - code: code.map(|s| s.to_string()), - lvl: lvl, + msg: db.message.to_string(), + code: db.code.clone(), + lvl: db.level, }); + for child in &db.children { + self.buffer.lock().unwrap().push(Diagnostic { + msg: child.message.to_string(), + code: None, + lvl: child.level, + }); + } } } - // On android, we by default compile for armv7 processors. This enables // things like double word CAS instructions (rather than emulating them) // which are *far* more efficient. This is obviously undesirable in some From 71ec2867e3c4cc448cb64890daffd1d5ffbe353b Mon Sep 17 00:00:00 2001 From: Jonathan Turner Date: Mon, 11 Jul 2016 16:02:03 -0400 Subject: [PATCH 05/19] Implement latest rfc style using simpler rendering --- src/librustc_errors/emitter.rs | 666 +++++++++++++++++++++++++++++++-- src/librustc_errors/lib.rs | 1 + src/librustc_errors/snippet.rs | 216 ++++------- src/libsyntax/test.rs | 2 +- src/libsyntax_pos/lib.rs | 2 +- 5 files changed, 693 insertions(+), 194 deletions(-) diff --git a/src/librustc_errors/emitter.rs b/src/librustc_errors/emitter.rs index a0d7120dd4f46..52c0ea931408f 100644 --- a/src/librustc_errors/emitter.rs +++ b/src/librustc_errors/emitter.rs @@ -10,14 +10,15 @@ use self::Destination::*; -use syntax_pos::{COMMAND_LINE_SP, DUMMY_SP, Span, MultiSpan, LineInfo}; +use syntax_pos::{COMMAND_LINE_SP, DUMMY_SP, FileMap, Span, MultiSpan, LineInfo, CharPos}; use registry; use check_old_skool; use {Level, RenderSpan, CodeSuggestion, DiagnosticBuilder, CodeMapper}; use RenderSpan::*; use Level::*; -use snippet::{RenderedLineKind, SnippetData, Style, FormatMode}; +use snippet::{SnippetData, StyledString, Style, FormatMode, Annotation, Line}; +use styled_buffer::StyledBuffer; use std::{cmp, fmt}; use std::io::prelude::*; @@ -33,14 +34,13 @@ pub trait Emitter { impl Emitter for EmitterWriter { fn emit(&mut self, db: &DiagnosticBuilder) { - self.emit_message(&FullSpan(db.span.clone()), - &db.message, - db.code.as_ref().map(|s| &**s), - db.level, - true, - true); - if check_old_skool() { + self.emit_message(&FullSpan(db.span.clone()), + &db.message, + db.code.as_ref().map(|s| &**s), + db.level, + true, + true); let db_span = FullSpan(db.span.clone()); for child in &db.children { @@ -60,18 +60,7 @@ impl Emitter for EmitterWriter { show_snippet); } } else { - 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, - true); - } + self.emit_messages_default(db); } } } @@ -109,6 +98,12 @@ pub struct EmitterWriter { format_mode: FormatMode } +struct FileWithAnnotatedLines { + file: Rc, + lines: Vec, +} + + /// Do not use this for messages that end in `\n` – use `println_maybe_styled` instead. See /// `EmitterWriter::print_maybe_styled` for details. macro_rules! print_maybe_styled { @@ -170,6 +165,560 @@ impl EmitterWriter { } } + fn preprocess_annotations(&self, msp: &MultiSpan) -> Vec { + fn add_annotation_to_file(file_vec: &mut Vec, + file: Rc, + line_index: usize, + ann: Annotation) { + + for slot in file_vec.iter_mut() { + // Look through each of our files for the one we're adding to + if slot.file.name == file.name { + // See if we already have a line for it + for line_slot in &mut slot.lines { + if line_slot.line_index == line_index { + line_slot.annotations.push(ann); + return; + } + } + // We don't have a line yet, create one + slot.lines.push(Line { + line_index: line_index, + annotations: vec![ann], + }); + slot.lines.sort(); + return; + } + } + // This is the first time we're seeing the file + file_vec.push(FileWithAnnotatedLines { + file: file, + lines: vec![Line { + line_index: line_index, + annotations: vec![ann], + }], + }); + } + + let mut output = vec![]; + + if let Some(ref cm) = self.cm { + for span_label in msp.span_labels() { + let lo = cm.lookup_char_pos(span_label.span.lo); + let hi = cm.lookup_char_pos(span_label.span.hi); + + // If the span is multi-line, simplify down to the span of one character + let (start_col, mut end_col, is_minimized) = if lo.line != hi.line { + (lo.col, CharPos(lo.col.0 + 1), true) + } else { + (lo.col, hi.col, false) + }; + + // Watch out for "empty spans". If we get a span like 6..6, we + // want to just display a `^` at 6, so convert that to + // 6..7. This is degenerate input, but it's best to degrade + // gracefully -- and the parser likes to supply a span like + // that for EOF, in particular. + if start_col == end_col { + end_col.0 += 1; + } + + add_annotation_to_file(&mut output, + lo.file, + lo.line, + Annotation { + start_col: lo.col.0, + end_col: hi.col.0, + is_primary: span_label.is_primary, + is_minimized: is_minimized, + label: span_label.label.clone(), + }); + } + } + output + } + + fn render_source_line(&self, + buffer: &mut StyledBuffer, + file: Rc, + line: &Line, + width_offset: usize) { + let source_string = file.get_line(line.line_index - 1) + .unwrap_or(""); + + let line_offset = buffer.num_lines(); + + // First create the source line we will highlight. + buffer.puts(line_offset, width_offset, &source_string, Style::Quotation); + buffer.puts(line_offset, + 0, + &(line.line_index.to_string()), + Style::LineNumber); + + draw_col_separator(buffer, line_offset, width_offset - 2); + + if line.annotations.is_empty() { + return; + } + + // We want to display like this: + // + // vec.push(vec.pop().unwrap()); + // --- ^^^ _ previous borrow ends here + // | | + // | 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); + let old_school = check_old_skool(); + + // Sort the annotations by (start, end col) + let mut annotations = line.annotations.clone(); + annotations.sort(); + + // Next, create the highlight line. + for annotation in &annotations { + if old_school { + for p in annotation.start_col..annotation.end_col { + if p == annotation.start_col { + buffer.putc(line_offset + 1, + width_offset + p, + '^', + if annotation.is_primary { + Style::UnderlinePrimary + } else { + Style::OldSchoolNote + }); + } else { + buffer.putc(line_offset + 1, + width_offset + p, + '~', + if annotation.is_primary { + Style::UnderlinePrimary + } else { + Style::OldSchoolNote + }); + } + } + } else { + for p in annotation.start_col..annotation.end_col { + if annotation.is_primary { + buffer.putc(line_offset + 1, + width_offset + p, + '^', + Style::UnderlinePrimary); + if !annotation.is_minimized { + buffer.set_style(line_offset, + width_offset + p, + Style::UnderlinePrimary); + } + } else { + buffer.putc(line_offset + 1, + width_offset + p, + '-', + Style::UnderlineSecondary); + if !annotation.is_minimized { + buffer.set_style(line_offset, + width_offset + p, + Style::UnderlineSecondary); + } + } + } + } + } + draw_col_separator(buffer, line_offset + 1, width_offset - 2); + + // Now we are going to write labels in. To start, we'll exclude + // the annotations with no labels. + let (labeled_annotations, unlabeled_annotations): (Vec<_>, _) = annotations.into_iter() + .partition(|a| a.label.is_some()); + + // If there are no annotations that need text, we're done. + if labeled_annotations.is_empty() { + return; + } + if old_school { + return; + } + + // 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 { + buffer.append(line_offset + 1, &highlight_label, Style::LabelPrimary); + } else { + buffer.append(line_offset + 1, &highlight_label, Style::LabelSecondary); + } + labeled_annotations = previous; + } + } + } + + // If that's the last annotation, we're done + if labeled_annotations.is_empty() { + return; + } + + for (index, annotation) in labeled_annotations.iter().enumerate() { + // Leave: + // - 1 extra line + // - One line for each thing that comes after + let comes_after = labeled_annotations.len() - index - 1; + let blank_lines = 3 + comes_after; + + // For each blank line, draw a `|` at our column. The + // text ought to be long enough for this. + for index in 2..blank_lines { + if annotation.is_primary { + buffer.putc(line_offset + index, + width_offset + annotation.start_col, + '|', + Style::UnderlinePrimary); + } else { + buffer.putc(line_offset + index, + width_offset + annotation.start_col, + '|', + Style::UnderlineSecondary); + } + draw_col_separator(buffer, line_offset + index, width_offset - 2); + } + + if annotation.is_primary { + buffer.puts(line_offset + blank_lines, + width_offset + annotation.start_col, + annotation.label.as_ref().unwrap(), + Style::LabelPrimary); + } else { + buffer.puts(line_offset + blank_lines, + width_offset + annotation.start_col, + annotation.label.as_ref().unwrap(), + Style::LabelSecondary); + } + draw_col_separator(buffer, line_offset + blank_lines, width_offset - 2); + } + } + + fn get_multispan_max_line_num(&mut self, msp: &MultiSpan) -> usize { + let mut max = 0; + if let Some(ref cm) = self.cm { + for primary_span in msp.primary_spans() { + let hi = cm.lookup_char_pos(primary_span.hi); + if hi.line > max { + max = hi.line; + } + } + for span_label in msp.span_labels() { + let hi = cm.lookup_char_pos(span_label.span.hi); + if hi.line > max { + max = hi.line; + } + } + } + max + } + + fn get_max_line_num(&mut self, db: &DiagnosticBuilder) -> usize { + let mut max = 0; + + let primary = self.get_multispan_max_line_num(&db.span); + max = if primary > max { primary } else { max }; + + for sub in &db.children { + let sub_result = self.get_multispan_max_line_num(&sub.span); + max = if sub_result > max { primary } else { max }; + } + max + } + + fn emit_message_default(&mut self, + msp: &MultiSpan, + msg: &str, + code: &Option, + level: &Level, + max_line_num_len: usize, + is_secondary: bool) + -> io::Result<()> { + let mut buffer = StyledBuffer::new(); + + if msp.primary_spans().is_empty() && msp.span_labels().is_empty() && is_secondary { + // This is a secondary message with no span info + for i in 0..max_line_num_len { + buffer.prepend(0, " ", Style::NoStyle); + } + draw_note_separator(&mut buffer, 0, max_line_num_len + 1); + buffer.append(0, &level.to_string(), Style::HeaderMsg); + buffer.append(0, ": ", Style::NoStyle); + buffer.append(0, msg, Style::NoStyle); + } + else { + buffer.append(0, &level.to_string(), Style::Level(level.clone())); + match code { + &Some(ref code) => { + buffer.append(0, "[", Style::Level(level.clone())); + buffer.append(0, &code, Style::Level(level.clone())); + buffer.append(0, "]", Style::Level(level.clone())); + } + _ => {} + } + buffer.append(0, ": ", Style::HeaderMsg); + buffer.append(0, msg, Style::HeaderMsg); + } + + // Preprocess all the annotations so that they are grouped by file and by line number + // This helps us quickly iterate over the whole message (including secondary file spans) + let mut annotated_files = self.preprocess_annotations(msp); + + // Make sure our primary file comes first + let primary_lo = + if let (Some(ref cm), Some(ref primary_span)) = (self.cm.as_ref(), + msp.primary_span().as_ref()) { + cm.lookup_char_pos(primary_span.lo) + } else { + // If we don't have span information, emit and exit + emit_to_destination(&buffer.render(), level, &mut self.dst); + return Ok(()); + }; + if let Ok(pos) = + annotated_files.binary_search_by(|x| x.file.name.cmp(&primary_lo.file.name)) { + annotated_files.swap(0, pos); + } + + // Print out the annotate source lines that correspond with the error + for annotated_file in annotated_files { + // print out the span location and spacer before we print the annotated source + // to do this, we need to know if this span will be primary + let is_primary = primary_lo.file.name == annotated_file.file.name; + if is_primary { + // remember where we are in the output buffer for easy reference + let mut buffer_msg_line_offset = buffer.num_lines(); + + buffer.prepend(buffer_msg_line_offset, "--> ", Style::LineNumber); + let loc = primary_lo.clone(); + buffer.append(buffer_msg_line_offset, + &format!("{}:{}:{}", loc.file.name, loc.line, loc.col.0), + Style::LineAndColumn); + for i in 0..max_line_num_len { + buffer.prepend(buffer_msg_line_offset, " ", Style::NoStyle); + } + } else { + // remember where we are in the output buffer for easy reference + let mut buffer_msg_line_offset = buffer.num_lines(); + + // Add spacing line + draw_col_separator(&mut buffer, buffer_msg_line_offset, max_line_num_len + 1); + + // Then, the secondary file indicator + buffer.prepend(buffer_msg_line_offset + 1, "::: ", Style::LineNumber); + buffer.append(buffer_msg_line_offset + 1, + &annotated_file.file.name, + Style::LineAndColumn); + for i in 0..max_line_num_len { + buffer.prepend(buffer_msg_line_offset + 1, " ", Style::NoStyle); + } + } + + // Put in the spacer between the location and annotated source + let mut buffer_msg_line_offset = buffer.num_lines(); + draw_col_separator(&mut buffer, buffer_msg_line_offset, max_line_num_len + 1); + + // Next, output the annotate source for this file + for line_idx in 0..annotated_file.lines.len() { + self.render_source_line(&mut buffer, + annotated_file.file.clone(), + &annotated_file.lines[line_idx], + 3 + max_line_num_len); + + // check to see if we need to print out or elide lines that come between + // this annotated line and the next one + if line_idx < (annotated_file.lines.len() - 1) { + let line_idx_delta = annotated_file.lines[line_idx + 1].line_index - + annotated_file.lines[line_idx].line_index; + if line_idx_delta > 2 { + let last_buffer_line_num = buffer.num_lines(); + buffer.puts(last_buffer_line_num, 0, "...", Style::LineNumber); + } else if line_idx_delta == 2 { + let unannotated_line = annotated_file.file + .get_line(annotated_file.lines[line_idx].line_index) + .unwrap_or(""); + + let last_buffer_line_num = buffer.num_lines(); + + buffer.puts(last_buffer_line_num, + 0, + &(annotated_file.lines[line_idx + 1].line_index - 1) + .to_string(), + Style::LineNumber); + draw_col_separator(&mut buffer, last_buffer_line_num, 1 + max_line_num_len); + buffer.puts(last_buffer_line_num, + 3 + max_line_num_len, + &unannotated_line, + Style::Quotation); + } + } + } + } + + // final step: take our styled buffer, render it, then output it + emit_to_destination(&buffer.render(), level, &mut self.dst); + + Ok(()) + } + fn emit_suggestion_default(&mut self, + suggestion: &CodeSuggestion, + level: &Level, + msg: &str, + max_line_num_len: usize) + -> io::Result<()> { + use std::borrow::Borrow; + + let primary_span = suggestion.msp.primary_span().unwrap(); + if let Some(ref cm) = self.cm { + let mut buffer = StyledBuffer::new(); + + buffer.append(0, &level.to_string(), Style::Level(level.clone())); + buffer.append(0, ": ", Style::HeaderMsg); + buffer.append(0, msg, Style::HeaderMsg); + + let lines = cm.span_to_lines(primary_span).unwrap(); + + assert!(!lines.lines.is_empty()); + + let complete = suggestion.splice_lines(cm.borrow()); + let line_count = cmp::min(lines.lines.len(), MAX_HIGHLIGHT_LINES); + let display_lines = &lines.lines[..line_count]; + + let fm = &*lines.file; + // Calculate the widest number to format evenly + let max_digits = line_num_max_digits(display_lines.last().unwrap()); + + // print the suggestion without any line numbers, but leave + // space for them. This helps with lining up with previous + // snippets from the actual error being reported. + let mut lines = complete.lines(); + let mut row_num = 1; + for line in lines.by_ref().take(MAX_HIGHLIGHT_LINES) { + draw_col_separator(&mut buffer, row_num, max_line_num_len + 1); + buffer.append(row_num, line, Style::NoStyle); + row_num += 1; + } + + // if we elided some lines, add an ellipsis + if let Some(_) = lines.next() { + buffer.append(row_num, "...", Style::NoStyle); + } + emit_to_destination(&buffer.render(), level, &mut self.dst); + } + Ok(()) + } + fn emit_messages_default(&mut self, db: &DiagnosticBuilder) { + let max_line_num = self.get_max_line_num(db); + let max_line_num_len = max_line_num.to_string().len(); + + match self.emit_message_default(&db.span, + &db.message, + &db.code, + &db.level, + max_line_num_len, + false) { + Ok(()) => { + if !db.children.is_empty() { + let mut buffer = StyledBuffer::new(); + draw_col_separator(&mut buffer, 0, max_line_num_len + 1); + emit_to_destination(&buffer.render(), &db.level, &mut self.dst); + } + for child in &db.children { + match child.render_span { + Some(FullSpan(ref msp)) => { + match self.emit_message_default(msp, + &child.message, + &None, + &child.level, + max_line_num_len, + true) { + Err(e) => panic!("failed to emit error: {}", e), + _ => () + } + }, + Some(Suggestion(ref cs)) => { + match self.emit_suggestion_default(cs, + &child.level, + &child.message, + max_line_num_len) { + Err(e) => panic!("failed to emit error: {}", e), + _ => () + } + }, + None => { + match self.emit_message_default(&child.span, + &child.message, + &None, + &child.level, + max_line_num_len, + true) { + Err(e) => panic!("failed to emit error: {}", e), + _ => () + } + } + } + } + } + Err(e) => panic!("failed to emit error: {}", e) + } + write!(&mut self.dst, "\n"); + } + fn emit_message_(&mut self, rsp: &RenderSpan, msg: &str, @@ -363,6 +912,7 @@ impl EmitterWriter { } 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 { @@ -372,6 +922,8 @@ impl EmitterWriter { } write!(&mut self.dst, "\n")?; } + */ + emit_to_destination(&snippet_data.render_lines(), &lvl, &mut self.dst); } } else { @@ -380,6 +932,8 @@ impl EmitterWriter { span_label.is_primary, span_label.label); } + emit_to_destination(&snippet_data.render_lines(), &lvl, &mut self.dst); + /* let rendered_lines = snippet_data.render_lines(); for rendered_line in &rendered_lines { for styled_string in &rendered_line.text { @@ -389,6 +943,7 @@ impl EmitterWriter { } write!(&mut self.dst, "\n")?; } + */ } Ok(()) } @@ -413,6 +968,33 @@ impl EmitterWriter { } } +fn draw_col_separator(buffer: &mut StyledBuffer, line: usize, col: usize) { + buffer.puts(line, col, "| ", Style::LineNumber); +} + +fn draw_note_separator(buffer: &mut StyledBuffer, line: usize, col: usize) { + buffer.puts(line, col, "= ", Style::LineNumber); +} + +fn overlaps(a1: &Annotation, a2: &Annotation) -> bool { + (a2.start_col..a2.end_col).contains(a1.start_col) || + (a1.start_col..a1.end_col).contains(a2.start_col) +} + +fn emit_to_destination(rendered_buffer: &Vec>, + lvl: &Level, + dst: &mut Destination) -> io::Result<()> { + for line in rendered_buffer { + for part in line { + dst.apply_style(lvl.clone(), part.style); + write!(dst, "{}", part.text); + dst.reset_attrs()?; + } + write!(dst, "\n"); + } + Ok(()) +} + fn line_num_max_digits(line: &LineInfo) -> usize { let mut max_line_num = line.line_index + 1; let mut digits = 0; @@ -480,7 +1062,7 @@ fn stderr_isatty() -> bool { } } -enum Destination { +pub enum Destination { Terminal(Box), Raw(Box), } @@ -495,35 +1077,39 @@ impl Destination { fn apply_style(&mut self, lvl: Level, - _kind: &RenderedLineKind, style: Style) -> io::Result<()> { match style { - Style::FileNameStyle | - Style::LineAndColumn => { - } + Style::FileNameStyle | Style::LineAndColumn => {} Style::LineNumber => { - self.start_attr(term::Attr::Bold)?; - self.start_attr(term::Attr::ForegroundColor(term::color::BRIGHT_BLUE))?; + try!(self.start_attr(term::Attr::Bold)); + try!(self.start_attr(term::Attr::ForegroundColor(term::color::BRIGHT_BLUE))); } - Style::Quotation => { + Style::ErrorCode => { + try!(self.start_attr(term::Attr::Bold)); + //try!(self.start_attr(term::Attr::ForegroundColor(term::color::BRIGHT_MAGENTA))); } - Style::OldSkoolNote => { - self.start_attr(term::Attr::Bold)?; - self.start_attr(term::Attr::ForegroundColor(term::color::BRIGHT_GREEN))?; + Style::Quotation => {} + Style::OldSchoolNote => { + try!(self.start_attr(term::Attr::Bold)); + try!(self.start_attr(term::Attr::ForegroundColor(term::color::BRIGHT_GREEN))); } - Style::OldSkoolNoteText => { - self.start_attr(term::Attr::Bold)?; + Style::OldSchoolNoteText | Style::HeaderMsg => { + try!(self.start_attr(term::Attr::Bold)); } Style::UnderlinePrimary | Style::LabelPrimary => { - self.start_attr(term::Attr::Bold)?; - self.start_attr(term::Attr::ForegroundColor(lvl.color()))?; + try!(self.start_attr(term::Attr::Bold)); + try!(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::UnderlineSecondary | + Style::LabelSecondary => { + try!(self.start_attr(term::Attr::Bold)); + try!(self.start_attr(term::Attr::ForegroundColor(term::color::BRIGHT_BLUE))); } - Style::NoStyle => { + Style::NoStyle => {} + Style::Level(l) => { + try!(self.start_attr(term::Attr::Bold)); + try!(self.start_attr(term::Attr::ForegroundColor(l.color()))); } } Ok(()) diff --git a/src/librustc_errors/lib.rs b/src/librustc_errors/lib.rs index 7c14c132382e7..33781bed759f8 100644 --- a/src/librustc_errors/lib.rs +++ b/src/librustc_errors/lib.rs @@ -49,6 +49,7 @@ use std::thread::panicking; pub mod emitter; pub mod snippet; pub mod registry; +pub mod styled_buffer; use syntax_pos::{BytePos, Loc, FileLinesResult, FileName, MultiSpan, Span, NO_EXPANSION }; use syntax_pos::{MacroBacktrace}; diff --git a/src/librustc_errors/snippet.rs b/src/librustc_errors/snippet.rs index 33f40ffc71a9f..525c83499fbe5 100644 --- a/src/librustc_errors/snippet.rs +++ b/src/librustc_errors/snippet.rs @@ -13,9 +13,11 @@ use syntax_pos::{Span, FileMap, CharPos, LineInfo}; use check_old_skool; use CodeMapper; +use styled_buffer::StyledBuffer; use std::cmp; use std::rc::Rc; use std::mem; +use {Level}; #[derive(Clone)] pub enum FormatMode { @@ -49,38 +51,40 @@ pub struct FileInfo { format_mode: FormatMode, } -#[derive(Clone, Debug)] -struct Line { - line_index: usize, - annotations: Vec, +#[derive(Clone, Debug, PartialOrd, Ord, PartialEq, Eq)] +pub struct Line { + pub line_index: usize, + pub annotations: Vec, } #[derive(Clone, Debug, PartialOrd, Ord, PartialEq, Eq)] -struct Annotation { +pub 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, + pub start_col: usize, /// End column within the line (exclusive) - end_col: usize, + pub end_col: usize, /// Is this annotation derived from primary span - is_primary: bool, + pub is_primary: bool, /// Is this a large span minimized down to a smaller span - is_minimized: bool, + pub is_minimized: bool, /// Optional label to display adjacent to the annotation. - label: Option, + pub label: Option, } +/* #[derive(Debug)] pub struct RenderedLine { pub text: Vec, pub kind: RenderedLineKind, } +*/ #[derive(Debug)] pub struct StyledString { @@ -88,14 +92,9 @@ pub struct StyledString { pub style: Style, } -#[derive(Debug)] -pub struct StyledBuffer { - text: Vec>, - styles: Vec> -} - #[derive(Copy, Clone, Debug, PartialEq)] pub enum Style { + HeaderMsg, FileNameStyle, LineAndColumn, LineNumber, @@ -104,11 +103,14 @@ pub enum Style { UnderlineSecondary, LabelPrimary, LabelSecondary, - OldSkoolNoteText, - OldSkoolNote, + OldSchoolNoteText, + OldSchoolNote, NoStyle, + ErrorCode, + Level(Level), } +/* #[derive(Debug, Clone)] pub enum RenderedLineKind { PrimaryFileName, @@ -120,6 +122,7 @@ pub enum RenderedLineKind { Annotations, Elision, } +*/ impl SnippetData { pub fn new(codemap: Rc, @@ -186,15 +189,15 @@ impl SnippetData { self.files.last_mut().unwrap() } - pub fn render_lines(&self) -> Vec { + 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, &self.format_mode); - trim_lines(&mut rendered_lines); + //prepend_prefixes(&mut rendered_lines, &self.format_mode); + //trim_lines(&mut rendered_lines); rendered_lines } } @@ -215,6 +218,7 @@ impl StringSource for Vec { } } +/* impl From<(S, Style, RenderedLineKind)> for RenderedLine where S: StringSource { @@ -282,96 +286,20 @@ impl RenderedLineKind { } } } +*/ -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 = 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: RenderedLineKind::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![]); - } +impl FileInfo { + fn get_max_line_num(&self) -> usize { + let mut max = 0; - if col < self.text[line].len() { - self.text[line][col] = chr; - self.styles[line][col] = style; - } else { - let mut i = self.text[line].len(); - while i < col { - let s = match self.text[0].get(i) { - Some(&'\t') => '\t', - _ => ' ' - }; - self.text[line].push(s); - self.styles[line].push(Style::NoStyle); - i += 1; + for line in &self.lines { + if line.line_index > max { + max = line.line_index; } - 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; } + max } - 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, @@ -469,16 +397,13 @@ impl FileInfo { return line_index - first_line_index; } - fn render_file_lines(&self, codemap: &Rc) -> Vec { + fn render_file_lines(&self, codemap: &Rc) -> Vec> { let old_school = match self.format_mode { FormatMode::OriginalErrorFormat => true, FormatMode::NewErrorFormat => false, FormatMode::EnvironmentSelected => check_old_skool() }; - // 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![]; @@ -487,39 +412,27 @@ impl FileInfo { match self.primary_span { Some(span) => { let lo = codemap.lookup_char_pos(span.lo); - output.push(RenderedLine { - text: vec![StyledString { + output.push(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, - }); - output.push(RenderedLine { - text: vec![StyledString { + }]); + output.push(vec![StyledString { text: "".to_string(), style: Style::FileNameStyle, - }], - kind: RenderedLineKind::Annotations, - }); + }]); } None => { - output.push(RenderedLine { - text: vec![StyledString { + output.push(vec![StyledString { text: self.file.name.clone(), style: Style::FileNameStyle, - }], - kind: RenderedLineKind::OtherFileName, - }); - output.push(RenderedLine { - text: vec![StyledString { + }]); + output.push(vec![StyledString { text: "".to_string(), style: Style::FileNameStyle, - }], - kind: RenderedLineKind::Annotations, - }); + }]); } } } @@ -541,8 +454,7 @@ impl FileInfo { //as an old-style note if !line.annotations[0].is_primary { if let Some(ann) = line.annotations[0].label.clone() { - output.push(RenderedLine { - text: vec![StyledString { + output.push(vec![StyledString { text: lo.file.name.clone(), style: Style::FileNameStyle, }, StyledString { @@ -551,31 +463,29 @@ impl FileInfo { style: Style::LineAndColumn, }, StyledString { text: format!("note: "), - style: Style::OldSkoolNote, + style: Style::OldSchoolNote, }, StyledString { text: format!("{}", ann), - style: Style::OldSkoolNoteText, - }], - kind: RenderedLineKind::Annotations, - }); + style: Style::OldSchoolNoteText, + }]); } } - rendered_lines[0].text.insert(0, StyledString { + rendered_lines[0].insert(0, StyledString { text: format!(":{} ", lo.line), style: Style::LineAndColumn, }); - rendered_lines[0].text.insert(0, StyledString { + rendered_lines[0].insert(0, StyledString { text: lo.file.name.clone(), style: Style::FileNameStyle, }); let gap_amount = - rendered_lines[0].text[0].text.len() + - rendered_lines[0].text[1].text.len(); + rendered_lines[0][0].text.len() + + rendered_lines[0][1].text.len(); assert!(rendered_lines.len() >= 2, "no annotations resulted from: {:?}", line); for i in 1..rendered_lines.len() { - rendered_lines[i].text.insert(0, StyledString { + rendered_lines[i].insert(0, StyledString { text: vec![" "; gap_amount].join(""), style: Style::NoStyle }); @@ -598,9 +508,7 @@ impl FileInfo { next_line = lines_iter.next(); } if unannotated_lines > 1 { - output.push(RenderedLine::from((String::new(), - Style::NoStyle, - RenderedLineKind::Elision))); + output.push(vec![StyledString{ text: String::new(), style: Style::NoStyle}]); } else if let Some(line) = unannotated_line { output.append(&mut self.render_line(line)); } @@ -609,7 +517,7 @@ impl FileInfo { output } - fn render_line(&self, line: &Line) -> Vec { + fn render_line(&self, line: &Line) -> Vec> { let old_school = match self.format_mode { FormatMode::OriginalErrorFormat => true, FormatMode::NewErrorFormat => false, @@ -618,10 +526,12 @@ impl FileInfo { let source_string = self.file.get_line(line.line_index) .unwrap_or(""); + /* let source_kind = RenderedLineKind::SourceText { file: self.file.clone(), line_index: line.line_index, }; + */ let mut styled_buffer = StyledBuffer::new(); @@ -629,7 +539,7 @@ impl FileInfo { styled_buffer.append(0, &source_string, Style::Quotation); if line.annotations.is_empty() { - return styled_buffer.render(source_kind); + return styled_buffer.render(); } // We want to display like this: @@ -666,7 +576,7 @@ impl FileInfo { if annotation.is_primary { Style::UnderlinePrimary } else { - Style::OldSkoolNote + Style::OldSchoolNote }); } else { @@ -674,7 +584,7 @@ impl FileInfo { if annotation.is_primary { Style::UnderlinePrimary } else { - Style::OldSkoolNote + Style::OldSchoolNote }); } } @@ -704,10 +614,10 @@ impl FileInfo { // If there are no annotations that need text, we're done. if labeled_annotations.is_empty() { - return styled_buffer.render(source_kind); + return styled_buffer.render(); } if old_school { - return styled_buffer.render(source_kind); + return styled_buffer.render(); } // Now add the text labels. We try, when possible, to stick the rightmost @@ -767,7 +677,7 @@ impl FileInfo { // If that's the last annotation, we're done if labeled_annotations.is_empty() { - return styled_buffer.render(source_kind); + return styled_buffer.render(); } for (index, annotation) in labeled_annotations.iter().enumerate() { @@ -796,10 +706,11 @@ impl FileInfo { } } - styled_buffer.render(source_kind) + styled_buffer.render() } } +/* fn prepend_prefixes(rendered_lines: &mut [RenderedLine], format_mode: &FormatMode) { let old_school = match *format_mode { FormatMode::OriginalErrorFormat => true, @@ -882,6 +793,7 @@ fn trim_lines(rendered_lines: &mut [RenderedLine]) { } } } +*/ impl Line { fn new(line_index: usize) -> Line { diff --git a/src/libsyntax/test.rs b/src/libsyntax/test.rs index 0a60b7fd430c4..570c0a09bc417 100644 --- a/src/libsyntax/test.rs +++ b/src/libsyntax/test.rs @@ -26,7 +26,7 @@ use std::rc::Rc; use codemap::{self, CodeMap, ExpnInfo, NameAndSpan, MacroAttribute}; use errors; -use errors::snippet::{RenderedLine, SnippetData}; +use errors::snippet::{SnippetData}; use config; use entry::{self, EntryPointType}; use ext::base::{ExtCtxt, DummyMacroLoader}; diff --git a/src/libsyntax_pos/lib.rs b/src/libsyntax_pos/lib.rs index 39bb5956312bc..7dfe19452a2a9 100644 --- a/src/libsyntax_pos/lib.rs +++ b/src/libsyntax_pos/lib.rs @@ -568,7 +568,7 @@ impl Sub for CharPos { // /// A source code location used for error reporting -#[derive(Debug)] +#[derive(Debug, Clone)] pub struct Loc { /// Information about the original source pub file: Rc, From 8612838dd04ae9343088955136626b1c1b579999 Mon Sep 17 00:00:00 2001 From: Jonathan Turner Date: Tue, 12 Jul 2016 10:41:26 -0400 Subject: [PATCH 06/19] Add back in old school mode --- src/librustc_errors/emitter.rs | 291 ++++++++++++++++++++++++++++++--- 1 file changed, 265 insertions(+), 26 deletions(-) diff --git a/src/librustc_errors/emitter.rs b/src/librustc_errors/emitter.rs index 52c0ea931408f..037d64ba128fb 100644 --- a/src/librustc_errors/emitter.rs +++ b/src/librustc_errors/emitter.rs @@ -34,31 +34,14 @@ pub trait Emitter { impl Emitter for EmitterWriter { fn emit(&mut self, db: &DiagnosticBuilder) { - if check_old_skool() { - self.emit_message(&FullSpan(db.span.clone()), - &db.message, - db.code.as_ref().map(|s| &**s), - db.level, - true, - true); - let db_span = FullSpan(db.span.clone()); - - for child in &db.children { - let render_span = child.render_span - .clone() - .unwrap_or_else( - || FullSpan(child.span.clone())); - 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); - } + let old_school = match self.format_mode { + FormatMode::NewErrorFormat => false, + FormatMode::OriginalErrorFormat => true, + FormatMode::EnvironmentSelected => check_old_skool() + }; + + if old_school { + self.emit_messages_old_school(db); } else { self.emit_messages_default(db); } @@ -718,6 +701,239 @@ impl EmitterWriter { } write!(&mut self.dst, "\n"); } + fn emit_message_old_school(&mut self, + msp: &MultiSpan, + msg: &str, + code: &Option, + level: &Level, + show_snippet: bool) + -> io::Result<()> { + let mut buffer = StyledBuffer::new(); + + let loc = match msp.primary_span() { + Some(COMMAND_LINE_SP) | Some(DUMMY_SP) => "".to_string(), + Some(ps) => if let Some(ref cm) = self.cm { + cm.span_to_string(ps) + } else { + "".to_string() + }, + None => { + "".to_string() + } + }; + if loc != "" { + buffer.append(0, &loc, Style::NoStyle); + buffer.append(0, " ", Style::NoStyle); + } + buffer.append(0, &level.to_string(), Style::Level(level.clone())); + buffer.append(0, ": ", Style::HeaderMsg); + buffer.append(0, msg, Style::HeaderMsg); + buffer.append(0, " ", Style::NoStyle); + match code { + &Some(ref code) => { + buffer.append(0, "[", Style::ErrorCode); + buffer.append(0, &code, Style::ErrorCode); + buffer.append(0, "]", Style::ErrorCode); + } + _ => {} + } + + if !show_snippet { + emit_to_destination(&buffer.render(), level, &mut self.dst); + return Ok(()); + } + + // Watch out for various nasty special spans; don't try to + // print any filename or anything for those. + match msp.primary_span() { + Some(COMMAND_LINE_SP) | Some(DUMMY_SP) => { + emit_to_destination(&buffer.render(), level, &mut self.dst); + return Ok(()); + } + _ => { } + } + + let mut annotated_files = self.preprocess_annotations(msp); + + if let (Some(ref cm), Some(ann_file), Some(ref primary_span)) = + (self.cm.as_ref(), annotated_files.first(), msp.primary_span().as_ref()) { + + // Next, print the source line and its squiggle + // for old school mode, we will render them to the buffer, then insert the file loc + // (or space the same amount) in front of the line and the squiggle + let source_string = ann_file.file.get_line(ann_file.lines[0].line_index - 1) + .unwrap_or(""); + + let line_offset = buffer.num_lines(); + + let lo = cm.lookup_char_pos(primary_span.lo); + //Before each secondary line in old skool-mode, print the label + //as an old-style note + let file_pos = format!("{}:{} ", lo.file.name.clone(), lo.line); + let file_pos_len = file_pos.len(); + + // First create the source line we will highlight. + buffer.puts(line_offset, 0, &file_pos, Style::FileNameStyle); + buffer.puts(line_offset, file_pos_len, &source_string, Style::Quotation); + // Sort the annotations by (start, end col) + let mut annotations = ann_file.lines[0].annotations.clone(); + + // Next, create the highlight line. + for annotation in &annotations { + for p in annotation.start_col..annotation.end_col { + if p == annotation.start_col { + buffer.putc(line_offset + 1, + file_pos_len + p, + '^', + if annotation.is_primary { + Style::UnderlinePrimary + } else { + Style::OldSchoolNote + }); + } else { + buffer.putc(line_offset + 1, + file_pos_len + p, + '~', + if annotation.is_primary { + Style::UnderlinePrimary + } else { + Style::OldSchoolNote + }); + } + } + } + } + if let Some(ref primary_span) = msp.primary_span().as_ref() { + self.render_macro_backtrace_old_school(primary_span, &mut buffer)?; + } + + match code { + &Some(ref code) if self.registry.as_ref() + .and_then(|registry| registry.find_description(code)) + .is_some() => { + let msg = "run `rustc --explain ".to_string() + &code.to_string() + + "` to see a detailed explanation"; + + let line_offset = buffer.num_lines(); + buffer.append(line_offset, &loc, Style::NoStyle); + buffer.append(line_offset, " ", Style::NoStyle); + buffer.append(line_offset, &Level::Help.to_string(), Style::Level(Level::Help)); + buffer.append(line_offset, ": ", Style::HeaderMsg); + buffer.append(line_offset, &msg, Style::HeaderMsg); + } + _ => () + } + + // final step: take our styled buffer, render it, then output it + emit_to_destination(&buffer.render(), level, &mut self.dst); + Ok(()) + } + fn emit_suggestion_old_school(&mut self, + suggestion: &CodeSuggestion, + level: &Level, + msg: &str) + -> io::Result<()> { + use std::borrow::Borrow; + + let primary_span = suggestion.msp.primary_span().unwrap(); + if let Some(ref cm) = self.cm { + let mut buffer = StyledBuffer::new(); + + let loc = cm.span_to_string(primary_span); + + if loc != "" { + buffer.append(0, &loc, Style::NoStyle); + buffer.append(0, " ", Style::NoStyle); + } + + buffer.append(0, &level.to_string(), Style::Level(level.clone())); + buffer.append(0, ": ", Style::HeaderMsg); + buffer.append(0, msg, Style::HeaderMsg); + + let lines = cm.span_to_lines(primary_span).unwrap(); + + assert!(!lines.lines.is_empty()); + + let complete = suggestion.splice_lines(cm.borrow()); + let line_count = cmp::min(lines.lines.len(), MAX_HIGHLIGHT_LINES); + let display_lines = &lines.lines[..line_count]; + + let fm = &*lines.file; + // Calculate the widest number to format evenly + let max_digits = line_num_max_digits(display_lines.last().unwrap()); + + // print the suggestion without any line numbers, but leave + // space for them. This helps with lining up with previous + // snippets from the actual error being reported. + let mut lines = complete.lines(); + let mut row_num = 1; + for line in lines.by_ref().take(MAX_HIGHLIGHT_LINES) { + buffer.append(row_num, &fm.name, Style::FileNameStyle); + for i in 0..max_digits+2 { + buffer.append(row_num, &" ", Style::NoStyle); + } + buffer.append(row_num, line, Style::NoStyle); + row_num += 1; + } + + // if we elided some lines, add an ellipsis + if let Some(_) = lines.next() { + buffer.append(row_num, "...", Style::NoStyle); + } + emit_to_destination(&buffer.render(), level, &mut self.dst); + } + Ok(()) + } + + fn emit_messages_old_school(&mut self, db: &DiagnosticBuilder) { + match self.emit_message_old_school(&db.span, + &db.message, + &db.code, + &db.level, + true) { + Ok(()) => { + for child in &db.children { + let (span, show_snippet) = if child.span.primary_spans().is_empty() { + (db.span.clone(), false) + } else { + (child.span.clone(), true) + }; + + match child.render_span { + Some(FullSpan(ref msp)) => { + match self.emit_message_old_school(&span, + &child.message, + &None, + &child.level, + show_snippet) { + Err(e) => panic!("failed to emit error: {}", e), + _ => () + } + }, + Some(Suggestion(ref cs)) => { + match self.emit_suggestion_old_school(cs, + &child.level, + &child.message) { + Err(e) => panic!("failed to emit error: {}", e), + _ => () + } + }, + None => { + match self.emit_message_old_school(&span, + &child.message, + &None, + &child.level, + show_snippet) { + Err(e) => panic!("failed to emit error: {}", e), + _ => () + } + } + } + } + } + Err(e) => panic!("failed to emit error: {}", e) + } + } fn emit_message_(&mut self, rsp: &RenderSpan, @@ -948,6 +1164,29 @@ impl EmitterWriter { Ok(()) } + fn render_macro_backtrace_old_school(&mut self, + sp: &Span, + buffer: &mut StyledBuffer) -> io::Result<()> { + if let Some(ref cm) = self.cm { + for trace in cm.macro_backtrace(sp.clone()) { + let line_offset = buffer.num_lines(); + + let mut diag_string = + format!("in this expansion of {}", trace.macro_decl_name); + if let Some(def_site_span) = trace.def_site_span { + diag_string.push_str( + &format!(" (defined in {})", + cm.span_to_filename(def_site_span))); + } + let snippet = cm.span_to_string(trace.call_site); + buffer.append(line_offset, &format!("{} ", snippet), Style::NoStyle); + buffer.append(line_offset, "Note", Style::Level(Level::Note)); + buffer.append(line_offset, ": ", Style::NoStyle); + buffer.append(line_offset, &diag_string, Style::OldSchoolNoteText); + } + } + Ok(()) + } fn print_macro_backtrace(&mut self, sp: Span) -> io::Result<()> { @@ -1087,7 +1326,7 @@ impl Destination { } Style::ErrorCode => { try!(self.start_attr(term::Attr::Bold)); - //try!(self.start_attr(term::Attr::ForegroundColor(term::color::BRIGHT_MAGENTA))); + try!(self.start_attr(term::Attr::ForegroundColor(term::color::BRIGHT_MAGENTA))); } Style::Quotation => {} Style::OldSchoolNote => { From f481879d2ae82a6f6ebe33202d4a1cfa8aece5ed Mon Sep 17 00:00:00 2001 From: Jonathan Turner Date: Tue, 12 Jul 2016 12:37:57 -0400 Subject: [PATCH 07/19] Fix a couple UI test failures --- src/librustc_errors/emitter.rs | 27 +++++++++++-------- .../ui/mismatched_types/issue-26480.stderr | 19 ++++++------- src/test/ui/mismatched_types/main.stderr | 14 +++++----- 3 files changed, 34 insertions(+), 26 deletions(-) diff --git a/src/librustc_errors/emitter.rs b/src/librustc_errors/emitter.rs index 037d64ba128fb..5147318d4a63d 100644 --- a/src/librustc_errors/emitter.rs +++ b/src/librustc_errors/emitter.rs @@ -187,23 +187,24 @@ impl EmitterWriter { if let Some(ref cm) = self.cm { for span_label in msp.span_labels() { - let lo = cm.lookup_char_pos(span_label.span.lo); - let hi = cm.lookup_char_pos(span_label.span.hi); + let mut lo = cm.lookup_char_pos(span_label.span.lo); + let mut hi = cm.lookup_char_pos(span_label.span.hi); + let mut is_minimized = false; // If the span is multi-line, simplify down to the span of one character - let (start_col, mut end_col, is_minimized) = if lo.line != hi.line { - (lo.col, CharPos(lo.col.0 + 1), true) - } else { - (lo.col, hi.col, false) - }; + if lo.line != hi.line { + hi.line = lo.line; + hi.col = CharPos(lo.col.0 + 1); + is_minimized = true; + } // Watch out for "empty spans". If we get a span like 6..6, we // want to just display a `^` at 6, so convert that to // 6..7. This is degenerate input, but it's best to degrade // gracefully -- and the parser likes to supply a span like // that for EOF, in particular. - if start_col == end_col { - end_col.0 += 1; + if lo.col == hi.col { + hi.col = CharPos(lo.col.0 + 1); } add_annotation_to_file(&mut output, @@ -530,7 +531,7 @@ impl EmitterWriter { buffer.prepend(buffer_msg_line_offset, "--> ", Style::LineNumber); let loc = primary_lo.clone(); buffer.append(buffer_msg_line_offset, - &format!("{}:{}:{}", loc.file.name, loc.line, loc.col.0), + &format!("{}:{}:{}", loc.file.name, loc.line, loc.col.0 + 1), Style::LineAndColumn); for i in 0..max_line_num_len { buffer.prepend(buffer_msg_line_offset, " ", Style::NoStyle); @@ -593,6 +594,10 @@ impl EmitterWriter { } } + if let Some(ref primary_span) = msp.primary_span().as_ref() { + self.render_macro_backtrace_old_school(primary_span, &mut buffer)?; + } + // final step: take our styled buffer, render it, then output it emit_to_destination(&buffer.render(), level, &mut self.dst); @@ -1180,7 +1185,7 @@ impl EmitterWriter { } let snippet = cm.span_to_string(trace.call_site); buffer.append(line_offset, &format!("{} ", snippet), Style::NoStyle); - buffer.append(line_offset, "Note", Style::Level(Level::Note)); + buffer.append(line_offset, "note", Style::Level(Level::Note)); buffer.append(line_offset, ": ", Style::NoStyle); buffer.append(line_offset, &diag_string, Style::OldSchoolNoteText); } diff --git a/src/test/ui/mismatched_types/issue-26480.stderr b/src/test/ui/mismatched_types/issue-26480.stderr index c00594a59c115..63f2ab4d7c6bf 100644 --- a/src/test/ui/mismatched_types/issue-26480.stderr +++ b/src/test/ui/mismatched_types/issue-26480.stderr @@ -1,15 +1,16 @@ -error: mismatched types [--explain E0308] +error[E0308]: mismatched types --> $DIR/issue-26480.rs:27:19 - |> -27 |> $arr.len() * size_of($arr[0])); - |> ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ expected u64, found usize -$DIR/issue-26480.rs:38:5: 38:19: note: in this expansion of write! (defined in $DIR/issue-26480.rs) + | +27 | $arr.len() * size_of($arr[0])); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ expected u64, found usize +$DIR/issue-26480.rs:38:5: 38:19 note: in this expansion of write! (defined in $DIR/issue-26480.rs) error: non-scalar cast: `_` as `()` --> $DIR/issue-26480.rs:33:19 - |> -33 |> ($x:expr) => ($x as ()) - |> ^^^^^^^^ -$DIR/issue-26480.rs:39:5: 39:14: note: in this expansion of cast! (defined in $DIR/issue-26480.rs) + | +33 | ($x:expr) => ($x as ()) + | ^^^^^^^^ +$DIR/issue-26480.rs:39:5: 39:14 note: in this expansion of cast! (defined in $DIR/issue-26480.rs) error: aborting due to 2 previous errors + diff --git a/src/test/ui/mismatched_types/main.stderr b/src/test/ui/mismatched_types/main.stderr index 1af332ee5bea7..ae1d417eca9ee 100644 --- a/src/test/ui/mismatched_types/main.stderr +++ b/src/test/ui/mismatched_types/main.stderr @@ -1,9 +1,11 @@ -error: mismatched types [--explain E0308] +error[E0308]: mismatched types --> $DIR/main.rs:14:18 - |> -14 |> let x: u32 = ( - |> ^ expected u32, found () -note: expected type `u32` -note: found type `()` + | +14 | let x: u32 = ( + | ^ expected u32, found () + | + = note: expected type `u32` + = note: found type `()` error: aborting due to previous error + From 2f2c3e178325dc1837badcd7573c2c0905fab979 Mon Sep 17 00:00:00 2001 From: Jonathan Turner Date: Tue, 12 Jul 2016 15:18:16 -0400 Subject: [PATCH 08/19] DCE and fixing some internal tests --- src/librustc_errors/emitter.rs | 406 ++---------------- src/librustc_errors/lib.rs | 10 - src/librustc_errors/snippet.rs | 733 +-------------------------------- src/libsyntax/codemap.rs | 196 ++++----- 4 files changed, 132 insertions(+), 1213 deletions(-) diff --git a/src/librustc_errors/emitter.rs b/src/librustc_errors/emitter.rs index 5147318d4a63d..901cd3403c1d2 100644 --- a/src/librustc_errors/emitter.rs +++ b/src/librustc_errors/emitter.rs @@ -14,13 +14,12 @@ use syntax_pos::{COMMAND_LINE_SP, DUMMY_SP, FileMap, Span, MultiSpan, LineInfo, use registry; use check_old_skool; -use {Level, RenderSpan, CodeSuggestion, DiagnosticBuilder, CodeMapper}; +use {Level, CodeSuggestion, DiagnosticBuilder, CodeMapper}; use RenderSpan::*; -use Level::*; -use snippet::{SnippetData, StyledString, Style, FormatMode, Annotation, Line}; +use snippet::{StyledString, Style, FormatMode, Annotation, Line}; use styled_buffer::StyledBuffer; -use std::{cmp, fmt}; +use std::cmp; use std::io::prelude::*; use std::io; use std::rc::Rc; @@ -73,10 +72,6 @@ pub struct EmitterWriter { registry: Option, cm: Option>, - /// 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 format_mode: FormatMode } @@ -112,13 +107,11 @@ impl EmitterWriter { EmitterWriter { dst: dst, registry: registry, cm: code_map, - first: true, format_mode: format_mode.clone() } } else { EmitterWriter { dst: Raw(Box::new(io::stderr())), registry: registry, cm: code_map, - first: true, format_mode: format_mode.clone() } } } @@ -131,23 +124,9 @@ impl EmitterWriter { EmitterWriter { dst: Raw(dst), registry: registry, cm: code_map, - first: true, format_mode: format_mode.clone() } } - fn emit_message(&mut self, - rsp: &RenderSpan, - msg: &str, - code: Option<&str>, - lvl: Level, - is_header: bool, - show_snippet: bool) { - match self.emit_message_(rsp, msg, code, lvl, is_header, show_snippet) { - Ok(()) => { } - Err(e) => panic!("failed to emit error: {}", e) - } - } - fn preprocess_annotations(&self, msp: &MultiSpan) -> Vec { fn add_annotation_to_file(file_vec: &mut Vec, file: Rc, @@ -187,7 +166,7 @@ impl EmitterWriter { if let Some(ref cm) = self.cm { for span_label in msp.span_labels() { - let mut lo = cm.lookup_char_pos(span_label.span.lo); + let lo = cm.lookup_char_pos(span_label.span.lo); let mut hi = cm.lookup_char_pos(span_label.span.hi); let mut is_minimized = false; @@ -478,7 +457,7 @@ impl EmitterWriter { if msp.primary_spans().is_empty() && msp.span_labels().is_empty() && is_secondary { // This is a secondary message with no span info - for i in 0..max_line_num_len { + for _ in 0..max_line_num_len { buffer.prepend(0, " ", Style::NoStyle); } draw_note_separator(&mut buffer, 0, max_line_num_len + 1); @@ -511,7 +490,7 @@ impl EmitterWriter { cm.lookup_char_pos(primary_span.lo) } else { // If we don't have span information, emit and exit - emit_to_destination(&buffer.render(), level, &mut self.dst); + emit_to_destination(&buffer.render(), level, &mut self.dst)?; return Ok(()); }; if let Ok(pos) = @@ -526,19 +505,19 @@ impl EmitterWriter { let is_primary = primary_lo.file.name == annotated_file.file.name; if is_primary { // remember where we are in the output buffer for easy reference - let mut buffer_msg_line_offset = buffer.num_lines(); + let buffer_msg_line_offset = buffer.num_lines(); buffer.prepend(buffer_msg_line_offset, "--> ", Style::LineNumber); let loc = primary_lo.clone(); buffer.append(buffer_msg_line_offset, &format!("{}:{}:{}", loc.file.name, loc.line, loc.col.0 + 1), Style::LineAndColumn); - for i in 0..max_line_num_len { + for _ in 0..max_line_num_len { buffer.prepend(buffer_msg_line_offset, " ", Style::NoStyle); } } else { // remember where we are in the output buffer for easy reference - let mut buffer_msg_line_offset = buffer.num_lines(); + let buffer_msg_line_offset = buffer.num_lines(); // Add spacing line draw_col_separator(&mut buffer, buffer_msg_line_offset, max_line_num_len + 1); @@ -548,13 +527,13 @@ impl EmitterWriter { buffer.append(buffer_msg_line_offset + 1, &annotated_file.file.name, Style::LineAndColumn); - for i in 0..max_line_num_len { + for _ in 0..max_line_num_len { buffer.prepend(buffer_msg_line_offset + 1, " ", Style::NoStyle); } } // Put in the spacer between the location and annotated source - let mut buffer_msg_line_offset = buffer.num_lines(); + let buffer_msg_line_offset = buffer.num_lines(); draw_col_separator(&mut buffer, buffer_msg_line_offset, max_line_num_len + 1); // Next, output the annotate source for this file @@ -599,7 +578,7 @@ impl EmitterWriter { } // final step: take our styled buffer, render it, then output it - emit_to_destination(&buffer.render(), level, &mut self.dst); + emit_to_destination(&buffer.render(), level, &mut self.dst)?; Ok(()) } @@ -624,12 +603,6 @@ impl EmitterWriter { assert!(!lines.lines.is_empty()); let complete = suggestion.splice_lines(cm.borrow()); - let line_count = cmp::min(lines.lines.len(), MAX_HIGHLIGHT_LINES); - let display_lines = &lines.lines[..line_count]; - - let fm = &*lines.file; - // Calculate the widest number to format evenly - let max_digits = line_num_max_digits(display_lines.last().unwrap()); // print the suggestion without any line numbers, but leave // space for them. This helps with lining up with previous @@ -646,7 +619,7 @@ impl EmitterWriter { if let Some(_) = lines.next() { buffer.append(row_num, "...", Style::NoStyle); } - emit_to_destination(&buffer.render(), level, &mut self.dst); + emit_to_destination(&buffer.render(), level, &mut self.dst)?; } Ok(()) } @@ -664,7 +637,10 @@ impl EmitterWriter { if !db.children.is_empty() { let mut buffer = StyledBuffer::new(); draw_col_separator(&mut buffer, 0, max_line_num_len + 1); - emit_to_destination(&buffer.render(), &db.level, &mut self.dst); + match emit_to_destination(&buffer.render(), &db.level, &mut self.dst) { + Ok(()) => (), + Err(e) => panic!("failed to emit error: {}", e) + } } for child in &db.children { match child.render_span { @@ -704,7 +680,10 @@ impl EmitterWriter { } Err(e) => panic!("failed to emit error: {}", e) } - write!(&mut self.dst, "\n"); + match write!(&mut self.dst, "\n") { + Err(e) => panic!("failed to emit error: {}", e), + _ => () + } } fn emit_message_old_school(&mut self, msp: &MultiSpan, @@ -744,7 +723,7 @@ impl EmitterWriter { } if !show_snippet { - emit_to_destination(&buffer.render(), level, &mut self.dst); + emit_to_destination(&buffer.render(), level, &mut self.dst)?; return Ok(()); } @@ -752,13 +731,13 @@ impl EmitterWriter { // print any filename or anything for those. match msp.primary_span() { Some(COMMAND_LINE_SP) | Some(DUMMY_SP) => { - emit_to_destination(&buffer.render(), level, &mut self.dst); + emit_to_destination(&buffer.render(), level, &mut self.dst)?; return Ok(()); } _ => { } } - let mut annotated_files = self.preprocess_annotations(msp); + let annotated_files = self.preprocess_annotations(msp); if let (Some(ref cm), Some(ann_file), Some(ref primary_span)) = (self.cm.as_ref(), annotated_files.first(), msp.primary_span().as_ref()) { @@ -781,7 +760,7 @@ impl EmitterWriter { buffer.puts(line_offset, 0, &file_pos, Style::FileNameStyle); buffer.puts(line_offset, file_pos_len, &source_string, Style::Quotation); // Sort the annotations by (start, end col) - let mut annotations = ann_file.lines[0].annotations.clone(); + let annotations = ann_file.lines[0].annotations.clone(); // Next, create the highlight line. for annotation in &annotations { @@ -830,7 +809,7 @@ impl EmitterWriter { } // final step: take our styled buffer, render it, then output it - emit_to_destination(&buffer.render(), level, &mut self.dst); + emit_to_destination(&buffer.render(), level, &mut self.dst)?; Ok(()) } fn emit_suggestion_old_school(&mut self, @@ -874,7 +853,7 @@ impl EmitterWriter { let mut row_num = 1; for line in lines.by_ref().take(MAX_HIGHLIGHT_LINES) { buffer.append(row_num, &fm.name, Style::FileNameStyle); - for i in 0..max_digits+2 { + for _ in 0..max_digits+2 { buffer.append(row_num, &" ", Style::NoStyle); } buffer.append(row_num, line, Style::NoStyle); @@ -885,7 +864,7 @@ impl EmitterWriter { if let Some(_) = lines.next() { buffer.append(row_num, "...", Style::NoStyle); } - emit_to_destination(&buffer.render(), level, &mut self.dst); + emit_to_destination(&buffer.render(), level, &mut self.dst)?; } Ok(()) } @@ -905,7 +884,7 @@ impl EmitterWriter { }; match child.render_span { - Some(FullSpan(ref msp)) => { + Some(FullSpan(_)) => { match self.emit_message_old_school(&span, &child.message, &None, @@ -940,235 +919,6 @@ impl EmitterWriter { } } - fn emit_message_(&mut self, - rsp: &RenderSpan, - msg: &str, - code: Option<&str>, - lvl: Level, - is_header: bool, - show_snippet: bool) - -> io::Result<()> { - let old_school = match self.format_mode { - FormatMode::NewErrorFormat => false, - FormatMode::OriginalErrorFormat => true, - FormatMode::EnvironmentSelected => check_old_skool() - }; - - if is_header { - if self.first { - self.first = false; - } else { - if !old_school { - write!(self.dst, "\n")?; - } - } - } - - match code { - Some(code) if self.registry.as_ref() - .and_then(|registry| registry.find_description(code)) - .is_some() => { - let code_with_explain = String::from("--explain ") + code; - if old_school { - let loc = match rsp.span().primary_span() { - Some(COMMAND_LINE_SP) | Some(DUMMY_SP) => "".to_string(), - Some(ps) => if let Some(ref cm) = self.cm { - cm.span_to_string(ps) - } else { - "".to_string() - }, - None => "".to_string() - }; - print_diagnostic(&mut self.dst, &loc, lvl, msg, Some(code))? - } - else { - print_diagnostic(&mut self.dst, "", lvl, msg, Some(&code_with_explain))? - } - } - _ => { - if old_school { - let loc = match rsp.span().primary_span() { - Some(COMMAND_LINE_SP) | Some(DUMMY_SP) => "".to_string(), - Some(ps) => if let Some(ref cm) = self.cm { - cm.span_to_string(ps) - } else { - "".to_string() - }, - None => "".to_string() - }; - print_diagnostic(&mut self.dst, &loc, lvl, msg, code)? - } - else { - print_diagnostic(&mut self.dst, "", lvl, msg, code)? - } - } - } - - if !show_snippet { - return Ok(()); - } - - // Watch out for various nasty special spans; don't try to - // print any filename or anything for those. - match rsp.span().primary_span() { - Some(COMMAND_LINE_SP) | Some(DUMMY_SP) => { - return Ok(()); - } - _ => { } - } - - // Otherwise, print out the snippet etc as needed. - match *rsp { - FullSpan(ref msp) => { - self.highlight_lines(msp, lvl)?; - if let Some(primary_span) = msp.primary_span() { - self.print_macro_backtrace(primary_span)?; - } - } - Suggestion(ref suggestion) => { - self.highlight_suggestion(suggestion)?; - if let Some(primary_span) = rsp.span().primary_span() { - self.print_macro_backtrace(primary_span)?; - } - } - } - if old_school { - match code { - Some(code) if self.registry.as_ref() - .and_then(|registry| registry.find_description(code)) - .is_some() => { - let loc = match rsp.span().primary_span() { - Some(COMMAND_LINE_SP) | Some(DUMMY_SP) => "".to_string(), - Some(ps) => if let Some(ref cm) = self.cm { - cm.span_to_string(ps) - } else { - "".to_string() - }, - None => "".to_string() - }; - let msg = "run `rustc --explain ".to_string() + &code.to_string() + - "` to see a detailed explanation"; - print_diagnostic(&mut self.dst, &loc, Level::Help, &msg, - None)? - } - _ => () - } - } - Ok(()) - } - - fn highlight_suggestion(&mut self, suggestion: &CodeSuggestion) -> io::Result<()> - { - use std::borrow::Borrow; - - let primary_span = suggestion.msp.primary_span().unwrap(); - if let Some(ref cm) = self.cm { - let lines = cm.span_to_lines(primary_span).unwrap(); - - assert!(!lines.lines.is_empty()); - - let complete = suggestion.splice_lines(cm.borrow()); - let line_count = cmp::min(lines.lines.len(), MAX_HIGHLIGHT_LINES); - let display_lines = &lines.lines[..line_count]; - - let fm = &*lines.file; - // Calculate the widest number to format evenly - let max_digits = line_num_max_digits(display_lines.last().unwrap()); - - // print the suggestion without any line numbers, but leave - // space for them. This helps with lining up with previous - // snippets from the actual error being reported. - let mut lines = complete.lines(); - for line in lines.by_ref().take(MAX_HIGHLIGHT_LINES) { - write!(&mut self.dst, "{0}:{1:2$} {3}\n", - fm.name, "", max_digits, line)?; - } - - // if we elided some lines, add an ellipsis - if let Some(_) = lines.next() { - write!(&mut self.dst, "{0:1$} {0:2$} ...\n", - "", fm.name.len(), max_digits)?; - } - } - Ok(()) - } - - pub fn highlight_lines(&mut self, - msp: &MultiSpan, - lvl: Level) - -> io::Result<()> - { - // Check to see if we have any lines to highlight, exit early if not - match self.cm { - None => return Ok(()), - _ => () - } - - let old_school = match self.format_mode { - FormatMode::NewErrorFormat => false, - FormatMode::OriginalErrorFormat => true, - FormatMode::EnvironmentSelected => check_old_skool() - }; - - let mut snippet_data = SnippetData::new(self.cm.as_ref().unwrap().clone(), - msp.primary_span(), - self.format_mode.clone()); - if old_school { - let mut output_vec = vec![]; - - for span_label in msp.span_labels() { - let mut snippet_data = SnippetData::new(self.cm.as_ref().unwrap().clone(), - Some(span_label.span), - self.format_mode.clone()); - - snippet_data.push(span_label.span, - span_label.is_primary, - span_label.label); - if span_label.is_primary { - output_vec.insert(0, snippet_data); - } - else { - output_vec.push(snippet_data); - } - } - - for snippet_data in output_vec.iter() { - /* - let rendered_lines = snippet_data.render_lines(); - for rendered_line in &rendered_lines { - for styled_string in &rendered_line.text { - self.dst.apply_style(lvl, &rendered_line.kind, styled_string.style)?; - write!(&mut self.dst, "{}", styled_string.text)?; - self.dst.reset_attrs()?; - } - write!(&mut self.dst, "\n")?; - } - */ - emit_to_destination(&snippet_data.render_lines(), &lvl, &mut self.dst); - } - } - else { - for span_label in msp.span_labels() { - snippet_data.push(span_label.span, - span_label.is_primary, - span_label.label); - } - emit_to_destination(&snippet_data.render_lines(), &lvl, &mut self.dst); - /* - let rendered_lines = snippet_data.render_lines(); - for rendered_line in &rendered_lines { - for styled_string in &rendered_line.text { - self.dst.apply_style(lvl, &rendered_line.kind, styled_string.style)?; - write!(&mut self.dst, "{}", styled_string.text)?; - self.dst.reset_attrs()?; - } - write!(&mut self.dst, "\n")?; - } - */ - } - Ok(()) - } - fn render_macro_backtrace_old_school(&mut self, sp: &Span, buffer: &mut StyledBuffer) -> io::Result<()> { @@ -1192,24 +942,6 @@ impl EmitterWriter { } Ok(()) } - fn print_macro_backtrace(&mut self, - sp: Span) - -> io::Result<()> { - if let Some(ref cm) = self.cm { - for trace in cm.macro_backtrace(sp) { - let mut diag_string = - format!("in this expansion of {}", trace.macro_decl_name); - if let Some(def_site_span) = trace.def_site_span { - diag_string.push_str( - &format!(" (defined in {})", - cm.span_to_filename(def_site_span))); - } - let snippet = cm.span_to_string(trace.call_site); - print_diagnostic(&mut self.dst, &snippet, Note, &diag_string, None)?; - } - } - Ok(()) - } } fn draw_col_separator(buffer: &mut StyledBuffer, line: usize, col: usize) { @@ -1230,11 +962,11 @@ fn emit_to_destination(rendered_buffer: &Vec>, dst: &mut Destination) -> io::Result<()> { for line in rendered_buffer { for part in line { - dst.apply_style(lvl.clone(), part.style); - write!(dst, "{}", part.text); + dst.apply_style(lvl.clone(), part.style)?; + write!(dst, "{}", part.text)?; dst.reset_attrs()?; } - write!(dst, "\n"); + write!(dst, "\n")?; } Ok(()) } @@ -1249,40 +981,6 @@ fn line_num_max_digits(line: &LineInfo) -> usize { digits } -fn print_diagnostic(dst: &mut Destination, - topic: &str, - lvl: Level, - msg: &str, - code: Option<&str>) - -> io::Result<()> { - if !topic.is_empty() { - let old_school = check_old_skool(); - if !old_school { - write!(dst, "{}: ", topic)?; - } - else { - write!(dst, "{} ", topic)?; - } - dst.reset_attrs()?; - } - dst.start_attr(term::Attr::Bold)?; - dst.start_attr(term::Attr::ForegroundColor(lvl.color()))?; - write!(dst, "{}", lvl.to_string())?; - dst.reset_attrs()?; - write!(dst, ": ")?; - dst.start_attr(term::Attr::Bold)?; - write!(dst, "{}", msg)?; - - if let Some(code) = code { - let style = term::Attr::ForegroundColor(term::color::BRIGHT_MAGENTA); - print_maybe_styled!(dst, style, " [{}]", code.clone())?; - } - - dst.reset_attrs()?; - write!(dst, "\n")?; - Ok(()) -} - #[cfg(unix)] fn stderr_isatty() -> bool { use libc; @@ -1374,46 +1072,6 @@ impl Destination { } Ok(()) } - - fn print_maybe_styled(&mut self, - args: fmt::Arguments, - color: term::Attr, - print_newline_at_end: bool) - -> io::Result<()> { - match *self { - Terminal(ref mut t) => { - t.attr(color)?; - // If `msg` ends in a newline, we need to reset the color before - // the newline. We're making the assumption that we end up writing - // to a `LineBufferedWriter`, which means that emitting the reset - // after the newline ends up buffering the reset until we print - // another line or exit. Buffering the reset is a problem if we're - // sharing the terminal with any other programs (e.g. other rustc - // instances via `make -jN`). - // - // Note that if `msg` contains any internal newlines, this will - // result in the `LineBufferedWriter` flushing twice instead of - // once, which still leaves the opportunity for interleaved output - // to be miscolored. We assume this is rare enough that we don't - // have to worry about it. - t.write_fmt(args)?; - t.reset()?; - if print_newline_at_end { - t.write_all(b"\n") - } else { - Ok(()) - } - } - Raw(ref mut w) => { - w.write_fmt(args)?; - if print_newline_at_end { - w.write_all(b"\n") - } else { - Ok(()) - } - } - } - } } impl Write for Destination { diff --git a/src/librustc_errors/lib.rs b/src/librustc_errors/lib.rs index 33781bed759f8..d5340e66ff0c4 100644 --- a/src/librustc_errors/lib.rs +++ b/src/librustc_errors/lib.rs @@ -82,16 +82,6 @@ pub trait CodeMapper { fn macro_backtrace(&self, span: Span) -> Vec; } -impl RenderSpan { - fn span(&self) -> &MultiSpan { - match *self { - FullSpan(ref msp) | - Suggestion(CodeSuggestion { ref msp, .. }) => - msp - } - } -} - impl CodeSuggestion { /// Returns the assembled code suggestion. pub fn splice_lines(&self, cm: &CodeMapper) -> String { diff --git a/src/librustc_errors/snippet.rs b/src/librustc_errors/snippet.rs index 525c83499fbe5..2f94a7f6832fe 100644 --- a/src/librustc_errors/snippet.rs +++ b/src/librustc_errors/snippet.rs @@ -10,13 +10,9 @@ // Code for annotating snippets. -use syntax_pos::{Span, FileMap, CharPos, LineInfo}; -use check_old_skool; +use syntax_pos::{Span, FileMap}; use CodeMapper; -use styled_buffer::StyledBuffer; -use std::cmp; use std::rc::Rc; -use std::mem; use {Level}; #[derive(Clone)] @@ -78,14 +74,6 @@ pub struct Annotation { pub label: Option, } -/* -#[derive(Debug)] -pub struct RenderedLine { - pub text: Vec, - pub kind: RenderedLineKind, -} -*/ - #[derive(Debug)] pub struct StyledString { pub text: String, @@ -108,721 +96,4 @@ pub enum Style { NoStyle, ErrorCode, Level(Level), -} - -/* -#[derive(Debug, Clone)] -pub enum RenderedLineKind { - PrimaryFileName, - OtherFileName, - SourceText { - file: Rc, - line_index: usize, - }, - Annotations, - Elision, -} -*/ - -impl SnippetData { - pub fn new(codemap: Rc, - primary_span: Option, - format_mode: FormatMode) // (*) - -> Self { - // (*) The primary span indicates the file that must appear - // first, and which will have a line number etc in its - // name. Outside of tests, this is always `Some`, but for many - // tests it's not relevant to test this portion of the logic, - // and it's tedious to pick a primary span (read: tedious to - // port older tests that predate the existence of a primary - // span). - - debug!("SnippetData::new(primary_span={:?})", primary_span); - - let mut data = SnippetData { - codemap: codemap.clone(), - files: vec![], - format_mode: format_mode.clone() - }; - if let Some(primary_span) = primary_span { - let lo = codemap.lookup_char_pos(primary_span.lo); - data.files.push( - FileInfo { - file: lo.file, - primary_span: Some(primary_span), - lines: vec![], - format_mode: format_mode.clone(), - }); - } - data - } - - pub fn push(&mut self, span: Span, is_primary: bool, label: Option) { - 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, - format_mode: self.format_mode.clone() - }); - 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, &self.format_mode); - //trim_lines(&mut rendered_lines); - rendered_lines - } -} - -pub trait StringSource { - fn make_string(self) -> String; -} - -impl StringSource for String { - fn make_string(self) -> String { - self - } -} - -impl StringSource for Vec { - 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 let Some(last_text) = self.text.last_mut() { - let len = last_text.text.trim_right().len(); - last_text.text.truncate(len); - } - } -} - -impl RenderedLineKind { - fn prefix(&self) -> StyledString { - match *self { - RenderedLineKind::SourceText { file: _, line_index } => - StyledString { - text: format!("{}", line_index + 1), - style: Style::LineNumber, - }, - RenderedLineKind::Elision => - StyledString { - text: String::from("..."), - style: Style::LineNumber, - }, - RenderedLineKind::PrimaryFileName | - RenderedLineKind::OtherFileName | - RenderedLineKind::Annotations => - StyledString { - text: String::from(""), - style: Style::LineNumber, - }, - } - } -} -*/ - -impl FileInfo { - fn get_max_line_num(&self) -> usize { - let mut max = 0; - - for line in &self.lines { - if line.line_index > max { - max = line.line_index; - } - } - max - } - - fn push_lines(&mut self, - lines: &[LineInfo], - is_primary: bool, - label: Option) { - assert!(lines.len() > 0); - - // If a span covers multiple lines, we reduce it to a single - // point at the start of the span. This means that instead - // of producing output like this: - // - // ``` - // --> foo.rs:2:1 - // 2 |> fn conflicting_items<'grammar>(state: &LR0State<'grammar>) - // |> ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - // 3 |> -> Set> - // |> ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - // (and so on) - // ``` - // - // we produce: - // - // ``` - // --> foo.rs:2:1 - // 2 |> fn conflicting_items<'grammar>(state: &LR0State<'grammar>) - // ^ - // ``` - // - // Basically, although this loses information, multi-line spans just - // never look good. - - let (line, start_col, mut end_col, is_minimized) = if lines.len() == 1 { - (lines[0].line_index, lines[0].start_col, lines[0].end_col, false) - } else { - (lines[0].line_index, lines[0].start_col, CharPos(lines[0].start_col.0 + 1), true) - }; - - // Watch out for "empty spans". If we get a span like 6..6, we - // want to just display a `^` at 6, so convert that to - // 6..7. This is degenerate input, but it's best to degrade - // gracefully -- and the parser likes to suply a span like - // that for EOF, in particular. - if start_col == end_col { - end_col.0 += 1; - } - - let index = self.ensure_source_line(line); - self.lines[index].push_annotation(start_col, - end_col, - is_primary, - is_minimized, - label); - } - - /// Ensure that we have a `Line` struct corresponding to - /// `line_index` in the file. If we already have some other lines, - /// then this will add the intervening lines to ensure that we - /// have a complete snippet. (Note that when we finally display, - /// some of those lines may be elided.) - fn ensure_source_line(&mut self, line_index: usize) -> usize { - if self.lines.is_empty() { - self.lines.push(Line::new(line_index)); - return 0; - } - - // Find the range of lines we have thus far. - let first_line_index = self.lines.first().unwrap().line_index; - let last_line_index = self.lines.last().unwrap().line_index; - assert!(first_line_index <= last_line_index); - - // If the new line is lower than all the lines we have thus - // far, then insert the new line and any intervening lines at - // the front. In a silly attempt at micro-optimization, we - // don't just call `insert` repeatedly, but instead make a new - // (empty) vector, pushing the new lines onto it, and then - // appending the old vector. - if line_index < first_line_index { - let lines = mem::replace(&mut self.lines, vec![]); - self.lines.extend( - (line_index .. first_line_index) - .map(|line| Line::new(line)) - .chain(lines)); - return 0; - } - - // If the new line comes after the ones we have so far, insert - // lines for it. - if line_index > last_line_index { - self.lines.extend( - (last_line_index+1 .. line_index+1) - .map(|line| Line::new(line))); - return self.lines.len() - 1; - } - - // Otherwise it should already exist. - return line_index - first_line_index; - } - - fn render_file_lines(&self, codemap: &Rc) -> Vec> { - let old_school = match self.format_mode { - FormatMode::OriginalErrorFormat => true, - FormatMode::NewErrorFormat => false, - FormatMode::EnvironmentSelected => check_old_skool() - }; - - let mut lines_iter = self.lines.iter(); - let mut output = vec![]; - - // First insert the name of the file. - if !old_school { - match self.primary_span { - Some(span) => { - let lo = codemap.lookup_char_pos(span.lo); - output.push(vec![StyledString { - text: lo.file.name.clone(), - style: Style::FileNameStyle, - }, StyledString { - text: format!(":{}:{}", lo.line, lo.col.0 + 1), - style: Style::LineAndColumn, - }]); - output.push(vec![StyledString { - text: "".to_string(), - style: Style::FileNameStyle, - }]); - } - None => { - output.push(vec![StyledString { - text: self.file.name.clone(), - style: Style::FileNameStyle, - }]); - output.push(vec![StyledString { - text: "".to_string(), - style: Style::FileNameStyle, - }]); - } - } - } - - let mut next_line = lines_iter.next(); - while next_line.is_some() { - // Consume lines with annotations. - while let Some(line) = next_line { - if line.annotations.is_empty() { break; } - - let mut rendered_lines = self.render_line(line); - assert!(!rendered_lines.is_empty()); - if old_school { - match self.primary_span { - Some(span) => { - let lo = codemap.lookup_char_pos(span.lo); - let hi = codemap.lookup_char_pos(span.hi); - //Before each secondary line in old skool-mode, print the label - //as an old-style note - if !line.annotations[0].is_primary { - if let Some(ann) = line.annotations[0].label.clone() { - output.push(vec![StyledString { - text: lo.file.name.clone(), - style: Style::FileNameStyle, - }, StyledString { - text: format!(":{}:{}: {}:{} ", lo.line, lo.col.0 + 1, - hi.line, hi.col.0+1), - style: Style::LineAndColumn, - }, StyledString { - text: format!("note: "), - style: Style::OldSchoolNote, - }, StyledString { - text: format!("{}", ann), - style: Style::OldSchoolNoteText, - }]); - } - } - rendered_lines[0].insert(0, StyledString { - text: format!(":{} ", lo.line), - style: Style::LineAndColumn, - }); - rendered_lines[0].insert(0, StyledString { - text: lo.file.name.clone(), - style: Style::FileNameStyle, - }); - let gap_amount = - rendered_lines[0][0].text.len() + - rendered_lines[0][1].text.len(); - assert!(rendered_lines.len() >= 2, - "no annotations resulted from: {:?}", - line); - for i in 1..rendered_lines.len() { - rendered_lines[i].insert(0, StyledString { - text: vec![" "; gap_amount].join(""), - style: Style::NoStyle - }); - } - } - _ =>() - } - } - output.append(&mut rendered_lines); - next_line = lines_iter.next(); - } - - // Emit lines without annotations, but only if they are - // followed by a line with an annotation. - let unannotated_line = next_line; - let mut unannotated_lines = 0; - while let Some(line) = next_line { - if !line.annotations.is_empty() { break; } - unannotated_lines += 1; - next_line = lines_iter.next(); - } - if unannotated_lines > 1 { - output.push(vec![StyledString{ text: String::new(), style: Style::NoStyle}]); - } else if let Some(line) = unannotated_line { - output.append(&mut self.render_line(line)); - } - } - - output - } - - fn render_line(&self, line: &Line) -> Vec> { - let old_school = match self.format_mode { - FormatMode::OriginalErrorFormat => true, - FormatMode::NewErrorFormat => false, - FormatMode::EnvironmentSelected => check_old_skool() - }; - - let source_string = self.file.get_line(line.line_index) - .unwrap_or(""); - /* - let source_kind = RenderedLineKind::SourceText { - file: self.file.clone(), - line_index: line.line_index, - }; - */ - - let mut styled_buffer = StyledBuffer::new(); - - // First create the source line we will highlight. - styled_buffer.append(0, &source_string, Style::Quotation); - - if line.annotations.is_empty() { - return styled_buffer.render(); - } - - // We want to display like this: - // - // vec.push(vec.pop().unwrap()); - // --- ^^^ _ previous borrow ends here - // | | - // | error occurs here - // previous borrow of `vec` occurs here - // - // But there are some weird edge cases to be aware of: - // - // vec.push(vec.pop().unwrap()); - // -------- - previous borrow ends here - // || - // |this makes no sense - // previous borrow of `vec` occurs here - // - // For this reason, we group the lines into "highlight lines" - // and "annotations lines", where the highlight lines have the `~`. - - //let mut highlight_line = Self::whitespace(&source_string); - - // Sort the annotations by (start, end col) - let mut annotations = line.annotations.clone(); - annotations.sort(); - - // Next, create the highlight line. - for annotation in &annotations { - if old_school { - for p in annotation.start_col .. annotation.end_col { - if p == annotation.start_col { - styled_buffer.putc(1, p, '^', - if annotation.is_primary { - Style::UnderlinePrimary - } else { - Style::OldSchoolNote - }); - } - else { - styled_buffer.putc(1, p, '~', - if annotation.is_primary { - Style::UnderlinePrimary - } else { - Style::OldSchoolNote - }); - } - } - } - else { - for p in annotation.start_col .. annotation.end_col { - if annotation.is_primary { - styled_buffer.putc(1, p, '^', Style::UnderlinePrimary); - if !annotation.is_minimized { - styled_buffer.set_style(0, p, Style::UnderlinePrimary); - } - } else { - styled_buffer.putc(1, p, '-', Style::UnderlineSecondary); - if !annotation.is_minimized { - styled_buffer.set_style(0, p, Style::UnderlineSecondary); - } - } - } - } - } - - // Now we are going to write labels in. To start, we'll exclude - // the annotations with no labels. - let (labeled_annotations, unlabeled_annotations): (Vec<_>, _) = - annotations.into_iter() - .partition(|a| a.label.is_some()); - - // If there are no annotations that need text, we're done. - if labeled_annotations.is_empty() { - return styled_buffer.render(); - } - if old_school { - return styled_buffer.render(); - } - - // Now add the text labels. We try, when possible, to stick the rightmost - // annotation at the end of the highlight line: - // - // vec.push(vec.pop().unwrap()); - // --- --- - previous borrow ends here - // - // But sometimes that's not possible because one of the other - // annotations overlaps it. For example, from the test - // `span_overlap_label`, we have the following annotations - // (written on distinct lines for clarity): - // - // fn foo(x: u32) { - // -------------- - // - - // - // In this case, we can't stick the rightmost-most label on - // the highlight line, or we would get: - // - // fn foo(x: u32) { - // -------- x_span - // | - // fn_span - // - // which is totally weird. Instead we want: - // - // fn foo(x: u32) { - // -------------- - // | | - // | x_span - // fn_span - // - // which is...less weird, at least. In fact, in general, if - // the rightmost span overlaps with any other span, we should - // use the "hang below" version, so we can at least make it - // clear where the span *starts*. - let mut labeled_annotations = &labeled_annotations[..]; - match labeled_annotations.split_last().unwrap() { - (last, previous) => { - if previous.iter() - .chain(&unlabeled_annotations) - .all(|a| !overlaps(a, last)) - { - // append the label afterwards; we keep it in a separate - // string - let highlight_label: String = format!(" {}", last.label.as_ref().unwrap()); - if last.is_primary { - styled_buffer.append(1, &highlight_label, Style::LabelPrimary); - } else { - styled_buffer.append(1, &highlight_label, Style::LabelSecondary); - } - labeled_annotations = previous; - } - } - } - - // If that's the last annotation, we're done - if labeled_annotations.is_empty() { - return styled_buffer.render(); - } - - for (index, annotation) in labeled_annotations.iter().enumerate() { - // Leave: - // - 1 extra line - // - One line for each thing that comes after - let comes_after = labeled_annotations.len() - index - 1; - let blank_lines = 3 + comes_after; - - // For each blank line, draw a `|` at our column. The - // text ought to be long enough for this. - for index in 2..blank_lines { - if annotation.is_primary { - styled_buffer.putc(index, annotation.start_col, '|', Style::UnderlinePrimary); - } else { - styled_buffer.putc(index, annotation.start_col, '|', Style::UnderlineSecondary); - } - } - - if annotation.is_primary { - styled_buffer.puts(blank_lines, annotation.start_col, - annotation.label.as_ref().unwrap(), Style::LabelPrimary); - } else { - styled_buffer.puts(blank_lines, annotation.start_col, - annotation.label.as_ref().unwrap(), Style::LabelSecondary); - } - } - - styled_buffer.render() - } -} - -/* -fn prepend_prefixes(rendered_lines: &mut [RenderedLine], format_mode: &FormatMode) { - let old_school = match *format_mode { - FormatMode::OriginalErrorFormat => true, - FormatMode::NewErrorFormat => false, - FormatMode::EnvironmentSelected => check_old_skool() - }; - if old_school { - return; - } - - let prefixes: Vec<_> = - rendered_lines.iter() - .map(|rl| rl.kind.prefix()) - .collect(); - - // find the max amount of spacing we need; add 1 to - // p.text.len() to leave space between the prefix and the - // source text - let padding_len = - prefixes.iter() - .map(|p| if p.text.len() == 0 { 0 } else { p.text.len() + 1 }) - .max() - .unwrap_or(0); - - // Ensure we insert at least one character of padding, so that the - // `-->` arrows can fit etc. - let padding_len = cmp::max(padding_len, 1); - - for (mut prefix, line) in prefixes.into_iter().zip(rendered_lines) { - let extra_spaces = (prefix.text.len() .. padding_len).map(|_| ' '); - prefix.text.extend(extra_spaces); - match line.kind { - RenderedLineKind::Elision => { - line.text.insert(0, prefix); - } - RenderedLineKind::PrimaryFileName => { - // --> filename - // 22 |> - // ^ - // padding_len - let dashes = (0..padding_len - 1).map(|_| ' ') - .chain(Some('-')) - .chain(Some('-')) - .chain(Some('>')) - .chain(Some(' ')); - line.text.insert(0, StyledString {text: dashes.collect(), - style: Style::LineNumber}) - } - RenderedLineKind::OtherFileName => { - // ::: filename - // 22 |> - // ^ - // padding_len - let dashes = (0..padding_len - 1).map(|_| ' ') - .chain(Some(':')) - .chain(Some(':')) - .chain(Some(':')) - .chain(Some(' ')); - line.text.insert(0, StyledString {text: dashes.collect(), - style: Style::LineNumber}) - } - _ => { - line.text.insert(0, prefix); - line.text.insert(1, StyledString {text: String::from("|> "), - style: Style::LineNumber}) - } - } - } -} - -fn trim_lines(rendered_lines: &mut [RenderedLine]) { - for line in rendered_lines { - while !line.text.is_empty() { - line.trim_last(); - if line.text.last().unwrap().text.is_empty() { - line.text.pop(); - } else { - break; - } - } - } -} -*/ - -impl Line { - fn new(line_index: usize) -> Line { - Line { - line_index: line_index, - annotations: vec![] - } - } - - fn push_annotation(&mut self, - start: CharPos, - end: CharPos, - is_primary: bool, - is_minimized: bool, - label: Option) { - self.annotations.push(Annotation { - start_col: start.0, - end_col: end.0, - is_primary: is_primary, - is_minimized: is_minimized, - label: label, - }); - } -} - -fn overlaps(a1: &Annotation, - a2: &Annotation) - -> bool -{ - (a2.start_col .. a2.end_col).contains(a1.start_col) || - (a1.start_col .. a1.end_col).contains(a2.start_col) -} +} \ No newline at end of file diff --git a/src/libsyntax/codemap.rs b/src/libsyntax/codemap.rs index 3b93dc0c4d37f..80b38a8e48ef9 100644 --- a/src/libsyntax/codemap.rs +++ b/src/libsyntax/codemap.rs @@ -1265,9 +1265,9 @@ r"blork2.rs:2:1: 2:12 println!("r#\"\n{}\"#", str); assert_eq!(str, &r#" --> dummy.txt:11:1 - |> -11 |> e-lä-vän - |> ^ + | +11 | e-lä-vän + | ^ "#[1..]); } @@ -1333,9 +1333,9 @@ r"blork2.rs:2:1: 2:12 let expect_start = &r#" --> dummy.txt:1:6 - |> -1 |> _____aaaaaa____bbbbbb__cccccdd_ - |> ^^^^^^ ^^^^^^ ^^^^^^^ + | +1 | _____aaaaaa____bbbbbb__cccccdd_ + | ^^^^^^ ^^^^^^ ^^^^^^^ "#[1..]; let span = |sp, expected| { @@ -1409,28 +1409,28 @@ r"blork2.rs:2:1: 2:12 let expect0 = &r#" --> dummy.txt:5:1 - |> -5 |> ccccc - |> ^ + | +5 | ccccc + | ^ ... -9 |> ddd__eee_ - |> ^^^ ^^^ -10 |> elided -11 |> __f_gg - |> ^ ^^ +9 | ddd__eee_ + | ^^^ ^^^ +10 | elided +11 | __f_gg + | ^ ^^ "#[1..]; let expect = &r#" --> dummy.txt:1:1 - |> -1 |> aaaaa - |> ^ + | +1 | aaaaa + | ^ ... -9 |> ddd__eee_ - |> ^^^ ^^^ -10 |> elided -11 |> __f_gg - |> ^ ^^ +9 | ddd__eee_ + | ^^^ ^^^ +10 | elided +11 | __f_gg + | ^ ^^ "#[1..]; macro_rules! test { @@ -1477,9 +1477,9 @@ fn foo() { let text = make_string(&lines); assert_eq!(&text[..], &" --> foo.rs:3:2 - |> -3 |> \tbar; - |> \t^^^ + | +3 | \tbar; + | \t^^^ "[1..]); } @@ -1510,12 +1510,12 @@ fn foo() { 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 + | +3 | vec.push(vec.pop().unwrap()); + | --- --- - previous borrow ends here + | | | + | | error occurs here + | previous borrow of `vec` occurs here "#[1..]); } @@ -1577,24 +1577,24 @@ fn bar() { println!("text=\n{}", text); - // Note that the `|>` remain aligned across both files: + // 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 + | +3 | vec.push(vec.pop().unwrap()); + | --- ^^^ - c + | | | + | | b + | a ::: bar.rs - |> -17 |> vec.push(); - |> --- - f - |> | - |> d + | +17 | vec.push(); + | --- - f + | | + | d ... -21 |> vec.pop().unwrap()); - |> --- e +21 | vec.pop().unwrap()); + | --- e "#[1..]); } @@ -1632,15 +1632,15 @@ fn foo() { println!("text=\n{}", text); assert_eq!(&text[..], &r#" ::: foo.rs - |> -3 |> let name = find_id(&data, 22).unwrap(); - |> ---- immutable borrow begins here + | +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 +6 | data.push(Data { name: format!("Hera"), id: 66 }); + | ---- mutable borrow occurs here ... -11 |> } - |> - immutable borrow ends here +11 | } + | - immutable borrow ends here "#[1..]); } @@ -1672,13 +1672,13 @@ fn foo() { println!("text=r#\"\n{}\".trim_left()", text); assert_eq!(&text[..], &r#" ::: foo.rs - |> -3 |> vec.push(vec.pop().unwrap()); - |> -------- ------ D - |> || - |> |C - |> A - |> B + | +3 | vec.push(vec.pop().unwrap()); + | -------- ------ D + | || + | |C + | A + | B "#[1..]); } @@ -1709,12 +1709,12 @@ fn foo() { 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 + | +3 | vec.push(vec.pop().unwrap()); + | --- --- - previous borrow ends here + | | | + | | error occurs here + | previous borrow of `vec` occurs here "#[1..]); } @@ -1748,12 +1748,12 @@ fn foo() { 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` + | +4 | let mut vec2 = vec; + | --- `vec` moved here because it has type `collections::vec::Vec` ... -9 |> vec.push(7); - |> --- use of moved value: `vec` +9 | vec.push(7); + | --- use of moved value: `vec` "#[1..]); } @@ -1785,11 +1785,11 @@ fn foo() { 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; - |> --- --- + | +3 | let mut vec = vec![0, 1, 2]; + | --- --- +4 | let mut vec2 = vec; + | --- --- "#[1..]); } @@ -1817,9 +1817,9 @@ impl SomeTrait for () { println!("r#\"\n{}\"", text); assert_eq!(text, &r#" ::: foo.rs - |> -3 |> fn foo(x: u32) { - |> - + | +3 | fn foo(x: u32) { + | - "#[1..]); } @@ -1847,12 +1847,12 @@ impl SomeTrait for () { println!("r#\"\n{}\"", text); assert_eq!(text, &r#" ::: foo.rs - |> -2 |> fn foo(x: u32) { - |> -------------- - |> | | - |> | x_span - |> fn_span + | +2 | fn foo(x: u32) { + | -------------- + | | | + | | x_span + | fn_span "#[1..]); } @@ -1882,12 +1882,12 @@ impl SomeTrait for () { println!("r#\"\n{}\"", text); assert_eq!(text, &r#" ::: foo.rs - |> -2 |> fn foo(x: u32) { - |> -------------- - |> | | - |> | x_span - |> fn_span + | +2 | fn foo(x: u32) { + | -------------- + | | | + | | x_span + | fn_span "#[1..]); } @@ -1928,11 +1928,11 @@ impl SomeTrait for () { println!("r#\"\n{}\"", text); assert_eq!(text, &r#" ::: foo.rs - |> -3 |> let closure = || { - |> - foo -4 |> inner - |> ----- bar + | +3 | let closure = || { + | - foo +4 | inner + | ----- bar "#[1..]); } @@ -1971,9 +1971,9 @@ fn main() { println!("r#\"\n{}\"", text); assert_eq!(text, &r#" --> foo.rs:11:2 - |> -11 |> } - |> - + | +11 | } + | - "#[1..]); } } From 012ff15c94ff44f45c07641bdd0957da6a625591 Mon Sep 17 00:00:00 2001 From: Jonathan Turner Date: Tue, 12 Jul 2016 16:10:01 -0400 Subject: [PATCH 09/19] Fix up some tidy-unfriendly spacing --- src/librustc_errors/emitter.rs | 10 ++++-- src/libsyntax/codemap.rs | 36 +++++++++---------- .../ui/mismatched_types/issue-26480.stderr | 4 +-- src/test/ui/mismatched_types/main.stderr | 4 +-- 4 files changed, 29 insertions(+), 25 deletions(-) diff --git a/src/librustc_errors/emitter.rs b/src/librustc_errors/emitter.rs index 901cd3403c1d2..8a5aea853f1c4 100644 --- a/src/librustc_errors/emitter.rs +++ b/src/librustc_errors/emitter.rs @@ -534,7 +534,7 @@ impl EmitterWriter { // Put in the spacer between the location and annotated source let buffer_msg_line_offset = buffer.num_lines(); - draw_col_separator(&mut buffer, buffer_msg_line_offset, max_line_num_len + 1); + draw_col_separator_no_space(&mut buffer, buffer_msg_line_offset, max_line_num_len + 1); // Next, output the annotate source for this file for line_idx in 0..annotated_file.lines.len() { @@ -636,7 +636,7 @@ impl EmitterWriter { Ok(()) => { if !db.children.is_empty() { let mut buffer = StyledBuffer::new(); - draw_col_separator(&mut buffer, 0, max_line_num_len + 1); + draw_col_separator_no_space(&mut buffer, 0, max_line_num_len + 1); match emit_to_destination(&buffer.render(), &db.level, &mut self.dst) { Ok(()) => (), Err(e) => panic!("failed to emit error: {}", e) @@ -948,6 +948,10 @@ fn draw_col_separator(buffer: &mut StyledBuffer, line: usize, col: usize) { buffer.puts(line, col, "| ", Style::LineNumber); } +fn draw_col_separator_no_space(buffer: &mut StyledBuffer, line: usize, col: usize) { + buffer.puts(line, col, "|", Style::LineNumber); +} + fn draw_note_separator(buffer: &mut StyledBuffer, line: usize, col: usize) { buffer.puts(line, col, "= ", Style::LineNumber); } @@ -1087,4 +1091,4 @@ impl Write for Destination { Raw(ref mut w) => w.flush(), } } -} +} \ No newline at end of file diff --git a/src/libsyntax/codemap.rs b/src/libsyntax/codemap.rs index 80b38a8e48ef9..9f8e08e061217 100644 --- a/src/libsyntax/codemap.rs +++ b/src/libsyntax/codemap.rs @@ -1265,7 +1265,7 @@ r"blork2.rs:2:1: 2:12 println!("r#\"\n{}\"#", str); assert_eq!(str, &r#" --> dummy.txt:11:1 - | + | 11 | e-lä-vän | ^ "#[1..]); @@ -1333,7 +1333,7 @@ r"blork2.rs:2:1: 2:12 let expect_start = &r#" --> dummy.txt:1:6 - | + | 1 | _____aaaaaa____bbbbbb__cccccdd_ | ^^^^^^ ^^^^^^ ^^^^^^^ "#[1..]; @@ -1409,7 +1409,7 @@ r"blork2.rs:2:1: 2:12 let expect0 = &r#" --> dummy.txt:5:1 - | + | 5 | ccccc | ^ ... @@ -1422,7 +1422,7 @@ r"blork2.rs:2:1: 2:12 let expect = &r#" --> dummy.txt:1:1 - | + | 1 | aaaaa | ^ ... @@ -1477,7 +1477,7 @@ fn foo() { let text = make_string(&lines); assert_eq!(&text[..], &" --> foo.rs:3:2 - | + | 3 | \tbar; | \t^^^ "[1..]); @@ -1510,7 +1510,7 @@ fn foo() { println!("text=\n{}", text); assert_eq!(&text[..], &r#" ::: foo.rs - | + | 3 | vec.push(vec.pop().unwrap()); | --- --- - previous borrow ends here | | | @@ -1580,14 +1580,14 @@ fn bar() { // 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 | | @@ -1632,7 +1632,7 @@ fn foo() { println!("text=\n{}", text); assert_eq!(&text[..], &r#" ::: foo.rs - | + | 3 | let name = find_id(&data, 22).unwrap(); | ---- immutable borrow begins here ... @@ -1672,7 +1672,7 @@ fn foo() { println!("text=r#\"\n{}\".trim_left()", text); assert_eq!(&text[..], &r#" ::: foo.rs - | + | 3 | vec.push(vec.pop().unwrap()); | -------- ------ D | || @@ -1709,7 +1709,7 @@ fn foo() { println!("text=r#\"\n{}\".trim_left()", text); assert_eq!(&text[..], &r#" ::: foo.rs - | + | 3 | vec.push(vec.pop().unwrap()); | --- --- - previous borrow ends here | | | @@ -1748,7 +1748,7 @@ fn foo() { 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` ... @@ -1785,7 +1785,7 @@ fn foo() { 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; @@ -1817,7 +1817,7 @@ impl SomeTrait for () { println!("r#\"\n{}\"", text); assert_eq!(text, &r#" ::: foo.rs - | + | 3 | fn foo(x: u32) { | - "#[1..]); @@ -1847,7 +1847,7 @@ impl SomeTrait for () { println!("r#\"\n{}\"", text); assert_eq!(text, &r#" ::: foo.rs - | + | 2 | fn foo(x: u32) { | -------------- | | | @@ -1882,7 +1882,7 @@ impl SomeTrait for () { println!("r#\"\n{}\"", text); assert_eq!(text, &r#" ::: foo.rs - | + | 2 | fn foo(x: u32) { | -------------- | | | @@ -1928,7 +1928,7 @@ impl SomeTrait for () { println!("r#\"\n{}\"", text); assert_eq!(text, &r#" ::: foo.rs - | + | 3 | let closure = || { | - foo 4 | inner @@ -1971,7 +1971,7 @@ fn main() { println!("r#\"\n{}\"", text); assert_eq!(text, &r#" --> foo.rs:11:2 - | + | 11 | } | - "#[1..]); diff --git a/src/test/ui/mismatched_types/issue-26480.stderr b/src/test/ui/mismatched_types/issue-26480.stderr index 63f2ab4d7c6bf..ff6920d28ccf9 100644 --- a/src/test/ui/mismatched_types/issue-26480.stderr +++ b/src/test/ui/mismatched_types/issue-26480.stderr @@ -1,13 +1,13 @@ error[E0308]: mismatched types --> $DIR/issue-26480.rs:27:19 - | + | 27 | $arr.len() * size_of($arr[0])); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ expected u64, found usize $DIR/issue-26480.rs:38:5: 38:19 note: in this expansion of write! (defined in $DIR/issue-26480.rs) error: non-scalar cast: `_` as `()` --> $DIR/issue-26480.rs:33:19 - | + | 33 | ($x:expr) => ($x as ()) | ^^^^^^^^ $DIR/issue-26480.rs:39:5: 39:14 note: in this expansion of cast! (defined in $DIR/issue-26480.rs) diff --git a/src/test/ui/mismatched_types/main.stderr b/src/test/ui/mismatched_types/main.stderr index ae1d417eca9ee..2903aa08c0a91 100644 --- a/src/test/ui/mismatched_types/main.stderr +++ b/src/test/ui/mismatched_types/main.stderr @@ -1,9 +1,9 @@ error[E0308]: mismatched types --> $DIR/main.rs:14:18 - | + | 14 | let x: u32 = ( | ^ expected u32, found () - | + | = note: expected type `u32` = note: found type `()` From 2e8e73cb951e2095e444c5cc91403f7e9c5f1065 Mon Sep 17 00:00:00 2001 From: Jonathan Turner Date: Wed, 13 Jul 2016 05:44:29 -0400 Subject: [PATCH 10/19] Add in styled_buffer.rs and remove some unused code --- src/librustc/infer/error_reporting.rs | 4 +- src/librustc_errors/emitter.rs | 73 ++++---------- src/librustc_errors/lib.rs | 4 +- src/librustc_errors/styled_buffer.rs | 133 ++++++++++++++++++++++++++ 4 files changed, 158 insertions(+), 56 deletions(-) create mode 100644 src/librustc_errors/styled_buffer.rs diff --git a/src/librustc/infer/error_reporting.rs b/src/librustc/infer/error_reporting.rs index 894044296cbd6..96ecad629f543 100644 --- a/src/librustc/infer/error_reporting.rs +++ b/src/librustc/infer/error_reporting.rs @@ -94,7 +94,7 @@ use syntax::ast; use syntax::parse::token; use syntax::ptr::P; use syntax_pos::{self, Pos, Span}; -use errors::{DiagnosticBuilder, check_old_skool}; +use errors::{DiagnosticBuilder, check_old_school}; impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> { pub fn note_and_explain_region(self, @@ -485,7 +485,7 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> { "{}", trace.origin); - if !is_simple_error || check_old_skool() { + if !is_simple_error || check_old_school() { err.note_expected_found(&"type", &expected, &found); } diff --git a/src/librustc_errors/emitter.rs b/src/librustc_errors/emitter.rs index 8a5aea853f1c4..161f2f7bb1c30 100644 --- a/src/librustc_errors/emitter.rs +++ b/src/librustc_errors/emitter.rs @@ -13,7 +13,7 @@ use self::Destination::*; use syntax_pos::{COMMAND_LINE_SP, DUMMY_SP, FileMap, Span, MultiSpan, LineInfo, CharPos}; use registry; -use check_old_skool; +use check_old_school; use {Level, CodeSuggestion, DiagnosticBuilder, CodeMapper}; use RenderSpan::*; use snippet::{StyledString, Style, FormatMode, Annotation, Line}; @@ -36,7 +36,7 @@ impl Emitter for EmitterWriter { let old_school = match self.format_mode { FormatMode::NewErrorFormat => false, FormatMode::OriginalErrorFormat => true, - FormatMode::EnvironmentSelected => check_old_skool() + FormatMode::EnvironmentSelected => check_old_school() }; if old_school { @@ -243,59 +243,32 @@ impl EmitterWriter { // 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); - let old_school = check_old_skool(); - // Sort the annotations by (start, end col) let mut annotations = line.annotations.clone(); annotations.sort(); // Next, create the highlight line. for annotation in &annotations { - if old_school { - for p in annotation.start_col..annotation.end_col { - if p == annotation.start_col { - buffer.putc(line_offset + 1, - width_offset + p, - '^', - if annotation.is_primary { - Style::UnderlinePrimary - } else { - Style::OldSchoolNote - }); - } else { - buffer.putc(line_offset + 1, - width_offset + p, - '~', - if annotation.is_primary { - Style::UnderlinePrimary - } else { - Style::OldSchoolNote - }); + for p in annotation.start_col..annotation.end_col { + if annotation.is_primary { + buffer.putc(line_offset + 1, + width_offset + p, + '^', + Style::UnderlinePrimary); + if !annotation.is_minimized { + buffer.set_style(line_offset, + width_offset + p, + Style::UnderlinePrimary); } - } - } else { - for p in annotation.start_col..annotation.end_col { - if annotation.is_primary { - buffer.putc(line_offset + 1, - width_offset + p, - '^', - Style::UnderlinePrimary); - if !annotation.is_minimized { - buffer.set_style(line_offset, - width_offset + p, - Style::UnderlinePrimary); - } - } else { - buffer.putc(line_offset + 1, - width_offset + p, - '-', - Style::UnderlineSecondary); - if !annotation.is_minimized { - buffer.set_style(line_offset, - width_offset + p, - Style::UnderlineSecondary); - } + } else { + buffer.putc(line_offset + 1, + width_offset + p, + '-', + Style::UnderlineSecondary); + if !annotation.is_minimized { + buffer.set_style(line_offset, + width_offset + p, + Style::UnderlineSecondary); } } } @@ -311,10 +284,6 @@ impl EmitterWriter { if labeled_annotations.is_empty() { return; } - if old_school { - return; - } - // Now add the text labels. We try, when possible, to stick the rightmost // annotation at the end of the highlight line: // diff --git a/src/librustc_errors/lib.rs b/src/librustc_errors/lib.rs index d5340e66ff0c4..6a48f65714cc5 100644 --- a/src/librustc_errors/lib.rs +++ b/src/librustc_errors/lib.rs @@ -756,13 +756,13 @@ pub fn expect(diag: &Handler, opt: Option, msg: M) -> T where /// /// FIXME(#33240) #[cfg(not(test))] -pub fn check_old_skool() -> bool { +pub fn check_old_school() -> bool { use std::env; env::var("RUST_NEW_ERROR_FORMAT").is_err() } /// For unit tests, use the new format. #[cfg(test)] -pub fn check_old_skool() -> bool { +pub fn check_old_school() -> bool { false } diff --git a/src/librustc_errors/styled_buffer.rs b/src/librustc_errors/styled_buffer.rs new file mode 100644 index 0000000000000..238caf93b83f0 --- /dev/null +++ b/src/librustc_errors/styled_buffer.rs @@ -0,0 +1,133 @@ +// 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 creating styled buffers + +use snippet::{Style, StyledString}; + +#[derive(Debug)] +pub struct StyledBuffer { + text: Vec>, + styles: Vec>, +} + +impl StyledBuffer { + pub fn new() -> StyledBuffer { + StyledBuffer { + text: vec![], + styles: vec![], + } + } + + pub fn render(&self) -> 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 = 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, + }); + } + + // We're done with the row, push and keep going + output.push(styled_vec); + + styled_vec = vec![]; + } + + output + } + + fn ensure_lines(&mut self, line: usize) { + while line >= self.text.len() { + self.text.push(vec![]); + self.styles.push(vec![]); + } + } + + pub fn putc(&mut self, line: usize, col: usize, chr: char, style: Style) { + self.ensure_lines(line); + if col < self.text[line].len() { + self.text[line][col] = chr; + self.styles[line][col] = style; + } else { + let mut i = self.text[line].len(); + while i < col { + let s = match self.text[0].get(i) { + Some(&'\t') => '\t', + _ => ' ', + }; + self.text[line].push(s); + self.styles[line].push(Style::NoStyle); + i += 1; + } + self.text[line].push(chr); + self.styles[line].push(style); + } + } + + pub 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; + } + } + + pub 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; + } + } + + pub fn prepend(&mut self, line: usize, string: &str, style: Style) { + self.ensure_lines(line); + let string_len = string.len(); + + // Push the old content over to make room for new content + for _ in 0..string_len { + self.styles[line].insert(0, Style::NoStyle); + self.text[line].insert(0, ' '); + } + + self.puts(line, 0, string, style); + } + + pub 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); + } + } + + pub fn num_lines(&self) -> usize { + self.text.len() + } +} From 1fd014a9654e11ae1bc7c0793c6b01b157d825cd Mon Sep 17 00:00:00 2001 From: Jonathan Turner Date: Wed, 13 Jul 2016 17:53:42 -0400 Subject: [PATCH 11/19] Add fix for tabs. Move error unit tests->ui tests --- src/librustc_errors/styled_buffer.rs | 25 +- src/libsyntax/codemap.rs | 770 +----------------- src/test/ui/codemap_tests/empty_span.rs | 19 + src/test/ui/codemap_tests/empty_span.stderr | 8 + .../codemap_tests/huge_multispan_highlight.rs | 104 +++ .../huge_multispan_highlight.stderr | 11 + src/test/ui/codemap_tests/issue-11715.rs | 104 +++ src/test/ui/codemap_tests/issue-11715.stderr | 12 + src/test/ui/codemap_tests/one_line.rs | 16 + src/test/ui/codemap_tests/one_line.stderr | 11 + .../ui/codemap_tests/overlapping_spans.rs | 24 + .../ui/codemap_tests/overlapping_spans.stderr | 11 + src/test/ui/codemap_tests/tab.rs | 16 + src/test/ui/codemap_tests/tab.stderr | 8 + src/test/ui/codemap_tests/two_files.rs | 18 + src/test/ui/codemap_tests/two_files.stderr | 13 + src/test/ui/codemap_tests/two_files_data.rs | 16 + 17 files changed, 414 insertions(+), 772 deletions(-) create mode 100644 src/test/ui/codemap_tests/empty_span.rs create mode 100644 src/test/ui/codemap_tests/empty_span.stderr create mode 100644 src/test/ui/codemap_tests/huge_multispan_highlight.rs create mode 100644 src/test/ui/codemap_tests/huge_multispan_highlight.stderr create mode 100644 src/test/ui/codemap_tests/issue-11715.rs create mode 100644 src/test/ui/codemap_tests/issue-11715.stderr create mode 100644 src/test/ui/codemap_tests/one_line.rs create mode 100644 src/test/ui/codemap_tests/one_line.stderr create mode 100644 src/test/ui/codemap_tests/overlapping_spans.rs create mode 100644 src/test/ui/codemap_tests/overlapping_spans.stderr create mode 100644 src/test/ui/codemap_tests/tab.rs create mode 100644 src/test/ui/codemap_tests/tab.stderr create mode 100644 src/test/ui/codemap_tests/two_files.rs create mode 100644 src/test/ui/codemap_tests/two_files.stderr create mode 100644 src/test/ui/codemap_tests/two_files_data.rs diff --git a/src/librustc_errors/styled_buffer.rs b/src/librustc_errors/styled_buffer.rs index 238caf93b83f0..9768b68619e79 100644 --- a/src/librustc_errors/styled_buffer.rs +++ b/src/librustc_errors/styled_buffer.rs @@ -26,10 +26,27 @@ impl StyledBuffer { } } - pub fn render(&self) -> Vec> { + pub fn copy_tabs(&mut self, row: usize) { + if row < self.text.len() { + for i in row+1..self.text.len() { + for j in 0..self.text[i].len() { + if self.text[row].len() > j && + self.text[row][j] == '\t' && + self.text[i][j] == ' ' { + self.text[i][j] = '\t'; + } + } + } + } + } + + pub fn render(&mut self) -> Vec> { let mut output: Vec> = vec![]; let mut styled_vec: Vec = vec![]; + //before we render, do a little patch-up work to support tabs + self.copy_tabs(3); + for (row, row_style) in self.text.iter().zip(&self.styles) { let mut current_style = Style::NoStyle; let mut current_text = String::new(); @@ -78,11 +95,7 @@ impl StyledBuffer { } else { let mut i = self.text[line].len(); while i < col { - let s = match self.text[0].get(i) { - Some(&'\t') => '\t', - _ => ' ', - }; - self.text[line].push(s); + self.text[line].push(' '); self.styles[line].push(Style::NoStyle); i += 1; } diff --git a/src/libsyntax/codemap.rs b/src/libsyntax/codemap.rs index 9f8e08e061217..afa5a3b38ba27 100644 --- a/src/libsyntax/codemap.rs +++ b/src/libsyntax/codemap.rs @@ -827,12 +827,7 @@ impl CodeMapper for CodeMap { #[cfg(test)] mod tests { use super::*; - use errors::{Level, CodeSuggestion}; - use errors::emitter::EmitterWriter; - use errors::snippet::{SnippetData, RenderedLine, FormatMode}; - use std::sync::{Arc, Mutex}; use std::io::{self, Write}; - use std::str::from_utf8; use std::rc::Rc; #[test] @@ -1130,12 +1125,12 @@ mod tests { } } - fn make_string(lines: &[RenderedLine]) -> String { + fn make_string(lines: Vec>) -> String { lines.iter() .flat_map(|rl| { - rl.text.iter() - .map(|s| &s.text[..]) - .chain(Some("\n")) + rl.iter() + .map(|s| &s.text[..]) + .chain(Some("\n")) }) .collect() } @@ -1219,761 +1214,4 @@ r"blork2.rs:2:1: 2:12 "; assert_eq!(sstr, res_str); } - - struct Sink(Arc>>); - impl Write for Sink { - fn write(&mut self, data: &[u8]) -> io::Result { - Write::write(&mut *self.0.lock().unwrap(), data) - } - fn flush(&mut self) -> io::Result<()> { Ok(()) } - } - - // Diagnostic doesn't align properly in span where line number increases by one digit - #[test] - fn test_hilight_suggestion_issue_11715() { - let data = Arc::new(Mutex::new(Vec::new())); - let cm = Rc::new(CodeMap::new()); - let mut ew = EmitterWriter::new(Box::new(Sink(data.clone())), - None, - Some(cm.clone()), - FormatMode::NewErrorFormat); - let content = "abcdefg - koksi - line3 - line4 - cinq - line6 - line7 - line8 - line9 - line10 - e-lä-vän - tolv - dreizehn - "; - let file = cm.new_filemap_and_lines("dummy.txt", None, content); - let start = file.lines.borrow()[10]; - let end = file.lines.borrow()[11]; - let sp = mk_sp(start, end); - let lvl = Level::Error; - println!("highlight_lines"); - ew.highlight_lines(&sp.into(), lvl).unwrap(); - println!("done"); - let vec = data.lock().unwrap().clone(); - let vec: &[u8] = &vec; - let str = from_utf8(vec).unwrap(); - println!("r#\"\n{}\"#", str); - assert_eq!(str, &r#" - --> dummy.txt:11:1 - | -11 | e-lä-vän - | ^ -"#[1..]); - } - - #[test] - fn test_single_span_splice() { - // 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"; - cm.new_filemap_and_lines("blork.rs", None, inputtext); - let sp = span_from_selection(inputtext, selection); - let msp: MultiSpan = sp.into(); - - // check that we are extracting the text we thought we were extracting - assert_eq!(&cm.span_to_snippet(sp).unwrap(), "BB\nCCC\nDDDDD"); - - let substitute = "ZZZZZZ".to_owned(); - let expected = "bbbbZZZZZZddddd"; - let suggest = CodeSuggestion { - msp: msp, - substitutes: vec![substitute], - }; - assert_eq!(suggest.splice_lines(&cm), expected); - } - - #[test] - fn test_multi_span_splice() { - // Test that a `MultiSpan` containing multiple spans splices a substition correctly - let cm = CodeMap::new(); - 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", None, 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()] - }; - - assert_eq!(suggest.splice_lines(&cm), expected); - } - - #[test] - fn test_multispan_highlight() { - let data = Arc::new(Mutex::new(Vec::new())); - let cm = Rc::new(CodeMap::new()); - let mut diag = EmitterWriter::new(Box::new(Sink(data.clone())), - None, - Some(cm.clone()), - FormatMode::NewErrorFormat); - - let inp = "_____aaaaaa____bbbbbb__cccccdd_"; - 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); - assert_eq!(&cm.span_to_snippet(sp).unwrap(), expected); - sp - }; - cm.new_filemap_and_lines("dummy.txt", None, inp); - let sp1 = span(sp1, "aaaaaa"); - let sp2 = span(sp2, "bbbbbb"); - let sp3 = span(sp3, "ccccc"); - let sp4 = span(sp4, "ccdd"); - let sp34 = span(sp34, "cccccdd"); - - let spans = vec![sp1, sp2, sp3, sp4]; - - let test = |expected, highlight: &mut FnMut()| { - data.lock().unwrap().clear(); - highlight(); - let vec = data.lock().unwrap().clone(); - let actual = from_utf8(&vec[..]).unwrap(); - println!("actual=\n{}", actual); - assert_eq!(actual, expected); - }; - - let msp = MultiSpan::from_spans(vec![sp1, sp2, sp34]); - test(expect_start, &mut || { - diag.highlight_lines(&msp, Level::Error).unwrap(); - }); - test(expect_start, &mut || { - let msp = MultiSpan::from_spans(spans.clone()); - diag.highlight_lines(&msp, Level::Error).unwrap(); - }); - } - - #[test] - fn test_huge_multispan_highlight() { - let data = Arc::new(Mutex::new(Vec::new())); - let cm = Rc::new(CodeMap::new()); - let mut diag = EmitterWriter::new(Box::new(Sink(data.clone())), - None, - Some(cm.clone()), - FormatMode::NewErrorFormat); - - let inp = "aaaaa\n\ - aaaaa\n\ - aaaaa\n\ - bbbbb\n\ - ccccc\n\ - xxxxx\n\ - yyyyy\n\ - _____\n\ - ddd__eee_\n\ - elided\n\ - __f_gg"; - let file = cm.new_filemap_and_lines("dummy.txt", None, inp); - - let span = |lo, hi, (off_lo, off_hi)| { - let lines = file.lines.borrow(); - let (mut lo, mut hi): (BytePos, BytePos) = (lines[lo], lines[hi]); - lo.0 += off_lo; - hi.0 += off_hi; - mk_sp(lo, hi) - }; - let sp0 = span(4, 6, (0, 5)); - let sp1 = span(0, 6, (0, 5)); - let sp2 = span(8, 8, (0, 3)); - let sp3 = span(8, 8, (5, 8)); - let sp4 = span(10, 10, (2, 3)); - let sp5 = span(10, 10, (4, 6)); - - let expect0 = &r#" - --> dummy.txt:5:1 - | -5 | ccccc - | ^ -... -9 | ddd__eee_ - | ^^^ ^^^ -10 | elided -11 | __f_gg - | ^ ^^ -"#[1..]; - - let expect = &r#" - --> dummy.txt:1:1 - | -1 | aaaaa - | ^ -... -9 | ddd__eee_ - | ^^^ ^^^ -10 | elided -11 | __f_gg - | ^ ^^ -"#[1..]; - - macro_rules! test { - ($expected: expr, $highlight: expr) => ({ - data.lock().unwrap().clear(); - $highlight(); - let vec = data.lock().unwrap().clone(); - let actual = from_utf8(&vec[..]).unwrap(); - println!("actual:"); - println!("{}", actual); - println!("expected:"); - println!("{}", $expected); - assert_eq!(&actual[..], &$expected[..]); - }); - } - - 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!(expect, || { - diag.highlight_lines(&msp, Level::Error).unwrap(); - }); - } - - #[test] - fn tab() { - let file_text = " -fn foo() { -\tbar; -} -"; - - let cm = Rc::new(CodeMap::new()); - let foo = cm.new_filemap_and_lines("foo.rs", None, file_text); - let span_bar = cm.span_substr(&foo, file_text, "bar", 0); - - let mut snippet = SnippetData::new(cm, Some(span_bar), FormatMode::NewErrorFormat); - snippet.push(span_bar, true, None); - - let lines = snippet.render_lines(); - let text = make_string(&lines); - assert_eq!(&text[..], &" - --> foo.rs:3:2 - | -3 | \tbar; - | \t^^^ -"[1..]); - } - - #[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", None, 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, FormatMode::NewErrorFormat); - 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", None, 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", None, 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), FormatMode::NewErrorFormat); - 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", None, 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, FormatMode::NewErrorFormat); - 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", None, 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, FormatMode::NewErrorFormat); - 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", None, 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, FormatMode::NewErrorFormat); - 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", None, 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, FormatMode::NewErrorFormat); - 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", None, file_text); - - let mut snippet = SnippetData::new(cm.clone(), None, FormatMode::NewErrorFormat); - 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", None, file_text); - - let mut snippet = SnippetData::new(cm.clone(), None, FormatMode::NewErrorFormat); - 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", None, file_text); - - let mut snippet = SnippetData::new(cm.clone(), None, FormatMode::NewErrorFormat); - 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", None, file_text); - - let mut snippet = SnippetData::new(cm.clone(), None, FormatMode::NewErrorFormat); - 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", None, file_text); - - let mut snippet = SnippetData::new(cm.clone(), None, FormatMode::NewErrorFormat); - - 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 -"#[1..]); - } - - #[test] - fn span_empty() { - // In one of the unit tests, we found that the parser sometimes - // gives empty spans, and in particular it supplied an EOF span - // like this one, which points at the very end. We want to - // fallback gracefully in this case. - - let file_text = r#" -fn main() { - struct Foo; - - impl !Sync for Foo {} - - unsafe impl Send for &'static Foo { - // error: cross-crate traits with a default impl, like `core::marker::Send`, - // can only be implemented for a struct/enum type, not - // `&'static Foo` -}"#; - - - let cm = Rc::new(CodeMap::new()); - let foo = cm.new_filemap_and_lines("foo.rs", None, file_text); - - let mut rbrace_span = cm.span_substr(&foo, file_text, "}", 1); - rbrace_span.lo = rbrace_span.hi; - - let mut snippet = SnippetData::new(cm.clone(), - Some(rbrace_span), - FormatMode::NewErrorFormat); - snippet.push(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:11:2 - | -11 | } - | - -"#[1..]); - } } diff --git a/src/test/ui/codemap_tests/empty_span.rs b/src/test/ui/codemap_tests/empty_span.rs new file mode 100644 index 0000000000000..c78a586763429 --- /dev/null +++ b/src/test/ui/codemap_tests/empty_span.rs @@ -0,0 +1,19 @@ +// Copyright 2016 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +// rustc-env:RUST_NEW_ERROR_FORMAT +#![feature(optin_builtin_traits)] +fn main() { + struct Foo; + + impl !Sync for Foo {} + + unsafe impl Send for &'static Foo { } +} diff --git a/src/test/ui/codemap_tests/empty_span.stderr b/src/test/ui/codemap_tests/empty_span.stderr new file mode 100644 index 0000000000000..f3e04ef02409b --- /dev/null +++ b/src/test/ui/codemap_tests/empty_span.stderr @@ -0,0 +1,8 @@ +error[E0321]: cross-crate traits with a default impl, like `std::marker::Send`, can only be implemented for a struct/enum type, not `&'static main::Foo` + --> $DIR/empty_span.rs:18:5 + | +18 | unsafe impl Send for &'static Foo { } + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +error: aborting due to previous error + diff --git a/src/test/ui/codemap_tests/huge_multispan_highlight.rs b/src/test/ui/codemap_tests/huge_multispan_highlight.rs new file mode 100644 index 0000000000000..b06832c7628ed --- /dev/null +++ b/src/test/ui/codemap_tests/huge_multispan_highlight.rs @@ -0,0 +1,104 @@ +// Copyright 2016 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +// rustc-env:RUST_NEW_ERROR_FORMAT + +fn main() { + let x = "foo"; + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + let y = &mut x; +} + + + diff --git a/src/test/ui/codemap_tests/huge_multispan_highlight.stderr b/src/test/ui/codemap_tests/huge_multispan_highlight.stderr new file mode 100644 index 0000000000000..6a898a434778e --- /dev/null +++ b/src/test/ui/codemap_tests/huge_multispan_highlight.stderr @@ -0,0 +1,11 @@ +error: cannot borrow immutable local variable `x` as mutable + --> $DIR/huge_multispan_highlight.rs:100:18 + | +14 | let x = "foo"; + | - use `mut x` here to make mutable +... +100 | let y = &mut x; + | ^ cannot borrow mutably + +error: aborting due to previous error + diff --git a/src/test/ui/codemap_tests/issue-11715.rs b/src/test/ui/codemap_tests/issue-11715.rs new file mode 100644 index 0000000000000..7ea497a25c832 --- /dev/null +++ b/src/test/ui/codemap_tests/issue-11715.rs @@ -0,0 +1,104 @@ +// Copyright 2016 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +// rustc-env:RUST_NEW_ERROR_FORMAT + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +fn main() { + let mut x = "foo"; + let y = &mut x; + let z = &mut x; +} + + + diff --git a/src/test/ui/codemap_tests/issue-11715.stderr b/src/test/ui/codemap_tests/issue-11715.stderr new file mode 100644 index 0000000000000..4947cbedd200e --- /dev/null +++ b/src/test/ui/codemap_tests/issue-11715.stderr @@ -0,0 +1,12 @@ +error[E0499]: cannot borrow `x` as mutable more than once at a time + --> $DIR/issue-11715.rs:100:18 + | +99 | let y = &mut x; + | - first mutable borrow occurs here +100 | let z = &mut x; + | ^ second mutable borrow occurs here +101 | } + | - first borrow ends here + +error: aborting due to previous error + diff --git a/src/test/ui/codemap_tests/one_line.rs b/src/test/ui/codemap_tests/one_line.rs new file mode 100644 index 0000000000000..2a5ee6f8711ef --- /dev/null +++ b/src/test/ui/codemap_tests/one_line.rs @@ -0,0 +1,16 @@ +// Copyright 2016 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +// rustc-env:RUST_NEW_ERROR_FORMAT + +fn main() { + let mut v = vec![Some("foo"), Some("bar")]; + v.push(v.pop().unwrap()); +} diff --git a/src/test/ui/codemap_tests/one_line.stderr b/src/test/ui/codemap_tests/one_line.stderr new file mode 100644 index 0000000000000..8f80489ea1aeb --- /dev/null +++ b/src/test/ui/codemap_tests/one_line.stderr @@ -0,0 +1,11 @@ +error[E0499]: cannot borrow `v` as mutable more than once at a time + --> $DIR/one_line.rs:15:12 + | +15 | v.push(v.pop().unwrap()); + | - ^ - first borrow ends here + | | | + | | second mutable borrow occurs here + | first mutable borrow occurs here + +error: aborting due to previous error + diff --git a/src/test/ui/codemap_tests/overlapping_spans.rs b/src/test/ui/codemap_tests/overlapping_spans.rs new file mode 100644 index 0000000000000..5a90852392c08 --- /dev/null +++ b/src/test/ui/codemap_tests/overlapping_spans.rs @@ -0,0 +1,24 @@ +// Copyright 2016 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +// rustc-env:RUST_NEW_ERROR_FORMAT +#[derive(Debug)] +struct Foo { } + +struct S {f:String} +impl Drop for S { + fn drop(&mut self) { println!("{}", self.f); } +} + +fn main() { + match (S {f:"foo".to_string()}) { + S {f:_s} => {} + } +} diff --git a/src/test/ui/codemap_tests/overlapping_spans.stderr b/src/test/ui/codemap_tests/overlapping_spans.stderr new file mode 100644 index 0000000000000..cbcf154eaba50 --- /dev/null +++ b/src/test/ui/codemap_tests/overlapping_spans.stderr @@ -0,0 +1,11 @@ +error[E0509]: cannot move out of type `S`, which implements the `Drop` trait + --> $DIR/overlapping_spans.rs:22:9 + | +22 | S {f:_s} => {} + | ^^^^^--^ + | | | + | | hint: to prevent move, use `ref _s` or `ref mut _s` + | cannot move out of here + +error: aborting due to previous error + diff --git a/src/test/ui/codemap_tests/tab.rs b/src/test/ui/codemap_tests/tab.rs new file mode 100644 index 0000000000000..aaaee8c5577fe --- /dev/null +++ b/src/test/ui/codemap_tests/tab.rs @@ -0,0 +1,16 @@ +// Copyright 2016 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +// rustc-env:RUST_NEW_ERROR_FORMAT +// ignore-tidy-tab +fn main() { + bar; +} + diff --git a/src/test/ui/codemap_tests/tab.stderr b/src/test/ui/codemap_tests/tab.stderr new file mode 100644 index 0000000000000..543c02fb701f3 --- /dev/null +++ b/src/test/ui/codemap_tests/tab.stderr @@ -0,0 +1,8 @@ +error[E0425]: unresolved name `bar` + --> $DIR/tab.rs:14:2 + | +14 | \tbar; + | \t^^^ + +error: aborting due to previous error + diff --git a/src/test/ui/codemap_tests/two_files.rs b/src/test/ui/codemap_tests/two_files.rs new file mode 100644 index 0000000000000..53e240e8c4738 --- /dev/null +++ b/src/test/ui/codemap_tests/two_files.rs @@ -0,0 +1,18 @@ +// Copyright 2016 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +// rustc-env:RUST_NEW_ERROR_FORMAT +include!("two_files_data.rs"); + +struct Baz { } + +impl Bar for Baz { } + +fn main() { } diff --git a/src/test/ui/codemap_tests/two_files.stderr b/src/test/ui/codemap_tests/two_files.stderr new file mode 100644 index 0000000000000..6c388cd69395b --- /dev/null +++ b/src/test/ui/codemap_tests/two_files.stderr @@ -0,0 +1,13 @@ +error[E0404]: `Bar` is not a trait + --> $DIR/two_files.rs:16:6 + | +16 | impl Bar for Baz { } + | ^^^ `Bar` is not a trait + | + ::: $DIR/two_files_data.rs + | +15 | type Bar = Foo; + | --------------- type aliases cannot be used for traits + +error: cannot continue compilation due to previous error + diff --git a/src/test/ui/codemap_tests/two_files_data.rs b/src/test/ui/codemap_tests/two_files_data.rs new file mode 100644 index 0000000000000..412c40f8e811b --- /dev/null +++ b/src/test/ui/codemap_tests/two_files_data.rs @@ -0,0 +1,16 @@ +// Copyright 2016 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +// rustc-env:RUST_NEW_ERROR_FORMAT +// ignore-test +trait Foo { } + +type Bar = Foo; + From d162b97c4bb63302d19f4d6ae61a369ba278ff42 Mon Sep 17 00:00:00 2001 From: Jonathan Turner Date: Thu, 14 Jul 2016 06:50:50 -0400 Subject: [PATCH 12/19] Teach EmitterWriter about the dangers of quasi-quoting --- src/librustc_errors/emitter.rs | 27 ++++++++++++++++++++------- 1 file changed, 20 insertions(+), 7 deletions(-) diff --git a/src/librustc_errors/emitter.rs b/src/librustc_errors/emitter.rs index 161f2f7bb1c30..6c47c01d0fb1e 100644 --- a/src/librustc_errors/emitter.rs +++ b/src/librustc_errors/emitter.rs @@ -166,6 +166,9 @@ impl EmitterWriter { if let Some(ref cm) = self.cm { for span_label in msp.span_labels() { + if span_label.span == DUMMY_SP || span_label.span == COMMAND_LINE_SP { + continue; + } let lo = cm.lookup_char_pos(span_label.span.lo); let mut hi = cm.lookup_char_pos(span_label.span.hi); let mut is_minimized = false; @@ -386,15 +389,19 @@ impl EmitterWriter { let mut max = 0; if let Some(ref cm) = self.cm { for primary_span in msp.primary_spans() { - let hi = cm.lookup_char_pos(primary_span.hi); - if hi.line > max { - max = hi.line; + if primary_span != &DUMMY_SP && primary_span != &COMMAND_LINE_SP { + let hi = cm.lookup_char_pos(primary_span.hi); + if hi.line > max { + max = hi.line; + } } } for span_label in msp.span_labels() { - let hi = cm.lookup_char_pos(span_label.span.hi); - if hi.line > max { - max = hi.line; + if span_label.span != DUMMY_SP && span_label.span != COMMAND_LINE_SP { + let hi = cm.lookup_char_pos(span_label.span.hi); + if hi.line > max { + max = hi.line; + } } } } @@ -456,7 +463,13 @@ impl EmitterWriter { let primary_lo = if let (Some(ref cm), Some(ref primary_span)) = (self.cm.as_ref(), msp.primary_span().as_ref()) { - cm.lookup_char_pos(primary_span.lo) + if primary_span != &&DUMMY_SP && primary_span != &&COMMAND_LINE_SP { + cm.lookup_char_pos(primary_span.lo) + } + else { + emit_to_destination(&buffer.render(), level, &mut self.dst)?; + return Ok(()); + } } else { // If we don't have span information, emit and exit emit_to_destination(&buffer.render(), level, &mut self.dst)?; From a9dfac8725bb8a550318034a577c9b273545fd27 Mon Sep 17 00:00:00 2001 From: Jonathan Turner Date: Thu, 14 Jul 2016 09:02:48 -0400 Subject: [PATCH 13/19] Add back in import needed for codemap tests --- src/libsyntax/codemap.rs | 1 + 1 file changed, 1 insertion(+) diff --git a/src/libsyntax/codemap.rs b/src/libsyntax/codemap.rs index afa5a3b38ba27..1e5f88dac49bc 100644 --- a/src/libsyntax/codemap.rs +++ b/src/libsyntax/codemap.rs @@ -828,6 +828,7 @@ impl CodeMapper for CodeMap { mod tests { use super::*; use std::io::{self, Write}; + use errors::snippet::StyledString; use std::rc::Rc; #[test] From c38d5df4a2a65ed11fefaf792b6535451c2fd767 Mon Sep 17 00:00:00 2001 From: Jonathan Turner Date: Thu, 14 Jul 2016 10:36:23 -0400 Subject: [PATCH 14/19] Remove unused imports --- src/libsyntax/codemap.rs | 19 ------------------- 1 file changed, 19 deletions(-) diff --git a/src/libsyntax/codemap.rs b/src/libsyntax/codemap.rs index 1e5f88dac49bc..42bb804cff2b9 100644 --- a/src/libsyntax/codemap.rs +++ b/src/libsyntax/codemap.rs @@ -827,7 +827,6 @@ impl CodeMapper for CodeMap { #[cfg(test)] mod tests { use super::*; - use std::io::{self, Write}; use errors::snippet::StyledString; use std::rc::Rc; @@ -1118,24 +1117,6 @@ mod tests { } } - fn splice(start: Span, end: Span) -> Span { - Span { - lo: start.lo, - hi: end.hi, - expn_id: NO_EXPANSION, - } - } - - fn make_string(lines: Vec>) -> String { - lines.iter() - .flat_map(|rl| { - rl.iter() - .map(|s| &s.text[..]) - .chain(Some("\n")) - }) - .collect() - } - fn init_expansion_chain(cm: &CodeMap) -> Span { // Creates an expansion chain containing two recursive calls // root -> expA -> expA -> expB -> expB -> end From 0b727f080108607188db8b56e47548a277cde0ff Mon Sep 17 00:00:00 2001 From: Jonathan Turner Date: Thu, 14 Jul 2016 10:55:09 -0400 Subject: [PATCH 15/19] Add unicode test to ui tests --- src/test/ui/codemap_tests/unicode.rs | 14 ++++++++++++++ src/test/ui/codemap_tests/unicode.stderr | 8 ++++++++ 2 files changed, 22 insertions(+) create mode 100644 src/test/ui/codemap_tests/unicode.rs create mode 100644 src/test/ui/codemap_tests/unicode.stderr diff --git a/src/test/ui/codemap_tests/unicode.rs b/src/test/ui/codemap_tests/unicode.rs new file mode 100644 index 0000000000000..19660133d6222 --- /dev/null +++ b/src/test/ui/codemap_tests/unicode.rs @@ -0,0 +1,14 @@ +// Copyright 2016 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +// rustc-env:RUST_NEW_ERROR_FORMAT +extern "路濫狼á́́" fn foo() {} + +fn main() { } diff --git a/src/test/ui/codemap_tests/unicode.stderr b/src/test/ui/codemap_tests/unicode.stderr new file mode 100644 index 0000000000000..178bee7b7f3ab --- /dev/null +++ b/src/test/ui/codemap_tests/unicode.stderr @@ -0,0 +1,8 @@ +error: invalid ABI: expected one of [cdecl, stdcall, fastcall, vectorcall, aapcs, win64, Rust, C, system, rust-intrinsic, rust-call, platform-intrinsic], found `路濫狼á́́` + --> $DIR/unicode.rs:12:8 + | +12 | extern "路濫狼á́́" fn foo() {} + | ^^^^^^^^ + +error: aborting due to previous error + From 01c87d77632ef9045f4c600a4b81711398372b9b Mon Sep 17 00:00:00 2001 From: Jonathan Turner Date: Thu, 14 Jul 2016 13:25:06 -0400 Subject: [PATCH 16/19] Remove more unused imports --- src/libsyntax/codemap.rs | 1 - 1 file changed, 1 deletion(-) diff --git a/src/libsyntax/codemap.rs b/src/libsyntax/codemap.rs index 42bb804cff2b9..a8aca90e6238d 100644 --- a/src/libsyntax/codemap.rs +++ b/src/libsyntax/codemap.rs @@ -827,7 +827,6 @@ impl CodeMapper for CodeMap { #[cfg(test)] mod tests { use super::*; - use errors::snippet::StyledString; use std::rc::Rc; #[test] From bf66a4840be3b7366b34454eb5573dca28ed8830 Mon Sep 17 00:00:00 2001 From: Jonathan Turner Date: Thu, 14 Jul 2016 15:43:53 -0400 Subject: [PATCH 17/19] Fix up more tests that I missed --- src/librustc_driver/test.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/librustc_driver/test.rs b/src/librustc_driver/test.rs index ace469680df27..a607d602a57ed 100644 --- a/src/librustc_driver/test.rs +++ b/src/librustc_driver/test.rs @@ -78,7 +78,7 @@ fn remove_message(e: &mut ExpectErrorEmitter, msg: &str, lvl: Level) { impl Emitter for ExpectErrorEmitter { fn emit(&mut self, db: &DiagnosticBuilder) { - remove_message(self, db.message, lvl); + remove_message(self, &db.message, db.level); for child in &db.children { remove_message(self, &child.message, child.level); } From dae8d073d4c5723099792f31769abcb3575bbda7 Mon Sep 17 00:00:00 2001 From: Jonathan Turner Date: Fri, 15 Jul 2016 06:52:19 -0400 Subject: [PATCH 18/19] Nudge travis by commenting a little --- src/librustc_errors/emitter.rs | 1 + 1 file changed, 1 insertion(+) diff --git a/src/librustc_errors/emitter.rs b/src/librustc_errors/emitter.rs index 6c47c01d0fb1e..893f8a6e4ddb0 100644 --- a/src/librustc_errors/emitter.rs +++ b/src/librustc_errors/emitter.rs @@ -33,6 +33,7 @@ pub trait Emitter { impl Emitter for EmitterWriter { fn emit(&mut self, db: &DiagnosticBuilder) { + // Pick old school mode either from env or let the test dictate the format let old_school = match self.format_mode { FormatMode::NewErrorFormat => false, FormatMode::OriginalErrorFormat => true, From c7158a143ae639081084755038c5ce1f8c398e93 Mon Sep 17 00:00:00 2001 From: Jonathan Turner Date: Fri, 15 Jul 2016 08:47:12 -0400 Subject: [PATCH 19/19] Remove unused import --- src/librustc_driver/test.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/librustc_driver/test.rs b/src/librustc_driver/test.rs index a607d602a57ed..39763bfa0eb61 100644 --- a/src/librustc_driver/test.rs +++ b/src/librustc_driver/test.rs @@ -34,7 +34,7 @@ use syntax::abi::Abi; use syntax::codemap::CodeMap; use errors; use errors::emitter::Emitter; -use errors::{Level, RenderSpan, DiagnosticBuilder}; +use errors::{Level, DiagnosticBuilder}; use syntax::parse::token; use syntax::feature_gate::UnstableFeatures; use syntax_pos::DUMMY_SP;