diff options
author | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-04-17 12:11:28 +0000 |
---|---|---|
committer | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-04-17 12:11:28 +0000 |
commit | 94a0819fe3a0d679c3042a77bfe6a2afc505daea (patch) | |
tree | 2b827afe6a05f3538db3f7803a88c4587fe85648 /compiler/rustc_mir_build/src/build/matches | |
parent | Adding upstream version 1.64.0+dfsg1. (diff) | |
download | rustc-94a0819fe3a0d679c3042a77bfe6a2afc505daea.tar.xz rustc-94a0819fe3a0d679c3042a77bfe6a2afc505daea.zip |
Adding upstream version 1.66.0+dfsg1.upstream/1.66.0+dfsg1
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
Diffstat (limited to '')
-rw-r--r-- | compiler/rustc_mir_build/src/build/matches/mod.rs | 233 | ||||
-rw-r--r-- | compiler/rustc_mir_build/src/build/matches/simplify.rs | 51 | ||||
-rw-r--r-- | compiler/rustc_mir_build/src/build/matches/test.rs | 71 | ||||
-rw-r--r-- | compiler/rustc_mir_build/src/build/matches/util.rs | 61 |
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: ®ion::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 } } } |