Skip to content
This repository was archived by the owner on May 28, 2025. It is now read-only.

Commit 6ee5142

Browse files
committed
Respect split invariants for Opaques
1 parent 25696cc commit 6ee5142

File tree

1 file changed

+59
-25
lines changed

1 file changed

+59
-25
lines changed

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

Lines changed: 59 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -41,6 +41,13 @@
4141
//! or-patterns; instead we just try the alternatives one-by-one. For details on splitting
4242
//! wildcards, see [`Constructor::split`]; for integer ranges, see
4343
//! [`IntRange::split`]; for slices, see [`Slice::split`].
44+
//!
45+
//! ## Opaque patterns
46+
//!
47+
//! Some patterns, such as TODO, cannot be inspected, which we handle with `Constructor::Opaque`.
48+
//! Since we know nothing of these patterns, we assume they never cover each other. In order to
49+
//! respect the invariants of [`SplitConstructorSet`], we give each `Opaque` constructor a unique id
50+
//! so we can recognize it.
4451
4552
use std::cell::Cell;
4653
use std::cmp::{self, max, min, Ordering};
@@ -617,6 +624,18 @@ impl Slice {
617624
}
618625
}
619626

627+
/// A globally unique id to distinguish `Opaque` patterns.
628+
#[derive(Clone, Debug, PartialEq, Eq)]
629+
pub(super) struct OpaqueId(u32);
630+
631+
impl OpaqueId {
632+
fn new() -> Self {
633+
use std::sync::atomic::{AtomicU32, Ordering};
634+
static OPAQUE_ID: AtomicU32 = AtomicU32::new(0);
635+
OpaqueId(OPAQUE_ID.fetch_add(1, Ordering::SeqCst))
636+
}
637+
}
638+
620639
/// A value can be decomposed into a constructor applied to some fields. This struct represents
621640
/// the constructor. See also `Fields`.
622641
///
@@ -642,10 +661,12 @@ pub(super) enum Constructor<'tcx> {
642661
Str(mir::Const<'tcx>),
643662
/// Array and slice patterns.
644663
Slice(Slice),
645-
/// Constants that must not be matched structurally. They are treated as black
646-
/// boxes for the purposes of exhaustiveness: we must not inspect them, and they
647-
/// don't count towards making a match exhaustive.
648-
Opaque,
664+
/// Constants that must not be matched structurally. They are treated as black boxes for the
665+
/// purposes of exhaustiveness: we must not inspect them, and they don't count towards making a
666+
/// match exhaustive.
667+
/// Carries an id that must be unique within a match. We need this to ensure the invariants of
668+
/// [`SplitConstructorSet`].
669+
Opaque(OpaqueId),
649670
/// Or-pattern.
650671
Or,
651672
/// Wildcard pattern.
@@ -663,6 +684,9 @@ pub(super) enum Constructor<'tcx> {
663684
}
664685

