aboutsummaryrefslogtreecommitdiff
path: root/crates/hir_ty/src/diagnostics
diff options
context:
space:
mode:
Diffstat (limited to 'crates/hir_ty/src/diagnostics')
-rw-r--r--crates/hir_ty/src/diagnostics/expr.rs39
-rw-r--r--crates/hir_ty/src/diagnostics/pattern.rs191
-rw-r--r--crates/hir_ty/src/diagnostics/pattern/deconstruct_pat.rs188
-rw-r--r--crates/hir_ty/src/diagnostics/pattern/pat_util.rs52
-rw-r--r--crates/hir_ty/src/diagnostics/pattern/usefulness.rs81
5 files changed, 387 insertions, 164 deletions
diff --git a/crates/hir_ty/src/diagnostics/expr.rs b/crates/hir_ty/src/diagnostics/expr.rs
index a62f0fa4f..8f141a308 100644
--- a/crates/hir_ty/src/diagnostics/expr.rs
+++ b/crates/hir_ty/src/diagnostics/expr.rs
@@ -2,7 +2,7 @@
2//! through the body using inference results: mismatched arg counts, missing 2//! through the body using inference results: mismatched arg counts, missing
3//! fields, etc. 3//! fields, etc.
4 4
5use std::sync::Arc; 5use std::{cell::RefCell, sync::Arc};
6 6
7use hir_def::{expr::Statement, path::path, resolver::HasResolver, AssocItemId, DefWithBodyId}; 7use hir_def::{expr::Statement, path::path, resolver::HasResolver, AssocItemId, DefWithBodyId};
8use hir_expand::name; 8use hir_expand::name;
@@ -26,7 +26,13 @@ pub(crate) use hir_def::{
26 LocalFieldId, VariantId, 26 LocalFieldId, VariantId,
27}; 27};
28 28
29use super::ReplaceFilterMapNextWithFindMap; 29use super::{
30 pattern::{
31 self,
32 usefulness::{expand_pattern, PatternArena},
33 },
34 ReplaceFilterMapNextWithFindMap,
35};
30 36
31pub(super) struct ExprValidator<'a, 'b: 'a> { 37pub(super) struct ExprValidator<'a, 'b: 'a> {
32 owner: DefWithBodyId, 38 owner: DefWithBodyId,
@@ -380,7 +386,16 @@ impl<'a, 'b> ExprValidator<'a, 'b> {
380 }; 386 };
381 // eprintln!("ExprValidator::validate_match2({:?})", _match_expr_ty.kind(&Interner)); 387 // eprintln!("ExprValidator::validate_match2({:?})", _match_expr_ty.kind(&Interner));
382 388
383 let pattern_arena = usefulness::PatternArena::clone_from(&body.pats); 389 let pattern_arena = RefCell::new(PatternArena::new());
390
391 let m_arms: Vec<_> = arms
392 .iter()
393 .map(|arm| usefulness::MatchArm {
394 pat: self.lower_pattern(arm.pat, &mut pattern_arena.borrow_mut(), db, &body),
395 has_guard: arm.guard.is_some(),
396 })
397 .collect();
398
384 let cx = usefulness::MatchCheckCtx { 399 let cx = usefulness::MatchCheckCtx {
385 module: self.owner.module(db.upcast()), 400 module: self.owner.module(db.upcast()),
386 match_expr, 401 match_expr,
@@ -389,12 +404,6 @@ impl<'a, 'b> ExprValidator<'a, 'b> {
389 db, 404 db,
390 pattern_arena: &pattern_arena, 405 pattern_arena: &pattern_arena,
391 }; 406 };
392
393 let m_arms: Vec<_> = arms
394 .iter()
395 .map(|arm| usefulness::MatchArm { pat: arm.pat, has_guard: arm.guard.is_some() })
396 .collect();
397
398 let report = usefulness::compute_match_usefulness(&cx, &m_arms); 407 let report = usefulness::compute_match_usefulness(&cx, &m_arms);
399 408
400 // TODO Report unreacheble arms 409 // TODO Report unreacheble arms
@@ -427,6 +436,18 @@ impl<'a, 'b> ExprValidator<'a, 'b> {
427 } 436 }
428 } 437 }
429 438
439 fn lower_pattern(
440 &self,
441 pat: PatId,
442 pattern_arena: &mut PatternArena,
443 db: &dyn HirDatabase,
444 body: &Body,
445 ) -> pattern::PatId {
446 let mut patcx = pattern::PatCtxt::new(db, &self.infer, body);
447 let pattern = patcx.lower_pattern(pat);
448 pattern_arena.alloc(expand_pattern(pattern))
449 }
450
430 fn validate_results_in_tail_expr(&mut self, body_id: ExprId, id: ExprId, db: &dyn HirDatabase) { 451 fn validate_results_in_tail_expr(&mut self, body_id: ExprId, id: ExprId, db: &dyn HirDatabase) {
431 // the mismatch will be on the whole block currently 452 // the mismatch will be on the whole block currently
432 let mismatch = match self.infer.type_mismatch_for_expr(body_id) { 453 let mismatch = match self.infer.type_mismatch_for_expr(body_id) {
diff --git a/crates/hir_ty/src/diagnostics/pattern.rs b/crates/hir_ty/src/diagnostics/pattern.rs
index 044506d66..6646826b3 100644
--- a/crates/hir_ty/src/diagnostics/pattern.rs
+++ b/crates/hir_ty/src/diagnostics/pattern.rs
@@ -2,8 +2,199 @@
2#![allow(unused)] // todo remove 2#![allow(unused)] // todo remove
3 3
4mod deconstruct_pat; 4mod deconstruct_pat;
5// TODO: find a better place for this?
6mod pat_util;
5pub mod usefulness; 7pub mod usefulness;
6 8
9use hir_def::{body::Body, EnumVariantId, LocalFieldId, VariantId};
10use la_arena::Idx;
11
12use crate::{db::HirDatabase, AdtId, InferenceResult, Interner, Substitution, Ty, TyKind};
13
14use self::{deconstruct_pat::ToDo, pat_util::EnumerateAndAdjustIterator};
15
16pub type PatId = Idx<Pat>;
17
18#[derive(Clone, Debug)]
19pub(crate) enum PatternError {
20 Unimplemented,
21}
22
23#[derive(Clone, Debug, PartialEq)]
24pub struct FieldPat {
25 pub field: LocalFieldId,
26 pub pattern: Pat,
27}
28
29#[derive(Clone, Debug, PartialEq)]
30pub struct Pat {
31 pub ty: Ty,
32 pub kind: Box<PatKind>,
33}
34
35impl Pat {
36 pub(crate) fn wildcard_from_ty(ty: &Ty) -> Self {
37 Pat { ty: ty.clone(), kind: Box::new(PatKind::Wild) }
38 }
39}
40
41#[derive(Clone, Debug, PartialEq)]
42pub enum PatKind {
43 Wild,
44
45 /// `x`, `ref x`, `x @ P`, etc.
46 Binding {
47 subpattern: Option<Pat>,
48 // todo: ToDo,
49 },
50
51 /// `Foo(...)` or `Foo{...}` or `Foo`, where `Foo` is a variant name from an ADT with
52 /// multiple variants.
53 Variant {
54 substs: Substitution,
55 enum_variant: EnumVariantId,
56 subpatterns: Vec<FieldPat>,
57 },
58
59 /// `(...)`, `Foo(...)`, `Foo{...}`, or `Foo`, where `Foo` is a variant name from an ADT with
60 /// a single variant.
61 Leaf {
62 subpatterns: Vec<FieldPat>,
63 },
64
65 /// `box P`, `&P`, `&mut P`, etc.
66 Deref {
67 subpattern: Pat,
68 },
69
70 /// An or-pattern, e.g. `p | q`.
71 /// Invariant: `pats.len() >= 2`.
72 Or {
73 pats: Vec<Pat>,
74 },
75}
76
77pub(crate) struct PatCtxt<'a> {
78 db: &'a dyn HirDatabase,
79 infer: &'a InferenceResult,
80 body: &'a Body,
81 pub(crate) errors: Vec<PatternError>,
82}
83
84impl<'a> PatCtxt<'a> {
85 pub(crate) fn new(db: &'a dyn HirDatabase, infer: &'a InferenceResult, body: &'a Body) -> Self {
86 Self { db, infer, body, errors: Vec::new() }
87 }
88
89 pub(crate) fn lower_pattern(&mut self, pat: hir_def::expr::PatId) -> Pat {
90 // TODO: pattern adjustments (implicit dereference)
91 // More info https://github.com/rust-lang/rust/issues/42640#issuecomment-313535089
92 let unadjusted_pat = self.lower_pattern_unadjusted(pat);
93 unadjusted_pat
94 }
95
96 fn lower_pattern_unadjusted(&mut self, pat: hir_def::expr::PatId) -> Pat {
97 let ty = &self.infer[pat];
98
99 let kind = match self.body[pat] {
100 hir_def::expr::Pat::Wild => PatKind::Wild,
101
102 hir_def::expr::Pat::Tuple { ref args, ellipsis } => {
103 let arity = match *ty.kind(&Interner) {
104 TyKind::Tuple(arity, _) => arity,
105 _ => panic!("unexpected type for tuple pattern: {:?}", ty),
106 };
107 let subpatterns = self.lower_tuple_subpats(args, arity, ellipsis);
108 PatKind::Leaf { subpatterns }
109 }
110
111 hir_def::expr::Pat::TupleStruct { ref args, ellipsis, .. } => {
112 let variant_data = match self.infer.variant_resolution_for_pat(pat) {
113 Some(variant_id) => variant_id.variant_data(self.db.upcast()),
114 None => panic!("tuple struct pattern not applied to an ADT {:?}", ty),
115 };
116 let subpatterns =
117 self.lower_tuple_subpats(args, variant_data.fields().len(), ellipsis);
118 self.lower_variant_or_leaf(pat, ty, subpatterns)
119 }
120
121 hir_def::expr::Pat::Record { ref args, .. } => {
122 let variant_data = match self.infer.variant_resolution_for_pat(pat) {
123 Some(variant_id) => variant_id.variant_data(self.db.upcast()),
124 None => panic!("record pattern not applied to an ADT {:?}", ty),
125 };
126 let subpatterns = args
127 .iter()
128 .map(|field| FieldPat {
129 // XXX(iDawer): field lookup is inefficient
130 field: variant_data.field(&field.name).unwrap_or_else(|| todo!()),
131 pattern: self.lower_pattern(field.pat),
132 })
133 .collect();
134 self.lower_variant_or_leaf(pat, ty, subpatterns)
135 }
136
137 hir_def::expr::Pat::Or(ref pats) => PatKind::Or { pats: self.lower_patterns(pats) },
138
139 _ => {
140 self.errors.push(PatternError::Unimplemented);
141 PatKind::Wild
142 }
143 };
144
145 Pat { ty: ty.clone(), kind: Box::new(kind) }
146 }
147
148 fn lower_tuple_subpats(
149 &mut self,
150 pats: &[hir_def::expr::PatId],
151 expected_len: usize,
152 ellipsis: Option<usize>,
153 ) -> Vec<FieldPat> {
154 pats.iter()
155 .enumerate_and_adjust(expected_len, ellipsis)
156 .map(|(i, &subpattern)| FieldPat {
157 field: LocalFieldId::from_raw((i as u32).into()),
158 pattern: self.lower_pattern(subpattern),
159 })
160 .collect()
161 }
162
163 fn lower_patterns(&mut self, pats: &[hir_def::expr::PatId]) -> Vec<Pat> {
164 pats.iter().map(|&p| self.lower_pattern(p)).collect()
165 }
166
167 fn lower_variant_or_leaf(
168 &mut self,
169 pat: hir_def::expr::PatId,
170 ty: &Ty,
171 subpatterns: Vec<FieldPat>,
172 ) -> PatKind {
173 let kind = match self.infer.variant_resolution_for_pat(pat) {
174 Some(variant_id) => {
175 if let VariantId::EnumVariantId(enum_variant) = variant_id {
176 let substs = match ty.kind(&Interner) {
177 TyKind::Adt(_, substs) | TyKind::FnDef(_, substs) => substs.clone(),
178 TyKind::Error => {
179 return PatKind::Wild;
180 }
181 _ => panic!("inappropriate type for def: {:?}", ty),
182 };
183 PatKind::Variant { substs, enum_variant, subpatterns }
184 } else {
185 PatKind::Leaf { subpatterns }
186 }
187 }
188 None => {
189 self.errors.push(PatternError::Unimplemented);
190 PatKind::Wild
191 }
192 };
193 // TODO: do we need PatKind::AscribeUserType ?
194 kind
195 }
196}
197
7#[cfg(test)] 198#[cfg(test)]
8mod tests { 199mod tests {
9 use crate::diagnostics::tests::check_diagnostics; 200 use crate::diagnostics::tests::check_diagnostics;
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}
diff --git a/crates/hir_ty/src/diagnostics/pattern/pat_util.rs b/crates/hir_ty/src/diagnostics/pattern/pat_util.rs
new file mode 100644
index 000000000..f8ad4e7c6
--- /dev/null
+++ b/crates/hir_ty/src/diagnostics/pattern/pat_util.rs
@@ -0,0 +1,52 @@
1use std::iter::{Enumerate, ExactSizeIterator};
2
3pub struct EnumerateAndAdjust<I> {
4 enumerate: Enumerate<I>,
5 gap_pos: usize,
6 gap_len: usize,
7}
8
9impl<I> Iterator for EnumerateAndAdjust<I>
10where
11 I: Iterator,
12{
13 type Item = (usize, <I as Iterator>::Item);
14
15 fn next(&mut self) -> Option<(usize, <I as Iterator>::Item)> {
16 self.enumerate
17 .next()
18 .map(|(i, elem)| (if i < self.gap_pos { i } else { i + self.gap_len }, elem))
19 }
20
21 fn size_hint(&self) -> (usize, Option<usize>) {
22 self.enumerate.size_hint()
23 }
24}
25
26pub trait EnumerateAndAdjustIterator {
27 fn enumerate_and_adjust(
28 self,
29 expected_len: usize,
30 gap_pos: Option<usize>,
31 ) -> EnumerateAndAdjust<Self>
32 where
33 Self: Sized;
34}
35
36impl<T: ExactSizeIterator> EnumerateAndAdjustIterator for T {
37 fn enumerate_and_adjust(
38 self,
39 expected_len: usize,
40 gap_pos: Option<usize>,
41 ) -> EnumerateAndAdjust<Self>
42 where
43 Self: Sized,
44 {
45 let actual_len = self.len();
46 EnumerateAndAdjust {
47 enumerate: self.enumerate(),
48 gap_pos: gap_pos.unwrap_or(expected_len),
49 gap_len: expected_len - actual_len,
50 }
51 }
52}
diff --git a/crates/hir_ty/src/diagnostics/pattern/usefulness.rs b/crates/hir_ty/src/diagnostics/pattern/usefulness.rs
index 2df87ccea..28b9e71f8 100644
--- a/crates/hir_ty/src/diagnostics/pattern/usefulness.rs
+++ b/crates/hir_ty/src/diagnostics/pattern/usefulness.rs
@@ -3,11 +3,7 @@
3 3
4use std::{cell::RefCell, iter::FromIterator, ops::Index, sync::Arc}; 4use std::{cell::RefCell, iter::FromIterator, ops::Index, sync::Arc};
5 5
6use hir_def::{ 6use hir_def::{body::Body, expr::ExprId, HasModule, ModuleId};
7 body::Body,
8 expr::{ExprId, Pat, PatId},
9 HasModule, ModuleId,
10};
11use la_arena::Arena; 7use la_arena::Arena;
12use once_cell::unsync::OnceCell; 8use once_cell::unsync::OnceCell;
13use rustc_hash::FxHashMap; 9use rustc_hash::FxHashMap;
@@ -15,7 +11,10 @@ use smallvec::{smallvec, SmallVec};
15 11
16use crate::{db::HirDatabase, InferenceResult, Ty}; 12use crate::{db::HirDatabase, InferenceResult, Ty};
17 13
18use super::deconstruct_pat::{Constructor, Fields, SplitWildcard}; 14use super::{
15 deconstruct_pat::{Constructor, Fields, SplitWildcard},
16 Pat, PatId, PatKind,
17};
19 18
20use self::{ 19use self::{
21 helper::{Captures, PatIdExt}, 20 helper::{Captures, PatIdExt},
@@ -55,14 +54,13 @@ impl<'a> MatchCheckCtx<'a> {
55 false 54 false
56 } 55 }
57 56
58 pub(super) fn alloc_pat(&self, pat: Pat, ty: &Ty) -> PatId { 57 pub(super) fn alloc_pat(&self, pat: Pat) -> PatId {
59 self.pattern_arena.borrow_mut().alloc(pat, ty) 58 self.pattern_arena.borrow_mut().alloc(pat)
60 } 59 }
61 60
62 /// Get type of a pattern. Handles expanded patterns. 61 /// Get type of a pattern. Handles expanded patterns.
63 pub(super) fn type_of(&self, pat: PatId) -> Ty { 62 pub(super) fn type_of(&self, pat: PatId) -> Ty {
64 let type_of_expanded_pat = self.pattern_arena.borrow().type_of_epat.get(&pat).cloned(); 63 self.pattern_arena.borrow()[pat].ty.clone()
65 type_of_expanded_pat.unwrap_or_else(|| self.infer[pat].clone())
66 } 64 }
67} 65}
68 66
@@ -76,30 +74,40 @@ pub(super) struct PatCtxt<'a> {
76 pub(super) is_top_level: bool, 74 pub(super) is_top_level: bool,
77} 75}
78 76
79impl PatIdExt for PatId { 77pub(crate) fn expand_pattern(pat: Pat) -> Pat {
80 fn is_wildcard(self, cx: &MatchCheckCtx<'_>) -> bool { 78 // TODO: LiteralExpander, it is about string literal patterns
81 matches!(cx.pattern_arena.borrow()[self], Pat::Bind { subpat: None, .. } | Pat::Wild) 79 pat
80}
81
82impl Pat {
83 fn is_wildcard(&self) -> bool {
84 matches!(*self.kind, PatKind::Binding { subpattern: None, .. } | PatKind::Wild)
82 } 85 }
86}
83 87
88impl PatIdExt for PatId {
84 fn is_or_pat(self, cx: &MatchCheckCtx<'_>) -> bool { 89 fn is_or_pat(self, cx: &MatchCheckCtx<'_>) -> bool {
85 matches!(cx.pattern_arena.borrow()[self], Pat::Or(..)) 90 matches!(*cx.pattern_arena.borrow()[self].kind, PatKind::Or { .. })
86 } 91 }
87 92
88 /// Recursively expand this pattern into its subpatterns. Only useful for or-patterns. 93 /// Recursively expand this pattern into its subpatterns. Only useful for or-patterns.
89 fn expand_or_pat(self, cx: &MatchCheckCtx<'_>) -> Vec<Self> { 94 fn expand_or_pat(self, cx: &MatchCheckCtx<'_>) -> Vec<Self> {
90 fn expand(pat: PatId, vec: &mut Vec<PatId>, pat_arena: &PatternArena) { 95 fn expand(pat: PatId, vec: &mut Vec<PatId>, mut pat_arena: &mut PatternArena) {
91 if let Pat::Or(pats) = &pat_arena[pat] { 96 if let PatKind::Or { pats } = pat_arena[pat].kind.as_ref() {
92 for &pat in pats { 97 // for pat in pats {
93 expand(pat, vec, pat_arena); 98 // // TODO(iDawer): Ugh, I want to go back to references (PatId -> &Pat)
94 } 99 // let pat = pat_arena.alloc(pat.clone());
100 // expand(pat, vec, pat_arena);
101 // }
102 todo!()
95 } else { 103 } else {
96 vec.push(pat) 104 vec.push(pat)
97 } 105 }
98 } 106 }
99 107
100 let pat_arena = cx.pattern_arena.borrow(); 108 let mut pat_arena = cx.pattern_arena.borrow_mut();
101 let mut pats = Vec::new(); 109 let mut pats = Vec::new();
102 expand(self, &mut pats, &pat_arena); 110 expand(self, &mut pats, &mut pat_arena);
103 pats 111 pats
104 } 112 }
105} 113}
@@ -866,7 +874,8 @@ pub(crate) fn compute_match_usefulness(
866 }) 874 })
867 .collect(); 875 .collect();
868 876
869 let wild_pattern = cx.pattern_arena.borrow_mut().alloc(Pat::Wild, &cx.infer[cx.match_expr]); 877 let wild_pattern =
878 cx.pattern_arena.borrow_mut().alloc(Pat::wildcard_from_ty(&cx.infer[cx.match_expr]));
870 let v = PatStack::from_pattern(wild_pattern); 879 let v = PatStack::from_pattern(wild_pattern);
871 let usefulness = is_useful(cx, &matrix, &v, ConstructWitness, false, true); 880 let usefulness = is_useful(cx, &matrix, &v, ConstructWitness, false, true);
872 let non_exhaustiveness_witnesses = match usefulness { 881 let non_exhaustiveness_witnesses = match usefulness {
@@ -876,31 +885,7 @@ pub(crate) fn compute_match_usefulness(
876 UsefulnessReport { arm_usefulness, non_exhaustiveness_witnesses } 885 UsefulnessReport { arm_usefulness, non_exhaustiveness_witnesses }
877} 886}
878 887
879pub(crate) struct PatternArena { 888pub(crate) type PatternArena = Arena<Pat>;
880 arena: Arena<Pat>,
881 /// Types of expanded patterns.
882 type_of_epat: FxHashMap<PatId, Ty>,
883}
884
885impl PatternArena {
886 pub(crate) fn clone_from(pats: &Arena<Pat>) -> RefCell<Self> {
887 PatternArena { arena: pats.clone(), type_of_epat: Default::default() }.into()
888 }
889
890 fn alloc(&mut self, pat: Pat, ty: &Ty) -> PatId {
891 let id = self.arena.alloc(pat);
892 self.type_of_epat.insert(id, ty.clone());
893 id
894 }
895}
896
897impl Index<PatId> for PatternArena {
898 type Output = Pat;
899
900 fn index(&self, pat: PatId) -> &Pat {
901 &self.arena[pat]
902 }
903}
904 889
905mod helper { 890mod helper {
906 use hir_def::expr::{Pat, PatId}; 891 use hir_def::expr::{Pat, PatId};
@@ -908,7 +893,7 @@ mod helper {
908 use super::MatchCheckCtx; 893 use super::MatchCheckCtx;
909 894
910 pub(super) trait PatIdExt: Sized { 895 pub(super) trait PatIdExt: Sized {
911 fn is_wildcard(self, cx: &MatchCheckCtx<'_>) -> bool; 896 // fn is_wildcard(self, cx: &MatchCheckCtx<'_>) -> bool;
912 fn is_or_pat(self, cx: &MatchCheckCtx<'_>) -> bool; 897 fn is_or_pat(self, cx: &MatchCheckCtx<'_>) -> bool;
913 fn expand_or_pat(self, cx: &MatchCheckCtx<'_>) -> Vec<Self>; 898 fn expand_or_pat(self, cx: &MatchCheckCtx<'_>) -> Vec<Self>;
914 } 899 }