1use std::borrow::Cow;
2use std::fmt::{self, Debug};
3use std::hash::{Hash, Hasher};
4use std::marker::PhantomData;
5use std::ops::{Deref, DerefMut};
6use std::panic;
7use std::path::PathBuf;
8use std::thread::panicking;
9
10use rustc_data_structures::fx::FxIndexMap;
11use rustc_error_messages::{FluentValue, fluent_value_from_str_list_sep_by_and};
12use rustc_lint_defs::Applicability;
13use rustc_macros::{Decodable, Encodable};
14use rustc_span::source_map::Spanned;
15use rustc_span::{DUMMY_SP, Span, Symbol};
16use tracing::debug;
17
18use crate::snippet::Style;
19use crate::{
20 CodeSuggestion, DiagCtxtHandle, DiagMessage, ErrCode, ErrorGuaranteed, ExplicitBug, Level,
21 MultiSpan, StashKey, SubdiagMessage, Substitution, SubstitutionPart, SuggestionStyle,
22 Suggestions,
23};
24
25pub type DiagArg<'iter> = (&'iter DiagArgName, &'iter DiagArgValue);
29
30pub type DiagArgName = Cow<'static, str>;
32
33#[derive(Clone, Debug, PartialEq, Eq, Hash, Encodable, Decodable)]
36pub enum DiagArgValue {
37 Str(Cow<'static, str>),
38 Number(i32),
42 StrListSepByAnd(Vec<Cow<'static, str>>),
43}
44
45pub type DiagArgMap = FxIndexMap<DiagArgName, DiagArgValue>;
46
47pub trait EmissionGuarantee: Sized {
50 type EmitResult = Self;
53
54 #[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#[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#[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#[rustc_diagnostic_item = "Diagnostic"]
130pub trait Diagnostic<'a, G: EmissionGuarantee = ErrorGuaranteed> {
131 #[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
146pub trait IntoDiagArg {
151 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#[rustc_diagnostic_item = "Subdiagnostic"]
179pub trait Subdiagnostic
180where
181 Self: Sized,
182{
183 fn add_to_diag<G: EmissionGuarantee>(self, diag: &mut Diag<'_, G>) {
185 self.add_to_diag_with(diag, &|_, m| m);
186 }
187
188 fn add_to_diag_with<G: EmissionGuarantee, F: SubdiagMessageOp<G>>(
191 self,
192 diag: &mut Diag<'_, G>,
193 f: &F,
194 );
195}
196
197pub trait SubdiagMessageOp<G: EmissionGuarantee> =
198 Fn(&mut Diag<'_, G>, SubdiagMessage) -> SubdiagMessage;
199
200#[rustc_diagnostic_item = "LintDiagnostic"]
203pub trait LintDiagnostic<'a, G: EmissionGuarantee> {
204 fn decorate_lint<'b>(self, diag: &'b mut Diag<'a, G>);
206}
207
208#[derive(Clone, Debug, Encodable, Decodable)]
209pub(crate) struct DiagLocation {
210 file: Cow<'static, str>,
211 line: u32,
212 col: u32,
213}
214
215impl DiagLocation {
216 #[track_caller]
217 fn caller() -> Self {
218 let loc = panic::Location::caller();
219 DiagLocation { file: loc.file().into(), line: loc.line(), col: loc.column() }
220 }
221}
222
223impl fmt::Display for DiagLocation {
224 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
225 write!(f, "{}:{}:{}", self.file, self.line, self.col)
226 }
227}
228
229#[derive(Clone, Debug, PartialEq, Eq, Hash, Encodable, Decodable)]
230pub struct IsLint {
231 pub(crate) name: String,
233 has_future_breakage: bool,
235}
236
237#[derive(Debug, PartialEq, Eq)]
238pub struct DiagStyledString(pub Vec<StringPart>);
239
240impl DiagStyledString {
241 pub fn new() -> DiagStyledString {
242 DiagStyledString(vec![])
243 }
244 pub fn push_normal<S: Into<String>>(&mut self, t: S) {
245 self.0.push(StringPart::normal(t));
246 }
247 pub fn push_highlighted<S: Into<String>>(&mut self, t: S) {
248 self.0.push(StringPart::highlighted(t));
249 }
250 pub fn push<S: Into<String>>(&mut self, t: S, highlight: bool) {
251 if highlight {
252 self.push_highlighted(t);
253 } else {
254 self.push_normal(t);
255 }
256 }
257 pub fn normal<S: Into<String>>(t: S) -> DiagStyledString {
258 DiagStyledString(vec![StringPart::normal(t)])
259 }
260
261 pub fn highlighted<S: Into<String>>(t: S) -> DiagStyledString {
262 DiagStyledString(vec![StringPart::highlighted(t)])
263 }
264
265 pub fn content(&self) -> String {
266 self.0.iter().map(|x| x.content.as_str()).collect::<String>()
267 }
268}
269
270#[derive(Debug, PartialEq, Eq)]
271pub struct StringPart {
272 content: String,
273 style: Style,
274}
275
276impl StringPart {
277 pub fn normal<S: Into<String>>(content: S) -> StringPart {
278 StringPart { content: content.into(), style: Style::NoStyle }
279 }
280
281 pub fn highlighted<S: Into<String>>(content: S) -> StringPart {
282 StringPart { content: content.into(), style: Style::Highlight }
283 }
284}
285
286#[must_use]
291#[derive(Clone, Debug, Encodable, Decodable)]
292pub struct DiagInner {
293 pub(crate) level: Level,
296
297 pub messages: Vec<(DiagMessage, Style)>,
298 pub code: Option<ErrCode>,
299 pub span: MultiSpan,
300 pub children: Vec<Subdiag>,
301 pub suggestions: Suggestions,
302 pub args: DiagArgMap,
303
304 pub sort_span: Span,
308
309 pub is_lint: Option<IsLint>,
310
311 pub long_ty_path: Option<PathBuf>,
312 pub(crate) emitted_at: DiagLocation,
315}
316
317impl DiagInner {
318 #[track_caller]
319 pub fn new<M: Into<DiagMessage>>(level: Level, message: M) -> Self {
320 DiagInner::new_with_messages(level, vec![(message.into(), Style::NoStyle)])
321 }
322
323 #[track_caller]
324 pub fn new_with_messages(level: Level, messages: Vec<(DiagMessage, Style)>) -> Self {
325 DiagInner {
326 level,
327 messages,
328 code: None,
329 span: MultiSpan::new(),
330 children: vec![],
331 suggestions: Suggestions::Enabled(vec![]),
332 args: Default::default(),
333 sort_span: DUMMY_SP,
334 is_lint: None,
335 long_ty_path: None,
336 emitted_at: DiagLocation::caller(),
337 }
338 }
339
340 #[inline(always)]
341 pub fn level(&self) -> Level {
342 self.level
343 }
344
345 pub fn is_error(&self) -> bool {
346 match self.level {
347 Level::Bug | Level::Fatal | Level::Error | Level::DelayedBug => true,
348
349 Level::ForceWarning(_)
350 | Level::Warning
351 | Level::Note
352 | Level::OnceNote
353 | Level::Help
354 | Level::OnceHelp
355 | Level::FailureNote
356 | Level::Allow
357 | Level::Expect(_) => false,
358 }
359 }
360
361 pub(crate) fn has_future_breakage(&self) -> bool {
363 matches!(self.is_lint, Some(IsLint { has_future_breakage: true, .. }))
364 }
365
366 pub(crate) fn is_force_warn(&self) -> bool {
367 match self.level {
368 Level::ForceWarning(_) => {
369 assert!(self.is_lint.is_some());
370 true
371 }
372 _ => false,
373 }
374 }
375
376 pub(crate) fn subdiagnostic_message_to_diagnostic_message(
378 &self,
379 attr: impl Into<SubdiagMessage>,
380 ) -> DiagMessage {
381 let msg =
382 self.messages.iter().map(|(msg, _)| msg).next().expect("diagnostic with no messages");
383 msg.with_subdiagnostic_message(attr.into())
384 }
385
386 pub(crate) fn sub(
387 &mut self,
388 level: Level,
389 message: impl Into<SubdiagMessage>,
390 span: MultiSpan,
391 ) {
392 let sub = Subdiag {
393 level,
394 messages: vec![(
395 self.subdiagnostic_message_to_diagnostic_message(message),
396 Style::NoStyle,
397 )],
398 span,
399 };
400 self.children.push(sub);
401 }
402
403 pub(crate) fn arg(&mut self, name: impl Into<DiagArgName>, arg: impl IntoDiagArg) {
404 self.args.insert(name.into(), arg.into_diag_arg(&mut self.long_ty_path));
405 }
406
407 fn keys(
409 &self,
410 ) -> (
411 &Level,
412 &[(DiagMessage, Style)],
413 &Option<ErrCode>,
414 &MultiSpan,
415 &[Subdiag],
416 &Suggestions,
417 Vec<(&DiagArgName, &DiagArgValue)>,
418 &Option<IsLint>,
419 ) {
420 (
421 &self.level,
422 &self.messages,
423 &self.code,
424 &self.span,
425 &self.children,
426 &self.suggestions,
427 self.args.iter().collect(),
428 &self.is_lint,
430 )
432 }
433}
434
435impl Hash for DiagInner {
436 fn hash<H>(&self, state: &mut H)
437 where
438 H: Hasher,
439 {
440 self.keys().hash(state);
441 }
442}
443
444impl PartialEq for DiagInner {
445 fn eq(&self, other: &Self) -> bool {
446 self.keys() == other.keys()
447 }
448}
449
450#[derive(Clone, Debug, PartialEq, Hash, Encodable, Decodable)]
453pub struct Subdiag {
454 pub level: Level,
455 pub messages: Vec<(DiagMessage, Style)>,
456 pub span: MultiSpan,
457}
458
459#[must_use]
472pub struct Diag<'a, G: EmissionGuarantee = ErrorGuaranteed> {
473 pub dcx: DiagCtxtHandle<'a>,
474
475 diag: Option<Box<DiagInner>>,
485
486 _marker: PhantomData<G>,
487}
488
489impl<G> !Clone for Diag<'_, G> {}
492
493rustc_data_structures::static_assert_size!(Diag<'_, ()>, 3 * size_of::<usize>());
494
495impl<G: EmissionGuarantee> Deref for Diag<'_, G> {
496 type Target = DiagInner;
497
498 fn deref(&self) -> &DiagInner {
499 self.diag.as_ref().unwrap()
500 }
501}
502
503impl<G: EmissionGuarantee> DerefMut for Diag<'_, G> {
504 fn deref_mut(&mut self) -> &mut DiagInner {
505 self.diag.as_mut().unwrap()
506 }
507}
508
509impl<G: EmissionGuarantee> Debug for Diag<'_, G> {
510 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
511 self.diag.fmt(f)
512 }
513}
514
515macro_rules! with_fn {
534 {
535 $with_f:ident,
536 $(#[$attrs:meta])*
537 pub fn $f:ident(&mut $self:ident, $($name:ident: $ty:ty),* $(,)?) -> &mut Self {
538 $($body:tt)*
539 }
540 } => {
541 $(#[$attrs])*
543 #[doc = concat!("See [`Diag::", stringify!($f), "()`].")]
544 pub fn $f(&mut $self, $($name: $ty),*) -> &mut Self {
545 $($body)*
546 }
547
548 $(#[$attrs])*
550 #[doc = concat!("See [`Diag::", stringify!($f), "()`].")]
551 pub fn $with_f(mut $self, $($name: $ty),*) -> Self {
552 $self.$f($($name),*);
553 $self
554 }
555 };
556}
557
558impl<'a, G: EmissionGuarantee> Diag<'a, G> {
559 #[rustc_lint_diagnostics]
560 #[track_caller]
561 pub fn new(dcx: DiagCtxtHandle<'a>, level: Level, message: impl Into<DiagMessage>) -> Self {
562 Self::new_diagnostic(dcx, DiagInner::new(level, message))
563 }
564
565 pub fn with_dcx(mut self, dcx: DiagCtxtHandle<'_>) -> Diag<'_, G> {
567 Diag { dcx, diag: self.diag.take(), _marker: PhantomData }
568 }
569
570 #[track_caller]
572 pub(crate) fn new_diagnostic(dcx: DiagCtxtHandle<'a>, diag: DiagInner) -> Self {
573 debug!("Created new diagnostic");
574 Self { dcx, diag: Some(Box::new(diag)), _marker: PhantomData }
575 }
576
577 #[rustc_lint_diagnostics]
588 #[track_caller]
589 pub fn downgrade_to_delayed_bug(&mut self) {
590 assert!(
591 matches!(self.level, Level::Error | Level::DelayedBug),
592 "downgrade_to_delayed_bug: cannot downgrade {:?} to DelayedBug: not an error",
593 self.level
594 );
595 self.level = Level::DelayedBug;
596 }
597
598 with_fn! { with_span_label,
599 #[rustc_lint_diagnostics]
612 pub fn span_label(&mut self, span: Span, label: impl Into<SubdiagMessage>) -> &mut Self {
613 let msg = self.subdiagnostic_message_to_diagnostic_message(label);
614 self.span.push_span_label(span, msg);
615 self
616 } }
617
618 with_fn! { with_span_labels,
619 #[rustc_lint_diagnostics]
622 pub fn span_labels(&mut self, spans: impl IntoIterator<Item = Span>, label: &str) -> &mut Self {
623 for span in spans {
624 self.span_label(span, label.to_string());
625 }
626 self
627 } }
628
629 #[rustc_lint_diagnostics]
630 pub fn replace_span_with(&mut self, after: Span, keep_label: bool) -> &mut Self {
631 let before = self.span.clone();
632 self.span(after);
633 for span_label in before.span_labels() {
634 if let Some(label) = span_label.label {
635 if span_label.is_primary && keep_label {
636 self.span.push_span_label(after, label);
637 } else {
638 self.span.push_span_label(span_label.span, label);
639 }
640 }
641 }
642 self
643 }
644
645 #[rustc_lint_diagnostics]
646 pub fn note_expected_found(
647 &mut self,
648 expected_label: &dyn fmt::Display,
649 expected: DiagStyledString,
650 found_label: &dyn fmt::Display,
651 found: DiagStyledString,
652 ) -> &mut Self {
653 self.note_expected_found_extra(
654 expected_label,
655 expected,
656 found_label,
657 found,
658 DiagStyledString::normal(""),
659 DiagStyledString::normal(""),
660 )
661 }
662
663 #[rustc_lint_diagnostics]
664 pub fn note_expected_found_extra(
665 &mut self,
666 expected_label: &dyn fmt::Display,
667 expected: DiagStyledString,
668 found_label: &dyn fmt::Display,
669 found: DiagStyledString,
670 expected_extra: DiagStyledString,
671 found_extra: DiagStyledString,
672 ) -> &mut Self {
673 let expected_label = expected_label.to_string();
674 let expected_label = if expected_label.is_empty() {
675 "expected".to_string()
676 } else {
677 format!("expected {expected_label}")
678 };
679 let found_label = found_label.to_string();
680 let found_label = if found_label.is_empty() {
681 "found".to_string()
682 } else {
683 format!("found {found_label}")
684 };
685 let (found_padding, expected_padding) = if expected_label.len() > found_label.len() {
686 (expected_label.len() - found_label.len(), 0)
687 } else {
688 (0, found_label.len() - expected_label.len())
689 };
690 let mut msg = vec![StringPart::normal(format!(
691 "{}{} `",
692 " ".repeat(expected_padding),
693 expected_label
694 ))];
695 msg.extend(expected.0);
696 msg.push(StringPart::normal(format!("`")));
697 msg.extend(expected_extra.0);
698 msg.push(StringPart::normal(format!("\n")));
699 msg.push(StringPart::normal(format!("{}{} `", " ".repeat(found_padding), found_label)));
700 msg.extend(found.0);
701 msg.push(StringPart::normal(format!("`")));
702 msg.extend(found_extra.0);
703
704 self.highlighted_note(msg);
706 self
707 }
708
709 #[rustc_lint_diagnostics]
710 pub fn note_trait_signature(&mut self, name: Symbol, signature: String) -> &mut Self {
711 self.highlighted_note(vec![
712 StringPart::normal(format!("`{name}` from trait: `")),
713 StringPart::highlighted(signature),
714 StringPart::normal("`"),
715 ]);
716 self
717 }
718
719 with_fn! { with_note,
720 #[rustc_lint_diagnostics]
722 pub fn note(&mut self, msg: impl Into<SubdiagMessage>) -> &mut Self {
723 self.sub(Level::Note, msg, MultiSpan::new());
724 self
725 } }
726
727 #[rustc_lint_diagnostics]
728 pub fn highlighted_note(&mut self, msg: Vec<StringPart>) -> &mut Self {
729 self.sub_with_highlights(Level::Note, msg, MultiSpan::new());
730 self
731 }
732
733 #[rustc_lint_diagnostics]
734 pub fn highlighted_span_note(
735 &mut self,
736 span: impl Into<MultiSpan>,
737 msg: Vec<StringPart>,
738 ) -> &mut Self {
739 self.sub_with_highlights(Level::Note, msg, span.into());
740 self
741 }
742
743 #[rustc_lint_diagnostics]
745 pub fn note_once(&mut self, msg: impl Into<SubdiagMessage>) -> &mut Self {
746 self.sub(Level::OnceNote, msg, MultiSpan::new());
747 self
748 }
749
750 with_fn! { with_span_note,
751 #[rustc_lint_diagnostics]
754 pub fn span_note(
755 &mut self,
756 sp: impl Into<MultiSpan>,
757 msg: impl Into<SubdiagMessage>,
758 ) -> &mut Self {
759 self.sub(Level::Note, msg, sp.into());
760 self
761 } }
762
763 #[rustc_lint_diagnostics]
766 pub fn span_note_once<S: Into<MultiSpan>>(
767 &mut self,
768 sp: S,
769 msg: impl Into<SubdiagMessage>,
770 ) -> &mut Self {
771 self.sub(Level::OnceNote, msg, sp.into());
772 self
773 }
774
775 with_fn! { with_warn,
776 #[rustc_lint_diagnostics]
778 pub fn warn(&mut self, msg: impl Into<SubdiagMessage>) -> &mut Self {
779 self.sub(Level::Warning, msg, MultiSpan::new());
780 self
781 } }
782
783 #[rustc_lint_diagnostics]
786 pub fn span_warn<S: Into<MultiSpan>>(
787 &mut self,
788 sp: S,
789 msg: impl Into<SubdiagMessage>,
790 ) -> &mut Self {
791 self.sub(Level::Warning, msg, sp.into());
792 self
793 }
794
795 with_fn! { with_help,
796 #[rustc_lint_diagnostics]
798 pub fn help(&mut self, msg: impl Into<SubdiagMessage>) -> &mut Self {
799 self.sub(Level::Help, msg, MultiSpan::new());
800 self
801 } }
802
803 #[rustc_lint_diagnostics]
805 pub fn help_once(&mut self, msg: impl Into<SubdiagMessage>) -> &mut Self {
806 self.sub(Level::OnceHelp, msg, MultiSpan::new());
807 self
808 }
809
810 #[rustc_lint_diagnostics]
812 pub fn highlighted_help(&mut self, msg: Vec<StringPart>) -> &mut Self {
813 self.sub_with_highlights(Level::Help, msg, MultiSpan::new());
814 self
815 }
816
817 #[rustc_lint_diagnostics]
819 pub fn highlighted_span_help(
820 &mut self,
821 span: impl Into<MultiSpan>,
822 msg: Vec<StringPart>,
823 ) -> &mut Self {
824 self.sub_with_highlights(Level::Help, msg, span.into());
825 self
826 }
827
828 #[rustc_lint_diagnostics]
831 pub fn span_help<S: Into<MultiSpan>>(
832 &mut self,
833 sp: S,
834 msg: impl Into<SubdiagMessage>,
835 ) -> &mut Self {
836 self.sub(Level::Help, msg, sp.into());
837 self
838 }
839
840 #[rustc_lint_diagnostics]
844 pub fn disable_suggestions(&mut self) -> &mut Self {
845 self.suggestions = Suggestions::Disabled;
846 self
847 }
848
849 #[rustc_lint_diagnostics]
854 pub fn seal_suggestions(&mut self) -> &mut Self {
855 if let Suggestions::Enabled(suggestions) = &mut self.suggestions {
856 let suggestions_slice = std::mem::take(suggestions).into_boxed_slice();
857 self.suggestions = Suggestions::Sealed(suggestions_slice);
858 }
859 self
860 }
861
862 #[rustc_lint_diagnostics]
867 fn push_suggestion(&mut self, suggestion: CodeSuggestion) {
868 for subst in &suggestion.substitutions {
869 for part in &subst.parts {
870 let span = part.span;
871 let call_site = span.ctxt().outer_expn_data().call_site;
872 if span.in_derive_expansion() && span.overlaps_or_adjacent(call_site) {
873 return;
875 }
876 }
877 }
878
879 if let Suggestions::Enabled(suggestions) = &mut self.suggestions {
880 suggestions.push(suggestion);
881 }
882 }
883
884 with_fn! { with_multipart_suggestion,
885 #[rustc_lint_diagnostics]
888 pub fn multipart_suggestion(
889 &mut self,
890 msg: impl Into<SubdiagMessage>,
891 suggestion: Vec<(Span, String)>,
892 applicability: Applicability,
893 ) -> &mut Self {
894 self.multipart_suggestion_with_style(
895 msg,
896 suggestion,
897 applicability,
898 SuggestionStyle::ShowCode,
899 )
900 } }
901
902 #[rustc_lint_diagnostics]
905 pub fn multipart_suggestion_verbose(
906 &mut self,
907 msg: impl Into<SubdiagMessage>,
908 suggestion: Vec<(Span, String)>,
909 applicability: Applicability,
910 ) -> &mut Self {
911 self.multipart_suggestion_with_style(
912 msg,
913 suggestion,
914 applicability,
915 SuggestionStyle::ShowAlways,
916 )
917 }
918
919 #[rustc_lint_diagnostics]
921 pub fn multipart_suggestion_with_style(
922 &mut self,
923 msg: impl Into<SubdiagMessage>,
924 mut suggestion: Vec<(Span, String)>,
925 applicability: Applicability,
926 style: SuggestionStyle,
927 ) -> &mut Self {
928 let mut seen = crate::FxHashSet::default();
929 suggestion.retain(|(span, msg)| seen.insert((span.lo(), span.hi(), msg.clone())));
930
931 let parts = suggestion
932 .into_iter()
933 .map(|(span, snippet)| SubstitutionPart { snippet, span })
934 .collect::<Vec<_>>();
935
936 assert!(!parts.is_empty());
937 debug_assert_eq!(
938 parts.iter().find(|part| part.span.is_empty() && part.snippet.is_empty()),
939 None,
940 "Span must not be empty and have no suggestion",
941 );
942 debug_assert_eq!(
943 parts.array_windows().find(|[a, b]| a.span.overlaps(b.span)),
944 None,
945 "suggestion must not have overlapping parts",
946 );
947
948 self.push_suggestion(CodeSuggestion {
949 substitutions: vec![Substitution { parts }],
950 msg: self.subdiagnostic_message_to_diagnostic_message(msg),
951 style,
952 applicability,
953 });
954 self
955 }
956
957 #[rustc_lint_diagnostics]
964 pub fn tool_only_multipart_suggestion(
965 &mut self,
966 msg: impl Into<SubdiagMessage>,
967 suggestion: Vec<(Span, String)>,
968 applicability: Applicability,
969 ) -> &mut Self {
970 self.multipart_suggestion_with_style(
971 msg,
972 suggestion,
973 applicability,
974 SuggestionStyle::CompletelyHidden,
975 )
976 }
977
978 with_fn! { with_span_suggestion,
979 #[rustc_lint_diagnostics]
997 pub fn span_suggestion(
998 &mut self,
999 sp: Span,
1000 msg: impl Into<SubdiagMessage>,
1001 suggestion: impl ToString,
1002 applicability: Applicability,
1003 ) -> &mut Self {
1004 self.span_suggestion_with_style(
1005 sp,
1006 msg,
1007 suggestion,
1008 applicability,
1009 SuggestionStyle::ShowCode,
1010 );
1011 self
1012 } }
1013
1014 #[rustc_lint_diagnostics]
1016 pub fn span_suggestion_with_style(
1017 &mut self,
1018 sp: Span,
1019 msg: impl Into<SubdiagMessage>,
1020 suggestion: impl ToString,
1021 applicability: Applicability,
1022 style: SuggestionStyle,
1023 ) -> &mut Self {
1024 debug_assert!(
1025 !(sp.is_empty() && suggestion.to_string().is_empty()),
1026 "Span must not be empty and have no suggestion"
1027 );
1028 self.push_suggestion(CodeSuggestion {
1029 substitutions: vec![Substitution {
1030 parts: vec![SubstitutionPart { snippet: suggestion.to_string(), span: sp }],
1031 }],
1032 msg: self.subdiagnostic_message_to_diagnostic_message(msg),
1033 style,
1034 applicability,
1035 });
1036 self
1037 }
1038
1039 with_fn! { with_span_suggestion_verbose,
1040 #[rustc_lint_diagnostics]
1042 pub fn span_suggestion_verbose(
1043 &mut self,
1044 sp: Span,
1045 msg: impl Into<SubdiagMessage>,
1046 suggestion: impl ToString,
1047 applicability: Applicability,
1048 ) -> &mut Self {
1049 self.span_suggestion_with_style(
1050 sp,
1051 msg,
1052 suggestion,
1053 applicability,
1054 SuggestionStyle::ShowAlways,
1055 );
1056 self
1057 } }
1058
1059 with_fn! { with_span_suggestions,
1060 #[rustc_lint_diagnostics]
1063 pub fn span_suggestions(
1064 &mut self,
1065 sp: Span,
1066 msg: impl Into<SubdiagMessage>,
1067 suggestions: impl IntoIterator<Item = String>,
1068 applicability: Applicability,
1069 ) -> &mut Self {
1070 self.span_suggestions_with_style(
1071 sp,
1072 msg,
1073 suggestions,
1074 applicability,
1075 SuggestionStyle::ShowCode,
1076 )
1077 } }
1078
1079 #[rustc_lint_diagnostics]
1080 pub fn span_suggestions_with_style(
1081 &mut self,
1082 sp: Span,
1083 msg: impl Into<SubdiagMessage>,
1084 suggestions: impl IntoIterator<Item = String>,
1085 applicability: Applicability,
1086 style: SuggestionStyle,
1087 ) -> &mut Self {
1088 let substitutions = suggestions
1089 .into_iter()
1090 .map(|snippet| {
1091 debug_assert!(
1092 !(sp.is_empty() && snippet.is_empty()),
1093 "Span must not be empty and have no suggestion"
1094 );
1095 Substitution { parts: vec![SubstitutionPart { snippet, span: sp }] }
1096 })
1097 .collect();
1098 self.push_suggestion(CodeSuggestion {
1099 substitutions,
1100 msg: self.subdiagnostic_message_to_diagnostic_message(msg),
1101 style,
1102 applicability,
1103 });
1104 self
1105 }
1106
1107 #[rustc_lint_diagnostics]
1111 pub fn multipart_suggestions(
1112 &mut self,
1113 msg: impl Into<SubdiagMessage>,
1114 suggestions: impl IntoIterator<Item = Vec<(Span, String)>>,
1115 applicability: Applicability,
1116 ) -> &mut Self {
1117 let substitutions = suggestions
1118 .into_iter()
1119 .map(|sugg| {
1120 let mut parts = sugg
1121 .into_iter()
1122 .map(|(span, snippet)| SubstitutionPart { snippet, span })
1123 .collect::<Vec<_>>();
1124
1125 parts.sort_unstable_by_key(|part| part.span);
1126
1127 assert!(!parts.is_empty());
1128 debug_assert_eq!(
1129 parts.iter().find(|part| part.span.is_empty() && part.snippet.is_empty()),
1130 None,
1131 "Span must not be empty and have no suggestion",
1132 );
1133 debug_assert_eq!(
1134 parts.array_windows().find(|[a, b]| a.span.overlaps(b.span)),
1135 None,
1136 "suggestion must not have overlapping parts",
1137 );
1138
1139 Substitution { parts }
1140 })
1141 .collect();
1142
1143 self.push_suggestion(CodeSuggestion {
1144 substitutions,
1145 msg: self.subdiagnostic_message_to_diagnostic_message(msg),
1146 style: SuggestionStyle::ShowCode,
1147 applicability,
1148 });
1149 self
1150 }
1151
1152 with_fn! { with_span_suggestion_short,
1153 #[rustc_lint_diagnostics]
1158 pub fn span_suggestion_short(
1159 &mut self,
1160 sp: Span,
1161 msg: impl Into<SubdiagMessage>,
1162 suggestion: impl ToString,
1163 applicability: Applicability,
1164 ) -> &mut Self {
1165 self.span_suggestion_with_style(
1166 sp,
1167 msg,
1168 suggestion,
1169 applicability,
1170 SuggestionStyle::HideCodeInline,
1171 );
1172 self
1173 } }
1174
1175 #[rustc_lint_diagnostics]
1182 pub fn span_suggestion_hidden(
1183 &mut self,
1184 sp: Span,
1185 msg: impl Into<SubdiagMessage>,
1186 suggestion: impl ToString,
1187 applicability: Applicability,
1188 ) -> &mut Self {
1189 self.span_suggestion_with_style(
1190 sp,
1191 msg,
1192 suggestion,
1193 applicability,
1194 SuggestionStyle::HideCodeAlways,
1195 );
1196 self
1197 }
1198
1199 with_fn! { with_tool_only_span_suggestion,
1200 #[rustc_lint_diagnostics]
1205 pub fn tool_only_span_suggestion(
1206 &mut self,
1207 sp: Span,
1208 msg: impl Into<SubdiagMessage>,
1209 suggestion: impl ToString,
1210 applicability: Applicability,
1211 ) -> &mut Self {
1212 self.span_suggestion_with_style(
1213 sp,
1214 msg,
1215 suggestion,
1216 applicability,
1217 SuggestionStyle::CompletelyHidden,
1218 );
1219 self
1220 } }
1221
1222 #[rustc_lint_diagnostics]
1227 pub fn subdiagnostic(&mut self, subdiagnostic: impl Subdiagnostic) -> &mut Self {
1228 let dcx = self.dcx;
1229 subdiagnostic.add_to_diag_with(self, &|diag, msg| {
1230 let args = diag.args.iter();
1231 let msg = diag.subdiagnostic_message_to_diagnostic_message(msg);
1232 dcx.eagerly_translate(msg, args)
1233 });
1234 self
1235 }
1236
1237 with_fn! { with_span,
1238 #[rustc_lint_diagnostics]
1240 pub fn span(&mut self, sp: impl Into<MultiSpan>) -> &mut Self {
1241 self.span = sp.into();
1242 if let Some(span) = self.span.primary_span() {
1243 self.sort_span = span;
1244 }
1245 self
1246 } }
1247
1248 #[rustc_lint_diagnostics]
1249 pub fn is_lint(&mut self, name: String, has_future_breakage: bool) -> &mut Self {
1250 self.is_lint = Some(IsLint { name, has_future_breakage });
1251 self
1252 }
1253
1254 with_fn! { with_code,
1255 #[rustc_lint_diagnostics]
1257 pub fn code(&mut self, code: ErrCode) -> &mut Self {
1258 self.code = Some(code);
1259 self
1260 } }
1261
1262 with_fn! { with_primary_message,
1263 #[rustc_lint_diagnostics]
1265 pub fn primary_message(&mut self, msg: impl Into<DiagMessage>) -> &mut Self {
1266 self.messages[0] = (msg.into(), Style::NoStyle);
1267 self
1268 } }
1269
1270 with_fn! { with_arg,
1271 #[rustc_lint_diagnostics]
1273 pub fn arg(
1274 &mut self,
1275 name: impl Into<DiagArgName>,
1276 arg: impl IntoDiagArg,
1277 ) -> &mut Self {
1278 self.deref_mut().arg(name, arg);
1279 self
1280 } }
1281
1282 pub(crate) fn subdiagnostic_message_to_diagnostic_message(
1286 &self,
1287 attr: impl Into<SubdiagMessage>,
1288 ) -> DiagMessage {
1289 self.deref().subdiagnostic_message_to_diagnostic_message(attr)
1290 }
1291
1292 pub fn sub(&mut self, level: Level, message: impl Into<SubdiagMessage>, span: MultiSpan) {
1297 self.deref_mut().sub(level, message, span);
1298 }
1299
1300 fn sub_with_highlights(&mut self, level: Level, messages: Vec<StringPart>, span: MultiSpan) {
1303 let messages = messages
1304 .into_iter()
1305 .map(|m| (self.subdiagnostic_message_to_diagnostic_message(m.content), m.style))
1306 .collect();
1307 let sub = Subdiag { level, messages, span };
1308 self.children.push(sub);
1309 }
1310
1311 fn take_diag(&mut self) -> DiagInner {
1315 if let Some(path) = &self.long_ty_path {
1316 self.note(format!(
1317 "the full name for the type has been written to '{}'",
1318 path.display()
1319 ));
1320 self.note("consider using `--verbose` to print the full type name to the console");
1321 }
1322 Box::into_inner(self.diag.take().unwrap())
1323 }
1324
1325 pub fn long_ty_path(&mut self) -> &mut Option<PathBuf> {
1343 &mut self.long_ty_path
1344 }
1345
1346 fn emit_producing_nothing(mut self) {
1348 let diag = self.take_diag();
1349 self.dcx.emit_diagnostic(diag);
1350 }
1351
1352 fn emit_producing_error_guaranteed(mut self) -> ErrorGuaranteed {
1354 let diag = self.take_diag();
1355
1356 assert!(
1365 matches!(diag.level, Level::Error | Level::DelayedBug),
1366 "invalid diagnostic level ({:?})",
1367 diag.level,
1368 );
1369
1370 let guar = self.dcx.emit_diagnostic(diag);
1371 guar.unwrap()
1372 }
1373
1374 #[track_caller]
1376 pub fn emit(self) -> G::EmitResult {
1377 G::emit_producing_guarantee(self)
1378 }
1379
1380 #[track_caller]
1385 pub fn emit_unless(mut self, delay: bool) -> G::EmitResult {
1386 if delay {
1387 self.downgrade_to_delayed_bug();
1388 }
1389 self.emit()
1390 }
1391
1392 pub fn cancel(mut self) {
1395 self.diag = None;
1396 drop(self);
1397 }
1398
1399 pub fn stash(mut self, span: Span, key: StashKey) -> Option<ErrorGuaranteed> {
1401 let diag = self.take_diag();
1402 self.dcx.stash_diagnostic(span, key, diag)
1403 }
1404
1405 #[track_caller]
1416 pub fn delay_as_bug(mut self) -> G::EmitResult {
1417 self.downgrade_to_delayed_bug();
1418 self.emit()
1419 }
1420}
1421
1422impl<G: EmissionGuarantee> Drop for Diag<'_, G> {
1425 fn drop(&mut self) {
1426 match self.diag.take() {
1427 Some(diag) if !panicking() => {
1428 self.dcx.emit_diagnostic(DiagInner::new(
1429 Level::Bug,
1430 DiagMessage::from("the following error was constructed but not emitted"),
1431 ));
1432 self.dcx.emit_diagnostic(*diag);
1433 panic!("error was constructed but not emitted");
1434 }
1435 _ => {}
1436 }
1437 }
1438}
1439
1440#[macro_export]
1441macro_rules! struct_span_code_err {
1442 ($dcx:expr, $span:expr, $code:expr, $($message:tt)*) => ({
1443 $dcx.struct_span_err($span, format!($($message)*)).with_code($code)
1444 })
1445}