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::ShowAlways,
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}
pFad - Phonifier reborn

Pfad - The Proxy pFad of © 2024 Garber Painting. All rights reserved.

Note: This service is not intended for secure transactions such as banking, social media, email, or purchasing. Use at your own risk. We assume no liability whatsoever for broken pages.


Alternative Proxies:

Alternative Proxy

pFad Proxy

pFad v3 Proxy

pFad v4 Proxy