rustc_errors/
diagnostic.rs

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;
9
10use rustc_data_structures::fx::FxIndexMap;
11use rustc_error_messages::{FluentValue, fluent_value_from_str_list_sep_by_and};
12use rustc_lint_defs::{Applicability, LintExpectationId};
13use rustc_macros::{Decodable, Encodable};
14use rustc_span::source_map::Spanned;
15use rustc_span::{DUMMY_SP, Span, Symbol};
16use tracing::debug;
17
18use crate::snippet::Style;
19use crate::{
20    CodeSuggestion, DiagCtxtHandle, DiagMessage, ErrCode, ErrorGuaranteed, ExplicitBug, Level,
21    MultiSpan, StashKey, SubdiagMessage, Substitution, SubstitutionPart, SuggestionStyle,
22    Suggestions,
23};
24
25/// Simplified version of `FluentArg` that can implement `Encodable` and `Decodable`. Collection of
26/// `DiagArg` are converted to `FluentArgs` (consuming the collection) at the start of diagnostic
27/// emission.
28pub type DiagArg<'iter> = (&'iter DiagArgName, &'iter DiagArgValue);
29
30/// Name of a diagnostic argument.
31pub type DiagArgName = Cow<'static, str>;
32
33/// Simplified version of `FluentValue` that can implement `Encodable` and `Decodable`. Converted
34/// to a `FluentValue` by the emitter to be used in diagnostic translation.
35#[derive(Clone, Debug, PartialEq, Eq, Hash, Encodable, Decodable)]
36pub enum DiagArgValue {
37    Str(Cow<'static, str>),
38    // This gets converted to a `FluentNumber`, which is an `f64`. An `i32`
39    // safely fits in an `f64`. Any integers bigger than that will be converted
40    // to strings in `into_diag_arg` and stored using the `Str` variant.
41    Number(i32),
42    StrListSepByAnd(Vec<Cow<'static, str>>),
43}
44
45pub type DiagArgMap = FxIndexMap<DiagArgName, DiagArgValue>;
46
47/// Trait for types that `Diag::emit` can return as a "guarantee" (or "proof")
48/// token that the emission happened.
49pub trait EmissionGuarantee: Sized {
50    /// This exists so that bugs and fatal errors can both result in `!` (an
51    /// abort) when emitted, but have different aborting behaviour.
52    type EmitResult = Self;
53
54    /// Implementation of `Diag::emit`, fully controlled by each `impl` of
55    /// `EmissionGuarantee`, to make it impossible to create a value of
56    /// `Self::EmitResult` without actually performing the emission.
57    #[track_caller]
58    fn emit_producing_guarantee(diag: Diag<'_, Self>) -> Self::EmitResult;
59}
60
61impl EmissionGuarantee for ErrorGuaranteed {
62    fn emit_producing_guarantee(diag: Diag<'_, Self>) -> Self::EmitResult {
63        diag.emit_producing_error_guaranteed()
64    }
65}
66
67impl EmissionGuarantee for () {
68    fn emit_producing_guarantee(diag: Diag<'_, Self>) -> Self::EmitResult {
69        diag.emit_producing_nothing();
70    }
71}
72
73/// Marker type which enables implementation of `create_bug` and `emit_bug` functions for
74/// bug diagnostics.
75#[derive(Copy, Clone)]
76pub struct BugAbort;
77
78impl EmissionGuarantee for BugAbort {
79    type EmitResult = !;
80
81    fn emit_producing_guarantee(diag: Diag<'_, Self>) -> Self::EmitResult {
82        diag.emit_producing_nothing();
83        panic::panic_any(ExplicitBug);
84    }
85}
86
87/// Marker type which enables implementation of `create_fatal` and `emit_fatal` functions for
88/// fatal diagnostics.
89#[derive(Copy, Clone)]
90pub struct FatalAbort;
91
92impl EmissionGuarantee for FatalAbort {
93    type EmitResult = !;
94
95    fn emit_producing_guarantee(diag: Diag<'_, Self>) -> Self::EmitResult {
96        diag.emit_producing_nothing();
97        crate::FatalError.raise()
98    }
99}
100
101impl EmissionGuarantee for rustc_span::fatal_error::FatalError {
102    fn emit_producing_guarantee(diag: Diag<'_, Self>) -> Self::EmitResult {
103        diag.emit_producing_nothing();
104        rustc_span::fatal_error::FatalError
105    }
106}
107
108/// Trait implemented by error types. This is rarely implemented manually. Instead, use
109/// `#[derive(Diagnostic)]` -- see [rustc_macros::Diagnostic].
110///
111/// When implemented manually, it should be generic over the emission
112/// guarantee, i.e.:
113/// ```ignore (fragment)
114/// impl<'a, G: EmissionGuarantee> Diagnostic<'a, G> for Foo { ... }
115/// ```
116/// rather than being specific:
117/// ```ignore (fragment)
118/// impl<'a> Diagnostic<'a> for Bar { ... }  // the default type param is `ErrorGuaranteed`
119/// impl<'a> Diagnostic<'a, ()> for Baz { ... }
120/// ```
121/// There are two reasons for this.
122/// - A diagnostic like `Foo` *could* be emitted at any level -- `level` is
123///   passed in to `into_diag` from outside. Even if in practice it is
124///   always emitted at a single level, we let the diagnostic creation/emission
125///   site determine the level (by using `create_err`, `emit_warn`, etc.)
126///   rather than the `Diagnostic` impl.
127/// - Derived impls are always generic, and it's good for the hand-written
128///   impls to be consistent with them.
129#[rustc_diagnostic_item = "Diagnostic"]
130pub trait Diagnostic<'a, G: EmissionGuarantee = ErrorGuaranteed> {
131    /// Write out as a diagnostic out of `DiagCtxt`.
132    #[must_use]
133    fn into_diag(self, dcx: DiagCtxtHandle<'a>, level: Level) -> Diag<'a, G>;
134}
135
136impl<'a, T, G> Diagnostic<'a, G> for Spanned<T>
137where
138    T: Diagnostic<'a, G>,
139    G: EmissionGuarantee,
140{
141    fn into_diag(self, dcx: DiagCtxtHandle<'a>, level: Level) -> Diag<'a, G> {
142        self.node.into_diag(dcx, level).with_span(self.span)
143    }
144}
145
146/// Converts a value of a type into a `DiagArg` (typically a field of an `Diag` struct).
147/// Implemented as a custom trait rather than `From` so that it is implemented on the type being
148/// converted rather than on `DiagArgValue`, which enables types from other `rustc_*` crates to
149/// implement this.
150pub trait IntoDiagArg {
151    /// Convert `Self` into a `DiagArgValue` suitable for rendering in a diagnostic.
152    ///
153    /// It takes a `path` where "long values" could be written to, if the `DiagArgValue` is too big
154    /// for displaying on the terminal. This path comes from the `Diag` itself. When rendering
155    /// values that come from `TyCtxt`, like `Ty<'_>`, they can use `TyCtxt::short_string`. If a
156    /// value has no shortening logic that could be used, the argument can be safely ignored.
157    fn into_diag_arg(self, path: &mut Option<std::path::PathBuf>) -> DiagArgValue;
158}
159
160impl IntoDiagArg for DiagArgValue {
161    fn into_diag_arg(self, _: &mut Option<std::path::PathBuf>) -> DiagArgValue {
162        self
163    }
164}
165
166impl From<DiagArgValue> for FluentValue<'static> {
167    fn from(val: DiagArgValue) -> Self {
168        match val {
169            DiagArgValue::Str(s) => From::from(s),
170            DiagArgValue::Number(n) => From::from(n),
171            DiagArgValue::StrListSepByAnd(l) => fluent_value_from_str_list_sep_by_and(l),
172        }
173    }
174}
175
176/// Trait implemented by error types. This should not be implemented manually. Instead, use
177/// `#[derive(Subdiagnostic)]` -- see [rustc_macros::Subdiagnostic].
178#[rustc_diagnostic_item = "Subdiagnostic"]
179pub trait Subdiagnostic
180where
181    Self: Sized,
182{
183    /// Add a subdiagnostic to an existing diagnostic.
184    fn add_to_diag<G: EmissionGuarantee>(self, diag: &mut Diag<'_, G>);
185}
186
187/// Trait implemented by lint types. This should not be implemented manually. Instead, use
188/// `#[derive(LintDiagnostic)]` -- see [rustc_macros::LintDiagnostic].
189#[rustc_diagnostic_item = "LintDiagnostic"]
190pub trait LintDiagnostic<'a, G: EmissionGuarantee> {
191    /// Decorate and emit a lint.
192    fn decorate_lint<'b>(self, diag: &'b mut Diag<'a, G>);
193}
194
195#[derive(Clone, Debug, Encodable, Decodable)]
196pub(crate) struct DiagLocation {
197    file: Cow<'static, str>,
198    line: u32,
199    col: u32,
200}
201
202impl DiagLocation {
203    #[track_caller]
204    fn caller() -> Self {
205        let loc = panic::Location::caller();
206        DiagLocation { file: loc.file().into(), line: loc.line(), col: loc.column() }
207    }
208}
209
210impl fmt::Display for DiagLocation {
211    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
212        write!(f, "{}:{}:{}", self.file, self.line, self.col)
213    }
214}
215
216#[derive(Clone, Debug, PartialEq, Eq, Hash, Encodable, Decodable)]
217pub struct IsLint {
218    /// The lint name.
219    pub(crate) name: String,
220    /// Indicates whether this lint should show up in cargo's future breakage report.
221    has_future_breakage: bool,
222}
223
224#[derive(Debug, PartialEq, Eq)]
225pub struct DiagStyledString(pub Vec<StringPart>);
226
227impl DiagStyledString {
228    pub fn new() -> DiagStyledString {
229        DiagStyledString(vec![])
230    }
231    pub fn push_normal<S: Into<String>>(&mut self, t: S) {
232        self.0.push(StringPart::normal(t));
233    }
234    pub fn push_highlighted<S: Into<String>>(&mut self, t: S) {
235        self.0.push(StringPart::highlighted(t));
236    }
237    pub fn push<S: Into<String>>(&mut self, t: S, highlight: bool) {
238        if highlight {
239            self.push_highlighted(t);
240        } else {
241            self.push_normal(t);
242        }
243    }
244    pub fn normal<S: Into<String>>(t: S) -> DiagStyledString {
245        DiagStyledString(vec![StringPart::normal(t)])
246    }
247
248    pub fn highlighted<S: Into<String>>(t: S) -> DiagStyledString {
249        DiagStyledString(vec![StringPart::highlighted(t)])
250    }
251
252    pub fn content(&self) -> String {
253        self.0.iter().map(|x| x.content.as_str()).collect::<String>()
254    }
255}
256
257#[derive(Debug, PartialEq, Eq)]
258pub struct StringPart {
259    content: String,
260    style: Style,
261}
262
263impl StringPart {
264    pub fn normal<S: Into<String>>(content: S) -> StringPart {
265        StringPart { content: content.into(), style: Style::NoStyle }
266    }
267
268    pub fn highlighted<S: Into<String>>(content: S) -> StringPart {
269        StringPart { content: content.into(), style: Style::Highlight }
270    }
271}
272
273/// The main part of a diagnostic. Note that `Diag`, which wraps this type, is
274/// used for most operations, and should be used instead whenever possible.
275/// This type should only be used when `Diag`'s lifetime causes difficulties,
276/// e.g. when storing diagnostics within `DiagCtxt`.
277#[must_use]
278#[derive(Clone, Debug, Encodable, Decodable)]
279pub struct DiagInner {
280    // NOTE(eddyb) this is private to disallow arbitrary after-the-fact changes,
281    // outside of what methods in this crate themselves allow.
282    pub(crate) level: Level,
283
284    pub messages: Vec<(DiagMessage, Style)>,
285    pub code: Option<ErrCode>,
286    pub lint_id: Option<LintExpectationId>,
287    pub span: MultiSpan,
288    pub children: Vec<Subdiag>,
289    pub suggestions: Suggestions,
290    pub args: DiagArgMap,
291
292    // This is used to store args and restore them after a subdiagnostic is rendered.
293    pub reserved_args: DiagArgMap,
294
295    /// This is not used for highlighting or rendering any error message. Rather, it can be used
296    /// as a sort key to sort a buffer of diagnostics. By default, it is the primary span of
297    /// `span` if there is one. Otherwise, it is `DUMMY_SP`.
298    pub sort_span: Span,
299
300    pub is_lint: Option<IsLint>,
301
302    pub long_ty_path: Option<PathBuf>,
303    /// With `-Ztrack_diagnostics` enabled,
304    /// we print where in rustc this error was emitted.
305    pub(crate) emitted_at: DiagLocation,
306}
307
308impl DiagInner {
309    #[track_caller]
310    pub fn new<M: Into<DiagMessage>>(level: Level, message: M) -> Self {
311        DiagInner::new_with_messages(level, vec![(message.into(), Style::NoStyle)])
312    }
313
314    #[track_caller]
315    pub fn new_with_messages(level: Level, messages: Vec<(DiagMessage, Style)>) -> Self {
316        DiagInner {
317            level,
318            lint_id: None,
319            messages,
320            code: None,
321            span: MultiSpan::new(),
322            children: vec![],
323            suggestions: Suggestions::Enabled(vec![]),
324            args: Default::default(),
325            reserved_args: Default::default(),
326            sort_span: DUMMY_SP,
327            is_lint: None,
328            long_ty_path: None,
329            emitted_at: DiagLocation::caller(),
330        }
331    }
332
333    #[inline(always)]
334    pub fn level(&self) -> Level {
335        self.level
336    }
337
338    pub fn is_error(&self) -> bool {
339        match self.level {
340            Level::Bug | Level::Fatal | Level::Error | Level::DelayedBug => true,
341
342            Level::ForceWarning
343            | Level::Warning
344            | Level::Note
345            | Level::OnceNote
346            | Level::Help
347            | Level::OnceHelp
348            | Level::FailureNote
349            | Level::Allow
350            | Level::Expect => false,
351        }
352    }
353
354    /// Indicates whether this diagnostic should show up in cargo's future breakage report.
355    pub(crate) fn has_future_breakage(&self) -> bool {
356        matches!(self.is_lint, Some(IsLint { has_future_breakage: true, .. }))
357    }
358
359    pub(crate) fn is_force_warn(&self) -> bool {
360        match self.level {
361            Level::ForceWarning => {
362                assert!(self.is_lint.is_some());
363                true
364            }
365            _ => false,
366        }
367    }
368
369    // See comment on `Diag::subdiagnostic_message_to_diagnostic_message`.
370    pub(crate) fn subdiagnostic_message_to_diagnostic_message(
371        &self,
372        attr: impl Into<SubdiagMessage>,
373    ) -> DiagMessage {
374        let msg =
375            self.messages.iter().map(|(msg, _)| msg).next().expect("diagnostic with no messages");
376        msg.with_subdiagnostic_message(attr.into())
377    }
378
379    pub(crate) fn sub(
380        &mut self,
381        level: Level,
382        message: impl Into<SubdiagMessage>,
383        span: MultiSpan,
384    ) {
385        let sub = Subdiag {
386            level,
387            messages: vec![(
388                self.subdiagnostic_message_to_diagnostic_message(message),
389                Style::NoStyle,
390            )],
391            span,
392        };
393        self.children.push(sub);
394    }
395
396    pub(crate) fn arg(&mut self, name: impl Into<DiagArgName>, arg: impl IntoDiagArg) {
397        let name = name.into();
398        let value = arg.into_diag_arg(&mut self.long_ty_path);
399        // This assertion is to avoid subdiagnostics overwriting an existing diagnostic arg.
400        debug_assert!(
401            !self.args.contains_key(&name) || self.args.get(&name) == Some(&value),
402            "arg {} already exists",
403            name
404        );
405        self.args.insert(name, value);
406    }
407
408    pub fn remove_arg(&mut self, name: &str) {
409        self.args.swap_remove(name);
410    }
411
412    pub fn store_args(&mut self) {
413        self.reserved_args = self.args.clone();
414    }
415
416    pub fn restore_args(&mut self) {
417        self.args = std::mem::take(&mut self.reserved_args);
418    }
419
420    pub fn emitted_at_sub_diag(&self) -> Subdiag {
421        let track = format!("-Ztrack-diagnostics: created at {}", self.emitted_at);
422        Subdiag {
423            level: crate::Level::Note,
424            messages: vec![(DiagMessage::Str(Cow::Owned(track)), Style::NoStyle)],
425            span: MultiSpan::new(),
426        }
427    }
428
429    /// Fields used for Hash, and PartialEq trait.
430    fn keys(
431        &self,
432    ) -> (
433        &Level,
434        &[(DiagMessage, Style)],
435        &Option<ErrCode>,
436        &MultiSpan,
437        &[Subdiag],
438        &Suggestions,
439        Vec<(&DiagArgName, &DiagArgValue)>,
440        &Option<IsLint>,
441    ) {
442        (
443            &self.level,
444            &self.messages,
445            &self.code,
446            &self.span,
447            &self.children,
448            &self.suggestions,
449            self.args.iter().collect(),
450            // omit self.sort_span
451            &self.is_lint,
452            // omit self.emitted_at
453        )
454    }
455}
456
457impl Hash for DiagInner {
458    fn hash<H>(&self, state: &mut H)
459    where
460        H: Hasher,
461    {
462        self.keys().hash(state);
463    }
464}
465
466impl PartialEq for DiagInner {
467    fn eq(&self, other: &Self) -> bool {
468        self.keys() == other.keys()
469    }
470}
471
472/// A "sub"-diagnostic attached to a parent diagnostic.
473/// For example, a note attached to an error.
474#[derive(Clone, Debug, PartialEq, Hash, Encodable, Decodable)]
475pub struct Subdiag {
476    pub level: Level,
477    pub messages: Vec<(DiagMessage, Style)>,
478    pub span: MultiSpan,
479}
480
481/// Used for emitting structured error messages and other diagnostic information.
482/// Wraps a `DiagInner`, adding some useful things.
483/// - The `dcx` field, allowing it to (a) emit itself, and (b) do a drop check
484///   that it has been emitted or cancelled.
485/// - The `EmissionGuarantee`, which determines the type returned from `emit`.
486///
487/// Each constructed `Diag` must be consumed by a function such as `emit`,
488/// `cancel`, `delay_as_bug`, or `into_diag`. A panic occurs if a `Diag`
489/// is dropped without being consumed by one of these functions.
490///
491/// If there is some state in a downstream crate you would like to access in
492/// the methods of `Diag` here, consider extending `DiagCtxtFlags`.
493#[must_use]
494pub struct Diag<'a, G: EmissionGuarantee = ErrorGuaranteed> {
495    pub dcx: DiagCtxtHandle<'a>,
496
497    /// Why the `Option`? It is always `Some` until the `Diag` is consumed via
498    /// `emit`, `cancel`, etc. At that point it is consumed and replaced with
499    /// `None`. Then `drop` checks that it is `None`; if not, it panics because
500    /// a diagnostic was built but not used.
501    ///
502    /// Why the Box? `DiagInner` is a large type, and `Diag` is often used as a
503    /// return value, especially within the frequently-used `PResult` type. In
504    /// theory, return value optimization (RVO) should avoid unnecessary
505    /// copying. In practice, it does not (at the time of writing).
506    diag: Option<Box<DiagInner>>,
507
508    _marker: PhantomData<G>,
509}
510
511// Cloning a `Diag` is a recipe for a diagnostic being emitted twice, which
512// would be bad.
513impl<G> !Clone for Diag<'_, G> {}
514
515rustc_data_structures::static_assert_size!(Diag<'_, ()>, 3 * size_of::<usize>());
516
517impl<G: EmissionGuarantee> Deref for Diag<'_, G> {
518    type Target = DiagInner;
519
520    fn deref(&self) -> &DiagInner {
521        self.diag.as_ref().unwrap()
522    }
523}
524
525impl<G: EmissionGuarantee> DerefMut for Diag<'_, G> {
526    fn deref_mut(&mut self) -> &mut DiagInner {
527        self.diag.as_mut().unwrap()
528    }
529}
530
531impl<G: EmissionGuarantee> Debug for Diag<'_, G> {
532    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
533        self.diag.fmt(f)
534    }
535}
536
537/// `Diag` impls many `&mut self -> &mut Self` methods. Each one modifies an
538/// existing diagnostic, either in a standalone fashion, e.g.
539/// `err.code(code);`, or in a chained fashion to make multiple modifications,
540/// e.g. `err.code(code).span(span);`.
541///
542/// This macro creates an equivalent `self -> Self` method, with a `with_`
543/// prefix. This can be used in a chained fashion when making a new diagnostic,
544/// e.g. `let err = struct_err(msg).with_code(code);`, or emitting a new
545/// diagnostic, e.g. `struct_err(msg).with_code(code).emit();`.
546///
547/// Although the latter method can be used to modify an existing diagnostic,
548/// e.g. `err = err.with_code(code);`, this should be avoided because the former
549/// method gives shorter code, e.g. `err.code(code);`.
550///
551/// Note: the `with_` methods are added only when needed. If you want to use
552/// one and it's not defined, feel free to add it.
553///
554/// Note: any doc comments must be within the `with_fn!` call.
555macro_rules! with_fn {
556    {
557        $with_f:ident,
558        $(#[$attrs:meta])*
559        pub fn $f:ident(&mut $self:ident, $($name:ident: $ty:ty),* $(,)?) -> &mut Self {
560            $($body:tt)*
561        }
562    } => {
563        // The original function.
564        $(#[$attrs])*
565        #[doc = concat!("See [`Diag::", stringify!($f), "()`].")]
566        pub fn $f(&mut $self, $($name: $ty),*) -> &mut Self {
567            $($body)*
568        }
569
570        // The `with_*` variant.
571        $(#[$attrs])*
572        #[doc = concat!("See [`Diag::", stringify!($f), "()`].")]
573        pub fn $with_f(mut $self, $($name: $ty),*) -> Self {
574            $self.$f($($name),*);
575            $self
576        }
577    };
578}
579
580impl<'a, G: EmissionGuarantee> Diag<'a, G> {
581    #[rustc_lint_diagnostics]
582    #[track_caller]
583    pub fn new(dcx: DiagCtxtHandle<'a>, level: Level, message: impl Into<DiagMessage>) -> Self {
584        Self::new_diagnostic(dcx, DiagInner::new(level, message))
585    }
586
587    /// Allow moving diagnostics between different error tainting contexts
588    pub fn with_dcx(mut self, dcx: DiagCtxtHandle<'_>) -> Diag<'_, G> {
589        Diag { dcx, diag: self.diag.take(), _marker: PhantomData }
590    }
591
592    /// Creates a new `Diag` with an already constructed diagnostic.
593    #[track_caller]
594    pub(crate) fn new_diagnostic(dcx: DiagCtxtHandle<'a>, diag: DiagInner) -> Self {
595        debug!("Created new diagnostic");
596        Self { dcx, diag: Some(Box::new(diag)), _marker: PhantomData }
597    }
598
599    /// Delay emission of this diagnostic as a bug.
600    ///
601    /// This can be useful in contexts where an error indicates a bug but
602    /// typically this only happens when other compilation errors have already
603    /// happened. In those cases this can be used to defer emission of this
604    /// diagnostic as a bug in the compiler only if no other errors have been
605    /// emitted.
606    ///
607    /// In the meantime, though, callsites are required to deal with the "bug"
608    /// locally in whichever way makes the most sense.
609    #[rustc_lint_diagnostics]
610    #[track_caller]
611    pub fn downgrade_to_delayed_bug(&mut self) {
612        assert!(
613            matches!(self.level, Level::Error | Level::DelayedBug),
614            "downgrade_to_delayed_bug: cannot downgrade {:?} to DelayedBug: not an error",
615            self.level
616        );
617        self.level = Level::DelayedBug;
618    }
619
620    with_fn! { with_span_label,
621    /// Appends a labeled span to the diagnostic.
622    ///
623    /// Labels are used to convey additional context for the diagnostic's primary span. They will
624    /// be shown together with the original diagnostic's span, *not* with spans added by
625    /// `span_note`, `span_help`, etc. Therefore, if the primary span is not displayable (because
626    /// the span is `DUMMY_SP` or the source code isn't found), labels will not be displayed
627    /// either.
628    ///
629    /// Implementation-wise, the label span is pushed onto the [`MultiSpan`] that was created when
630    /// the diagnostic was constructed. However, the label span is *not* considered a
631    /// ["primary span"][`MultiSpan`]; only the `Span` supplied when creating the diagnostic is
632    /// primary.
633    #[rustc_lint_diagnostics]
634    pub fn span_label(&mut self, span: Span, label: impl Into<SubdiagMessage>) -> &mut Self {
635        let msg = self.subdiagnostic_message_to_diagnostic_message(label);
636        self.span.push_span_label(span, msg);
637        self
638    } }
639
640    with_fn! { with_span_labels,
641    /// Labels all the given spans with the provided label.
642    /// See [`Self::span_label()`] for more information.
643    #[rustc_lint_diagnostics]
644    pub fn span_labels(&mut self, spans: impl IntoIterator<Item = Span>, label: &str) -> &mut Self {
645        for span in spans {
646            self.span_label(span, label.to_string());
647        }
648        self
649    } }
650
651    #[rustc_lint_diagnostics]
652    pub fn replace_span_with(&mut self, after: Span, keep_label: bool) -> &mut Self {
653        let before = self.span.clone();
654        self.span(after);
655        for span_label in before.span_labels() {
656            if let Some(label) = span_label.label {
657                if span_label.is_primary && keep_label {
658                    self.span.push_span_label(after, label);
659                } else {
660                    self.span.push_span_label(span_label.span, label);
661                }
662            }
663        }
664        self
665    }
666
667    #[rustc_lint_diagnostics]
668    pub fn note_expected_found(
669        &mut self,
670        expected_label: &str,
671        expected: DiagStyledString,
672        found_label: &str,
673        found: DiagStyledString,
674    ) -> &mut Self {
675        self.note_expected_found_extra(
676            expected_label,
677            expected,
678            found_label,
679            found,
680            DiagStyledString::normal(""),
681            DiagStyledString::normal(""),
682        )
683    }
684
685    #[rustc_lint_diagnostics]
686    pub fn note_expected_found_extra(
687        &mut self,
688        expected_label: &str,
689        expected: DiagStyledString,
690        found_label: &str,
691        found: DiagStyledString,
692        expected_extra: DiagStyledString,
693        found_extra: DiagStyledString,
694    ) -> &mut Self {
695        let expected_label = expected_label.to_string();
696        let expected_label = if expected_label.is_empty() {
697            "expected".to_string()
698        } else {
699            format!("expected {expected_label}")
700        };
701        let found_label = found_label.to_string();
702        let found_label = if found_label.is_empty() {
703            "found".to_string()
704        } else {
705            format!("found {found_label}")
706        };
707        let (found_padding, expected_padding) = if expected_label.len() > found_label.len() {
708            (expected_label.len() - found_label.len(), 0)
709        } else {
710            (0, found_label.len() - expected_label.len())
711        };
712        let mut msg = vec![StringPart::normal(format!(
713            "{}{} `",
714            " ".repeat(expected_padding),
715            expected_label
716        ))];
717        msg.extend(expected.0);
718        msg.push(StringPart::normal(format!("`")));
719        msg.extend(expected_extra.0);
720        msg.push(StringPart::normal(format!("\n")));
721        msg.push(StringPart::normal(format!("{}{} `", " ".repeat(found_padding), found_label)));
722        msg.extend(found.0);
723        msg.push(StringPart::normal(format!("`")));
724        msg.extend(found_extra.0);
725
726        // For now, just attach these as notes.
727        self.highlighted_note(msg);
728        self
729    }
730
731    #[rustc_lint_diagnostics]
732    pub fn note_trait_signature(&mut self, name: Symbol, signature: String) -> &mut Self {
733        self.highlighted_note(vec![
734            StringPart::normal(format!("`{name}` from trait: `")),
735            StringPart::highlighted(signature),
736            StringPart::normal("`"),
737        ]);
738        self
739    }
740
741    with_fn! { with_note,
742    /// Add a note attached to this diagnostic.
743    #[rustc_lint_diagnostics]
744    pub fn note(&mut self, msg: impl Into<SubdiagMessage>) -> &mut Self {
745        self.sub(Level::Note, msg, MultiSpan::new());
746        self
747    } }
748
749    #[rustc_lint_diagnostics]
750    pub fn highlighted_note(&mut self, msg: Vec<StringPart>) -> &mut Self {
751        self.sub_with_highlights(Level::Note, msg, MultiSpan::new());
752        self
753    }
754
755    #[rustc_lint_diagnostics]
756    pub fn highlighted_span_note(
757        &mut self,
758        span: impl Into<MultiSpan>,
759        msg: Vec<StringPart>,
760    ) -> &mut Self {
761        self.sub_with_highlights(Level::Note, msg, span.into());
762        self
763    }
764
765    /// This is like [`Diag::note()`], but it's only printed once.
766    #[rustc_lint_diagnostics]
767    pub fn note_once(&mut self, msg: impl Into<SubdiagMessage>) -> &mut Self {
768        self.sub(Level::OnceNote, msg, MultiSpan::new());
769        self
770    }
771
772    with_fn! { with_span_note,
773    /// Prints the span with a note above it.
774    /// This is like [`Diag::note()`], but it gets its own span.
775    #[rustc_lint_diagnostics]
776    pub fn span_note(
777        &mut self,
778        sp: impl Into<MultiSpan>,
779        msg: impl Into<SubdiagMessage>,
780    ) -> &mut Self {
781        self.sub(Level::Note, msg, sp.into());
782        self
783    } }
784
785    /// Prints the span with a note above it.
786    /// This is like [`Diag::note_once()`], but it gets its own span.
787    #[rustc_lint_diagnostics]
788    pub fn span_note_once<S: Into<MultiSpan>>(
789        &mut self,
790        sp: S,
791        msg: impl Into<SubdiagMessage>,
792    ) -> &mut Self {
793        self.sub(Level::OnceNote, msg, sp.into());
794        self
795    }
796
797    with_fn! { with_warn,
798    /// Add a warning attached to this diagnostic.
799    #[rustc_lint_diagnostics]
800    pub fn warn(&mut self, msg: impl Into<SubdiagMessage>) -> &mut Self {
801        self.sub(Level::Warning, msg, MultiSpan::new());
802        self
803    } }
804
805    /// Prints the span with a warning above it.
806    /// This is like [`Diag::warn()`], but it gets its own span.
807    #[rustc_lint_diagnostics]
808    pub fn span_warn<S: Into<MultiSpan>>(
809        &mut self,
810        sp: S,
811        msg: impl Into<SubdiagMessage>,
812    ) -> &mut Self {
813        self.sub(Level::Warning, msg, sp.into());
814        self
815    }
816
817    with_fn! { with_help,
818    /// Add a help message attached to this diagnostic.
819    #[rustc_lint_diagnostics]
820    pub fn help(&mut self, msg: impl Into<SubdiagMessage>) -> &mut Self {
821        self.sub(Level::Help, msg, MultiSpan::new());
822        self
823    } }
824
825    /// This is like [`Diag::help()`], but it's only printed once.
826    #[rustc_lint_diagnostics]
827    pub fn help_once(&mut self, msg: impl Into<SubdiagMessage>) -> &mut Self {
828        self.sub(Level::OnceHelp, msg, MultiSpan::new());
829        self
830    }
831
832    /// Add a help message attached to this diagnostic with a customizable highlighted message.
833    #[rustc_lint_diagnostics]
834    pub fn highlighted_help(&mut self, msg: Vec<StringPart>) -> &mut Self {
835        self.sub_with_highlights(Level::Help, msg, MultiSpan::new());
836        self
837    }
838
839    /// Add a help message attached to this diagnostic with a customizable highlighted message.
840    #[rustc_lint_diagnostics]
841    pub fn highlighted_span_help(
842        &mut self,
843        span: impl Into<MultiSpan>,
844        msg: Vec<StringPart>,
845    ) -> &mut Self {
846        self.sub_with_highlights(Level::Help, msg, span.into());
847        self
848    }
849
850    with_fn! { with_span_help,
851    /// Prints the span with some help above it.
852    /// This is like [`Diag::help()`], but it gets its own span.
853    #[rustc_lint_diagnostics]
854    pub fn span_help(
855        &mut self,
856        sp: impl Into<MultiSpan>,
857        msg: impl Into<SubdiagMessage>,
858    ) -> &mut Self {
859        self.sub(Level::Help, msg, sp.into());
860        self
861    } }
862
863    /// Disallow attaching suggestions to this diagnostic.
864    /// Any suggestions attached e.g. with the `span_suggestion_*` methods
865    /// (before and after the call to `disable_suggestions`) will be ignored.
866    #[rustc_lint_diagnostics]
867    pub fn disable_suggestions(&mut self) -> &mut Self {
868        self.suggestions = Suggestions::Disabled;
869        self
870    }
871
872    /// Prevent new suggestions from being added to this diagnostic.
873    ///
874    /// Suggestions added before the call to `.seal_suggestions()` will be preserved
875    /// and new suggestions will be ignored.
876    #[rustc_lint_diagnostics]
877    pub fn seal_suggestions(&mut self) -> &mut Self {
878        if let Suggestions::Enabled(suggestions) = &mut self.suggestions {
879            let suggestions_slice = std::mem::take(suggestions).into_boxed_slice();
880            self.suggestions = Suggestions::Sealed(suggestions_slice);
881        }
882        self
883    }
884
885    /// Helper for pushing to `self.suggestions`.
886    ///
887    /// A new suggestion is added if suggestions are enabled for this diagnostic.
888    /// Otherwise, they are ignored.
889    #[rustc_lint_diagnostics]
890    fn push_suggestion(&mut self, suggestion: CodeSuggestion) {
891        for subst in &suggestion.substitutions {
892            for part in &subst.parts {
893                let span = part.span;
894                let call_site = span.ctxt().outer_expn_data().call_site;
895                if span.in_derive_expansion() && span.overlaps_or_adjacent(call_site) {
896                    // Ignore if spans is from derive macro.
897                    return;
898                }
899            }
900        }
901
902        if let Suggestions::Enabled(suggestions) = &mut self.suggestions {
903            suggestions.push(suggestion);
904        }
905    }
906
907    with_fn! { with_multipart_suggestion,
908    /// Show a suggestion that has multiple parts to it.
909    /// In other words, multiple changes need to be applied as part of this suggestion.
910    #[rustc_lint_diagnostics]
911    pub fn multipart_suggestion(
912        &mut self,
913        msg: impl Into<SubdiagMessage>,
914        suggestion: Vec<(Span, String)>,
915        applicability: Applicability,
916    ) -> &mut Self {
917        self.multipart_suggestion_with_style(
918            msg,
919            suggestion,
920            applicability,
921            SuggestionStyle::ShowCode,
922        )
923    } }
924
925    /// Show a suggestion that has multiple parts to it, always as its own subdiagnostic.
926    /// In other words, multiple changes need to be applied as part of this suggestion.
927    #[rustc_lint_diagnostics]
928    pub fn multipart_suggestion_verbose(
929        &mut self,
930        msg: impl Into<SubdiagMessage>,
931        suggestion: Vec<(Span, String)>,
932        applicability: Applicability,
933    ) -> &mut Self {
934        self.multipart_suggestion_with_style(
935            msg,
936            suggestion,
937            applicability,
938            SuggestionStyle::ShowAlways,
939        )
940    }
941
942    /// [`Diag::multipart_suggestion()`] but you can set the [`SuggestionStyle`].
943    #[rustc_lint_diagnostics]
944    pub fn multipart_suggestion_with_style(
945        &mut self,
946        msg: impl Into<SubdiagMessage>,
947        mut suggestion: Vec<(Span, String)>,
948        applicability: Applicability,
949        style: SuggestionStyle,
950    ) -> &mut Self {
951        let mut seen = crate::FxHashSet::default();
952        suggestion.retain(|(span, msg)| seen.insert((span.lo(), span.hi(), msg.clone())));
953
954        let parts = suggestion
955            .into_iter()
956            .map(|(span, snippet)| SubstitutionPart { snippet, span })
957            .collect::<Vec<_>>();
958
959        assert!(!parts.is_empty());
960        debug_assert_eq!(
961            parts.iter().find(|part| part.span.is_empty() && part.snippet.is_empty()),
962            None,
963            "Span must not be empty and have no suggestion",
964        );
965        debug_assert_eq!(
966            parts.array_windows().find(|[a, b]| a.span.overlaps(b.span)),
967            None,
968            "suggestion must not have overlapping parts",
969        );
970
971        self.push_suggestion(CodeSuggestion {
972            substitutions: vec![Substitution { parts }],
973            msg: self.subdiagnostic_message_to_diagnostic_message(msg),
974            style,
975            applicability,
976        });
977        self
978    }
979
980    /// Prints out a message with for a multipart suggestion without showing the suggested code.
981    ///
982    /// This is intended to be used for suggestions that are obvious in what the changes need to
983    /// be from the message, showing the span label inline would be visually unpleasant
984    /// (marginally overlapping spans or multiline spans) and showing the snippet window wouldn't
985    /// improve understandability.
986    #[rustc_lint_diagnostics]
987    pub fn tool_only_multipart_suggestion(
988        &mut self,
989        msg: impl Into<SubdiagMessage>,
990        suggestion: Vec<(Span, String)>,
991        applicability: Applicability,
992    ) -> &mut Self {
993        self.multipart_suggestion_with_style(
994            msg,
995            suggestion,
996            applicability,
997            SuggestionStyle::CompletelyHidden,
998        )
999    }
1000
1001    with_fn! { with_span_suggestion,
1002    /// Prints out a message with a suggested edit of the code.
1003    ///
1004    /// In case of short messages and a simple suggestion, rustc displays it as a label:
1005    ///
1006    /// ```text
1007    /// try adding parentheses: `(tup.0).1`
1008    /// ```
1009    ///
1010    /// The message
1011    ///
1012    /// * should not end in any punctuation (a `:` is added automatically)
1013    /// * should not be a question (avoid language like "did you mean")
1014    /// * should not contain any phrases like "the following", "as shown", etc.
1015    /// * may look like "to do xyz, use" or "to do xyz, use abc"
1016    /// * may contain a name of a function, variable, or type, but not whole expressions
1017    ///
1018    /// See [`CodeSuggestion`] for more information.
1019    #[rustc_lint_diagnostics]
1020    pub fn span_suggestion(
1021        &mut self,
1022        sp: Span,
1023        msg: impl Into<SubdiagMessage>,
1024        suggestion: impl ToString,
1025        applicability: Applicability,
1026    ) -> &mut Self {
1027        self.span_suggestion_with_style(
1028            sp,
1029            msg,
1030            suggestion,
1031            applicability,
1032            SuggestionStyle::ShowCode,
1033        );
1034        self
1035    } }
1036
1037    /// [`Diag::span_suggestion()`] but you can set the [`SuggestionStyle`].
1038    #[rustc_lint_diagnostics]
1039    pub fn span_suggestion_with_style(
1040        &mut self,
1041        sp: Span,
1042        msg: impl Into<SubdiagMessage>,
1043        suggestion: impl ToString,
1044        applicability: Applicability,
1045        style: SuggestionStyle,
1046    ) -> &mut Self {
1047        debug_assert!(
1048            !(sp.is_empty() && suggestion.to_string().is_empty()),
1049            "Span must not be empty and have no suggestion"
1050        );
1051        self.push_suggestion(CodeSuggestion {
1052            substitutions: vec![Substitution {
1053                parts: vec![SubstitutionPart { snippet: suggestion.to_string(), span: sp }],
1054            }],
1055            msg: self.subdiagnostic_message_to_diagnostic_message(msg),
1056            style,
1057            applicability,
1058        });
1059        self
1060    }
1061
1062    with_fn! { with_span_suggestion_verbose,
1063    /// Always show the suggested change.
1064    #[rustc_lint_diagnostics]
1065    pub fn span_suggestion_verbose(
1066        &mut self,
1067        sp: Span,
1068        msg: impl Into<SubdiagMessage>,
1069        suggestion: impl ToString,
1070        applicability: Applicability,
1071    ) -> &mut Self {
1072        self.span_suggestion_with_style(
1073            sp,
1074            msg,
1075            suggestion,
1076            applicability,
1077            SuggestionStyle::ShowAlways,
1078        );
1079        self
1080    } }
1081
1082    with_fn! { with_span_suggestions,
1083    /// Prints out a message with multiple suggested edits of the code.
1084    /// See also [`Diag::span_suggestion()`].
1085    #[rustc_lint_diagnostics]
1086    pub fn span_suggestions(
1087        &mut self,
1088        sp: Span,
1089        msg: impl Into<SubdiagMessage>,
1090        suggestions: impl IntoIterator<Item = String>,
1091        applicability: Applicability,
1092    ) -> &mut Self {
1093        self.span_suggestions_with_style(
1094            sp,
1095            msg,
1096            suggestions,
1097            applicability,
1098            SuggestionStyle::ShowCode,
1099        )
1100    } }
1101
1102    #[rustc_lint_diagnostics]
1103    pub fn span_suggestions_with_style(
1104        &mut self,
1105        sp: Span,
1106        msg: impl Into<SubdiagMessage>,
1107        suggestions: impl IntoIterator<Item = String>,
1108        applicability: Applicability,
1109        style: SuggestionStyle,
1110    ) -> &mut Self {
1111        let substitutions = suggestions
1112            .into_iter()
1113            .map(|snippet| {
1114                debug_assert!(
1115                    !(sp.is_empty() && snippet.is_empty()),
1116                    "Span must not be empty and have no suggestion"
1117                );
1118                Substitution { parts: vec![SubstitutionPart { snippet, span: sp }] }
1119            })
1120            .collect();
1121        self.push_suggestion(CodeSuggestion {
1122            substitutions,
1123            msg: self.subdiagnostic_message_to_diagnostic_message(msg),
1124            style,
1125            applicability,
1126        });
1127        self
1128    }
1129
1130    /// Prints out a message with multiple suggested edits of the code, where each edit consists of
1131    /// multiple parts.
1132    /// See also [`Diag::multipart_suggestion()`].
1133    #[rustc_lint_diagnostics]
1134    pub fn multipart_suggestions(
1135        &mut self,
1136        msg: impl Into<SubdiagMessage>,
1137        suggestions: impl IntoIterator<Item = Vec<(Span, String)>>,
1138        applicability: Applicability,
1139    ) -> &mut Self {
1140        let substitutions = suggestions
1141            .into_iter()
1142            .map(|sugg| {
1143                let mut parts = sugg
1144                    .into_iter()
1145                    .map(|(span, snippet)| SubstitutionPart { snippet, span })
1146                    .collect::<Vec<_>>();
1147
1148                parts.sort_unstable_by_key(|part| part.span);
1149
1150                assert!(!parts.is_empty());
1151                debug_assert_eq!(
1152                    parts.iter().find(|part| part.span.is_empty() && part.snippet.is_empty()),
1153                    None,
1154                    "Span must not be empty and have no suggestion",
1155                );
1156                debug_assert_eq!(
1157                    parts.array_windows().find(|[a, b]| a.span.overlaps(b.span)),
1158                    None,
1159                    "suggestion must not have overlapping parts",
1160                );
1161
1162                Substitution { parts }
1163            })
1164            .collect();
1165
1166        self.push_suggestion(CodeSuggestion {
1167            substitutions,
1168            msg: self.subdiagnostic_message_to_diagnostic_message(msg),
1169            style: SuggestionStyle::ShowAlways,
1170            applicability,
1171        });
1172        self
1173    }
1174
1175    with_fn! { with_span_suggestion_short,
1176    /// Prints out a message with a suggested edit of the code. If the suggestion is presented
1177    /// inline, it will only show the message and not the suggestion.
1178    ///
1179    /// See [`CodeSuggestion`] for more information.
1180    #[rustc_lint_diagnostics]
1181    pub fn span_suggestion_short(
1182        &mut self,
1183        sp: Span,
1184        msg: impl Into<SubdiagMessage>,
1185        suggestion: impl ToString,
1186        applicability: Applicability,
1187    ) -> &mut Self {
1188        self.span_suggestion_with_style(
1189            sp,
1190            msg,
1191            suggestion,
1192            applicability,
1193            SuggestionStyle::HideCodeInline,
1194        );
1195        self
1196    } }
1197
1198    /// Prints out a message for a suggestion without showing the suggested code.
1199    ///
1200    /// This is intended to be used for suggestions that are obvious in what the changes need to
1201    /// be from the message, showing the span label inline would be visually unpleasant
1202    /// (marginally overlapping spans or multiline spans) and showing the snippet window wouldn't
1203    /// improve understandability.
1204    #[rustc_lint_diagnostics]
1205    pub fn span_suggestion_hidden(
1206        &mut self,
1207        sp: Span,
1208        msg: impl Into<SubdiagMessage>,
1209        suggestion: impl ToString,
1210        applicability: Applicability,
1211    ) -> &mut Self {
1212        self.span_suggestion_with_style(
1213            sp,
1214            msg,
1215            suggestion,
1216            applicability,
1217            SuggestionStyle::HideCodeAlways,
1218        );
1219        self
1220    }
1221
1222    with_fn! { with_tool_only_span_suggestion,
1223    /// Adds a suggestion to the JSON output that will not be shown in the CLI.
1224    ///
1225    /// This is intended to be used for suggestions that are *very* obvious in what the changes
1226    /// need to be from the message, but we still want other tools to be able to apply them.
1227    #[rustc_lint_diagnostics]
1228    pub fn tool_only_span_suggestion(
1229        &mut self,
1230        sp: Span,
1231        msg: impl Into<SubdiagMessage>,
1232        suggestion: impl ToString,
1233        applicability: Applicability,
1234    ) -> &mut Self {
1235        self.span_suggestion_with_style(
1236            sp,
1237            msg,
1238            suggestion,
1239            applicability,
1240            SuggestionStyle::CompletelyHidden,
1241        );
1242        self
1243    } }
1244
1245    /// Add a subdiagnostic from a type that implements `Subdiagnostic` (see
1246    /// [rustc_macros::Subdiagnostic]). Performs eager translation of any translatable messages
1247    /// used in the subdiagnostic, so suitable for use with repeated messages (i.e. re-use of
1248    /// interpolated variables).
1249    #[rustc_lint_diagnostics]
1250    pub fn subdiagnostic(&mut self, subdiagnostic: impl Subdiagnostic) -> &mut Self {
1251        subdiagnostic.add_to_diag(self);
1252        self
1253    }
1254
1255    /// Fluent variables are not namespaced from each other, so when
1256    /// `Diagnostic`s and `Subdiagnostic`s use the same variable name,
1257    /// one value will clobber the other. Eagerly translating the
1258    /// diagnostic uses the variables defined right then, before the
1259    /// clobbering occurs.
1260    pub fn eagerly_translate(&self, msg: impl Into<SubdiagMessage>) -> SubdiagMessage {
1261        let args = self.args.iter();
1262        let msg = self.subdiagnostic_message_to_diagnostic_message(msg.into());
1263        self.dcx.eagerly_translate(msg, args)
1264    }
1265
1266    with_fn! { with_span,
1267    /// Add a span.
1268    #[rustc_lint_diagnostics]
1269    pub fn span(&mut self, sp: impl Into<MultiSpan>) -> &mut Self {
1270        self.span = sp.into();
1271        if let Some(span) = self.span.primary_span() {
1272            self.sort_span = span;
1273        }
1274        self
1275    } }
1276
1277    #[rustc_lint_diagnostics]
1278    pub fn is_lint(&mut self, name: String, has_future_breakage: bool) -> &mut Self {
1279        self.is_lint = Some(IsLint { name, has_future_breakage });
1280        self
1281    }
1282
1283    with_fn! { with_code,
1284    /// Add an error code.
1285    #[rustc_lint_diagnostics]
1286    pub fn code(&mut self, code: ErrCode) -> &mut Self {
1287        self.code = Some(code);
1288        self
1289    } }
1290
1291    with_fn! { with_lint_id,
1292    /// Add an argument.
1293    #[rustc_lint_diagnostics]
1294    pub fn lint_id(
1295        &mut self,
1296        id: LintExpectationId,
1297    ) -> &mut Self {
1298        self.lint_id = Some(id);
1299        self
1300    } }
1301
1302    with_fn! { with_primary_message,
1303    /// Add a primary message.
1304    #[rustc_lint_diagnostics]
1305    pub fn primary_message(&mut self, msg: impl Into<DiagMessage>) -> &mut Self {
1306        self.messages[0] = (msg.into(), Style::NoStyle);
1307        self
1308    } }
1309
1310    with_fn! { with_arg,
1311    /// Add an argument.
1312    #[rustc_lint_diagnostics]
1313    pub fn arg(
1314        &mut self,
1315        name: impl Into<DiagArgName>,
1316        arg: impl IntoDiagArg,
1317    ) -> &mut Self {
1318        self.deref_mut().arg(name, arg);
1319        self
1320    } }
1321
1322    /// Helper function that takes a `SubdiagMessage` and returns a `DiagMessage` by
1323    /// combining it with the primary message of the diagnostic (if translatable, otherwise it just
1324    /// passes the user's string along).
1325    pub(crate) fn subdiagnostic_message_to_diagnostic_message(
1326        &self,
1327        attr: impl Into<SubdiagMessage>,
1328    ) -> DiagMessage {
1329        self.deref().subdiagnostic_message_to_diagnostic_message(attr)
1330    }
1331
1332    /// Convenience function for internal use, clients should use one of the
1333    /// public methods above.
1334    ///
1335    /// Used by `proc_macro_server` for implementing `server::Diagnostic`.
1336    pub fn sub(&mut self, level: Level, message: impl Into<SubdiagMessage>, span: MultiSpan) {
1337        self.deref_mut().sub(level, message, span);
1338    }
1339
1340    /// Convenience function for internal use, clients should use one of the
1341    /// public methods above.
1342    fn sub_with_highlights(&mut self, level: Level, messages: Vec<StringPart>, span: MultiSpan) {
1343        let messages = messages
1344            .into_iter()
1345            .map(|m| (self.subdiagnostic_message_to_diagnostic_message(m.content), m.style))
1346            .collect();
1347        let sub = Subdiag { level, messages, span };
1348        self.children.push(sub);
1349    }
1350
1351    /// Takes the diagnostic. For use by methods that consume the Diag: `emit`,
1352    /// `cancel`, etc. Afterwards, `drop` is the only code that will be run on
1353    /// `self`.
1354    fn take_diag(&mut self) -> DiagInner {
1355        if let Some(path) = &self.long_ty_path {
1356            self.note(format!(
1357                "the full name for the type has been written to '{}'",
1358                path.display()
1359            ));
1360            self.note("consider using `--verbose` to print the full type name to the console");
1361        }
1362        *self.diag.take().unwrap()
1363    }
1364
1365    /// This method allows us to access the path of the file where "long types" are written to.
1366    ///
1367    /// When calling `Diag::emit`, as part of that we will check if a `long_ty_path` has been set,
1368    /// and if it has been then we add a note mentioning the file where the "long types" were
1369    /// written to.
1370    ///
1371    /// When calling `tcx.short_string()` after a `Diag` is constructed, the preferred way of doing
1372    /// so is `tcx.short_string(ty, diag.long_ty_path())`. The diagnostic itself is the one that
1373    /// keeps the existence of a "long type" anywhere in the diagnostic, so the note telling the
1374    /// user where we wrote the file to is only printed once at most, *and* it makes it much harder
1375    /// to forget to set it.
1376    ///
1377    /// If the diagnostic hasn't been created before a "short ty string" is created, then you should
1378    /// ensure that this method is called to set it `*diag.long_ty_path() = path`.
1379    ///
1380    /// As a rule of thumb, if you see or add at least one `tcx.short_string()` call anywhere, in a
1381    /// scope, `diag.long_ty_path()` should be called once somewhere close by.
1382    pub fn long_ty_path(&mut self) -> &mut Option<PathBuf> {
1383        &mut self.long_ty_path
1384    }
1385
1386    pub fn with_long_ty_path(mut self, long_ty_path: Option<PathBuf>) -> Self {
1387        self.long_ty_path = long_ty_path;
1388        self
1389    }
1390
1391    /// Most `emit_producing_guarantee` functions use this as a starting point.
1392    fn emit_producing_nothing(mut self) {
1393        let diag = self.take_diag();
1394        self.dcx.emit_diagnostic(diag);
1395    }
1396
1397    /// `ErrorGuaranteed::emit_producing_guarantee` uses this.
1398    fn emit_producing_error_guaranteed(mut self) -> ErrorGuaranteed {
1399        let diag = self.take_diag();
1400
1401        // The only error levels that produce `ErrorGuaranteed` are
1402        // `Error` and `DelayedBug`. But `DelayedBug` should never occur here
1403        // because delayed bugs have their level changed to `Bug` when they are
1404        // actually printed, so they produce an ICE.
1405        //
1406        // (Also, even though `level` isn't `pub`, the whole `DiagInner` could
1407        // be overwritten with a new one thanks to `DerefMut`. So this assert
1408        // protects against that, too.)
1409        assert!(
1410            matches!(diag.level, Level::Error | Level::DelayedBug),
1411            "invalid diagnostic level ({:?})",
1412            diag.level,
1413        );
1414
1415        let guar = self.dcx.emit_diagnostic(diag);
1416        guar.unwrap()
1417    }
1418
1419    /// Emit and consume the diagnostic.
1420    #[track_caller]
1421    pub fn emit(self) -> G::EmitResult {
1422        G::emit_producing_guarantee(self)
1423    }
1424
1425    /// Emit the diagnostic unless `delay` is true,
1426    /// in which case the emission will be delayed as a bug.
1427    ///
1428    /// See `emit` and `delay_as_bug` for details.
1429    #[track_caller]
1430    pub fn emit_unless_delay(mut self, delay: bool) -> G::EmitResult {
1431        if delay {
1432            self.downgrade_to_delayed_bug();
1433        }
1434        self.emit()
1435    }
1436
1437    /// Cancel and consume the diagnostic. (A diagnostic must either be emitted or
1438    /// cancelled or it will panic when dropped).
1439    pub fn cancel(mut self) {
1440        self.diag = None;
1441        drop(self);
1442    }
1443
1444    /// See `DiagCtxt::stash_diagnostic` for details.
1445    pub fn stash(mut self, span: Span, key: StashKey) -> Option<ErrorGuaranteed> {
1446        let diag = self.take_diag();
1447        self.dcx.stash_diagnostic(span, key, diag)
1448    }
1449
1450    /// Delay emission of this diagnostic as a bug.
1451    ///
1452    /// This can be useful in contexts where an error indicates a bug but
1453    /// typically this only happens when other compilation errors have already
1454    /// happened. In those cases this can be used to defer emission of this
1455    /// diagnostic as a bug in the compiler only if no other errors have been
1456    /// emitted.
1457    ///
1458    /// In the meantime, though, callsites are required to deal with the "bug"
1459    /// locally in whichever way makes the most sense.
1460    #[track_caller]
1461    pub fn delay_as_bug(mut self) -> G::EmitResult {
1462        self.downgrade_to_delayed_bug();
1463        self.emit()
1464    }
1465
1466    pub fn remove_arg(&mut self, name: &str) {
1467        if let Some(diag) = self.diag.as_mut() {
1468            diag.remove_arg(name);
1469        }
1470    }
1471}
1472
1473/// Destructor bomb: every `Diag` must be consumed (emitted, cancelled, etc.)
1474/// or we emit a bug.
1475impl<G: EmissionGuarantee> Drop for Diag<'_, G> {
1476    fn drop(&mut self) {
1477        match self.diag.take() {
1478            Some(diag) if !panicking() => {
1479                self.dcx.emit_diagnostic(DiagInner::new(
1480                    Level::Bug,
1481                    DiagMessage::from("the following error was constructed but not emitted"),
1482                ));
1483                self.dcx.emit_diagnostic(*diag);
1484                panic!("error was constructed but not emitted");
1485            }
1486            _ => {}
1487        }
1488    }
1489}
1490
1491#[macro_export]
1492macro_rules! struct_span_code_err {
1493    ($dcx:expr, $span:expr, $code:expr, $($message:tt)*) => ({
1494        $dcx.struct_span_err($span, format!($($message)*)).with_code($code)
1495    })
1496}