rustc_errors/
diagnostic.rs

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