diff options
Diffstat (limited to 'crates/hir_ty/src/diagnostics')
-rw-r--r-- | crates/hir_ty/src/diagnostics/expr.rs | 39 | ||||
-rw-r--r-- | crates/hir_ty/src/diagnostics/pattern.rs | 191 | ||||
-rw-r--r-- | crates/hir_ty/src/diagnostics/pattern/deconstruct_pat.rs | 188 | ||||
-rw-r--r-- | crates/hir_ty/src/diagnostics/pattern/pat_util.rs | 52 | ||||
-rw-r--r-- | crates/hir_ty/src/diagnostics/pattern/usefulness.rs | 81 |
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 | ||
5 | use std::sync::Arc; | 5 | use std::{cell::RefCell, sync::Arc}; |
6 | 6 | ||
7 | use hir_def::{expr::Statement, path::path, resolver::HasResolver, AssocItemId, DefWithBodyId}; | 7 | use hir_def::{expr::Statement, path::path, resolver::HasResolver, AssocItemId, DefWithBodyId}; |
8 | use hir_expand::name; | 8 | use hir_expand::name; |
@@ -26,7 +26,13 @@ pub(crate) use hir_def::{ | |||
26 | LocalFieldId, VariantId, | 26 | LocalFieldId, VariantId, |
27 | }; | 27 | }; |
28 | 28 | ||
29 | use super::ReplaceFilterMapNextWithFindMap; | 29 | use super::{ |
30 | pattern::{ | ||
31 | self, | ||
32 | usefulness::{expand_pattern, PatternArena}, | ||
33 | }, | ||
34 | ReplaceFilterMapNextWithFindMap, | ||
35 | }; | ||
30 | 36 | ||
31 | pub(super) struct ExprValidator<'a, 'b: 'a> { | 37 | pub(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 | ||
4 | mod deconstruct_pat; | 4 | mod deconstruct_pat; |
5 | // TODO: find a better place for this? | ||
6 | mod pat_util; | ||
5 | pub mod usefulness; | 7 | pub mod usefulness; |
6 | 8 | ||
9 | use hir_def::{body::Body, EnumVariantId, LocalFieldId, VariantId}; | ||
10 | use la_arena::Idx; | ||
11 | |||
12 | use crate::{db::HirDatabase, AdtId, InferenceResult, Interner, Substitution, Ty, TyKind}; | ||
13 | |||
14 | use self::{deconstruct_pat::ToDo, pat_util::EnumerateAndAdjustIterator}; | ||
15 | |||
16 | pub type PatId = Idx<Pat>; | ||
17 | |||
18 | #[derive(Clone, Debug)] | ||
19 | pub(crate) enum PatternError { | ||
20 | Unimplemented, | ||
21 | } | ||
22 | |||
23 | #[derive(Clone, Debug, PartialEq)] | ||
24 | pub struct FieldPat { | ||
25 | pub field: LocalFieldId, | ||
26 | pub pattern: Pat, | ||
27 | } | ||
28 | |||
29 | #[derive(Clone, Debug, PartialEq)] | ||
30 | pub struct Pat { | ||
31 | pub ty: Ty, | ||
32 | pub kind: Box<PatKind>, | ||
33 | } | ||
34 | |||
35 | impl 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)] | ||
42 | pub 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 | |||
77 | pub(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 | |||
84 | impl<'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)] |
8 | mod tests { | 199 | mod 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 | ||
7 | use hir_def::{ | 7 | use 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 | }; |
15 | use smallvec::{smallvec, SmallVec}; | 12 | use smallvec::{smallvec, SmallVec}; |
16 | 13 | ||
17 | use crate::{AdtId, Interner, Scalar, Ty, TyExt, TyKind}; | 14 | use crate::{AdtId, Interner, Scalar, Ty, TyExt, TyKind}; |
18 | 15 | ||
19 | use super::usefulness::{MatchCheckCtx, PatCtxt}; | 16 | use super::{ |
17 | usefulness::{MatchCheckCtx, PatCtxt}, | ||
18 | FieldPat, Pat, PatId, PatKind, | ||
19 | }; | ||
20 | 20 | ||
21 | use self::Constructor::*; | 21 | use 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 @@ | |||
1 | use std::iter::{Enumerate, ExactSizeIterator}; | ||
2 | |||
3 | pub struct EnumerateAndAdjust<I> { | ||
4 | enumerate: Enumerate<I>, | ||
5 | gap_pos: usize, | ||
6 | gap_len: usize, | ||
7 | } | ||
8 | |||
9 | impl<I> Iterator for EnumerateAndAdjust<I> | ||
10 | where | ||
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 | |||
26 | pub 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 | |||
36 | impl<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 | ||
4 | use std::{cell::RefCell, iter::FromIterator, ops::Index, sync::Arc}; | 4 | use std::{cell::RefCell, iter::FromIterator, ops::Index, sync::Arc}; |
5 | 5 | ||
6 | use hir_def::{ | 6 | use hir_def::{body::Body, expr::ExprId, HasModule, ModuleId}; |
7 | body::Body, | ||
8 | expr::{ExprId, Pat, PatId}, | ||
9 | HasModule, ModuleId, | ||
10 | }; | ||
11 | use la_arena::Arena; | 7 | use la_arena::Arena; |
12 | use once_cell::unsync::OnceCell; | 8 | use once_cell::unsync::OnceCell; |
13 | use rustc_hash::FxHashMap; | 9 | use rustc_hash::FxHashMap; |
@@ -15,7 +11,10 @@ use smallvec::{smallvec, SmallVec}; | |||
15 | 11 | ||
16 | use crate::{db::HirDatabase, InferenceResult, Ty}; | 12 | use crate::{db::HirDatabase, InferenceResult, Ty}; |
17 | 13 | ||
18 | use super::deconstruct_pat::{Constructor, Fields, SplitWildcard}; | 14 | use super::{ |
15 | deconstruct_pat::{Constructor, Fields, SplitWildcard}, | ||
16 | Pat, PatId, PatKind, | ||
17 | }; | ||
19 | 18 | ||
20 | use self::{ | 19 | use 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 | ||
79 | impl PatIdExt for PatId { | 77 | pub(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 | |||
82 | impl Pat { | ||
83 | fn is_wildcard(&self) -> bool { | ||
84 | matches!(*self.kind, PatKind::Binding { subpattern: None, .. } | PatKind::Wild) | ||
82 | } | 85 | } |
86 | } | ||
83 | 87 | ||
88 | impl 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 | ||
879 | pub(crate) struct PatternArena { | 888 | pub(crate) type PatternArena = Arena<Pat>; |
880 | arena: Arena<Pat>, | ||
881 | /// Types of expanded patterns. | ||
882 | type_of_epat: FxHashMap<PatId, Ty>, | ||
883 | } | ||
884 | |||
885 | impl 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 | |||
897 | impl Index<PatId> for PatternArena { | ||
898 | type Output = Pat; | ||
899 | |||
900 | fn index(&self, pat: PatId) -> &Pat { | ||
901 | &self.arena[pat] | ||
902 | } | ||
903 | } | ||
904 | 889 | ||
905 | mod helper { | 890 | mod 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 | } |