Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Refactor suggestions into a structured form internally #39973

Closed
wants to merge 10 commits into from
2 changes: 1 addition & 1 deletion src/libproc_macro/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -161,7 +161,7 @@ pub mod __internal {
}

fn parse_to_lex_err(mut err: DiagnosticBuilder) -> LexError {
err.cancel();
let _ = err.cancel();
LexError { _inner: () }
}

Expand Down
2 changes: 1 addition & 1 deletion src/librustc/traits/error_reporting.rs
Original file line number Diff line number Diff line change
Expand Up @@ -483,7 +483,7 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> {
self.tcx.sess.add_lint_diagnostic(EXTRA_REQUIREMENT_IN_IMPL,
node_id,
(*err).clone());
err.cancel();
let _ = err.cancel();
}

err
Expand Down
4 changes: 2 additions & 2 deletions src/librustc_driver/test.rs
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,7 @@ use syntax::abi::Abi;
use syntax::codemap::CodeMap;
use errors;
use errors::emitter::Emitter;
use errors::{Level, DiagnosticBuilder};
use errors::{Level, Diagnostic};
use syntax::feature_gate::UnstableFeatures;
use syntax::symbol::Symbol;
use syntax_pos::DUMMY_SP;
Expand Down Expand Up @@ -78,7 +78,7 @@ fn remove_message(e: &mut ExpectErrorEmitter, msg: &str, lvl: Level) {
}

