1use std::borrow::Cow;
2use std::fmt::{self, Debug};
3use std::hash::Hash;
4use std::ops::{Deref, DerefMut};
5use std::panic;
6use std::path::PathBuf;
7use std::thread::panicking;
89use rustc_ast::attr::version::RustcVersion;
10use rustc_data_structures::stable_hash::StableHasher;
11use rustc_error_messages::{DiagArgMap, DiagArgName, IntoDiagArg};
12use rustc_hashes::Hash128;
13use rustc_lint_defs::{Applicability, LintExpectationId};
14use rustc_macros::{Decodable, Encodable};
15use rustc_span::{Span, Spanned, Symbol};
16use tracing::debug;
1718use crate::{
19CodeSuggestion, DiagCtxtHandle, DiagMessage, ErrCode, ErrorGuaranteed, ExplicitBug, Level,
20MultiSpan, StashKey, Style, Sublevel, Substitution, SubstitutionPart, SuggestionStyle,
21Suggestions,
22};
2324/// Trait implemented by error types. This is rarely implemented manually. Instead, use
25/// `#[derive(Diagnostic)]` -- see [rustc_macros::Diagnostic].
26pub trait Diagnostic<'a> {
27/// Write out as a diagnostic out of `DiagCtxt`.
28#[must_use]
29 #[track_caller]
30fn into_diag(self, dcx: DiagCtxtHandle<'a>, level: Level) -> Diag<'a>;
31}
3233impl<'a, T> Diagnostic<'a> for Spanned<T>
34where
35T: Diagnostic<'a>,
36{
37fn into_diag(self, dcx: DiagCtxtHandle<'a>, level: Level) -> Diag<'a> {
38self.node.into_diag(dcx, level).with_span(self.span)
39 }
40}
4142/// Type used to emit diagnostic through a closure instead of implementing the `Diagnostic` trait.
43pub struct DiagDecorator<F: FnOnce(&mut Diag<'_>)>(pub F);
4445impl<'a, F: FnOnce(&mut Diag<'_>)> Diagnostic<'a> for DiagDecorator<F> {
46fn into_diag(self, dcx: DiagCtxtHandle<'a>, level: Level) -> Diag<'a> {
47let mut diag = Diag::new(dcx, level, "");
48 (self.0)(&mut diag);
49diag50 }
51}
5253/// Trait implemented by error types. This should not be implemented manually. Instead, use
54/// `#[derive(Subdiagnostic)]` -- see [rustc_macros::Subdiagnostic].
55pub trait Subdiagnostic {
56/// Add a subdiagnostic to an existing diagnostic.
57fn add_to_diag(self, diag: &mut Diag<'_>);
58}
5960#[derive(#[automatically_derived]
impl ::core::clone::Clone for DiagLocation {
#[inline]
fn clone(&self) -> Self {
Self {
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)]
61pub struct DiagLocation {
62 file: Cow<'static, str>,
63 line: u32,
64 col: u32,
65}
6667impl DiagLocation {
68pub fn from_location(loc: &'static panic::Location<'static>) -> Self {
69DiagLocation { file: loc.file().into(), line: loc.line(), col: loc.column() }
70 }
7172#[track_caller]
73pub fn caller() -> Self {
74Self::from_location(panic::Location::caller())
75 }
76}
7778impl fmt::Displayfor DiagLocation {
79fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
80f.write_fmt(format_args!("{0}:{1}:{2}", self.file, self.line, self.col))write!(f, "{}:{}:{}", self.file, self.line, self.col)81 }
82}
8384#[derive(#[automatically_derived]
impl ::core::clone::Clone for IsLint {
#[inline]
fn clone(&self) -> Self {
Self {
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: &Self) -> 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)]
85pub struct IsLint {
86/// The lint name.
87pub(crate) name: String,
88/// Indicates whether this lint should show up in cargo's future breakage report.
89has_future_breakage: bool,
90/// Indicates the minimum rust version this lint applies to
91rust_version: Option<RustcVersion>,
92}
9394#[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: &Self) -> 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)]
95pub struct DiagStyledString(pub Vec<StringPart>);
9697impl DiagStyledString {
98pub fn new() -> DiagStyledString {
99DiagStyledString(::alloc::vec::Vec::new()vec![])
100 }
101pub fn push_normal<S: Into<String>>(&mut self, t: S) {
102self.0.push(StringPart::normal(t));
103 }
104pub fn push_highlighted<S: Into<String>>(&mut self, t: S) {
105self.0.push(StringPart::highlighted(t));
106 }
107pub fn push<S: Into<String>>(&mut self, t: S, highlight: bool) {
108if highlight {
109self.push_highlighted(t);
110 } else {
111self.push_normal(t);
112 }
113 }
114pub fn normal<S: Into<String>>(t: S) -> DiagStyledString {
115DiagStyledString(::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)])
116 }
117118pub fn highlighted<S: Into<String>>(t: S) -> DiagStyledString {
119DiagStyledString(::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)])
120 }
121122pub fn content(&self) -> String {
123self.0.iter().map(|x| x.content.as_str()).collect::<String>()
124 }
125126/// Merge segments of the same style.
127pub fn compact(&mut self) {
128let segments = std::mem::take(&mut self.0);
129let mut iter = segments.into_iter();
130let Some(mut prev) = iter.next() else { return };
131while let Some(segment) = iter.next() {
132if prev.style == segment.style {
133 prev.content.push_str(&segment.content);
134 } else {
135self.0.push(prev);
136 prev = segment;
137 }
138 }
139self.0.push(prev);
140 }
141142/// Remove the middle of all long segments for shorter rendering.
143pub fn shorten(&mut self) {
144self.compact();
145/// The marker for removed text.
146const ELLIPSIS: &str = "...";
147/// How many chars at the start and end will remain.
148const PADDING: usize = 6;
149/// The distance after which it is not worth it to reduce the text.
150const DELTA: usize = 3;
151152for segment in self.0.iter_mut() {
153let char_len = segment.content.chars().count();
154if char_len > PADDING * 2 + ELLIPSIS.chars().count() + DELTA
155 && let Some((left, _)) = segment.content.char_indices().nth(PADDING)
156 && let Some((right, _)) = segment.content.char_indices().nth(char_len - PADDING)
157 {
158 segment.content.replace_range(left..right, ELLIPSIS);
159 }
160 }
161 }
162}
163164#[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: &Self) -> 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)]
165pub struct StringPart {
166 content: String,
167 style: Style,
168}
169170impl StringPart {
171pub fn normal<S: Into<String>>(content: S) -> StringPart {
172StringPart { content: content.into(), style: Style::NoStyle }
173 }
174175pub fn highlighted<S: Into<String>>(content: S) -> StringPart {
176StringPart { content: content.into(), style: Style::Highlight }
177 }
178}
179180/// The main part of a diagnostic. Note that `Diag`, which wraps this type, is
181/// used for most operations, and should be used instead whenever possible.
182/// This type should only be used when `Diag`'s lifetime causes difficulties,
183/// e.g. when storing diagnostics within `DiagCtxt`.
184#[must_use]
185#[derive(#[automatically_derived]
impl ::core::clone::Clone for DiagInner {
#[inline]
fn clone(&self) -> Self {
Self {
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),
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", "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.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,
is_lint: ref __binding_8,
long_ty_path: ref __binding_9,
emitted_at: ref __binding_10 } = *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);
}
}
};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),
is_lint: ::rustc_serialize::Decodable::decode(__decoder),
long_ty_path: ::rustc_serialize::Decodable::decode(__decoder),
emitted_at: ::rustc_serialize::Decodable::decode(__decoder),
}
}
}
};Decodable)]
186pub struct DiagInner {
187// NOTE(eddyb) this is private to disallow arbitrary after-the-fact changes,
188 // outside of what methods in this crate themselves allow.
189pub(crate) level: Level,
190191pub messages: Vec<(DiagMessage, Style)>,
192pub code: Option<ErrCode>,
193pub lint_id: Option<LintExpectationId>,
194pub span: MultiSpan,
195pub children: Vec<Subdiag>,
196pub suggestions: Suggestions,
197pub args: DiagArgMap,
198pub is_lint: Option<IsLint>,
199pub long_ty_path: Option<PathBuf>,
200/// With `-Ztrack_diagnostics` enabled,
201 /// we print where in rustc this error was emitted.
202pub emitted_at: DiagLocation,
203}
204205impl DiagInner {
206#[track_caller]
207pub fn new<M: Into<DiagMessage>>(level: Level, message: M) -> Self {
208DiagInner::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)])
209 }
210211#[track_caller]
212pub fn new_with_messages(level: Level, messages: Vec<(DiagMessage, Style)>) -> Self {
213DiagInner {
214level,
215 lint_id: None,
216messages,
217 code: None,
218 span: MultiSpan::new(),
219 children: ::alloc::vec::Vec::new()vec![],
220 suggestions: Suggestions::Enabled(::alloc::vec::Vec::new()vec![]),
221 args: Default::default(),
222 is_lint: None,
223 long_ty_path: None,
224 emitted_at: DiagLocation::caller(),
225 }
226 }
227228#[inline(always)]
229pub fn level(&self) -> Level {
230self.level
231 }
232233pub fn is_error(&self) -> bool {
234match self.level {
235 Level::Bug | Level::Fatal | Level::Error | Level::DelayedBug => true,
236237 Level::ForceWarning238 | Level::Warning239 | Level::Note240 | Level::Help241 | Level::FailureNote242 | Level::Allow243 | Level::Expect => false,
244 }
245 }
246247/// Indicates whether this diagnostic should show up in cargo's future breakage report.
248pub(crate) fn has_future_breakage(&self) -> bool {
249#[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, .. }))250 }
251252/// Indicates the minimum rust version this lint applies to.
253pub(crate) fn rust_version(&self) -> Option<RustcVersion> {
254self.is_lint.as_ref().and_then(|is| is.rust_version)
255 }
256257pub(crate) fn is_force_warn(&self) -> bool {
258match self.level {
259 Level::ForceWarning => {
260if !self.is_lint.is_some() {
::core::panicking::panic("assertion failed: self.is_lint.is_some()")
};assert!(self.is_lint.is_some());
261true
262}
263_ => false,
264 }
265 }
266267pub(crate) fn sub(
268&mut self,
269 level: Sublevel,
270 message: impl Into<DiagMessage>,
271 span: MultiSpan,
272 ) {
273let 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 };
274self.children.push(sub);
275 }
276277pub(crate) fn arg(&mut self, name: impl Into<DiagArgName>, arg: impl IntoDiagArg) {
278let name = name.into();
279let value = arg.into_diag_arg(&mut self.long_ty_path);
280// This assertion is to avoid subdiagnostics overwriting an existing diagnostic arg.
281if 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!(
282 !self.args.contains_key(&name) || self.args.get(&name) == Some(&value),
283"arg {} already exists",
284 name
285 );
286self.args.insert(name, value);
287 }
288289pub fn remove_arg(&mut self, name: &str) {
290self.args.swap_remove(name);
291 }
292293pub fn emitted_at_sub_diag(&self) -> Subdiag {
294let 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);
295Subdiag {
296 level: crate::Sublevel::Note,
297 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)],
298 span: MultiSpan::new(),
299 }
300 }
301302/// Hash used to determine if two diagnostics are the same. Used by
303 /// `DiagCtxtInner::emitted_diagnostics`. Some fields are ignored for the hash.
304pub(crate) fn dedup_hash(&self) -> Hash128 {
305// Deconstruct to ensure all fields are considered.
306let DiagInner {
307 level,
308 messages,
309 code,
310 lint_id: _, // ignore
311span,
312 children,
313 suggestions,
314 args,
315 is_lint,
316 long_ty_path: _, // ignore
317emitted_at: _, // ignore
318} = self;
319320let hashed_parts =
321 (level, messages, code, span, children, suggestions, args.as_slice(), is_lint);
322323let mut hasher = StableHasher::new();
324hashed_parts.hash(&mut hasher);
325hasher.finish()
326 }
327}
328329/// A "sub"-diagnostic attached to a parent diagnostic.
330/// For example, a note attached to an error.
331#[derive(#[automatically_derived]
impl ::core::clone::Clone for Subdiag {
#[inline]
fn clone(&self) -> Self {
Self {
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: &Self) -> 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)]
332pub struct Subdiag {
333pub level: Sublevel,
334pub messages: Vec<(DiagMessage, Style)>,
335pub span: MultiSpan,
336}
337338/// Used for emitting structured error messages and other diagnostic information.
339/// Wraps a `DiagInner`, adding some useful things.
340/// - The `dcx` field, allowing it to (a) emit itself, and (b) do a drop check
341/// that it has been emitted or cancelled.
342///
343/// Each constructed `Diag` must be consumed by a function such as
344/// `emit_bug`/`emit_fatal`/`emit_err`/`emit`, `cancel`, or `delay_as_bug`. A
345/// panic occurs if a `Diag` is dropped without being consumed by one of these
346/// functions.
347///
348/// If there is some state in a downstream crate you would like to access in
349/// the methods of `Diag` here, consider extending `DiagCtxtFlags`.
350#[must_use]
351pub struct Diag<'a> {
352pub dcx: DiagCtxtHandle<'a>,
353354/// Why the `Option`? It is always `Some` until the `Diag` is consumed via
355 /// `emit`, `cancel`, etc. At that point it is consumed and replaced with
356 /// `None`. Then `drop` checks that it is `None`; if not, it panics because
357 /// a diagnostic was built but not used.
358 ///
359 /// Why the Box? `DiagInner` is a large type, and `Diag` is often used as a
360 /// return value, especially within the frequently-used `PResult` type. In
361 /// theory, return value optimization (RVO) should avoid unnecessary
362 /// copying. In practice, it does not (at the time of writing).
363diag: Option<Box<DiagInner>>,
364}
365366// Cloning a `Diag` is a recipe for a diagnostic being emitted twice, which
367// would be bad.
368impl !Clonefor Diag<'_> {}
369370const _: [(); 3 * size_of::<usize>()] =
[(); ::std::mem::size_of::<Diag<'_>>()];rustc_data_structures::static_assert_size!(Diag<'_>, 3 * size_of::<usize>());
371372impl Dereffor Diag<'_> {
373type Target = DiagInner;
374375fn deref(&self) -> &DiagInner {
376self.diag.as_ref().unwrap()
377 }
378}
379380impl DerefMutfor Diag<'_> {
381fn deref_mut(&mut self) -> &mut DiagInner {
382self.diag.as_mut().unwrap()
383 }
384}
385386impl Debugfor Diag<'_> {
387fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
388self.diag.fmt(f)
389 }
390}
391392/// `Diag` impls many `&mut self -> &mut Self` methods. Each one modifies an
393/// existing diagnostic, either in a standalone fashion, e.g.
394/// `err.code(code);`, or in a chained fashion to make multiple modifications,
395/// e.g. `err.code(code).span(span);`.
396///
397/// This macro creates an equivalent `self -> Self` method, with a `with_`
398/// prefix. This can be used in a chained fashion when making a new diagnostic,
399/// e.g. `let err = struct_err(msg).with_code(code);`, or emitting a new
400/// diagnostic, e.g. `struct_err(msg).with_code(code).emit();`.
401///
402/// Although the latter method can be used to modify an existing diagnostic,
403/// e.g. `err = err.with_code(code);`, this should be avoided because the former
404/// method gives shorter code, e.g. `err.code(code);`.
405///
406/// Note: the `with_` methods are added only when needed. If you want to use
407/// one and it's not defined, feel free to add it.
408///
409/// Note: any doc comments must be within the `with_fn!` call.
410macro_rules!with_fn {
411 {
412$with_f:ident,
413 $(#[$attrs:meta])*
414pub fn $f:ident(&mut $self:ident, $($name:ident: $ty:ty),* $(,)?) -> &mut Self {
415 $($body:tt)*
416 }
417 } => {
418// The original function.
419$(#[$attrs])*
420#[doc = concat!("See [`Diag::", stringify!($f), "()`].")]
421pub fn $f(&mut $self, $($name: $ty),*) -> &mut Self {
422 $($body)*
423 }
424425// The `with_*` variant.
426$(#[$attrs])*
427#[doc = concat!("See [`Diag::", stringify!($f), "()`].")]
428pub fn $with_f(mut $self, $($name: $ty),*) -> Self {
429$self.$f($($name),*);
430$self
431}
432 };
433}
434435impl<'a> Diag<'a> {
436#[track_caller]
437pub fn new(dcx: DiagCtxtHandle<'a>, level: Level, message: impl Into<DiagMessage>) -> Self {
438Self::new_diagnostic(dcx, DiagInner::new(level, message))
439 }
440441/// Allow moving diagnostics between different error tainting contexts
442pub fn with_dcx(mut self, dcx: DiagCtxtHandle<'_>) -> Diag<'_> {
443Diag { dcx, diag: self.diag.take() }
444 }
445446/// Creates a new `Diag` with an already constructed diagnostic.
447#[track_caller]
448pub(crate) fn new_diagnostic(dcx: DiagCtxtHandle<'a>, diag: DiagInner) -> Self {
449{
use ::tracing::__macro_support::Callsite as _;
static __CALLSITE: ::tracing::callsite::DefaultCallsite =
{
static META: ::tracing::Metadata<'static> =
{
::tracing_core::metadata::Metadata::new("event /rustc-dev/f7575a9da8e4a4fca3b5668d5a2ea7476db44b3f/compiler/rustc_errors/src/diagnostic.rs:449",
"rustc_errors::diagnostic", ::tracing::Level::DEBUG,
::tracing_core::__macro_support::Option::Some("/rustc-dev/f7575a9da8e4a4fca3b5668d5a2ea7476db44b3f/compiler/rustc_errors/src/diagnostic.rs"),
::tracing_core::__macro_support::Option::Some(449u32),
::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");
450Self { dcx, diag: Some(Box::new(diag)) }
451 }
452453/// Delay emission of this diagnostic as a bug.
454 ///
455 /// This can be useful in contexts where an error indicates a bug but
456 /// typically this only happens when other compilation errors have already
457 /// happened. In those cases this can be used to defer emission of this
458 /// diagnostic as a bug in the compiler only if no other errors have been
459 /// emitted.
460 ///
461 /// In the meantime, though, callsites are required to deal with the "bug"
462 /// locally in whichever way makes the most sense.
463#[track_caller]
464pub fn downgrade_to_delayed_bug(&mut self) {
465if !#[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!(
466matches!(self.level, Level::Error | Level::DelayedBug),
467"downgrade_to_delayed_bug: cannot downgrade {:?} to DelayedBug: not an error",
468self.level
469 );
470self.level = Level::DelayedBug;
471 }
472473/// Make emitting this diagnostic fatal.
474#[track_caller]
475pub fn upgrade_to_fatal(mut self) -> Diag<'a> {
476if !#[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!(
477matches!(self.level, Level::Error),
478"upgrade_to_fatal: cannot upgrade {:?} to Fatal: not an error",
479self.level
480 );
481self.level = Level::Fatal;
482483// Take is okay since we immediately rewrap it in another diagnostic.
484 // i.e. we do emit it despite defusing the original diagnostic's drop bomb.
485let diag = self.diag.take();
486Diag { dcx: self.dcx, diag }
487 }
488489#[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,
490/// Appends a labeled span to the diagnostic.
491 ///
492 /// Labels are used to convey additional context for the diagnostic's primary span. They will
493 /// be shown together with the original diagnostic's span, *not* with spans added by
494 /// `span_note`, `span_help`, etc. Therefore, if the primary span is not displayable (because
495 /// the span is `DUMMY_SP` or the source code isn't found), labels will not be displayed
496 /// either.
497 ///
498 /// Implementation-wise, the label span is pushed onto the [`MultiSpan`] that was created when
499 /// the diagnostic was constructed. However, the label span is *not* considered a
500 /// ["primary span"][`MultiSpan`]; only the `Span` supplied when creating the diagnostic is
501 /// primary.
502pub fn span_label(&mut self, span: Span, label: impl Into<DiagMessage>) -> &mut Self {
503self.span.push_span_label(span, label.into());
504self
505} }506507#[doc = "See [`Diag::span_context()`]."]
pub fn span_context(&mut self, span: Span) -> &mut Self {
self.span.push_span_context(span);
self
}
#[doc = "See [`Diag::span_context()`]."]
pub fn with_span_context(mut self, span: Span) -> Self {
self.span_context(span);
self
}with_fn! { with_span_context,
508pub fn span_context(&mut self, span: Span) -> &mut Self {
509self.span.push_span_context(span);
510self
511} }512513#[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,
514/// Labels all the given spans with the provided label.
515 /// See [`Self::span_label()`] for more information.
516pub fn span_labels(&mut self, spans: impl IntoIterator<Item = Span>, label: &str) -> &mut Self {
517for span in spans {
518self.span_label(span, label.to_string());
519 }
520self
521} }522523pub fn replace_span_with(&mut self, after: Span, keep_label: bool) -> &mut Self {
524let before = self.span.clone();
525self.span(after);
526for span_label in before.span_labels() {
527if let Some(label) = span_label.label {
528if span_label.is_primary && keep_label {
529self.span.push_span_label(after, label);
530 } else {
531self.span.push_span_label(span_label.span, label);
532 }
533 }
534 }
535self536 }
537538pub fn note_expected_found(
539&mut self,
540 expected_label: &str,
541 expected: DiagStyledString,
542 found_label: &str,
543 found: DiagStyledString,
544 ) -> &mut Self {
545self.note_expected_found_extra(
546expected_label,
547expected,
548found_label,
549found,
550DiagStyledString::normal(""),
551DiagStyledString::normal(""),
552 )
553 }
554555pub fn note_expected_found_extra(
556&mut self,
557 expected_label: &str,
558 expected: DiagStyledString,
559 found_label: &str,
560 found: DiagStyledString,
561 expected_extra: DiagStyledString,
562 found_extra: DiagStyledString,
563 ) -> &mut Self {
564let expected_label = expected_label.to_string();
565let expected_label = if expected_label.is_empty() {
566"expected".to_string()
567 } else {
568::alloc::__export::must_use({
::alloc::fmt::format(format_args!("expected {0}", expected_label))
})format!("expected {expected_label}")569 };
570let found_label = found_label.to_string();
571let found_label = if found_label.is_empty() {
572"found".to_string()
573 } else {
574::alloc::__export::must_use({
::alloc::fmt::format(format_args!("found {0}", found_label))
})format!("found {found_label}")575 };
576let (found_padding, expected_padding) = if expected_label.len() > found_label.len() {
577 (expected_label.len() - found_label.len(), 0)
578 } else {
579 (0, found_label.len() - expected_label.len())
580 };
581let 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!(
582"{}{} `",
583" ".repeat(expected_padding),
584 expected_label
585 ))];
586msg.extend(expected.0);
587msg.push(StringPart::normal(::alloc::__export::must_use({ ::alloc::fmt::format(format_args!("`")) })format!("`")));
588msg.extend(expected_extra.0);
589msg.push(StringPart::normal(::alloc::__export::must_use({ ::alloc::fmt::format(format_args!("\n")) })format!("\n")));
590msg.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)));
591msg.extend(found.0);
592msg.push(StringPart::normal(::alloc::__export::must_use({ ::alloc::fmt::format(format_args!("`")) })format!("`")));
593msg.extend(found_extra.0);
594595// For now, just attach these as notes.
596self.highlighted_note(msg);
597self598 }
599600pub fn note_trait_signature(&mut self, name: Symbol, signature: String) -> &mut Self {
601self.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![
602 StringPart::normal(format!("`{name}` from trait: `")),
603 StringPart::highlighted(signature),
604 StringPart::normal("`"),
605 ]);
606self607 }
608609#[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,
610/// Add a note attached to this diagnostic.
611pub fn note(&mut self, msg: impl Into<DiagMessage>) -> &mut Self {
612self.sub(Sublevel::Note, msg, MultiSpan::new());
613self
614} }615616pub fn highlighted_note(&mut self, msg: Vec<StringPart>) -> &mut Self {
617self.sub_with_highlights(Sublevel::Note, msg, MultiSpan::new());
618self619 }
620621pub fn highlighted_span_note(
622&mut self,
623 span: impl Into<MultiSpan>,
624 msg: Vec<StringPart>,
625 ) -> &mut Self {
626self.sub_with_highlights(Sublevel::Note, msg, span.into());
627self628 }
629630/// This is like [`Diag::note()`], but it's only printed once.
631pub fn note_once(&mut self, msg: impl Into<DiagMessage>) -> &mut Self {
632self.sub(Sublevel::OnceNote, msg, MultiSpan::new());
633self634 }
635636#[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,
637/// Prints the span with a note above it.
638 /// This is like [`Diag::note()`], but it gets its own span.
639pub fn span_note(
640&mut self,
641 sp: impl Into<MultiSpan>,
642 msg: impl Into<DiagMessage>,
643 ) -> &mut Self {
644self.sub(Sublevel::Note, msg, sp.into());
645self
646} }647648/// Prints the span with a note above it.
649 /// This is like [`Diag::note_once()`], but it gets its own span.
650pub fn span_note_once<S: Into<MultiSpan>>(
651&mut self,
652 sp: S,
653 msg: impl Into<DiagMessage>,
654 ) -> &mut Self {
655self.sub(Sublevel::OnceNote, msg, sp.into());
656self657 }
658659#[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,
660/// Add a warning attached to this diagnostic.
661pub fn warn(&mut self, msg: impl Into<DiagMessage>) -> &mut Self {
662self.sub(Sublevel::Warning, msg, MultiSpan::new());
663self
664} }665666/// Prints the span with a warning above it.
667 /// This is like [`Diag::warn()`], but it gets its own span.
668pub fn span_warn<S: Into<MultiSpan>>(
669&mut self,
670 sp: S,
671 msg: impl Into<DiagMessage>,
672 ) -> &mut Self {
673self.sub(Sublevel::Warning, msg, sp.into());
674self675 }
676677#[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,
678/// Add a help message attached to this diagnostic.
679pub fn help(&mut self, msg: impl Into<DiagMessage>) -> &mut Self {
680self.sub(Sublevel::Help, msg, MultiSpan::new());
681self
682} }683684/// This is like [`Diag::help()`], but it's only printed once.
685pub fn help_once(&mut self, msg: impl Into<DiagMessage>) -> &mut Self {
686self.sub(Sublevel::OnceHelp, msg, MultiSpan::new());
687self688 }
689690/// Add a help message attached to this diagnostic with a customizable highlighted message.
691pub fn highlighted_help(&mut self, msg: Vec<StringPart>) -> &mut Self {
692self.sub_with_highlights(Sublevel::Help, msg, MultiSpan::new());
693self694 }
695696/// Add a help message attached to this diagnostic with a customizable highlighted message.
697pub fn highlighted_span_help(
698&mut self,
699 span: impl Into<MultiSpan>,
700 msg: Vec<StringPart>,
701 ) -> &mut Self {
702self.sub_with_highlights(Sublevel::Help, msg, span.into());
703self704 }
705706#[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,
707/// Prints the span with some help above it.
708 /// This is like [`Diag::help()`], but it gets its own span.
709pub fn span_help(
710&mut self,
711 sp: impl Into<MultiSpan>,
712 msg: impl Into<DiagMessage>,
713 ) -> &mut Self {
714self.sub(Sublevel::Help, msg, sp.into());
715self
716} }717718/// Disallow attaching suggestions to this diagnostic.
719 /// Any suggestions attached e.g. with the `span_suggestion_*` methods
720 /// (before and after the call to `disable_suggestions`) will be ignored.
721pub fn disable_suggestions(&mut self) -> &mut Self {
722self.suggestions = Suggestions::Disabled;
723self724 }
725726/// Prevent new suggestions from being added to this diagnostic.
727 ///
728 /// Suggestions added before the call to `.seal_suggestions()` will be preserved
729 /// and new suggestions will be ignored.
730pub fn seal_suggestions(&mut self) -> &mut Self {
731if let Suggestions::Enabled(suggestions) = &mut self.suggestions {
732let suggestions_slice = std::mem::take(suggestions).into_boxed_slice();
733self.suggestions = Suggestions::Sealed(suggestions_slice);
734 }
735self736 }
737738/// Helper for pushing to `self.suggestions`.
739 ///
740 /// A new suggestion is added if suggestions are enabled for this diagnostic.
741 /// Otherwise, they are ignored.
742fn push_suggestion(&mut self, suggestion: CodeSuggestion) {
743for subst in &suggestion.substitutions {
744for part in &subst.parts {
745let span = part.span;
746let call_site = span.ctxt().outer_expn_data().call_site;
747if span.in_derive_expansion() && span.overlaps_or_adjacent(call_site) {
748// Ignore if spans is from derive macro.
749return;
750 }
751 }
752 }
753754if let Suggestions::Enabled(suggestions) = &mut self.suggestions {
755suggestions.push(suggestion);
756 }
757 }
758759#[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,
760/// Show a suggestion that has multiple parts to it, always as its own subdiagnostic.
761 /// In other words, multiple changes need to be applied as part of this suggestion.
762pub fn multipart_suggestion(
763&mut self,
764 msg: impl Into<DiagMessage>,
765 suggestion: Vec<(Span, String)>,
766 applicability: Applicability,
767 ) -> &mut Self {
768self.multipart_suggestion_with_style(
769 msg,
770 suggestion,
771 applicability,
772 SuggestionStyle::ShowAlways,
773 )
774 } }775776/// [`Diag::multipart_suggestion()`] but you can set the [`SuggestionStyle`].
777pub fn multipart_suggestion_with_style(
778&mut self,
779 msg: impl Into<DiagMessage>,
780mut suggestion: Vec<(Span, String)>,
781 applicability: Applicability,
782 style: SuggestionStyle,
783 ) -> &mut Self {
784let mut seen = crate::FxHashSet::default();
785suggestion.retain(|(span, msg)| seen.insert((span.lo(), span.hi(), msg.clone())));
786787let parts = suggestion788 .into_iter()
789 .map(|(span, snippet)| SubstitutionPart { snippet, span })
790 .collect::<Vec<_>>();
791792if !!parts.is_empty() {
::core::panicking::panic("assertion failed: !parts.is_empty()")
};assert!(!parts.is_empty());
793if 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!(
794 parts.iter().find(|part| part.span.is_empty() && part.snippet.is_empty()),
795None,
796"Span must not be empty and have no suggestion",
797 );
798if 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!(
799 parts.array_windows().find(|[a, b]| a.span.overlaps(b.span)),
800None,
801"suggestion must not have overlapping parts",
802 );
803804self.push_suggestion(CodeSuggestion {
805 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 }],
806 msg: msg.into(),
807style,
808applicability,
809 });
810self811 }
812813/// Prints out a message with for a multipart suggestion without showing the suggested code.
814 ///
815 /// This is intended to be used for suggestions that are obvious in what the changes need to
816 /// be from the message, showing the span label inline would be visually unpleasant
817 /// (marginally overlapping spans or multiline spans) and showing the snippet window wouldn't
818 /// improve understandability.
819pub fn tool_only_multipart_suggestion(
820&mut self,
821 msg: impl Into<DiagMessage>,
822 suggestion: Vec<(Span, String)>,
823 applicability: Applicability,
824 ) -> &mut Self {
825self.multipart_suggestion_with_style(
826msg,
827suggestion,
828applicability,
829 SuggestionStyle::CompletelyHidden,
830 )
831 }
832833#[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,
834/// Prints out a message with a suggested edit of the code.
835 ///
836 /// In case of short messages and a simple suggestion, rustc displays it as a label:
837 ///
838 /// ```text
839 /// try adding parentheses: `(tup.0).1`
840 /// ```
841 ///
842 /// The message
843 ///
844 /// * should not end in any punctuation (a `:` is added automatically)
845 /// * should not be a question (avoid language like "did you mean")
846 /// * should not contain any phrases like "the following", "as shown", etc.
847 /// * may look like "to do xyz, use" or "to do xyz, use abc"
848 /// * may contain a name of a function, variable, or type, but not whole expressions
849 ///
850 /// See [`CodeSuggestion`] for more information.
851pub fn span_suggestion(
852&mut self,
853 sp: Span,
854 msg: impl Into<DiagMessage>,
855 suggestion: impl ToString,
856 applicability: Applicability,
857 ) -> &mut Self {
858self.span_suggestion_with_style(
859 sp,
860 msg,
861 suggestion,
862 applicability,
863 SuggestionStyle::ShowCode,
864 );
865self
866} }867868#[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,
869/// [`Diag::span_suggestion()`] but you can set the [`SuggestionStyle`].
870pub fn span_suggestion_with_style(
871&mut self,
872 sp: Span,
873 msg: impl Into<DiagMessage>,
874 suggestion: impl ToString,
875 applicability: Applicability,
876 style: SuggestionStyle,
877 ) -> &mut Self {
878debug_assert!(
879 !(sp.is_empty() && suggestion.to_string().is_empty()),
880"Span must not be empty and have no suggestion"
881);
882self.push_suggestion(CodeSuggestion {
883 substitutions: vec![Substitution {
884 parts: vec![SubstitutionPart { snippet: suggestion.to_string(), span: sp }],
885 }],
886 msg: msg.into(),
887 style,
888 applicability,
889 });
890self
891} }892893#[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,
894/// Always show the suggested change.
895pub fn span_suggestion_verbose(
896&mut self,
897 sp: Span,
898 msg: impl Into<DiagMessage>,
899 suggestion: impl ToString,
900 applicability: Applicability,
901 ) -> &mut Self {
902self.span_suggestion_with_style(
903 sp,
904 msg,
905 suggestion,
906 applicability,
907 SuggestionStyle::ShowAlways,
908 );
909self
910} }911912#[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,
913/// Prints out a message with multiple suggested edits of the code.
914 /// See also [`Diag::span_suggestion()`].
915pub fn span_suggestions(
916&mut self,
917 sp: Span,
918 msg: impl Into<DiagMessage>,
919 suggestions: impl IntoIterator<Item = String>,
920 applicability: Applicability,
921 ) -> &mut Self {
922self.span_suggestions_with_style(
923 sp,
924 msg,
925 suggestions,
926 applicability,
927 SuggestionStyle::ShowAlways,
928 )
929 } }930931pub fn span_suggestions_with_style(
932&mut self,
933 sp: Span,
934 msg: impl Into<DiagMessage>,
935 suggestions: impl IntoIterator<Item = String>,
936 applicability: Applicability,
937 style: SuggestionStyle,
938 ) -> &mut Self {
939let substitutions = suggestions940 .into_iter()
941 .map(|snippet| {
942if 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!(
943 !(sp.is_empty() && snippet.is_empty()),
944"Span `{sp:?}` must not be empty and have no suggestion"
945);
946Substitution { 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 }] }
947 })
948 .collect();
949self.push_suggestion(CodeSuggestion {
950substitutions,
951 msg: msg.into(),
952style,
953applicability,
954 });
955self956 }
957958/// Prints out a message with multiple suggested edits of the code, where each edit consists of
959 /// multiple parts.
960 /// See also [`Diag::multipart_suggestion()`].
961pub fn multipart_suggestions(
962&mut self,
963 msg: impl Into<DiagMessage>,
964 suggestions: impl IntoIterator<Item = Vec<(Span, String)>>,
965 applicability: Applicability,
966 ) -> &mut Self {
967let substitutions = suggestions968 .into_iter()
969 .map(|sugg| {
970let mut parts = sugg971 .into_iter()
972 .map(|(span, snippet)| SubstitutionPart { snippet, span })
973 .collect::<Vec<_>>();
974975parts.sort_unstable_by_key(|part| part.span);
976977if !!parts.is_empty() {
::core::panicking::panic("assertion failed: !parts.is_empty()")
};assert!(!parts.is_empty());
978if 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!(
979 parts.iter().find(|part| part.span.is_empty() && part.snippet.is_empty()),
980None,
981"Span must not be empty and have no suggestion",
982 );
983if 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!(
984 parts.array_windows().find(|[a, b]| a.span.overlaps(b.span)),
985None,
986"suggestion must not have overlapping parts",
987 );
988989Substitution { parts }
990 })
991 .collect();
992993self.push_suggestion(CodeSuggestion {
994substitutions,
995 msg: msg.into(),
996 style: SuggestionStyle::ShowAlways,
997applicability,
998 });
999self1000 }
10011002#[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,
1003/// Prints out a message with a suggested edit of the code. If the suggestion is presented
1004 /// inline, it will only show the message and not the suggestion.
1005 ///
1006 /// See [`CodeSuggestion`] for more information.
1007pub fn span_suggestion_short(
1008&mut self,
1009 sp: Span,
1010 msg: impl Into<DiagMessage>,
1011 suggestion: impl ToString,
1012 applicability: Applicability,
1013 ) -> &mut Self {
1014self.span_suggestion_with_style(
1015 sp,
1016 msg,
1017 suggestion,
1018 applicability,
1019 SuggestionStyle::HideCodeInline,
1020 );
1021self
1022} }10231024/// Prints out a message for a suggestion without showing the suggested code.
1025 ///
1026 /// This is intended to be used for suggestions that are obvious in what the changes need to
1027 /// be from the message, showing the span label inline would be visually unpleasant
1028 /// (marginally overlapping spans or multiline spans) and showing the snippet window wouldn't
1029 /// improve understandability.
1030pub fn span_suggestion_hidden(
1031&mut self,
1032 sp: Span,
1033 msg: impl Into<DiagMessage>,
1034 suggestion: impl ToString,
1035 applicability: Applicability,
1036 ) -> &mut Self {
1037self.span_suggestion_with_style(
1038sp,
1039msg,
1040suggestion,
1041applicability,
1042 SuggestionStyle::HideCodeAlways,
1043 );
1044self1045 }
10461047#[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,
1048/// Adds a suggestion to the JSON output that will not be shown in the CLI.
1049 ///
1050 /// This is intended to be used for suggestions that are *very* obvious in what the changes
1051 /// need to be from the message, but we still want other tools to be able to apply them.
1052pub fn tool_only_span_suggestion(
1053&mut self,
1054 sp: Span,
1055 msg: impl Into<DiagMessage>,
1056 suggestion: impl ToString,
1057 applicability: Applicability,
1058 ) -> &mut Self {
1059self.span_suggestion_with_style(
1060 sp,
1061 msg,
1062 suggestion,
1063 applicability,
1064 SuggestionStyle::CompletelyHidden,
1065 );
1066self
1067} }10681069/// Add a subdiagnostic from a type that implements `Subdiagnostic` (see
1070 /// [rustc_macros::Subdiagnostic]). Performs eager formatting of any messages
1071 /// used in the subdiagnostic, so suitable for use with repeated messages (i.e. re-use of
1072 /// interpolated variables).
1073pub fn subdiagnostic(&mut self, subdiagnostic: impl Subdiagnostic) -> &mut Self {
1074subdiagnostic.add_to_diag(self);
1075self1076 }
10771078#[doc = r" Add a span."]
#[doc = "See [`Diag::span()`]."]
pub fn span(&mut self, sp: impl Into<MultiSpan>) -> &mut Self {
self.span = sp.into();
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,
1079/// Add a span.
1080pub fn span(&mut self, sp: impl Into<MultiSpan>) -> &mut Self {
1081self.span = sp.into();
1082self
1083} }10841085pub fn is_lint(
1086&mut self,
1087 name: String,
1088 has_future_breakage: bool,
1089 rust_version: Option<RustcVersion>,
1090 ) -> &mut Self {
1091self.is_lint = Some(IsLint { name, has_future_breakage, rust_version });
1092self1093 }
10941095#[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,
1096/// Add an error code.
1097pub fn code(&mut self, code: ErrCode) -> &mut Self {
1098self.code = Some(code);
1099self
1100} }11011102#[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,
1103/// Add an argument.
1104pub fn lint_id(
1105&mut self,
1106 id: LintExpectationId,
1107 ) -> &mut Self {
1108self.lint_id = Some(id);
1109self
1110} }11111112#[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,
1113/// Add a primary message.
1114pub fn primary_message(&mut self, msg: impl Into<DiagMessage>) -> &mut Self {
1115self.messages[0] = (msg.into(), Style::NoStyle);
1116self
1117} }11181119#[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,
1120/// Add an argument.
1121pub fn arg(
1122&mut self,
1123 name: impl Into<DiagArgName>,
1124 arg: impl IntoDiagArg,
1125 ) -> &mut Self {
1126self.deref_mut().arg(name, arg);
1127self
1128} }11291130/// Convenience function for internal use, clients should use one of the
1131 /// public methods above.
1132 ///
1133 /// Used by `proc_macro_server` for implementing `server::Diagnostic`.
1134pub fn sub(&mut self, level: Sublevel, message: impl Into<DiagMessage>, span: MultiSpan) {
1135self.deref_mut().sub(level, message, span);
1136 }
11371138/// Convenience function for internal use, clients should use one of the
1139 /// public methods above.
1140fn sub_with_highlights(&mut self, level: Sublevel, messages: Vec<StringPart>, span: MultiSpan) {
1141let messages = messages.into_iter().map(|m| (m.content.into(), m.style)).collect();
1142let sub = Subdiag { level, messages, span };
1143self.children.push(sub);
1144 }
11451146/// Takes the diagnostic. For use by methods that consume the Diag: `emit`,
1147 /// `cancel`, etc. Afterwards, `drop` is the only code that will be run on
1148 /// `self`.
1149fn take_diag(&mut self) -> DiagInner {
1150if let Some(path) = &self.long_ty_path {
1151self.note(::alloc::__export::must_use({
::alloc::fmt::format(format_args!("the full name for the type has been written to \'{0}\'",
path.display()))
})format!(
1152"the full name for the type has been written to '{}'",
1153 path.display()
1154 ));
1155self.note("consider using `--verbose` to print the full type name to the console");
1156 }
1157*self.diag.take().unwrap()
1158 }
11591160/// This method allows us to access the path of the file where "long types" are written to.
1161 ///
1162 /// When calling `Diag::emit`, as part of that we will check if a `long_ty_path` has been set,
1163 /// and if it has been then we add a note mentioning the file where the "long types" were
1164 /// written to.
1165 ///
1166 /// When calling `tcx.short_string()` after a `Diag` is constructed, the preferred way of doing
1167 /// so is `tcx.short_string(ty, diag.long_ty_path())`. The diagnostic itself is the one that
1168 /// keeps the existence of a "long type" anywhere in the diagnostic, so the note telling the
1169 /// user where we wrote the file to is only printed once at most, *and* it makes it much harder
1170 /// to forget to set it.
1171 ///
1172 /// If the diagnostic hasn't been created before a "short ty string" is created, then you should
1173 /// ensure that this method is called to set it `*diag.long_ty_path() = path`.
1174 ///
1175 /// As a rule of thumb, if you see or add at least one `tcx.short_string()` call anywhere, in a
1176 /// scope, `diag.long_ty_path()` should be called once somewhere close by.
1177pub fn long_ty_path(&mut self) -> &mut Option<PathBuf> {
1178&mut self.long_ty_path
1179 }
11801181pub fn with_long_ty_path(mut self, long_ty_path: Option<PathBuf>) -> Self {
1182self.long_ty_path = long_ty_path;
1183self1184 }
11851186/// Emit the diagnostic. Will also abort appropriately if the level is `Bug` or `Fatal`.
1187#[track_caller]
1188pub fn emit(mut self) {
1189let level = self.level; // get level before taking the inner diag
1190let diag = self.take_diag();
1191self.dcx.emit_diagnostic(diag);
11921193match level {
1194 Level::Bug => panic::panic_any(ExplicitBug),
1195 Level::Fatal => crate::FatalError.raise(),
1196_ => {}
1197 }
1198 }
11991200/// Use this on a `Bug` diagnostic if you need the `!` return type. Otherwise `emit` suffices.
1201 /// Aborts if used on a non-`Bug` diagnostic.
1202#[track_caller]
1203pub fn emit_bug(self) -> ! {
1204{
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);
1205self.emit();
1206::core::panicking::panic("internal error: entered unreachable code");unreachable!(); // `emit` will have aborted
1207}
12081209/// Use this on a `Fatal` diagnostic if you need the `!` return type. Otherwise `emit`
1210 /// suffices. Aborts if used on a non-`Fatal` diagnostic.
1211#[track_caller]
1212pub fn emit_fatal(self) -> ! {
1213{
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);
1214self.emit();
1215::core::panicking::panic("internal error: entered unreachable code");unreachable!(); // `emit` will have aborted
1216}
12171218/// Use this on an `Error`/`DelayedBug` diagnostic if you need the `ErrorGuaranteed` return
1219 /// type. Otherwise `emit` suffices. Aborts if used on a non-`Error`/`DelayedBug` diagnostic.
1220#[track_caller]
1221pub fn emit_err(mut self) -> ErrorGuaranteed {
1222let diag = self.take_diag();
12231224// The only error levels that should reach here are `Error` and `DelayedBug`.
1225 // (Also, even though `level` isn't `pub`, the whole `DiagInner` could
1226 // be overwritten with a new one thanks to `DerefMut`. So this assert
1227 // protects against that, too.)
1228if !#[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!(
1229matches!(diag.level, Level::Error | Level::DelayedBug),
1230"invalid diagnostic level ({:?})",
1231 diag.level,
1232 );
12331234let guar = self.dcx.emit_diagnostic(diag);
1235guar.unwrap()
1236 }
12371238/// Emit the diagnostic unless `delay` is true,
1239 /// in which case the emission will be delayed as a bug.
1240 ///
1241 /// See `emit` and `delay_as_bug` for details.
1242#[track_caller]
1243pub fn emit_err_unless_delay(mut self, delay: bool) -> ErrorGuaranteed {
1244if delay {
1245self.downgrade_to_delayed_bug();
1246 }
1247self.emit_err()
1248 }
12491250/// Cancel and consume the diagnostic. (A diagnostic must either be emitted or
1251 /// cancelled or it will panic when dropped).
1252pub fn cancel(mut self) {
1253self.diag = None;
1254drop(self);
1255 }
12561257/// Cancels this diagnostic and returns its first message, if it exists.
1258pub fn cancel_into_message(self) -> Option<String> {
1259let s = self.diag.as_ref()?.messages.get(0)?.0.as_str().map(ToString::to_string);
1260self.cancel();
1261s1262 }
12631264/// See `DiagCtxtHandle::stash_diagnostic` for details.
1265pub fn stash(mut self, span: Span, key: StashKey) -> Option<ErrorGuaranteed> {
1266let diag = self.take_diag();
1267self.dcx.stash_diagnostic(span, key, diag)
1268 }
12691270/// Delay emission of this diagnostic as a bug.
1271 ///
1272 /// This can be useful in contexts where an error indicates a bug but
1273 /// typically this only happens when other compilation errors have already
1274 /// happened. In those cases this can be used to defer emission of this
1275 /// diagnostic as a bug in the compiler only if no other errors have been
1276 /// emitted.
1277 ///
1278 /// In the meantime, though, callsites are required to deal with the "bug"
1279 /// locally in whichever way makes the most sense.
1280#[track_caller]
1281pub fn delay_as_bug(mut self) -> ErrorGuaranteed {
1282self.downgrade_to_delayed_bug();
1283self.emit_err()
1284 }
1285}
12861287/// Destructor bomb: every `Diag` must be consumed (emitted, cancelled, etc.)
1288/// or we emit a bug.
1289impl Dropfor Diag<'_> {
1290fn drop(&mut self) {
1291match self.diag.take() {
1292Some(diag) if !panicking() => {
1293self.dcx.emit_diagnostic(DiagInner::new(
1294 Level::Bug,
1295DiagMessage::from("the following error was constructed but not emitted"),
1296 ));
1297self.dcx.emit_diagnostic(*diag);
1298{
::core::panicking::panic_fmt(format_args!("error was constructed but not emitted"));
};panic!("error was constructed but not emitted");
1299 }
1300_ => {}
1301 }
1302 }
1303}
13041305#[macro_export]
1306macro_rules!struct_span_code_err {
1307 ($dcx:expr, $span:expr, $code:expr, $($message:tt)*) => ({
1308$dcx.struct_span_err($span, format!($($message)*)).with_code($code)
1309 })
1310}