aboutsummaryrefslogtreecommitdiff
path: root/crates/hir_ty/src/diagnostics/pattern/deconstruct_pat.rs
diff options
context:
space:
mode:
Diffstat (limited to 'crates/hir_ty/src/diagnostics/pattern/deconstruct_pat.rs')
-rw-r--r--crates/hir_ty/src/diagnostics/pattern/deconstruct_pat.rs188
1 files changed, 81 insertions, 107 deletions
diff --git a/crates/hir_ty/src/diagnostics/pattern/deconstruct_pat.rs b/crates/hir_ty/src/diagnostics/pattern/deconstruct_pat.rs
index 248a379b3..479e0dc73 100644
--- a/crates/hir_ty/src/diagnostics/pattern/deconstruct_pat.rs
+++ b/crates/hir_ty/src/diagnostics/pattern/deconstruct_pat.rs
@@ -5,18 +5,18 @@ use std::{
5}; 5};
6 6
7use hir_def::{ 7use hir_def::{
8 expr::{Expr, Literal, Pat, PatId, RecordFieldPat}, 8 expr::{Expr, Literal, RecordFieldPat},
9 find_path::find_path,
10 item_scope::ItemInNs,
11 path::Path,
12 type_ref::Mutability, 9 type_ref::Mutability,
13 AttrDefId, EnumVariantId, HasModule, VariantId, 10 AttrDefId, EnumVariantId, HasModule, LocalFieldId, VariantId,
14}; 11};
15use smallvec::{smallvec, SmallVec}; 12use smallvec::{smallvec, SmallVec};
16 13
17use crate::{AdtId, Interner, Scalar, Ty, TyExt, TyKind}; 14use crate::{AdtId, Interner, Scalar, Ty, TyExt, TyKind};
18 15
19use super::usefulness::{MatchCheckCtx, PatCtxt}; 16use super::{
17 usefulness::{MatchCheckCtx, PatCtxt},
18 FieldPat, Pat, PatId, PatKind,
19};
20 20
21use self::Constructor::*; 21use self::Constructor::*;
22 22
@@ -271,29 +271,18 @@ impl Constructor {
271 /// Determines the constructor that the given pattern can be specialized to. 271 /// Determines the constructor that the given pattern can be specialized to.
272 pub(super) fn from_pat(cx: &MatchCheckCtx<'_>, pat: PatId) -> Self { 272 pub(super) fn from_pat(cx: &MatchCheckCtx<'_>, pat: PatId) -> Self {
273 let ty = cx.type_of(pat); 273 let ty = cx.type_of(pat);
274 match &cx.pattern_arena.borrow()[pat] { 274 match cx.pattern_arena.borrow()[pat].kind.as_ref() {
275 Pat::Bind { .. } | Pat::Wild => Wildcard, 275 PatKind::Binding { .. } | PatKind::Wild => Wildcard,
276 Pat::Tuple { .. } | Pat::Ref { .. } | Pat::Box { .. } => Single, 276 PatKind::Leaf { .. } | PatKind::Deref { .. } => Single,
277 Pat::Record { .. } | Pat::Path(_) | Pat::TupleStruct { .. } => { 277 &PatKind::Variant { enum_variant, .. } => Variant(enum_variant),
278 // TODO: path to const 278
279 let variant_id = 279 //Todo
280 cx.infer.variant_resolution_for_pat(pat).unwrap_or_else(|| todo!()); 280 // &Pat::Lit(expr_id) => match cx.body[expr_id] {
281 match variant_id { 281 // Expr::Literal(Literal::Bool(val)) => IntRange(IntRange::from_bool(val)),
282 VariantId::EnumVariantId(id) => Variant(id), 282 // _ => todo!(),
283 VariantId::StructId(_) | VariantId::UnionId(_) => Single, 283 // },
284 } 284 PatKind::Or { .. } => panic!("bug: Or-pattern should have been expanded earlier on."),
285 }
286 &Pat::Lit(expr_id) => match cx.body[expr_id] {
287 Expr::Literal(Literal::Bool(val)) => IntRange(IntRange::from_bool(val)),
288 _ => todo!(),
289 },
290
291 Pat::Or(..) => panic!("bug: Or-pattern should have been expanded earlier on."),
292 Pat::Missing => todo!("Fail gracefully when there is an error in a pattern"),
293 pat => todo!("Constructor::from_pat {:?}", pat), 285 pat => todo!("Constructor::from_pat {:?}", pat),
294 // Pat::Range { start, end } => {}
295 // Pat::Slice { prefix, slice, suffix } => {}
296 // Pat::ConstBlock(_) => {}
297 } 286 }
298 } 287 }
299 288
@@ -620,15 +609,15 @@ impl Fields {
620 cx: &MatchCheckCtx<'_>, 609 cx: &MatchCheckCtx<'_>,
621 tys: impl IntoIterator<Item = &'a Ty>, 610 tys: impl IntoIterator<Item = &'a Ty>,
622 ) -> Self { 611 ) -> Self {
623 let wilds = tys.into_iter().map(|ty| (Pat::Wild, ty)); 612 let wilds = tys.into_iter().map(Pat::wildcard_from_ty);
624 let pats = wilds.map(|(pat, ty)| cx.alloc_pat(pat, ty)).collect(); 613 let pats = wilds.map(|pat| cx.alloc_pat(pat)).collect();
625 Fields::Vec(pats) 614 Fields::Vec(pats)
626 } 615 }
627 616
628 pub(crate) fn wildcards(pcx: PatCtxt<'_>, constructor: &Constructor) -> Self { 617 pub(crate) fn wildcards(pcx: PatCtxt<'_>, constructor: &Constructor) -> Self {
629 let ty = pcx.ty; 618 let ty = pcx.ty;
630 let cx = pcx.cx; 619 let cx = pcx.cx;
631 let wildcard_from_ty = |ty| cx.alloc_pat(Pat::Wild, ty); 620 let wildcard_from_ty = |ty| cx.alloc_pat(Pat::wildcard_from_ty(ty));
632 621
633 let ret = match constructor { 622 let ret = match constructor {
634 Single | Variant(_) => match ty.kind(&Interner) { 623 Single | Variant(_) => match ty.kind(&Interner) {
@@ -696,64 +685,60 @@ impl Fields {
696 /// returns `Some(false)` 685 /// returns `Some(false)`
697 pub(super) fn apply(self, pcx: PatCtxt<'_>, ctor: &Constructor) -> Pat { 686 pub(super) fn apply(self, pcx: PatCtxt<'_>, ctor: &Constructor) -> Pat {
698 let subpatterns_and_indices = self.patterns_and_indices(); 687 let subpatterns_and_indices = self.patterns_and_indices();
699 let mut subpatterns = subpatterns_and_indices.iter().map(|&(_, p)| p); 688 let mut subpatterns =
700 // TODO witnesses are not yet used 689 subpatterns_and_indices.iter().map(|&(_, p)| pcx.cx.pattern_arena.borrow()[p].clone());
701 const TODO: Pat = Pat::Wild; 690 // FIXME(iDawer) witnesses are not yet used
691 const UNIMPLEMENTED: PatKind = PatKind::Wild;
702 692
703 match ctor { 693 let pat = match ctor {
704 Single | Variant(_) => match pcx.ty.kind(&Interner) { 694 Single | Variant(_) => match pcx.ty.kind(&Interner) {
705 TyKind::Adt(..) | TyKind::Tuple(..) => { 695 TyKind::Adt(..) | TyKind::Tuple(..) => {
706 // We want the real indices here. 696 // We want the real indices here.
707 // TODO indices and ellipsis interaction, tests 697 let subpatterns = subpatterns_and_indices
708 let subpatterns = subpatterns_and_indices.iter().map(|&(_, pat)| pat).collect(); 698 .iter()
699 .map(|&(field, pat)| FieldPat {
700 field,
701 pattern: pcx.cx.pattern_arena.borrow()[pat].clone(),
702 })
703 .collect();
709 704
710 if let Some((adt, substs)) = pcx.ty.as_adt() { 705 if let Some((adt, substs)) = pcx.ty.as_adt() {
711 let item = ItemInNs::Types(adt.into()); 706 if let hir_def::AdtId::EnumId(_) = adt {
712 let path = find_path(pcx.cx.db.upcast(), item, pcx.cx.module) 707 let enum_variant = match ctor {
713 .map(|mpath| Path::from_known_path(mpath, Vec::new()).into()); 708 &Variant(id) => id,
714 match adt { 709 _ => unreachable!(),
715 hir_def::AdtId::EnumId(id) => TODO, 710 };
716 hir_def::AdtId::StructId(id) => { 711 PatKind::Variant { substs: substs.clone(), enum_variant, subpatterns }
717 let variant_data = &pcx.cx.db.struct_data(id).variant_data; 712 } else {
718 let args = subpatterns_and_indices 713 PatKind::Leaf { subpatterns }
719 .iter()
720 .zip(variant_data.fields().iter())
721 .map(|(&(_, pat), (_, field_data))| RecordFieldPat {
722 name: field_data.name.clone(),
723 pat,
724 })
725 .collect();
726 Pat::Record { path, args, ellipsis: false }
727 }
728 hir_def::AdtId::UnionId(_) => Pat::Wild,
729 } 714 }
730 } else { 715 } else {
731 Pat::Tuple { args: subpatterns, ellipsis: None } 716 PatKind::Leaf { subpatterns }
732 } 717 }
733 } 718 }
734 // Note: given the expansion of `&str` patterns done in `expand_pattern`, we should 719 // Note: given the expansion of `&str` patterns done in `expand_pattern`, we should
735 // be careful to reconstruct the correct constant pattern here. However a string 720 // be careful to reconstruct the correct constant pattern here. However a string
736 // literal pattern will never be reported as a non-exhaustiveness witness, so we 721 // literal pattern will never be reported as a non-exhaustiveness witness, so we
737 // can ignore this issue. 722 // can ignore this issue.
738 TyKind::Ref(..) => { 723 TyKind::Ref(..) => PatKind::Deref { subpattern: subpatterns.next().unwrap() },
739 Pat::Ref { pat: subpatterns.next().unwrap(), mutability: Mutability::Shared }
740 }
741 TyKind::Slice(..) | TyKind::Array(..) => { 724 TyKind::Slice(..) | TyKind::Array(..) => {
742 panic!("bug: bad slice pattern {:?} {:?}", ctor, pcx.ty) 725 panic!("bug: bad slice pattern {:?} {:?}", ctor, pcx.ty)
743 } 726 }
744 _ => Pat::Wild, 727 _ => PatKind::Wild,
745 }, 728 },
746 Constructor::Slice(slice) => TODO, 729 Constructor::Slice(slice) => UNIMPLEMENTED,
747 Str(_) => TODO, 730 Str(_) => UNIMPLEMENTED,
748 FloatRange(..) => TODO, 731 FloatRange(..) => UNIMPLEMENTED,
749 Constructor::IntRange(_) => TODO, 732 Constructor::IntRange(_) => UNIMPLEMENTED,
750 NonExhaustive => Pat::Wild, 733 NonExhaustive => PatKind::Wild,
751 Wildcard => Pat::Wild, 734 Wildcard => return Pat::wildcard_from_ty(pcx.ty),
752 Opaque => panic!("bug: we should not try to apply an opaque constructor"), 735 Opaque => panic!("bug: we should not try to apply an opaque constructor"),
753 Missing => { 736 Missing => {
754 panic!("bug: trying to apply the `Missing` constructor; this should have been done in `apply_constructors`") 737 panic!("bug: trying to apply the `Missing` constructor; this should have been done in `apply_constructors`")
755 } 738 }
756 } 739 };
740
741 Pat { ty: pcx.ty.clone(), kind: Box::new(pat) }
757 } 742 }
758 743
759 /// Returns the number of patterns. This is the same as the arity of the constructor used to 744 /// Returns the number of patterns. This is the same as the arity of the constructor used to
@@ -765,9 +750,14 @@ impl Fields {
765 } 750 }
766 751
767 /// Returns the list of patterns along with the corresponding field indices. 752 /// Returns the list of patterns along with the corresponding field indices.
768 fn patterns_and_indices(&self) -> SmallVec<[(usize, PatId); 2]> { 753 fn patterns_and_indices(&self) -> SmallVec<[(LocalFieldId, PatId); 2]> {
769 match self { 754 match self {
770 Fields::Vec(pats) => pats.iter().copied().enumerate().collect(), 755 Fields::Vec(pats) => pats
756 .iter()
757 .copied()
758 .enumerate()
759 .map(|(i, p)| (LocalFieldId::from_raw((i as u32).into()), p))
760 .collect(),
771 } 761 }
772 } 762 }
773 763
@@ -779,8 +769,13 @@ impl Fields {
779 769
780 /// Overrides some of the fields with the provided patterns. Exactly like 770 /// Overrides some of the fields with the provided patterns. Exactly like
781 /// `replace_fields_indexed`, except that it takes `FieldPat`s as input. 771 /// `replace_fields_indexed`, except that it takes `FieldPat`s as input.
782 fn replace_with_fieldpats(&self, new_pats: impl IntoIterator<Item = PatId>) -> Self { 772 fn replace_with_fieldpats(
783 self.replace_fields_indexed(new_pats.into_iter().enumerate()) 773 &self,
774 new_pats: impl IntoIterator<Item = (LocalFieldId, PatId)>,
775 ) -> Self {
776 self.replace_fields_indexed(
777 new_pats.into_iter().map(|(field, pat)| (u32::from(field.into_raw()) as usize, pat)),
778 )
784 } 779 }
785 780
786 /// Overrides some of the fields with the provided patterns. This is used when a pattern 781 /// Overrides some of the fields with the provided patterns. This is used when a pattern
@@ -814,10 +809,7 @@ impl Fields {
814 let tys: SmallVec<[Ty; 2]> = match self { 809 let tys: SmallVec<[Ty; 2]> = match self {
815 Fields::Vec(pats) => pats.iter().copied().map(|pat| cx.type_of(pat)).collect(), 810 Fields::Vec(pats) => pats.iter().copied().map(|pat| cx.type_of(pat)).collect(),
816 }; 811 };
817 pats.into_iter() 812 pats.into_iter().zip(tys.into_iter()).map(move |(pat, ty)| cx.alloc_pat(pat)).collect()
818 .zip(tys.into_iter())
819 .map(move |(pat, ty)| cx.alloc_pat(pat, &ty))
820 .collect()
821 }; 813 };
822 814
823 match self { 815 match self {
@@ -845,42 +837,24 @@ impl Fields {
845 pat: PatId, 837 pat: PatId,
846 cx: &MatchCheckCtx<'_>, 838 cx: &MatchCheckCtx<'_>,
847 ) -> Self { 839 ) -> Self {
848 match &cx.pattern_arena.borrow()[pat] { 840 // TODO: these alocations are so unfortunate (+1 for switching to references)
849 Pat::Ref { pat: subpattern, .. } | Pat::Box { inner: subpattern } => { 841 match cx.pattern_arena.borrow()[pat].kind.as_ref() {
842 PatKind::Deref { subpattern } => {
850 assert_eq!(self.len(), 1); 843 assert_eq!(self.len(), 1);
851 Fields::from_single_pattern(*subpattern) 844 let subpattern = cx.pattern_arena.borrow_mut().alloc(subpattern.clone());
845 Fields::from_single_pattern(subpattern)
852 } 846 }
853 Pat::Tuple { args, ellipsis } | Pat::TupleStruct { args, ellipsis, .. } => { 847 PatKind::Leaf { subpatterns } | PatKind::Variant { subpatterns, .. } => {
854 // FIXME(iDawer) handle ellipsis. 848 let subpatterns = subpatterns.iter().map(|field_pat| {
855 // XXX(iDawer): in rustc, this is handled by HIR->TypedHIR lowering 849 (
856 // rustc_mir_build::thir::pattern::PatCtxt::lower_tuple_subpats(..) 850 field_pat.field,
857 self.replace_with_fieldpats(args.iter().copied()) 851 cx.pattern_arena.borrow_mut().alloc(field_pat.pattern.clone()),
858 } 852 )
859 Pat::Record { args, ellipsis, .. } => {
860 let variant_id =
861 cx.infer.variant_resolution_for_pat(pat).unwrap_or_else(|| todo!());
862 let variant_data = variant_id.variant_data(cx.db.upcast());
863
864 let new_pats = args.iter().map(|field_pat| {
865 // TODO: field lookup is inefficient
866 let raw =
867 variant_data.field(&field_pat.name).unwrap_or_else(|| todo!()).into_raw();
868 let idx = u32::from(raw) as usize;
869 (idx, field_pat.pat)
870 }); 853 });
871 self.replace_fields_indexed(new_pats) 854 self.replace_with_fieldpats(subpatterns)
872 }
873 Pat::Slice { .. } => {
874 todo!()
875 } 855 }
876 Pat::Missing 856
877 | Pat::Wild 857 PatKind::Wild | PatKind::Binding { .. } | PatKind::Or { .. } => self.clone(),
878 | Pat::Or(_)
879 | Pat::Range { .. }
880 | Pat::Path(_)
881 | Pat::Lit(_)
882 | Pat::Bind { .. }
883 | Pat::ConstBlock(_) => self.clone(),
884 } 858 }
885 } 859 }
886} 860}