lisette_diagnostics/
pattern.rs1use crate::LisetteDiagnostic;
2use syntax::ast::Span;
3
4use crate::IssueKind;
5
6#[derive(Debug, Clone)]
7pub struct PatternIssue {
8 pub span: Span,
9 pub kind: IssueKind,
10}
11
12pub fn non_exhaustive(match_span: Span, case: &str) -> LisetteDiagnostic {
13 LisetteDiagnostic::error("`match` is not exhaustive")
14 .with_infer_code("non_exhaustive")
15 .with_span_label(&match_span, "not all patterns covered")
16 .with_help(format!(
17 "Handle the missing case `{}`, e.g. `{} => {{ ... }}`",
18 case, case
19 ))
20}
21
22pub fn irrefutable_while_let(pattern_span: Span) -> LisetteDiagnostic {
23 LisetteDiagnostic::error("Pattern always matches")
24 .with_infer_code("irrefutable_while_let")
25 .with_span_label(&pattern_span, "always matches")
26 .with_help("Use `loop` with `let` binding instead")
27}
28
29pub fn redundant_arm(
30 span: Span,
31 label: impl Into<String>,
32 help: impl Into<String>,
33) -> LisetteDiagnostic {
34 LisetteDiagnostic::error("Unreachable pattern")
35 .with_infer_code("redundant_arm")
36 .with_span_label(&span, label)
37 .with_help(help)
38}
39
40pub fn refutable_pattern(
41 pattern_span: Span,
42 witness: &str,
43 slice_info: Option<(usize, bool)>,
44) -> LisetteDiagnostic {
45 let label = describe_pattern_expectation(witness, slice_info);
46 let help = build_refutability_help(witness);
47
48 LisetteDiagnostic::error("Pattern might not match")
49 .with_infer_code("refutable_pattern")
50 .with_span_label(&pattern_span, label)
51 .with_help(help)
52}
53
54fn describe_pattern_expectation(witness: &str, slice_info: Option<(usize, bool)>) -> String {
55 if witness.starts_with('[') {
56 if let Some((len, has_rest)) = slice_info {
57 if has_rest {
58 return format!("only matches {} or more elements", len);
59 }
60 let word = if len == 1 { "element" } else { "elements" };
61 return format!("only matches {} {}", len, word);
62 }
63
64 return "only matches specific length".to_string();
65 }
66
67 if witness.contains("None") {
68 return "only matches `Some`".to_string();
69 }
70
71 if witness.contains("Err") {
72 return "only matches `Ok`".to_string();
73 }
74
75 format!("does not match `{}`", witness)
76}
77
78fn build_refutability_help(witness: &str) -> String {
79 if witness.starts_with('[') {
80 return r#"Use `match` to handle slices of any length:
81 match slice {
82 [a, b] => ...,
83 _ => ...,
84 }"#
85 .to_string();
86 }
87
88 if witness.contains("None") {
89 return r#"Use `if let` to handle only `Some`:
90 if let Some(x) = opt {
91 ...
92 }
93Or use `match` to also handle `None`:
94 match opt {
95 Some(x) => ...,
96 None => ...,
97 }"#
98 .to_string();
99 }
100
101 if witness.contains("Err") {
102 return r#"Use `if let` to handle only `Ok`:
103 if let Ok(x) = result {
104 ...
105 }
106Or use `match` to also handle `Err`:
107 match result {
108 Ok(x) => ...,
109 Err(e) => ...,
110 }"#
111 .to_string();
112 }
113
114 format!(
115 "Use `match` to handle all cases:\n match value {{\n {} => ...,\n _ => ...,\n }}",
116 witness
117 )
118}