rustc_errors/
diagnostic.rs

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