aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--crates/hir_ty/src/diagnostics/pattern.rs98
-rw-r--r--crates/hir_ty/src/diagnostics/pattern/usefulness.rs18
2 files changed, 110 insertions, 6 deletions
diff --git a/crates/hir_ty/src/diagnostics/pattern.rs b/crates/hir_ty/src/diagnostics/pattern.rs
index 9f65e38d6..d98fb0867 100644
--- a/crates/hir_ty/src/diagnostics/pattern.rs
+++ b/crates/hir_ty/src/diagnostics/pattern.rs
@@ -239,6 +239,101 @@ impl<'a> PatCtxt<'a> {
239 } 239 }
240} 240}
241 241
242pub(crate) trait PatternFoldable: Sized {
243 fn fold_with<F: PatternFolder>(&self, folder: &mut F) -> Self {
244 self.super_fold_with(folder)
245 }
246
247 fn super_fold_with<F: PatternFolder>(&self, folder: &mut F) -> Self;
248}
249
250pub(crate) trait PatternFolder: Sized {
251 fn fold_pattern(&mut self, pattern: &Pat) -> Pat {
252 pattern.super_fold_with(self)
253 }
254
255 fn fold_pattern_kind(&mut self, kind: &PatKind) -> PatKind {
256 kind.super_fold_with(self)
257 }
258}
259
260impl<T: PatternFoldable> PatternFoldable for Box<T> {
261 fn super_fold_with<F: PatternFolder>(&self, folder: &mut F) -> Self {
262 let content: T = (**self).fold_with(folder);
263 Box::new(content)
264 }
265}
266
267impl<T: PatternFoldable> PatternFoldable for Vec<T> {
268 fn super_fold_with<F: PatternFolder>(&self, folder: &mut F) -> Self {
269 self.iter().map(|t| t.fold_with(folder)).collect()
270 }
271}
272
273impl<T: PatternFoldable> PatternFoldable for Option<T> {
274 fn super_fold_with<F: PatternFolder>(&self, folder: &mut F) -> Self {
275 self.as_ref().map(|t| t.fold_with(folder))
276 }
277}
278
279macro_rules! clone_impls {
280 ($($ty:ty),+) => {
281 $(
282 impl PatternFoldable for $ty {
283 fn super_fold_with<F: PatternFolder>(&self, _: &mut F) -> Self {
284 Clone::clone(self)
285 }
286 }
287 )+
288 }
289}
290
291clone_impls! { LocalFieldId, Ty, Substitution, EnumVariantId }
292
293impl PatternFoldable for FieldPat {
294 fn super_fold_with<F: PatternFolder>(&self, folder: &mut F) -> Self {
295 FieldPat { field: self.field.fold_with(folder), pattern: self.pattern.fold_with(folder) }
296 }
297}
298
299impl PatternFoldable for Pat {
300 fn fold_with<F: PatternFolder>(&self, folder: &mut F) -> Self {
301 folder.fold_pattern(self)
302 }
303
304 fn super_fold_with<F: PatternFolder>(&self, folder: &mut F) -> Self {
305 Pat { ty: self.ty.fold_with(folder), kind: self.kind.fold_with(folder) }
306 }
307}
308
309impl PatternFoldable for PatKind {
310 fn fold_with<F: PatternFolder>(&self, folder: &mut F) -> Self {
311 folder.fold_pattern_kind(self)
312 }
313
314 fn super_fold_with<F: PatternFolder>(&self, folder: &mut F) -> Self {
315 match self {
316 PatKind::Wild => PatKind::Wild,
317 PatKind::Binding { subpattern } => {
318 PatKind::Binding { subpattern: subpattern.fold_with(folder) }
319 }
320 PatKind::Variant { substs, enum_variant, subpatterns } => PatKind::Variant {
321 substs: substs.fold_with(folder),
322 enum_variant: enum_variant.fold_with(folder),
323 subpatterns: subpatterns.fold_with(folder),
324 },
325 PatKind::Leaf { subpatterns } => {
326 PatKind::Leaf { subpatterns: subpatterns.fold_with(folder) }
327 }
328 PatKind::Deref { subpattern } => {
329 PatKind::Deref { subpattern: subpattern.fold_with(folder) }
330 }
331 &PatKind::LiteralBool { value } => PatKind::LiteralBool { value },
332 PatKind::Or { pats } => PatKind::Or { pats: pats.fold_with(folder) },
333 }
334 }
335}
336
242#[cfg(test)] 337#[cfg(test)]
243mod tests { 338mod tests {
244 use crate::diagnostics::tests::check_diagnostics; 339 use crate::diagnostics::tests::check_diagnostics;
@@ -410,9 +505,8 @@ fn main() {
410 _x @ true => {} 505 _x @ true => {}
411 false => {} 506 false => {}
412 } 507 }
413 //FIXME: false negative.
414 // Binding patterns should be expanded in `usefulness::expand_pattern()`
415 match true { _x @ true => {} } 508 match true { _x @ true => {} }
509 //^^^^ Missing match arm
416} 510}
417"#, 511"#,
418 ); 512 );
diff --git a/crates/hir_ty/src/diagnostics/pattern/usefulness.rs b/crates/hir_ty/src/diagnostics/pattern/usefulness.rs
index 76dc4412f..ef2be7530 100644
--- a/crates/hir_ty/src/diagnostics/pattern/usefulness.rs
+++ b/crates/hir_ty/src/diagnostics/pattern/usefulness.rs
@@ -9,11 +9,11 @@ use once_cell::unsync::OnceCell;
9use rustc_hash::FxHashMap; 9use rustc_hash::FxHashMap;
10use smallvec::{smallvec, SmallVec}; 10use smallvec::{smallvec, SmallVec};
11 11
12use crate::{db::HirDatabase, InferenceResult, Ty}; 12use crate::{db::HirDatabase, InferenceResult, Interner, Ty};
13 13
14use super::{ 14use super::{
15 deconstruct_pat::{Constructor, Fields, SplitWildcard}, 15 deconstruct_pat::{Constructor, Fields, SplitWildcard},
16 Pat, PatId, PatKind, 16 Pat, PatId, PatKind, PatternFoldable, PatternFolder,
17}; 17};
18 18
19use self::{ 19use self::{
@@ -75,8 +75,18 @@ pub(super) struct PatCtxt<'a> {
75} 75}
76 76
77pub(crate) fn expand_pattern(pat: Pat) -> Pat { 77pub(crate) fn expand_pattern(pat: Pat) -> Pat {
78 // TODO: LiteralExpander, it is about string literal patterns 78 LiteralExpander.fold_pattern(&pat)
79 pat 79}
80
81struct LiteralExpander;
82
83impl PatternFolder for LiteralExpander {
84 fn fold_pattern(&mut self, pat: &Pat) -> Pat {
85 match (pat.ty.kind(&Interner), pat.kind.as_ref()) {
86 (_, PatKind::Binding { subpattern: Some(s), .. }) => s.fold_with(self),
87 _ => pat.super_fold_with(self),
88 }
89 }
80} 90}
81 91
82impl Pat { 92impl Pat {