errors: implement fallback diagnostic translation
This commit updates the signatures of all diagnostic functions to accept types that can be converted into a `DiagnosticMessage`. This enables existing diagnostic calls to continue to work as before and Fluent identifiers to be provided. The `SessionDiagnostic` derive just generates normal diagnostic calls, so these APIs had to be modified to accept Fluent identifiers. In addition, loading of the "fallback" Fluent bundle, which contains the built-in English messages, has been implemented. Each diagnostic now has "arguments" which correspond to variables in the Fluent messages (necessary to render a Fluent message) but no API for adding arguments has been added yet. Therefore, diagnostics (that do not require interpolation) can be converted to use Fluent identifiers and will be output as before.
This commit is contained in:
@@ -31,7 +31,9 @@ use rustc_data_structures::fx::{FxHashMap, FxHashSet, FxIndexMap};
|
||||
use rustc_data_structures::stable_hasher::StableHasher;
|
||||
use rustc_data_structures::sync::{self, Lock, Lrc};
|
||||
use rustc_data_structures::AtomicRef;
|
||||
pub use rustc_error_messages::{DiagnosticMessage, MultiSpan, SpanLabel};
|
||||
pub use rustc_error_messages::{
|
||||
fallback_fluent_bundle, DiagnosticMessage, FluentBundle, MultiSpan, SpanLabel,
|
||||
};
|
||||
pub use rustc_lint_defs::{pluralize, Applicability};
|
||||
use rustc_serialize::json::Json;
|
||||
use rustc_serialize::{Decodable, Decoder, Encodable, Encoder};
|
||||
@@ -402,7 +404,9 @@ impl fmt::Display for ExplicitBug {
|
||||
|
||||
impl error::Error for ExplicitBug {}
|
||||
|
||||
pub use diagnostic::{Diagnostic, DiagnosticId, DiagnosticStyledString, SubDiagnostic};
|
||||
pub use diagnostic::{
|
||||
Diagnostic, DiagnosticArg, DiagnosticId, DiagnosticStyledString, SubDiagnostic,
|
||||
};
|
||||
pub use diagnostic_builder::{DiagnosticBuilder, EmissionGuarantee};
|
||||
use std::backtrace::Backtrace;
|
||||
|
||||
@@ -540,10 +544,12 @@ impl Handler {
|
||||
can_emit_warnings: bool,
|
||||
treat_err_as_bug: Option<NonZeroUsize>,
|
||||
sm: Option<Lrc<SourceMap>>,
|
||||
fallback_bundle: Lrc<FluentBundle>,
|
||||
) -> Self {
|
||||
Self::with_tty_emitter_and_flags(
|
||||
color_config,
|
||||
sm,
|
||||
fallback_bundle,
|
||||
HandlerFlags { can_emit_warnings, treat_err_as_bug, ..Default::default() },
|
||||
)
|
||||
}
|
||||
@@ -551,11 +557,13 @@ impl Handler {
|
||||
pub fn with_tty_emitter_and_flags(
|
||||
color_config: ColorConfig,
|
||||
sm: Option<Lrc<SourceMap>>,
|
||||
fallback_bundle: Lrc<FluentBundle>,
|
||||
flags: HandlerFlags,
|
||||
) -> Self {
|
||||
let emitter = Box::new(EmitterWriter::stderr(
|
||||
color_config,
|
||||
sm,
|
||||
fallback_bundle,
|
||||
false,
|
||||
false,
|
||||
None,
|
||||
@@ -660,7 +668,7 @@ impl Handler {
|
||||
pub fn struct_span_warn(
|
||||
&self,
|
||||
span: impl Into<MultiSpan>,
|
||||
msg: &str,
|
||||
msg: impl Into<DiagnosticMessage>,
|
||||
) -> DiagnosticBuilder<'_, ()> {
|
||||
let mut result = self.struct_warn(msg);
|
||||
result.set_span(span);
|
||||
@@ -671,7 +679,7 @@ impl Handler {
|
||||
pub fn struct_span_allow(
|
||||
&self,
|
||||
span: impl Into<MultiSpan>,
|
||||
msg: &str,
|
||||
msg: impl Into<DiagnosticMessage>,
|
||||
) -> DiagnosticBuilder<'_, ()> {
|
||||
let mut result = self.struct_allow(msg);
|
||||
result.set_span(span);
|
||||
@@ -683,7 +691,7 @@ impl Handler {
|
||||
pub fn struct_span_warn_with_code(
|
||||
&self,
|
||||
span: impl Into<MultiSpan>,
|
||||
msg: &str,
|
||||
msg: impl Into<DiagnosticMessage>,
|
||||
code: DiagnosticId,
|
||||
) -> DiagnosticBuilder<'_, ()> {
|
||||
let mut result = self.struct_span_warn(span, msg);
|
||||
@@ -696,17 +704,21 @@ impl Handler {
|
||||
/// Attempting to `.emit()` the builder will only emit if either:
|
||||
/// * `can_emit_warnings` is `true`
|
||||
/// * `is_force_warn` was set in `DiagnosticId::Lint`
|
||||
pub fn struct_warn(&self, msg: &str) -> DiagnosticBuilder<'_, ()> {
|
||||
pub fn struct_warn(&self, msg: impl Into<DiagnosticMessage>) -> DiagnosticBuilder<'_, ()> {
|
||||
DiagnosticBuilder::new(self, Level::Warning, msg)
|
||||
}
|
||||
|
||||
/// Construct a builder at the `Allow` level with the `msg`.
|
||||
pub fn struct_allow(&self, msg: &str) -> DiagnosticBuilder<'_, ()> {
|
||||
pub fn struct_allow(&self, msg: impl Into<DiagnosticMessage>) -> DiagnosticBuilder<'_, ()> {
|
||||
DiagnosticBuilder::new(self, Level::Allow, msg)
|
||||
}
|
||||
|
||||
/// Construct a builder at the `Expect` level with the `msg`.
|
||||
pub fn struct_expect(&self, msg: &str, id: LintExpectationId) -> DiagnosticBuilder<'_, ()> {
|
||||
pub fn struct_expect(
|
||||
&self,
|
||||
msg: impl Into<DiagnosticMessage>,
|
||||
id: LintExpectationId,
|
||||
) -> DiagnosticBuilder<'_, ()> {
|
||||
DiagnosticBuilder::new(self, Level::Expect(id), msg)
|
||||
}
|
||||
|
||||
@@ -714,7 +726,7 @@ impl Handler {
|
||||
pub fn struct_span_err(
|
||||
&self,
|
||||
span: impl Into<MultiSpan>,
|
||||
msg: &str,
|
||||
msg: impl Into<DiagnosticMessage>,
|
||||
) -> DiagnosticBuilder<'_, ErrorGuaranteed> {
|
||||
let mut result = self.struct_err(msg);
|
||||
result.set_span(span);
|
||||
@@ -725,7 +737,7 @@ impl Handler {
|
||||
pub fn struct_span_err_with_code(
|
||||
&self,
|
||||
span: impl Into<MultiSpan>,
|
||||
msg: &str,
|
||||
msg: impl Into<DiagnosticMessage>,
|
||||
code: DiagnosticId,
|
||||
) -> DiagnosticBuilder<'_, ErrorGuaranteed> {
|
||||
let mut result = self.struct_span_err(span, msg);
|
||||
@@ -735,20 +747,23 @@ impl Handler {
|
||||
|
||||
/// Construct a builder at the `Error` level with the `msg`.
|
||||
// FIXME: This method should be removed (every error should have an associated error code).
|
||||
pub fn struct_err(&self, msg: &str) -> DiagnosticBuilder<'_, ErrorGuaranteed> {
|
||||
DiagnosticBuilder::new_guaranteeing_error::<{ Level::Error { lint: false } }>(self, msg)
|
||||
pub fn struct_err(
|
||||
&self,
|
||||
msg: impl Into<DiagnosticMessage>,
|
||||
) -> DiagnosticBuilder<'_, ErrorGuaranteed> {
|
||||
DiagnosticBuilder::new_guaranteeing_error::<_, { Level::Error { lint: false } }>(self, msg)
|
||||
}
|
||||
|
||||
/// This should only be used by `rustc_middle::lint::struct_lint_level`. Do not use it for hard errors.
|
||||
#[doc(hidden)]
|
||||
pub fn struct_err_lint(&self, msg: &str) -> DiagnosticBuilder<'_, ()> {
|
||||
pub fn struct_err_lint(&self, msg: impl Into<DiagnosticMessage>) -> DiagnosticBuilder<'_, ()> {
|
||||
DiagnosticBuilder::new(self, Level::Error { lint: true }, msg)
|
||||
}
|
||||
|
||||
/// Construct a builder at the `Error` level with the `msg` and the `code`.
|
||||
pub fn struct_err_with_code(
|
||||
&self,
|
||||
msg: &str,
|
||||
msg: impl Into<DiagnosticMessage>,
|
||||
code: DiagnosticId,
|
||||
) -> DiagnosticBuilder<'_, ErrorGuaranteed> {
|
||||
let mut result = self.struct_err(msg);
|
||||
@@ -760,7 +775,7 @@ impl Handler {
|
||||
pub fn struct_span_fatal(
|
||||
&self,
|
||||
span: impl Into<MultiSpan>,
|
||||
msg: &str,
|
||||
msg: impl Into<DiagnosticMessage>,
|
||||
) -> DiagnosticBuilder<'_, !> {
|
||||
let mut result = self.struct_fatal(msg);
|
||||
result.set_span(span);
|
||||
@@ -771,7 +786,7 @@ impl Handler {
|
||||
pub fn struct_span_fatal_with_code(
|
||||
&self,
|
||||
span: impl Into<MultiSpan>,
|
||||
msg: &str,
|
||||
msg: impl Into<DiagnosticMessage>,
|
||||
code: DiagnosticId,
|
||||
) -> DiagnosticBuilder<'_, !> {
|
||||
let mut result = self.struct_span_fatal(span, msg);
|
||||
@@ -780,21 +795,24 @@ impl Handler {
|
||||
}
|
||||
|
||||
/// Construct a builder at the `Error` level with the `msg`.
|
||||
pub fn struct_fatal(&self, msg: &str) -> DiagnosticBuilder<'_, !> {
|
||||
pub fn struct_fatal(&self, msg: impl Into<DiagnosticMessage>) -> DiagnosticBuilder<'_, !> {
|
||||
DiagnosticBuilder::new_fatal(self, msg)
|
||||
}
|
||||
|
||||
/// Construct a builder at the `Help` level with the `msg`.
|
||||
pub fn struct_help(&self, msg: &str) -> DiagnosticBuilder<'_, ()> {
|
||||
pub fn struct_help(&self, msg: impl Into<DiagnosticMessage>) -> DiagnosticBuilder<'_, ()> {
|
||||
DiagnosticBuilder::new(self, Level::Help, msg)
|
||||
}
|
||||
|
||||
/// Construct a builder at the `Note` level with the `msg`.
|
||||
pub fn struct_note_without_error(&self, msg: &str) -> DiagnosticBuilder<'_, ()> {
|
||||
pub fn struct_note_without_error(
|
||||
&self,
|
||||
msg: impl Into<DiagnosticMessage>,
|
||||
) -> DiagnosticBuilder<'_, ()> {
|
||||
DiagnosticBuilder::new(self, Level::Note, msg)
|
||||
}
|
||||
|
||||
pub fn span_fatal(&self, span: impl Into<MultiSpan>, msg: &str) -> ! {
|
||||
pub fn span_fatal(&self, span: impl Into<MultiSpan>, msg: impl Into<DiagnosticMessage>) -> ! {
|
||||
self.emit_diag_at_span(Diagnostic::new(Fatal, msg), span);
|
||||
FatalError.raise()
|
||||
}
|
||||
@@ -802,80 +820,106 @@ impl Handler {
|
||||
pub fn span_fatal_with_code(
|
||||
&self,
|
||||
span: impl Into<MultiSpan>,
|
||||
msg: &str,
|
||||
msg: impl Into<DiagnosticMessage>,
|
||||
code: DiagnosticId,
|
||||
) -> ! {
|
||||
self.emit_diag_at_span(Diagnostic::new_with_code(Fatal, Some(code), msg), span);
|
||||
FatalError.raise()
|
||||
}
|
||||
|
||||
pub fn span_err(&self, span: impl Into<MultiSpan>, msg: &str) -> ErrorGuaranteed {
|
||||
pub fn span_err(
|
||||
&self,
|
||||
span: impl Into<MultiSpan>,
|
||||
msg: impl Into<DiagnosticMessage>,
|
||||
) -> ErrorGuaranteed {
|
||||
self.emit_diag_at_span(Diagnostic::new(Error { lint: false }, msg), span).unwrap()
|
||||
}
|
||||
|
||||
pub fn span_err_with_code(&self, span: impl Into<MultiSpan>, msg: &str, code: DiagnosticId) {
|
||||
pub fn span_err_with_code(
|
||||
&self,
|
||||
span: impl Into<MultiSpan>,
|
||||
msg: impl Into<DiagnosticMessage>,
|
||||
code: DiagnosticId,
|
||||
) {
|
||||
self.emit_diag_at_span(
|
||||
Diagnostic::new_with_code(Error { lint: false }, Some(code), msg),
|
||||
span,
|
||||
);
|
||||
}
|
||||
|
||||
pub fn span_warn(&self, span: impl Into<MultiSpan>, msg: &str) {
|
||||
pub fn span_warn(&self, span: impl Into<MultiSpan>, msg: impl Into<DiagnosticMessage>) {
|
||||
self.emit_diag_at_span(Diagnostic::new(Warning, msg), span);
|
||||
}
|
||||
|
||||
pub fn span_warn_with_code(&self, span: impl Into<MultiSpan>, msg: &str, code: DiagnosticId) {
|
||||
pub fn span_warn_with_code(
|
||||
&self,
|
||||
span: impl Into<MultiSpan>,
|
||||
msg: impl Into<DiagnosticMessage>,
|
||||
code: DiagnosticId,
|
||||
) {
|
||||
self.emit_diag_at_span(Diagnostic::new_with_code(Warning, Some(code), msg), span);
|
||||
}
|
||||
|
||||
pub fn span_bug(&self, span: impl Into<MultiSpan>, msg: &str) -> ! {
|
||||
pub fn span_bug(&self, span: impl Into<MultiSpan>, msg: impl Into<DiagnosticMessage>) -> ! {
|
||||
self.inner.borrow_mut().span_bug(span, msg)
|
||||
}
|
||||
|
||||
#[track_caller]
|
||||
pub fn delay_span_bug(&self, span: impl Into<MultiSpan>, msg: &str) -> ErrorGuaranteed {
|
||||
pub fn delay_span_bug(
|
||||
&self,
|
||||
span: impl Into<MultiSpan>,
|
||||
msg: impl Into<DiagnosticMessage>,
|
||||
) -> ErrorGuaranteed {
|
||||
self.inner.borrow_mut().delay_span_bug(span, msg)
|
||||
}
|
||||
|
||||
// FIXME(eddyb) note the comment inside `impl Drop for HandlerInner`, that's
|
||||
// where the explanation of what "good path" is (also, it should be renamed).
|
||||
pub fn delay_good_path_bug(&self, msg: &str) {
|
||||
pub fn delay_good_path_bug(&self, msg: impl Into<DiagnosticMessage>) {
|
||||
self.inner.borrow_mut().delay_good_path_bug(msg)
|
||||
}
|
||||
|
||||
pub fn span_bug_no_panic(&self, span: impl Into<MultiSpan>, msg: &str) {
|
||||
pub fn span_bug_no_panic(&self, span: impl Into<MultiSpan>, msg: impl Into<DiagnosticMessage>) {
|
||||
self.emit_diag_at_span(Diagnostic::new(Bug, msg), span);
|
||||
}
|
||||
|
||||
pub fn span_note_without_error(&self, span: impl Into<MultiSpan>, msg: &str) {
|
||||
pub fn span_note_without_error(
|
||||
&self,
|
||||
span: impl Into<MultiSpan>,
|
||||
msg: impl Into<DiagnosticMessage>,
|
||||
) {
|
||||
self.emit_diag_at_span(Diagnostic::new(Note, msg), span);
|
||||
}
|
||||
|
||||
pub fn span_note_diag(&self, span: Span, msg: &str) -> DiagnosticBuilder<'_, ()> {
|
||||
pub fn span_note_diag(
|
||||
&self,
|
||||
span: Span,
|
||||
msg: impl Into<DiagnosticMessage>,
|
||||
) -> DiagnosticBuilder<'_, ()> {
|
||||
let mut db = DiagnosticBuilder::new(self, Note, msg);
|
||||
db.set_span(span);
|
||||
db
|
||||
}
|
||||
|
||||
// NOTE: intentionally doesn't raise an error so rustc_codegen_ssa only reports fatal errors in the main thread
|
||||
pub fn fatal(&self, msg: &str) -> FatalError {
|
||||
pub fn fatal(&self, msg: impl Into<DiagnosticMessage>) -> FatalError {
|
||||
self.inner.borrow_mut().fatal(msg)
|
||||
}
|
||||
|
||||
pub fn err(&self, msg: &str) -> ErrorGuaranteed {
|
||||
pub fn err(&self, msg: impl Into<DiagnosticMessage>) -> ErrorGuaranteed {
|
||||
self.inner.borrow_mut().err(msg)
|
||||
}
|
||||
|
||||
pub fn warn(&self, msg: &str) {
|
||||
pub fn warn(&self, msg: impl Into<DiagnosticMessage>) {
|
||||
let mut db = DiagnosticBuilder::new(self, Warning, msg);
|
||||
db.emit();
|
||||
}
|
||||
|
||||
pub fn note_without_error(&self, msg: &str) {
|
||||
pub fn note_without_error(&self, msg: impl Into<DiagnosticMessage>) {
|
||||
DiagnosticBuilder::new(self, Note, msg).emit();
|
||||
}
|
||||
|
||||
pub fn bug(&self, msg: &str) -> ! {
|
||||
pub fn bug(&self, msg: impl Into<DiagnosticMessage>) -> ! {
|
||||
self.inner.borrow_mut().bug(msg)
|
||||
}
|
||||
|
||||
@@ -1145,7 +1189,10 @@ impl HandlerInner {
|
||||
|
||||
match (errors.len(), warnings.len()) {
|
||||
(0, 0) => return,
|
||||
(0, _) => self.emitter.emit_diagnostic(&Diagnostic::new(Level::Warning, &warnings)),
|
||||
(0, _) => self.emitter.emit_diagnostic(&Diagnostic::new(
|
||||
Level::Warning,
|
||||
DiagnosticMessage::Str(warnings.to_owned()),
|
||||
)),
|
||||
(_, 0) => {
|
||||
let _ = self.fatal(&errors);
|
||||
}
|
||||
@@ -1220,7 +1267,7 @@ impl HandlerInner {
|
||||
}
|
||||
}
|
||||
|
||||
fn span_bug(&mut self, sp: impl Into<MultiSpan>, msg: &str) -> ! {
|
||||
fn span_bug(&mut self, sp: impl Into<MultiSpan>, msg: impl Into<DiagnosticMessage>) -> ! {
|
||||
self.emit_diag_at_span(Diagnostic::new(Bug, msg), sp);
|
||||
panic::panic_any(ExplicitBug);
|
||||
}
|
||||
@@ -1230,7 +1277,11 @@ impl HandlerInner {
|
||||
}
|
||||
|
||||
#[track_caller]
|
||||
fn delay_span_bug(&mut self, sp: impl Into<MultiSpan>, msg: &str) -> ErrorGuaranteed {
|
||||
fn delay_span_bug(
|
||||
&mut self,
|
||||
sp: impl Into<MultiSpan>,
|
||||
msg: impl Into<DiagnosticMessage>,
|
||||
) -> ErrorGuaranteed {
|
||||
// This is technically `self.treat_err_as_bug()` but `delay_span_bug` is called before
|
||||
// incrementing `err_count` by one, so we need to +1 the comparing.
|
||||
// FIXME: Would be nice to increment err_count in a more coherent way.
|
||||
@@ -1246,7 +1297,7 @@ impl HandlerInner {
|
||||
|
||||
// FIXME(eddyb) note the comment inside `impl Drop for HandlerInner`, that's
|
||||
// where the explanation of what "good path" is (also, it should be renamed).
|
||||
fn delay_good_path_bug(&mut self, msg: &str) {
|
||||
fn delay_good_path_bug(&mut self, msg: impl Into<DiagnosticMessage>) {
|
||||
let mut diagnostic = Diagnostic::new(Level::DelayedBug, msg);
|
||||
if self.flags.report_delayed_bugs {
|
||||
self.emit_diagnostic(&mut diagnostic);
|
||||
@@ -1255,33 +1306,37 @@ impl HandlerInner {
|
||||
self.delayed_good_path_bugs.push(DelayedDiagnostic::with_backtrace(diagnostic, backtrace));
|
||||
}
|
||||
|
||||
fn failure(&mut self, msg: &str) {
|
||||
fn failure(&mut self, msg: impl Into<DiagnosticMessage>) {
|
||||
self.emit_diagnostic(&mut Diagnostic::new(FailureNote, msg));
|
||||
}
|
||||
|
||||
fn fatal(&mut self, msg: &str) -> FatalError {
|
||||
fn fatal(&mut self, msg: impl Into<DiagnosticMessage>) -> FatalError {
|
||||
self.emit(Fatal, msg);
|
||||
FatalError
|
||||
}
|
||||
|
||||
fn err(&mut self, msg: &str) -> ErrorGuaranteed {
|
||||
fn err(&mut self, msg: impl Into<DiagnosticMessage>) -> ErrorGuaranteed {
|
||||
self.emit(Error { lint: false }, msg)
|
||||
}
|
||||
|
||||
/// Emit an error; level should be `Error` or `Fatal`.
|
||||
fn emit(&mut self, level: Level, msg: &str) -> ErrorGuaranteed {
|
||||
fn emit(&mut self, level: Level, msg: impl Into<DiagnosticMessage>) -> ErrorGuaranteed {
|
||||
if self.treat_err_as_bug() {
|
||||
self.bug(msg);
|
||||
}
|
||||
self.emit_diagnostic(&mut Diagnostic::new(level, msg)).unwrap()
|
||||
}
|
||||
|
||||
fn bug(&mut self, msg: &str) -> ! {
|
||||
fn bug(&mut self, msg: impl Into<DiagnosticMessage>) -> ! {
|
||||
self.emit_diagnostic(&mut Diagnostic::new(Bug, msg));
|
||||
panic::panic_any(ExplicitBug);
|
||||
}
|
||||
|
||||
fn flush_delayed(&mut self, bugs: impl IntoIterator<Item = Diagnostic>, explanation: &str) {
|
||||
fn flush_delayed(
|
||||
&mut self,
|
||||
bugs: impl IntoIterator<Item = Diagnostic>,
|
||||
explanation: impl Into<DiagnosticMessage> + Copy,
|
||||
) {
|
||||
let mut no_bugs = true;
|
||||
for mut bug in bugs {
|
||||
if no_bugs {
|
||||
|
||||
Reference in New Issue
Block a user