diff options
Diffstat (limited to 'src/libsyntax/errors')
| -rw-r--r-- | src/libsyntax/errors/emitter.rs | 18 | ||||
| -rw-r--r-- | src/libsyntax/errors/mod.rs | 265 |
2 files changed, 253 insertions, 30 deletions
diff --git a/src/libsyntax/errors/emitter.rs b/src/libsyntax/errors/emitter.rs index 7fef85a833e..990e4bb421d 100644 --- a/src/libsyntax/errors/emitter.rs +++ b/src/libsyntax/errors/emitter.rs @@ -13,7 +13,7 @@ use self::Destination::*; use codemap::{self, COMMAND_LINE_SP, COMMAND_LINE_EXPN, Pos, Span}; use diagnostics; -use errors::{Level, RenderSpan}; +use errors::{Level, RenderSpan, DiagnosticBuilder}; use errors::RenderSpan::*; use errors::Level::*; @@ -27,6 +27,17 @@ use term; pub trait Emitter { fn emit(&mut self, span: Option<Span>, msg: &str, code: Option<&str>, lvl: Level); fn custom_emit(&mut self, sp: RenderSpan, msg: &str, lvl: Level); + + // Emit a structured diagnostic. + fn emit_struct(&mut self, db: &DiagnosticBuilder) { + self.emit(db.span, db.message, db.code.as_ref().map(|s| &**s), db.level); + for child in &db.children { + match child.render_span { + Some(ref sp) => self.custom_emit(sp.clone(), &child.message, child.level), + None => self.emit(child.span, &child.message, None, child.level), + } + } + } } /// maximum number of lines we will print for each error; arbitrary. @@ -111,9 +122,8 @@ impl Emitter for EmitterWriter { sp: RenderSpan, msg: &str, lvl: Level) { - match self.emit_(sp, msg, None, lvl) { - Ok(()) => {} - Err(e) => panic!("failed to print diagnostics: {:?}", e), + if let Err(e) = self.emit_(sp, msg, None, lvl) { + panic!("failed to print diagnostics: {:?}", e); } } } diff --git a/src/libsyntax/errors/mod.rs b/src/libsyntax/errors/mod.rs index f2e61090ba2..3b75bf9a8bd 100644 --- a/src/libsyntax/errors/mod.rs +++ b/src/libsyntax/errors/mod.rs @@ -98,6 +98,164 @@ impl error::Error for ExplicitBug { } } +// Used for emitting structured error messages and other diagnostic information. +#[must_use] +pub struct DiagnosticBuilder<'a> { + emitter: &'a RefCell<Box<Emitter>>, + level: Level, + message: String, + code: Option<String>, + span: Option<Span>, + children: Vec<SubDiagnostic>, + cancelled: bool, +} + +// For example a note attached to an error. +struct SubDiagnostic { + level: Level, + message: String, + span: Option<Span>, + render_span: Option<RenderSpan>, +} + +impl<'a> DiagnosticBuilder<'a> { + // Emit the diagnostic. + pub fn emit(&mut self) { + if self.cancelled { + return; + } + + self.cancel(); + self.emitter.borrow_mut().emit_struct(&self); + + // if self.is_fatal() { + // panic!(FatalError); + // } + } + + // Cancel the diagnostic (a structured diagnostic must either be emitted or + // cancelled or it will panic when dropped). + pub fn cancel(&mut self) { + self.cancelled = true; + } + + pub fn is_fatal(&self) -> bool { + self.level == Level::Fatal + } + + pub fn note(&mut self , msg: &str) -> &mut DiagnosticBuilder<'a> { + self.sub(Level::Note, msg, None, None); + self + } + pub fn span_note(&mut self , + sp: Span, + msg: &str) + -> &mut DiagnosticBuilder<'a> { + self.sub(Level::Note, msg, Some(sp), None); + self + } + pub fn note_rfc_1214(&mut self , span: Span) -> &mut DiagnosticBuilder<'a> { + self.span_note(span, + "this warning results from recent bug fixes and clarifications; \ + it will become a HARD ERROR in the next release. \ + See RFC 1214 for details.") + } + pub fn help(&mut self , msg: &str) -> &mut DiagnosticBuilder<'a> { + self.sub(Level::Help, msg, None, None); + self + } + pub fn span_help(&mut self , + sp: Span, + msg: &str) + -> &mut DiagnosticBuilder<'a> { + self.sub(Level::Help, msg, Some(sp), None); + self + } + /// Prints out a message with a suggested edit of the code. + /// + /// See `diagnostic::RenderSpan::Suggestion` for more information. + pub fn span_suggestion(&mut self , + sp: Span, + msg: &str, + suggestion: String) + -> &mut DiagnosticBuilder<'a> { + self.sub(Level::Help, msg, Some(sp), Some(Suggestion(sp, suggestion))); + self + } + pub fn span_end_note(&mut self , + sp: Span, + msg: &str) + -> &mut DiagnosticBuilder<'a> { + self.sub(Level::Note, msg, Some(sp), Some(EndSpan(sp))); + self + } + pub fn fileline_note(&mut self , + sp: Span, + msg: &str) + -> &mut DiagnosticBuilder<'a> { + self.sub(Level::Note, msg, Some(sp), Some(FileLine(sp))); + self + } + pub fn fileline_help(&mut self , + sp: Span, + msg: &str) + -> &mut DiagnosticBuilder<'a> { + self.sub(Level::Help, msg, Some(sp), Some(FileLine(sp))); + self + } + + // Convenience function for internal use, clients should use one of the + // struct_* methods on Handler. + fn new(emitter: &'a RefCell<Box<Emitter>>, + level: Level, + message: &str, + code: Option<String>, + span: Option<Span>) -> DiagnosticBuilder<'a> { + DiagnosticBuilder { + emitter: emitter, + level: level, + message: message.to_owned(), + code: code, + span: span, + children: vec![], + cancelled: false, + } + } + + // Convenience function for internal use, clients should use one of the + // public methods above. + fn sub(&mut self, + level: Level, + message: &str, + span: Option<Span>, + render_span: Option<RenderSpan>) { + let sub = SubDiagnostic { + level: level, + message: message.to_owned(), + span: span, + render_span: render_span, + }; + self.children.push(sub); + } +} + +impl<'a> fmt::Debug for DiagnosticBuilder<'a> { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + self.message.fmt(f) + } +} + +// Destructor bomb - a DiagnosticBuilder must be either emitted or cancelled or +// we emit a bug. +impl<'a> Drop for DiagnosticBuilder<'a> { + fn drop(&mut self) { + if !self.cancelled { + self.emitter.borrow_mut().emit(None, "Error constructed but not emitted", None, Bug); + panic!(); + } + } +} + /// A handler deals with errors; certain errors /// (fatal, bug, unimpl) may cause immediate exit, /// others log errors for later reporting. @@ -132,11 +290,85 @@ impl Handler { } } + pub fn struct_span_warn<'a>(&'a self, + sp: Span, + msg: &str) + -> DiagnosticBuilder<'a> { + let mut result = DiagnosticBuilder::new(&self.emit, Level::Warning, msg, None, Some(sp)); + if !self.can_emit_warnings { + result.cancel(); + } + result + } + pub fn struct_span_warn_with_code<'a>(&'a self, + sp: Span, + msg: &str, + code: &str) + -> DiagnosticBuilder<'a> { + let mut result = DiagnosticBuilder::new(&self.emit, + Level::Warning, + msg, + Some(code.to_owned()), + Some(sp)); + if !self.can_emit_warnings { + result.cancel(); + } + result + } + pub fn struct_warn<'a>(&'a self, msg: &str) -> DiagnosticBuilder<'a> { + let mut result = DiagnosticBuilder::new(&self.emit, Level::Warning, msg, None, None); + if !self.can_emit_warnings { + result.cancel(); + } + result + } + pub fn struct_span_err<'a>(&'a self, + sp: Span, + msg: &str) + -> DiagnosticBuilder<'a> { + self.bump_err_count(); + DiagnosticBuilder::new(&self.emit, Level::Error, msg, None, Some(sp)) + } + pub fn struct_span_err_with_code<'a>(&'a self, + sp: Span, + msg: &str, + code: &str) + -> DiagnosticBuilder<'a> { + // FIXME (and below) this is potentially inaccurate, since the DiagnosticBuilder + // might be cancelled. + self.bump_err_count(); + DiagnosticBuilder::new(&self.emit, Level::Error, msg, Some(code.to_owned()), Some(sp)) + } + pub fn struct_err<'a>(&'a self, msg: &str) -> DiagnosticBuilder<'a> { + self.bump_err_count(); + DiagnosticBuilder::new(&self.emit, Level::Error, msg, None, None) + } + pub fn struct_span_fatal<'a>(&'a self, + sp: Span, + msg: &str) + -> DiagnosticBuilder<'a> { + self.bump_err_count(); + DiagnosticBuilder::new(&self.emit, Level::Fatal, msg, None, Some(sp)) + } + pub fn struct_span_fatal_with_code<'a>(&'a self, + sp: Span, + msg: &str, + code: &str) + -> DiagnosticBuilder<'a> { + self.bump_err_count(); + DiagnosticBuilder::new(&self.emit, Level::Fatal, msg, Some(code.to_owned()), Some(sp)) + } + pub fn struct_fatal<'a>(&'a self, msg: &str) -> DiagnosticBuilder<'a> { + self.bump_err_count(); + DiagnosticBuilder::new(&self.emit, Level::Fatal, msg, None, None) + } + pub fn span_fatal(&self, sp: Span, msg: &str) -> FatalError { if self.treat_err_as_bug { self.span_bug(sp, msg); } self.emit(Some(sp), msg, Fatal); + self.bump_err_count(); return FatalError; } pub fn span_fatal_with_code(&self, sp: Span, msg: &str, code: &str) -> FatalError { @@ -144,6 +376,7 @@ impl Handler { self.span_bug(sp, msg); } self.emit_with_code(Some(sp), msg, code, Fatal); + self.bump_err_count(); return FatalError; } pub fn span_err(&self, sp: Span, msg: &str) { @@ -166,27 +399,6 @@ impl Handler { pub fn span_warn_with_code(&self, sp: Span, msg: &str, code: &str) { self.emit_with_code(Some(sp), msg, code, Warning); } - pub fn span_note(&self, sp: Span, msg: &str) { - self.emit(Some(sp), msg, Note); - } - pub fn span_end_note(&self, sp: Span, msg: &str) { - self.custom_emit(EndSpan(sp), msg, Note); - } - pub fn span_help(&self, sp: Span, msg: &str) { - self.emit(Some(sp), msg, Help); - } - /// Prints out a message with a suggested edit of the code. - /// - /// See `diagnostic::RenderSpan::Suggestion` for more information. - pub fn span_suggestion(&self, sp: Span, msg: &str, suggestion: String) { - self.custom_emit(Suggestion(sp, suggestion), msg, Help); - } - pub fn fileline_note(&self, sp: Span, msg: &str) { - self.custom_emit(FileLine(sp), msg, Note); - } - pub fn fileline_help(&self, sp: Span, msg: &str) { - self.custom_emit(FileLine(sp), msg, Help); - } pub fn span_bug(&self, sp: Span, msg: &str) -> ! { self.emit(Some(sp), msg, Bug); panic!(ExplicitBug); @@ -199,6 +411,9 @@ impl Handler { self.emit(Some(sp), msg, Bug); self.bump_err_count(); } + pub fn span_note_without_error(&self, sp: Span, msg: &str) { + self.emit.borrow_mut().emit(Some(sp), msg, None, Note); + } pub fn span_unimpl(&self, sp: Span, msg: &str) -> ! { self.span_bug(sp, &format!("unimplemented {}", msg)); } @@ -207,6 +422,7 @@ impl Handler { self.bug(msg); } self.emit.borrow_mut().emit(None, msg, None, Fatal); + self.bump_err_count(); FatalError } pub fn err(&self, msg: &str) { @@ -219,12 +435,9 @@ impl Handler { pub fn warn(&self, msg: &str) { self.emit.borrow_mut().emit(None, msg, None, Warning); } - pub fn note(&self, msg: &str) { + pub fn note_without_error(&self, msg: &str) { self.emit.borrow_mut().emit(None, msg, None, Note); } - pub fn help(&self, msg: &str) { - self.emit.borrow_mut().emit(None, msg, None, Help); - } pub fn bug(&self, msg: &str) -> ! { self.emit.borrow_mut().emit(None, msg, None, Bug); panic!(ExplicitBug); @@ -266,7 +479,7 @@ impl Handler { } } - panic!(self.fatal(&s[..])); + panic!(self.fatal(&s)); } pub fn emit(&self, |