impl Emitter for ExpectErrorEmitter {
fn emit(&mut self, db: &DiagnosticBuilder) {
fn emit(&mut self, db: Diagnostic) {
remove_message(self, &db.message(), db.level);
for child in &db.children {
remove_message(self, &child.message(), child.level);
Expand Down
110 changes: 66 additions & 44 deletions src/librustc_errors/diagnostic.rs
Original file line number Diff line number Diff line change
Expand Up @@ -10,9 +10,7 @@

use CodeSuggestion;
use Level;
use RenderSpan;
use RenderSpan::Suggestion;
use std::fmt;
use std::{fmt, iter};
use syntax_pos::{MultiSpan, Span};
use snippet::Style;

Expand All @@ -24,6 +22,19 @@ pub struct Diagnostic {
pub code: Option<String>,
pub span: MultiSpan,
pub children: Vec<SubDiagnostic>,
pub code_hints: Option<DiagnosticCodeHint>,
}

#[derive(Clone, Debug, PartialEq, RustcEncodable, RustcDecodable)]
pub enum DiagnosticCodeHint {
Suggestion {
msg: String,
sugg: CodeSuggestion,
},
Guesses {
msg: String,
guesses: Vec<CodeSuggestion>,
},
}

/// For example a note attached to an error.
Expand All @@ -32,7 +43,7 @@ pub struct SubDiagnostic {
pub level: Level,
pub message: Vec<(String, Style)>,
pub span: MultiSpan,
pub render_span: Option<RenderSpan>,
pub render_span: Option<MultiSpan>,
}

impl Diagnostic {
Expand All @@ -47,18 +58,10 @@ impl Diagnostic {
code: code,
span: MultiSpan::new(),
children: vec![],
code_hints: None,
}
}

/// Cancel the diagnostic (a structured diagnostic must either be emitted or
/// cancelled or it will panic when dropped).
/// BEWARE: if this DiagnosticBuilder is an error, then creating it will
/// bump the error count on the Handler and cancelling it won't undo that.
/// If you want to decrement the error count you should use `Handler::cancel`.
pub fn cancel(&mut self) {
self.level = Level::Cancelled;
}

pub fn cancelled(&self) -> bool {
self.level == Level::Cancelled
}
Expand Down Expand Up @@ -109,67 +112,90 @@ impl Diagnostic {
}

pub fn note(&mut self, msg: &str) -> &mut Self {
self.sub(Level::Note, msg, MultiSpan::new(), None);
self.sub(Level::Note, msg, MultiSpan::new());
self
}

pub fn highlighted_note(&mut self, msg: Vec<(String, Style)>) -> &mut Self {
self.sub_with_highlights(Level::Note, msg, MultiSpan::new(), None);
self.sub_with_highlights(Level::Note, msg, MultiSpan::new());
self
}

pub fn span_note<S: Into<MultiSpan>>(&mut self,
sp: S,
msg: &str)
-> &mut Self {
self.sub(Level::Note, msg, sp.into(), None);
self.sub(Level::Note, msg, sp.into());
self
}

pub fn warn(&mut self, msg: &str) -> &mut Self {
self.sub(Level::Warning, msg, MultiSpan::new(), None);
self.sub(Level::Warning, msg, MultiSpan::new());
self
}

pub fn span_warn<S: Into<MultiSpan>>(&mut self,
sp: S,
msg: &str)
-> &mut Self {
self.sub(Level::Warning, msg, sp.into(), None);
self.sub(Level::Warning, msg, sp.into());
self
}

pub fn help(&mut self , msg: &str) -> &mut Self {
self.sub(Level::Help, msg, MultiSpan::new(), None);
self.sub(Level::Help, msg, MultiSpan::new());
self
}

pub fn span_help<S: Into<MultiSpan>>(&mut self,
sp: S,
msg: &str)
-> &mut Self {
self.sub(Level::Help, msg, sp.into(), None);
self.sub(Level::Help, msg, sp.into());
self
}

/// Prints out a message with a suggested edit of the code.
///
/// See `diagnostic::RenderSpan::Suggestion` for more information.
pub fn span_suggestion<S: Into<MultiSpan>>(&mut self,
sp: S,
msg: &str,
suggestion: String)
-> &mut Self {
self.sub(Level::Help,
msg,
MultiSpan::new(),
Some(Suggestion(CodeSuggestion {
msp: sp.into(),
substitutes: vec![suggestion],
})));
pub fn span_suggestion(&mut self, sp: Span, msg: &str, suggestion: String) -> &mut Self {
assert!(self.code_hints.is_none(),
"use guesses to assign multiple suggestions to an error");
self.code_hints = Some(DiagnosticCodeHint::Suggestion {
sugg: CodeSuggestion {
msp: sp.into(),
substitutes: vec![suggestion],
},
msg: msg.to_owned(),
});
self
}

/// Prints out a message with one or multiple suggested edits of the
/// code, which may break the code, require manual intervention
/// or be plain out wrong, but might possibly be the correct solution.
///
/// See `diagnostic::RenderSpan::Guesses` for more information.
pub fn span_guesses<I>(&mut self, sp: Span, msg: &str, guesses: I) -> &mut Self
where I: IntoIterator<Item = String>
{
assert!(self.code_hints.is_none(),
"cannot attach multiple guesses to the same error");
let guesses = guesses.into_iter().map(|guess| CodeSuggestion {
msp: sp.into(),
substitutes: vec![guess],
}).collect();
self.code_hints = Some(DiagnosticCodeHint::Guesses {
guesses: guesses,
msg: msg.to_owned(),
});
self
}

pub fn span_guess(&mut self, sp: Span, msg: &str, guess: String) -> &mut Self {
self.span_guesses(sp, msg, iter::once(guess))
}

pub fn set_span<S: Into<MultiSpan>>(&mut self, sp: S) -> &mut Self {
self.span = sp.into();
self
Expand Down Expand Up @@ -205,29 +231,25 @@ impl Diagnostic {
fn sub(&mut self,
level: Level,
message: &str,
span: MultiSpan,
render_span: Option<RenderSpan>) {
let sub = SubDiagnostic {
level: level,
message: vec![(message.to_owned(), Style::NoStyle)],
span: span,
render_span: render_span,
};
self.children.push(sub);
span: MultiSpan) {
self.sub_with_highlights(
level,
vec![(message.to_owned(), Style::NoStyle)],
span,
);
}

/// Convenience function for internal use, clients should use one of the
/// public methods above.
fn sub_with_highlights(&mut self,
level: Level,
message: Vec<(String, Style)>,
span: MultiSpan,
render_span: Option<RenderSpan>) {
span: MultiSpan) {
let sub = SubDiagnostic {
level: level,
message: message,
span: span,
render_span: render_span,
render_span: None,
};
self.children.push(sub);
}
Expand Down
41 changes: 31 additions & 10 deletions src/librustc_errors/diagnostic_builder.rs
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ use std::fmt::{self, Debug};
use std::ops::{Deref, DerefMut};
use std::thread::panicking;
use syntax_pos::{MultiSpan, Span};
use std::mem;

/// Used for emitting structured error messages and other diagnostic information.
#[must_use]
Expand Down Expand Up @@ -95,8 +96,8 @@ impl<'a> DiagnosticBuilder<'a> {
}
}

self.handler.emitter.borrow_mut().emit(&self);
self.cancel();
let db = self.cancel();
self.handler.emitter.borrow_mut().emit(db);
self.handler.panic_if_treat_err_as_bug();

// if self.is_fatal() {
Expand Down Expand Up @@ -139,20 +140,28 @@ impl<'a> DiagnosticBuilder<'a> {
sp: S,
msg: &str)
-> &mut Self);
forward!(pub fn span_suggestion<S: Into<MultiSpan>>(&mut self,
sp: S,
msg: &str,
suggestion: String)
-> &mut Self);
forward!(pub fn span_suggestion(&mut self,
sp: Span,
msg: &str,
suggestion: String)
-> &mut Self);
forward!(pub fn set_span<S: Into<MultiSpan>>(&mut self, sp: S) -> &mut Self);
forward!(pub fn code(&mut self, s: String) -> &mut Self);
forward!(pub fn span_guess(&mut self, sp: Span, msg: &str, guess: String) -> &mut Self);

/// Convenience function for internal use, clients should use one of the
/// struct_* methods on Handler.
pub fn new(handler: &'a Handler, level: Level, message: &str) -> DiagnosticBuilder<'a> {
DiagnosticBuilder::new_with_code(handler, level, None, message)
}

pub fn span_guesses<I>(&mut self, sp: Span, msg: &str, guesses: I) -> &mut Self
where I: IntoIterator<Item = String>
{
self.diagnostic.span_guesses(sp, msg, guesses);
self
}

/// Convenience function for internal use, clients should use one of the
/// struct_* methods on Handler.
pub fn new_with_code(handler: &'a Handler,
Expand All @@ -166,10 +175,22 @@ impl<'a> DiagnosticBuilder<'a> {
}
}

pub fn into_diagnostic(mut self) -> Diagnostic {
/// Cancel the diagnostic (a structured diagnostic must either be emitted or
/// cancelled or it will panic when dropped).
/// BEWARE: if this DiagnosticBuilder is an error, then creating it will
/// bump the error count on the Handler and cancelling it won't undo that.
/// If you want to decrement the error count you should use `Handler::cancel`.
/// The function yields the inner Diagnostic by value
pub fn cancel(&mut self) -> Diagnostic {
// annoyingly, the Drop impl means we can't actually move
let result = self.diagnostic.clone();
self.cancel();
let result = mem::replace(&mut self.diagnostic, Diagnostic {
level: Level::Cancelled,
message: vec![],
code: None,
span: MultiSpan::new(),
children: vec![],
code_hints: None,
});
result
}
}
Expand Down
Loading