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