mirror of
https://github.com/rust-lang/rust-analyzer.git
synced 2025-10-01 11:31:15 +00:00
Take substitutions into account.
This commit is contained in:
parent
e16f413582
commit
3088ca0a53
@ -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
|
||||||
|
@ -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;\
|
||||||
|
@ -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 {
|
||||||
|
Loading…
x
Reference in New Issue
Block a user