Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
35 changes: 17 additions & 18 deletions compiler/rustc_mir_build/src/builder/matches/buckets.rs
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ use tracing::debug;

use crate::builder::Builder;
use crate::builder::matches::test::is_switch_ty;
use crate::builder::matches::{Candidate, Test, TestBranch, TestCase, TestKind};
use crate::builder::matches::{Candidate, Test, TestBranch, TestKind, TestableCase};

/// Output of [`Builder::partition_candidates_into_buckets`].
pub(crate) struct PartitionedCandidates<'tcx, 'b, 'c> {
Expand Down Expand Up @@ -140,12 +140,12 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
// branch, so it can be removed. If false, the match pair is _compatible_
// with its test branch, but still needs a more specific test.
let fully_matched;
let ret = match (&test.kind, &match_pair.test_case) {
let ret = match (&test.kind, &match_pair.testable_case) {
// If we are performing a variant switch, then this
// informs variant patterns, but nothing else.
(
&TestKind::Switch { adt_def: tested_adt_def },
&TestCase::Variant { adt_def, variant_index },
&TestableCase::Variant { adt_def, variant_index },
) => {
assert_eq!(adt_def, tested_adt_def);
fully_matched = true;
Expand All @@ -159,24 +159,23 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
// things out here, in some cases.
//
// FIXME(Zalathar): Is the `is_switch_ty` test unnecessary?
(TestKind::SwitchInt, &TestCase::Constant { value })
(TestKind::SwitchInt, &TestableCase::Constant { value })
if is_switch_ty(match_pair.pattern_ty) =>
{
// An important invariant of candidate bucketing is that a candidate
// must not match in multiple branches. For `SwitchInt` tests, adding
// a new value might invalidate that property for range patterns that
// have already been partitioned into the failure arm, so we must take care
// not to add such values here.
let is_covering_range = |test_case: &TestCase<'tcx>| {
test_case.as_range().is_some_and(|range| {
let is_covering_range = |testable_case: &TestableCase<'tcx>| {
testable_case.as_range().is_some_and(|range| {
matches!(range.contains(value, self.tcx), None | Some(true))
})
};
let is_conflicting_candidate = |candidate: &&mut Candidate<'tcx>| {
candidate
.match_pairs
.iter()
.any(|mp| mp.place == Some(test_place) && is_covering_range(&mp.test_case))
candidate.match_pairs.iter().any(|mp| {
mp.place == Some(test_place) && is_covering_range(&mp.testable_case)
})
};
if prior_candidates
.get(&TestBranch::Failure)
Expand All @@ -189,7 +188,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
Some(TestBranch::Constant(value))
}
}
(TestKind::SwitchInt, TestCase::Range(range)) => {
(TestKind::SwitchInt, TestableCase::Range(range)) => {
// When performing a `SwitchInt` test, a range pattern can be
// sorted into the failure arm if it doesn't contain _any_ of
// the values being tested. (This restricts what values can be
Expand All @@ -207,7 +206,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
})
}

(TestKind::If, TestCase::Constant { value }) => {
(TestKind::If, TestableCase::Constant { value }) => {
fully_matched = true;
let value = value.try_to_bool().unwrap_or_else(|| {
span_bug!(test.span, "expected boolean value but got {value:?}")
Expand All @@ -217,7 +216,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {

(
&TestKind::Len { len: test_len, op: BinOp::Eq },
&TestCase::Slice { len, variable_length },
&TestableCase::Slice { len, variable_length },
) => {
match (test_len.cmp(&(len as u64)), variable_length) {
(Ordering::Equal, false) => {
Expand Down Expand Up @@ -249,7 +248,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
}
(
&TestKind::Len { len: test_len, op: BinOp::Ge },
&TestCase::Slice { len, variable_length },
&TestableCase::Slice { len, variable_length },
) => {
// the test is `$actual_len >= test_len`
match (test_len.cmp(&(len as u64)), variable_length) {
Expand Down Expand Up @@ -281,7 +280,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
}
}

(TestKind::Range(test), TestCase::Range(pat)) => {
(TestKind::Range(test), TestableCase::Range(pat)) => {
if test == pat {
fully_matched = true;
Some(TestBranch::Success)
Expand All @@ -292,7 +291,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
if !test.overlaps(pat, self.tcx)? { Some(TestBranch::Failure) } else { None }
}
}
(TestKind::Range(range), &TestCase::Constant { value }) => {
(TestKind::Range(range), &TestableCase::Constant { value }) => {
fully_matched = false;
if !range.contains(value, self.tcx)? {
// `value` is not contained in the testing range,
Expand All @@ -303,7 +302,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
}
}

(TestKind::Eq { value: test_val, .. }, TestCase::Constant { value: case_val }) => {
(TestKind::Eq { value: test_val, .. }, TestableCase::Constant { value: case_val }) => {
if test_val == case_val {
fully_matched = true;
Some(TestBranch::Success)
Expand All @@ -313,7 +312,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
}
}

(TestKind::Deref { temp: test_temp, .. }, TestCase::Deref { temp, .. })
(TestKind::Deref { temp: test_temp, .. }, TestableCase::Deref { temp, .. })
if test_temp == temp =>
{
fully_matched = true;
Expand Down
26 changes: 15 additions & 11 deletions compiler/rustc_mir_build/src/builder/matches/match_pair.rs
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ use rustc_middle::ty::{self, Pinnedness, Ty, TypeVisitableExt};

use crate::builder::Builder;
use crate::builder::expr::as_place::{PlaceBase, PlaceBuilder};
use crate::builder::matches::{FlatPat, MatchPairTree, PatternExtraData, TestCase};
use crate::builder::matches::{FlatPat, MatchPairTree, PatternExtraData, TestableCase};

impl<'a, 'tcx> Builder<'a, 'tcx> {
/// Builds and pushes [`MatchPairTree`] subtrees, one for each pattern in
Expand Down Expand Up @@ -132,7 +132,7 @@ impl<'tcx> MatchPairTree<'tcx> {

let place = place_builder.try_to_place(cx);
let mut subpairs = Vec::new();
let test_case = match pattern.kind {
let testable_case = match pattern.kind {
PatKind::Missing | PatKind::Wild | PatKind::Error(_) => None,

PatKind::Or { ref pats } => {
Expand All @@ -146,18 +146,18 @@ impl<'tcx> MatchPairTree<'tcx> {
// FIXME(@dianne): this needs updating/removing if we always merge or-patterns
extra_data.bindings.push(super::SubpatternBindings::FromOrPattern);
}
Some(TestCase::Or { pats })
Some(TestableCase::Or { pats })
}

PatKind::Range(ref range) => {
if range.is_full_range(cx.tcx) == Some(true) {
None
} else {
Some(TestCase::Range(Arc::clone(range)))
Some(TestableCase::Range(Arc::clone(range)))
}
}

PatKind::Constant { value } => Some(TestCase::Constant { value }),
PatKind::Constant { value } => Some(TestableCase::Constant { value }),

PatKind::AscribeUserType {
ascription: Ascription { ref annotation, variance },
Expand Down Expand Up @@ -256,7 +256,7 @@ impl<'tcx> MatchPairTree<'tcx> {
if prefix.is_empty() && slice.is_some() && suffix.is_empty() {
None
} else {
Some(TestCase::Slice {
Some(TestableCase::Slice {
len: prefix.len() + suffix.len(),
variable_length: slice.is_some(),
})
Expand All @@ -275,7 +275,11 @@ impl<'tcx> MatchPairTree<'tcx> {
cx.def_id.into(),
)
}) && !adt_def.variant_list_has_applicable_non_exhaustive();
if irrefutable { None } else { Some(TestCase::Variant { adt_def, variant_index }) }
if irrefutable {
None
} else {
Some(TestableCase::Variant { adt_def, variant_index })
}
}

PatKind::Leaf { ref subpatterns } => {
Expand Down Expand Up @@ -331,17 +335,17 @@ impl<'tcx> MatchPairTree<'tcx> {
&mut subpairs,
extra_data,
);
Some(TestCase::Deref { temp, mutability })
Some(TestableCase::Deref { temp, mutability })
}

PatKind::Never => Some(TestCase::Never),
PatKind::Never => Some(TestableCase::Never),
};

if let Some(test_case) = test_case {
if let Some(testable_case) = testable_case {
// This pattern is refutable, so push a new match-pair node.
match_pairs.push(MatchPairTree {
place,
test_case,
testable_case,
subpairs,
pattern_ty: pattern.ty,
pattern_span: pattern.span,
Expand Down
25 changes: 14 additions & 11 deletions compiler/rustc_mir_build/src/builder/matches/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1078,7 +1078,7 @@ struct Candidate<'tcx> {
/// (see [`Builder::test_remaining_match_pairs_after_or`]).
///
/// Invariants:
/// - All or-patterns ([`TestCase::Or`]) have been sorted to the end.
/// - All or-patterns ([`TestableCase::Or`]) have been sorted to the end.
match_pairs: Vec<MatchPairTree<'tcx>>,

/// ...and if this is non-empty, one of these subcandidates also has to match...
Expand Down Expand Up @@ -1164,12 +1164,15 @@ impl<'tcx> Candidate<'tcx> {

/// Restores the invariant that or-patterns must be sorted to the end.
fn sort_match_pairs(&mut self) {
self.match_pairs.sort_by_key(|pair| matches!(pair.test_case, TestCase::Or { .. }));
self.match_pairs.sort_by_key(|pair| matches!(pair.testable_case, TestableCase::Or { .. }));
}

/// Returns whether the first match pair of this candidate is an or-pattern.
fn starts_with_or_pattern(&self) -> bool {
matches!(&*self.match_pairs, [MatchPairTree { test_case: TestCase::Or { .. }, .. }, ..])
matches!(
&*self.match_pairs,
[MatchPairTree { testable_case: TestableCase::Or { .. }, .. }, ..]
)
}

/// Visit the leaf candidates (those with no subcandidates) contained in
Expand Down Expand Up @@ -1261,7 +1264,7 @@ struct Ascription<'tcx> {
/// Instead they participate in or-pattern expansion, where they are transformed into
/// subcandidates. See [`Builder::expand_and_match_or_candidates`].
#[derive(Debug, Clone)]
enum TestCase<'tcx> {
enum TestableCase<'tcx> {
Comment on lines -1264 to +1267
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

For me TestableCase is more confusing than TestCase. I would prefer TestOutcome for example

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hmm, my main motivation is to get rid of the Test prefix, because that's the part that keeps confusing me.

I think I would find TestOutcome even more confusing, because of TestBranch.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

oh, fair point x)

Variant { adt_def: ty::AdtDef<'tcx>, variant_index: VariantIdx },
Constant { value: ty::Value<'tcx> },
Range(Arc<PatRange<'tcx>>),
Expand All @@ -1271,7 +1274,7 @@ enum TestCase<'tcx> {
Or { pats: Box<[FlatPat<'tcx>]> },
}

impl<'tcx> TestCase<'tcx> {
impl<'tcx> TestableCase<'tcx> {
fn as_range(&self) -> Option<&PatRange<'tcx>> {
if let Self::Range(v) = self { Some(v.as_ref()) } else { None }
}
Expand All @@ -1289,12 +1292,12 @@ pub(crate) struct MatchPairTree<'tcx> {
/// ---
/// This can be `None` if it referred to a non-captured place in a closure.
///
/// Invariant: Can only be `None` when `test_case` is `Or`.
/// Invariant: Can only be `None` when `testable_case` is `Or`.
/// Therefore this must be `Some(_)` after or-pattern expansion.
place: Option<Place<'tcx>>,

/// ... must pass this test...
test_case: TestCase<'tcx>,
testable_case: TestableCase<'tcx>,

/// ... and these subpairs must match.
///
Expand All @@ -1317,7 +1320,7 @@ enum TestKind<'tcx> {
/// Test what enum variant a value is.
///
/// The subset of expected variants is not stored here; instead they are
/// extracted from the [`TestCase`]s of the candidates participating in the
/// extracted from the [`TestableCase`]s of the candidates participating in the
/// test.
Switch {
/// The enum type being tested.
Expand All @@ -1327,7 +1330,7 @@ enum TestKind<'tcx> {
/// Test what value an integer or `char` has.
///
/// The test's target values are not stored here; instead they are extracted
/// from the [`TestCase`]s of the candidates participating in the test.
/// from the [`TestableCase`]s of the candidates participating in the test.
SwitchInt,

/// Test whether a `bool` is `true` or `false`.
Expand Down Expand Up @@ -1948,7 +1951,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
candidate: &mut Candidate<'tcx>,
match_pair: MatchPairTree<'tcx>,
) {
let TestCase::Or { pats } = match_pair.test_case else { bug!() };
let TestableCase::Or { pats } = match_pair.testable_case else { bug!() };
debug!("expanding or-pattern: candidate={:#?}\npats={:#?}", candidate, pats);
candidate.or_span = Some(match_pair.pattern_span);
candidate.subcandidates = pats
Expand Down Expand Up @@ -2116,7 +2119,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
debug_assert!(
remaining_match_pairs
.iter()
.all(|match_pair| matches!(match_pair.test_case, TestCase::Or { .. }))
.all(|match_pair| matches!(match_pair.testable_case, TestableCase::Or { .. }))
);

// Visit each leaf candidate within this subtree, add a copy of the remaining
Expand Down
26 changes: 15 additions & 11 deletions compiler/rustc_mir_build/src/builder/matches/test.rs
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@ use rustc_span::{DUMMY_SP, Span, Symbol, sym};
use tracing::{debug, instrument};

use crate::builder::Builder;
use crate::builder::matches::{MatchPairTree, Test, TestBranch, TestCase, TestKind};
use crate::builder::matches::{MatchPairTree, Test, TestBranch, TestKind, TestableCase};

impl<'a, 'tcx> Builder<'a, 'tcx> {
/// Identifies what test is needed to decide if `match_pair` is applicable.
Expand All @@ -29,30 +29,34 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
&mut self,
match_pair: &MatchPairTree<'tcx>,
) -> Test<'tcx> {
let kind = match match_pair.test_case {
TestCase::Variant { adt_def, variant_index: _ } => TestKind::Switch { adt_def },
let kind = match match_pair.testable_case {
TestableCase::Variant { adt_def, variant_index: _ } => TestKind::Switch { adt_def },

TestCase::Constant { .. } if match_pair.pattern_ty.is_bool() => TestKind::If,
TestCase::Constant { .. } if is_switch_ty(match_pair.pattern_ty) => TestKind::SwitchInt,
TestCase::Constant { value } => TestKind::Eq { value, cast_ty: match_pair.pattern_ty },
TestableCase::Constant { .. } if match_pair.pattern_ty.is_bool() => TestKind::If,
TestableCase::Constant { .. } if is_switch_ty(match_pair.pattern_ty) => {
TestKind::SwitchInt
}
TestableCase::Constant { value } => {
TestKind::Eq { value, cast_ty: match_pair.pattern_ty }
}

TestCase::Range(ref range) => {
TestableCase::Range(ref range) => {
assert_eq!(range.ty, match_pair.pattern_ty);
TestKind::Range(Arc::clone(range))
}

TestCase::Slice { len, variable_length } => {
TestableCase::Slice { len, variable_length } => {
let op = if variable_length { BinOp::Ge } else { BinOp::Eq };
TestKind::Len { len: len as u64, op }
}

TestCase::Deref { temp, mutability } => TestKind::Deref { temp, mutability },
TestableCase::Deref { temp, mutability } => TestKind::Deref { temp, mutability },

TestCase::Never => TestKind::Never,
TestableCase::Never => TestKind::Never,

// Or-patterns are not tested directly; instead they are expanded into subcandidates,
// which are then distinguished by testing whatever non-or patterns they contain.
TestCase::Or { .. } => bug!("or-patterns should have already been handled"),
TestableCase::Or { .. } => bug!("or-patterns should have already been handled"),
};

Test { span: match_pair.pattern_span, kind }
Expand Down
6 changes: 3 additions & 3 deletions compiler/rustc_mir_build/src/builder/matches/util.rs
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ use tracing::debug;

use crate::builder::Builder;
use crate::builder::expr::as_place::PlaceBase;
use crate::builder::matches::{Binding, Candidate, FlatPat, MatchPairTree, TestCase};
use crate::builder::matches::{Binding, Candidate, FlatPat, MatchPairTree, TestableCase};

impl<'a, 'tcx> Builder<'a, 'tcx> {
/// Creates a false edge to `imaginary_target` and a real edge to
Expand Down Expand Up @@ -159,11 +159,11 @@ impl<'a, 'b, 'tcx> FakeBorrowCollector<'a, 'b, 'tcx> {
}

fn visit_match_pair(&mut self, match_pair: &MatchPairTree<'tcx>) {
if let TestCase::Or { pats, .. } = &match_pair.test_case {
if let TestableCase::Or { pats, .. } = &match_pair.testable_case {
for flat_pat in pats.iter() {
self.visit_flat_pat(flat_pat)
}
} else if matches!(match_pair.test_case, TestCase::Deref { .. }) {
} else if matches!(match_pair.testable_case, TestableCase::Deref { .. }) {
// The subpairs of a deref pattern are all places relative to the deref temporary, so we
// don't fake borrow them. Problem is, if we only shallowly fake-borrowed
// `match_pair.place`, this would allow:
Expand Down
Loading