diff options
-rw-r--r-- | crates/hir_ty/src/diagnostics/pattern.rs | 98 | ||||
-rw-r--r-- | crates/hir_ty/src/diagnostics/pattern/usefulness.rs | 18 |
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 | ||
242 | pub(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 | |||
250 | pub(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 | |||
260 | impl<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 | |||
267 | impl<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 | |||
273 | impl<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 | |||
279 | macro_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 | |||
291 | clone_impls! { LocalFieldId, Ty, Substitution, EnumVariantId } | ||
292 | |||
293 | impl 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 | |||
299 | impl 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 | |||
309 | impl 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)] |
243 | mod tests { | 338 | mod 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; | |||
9 | use rustc_hash::FxHashMap; | 9 | use rustc_hash::FxHashMap; |
10 | use smallvec::{smallvec, SmallVec}; | 10 | use smallvec::{smallvec, SmallVec}; |
11 | 11 | ||
12 | use crate::{db::HirDatabase, InferenceResult, Ty}; | 12 | use crate::{db::HirDatabase, InferenceResult, Interner, Ty}; |
13 | 13 | ||
14 | use super::{ | 14 | use 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 | ||
19 | use self::{ | 19 | use self::{ |
@@ -75,8 +75,18 @@ pub(super) struct PatCtxt<'a> { | |||
75 | } | 75 | } |
76 | 76 | ||
77 | pub(crate) fn expand_pattern(pat: Pat) -> Pat { | 77 | pub(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 | |||
81 | struct LiteralExpander; | ||
82 | |||
83 | impl 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 | ||
82 | impl Pat { | 92 | impl Pat { |