Take substitutions into account.

This commit is contained in:
Dawer 2021-05-19 18:08:13 +05:00
parent e16f413582
commit 3088ca0a53
3 changed files with 33 additions and 14 deletions

View File

@ -39,8 +39,8 @@ pub(crate) struct Pat {
} }
impl Pat { impl Pat {
pub(crate) fn wildcard_from_ty(ty: &Ty) -> Self { pub(crate) fn wildcard_from_ty(ty: Ty) -> Self {
Pat { ty: ty.clone(), kind: Box::new(PatKind::Wild) } 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>(T);
struct Bar;
fn main() {
match Foo(Bar) {
_ | Foo(Bar) => {}
}
}
"#,
);
}
mod false_negatives { mod false_negatives {
//! The implementation of match checking here is a work in progress. As we roll this out, we //! 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 //! prefer false negatives to false positives (ideally there would be no false positives). This

View File

@ -632,10 +632,7 @@ impl Fields {
} }
/// Convenience; internal use. /// Convenience; internal use.
fn wildcards_from_tys<'a>( fn wildcards_from_tys(cx: &MatchCheckCtx<'_>, tys: impl IntoIterator<Item = Ty>) -> Self {
cx: &MatchCheckCtx<'_>,
tys: impl IntoIterator<Item = &'a Ty>,
) -> Self {
let wilds = tys.into_iter().map(Pat::wildcard_from_ty); let wilds = tys.into_iter().map(Pat::wildcard_from_ty);
let pats = wilds.map(|pat| cx.alloc_pat(pat)).collect(); let pats = wilds.map(|pat| cx.alloc_pat(pat)).collect();
Fields::Vec(pats) Fields::Vec(pats)
@ -645,13 +642,13 @@ impl Fields {
pub(crate) fn wildcards(pcx: PatCtxt<'_>, constructor: &Constructor) -> Self { pub(crate) fn wildcards(pcx: PatCtxt<'_>, constructor: &Constructor) -> Self {
let ty = pcx.ty; let ty = pcx.ty;
let cx = pcx.cx; 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 { let ret = match constructor {
Single | Variant(_) => match ty.kind(&Interner) { Single | Variant(_) => match ty.kind(&Interner) {
TyKind::Tuple(_, substs) => { TyKind::Tuple(_, substs) => {
let tys = substs.iter(&Interner).map(|ty| ty.assert_ty_ref(&Interner)); 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::Ref(.., rty) => Fields::from_single_pattern(wildcard_from_ty(rty)),
&TyKind::Adt(AdtId(adt), ref substs) => { &TyKind::Adt(AdtId(adt), ref substs) => {
@ -666,14 +663,20 @@ impl Fields {
// Whether we must not match the fields of this variant exhaustively. // Whether we must not match the fields of this variant exhaustively.
let is_non_exhaustive = let is_non_exhaustive =
is_field_list_non_exhaustive(variant_id, cx) && !adt_is_local; is_field_list_non_exhaustive(variant_id, cx) && !adt_is_local;
let field_ty_arena = cx.db.field_types(variant_id);
let field_tys = cov_mark::hit!(match_check_wildcard_expanded_to_substitutions);
|| field_ty_arena.iter().map(|(_, binders)| binders.skip_binders()); 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 // 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. // the vast majority of real cases, since uninhabited fields are uncommon.
let has_no_hidden_fields = (matches!(adt, hir_def::AdtId::EnumId(_)) let has_no_hidden_fields = (matches!(adt, hir_def::AdtId::EnumId(_))
&& !is_non_exhaustive) && !is_non_exhaustive)
|| !field_tys().any(|ty| cx.is_uninhabited(ty)); || !field_tys().any(|ty| cx.is_uninhabited(&ty));
if has_no_hidden_fields { if has_no_hidden_fields {
Fields::wildcards_from_tys(cx, field_tys()) Fields::wildcards_from_tys(cx, field_tys())
@ -759,7 +762,7 @@ impl Fields {
FloatRange(..) => UNHANDLED, FloatRange(..) => UNHANDLED,
Constructor::IntRange(_) => UNHANDLED, Constructor::IntRange(_) => UNHANDLED,
NonExhaustive => PatKind::Wild, 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"), Opaque => pcx.cx.bug("we should not try to apply an opaque constructor"),
Missing => pcx.cx.bug( Missing => pcx.cx.bug(
"trying to apply the `Missing` constructor;\ "trying to apply the `Missing` constructor;\

View File

@ -1152,7 +1152,7 @@ pub(crate) fn compute_match_usefulness(
.collect(); .collect();
let wild_pattern = 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 v = PatStack::from_pattern(wild_pattern);
let usefulness = is_useful(cx, &matrix, &v, ConstructWitness, false, true); let usefulness = is_useful(cx, &matrix, &v, ConstructWitness, false, true);
let non_exhaustiveness_witnesses = match usefulness { let non_exhaustiveness_witnesses = match usefulness {