Skip to content

Commit 728c7e8

Browse files
committed
Allow destructuring opaque types, since the patterns constrain the opaque types
1 parent 12457f8 commit 728c7e8

14 files changed

+116
-31
lines changed

compiler/rustc_mir_build/src/build/expr/as_place.rs

+28-5
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@ use rustc_hir::def_id::{DefId, LocalDefId};
77
use rustc_middle::hir::place::Projection as HirProjection;
88
use rustc_middle::hir::place::ProjectionKind as HirProjectionKind;
99
use rustc_middle::middle::region;
10+
use rustc_middle::mir::tcx::PlaceTy;
1011
use rustc_middle::mir::AssertKind::BoundsCheck;
1112
use rustc_middle::mir::*;
1213
use rustc_middle::thir::*;
@@ -104,8 +105,9 @@ fn convert_to_hir_projections_and_truncate_for_capture<'tcx>(
104105
variant = Some(*idx);
105106
continue;
106107
}
108+
// These do not affect anything, they just make sure we know the right type.
109+
ProjectionElem::OpaqueCast(_) => continue,
107110
ProjectionElem::Index(..)
108-
| ProjectionElem::OpaqueCast(_)
109111
| ProjectionElem::ConstantIndex { .. }
110112
| ProjectionElem::Subslice { .. } => {
111113
// We don't capture array-access projections.
@@ -297,16 +299,21 @@ fn strip_prefix<'tcx>(
297299
prefix_projections: &[HirProjection<'tcx>],
298300
) -> impl Iterator<Item = PlaceElem<'tcx>> {
299301
let mut iter = projections.into_iter();
302+
let mut next = || match iter.next()? {
303+
// Filter out opaque casts, they are unnecessary in the prefix.
304+
ProjectionElem::OpaqueCast(..) => iter.next(),
305+
other => Some(other),
306+
};
300307
for projection in prefix_projections {
301308
match projection.kind {
302309
HirProjectionKind::Deref => {
303-
assert!(matches!(iter.next(), Some(ProjectionElem::Deref)));
310+
assert!(matches!(next(), Some(ProjectionElem::Deref)));
304311
}
305312
HirProjectionKind::Field(..) => {
306313
if base_ty.is_enum() {
307-
assert!(matches!(iter.next(), Some(ProjectionElem::Downcast(..))));
314+
assert!(matches!(next(), Some(ProjectionElem::Downcast(..))));
308315
}
309-
assert!(matches!(iter.next(), Some(ProjectionElem::Field(..))));
316+
assert!(matches!(next(), Some(ProjectionElem::Field(..))));
310317
}
311318
HirProjectionKind::Index | HirProjectionKind::Subslice => {
312319
bug!("unexpected projection kind: {:?}", projection);
@@ -320,7 +327,23 @@ fn strip_prefix<'tcx>(
320327
impl<'tcx> PlaceBuilder<'tcx> {
321328
pub(crate) fn into_place(self, cx: &Builder<'_, 'tcx>) -> Place<'tcx> {
322329
if let PlaceBase::Local(local) = self.base {
323-
Place { local, projection: cx.tcx.intern_place_elems(&self.projection) }
330+
let mut projections = vec![];
331+
let mut ty = PlaceTy::from_ty(cx.local_decls[local].ty);
332+
for projection in self.projection {
333+
// Only preserve those opaque casts that actually go from an opaque type
334+
// to another type.
335+
if let ProjectionElem::OpaqueCast(t) = projection {
336+
if let ty::Opaque(..) = ty.ty.kind() {
337+
if t != ty.ty {
338+
projections.push(ProjectionElem::OpaqueCast(t));
339+
}
340+
}
341+
} else {
342+
projections.push(projection);
343+
}
344+
ty = ty.projection_ty(cx.tcx, projection);
345+
}
346+
Place { local, projection: cx.tcx.intern_place_elems(&projections) }
324347
} else {
325348
self.expect_upvars_resolved(cx).into_place(cx)
326349
}

compiler/rustc_mir_build/src/build/matches/mod.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -867,7 +867,7 @@ impl<'tcx, 'pat> Candidate<'pat, 'tcx> {
867867
Candidate {
868868
span: pattern.span,
869869
has_guard,
870-
match_pairs: smallvec![MatchPair { place, pattern }],
870+
match_pairs: smallvec![MatchPair::new(place, pattern)],
871871
bindings: Vec::new(),
872872
ascriptions: Vec::new(),
873873
subcandidates: Vec::new(),

compiler/rustc_mir_build/src/build/matches/util.rs

+4
Original file line numberDiff line numberDiff line change
@@ -98,6 +98,10 @@ impl<'pat, 'tcx> MatchPair<'pat, 'tcx> {
9898
place: PlaceBuilder<'tcx>,
9999
pattern: &'pat Pat<'tcx>,
100100
) -> MatchPair<'pat, 'tcx> {
101+
// Force the place type to the pattern's type.
102+
// FIXME(oli-obk): only do this when we don't already know the place type.
103+
// FIXME(oli-obk): can we use this to simplify slice/array pattern hacks?
104+
let place = place.project(ProjectionElem::OpaqueCast(pattern.ty));
101105
MatchPair { place, pattern }
102106
}
103107
}

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

+5-1
Original file line numberDiff line numberDiff line change
@@ -967,7 +967,11 @@ pub(crate) fn compute_match_usefulness<'p, 'tcx>(
967967
})
968968
.collect();
969969

970-
let wild_pattern = cx.pattern_arena.alloc(DeconstructedPat::wildcard(scrut_ty));
970+
// In case we're matching on an opaque type in its defining scope, the patterns define the hidden type.
971+
// The wildcard pattern needs to have the same type, otherwise it will always be deemed useful, even if the
972+
// match is exhaustive for the pattern type.
973+
let wild_ty = arms.first().map_or(scrut_ty, |arm| arm.pat.ty());
974+
let wild_pattern = cx.pattern_arena.alloc(DeconstructedPat::wildcard(wild_ty));
971975
let v = PatStack::from_pattern(wild_pattern);
972976
let usefulness = is_useful(cx, &matrix, &v, FakeExtraWildcard, scrut_hir_id, false, true);
973977
let non_exhaustiveness_witnesses = match usefulness {
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,9 @@
11
// compile-flags: --edition=2021
2+
// check-pass
23
#![feature(type_alias_impl_trait)]
34

45
fn main() {
5-
type T = impl Copy; //~ ERROR unconstrained opaque type
6+
type T = impl Copy;
67
let foo: T = (1u32, 2u32);
78
let (a, b): (u32, u32) = foo;
89
}

src/test/ui/type-alias-impl-trait/cross_inference_pattern_bug.stderr

-10
This file was deleted.
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,13 @@
1-
// known-bug: #96572
21
// compile-flags: --edition=2021 --crate-type=lib
32
// rustc-env:RUST_BACKTRACE=0
3+
// check-pass
44

55
// tracked in https://github.com/rust-lang/rust/issues/96572
66

77
#![feature(type_alias_impl_trait)]
88

99
fn main() {
10-
type T = impl Copy; // error: unconstrained opaque type
10+
type T = impl Copy;
1111
let foo: T = (1u32, 2u32);
12-
let (a, b) = foo; // removing this line makes the code compile
12+
let (a, b) = foo; // this line used to make the code fail
1313
}

src/test/ui/type-alias-impl-trait/cross_inference_pattern_bug_no_type.stderr

-10
This file was deleted.
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
#![feature(type_alias_impl_trait)]
2+
3+
fn main() {
4+
type T = impl Copy;
5+
let foo: T = Some((1u32, 2u32));
6+
match foo {
7+
None => (),
8+
Some((a, b, c)) => (), //~ ERROR mismatched types
9+
}
10+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
error[E0308]: mismatched types
2+
--> $DIR/issue-96572-unconstrained-mismatch.rs:8:14
3+
|
4+
LL | match foo {
5+
| --- this expression has type `T`
6+
LL | None => (),
7+
LL | Some((a, b, c)) => (),
8+
| ^^^^^^^^^ expected a tuple with 2 elements, found one with 3 elements
9+
|
10+
= note: expected tuple `(u32, u32)`
11+
found tuple `(_, _, _)`
12+
13+
error: aborting due to previous error
14+
15+
For more information about this error, try `rustc --explain E0308`.
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
#![feature(type_alias_impl_trait)]
2+
// check-pass
3+
4+
#[derive(Copy, Clone)]
5+
struct Foo((u32, u32));
6+
7+
fn main() {
8+
type U = impl Copy;
9+
let foo: U = Foo((1u32, 2u32));
10+
let Foo((a, b)) = foo;
11+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
#![feature(type_alias_impl_trait)]
2+
// check-pass
3+
4+
fn main() {
5+
type T = impl Copy;
6+
let foo: T = Some((1u32, 2u32));
7+
let x = move || {
8+
match foo {
9+
None => (),
10+
Some((a, b)) => (),
11+
}
12+
};
13+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
#![feature(type_alias_impl_trait)]
2+
// check-pass
3+
4+
#[derive(Copy, Clone)]
5+
struct Foo((u32, u32));
6+
7+
fn main() {
8+
type T = impl Copy;
9+
let foo: T = Foo((1u32, 2u32));
10+
let x = move || {
11+
let Foo((a, b)) = foo;
12+
};
13+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
#![feature(type_alias_impl_trait)]
2+
// check-pass
3+
4+
fn main() {
5+
type T = impl Copy;
6+
let foo: T = Some((1u32, 2u32));
7+
match foo {
8+
None => (),
9+
Some((a, b)) => (),
10+
}
11+
}

0 commit comments

Comments
 (0)