mirror of
https://github.com/rust-lang/rust.git
synced 2024-11-22 23:04:33 +00:00
Infer wildcard type from other patterns at every pattern level
This commit is contained in:
parent
92e470a1de
commit
57e9f7a556
@ -1202,35 +1202,32 @@ impl<'p, 'tcx> Fields<'p, 'tcx> {
|
||||
|
||||
/// Creates a new list of wildcard fields for a given constructor. The result must have a
|
||||
/// length of `constructor.arity()`.
|
||||
pub(super) fn wildcards(
|
||||
cx: &MatchCheckCtxt<'p, 'tcx>,
|
||||
ty: Ty<'tcx>,
|
||||
constructor: &Constructor<'tcx>,
|
||||
) -> Self {
|
||||
#[instrument(level = "trace")]
|
||||
pub(super) fn wildcards(pcx: PatCtxt<'_, 'p, 'tcx>, constructor: &Constructor<'tcx>) -> Self {
|
||||
let ret = match constructor {
|
||||
Single | Variant(_) => match ty.kind() {
|
||||
ty::Tuple(fs) => Fields::wildcards_from_tys(cx, fs.iter()),
|
||||
ty::Ref(_, rty, _) => Fields::wildcards_from_tys(cx, once(*rty)),
|
||||
Single | Variant(_) => match pcx.ty.kind() {
|
||||
ty::Tuple(fs) => Fields::wildcards_from_tys(pcx.cx, fs.iter()),
|
||||
ty::Ref(_, rty, _) => Fields::wildcards_from_tys(pcx.cx, once(*rty)),
|
||||
ty::Adt(adt, substs) => {
|
||||
if adt.is_box() {
|
||||
// The only legal patterns of type `Box` (outside `std`) are `_` and box
|
||||
// patterns. If we're here we can assume this is a box pattern.
|
||||
Fields::wildcards_from_tys(cx, once(substs.type_at(0)))
|
||||
Fields::wildcards_from_tys(pcx.cx, once(substs.type_at(0)))
|
||||
} else {
|
||||
let variant = &adt.variant(constructor.variant_index_for_adt(*adt));
|
||||
let tys = Fields::list_variant_nonhidden_fields(cx, ty, variant)
|
||||
let tys = Fields::list_variant_nonhidden_fields(pcx.cx, pcx.ty, variant)
|
||||
.map(|(_, ty)| ty);
|
||||
Fields::wildcards_from_tys(cx, tys)
|
||||
Fields::wildcards_from_tys(pcx.cx, tys)
|
||||
}
|
||||
}
|
||||
_ => bug!("Unexpected type for `Single` constructor: {:?}", ty),
|
||||
_ => bug!("Unexpected type for `Single` constructor: {:?}", pcx),
|
||||
},
|
||||
Slice(slice) => match *ty.kind() {
|
||||
Slice(slice) => match *pcx.ty.kind() {
|
||||
ty::Slice(ty) | ty::Array(ty, _) => {
|
||||
let arity = slice.arity();
|
||||
Fields::wildcards_from_tys(cx, (0..arity).map(|_| ty))
|
||||
Fields::wildcards_from_tys(pcx.cx, (0..arity).map(|_| ty))
|
||||
}
|
||||
_ => bug!("bad slice pattern {:?} {:?}", constructor, ty),
|
||||
_ => bug!("bad slice pattern {:?} {:?}", constructor, pcx),
|
||||
},
|
||||
Str(..)
|
||||
| FloatRange(..)
|
||||
@ -1243,7 +1240,7 @@ impl<'p, 'tcx> Fields<'p, 'tcx> {
|
||||
bug!("called `Fields::wildcards` on an `Or` ctor")
|
||||
}
|
||||
};
|
||||
debug!("Fields::wildcards({:?}, {:?}) = {:#?}", constructor, ty, ret);
|
||||
debug!(?ret);
|
||||
ret
|
||||
}
|
||||
|
||||
@ -1286,7 +1283,7 @@ impl<'p, 'tcx> DeconstructedPat<'p, 'tcx> {
|
||||
/// For example, if `ctor` is a `Constructor::Variant` for `Option::Some`, we get the pattern
|
||||
/// `Some(_)`.
|
||||
pub(super) fn wild_from_ctor(pcx: PatCtxt<'_, 'p, 'tcx>, ctor: Constructor<'tcx>) -> Self {
|
||||
let fields = Fields::wildcards(pcx.cx, pcx.ty, &ctor);
|
||||
let fields = Fields::wildcards(pcx, &ctor);
|
||||
DeconstructedPat::new(ctor, fields, pcx.ty, DUMMY_SP)
|
||||
}
|
||||
|
||||
@ -1553,13 +1550,13 @@ impl<'p, 'tcx> DeconstructedPat<'p, 'tcx> {
|
||||
/// `other_ctor` can be different from `self.ctor`, but must be covered by it.
|
||||
pub(super) fn specialize<'a>(
|
||||
&'a self,
|
||||
cx: &MatchCheckCtxt<'p, 'tcx>,
|
||||
pcx: PatCtxt<'_, 'p, 'tcx>,
|
||||
other_ctor: &Constructor<'tcx>,
|
||||
) -> SmallVec<[&'p DeconstructedPat<'p, 'tcx>; 2]> {
|
||||
match (&self.ctor, other_ctor) {
|
||||
(Wildcard, _) => {
|
||||
// We return a wildcard for each field of `other_ctor`.
|
||||
Fields::wildcards(cx, self.ty, other_ctor).iter_patterns().collect()
|
||||
Fields::wildcards(pcx, other_ctor).iter_patterns().collect()
|
||||
}
|
||||
(Slice(self_slice), Slice(other_slice))
|
||||
if self_slice.arity() != other_slice.arity() =>
|
||||
@ -1578,7 +1575,7 @@ impl<'p, 'tcx> DeconstructedPat<'p, 'tcx> {
|
||||
let prefix = &self.fields.fields[..prefix];
|
||||
let suffix = &self.fields.fields[self_slice.arity() - suffix..];
|
||||
let wildcard: &_ =
|
||||
cx.pattern_arena.alloc(DeconstructedPat::wildcard(inner_ty));
|
||||
pcx.cx.pattern_arena.alloc(DeconstructedPat::wildcard(inner_ty));
|
||||
let extra_wildcards = other_slice.arity() - self_slice.arity();
|
||||
let extra_wildcards = (0..extra_wildcards).map(|_| wildcard);
|
||||
prefix.iter().chain(extra_wildcards).chain(suffix).collect()
|
||||
|
@ -411,12 +411,12 @@ impl<'p, 'tcx> PatStack<'p, 'tcx> {
|
||||
/// This is roughly the inverse of `Constructor::apply`.
|
||||
fn pop_head_constructor(
|
||||
&self,
|
||||
cx: &MatchCheckCtxt<'p, 'tcx>,
|
||||
pcx: PatCtxt<'_, 'p, 'tcx>,
|
||||
ctor: &Constructor<'tcx>,
|
||||
) -> PatStack<'p, 'tcx> {
|
||||
// We pop the head pattern and push the new fields extracted from the arguments of
|
||||
// `self.head()`.
|
||||
let mut new_fields: SmallVec<[_; 2]> = self.head().specialize(cx, ctor);
|
||||
let mut new_fields: SmallVec<[_; 2]> = self.head().specialize(pcx, ctor);
|
||||
new_fields.extend_from_slice(&self.pats[1..]);
|
||||
PatStack::from_vec(new_fields)
|
||||
}
|
||||
@ -475,7 +475,7 @@ impl<'p, 'tcx> Matrix<'p, 'tcx> {
|
||||
let mut matrix = Matrix::empty();
|
||||
for row in &self.patterns {
|
||||
if ctor.is_covered_by(pcx, row.head().ctor()) {
|
||||
let new_row = row.pop_head_constructor(pcx.cx, ctor);
|
||||
let new_row = row.pop_head_constructor(pcx, ctor);
|
||||
matrix.push(new_row);
|
||||
}
|
||||
}
|
||||
@ -786,7 +786,7 @@ fn is_useful<'p, 'tcx>(
|
||||
is_under_guard: bool,
|
||||
is_top_level: bool,
|
||||
) -> Usefulness<'p, 'tcx> {
|
||||
debug!("matrix,v={:?}{:?}", matrix, v);
|
||||
debug!(?matrix, ?v);
|
||||
let Matrix { patterns: rows, .. } = matrix;
|
||||
|
||||
// The base case. We are pattern-matching on () and the return value is
|
||||
@ -827,7 +827,15 @@ fn is_useful<'p, 'tcx>(
|
||||
}
|
||||
}
|
||||
} else {
|
||||
let ty = v.head().ty();
|
||||
let mut ty = v.head().ty();
|
||||
|
||||
// Opaque types can't get destructured/split, but the patterns can
|
||||
// actually hint at hidden types, so we use the patterns' types instead.
|
||||
if let ty::Opaque(..) = v.head().ty().kind() {
|
||||
if let Some(row) = rows.first() {
|
||||
ty = row.head().ty();
|
||||
}
|
||||
}
|
||||
let is_non_exhaustive = cx.is_foreign_non_exhaustive_enum(ty);
|
||||
debug!("v.head: {:?}, v.span: {:?}", v.head(), v.head().span());
|
||||
let pcx = PatCtxt { cx, ty, span: v.head().span(), is_top_level, is_non_exhaustive };
|
||||
@ -853,7 +861,7 @@ fn is_useful<'p, 'tcx>(
|
||||
debug!("specialize({:?})", ctor);
|
||||
// We cache the result of `Fields::wildcards` because it is used a lot.
|
||||
let spec_matrix = start_matrix.specialize_constructor(pcx, &ctor);
|
||||
let v = v.pop_head_constructor(cx, &ctor);
|
||||
let v = v.pop_head_constructor(pcx, &ctor);
|
||||
let usefulness = ensure_sufficient_stack(|| {
|
||||
is_useful(cx, &spec_matrix, &v, witness_preference, hir_id, is_under_guard, false)
|
||||
});
|
||||
|
@ -0,0 +1,29 @@
|
||||
// check-pass
|
||||
|
||||
#[allow(unconditional_recursion)]
|
||||
fn foo(b: bool) -> impl Copy {
|
||||
let (mut x, mut y) = foo(false);
|
||||
x = 42;
|
||||
y = "foo";
|
||||
if b {
|
||||
panic!()
|
||||
} else {
|
||||
foo(true)
|
||||
}
|
||||
}
|
||||
|
||||
fn bar(b: bool) -> Option<impl Copy> {
|
||||
if b {
|
||||
return None;
|
||||
}
|
||||
match bar(!b) {
|
||||
Some((mut x, mut y)) => {
|
||||
x = 42;
|
||||
y = "foo";
|
||||
}
|
||||
None => {}
|
||||
}
|
||||
None
|
||||
}
|
||||
|
||||
fn main() {}
|
@ -9,4 +9,16 @@ fn foo(foo: T) {
|
||||
y = "foo";
|
||||
}
|
||||
|
||||
type U = impl Copy;
|
||||
|
||||
fn bar(bar: Option<U>) {
|
||||
match bar {
|
||||
Some((mut x, mut y)) => {
|
||||
x = 42;
|
||||
y = "foo";
|
||||
}
|
||||
None => {}
|
||||
}
|
||||
}
|
||||
|
||||
fn main() {}
|
||||
|
Loading…
Reference in New Issue
Block a user