diff options
| author | bors <bors@rust-lang.org> | 2014-07-10 23:26:39 +0000 |
|---|---|---|
| committer | bors <bors@rust-lang.org> | 2014-07-10 23:26:39 +0000 |
| commit | 0e80dbe59ea986ea53cc3caabffd40b2eaee4dc6 (patch) | |
| tree | 3044cbdb7fe356d52a07c9048bc431aac3de5c4a /src/libsyntax/diagnostic.rs | |
| parent | a672456c40d28f051ecbdb2caf5bf6733371d494 (diff) | |
| parent | 9b9cce2316119a2ffdc9556d410e464b7542d64d (diff) | |
| download | rust-0e80dbe59ea986ea53cc3caabffd40b2eaee4dc6.tar.gz rust-0e80dbe59ea986ea53cc3caabffd40b2eaee4dc6.zip | |
auto merge of #15336 : jakub-/rust/diagnostics, r=brson
This is a continuation of @brson's work from https://github.com/rust-lang/rust/pull/12144.
This implements the minimal scaffolding that allows mapping diagnostic messages to alpha-numeric codes, which could improve the searchability of errors. In addition, there's a new compiler option, `--explain {code}` which takes an error code and prints out a somewhat detailed explanation of the error. Example:
```rust
fn f(x: Option<bool>) {
match x {
Some(true) | Some(false) => (),
None => (),
Some(true) => ()
}
}
```
```shell
[~/rust]$ ./build/x86_64-apple-darwin/stage2/bin/rustc ./diagnostics.rs --crate-type dylib
diagnostics.rs:5:3: 5:13 error: unreachable pattern [E0001] (pass `--explain E0001` to see a detailed explanation)
diagnostics.rs:5 Some(true) => ()
^~~~~~~~~~
error: aborting due to previous error
[~/rust]$ ./build/x86_64-apple-darwin/stage2/bin/rustc --explain E0001
This error suggests that the expression arm corresponding to the noted pattern
will never be reached as for all possible values of the expression being matched,
one of the preceeding patterns will match.
This means that perhaps some of the preceeding patterns are too general, this
one is too specific or the ordering is incorrect.
```
I've refrained from migrating many errors to actually use the new macros as it can be done in an incremental fashion but if we're happy with the approach, it'd be good to do all of them sooner rather than later.
Originally, I was going to make libdiagnostics a separate crate but that's posing some interesting challenges with semi-circular dependencies. In particular, librustc would have a plugin-phase dependency on libdiagnostics, which itself depends on librustc. Per my conversation with @alexcrichton, it seems like the snapshotting process would also have to change. So for now the relevant modules from libdiagnostics are included using `#[path = ...] mod`.
Diffstat (limited to 'src/libsyntax/diagnostic.rs')
| -rw-r--r-- | src/libsyntax/diagnostic.rs | 87 |
1 files changed, 60 insertions, 27 deletions
diff --git a/src/libsyntax/diagnostic.rs b/src/libsyntax/diagnostic.rs index e469f327ae8..9bb5eae2ed2 100644 --- a/src/libsyntax/diagnostic.rs +++ b/src/libsyntax/diagnostic.rs @@ -12,6 +12,7 @@ extern crate libc; use codemap::{Pos, Span}; use codemap; +use diagnostics; use std::cell::{RefCell, Cell}; use std::fmt; @@ -59,7 +60,7 @@ pub enum ColorConfig { pub trait Emitter { fn emit(&mut self, cmsp: Option<(&codemap::CodeMap, Span)>, - msg: &str, lvl: Level); + msg: &str, code: Option<&str>, lvl: Level); fn custom_emit(&mut self, cm: &codemap::CodeMap, sp: RenderSpan, msg: &str, lvl: Level); } @@ -90,6 +91,10 @@ impl SpanHandler { self.handler.emit(Some((&self.cm, sp)), msg, Error); self.handler.bump_err_count(); } + pub fn span_err_with_code(&self, sp: Span, msg: &str, code: &str) { + self.handler.emit_with_code(Some((&self.cm, sp)), msg, code, Error); + self.handler.bump_err_count(); + } pub fn span_warn(&self, sp: Span, msg: &str) { self.handler.emit(Some((&self.cm, sp)), msg, Warning); } @@ -124,11 +129,11 @@ pub struct Handler { impl Handler { pub fn fatal(&self, msg: &str) -> ! { - self.emit.borrow_mut().emit(None, msg, Fatal); + self.emit.borrow_mut().emit(None, msg, None, Fatal); fail!(FatalError); } pub fn err(&self, msg: &str) { - self.emit.borrow_mut().emit(None, msg, Error); + self.emit.borrow_mut().emit(None, msg, None, Error); self.bump_err_count(); } pub fn bump_err_count(&self) { @@ -153,13 +158,13 @@ impl Handler { self.fatal(s.as_slice()); } pub fn warn(&self, msg: &str) { - self.emit.borrow_mut().emit(None, msg, Warning); + self.emit.borrow_mut().emit(None, msg, None, Warning); } pub fn note(&self, msg: &str) { - self.emit.borrow_mut().emit(None, msg, Note); + self.emit.borrow_mut().emit(None, msg, None, Note); } pub fn bug(&self, msg: &str) -> ! { - self.emit.borrow_mut().emit(None, msg, Bug); + self.emit.borrow_mut().emit(None, msg, None, Bug); fail!(ExplicitBug); } pub fn unimpl(&self, msg: &str) -> ! { @@ -169,7 +174,14 @@ impl Handler { cmsp: Option<(&codemap::CodeMap, Span)>, msg: &str, lvl: Level) { - self.emit.borrow_mut().emit(cmsp, msg, lvl); + self.emit.borrow_mut().emit(cmsp, msg, None, lvl); + } + pub fn emit_with_code(&self, + cmsp: Option<(&codemap::CodeMap, Span)>, + msg: &str, + code: &str, + lvl: Level) { + self.emit.borrow_mut().emit(cmsp, msg, Some(code), lvl); } pub fn custom_emit(&self, cm: &codemap::CodeMap, sp: RenderSpan, msg: &str, lvl: Level) { @@ -184,8 +196,9 @@ pub fn mk_span_handler(handler: Handler, cm: codemap::CodeMap) -> SpanHandler { } } -pub fn default_handler(color_config: ColorConfig) -> Handler { - mk_handler(box EmitterWriter::stderr(color_config)) +pub fn default_handler(color_config: ColorConfig, + registry: Option<diagnostics::registry::Registry>) -> Handler { + mk_handler(box EmitterWriter::stderr(color_config, registry)) } pub fn mk_handler(e: Box<Emitter + Send>) -> Handler { @@ -262,8 +275,8 @@ fn print_maybe_styled(w: &mut EmitterWriter, } } -fn print_diagnostic(dst: &mut EmitterWriter, - topic: &str, lvl: Level, msg: &str) -> io::IoResult<()> { +fn print_diagnostic(dst: &mut EmitterWriter, topic: &str, lvl: Level, + msg: &str, code: Option<&str>) -> io::IoResult<()> { if !topic.is_empty() { try!(write!(&mut dst.dst, "{} ", topic)); } @@ -272,13 +285,32 @@ fn print_diagnostic(dst: &mut EmitterWriter, format!("{}: ", lvl.to_string()).as_slice(), term::attr::ForegroundColor(lvl.color()))); try!(print_maybe_styled(dst, - format!("{}\n", msg).as_slice(), + format!("{}", msg).as_slice(), term::attr::Bold)); + + match code { + Some(code) => { + let style = term::attr::ForegroundColor(term::color::BRIGHT_MAGENTA); + try!(print_maybe_styled(dst, format!(" [{}]", code.clone()).as_slice(), style)); + match dst.registry.as_ref().and_then(|registry| registry.find_description(code)) { + Some(_) => { + try!(write!(&mut dst.dst, + " (pass `--explain {}` to see a detailed explanation)", + code + )); + } + None => () + } + } + None => () + } + try!(dst.dst.write_char('\n')); Ok(()) } pub struct EmitterWriter { dst: Destination, + registry: Option<diagnostics::registry::Registry> } enum Destination { @@ -287,7 +319,8 @@ enum Destination { } impl EmitterWriter { - pub fn stderr(color_config: ColorConfig) -> EmitterWriter { + pub fn stderr(color_config: ColorConfig, + registry: Option<diagnostics::registry::Registry>) -> EmitterWriter { let stderr = io::stderr(); let use_color = match color_config { @@ -301,14 +334,15 @@ impl EmitterWriter { Some(t) => Terminal(t), None => Raw(box stderr), }; - EmitterWriter { dst: dst } + EmitterWriter { dst: dst, registry: registry } } else { - EmitterWriter { dst: Raw(box stderr) } + EmitterWriter { dst: Raw(box stderr), registry: registry } } } - pub fn new(dst: Box<Writer + Send>) -> EmitterWriter { - EmitterWriter { dst: Raw(dst) } + pub fn new(dst: Box<Writer + Send>, + registry: Option<diagnostics::registry::Registry>) -> EmitterWriter { + EmitterWriter { dst: Raw(dst), registry: registry } } } @@ -324,11 +358,10 @@ impl Writer for Destination { impl Emitter for EmitterWriter { fn emit(&mut self, cmsp: Option<(&codemap::CodeMap, Span)>, - msg: &str, - lvl: Level) { + msg: &str, code: Option<&str>, lvl: Level) { let error = match cmsp { - Some((cm, sp)) => emit(self, cm, FullSpan(sp), msg, lvl, false), - None => print_diagnostic(self, "", lvl, msg), + Some((cm, sp)) => emit(self, cm, FullSpan(sp), msg, code, lvl, false), + None => print_diagnostic(self, "", lvl, msg, code), }; match error { @@ -339,7 +372,7 @@ impl Emitter for EmitterWriter { fn custom_emit(&mut self, cm: &codemap::CodeMap, sp: RenderSpan, msg: &str, lvl: Level) { - match emit(self, cm, sp, msg, lvl, true) { + match emit(self, cm, sp, msg, None, lvl, true) { Ok(()) => {} Err(e) => fail!("failed to print diagnostics: {}", e), } @@ -347,7 +380,7 @@ impl Emitter for EmitterWriter { } fn emit(dst: &mut EmitterWriter, cm: &codemap::CodeMap, rsp: RenderSpan, - msg: &str, lvl: Level, custom: bool) -> io::IoResult<()> { + msg: &str, code: Option<&str>, lvl: Level, custom: bool) -> io::IoResult<()> { let sp = rsp.span(); let ss = cm.span_to_string(sp); let lines = cm.span_to_lines(sp); @@ -357,12 +390,12 @@ fn emit(dst: &mut EmitterWriter, cm: &codemap::CodeMap, rsp: RenderSpan, // the span) let span_end = Span { lo: sp.hi, hi: sp.hi, expn_info: sp.expn_info}; let ses = cm.span_to_string(span_end); - try!(print_diagnostic(dst, ses.as_slice(), lvl, msg)); + try!(print_diagnostic(dst, ses.as_slice(), lvl, msg, code)); if rsp.is_full_span() { try!(custom_highlight_lines(dst, cm, sp, lvl, lines)); } } else { - try!(print_diagnostic(dst, ss.as_slice(), lvl, msg)); + try!(print_diagnostic(dst, ss.as_slice(), lvl, msg, code)); if rsp.is_full_span() { try!(highlight_lines(dst, cm, sp, lvl, lines)); } @@ -501,9 +534,9 @@ fn print_macro_backtrace(w: &mut EmitterWriter, try!(print_diagnostic(w, ss.as_slice(), Note, format!("in expansion of {}{}{}", pre, ei.callee.name, - post).as_slice())); + post).as_slice(), None)); let ss = cm.span_to_string(ei.call_site); - try!(print_diagnostic(w, ss.as_slice(), Note, "expansion site")); + try!(print_diagnostic(w, ss.as_slice(), Note, "expansion site", None)); try!(print_macro_backtrace(w, cm, ei.call_site)); } Ok(()) |
