rustc_pattern_analysis/
errors.rs

1use rustc_errors::{Diag, EmissionGuarantee, SubdiagMessageOp, Subdiagnostic};
2use rustc_macros::{LintDiagnostic, Subdiagnostic};
3use rustc_middle::ty::Ty;
4use rustc_span::Span;
5
6use crate::rustc::{RustcPatCtxt, WitnessPat};
7
8#[derive(Subdiagnostic)]
9#[label(pattern_analysis_uncovered)]
10pub struct Uncovered {
11    #[primary_span]
12    span: Span,
13    count: usize,
14    witness_1: String, // a printed pattern
15    witness_2: String, // a printed pattern
16    witness_3: String, // a printed pattern
17    remainder: usize,
18}
19
20impl Uncovered {
21    pub fn new<'p, 'tcx>(
22        span: Span,
23        cx: &RustcPatCtxt<'p, 'tcx>,
24        witnesses: Vec<WitnessPat<'p, 'tcx>>,
25    ) -> Self
26    where
27        'tcx: 'p,
28    {
29        let witness_1 = cx.print_witness_pat(witnesses.get(0).unwrap());
30        Self {
31            span,
32            count: witnesses.len(),
33            // Substitute dummy values if witnesses is smaller than 3. These will never be read.
34            witness_2: witnesses.get(1).map(|w| cx.print_witness_pat(w)).unwrap_or_default(),
35            witness_3: witnesses.get(2).map(|w| cx.print_witness_pat(w)).unwrap_or_default(),
36            witness_1,
37            remainder: witnesses.len().saturating_sub(3),
38        }
39    }
40}
41
42#[derive(LintDiagnostic)]
43#[diag(pattern_analysis_overlapping_range_endpoints)]
44#[note]
45pub struct OverlappingRangeEndpoints {
46    #[label]
47    pub range: Span,
48    #[subdiagnostic]
49    pub overlap: Vec<Overlap>,
50}
51
52pub struct Overlap {
53    pub span: Span,
54    pub range: String, // a printed pattern
55}
56
57impl Subdiagnostic for Overlap {
58    fn add_to_diag_with<G: EmissionGuarantee, F: SubdiagMessageOp<G>>(
59        self,
60        diag: &mut Diag<'_, G>,
61        _: &F,
62    ) {
63        let Overlap { span, range } = self;
64
65        // FIXME(mejrs) unfortunately `#[derive(LintDiagnostic)]`
66        // does not support `#[subdiagnostic(eager)]`...
67        let message = format!("this range overlaps on `{range}`...");
68        diag.span_label(span, message);
69    }
70}
71
72#[derive(LintDiagnostic)]
73#[diag(pattern_analysis_excluside_range_missing_max)]
74pub struct ExclusiveRangeMissingMax {
75    #[label]
76    #[suggestion(code = "{suggestion}", applicability = "maybe-incorrect")]
77    /// This is an exclusive range that looks like `lo..max` (i.e. doesn't match `max`).
78    pub first_range: Span,
79    /// Suggest `lo..=max` instead.
80    pub suggestion: String,
81    pub max: String, // a printed pattern
82}
83
84#[derive(LintDiagnostic)]
85#[diag(pattern_analysis_excluside_range_missing_gap)]
86pub struct ExclusiveRangeMissingGap {
87    #[label]
88    #[suggestion(code = "{suggestion}", applicability = "maybe-incorrect")]
89    /// This is an exclusive range that looks like `lo..gap` (i.e. doesn't match `gap`).
90    pub first_range: Span,
91    pub gap: String, // a printed pattern
92    /// Suggest `lo..=gap` instead.
93    pub suggestion: String,
94    #[subdiagnostic]
95    /// All these ranges skipped over `gap` which we think is probably a mistake.
96    pub gap_with: Vec<GappedRange>,
97}
98
99pub struct GappedRange {
100    pub span: Span,
101    pub gap: String,         // a printed pattern
102    pub first_range: String, // a printed pattern
103}
104
105impl Subdiagnostic for GappedRange {
106    fn add_to_diag_with<G: EmissionGuarantee, F: SubdiagMessageOp<G>>(
107        self,
108        diag: &mut Diag<'_, G>,
109        _: &F,
110    ) {
111        let GappedRange { span, gap, first_range } = self;
112
113        // FIXME(mejrs) unfortunately `#[derive(LintDiagnostic)]`
114        // does not support `#[subdiagnostic(eager)]`...
115        let message = format!(
116            "this could appear to continue range `{first_range}`, but `{gap}` isn't matched by \
117            either of them"
118        );
119        diag.span_label(span, message);
120    }
121}
122
123#[derive(LintDiagnostic)]
124#[diag(pattern_analysis_non_exhaustive_omitted_pattern)]
125#[help]
126#[note]
127pub(crate) struct NonExhaustiveOmittedPattern<'tcx> {
128    pub scrut_ty: Ty<'tcx>,
129    #[subdiagnostic]
130    pub uncovered: Uncovered,
131}
132
133#[derive(LintDiagnostic)]
134#[diag(pattern_analysis_non_exhaustive_omitted_pattern_lint_on_arm)]
135#[help]
136pub(crate) struct NonExhaustiveOmittedPatternLintOnArm {
137    #[label]
138    pub lint_span: Span,
139    #[suggestion(code = "#[{lint_level}({lint_name})]\n", applicability = "maybe-incorrect")]
140    pub suggest_lint_on_match: Option<Span>,
141    pub lint_level: &'static str,
142    pub lint_name: &'static str,
143}