diff options
Diffstat (limited to 'crates/hir_ty/src')
-rw-r--r-- | crates/hir_ty/src/diagnostics/expr.rs | 2 | ||||
-rw-r--r-- | crates/hir_ty/src/diagnostics/pattern.rs | 55 | ||||
-rw-r--r-- | crates/hir_ty/src/diagnostics/pattern/deconstruct_pat.rs | 123 | ||||
-rw-r--r-- | crates/hir_ty/src/diagnostics/pattern/usefulness.rs | 8 |
4 files changed, 120 insertions, 68 deletions
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#" |
17 | fn main() { | 17 | fn 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#" |
29 | fn main() { | 31 | fn 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#" | ||
49 | struct A; struct B; | ||
50 | fn 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#" | ||
66 | struct A; struct B; | ||
67 | struct S { a: A, b: B} | ||
68 | fn 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 @@ | |||
1 | use hir_def::{ | 1 | use 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 | ||
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 base_db::CrateId; | 6 | use hir_def::{ModuleId, body::Body, expr::{ExprId, Pat, PatId}}; |
7 | use hir_def::{ | ||
8 | body::Body, | ||
9 | expr::{ExprId, Pat, PatId}, | ||
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; |
@@ -24,7 +20,7 @@ use self::{ | |||
24 | }; | 20 | }; |
25 | 21 | ||
26 | pub(crate) struct MatchCheckCtx<'a> { | 22 | pub(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, |