Skip to content

Commit ce1230a

Browse files
committed
Implement general or-patterns in let statements
1 parent 9eaed8d commit ce1230a

File tree

1 file changed

+55
-52
lines changed
  • src/librustc_mir/build/matches

1 file changed

+55
-52
lines changed

src/librustc_mir/build/matches/mod.rs

+55-52
Original file line numberDiff line numberDiff line change
@@ -96,11 +96,11 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
9696
let mut arm_candidates = self.create_match_candidates(&scrutinee_place, &arms);
9797

9898
let match_has_guard = arms.iter().any(|arm| arm.guard.is_some());
99-
let candidates =
99+
let mut candidates =
100100
arm_candidates.iter_mut().map(|(_, candidate)| candidate).collect::<Vec<_>>();
101101

102102
let fake_borrow_temps =
103-
self.lower_match_tree(block, scrutinee_span, match_has_guard, candidates);
103+
self.lower_match_tree(block, scrutinee_span, match_has_guard, &mut candidates);
104104

105105
self.lower_match_arms(
106106
&destination,
@@ -181,7 +181,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
181181
block: BasicBlock,
182182
scrutinee_span: Span,
183183
match_has_guard: bool,
184-
mut candidates: Vec<&mut Candidate<'pat, 'tcx>>,
184+
candidates: &mut [&mut Candidate<'pat, 'tcx>],
185185
) -> Vec<(Place<'tcx>, Local)> {
186186
// The set of places that we are creating fake borrows of. If there are
187187
// no match guards then we don't need any fake borrows, so don't track
@@ -192,13 +192,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
192192

193193
// This will generate code to test scrutinee_place and
194194
// branch to the appropriate arm block
195-
self.match_candidates(
196-
scrutinee_span,
197-
block,
198-
&mut otherwise,
199-
&mut candidates,
200-
&mut fake_borrows,
201-
);
195+
self.match_candidates(scrutinee_span, block, &mut otherwise, candidates, &mut fake_borrows);
202196

203197
if let Some(otherwise_block) = otherwise {
204198
let source_info = self.source_info(scrutinee_span);
@@ -207,7 +201,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
207201

208202
let mut previous_candidate: Option<&mut Candidate<'_, '_>> = None;
209203

210-
for candidate in candidates.into_iter() {
204+
for candidate in candidates {
211205
candidate.visit_leaves(|leaf_candidate| {
212206
if let Some(ref mut prev) = previous_candidate {
213207
prev.next_candidate_pre_binding_block = leaf_candidate.pre_binding_block;
@@ -263,7 +257,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
263257
arm.guard.as_ref().map(|g| (g, match_scope)),
264258
&fake_borrow_temps,
265259
scrutinee_span,
266-
arm.scope,
260+
Some(arm.scope),
267261
);
268262

269263
if let Some(source_scope) = scope {
@@ -297,7 +291,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
297291
guard: Option<(&Guard<'tcx>, region::Scope)>,
298292
fake_borrow_temps: &Vec<(Place<'tcx>, Local)>,
299293
scrutinee_span: Span,
300-
arm_scope: region::Scope,
294+
arm_scope: Option<region::Scope>,
301295
) -> BasicBlock {
302296
if candidate.subcandidates.is_empty() {
303297
// Avoid generating another `BasicBlock` when we only have one
@@ -308,25 +302,36 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
308302
guard,
309303
fake_borrow_temps,
310304
scrutinee_span,
305+
true,
311306
)
312307
} else {
313308
let target_block = self.cfg.start_new_block();
314-
309+
let mut schedule_drops = true;
315310
// We keep a stack of all of the bindings and type asciptions
316311
// from the the parent candidates that we visit, that also need to
317312
// be bound for each candidate.
318313
traverse_candidate(
319314
candidate,
320315
&mut Vec::new(),
321316
&mut |leaf_candidate, parent_bindings| {
322-
self.clear_top_scope(arm_scope);
317+
if let Some(arm_scope) = arm_scope {
318+
// Avoid scheduling drops multiple times by unscheduling drops.
319+
self.clear_top_scope(arm_scope);
320+
}
323321
let binding_end = self.bind_and_guard_matched_candidate(
324322
leaf_candidate,
325323
parent_bindings,
326324
guard,
327325
&fake_borrow_temps,
328326
scrutinee_span,
327+
schedule_drops,
329328
);
329+
if arm_scope.is_none() {
330+
// If we aren't in a match, then our bindings may not be
331+
// the only thing in the top scope, so only schedule
332+
// them to drop for the first pattern instead.
333+
schedule_drops = false;
334+
}
330335
self.cfg.goto(binding_end, outer_source_info, target_block);
331336
},
332337
|inner_candidate, parent_bindings| {
@@ -460,51 +465,43 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
460465
subcandidates: vec![],
461466
};
462467

463-
// Simplify the candidate. Since the pattern is irrefutable, this should
464-
// always convert all match-pairs into bindings.
465-
self.simplify_candidate(&mut candidate);
466-
467-
if !candidate.match_pairs.is_empty() {
468-
// ICE if no other errors have been emitted. This used to be a hard error that wouldn't
469-
// be reached because `hair::pattern::check_match::check_match` wouldn't have let the
470-
// compiler continue. In our tests this is only ever hit by
471-
// `ui/consts/const-match-check.rs` with `--cfg eval1`, and that file already generates
472-
// a different error before hand.
473-
self.hir.tcx().sess.delay_span_bug(
474-
candidate.match_pairs[0].pattern.span,
475-
&format!(
476-
"match pairs {:?} remaining after simplifying irrefutable pattern",
477-
candidate.match_pairs,
478-
),
479-
);
480-
}
468+
let fake_borrow_temps =
469+
self.lower_match_tree(block, irrefutable_pat.span, false, &mut [&mut candidate]);
481470

482471
// for matches and function arguments, the place that is being matched
483472
// can be set when creating the variables. But the place for
484473
// let PATTERN = ... might not even exist until we do the assignment.
485474
// so we set it here instead
486475
if set_match_place {
487-
for binding in &candidate.bindings {
488-
let local = self.var_local_id(binding.var_id, OutsideGuard);
489-
490-
if let LocalInfo::User(ClearCrossCrate::Set(BindingForm::Var(VarBindingForm {
491-
opt_match_place: Some((ref mut match_place, _)),
492-
..
493-
}))) = self.local_decls[local].local_info
494-
{
495-
*match_place = Some(initializer.clone());
496-
} else {
497-
bug!("Let binding to non-user variable.")
476+
let mut candidate_ref = &candidate;
477+
while let Some(next) = {
478+
for binding in &candidate_ref.bindings {
479+
let local = self.var_local_id(binding.var_id, OutsideGuard);
480+
481+
if let LocalInfo::User(ClearCrossCrate::Set(BindingForm::Var(
482+
VarBindingForm { opt_match_place: Some((ref mut match_place, _)), .. },
483+
))) = self.local_decls[local].local_info
484+
{
485+
*match_place = Some(initializer.clone());
486+
} else {
487+
bug!("Let binding to non-user variable.")
488+
}
498489
}
490+
candidate_ref.subcandidates.get(0)
491+
} {
492+
candidate_ref = next;
499493
}
500494
}
501495

502-
self.ascribe_types(block, &candidate.ascriptions);
503-
504-
// now apply the bindings, which will also declare the variables
505-
self.bind_matched_candidate_for_arm_body(block, &candidate.bindings);
506-
507-
block.unit()
496+
self.bind_pattern(
497+
self.source_info(irrefutable_pat.span),
498+
candidate,
499+
None,
500+
&fake_borrow_temps,
501+
irrefutable_pat.span,
502+
None,
503+
)
504+
.unit()
508505
}
509506

510507
/// Declares the bindings of the given patterns and returns the visibility
@@ -1486,6 +1483,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
14861483
guard: Option<(&Guard<'tcx>, region::Scope)>,
14871484
fake_borrows: &Vec<(Place<'tcx>, Local)>,
14881485
scrutinee_span: Span,
1486+
schedule_drops: bool,
14891487
) -> BasicBlock {
14901488
debug!("bind_and_guard_matched_candidate(candidate={:?})", candidate);
14911489

@@ -1692,7 +1690,8 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
16921690
let cause = FakeReadCause::ForGuardBinding;
16931691
self.cfg.push_fake_read(post_guard_block, guard_end, cause, Place::from(local_id));
16941692
}
1695-
self.bind_matched_candidate_for_arm_body(post_guard_block, by_value_bindings);
1693+
assert!(schedule_drops, "patterns with guards must schedule drops");
1694+
self.bind_matched_candidate_for_arm_body(post_guard_block, true, by_value_bindings);
16961695

16971696
post_guard_block
16981697
} else {
@@ -1701,6 +1700,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
17011700
// that we have to inspect before we bind them.)
17021701
self.bind_matched_candidate_for_arm_body(
17031702
block,
1703+
schedule_drops,
17041704
parent_bindings
17051705
.iter()
17061706
.flat_map(|(bindings, _)| bindings)
@@ -1793,6 +1793,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
17931793
fn bind_matched_candidate_for_arm_body<'b>(
17941794
&mut self,
17951795
block: BasicBlock,
1796+
schedule_drops: bool,
17961797
bindings: impl IntoIterator<Item = &'b Binding<'tcx>>,
17971798
) where
17981799
'tcx: 'b,
@@ -1805,7 +1806,9 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
18051806
let source_info = self.source_info(binding.span);
18061807
let local =
18071808
self.storage_live_binding(block, binding.var_id, binding.span, OutsideGuard);
1808-
self.schedule_drop_for_binding(binding.var_id, binding.span, OutsideGuard);
1809+
if schedule_drops {
1810+
self.schedule_drop_for_binding(binding.var_id, binding.span, OutsideGuard);
1811+
}
18091812
let rvalue = match binding.binding_mode {
18101813
BindingMode::ByValue => {
18111814
Rvalue::Use(self.consume_by_copy_or_move(binding.source.clone()))

0 commit comments

Comments
 (0)