diff --git a/src/compiletest/runtest.rs b/src/compiletest/runtest.rs index 5de93c5202922..5579479c5e5ac 100644 --- a/src/compiletest/runtest.rs +++ b/src/compiletest/runtest.rs @@ -966,6 +966,16 @@ fn check_expected_errors(expected_errors: Vec , line.starts_with( prefix ) } + // A multi-line error will have followup lines which will always + // start with one of these strings. + fn continuation( line: &str) -> bool { + line.starts_with(" expected") || + line.starts_with(" found") || + // 1234 + // Should have 4 spaces: see issue 18946 + line.starts_with("(") + } + // Scan and extract our error/warning messages, // which look like: // filename:line1:col1: line2:col2: *error:* msg @@ -981,7 +991,7 @@ fn check_expected_errors(expected_errors: Vec , ee.kind, ee.msg, line); - if prefix_matches(line, prefixes[i].as_slice()) && + if (prefix_matches(line, prefixes[i].as_slice()) || continuation(line)) && line.contains(ee.kind.as_slice()) && line.contains(ee.msg.as_slice()) { found_flags[i] = true; diff --git a/src/librustc/lib.rs b/src/librustc/lib.rs index fb7c5296d020e..eb6c49f6ad001 100644 --- a/src/librustc/lib.rs +++ b/src/librustc/lib.rs @@ -35,6 +35,7 @@ extern crate flate; extern crate getopts; extern crate graphviz; extern crate libc; +extern crate regex; extern crate rustc_llvm; extern crate rustc_back; extern crate serialize; diff --git a/src/librustc/session/mod.rs b/src/librustc/session/mod.rs index 26d5a9daf89b0..27acc39c77863 100644 --- a/src/librustc/session/mod.rs +++ b/src/librustc/session/mod.rs @@ -15,6 +15,8 @@ use metadata::filesearch; use session::search_paths::PathKind; use util::nodemap::NodeMap; +use regex::Regex; + use syntax::ast::NodeId; use syntax::codemap::Span; use syntax::diagnostic::{self, Emitter}; @@ -71,7 +73,58 @@ impl Session { self.diagnostic().handler().fatal(msg) } pub fn span_err(&self, sp: Span, msg: &str) { - self.diagnostic().span_err(sp, msg) + // Conditions for enabling multi-line errors: + if !msg.contains("mismatched types") && + !msg.contains("type mismatch resolving") && + !msg.contains("if and else have incompatible types") && + !msg.contains("if may be missing an else clause") && + !msg.contains("match arms have incompatible types") && + !msg.contains("structure constructor specifies a structure of type") { + return self.diagnostic().span_err(sp, msg); + } + + let first = Regex::new(r"[( ]expected").unwrap(); + let second = Regex::new(r" found").unwrap(); + let third = Regex::new( + r"\((values differ|lifetime|cyclic type of infinite size)").unwrap(); + + let mut new_msg = String::new(); + let mut head = 0u; + + // Insert `\n` before expected and found. + for (pos1, pos2) in first.find_iter(msg).zip( + second.find_iter(msg)) { + new_msg = new_msg + + // A `(` may be preceded by a space and it should be trimmed + msg[head..pos1.0].trim_right() + // prefix + "\n" + // insert before first + &msg[pos1.0..pos1.1] + // insert what first matched + &msg[pos1.1..pos2.0] + // between matches + "\n " + // insert before second + // 123 + // `expected` is 3 char longer than `found`. To align the types, `found` gets + // 3 spaces prepended. + &msg[pos2.0..pos2.1]; // insert what second matched + + head = pos2.1; + } + + let mut tail = &msg[head..]; + // Insert `\n` before any remaining messages which match. + for pos in third.find_iter(tail).take(1) { + // The end of the message may just be wrapped in `()` without `expected`/`found`. + // Push this also to a new line and add the final tail after. + new_msg = new_msg + + // `(` is usually preceded by a space and should be trimmed. + tail[..pos.0].trim_right() + // prefix + "\n" + // insert before paren + &tail[pos.0..]; // append the tail + + tail = ""; + } + + new_msg.push_str(tail); + self.diagnostic().span_err(sp, &new_msg[]) } pub fn span_err_with_code(&self, sp: Span, msg: &str, code: &str) { self.diagnostic().span_err_with_code(sp, msg, code)