1use std::borrow::Cow;
2use std::fmt::{self, Debug};
3use std::hash::{Hash, Hasher};
4use std::marker::PhantomData;
5use std::ops::{Deref, DerefMut};
6use std::panic;
7use std::path::PathBuf;
8use std::thread::panicking;
910use rustc_ast::attr::version::RustcVersion;
11use rustc_data_structures::sync::{DynSend, DynSync};
12use rustc_error_messages::{DiagArgMap, DiagArgName, DiagArgValue, IntoDiagArg};
13use rustc_lint_defs::{Applicability, LintExpectationId};
14use rustc_macros::{Decodable, Encodable};
15use rustc_span::{DUMMY_SP, Span, Spanned, Symbol};
16use tracing::debug;
1718use crate::{
19CodeSuggestion, DiagCtxtHandle, DiagMessage, ErrCode, ErrorGuaranteed, ExplicitBug, Level,
20MultiSpan, StashKey, Style, Substitution, SubstitutionPart, SuggestionStyle, Suggestions,
21};
2223/// Trait for types that `Diag::emit` can return as a "guarantee" (or "proof")
24/// token that the emission happened.
25pub trait EmissionGuarantee: Sized {
26/// This exists so that bugs and fatal errors can both result in `!` (an
27 /// abort) when emitted, but have different aborting behaviour.
28type EmitResult = Self;
2930/// Implementation of `Diag::emit`, fully controlled by each `impl` of
31 /// `EmissionGuarantee`, to make it impossible to create a value of
32 /// `Self::EmitResult` without actually performing the emission.
33#[track_caller]
34fn emit_producing_guarantee(diag: Diag<'_, Self>) -> Self::EmitResult;
35}
3637impl EmissionGuaranteefor ErrorGuaranteed {
38fn emit_producing_guarantee(diag: Diag<'_, Self>) -> Self::EmitResult {
39diag.emit_producing_error_guaranteed()
40 }
41}
4243impl EmissionGuaranteefor () {
44fn emit_producing_guarantee(diag: Diag<'_, Self>) -> Self::EmitResult {
45diag.emit_producing_nothing();
46 }
47}
4849/// Marker type which enables implementation of `create_bug` and `emit_bug` functions for
50/// bug diagnostics.
51#[derive(#[automatically_derived]
impl ::core::marker::Copy for BugAbort { }Copy, #[automatically_derived]
impl ::core::clone::Clone for BugAbort {
#[inline]
fn clone(&self) -> BugAbort { *self }
}Clone)]
52pub struct BugAbort;
5354impl EmissionGuaranteefor BugAbort {
55type EmitResult = !;
5657fn emit_producing_guarantee(diag: Diag<'_, Self>) -> Self::EmitResult {
58diag.emit_producing_nothing();
59 panic::panic_any(ExplicitBug);
60 }
61}
6263/// Marker type which enables implementation of `create_fatal` and `emit_fatal` functions for
64/// fatal diagnostics.
65#[derive(#[automatically_derived]
impl ::core::marker::Copy for FatalAbort { }Copy, #[automatically_derived]
impl ::core::clone::Clone for FatalAbort {
#[inline]
fn clone(&self) -> FatalAbort { *self }
}Clone)]
66pub struct FatalAbort;
6768impl EmissionGuaranteefor FatalAbort {
69type EmitResult = !;
7071fn emit_producing_guarantee(diag: Diag<'_, Self>) -> Self::EmitResult {
72diag.emit_producing_nothing();
73crate::FatalError.raise()
74 }
75}
7677impl EmissionGuaranteefor rustc_span::fatal_error::FatalError {
78fn emit_producing_guarantee(diag: Diag<'_, Self>) -> Self::EmitResult {
79diag.emit_producing_nothing();
80 rustc_span::fatal_error::FatalError81 }
82}
8384/// Trait implemented by error types. This is rarely implemented manually. Instead, use
85/// `#[derive(Diagnostic)]` -- see [rustc_macros::Diagnostic].
86///
87/// When implemented manually, it should be generic over the emission
88/// guarantee, i.e.:
89/// ```ignore (fragment)
90/// impl<'a, G: EmissionGuarantee> Diagnostic<'a, G> for Foo { ... }
91/// ```
92/// rather than being specific:
93/// ```ignore (fragment)
94/// impl<'a> Diagnostic<'a> for Bar { ... } // the default type param is `ErrorGuaranteed`
95/// impl<'a> Diagnostic<'a, ()> for Baz { ... }
96/// ```
97/// There are two reasons for this.
98/// - A diagnostic like `Foo` *could* be emitted at any level -- `level` is
99/// passed in to `into_diag` from outside. Even if in practice it is
100/// always emitted at a single level, we let the diagnostic creation/emission
101/// site determine the level (by using `create_err`, `emit_warn`, etc.)
102/// rather than the `Diagnostic` impl.
103/// - Derived impls are always generic, and it's good for the hand-written
104/// impls to be consistent with them.
105#[rustc_diagnostic_item = "Diagnostic"]
106pub trait Diagnostic<'a, G: EmissionGuarantee = ErrorGuaranteed> {
107/// Write out as a diagnostic out of `DiagCtxt`.
108#[must_use]
109 #[track_caller]
110fn into_diag(self, dcx: DiagCtxtHandle<'a>, level: Level) -> Diag<'a, G>;
111}
112113impl<'a, T, G> Diagnostic<'a, G> for Spanned<T>
114where
115T: Diagnostic<'a, G>,
116 G: EmissionGuarantee,
117{
118fn into_diag(self, dcx: DiagCtxtHandle<'a>, level: Level) -> Diag<'a, G> {
119self.node.into_diag(dcx, level).with_span(self.span)
120 }
121}
122123impl<'a> Diagnostic<'a, ()>
124for Box<
125dyn for<'b> FnOnce(DiagCtxtHandle<'b>, Level) -> Diag<'b, ()> + DynSync + DynSend + 'static,
126 >
127{
128fn into_diag(self, dcx: DiagCtxtHandle<'a>, level: Level) -> Diag<'a, ()> {
129self(dcx, level)
130 }
131}
132133/// Type used to emit diagnostic through a closure instead of implementing the `Diagnostic` trait.
134pub struct DiagDecorator<F: FnOnce(&mut Diag<'_, ()>)>(pub F);
135136impl<'a, F: FnOnce(&mut Diag<'_, ()>)> Diagnostic<'a, ()> for DiagDecorator<F> {
137fn into_diag(self, dcx: DiagCtxtHandle<'a>, level: Level) -> Diag<'a, ()> {
138let mut diag = Diag::new(dcx, level, "");
139 (self.0)(&mut diag);
140diag141 }
142}
143144/// Trait implemented by error types. This should not be implemented manually. Instead, use
145/// `#[derive(Subdiagnostic)]` -- see [rustc_macros::Subdiagnostic].
146#[rustc_diagnostic_item = "Subdiagnostic"]
147pub trait Subdiagnostic {
148/// Add a subdiagnostic to an existing diagnostic.
149fn add_to_diag<G: EmissionGuarantee>(self, diag: &mut Diag<'_, G>);
150}
151152#[derive(#[automatically_derived]
impl ::core::clone::Clone for DiagLocation {
#[inline]
fn clone(&self) -> DiagLocation {
DiagLocation {
file: ::core::clone::Clone::clone(&self.file),
line: ::core::clone::Clone::clone(&self.line),
col: ::core::clone::Clone::clone(&self.col),
}
}
}Clone, #[automatically_derived]
impl ::core::fmt::Debug for DiagLocation {
#[inline]
fn fmt(&self, f: &mut ::core::fmt::Formatter) -> ::core::fmt::Result {
::core::fmt::Formatter::debug_struct_field3_finish(f, "DiagLocation",
"file", &self.file, "line", &self.line, "col", &&self.col)
}
}Debug, const _: () =
{
impl<__E: ::rustc_span::SpanEncoder> ::rustc_serialize::Encodable<__E>
for DiagLocation {
fn encode(&self, __encoder: &mut __E) {
match *self {
DiagLocation {
file: ref __binding_0,
line: ref __binding_1,
col: ref __binding_2 } => {
::rustc_serialize::Encodable::<__E>::encode(__binding_0,
__encoder);
::rustc_serialize::Encodable::<__E>::encode(__binding_1,
__encoder);
::rustc_serialize::Encodable::<__E>::encode(__binding_2,
__encoder);
}
}
}
}
};Encodable, const _: () =
{
impl<__D: ::rustc_span::SpanDecoder> ::rustc_serialize::Decodable<__D>
for DiagLocation {
fn decode(__decoder: &mut __D) -> Self {
DiagLocation {
file: ::rustc_serialize::Decodable::decode(__decoder),
line: ::rustc_serialize::Decodable::decode(__decoder),
col: ::rustc_serialize::Decodable::decode(__decoder),
}
}
}
};Decodable)]
153pub struct DiagLocation {
154 file: Cow<'static, str>,
155 line: u32,
156 col: u32,
157}
158159impl DiagLocation {
160#[track_caller]
161pub fn caller() -> Self {
162let loc = panic::Location::caller();
163DiagLocation { file: loc.file().into(), line: loc.line(), col: loc.column() }
164 }
165}
166167impl fmt::Displayfor DiagLocation {
168fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
169f.write_fmt(format_args!("{0}:{1}:{2}", self.file, self.line, self.col))write!(f, "{}:{}:{}", self.file, self.line, self.col)170 }
171}
172173#[derive(#[automatically_derived]
impl ::core::clone::Clone for IsLint {
#[inline]
fn clone(&self) -> IsLint {
IsLint {
name: ::core::clone::Clone::clone(&self.name),
has_future_breakage: ::core::clone::Clone::clone(&self.has_future_breakage),
rust_version: ::core::clone::Clone::clone(&self.rust_version),
}
}
}Clone, #[automatically_derived]
impl ::core::fmt::Debug for IsLint {
#[inline]
fn fmt(&self, f: &mut ::core::fmt::Formatter) -> ::core::fmt::Result {
::core::fmt::Formatter::debug_struct_field3_finish(f, "IsLint",
"name", &self.name, "has_future_breakage",
&self.has_future_breakage, "rust_version", &&self.rust_version)
}
}Debug, #[automatically_derived]
impl ::core::cmp::PartialEq for IsLint {
#[inline]
fn eq(&self, other: &IsLint) -> bool {
self.has_future_breakage == other.has_future_breakage &&
self.name == other.name &&
self.rust_version == other.rust_version
}
}PartialEq, #[automatically_derived]
impl ::core::cmp::Eq for IsLint {
#[inline]
#[doc(hidden)]
#[coverage(off)]
fn assert_fields_are_eq(&self) {
let _: ::core::cmp::AssertParamIsEq<String>;
let _: ::core::cmp::AssertParamIsEq<bool>;
let _: ::core::cmp::AssertParamIsEq<Option<RustcVersion>>;
}
}Eq, #[automatically_derived]
impl ::core::hash::Hash for IsLint {
#[inline]
fn hash<__H: ::core::hash::Hasher>(&self, state: &mut __H) {
::core::hash::Hash::hash(&self.name, state);
::core::hash::Hash::hash(&self.has_future_breakage, state);
::core::hash::Hash::hash(&self.rust_version, state)
}
}Hash, const _: () =
{
impl<__E: ::rustc_span::SpanEncoder> ::rustc_serialize::Encodable<__E>
for IsLint {
fn encode(&self, __encoder: &mut __E) {
match *self {
IsLint {
name: ref __binding_0,
has_future_breakage: ref __binding_1,
rust_version: ref __binding_2 } => {
::rustc_serialize::Encodable::<__E>::encode(__binding_0,
__encoder);
::rustc_serialize::Encodable::<__E>::encode(__binding_1,
__encoder);
::rustc_serialize::Encodable::<__E>::encode(__binding_2,
__encoder);
}
}
}
}
};Encodable, const _: () =
{
impl<__D: ::rustc_span::SpanDecoder> ::rustc_serialize::Decodable<__D>
for IsLint {
fn decode(__decoder: &mut __D) -> Self {
IsLint {
name: ::rustc_serialize::Decodable::decode(__decoder),
has_future_breakage: ::rustc_serialize::Decodable::decode(__decoder),
rust_version: ::rustc_serialize::Decodable::decode(__decoder),
}
}
}
};Decodable)]
174pub struct IsLint {
175/// The lint name.
176pub(crate) name: String,
177/// Indicates whether this lint should show up in cargo's future breakage report.
178has_future_breakage: bool,
179/// Indicates the minimum rust version this lint applies to
180rust_version: Option<RustcVersion>,
181}
182183#[derive(#[automatically_derived]
impl ::core::fmt::Debug for DiagStyledString {
#[inline]
fn fmt(&self, f: &mut ::core::fmt::Formatter) -> ::core::fmt::Result {
::core::fmt::Formatter::debug_tuple_field1_finish(f,
"DiagStyledString", &&self.0)
}
}Debug, #[automatically_derived]
impl ::core::cmp::PartialEq for DiagStyledString {
#[inline]
fn eq(&self, other: &DiagStyledString) -> bool { self.0 == other.0 }
}PartialEq, #[automatically_derived]
impl ::core::cmp::Eq for DiagStyledString {
#[inline]
#[doc(hidden)]
#[coverage(off)]
fn assert_fields_are_eq(&self) {
let _: ::core::cmp::AssertParamIsEq<Vec<StringPart>>;
}
}Eq)]
184pub struct DiagStyledString(pub Vec<StringPart>);
185186impl DiagStyledString {
187pub fn new() -> DiagStyledString {
188DiagStyledString(::alloc::vec::Vec::new()vec![])
189 }
190pub fn push_normal<S: Into<String>>(&mut self, t: S) {
191self.0.push(StringPart::normal(t));
192 }
193pub fn push_highlighted<S: Into<String>>(&mut self, t: S) {
194self.0.push(StringPart::highlighted(t));
195 }
196pub fn push<S: Into<String>>(&mut self, t: S, highlight: bool) {
197if highlight {
198self.push_highlighted(t);
199 } else {
200self.push_normal(t);
201 }
202 }
203pub fn normal<S: Into<String>>(t: S) -> DiagStyledString {
204DiagStyledString(::alloc::boxed::box_assume_init_into_vec_unsafe(::alloc::intrinsics::write_box_via_move(::alloc::boxed::Box::new_uninit(),
[StringPart::normal(t)]))vec![StringPart::normal(t)])
205 }
206207pub fn highlighted<S: Into<String>>(t: S) -> DiagStyledString {
208DiagStyledString(::alloc::boxed::box_assume_init_into_vec_unsafe(::alloc::intrinsics::write_box_via_move(::alloc::boxed::Box::new_uninit(),
[StringPart::highlighted(t)]))vec![StringPart::highlighted(t)])
209 }
210211pub fn content(&self) -> String {
212self.0.iter().map(|x| x.content.as_str()).collect::<String>()
213 }
214}
215216#[derive(#[automatically_derived]
impl ::core::fmt::Debug for StringPart {
#[inline]
fn fmt(&self, f: &mut ::core::fmt::Formatter) -> ::core::fmt::Result {
::core::fmt::Formatter::debug_struct_field2_finish(f, "StringPart",
"content", &self.content, "style", &&self.style)
}
}Debug, #[automatically_derived]
impl ::core::cmp::PartialEq for StringPart {
#[inline]
fn eq(&self, other: &StringPart) -> bool {
self.content == other.content && self.style == other.style
}
}PartialEq, #[automatically_derived]
impl ::core::cmp::Eq for StringPart {
#[inline]
#[doc(hidden)]
#[coverage(off)]
fn assert_fields_are_eq(&self) {
let _: ::core::cmp::AssertParamIsEq<String>;
let _: ::core::cmp::AssertParamIsEq<Style>;
}
}Eq)]
217pub struct StringPart {
218 content: String,
219 style: Style,
220}
221222impl StringPart {
223pub fn normal<S: Into<String>>(content: S) -> StringPart {
224StringPart { content: content.into(), style: Style::NoStyle }
225 }
226227pub fn highlighted<S: Into<String>>(content: S) -> StringPart {
228StringPart { content: content.into(), style: Style::Highlight }
229 }
230}
231232/// The main part of a diagnostic. Note that `Diag`, which wraps this type, is
233/// used for most operations, and should be used instead whenever possible.
234/// This type should only be used when `Diag`'s lifetime causes difficulties,
235/// e.g. when storing diagnostics within `DiagCtxt`.
236#[must_use]
237#[derive(#[automatically_derived]
impl ::core::clone::Clone for DiagInner {
#[inline]
fn clone(&self) -> DiagInner {
DiagInner {
level: ::core::clone::Clone::clone(&self.level),
messages: ::core::clone::Clone::clone(&self.messages),
code: ::core::clone::Clone::clone(&self.code),
lint_id: ::core::clone::Clone::clone(&self.lint_id),
span: ::core::clone::Clone::clone(&self.span),
children: ::core::clone::Clone::clone(&self.children),
suggestions: ::core::clone::Clone::clone(&self.suggestions),
args: ::core::clone::Clone::clone(&self.args),
sort_span: ::core::clone::Clone::clone(&self.sort_span),
is_lint: ::core::clone::Clone::clone(&self.is_lint),
long_ty_path: ::core::clone::Clone::clone(&self.long_ty_path),
emitted_at: ::core::clone::Clone::clone(&self.emitted_at),
}
}
}Clone, #[automatically_derived]
impl ::core::fmt::Debug for DiagInner {
#[inline]
fn fmt(&self, f: &mut ::core::fmt::Formatter) -> ::core::fmt::Result {
let names: &'static _ =
&["level", "messages", "code", "lint_id", "span", "children",
"suggestions", "args", "sort_span", "is_lint",
"long_ty_path", "emitted_at"];
let values: &[&dyn ::core::fmt::Debug] =
&[&self.level, &self.messages, &self.code, &self.lint_id,
&self.span, &self.children, &self.suggestions, &self.args,
&self.sort_span, &self.is_lint, &self.long_ty_path,
&&self.emitted_at];
::core::fmt::Formatter::debug_struct_fields_finish(f, "DiagInner",
names, values)
}
}Debug, const _: () =
{
impl<__E: ::rustc_span::SpanEncoder> ::rustc_serialize::Encodable<__E>
for DiagInner {
fn encode(&self, __encoder: &mut __E) {
match *self {
DiagInner {
level: ref __binding_0,
messages: ref __binding_1,
code: ref __binding_2,
lint_id: ref __binding_3,
span: ref __binding_4,
children: ref __binding_5,
suggestions: ref __binding_6,
args: ref __binding_7,
sort_span: ref __binding_8,
is_lint: ref __binding_9,
long_ty_path: ref __binding_10,
emitted_at: ref __binding_11 } => {
::rustc_serialize::Encodable::<__E>::encode(__binding_0,
__encoder);
::rustc_serialize::Encodable::<__E>::encode(__binding_1,
__encoder);
::rustc_serialize::Encodable::<__E>::encode(__binding_2,
__encoder);
::rustc_serialize::Encodable::<__E>::encode(__binding_3,
__encoder);
::rustc_serialize::Encodable::<__E>::encode(__binding_4,
__encoder);
::rustc_serialize::Encodable::<__E>::encode(__binding_5,
__encoder);
::rustc_serialize::Encodable::<__E>::encode(__binding_6,
__encoder);
::rustc_serialize::Encodable::<__E>::encode(__binding_7,
__encoder);
::rustc_serialize::Encodable::<__E>::encode(__binding_8,
__encoder);
::rustc_serialize::Encodable::<__E>::encode(__binding_9,
__encoder);
::rustc_serialize::Encodable::<__E>::encode(__binding_10,
__encoder);
::rustc_serialize::Encodable::<__E>::encode(__binding_11,
__encoder);
}
}
}
}
};Encodable, const _: () =
{
impl<__D: ::rustc_span::SpanDecoder> ::rustc_serialize::Decodable<__D>
for DiagInner {
fn decode(__decoder: &mut __D) -> Self {
DiagInner {
level: ::rustc_serialize::Decodable::decode(__decoder),
messages: ::rustc_serialize::Decodable::decode(__decoder),
code: ::rustc_serialize::Decodable::decode(__decoder),
lint_id: ::rustc_serialize::Decodable::decode(__decoder),
span: ::rustc_serialize::Decodable::decode(__decoder),
children: ::rustc_serialize::Decodable::decode(__decoder),
suggestions: ::rustc_serialize::Decodable::decode(__decoder),
args: ::rustc_serialize::Decodable::decode(__decoder),
sort_span: ::rustc_serialize::Decodable::decode(__decoder),
is_lint: ::rustc_serialize::Decodable::decode(__decoder),
long_ty_path: ::rustc_serialize::Decodable::decode(__decoder),
emitted_at: ::rustc_serialize::Decodable::decode(__decoder),
}
}
}
};Decodable)]
238pub struct DiagInner {
239// NOTE(eddyb) this is private to disallow arbitrary after-the-fact changes,
240 // outside of what methods in this crate themselves allow.
241pub(crate) level: Level,
242243pub messages: Vec<(DiagMessage, Style)>,
244pub code: Option<ErrCode>,
245pub lint_id: Option<LintExpectationId>,
246pub span: MultiSpan,
247pub children: Vec<Subdiag>,
248pub suggestions: Suggestions,
249pub args: DiagArgMap,
250251/// This is not used for highlighting or rendering any error message. Rather, it can be used
252 /// as a sort key to sort a buffer of diagnostics. By default, it is the primary span of
253 /// `span` if there is one. Otherwise, it is `DUMMY_SP`.
254pub sort_span: Span,
255256pub is_lint: Option<IsLint>,
257258pub long_ty_path: Option<PathBuf>,
259/// With `-Ztrack_diagnostics` enabled,
260 /// we print where in rustc this error was emitted.
261pub emitted_at: DiagLocation,
262}
263264impl DiagInner {
265#[track_caller]
266pub fn new<M: Into<DiagMessage>>(level: Level, message: M) -> Self {
267DiagInner::new_with_messages(level, ::alloc::boxed::box_assume_init_into_vec_unsafe(::alloc::intrinsics::write_box_via_move(::alloc::boxed::Box::new_uninit(),
[(message.into(), Style::NoStyle)]))vec![(message.into(), Style::NoStyle)])
268 }
269270#[track_caller]
271pub fn new_with_messages(level: Level, messages: Vec<(DiagMessage, Style)>) -> Self {
272DiagInner {
273level,
274 lint_id: None,
275messages,
276 code: None,
277 span: MultiSpan::new(),
278 children: ::alloc::vec::Vec::new()vec![],
279 suggestions: Suggestions::Enabled(::alloc::vec::Vec::new()vec![]),
280 args: Default::default(),
281 sort_span: DUMMY_SP,
282 is_lint: None,
283 long_ty_path: None,
284 emitted_at: DiagLocation::caller(),
285 }
286 }
287288#[inline(always)]
289pub fn level(&self) -> Level {
290self.level
291 }
292293pub fn is_error(&self) -> bool {
294match self.level {
295 Level::Bug | Level::Fatal | Level::Error | Level::DelayedBug => true,
296297 Level::ForceWarning298 | Level::Warning299 | Level::Note300 | Level::OnceNote301 | Level::Help302 | Level::OnceHelp303 | Level::FailureNote304 | Level::Allow305 | Level::Expect => false,
306 }
307 }
308309/// Indicates whether this diagnostic should show up in cargo's future breakage report.
310pub(crate) fn has_future_breakage(&self) -> bool {
311#[allow(non_exhaustive_omitted_patterns)] match self.is_lint {
Some(IsLint { has_future_breakage: true, .. }) => true,
_ => false,
}matches!(self.is_lint, Some(IsLint { has_future_breakage: true, .. }))312 }
313314/// Indicates the minimum rust version this lint applies to.
315pub(crate) fn rust_version(&self) -> Option<RustcVersion> {
316self.is_lint.as_ref().and_then(|is| is.rust_version)
317 }
318319pub(crate) fn is_force_warn(&self) -> bool {
320match self.level {
321 Level::ForceWarning => {
322if !self.is_lint.is_some() {
::core::panicking::panic("assertion failed: self.is_lint.is_some()")
};assert!(self.is_lint.is_some());
323true
324}
325_ => false,
326 }
327 }
328329pub(crate) fn sub(&mut self, level: Level, message: impl Into<DiagMessage>, span: MultiSpan) {
330let sub = Subdiag { level, messages: ::alloc::boxed::box_assume_init_into_vec_unsafe(::alloc::intrinsics::write_box_via_move(::alloc::boxed::Box::new_uninit(),
[(message.into(), Style::NoStyle)]))vec![(message.into(), Style::NoStyle)], span };
331self.children.push(sub);
332 }
333334pub(crate) fn arg(&mut self, name: impl Into<DiagArgName>, arg: impl IntoDiagArg) {
335let name = name.into();
336let value = arg.into_diag_arg(&mut self.long_ty_path);
337// This assertion is to avoid subdiagnostics overwriting an existing diagnostic arg.
338if true {
if !(!self.args.contains_key(&name) ||
self.args.get(&name) == Some(&value)) {
{
::core::panicking::panic_fmt(format_args!("arg {0} already exists",
name));
}
};
};debug_assert!(
339 !self.args.contains_key(&name) || self.args.get(&name) == Some(&value),
340"arg {} already exists",
341 name
342 );
343self.args.insert(name, value);
344 }
345346pub fn remove_arg(&mut self, name: &str) {
347self.args.swap_remove(name);
348 }
349350pub fn emitted_at_sub_diag(&self) -> Subdiag {
351let track = ::alloc::__export::must_use({
::alloc::fmt::format(format_args!("-Ztrack-diagnostics: created at {0}",
self.emitted_at))
})format!("-Ztrack-diagnostics: created at {}", self.emitted_at);
352Subdiag {
353 level: crate::Level::Note,
354 messages: ::alloc::boxed::box_assume_init_into_vec_unsafe(::alloc::intrinsics::write_box_via_move(::alloc::boxed::Box::new_uninit(),
[(DiagMessage::Str(Cow::Owned(track)), Style::NoStyle)]))vec![(DiagMessage::Str(Cow::Owned(track)), Style::NoStyle)],
355 span: MultiSpan::new(),
356 }
357 }
358359/// Fields used for Hash, and PartialEq trait.
360fn keys(
361&self,
362 ) -> (
363&Level,
364&[(DiagMessage, Style)],
365&Option<ErrCode>,
366&MultiSpan,
367&[Subdiag],
368&Suggestions,
369Vec<(&DiagArgName, &DiagArgValue)>,
370&Option<IsLint>,
371 ) {
372 (
373&self.level,
374&self.messages,
375&self.code,
376&self.span,
377&self.children,
378&self.suggestions,
379self.args.iter().collect(),
380// omit self.sort_span
381&self.is_lint,
382// omit self.emitted_at
383)
384 }
385}
386387impl Hashfor DiagInner {
388fn hash<H>(&self, state: &mut H)
389where
390H: Hasher,
391 {
392self.keys().hash(state);
393 }
394}
395396impl PartialEqfor DiagInner {
397fn eq(&self, other: &Self) -> bool {
398self.keys() == other.keys()
399 }
400}
401402/// A "sub"-diagnostic attached to a parent diagnostic.
403/// For example, a note attached to an error.
404#[derive(#[automatically_derived]
impl ::core::clone::Clone for Subdiag {
#[inline]
fn clone(&self) -> Subdiag {
Subdiag {
level: ::core::clone::Clone::clone(&self.level),
messages: ::core::clone::Clone::clone(&self.messages),
span: ::core::clone::Clone::clone(&self.span),
}
}
}Clone, #[automatically_derived]
impl ::core::fmt::Debug for Subdiag {
#[inline]
fn fmt(&self, f: &mut ::core::fmt::Formatter) -> ::core::fmt::Result {
::core::fmt::Formatter::debug_struct_field3_finish(f, "Subdiag",
"level", &self.level, "messages", &self.messages, "span",
&&self.span)
}
}Debug, #[automatically_derived]
impl ::core::cmp::PartialEq for Subdiag {
#[inline]
fn eq(&self, other: &Subdiag) -> bool {
self.level == other.level && self.messages == other.messages &&
self.span == other.span
}
}PartialEq, #[automatically_derived]
impl ::core::hash::Hash for Subdiag {
#[inline]
fn hash<__H: ::core::hash::Hasher>(&self, state: &mut __H) {
::core::hash::Hash::hash(&self.level, state);
::core::hash::Hash::hash(&self.messages, state);
::core::hash::Hash::hash(&self.span, state)
}
}Hash, const _: () =
{
impl<__E: ::rustc_span::SpanEncoder> ::rustc_serialize::Encodable<__E>
for Subdiag {
fn encode(&self, __encoder: &mut __E) {
match *self {
Subdiag {
level: ref __binding_0,
messages: ref __binding_1,
span: ref __binding_2 } => {
::rustc_serialize::Encodable::<__E>::encode(__binding_0,
__encoder);
::rustc_serialize::Encodable::<__E>::encode(__binding_1,
__encoder);
::rustc_serialize::Encodable::<__E>::encode(__binding_2,
__encoder);
}
}
}
}
};Encodable, const _: () =
{
impl<__D: ::rustc_span::SpanDecoder> ::rustc_serialize::Decodable<__D>
for Subdiag {
fn decode(__decoder: &mut __D) -> Self {
Subdiag {
level: ::rustc_serialize::Decodable::decode(__decoder),
messages: ::rustc_serialize::Decodable::decode(__decoder),
span: ::rustc_serialize::Decodable::decode(__decoder),
}
}
}
};Decodable)]
405pub struct Subdiag {
406pub level: Level,
407pub messages: Vec<(DiagMessage, Style)>,
408pub span: MultiSpan,
409}
410411/// Used for emitting structured error messages and other diagnostic information.
412/// Wraps a `DiagInner`, adding some useful things.
413/// - The `dcx` field, allowing it to (a) emit itself, and (b) do a drop check
414/// that it has been emitted or cancelled.
415/// - The `EmissionGuarantee`, which determines the type returned from `emit`.
416///
417/// Each constructed `Diag` must be consumed by a function such as `emit`,
418/// `cancel`, `delay_as_bug`, or `into_diag`. A panic occurs if a `Diag`
419/// is dropped without being consumed by one of these functions.
420///
421/// If there is some state in a downstream crate you would like to access in
422/// the methods of `Diag` here, consider extending `DiagCtxtFlags`.
423#[must_use]
424pub struct Diag<'a, G: EmissionGuarantee = ErrorGuaranteed> {
425pub dcx: DiagCtxtHandle<'a>,
426427/// Why the `Option`? It is always `Some` until the `Diag` is consumed via
428 /// `emit`, `cancel`, etc. At that point it is consumed and replaced with
429 /// `None`. Then `drop` checks that it is `None`; if not, it panics because
430 /// a diagnostic was built but not used.
431 ///
432 /// Why the Box? `DiagInner` is a large type, and `Diag` is often used as a
433 /// return value, especially within the frequently-used `PResult` type. In
434 /// theory, return value optimization (RVO) should avoid unnecessary
435 /// copying. In practice, it does not (at the time of writing).
436diag: Option<Box<DiagInner>>,
437438 _marker: PhantomData<G>,
439}
440441// Cloning a `Diag` is a recipe for a diagnostic being emitted twice, which
442// would be bad.
443impl<G> !Clonefor Diag<'_, G> {}
444445const _: [(); 3 * size_of::<usize>()] =
[(); ::std::mem::size_of::<Diag<'_, ()>>()];rustc_data_structures::static_assert_size!(Diag<'_, ()>, 3 * size_of::<usize>());
446447impl<G: EmissionGuarantee> Dereffor Diag<'_, G> {
448type Target = DiagInner;
449450fn deref(&self) -> &DiagInner {
451self.diag.as_ref().unwrap()
452 }
453}
454455impl<G: EmissionGuarantee> DerefMutfor Diag<'_, G> {
456fn deref_mut(&mut self) -> &mut DiagInner {
457self.diag.as_mut().unwrap()
458 }
459}
460461impl<G: EmissionGuarantee> Debugfor Diag<'_, G> {
462fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
463self.diag.fmt(f)
464 }
465}
466467/// `Diag` impls many `&mut self -> &mut Self` methods. Each one modifies an
468/// existing diagnostic, either in a standalone fashion, e.g.
469/// `err.code(code);`, or in a chained fashion to make multiple modifications,
470/// e.g. `err.code(code).span(span);`.
471///
472/// This macro creates an equivalent `self -> Self` method, with a `with_`
473/// prefix. This can be used in a chained fashion when making a new diagnostic,
474/// e.g. `let err = struct_err(msg).with_code(code);`, or emitting a new
475/// diagnostic, e.g. `struct_err(msg).with_code(code).emit();`.
476///
477/// Although the latter method can be used to modify an existing diagnostic,
478/// e.g. `err = err.with_code(code);`, this should be avoided because the former
479/// method gives shorter code, e.g. `err.code(code);`.
480///
481/// Note: the `with_` methods are added only when needed. If you want to use
482/// one and it's not defined, feel free to add it.
483///
484/// Note: any doc comments must be within the `with_fn!` call.
485macro_rules!with_fn {
486 {
487$with_f:ident,
488 $(#[$attrs:meta])*
489pub fn $f:ident(&mut $self:ident, $($name:ident: $ty:ty),* $(,)?) -> &mut Self {
490 $($body:tt)*
491 }
492 } => {
493// The original function.
494$(#[$attrs])*
495#[doc = concat!("See [`Diag::", stringify!($f), "()`].")]
496pub fn $f(&mut $self, $($name: $ty),*) -> &mut Self {
497 $($body)*
498 }
499500// The `with_*` variant.
501$(#[$attrs])*
502#[doc = concat!("See [`Diag::", stringify!($f), "()`].")]
503pub fn $with_f(mut $self, $($name: $ty),*) -> Self {
504$self.$f($($name),*);
505$self
506}
507 };
508}
509510impl<'a, G: EmissionGuarantee> Diag<'a, G> {
511#[track_caller]
512pub fn new(dcx: DiagCtxtHandle<'a>, level: Level, message: impl Into<DiagMessage>) -> Self {
513Self::new_diagnostic(dcx, DiagInner::new(level, message))
514 }
515516/// Allow moving diagnostics between different error tainting contexts
517pub fn with_dcx(mut self, dcx: DiagCtxtHandle<'_>) -> Diag<'_, G> {
518Diag { dcx, diag: self.diag.take(), _marker: PhantomData }
519 }
520521/// Creates a new `Diag` with an already constructed diagnostic.
522#[track_caller]
523pub(crate) fn new_diagnostic(dcx: DiagCtxtHandle<'a>, diag: DiagInner) -> Self {
524{
use ::tracing::__macro_support::Callsite as _;
static __CALLSITE: ::tracing::callsite::DefaultCallsite =
{
static META: ::tracing::Metadata<'static> =
{
::tracing_core::metadata::Metadata::new("event compiler/rustc_errors/src/diagnostic.rs:524",
"rustc_errors::diagnostic", ::tracing::Level::DEBUG,
::tracing_core::__macro_support::Option::Some("compiler/rustc_errors/src/diagnostic.rs"),
::tracing_core::__macro_support::Option::Some(524u32),
::tracing_core::__macro_support::Option::Some("rustc_errors::diagnostic"),
::tracing_core::field::FieldSet::new(&["message"],
::tracing_core::callsite::Identifier(&__CALLSITE)),
::tracing::metadata::Kind::EVENT)
};
::tracing::callsite::DefaultCallsite::new(&META)
};
let enabled =
::tracing::Level::DEBUG <= ::tracing::level_filters::STATIC_MAX_LEVEL
&&
::tracing::Level::DEBUG <=
::tracing::level_filters::LevelFilter::current() &&
{
let interest = __CALLSITE.interest();
!interest.is_never() &&
::tracing::__macro_support::__is_enabled(__CALLSITE.metadata(),
interest)
};
if enabled {
(|value_set: ::tracing::field::ValueSet|
{
let meta = __CALLSITE.metadata();
::tracing::Event::dispatch(meta, &value_set);
;
})({
#[allow(unused_imports)]
use ::tracing::field::{debug, display, Value};
let mut iter = __CALLSITE.metadata().fields().iter();
__CALLSITE.metadata().fields().value_set(&[(&::tracing::__macro_support::Iterator::next(&mut iter).expect("FieldSet corrupted (this is a bug)"),
::tracing::__macro_support::Option::Some(&format_args!("Created new diagnostic")
as &dyn Value))])
});
} else { ; }
};debug!("Created new diagnostic");
525Self { dcx, diag: Some(Box::new(diag)), _marker: PhantomData }
526 }
527528/// Delay emission of this diagnostic as a bug.
529 ///
530 /// This can be useful in contexts where an error indicates a bug but
531 /// typically this only happens when other compilation errors have already
532 /// happened. In those cases this can be used to defer emission of this
533 /// diagnostic as a bug in the compiler only if no other errors have been
534 /// emitted.
535 ///
536 /// In the meantime, though, callsites are required to deal with the "bug"
537 /// locally in whichever way makes the most sense.
538#[track_caller]
539pub fn downgrade_to_delayed_bug(&mut self) {
540if !#[allow(non_exhaustive_omitted_patterns)] match self.level {
Level::Error | Level::DelayedBug => true,
_ => false,
} {
{
::core::panicking::panic_fmt(format_args!("downgrade_to_delayed_bug: cannot downgrade {0:?} to DelayedBug: not an error",
self.level));
}
};assert!(
541matches!(self.level, Level::Error | Level::DelayedBug),
542"downgrade_to_delayed_bug: cannot downgrade {:?} to DelayedBug: not an error",
543self.level
544 );
545self.level = Level::DelayedBug;
546 }
547548/// Make emitting this diagnostic fatal
549 ///
550 /// Changes the level of this diagnostic to Fatal, and importantly also changes the emission guarantee.
551 /// This is sound for errors that would otherwise be printed, but now simply exit the process instead.
552 /// This function still gives an emission guarantee, the guarantee is now just that it exits fatally.
553 /// For delayed bugs this is different, since those are buffered. If we upgrade one to fatal, another
554 /// might now be ignored.
555#[track_caller]
556pub fn upgrade_to_fatal(mut self) -> Diag<'a, FatalAbort> {
557if !#[allow(non_exhaustive_omitted_patterns)] match self.level {
Level::Error => true,
_ => false,
} {
{
::core::panicking::panic_fmt(format_args!("upgrade_to_fatal: cannot upgrade {0:?} to Fatal: not an error",
self.level));
}
};assert!(
558matches!(self.level, Level::Error),
559"upgrade_to_fatal: cannot upgrade {:?} to Fatal: not an error",
560self.level
561 );
562self.level = Level::Fatal;
563564// Take is okay since we immediately rewrap it in another diagnostic.
565 // i.e. we do emit it despite defusing the original diagnostic's drop bomb.
566let diag = self.diag.take();
567Diag { dcx: self.dcx, diag, _marker: PhantomData }
568 }
569570#[doc = r" Appends a labeled span to the diagnostic."]
#[doc = r""]
#[doc =
r" Labels are used to convey additional context for the diagnostic's primary span. They will"]
#[doc =
r" be shown together with the original diagnostic's span, *not* with spans added by"]
#[doc =
r" `span_note`, `span_help`, etc. Therefore, if the primary span is not displayable (because"]
#[doc =
r" the span is `DUMMY_SP` or the source code isn't found), labels will not be displayed"]
#[doc = r" either."]
#[doc = r""]
#[doc =
r" Implementation-wise, the label span is pushed onto the [`MultiSpan`] that was created when"]
#[doc =
r" the diagnostic was constructed. However, the label span is *not* considered a"]
#[doc =
r#" ["primary span"][`MultiSpan`]; only the `Span` supplied when creating the diagnostic is"#]
#[doc = r" primary."]
#[doc = "See [`Diag::span_label()`]."]
pub fn span_label(&mut self, span: Span, label: impl Into<DiagMessage>)
-> &mut Self {
self.span.push_span_label(span, label.into());
self
}
#[doc = r" Appends a labeled span to the diagnostic."]
#[doc = r""]
#[doc =
r" Labels are used to convey additional context for the diagnostic's primary span. They will"]
#[doc =
r" be shown together with the original diagnostic's span, *not* with spans added by"]
#[doc =
r" `span_note`, `span_help`, etc. Therefore, if the primary span is not displayable (because"]
#[doc =
r" the span is `DUMMY_SP` or the source code isn't found), labels will not be displayed"]
#[doc = r" either."]
#[doc = r""]
#[doc =
r" Implementation-wise, the label span is pushed onto the [`MultiSpan`] that was created when"]
#[doc =
r" the diagnostic was constructed. However, the label span is *not* considered a"]
#[doc =
r#" ["primary span"][`MultiSpan`]; only the `Span` supplied when creating the diagnostic is"#]
#[doc = r" primary."]
#[doc = "See [`Diag::span_label()`]."]
pub fn with_span_label(mut self, span: Span, label: impl Into<DiagMessage>)
-> Self {
self.span_label(span, label);
self
}with_fn! { with_span_label,
571/// Appends a labeled span to the diagnostic.
572 ///
573 /// Labels are used to convey additional context for the diagnostic's primary span. They will
574 /// be shown together with the original diagnostic's span, *not* with spans added by
575 /// `span_note`, `span_help`, etc. Therefore, if the primary span is not displayable (because
576 /// the span is `DUMMY_SP` or the source code isn't found), labels will not be displayed
577 /// either.
578 ///
579 /// Implementation-wise, the label span is pushed onto the [`MultiSpan`] that was created when
580 /// the diagnostic was constructed. However, the label span is *not* considered a
581 /// ["primary span"][`MultiSpan`]; only the `Span` supplied when creating the diagnostic is
582 /// primary.
583pub fn span_label(&mut self, span: Span, label: impl Into<DiagMessage>) -> &mut Self {
584self.span.push_span_label(span, label.into());
585self
586} }587588#[doc = r" Labels all the given spans with the provided label."]
#[doc = r" See [`Self::span_label()`] for more information."]
#[doc = "See [`Diag::span_labels()`]."]
pub fn span_labels(&mut self, spans: impl IntoIterator<Item = Span>,
label: &str) -> &mut Self {
for span in spans { self.span_label(span, label.to_string()); }
self
}
#[doc = r" Labels all the given spans with the provided label."]
#[doc = r" See [`Self::span_label()`] for more information."]
#[doc = "See [`Diag::span_labels()`]."]
pub fn with_span_labels(mut self, spans: impl IntoIterator<Item = Span>,
label: &str) -> Self {
self.span_labels(spans, label);
self
}with_fn! { with_span_labels,
589/// Labels all the given spans with the provided label.
590 /// See [`Self::span_label()`] for more information.
591pub fn span_labels(&mut self, spans: impl IntoIterator<Item = Span>, label: &str) -> &mut Self {
592for span in spans {
593self.span_label(span, label.to_string());
594 }
595self
596} }597598pub fn replace_span_with(&mut self, after: Span, keep_label: bool) -> &mut Self {
599let before = self.span.clone();
600self.span(after);
601for span_label in before.span_labels() {
602if let Some(label) = span_label.label {
603if span_label.is_primary && keep_label {
604self.span.push_span_label(after, label);
605 } else {
606self.span.push_span_label(span_label.span, label);
607 }
608 }
609 }
610self611 }
612613pub fn note_expected_found(
614&mut self,
615 expected_label: &str,
616 expected: DiagStyledString,
617 found_label: &str,
618 found: DiagStyledString,
619 ) -> &mut Self {
620self.note_expected_found_extra(
621expected_label,
622expected,
623found_label,
624found,
625DiagStyledString::normal(""),
626DiagStyledString::normal(""),
627 )
628 }
629630pub fn note_expected_found_extra(
631&mut self,
632 expected_label: &str,
633 expected: DiagStyledString,
634 found_label: &str,
635 found: DiagStyledString,
636 expected_extra: DiagStyledString,
637 found_extra: DiagStyledString,
638 ) -> &mut Self {
639let expected_label = expected_label.to_string();
640let expected_label = if expected_label.is_empty() {
641"expected".to_string()
642 } else {
643::alloc::__export::must_use({
::alloc::fmt::format(format_args!("expected {0}", expected_label))
})format!("expected {expected_label}")644 };
645let found_label = found_label.to_string();
646let found_label = if found_label.is_empty() {
647"found".to_string()
648 } else {
649::alloc::__export::must_use({
::alloc::fmt::format(format_args!("found {0}", found_label))
})format!("found {found_label}")650 };
651let (found_padding, expected_padding) = if expected_label.len() > found_label.len() {
652 (expected_label.len() - found_label.len(), 0)
653 } else {
654 (0, found_label.len() - expected_label.len())
655 };
656let mut msg = ::alloc::boxed::box_assume_init_into_vec_unsafe(::alloc::intrinsics::write_box_via_move(::alloc::boxed::Box::new_uninit(),
[StringPart::normal(::alloc::__export::must_use({
::alloc::fmt::format(format_args!("{0}{1} `",
" ".repeat(expected_padding), expected_label))
}))]))vec![StringPart::normal(format!(
657"{}{} `",
658" ".repeat(expected_padding),
659 expected_label
660 ))];
661msg.extend(expected.0);
662msg.push(StringPart::normal(::alloc::__export::must_use({ ::alloc::fmt::format(format_args!("`")) })format!("`")));
663msg.extend(expected_extra.0);
664msg.push(StringPart::normal(::alloc::__export::must_use({ ::alloc::fmt::format(format_args!("\n")) })format!("\n")));
665msg.push(StringPart::normal(::alloc::__export::must_use({
::alloc::fmt::format(format_args!("{0}{1} `",
" ".repeat(found_padding), found_label))
})format!("{}{} `", " ".repeat(found_padding), found_label)));
666msg.extend(found.0);
667msg.push(StringPart::normal(::alloc::__export::must_use({ ::alloc::fmt::format(format_args!("`")) })format!("`")));
668msg.extend(found_extra.0);
669670// For now, just attach these as notes.
671self.highlighted_note(msg);
672self673 }
674675pub fn note_trait_signature(&mut self, name: Symbol, signature: String) -> &mut Self {
676self.highlighted_note(::alloc::boxed::box_assume_init_into_vec_unsafe(::alloc::intrinsics::write_box_via_move(::alloc::boxed::Box::new_uninit(),
[StringPart::normal(::alloc::__export::must_use({
::alloc::fmt::format(format_args!("`{0}` from trait: `",
name))
})), StringPart::highlighted(signature),
StringPart::normal("`")]))vec![
677 StringPart::normal(format!("`{name}` from trait: `")),
678 StringPart::highlighted(signature),
679 StringPart::normal("`"),
680 ]);
681self682 }
683684#[doc = r" Add a note attached to this diagnostic."]
#[doc = "See [`Diag::note()`]."]
pub fn note(&mut self, msg: impl Into<DiagMessage>) -> &mut Self {
self.sub(Level::Note, msg, MultiSpan::new());
self
}
#[doc = r" Add a note attached to this diagnostic."]
#[doc = "See [`Diag::note()`]."]
pub fn with_note(mut self, msg: impl Into<DiagMessage>) -> Self {
self.note(msg);
self
}with_fn! { with_note,
685/// Add a note attached to this diagnostic.
686pub fn note(&mut self, msg: impl Into<DiagMessage>) -> &mut Self {
687self.sub(Level::Note, msg, MultiSpan::new());
688self
689} }690691pub fn highlighted_note(&mut self, msg: Vec<StringPart>) -> &mut Self {
692self.sub_with_highlights(Level::Note, msg, MultiSpan::new());
693self694 }
695696pub fn highlighted_span_note(
697&mut self,
698 span: impl Into<MultiSpan>,
699 msg: Vec<StringPart>,
700 ) -> &mut Self {
701self.sub_with_highlights(Level::Note, msg, span.into());
702self703 }
704705/// This is like [`Diag::note()`], but it's only printed once.
706pub fn note_once(&mut self, msg: impl Into<DiagMessage>) -> &mut Self {
707self.sub(Level::OnceNote, msg, MultiSpan::new());
708self709 }
710711#[doc = r" Prints the span with a note above it."]
#[doc = r" This is like [`Diag::note()`], but it gets its own span."]
#[doc = "See [`Diag::span_note()`]."]
pub fn span_note(&mut self, sp: impl Into<MultiSpan>,
msg: impl Into<DiagMessage>) -> &mut Self {
self.sub(Level::Note, msg, sp.into());
self
}
#[doc = r" Prints the span with a note above it."]
#[doc = r" This is like [`Diag::note()`], but it gets its own span."]
#[doc = "See [`Diag::span_note()`]."]
pub fn with_span_note(mut self, sp: impl Into<MultiSpan>,
msg: impl Into<DiagMessage>) -> Self {
self.span_note(sp, msg);
self
}with_fn! { with_span_note,
712/// Prints the span with a note above it.
713 /// This is like [`Diag::note()`], but it gets its own span.
714pub fn span_note(
715&mut self,
716 sp: impl Into<MultiSpan>,
717 msg: impl Into<DiagMessage>,
718 ) -> &mut Self {
719self.sub(Level::Note, msg, sp.into());
720self
721} }722723/// Prints the span with a note above it.
724 /// This is like [`Diag::note_once()`], but it gets its own span.
725pub fn span_note_once<S: Into<MultiSpan>>(
726&mut self,
727 sp: S,
728 msg: impl Into<DiagMessage>,
729 ) -> &mut Self {
730self.sub(Level::OnceNote, msg, sp.into());
731self732 }
733734#[doc = r" Add a warning attached to this diagnostic."]
#[doc = "See [`Diag::warn()`]."]
pub fn warn(&mut self, msg: impl Into<DiagMessage>) -> &mut Self {
self.sub(Level::Warning, msg, MultiSpan::new());
self
}
#[doc = r" Add a warning attached to this diagnostic."]
#[doc = "See [`Diag::warn()`]."]
pub fn with_warn(mut self, msg: impl Into<DiagMessage>) -> Self {
self.warn(msg);
self
}with_fn! { with_warn,
735/// Add a warning attached to this diagnostic.
736pub fn warn(&mut self, msg: impl Into<DiagMessage>) -> &mut Self {
737self.sub(Level::Warning, msg, MultiSpan::new());
738self
739} }740741/// Prints the span with a warning above it.
742 /// This is like [`Diag::warn()`], but it gets its own span.
743pub fn span_warn<S: Into<MultiSpan>>(
744&mut self,
745 sp: S,
746 msg: impl Into<DiagMessage>,
747 ) -> &mut Self {
748self.sub(Level::Warning, msg, sp.into());
749self750 }
751752#[doc = r" Add a help message attached to this diagnostic."]
#[doc = "See [`Diag::help()`]."]
pub fn help(&mut self, msg: impl Into<DiagMessage>) -> &mut Self {
self.sub(Level::Help, msg, MultiSpan::new());
self
}
#[doc = r" Add a help message attached to this diagnostic."]
#[doc = "See [`Diag::help()`]."]
pub fn with_help(mut self, msg: impl Into<DiagMessage>) -> Self {
self.help(msg);
self
}with_fn! { with_help,
753/// Add a help message attached to this diagnostic.
754pub fn help(&mut self, msg: impl Into<DiagMessage>) -> &mut Self {
755self.sub(Level::Help, msg, MultiSpan::new());
756self
757} }758759/// This is like [`Diag::help()`], but it's only printed once.
760pub fn help_once(&mut self, msg: impl Into<DiagMessage>) -> &mut Self {
761self.sub(Level::OnceHelp, msg, MultiSpan::new());
762self763 }
764765/// Add a help message attached to this diagnostic with a customizable highlighted message.
766pub fn highlighted_help(&mut self, msg: Vec<StringPart>) -> &mut Self {
767self.sub_with_highlights(Level::Help, msg, MultiSpan::new());
768self769 }
770771/// Add a help message attached to this diagnostic with a customizable highlighted message.
772pub fn highlighted_span_help(
773&mut self,
774 span: impl Into<MultiSpan>,
775 msg: Vec<StringPart>,
776 ) -> &mut Self {
777self.sub_with_highlights(Level::Help, msg, span.into());
778self779 }
780781#[doc = r" Prints the span with some help above it."]
#[doc = r" This is like [`Diag::help()`], but it gets its own span."]
#[doc = "See [`Diag::span_help()`]."]
pub fn span_help(&mut self, sp: impl Into<MultiSpan>,
msg: impl Into<DiagMessage>) -> &mut Self {
self.sub(Level::Help, msg, sp.into());
self
}
#[doc = r" Prints the span with some help above it."]
#[doc = r" This is like [`Diag::help()`], but it gets its own span."]
#[doc = "See [`Diag::span_help()`]."]
pub fn with_span_help(mut self, sp: impl Into<MultiSpan>,
msg: impl Into<DiagMessage>) -> Self {
self.span_help(sp, msg);
self
}with_fn! { with_span_help,
782/// Prints the span with some help above it.
783 /// This is like [`Diag::help()`], but it gets its own span.
784pub fn span_help(
785&mut self,
786 sp: impl Into<MultiSpan>,
787 msg: impl Into<DiagMessage>,
788 ) -> &mut Self {
789self.sub(Level::Help, msg, sp.into());
790self
791} }792793/// Disallow attaching suggestions to this diagnostic.
794 /// Any suggestions attached e.g. with the `span_suggestion_*` methods
795 /// (before and after the call to `disable_suggestions`) will be ignored.
796pub fn disable_suggestions(&mut self) -> &mut Self {
797self.suggestions = Suggestions::Disabled;
798self799 }
800801/// Prevent new suggestions from being added to this diagnostic.
802 ///
803 /// Suggestions added before the call to `.seal_suggestions()` will be preserved
804 /// and new suggestions will be ignored.
805pub fn seal_suggestions(&mut self) -> &mut Self {
806if let Suggestions::Enabled(suggestions) = &mut self.suggestions {
807let suggestions_slice = std::mem::take(suggestions).into_boxed_slice();
808self.suggestions = Suggestions::Sealed(suggestions_slice);
809 }
810self811 }
812813/// Helper for pushing to `self.suggestions`.
814 ///
815 /// A new suggestion is added if suggestions are enabled for this diagnostic.
816 /// Otherwise, they are ignored.
817fn push_suggestion(&mut self, suggestion: CodeSuggestion) {
818for subst in &suggestion.substitutions {
819for part in &subst.parts {
820let span = part.span;
821let call_site = span.ctxt().outer_expn_data().call_site;
822if span.in_derive_expansion() && span.overlaps_or_adjacent(call_site) {
823// Ignore if spans is from derive macro.
824return;
825 }
826 }
827 }
828829if let Suggestions::Enabled(suggestions) = &mut self.suggestions {
830suggestions.push(suggestion);
831 }
832 }
833834#[doc =
r" Show a suggestion that has multiple parts to it, always as its own subdiagnostic."]
#[doc =
r" In other words, multiple changes need to be applied as part of this suggestion."]
#[doc = "See [`Diag::multipart_suggestion()`]."]
pub fn multipart_suggestion(&mut self, msg: impl Into<DiagMessage>,
suggestion: Vec<(Span, String)>, applicability: Applicability)
-> &mut Self {
self.multipart_suggestion_with_style(msg, suggestion, applicability,
SuggestionStyle::ShowAlways)
}
#[doc =
r" Show a suggestion that has multiple parts to it, always as its own subdiagnostic."]
#[doc =
r" In other words, multiple changes need to be applied as part of this suggestion."]
#[doc = "See [`Diag::multipart_suggestion()`]."]
pub fn with_multipart_suggestion(mut self, msg: impl Into<DiagMessage>,
suggestion: Vec<(Span, String)>, applicability: Applicability) -> Self {
self.multipart_suggestion(msg, suggestion, applicability);
self
}with_fn! { with_multipart_suggestion,
835/// Show a suggestion that has multiple parts to it, always as its own subdiagnostic.
836 /// In other words, multiple changes need to be applied as part of this suggestion.
837pub fn multipart_suggestion(
838&mut self,
839 msg: impl Into<DiagMessage>,
840 suggestion: Vec<(Span, String)>,
841 applicability: Applicability,
842 ) -> &mut Self {
843self.multipart_suggestion_with_style(
844 msg,
845 suggestion,
846 applicability,
847 SuggestionStyle::ShowAlways,
848 )
849 } }850851/// [`Diag::multipart_suggestion()`] but you can set the [`SuggestionStyle`].
852pub fn multipart_suggestion_with_style(
853&mut self,
854 msg: impl Into<DiagMessage>,
855mut suggestion: Vec<(Span, String)>,
856 applicability: Applicability,
857 style: SuggestionStyle,
858 ) -> &mut Self {
859let mut seen = crate::FxHashSet::default();
860suggestion.retain(|(span, msg)| seen.insert((span.lo(), span.hi(), msg.clone())));
861862let parts = suggestion863 .into_iter()
864 .map(|(span, snippet)| SubstitutionPart { snippet, span })
865 .collect::<Vec<_>>();
866867if !!parts.is_empty() {
::core::panicking::panic("assertion failed: !parts.is_empty()")
};assert!(!parts.is_empty());
868if true {
match (&parts.iter().find(|part|
part.span.is_empty() && part.snippet.is_empty()), &None) {
(left_val, right_val) => {
if !(*left_val == *right_val) {
let kind = ::core::panicking::AssertKind::Eq;
::core::panicking::assert_failed(kind, &*left_val,
&*right_val,
::core::option::Option::Some(format_args!("Span must not be empty and have no suggestion")));
}
}
};
};debug_assert_eq!(
869 parts.iter().find(|part| part.span.is_empty() && part.snippet.is_empty()),
870None,
871"Span must not be empty and have no suggestion",
872 );
873if true {
match (&parts.array_windows().find(|[a, b]| a.span.overlaps(b.span)),
&None) {
(left_val, right_val) => {
if !(*left_val == *right_val) {
let kind = ::core::panicking::AssertKind::Eq;
::core::panicking::assert_failed(kind, &*left_val,
&*right_val,
::core::option::Option::Some(format_args!("suggestion must not have overlapping parts")));
}
}
};
};debug_assert_eq!(
874 parts.array_windows().find(|[a, b]| a.span.overlaps(b.span)),
875None,
876"suggestion must not have overlapping parts",
877 );
878879self.push_suggestion(CodeSuggestion {
880 substitutions: ::alloc::boxed::box_assume_init_into_vec_unsafe(::alloc::intrinsics::write_box_via_move(::alloc::boxed::Box::new_uninit(),
[Substitution { parts }]))vec![Substitution { parts }],
881 msg: msg.into(),
882style,
883applicability,
884 });
885self886 }
887888/// Prints out a message with for a multipart suggestion without showing the suggested code.
889 ///
890 /// This is intended to be used for suggestions that are obvious in what the changes need to
891 /// be from the message, showing the span label inline would be visually unpleasant
892 /// (marginally overlapping spans or multiline spans) and showing the snippet window wouldn't
893 /// improve understandability.
894pub fn tool_only_multipart_suggestion(
895&mut self,
896 msg: impl Into<DiagMessage>,
897 suggestion: Vec<(Span, String)>,
898 applicability: Applicability,
899 ) -> &mut Self {
900self.multipart_suggestion_with_style(
901msg,
902suggestion,
903applicability,
904 SuggestionStyle::CompletelyHidden,
905 )
906 }
907908#[doc = r" Prints out a message with a suggested edit of the code."]
#[doc = r""]
#[doc =
r" In case of short messages and a simple suggestion, rustc displays it as a label:"]
#[doc = r""]
#[doc = r" ```text"]
#[doc = r" try adding parentheses: `(tup.0).1`"]
#[doc = r" ```"]
#[doc = r""]
#[doc = r" The message"]
#[doc = r""]
#[doc =
r" * should not end in any punctuation (a `:` is added automatically)"]
#[doc = r#" * should not be a question (avoid language like "did you mean")"#]
#[doc =
r#" * should not contain any phrases like "the following", "as shown", etc."#]
#[doc = r#" * may look like "to do xyz, use" or "to do xyz, use abc""#]
#[doc =
r" * may contain a name of a function, variable, or type, but not whole expressions"]
#[doc = r""]
#[doc = r" See [`CodeSuggestion`] for more information."]
#[doc = "See [`Diag::span_suggestion()`]."]
pub fn span_suggestion(&mut self, sp: Span, msg: impl Into<DiagMessage>,
suggestion: impl ToString, applicability: Applicability) -> &mut Self {
self.span_suggestion_with_style(sp, msg, suggestion, applicability,
SuggestionStyle::ShowCode);
self
}
#[doc = r" Prints out a message with a suggested edit of the code."]
#[doc = r""]
#[doc =
r" In case of short messages and a simple suggestion, rustc displays it as a label:"]
#[doc = r""]
#[doc = r" ```text"]
#[doc = r" try adding parentheses: `(tup.0).1`"]
#[doc = r" ```"]
#[doc = r""]
#[doc = r" The message"]
#[doc = r""]
#[doc =
r" * should not end in any punctuation (a `:` is added automatically)"]
#[doc = r#" * should not be a question (avoid language like "did you mean")"#]
#[doc =
r#" * should not contain any phrases like "the following", "as shown", etc."#]
#[doc = r#" * may look like "to do xyz, use" or "to do xyz, use abc""#]
#[doc =
r" * may contain a name of a function, variable, or type, but not whole expressions"]
#[doc = r""]
#[doc = r" See [`CodeSuggestion`] for more information."]
#[doc = "See [`Diag::span_suggestion()`]."]
pub fn with_span_suggestion(mut self, sp: Span, msg: impl Into<DiagMessage>,
suggestion: impl ToString, applicability: Applicability) -> Self {
self.span_suggestion(sp, msg, suggestion, applicability);
self
}with_fn! { with_span_suggestion,
909/// Prints out a message with a suggested edit of the code.
910 ///
911 /// In case of short messages and a simple suggestion, rustc displays it as a label:
912 ///
913 /// ```text
914 /// try adding parentheses: `(tup.0).1`
915 /// ```
916 ///
917 /// The message
918 ///
919 /// * should not end in any punctuation (a `:` is added automatically)
920 /// * should not be a question (avoid language like "did you mean")
921 /// * should not contain any phrases like "the following", "as shown", etc.
922 /// * may look like "to do xyz, use" or "to do xyz, use abc"
923 /// * may contain a name of a function, variable, or type, but not whole expressions
924 ///
925 /// See [`CodeSuggestion`] for more information.
926pub fn span_suggestion(
927&mut self,
928 sp: Span,
929 msg: impl Into<DiagMessage>,
930 suggestion: impl ToString,
931 applicability: Applicability,
932 ) -> &mut Self {
933self.span_suggestion_with_style(
934 sp,
935 msg,
936 suggestion,
937 applicability,
938 SuggestionStyle::ShowCode,
939 );
940self
941} }942943#[doc =
r" [`Diag::span_suggestion()`] but you can set the [`SuggestionStyle`]."]
#[doc = "See [`Diag::span_suggestion_with_style()`]."]
pub fn span_suggestion_with_style(&mut self, sp: Span,
msg: impl Into<DiagMessage>, suggestion: impl ToString,
applicability: Applicability, style: SuggestionStyle) -> &mut Self {
if true {
if !!(sp.is_empty() && suggestion.to_string().is_empty()) {
{
::core::panicking::panic_fmt(format_args!("Span must not be empty and have no suggestion"));
}
};
};
self.push_suggestion(CodeSuggestion {
substitutions: ::alloc::boxed::box_assume_init_into_vec_unsafe(::alloc::intrinsics::write_box_via_move(::alloc::boxed::Box::new_uninit(),
[Substitution {
parts: ::alloc::boxed::box_assume_init_into_vec_unsafe(::alloc::intrinsics::write_box_via_move(::alloc::boxed::Box::new_uninit(),
[SubstitutionPart {
snippet: suggestion.to_string(),
span: sp,
}])),
}])),
msg: msg.into(),
style,
applicability,
});
self
}
#[doc =
r" [`Diag::span_suggestion()`] but you can set the [`SuggestionStyle`]."]
#[doc = "See [`Diag::span_suggestion_with_style()`]."]
pub fn with_span_suggestion_with_style(mut self, sp: Span,
msg: impl Into<DiagMessage>, suggestion: impl ToString,
applicability: Applicability, style: SuggestionStyle) -> Self {
self.span_suggestion_with_style(sp, msg, suggestion, applicability,
style);
self
}with_fn! { with_span_suggestion_with_style,
944/// [`Diag::span_suggestion()`] but you can set the [`SuggestionStyle`].
945pub fn span_suggestion_with_style(
946&mut self,
947 sp: Span,
948 msg: impl Into<DiagMessage>,
949 suggestion: impl ToString,
950 applicability: Applicability,
951 style: SuggestionStyle,
952 ) -> &mut Self {
953debug_assert!(
954 !(sp.is_empty() && suggestion.to_string().is_empty()),
955"Span must not be empty and have no suggestion"
956);
957self.push_suggestion(CodeSuggestion {
958 substitutions: vec![Substitution {
959 parts: vec![SubstitutionPart { snippet: suggestion.to_string(), span: sp }],
960 }],
961 msg: msg.into(),
962 style,
963 applicability,
964 });
965self
966} }967968#[doc = r" Always show the suggested change."]
#[doc = "See [`Diag::span_suggestion_verbose()`]."]
pub fn span_suggestion_verbose(&mut self, sp: Span,
msg: impl Into<DiagMessage>, suggestion: impl ToString,
applicability: Applicability) -> &mut Self {
self.span_suggestion_with_style(sp, msg, suggestion, applicability,
SuggestionStyle::ShowAlways);
self
}
#[doc = r" Always show the suggested change."]
#[doc = "See [`Diag::span_suggestion_verbose()`]."]
pub fn with_span_suggestion_verbose(mut self, sp: Span,
msg: impl Into<DiagMessage>, suggestion: impl ToString,
applicability: Applicability) -> Self {
self.span_suggestion_verbose(sp, msg, suggestion, applicability);
self
}with_fn! { with_span_suggestion_verbose,
969/// Always show the suggested change.
970pub fn span_suggestion_verbose(
971&mut self,
972 sp: Span,
973 msg: impl Into<DiagMessage>,
974 suggestion: impl ToString,
975 applicability: Applicability,
976 ) -> &mut Self {
977self.span_suggestion_with_style(
978 sp,
979 msg,
980 suggestion,
981 applicability,
982 SuggestionStyle::ShowAlways,
983 );
984self
985} }986987#[doc = r" Prints out a message with multiple suggested edits of the code."]
#[doc = r" See also [`Diag::span_suggestion()`]."]
#[doc = "See [`Diag::span_suggestions()`]."]
pub fn span_suggestions(&mut self, sp: Span, msg: impl Into<DiagMessage>,
suggestions: impl IntoIterator<Item = String>,
applicability: Applicability) -> &mut Self {
self.span_suggestions_with_style(sp, msg, suggestions, applicability,
SuggestionStyle::ShowAlways)
}
#[doc = r" Prints out a message with multiple suggested edits of the code."]
#[doc = r" See also [`Diag::span_suggestion()`]."]
#[doc = "See [`Diag::span_suggestions()`]."]
pub fn with_span_suggestions(mut self, sp: Span, msg: impl Into<DiagMessage>,
suggestions: impl IntoIterator<Item = String>,
applicability: Applicability) -> Self {
self.span_suggestions(sp, msg, suggestions, applicability);
self
}with_fn! { with_span_suggestions,
988/// Prints out a message with multiple suggested edits of the code.
989 /// See also [`Diag::span_suggestion()`].
990pub fn span_suggestions(
991&mut self,
992 sp: Span,
993 msg: impl Into<DiagMessage>,
994 suggestions: impl IntoIterator<Item = String>,
995 applicability: Applicability,
996 ) -> &mut Self {
997self.span_suggestions_with_style(
998 sp,
999 msg,
1000 suggestions,
1001 applicability,
1002 SuggestionStyle::ShowAlways,
1003 )
1004 } }10051006pub fn span_suggestions_with_style(
1007&mut self,
1008 sp: Span,
1009 msg: impl Into<DiagMessage>,
1010 suggestions: impl IntoIterator<Item = String>,
1011 applicability: Applicability,
1012 style: SuggestionStyle,
1013 ) -> &mut Self {
1014let substitutions = suggestions1015 .into_iter()
1016 .map(|snippet| {
1017if true {
if !!(sp.is_empty() && snippet.is_empty()) {
{
::core::panicking::panic_fmt(format_args!("Span `{0:?}` must not be empty and have no suggestion",
sp));
}
};
};debug_assert!(
1018 !(sp.is_empty() && snippet.is_empty()),
1019"Span `{sp:?}` must not be empty and have no suggestion"
1020);
1021Substitution { parts: ::alloc::boxed::box_assume_init_into_vec_unsafe(::alloc::intrinsics::write_box_via_move(::alloc::boxed::Box::new_uninit(),
[SubstitutionPart { snippet, span: sp }]))vec![SubstitutionPart { snippet, span: sp }] }
1022 })
1023 .collect();
1024self.push_suggestion(CodeSuggestion {
1025substitutions,
1026 msg: msg.into(),
1027style,
1028applicability,
1029 });
1030self1031 }
10321033/// Prints out a message with multiple suggested edits of the code, where each edit consists of
1034 /// multiple parts.
1035 /// See also [`Diag::multipart_suggestion()`].
1036pub fn multipart_suggestions(
1037&mut self,
1038 msg: impl Into<DiagMessage>,
1039 suggestions: impl IntoIterator<Item = Vec<(Span, String)>>,
1040 applicability: Applicability,
1041 ) -> &mut Self {
1042let substitutions = suggestions1043 .into_iter()
1044 .map(|sugg| {
1045let mut parts = sugg1046 .into_iter()
1047 .map(|(span, snippet)| SubstitutionPart { snippet, span })
1048 .collect::<Vec<_>>();
10491050parts.sort_unstable_by_key(|part| part.span);
10511052if !!parts.is_empty() {
::core::panicking::panic("assertion failed: !parts.is_empty()")
};assert!(!parts.is_empty());
1053if true {
match (&parts.iter().find(|part|
part.span.is_empty() && part.snippet.is_empty()), &None) {
(left_val, right_val) => {
if !(*left_val == *right_val) {
let kind = ::core::panicking::AssertKind::Eq;
::core::panicking::assert_failed(kind, &*left_val,
&*right_val,
::core::option::Option::Some(format_args!("Span must not be empty and have no suggestion")));
}
}
};
};debug_assert_eq!(
1054 parts.iter().find(|part| part.span.is_empty() && part.snippet.is_empty()),
1055None,
1056"Span must not be empty and have no suggestion",
1057 );
1058if true {
match (&parts.array_windows().find(|[a, b]| a.span.overlaps(b.span)),
&None) {
(left_val, right_val) => {
if !(*left_val == *right_val) {
let kind = ::core::panicking::AssertKind::Eq;
::core::panicking::assert_failed(kind, &*left_val,
&*right_val,
::core::option::Option::Some(format_args!("suggestion must not have overlapping parts")));
}
}
};
};debug_assert_eq!(
1059 parts.array_windows().find(|[a, b]| a.span.overlaps(b.span)),
1060None,
1061"suggestion must not have overlapping parts",
1062 );
10631064Substitution { parts }
1065 })
1066 .collect();
10671068self.push_suggestion(CodeSuggestion {
1069substitutions,
1070 msg: msg.into(),
1071 style: SuggestionStyle::ShowAlways,
1072applicability,
1073 });
1074self1075 }
10761077#[doc =
r" Prints out a message with a suggested edit of the code. If the suggestion is presented"]
#[doc = r" inline, it will only show the message and not the suggestion."]
#[doc = r""]
#[doc = r" See [`CodeSuggestion`] for more information."]
#[doc = "See [`Diag::span_suggestion_short()`]."]
pub fn span_suggestion_short(&mut self, sp: Span, msg: impl Into<DiagMessage>,
suggestion: impl ToString, applicability: Applicability) -> &mut Self {
self.span_suggestion_with_style(sp, msg, suggestion, applicability,
SuggestionStyle::HideCodeInline);
self
}
#[doc =
r" Prints out a message with a suggested edit of the code. If the suggestion is presented"]
#[doc = r" inline, it will only show the message and not the suggestion."]
#[doc = r""]
#[doc = r" See [`CodeSuggestion`] for more information."]
#[doc = "See [`Diag::span_suggestion_short()`]."]
pub fn with_span_suggestion_short(mut self, sp: Span,
msg: impl Into<DiagMessage>, suggestion: impl ToString,
applicability: Applicability) -> Self {
self.span_suggestion_short(sp, msg, suggestion, applicability);
self
}with_fn! { with_span_suggestion_short,
1078/// Prints out a message with a suggested edit of the code. If the suggestion is presented
1079 /// inline, it will only show the message and not the suggestion.
1080 ///
1081 /// See [`CodeSuggestion`] for more information.
1082pub fn span_suggestion_short(
1083&mut self,
1084 sp: Span,
1085 msg: impl Into<DiagMessage>,
1086 suggestion: impl ToString,
1087 applicability: Applicability,
1088 ) -> &mut Self {
1089self.span_suggestion_with_style(
1090 sp,
1091 msg,
1092 suggestion,
1093 applicability,
1094 SuggestionStyle::HideCodeInline,
1095 );
1096self
1097} }10981099/// Prints out a message for a suggestion without showing the suggested code.
1100 ///
1101 /// This is intended to be used for suggestions that are obvious in what the changes need to
1102 /// be from the message, showing the span label inline would be visually unpleasant
1103 /// (marginally overlapping spans or multiline spans) and showing the snippet window wouldn't
1104 /// improve understandability.
1105pub fn span_suggestion_hidden(
1106&mut self,
1107 sp: Span,
1108 msg: impl Into<DiagMessage>,
1109 suggestion: impl ToString,
1110 applicability: Applicability,
1111 ) -> &mut Self {
1112self.span_suggestion_with_style(
1113sp,
1114msg,
1115suggestion,
1116applicability,
1117 SuggestionStyle::HideCodeAlways,
1118 );
1119self1120 }
11211122#[doc =
r" Adds a suggestion to the JSON output that will not be shown in the CLI."]
#[doc = r""]
#[doc =
r" This is intended to be used for suggestions that are *very* obvious in what the changes"]
#[doc =
r" need to be from the message, but we still want other tools to be able to apply them."]
#[doc = "See [`Diag::tool_only_span_suggestion()`]."]
pub fn tool_only_span_suggestion(&mut self, sp: Span,
msg: impl Into<DiagMessage>, suggestion: impl ToString,
applicability: Applicability) -> &mut Self {
self.span_suggestion_with_style(sp, msg, suggestion, applicability,
SuggestionStyle::CompletelyHidden);
self
}
#[doc =
r" Adds a suggestion to the JSON output that will not be shown in the CLI."]
#[doc = r""]
#[doc =
r" This is intended to be used for suggestions that are *very* obvious in what the changes"]
#[doc =
r" need to be from the message, but we still want other tools to be able to apply them."]
#[doc = "See [`Diag::tool_only_span_suggestion()`]."]
pub fn with_tool_only_span_suggestion(mut self, sp: Span,
msg: impl Into<DiagMessage>, suggestion: impl ToString,
applicability: Applicability) -> Self {
self.tool_only_span_suggestion(sp, msg, suggestion, applicability);
self
}with_fn! { with_tool_only_span_suggestion,
1123/// Adds a suggestion to the JSON output that will not be shown in the CLI.
1124 ///
1125 /// This is intended to be used for suggestions that are *very* obvious in what the changes
1126 /// need to be from the message, but we still want other tools to be able to apply them.
1127pub fn tool_only_span_suggestion(
1128&mut self,
1129 sp: Span,
1130 msg: impl Into<DiagMessage>,
1131 suggestion: impl ToString,
1132 applicability: Applicability,
1133 ) -> &mut Self {
1134self.span_suggestion_with_style(
1135 sp,
1136 msg,
1137 suggestion,
1138 applicability,
1139 SuggestionStyle::CompletelyHidden,
1140 );
1141self
1142} }11431144/// Add a subdiagnostic from a type that implements `Subdiagnostic` (see
1145 /// [rustc_macros::Subdiagnostic]). Performs eager formatting of any messages
1146 /// used in the subdiagnostic, so suitable for use with repeated messages (i.e. re-use of
1147 /// interpolated variables).
1148pub fn subdiagnostic(&mut self, subdiagnostic: impl Subdiagnostic) -> &mut Self {
1149subdiagnostic.add_to_diag(self);
1150self1151 }
11521153#[doc = r" Add a span."]
#[doc = "See [`Diag::span()`]."]
pub fn span(&mut self, sp: impl Into<MultiSpan>) -> &mut Self {
self.span = sp.into();
if let Some(span) = self.span.primary_span() { self.sort_span = span; }
self
}
#[doc = r" Add a span."]
#[doc = "See [`Diag::span()`]."]
pub fn with_span(mut self, sp: impl Into<MultiSpan>) -> Self {
self.span(sp);
self
}with_fn! { with_span,
1154/// Add a span.
1155pub fn span(&mut self, sp: impl Into<MultiSpan>) -> &mut Self {
1156self.span = sp.into();
1157if let Some(span) = self.span.primary_span() {
1158self.sort_span = span;
1159 }
1160self
1161} }11621163pub fn is_lint(
1164&mut self,
1165 name: String,
1166 has_future_breakage: bool,
1167 rust_version: Option<RustcVersion>,
1168 ) -> &mut Self {
1169self.is_lint = Some(IsLint { name, has_future_breakage, rust_version });
1170self1171 }
11721173#[doc = r" Add an error code."]
#[doc = "See [`Diag::code()`]."]
pub fn code(&mut self, code: ErrCode) -> &mut Self {
self.code = Some(code);
self
}
#[doc = r" Add an error code."]
#[doc = "See [`Diag::code()`]."]
pub fn with_code(mut self, code: ErrCode) -> Self { self.code(code); self }with_fn! { with_code,
1174/// Add an error code.
1175pub fn code(&mut self, code: ErrCode) -> &mut Self {
1176self.code = Some(code);
1177self
1178} }11791180#[doc = r" Add an argument."]
#[doc = "See [`Diag::lint_id()`]."]
pub fn lint_id(&mut self, id: LintExpectationId) -> &mut Self {
self.lint_id = Some(id);
self
}
#[doc = r" Add an argument."]
#[doc = "See [`Diag::lint_id()`]."]
pub fn with_lint_id(mut self, id: LintExpectationId) -> Self {
self.lint_id(id);
self
}with_fn! { with_lint_id,
1181/// Add an argument.
1182pub fn lint_id(
1183&mut self,
1184 id: LintExpectationId,
1185 ) -> &mut Self {
1186self.lint_id = Some(id);
1187self
1188} }11891190#[doc = r" Add a primary message."]
#[doc = "See [`Diag::primary_message()`]."]
pub fn primary_message(&mut self, msg: impl Into<DiagMessage>) -> &mut Self {
self.messages[0] = (msg.into(), Style::NoStyle);
self
}
#[doc = r" Add a primary message."]
#[doc = "See [`Diag::primary_message()`]."]
pub fn with_primary_message(mut self, msg: impl Into<DiagMessage>) -> Self {
self.primary_message(msg);
self
}with_fn! { with_primary_message,
1191/// Add a primary message.
1192pub fn primary_message(&mut self, msg: impl Into<DiagMessage>) -> &mut Self {
1193self.messages[0] = (msg.into(), Style::NoStyle);
1194self
1195} }11961197#[doc = r" Add an argument."]
#[doc = "See [`Diag::arg()`]."]
pub fn arg(&mut self, name: impl Into<DiagArgName>, arg: impl IntoDiagArg)
-> &mut Self {
self.deref_mut().arg(name, arg);
self
}
#[doc = r" Add an argument."]
#[doc = "See [`Diag::arg()`]."]
pub fn with_arg(mut self, name: impl Into<DiagArgName>, arg: impl IntoDiagArg)
-> Self {
self.arg(name, arg);
self
}with_fn! { with_arg,
1198/// Add an argument.
1199pub fn arg(
1200&mut self,
1201 name: impl Into<DiagArgName>,
1202 arg: impl IntoDiagArg,
1203 ) -> &mut Self {
1204self.deref_mut().arg(name, arg);
1205self
1206} }12071208/// Convenience function for internal use, clients should use one of the
1209 /// public methods above.
1210 ///
1211 /// Used by `proc_macro_server` for implementing `server::Diagnostic`.
1212pub fn sub(&mut self, level: Level, message: impl Into<DiagMessage>, span: MultiSpan) {
1213self.deref_mut().sub(level, message, span);
1214 }
12151216/// Convenience function for internal use, clients should use one of the
1217 /// public methods above.
1218fn sub_with_highlights(&mut self, level: Level, messages: Vec<StringPart>, span: MultiSpan) {
1219let messages = messages.into_iter().map(|m| (m.content.into(), m.style)).collect();
1220let sub = Subdiag { level, messages, span };
1221self.children.push(sub);
1222 }
12231224/// Takes the diagnostic. For use by methods that consume the Diag: `emit`,
1225 /// `cancel`, etc. Afterwards, `drop` is the only code that will be run on
1226 /// `self`.
1227fn take_diag(&mut self) -> DiagInner {
1228if let Some(path) = &self.long_ty_path {
1229self.note(::alloc::__export::must_use({
::alloc::fmt::format(format_args!("the full name for the type has been written to \'{0}\'",
path.display()))
})format!(
1230"the full name for the type has been written to '{}'",
1231 path.display()
1232 ));
1233self.note("consider using `--verbose` to print the full type name to the console");
1234 }
1235*self.diag.take().unwrap()
1236 }
12371238/// This method allows us to access the path of the file where "long types" are written to.
1239 ///
1240 /// When calling `Diag::emit`, as part of that we will check if a `long_ty_path` has been set,
1241 /// and if it has been then we add a note mentioning the file where the "long types" were
1242 /// written to.
1243 ///
1244 /// When calling `tcx.short_string()` after a `Diag` is constructed, the preferred way of doing
1245 /// so is `tcx.short_string(ty, diag.long_ty_path())`. The diagnostic itself is the one that
1246 /// keeps the existence of a "long type" anywhere in the diagnostic, so the note telling the
1247 /// user where we wrote the file to is only printed once at most, *and* it makes it much harder
1248 /// to forget to set it.
1249 ///
1250 /// If the diagnostic hasn't been created before a "short ty string" is created, then you should
1251 /// ensure that this method is called to set it `*diag.long_ty_path() = path`.
1252 ///
1253 /// As a rule of thumb, if you see or add at least one `tcx.short_string()` call anywhere, in a
1254 /// scope, `diag.long_ty_path()` should be called once somewhere close by.
1255pub fn long_ty_path(&mut self) -> &mut Option<PathBuf> {
1256&mut self.long_ty_path
1257 }
12581259pub fn with_long_ty_path(mut self, long_ty_path: Option<PathBuf>) -> Self {
1260self.long_ty_path = long_ty_path;
1261self1262 }
12631264/// Most `emit_producing_guarantee` functions use this as a starting point.
1265fn emit_producing_nothing(mut self) {
1266let diag = self.take_diag();
1267self.dcx.emit_diagnostic(diag);
1268 }
12691270/// `ErrorGuaranteed::emit_producing_guarantee` uses this.
1271fn emit_producing_error_guaranteed(mut self) -> ErrorGuaranteed {
1272let diag = self.take_diag();
12731274// The only error levels that produce `ErrorGuaranteed` are
1275 // `Error` and `DelayedBug`. But `DelayedBug` should never occur here
1276 // because delayed bugs have their level changed to `Bug` when they are
1277 // actually printed, so they produce an ICE.
1278 //
1279 // (Also, even though `level` isn't `pub`, the whole `DiagInner` could
1280 // be overwritten with a new one thanks to `DerefMut`. So this assert
1281 // protects against that, too.)
1282if !#[allow(non_exhaustive_omitted_patterns)] match diag.level {
Level::Error | Level::DelayedBug => true,
_ => false,
} {
{
::core::panicking::panic_fmt(format_args!("invalid diagnostic level ({0:?})",
diag.level));
}
};assert!(
1283matches!(diag.level, Level::Error | Level::DelayedBug),
1284"invalid diagnostic level ({:?})",
1285 diag.level,
1286 );
12871288let guar = self.dcx.emit_diagnostic(diag);
1289guar.unwrap()
1290 }
12911292/// Emit and consume the diagnostic.
1293#[track_caller]
1294pub fn emit(self) -> G::EmitResult {
1295 G::emit_producing_guarantee(self)
1296 }
12971298/// Emit the diagnostic unless `delay` is true,
1299 /// in which case the emission will be delayed as a bug.
1300 ///
1301 /// See `emit` and `delay_as_bug` for details.
1302#[track_caller]
1303pub fn emit_unless_delay(mut self, delay: bool) -> G::EmitResult {
1304if delay {
1305self.downgrade_to_delayed_bug();
1306 }
1307self.emit()
1308 }
13091310/// Cancel and consume the diagnostic. (A diagnostic must either be emitted or
1311 /// cancelled or it will panic when dropped).
1312pub fn cancel(mut self) {
1313self.diag = None;
1314drop(self);
1315 }
13161317/// Cancels this diagnostic and returns its first message, if it exists.
1318pub fn cancel_into_message(self) -> Option<String> {
1319let s = self.diag.as_ref()?.messages.get(0)?.0.as_str().map(ToString::to_string);
1320self.cancel();
1321s1322 }
13231324/// See `DiagCtxt::stash_diagnostic` for details.
1325pub fn stash(mut self, span: Span, key: StashKey) -> Option<ErrorGuaranteed> {
1326let diag = self.take_diag();
1327self.dcx.stash_diagnostic(span, key, diag)
1328 }
13291330/// Delay emission of this diagnostic as a bug.
1331 ///
1332 /// This can be useful in contexts where an error indicates a bug but
1333 /// typically this only happens when other compilation errors have already
1334 /// happened. In those cases this can be used to defer emission of this
1335 /// diagnostic as a bug in the compiler only if no other errors have been
1336 /// emitted.
1337 ///
1338 /// In the meantime, though, callsites are required to deal with the "bug"
1339 /// locally in whichever way makes the most sense.
1340#[track_caller]
1341pub fn delay_as_bug(mut self) -> G::EmitResult {
1342self.downgrade_to_delayed_bug();
1343self.emit()
1344 }
1345}
13461347/// Destructor bomb: every `Diag` must be consumed (emitted, cancelled, etc.)
1348/// or we emit a bug.
1349impl<G: EmissionGuarantee> Dropfor Diag<'_, G> {
1350fn drop(&mut self) {
1351match self.diag.take() {
1352Some(diag) if !panicking() => {
1353self.dcx.emit_diagnostic(DiagInner::new(
1354 Level::Bug,
1355DiagMessage::from("the following error was constructed but not emitted"),
1356 ));
1357self.dcx.emit_diagnostic(*diag);
1358{
::core::panicking::panic_fmt(format_args!("error was constructed but not emitted"));
};panic!("error was constructed but not emitted");
1359 }
1360_ => {}
1361 }
1362 }
1363}
13641365#[macro_export]
1366macro_rules!struct_span_code_err {
1367 ($dcx:expr, $span:expr, $code:expr, $($message:tt)*) => ({
1368$dcx.struct_span_err($span, format!($($message)*)).with_code($code)
1369 })
1370}