From 9b841a9a044d9d71cece62a3e44880325bc15f78 Mon Sep 17 00:00:00 2001 From: Dawer <7803845+iDawer@users.noreply.github.com> Date: Sat, 8 May 2021 23:06:17 +0500 Subject: Expand binding patterns. --- crates/hir_ty/src/diagnostics/pattern.rs | 98 +++++++++++++++++++++- .../hir_ty/src/diagnostics/pattern/usefulness.rs | 18 +++- 2 files changed, 110 insertions(+), 6 deletions(-) (limited to 'crates') 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> { } } +pub(crate) trait PatternFoldable: Sized { + fn fold_with(&self, folder: &mut F) -> Self { + self.super_fold_with(folder) + } + + fn super_fold_with(&self, folder: &mut F) -> Self; +} + +pub(crate) trait PatternFolder: Sized { + fn fold_pattern(&mut self, pattern: &Pat) -> Pat { + pattern.super_fold_with(self) + } + + fn fold_pattern_kind(&mut self, kind: &PatKind) -> PatKind { + kind.super_fold_with(self) + } +} + +impl PatternFoldable for Box { + fn super_fold_with(&self, folder: &mut F) -> Self { + let content: T = (**self).fold_with(folder); + Box::new(content) + } +} + +impl PatternFoldable for Vec { + fn super_fold_with(&self, folder: &mut F) -> Self { + self.iter().map(|t| t.fold_with(folder)).collect() + } +} + +impl PatternFoldable for Option { + fn super_fold_with(&self, folder: &mut F) -> Self { + self.as_ref().map(|t| t.fold_with(folder)) + } +} + +macro_rules! clone_impls { + ($($ty:ty),+) => { + $( + impl PatternFoldable for $ty { + fn super_fold_with(&self, _: &mut F) -> Self { + Clone::clone(self) + } + } + )+ + } +} + +clone_impls! { LocalFieldId, Ty, Substitution, EnumVariantId } + +impl PatternFoldable for FieldPat { + fn super_fold_with(&self, folder: &mut F) -> Self { + FieldPat { field: self.field.fold_with(folder), pattern: self.pattern.fold_with(folder) } + } +} + +impl PatternFoldable for Pat { + fn fold_with(&self, folder: &mut F) -> Self { + folder.fold_pattern(self) + } + + fn super_fold_with(&self, folder: &mut F) -> Self { + Pat { ty: self.ty.fold_with(folder), kind: self.kind.fold_with(folder) } + } +} + +impl PatternFoldable for PatKind { + fn fold_with(&self, folder: &mut F) -> Self { + folder.fold_pattern_kind(self) + } + + fn super_fold_with(&self, folder: &mut F) -> Self { + match self { + PatKind::Wild => PatKind::Wild, + PatKind::Binding { subpattern } => { + PatKind::Binding { subpattern: subpattern.fold_with(folder) } + } + PatKind::Variant { substs, enum_variant, subpatterns } => PatKind::Variant { + substs: substs.fold_with(folder), + enum_variant: enum_variant.fold_with(folder), + subpatterns: subpatterns.fold_with(folder), + }, + PatKind::Leaf { subpatterns } => { + PatKind::Leaf { subpatterns: subpatterns.fold_with(folder) } + } + PatKind::Deref { subpattern } => { + PatKind::Deref { subpattern: subpattern.fold_with(folder) } + } + &PatKind::LiteralBool { value } => PatKind::LiteralBool { value }, + PatKind::Or { pats } => PatKind::Or { pats: pats.fold_with(folder) }, + } + } +} + #[cfg(test)] mod tests { use crate::diagnostics::tests::check_diagnostics; @@ -410,9 +505,8 @@ fn main() { _x @ true => {} false => {} } - //FIXME: false negative. - // Binding patterns should be expanded in `usefulness::expand_pattern()` match true { _x @ true => {} } + //^^^^ Missing match arm } "#, ); 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; use rustc_hash::FxHashMap; use smallvec::{smallvec, SmallVec}; -use crate::{db::HirDatabase, InferenceResult, Ty}; +use crate::{db::HirDatabase, InferenceResult, Interner, Ty}; use super::{ deconstruct_pat::{Constructor, Fields, SplitWildcard}, - Pat, PatId, PatKind, + Pat, PatId, PatKind, PatternFoldable, PatternFolder, }; use self::{ @@ -75,8 +75,18 @@ pub(super) struct PatCtxt<'a> { } pub(crate) fn expand_pattern(pat: Pat) -> Pat { - // TODO: LiteralExpander, it is about string literal patterns - pat + LiteralExpander.fold_pattern(&pat) +} + +struct LiteralExpander; + +impl PatternFolder for LiteralExpander { + fn fold_pattern(&mut self, pat: &Pat) -> Pat { + match (pat.ty.kind(&Interner), pat.kind.as_ref()) { + (_, PatKind::Binding { subpattern: Some(s), .. }) => s.fold_with(self), + _ => pat.super_fold_with(self), + } + } } impl Pat { -- cgit v1.2.3