Implement general or-patterns in let statements

This commit is contained in:
Matthew Jasper 2019-12-27 17:31:21 +00:00
parent 5cc4352bc4
commit a20969c489

View File

@ -96,11 +96,11 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
let mut arm_candidates = self.create_match_candidates(&scrutinee_place, &arms);
let match_has_guard = arms.iter().any(|arm| arm.guard.is_some());
let candidates =
let mut candidates =
arm_candidates.iter_mut().map(|(_, candidate)| candidate).collect::<Vec<_>>();
let fake_borrow_temps =
self.lower_match_tree(block, scrutinee_span, match_has_guard, candidates);
self.lower_match_tree(block, scrutinee_span, match_has_guard, &mut candidates);
self.lower_match_arms(
&destination,
@ -181,7 +181,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
block: BasicBlock,
scrutinee_span: Span,
match_has_guard: bool,
mut candidates: Vec<&mut Candidate<'pat, 'tcx>>,
candidates: &mut [&mut Candidate<'pat, 'tcx>],
) -> Vec<(Place<'tcx>, Local)> {
// The set of places that we are creating fake borrows of. If there are
// 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> {
// This will generate code to test scrutinee_place and
// branch to the appropriate arm block
self.match_candidates(
scrutinee_span,
block,
&mut otherwise,
&mut candidates,
&mut fake_borrows,
);
self.match_candidates(scrutinee_span, block, &mut otherwise, candidates, &mut fake_borrows);
if let Some(otherwise_block) = otherwise {
let source_info = self.source_info(scrutinee_span);
@ -207,7 +201,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
let mut previous_candidate: Option<&mut Candidate<'_, '_>> = None;
for candidate in candidates.into_iter() {
for candidate in candidates {
candidate.visit_leaves(|leaf_candidate| {
if let Some(ref mut prev) = previous_candidate {
prev.next_candidate_pre_binding_block = leaf_candidate.pre_binding_block;
@ -263,7 +257,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
arm.guard.as_ref().map(|g| (g, match_scope)),
&fake_borrow_temps,
scrutinee_span,
arm.scope,
Some(arm.scope),
);
if let Some(source_scope) = scope {
@ -297,7 +291,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
guard: Option<(&Guard<'tcx>, region::Scope)>,
fake_borrow_temps: &Vec<(Place<'tcx>, Local)>,
scrutinee_span: Span,
arm_scope: region::Scope,
arm_scope: Option<region::Scope>,
) -> BasicBlock {
if candidate.subcandidates.is_empty() {
// Avoid generating another `BasicBlock` when we only have one
@ -308,10 +302,11 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
guard,
fake_borrow_temps,
scrutinee_span,
true,
)
} else {
let target_block = self.cfg.start_new_block();
let mut schedule_drops = true;
// We keep a stack of all of the bindings and type asciptions
// from the the parent candidates that we visit, that also need to
// be bound for each candidate.
@ -319,14 +314,24 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
candidate,
&mut Vec::new(),
&mut |leaf_candidate, parent_bindings| {
self.clear_top_scope(arm_scope);
if let Some(arm_scope) = arm_scope {
// Avoid scheduling drops multiple times by unscheduling drops.
self.clear_top_scope(arm_scope);
}
let binding_end = self.bind_and_guard_matched_candidate(
leaf_candidate,
parent_bindings,
guard,
&fake_borrow_temps,
scrutinee_span,
schedule_drops,
);
if arm_scope.is_none() {
// If we aren't in a match, then our bindings may not be
// the only thing in the top scope, so only schedule
// them to drop for the first pattern instead.
schedule_drops = false;
}
self.cfg.goto(binding_end, outer_source_info, target_block);
},
|inner_candidate, parent_bindings| {
@ -460,51 +465,43 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
subcandidates: vec![],
};
// Simplify the candidate. Since the pattern is irrefutable, this should
// always convert all match-pairs into bindings.
self.simplify_candidate(&mut candidate);
if !candidate.match_pairs.is_empty() {
// ICE if no other errors have been emitted. This used to be a hard error that wouldn't
// be reached because `hair::pattern::check_match::check_match` wouldn't have let the
// compiler continue. In our tests this is only ever hit by
// `ui/consts/const-match-check.rs` with `--cfg eval1`, and that file already generates
// a different error before hand.
self.hir.tcx().sess.delay_span_bug(
candidate.match_pairs[0].pattern.span,
&format!(
"match pairs {:?} remaining after simplifying irrefutable pattern",
candidate.match_pairs,
),
);
}
let fake_borrow_temps =
self.lower_match_tree(block, irrefutable_pat.span, false, &mut [&mut candidate]);
// for matches and function arguments, the place that is being matched
// can be set when creating the variables. But the place for
// let PATTERN = ... might not even exist until we do the assignment.
// so we set it here instead
if set_match_place {
for binding in &candidate.bindings {
let local = self.var_local_id(binding.var_id, OutsideGuard);
let mut candidate_ref = &candidate;
while let Some(next) = {
for binding in &candidate_ref.bindings {
let local = self.var_local_id(binding.var_id, OutsideGuard);
if let LocalInfo::User(ClearCrossCrate::Set(BindingForm::Var(VarBindingForm {
opt_match_place: Some((ref mut match_place, _)),
..
}))) = self.local_decls[local].local_info
{
*match_place = Some(*initializer);
} else {
bug!("Let binding to non-user variable.")
if let LocalInfo::User(ClearCrossCrate::Set(BindingForm::Var(
VarBindingForm { opt_match_place: Some((ref mut match_place, _)), .. },
))) = self.local_decls[local].local_info
{
*match_place = Some(*initializer);
} else {
bug!("Let binding to non-user variable.")
}
}
candidate_ref.subcandidates.get(0)
} {
candidate_ref = next;
}
}
self.ascribe_types(block, &candidate.ascriptions);
// now apply the bindings, which will also declare the variables
self.bind_matched_candidate_for_arm_body(block, &candidate.bindings);
block.unit()
self.bind_pattern(
self.source_info(irrefutable_pat.span),
candidate,
None,
&fake_borrow_temps,
irrefutable_pat.span,
None,
)
.unit()
}
/// Declares the bindings of the given patterns and returns the visibility
@ -1486,6 +1483,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
guard: Option<(&Guard<'tcx>, region::Scope)>,
fake_borrows: &Vec<(Place<'tcx>, Local)>,
scrutinee_span: Span,
schedule_drops: bool,
) -> BasicBlock {
debug!("bind_and_guard_matched_candidate(candidate={:?})", candidate);
@ -1692,7 +1690,8 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
let cause = FakeReadCause::ForGuardBinding;
self.cfg.push_fake_read(post_guard_block, guard_end, cause, Place::from(local_id));
}
self.bind_matched_candidate_for_arm_body(post_guard_block, by_value_bindings);
assert!(schedule_drops, "patterns with guards must schedule drops");
self.bind_matched_candidate_for_arm_body(post_guard_block, true, by_value_bindings);
post_guard_block
} else {
@ -1701,6 +1700,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
// that we have to inspect before we bind them.)
self.bind_matched_candidate_for_arm_body(
block,
schedule_drops,
parent_bindings
.iter()
.flat_map(|(bindings, _)| bindings)
@ -1793,6 +1793,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
fn bind_matched_candidate_for_arm_body<'b>(
&mut self,
block: BasicBlock,
schedule_drops: bool,
bindings: impl IntoIterator<Item = &'b Binding<'tcx>>,
) where
'tcx: 'b,
@ -1805,7 +1806,9 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
let source_info = self.source_info(binding.span);
let local =
self.storage_live_binding(block, binding.var_id, binding.span, OutsideGuard);
self.schedule_drop_for_binding(binding.var_id, binding.span, OutsideGuard);
if schedule_drops {
self.schedule_drop_for_binding(binding.var_id, binding.span, OutsideGuard);
}
let rvalue = match binding.binding_mode {
BindingMode::ByValue => {
Rvalue::Use(self.consume_by_copy_or_move(binding.source.clone()))