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 not used for highlighting or rendering any error message. Rather, it can be used
293    /// as a sort key to sort a buffer of diagnostics. By default, it is the primary span of
294    /// `span` if there is one. Otherwise, it is `DUMMY_SP`.
295    pub sort_span: Span,
296
297    pub is_lint: Option<IsLint>,
298
299    pub long_ty_path: Option<PathBuf>,
300    /// With `-Ztrack_diagnostics` enabled,
301    /// we print where in rustc this error was emitted.
302    pub(crate) emitted_at: DiagLocation,
303}
304
305impl DiagInner {
306    #[track_caller]
307    pub fn new<M: Into<DiagMessage>>(level: Level, message: M) -> Self {
308        DiagInner::new_with_messages(level, vec![(message.into(), Style::NoStyle)])
309    }
310
311    #[track_caller]
312    pub fn new_with_messages(level: Level, messages: Vec<(DiagMessage, Style)>) -> Self {
313        DiagInner {
314            level,
315            lint_id: None,
316            messages,
317            code: None,
318            span: MultiSpan::new(),
319            children: vec![],
320            suggestions: Suggestions::Enabled(vec![]),
321            args: Default::default(),
322            sort_span: DUMMY_SP,
323            is_lint: None,
324            long_ty_path: None,
325            emitted_at: DiagLocation::caller(),
326        }
327    }
328
329    #[inline(always)]
330    pub fn level(&self) -> Level {
331        self.level
332    }
333
334    pub fn is_error(&self) -> bool {
335        match self.level {
336            Level::Bug | Level::Fatal | Level::Error | Level::DelayedBug => true,
337
338            Level::ForceWarning
339            | Level::Warning
340            | Level::Note
341            | Level::OnceNote
342            | Level::Help
343            | Level::OnceHelp
344            | Level::FailureNote
345            | Level::Allow
346            | Level::Expect => false,
347        }
348    }
349
350    /// Indicates whether this diagnostic should show up in cargo's future breakage report.
351    pub(crate) fn has_future_breakage(&self) -> bool {
352        matches!(self.is_lint, Some(IsLint { has_future_breakage: true, .. }))
353    }
354
355    pub(crate) fn is_force_warn(&self) -> bool {
356        match self.level {
357            Level::ForceWarning => {
358                assert!(self.is_lint.is_some());
359                true
360            }
361            _ => false,
362        }
363    }
364
365    // See comment on `Diag::subdiagnostic_message_to_diagnostic_message`.
366    pub(crate) fn subdiagnostic_message_to_diagnostic_message(
367        &self,
368        attr: impl Into<SubdiagMessage>,
369    ) -> DiagMessage {
370        let msg =
371            self.messages.iter().map(|(msg, _)| msg).next().expect("diagnostic with no messages");
372        msg.with_subdiagnostic_message(attr.into())
373    }
374
375    pub(crate) fn sub(
376        &mut self,
377        level: Level,
378        message: impl Into<SubdiagMessage>,
379        span: MultiSpan,
380    ) {
381        let sub = Subdiag {
382            level,
383            messages: vec![(
384                self.subdiagnostic_message_to_diagnostic_message(message),
385                Style::NoStyle,
386            )],
387            span,
388        };
389        self.children.push(sub);
390    }
391
392    pub(crate) fn arg(&mut self, name: impl Into<DiagArgName>, arg: impl IntoDiagArg) {
393        self.args.insert(name.into(), arg.into_diag_arg(&mut self.long_ty_path));
394    }
395
396    /// Fields used for Hash, and PartialEq trait.
397    fn keys(
398        &self,
399    ) -> (
400        &Level,
401        &[(DiagMessage, Style)],
402        &Option<ErrCode>,
403        &MultiSpan,
404        &[Subdiag],
405        &Suggestions,
406        Vec<(&DiagArgName, &DiagArgValue)>,
407        &Option<IsLint>,
408    ) {
409        (
410            &self.level,
411            &self.messages,
412            &self.code,
413            &self.span,
414            &self.children,
415            &self.suggestions,
416            self.args.iter().collect(),
417            // omit self.sort_span
418            &self.is_lint,
419            // omit self.emitted_at
420        )
421    }
422}
423
424impl Hash for DiagInner {
425    fn hash<H>(&self, state: &mut H)
426    where
427        H: Hasher,
428    {
429        self.keys().hash(state);
430    }
431}
432
433impl PartialEq for DiagInner {
434    fn eq(&self, other: &Self) -> bool {
435        self.keys() == other.keys()
436    }
437}
438
439/// A "sub"-diagnostic attached to a parent diagnostic.
440/// For example, a note attached to an error.
441#[derive(Clone, Debug, PartialEq, Hash, Encodable, Decodable)]
442pub struct Subdiag {
443    pub level: Level,
444    pub messages: Vec<(DiagMessage, Style)>,
445    pub span: MultiSpan,
446}
447
448/// Used for emitting structured error messages and other diagnostic information.
449/// Wraps a `DiagInner`, adding some useful things.
450/// - The `dcx` field, allowing it to (a) emit itself, and (b) do a drop check
451///   that it has been emitted or cancelled.
452/// - The `EmissionGuarantee`, which determines the type returned from `emit`.
453///
454/// Each constructed `Diag` must be consumed by a function such as `emit`,
455/// `cancel`, `delay_as_bug`, or `into_diag`. A panic occurs if a `Diag`
456/// is dropped without being consumed by one of these functions.
457///
458/// If there is some state in a downstream crate you would like to access in
459/// the methods of `Diag` here, consider extending `DiagCtxtFlags`.
460#[must_use]
461pub struct Diag<'a, G: EmissionGuarantee = ErrorGuaranteed> {
462    pub dcx: DiagCtxtHandle<'a>,
463
464    /// Why the `Option`? It is always `Some` until the `Diag` is consumed via
465    /// `emit`, `cancel`, etc. At that point it is consumed and replaced with
466    /// `None`. Then `drop` checks that it is `None`; if not, it panics because
467    /// a diagnostic was built but not used.
468    ///
469    /// Why the Box? `DiagInner` is a large type, and `Diag` is often used as a
470    /// return value, especially within the frequently-used `PResult` type. In
471    /// theory, return value optimization (RVO) should avoid unnecessary
472    /// copying. In practice, it does not (at the time of writing).
473    diag: Option<Box<DiagInner>>,
474
475    _marker: PhantomData<G>,
476}
477
478// Cloning a `Diag` is a recipe for a diagnostic being emitted twice, which
479// would be bad.
480impl<G> !Clone for Diag<'_, G> {}
481
482rustc_data_structures::static_assert_size!(Diag<'_, ()>, 3 * size_of::<usize>());
483
484impl<G: EmissionGuarantee> Deref for Diag<'_, G> {
485    type Target = DiagInner;
486
487    fn deref(&self) -> &DiagInner {
488        self.diag.as_ref().unwrap()
489    }
490}
491
492impl<G: EmissionGuarantee> DerefMut for Diag<'_, G> {
493    fn deref_mut(&mut self) -> &mut DiagInner {
494        self.diag.as_mut().unwrap()
495    }
496}
497
498impl<G: EmissionGuarantee> Debug for Diag<'_, G> {
499    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
500        self.diag.fmt(f)
501    }
502}
503
504/// `Diag` impls many `&mut self -> &mut Self` methods. Each one modifies an
505/// existing diagnostic, either in a standalone fashion, e.g.
506/// `err.code(code);`, or in a chained fashion to make multiple modifications,
507/// e.g. `err.code(code).span(span);`.
508///
509/// This macro creates an equivalent `self -> Self` method, with a `with_`
510/// prefix. This can be used in a chained fashion when making a new diagnostic,
511/// e.g. `let err = struct_err(msg).with_code(code);`, or emitting a new
512/// diagnostic, e.g. `struct_err(msg).with_code(code).emit();`.
513///
514/// Although the latter method can be used to modify an existing diagnostic,
515/// e.g. `err = err.with_code(code);`, this should be avoided because the former
516/// method gives shorter code, e.g. `err.code(code);`.
517///
518/// Note: the `with_` methods are added only when needed. If you want to use
519/// one and it's not defined, feel free to add it.
520///
521/// Note: any doc comments must be within the `with_fn!` call.
522macro_rules! with_fn {
523    {
524        $with_f:ident,
525        $(#[$attrs:meta])*
526        pub fn $f:ident(&mut $self:ident, $($name:ident: $ty:ty),* $(,)?) -> &mut Self {
527            $($body:tt)*
528        }
529    } => {
530        // The original function.
531        $(#[$attrs])*
532        #[doc = concat!("See [`Diag::", stringify!($f), "()`].")]
533        pub fn $f(&mut $self, $($name: $ty),*) -> &mut Self {
534            $($body)*
535        }
536
537        // The `with_*` variant.
538        $(#[$attrs])*
539        #[doc = concat!("See [`Diag::", stringify!($f), "()`].")]
540        pub fn $with_f(mut $self, $($name: $ty),*) -> Self {
541            $self.$f($($name),*);
542            $self
543        }
544    };
545}
546
547impl<'a, G: EmissionGuarantee> Diag<'a, G> {
548    #[rustc_lint_diagnostics]
549    #[track_caller]
550    pub fn new(dcx: DiagCtxtHandle<'a>, level: Level, message: impl Into<DiagMessage>) -> Self {
551        Self::new_diagnostic(dcx, DiagInner::new(level, message))
552    }
553
554    /// Allow moving diagnostics between different error tainting contexts
555    pub fn with_dcx(mut self, dcx: DiagCtxtHandle<'_>) -> Diag<'_, G> {
556        Diag { dcx, diag: self.diag.take(), _marker: PhantomData }
557    }
558
559    /// Creates a new `Diag` with an already constructed diagnostic.
560    #[track_caller]
561    pub(crate) fn new_diagnostic(dcx: DiagCtxtHandle<'a>, diag: DiagInner) -> Self {
562        debug!("Created new diagnostic");
563        Self { dcx, diag: Some(Box::new(diag)), _marker: PhantomData }
564    }
565
566    /// Delay emission of this diagnostic as a bug.
567    ///
568    /// This can be useful in contexts where an error indicates a bug but
569    /// typically this only happens when other compilation errors have already
570    /// happened. In those cases this can be used to defer emission of this
571    /// diagnostic as a bug in the compiler only if no other errors have been
572    /// emitted.
573    ///
574    /// In the meantime, though, callsites are required to deal with the "bug"
575    /// locally in whichever way makes the most sense.
576    #[rustc_lint_diagnostics]
577    #[track_caller]
578    pub fn downgrade_to_delayed_bug(&mut self) {
579        assert!(
580            matches!(self.level, Level::Error | Level::DelayedBug),
581            "downgrade_to_delayed_bug: cannot downgrade {:?} to DelayedBug: not an error",
582            self.level
583        );
584        self.level = Level::DelayedBug;
585    }
586
587    with_fn! { with_span_label,
588    /// Appends a labeled span to the diagnostic.
589    ///
590    /// Labels are used to convey additional context for the diagnostic's primary span. They will
591    /// be shown together with the original diagnostic's span, *not* with spans added by
592    /// `span_note`, `span_help`, etc. Therefore, if the primary span is not displayable (because
593    /// the span is `DUMMY_SP` or the source code isn't found), labels will not be displayed
594    /// either.
595    ///
596    /// Implementation-wise, the label span is pushed onto the [`MultiSpan`] that was created when
597    /// the diagnostic was constructed. However, the label span is *not* considered a
598    /// ["primary span"][`MultiSpan`]; only the `Span` supplied when creating the diagnostic is
599    /// primary.
600    #[rustc_lint_diagnostics]
601    pub fn span_label(&mut self, span: Span, label: impl Into<SubdiagMessage>) -> &mut Self {
602        let msg = self.subdiagnostic_message_to_diagnostic_message(label);
603        self.span.push_span_label(span, msg);
604        self
605    } }
606
607    with_fn! { with_span_labels,
608    /// Labels all the given spans with the provided label.
609    /// See [`Self::span_label()`] for more information.
610    #[rustc_lint_diagnostics]
611    pub fn span_labels(&mut self, spans: impl IntoIterator<Item = Span>, label: &str) -> &mut Self {
612        for span in spans {
613            self.span_label(span, label.to_string());
614        }
615        self
616    } }
617
618    #[rustc_lint_diagnostics]
619    pub fn replace_span_with(&mut self, after: Span, keep_label: bool) -> &mut Self {
620        let before = self.span.clone();
621        self.span(after);
622        for span_label in before.span_labels() {
623            if let Some(label) = span_label.label {
624                if span_label.is_primary && keep_label {
625                    self.span.push_span_label(after, label);
626                } else {
627                    self.span.push_span_label(span_label.span, label);
628                }
629            }
630        }
631        self
632    }
633
634    #[rustc_lint_diagnostics]
635    pub fn note_expected_found(
636        &mut self,
637        expected_label: &str,
638        expected: DiagStyledString,
639        found_label: &str,
640        found: DiagStyledString,
641    ) -> &mut Self {
642        self.note_expected_found_extra(
643            expected_label,
644            expected,
645            found_label,
646            found,
647            DiagStyledString::normal(""),
648            DiagStyledString::normal(""),
649        )
650    }
651
652    #[rustc_lint_diagnostics]
653    pub fn note_expected_found_extra(
654        &mut self,
655        expected_label: &str,
656        expected: DiagStyledString,
657        found_label: &str,
658        found: DiagStyledString,
659        expected_extra: DiagStyledString,
660        found_extra: DiagStyledString,
661    ) -> &mut Self {
662        let expected_label = expected_label.to_string();
663        let expected_label = if expected_label.is_empty() {
664            "expected".to_string()
665        } else {
666            format!("expected {expected_label}")
667        };
668        let found_label = found_label.to_string();
669        let found_label = if found_label.is_empty() {
670            "found".to_string()
671        } else {
672            format!("found {found_label}")
673        };
674        let (found_padding, expected_padding) = if expected_label.len() > found_label.len() {
675            (expected_label.len() - found_label.len(), 0)
676        } else {
677            (0, found_label.len() - expected_label.len())
678        };
679        let mut msg = vec![StringPart::normal(format!(
680            "{}{} `",
681            " ".repeat(expected_padding),
682            expected_label
683        ))];
684        msg.extend(expected.0);
685        msg.push(StringPart::normal(format!("`")));
686        msg.extend(expected_extra.0);
687        msg.push(StringPart::normal(format!("\n")));
688        msg.push(StringPart::normal(format!("{}{} `", " ".repeat(found_padding), found_label)));
689        msg.extend(found.0);
690        msg.push(StringPart::normal(format!("`")));
691        msg.extend(found_extra.0);
692
693        // For now, just attach these as notes.
694        self.highlighted_note(msg);
695        self
696    }
697
698    #[rustc_lint_diagnostics]
699    pub fn note_trait_signature(&mut self, name: Symbol, signature: String) -> &mut Self {
700        self.highlighted_note(vec![
701            StringPart::normal(format!("`{name}` from trait: `")),
702            StringPart::highlighted(signature),
703            StringPart::normal("`"),
704        ]);
705        self
706    }
707
708    with_fn! { with_note,
709    /// Add a note attached to this diagnostic.
710    #[rustc_lint_diagnostics]
711    pub fn note(&mut self, msg: impl Into<SubdiagMessage>) -> &mut Self {
712        self.sub(Level::Note, msg, MultiSpan::new());
713        self
714    } }
715
716    #[rustc_lint_diagnostics]
717    pub fn highlighted_note(&mut self, msg: Vec<StringPart>) -> &mut Self {
718        self.sub_with_highlights(Level::Note, msg, MultiSpan::new());
719        self
720    }
721
722    #[rustc_lint_diagnostics]
723    pub fn highlighted_span_note(
724        &mut self,
725        span: impl Into<MultiSpan>,
726        msg: Vec<StringPart>,
727    ) -> &mut Self {
728        self.sub_with_highlights(Level::Note, msg, span.into());
729        self
730    }
731
732    /// This is like [`Diag::note()`], but it's only printed once.
733    #[rustc_lint_diagnostics]
734    pub fn note_once(&mut self, msg: impl Into<SubdiagMessage>) -> &mut Self {
735        self.sub(Level::OnceNote, msg, MultiSpan::new());
736        self
737    }
738
739    with_fn! { with_span_note,
740    /// Prints the span with a note above it.
741    /// This is like [`Diag::note()`], but it gets its own span.
742    #[rustc_lint_diagnostics]
743    pub fn span_note(
744        &mut self,
745        sp: impl Into<MultiSpan>,
746        msg: impl Into<SubdiagMessage>,
747    ) -> &mut Self {
748        self.sub(Level::Note, msg, sp.into());
749        self
750    } }
751
752    /// Prints the span with a note above it.
753    /// This is like [`Diag::note_once()`], but it gets its own span.
754    #[rustc_lint_diagnostics]
755    pub fn span_note_once<S: Into<MultiSpan>>(
756        &mut self,
757        sp: S,
758        msg: impl Into<SubdiagMessage>,
759    ) -> &mut Self {
760        self.sub(Level::OnceNote, msg, sp.into());
761        self
762    }
763
764    with_fn! { with_warn,
765    /// Add a warning attached to this diagnostic.
766    #[rustc_lint_diagnostics]
767    pub fn warn(&mut self, msg: impl Into<SubdiagMessage>) -> &mut Self {
768        self.sub(Level::Warning, msg, MultiSpan::new());
769        self
770    } }
771
772    /// Prints the span with a warning above it.
773    /// This is like [`Diag::warn()`], but it gets its own span.
774    #[rustc_lint_diagnostics]
775    pub fn span_warn<S: Into<MultiSpan>>(
776        &mut self,
777        sp: S,
778        msg: impl Into<SubdiagMessage>,
779    ) -> &mut Self {
780        self.sub(Level::Warning, msg, sp.into());
781        self
782    }
783
784    with_fn! { with_help,
785    /// Add a help message attached to this diagnostic.
786    #[rustc_lint_diagnostics]
787    pub fn help(&mut self, msg: impl Into<SubdiagMessage>) -> &mut Self {
788        self.sub(Level::Help, msg, MultiSpan::new());
789        self
790    } }
791
792    /// This is like [`Diag::help()`], but it's only printed once.
793    #[rustc_lint_diagnostics]
794    pub fn help_once(&mut self, msg: impl Into<SubdiagMessage>) -> &mut Self {
795        self.sub(Level::OnceHelp, msg, MultiSpan::new());
796        self
797    }
798
799    /// Add a help message attached to this diagnostic with a customizable highlighted message.
800    #[rustc_lint_diagnostics]
801    pub fn highlighted_help(&mut self, msg: Vec<StringPart>) -> &mut Self {
802        self.sub_with_highlights(Level::Help, msg, MultiSpan::new());
803        self
804    }
805
806    /// Add a help message attached to this diagnostic with a customizable highlighted message.
807    #[rustc_lint_diagnostics]
808    pub fn highlighted_span_help(
809        &mut self,
810        span: impl Into<MultiSpan>,
811        msg: Vec<StringPart>,
812    ) -> &mut Self {
813        self.sub_with_highlights(Level::Help, msg, span.into());
814        self
815    }
816
817    /// Prints the span with some help above it.
818    /// This is like [`Diag::help()`], but it gets its own span.
819    #[rustc_lint_diagnostics]
820    pub fn span_help<S: Into<MultiSpan>>(
821        &mut self,
822        sp: S,
823        msg: impl Into<SubdiagMessage>,
824    ) -> &mut Self {
825        self.sub(Level::Help, msg, sp.into());
826        self
827    }
828
829    /// Disallow attaching suggestions to this diagnostic.
830    /// Any suggestions attached e.g. with the `span_suggestion_*` methods
831    /// (before and after the call to `disable_suggestions`) will be ignored.
832    #[rustc_lint_diagnostics]
833    pub fn disable_suggestions(&mut self) -> &mut Self {
834        self.suggestions = Suggestions::Disabled;
835        self
836    }
837
838    /// Prevent new suggestions from being added to this diagnostic.
839    ///
840    /// Suggestions added before the call to `.seal_suggestions()` will be preserved
841    /// and new suggestions will be ignored.
842    #[rustc_lint_diagnostics]
843    pub fn seal_suggestions(&mut self) -> &mut Self {
844        if let Suggestions::Enabled(suggestions) = &mut self.suggestions {
845            let suggestions_slice = std::mem::take(suggestions).into_boxed_slice();
846            self.suggestions = Suggestions::Sealed(suggestions_slice);
847        }
848        self
849    }
850
851    /// Helper for pushing to `self.suggestions`.
852    ///
853    /// A new suggestion is added if suggestions are enabled for this diagnostic.
854    /// Otherwise, they are ignored.
855    #[rustc_lint_diagnostics]
856    fn push_suggestion(&mut self, suggestion: CodeSuggestion) {
857        for subst in &suggestion.substitutions {
858            for part in &subst.parts {
859                let span = part.span;
860                let call_site = span.ctxt().outer_expn_data().call_site;
861                if span.in_derive_expansion() && span.overlaps_or_adjacent(call_site) {
862                    // Ignore if spans is from derive macro.
863                    return;
864                }
865            }
866        }
867
868        if let Suggestions::Enabled(suggestions) = &mut self.suggestions {
869            suggestions.push(suggestion);
870        }
871    }
872
873    with_fn! { with_multipart_suggestion,
874    /// Show a suggestion that has multiple parts to it.
875    /// In other words, multiple changes need to be applied as part of this suggestion.
876    #[rustc_lint_diagnostics]
877    pub fn multipart_suggestion(
878        &mut self,
879        msg: impl Into<SubdiagMessage>,
880        suggestion: Vec<(Span, String)>,
881        applicability: Applicability,
882    ) -> &mut Self {
883        self.multipart_suggestion_with_style(
884            msg,
885            suggestion,
886            applicability,
887            SuggestionStyle::ShowCode,
888        )
889    } }
890
891    /// Show a suggestion that has multiple parts to it, always as its own subdiagnostic.
892    /// In other words, multiple changes need to be applied as part of this suggestion.
893    #[rustc_lint_diagnostics]
894    pub fn multipart_suggestion_verbose(
895        &mut self,
896        msg: impl Into<SubdiagMessage>,
897        suggestion: Vec<(Span, String)>,
898        applicability: Applicability,
899    ) -> &mut Self {
900        self.multipart_suggestion_with_style(
901            msg,
902            suggestion,
903            applicability,
904            SuggestionStyle::ShowAlways,
905        )
906    }
907
908    /// [`Diag::multipart_suggestion()`] but you can set the [`SuggestionStyle`].
909    #[rustc_lint_diagnostics]
910    pub fn multipart_suggestion_with_style(
911        &mut self,
912        msg: impl Into<SubdiagMessage>,
913        mut suggestion: Vec<(Span, String)>,
914        applicability: Applicability,
915        style: SuggestionStyle,
916    ) -> &mut Self {
917        let mut seen = crate::FxHashSet::default();
918        suggestion.retain(|(span, msg)| seen.insert((span.lo(), span.hi(), msg.clone())));
919
920        let parts = suggestion
921            .into_iter()
922            .map(|(span, snippet)| SubstitutionPart { snippet, span })
923            .collect::<Vec<_>>();
924
925        assert!(!parts.is_empty());
926        debug_assert_eq!(
927            parts.iter().find(|part| part.span.is_empty() && part.snippet.is_empty()),
928            None,
929            "Span must not be empty and have no suggestion",
930        );
931        debug_assert_eq!(
932            parts.array_windows().find(|[a, b]| a.span.overlaps(b.span)),
933            None,
934            "suggestion must not have overlapping parts",
935        );
936
937        self.push_suggestion(CodeSuggestion {
938            substitutions: vec![Substitution { parts }],
939            msg: self.subdiagnostic_message_to_diagnostic_message(msg),
940            style,
941            applicability,
942        });
943        self
944    }
945
946    /// Prints out a message with for a multipart suggestion without showing the suggested code.
947    ///
948    /// This is intended to be used for suggestions that are obvious in what the changes need to
949    /// be from the message, showing the span label inline would be visually unpleasant
950    /// (marginally overlapping spans or multiline spans) and showing the snippet window wouldn't
951    /// improve understandability.
952    #[rustc_lint_diagnostics]
953    pub fn tool_only_multipart_suggestion(
954        &mut self,
955        msg: impl Into<SubdiagMessage>,
956        suggestion: Vec<(Span, String)>,
957        applicability: Applicability,
958    ) -> &mut Self {
959        self.multipart_suggestion_with_style(
960            msg,
961            suggestion,
962            applicability,
963            SuggestionStyle::CompletelyHidden,
964        )
965    }
966
967    with_fn! { with_span_suggestion,
968    /// Prints out a message with a suggested edit of the code.
969    ///
970    /// In case of short messages and a simple suggestion, rustc displays it as a label:
971    ///
972    /// ```text
973    /// try adding parentheses: `(tup.0).1`
974    /// ```
975    ///
976    /// The message
977    ///
978    /// * should not end in any punctuation (a `:` is added automatically)
979    /// * should not be a question (avoid language like "did you mean")
980    /// * should not contain any phrases like "the following", "as shown", etc.
981    /// * may look like "to do xyz, use" or "to do xyz, use abc"
982    /// * may contain a name of a function, variable, or type, but not whole expressions
983    ///
984    /// See `CodeSuggestion` for more information.
985    #[rustc_lint_diagnostics]
986    pub fn span_suggestion(
987        &mut self,
988        sp: Span,
989        msg: impl Into<SubdiagMessage>,
990        suggestion: impl ToString,
991        applicability: Applicability,
992    ) -> &mut Self {
993        self.span_suggestion_with_style(
994            sp,
995            msg,
996            suggestion,
997            applicability,
998            SuggestionStyle::ShowCode,
999        );
1000        self
1001    } }
1002
1003    /// [`Diag::span_suggestion()`] but you can set the [`SuggestionStyle`].
1004    #[rustc_lint_diagnostics]
1005    pub fn span_suggestion_with_style(
1006        &mut self,
1007        sp: Span,
1008        msg: impl Into<SubdiagMessage>,
1009        suggestion: impl ToString,
1010        applicability: Applicability,
1011        style: SuggestionStyle,
1012    ) -> &mut Self {
1013        debug_assert!(
1014            !(sp.is_empty() && suggestion.to_string().is_empty()),
1015            "Span must not be empty and have no suggestion"
1016        );
1017        self.push_suggestion(CodeSuggestion {
1018            substitutions: vec![Substitution {
1019                parts: vec![SubstitutionPart { snippet: suggestion.to_string(), span: sp }],
1020            }],
1021            msg: self.subdiagnostic_message_to_diagnostic_message(msg),
1022            style,
1023            applicability,
1024        });
1025        self
1026    }
1027
1028    with_fn! { with_span_suggestion_verbose,
1029    /// Always show the suggested change.
1030    #[rustc_lint_diagnostics]
1031    pub fn span_suggestion_verbose(
1032        &mut self,
1033        sp: Span,
1034        msg: impl Into<SubdiagMessage>,
1035        suggestion: impl ToString,
1036        applicability: Applicability,
1037    ) -> &mut Self {
1038        self.span_suggestion_with_style(
1039            sp,
1040            msg,
1041            suggestion,
1042            applicability,
1043            SuggestionStyle::ShowAlways,
1044        );
1045        self
1046    } }
1047
1048    with_fn! { with_span_suggestions,
1049    /// Prints out a message with multiple suggested edits of the code.
1050    /// See also [`Diag::span_suggestion()`].
1051    #[rustc_lint_diagnostics]
1052    pub fn span_suggestions(
1053        &mut self,
1054        sp: Span,
1055        msg: impl Into<SubdiagMessage>,
1056        suggestions: impl IntoIterator<Item = String>,
1057        applicability: Applicability,
1058    ) -> &mut Self {
1059        self.span_suggestions_with_style(
1060            sp,
1061            msg,
1062            suggestions,
1063            applicability,
1064            SuggestionStyle::ShowCode,
1065        )
1066    } }
1067
1068    #[rustc_lint_diagnostics]
1069    pub fn span_suggestions_with_style(
1070        &mut self,
1071        sp: Span,
1072        msg: impl Into<SubdiagMessage>,
1073        suggestions: impl IntoIterator<Item = String>,
1074        applicability: Applicability,
1075        style: SuggestionStyle,
1076    ) -> &mut Self {
1077        let substitutions = suggestions
1078            .into_iter()
1079            .map(|snippet| {
1080                debug_assert!(
1081                    !(sp.is_empty() && snippet.is_empty()),
1082                    "Span must not be empty and have no suggestion"
1083                );
1084                Substitution { parts: vec![SubstitutionPart { snippet, span: sp }] }
1085            })
1086            .collect();
1087        self.push_suggestion(CodeSuggestion {
1088            substitutions,
1089            msg: self.subdiagnostic_message_to_diagnostic_message(msg),
1090            style,
1091            applicability,
1092        });
1093        self
1094    }
1095
1096    /// Prints out a message with multiple suggested edits of the code, where each edit consists of
1097    /// multiple parts.
1098    /// See also [`Diag::multipart_suggestion()`].
1099    #[rustc_lint_diagnostics]
1100    pub fn multipart_suggestions(
1101        &mut self,
1102        msg: impl Into<SubdiagMessage>,
1103        suggestions: impl IntoIterator<Item = Vec<(Span, String)>>,
1104        applicability: Applicability,
1105    ) -> &mut Self {
1106        let substitutions = suggestions
1107            .into_iter()
1108            .map(|sugg| {
1109                let mut parts = sugg
1110                    .into_iter()
1111                    .map(|(span, snippet)| SubstitutionPart { snippet, span })
1112                    .collect::<Vec<_>>();
1113
1114                parts.sort_unstable_by_key(|part| part.span);
1115
1116                assert!(!parts.is_empty());
1117                debug_assert_eq!(
1118                    parts.iter().find(|part| part.span.is_empty() && part.snippet.is_empty()),
1119                    None,
1120                    "Span must not be empty and have no suggestion",
1121                );
1122                debug_assert_eq!(
1123                    parts.array_windows().find(|[a, b]| a.span.overlaps(b.span)),
1124                    None,
1125                    "suggestion must not have overlapping parts",
1126                );
1127
1128                Substitution { parts }
1129            })
1130            .collect();
1131
1132        self.push_suggestion(CodeSuggestion {
1133            substitutions,
1134            msg: self.subdiagnostic_message_to_diagnostic_message(msg),
1135            style: SuggestionStyle::ShowCode,
1136            applicability,
1137        });
1138        self
1139    }
1140
1141    with_fn! { with_span_suggestion_short,
1142    /// Prints out a message with a suggested edit of the code. If the suggestion is presented
1143    /// inline, it will only show the message and not the suggestion.
1144    ///
1145    /// See `CodeSuggestion` for more information.
1146    #[rustc_lint_diagnostics]
1147    pub fn span_suggestion_short(
1148        &mut self,
1149        sp: Span,
1150        msg: impl Into<SubdiagMessage>,
1151        suggestion: impl ToString,
1152        applicability: Applicability,
1153    ) -> &mut Self {
1154        self.span_suggestion_with_style(
1155            sp,
1156            msg,
1157            suggestion,
1158            applicability,
1159            SuggestionStyle::HideCodeInline,
1160        );
1161        self
1162    } }
1163
1164    /// Prints out a message for a suggestion without showing the suggested code.
1165    ///
1166    /// This is intended to be used for suggestions that are obvious in what the changes need to
1167    /// be from the message, showing the span label inline would be visually unpleasant
1168    /// (marginally overlapping spans or multiline spans) and showing the snippet window wouldn't
1169    /// improve understandability.
1170    #[rustc_lint_diagnostics]
1171    pub fn span_suggestion_hidden(
1172        &mut self,
1173        sp: Span,
1174        msg: impl Into<SubdiagMessage>,
1175        suggestion: impl ToString,
1176        applicability: Applicability,
1177    ) -> &mut Self {
1178        self.span_suggestion_with_style(
1179            sp,
1180            msg,
1181            suggestion,
1182            applicability,
1183            SuggestionStyle::HideCodeAlways,
1184        );
1185        self
1186    }
1187
1188    with_fn! { with_tool_only_span_suggestion,
1189    /// Adds a suggestion to the JSON output that will not be shown in the CLI.
1190    ///
1191    /// This is intended to be used for suggestions that are *very* obvious in what the changes
1192    /// need to be from the message, but we still want other tools to be able to apply them.
1193    #[rustc_lint_diagnostics]
1194    pub fn tool_only_span_suggestion(
1195        &mut self,
1196        sp: Span,
1197        msg: impl Into<SubdiagMessage>,
1198        suggestion: impl ToString,
1199        applicability: Applicability,
1200    ) -> &mut Self {
1201        self.span_suggestion_with_style(
1202            sp,
1203            msg,
1204            suggestion,
1205            applicability,
1206            SuggestionStyle::CompletelyHidden,
1207        );
1208        self
1209    } }
1210
1211    /// Add a subdiagnostic from a type that implements `Subdiagnostic` (see
1212    /// [rustc_macros::Subdiagnostic]). Performs eager translation of any translatable messages
1213    /// used in the subdiagnostic, so suitable for use with repeated messages (i.e. re-use of
1214    /// interpolated variables).
1215    #[rustc_lint_diagnostics]
1216    pub fn subdiagnostic(&mut self, subdiagnostic: impl Subdiagnostic) -> &mut Self {
1217        subdiagnostic.add_to_diag(self);
1218        self
1219    }
1220
1221    /// Fluent variables are not namespaced from each other, so when
1222    /// `Diagnostic`s and `Subdiagnostic`s use the same variable name,
1223    /// one value will clobber the other. Eagerly translating the
1224    /// diagnostic uses the variables defined right then, before the
1225    /// clobbering occurs.
1226    pub fn eagerly_translate(&self, msg: impl Into<SubdiagMessage>) -> SubdiagMessage {
1227        let args = self.args.iter();
1228        let msg = self.subdiagnostic_message_to_diagnostic_message(msg.into());
1229        self.dcx.eagerly_translate(msg, args)
1230    }
1231
1232    with_fn! { with_span,
1233    /// Add a span.
1234    #[rustc_lint_diagnostics]
1235    pub fn span(&mut self, sp: impl Into<MultiSpan>) -> &mut Self {
1236        self.span = sp.into();
1237        if let Some(span) = self.span.primary_span() {
1238            self.sort_span = span;
1239        }
1240        self
1241    } }
1242
1243    #[rustc_lint_diagnostics]
1244    pub fn is_lint(&mut self, name: String, has_future_breakage: bool) -> &mut Self {
1245        self.is_lint = Some(IsLint { name, has_future_breakage });
1246        self
1247    }
1248
1249    with_fn! { with_code,
1250    /// Add an error code.
1251    #[rustc_lint_diagnostics]
1252    pub fn code(&mut self, code: ErrCode) -> &mut Self {
1253        self.code = Some(code);
1254        self
1255    } }
1256
1257    with_fn! { with_lint_id,
1258    /// Add an argument.
1259    #[rustc_lint_diagnostics]
1260    pub fn lint_id(
1261        &mut self,
1262        id: LintExpectationId,
1263    ) -> &mut Self {
1264        self.lint_id = Some(id);
1265        self
1266    } }
1267
1268    with_fn! { with_primary_message,
1269    /// Add a primary message.
1270    #[rustc_lint_diagnostics]
1271    pub fn primary_message(&mut self, msg: impl Into<DiagMessage>) -> &mut Self {
1272        self.messages[0] = (msg.into(), Style::NoStyle);
1273        self
1274    } }
1275
1276    with_fn! { with_arg,
1277    /// Add an argument.
1278    #[rustc_lint_diagnostics]
1279    pub fn arg(
1280        &mut self,
1281        name: impl Into<DiagArgName>,
1282        arg: impl IntoDiagArg,
1283    ) -> &mut Self {
1284        self.deref_mut().arg(name, arg);
1285        self
1286    } }
1287
1288    /// Helper function that takes a `SubdiagMessage` and returns a `DiagMessage` by
1289    /// combining it with the primary message of the diagnostic (if translatable, otherwise it just
1290    /// passes the user's string along).
1291    pub(crate) fn subdiagnostic_message_to_diagnostic_message(
1292        &self,
1293        attr: impl Into<SubdiagMessage>,
1294    ) -> DiagMessage {
1295        self.deref().subdiagnostic_message_to_diagnostic_message(attr)
1296    }
1297
1298    /// Convenience function for internal use, clients should use one of the
1299    /// public methods above.
1300    ///
1301    /// Used by `proc_macro_server` for implementing `server::Diagnostic`.
1302    pub fn sub(&mut self, level: Level, message: impl Into<SubdiagMessage>, span: MultiSpan) {
1303        self.deref_mut().sub(level, message, span);
1304    }
1305
1306    /// Convenience function for internal use, clients should use one of the
1307    /// public methods above.
1308    fn sub_with_highlights(&mut self, level: Level, messages: Vec<StringPart>, span: MultiSpan) {
1309        let messages = messages
1310            .into_iter()
1311            .map(|m| (self.subdiagnostic_message_to_diagnostic_message(m.content), m.style))
1312            .collect();
1313        let sub = Subdiag { level, messages, span };
1314        self.children.push(sub);
1315    }
1316
1317    /// Takes the diagnostic. For use by methods that consume the Diag: `emit`,
1318    /// `cancel`, etc. Afterwards, `drop` is the only code that will be run on
1319    /// `self`.
1320    fn take_diag(&mut self) -> DiagInner {
1321        if let Some(path) = &self.long_ty_path {
1322            self.note(format!(
1323                "the full name for the type has been written to '{}'",
1324                path.display()
1325            ));
1326            self.note("consider using `--verbose` to print the full type name to the console");
1327        }
1328        Box::into_inner(self.diag.take().unwrap())
1329    }
1330
1331    /// This method allows us to access the path of the file where "long types" are written to.
1332    ///
1333    /// When calling `Diag::emit`, as part of that we will check if a `long_ty_path` has been set,
1334    /// and if it has been then we add a note mentioning the file where the "long types" were
1335    /// written to.
1336    ///
1337    /// When calling `tcx.short_string()` after a `Diag` is constructed, the preferred way of doing
1338    /// so is `tcx.short_string(ty, diag.long_ty_path())`. The diagnostic itself is the one that
1339    /// keeps the existence of a "long type" anywhere in the diagnostic, so the note telling the
1340    /// user where we wrote the file to is only printed once at most, *and* it makes it much harder
1341    /// to forget to set it.
1342    ///
1343    /// If the diagnostic hasn't been created before a "short ty string" is created, then you should
1344    /// ensure that this method is called to set it `*diag.long_ty_path() = path`.
1345    ///
1346    /// As a rule of thumb, if you see or add at least one `tcx.short_string()` call anywhere, in a
1347    /// scope, `diag.long_ty_path()` should be called once somewhere close by.
1348    pub fn long_ty_path(&mut self) -> &mut Option<PathBuf> {
1349        &mut self.long_ty_path
1350    }
1351
1352    /// Most `emit_producing_guarantee` functions use this as a starting point.
1353    fn emit_producing_nothing(mut self) {
1354        let diag = self.take_diag();
1355        self.dcx.emit_diagnostic(diag);
1356    }
1357
1358    /// `ErrorGuaranteed::emit_producing_guarantee` uses this.
1359    fn emit_producing_error_guaranteed(mut self) -> ErrorGuaranteed {
1360        let diag = self.take_diag();
1361
1362        // The only error levels that produce `ErrorGuaranteed` are
1363        // `Error` and `DelayedBug`. But `DelayedBug` should never occur here
1364        // because delayed bugs have their level changed to `Bug` when they are
1365        // actually printed, so they produce an ICE.
1366        //
1367        // (Also, even though `level` isn't `pub`, the whole `DiagInner` could
1368        // be overwritten with a new one thanks to `DerefMut`. So this assert
1369        // protects against that, too.)
1370        assert!(
1371            matches!(diag.level, Level::Error | Level::DelayedBug),
1372            "invalid diagnostic level ({:?})",
1373            diag.level,
1374        );
1375
1376        let guar = self.dcx.emit_diagnostic(diag);
1377        guar.unwrap()
1378    }
1379
1380    /// Emit and consume the diagnostic.
1381    #[track_caller]
1382    pub fn emit(self) -> G::EmitResult {
1383        G::emit_producing_guarantee(self)
1384    }
1385
1386    /// Emit the diagnostic unless `delay` is true,
1387    /// in which case the emission will be delayed as a bug.
1388    ///
1389    /// See `emit` and `delay_as_bug` for details.
1390    #[track_caller]
1391    pub fn emit_unless(mut self, delay: bool) -> G::EmitResult {
1392        if delay {
1393            self.downgrade_to_delayed_bug();
1394        }
1395        self.emit()
1396    }
1397
1398    /// Cancel and consume the diagnostic. (A diagnostic must either be emitted or
1399    /// cancelled or it will panic when dropped).
1400    pub fn cancel(mut self) {
1401        self.diag = None;
1402        drop(self);
1403    }
1404
1405    /// See `DiagCtxt::stash_diagnostic` for details.
1406    pub fn stash(mut self, span: Span, key: StashKey) -> Option<ErrorGuaranteed> {
1407        let diag = self.take_diag();
1408        self.dcx.stash_diagnostic(span, key, diag)
1409    }
1410
1411    /// Delay emission of this diagnostic as a bug.
1412    ///
1413    /// This can be useful in contexts where an error indicates a bug but
1414    /// typically this only happens when other compilation errors have already
1415    /// happened. In those cases this can be used to defer emission of this
1416    /// diagnostic as a bug in the compiler only if no other errors have been
1417    /// emitted.
1418    ///
1419    /// In the meantime, though, callsites are required to deal with the "bug"
1420    /// locally in whichever way makes the most sense.
1421    #[track_caller]
1422    pub fn delay_as_bug(mut self) -> G::EmitResult {
1423        self.downgrade_to_delayed_bug();
1424        self.emit()
1425    }
1426}
1427
1428/// Destructor bomb: every `Diag` must be consumed (emitted, cancelled, etc.)
1429/// or we emit a bug.
1430impl<G: EmissionGuarantee> Drop for Diag<'_, G> {
1431    fn drop(&mut self) {
1432        match self.diag.take() {
1433            Some(diag) if !panicking() => {
1434                self.dcx.emit_diagnostic(DiagInner::new(
1435                    Level::Bug,
1436                    DiagMessage::from("the following error was constructed but not emitted"),
1437                ));
1438                self.dcx.emit_diagnostic(*diag);
1439                panic!("error was constructed but not emitted");
1440            }
1441            _ => {}
1442        }
1443    }
1444}
1445
1446#[macro_export]
1447macro_rules! struct_span_code_err {
1448    ($dcx:expr, $span:expr, $code:expr, $($message:tt)*) => ({
1449        $dcx.struct_span_err($span, format!($($message)*)).with_code($code)
1450    })
1451}