summaryrefslogtreecommitdiffstats
path: root/compiler/rustc_mir_build/src/build/matches
diff options
context:
space:
mode:
Diffstat (limited to 'compiler/rustc_mir_build/src/build/matches')
-rw-r--r--compiler/rustc_mir_build/src/build/matches/mod.rs233
-rw-r--r--compiler/rustc_mir_build/src/build/matches/simplify.rs51
-rw-r--r--compiler/rustc_mir_build/src/build/matches/test.rs71
-rw-r--r--compiler/rustc_mir_build/src/build/matches/util.rs61
4 files changed, 201 insertions, 215 deletions
diff --git a/compiler/rustc_mir_build/src/build/matches/mod.rs b/compiler/rustc_mir_build/src/build/matches/mod.rs
index 58b1564cc..3f813e0af 100644
--- a/compiler/rustc_mir_build/src/build/matches/mod.rs
+++ b/compiler/rustc_mir_build/src/build/matches/mod.rs
@@ -155,7 +155,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
///
/// * From each pre-binding block to the next pre-binding block.
/// * From each otherwise block to the next pre-binding block.
- #[tracing::instrument(level = "debug", skip(self, arms))]
+ #[instrument(level = "debug", skip(self, arms))]
pub(crate) fn match_expr(
&mut self,
destination: Place<'tcx>,
@@ -170,7 +170,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
let mut arm_candidates = self.create_match_candidates(scrutinee_place.clone(), &arms);
- let match_has_guard = arms.iter().copied().any(|arm| self.thir[arm].guard.is_some());
+ let match_has_guard = arm_candidates.iter().any(|(_, candidate)| candidate.has_guard);
let mut candidates =
arm_candidates.iter_mut().map(|(_, candidate)| candidate).collect::<Vec<_>>();
@@ -220,10 +220,8 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
let cause_matched_place = FakeReadCause::ForMatchedPlace(None);
let source_info = self.source_info(scrutinee_span);
- if let Ok(scrutinee_builder) =
- scrutinee_place_builder.clone().try_upvars_resolved(self.tcx, self.typeck_results)
- {
- let scrutinee_place = scrutinee_builder.into_place(self.tcx, self.typeck_results);
+ if let Ok(scrutinee_builder) = scrutinee_place_builder.clone().try_upvars_resolved(self) {
+ let scrutinee_place = scrutinee_builder.into_place(self);
self.cfg.push_fake_read(block, source_info, cause_matched_place, scrutinee_place);
}
@@ -246,7 +244,8 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
.map(|arm| {
let arm = &self.thir[arm];
let arm_has_guard = arm.guard.is_some();
- let arm_candidate = Candidate::new(scrutinee.clone(), &arm.pattern, arm_has_guard);
+ let arm_candidate =
+ Candidate::new(scrutinee.clone(), &arm.pattern, arm_has_guard, self);
(arm, arm_candidate)
})
.collect()
@@ -348,12 +347,10 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
// ```
let mut opt_scrutinee_place: Option<(Option<&Place<'tcx>>, Span)> = None;
let scrutinee_place: Place<'tcx>;
- if let Ok(scrutinee_builder) = scrutinee_place_builder
- .clone()
- .try_upvars_resolved(this.tcx, this.typeck_results)
+ if let Ok(scrutinee_builder) =
+ scrutinee_place_builder.clone().try_upvars_resolved(this)
{
- scrutinee_place =
- scrutinee_builder.into_place(this.tcx, this.typeck_results);
+ scrutinee_place = scrutinee_builder.into_place(this);
opt_scrutinee_place = Some((Some(&scrutinee_place), scrutinee_span));
}
let scope = this.declare_bindings(
@@ -373,6 +370,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
Some(arm.span),
Some(arm.scope),
Some(match_scope),
+ false,
);
if let Some(source_scope) = scope {
@@ -418,6 +416,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
arm_span: Option<Span>,
arm_scope: Option<region::Scope>,
match_scope: Option<region::Scope>,
+ storages_alive: bool,
) -> BasicBlock {
if candidate.subcandidates.is_empty() {
// Avoid generating another `BasicBlock` when we only have one
@@ -431,6 +430,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
arm_span,
match_scope,
true,
+ storages_alive,
)
} else {
// It's helpful to avoid scheduling drops multiple times to save
@@ -468,6 +468,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
arm_span,
match_scope,
schedule_drops,
+ storages_alive,
);
if arm_scope.is_none() {
schedule_drops = false;
@@ -490,10 +491,10 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
pub(super) fn expr_into_pattern(
&mut self,
mut block: BasicBlock,
- irrefutable_pat: Pat<'tcx>,
+ irrefutable_pat: &Pat<'tcx>,
initializer: &Expr<'tcx>,
) -> BlockAnd<()> {
- match *irrefutable_pat.kind {
+ match irrefutable_pat.kind {
// Optimize the case of `let x = ...` to write directly into `x`
PatKind::Binding { mode: BindingMode::ByValue, var, subpattern: None, .. } => {
let place =
@@ -518,17 +519,14 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
// broken.
PatKind::AscribeUserType {
subpattern:
- Pat {
+ box Pat {
kind:
- box PatKind::Binding {
- mode: BindingMode::ByValue,
- var,
- subpattern: None,
- ..
+ PatKind::Binding {
+ mode: BindingMode::ByValue, var, subpattern: None, ..
},
..
},
- ascription: thir::Ascription { annotation, variance: _ },
+ ascription: thir::Ascription { ref annotation, variance: _ },
} => {
let place =
self.storage_live_binding(block, var, irrefutable_pat.span, OutsideGuard, true);
@@ -541,7 +539,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
let ty_source_info = self.source_info(annotation.span);
- let base = self.canonical_user_type_annotations.push(annotation);
+ let base = self.canonical_user_type_annotations.push(annotation.clone());
self.cfg.push(
block,
Statement {
@@ -573,7 +571,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
_ => {
let place_builder = unpack!(block = self.as_place_builder(block, initializer));
- self.place_into_pattern(block, irrefutable_pat, place_builder, true)
+ self.place_into_pattern(block, &irrefutable_pat, place_builder, true)
}
}
}
@@ -581,11 +579,11 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
pub(crate) fn place_into_pattern(
&mut self,
block: BasicBlock,
- irrefutable_pat: Pat<'tcx>,
+ irrefutable_pat: &Pat<'tcx>,
initializer: PlaceBuilder<'tcx>,
set_match_place: bool,
) -> BlockAnd<()> {
- let mut candidate = Candidate::new(initializer.clone(), &irrefutable_pat, false);
+ let mut candidate = Candidate::new(initializer.clone(), &irrefutable_pat, false, self);
let fake_borrow_temps = self.lower_match_tree(
block,
irrefutable_pat.span,
@@ -602,12 +600,6 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
while let Some(next) = {
for binding in &candidate_ref.bindings {
let local = self.var_local_id(binding.var_id, OutsideGuard);
-
- let Some(box LocalInfo::User(ClearCrossCrate::Set(BindingForm::Var(
- VarBindingForm { opt_match_place: Some((ref mut match_place, _)), .. },
- )))) = self.local_decls[local].local_info else {
- bug!("Let binding to non-user variable.")
- };
// `try_upvars_resolved` may fail if it is unable to resolve the given
// `PlaceBuilder` inside a closure. In this case, we don't want to include
// a scrutinee place. `scrutinee_place_builder` will fail for destructured
@@ -622,10 +614,14 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
// let (v1, v2) = foo;
// };
// ```
- if let Ok(match_pair_resolved) =
- initializer.clone().try_upvars_resolved(self.tcx, self.typeck_results)
- {
- let place = match_pair_resolved.into_place(self.tcx, self.typeck_results);
+ if let Ok(match_pair_resolved) = initializer.clone().try_upvars_resolved(self) {
+ let place = match_pair_resolved.into_place(self);
+
+ let Some(box LocalInfo::User(ClearCrossCrate::Set(BindingForm::Var(
+ VarBindingForm { opt_match_place: Some((ref mut match_place, _)), .. },
+ )))) = self.local_decls[local].local_info else {
+ bug!("Let binding to non-user variable.")
+ };
*match_place = Some(place);
}
}
@@ -646,6 +642,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
None,
None,
None,
+ false,
)
.unit()
}
@@ -654,6 +651,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
/// scope for the bindings in these patterns, if such a scope had to be
/// created. NOTE: Declaring the bindings should always be done in their
/// drop scope.
+ #[instrument(skip(self), level = "debug")]
pub(crate) fn declare_bindings(
&mut self,
mut visibility_scope: Option<SourceScope>,
@@ -662,7 +660,6 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
has_guard: ArmHasGuard,
opt_match_place: Option<(Option<&Place<'tcx>>, Span)>,
) -> Option<SourceScope> {
- debug!("declare_bindings: pattern={:?}", pattern);
self.visit_primary_bindings(
&pattern,
UserTypeProjections::none(),
@@ -702,9 +699,9 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
let local_id = self.var_local_id(var, for_guard);
let source_info = self.source_info(span);
self.cfg.push(block, Statement { source_info, kind: StatementKind::StorageLive(local_id) });
- // Altough there is almost always scope for given variable in corner cases
+ // Although there is almost always scope for given variable in corner cases
// like #92893 we might get variable with no scope.
- if let Some(region_scope) = self.region_scope_tree.var_scope(var.0.local_id) && schedule_drop{
+ if let Some(region_scope) = self.region_scope_tree.var_scope(var.0.local_id) && schedule_drop {
self.schedule_drop(span, region_scope, local_id, DropKind::Storage);
}
Place::from(local_id)
@@ -744,7 +741,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
"visit_primary_bindings: pattern={:?} pattern_user_ty={:?}",
pattern, pattern_user_ty
);
- match *pattern.kind {
+ match pattern.kind {
PatKind::Binding {
mutability,
name,
@@ -767,7 +764,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
| PatKind::Slice { ref prefix, ref slice, ref suffix } => {
let from = u64::try_from(prefix.len()).unwrap();
let to = u64::try_from(suffix.len()).unwrap();
- for subpattern in prefix {
+ for subpattern in prefix.iter() {
self.visit_primary_bindings(subpattern, pattern_user_ty.clone().index(), f);
}
for subpattern in slice {
@@ -777,7 +774,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
f,
);
}
- for subpattern in suffix {
+ for subpattern in suffix.iter() {
self.visit_primary_bindings(subpattern, pattern_user_ty.clone().index(), f);
}
}
@@ -830,7 +827,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
// may not all be in the leftmost subpattern. For example in
// `let (x | y) = ...`, the primary binding of `y` occurs in
// the right subpattern
- for subpattern in pats {
+ for subpattern in pats.iter() {
self.visit_primary_bindings(subpattern, pattern_user_ty.clone(), f);
}
}
@@ -868,11 +865,16 @@ struct Candidate<'pat, 'tcx> {
}
impl<'tcx, 'pat> Candidate<'pat, 'tcx> {
- fn new(place: PlaceBuilder<'tcx>, pattern: &'pat Pat<'tcx>, has_guard: bool) -> Self {
+ fn new(
+ place: PlaceBuilder<'tcx>,
+ pattern: &'pat Pat<'tcx>,
+ has_guard: bool,
+ cx: &Builder<'_, 'tcx>,
+ ) -> Self {
Candidate {
span: pattern.span,
has_guard,
- match_pairs: smallvec![MatchPair { place, pattern }],
+ match_pairs: smallvec![MatchPair::new(place, pattern, cx)],
bindings: Vec::new(),
ascriptions: Vec::new(),
subcandidates: Vec::new(),
@@ -982,7 +984,7 @@ enum TestKind<'tcx> {
},
/// Test whether the value falls within an inclusive or exclusive range
- Range(PatRange<'tcx>),
+ Range(Box<PatRange<'tcx>>),
/// Test that the length of the slice is equal to `len`.
Len { len: u64, op: BinOp },
@@ -1048,6 +1050,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
/// if `x.0` matches `false` (for the third arm). In the (impossible at
/// runtime) case when `x.0` is now `true`, we branch to
/// `otherwise_block`.
+ #[instrument(skip(self, fake_borrows), level = "debug")]
fn match_candidates<'pat>(
&mut self,
span: Span,
@@ -1057,11 +1060,6 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
candidates: &mut [&mut Candidate<'pat, 'tcx>],
fake_borrows: &mut Option<FxIndexSet<Place<'tcx>>>,
) {
- debug!(
- "matched_candidate(span={:?}, candidates={:?}, start_block={:?}, otherwise_block={:?})",
- span, candidates, start_block, otherwise_block,
- );
-
// Start by simplifying candidates. Once this process is complete, all
// the match pairs which remain require some form of test, whether it
// be a switch or pattern comparison.
@@ -1330,7 +1328,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
// All of the or-patterns have been sorted to the end, so if the first
// pattern is an or-pattern we only have or-patterns.
- match *first_candidate.match_pairs[0].pattern.kind {
+ match first_candidate.match_pairs[0].pattern.kind {
PatKind::Or { .. } => (),
_ => {
self.test_candidates(
@@ -1350,7 +1348,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
let mut otherwise = None;
for match_pair in match_pairs {
- let PatKind::Or { ref pats } = &*match_pair.pattern.kind else {
+ let PatKind::Or { ref pats } = &match_pair.pattern.kind else {
bug!("Or-patterns should have been sorted to the end");
};
let or_span = match_pair.pattern.span;
@@ -1380,19 +1378,23 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
)
}
+ #[instrument(
+ skip(self, otherwise, or_span, place, fake_borrows, candidate, pats),
+ level = "debug"
+ )]
fn test_or_pattern<'pat>(
&mut self,
candidate: &mut Candidate<'pat, 'tcx>,
otherwise: &mut Option<BasicBlock>,
- pats: &'pat [Pat<'tcx>],
+ pats: &'pat [Box<Pat<'tcx>>],
or_span: Span,
place: PlaceBuilder<'tcx>,
fake_borrows: &mut Option<FxIndexSet<Place<'tcx>>>,
) {
- debug!("test_or_pattern:\ncandidate={:#?}\npats={:#?}", candidate, pats);
+ debug!("candidate={:#?}\npats={:#?}", candidate, pats);
let mut or_candidates: Vec<_> = pats
.iter()
- .map(|pat| Candidate::new(place.clone(), pat, candidate.has_guard))
+ .map(|pat| Candidate::new(place.clone(), pat, candidate.has_guard, self))
.collect();
let mut or_candidate_refs: Vec<_> = or_candidates.iter_mut().collect();
let otherwise = if candidate.otherwise_block.is_some() {
@@ -1605,9 +1607,9 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
// Insert a Shallow borrow of any places that is switched on.
if let Some(fb) = fake_borrows && let Ok(match_place_resolved) =
- match_place.clone().try_upvars_resolved(self.tcx, self.typeck_results)
+ match_place.clone().try_upvars_resolved(self)
{
- let resolved_place = match_place_resolved.into_place(self.tcx, self.typeck_results);
+ let resolved_place = match_place_resolved.into_place(self);
fb.insert(resolved_place);
}
@@ -1634,9 +1636,14 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
candidates = rest;
}
// at least the first candidate ought to be tested
- assert!(total_candidate_count > candidates.len());
- debug!("test_candidates: tested_candidates: {}", total_candidate_count - candidates.len());
- debug!("test_candidates: untested_candidates: {}", candidates.len());
+ assert!(
+ total_candidate_count > candidates.len(),
+ "{}, {:#?}",
+ total_candidate_count,
+ candidates
+ );
+ debug!("tested_candidates: {}", total_candidate_count - candidates.len());
+ debug!("untested_candidates: {}", candidates.len());
// HACK(matthewjasper) This is a closure so that we can let the test
// create its blocks before the rest of the match. This currently
@@ -1783,8 +1790,9 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
let expr_span = expr.span;
let expr_place_builder = unpack!(block = self.lower_scrutinee(block, expr, expr_span));
let wildcard = Pat::wildcard_from_ty(pat.ty);
- let mut guard_candidate = Candidate::new(expr_place_builder.clone(), &pat, false);
- let mut otherwise_candidate = Candidate::new(expr_place_builder.clone(), &wildcard, false);
+ let mut guard_candidate = Candidate::new(expr_place_builder.clone(), &pat, false, self);
+ let mut otherwise_candidate =
+ Candidate::new(expr_place_builder.clone(), &wildcard, false, self);
let fake_borrow_temps = self.lower_match_tree(
block,
pat.span,
@@ -1794,10 +1802,8 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
);
let mut opt_expr_place: Option<(Option<&Place<'tcx>>, Span)> = None;
let expr_place: Place<'tcx>;
- if let Ok(expr_builder) =
- expr_place_builder.try_upvars_resolved(self.tcx, self.typeck_results)
- {
- expr_place = expr_builder.into_place(self.tcx, self.typeck_results);
+ if let Ok(expr_builder) = expr_place_builder.try_upvars_resolved(self) {
+ expr_place = expr_builder.into_place(self);
opt_expr_place = Some((Some(&expr_place), expr_span));
}
let otherwise_post_guard_block = otherwise_candidate.pre_binding_block.unwrap();
@@ -1820,6 +1826,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
None,
None,
None,
+ false,
);
post_guard_block.unit()
@@ -1843,6 +1850,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
arm_span: Option<Span>,
match_scope: Option<region::Scope>,
schedule_drops: bool,
+ storages_alive: bool,
) -> BasicBlock {
debug!("bind_and_guard_matched_candidate(candidate={:?})", candidate);
@@ -1978,7 +1986,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
let mut guard_span = rustc_span::DUMMY_SP;
let (post_guard_block, otherwise_post_guard_block) =
- self.in_if_then_scope(match_scope, |this| match *guard {
+ self.in_if_then_scope(match_scope, guard_span, |this| match *guard {
Guard::If(e) => {
let e = &this.thir[e];
guard_span = e.span;
@@ -2058,7 +2066,12 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
self.cfg.push_fake_read(post_guard_block, guard_end, cause, Place::from(local_id));
}
assert!(schedule_drops, "patterns with guards must schedule drops");
- self.bind_matched_candidate_for_arm_body(post_guard_block, true, by_value_bindings);
+ self.bind_matched_candidate_for_arm_body(
+ post_guard_block,
+ true,
+ by_value_bindings,
+ storages_alive,
+ );
post_guard_block
} else {
@@ -2072,6 +2085,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
.iter()
.flat_map(|(bindings, _)| bindings)
.chain(&candidate.bindings),
+ storages_alive,
);
block
}
@@ -2161,6 +2175,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
block: BasicBlock,
schedule_drops: bool,
bindings: impl IntoIterator<Item = &'b Binding<'tcx>>,
+ storages_alive: bool,
) where
'tcx: 'b,
{
@@ -2170,13 +2185,20 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
// Assign each of the bindings. This may trigger moves out of the candidate.
for binding in bindings {
let source_info = self.source_info(binding.span);
- let local = self.storage_live_binding(
- block,
- binding.var_id,
- binding.span,
- OutsideGuard,
- schedule_drops,
- );
+ let local = if storages_alive {
+ // Here storages are already alive, probably because this is a binding
+ // from let-else.
+ // We just need to schedule drop for the value.
+ self.var_local_id(binding.var_id, OutsideGuard).into()
+ } else {
+ self.storage_live_binding(
+ block,
+ binding.var_id,
+ binding.span,
+ OutsideGuard,
+ schedule_drops,
+ )
+ };
if schedule_drops {
self.schedule_drop_for_binding(binding.var_id, binding.span, OutsideGuard);
}
@@ -2195,6 +2217,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
/// first local is a binding for occurrences of `var` in the guard, which
/// will have type `&T`. The second local is a binding for occurrences of
/// `var` in the arm body, which will have type `T`.
+ #[instrument(skip(self), level = "debug")]
fn declare_binding(
&mut self,
source_info: SourceInfo,
@@ -2209,19 +2232,12 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
opt_match_place: Option<(Option<Place<'tcx>>, Span)>,
pat_span: Span,
) {
- debug!(
- "declare_binding(var_id={:?}, name={:?}, mode={:?}, var_ty={:?}, \
- visibility_scope={:?}, source_info={:?})",
- var_id, name, mode, var_ty, visibility_scope, source_info
- );
-
let tcx = self.tcx;
let debug_source_info = SourceInfo { span: source_info.span, scope: visibility_scope };
let binding_mode = match mode {
BindingMode::ByValue => ty::BindingMode::BindByValue(mutability),
BindingMode::ByRef(_) => ty::BindingMode::BindByReference(mutability),
};
- debug!("declare_binding: user_ty={:?}", user_ty);
let local = LocalDecl::<'tcx> {
mutability,
ty: var_ty,
@@ -2271,7 +2287,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
} else {
LocalsForNode::One(for_arm_body)
};
- debug!("declare_binding: vars={:?}", locals);
+ debug!(?locals);
self.var_indices.insert(var_id, locals);
}
@@ -2280,24 +2296,16 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
mut block: BasicBlock,
init: &Expr<'tcx>,
initializer_span: Span,
- else_block: &Block,
- visibility_scope: Option<SourceScope>,
- remainder_scope: region::Scope,
- remainder_span: Span,
+ else_block: BlockId,
+ let_else_scope: &region::Scope,
pattern: &Pat<'tcx>,
- ) -> BlockAnd<()> {
- let (matching, failure) = self.in_if_then_scope(remainder_scope, |this| {
+ ) -> BlockAnd<BasicBlock> {
+ let else_block_span = self.thir[else_block].span;
+ let (matching, failure) = self.in_if_then_scope(*let_else_scope, else_block_span, |this| {
let scrutinee = unpack!(block = this.lower_scrutinee(block, init, initializer_span));
- let pat = Pat { ty: init.ty, span: else_block.span, kind: Box::new(PatKind::Wild) };
- let mut wildcard = Candidate::new(scrutinee.clone(), &pat, false);
- this.declare_bindings(
- visibility_scope,
- remainder_span,
- pattern,
- ArmHasGuard(false),
- Some((None, initializer_span)),
- );
- let mut candidate = Candidate::new(scrutinee.clone(), pattern, false);
+ let pat = Pat { ty: init.ty, span: else_block_span, kind: PatKind::Wild };
+ let mut wildcard = Candidate::new(scrutinee.clone(), &pat, false, this);
+ let mut candidate = Candidate::new(scrutinee.clone(), pattern, false, this);
let fake_borrow_temps = this.lower_match_tree(
block,
initializer_span,
@@ -2315,10 +2323,11 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
None,
None,
None,
+ true,
);
// This block is for the failure case
let failure = this.bind_pattern(
- this.source_info(else_block.span),
+ this.source_info(else_block_span),
wildcard,
None,
&fake_borrow_temps,
@@ -2326,29 +2335,11 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
None,
None,
None,
+ true,
);
- this.break_for_else(failure, remainder_scope, this.source_info(initializer_span));
+ this.break_for_else(failure, *let_else_scope, this.source_info(initializer_span));
matching.unit()
});
-
- // This place is not really used because this destination place
- // should never be used to take values at the end of the failure
- // block.
- let dummy_place = Place { local: RETURN_PLACE, projection: ty::List::empty() };
- let failure_block;
- unpack!(
- failure_block = self.ast_block(
- dummy_place,
- failure,
- else_block,
- self.source_info(else_block.span),
- )
- );
- self.cfg.terminate(
- failure_block,
- self.source_info(else_block.span),
- TerminatorKind::Unreachable,
- );
- matching.unit()
+ matching.and(failure)
}
}
diff --git a/compiler/rustc_mir_build/src/build/matches/simplify.rs b/compiler/rustc_mir_build/src/build/matches/simplify.rs
index c62989041..924d2f555 100644
--- a/compiler/rustc_mir_build/src/build/matches/simplify.rs
+++ b/compiler/rustc_mir_build/src/build/matches/simplify.rs
@@ -37,12 +37,13 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
///
/// only generates a single switch. If this happens this method returns
/// `true`.
+ #[instrument(skip(self, candidate), level = "debug")]
pub(super) fn simplify_candidate<'pat>(
&mut self,
candidate: &mut Candidate<'pat, 'tcx>,
) -> bool {
// repeatedly simplify match pairs until fixed point is reached
- debug!(?candidate, "simplify_candidate");
+ debug!("{candidate:#?}");
// existing_bindings and new_bindings exists to keep the semantics in order.
// Reversing the binding order for bindings after `@` changes the binding order in places
@@ -67,7 +68,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
loop {
let match_pairs = mem::take(&mut candidate.match_pairs);
- if let [MatchPair { pattern: Pat { kind: box PatKind::Or { pats }, .. }, place }] =
+ if let [MatchPair { pattern: Pat { kind: PatKind::Or { pats }, .. }, place }] =
&*match_pairs
{
existing_bindings.extend_from_slice(&new_bindings);
@@ -113,7 +114,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
// late as possible.
candidate
.match_pairs
- .sort_by_key(|pair| matches!(*pair.pattern.kind, PatKind::Or { .. }));
+ .sort_by_key(|pair| matches!(pair.pattern.kind, PatKind::Or { .. }));
debug!(simplified = ?candidate, "simplify_candidate");
return false; // if we were not able to simplify any, done.
}
@@ -127,11 +128,11 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
&mut self,
candidate: &Candidate<'pat, 'tcx>,
place: PlaceBuilder<'tcx>,
- pats: &'pat [Pat<'tcx>],
+ pats: &'pat [Box<Pat<'tcx>>],
) -> Vec<Candidate<'pat, 'tcx>> {
pats.iter()
- .map(|pat| {
- let mut candidate = Candidate::new(place.clone(), pat, candidate.has_guard);
+ .map(|box pat| {
+ let mut candidate = Candidate::new(place.clone(), pat, candidate.has_guard, self);
self.simplify_candidate(&mut candidate);
candidate
})
@@ -149,23 +150,21 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
candidate: &mut Candidate<'pat, 'tcx>,
) -> Result<(), MatchPair<'pat, 'tcx>> {
let tcx = self.tcx;
- match *match_pair.pattern.kind {
+ match match_pair.pattern.kind {
PatKind::AscribeUserType {
ref subpattern,
ascription: thir::Ascription { ref annotation, variance },
} => {
// Apply the type ascription to the value at `match_pair.place`, which is the
- if let Ok(place_resolved) =
- match_pair.place.clone().try_upvars_resolved(self.tcx, self.typeck_results)
- {
+ if let Ok(place_resolved) = match_pair.place.clone().try_upvars_resolved(self) {
candidate.ascriptions.push(Ascription {
annotation: annotation.clone(),
- source: place_resolved.into_place(self.tcx, self.typeck_results),
+ source: place_resolved.into_place(self),
variance,
});
}
- candidate.match_pairs.push(MatchPair::new(match_pair.place, subpattern));
+ candidate.match_pairs.push(MatchPair::new(match_pair.place, subpattern, self));
Ok(())
}
@@ -184,12 +183,10 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
ref subpattern,
is_primary: _,
} => {
- if let Ok(place_resolved) =
- match_pair.place.clone().try_upvars_resolved(self.tcx, self.typeck_results)
- {
+ if let Ok(place_resolved) = match_pair.place.clone().try_upvars_resolved(self) {
candidate.bindings.push(Binding {
span: match_pair.pattern.span,
- source: place_resolved.into_place(self.tcx, self.typeck_results),
+ source: place_resolved.into_place(self),
var_id: var,
binding_mode: mode,
});
@@ -197,7 +194,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
if let Some(subpattern) = subpattern.as_ref() {
// this is the `x @ P` case; have to keep matching against `P` now
- candidate.match_pairs.push(MatchPair::new(match_pair.place, subpattern));
+ candidate.match_pairs.push(MatchPair::new(match_pair.place, subpattern, self));
}
Ok(())
@@ -208,7 +205,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
Err(match_pair)
}
- PatKind::Range(PatRange { lo, hi, end }) => {
+ PatKind::Range(box PatRange { lo, hi, end }) => {
let (range, bias) = match *lo.ty().kind() {
ty::Char => {
(Some(('\u{0000}' as u128, '\u{10FFFF}' as u128, Size::from_bits(32))), 0)
@@ -254,7 +251,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
&mut candidate.match_pairs,
&match_pair.place,
prefix,
- slice.as_ref(),
+ slice,
suffix,
);
Ok(())
@@ -267,14 +264,10 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
let irrefutable = adt_def.variants().iter_enumerated().all(|(i, v)| {
i == variant_index || {
self.tcx.features().exhaustive_patterns
- && !v
- .uninhabited_from(
- self.tcx,
- substs,
- adt_def.adt_kind(),
- self.param_env,
- )
- .is_empty()
+ && v.inhabited_predicate(self.tcx, adt_def)
+ .subst(self.tcx, substs)
+ .apply_any_module(self.tcx, self.param_env)
+ != Some(true)
}
}) && (adt_def.did().is_local()
|| !adt_def.is_variant_list_non_exhaustive());
@@ -294,7 +287,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
&mut candidate.match_pairs,
&match_pair.place,
prefix,
- slice.as_ref(),
+ slice,
suffix,
);
Ok(())
@@ -308,7 +301,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
PatKind::Deref { ref subpattern } => {
let place_builder = match_pair.place.deref();
- candidate.match_pairs.push(MatchPair::new(place_builder, subpattern));
+ candidate.match_pairs.push(MatchPair::new(place_builder, subpattern, self));
Ok(())
}
diff --git a/compiler/rustc_mir_build/src/build/matches/test.rs b/compiler/rustc_mir_build/src/build/matches/test.rs
index 598da80c5..b597ecfaa 100644
--- a/compiler/rustc_mir_build/src/build/matches/test.rs
+++ b/compiler/rustc_mir_build/src/build/matches/test.rs
@@ -14,8 +14,8 @@ use rustc_hir::{LangItem, RangeEnd};
use rustc_index::bit_set::BitSet;
use rustc_middle::mir::*;
use rustc_middle::thir::*;
-use rustc_middle::ty::subst::{GenericArg, Subst};
use rustc_middle::ty::util::IntTypeExt;
+use rustc_middle::ty::GenericArg;
use rustc_middle::ty::{self, adjustment::PointerCast, Ty, TyCtxt};
use rustc_span::def_id::DefId;
use rustc_span::symbol::{sym, Symbol};
@@ -29,7 +29,7 @@ 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 {
+ match match_pair.pattern.kind {
PatKind::Variant { adt_def, substs: _, variant_index: _, subpatterns: _ } => Test {
span: match_pair.pattern.span,
kind: TestKind::Switch {
@@ -58,10 +58,10 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
kind: TestKind::Eq { value, ty: match_pair.pattern.ty },
},
- PatKind::Range(range) => {
+ PatKind::Range(ref range) => {
assert_eq!(range.lo.ty(), match_pair.pattern.ty);
assert_eq!(range.hi.ty(), match_pair.pattern.ty);
- Test { span: match_pair.pattern.span, kind: TestKind::Range(range) }
+ Test { span: match_pair.pattern.span, kind: TestKind::Range(range.clone()) }
}
PatKind::Slice { ref prefix, ref slice, ref suffix } => {
@@ -92,7 +92,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
return false;
};
- match *match_pair.pattern.kind {
+ match match_pair.pattern.kind {
PatKind::Constant { value } => {
options
.entry(value)
@@ -102,9 +102,9 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
PatKind::Variant { .. } => {
panic!("you should have called add_variants_to_switch instead!");
}
- PatKind::Range(range) => {
+ PatKind::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)
+ self.values_not_contained_in_range(&*range, options).unwrap_or(false)
}
PatKind::Slice { .. }
| PatKind::Array { .. }
@@ -130,7 +130,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
return false;
};
- match *match_pair.pattern.kind {
+ match match_pair.pattern.kind {
PatKind::Variant { adt_def: _, variant_index, .. } => {
// We have a pattern testing for variant `variant_index`
// set the corresponding index to true
@@ -144,6 +144,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
}
}
+ #[instrument(skip(self, make_target_blocks, place_builder), level = "debug")]
pub(super) fn perform_test(
&mut self,
match_start_span: Span,
@@ -153,21 +154,9 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
test: &Test<'tcx>,
make_target_blocks: impl FnOnce(&mut Self) -> Vec<BasicBlock>,
) {
- let place: Place<'tcx>;
- if let Ok(test_place_builder) =
- place_builder.try_upvars_resolved(self.tcx, self.typeck_results)
- {
- place = test_place_builder.into_place(self.tcx, self.typeck_results);
- } else {
- return;
- }
- debug!(
- "perform_test({:?}, {:?}: {:?}, {:?})",
- block,
- place,
- place.ty(&self.local_decls, self.tcx),
- test
- );
+ let place = place_builder.into_place(self);
+ let place_ty = place.ty(&self.local_decls, self.tcx);
+ debug!(?place, ?place_ty,);
let source_info = self.source_info(test.span);
match test.kind {
@@ -272,7 +261,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
}
}
- TestKind::Range(PatRange { lo, hi, ref end }) => {
+ TestKind::Range(box PatRange { lo, hi, ref end }) => {
let lower_bound_success = self.cfg.start_new_block();
let target_blocks = make_target_blocks(self);
@@ -506,7 +495,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
let (match_pair_index, match_pair) =
candidate.match_pairs.iter().enumerate().find(|&(_, mp)| mp.place == *test_place)?;
- match (&test.kind, &*match_pair.pattern.kind) {
+ match (&test.kind, &match_pair.pattern.kind) {
// If we are performing a variant switch, then this
// informs variant patterns, but nothing else.
(
@@ -540,9 +529,9 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
Some(index)
}
- (&TestKind::SwitchInt { switch_ty: _, ref options }, &PatKind::Range(range)) => {
+ (&TestKind::SwitchInt { switch_ty: _, ref options }, &PatKind::Range(ref range)) => {
let not_contained =
- self.values_not_contained_in_range(range, options).unwrap_or(false);
+ self.values_not_contained_in_range(&*range, options).unwrap_or(false);
if not_contained {
// No switch values are contained in the pattern range,
@@ -569,7 +558,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
match_pair_index,
candidate,
prefix,
- slice.as_ref(),
+ slice,
suffix,
);
Some(0)
@@ -607,7 +596,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
match_pair_index,
candidate,
prefix,
- slice.as_ref(),
+ slice,
suffix,
);
Some(0)
@@ -631,7 +620,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
}
}
- (&TestKind::Range(test), &PatKind::Range(pat)) => {
+ (&TestKind::Range(ref test), &PatKind::Range(ref pat)) => {
use std::cmp::Ordering::*;
if test == pat {
@@ -658,8 +647,8 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
no_overlap
}
- (&TestKind::Range(range), &PatKind::Constant { value }) => {
- if let Some(false) = self.const_range_contains(range, value) {
+ (&TestKind::Range(ref range), &PatKind::Constant { value }) => {
+ if let Some(false) = self.const_range_contains(&*range, value) {
// `value` is not contained in the testing range,
// so `value` can be matched only if this test fails.
Some(1)
@@ -678,7 +667,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 PatKind::Or { .. } = &match_pair.pattern.kind {
return None;
}
@@ -708,9 +697,9 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
&mut self,
match_pair_index: usize,
candidate: &mut Candidate<'pat, 'tcx>,
- prefix: &'pat [Pat<'tcx>],
- opt_slice: Option<&'pat Pat<'tcx>>,
- suffix: &'pat [Pat<'tcx>],
+ prefix: &'pat [Box<Pat<'tcx>>],
+ opt_slice: &'pat Option<Box<Pat<'tcx>>>,
+ suffix: &'pat [Box<Pat<'tcx>>],
) {
let removed_place = candidate.match_pairs.remove(match_pair_index).place;
self.prefix_slice_suffix(
@@ -735,14 +724,12 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
// So, if we have a match-pattern like `x @ Enum::Variant(P1, P2)`,
// we want to create a set of derived match-patterns like
// `(x as Variant).0 @ P1` and `(x as Variant).1 @ P1`.
- let elem =
- ProjectionElem::Downcast(Some(adt_def.variant(variant_index).name), variant_index);
- let downcast_place = match_pair.place.project(elem); // `(x as Variant)`
+ let downcast_place = match_pair.place.downcast(adt_def, variant_index); // `(x as Variant)`
let consequent_match_pairs = subpatterns.iter().map(|subpattern| {
// e.g., `(x as Variant).0`
let place = downcast_place.clone().field(subpattern.field, subpattern.pattern.ty);
// e.g., `(x as Variant).0 @ P1`
- MatchPair::new(place, &subpattern.pattern)
+ MatchPair::new(place, &subpattern.pattern, self)
});
candidate.match_pairs.extend(consequent_match_pairs);
@@ -754,7 +741,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
fn const_range_contains(
&self,
- range: PatRange<'tcx>,
+ range: &PatRange<'tcx>,
value: ConstantKind<'tcx>,
) -> Option<bool> {
use std::cmp::Ordering::*;
@@ -772,7 +759,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
fn values_not_contained_in_range(
&self,
- range: PatRange<'tcx>,
+ range: &PatRange<'tcx>,
options: &FxIndexMap<ConstantKind<'tcx>, u128>,
) -> Option<bool> {
for &val in options.keys() {
diff --git a/compiler/rustc_mir_build/src/build/matches/util.rs b/compiler/rustc_mir_build/src/build/matches/util.rs
index 9a1e98d3b..b854ba47f 100644
--- a/compiler/rustc_mir_build/src/build/matches/util.rs
+++ b/compiler/rustc_mir_build/src/build/matches/util.rs
@@ -1,9 +1,11 @@
+use crate::build::expr::as_place::PlaceBase;
use crate::build::expr::as_place::PlaceBuilder;
use crate::build::matches::MatchPair;
use crate::build::Builder;
use rustc_middle::mir::*;
use rustc_middle::thir::*;
use rustc_middle::ty;
+use rustc_middle::ty::TypeVisitable;
use smallvec::SmallVec;
use std::convert::TryInto;
@@ -17,7 +19,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
.iter()
.map(|fieldpat| {
let place = place.clone().field(fieldpat.field, fieldpat.pattern.ty);
- MatchPair::new(place, &fieldpat.pattern)
+ MatchPair::new(place, &fieldpat.pattern, self)
})
.collect()
}
@@ -26,32 +28,26 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
&mut self,
match_pairs: &mut SmallVec<[MatchPair<'pat, 'tcx>; 1]>,
place: &PlaceBuilder<'tcx>,
- prefix: &'pat [Pat<'tcx>],
- opt_slice: Option<&'pat Pat<'tcx>>,
- suffix: &'pat [Pat<'tcx>],
+ prefix: &'pat [Box<Pat<'tcx>>],
+ opt_slice: &'pat Option<Box<Pat<'tcx>>>,
+ suffix: &'pat [Box<Pat<'tcx>>],
) {
let tcx = self.tcx;
- let (min_length, exact_size) = if let Ok(place_resolved) =
- place.clone().try_upvars_resolved(tcx, self.typeck_results)
- {
- match place_resolved
- .into_place(tcx, self.typeck_results)
- .ty(&self.local_decls, tcx)
- .ty
- .kind()
- {
- ty::Array(_, length) => (length.eval_usize(tcx, self.param_env), true),
- _ => ((prefix.len() + suffix.len()).try_into().unwrap(), false),
- }
- } else {
- ((prefix.len() + suffix.len()).try_into().unwrap(), false)
- };
+ let (min_length, exact_size) =
+ if let Ok(place_resolved) = place.clone().try_upvars_resolved(self) {
+ match place_resolved.into_place(self).ty(&self.local_decls, tcx).ty.kind() {
+ ty::Array(_, length) => (length.eval_usize(tcx, self.param_env), true),
+ _ => ((prefix.len() + suffix.len()).try_into().unwrap(), false),
+ }
+ } else {
+ ((prefix.len() + suffix.len()).try_into().unwrap(), false)
+ };
match_pairs.extend(prefix.iter().enumerate().map(|(idx, subpattern)| {
let elem =
ProjectionElem::ConstantIndex { offset: idx as u64, min_length, from_end: false };
let place = place.clone().project(elem);
- MatchPair::new(place, subpattern)
+ MatchPair::new(place, subpattern, self)
}));
if let Some(subslice_pat) = opt_slice {
@@ -61,7 +57,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
to: if exact_size { min_length - suffix_len } else { suffix_len },
from_end: !exact_size,
});
- match_pairs.push(MatchPair::new(subslice, subslice_pat));
+ match_pairs.push(MatchPair::new(subslice, subslice_pat, self));
}
match_pairs.extend(suffix.iter().rev().enumerate().map(|(idx, subpattern)| {
@@ -72,7 +68,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
from_end: !exact_size,
};
let place = place.clone().project(elem);
- MatchPair::new(place, subpattern)
+ MatchPair::new(place, subpattern, self)
}));
}
@@ -100,10 +96,29 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
}
impl<'pat, 'tcx> MatchPair<'pat, 'tcx> {
- pub(crate) fn new(
+ pub(in crate::build) fn new(
place: PlaceBuilder<'tcx>,
pattern: &'pat Pat<'tcx>,
+ cx: &Builder<'_, 'tcx>,
) -> MatchPair<'pat, 'tcx> {
+ // Force the place type to the pattern's type.
+ // FIXME(oli-obk): can we use this to simplify slice/array pattern hacks?
+ let mut place = match place.try_upvars_resolved(cx) {
+ Ok(val) | Err(val) => val,
+ };
+
+ // Only add the OpaqueCast projection if the given place is an opaque type and the
+ // expected type from the pattern is not.
+ let may_need_cast = match place.base() {
+ PlaceBase::Local(local) => {
+ let ty = Place::ty_from(local, place.projection(), &cx.local_decls, cx.tcx).ty;
+ ty != pattern.ty && ty.has_opaque_types()
+ }
+ _ => true,
+ };
+ if may_need_cast {
+ place = place.project(ProjectionElem::OpaqueCast(pattern.ty));
+ }
MatchPair { place, pattern }
}
}