summaryrefslogtreecommitdiffstats
path: root/compiler/rustc_errors/src/diagnostic.rs
diff options
context:
space:
mode:
Diffstat (limited to 'compiler/rustc_errors/src/diagnostic.rs')
-rw-r--r--compiler/rustc_errors/src/diagnostic.rs82
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
}