Skip to content

Commit da0ba2f

Browse files
committed
The only remaining constant patterns are opaque
1 parent d1a784e commit da0ba2f

File tree

4 files changed

+50
-37
lines changed

4 files changed

+50
-37
lines changed

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

+41-28
Original file line numberDiff line numberDiff line change
@@ -394,9 +394,15 @@ impl<'p, 'tcx> PatStack<'p, 'tcx> {
394394
cx: &mut MatchCheckCtxt<'p, 'tcx>,
395395
constructor: &Constructor<'tcx>,
396396
ctor_wild_subpatterns: &Fields<'p, 'tcx>,
397+
is_my_head_ctor: bool,
397398
) -> Option<PatStack<'p, 'tcx>> {
398-
let new_fields =
399-
specialize_one_pattern(cx, self.head(), constructor, ctor_wild_subpatterns)?;
399+
let new_fields = specialize_one_pattern(
400+
cx,
401+
self.head(),
402+
constructor,
403+
ctor_wild_subpatterns,
404+
is_my_head_ctor,
405+
)?;
400406
Some(new_fields.push_on_patstack(&self.0[1..]))
401407
}
402408
}
@@ -574,6 +580,7 @@ impl<'p, 'tcx> Matrix<'p, 'tcx> {
574580
cx,
575581
constructor,
576582
ctor_wild_subpatterns,
583+
false,
577584
)
578585
})
579586
.collect()
@@ -599,7 +606,9 @@ impl<'p, 'tcx> Matrix<'p, 'tcx> {
599606
SpecializationCache::Incompatible => self
600607
.patterns
601608
.iter()
602-
.filter_map(|r| r.specialize_constructor(cx, constructor, ctor_wild_subpatterns))
609+
.filter_map(|r| {
610+
r.specialize_constructor(cx, constructor, ctor_wild_subpatterns, false)
611+
})
603612
.collect(),
604613
}
605614
}
@@ -821,8 +830,6 @@ enum Constructor<'tcx> {
821830
Single,
822831
/// Enum variants.
823832
Variant(DefId),
824-
/// Literal values.
825-
ConstantValue(&'tcx ty::Const<'tcx>),
826833
/// Ranges of integer literal values (`2`, `2..=5` or `2..5`).
827834
IntRange(IntRange<'tcx>),
828835
/// Ranges of floating-point literal values (`2.0..=5.2`).
@@ -831,27 +838,22 @@ enum Constructor<'tcx> {
831838
Str(&'tcx ty::Const<'tcx>),
832839
/// Array and slice patterns.
833840
Slice(Slice),
841+
/// Constants that must not be matched structurally. They are treated as black
842+
/// boxes for the purposes of exhaustiveness: we must not inspect them, and they
843+
/// don't count towards making a match exhaustive.
844+
Opaque,
834845
/// Fake extra constructor for enums that aren't allowed to be matched exhaustively.
835846
NonExhaustive,
836847
}
837848

