From 3088ca0a53540e0d7ae14f0d18efcad16cad0735 Mon Sep 17 00:00:00 2001 From: Dawer <7803845+iDawer@users.noreply.github.com> Date: Wed, 19 May 2021 18:08:13 +0500 Subject: Take substitutions into account. --- crates/hir_ty/src/diagnostics/match_check.rs | 20 +++++++++++++++-- .../src/diagnostics/match_check/deconstruct_pat.rs | 25 ++++++++++++---------- .../src/diagnostics/match_check/usefulness.rs | 2 +- 3 files changed, 33 insertions(+), 14 deletions(-) diff --git a/crates/hir_ty/src/diagnostics/match_check.rs b/crates/hir_ty/src/diagnostics/match_check.rs index 5fb98ff35..992bb8682 100644 --- a/crates/hir_ty/src/diagnostics/match_check.rs +++ b/crates/hir_ty/src/diagnostics/match_check.rs @@ -39,8 +39,8 @@ pub(crate) struct Pat { } impl Pat { - pub(crate) fn wildcard_from_ty(ty: &Ty) -> Self { - Pat { ty: ty.clone(), kind: Box::new(PatKind::Wild) } + pub(crate) fn wildcard_from_ty(ty: Ty) -> Self { + Pat { ty, kind: Box::new(PatKind::Wild) } } } @@ -1145,6 +1145,22 @@ fn main() { ); } + #[test] + fn pattern_type_is_of_substitution() { + cov_mark::check!(match_check_wildcard_expanded_to_substitutions); + check_diagnostics( + r#" +struct Foo(T); +struct Bar; +fn main() { + match Foo(Bar) { + _ | Foo(Bar) => {} + } +} +"#, + ); + } + mod false_negatives { //! The implementation of match checking here is a work in progress. As we roll this out, we //! prefer false negatives to false positives (ideally there would be no false positives). This diff --git a/crates/hir_ty/src/diagnostics/match_check/deconstruct_pat.rs b/crates/hir_ty/src/diagnostics/match_check/deconstruct_pat.rs index 15ec5cf45..a47082617 100644 --- a/crates/hir_ty/src/diagnostics/match_check/deconstruct_pat.rs +++ b/crates/hir_ty/src/diagnostics/match_check/deconstruct_pat.rs @@ -632,10 +632,7 @@ impl Fields { } /// Convenience; internal use. - fn wildcards_from_tys<'a>( - cx: &MatchCheckCtx<'_>, - tys: impl IntoIterator, - ) -> Self { + fn wildcards_from_tys(cx: &MatchCheckCtx<'_>, tys: impl IntoIterator) -> Self { let wilds = tys.into_iter().map(Pat::wildcard_from_ty); let pats = wilds.map(|pat| cx.alloc_pat(pat)).collect(); Fields::Vec(pats) @@ -645,13 +642,13 @@ impl Fields { pub(crate) fn wildcards(pcx: PatCtxt<'_>, constructor: &Constructor) -> Self { let ty = pcx.ty; let cx = pcx.cx; - let wildcard_from_ty = |ty| cx.alloc_pat(Pat::wildcard_from_ty(ty)); + let wildcard_from_ty = |ty: &Ty| cx.alloc_pat(Pat::wildcard_from_ty(ty.clone())); let ret = match constructor { Single | Variant(_) => match ty.kind(&Interner) { TyKind::Tuple(_, substs) => { let tys = substs.iter(&Interner).map(|ty| ty.assert_ty_ref(&Interner)); - Fields::wildcards_from_tys(cx, tys) + Fields::wildcards_from_tys(cx, tys.cloned()) } TyKind::Ref(.., rty) => Fields::from_single_pattern(wildcard_from_ty(rty)), &TyKind::Adt(AdtId(adt), ref substs) => { @@ -666,14 +663,20 @@ impl Fields { // Whether we must not match the fields of this variant exhaustively. let is_non_exhaustive = is_field_list_non_exhaustive(variant_id, cx) && !adt_is_local; - let field_ty_arena = cx.db.field_types(variant_id); - let field_tys = - || field_ty_arena.iter().map(|(_, binders)| binders.skip_binders()); + + cov_mark::hit!(match_check_wildcard_expanded_to_substitutions); + let field_ty_data = cx.db.field_types(variant_id); + let field_tys = || { + field_ty_data + .iter() + .map(|(_, binders)| binders.clone().substitute(&Interner, substs)) + }; + // In the following cases, we don't need to filter out any fields. This is // the vast majority of real cases, since uninhabited fields are uncommon. let has_no_hidden_fields = (matches!(adt, hir_def::AdtId::EnumId(_)) && !is_non_exhaustive) - || !field_tys().any(|ty| cx.is_uninhabited(ty)); + || !field_tys().any(|ty| cx.is_uninhabited(&ty)); if has_no_hidden_fields { Fields::wildcards_from_tys(cx, field_tys()) @@ -759,7 +762,7 @@ impl Fields { FloatRange(..) => UNHANDLED, Constructor::IntRange(_) => UNHANDLED, NonExhaustive => PatKind::Wild, - Wildcard => return Pat::wildcard_from_ty(pcx.ty), + Wildcard => return Pat::wildcard_from_ty(pcx.ty.clone()), Opaque => pcx.cx.bug("we should not try to apply an opaque constructor"), Missing => pcx.cx.bug( "trying to apply the `Missing` constructor;\ diff --git a/crates/hir_ty/src/diagnostics/match_check/usefulness.rs b/crates/hir_ty/src/diagnostics/match_check/usefulness.rs index cb322a3de..61fba41bf 100644 --- a/crates/hir_ty/src/diagnostics/match_check/usefulness.rs +++ b/crates/hir_ty/src/diagnostics/match_check/usefulness.rs @@ -1152,7 +1152,7 @@ pub(crate) fn compute_match_usefulness( .collect(); let wild_pattern = - cx.pattern_arena.borrow_mut().alloc(Pat::wildcard_from_ty(&cx.infer[cx.match_expr])); + cx.pattern_arena.borrow_mut().alloc(Pat::wildcard_from_ty(cx.infer[cx.match_expr].clone())); let v = PatStack::from_pattern(wild_pattern); let usefulness = is_useful(cx, &matrix, &v, ConstructWitness, false, true); let non_exhaustiveness_witnesses = match usefulness { -- cgit v1.2.3