Skip to content

Commit 57e9f7a

Browse files
committed
Infer wildcard type from other patterns at every pattern level
1 parent 92e470a commit 57e9f7a

File tree

4 files changed

+72
-26
lines changed

4 files changed

+72
-26
lines changed

compiler/rustc_mir_build/src/thir/pattern/deconstruct_pat.rs

+17-20
Original file line numberDiff line numberDiff line change
@@ -1202,35 +1202,32 @@ impl<'p, 'tcx> Fields<'p, 'tcx> {
12021202

12031203
/// Creates a new list of wildcard fields for a given constructor. The result must have a
12041204
/// length of `constructor.arity()`.
1205-
pub(super) fn wildcards(
1206-
cx: &MatchCheckCtxt<'p, 'tcx>,
1207-
ty: Ty<'tcx>,
1208-
constructor: &Constructor<'tcx>,
1209-
) -> Self {
1205+
#[instrument(level = "trace")]
1206+
pub(super) fn wildcards(pcx: PatCtxt<'_, 'p, 'tcx>, constructor: &Constructor<'tcx>) -> Self {
12101207
let ret = match constructor {
1211-
Single | Variant(_) => match ty.kind() {
1212-
ty::Tuple(fs) => Fields::wildcards_from_tys(cx, fs.iter()),
1213-
ty::Ref(_, rty, _) => Fields::wildcards_from_tys(cx, once(*rty)),
1208+
Single | Variant(_) => match pcx.ty.kind() {
1209+
ty::Tuple(fs) => Fields::wildcards_from_tys(pcx.cx, fs.iter()),
1210+
ty::Ref(_, rty, _) => Fields::wildcards_from_tys(pcx.cx, once(*rty)),
12141211
ty::Adt(adt, substs) => {
12151212
if adt.is_box() {
12161213
// The only legal patterns of type `Box` (outside `std`) are `_` and box
12171214
// patterns. If we're here we can assume this is a box pattern.
1218-
Fields::wildcards_from_tys(cx, once(substs.type_at(0)))
1215+
Fields::wildcards_from_tys(pcx.cx, once(substs.type_at(0)))
12191216
} else {
12201217
let variant = &adt.variant(constructor.variant_index_for_adt(*adt));
1221-
let tys = Fields::list_variant_nonhidden_fields(cx, ty, variant)
1218+
let tys = Fields::list_variant_nonhidden_fields(pcx.cx, pcx.ty, variant)
12221219
.map(|(_, ty)| ty);
1223-
Fields::wildcards_from_tys(cx, tys)
1220+
Fields::wildcards_from_tys(pcx.cx, tys)
12241221
}
12251222
}
1226-
_ => bug!("Unexpected type for `Single` constructor: {:?}", ty),
1223+
_ => bug!("Unexpected type for `Single` constructor: {:?}", pcx),
12271224
},
1228-
Slice(slice) => match *ty.kind() {
1225+
Slice(slice) => match *pcx.ty.kind() {
12291226
ty::Slice(ty) | ty::Array(ty, _) => {
12301227
let arity = slice.arity();
1231-
Fields::wildcards_from_tys(cx, (0..arity).map(|_| ty))
1228+
Fields::wildcards_from_tys(pcx.cx, (0..arity).map(|_| ty))
12321229
}
1233-
_ => bug!("bad slice pattern {:?} {:?}", constructor, ty),
1230+
_ => bug!("bad slice pattern {:?} {:?}", constructor, pcx),
12341231
},
12351232
Str(..)
12361233
| FloatRange(..)
@@ -1243,7 +1240,7 @@ impl<'p, 'tcx> Fields<'p, 'tcx> {
12431240
bug!("called `Fields::wildcards` on an `Or` ctor")
12441241
}
12451242
};
1246-
debug!("Fields::wildcards({:?}, {:?}) = {:#?}", constructor, ty, ret);
1243+
debug!(?ret);
12471244
ret
12481245
}
12491246

@@ -1286,7 +1283,7 @@ impl<'p, 'tcx> DeconstructedPat<'p, 'tcx> {
12861283
/// For example, if `ctor` is a `Constructor::Variant` for `Option::Some`, we get the pattern
12871284
/// `Some(_)`.
12881285
pub(super) fn wild_from_ctor(pcx: PatCtxt<'_, 'p, 'tcx>, ctor: Constructor<'tcx>) -> Self {
1289-
let fields = Fields::wildcards(pcx.cx, pcx.ty, &ctor);
1286+
let fields = Fields::wildcards(pcx, &ctor);
12901287
DeconstructedPat::new(ctor, fields, pcx.ty, DUMMY_SP)
12911288
}
12921289

@@ -1553,13 +1550,13 @@ impl<'p, 'tcx> DeconstructedPat<'p, 'tcx> {
15531550
/// `other_ctor` can be different from `self.ctor`, but must be covered by it.
15541551
pub(super) fn specialize<'a>(
15551552
&'a self,
1556-
cx: &MatchCheckCtxt<'p, 'tcx>,
1553+
pcx: PatCtxt<'_, 'p, 'tcx>,
15571554
other_ctor: &Constructor<'tcx>,
15581555
) -> SmallVec<[&'p DeconstructedPat<'p, 'tcx>; 2]> {
15591556
match (&self.ctor, other_ctor) {
15601557
(Wildcard, _) => {
15611558
// We return a wildcard for each field of `other_ctor`.
1562-
Fields::wildcards(cx, self.ty, other_ctor).iter_patterns().collect()
1559+
Fields::wildcards(pcx, other_ctor).iter_patterns().collect()
15631560
}
15641561
(Slice(self_slice), Slice(other_slice))
15651562
if self_slice.arity() != other_slice.arity() =>
@@ -1578,7 +1575,7 @@ impl<'p, 'tcx> DeconstructedPat<'p, 'tcx> {
15781575
let prefix = &self.fields.fields[..prefix];
15791576
let suffix = &self.fields.fields[self_slice.arity() - suffix..];
15801577
let wildcard: &_ =
1581-
cx.pattern_arena.alloc(DeconstructedPat::wildcard(inner_ty));
1578+
pcx.cx.pattern_arena.alloc(DeconstructedPat::wildcard(inner_ty));
15821579
let extra_wildcards = other_slice.arity() - self_slice.arity();
15831580
let extra_wildcards = (0..extra_wildcards).map(|_| wildcard);
15841581
prefix.iter().chain(extra_wildcards).chain(suffix).collect()

compiler/rustc_mir_build/src/thir/pattern/usefulness.rs

+14-6
Original file line numberDiff line numberDiff line change
@@ -411,12 +411,12 @@ impl<'p, 'tcx> PatStack<'p, 'tcx> {
411411
/// This is roughly the inverse of `Constructor::apply`.
412412
fn pop_head_constructor(
413413
&self,
414-
cx: &MatchCheckCtxt<'p, 'tcx>,
414+
pcx: PatCtxt<'_, 'p, 'tcx>,
415415
ctor: &Constructor<'tcx>,
416416
) -> PatStack<'p, 'tcx> {
417417
// We pop the head pattern and push the new fields extracted from the arguments of
418418
// `self.head()`.
419-
let mut new_fields: SmallVec<[_; 2]> = self.head().specialize(cx, ctor);
419+
let mut new_fields: SmallVec<[_; 2]> = self.head().specialize(pcx, ctor);
420420
new_fields.extend_from_slice(&self.pats[1..]);
421421
PatStack::from_vec(new_fields)
422422
}
@@ -475,7 +475,7 @@ impl<'p, 'tcx> Matrix<'p, 'tcx> {
475475
let mut matrix = Matrix::empty();
476476
for row in &self.patterns {
477477
if ctor.is_covered_by(pcx, row.head().ctor()) {
478-
let new_row = row.pop_head_constructor(pcx.cx, ctor);
478+
let new_row = row.pop_head_constructor(pcx, ctor);
479479
matrix.push(new_row);
480480
}
481481
}
@@ -786,7 +786,7 @@ fn is_useful<'p, 'tcx>(
786786
is_under_guard: bool,
787787
is_top_level: bool,
788788
) -> Usefulness<'p, 'tcx> {
789-
debug!("matrix,v={:?}{:?}", matrix, v);
789+
debug!(?matrix, ?v);
790790
let Matrix { patterns: rows, .. } = matrix;
791791

792792
// The base case. We are pattern-matching on () and the return value is
@@ -827,7 +827,15 @@ fn is_useful<'p, 'tcx>(
827827
}
828828
}
829829
} else {
830-
let ty = v.head().ty();
830+
let mut ty = v.head().ty();
831+
832+
// Opaque types can't get destructured/split, but the patterns can
833+
// actually hint at hidden types, so we use the patterns' types instead.
834+
if let ty::Opaque(..) = v.head().ty().kind() {
835+
if let Some(row) = rows.first() {
836+
ty = row.head().ty();
837+
}
838+
}
831839
let is_non_exhaustive = cx.is_foreign_non_exhaustive_enum(ty);
832840
debug!("v.head: {:?}, v.span: {:?}", v.head(), v.head().span());
833841
let pcx = PatCtxt { cx, ty, span: v.head().span(), is_top_level, is_non_exhaustive };
@@ -853,7 +861,7 @@ fn is_useful<'p, 'tcx>(
853861
debug!("specialize({:?})", ctor);
854862
// We cache the result of `Fields::wildcards` because it is used a lot.
855863
let spec_matrix = start_matrix.specialize_constructor(pcx, &ctor);
856-
let v = v.pop_head_constructor(cx, &ctor);
864+
let v = v.pop_head_constructor(pcx, &ctor);
857865
let usefulness = ensure_sufficient_stack(|| {
858866
is_useful(cx, &spec_matrix, &v, witness_preference, hir_id, is_under_guard, false)
859867
});
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,29 @@
1+
// check-pass
2+
3+
#[allow(unconditional_recursion)]
4+
fn foo(b: bool) -> impl Copy {
5+
let (mut x, mut y) = foo(false);
6+
x = 42;
7+
y = "foo";
8+
if b {
9+
panic!()
10+
} else {
11+
foo(true)
12+
}
13+
}
14+
15+
fn bar(b: bool) -> Option<impl Copy> {
16+
if b {
17+
return None;
18+
}
19+
match bar(!b) {
20+
Some((mut x, mut y)) => {
21+
x = 42;
22+
y = "foo";
23+
}
24+
None => {}
25+
}
26+
None
27+
}
28+
29+
fn main() {}

src/test/ui/type-alias-impl-trait/issue-96572-unconstrained-only-pattern.rs

+12
Original file line numberDiff line numberDiff line change
@@ -9,4 +9,16 @@ fn foo(foo: T) {
99
y = "foo";
1010
}
1111

12+
type U = impl Copy;
13+
14+
fn bar(bar: Option<U>) {
15+
match bar {
16+
Some((mut x, mut y)) => {
17+
x = 42;
18+
y = "foo";
19+
}
20+
None => {}
21+
}
22+
}
23+
1224
fn main() {}

0 commit comments

Comments
 (0)