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 {
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>(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

View file

@ -632,10 +632,7 @@ impl Fields {
}
/// Convenience; internal use.
fn wildcards_from_tys<'a>(
cx: &MatchCheckCtx<'_>,
tys: impl IntoIterator<Item = &'a Ty>,
) -> Self {
fn wildcards_from_tys(cx: &MatchCheckCtx<'_>, tys: impl IntoIterator<Item = Ty>) -> 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;\

View file

@ -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 {