838849
impl<'tcx> Constructor<'tcx> {
839-
fn variant_index_for_adt<'a>(
840-
&self,
841-
cx: &MatchCheckCtxt<'a, 'tcx>,
842-
adt: &'tcx ty::AdtDef,
843-
) -> VariantIdx {
850+
fn variant_index_for_adt(&self, adt: &'tcx ty::AdtDef) -> VariantIdx {
844851
match *self {
845852
Variant(id) => adt.variant_index_with_id(id),
846853
Single => {
847854
assert!(!adt.is_enum());
848855
VariantIdx::new(0)
849856
}
850-
ConstantValue(c) => cx
851-
.tcx
852-
.destructure_const(cx.param_env.and(c))
853-
.variant
854-
.expect("destructed const of adt without variant id"),
855857
_ => bug!("bad constructor {:?} for adt {:?}", self, adt),
856858
}
857859
}
@@ -865,7 +867,7 @@ impl<'tcx> Constructor<'tcx> {
865867

866868
match self {
867869
// Those constructors can only match themselves.
868-
Single | Variant(_) | ConstantValue(..) | Str(..) | FloatRange(..) => {
870+
Single | Variant(_) | Str(..) | FloatRange(..) => {
869871
if other_ctors.iter().any(|c| c == self) { vec![] } else { vec![self.clone()] }
870872
}
871873
&Slice(slice) => {
@@ -936,6 +938,7 @@ impl<'tcx> Constructor<'tcx> {
936938
}
937939
// This constructor is never covered by anything else
938940
NonExhaustive => vec![NonExhaustive],
941+
Opaque => bug!("unexpected opaque ctor {:?} found in all_ctors", self),
939942
}
940943
}
941944

@@ -975,7 +978,7 @@ impl<'tcx> Constructor<'tcx> {
975978
PatKind::Variant {
976979
adt_def: adt,
977980
substs,
978-
variant_index: self.variant_index_for_adt(cx, adt),
981+
variant_index: self.variant_index_for_adt(adt),
979982
subpatterns,
980983
}
981984
} else {
@@ -1014,11 +1017,11 @@ impl<'tcx> Constructor<'tcx> {
10141017
PatKind::Slice { prefix, slice: Some(wild), suffix }
10151018
}
10161019
},
1017-
&ConstantValue(value) => PatKind::Constant { value },
10181020
&Str(value) => PatKind::Constant { value },
10191021
&FloatRange(lo, hi, end) => PatKind::Range(PatRange { lo, hi, end }),
10201022
IntRange(range) => return range.to_pat(cx.tcx),
10211023
NonExhaustive => PatKind::Wild,
1024+
Opaque => bug!("we should not try to apply an opaque constructor {:?}", self),
10221025
};
10231026

10241027
Pat { ty, span: DUMMY_SP, kind: Box::new(pat) }
@@ -1122,7 +1125,7 @@ impl<'p, 'tcx> Fields<'p, 'tcx> {
11221125
// Use T as the sub pattern type of Box<T>.
11231126
Fields::from_single_pattern(wildcard_from_ty(substs.type_at(0)))
11241127
} else {
1125-
let variant = &adt.variants[constructor.variant_index_for_adt(cx, adt)];
1128+
let variant = &adt.variants[constructor.variant_index_for_adt(adt)];
11261129
// Whether we must not match the fields of this variant exhaustively.
11271130
let is_non_exhaustive =
11281131
variant.is_field_list_non_exhaustive() && !adt.did.is_local();
@@ -1170,9 +1173,7 @@ impl<'p, 'tcx> Fields<'p, 'tcx> {
11701173
}
11711174
_ => bug!("bad slice pattern {:?} {:?}", constructor, ty),
11721175
},
1173-
ConstantValue(..) | Str(..) | FloatRange(..) | IntRange(..) | NonExhaustive => {
1174-
Fields::empty()
1175-
}
1176+
Str(..) | FloatRange(..) | IntRange(..) | NonExhaustive | Opaque => Fields::empty(),
11761177
};
11771178
debug!("Fields::wildcards({:?}, {:?}) = {:#?}", constructor, ty, ret);
11781179
ret
@@ -2085,7 +2086,7 @@ fn is_useful_specialized<'p, 'tcx>(
20852086
// We cache the result of `Fields::wildcards` because it is used a lot.
20862087
let ctor_wild_subpatterns = Fields::wildcards(cx, &ctor, ty);
20872088
let matrix = matrix.specialize_constructor(cx, &ctor, &ctor_wild_subpatterns);
2088-
v.specialize_constructor(cx, &ctor, &ctor_wild_subpatterns)
2089+
v.specialize_constructor(cx, &ctor, &ctor_wild_subpatterns, true)
20892090
.map(|v| is_useful(cx, &matrix, &v, witness_preference, hir_id, is_under_guard, false))
20902091
.map(|u| u.apply_constructor(cx, &ctor, ty, &ctor_wild_subpatterns))
20912092
.unwrap_or(NotUseful)
@@ -2112,7 +2113,7 @@ fn pat_constructor<'tcx>(
21122113
match value.ty.kind() {
21132114
ty::Float(_) => Some(FloatRange(value, value, RangeEnd::Included)),
21142115
ty::Ref(_, t, _) if t.is_str() => Some(Str(value)),
2115-
_ => Some(ConstantValue(value)),
2116+
_ => Some(Opaque),
21162117
}
21172118
}
21182119
}
@@ -2461,15 +2462,26 @@ fn specialize_one_pattern<'p, 'tcx>(
24612462
pat: &'p Pat<'tcx>,
24622463
constructor: &Constructor<'tcx>,
24632464
ctor_wild_subpatterns: &Fields<'p, 'tcx>,
2465+
is_its_own_ctor: bool, // Whether `ctor` is known to be derived from `pat`
24642466
) -> Option<Fields<'p, 'tcx>> {
24652467
if let NonExhaustive = constructor {
2466-
// Only a wildcard pattern can match the special extra constructor
2468+
// Only a wildcard pattern can match the special extra constructor.
24672469
if !pat.is_wildcard() {
24682470
return None;
24692471
}
24702472
return Some(Fields::empty());
24712473
}
24722474

2475+
if let Opaque = constructor {
2476+
// Only a wildcard pattern can match an opaque constant, unless we're specializing the
2477+
// value against its own constructor.
2478+
if is_its_own_ctor || pat.is_wildcard() {
2479+
return Some(Fields::empty());
2480+
} else {
2481+
return None;
2482+
}
2483+
}
2484+
24732485
let result = match *pat.kind {
24742486
PatKind::AscribeUserType { .. } => bug!(), // Handled by `expand_pattern`
24752487

@@ -2491,7 +2503,6 @@ fn specialize_one_pattern<'p, 'tcx>(
24912503

24922504
PatKind::Constant { .. } | PatKind::Range { .. } => {
24932505
match constructor {
2494-
Single => {}
24952506
IntRange(ctor) => {
24962507
let pat = IntRange::from_pat(cx.tcx, cx.param_env, pat)?;
24972508
ctor.intersection(cx.tcx, &pat)?;
@@ -2514,7 +2525,7 @@ fn specialize_one_pattern<'p, 'tcx>(
25142525
return None;
25152526
}
25162527
}
2517-
ConstantValue(ctor_value) | Str(ctor_value) => {
2528+
Str(ctor_value) => {
25182529
let pat_value = match *pat.kind {
25192530
PatKind::Constant { value } => value,
25202531
_ => span_bug!(
@@ -2532,7 +2543,9 @@ fn specialize_one_pattern<'p, 'tcx>(
25322543
}
25332544
}
25342545
_ => {
2535-
span_bug!(pat.span, "unexpected pattern {:?} with ctor {:?}", pat, constructor)
2546+
// If we reach here, we must be trying to inspect an opaque constant. Thus we skip
2547+
// the row.
2548+
return None;
25362549
}
25372550
}
25382551
Some(Fields::empty())

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

+7
Original file line numberDiff line numberDiff line change
@@ -158,6 +158,13 @@ crate enum PatKind<'tcx> {
158158
subpattern: Pat<'tcx>,
159159
},
160160

161+
/// One of the following:
162+
/// * `&str`, which will be handled as a string pattern and thus exhaustiveness
163+
/// checking will detect if you use the same string twice in different patterns.
164+
/// * integer, bool, char or float, which will be handled by exhaustivenes to cover exactly
165+
/// its own value, similar to `&str`, but these values are much simpler.
166+
/// * Opaque constants, that must not be matched structurally. So anything that does not derive
167+
/// `PartialEq` and `Eq`.
161168
Constant {
162169
value: &'tcx ty::Const<'tcx>,
163170
},

src/test/ui/pattern/usefulness/consts-opaque.rs

+1-2
Original file line numberDiff line numberDiff line change
@@ -106,8 +106,7 @@ fn main() {
106106

107107
match QUUX {
108108
QUUX => {}
109-
QUUX => {} // should not be emitting unreachable warning
110-
//~^ ERROR unreachable pattern
109+
QUUX => {}
111110
_ => {}
112111
}
113112
}

src/test/ui/pattern/usefulness/consts-opaque.stderr

+1-7
Original file line numberDiff line numberDiff line change
@@ -144,11 +144,5 @@ error: unreachable pattern
144144
LL | _ => {} // should not be emitting unreachable warning
145145
| ^
146146

147-
error: unreachable pattern
148-
--> $DIR/consts-opaque.rs:109:9
149-
|
150-
LL | QUUX => {} // should not be emitting unreachable warning
151-
| ^^^^
152-
153-
error: aborting due to 23 previous errors
147+
error: aborting due to 22 previous errors
154148

0 commit comments

Comments
 (0)