Take substitutions into account.
This commit is contained in:
parent
e16f413582
commit
3088ca0a53
@ -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
|
||||
|
@ -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;\
|
||||
|
@ -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 {
|
||||
|
Loading…
x
Reference in New Issue
Block a user