diff options
Diffstat (limited to 'compiler/rustc_errors/src/diagnostic.rs')
-rw-r--r-- | compiler/rustc_errors/src/diagnostic.rs | 82 |
1 files changed, 74 insertions, 8 deletions
diff --git a/compiler/rustc_errors/src/diagnostic.rs b/compiler/rustc_errors/src/diagnostic.rs index 23f29a24f..06bb5edc0 100644 --- a/compiler/rustc_errors/src/diagnostic.rs +++ b/compiler/rustc_errors/src/diagnostic.rs @@ -4,6 +4,7 @@ use crate::{ SubdiagnosticMessage, Substitution, SubstitutionPart, SuggestionStyle, }; use rustc_data_structures::fx::FxHashMap; +use rustc_error_messages::fluent_value_from_str_list_sep_by_and; use rustc_error_messages::FluentValue; use rustc_lint_defs::{Applicability, LintExpectationId}; use rustc_span::edition::LATEST_STABLE_EDITION; @@ -12,6 +13,7 @@ use rustc_span::{Span, DUMMY_SP}; use std::borrow::Cow; use std::fmt; use std::hash::{Hash, Hasher}; +use std::panic::Location; /// Error type for `Diagnostic`'s `suggestions` field, indicating that /// `.disable_suggestions()` was called on the `Diagnostic`. @@ -33,6 +35,7 @@ pub type DiagnosticArgName<'source> = Cow<'source, str>; pub enum DiagnosticArgValue<'source> { Str(Cow<'source, str>), Number(usize), + StrListSepByAnd(Vec<Cow<'source, str>>), } /// Converts a value of a type into a `DiagnosticArg` (typically a field of an `IntoDiagnostic` @@ -43,19 +46,31 @@ pub trait IntoDiagnosticArg { fn into_diagnostic_arg(self) -> DiagnosticArgValue<'static>; } +impl<'source> IntoDiagnosticArg for DiagnosticArgValue<'source> { + fn into_diagnostic_arg(self) -> DiagnosticArgValue<'static> { + match self { + DiagnosticArgValue::Str(s) => DiagnosticArgValue::Str(Cow::Owned(s.into_owned())), + DiagnosticArgValue::Number(n) => DiagnosticArgValue::Number(n), + DiagnosticArgValue::StrListSepByAnd(l) => DiagnosticArgValue::StrListSepByAnd( + l.into_iter().map(|s| Cow::Owned(s.into_owned())).collect(), + ), + } + } +} + impl<'source> Into<FluentValue<'source>> for DiagnosticArgValue<'source> { fn into(self) -> FluentValue<'source> { match self { DiagnosticArgValue::Str(s) => From::from(s), DiagnosticArgValue::Number(n) => From::from(n), + DiagnosticArgValue::StrListSepByAnd(l) => fluent_value_from_str_list_sep_by_and(l), } } } /// Trait implemented by error types. This should not be implemented manually. Instead, use /// `#[derive(Subdiagnostic)]` -- see [rustc_macros::Subdiagnostic]. -#[cfg_attr(bootstrap, rustc_diagnostic_item = "AddSubdiagnostic")] -#[cfg_attr(not(bootstrap), rustc_diagnostic_item = "AddToDiagnostic")] +#[rustc_diagnostic_item = "AddToDiagnostic"] pub trait AddToDiagnostic where Self: Sized, @@ -107,6 +122,31 @@ pub struct Diagnostic { /// If diagnostic is from Lint, custom hash function ignores notes /// otherwise hash is based on the all the fields pub is_lint: bool, + + /// With `-Ztrack_diagnostics` enabled, + /// we print where in rustc this error was emitted. + pub emitted_at: DiagnosticLocation, +} + +#[derive(Clone, Debug, Encodable, Decodable)] +pub struct DiagnosticLocation { + file: Cow<'static, str>, + line: u32, + col: u32, +} + +impl DiagnosticLocation { + #[track_caller] + fn caller() -> Self { + let loc = Location::caller(); + DiagnosticLocation { file: loc.file().into(), line: loc.line(), col: loc.column() } + } +} + +impl fmt::Display for DiagnosticLocation { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + write!(f, "{}:{}:{}", self.file, self.line, self.col) + } } #[derive(Clone, Debug, PartialEq, Eq, Hash, Encodable, Decodable)] @@ -173,10 +213,28 @@ impl StringPart { } impl Diagnostic { + #[track_caller] pub fn new<M: Into<DiagnosticMessage>>(level: Level, message: M) -> Self { Diagnostic::new_with_code(level, None, message) } + #[track_caller] + pub fn new_with_messages(level: Level, messages: Vec<(DiagnosticMessage, Style)>) -> Self { + Diagnostic { + level, + message: messages, + code: None, + span: MultiSpan::new(), + children: vec![], + suggestions: Ok(vec![]), + args: Default::default(), + sort_span: DUMMY_SP, + is_lint: false, + emitted_at: DiagnosticLocation::caller(), + } + } + + #[track_caller] pub fn new_with_code<M: Into<DiagnosticMessage>>( level: Level, code: Option<DiagnosticId>, @@ -192,6 +250,7 @@ impl Diagnostic { args: Default::default(), sort_span: DUMMY_SP, is_lint: false, + emitted_at: DiagnosticLocation::caller(), } } @@ -233,7 +292,7 @@ impl Diagnostic { let lint_index = expectation_id.get_lint_index(); expectation_id.set_lint_index(None); let mut stable_id = unstable_to_stable - .get(&expectation_id) + .get(expectation_id) .expect("each unstable `LintExpectationId` must have a matching stable id") .normalize(); @@ -688,7 +747,7 @@ impl Diagnostic { &mut self, sp: Span, msg: impl Into<SubdiagnosticMessage>, - suggestions: impl Iterator<Item = String>, + suggestions: impl IntoIterator<Item = String>, applicability: Applicability, ) -> &mut Self { self.span_suggestions_with_style( @@ -705,11 +764,11 @@ impl Diagnostic { &mut self, sp: Span, msg: impl Into<SubdiagnosticMessage>, - suggestions: impl Iterator<Item = String>, + suggestions: impl IntoIterator<Item = String>, applicability: Applicability, style: SuggestionStyle, ) -> &mut Self { - let mut suggestions: Vec<_> = suggestions.collect(); + let mut suggestions: Vec<_> = suggestions.into_iter().collect(); suggestions.sort(); debug_assert!( @@ -736,10 +795,10 @@ impl Diagnostic { pub fn multipart_suggestions( &mut self, msg: impl Into<SubdiagnosticMessage>, - suggestions: impl Iterator<Item = Vec<(Span, String)>>, + suggestions: impl IntoIterator<Item = Vec<(Span, String)>>, applicability: Applicability, ) -> &mut Self { - let suggestions: Vec<_> = suggestions.collect(); + let suggestions: Vec<_> = suggestions.into_iter().collect(); debug_assert!( !(suggestions .iter() @@ -902,6 +961,13 @@ impl Diagnostic { self } + pub fn replace_args( + &mut self, + args: FxHashMap<DiagnosticArgName<'static>, DiagnosticArgValue<'static>>, + ) { + self.args = args; + } + pub fn styled_message(&self) -> &[(DiagnosticMessage, Style)] { &self.message } |