665686
impl<'tcx> Constructor<'tcx> {
687+
pub(super) fn is_wildcard(&self) -> bool {
688+
matches!(self, Wildcard)
689+
}
666690
pub(super) fn is_non_exhaustive(&self) -> bool {
667691
matches!(self, NonExhaustive)
668692
}
@@ -728,7 +752,7 @@ impl<'tcx> Constructor<'tcx> {
728752
| F32Range(..)
729753
| F64Range(..)
730754
| Str(..)
731-
| Opaque
755+
| Opaque(..)
732756
| NonExhaustive
733757
| Hidden
734758
| Missing { .. }
@@ -869,8 +893,10 @@ impl<'tcx> Constructor<'tcx> {
869893
}
870894
(Slice(self_slice), Slice(other_slice)) => self_slice.is_covered_by(*other_slice),
871895

872-
// We are trying to inspect an opaque constant. Thus we skip the row.
873-
(Opaque, _) | (_, Opaque) => false,
896+
// Opaque constructors don't interact with anything unless they come from the
897+
// syntactically identical pattern.
898+
(Opaque(self_id), Opaque(other_id)) => self_id == other_id,
899+
(Opaque(..), _) | (_, Opaque(..)) => false,
874900

875901
_ => span_bug!(
876902
pcx.span,
@@ -1083,18 +1109,26 @@ impl ConstructorSet {
10831109
{
10841110
let mut present: SmallVec<[_; 1]> = SmallVec::new();
10851111
let mut missing = Vec::new();
1086-
// Constructors in `ctors`, except wildcards.
1087-
let mut seen = ctors.filter(|c| !(matches!(c, Opaque | Wildcard)));
1112+
// Constructors in `ctors`, except wildcards and opaques.
1113+
let mut seen = Vec::new();
1114+
for ctor in ctors.cloned() {
1115+
if let Constructor::Opaque(..) = ctor {
1116+
present.push(ctor);
1117+
} else if !ctor.is_wildcard() {
1118+
seen.push(ctor);
1119+
}
1120+
}
1121+
10881122
match self {
10891123
ConstructorSet::Single => {
1090-
if seen.next().is_none() {
1124+
if seen.is_empty() {
10911125
missing.push(Single);
10921126
} else {
10931127
present.push(Single);
10941128
}
10951129
}
10961130
ConstructorSet::Variants { visible_variants, hidden_variants, non_exhaustive } => {
1097-
let seen_set: FxHashSet<_> = seen.map(|c| c.as_variant().unwrap()).collect();
1131+
let seen_set: FxHashSet<_> = seen.iter().map(|c| c.as_variant().unwrap()).collect();
10981132
let mut skipped_a_hidden_variant = false;
10991133

11001134
for variant in visible_variants {
@@ -1125,7 +1159,7 @@ impl ConstructorSet {
11251159
ConstructorSet::Bool => {
11261160
let mut seen_false = false;
11271161
let mut seen_true = false;
1128-
for b in seen.map(|ctor| ctor.as_bool().unwrap()) {
1162+
for b in seen.iter().map(|ctor| ctor.as_bool().unwrap()) {
11291163
if b {
11301164
seen_true = true;
11311165
} else {
@@ -1145,7 +1179,7 @@ impl ConstructorSet {
11451179
}
11461180
ConstructorSet::Integers { range_1, range_2 } => {
11471181
let seen_ranges: Vec<_> =
1148-
seen.map(|ctor| ctor.as_int_range().unwrap().clone()).collect();
1182+
seen.iter().map(|ctor| ctor.as_int_range().unwrap().clone()).collect();
11491183
for (seen, splitted_range) in range_1.split(seen_ranges.iter().cloned()) {
11501184
match seen {
11511185
Presence::Unseen => missing.push(IntRange(splitted_range)),
@@ -1162,7 +1196,7 @@ impl ConstructorSet {
11621196
}
11631197
}
11641198
&ConstructorSet::Slice(array_len) => {
1165-
let seen_slices = seen.map(|c| c.as_slice().unwrap());
1199+
let seen_slices = seen.iter().map(|c| c.as_slice().unwrap());
11661200
let base_slice = Slice::new(array_len, VarLen(0, 0));
11671201
for (seen, splitted_slice) in base_slice.split(seen_slices) {
11681202
let ctor = Slice(splitted_slice);
@@ -1178,7 +1212,7 @@ impl ConstructorSet {
11781212
// unreachable if length != 0.
11791213
// We still gather the seen constructors in `present`, but the only slice that can
11801214
// go in `missing` is `[]`.
1181-
let seen_slices = seen.map(|c| c.as_slice().unwrap());
1215+
let seen_slices = seen.iter().map(|c| c.as_slice().unwrap());
11821216
let base_slice = Slice::new(None, VarLen(0, 0));
11831217
for (seen, splitted_slice) in base_slice.split(seen_slices) {
11841218
let ctor = Slice(splitted_slice);
@@ -1194,7 +1228,7 @@ impl ConstructorSet {
11941228
ConstructorSet::Unlistable => {
11951229
// Since we can't list constructors, we take the ones in the column. This might list
11961230
// some constructors several times but there's not much we can do.
1197-
present.extend(seen.cloned());
1231+
present.extend(seen);
11981232
missing.push(NonExhaustive);
11991233
}
12001234
// If `exhaustive_patterns` is disabled and our scrutinee is an empty type, we cannot
@@ -1339,7 +1373,7 @@ impl<'p, 'tcx> Fields<'p, 'tcx> {
13391373
| F32Range(..)
13401374
| F64Range(..)
13411375
| Str(..)
1342-
| Opaque
1376+
| Opaque(..)
13431377
| NonExhaustive
13441378
| Hidden
13451379
| Missing { .. }
@@ -1470,14 +1504,14 @@ impl<'p, 'tcx> DeconstructedPat<'p, 'tcx> {
14701504
ty::Bool => {
14711505
ctor = match value.try_eval_bool(cx.tcx, cx.param_env) {
14721506
Some(b) => Bool(b),
1473-
None => Opaque,
1507+
None => Opaque(OpaqueId::new()),
14741508
};
14751509
fields = Fields::empty();
14761510
}
14771511
ty::Char | ty::Int(_) | ty::Uint(_) => {
14781512
ctor = match value.try_eval_bits(cx.tcx, cx.param_env) {
14791513
Some(bits) => IntRange(IntRange::from_bits(cx.tcx, pat.ty, bits)),
1480-
None => Opaque,
1514+
None => Opaque(OpaqueId::new()),
14811515
};
14821516
fields = Fields::empty();
14831517
}
@@ -1488,7 +1522,7 @@ impl<'p, 'tcx> DeconstructedPat<'p, 'tcx> {
14881522
let value = rustc_apfloat::ieee::Single::from_bits(bits);
14891523
F32Range(value, value, RangeEnd::Included)
14901524
}
1491-
None => Opaque,
1525+
None => Opaque(OpaqueId::new()),
14921526
};
14931527
fields = Fields::empty();
14941528
}
@@ -1499,7 +1533,7 @@ impl<'p, 'tcx> DeconstructedPat<'p, 'tcx> {
14991533
let value = rustc_apfloat::ieee::Double::from_bits(bits);
15001534
F64Range(value, value, RangeEnd::Included)
15011535
}
1502-
None => Opaque,
1536+
None => Opaque(OpaqueId::new()),
15031537
};
15041538
fields = Fields::empty();
15051539
}
@@ -1520,7 +1554,7 @@ impl<'p, 'tcx> DeconstructedPat<'p, 'tcx> {
15201554
// into the corresponding `Pat`s by `const_to_pat`. Constants that remain are
15211555
// opaque.
15221556
_ => {
1523-
ctor = Opaque;
1557+
ctor = Opaque(OpaqueId::new());
15241558
fields = Fields::empty();
15251559
}
15261560
}
@@ -1581,7 +1615,7 @@ impl<'p, 'tcx> DeconstructedPat<'p, 'tcx> {
15811615
fields = Fields::from_iter(cx, pats.into_iter().map(mkpat));
15821616
}
15831617
PatKind::Error(_) => {
1584-
ctor = Opaque;
1618+
ctor = Opaque(OpaqueId::new());
15851619
fields = Fields::empty();
15861620
}
15871621
}
@@ -1768,7 +1802,7 @@ impl<'p, 'tcx> fmt::Debug for DeconstructedPat<'p, 'tcx> {
17681802
F32Range(lo, hi, end) => write!(f, "{lo}{end}{hi}"),
17691803
F64Range(lo, hi, end) => write!(f, "{lo}{end}{hi}"),
17701804
Str(value) => write!(f, "{value}"),
1771-
Opaque => write!(f, "<constant pattern>"),
1805+
Opaque(..) => write!(f, "<constant pattern>"),
17721806
Or => {
17731807
for pat in self.iter_fields() {
17741808
write!(f, "{}{:?}", start_or_continue(" | "), pat)?;
@@ -1898,7 +1932,7 @@ impl<'tcx> WitnessPat<'tcx> {
18981932
"trying to convert a `Missing` constructor into a `Pat`; this is probably a bug,
18991933
`Missing` should have been processed in `apply_constructors`"
19001934
),
1901-
F32Range(..) | F64Range(..) | Opaque | Or => {
1935+
F32Range(..) | F64Range(..) | Opaque(..) | Or => {
19021936
bug!("can't convert to pattern: {:?}", self)
19031937
}
19041938
};

0 commit comments

Comments
 (0)