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_error_messages::{DiagArgMap, DiagArgName, DiagArgValue, IntoDiagArg};
12use rustc_lint_defs::{Applicability, LintExpectationId};
13use rustc_macros::{Decodable, Encodable};
14use rustc_span::{DUMMY_SP, Span, Spanned, Symbol};
15use tracing::debug;
1617use crate::{
18CodeSuggestion, DiagCtxtHandle, DiagMessage, ErrCode, ErrorGuaranteed, ExplicitBug, Level,
19MultiSpan, StashKey, Style, Sublevel, Substitution, SubstitutionPart, SuggestionStyle,
20Suggestions,
21};
2223/// Marker type which enables implementation of `create_bug` and `emit_bug` functions for
24/// bug diagnostics.
25#[derive(#[automatically_derived]
impl ::core::marker::Copy for BugAbort { }Copy, #[automatically_derived]
#[doc(hidden)]
unsafe impl ::core::clone::TrivialClone for BugAbort { }
#[automatically_derived]
impl ::core::clone::Clone for BugAbort {
#[inline]
fn clone(&self) -> BugAbort { *self }
}Clone)]
26pub struct BugAbort;
2728/// Marker type which enables implementation of `create_fatal` and `emit_fatal` functions for
29/// fatal diagnostics.
30#[derive(#[automatically_derived]
impl ::core::marker::Copy for FatalAbort { }Copy, #[automatically_derived]
#[doc(hidden)]
unsafe impl ::core::clone::TrivialClone for FatalAbort { }
#[automatically_derived]
impl ::core::clone::Clone for FatalAbort {
#[inline]
fn clone(&self) -> FatalAbort { *self }
}Clone)]
31pub struct FatalAbort;
3233/// Trait implemented by error types. This is rarely implemented manually. Instead, use
34/// `#[derive(Diagnostic)]` -- see [rustc_macros::Diagnostic].
35///
36/// When implemented manually, it should be generic over the emission
37/// guarantee, i.e.:
38/// ```ignore (fragment)
39/// impl<'a, G> Diagnostic<'a, G> for Foo { ... }
40/// ```
41/// rather than being specific:
42/// ```ignore (fragment)
43/// impl<'a> Diagnostic<'a> for Bar { ... } // the default type param is `ErrorGuaranteed`
44/// impl<'a> Diagnostic<'a, ()> for Baz { ... }
45/// ```
46/// There are two reasons for this.
47/// - A diagnostic like `Foo` *could* be emitted at any level -- `level` is
48/// passed in to `into_diag` from outside. Even if in practice it is
49/// always emitted at a single level, we let the diagnostic creation/emission
50/// site determine the level (by using `create_err`, `emit_warn`, etc.)
51/// rather than the `Diagnostic` impl.
52/// - Derived impls are always generic, and it's good for the hand-written
53/// impls to be consistent with them.
54pub trait Diagnostic<'a, G = ErrorGuaranteed> {
55/// Write out as a diagnostic out of `DiagCtxt`.
56#[must_use]
57 #[track_caller]
58fn into_diag(self, dcx: DiagCtxtHandle<'a>, level: Level) -> Diag<'a, G>;
59}
6061impl<'a, T, G> Diagnostic<'a, G> for Spanned<T>
62where
63T: Diagnostic<'a, G>,
64{
65fn into_diag(self, dcx: DiagCtxtHandle<'a>, level: Level) -> Diag<'a, G> {
66self.node.into_diag(dcx, level).with_span(self.span)
67 }
68}
6970/// Type used to emit diagnostic through a closure instead of implementing the `Diagnostic` trait.
71pub struct DiagDecorator<F: FnOnce(&mut Diag<'_, ()>)>(pub F);
7273impl<'a, F: FnOnce(&mut Diag<'_, ()>)> Diagnostic<'a, ()> for DiagDecorator<F> {
74fn into_diag(self, dcx: DiagCtxtHandle<'a>, level: Level) -> Diag<'a, ()> {
75let mut diag = Diag::new(dcx, level, "");
76 (self.0)(&mut diag);
77diag78 }
79}
8081/// Trait implemented by error types. This should not be implemented manually. Instead, use
82/// `#[derive(Subdiagnostic)]` -- see [rustc_macros::Subdiagnostic].
83pub trait Subdiagnostic {
84/// Add a subdiagnostic to an existing diagnostic.
85fn add_to_diag<G>(self, diag: &mut Diag<'_, G>);
86}
8788#[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) {
let DiagLocation {
file: ref __binding_0,
line: ref __binding_1,
col: ref __binding_2 } = *self;
::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)]
89pub struct DiagLocation {
90 file: Cow<'static, str>,
91 line: u32,
92 col: u32,
93}
9495impl DiagLocation {
96#[track_caller]
97pub fn caller() -> Self {
98let loc = panic::Location::caller();
99DiagLocation { file: loc.file().into(), line: loc.line(), col: loc.column() }
100 }
101}
102103impl fmt::Displayfor DiagLocation {
104fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
105f.write_fmt(format_args!("{0}:{1}:{2}", self.file, self.line, self.col))write!(f, "{}:{}:{}", self.file, self.line, self.col)106 }
107}
108109#[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::marker::StructuralPartialEq for IsLint { }
#[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) {
let IsLint {
name: ref __binding_0,
has_future_breakage: ref __binding_1,
rust_version: ref __binding_2 } = *self;
::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)]
110pub struct IsLint {
111/// The lint name.
112pub(crate) name: String,
113/// Indicates whether this lint should show up in cargo's future breakage report.
114has_future_breakage: bool,
115/// Indicates the minimum rust version this lint applies to
116rust_version: Option<RustcVersion>,
117}
118119#[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::marker::StructuralPartialEq for DiagStyledString { }
#[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)]
120pub struct DiagStyledString(pub Vec<StringPart>);
121122impl DiagStyledString {
123pub fn new() -> DiagStyledString {
124DiagStyledString(::alloc::vec::Vec::new()vec![])
125 }
126pub fn push_normal<S: Into<String>>(&mut self, t: S) {
127self.0.push(StringPart::normal(t));
128 }
129pub fn push_highlighted<S: Into<String>>(&mut self, t: S) {
130self.0.push(StringPart::highlighted(t));
131 }
132pub fn push<S: Into<String>>(&mut self, t: S, highlight: bool) {
133if highlight {
134self.push_highlighted(t);
135 } else {
136self.push_normal(t);
137 }
138 }
139pub fn normal<S: Into<String>>(t: S) -> DiagStyledString {
140DiagStyledString(::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)])
141 }
142143pub fn highlighted<S: Into<String>>(t: S) -> DiagStyledString {
144DiagStyledString(::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)])
145 }
146147pub fn content(&self) -> String {
148self.0.iter().map(|x| x.content.as_str()).collect::<String>()
149 }
150151/// Merge segments of the same style.
152pub fn compact(&mut self) {
153let segments = std::mem::take(&mut self.0);
154let mut iter = segments.into_iter();
155let Some(mut prev) = iter.next() else { return };
156while let Some(segment) = iter.next() {
157if prev.style == segment.style {
158 prev.content.push_str(&segment.content);
159 } else {
160self.0.push(prev);
161 prev = segment;
162 }
163 }
164self.0.push(prev);
165 }
166167/// Remove the middle of all long segments for shorter rendering.
168pub fn shorten(&mut self) {
169self.compact();
170/// The marker for removed text.
171const ELLIPSIS: &str = "...";
172/// How many chars at the start and end will remain.
173const PADDING: usize = 6;
174/// The distance after which it is not worth it to reduce the text.
175const DELTA: usize = 3;
176177for segment in self.0.iter_mut() {
178let char_len = segment.content.chars().count();
179if char_len > PADDING * 2 + ELLIPSIS.chars().count() + DELTA
180 && let Some((left, _)) = segment.content.char_indices().nth(PADDING)
181 && let Some((right, _)) = segment.content.char_indices().nth(char_len - PADDING)
182 {
183 segment.content.replace_range(left..right, ELLIPSIS);
184 }
185 }
186 }
187}
188189#[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::marker::StructuralPartialEq for StringPart { }
#[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)]
190pub struct StringPart {
191 content: String,
192 style: Style,
193}
194195impl StringPart {
196pub fn normal<S: Into<String>>(content: S) -> StringPart {
197StringPart { content: content.into(), style: Style::NoStyle }
198 }
199200pub fn highlighted<S: Into<String>>(content: S) -> StringPart {
201StringPart { content: content.into(), style: Style::Highlight }
202 }
203}
204205/// The main part of a diagnostic. Note that `Diag`, which wraps this type, is
206/// used for most operations, and should be used instead whenever possible.
207/// This type should only be used when `Diag`'s lifetime causes difficulties,
208/// e.g. when storing diagnostics within `DiagCtxt`.
209#[must_use]
210#[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) {
let 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 } = *self;
::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)]
211pub struct DiagInner {
212// NOTE(eddyb) this is private to disallow arbitrary after-the-fact changes,
213 // outside of what methods in this crate themselves allow.
214pub(crate) level: Level,
215216pub messages: Vec<(DiagMessage, Style)>,
217pub code: Option<ErrCode>,
218pub lint_id: Option<LintExpectationId>,
219pub span: MultiSpan,
220pub children: Vec<Subdiag>,
221pub suggestions: Suggestions,
222pub args: DiagArgMap,
223224/// This is not used for highlighting or rendering any error message. Rather, it can be used
225 /// as a sort key to sort a buffer of diagnostics. By default, it is the primary span of
226 /// `span` if there is one. Otherwise, it is `DUMMY_SP`.
227pub sort_span: Span,
228229pub is_lint: Option<IsLint>,
230231pub long_ty_path: Option<PathBuf>,
232/// With `-Ztrack_diagnostics` enabled,
233 /// we print where in rustc this error was emitted.
234pub emitted_at: DiagLocation,
235}
236237impl DiagInner {
238#[track_caller]
239pub fn new<M: Into<DiagMessage>>(level: Level, message: M) -> Self {
240DiagInner::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)])
241 }
242243#[track_caller]
244pub fn new_with_messages(level: Level, messages: Vec<(DiagMessage, Style)>) -> Self {
245DiagInner {
246level,
247 lint_id: None,
248messages,
249 code: None,
250 span: MultiSpan::new(),
251 children: ::alloc::vec::Vec::new()vec![],
252 suggestions: Suggestions::Enabled(::alloc::vec::Vec::new()vec![]),
253 args: Default::default(),
254 sort_span: DUMMY_SP,
255 is_lint: None,
256 long_ty_path: None,
257 emitted_at: DiagLocation::caller(),
258 }
259 }
260261#[inline(always)]
262pub fn level(&self) -> Level {
263self.level
264 }
265266pub fn is_error(&self) -> bool {
267match self.level {
268 Level::Bug | Level::Fatal | Level::Error | Level::DelayedBug => true,
269270 Level::ForceWarning271 | Level::Warning272 | Level::Note273 | Level::Help274 | Level::FailureNote275 | Level::Allow276 | Level::Expect => false,
277 }
278 }
279280/// Indicates whether this diagnostic should show up in cargo's future breakage report.
281pub(crate) fn has_future_breakage(&self) -> bool {
282#[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, .. }))283 }
284285/// Indicates the minimum rust version this lint applies to.
286pub(crate) fn rust_version(&self) -> Option<RustcVersion> {
287self.is_lint.as_ref().and_then(|is| is.rust_version)
288 }
289290pub(crate) fn is_force_warn(&self) -> bool {
291match self.level {
292 Level::ForceWarning => {
293if !self.is_lint.is_some() {
::core::panicking::panic("assertion failed: self.is_lint.is_some()")
};assert!(self.is_lint.is_some());
294true
295}
296_ => false,
297 }
298 }
299300pub(crate) fn sub(
301&mut self,
302 level: Sublevel,
303 message: impl Into<DiagMessage>,
304 span: MultiSpan,
305 ) {
306let 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 };
307self.children.push(sub);
308 }
309310pub(crate) fn arg(&mut self, name: impl Into<DiagArgName>, arg: impl IntoDiagArg) {
311let name = name.into();
312let value = arg.into_diag_arg(&mut self.long_ty_path);
313// This assertion is to avoid subdiagnostics overwriting an existing diagnostic arg.
314if 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!(
315 !self.args.contains_key(&name) || self.args.get(&name) == Some(&value),
316"arg {} already exists",
317 name
318 );
319self.args.insert(name, value);
320 }
321322pub fn remove_arg(&mut self, name: &str) {
323self.args.swap_remove(name);
324 }
325326pub fn emitted_at_sub_diag(&self) -> Subdiag {
327let 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);
328Subdiag {
329 level: crate::Sublevel::Note,
330 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)],
331 span: MultiSpan::new(),
332 }
333 }
334335/// Fields used for Hash, and PartialEq trait.
336fn keys(
337&self,
338 ) -> (
339&Level,
340&[(DiagMessage, Style)],
341&Option<ErrCode>,
342&MultiSpan,
343&[Subdiag],
344&Suggestions,
345Vec<(&DiagArgName, &DiagArgValue)>,
346&Option<IsLint>,
347 ) {
348 (
349&self.level,
350&self.messages,
351&self.code,
352&self.span,
353&self.children,
354&self.suggestions,
355self.args.iter().collect(),
356// omit self.sort_span
357&self.is_lint,
358// omit self.emitted_at
359)
360 }
361}
362363impl Hashfor DiagInner {
364fn hash<H>(&self, state: &mut H)
365where
366H: Hasher,
367 {
368self.keys().hash(state);
369 }
370}
371372impl PartialEqfor DiagInner {
373fn eq(&self, other: &Self) -> bool {
374self.keys() == other.keys()
375 }
376}
377378/// A "sub"-diagnostic attached to a parent diagnostic.
379/// For example, a note attached to an error.
380#[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::marker::StructuralPartialEq for Subdiag { }
#[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) {
let Subdiag {
level: ref __binding_0,
messages: ref __binding_1,
span: ref __binding_2 } = *self;
::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)]
381pub struct Subdiag {
382pub level: Sublevel,
383pub messages: Vec<(DiagMessage, Style)>,
384pub span: MultiSpan,
385}
386387/// Used for emitting structured error messages and other diagnostic information.
388/// Wraps a `DiagInner`, adding some useful things.
389/// - The `dcx` field, allowing it to (a) emit itself, and (b) do a drop check
390/// that it has been emitted or cancelled.
391/// - `G`, which determines the type returned from `emit`.
392///
393/// Each constructed `Diag` must be consumed by a function such as `emit`,
394/// `cancel`, or `delay_as_bug`. A panic occurs if a `Diag` is dropped without
395/// being consumed by one of these functions.
396///
397/// If there is some state in a downstream crate you would like to access in
398/// the methods of `Diag` here, consider extending `DiagCtxtFlags`.
399#[must_use]
400pub struct Diag<'a, G = ErrorGuaranteed> {
401pub dcx: DiagCtxtHandle<'a>,
402403/// Why the `Option`? It is always `Some` until the `Diag` is consumed via
404 /// `emit`, `cancel`, etc. At that point it is consumed and replaced with
405 /// `None`. Then `drop` checks that it is `None`; if not, it panics because
406 /// a diagnostic was built but not used.
407 ///
408 /// Why the Box? `DiagInner` is a large type, and `Diag` is often used as a
409 /// return value, especially within the frequently-used `PResult` type. In
410 /// theory, return value optimization (RVO) should avoid unnecessary
411 /// copying. In practice, it does not (at the time of writing).
412diag: Option<Box<DiagInner>>,
413414 _marker: PhantomData<G>,
415}
416417// Cloning a `Diag` is a recipe for a diagnostic being emitted twice, which
418// would be bad.
419impl<G> !Clonefor Diag<'_, G> {}
420421const _: [(); 3 * size_of::<usize>()] =
[(); ::std::mem::size_of::<Diag<'_, ()>>()];rustc_data_structures::static_assert_size!(Diag<'_, ()>, 3 * size_of::<usize>());
422423impl<G> Dereffor Diag<'_, G> {
424type Target = DiagInner;
425426fn deref(&self) -> &DiagInner {
427self.diag.as_ref().unwrap()
428 }
429}
430431impl<G> DerefMutfor Diag<'_, G> {
432fn deref_mut(&mut self) -> &mut DiagInner {
433self.diag.as_mut().unwrap()
434 }
435}
436437impl<G> Debugfor Diag<'_, G> {
438fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
439self.diag.fmt(f)
440 }
441}
442443impl Diag<'_, BugAbort> {
444#[track_caller]
445pub fn emit(self) -> ! {
446{
match (&self.level, &Level::Bug) {
(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::None);
}
}
}
};assert_eq!(self.level, Level::Bug);
447self.emit_producing_nothing();
448 panic::panic_any(ExplicitBug);
449 }
450}
451452impl Diag<'_, FatalAbort> {
453#[track_caller]
454pub fn emit(self) -> ! {
455{
match (&self.level, &Level::Fatal) {
(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::None);
}
}
}
};assert_eq!(self.level, Level::Fatal);
456self.emit_producing_nothing();
457crate::FatalError.raise()
458 }
459}
460461impl Diag<'_, ErrorGuaranteed> {
462#[track_caller]
463pub fn emit(self) -> ErrorGuaranteed {
464self.emit_producing_error_guaranteed()
465 }
466467/// Emit the diagnostic unless `delay` is true,
468 /// in which case the emission will be delayed as a bug.
469 ///
470 /// See `emit` and `delay_as_bug` for details.
471#[track_caller]
472pub fn emit_unless_delay(mut self, delay: bool) -> ErrorGuaranteed {
473if delay {
474self.downgrade_to_delayed_bug();
475 }
476self.emit()
477 }
478479/// Delay emission of this diagnostic as a bug.
480 ///
481 /// This can be useful in contexts where an error indicates a bug but
482 /// typically this only happens when other compilation errors have already
483 /// happened. In those cases this can be used to defer emission of this
484 /// diagnostic as a bug in the compiler only if no other errors have been
485 /// emitted.
486 ///
487 /// In the meantime, though, callsites are required to deal with the "bug"
488 /// locally in whichever way makes the most sense.
489#[track_caller]
490pub fn delay_as_bug(mut self) -> ErrorGuaranteed {
491self.downgrade_to_delayed_bug();
492self.emit()
493 }
494}
495496impl Diag<'_, ()> {
497#[track_caller]
498pub fn emit(self) {
499{
match (&self.level, &Level::Bug) {
(left_val, right_val) => {
if *left_val == *right_val {
let kind = ::core::panicking::AssertKind::Ne;
::core::panicking::assert_failed(kind, &*left_val,
&*right_val, ::core::option::Option::None);
}
}
}
};assert_ne!(self.level, Level::Bug);
500{
match (&self.level, &Level::Fatal) {
(left_val, right_val) => {
if *left_val == *right_val {
let kind = ::core::panicking::AssertKind::Ne;
::core::panicking::assert_failed(kind, &*left_val,
&*right_val, ::core::option::Option::None);
}
}
}
};assert_ne!(self.level, Level::Fatal);
501self.emit_producing_nothing();
502 }
503}
504505/// `Diag` impls many `&mut self -> &mut Self` methods. Each one modifies an
506/// existing diagnostic, either in a standalone fashion, e.g.
507/// `err.code(code);`, or in a chained fashion to make multiple modifications,
508/// e.g. `err.code(code).span(span);`.
509///
510/// This macro creates an equivalent `self -> Self` method, with a `with_`
511/// prefix. This can be used in a chained fashion when making a new diagnostic,
512/// e.g. `let err = struct_err(msg).with_code(code);`, or emitting a new
513/// diagnostic, e.g. `struct_err(msg).with_code(code).emit();`.
514///
515/// Although the latter method can be used to modify an existing diagnostic,
516/// e.g. `err = err.with_code(code);`, this should be avoided because the former
517/// method gives shorter code, e.g. `err.code(code);`.
518///
519/// Note: the `with_` methods are added only when needed. If you want to use
520/// one and it's not defined, feel free to add it.
521///
522/// Note: any doc comments must be within the `with_fn!` call.
523macro_rules!with_fn {
524 {
525$with_f:ident,
526 $(#[$attrs:meta])*
527pub fn $f:ident(&mut $self:ident, $($name:ident: $ty:ty),* $(,)?) -> &mut Self {
528 $($body:tt)*
529 }
530 } => {
531// The original function.
532$(#[$attrs])*
533#[doc = concat!("See [`Diag::", stringify!($f), "()`].")]
534pub fn $f(&mut $self, $($name: $ty),*) -> &mut Self {
535 $($body)*
536 }
537538// The `with_*` variant.
539$(#[$attrs])*
540#[doc = concat!("See [`Diag::", stringify!($f), "()`].")]
541pub fn $with_f(mut $self, $($name: $ty),*) -> Self {
542$self.$f($($name),*);
543$self
544}
545 };
546}
547548impl<'a, G> Diag<'a, G> {
549#[track_caller]
550pub fn new(dcx: DiagCtxtHandle<'a>, level: Level, message: impl Into<DiagMessage>) -> Self {
551Self::new_diagnostic(dcx, DiagInner::new(level, message))
552 }
553554/// Allow moving diagnostics between different error tainting contexts
555pub fn with_dcx(mut self, dcx: DiagCtxtHandle<'_>) -> Diag<'_, G> {
556Diag { dcx, diag: self.diag.take(), _marker: PhantomData }
557 }
558559/// Creates a new `Diag` with an already constructed diagnostic.
560#[track_caller]
561pub(crate) fn new_diagnostic(dcx: DiagCtxtHandle<'a>, diag: DiagInner) -> Self {
562{
use ::tracing::__macro_support::Callsite as _;
static __CALLSITE: ::tracing::callsite::DefaultCallsite =
{
static META: ::tracing::Metadata<'static> =
{
::tracing_core::metadata::Metadata::new("event /rustc-dev/923c95cdf5ba65cea505aa2ea829f578e1506ed8/compiler/rustc_errors/src/diagnostic.rs:562",
"rustc_errors::diagnostic", ::tracing::Level::DEBUG,
::tracing_core::__macro_support::Option::Some("/rustc-dev/923c95cdf5ba65cea505aa2ea829f578e1506ed8/compiler/rustc_errors/src/diagnostic.rs"),
::tracing_core::__macro_support::Option::Some(562u32),
::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};
__CALLSITE.metadata().fields().value_set_all(&[(::tracing::__macro_support::Option::Some(&format_args!("Created new diagnostic")
as &dyn ::tracing::field::Value))])
});
} else { ; }
};debug!("Created new diagnostic");
563Self { dcx, diag: Some(Box::new(diag)), _marker: PhantomData }
564 }
565566/// Delay emission of this diagnostic as a bug.
567 ///
568 /// This can be useful in contexts where an error indicates a bug but
569 /// typically this only happens when other compilation errors have already
570 /// happened. In those cases this can be used to defer emission of this
571 /// diagnostic as a bug in the compiler only if no other errors have been
572 /// emitted.
573 ///
574 /// In the meantime, though, callsites are required to deal with the "bug"
575 /// locally in whichever way makes the most sense.
576#[track_caller]
577pub fn downgrade_to_delayed_bug(&mut self) {
578if !#[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!(
579matches!(self.level, Level::Error | Level::DelayedBug),
580"downgrade_to_delayed_bug: cannot downgrade {:?} to DelayedBug: not an error",
581self.level
582 );
583self.level = Level::DelayedBug;
584 }
585586/// Make emitting this diagnostic fatal.
587#[track_caller]
588pub fn upgrade_to_fatal(mut self) -> Diag<'a, FatalAbort> {
589if !#[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!(
590matches!(self.level, Level::Error),
591"upgrade_to_fatal: cannot upgrade {:?} to Fatal: not an error",
592self.level
593 );
594self.level = Level::Fatal;
595596// Take is okay since we immediately rewrap it in another diagnostic.
597 // i.e. we do emit it despite defusing the original diagnostic's drop bomb.
598let diag = self.diag.take();
599Diag { dcx: self.dcx, diag, _marker: PhantomData }
600 }
601602#[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,
603/// Appends a labeled span to the diagnostic.
604 ///
605 /// Labels are used to convey additional context for the diagnostic's primary span. They will
606 /// be shown together with the original diagnostic's span, *not* with spans added by
607 /// `span_note`, `span_help`, etc. Therefore, if the primary span is not displayable (because
608 /// the span is `DUMMY_SP` or the source code isn't found), labels will not be displayed
609 /// either.
610 ///
611 /// Implementation-wise, the label span is pushed onto the [`MultiSpan`] that was created when
612 /// the diagnostic was constructed. However, the label span is *not* considered a
613 /// ["primary span"][`MultiSpan`]; only the `Span` supplied when creating the diagnostic is
614 /// primary.
615pub fn span_label(&mut self, span: Span, label: impl Into<DiagMessage>) -> &mut Self {
616self.span.push_span_label(span, label.into());
617self
618} }619620#[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,
621/// Labels all the given spans with the provided label.
622 /// See [`Self::span_label()`] for more information.
623pub fn span_labels(&mut self, spans: impl IntoIterator<Item = Span>, label: &str) -> &mut Self {
624for span in spans {
625self.span_label(span, label.to_string());
626 }
627self
628} }629630pub fn replace_span_with(&mut self, after: Span, keep_label: bool) -> &mut Self {
631let before = self.span.clone();
632self.span(after);
633for span_label in before.span_labels() {
634if let Some(label) = span_label.label {
635if span_label.is_primary && keep_label {
636self.span.push_span_label(after, label);
637 } else {
638self.span.push_span_label(span_label.span, label);
639 }
640 }
641 }
642self643 }
644645pub fn note_expected_found(
646&mut self,
647 expected_label: &str,
648 expected: DiagStyledString,
649 found_label: &str,
650 found: DiagStyledString,
651 ) -> &mut Self {
652self.note_expected_found_extra(
653expected_label,
654expected,
655found_label,
656found,
657DiagStyledString::normal(""),
658DiagStyledString::normal(""),
659 )
660 }
661662pub fn note_expected_found_extra(
663&mut self,
664 expected_label: &str,
665 expected: DiagStyledString,
666 found_label: &str,
667 found: DiagStyledString,
668 expected_extra: DiagStyledString,
669 found_extra: DiagStyledString,
670 ) -> &mut Self {
671let expected_label = expected_label.to_string();
672let expected_label = if expected_label.is_empty() {
673"expected".to_string()
674 } else {
675::alloc::__export::must_use({
::alloc::fmt::format(format_args!("expected {0}", expected_label))
})format!("expected {expected_label}")676 };
677let found_label = found_label.to_string();
678let found_label = if found_label.is_empty() {
679"found".to_string()
680 } else {
681::alloc::__export::must_use({
::alloc::fmt::format(format_args!("found {0}", found_label))
})format!("found {found_label}")682 };
683let (found_padding, expected_padding) = if expected_label.len() > found_label.len() {
684 (expected_label.len() - found_label.len(), 0)
685 } else {
686 (0, found_label.len() - expected_label.len())
687 };
688let 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!(
689"{}{} `",
690" ".repeat(expected_padding),
691 expected_label
692 ))];
693msg.extend(expected.0);
694msg.push(StringPart::normal(::alloc::__export::must_use({ ::alloc::fmt::format(format_args!("`")) })format!("`")));
695msg.extend(expected_extra.0);
696msg.push(StringPart::normal(::alloc::__export::must_use({ ::alloc::fmt::format(format_args!("\n")) })format!("\n")));
697msg.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)));
698msg.extend(found.0);
699msg.push(StringPart::normal(::alloc::__export::must_use({ ::alloc::fmt::format(format_args!("`")) })format!("`")));
700msg.extend(found_extra.0);
701702// For now, just attach these as notes.
703self.highlighted_note(msg);
704self705 }
706707pub fn note_trait_signature(&mut self, name: Symbol, signature: String) -> &mut Self {
708self.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![
709 StringPart::normal(format!("`{name}` from trait: `")),
710 StringPart::highlighted(signature),
711 StringPart::normal("`"),
712 ]);
713self714 }
715716#[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(Sublevel::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,
717/// Add a note attached to this diagnostic.
718pub fn note(&mut self, msg: impl Into<DiagMessage>) -> &mut Self {
719self.sub(Sublevel::Note, msg, MultiSpan::new());
720self
721} }722723pub fn highlighted_note(&mut self, msg: Vec<StringPart>) -> &mut Self {
724self.sub_with_highlights(Sublevel::Note, msg, MultiSpan::new());
725self726 }
727728pub fn highlighted_span_note(
729&mut self,
730 span: impl Into<MultiSpan>,
731 msg: Vec<StringPart>,
732 ) -> &mut Self {
733self.sub_with_highlights(Sublevel::Note, msg, span.into());
734self735 }
736737/// This is like [`Diag::note()`], but it's only printed once.
738pub fn note_once(&mut self, msg: impl Into<DiagMessage>) -> &mut Self {
739self.sub(Sublevel::OnceNote, msg, MultiSpan::new());
740self741 }
742743#[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(Sublevel::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,
744/// Prints the span with a note above it.
745 /// This is like [`Diag::note()`], but it gets its own span.
746pub fn span_note(
747&mut self,
748 sp: impl Into<MultiSpan>,
749 msg: impl Into<DiagMessage>,
750 ) -> &mut Self {
751self.sub(Sublevel::Note, msg, sp.into());
752self
753} }754755/// Prints the span with a note above it.
756 /// This is like [`Diag::note_once()`], but it gets its own span.
757pub fn span_note_once<S: Into<MultiSpan>>(
758&mut self,
759 sp: S,
760 msg: impl Into<DiagMessage>,
761 ) -> &mut Self {
762self.sub(Sublevel::OnceNote, msg, sp.into());
763self764 }
765766#[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(Sublevel::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,
767/// Add a warning attached to this diagnostic.
768pub fn warn(&mut self, msg: impl Into<DiagMessage>) -> &mut Self {
769self.sub(Sublevel::Warning, msg, MultiSpan::new());
770self
771} }772773/// Prints the span with a warning above it.
774 /// This is like [`Diag::warn()`], but it gets its own span.
775pub fn span_warn<S: Into<MultiSpan>>(
776&mut self,
777 sp: S,
778 msg: impl Into<DiagMessage>,
779 ) -> &mut Self {
780self.sub(Sublevel::Warning, msg, sp.into());
781self782 }
783784#[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(Sublevel::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,
785/// Add a help message attached to this diagnostic.
786pub fn help(&mut self, msg: impl Into<DiagMessage>) -> &mut Self {
787self.sub(Sublevel::Help, msg, MultiSpan::new());
788self
789} }790791/// This is like [`Diag::help()`], but it's only printed once.
792pub fn help_once(&mut self, msg: impl Into<DiagMessage>) -> &mut Self {
793self.sub(Sublevel::OnceHelp, msg, MultiSpan::new());
794self795 }
796797/// Add a help message attached to this diagnostic with a customizable highlighted message.
798pub fn highlighted_help(&mut self, msg: Vec<StringPart>) -> &mut Self {
799self.sub_with_highlights(Sublevel::Help, msg, MultiSpan::new());
800self801 }
802803/// Add a help message attached to this diagnostic with a customizable highlighted message.
804pub fn highlighted_span_help(
805&mut self,
806 span: impl Into<MultiSpan>,
807 msg: Vec<StringPart>,
808 ) -> &mut Self {
809self.sub_with_highlights(Sublevel::Help, msg, span.into());
810self811 }
812813#[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(Sublevel::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,
814/// Prints the span with some help above it.
815 /// This is like [`Diag::help()`], but it gets its own span.
816pub fn span_help(
817&mut self,
818 sp: impl Into<MultiSpan>,
819 msg: impl Into<DiagMessage>,
820 ) -> &mut Self {
821self.sub(Sublevel::Help, msg, sp.into());
822self
823} }824825/// Disallow attaching suggestions to this diagnostic.
826 /// Any suggestions attached e.g. with the `span_suggestion_*` methods
827 /// (before and after the call to `disable_suggestions`) will be ignored.
828pub fn disable_suggestions(&mut self) -> &mut Self {
829self.suggestions = Suggestions::Disabled;
830self831 }
832833/// Prevent new suggestions from being added to this diagnostic.
834 ///
835 /// Suggestions added before the call to `.seal_suggestions()` will be preserved
836 /// and new suggestions will be ignored.
837pub fn seal_suggestions(&mut self) -> &mut Self {
838if let Suggestions::Enabled(suggestions) = &mut self.suggestions {
839let suggestions_slice = std::mem::take(suggestions).into_boxed_slice();
840self.suggestions = Suggestions::Sealed(suggestions_slice);
841 }
842self843 }
844845/// Helper for pushing to `self.suggestions`.
846 ///
847 /// A new suggestion is added if suggestions are enabled for this diagnostic.
848 /// Otherwise, they are ignored.
849fn push_suggestion(&mut self, suggestion: CodeSuggestion) {
850for subst in &suggestion.substitutions {
851for part in &subst.parts {
852let span = part.span;
853let call_site = span.ctxt().outer_expn_data().call_site;
854if span.in_derive_expansion() && span.overlaps_or_adjacent(call_site) {
855// Ignore if spans is from derive macro.
856return;
857 }
858 }
859 }
860861if let Suggestions::Enabled(suggestions) = &mut self.suggestions {
862suggestions.push(suggestion);
863 }
864 }
865866#[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,
867/// Show a suggestion that has multiple parts to it, always as its own subdiagnostic.
868 /// In other words, multiple changes need to be applied as part of this suggestion.
869pub fn multipart_suggestion(
870&mut self,
871 msg: impl Into<DiagMessage>,
872 suggestion: Vec<(Span, String)>,
873 applicability: Applicability,
874 ) -> &mut Self {
875self.multipart_suggestion_with_style(
876 msg,
877 suggestion,
878 applicability,
879 SuggestionStyle::ShowAlways,
880 )
881 } }882883/// [`Diag::multipart_suggestion()`] but you can set the [`SuggestionStyle`].
884pub fn multipart_suggestion_with_style(
885&mut self,
886 msg: impl Into<DiagMessage>,
887mut suggestion: Vec<(Span, String)>,
888 applicability: Applicability,
889 style: SuggestionStyle,
890 ) -> &mut Self {
891let mut seen = crate::FxHashSet::default();
892suggestion.retain(|(span, msg)| seen.insert((span.lo(), span.hi(), msg.clone())));
893894let parts = suggestion895 .into_iter()
896 .map(|(span, snippet)| SubstitutionPart { snippet, span })
897 .collect::<Vec<_>>();
898899if !!parts.is_empty() {
::core::panicking::panic("assertion failed: !parts.is_empty()")
};assert!(!parts.is_empty());
900if 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!(
901 parts.iter().find(|part| part.span.is_empty() && part.snippet.is_empty()),
902None,
903"Span must not be empty and have no suggestion",
904 );
905if 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!(
906 parts.array_windows().find(|[a, b]| a.span.overlaps(b.span)),
907None,
908"suggestion must not have overlapping parts",
909 );
910911self.push_suggestion(CodeSuggestion {
912 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 }],
913 msg: msg.into(),
914style,
915applicability,
916 });
917self918 }
919920/// Prints out a message with for a multipart suggestion without showing the suggested code.
921 ///
922 /// This is intended to be used for suggestions that are obvious in what the changes need to
923 /// be from the message, showing the span label inline would be visually unpleasant
924 /// (marginally overlapping spans or multiline spans) and showing the snippet window wouldn't
925 /// improve understandability.
926pub fn tool_only_multipart_suggestion(
927&mut self,
928 msg: impl Into<DiagMessage>,
929 suggestion: Vec<(Span, String)>,
930 applicability: Applicability,
931 ) -> &mut Self {
932self.multipart_suggestion_with_style(
933msg,
934suggestion,
935applicability,
936 SuggestionStyle::CompletelyHidden,
937 )
938 }
939940#[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,
941/// Prints out a message with a suggested edit of the code.
942 ///
943 /// In case of short messages and a simple suggestion, rustc displays it as a label:
944 ///
945 /// ```text
946 /// try adding parentheses: `(tup.0).1`
947 /// ```
948 ///
949 /// The message
950 ///
951 /// * should not end in any punctuation (a `:` is added automatically)
952 /// * should not be a question (avoid language like "did you mean")
953 /// * should not contain any phrases like "the following", "as shown", etc.
954 /// * may look like "to do xyz, use" or "to do xyz, use abc"
955 /// * may contain a name of a function, variable, or type, but not whole expressions
956 ///
957 /// See [`CodeSuggestion`] for more information.
958pub fn span_suggestion(
959&mut self,
960 sp: Span,
961 msg: impl Into<DiagMessage>,
962 suggestion: impl ToString,
963 applicability: Applicability,
964 ) -> &mut Self {
965self.span_suggestion_with_style(
966 sp,
967 msg,
968 suggestion,
969 applicability,
970 SuggestionStyle::ShowCode,
971 );
972self
973} }974975#[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,
976/// [`Diag::span_suggestion()`] but you can set the [`SuggestionStyle`].
977pub fn span_suggestion_with_style(
978&mut self,
979 sp: Span,
980 msg: impl Into<DiagMessage>,
981 suggestion: impl ToString,
982 applicability: Applicability,
983 style: SuggestionStyle,
984 ) -> &mut Self {
985debug_assert!(
986 !(sp.is_empty() && suggestion.to_string().is_empty()),
987"Span must not be empty and have no suggestion"
988);
989self.push_suggestion(CodeSuggestion {
990 substitutions: vec![Substitution {
991 parts: vec![SubstitutionPart { snippet: suggestion.to_string(), span: sp }],
992 }],
993 msg: msg.into(),
994 style,
995 applicability,
996 });
997self
998} }9991000#[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,
1001/// Always show the suggested change.
1002pub fn span_suggestion_verbose(
1003&mut self,
1004 sp: Span,
1005 msg: impl Into<DiagMessage>,
1006 suggestion: impl ToString,
1007 applicability: Applicability,
1008 ) -> &mut Self {
1009self.span_suggestion_with_style(
1010 sp,
1011 msg,
1012 suggestion,
1013 applicability,
1014 SuggestionStyle::ShowAlways,
1015 );
1016self
1017} }10181019#[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,
1020/// Prints out a message with multiple suggested edits of the code.
1021 /// See also [`Diag::span_suggestion()`].
1022pub fn span_suggestions(
1023&mut self,
1024 sp: Span,
1025 msg: impl Into<DiagMessage>,
1026 suggestions: impl IntoIterator<Item = String>,
1027 applicability: Applicability,
1028 ) -> &mut Self {
1029self.span_suggestions_with_style(
1030 sp,
1031 msg,
1032 suggestions,
1033 applicability,
1034 SuggestionStyle::ShowAlways,
1035 )
1036 } }10371038pub fn span_suggestions_with_style(
1039&mut self,
1040 sp: Span,
1041 msg: impl Into<DiagMessage>,
1042 suggestions: impl IntoIterator<Item = String>,
1043 applicability: Applicability,
1044 style: SuggestionStyle,
1045 ) -> &mut Self {
1046let substitutions = suggestions1047 .into_iter()
1048 .map(|snippet| {
1049if 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!(
1050 !(sp.is_empty() && snippet.is_empty()),
1051"Span `{sp:?}` must not be empty and have no suggestion"
1052);
1053Substitution { 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 }] }
1054 })
1055 .collect();
1056self.push_suggestion(CodeSuggestion {
1057substitutions,
1058 msg: msg.into(),
1059style,
1060applicability,
1061 });
1062self1063 }
10641065/// Prints out a message with multiple suggested edits of the code, where each edit consists of
1066 /// multiple parts.
1067 /// See also [`Diag::multipart_suggestion()`].
1068pub fn multipart_suggestions(
1069&mut self,
1070 msg: impl Into<DiagMessage>,
1071 suggestions: impl IntoIterator<Item = Vec<(Span, String)>>,
1072 applicability: Applicability,
1073 ) -> &mut Self {
1074let substitutions = suggestions1075 .into_iter()
1076 .map(|sugg| {
1077let mut parts = sugg1078 .into_iter()
1079 .map(|(span, snippet)| SubstitutionPart { snippet, span })
1080 .collect::<Vec<_>>();
10811082parts.sort_unstable_by_key(|part| part.span);
10831084if !!parts.is_empty() {
::core::panicking::panic("assertion failed: !parts.is_empty()")
};assert!(!parts.is_empty());
1085if 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!(
1086 parts.iter().find(|part| part.span.is_empty() && part.snippet.is_empty()),
1087None,
1088"Span must not be empty and have no suggestion",
1089 );
1090if 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!(
1091 parts.array_windows().find(|[a, b]| a.span.overlaps(b.span)),
1092None,
1093"suggestion must not have overlapping parts",
1094 );
10951096Substitution { parts }
1097 })
1098 .collect();
10991100self.push_suggestion(CodeSuggestion {
1101substitutions,
1102 msg: msg.into(),
1103 style: SuggestionStyle::ShowAlways,
1104applicability,
1105 });
1106self1107 }
11081109#[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,
1110/// Prints out a message with a suggested edit of the code. If the suggestion is presented
1111 /// inline, it will only show the message and not the suggestion.
1112 ///
1113 /// See [`CodeSuggestion`] for more information.
1114pub fn span_suggestion_short(
1115&mut self,
1116 sp: Span,
1117 msg: impl Into<DiagMessage>,
1118 suggestion: impl ToString,
1119 applicability: Applicability,
1120 ) -> &mut Self {
1121self.span_suggestion_with_style(
1122 sp,
1123 msg,
1124 suggestion,
1125 applicability,
1126 SuggestionStyle::HideCodeInline,
1127 );
1128self
1129} }11301131/// Prints out a message for a suggestion without showing the suggested code.
1132 ///
1133 /// This is intended to be used for suggestions that are obvious in what the changes need to
1134 /// be from the message, showing the span label inline would be visually unpleasant
1135 /// (marginally overlapping spans or multiline spans) and showing the snippet window wouldn't
1136 /// improve understandability.
1137pub fn span_suggestion_hidden(
1138&mut self,
1139 sp: Span,
1140 msg: impl Into<DiagMessage>,
1141 suggestion: impl ToString,
1142 applicability: Applicability,
1143 ) -> &mut Self {
1144self.span_suggestion_with_style(
1145sp,
1146msg,
1147suggestion,
1148applicability,
1149 SuggestionStyle::HideCodeAlways,
1150 );
1151self1152 }
11531154#[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,
1155/// Adds a suggestion to the JSON output that will not be shown in the CLI.
1156 ///
1157 /// This is intended to be used for suggestions that are *very* obvious in what the changes
1158 /// need to be from the message, but we still want other tools to be able to apply them.
1159pub fn tool_only_span_suggestion(
1160&mut self,
1161 sp: Span,
1162 msg: impl Into<DiagMessage>,
1163 suggestion: impl ToString,
1164 applicability: Applicability,
1165 ) -> &mut Self {
1166self.span_suggestion_with_style(
1167 sp,
1168 msg,
1169 suggestion,
1170 applicability,
1171 SuggestionStyle::CompletelyHidden,
1172 );
1173self
1174} }11751176/// Add a subdiagnostic from a type that implements `Subdiagnostic` (see
1177 /// [rustc_macros::Subdiagnostic]). Performs eager formatting of any messages
1178 /// used in the subdiagnostic, so suitable for use with repeated messages (i.e. re-use of
1179 /// interpolated variables).
1180pub fn subdiagnostic(&mut self, subdiagnostic: impl Subdiagnostic) -> &mut Self {
1181subdiagnostic.add_to_diag(self);
1182self1183 }
11841185#[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,
1186/// Add a span.
1187pub fn span(&mut self, sp: impl Into<MultiSpan>) -> &mut Self {
1188self.span = sp.into();
1189if let Some(span) = self.span.primary_span() {
1190self.sort_span = span;
1191 }
1192self
1193} }11941195pub fn is_lint(
1196&mut self,
1197 name: String,
1198 has_future_breakage: bool,
1199 rust_version: Option<RustcVersion>,
1200 ) -> &mut Self {
1201self.is_lint = Some(IsLint { name, has_future_breakage, rust_version });
1202self1203 }
12041205#[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,
1206/// Add an error code.
1207pub fn code(&mut self, code: ErrCode) -> &mut Self {
1208self.code = Some(code);
1209self
1210} }12111212#[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,
1213/// Add an argument.
1214pub fn lint_id(
1215&mut self,
1216 id: LintExpectationId,
1217 ) -> &mut Self {
1218self.lint_id = Some(id);
1219self
1220} }12211222#[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,
1223/// Add a primary message.
1224pub fn primary_message(&mut self, msg: impl Into<DiagMessage>) -> &mut Self {
1225self.messages[0] = (msg.into(), Style::NoStyle);
1226self
1227} }12281229#[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,
1230/// Add an argument.
1231pub fn arg(
1232&mut self,
1233 name: impl Into<DiagArgName>,
1234 arg: impl IntoDiagArg,
1235 ) -> &mut Self {
1236self.deref_mut().arg(name, arg);
1237self
1238} }12391240/// Convenience function for internal use, clients should use one of the
1241 /// public methods above.
1242 ///
1243 /// Used by `proc_macro_server` for implementing `server::Diagnostic`.
1244pub fn sub(&mut self, level: Sublevel, message: impl Into<DiagMessage>, span: MultiSpan) {
1245self.deref_mut().sub(level, message, span);
1246 }
12471248/// Convenience function for internal use, clients should use one of the
1249 /// public methods above.
1250fn sub_with_highlights(&mut self, level: Sublevel, messages: Vec<StringPart>, span: MultiSpan) {
1251let messages = messages.into_iter().map(|m| (m.content.into(), m.style)).collect();
1252let sub = Subdiag { level, messages, span };
1253self.children.push(sub);
1254 }
12551256/// Takes the diagnostic. For use by methods that consume the Diag: `emit`,
1257 /// `cancel`, etc. Afterwards, `drop` is the only code that will be run on
1258 /// `self`.
1259fn take_diag(&mut self) -> DiagInner {
1260if let Some(path) = &self.long_ty_path {
1261self.note(::alloc::__export::must_use({
::alloc::fmt::format(format_args!("the full name for the type has been written to \'{0}\'",
path.display()))
})format!(
1262"the full name for the type has been written to '{}'",
1263 path.display()
1264 ));
1265self.note("consider using `--verbose` to print the full type name to the console");
1266 }
1267*self.diag.take().unwrap()
1268 }
12691270/// This method allows us to access the path of the file where "long types" are written to.
1271 ///
1272 /// When calling `Diag::emit`, as part of that we will check if a `long_ty_path` has been set,
1273 /// and if it has been then we add a note mentioning the file where the "long types" were
1274 /// written to.
1275 ///
1276 /// When calling `tcx.short_string()` after a `Diag` is constructed, the preferred way of doing
1277 /// so is `tcx.short_string(ty, diag.long_ty_path())`. The diagnostic itself is the one that
1278 /// keeps the existence of a "long type" anywhere in the diagnostic, so the note telling the
1279 /// user where we wrote the file to is only printed once at most, *and* it makes it much harder
1280 /// to forget to set it.
1281 ///
1282 /// If the diagnostic hasn't been created before a "short ty string" is created, then you should
1283 /// ensure that this method is called to set it `*diag.long_ty_path() = path`.
1284 ///
1285 /// As a rule of thumb, if you see or add at least one `tcx.short_string()` call anywhere, in a
1286 /// scope, `diag.long_ty_path()` should be called once somewhere close by.
1287pub fn long_ty_path(&mut self) -> &mut Option<PathBuf> {
1288&mut self.long_ty_path
1289 }
12901291pub fn with_long_ty_path(mut self, long_ty_path: Option<PathBuf>) -> Self {
1292self.long_ty_path = long_ty_path;
1293self1294 }
12951296/// Most `emit` methods use this as a starting point.
1297pub fn emit_producing_nothing(mut self) {
1298let diag = self.take_diag();
1299self.dcx.emit_diagnostic(diag);
1300 }
13011302/// `Diag<'_, ErrorGuaranteed>::emit` uses this.
1303fn emit_producing_error_guaranteed(mut self) -> ErrorGuaranteed {
1304let diag = self.take_diag();
13051306// The only error levels that produce `ErrorGuaranteed` are
1307 // `Error` and `DelayedBug`. But `DelayedBug` should never occur here
1308 // because delayed bugs have their level changed to `Bug` when they are
1309 // actually printed, so they produce an ICE.
1310 //
1311 // (Also, even though `level` isn't `pub`, the whole `DiagInner` could
1312 // be overwritten with a new one thanks to `DerefMut`. So this assert
1313 // protects against that, too.)
1314if !#[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!(
1315matches!(diag.level, Level::Error | Level::DelayedBug),
1316"invalid diagnostic level ({:?})",
1317 diag.level,
1318 );
13191320let guar = self.dcx.emit_diagnostic(diag);
1321guar.unwrap()
1322 }
13231324/// Cancel and consume the diagnostic. (A diagnostic must either be emitted or
1325 /// cancelled or it will panic when dropped).
1326pub fn cancel(mut self) {
1327self.diag = None;
1328drop(self);
1329 }
13301331/// Cancels this diagnostic and returns its first message, if it exists.
1332pub fn cancel_into_message(self) -> Option<String> {
1333let s = self.diag.as_ref()?.messages.get(0)?.0.as_str().map(ToString::to_string);
1334self.cancel();
1335s1336 }
13371338/// See `DiagCtxtHandle::stash_diagnostic` for details.
1339pub fn stash(mut self, span: Span, key: StashKey) -> Option<ErrorGuaranteed> {
1340let diag = self.take_diag();
1341self.dcx.stash_diagnostic(span, key, diag)
1342 }
1343}
13441345/// Destructor bomb: every `Diag` must be consumed (emitted, cancelled, etc.)
1346/// or we emit a bug.
1347impl<G> Dropfor Diag<'_, G> {
1348fn drop(&mut self) {
1349match self.diag.take() {
1350Some(diag) if !panicking() => {
1351self.dcx.emit_diagnostic(DiagInner::new(
1352 Level::Bug,
1353DiagMessage::from("the following error was constructed but not emitted"),
1354 ));
1355self.dcx.emit_diagnostic(*diag);
1356{
::core::panicking::panic_fmt(format_args!("error was constructed but not emitted"));
};panic!("error was constructed but not emitted");
1357 }
1358_ => {}
1359 }
1360 }
1361}
13621363#[macro_export]
1364macro_rules!struct_span_code_err {
1365 ($dcx:expr, $span:expr, $code:expr, $($message:tt)*) => ({
1366$dcx.struct_span_err($span, format!($($message)*)).with_code($code)
1367 })
1368}