aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--crates/hir_def/src/path.rs2
-rw-r--r--crates/hir_ty/src/diagnostics/expr.rs2
-rw-r--r--crates/hir_ty/src/diagnostics/pattern.rs55
-rw-r--r--crates/hir_ty/src/diagnostics/pattern/deconstruct_pat.rs123
-rw-r--r--crates/hir_ty/src/diagnostics/pattern/usefulness.rs8
5 files changed, 121 insertions, 69 deletions
diff --git a/crates/hir_def/src/path.rs b/crates/hir_def/src/path.rs
index 16440041d..4cdb5913d 100644
--- a/crates/hir_def/src/path.rs
+++ b/crates/hir_def/src/path.rs
@@ -166,7 +166,7 @@ impl Path {
166 } 166 }
167 167
168 /// Converts a known mod path to `Path`. 168 /// Converts a known mod path to `Path`.
169 pub(crate) fn from_known_path( 169 pub fn from_known_path(
170 path: ModPath, 170 path: ModPath,
171 generic_args: Vec<Option<Interned<GenericArgs>>>, 171 generic_args: Vec<Option<Interned<GenericArgs>>>,
172 ) -> Path { 172 ) -> Path {
diff --git a/crates/hir_ty/src/diagnostics/expr.rs b/crates/hir_ty/src/diagnostics/expr.rs
index 88018b5d9..a62f0fa4f 100644
--- a/crates/hir_ty/src/diagnostics/expr.rs
+++ b/crates/hir_ty/src/diagnostics/expr.rs
@@ -382,7 +382,7 @@ impl<'a, 'b> ExprValidator<'a, 'b> {
382 382
383 let pattern_arena = usefulness::PatternArena::clone_from(&body.pats); 383 let pattern_arena = usefulness::PatternArena::clone_from(&body.pats);
384 let cx = usefulness::MatchCheckCtx { 384 let cx = usefulness::MatchCheckCtx {
385 krate: self.owner.module(db.upcast()).krate(), 385 module: self.owner.module(db.upcast()),
386 match_expr, 386 match_expr,
387 body, 387 body,
388 infer: &infer, 388 infer: &infer,
diff --git a/crates/hir_ty/src/diagnostics/pattern.rs b/crates/hir_ty/src/diagnostics/pattern.rs
index 28c7a244d..4dcbd7f9f 100644
--- a/crates/hir_ty/src/diagnostics/pattern.rs
+++ b/crates/hir_ty/src/diagnostics/pattern.rs
@@ -11,24 +11,67 @@ mod tests {
11 use super::*; 11 use super::*;
12 12
13 #[test] 13 #[test]
14 fn unit_exhaustive() { 14 fn unit() {
15 check_diagnostics( 15 check_diagnostics(
16 r#" 16 r#"
17fn main() { 17fn main() {
18 match () { () => {} } 18 match () { () => {} }
19 match () { _ => {} } 19 match () { _ => {} }
20 match () { }
21 //^^ Missing match arm
20} 22}
21"#, 23"#,
22 ); 24 );
23 } 25 }
24 26
25 #[test] 27 #[test]
26 fn unit_non_exhaustive() { 28 fn tuple_of_units() {
27 check_diagnostics( 29 check_diagnostics(
28 r#" 30 r#"
29fn main() { 31fn main() {
30 match () { } 32 match ((), ()) { ((), ()) => {} }
31 //^^ Missing match arm 33 match ((), ()) { ((), _) => {} }
34 match ((), ()) { (_, _) => {} }
35 match ((), ()) { _ => {} }
36 match ((), ()) { }
37 //^^^^^^^^ Missing match arm
38}
39"#,
40 );
41 }
42
43 #[test]
44 fn tuple_with_ellipsis() {
45 // TODO: test non-exhaustive match with ellipsis in the middle
46 // of a pattern, check reported witness
47 check_diagnostics(
48 r#"
49struct A; struct B;
50fn main(v: (A, (), B)) {
51 match v { (A, ..) => {} }
52 match v { (.., B) => {} }
53 match v { (A, .., B) => {} }
54 match v { (..) => {} }
55 match v { }
56 //^ Missing match arm
57}
58"#,
59 );
60 }
61
62 #[test]
63 fn strukt() {
64 check_diagnostics(
65 r#"
66struct A; struct B;
67struct S { a: A, b: B}
68fn main(v: S) {
69 match v { S { a, b } => {} }
70 match v { S { a: _, b: _ } => {} }
71 match v { S { .. } => {} }
72 match v { _ => {} }
73 match v { }
74 //^ Missing match arm
32} 75}
33"#, 76"#,
34 ); 77 );
diff --git a/crates/hir_ty/src/diagnostics/pattern/deconstruct_pat.rs b/crates/hir_ty/src/diagnostics/pattern/deconstruct_pat.rs
index c02e783af..7bd02a502 100644
--- a/crates/hir_ty/src/diagnostics/pattern/deconstruct_pat.rs
+++ b/crates/hir_ty/src/diagnostics/pattern/deconstruct_pat.rs
@@ -1,5 +1,9 @@
1use hir_def::{ 1use hir_def::{
2 expr::{Pat, PatId}, 2 expr::{Pat, PatId, RecordFieldPat},
3 find_path::find_path,
4 item_scope::ItemInNs,
5 path::Path,
6 type_ref::Mutability,
3 AttrDefId, EnumVariantId, HasModule, VariantId, 7 AttrDefId, EnumVariantId, HasModule, VariantId,
4}; 8};
5 9
@@ -126,19 +130,25 @@ impl Constructor {
126 130
127 /// Determines the constructor that the given pattern can be specialized to. 131 /// Determines the constructor that the given pattern can be specialized to.
128 pub(super) fn from_pat(cx: &MatchCheckCtx<'_>, pat: PatId) -> Self { 132 pub(super) fn from_pat(cx: &MatchCheckCtx<'_>, pat: PatId) -> Self {
133 let ty = cx.type_of(pat);
129 match &cx.pattern_arena.borrow()[pat] { 134 match &cx.pattern_arena.borrow()[pat] {
130 Pat::Bind { .. } | Pat::Wild => Wildcard, 135 Pat::Bind { .. } | Pat::Wild => Wildcard,
131 Pat::Tuple { .. } | Pat::Ref { .. } | Pat::Box { .. } => Single, 136 Pat::Tuple { .. } | Pat::Ref { .. } | Pat::Box { .. } => Single,
137 Pat::Record { .. } | Pat::Path(_) | Pat::TupleStruct { .. } => {
138 let variant_id =
139 cx.infer.variant_resolution_for_pat(pat).unwrap_or_else(|| todo!());
140 match variant_id {
141 VariantId::EnumVariantId(id) => Variant(id),
142 VariantId::StructId(_) | VariantId::UnionId(_) => Single,
143 }
144 }
132 145
146 Pat::Or(..) => panic!("bug: Or-pattern should have been expanded earlier on."),
133 pat => todo!("Constructor::from_pat {:?}", pat), 147 pat => todo!("Constructor::from_pat {:?}", pat),
134 // Pat::Missing => {} 148 // Pat::Missing => {}
135 // Pat::Or(_) => {}
136 // Pat::Record { path, args, ellipsis } => {}
137 // Pat::Range { start, end } => {} 149 // Pat::Range { start, end } => {}
138 // Pat::Slice { prefix, slice, suffix } => {} 150 // Pat::Slice { prefix, slice, suffix } => {}
139 // Pat::Path(_) => {}
140 // Pat::Lit(_) => {} 151 // Pat::Lit(_) => {}
141 // Pat::TupleStruct { path, args, ellipsis } => {}
142 // Pat::ConstBlock(_) => {} 152 // Pat::ConstBlock(_) => {}
143 } 153 }
144 } 154 }
@@ -435,7 +445,8 @@ impl Fields {
435 } else { 445 } else {
436 let variant_id = constructor.variant_id_for_adt(*adt, cx); 446 let variant_id = constructor.variant_id_for_adt(*adt, cx);
437 let variant = variant_id.variant_data(cx.db.upcast()); 447 let variant = variant_id.variant_data(cx.db.upcast());
438 let adt_is_local = variant_id.module(cx.db.upcast()).krate() == cx.krate; 448 let adt_is_local =
449 variant_id.module(cx.db.upcast()).krate() == cx.module.krate();
439 // Whether we must not match the fields of this variant exhaustively. 450 // Whether we must not match the fields of this variant exhaustively.
440 let is_non_exhaustive = 451 let is_non_exhaustive =
441 is_field_list_non_exhaustive(variant_id, cx) && !adt_is_local; 452 is_field_list_non_exhaustive(variant_id, cx) && !adt_is_local;
@@ -490,43 +501,44 @@ impl Fields {
490 Single | Variant(_) => match pcx.ty.kind(&Interner) { 501 Single | Variant(_) => match pcx.ty.kind(&Interner) {
491 TyKind::Adt(..) | TyKind::Tuple(..) => { 502 TyKind::Adt(..) | TyKind::Tuple(..) => {
492 // We want the real indices here. 503 // We want the real indices here.
493 // TODO indices 504 // TODO indices and ellipsis interaction, tests
494 let subpatterns = subpatterns_and_indices.iter().map(|&(_, pat)| pat).collect(); 505 let subpatterns = subpatterns_and_indices.iter().map(|&(_, pat)| pat).collect();
495 506
496 if let Some((adt, substs)) = pcx.ty.as_adt() { 507 if let Some((adt, substs)) = pcx.ty.as_adt() {
497 if let hir_def::AdtId::EnumId(_) = adt { 508 let item = ItemInNs::Types(adt.into());
498 todo!() 509 let path = find_path(pcx.cx.db.upcast(), item, pcx.cx.module)
499 } else { 510 .map(|mpath| Path::from_known_path(mpath, Vec::new()).into());
500 todo!() 511 match adt {
512 hir_def::AdtId::EnumId(_) => todo!(),
513 hir_def::AdtId::StructId(id) => {
514 let variant_data = &pcx.cx.db.struct_data(id).variant_data;
515 let args = subpatterns_and_indices
516 .iter()
517 .zip(variant_data.fields().iter())
518 .map(|(&(_, pat), (_, field_data))| RecordFieldPat {
519 name: field_data.name.clone(),
520 pat,
521 })
522 .collect();
523 Pat::Record { path, args, ellipsis: false }
524 }
525 hir_def::AdtId::UnionId(_) => todo!(),
501 } 526 }
502 } else { 527 } else {
503 // TODO ellipsis
504 Pat::Tuple { args: subpatterns, ellipsis: None } 528 Pat::Tuple { args: subpatterns, ellipsis: None }
505 } 529 }
506 } 530 }
507 531 // Note: given the expansion of `&str` patterns done in `expand_pattern`, we should
508 _ => todo!(), 532 // be careful to reconstruct the correct constant pattern here. However a string
509 // TyKind::AssociatedType(_, _) => {} 533 // literal pattern will never be reported as a non-exhaustiveness witness, so we
510 // TyKind::Scalar(_) => {} 534 // can ignore this issue.
511 // TyKind::Array(_, _) => {} 535 TyKind::Ref(..) => {
512 // TyKind::Slice(_) => {} 536 Pat::Ref { pat: subpatterns.next().unwrap(), mutability: Mutability::Shared }
513 // TyKind::Raw(_, _) => {} 537 }
514 // TyKind::Ref(_, _, _) => {} 538 TyKind::Slice(..) | TyKind::Array(..) => {
515 // TyKind::OpaqueType(_, _) => {} 539 panic!("bug: bad slice pattern {:?} {:?}", ctor, pcx.ty)
516 // TyKind::FnDef(_, _) => {} 540 }
517 // TyKind::Str => {} 541 _ => Pat::Wild,
518 // TyKind::Never => {}
519 // TyKind::Closure(_, _) => {}
520 // TyKind::Generator(_, _) => {}
521 // TyKind::GeneratorWitness(_, _) => {}
522 // TyKind::Foreign(_) => {}
523 // TyKind::Error => {}
524 // TyKind::Placeholder(_) => {}
525 // TyKind::Dyn(_) => {}
526 // TyKind::Alias(_) => {}
527 // TyKind::Function(_) => {}
528 // TyKind::BoundVar(_) => {}
529 // TyKind::InferenceVar(_, _) => {}
530 }, 542 },
531 Constructor::Slice(slice) => { 543 Constructor::Slice(slice) => {
532 todo!() 544 todo!()
@@ -537,9 +549,9 @@ impl Fields {
537 NonExhaustive => Pat::Wild, 549 NonExhaustive => Pat::Wild,
538 Wildcard => Pat::Wild, 550 Wildcard => Pat::Wild,
539 Opaque => panic!("bug: we should not try to apply an opaque constructor"), 551 Opaque => panic!("bug: we should not try to apply an opaque constructor"),
540 Missing => panic!( 552 Missing => {
541 "bug: trying to apply the `Missing` constructor; this should have been done in `apply_constructors`" 553 panic!("bug: trying to apply the `Missing` constructor; this should have been done in `apply_constructors`")
542 ), 554 }
543 } 555 }
544 } 556 }
545 557
@@ -628,30 +640,31 @@ impl Fields {
628 cx: &MatchCheckCtx<'_>, 640 cx: &MatchCheckCtx<'_>,
629 ) -> Self { 641 ) -> Self {
630 match &cx.pattern_arena.borrow()[pat] { 642 match &cx.pattern_arena.borrow()[pat] {
631 Pat::Ref { pat: subpattern, .. } => { 643 Pat::Ref { pat: subpattern, .. } | Pat::Box { inner: subpattern } => {
632 assert_eq!(self.len(), 1); 644 assert_eq!(self.len(), 1);
633 Fields::from_single_pattern(*subpattern) 645 Fields::from_single_pattern(*subpattern)
634 } 646 }
635 Pat::Tuple { args: subpatterns, ellipsis } => { 647 Pat::Tuple { args, ellipsis } | Pat::TupleStruct { args, ellipsis, .. } => {
636 // FIXME(iDawer) handle ellipsis. 648 // FIXME(iDawer) handle ellipsis.
637 // XXX(iDawer): in rustc, this is handled by HIR->TypedHIR lowering 649 // XXX(iDawer): in rustc, this is handled by HIR->TypedHIR lowering
638 // rustc_mir_build::thir::pattern::PatCtxt::lower_tuple_subpats(..) 650 // rustc_mir_build::thir::pattern::PatCtxt::lower_tuple_subpats(..)
639 self.replace_with_fieldpats(subpatterns.iter().copied()) 651 self.replace_with_fieldpats(args.iter().copied())
640 } 652 }
641 653 Pat::Record { args, ellipsis, .. } => {
642 Pat::Wild => self.clone(), 654 // FIXME(iDawer) handle ellipsis.
643 pat => todo!("Fields::replace_with_pattern_arguments({:?})", pat), 655 self.replace_with_fieldpats(args.iter().map(|field_pat| field_pat.pat))
644 // Pat::Missing => {} 656 }
645 // Pat::Or(_) => {} 657 Pat::Slice { .. } => {
646 // Pat::Record { path, args, ellipsis } => {} 658 todo!()
647 // Pat::Range { start, end } => {} 659 }
648 // Pat::Slice { prefix, slice, suffix } => {} 660 Pat::Missing
649 // Pat::Path(_) => {} 661 | Pat::Wild
650 // Pat::Lit(_) => {} 662 | Pat::Or(_)
651 // Pat::Bind { mode, name, subpat } => {} 663 | Pat::Range { .. }
652 // Pat::TupleStruct { path, args, ellipsis } => {} 664 | Pat::Path(_)
653 // Pat::Box { inner } => {} 665 | Pat::Lit(_)
654 // Pat::ConstBlock(_) => {} 666 | Pat::Bind { .. }
667 | Pat::ConstBlock(_) => self.clone(),
655 } 668 }
656 } 669 }
657} 670}
diff --git a/crates/hir_ty/src/diagnostics/pattern/usefulness.rs b/crates/hir_ty/src/diagnostics/pattern/usefulness.rs
index 2e5d2fb6c..4b55aee97 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 base_db::CrateId; 6use hir_def::{ModuleId, body::Body, expr::{ExprId, Pat, PatId}};
7use hir_def::{
8 body::Body,
9 expr::{ExprId, Pat, PatId},
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;
@@ -24,7 +20,7 @@ use self::{
24}; 20};
25 21
26pub(crate) struct MatchCheckCtx<'a> { 22pub(crate) struct MatchCheckCtx<'a> {
27 pub(crate) krate: CrateId, 23 pub(crate) module: ModuleId,
28 pub(crate) match_expr: ExprId, 24 pub(crate) match_expr: ExprId,
29 pub(crate) body: Arc<Body>, 25 pub(crate) body: Arc<Body>,
30 pub(crate) infer: &'a InferenceResult, 26 pub(crate) infer: &'a InferenceResult,