From 5c9d580feaac41f9522958a8448bc0121ed53e4b Mon Sep 17 00:00:00 2001 From: Nadrieril Date: Mon, 19 Feb 2024 02:42:14 +0100 Subject: [PATCH 1/4] Tiny simplification --- .../rustc_mir_build/src/build/matches/test.rs | 40 ++++++++----------- 1 file changed, 16 insertions(+), 24 deletions(-) diff --git a/compiler/rustc_mir_build/src/build/matches/test.rs b/compiler/rustc_mir_build/src/build/matches/test.rs index ae9ebe7170ba9..95c0de29aa4a2 100644 --- a/compiler/rustc_mir_build/src/build/matches/test.rs +++ b/compiler/rustc_mir_build/src/build/matches/test.rs @@ -29,44 +29,34 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { /// /// It is a bug to call this with a not-fully-simplified pattern. pub(super) fn test<'pat>(&mut self, match_pair: &MatchPair<'pat, 'tcx>) -> Test<'tcx> { - match match_pair.pattern.kind { - PatKind::Variant { adt_def, args: _, variant_index: _, subpatterns: _ } => Test { - span: match_pair.pattern.span, - kind: TestKind::Switch { - adt_def, - variants: BitSet::new_empty(adt_def.variants().len()), - }, - }, + let kind = match match_pair.pattern.kind { + PatKind::Variant { adt_def, args: _, variant_index: _, subpatterns: _ } => { + TestKind::Switch { adt_def, variants: BitSet::new_empty(adt_def.variants().len()) } + } PatKind::Constant { .. } if is_switch_ty(match_pair.pattern.ty) => { // For integers, we use a `SwitchInt` match, which allows // us to handle more cases. - Test { - span: match_pair.pattern.span, - kind: TestKind::SwitchInt { - switch_ty: match_pair.pattern.ty, - - // these maps are empty to start; cases are - // added below in add_cases_to_switch - options: Default::default(), - }, + TestKind::SwitchInt { + switch_ty: match_pair.pattern.ty, + + // these maps are empty to start; cases are + // added below in add_cases_to_switch + options: Default::default(), } } - PatKind::Constant { value } => Test { - span: match_pair.pattern.span, - kind: TestKind::Eq { value, ty: match_pair.pattern.ty }, - }, + PatKind::Constant { value } => TestKind::Eq { value, ty: match_pair.pattern.ty }, PatKind::Range(ref range) => { assert_eq!(range.ty, match_pair.pattern.ty); - Test { span: match_pair.pattern.span, kind: TestKind::Range(range.clone()) } + TestKind::Range(range.clone()) } PatKind::Slice { ref prefix, ref slice, ref suffix } => { let len = prefix.len() + suffix.len(); let op = if slice.is_some() { BinOp::Ge } else { BinOp::Eq }; - Test { span: match_pair.pattern.span, kind: TestKind::Len { len: len as u64, op } } + TestKind::Len { len: len as u64, op } } PatKind::Or { .. } => bug!("or-patterns should have already been handled"), @@ -80,7 +70,9 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { | PatKind::Leaf { .. } | PatKind::Deref { .. } | PatKind::Error(_) => self.error_simplifiable(match_pair), - } + }; + + Test { span: match_pair.pattern.span, kind } } pub(super) fn add_cases_to_switch<'pat>( From a181bdc065946b98fead7c86684d1f01d2b974ca Mon Sep 17 00:00:00 2001 From: Nadrieril Date: Sun, 11 Feb 2024 00:39:35 +0100 Subject: [PATCH 2/4] Introduce `TestCase` enum to replace most matching on `PatKind` --- .../rustc_mir_build/src/build/matches/mod.rs | 27 ++-- .../src/build/matches/simplify.rs | 60 ++------- .../rustc_mir_build/src/build/matches/test.rs | 119 +++++++----------- .../rustc_mir_build/src/build/matches/util.rs | 69 +++++++--- 4 files changed, 132 insertions(+), 143 deletions(-) diff --git a/compiler/rustc_mir_build/src/build/matches/mod.rs b/compiler/rustc_mir_build/src/build/matches/mod.rs index 88a5eae281b31..20f74a2569c92 100644 --- a/compiler/rustc_mir_build/src/build/matches/mod.rs +++ b/compiler/rustc_mir_build/src/build/matches/mod.rs @@ -16,7 +16,7 @@ use rustc_data_structures::{ }; use rustc_index::bit_set::BitSet; use rustc_middle::middle::region; -use rustc_middle::mir::*; +use rustc_middle::mir::{self, *}; use rustc_middle::thir::{self, *}; use rustc_middle::ty::{self, CanonicalUserTypeAnnotation, Ty}; use rustc_span::symbol::Symbol; @@ -1052,18 +1052,31 @@ struct Ascription<'tcx> { variance: ty::Variance, } +#[derive(Debug, Clone)] +enum TestCase<'pat, 'tcx> { + Irrefutable, + Variant { adt_def: ty::AdtDef<'tcx>, variant_index: VariantIdx }, + Constant { value: mir::Const<'tcx> }, + Range(&'pat PatRange<'tcx>), + Slice { len: usize, variable_length: bool }, + Or, +} + #[derive(Debug, Clone)] pub(crate) struct MatchPair<'pat, 'tcx> { - // This place... + /// This place... place: PlaceBuilder<'tcx>, - // ... must match this pattern. - // Invariant: after creation and simplification in `Candidate::new()`, all match pairs must be - // simplified, i.e. require a test. - pattern: &'pat Pat<'tcx>, + /// ... must pass this test... + // Invariant: after creation and simplification in `Candidate::new()`, this must not be + // `Irrefutable`. + test_case: TestCase<'pat, 'tcx>, - /// Precomputed sub-match pairs of `pattern`. + /// ... and these subpairs must match. subpairs: Vec, + + /// The pattern this was created from. + pattern: &'pat Pat<'tcx>, } /// See [`Test`] for more. diff --git a/compiler/rustc_mir_build/src/build/matches/simplify.rs b/compiler/rustc_mir_build/src/build/matches/simplify.rs index 83922dce327da..28971d4de44bf 100644 --- a/compiler/rustc_mir_build/src/build/matches/simplify.rs +++ b/compiler/rustc_mir_build/src/build/matches/simplify.rs @@ -13,7 +13,7 @@ //! testing a value against a constant. use crate::build::expr::as_place::PlaceBuilder; -use crate::build::matches::{Ascription, Binding, Candidate, MatchPair}; +use crate::build::matches::{Ascription, Binding, Candidate, MatchPair, TestCase}; use crate::build::Builder; use rustc_infer::infer::type_variable::{TypeVariableOrigin, TypeVariableOriginKind}; use rustc_middle::thir::{self, *}; @@ -128,14 +128,8 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { ascriptions: &mut Vec>, match_pairs: &mut Vec>, ) -> Result<(), MatchPair<'pat, 'tcx>> { + // Collect bindings and ascriptions. match match_pair.pattern.kind { - PatKind::Leaf { .. } - | PatKind::Deref { .. } - | PatKind::Array { .. } - | PatKind::Never - | PatKind::Wild - | PatKind::Error(_) => {} - PatKind::AscribeUserType { ascription: thir::Ascription { ref annotation, variance }, .. @@ -203,47 +197,17 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { } } - PatKind::Constant { .. } => { - // FIXME normalize patterns when possible - return Err(match_pair); - } - - PatKind::Range(ref range) => { - if range.is_full_range(self.tcx) != Some(true) { - return Err(match_pair); - } - } - - PatKind::Slice { ref prefix, ref slice, ref suffix } => { - if !(prefix.is_empty() && slice.is_some() && suffix.is_empty()) { - self.simplify_match_pairs(&mut match_pair.subpairs, bindings, ascriptions); - return Err(match_pair); - } - } - - PatKind::Variant { adt_def, args, variant_index, subpatterns: _ } => { - let irrefutable = adt_def.variants().iter_enumerated().all(|(i, v)| { - i == variant_index || { - (self.tcx.features().exhaustive_patterns - || self.tcx.features().min_exhaustive_patterns) - && !v - .inhabited_predicate(self.tcx, adt_def) - .instantiate(self.tcx, args) - .apply_ignore_module(self.tcx, self.param_env) - } - }) && (adt_def.did().is_local() - || !adt_def.is_variant_list_non_exhaustive()); - if !irrefutable { - self.simplify_match_pairs(&mut match_pair.subpairs, bindings, ascriptions); - return Err(match_pair); - } - } - - PatKind::Or { .. } => return Err(match_pair), + _ => {} } - // Simplifiable pattern; we replace it with its subpairs. - match_pairs.append(&mut match_pair.subpairs); - Ok(()) + if let TestCase::Irrefutable = match_pair.test_case { + // Simplifiable pattern; we replace it with its subpairs. + match_pairs.append(&mut match_pair.subpairs); + Ok(()) + } else { + // Unsimplifiable pattern; we recursively simplify its subpairs. + self.simplify_match_pairs(&mut match_pair.subpairs, bindings, ascriptions); + Err(match_pair) + } } } diff --git a/compiler/rustc_mir_build/src/build/matches/test.rs b/compiler/rustc_mir_build/src/build/matches/test.rs index 95c0de29aa4a2..41cfa0cfb2785 100644 --- a/compiler/rustc_mir_build/src/build/matches/test.rs +++ b/compiler/rustc_mir_build/src/build/matches/test.rs @@ -6,7 +6,7 @@ // the candidates based on the result. use crate::build::expr::as_place::PlaceBuilder; -use crate::build::matches::{Candidate, MatchPair, Test, TestKind}; +use crate::build::matches::{Candidate, MatchPair, Test, TestCase, TestKind}; use crate::build::Builder; use rustc_data_structures::fx::FxIndexMap; use rustc_hir::{LangItem, RangeEnd}; @@ -29,12 +29,12 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { /// /// It is a bug to call this with a not-fully-simplified pattern. pub(super) fn test<'pat>(&mut self, match_pair: &MatchPair<'pat, 'tcx>) -> Test<'tcx> { - let kind = match match_pair.pattern.kind { - PatKind::Variant { adt_def, args: _, variant_index: _, subpatterns: _ } => { + let kind = match match_pair.test_case { + TestCase::Variant { adt_def, variant_index: _ } => { TestKind::Switch { adt_def, variants: BitSet::new_empty(adt_def.variants().len()) } } - PatKind::Constant { .. } if is_switch_ty(match_pair.pattern.ty) => { + TestCase::Constant { .. } if is_switch_ty(match_pair.pattern.ty) => { // For integers, we use a `SwitchInt` match, which allows // us to handle more cases. TestKind::SwitchInt { @@ -46,30 +46,25 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { } } - PatKind::Constant { value } => TestKind::Eq { value, ty: match_pair.pattern.ty }, + TestCase::Constant { value } => TestKind::Eq { value, ty: match_pair.pattern.ty }, - PatKind::Range(ref range) => { + TestCase::Range(range) => { assert_eq!(range.ty, match_pair.pattern.ty); - TestKind::Range(range.clone()) + TestKind::Range(Box::new(range.clone())) } - PatKind::Slice { ref prefix, ref slice, ref suffix } => { - let len = prefix.len() + suffix.len(); - let op = if slice.is_some() { BinOp::Ge } else { BinOp::Eq }; + TestCase::Slice { len, variable_length } => { + let op = if variable_length { BinOp::Ge } else { BinOp::Eq }; TestKind::Len { len: len as u64, op } } - PatKind::Or { .. } => bug!("or-patterns should have already been handled"), - - PatKind::AscribeUserType { .. } - | PatKind::InlineConstant { .. } - | PatKind::Array { .. } - | PatKind::Wild - | PatKind::Binding { .. } - | PatKind::Never - | PatKind::Leaf { .. } - | PatKind::Deref { .. } - | PatKind::Error(_) => self.error_simplifiable(match_pair), + TestCase::Or { .. } => bug!("or-patterns should have already been handled"), + + TestCase::Irrefutable => span_bug!( + match_pair.pattern.span, + "simplifiable pattern found: {:?}", + match_pair.pattern + ), }; Test { span: match_pair.pattern.span, kind } @@ -86,32 +81,20 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { return false; }; - match match_pair.pattern.kind { - PatKind::Constant { value } => { + match match_pair.test_case { + TestCase::Constant { value } => { options.entry(value).or_insert_with(|| value.eval_bits(self.tcx, self.param_env)); true } - PatKind::Variant { .. } => { + TestCase::Variant { .. } => { panic!("you should have called add_variants_to_switch instead!"); } - PatKind::Range(ref range) => { + TestCase::Range(ref range) => { // Check that none of the switch values are in the range. self.values_not_contained_in_range(&*range, options).unwrap_or(false) } - PatKind::Slice { .. } - | PatKind::Array { .. } - | PatKind::Wild - | PatKind::Never - | PatKind::Or { .. } - | PatKind::Binding { .. } - | PatKind::AscribeUserType { .. } - | PatKind::InlineConstant { .. } - | PatKind::Leaf { .. } - | PatKind::Deref { .. } - | PatKind::Error(_) => { - // don't know how to add these patterns to a switch - false - } + // don't know how to add these patterns to a switch + _ => false, } } @@ -126,17 +109,15 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { return false; }; - match match_pair.pattern.kind { - PatKind::Variant { adt_def: _, variant_index, .. } => { + match match_pair.test_case { + TestCase::Variant { variant_index, .. } => { // We have a pattern testing for variant `variant_index` // set the corresponding index to true variants.insert(variant_index); true } - _ => { - // don't know how to add these patterns to a switch - false - } + // don't know how to add these patterns to a switch + _ => false, } } @@ -583,12 +564,12 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { candidate.match_pairs.iter().enumerate().find(|&(_, mp)| mp.place == *test_place)?; let fully_matched; - let ret = match (&test.kind, &match_pair.pattern.kind) { + let ret = match (&test.kind, &match_pair.test_case) { // If we are performing a variant switch, then this // informs variant patterns, but nothing else. ( &TestKind::Switch { adt_def: tested_adt_def, .. }, - &PatKind::Variant { adt_def, variant_index, .. }, + &TestCase::Variant { adt_def, variant_index }, ) => { assert_eq!(adt_def, tested_adt_def); fully_matched = true; @@ -604,14 +585,14 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { // // FIXME(#29623) we could use PatKind::Range to rule // things out here, in some cases. - (TestKind::SwitchInt { switch_ty: _, options }, PatKind::Constant { value }) + (TestKind::SwitchInt { switch_ty: _, options }, TestCase::Constant { value }) if is_switch_ty(match_pair.pattern.ty) => { fully_matched = true; let index = options.get_index_of(value).unwrap(); Some(index) } - (TestKind::SwitchInt { switch_ty: _, options }, PatKind::Range(range)) => { + (TestKind::SwitchInt { switch_ty: _, options }, TestCase::Range(range)) => { fully_matched = false; let not_contained = self.values_not_contained_in_range(&*range, options).unwrap_or(false); @@ -629,11 +610,10 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { ( &TestKind::Len { len: test_len, op: BinOp::Eq }, - PatKind::Slice { prefix, slice, suffix }, + &TestCase::Slice { len, variable_length }, ) => { - let pat_len = (prefix.len() + suffix.len()) as u64; - match (test_len.cmp(&pat_len), slice) { - (Ordering::Equal, &None) => { + match (test_len.cmp(&(len as u64)), variable_length) { + (Ordering::Equal, false) => { // on true, min_len = len = $actual_length, // on false, len != $actual_length fully_matched = true; @@ -646,13 +626,13 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { fully_matched = false; Some(1) } - (Ordering::Equal | Ordering::Greater, &Some(_)) => { + (Ordering::Equal | Ordering::Greater, true) => { // This can match both if $actual_len = test_len >= pat_len, // and if $actual_len > test_len. We can't advance. fully_matched = false; None } - (Ordering::Greater, &None) => { + (Ordering::Greater, false) => { // test_len != pat_len, so if $actual_len = test_len, then // $actual_len != pat_len. fully_matched = false; @@ -662,31 +642,30 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { } ( &TestKind::Len { len: test_len, op: BinOp::Ge }, - PatKind::Slice { prefix, slice, suffix }, + &TestCase::Slice { len, variable_length }, ) => { // the test is `$actual_len >= test_len` - let pat_len = (prefix.len() + suffix.len()) as u64; - match (test_len.cmp(&pat_len), slice) { - (Ordering::Equal, &Some(_)) => { + match (test_len.cmp(&(len as u64)), variable_length) { + (Ordering::Equal, true) => { // $actual_len >= test_len = pat_len, // so we can match. fully_matched = true; Some(0) } - (Ordering::Less, _) | (Ordering::Equal, &None) => { + (Ordering::Less, _) | (Ordering::Equal, false) => { // test_len <= pat_len. If $actual_len < test_len, // then it is also < pat_len, so the test passing is // necessary (but insufficient). fully_matched = false; Some(0) } - (Ordering::Greater, &None) => { + (Ordering::Greater, false) => { // test_len > pat_len. If $actual_len >= test_len > pat_len, // then we know we won't have a match. fully_matched = false; Some(1) } - (Ordering::Greater, &Some(_)) => { + (Ordering::Greater, true) => { // test_len < pat_len, and is therefore less // strict. This can still go both ways. fully_matched = false; @@ -695,8 +674,8 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { } } - (TestKind::Range(test), PatKind::Range(pat)) => { - if test == pat { + (TestKind::Range(test), &TestCase::Range(pat)) => { + if test.as_ref() == pat { fully_matched = true; Some(0) } else { @@ -706,7 +685,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { if !test.overlaps(pat, self.tcx, self.param_env)? { Some(1) } else { None } } } - (TestKind::Range(range), &PatKind::Constant { value }) => { + (TestKind::Range(range), &TestCase::Constant { value }) => { fully_matched = false; if !range.contains(value, self.tcx, self.param_env)? { // `value` is not contained in the testing range, @@ -729,7 +708,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { // However, at this point we can still encounter or-patterns that were extracted // from previous calls to `sort_candidate`, so we need to manually address that // case to avoid panicking in `self.test()`. - if let PatKind::Or { .. } = &match_pair.pattern.kind { + if let TestCase::Or { .. } = &match_pair.test_case { return None; } @@ -752,18 +731,12 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { let match_pair = candidate.match_pairs.remove(match_pair_index); candidate.match_pairs.extend(match_pair.subpairs); // Move or-patterns to the end. - candidate - .match_pairs - .sort_by_key(|pair| matches!(pair.pattern.kind, PatKind::Or { .. })); + candidate.match_pairs.sort_by_key(|pair| matches!(pair.test_case, TestCase::Or { .. })); } ret } - fn error_simplifiable<'pat>(&mut self, match_pair: &MatchPair<'pat, 'tcx>) -> ! { - span_bug!(match_pair.pattern.span, "simplifiable pattern found: {:?}", match_pair.pattern) - } - fn values_not_contained_in_range( &self, range: &PatRange<'tcx>, diff --git a/compiler/rustc_mir_build/src/build/matches/util.rs b/compiler/rustc_mir_build/src/build/matches/util.rs index e42d764147ca8..cf5a051f44342 100644 --- a/compiler/rustc_mir_build/src/build/matches/util.rs +++ b/compiler/rustc_mir_build/src/build/matches/util.rs @@ -1,6 +1,5 @@ -use crate::build::expr::as_place::PlaceBase; -use crate::build::expr::as_place::PlaceBuilder; -use crate::build::matches::MatchPair; +use crate::build::expr::as_place::{PlaceBase, PlaceBuilder}; +use crate::build::matches::{MatchPair, TestCase}; use crate::build::Builder; use rustc_middle::mir::*; use rustc_middle::thir::*; @@ -118,16 +117,23 @@ impl<'pat, 'tcx> MatchPair<'pat, 'tcx> { } let mut subpairs = Vec::new(); - match pattern.kind { - PatKind::Constant { .. } - | PatKind::Range(_) - | PatKind::Or { .. } - | PatKind::Never - | PatKind::Wild - | PatKind::Error(_) => {} + let test_case = match pattern.kind { + PatKind::Never | PatKind::Wild | PatKind::Error(_) => TestCase::Irrefutable, + PatKind::Or { .. } => TestCase::Or, + + PatKind::Range(ref range) => { + if range.is_full_range(cx.tcx) == Some(true) { + TestCase::Irrefutable + } else { + TestCase::Range(range) + } + } + + PatKind::Constant { value } => TestCase::Constant { value }, PatKind::AscribeUserType { ref subpattern, .. } => { subpairs.push(MatchPair::new(place.clone(), subpattern, cx)); + TestCase::Irrefutable } PatKind::Binding { ref subpattern, .. } => { @@ -135,32 +141,65 @@ impl<'pat, 'tcx> MatchPair<'pat, 'tcx> { // this is the `x @ P` case; have to keep matching against `P` now subpairs.push(MatchPair::new(place.clone(), subpattern, cx)); } + TestCase::Irrefutable } PatKind::InlineConstant { subpattern: ref pattern, .. } => { subpairs.push(MatchPair::new(place.clone(), pattern, cx)); + TestCase::Irrefutable } - PatKind::Slice { ref prefix, ref slice, ref suffix } - | PatKind::Array { ref prefix, ref slice, ref suffix } => { + PatKind::Array { ref prefix, ref slice, ref suffix } => { cx.prefix_slice_suffix(&mut subpairs, &place, prefix, slice, suffix); + TestCase::Irrefutable } + PatKind::Slice { ref prefix, ref slice, ref suffix } => { + cx.prefix_slice_suffix(&mut subpairs, &place, prefix, slice, suffix); - PatKind::Variant { adt_def, variant_index, ref subpatterns, .. } => { + if prefix.is_empty() && slice.is_some() && suffix.is_empty() { + TestCase::Irrefutable + } else { + TestCase::Slice { + len: prefix.len() + suffix.len(), + variable_length: slice.is_some(), + } + } + } + + PatKind::Variant { adt_def, variant_index, args, ref subpatterns } => { let downcast_place = place.clone().downcast(adt_def, variant_index); // `(x as Variant)` subpairs = cx.field_match_pairs(downcast_place, subpatterns); + + let irrefutable = adt_def.variants().iter_enumerated().all(|(i, v)| { + i == variant_index || { + (cx.tcx.features().exhaustive_patterns + || cx.tcx.features().min_exhaustive_patterns) + && !v + .inhabited_predicate(cx.tcx, adt_def) + .instantiate(cx.tcx, args) + .apply_ignore_module(cx.tcx, cx.param_env) + } + }) && (adt_def.did().is_local() + || !adt_def.is_variant_list_non_exhaustive()); + if irrefutable { + TestCase::Irrefutable + } else { + TestCase::Variant { adt_def, variant_index } + } } PatKind::Leaf { ref subpatterns } => { subpairs = cx.field_match_pairs(place.clone(), subpatterns); + TestCase::Irrefutable } PatKind::Deref { ref subpattern } => { let place_builder = place.clone().deref(); subpairs.push(MatchPair::new(place_builder, subpattern, cx)); + TestCase::Irrefutable } - } + }; - MatchPair { place, pattern, subpairs } + MatchPair { place, test_case, subpairs, pattern } } } From b1a0607e10e8eeb8c4d55523f8491511a4cf32e2 Mon Sep 17 00:00:00 2001 From: Nadrieril Date: Tue, 20 Feb 2024 22:36:48 +0100 Subject: [PATCH 3/4] Process bindings and ascriptions in `MatchPair::new()` --- .../rustc_mir_build/src/build/matches/mod.rs | 2 +- .../src/build/matches/simplify.rs | 80 ++---------------- .../rustc_mir_build/src/build/matches/test.rs | 2 +- .../rustc_mir_build/src/build/matches/util.rs | 83 +++++++++++++++---- 4 files changed, 77 insertions(+), 90 deletions(-) diff --git a/compiler/rustc_mir_build/src/build/matches/mod.rs b/compiler/rustc_mir_build/src/build/matches/mod.rs index 20f74a2569c92..f9a8795f5d6ef 100644 --- a/compiler/rustc_mir_build/src/build/matches/mod.rs +++ b/compiler/rustc_mir_build/src/build/matches/mod.rs @@ -1054,7 +1054,7 @@ struct Ascription<'tcx> { #[derive(Debug, Clone)] enum TestCase<'pat, 'tcx> { - Irrefutable, + Irrefutable { binding: Option>, ascription: Option> }, Variant { adt_def: ty::AdtDef<'tcx>, variant_index: VariantIdx }, Constant { value: mir::Const<'tcx> }, Range(&'pat PatRange<'tcx>), diff --git a/compiler/rustc_mir_build/src/build/matches/simplify.rs b/compiler/rustc_mir_build/src/build/matches/simplify.rs index 28971d4de44bf..a78dda39e888d 100644 --- a/compiler/rustc_mir_build/src/build/matches/simplify.rs +++ b/compiler/rustc_mir_build/src/build/matches/simplify.rs @@ -15,9 +15,7 @@ use crate::build::expr::as_place::PlaceBuilder; use crate::build::matches::{Ascription, Binding, Candidate, MatchPair, TestCase}; use crate::build::Builder; -use rustc_infer::infer::type_variable::{TypeVariableOrigin, TypeVariableOriginKind}; -use rustc_middle::thir::{self, *}; -use rustc_middle::ty; +use rustc_middle::thir::{Pat, PatKind}; use std::mem; @@ -128,79 +126,13 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { ascriptions: &mut Vec>, match_pairs: &mut Vec>, ) -> Result<(), MatchPair<'pat, 'tcx>> { - // Collect bindings and ascriptions. - match match_pair.pattern.kind { - PatKind::AscribeUserType { - ascription: thir::Ascription { ref annotation, variance }, - .. - } => { - // Apply the type ascription to the value at `match_pair.place` - if let Some(source) = match_pair.place.try_to_place(self) { - ascriptions.push(Ascription { - annotation: annotation.clone(), - source, - variance, - }); - } + if let TestCase::Irrefutable { binding, ascription } = match_pair.test_case { + if let Some(binding) = binding { + bindings.push(binding); } - - PatKind::Binding { - name: _, - mutability: _, - mode, - var, - ty: _, - subpattern: _, - is_primary: _, - } => { - if let Some(source) = match_pair.place.try_to_place(self) { - bindings.push(Binding { - span: match_pair.pattern.span, - source, - var_id: var, - binding_mode: mode, - }); - } + if let Some(ascription) = ascription { + ascriptions.push(ascription); } - - PatKind::InlineConstant { subpattern: ref pattern, def } => { - // Apply a type ascription for the inline constant to the value at `match_pair.place` - if let Some(source) = match_pair.place.try_to_place(self) { - let span = match_pair.pattern.span; - let parent_id = self.tcx.typeck_root_def_id(self.def_id.to_def_id()); - let args = ty::InlineConstArgs::new( - self.tcx, - ty::InlineConstArgsParts { - parent_args: ty::GenericArgs::identity_for_item(self.tcx, parent_id), - ty: self.infcx.next_ty_var(TypeVariableOrigin { - kind: TypeVariableOriginKind::MiscVariable, - span, - }), - }, - ) - .args; - let user_ty = - self.infcx.canonicalize_user_type_annotation(ty::UserType::TypeOf( - def.to_def_id(), - ty::UserArgs { args, user_self_ty: None }, - )); - let annotation = ty::CanonicalUserTypeAnnotation { - inferred_ty: pattern.ty, - span, - user_ty: Box::new(user_ty), - }; - ascriptions.push(Ascription { - annotation, - source, - variance: ty::Contravariant, - }); - } - } - - _ => {} - } - - if let TestCase::Irrefutable = match_pair.test_case { // Simplifiable pattern; we replace it with its subpairs. match_pairs.append(&mut match_pair.subpairs); Ok(()) diff --git a/compiler/rustc_mir_build/src/build/matches/test.rs b/compiler/rustc_mir_build/src/build/matches/test.rs index 41cfa0cfb2785..1c97de58863bd 100644 --- a/compiler/rustc_mir_build/src/build/matches/test.rs +++ b/compiler/rustc_mir_build/src/build/matches/test.rs @@ -60,7 +60,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { TestCase::Or { .. } => bug!("or-patterns should have already been handled"), - TestCase::Irrefutable => span_bug!( + TestCase::Irrefutable { .. } => span_bug!( match_pair.pattern.span, "simplifiable pattern found: {:?}", match_pair.pattern diff --git a/compiler/rustc_mir_build/src/build/matches/util.rs b/compiler/rustc_mir_build/src/build/matches/util.rs index cf5a051f44342..3f7e7a348ed64 100644 --- a/compiler/rustc_mir_build/src/build/matches/util.rs +++ b/compiler/rustc_mir_build/src/build/matches/util.rs @@ -1,8 +1,9 @@ use crate::build::expr::as_place::{PlaceBase, PlaceBuilder}; use crate::build::matches::{MatchPair, TestCase}; use crate::build::Builder; +use rustc_infer::infer::type_variable::{TypeVariableOrigin, TypeVariableOriginKind}; use rustc_middle::mir::*; -use rustc_middle::thir::*; +use rustc_middle::thir::{self, *}; use rustc_middle::ty; use rustc_middle::ty::TypeVisitableExt; @@ -116,14 +117,15 @@ impl<'pat, 'tcx> MatchPair<'pat, 'tcx> { place = place.project(ProjectionElem::OpaqueCast(pattern.ty)); } + let default_irrefutable = || TestCase::Irrefutable { binding: None, ascription: None }; let mut subpairs = Vec::new(); let test_case = match pattern.kind { - PatKind::Never | PatKind::Wild | PatKind::Error(_) => TestCase::Irrefutable, + PatKind::Never | PatKind::Wild | PatKind::Error(_) => default_irrefutable(), PatKind::Or { .. } => TestCase::Or, PatKind::Range(ref range) => { if range.is_full_range(cx.tcx) == Some(true) { - TestCase::Irrefutable + default_irrefutable() } else { TestCase::Range(range) } @@ -131,33 +133,86 @@ impl<'pat, 'tcx> MatchPair<'pat, 'tcx> { PatKind::Constant { value } => TestCase::Constant { value }, - PatKind::AscribeUserType { ref subpattern, .. } => { + PatKind::AscribeUserType { + ascription: thir::Ascription { ref annotation, variance }, + ref subpattern, + .. + } => { + // Apply the type ascription to the value at `match_pair.place` + let ascription = place.try_to_place(cx).map(|source| super::Ascription { + annotation: annotation.clone(), + source, + variance, + }); + subpairs.push(MatchPair::new(place.clone(), subpattern, cx)); - TestCase::Irrefutable + TestCase::Irrefutable { ascription, binding: None } } - PatKind::Binding { ref subpattern, .. } => { + PatKind::Binding { + name: _, + mutability: _, + mode, + var, + ty: _, + ref subpattern, + is_primary: _, + } => { + let binding = place.try_to_place(cx).map(|source| super::Binding { + span: pattern.span, + source, + var_id: var, + binding_mode: mode, + }); + if let Some(subpattern) = subpattern.as_ref() { // this is the `x @ P` case; have to keep matching against `P` now subpairs.push(MatchPair::new(place.clone(), subpattern, cx)); } - TestCase::Irrefutable + TestCase::Irrefutable { ascription: None, binding } } - PatKind::InlineConstant { subpattern: ref pattern, .. } => { + PatKind::InlineConstant { subpattern: ref pattern, def, .. } => { + // Apply a type ascription for the inline constant to the value at `match_pair.place` + let ascription = place.try_to_place(cx).map(|source| { + let span = pattern.span; + let parent_id = cx.tcx.typeck_root_def_id(cx.def_id.to_def_id()); + let args = ty::InlineConstArgs::new( + cx.tcx, + ty::InlineConstArgsParts { + parent_args: ty::GenericArgs::identity_for_item(cx.tcx, parent_id), + ty: cx.infcx.next_ty_var(TypeVariableOrigin { + kind: TypeVariableOriginKind::MiscVariable, + span, + }), + }, + ) + .args; + let user_ty = cx.infcx.canonicalize_user_type_annotation(ty::UserType::TypeOf( + def.to_def_id(), + ty::UserArgs { args, user_self_ty: None }, + )); + let annotation = ty::CanonicalUserTypeAnnotation { + inferred_ty: pattern.ty, + span, + user_ty: Box::new(user_ty), + }; + super::Ascription { annotation, source, variance: ty::Contravariant } + }); + subpairs.push(MatchPair::new(place.clone(), pattern, cx)); - TestCase::Irrefutable + TestCase::Irrefutable { ascription, binding: None } } PatKind::Array { ref prefix, ref slice, ref suffix } => { cx.prefix_slice_suffix(&mut subpairs, &place, prefix, slice, suffix); - TestCase::Irrefutable + default_irrefutable() } PatKind::Slice { ref prefix, ref slice, ref suffix } => { cx.prefix_slice_suffix(&mut subpairs, &place, prefix, slice, suffix); if prefix.is_empty() && slice.is_some() && suffix.is_empty() { - TestCase::Irrefutable + default_irrefutable() } else { TestCase::Slice { len: prefix.len() + suffix.len(), @@ -182,7 +237,7 @@ impl<'pat, 'tcx> MatchPair<'pat, 'tcx> { }) && (adt_def.did().is_local() || !adt_def.is_variant_list_non_exhaustive()); if irrefutable { - TestCase::Irrefutable + default_irrefutable() } else { TestCase::Variant { adt_def, variant_index } } @@ -190,13 +245,13 @@ impl<'pat, 'tcx> MatchPair<'pat, 'tcx> { PatKind::Leaf { ref subpatterns } => { subpairs = cx.field_match_pairs(place.clone(), subpatterns); - TestCase::Irrefutable + default_irrefutable() } PatKind::Deref { ref subpattern } => { let place_builder = place.clone().deref(); subpairs.push(MatchPair::new(place_builder, subpattern, cx)); - TestCase::Irrefutable + default_irrefutable() } }; From 0610f59194575054ab8cfa5d677240a6bc07817e Mon Sep 17 00:00:00 2001 From: Nadrieril Date: Tue, 20 Feb 2024 22:40:20 +0100 Subject: [PATCH 4/4] Inline `simplify_match_pair` --- .../src/build/matches/simplify.rs | 52 +++++++------------ 1 file changed, 18 insertions(+), 34 deletions(-) diff --git a/compiler/rustc_mir_build/src/build/matches/simplify.rs b/compiler/rustc_mir_build/src/build/matches/simplify.rs index a78dda39e888d..53a5056cc3f0c 100644 --- a/compiler/rustc_mir_build/src/build/matches/simplify.rs +++ b/compiler/rustc_mir_build/src/build/matches/simplify.rs @@ -60,13 +60,24 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { let mut simplified_match_pairs = Vec::new(); // Repeatedly simplify match pairs until we're left with only unsimplifiable ones. loop { - for match_pair in mem::take(match_pairs) { - if let Err(match_pair) = self.simplify_match_pair( - match_pair, - candidate_bindings, - candidate_ascriptions, - match_pairs, - ) { + for mut match_pair in mem::take(match_pairs) { + if let TestCase::Irrefutable { binding, ascription } = match_pair.test_case { + if let Some(binding) = binding { + candidate_bindings.push(binding); + } + if let Some(ascription) = ascription { + candidate_ascriptions.push(ascription); + } + // Simplifiable pattern; we replace it with its subpairs and simplify further. + match_pairs.append(&mut match_pair.subpairs); + } else { + // Unsimplifiable pattern; we recursively simplify its subpairs and don't + // process it further. + self.simplify_match_pairs( + &mut match_pair.subpairs, + candidate_bindings, + candidate_ascriptions, + ); simplified_match_pairs.push(match_pair); } } @@ -115,31 +126,4 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { }) .collect() } - - /// Tries to simplify `match_pair`, returning `Ok(())` if successful. If successful, new match - /// pairs and bindings will have been pushed into the respective `Vec`s. If no simplification is - /// possible, `Err` is returned. - fn simplify_match_pair<'pat>( - &mut self, - mut match_pair: MatchPair<'pat, 'tcx>, - bindings: &mut Vec>, - ascriptions: &mut Vec>, - match_pairs: &mut Vec>, - ) -> Result<(), MatchPair<'pat, 'tcx>> { - if let TestCase::Irrefutable { binding, ascription } = match_pair.test_case { - if let Some(binding) = binding { - bindings.push(binding); - } - if let Some(ascription) = ascription { - ascriptions.push(ascription); - } - // Simplifiable pattern; we replace it with its subpairs. - match_pairs.append(&mut match_pair.subpairs); - Ok(()) - } else { - // Unsimplifiable pattern; we recursively simplify its subpairs. - self.simplify_match_pairs(&mut match_pair.subpairs, bindings, ascriptions); - Err(match_pair) - } - } }