Created
May 31, 2016 21:57
-
-
Save scottcarr/ba1900b83f00123a609782358409bc92 to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
diff --git a/src/librustc_mir/build/matches/mod.rs b/src/librustc_mir/build/matches/mod.rs | |
index c1a0e1f..52a3cad 100644 | |
--- a/src/librustc_mir/build/matches/mod.rs | |
+++ b/src/librustc_mir/build/matches/mod.rs | |
@@ -266,6 +266,7 @@ enum TestKind<'tcx> { | |
// test the branches of enum | |
Switch { | |
adt_def: AdtDef<'tcx>, | |
+ options: Vec<usize>, // SCOTT: a vec to hold the variants we want to test | |
}, | |
// test the branches of enum | |
@@ -391,9 +392,11 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> { | |
fn join_otherwise_blocks(&mut self, | |
span: Span, | |
- otherwise: Vec<BasicBlock>) | |
+ mut otherwise: Vec<BasicBlock>) | |
-> BasicBlock | |
{ | |
+ otherwise.sort(); | |
+ otherwise.dedup(); // variant switches can introduce duplicate target blocks | |
let scope_id = self.innermost_scope_id(); | |
if otherwise.len() == 1 { | |
otherwise[0] | |
@@ -502,6 +505,18 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> { | |
} | |
} | |
} | |
+ // SCOTT | |
+ // maybe there should be a case for TestKind::Switch? | |
+ // it would need to call a different function than add_cases_to_switch? | |
+ TestKind::Switch { adt_def, ref mut options} => { | |
+ for candidate in candidates.iter() { | |
+ if !self.add_cases_to_switch_switch(&match_pair.lvalue, | |
+ candidate, | |
+ options) { | |
+ break; | |
+ } | |
+ } | |
+ } | |
_ => { } | |
} | |
@@ -513,18 +528,27 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> { | |
let target_blocks = self.perform_test(block, &match_pair.lvalue, &test); | |
let mut target_candidates: Vec<_> = (0..target_blocks.len()).map(|_| vec![]).collect(); | |
+ // SCOTT does sort candidates still work? | |
+ // we want to consider all the branches tested | |
+ // when we switch over a variant | |
+ | |
// Sort the candidates into the appropriate vector in | |
// `target_candidates`. Note that at some point we may | |
// encounter a candidate where the test is not relevant; at | |
// that point, we stop sorting. | |
let tested_candidates = | |
candidates.iter() | |
- .take_while(|c| self.sort_candidate(&match_pair.lvalue, | |
- &test, | |
- c, | |
- &mut target_candidates)) | |
- .count(); | |
+ .take_while(|c| self.sort_candidate(&match_pair.lvalue, | |
+ &test, | |
+ c, | |
+ &mut target_candidates)) | |
+ .count(); | |
assert!(tested_candidates > 0); // at least the last candidate ought to be tested | |
+ debug!("tested_candidates: {}", tested_candidates); | |
+ debug!("untested_candidates: {}", candidates.len() - tested_candidates); | |
+ | |
+ // we still recursive on every target candidate... | |
+ // so the # of tested candidates doesn't matter at the moment? | |
// For each outcome of test, process the candidates that still | |
// apply. Collect a list of blocks where control flow will | |
@@ -532,14 +556,14 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> { | |
// exhaustive. | |
let otherwise: Vec<_> = | |
target_blocks.into_iter() | |
- .zip(target_candidates) | |
- .flat_map(|(target_block, target_candidates)| { | |
- self.match_candidates(span, | |
- arm_blocks, | |
- target_candidates, | |
- target_block) | |
- }) | |
- .collect(); | |
+ .zip(target_candidates) | |
+ .flat_map(|(target_block, target_candidates)| { | |
+ self.match_candidates(span, | |
+ arm_blocks, | |
+ target_candidates, | |
+ target_block) | |
+ }) | |
+ .collect(); | |
(otherwise, tested_candidates) | |
} | |
diff --git a/src/librustc_mir/build/matches/test.rs b/src/librustc_mir/build/matches/test.rs | |
index e53584a..117d331 100644 | |
--- a/src/librustc_mir/build/matches/test.rs | |
+++ b/src/librustc_mir/build/matches/test.rs | |
@@ -33,7 +33,10 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> { | |
PatternKind::Variant { ref adt_def, variant_index: _, subpatterns: _ } => { | |
Test { | |
span: match_pair.pattern.span, | |
- kind: TestKind::Switch { adt_def: adt_def.clone() }, | |
+ kind: TestKind::Switch { | |
+ adt_def: adt_def.clone(), | |
+ options: vec![], | |
+ }, | |
} | |
} | |
@@ -125,9 +128,11 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> { | |
}); | |
true | |
} | |
- | |
+ PatternKind::Variant { .. } => { | |
+ panic!("you should have called add_cases_to_switch_swith instead!"); | |
+ } | |
PatternKind::Range { .. } | | |
- PatternKind::Variant { .. } | | |
+ //PatternKind::Variant { .. } | | |
PatternKind::Slice { .. } | | |
PatternKind::Array { .. } | | |
PatternKind::Wild | | |
@@ -140,6 +145,30 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> { | |
} | |
} | |
+ pub fn add_cases_to_switch_switch<'pat>(&mut self, | |
+ test_lvalue: &Lvalue<'tcx>, | |
+ candidate: &Candidate<'pat, 'tcx>, | |
+ options: &mut Vec<usize>) | |
+ -> bool | |
+ { | |
+ let match_pair = match candidate.match_pairs.iter().find(|mp| mp.lvalue == *test_lvalue) { | |
+ Some(match_pair) => match_pair, | |
+ _ => { return false; } | |
+ }; | |
+ | |
+ match *match_pair.pattern.kind { | |
+ PatternKind::Variant { adt_def , variant_index, .. } => { | |
+ // Do I need to look at the PatternKind::Variant subpatterns? | |
+ options.push(variant_index); | |
+ true | |
+ } | |
+ _ => { | |
+ // don't know how to add these patterns to a switch | |
+ false | |
+ } | |
+ } | |
+ } | |
+ | |
/// Generates the code to perform a test. | |
pub fn perform_test(&mut self, | |
block: BasicBlock, | |
@@ -148,11 +177,32 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> { | |
-> Vec<BasicBlock> { | |
let scope_id = self.innermost_scope_id(); | |
match test.kind { | |
- TestKind::Switch { adt_def } => { | |
+ TestKind::Switch { adt_def, ref options } => { | |
let num_enum_variants = self.hir.num_variants(adt_def); | |
- let target_blocks: Vec<_> = | |
- (0..num_enum_variants).map(|_| self.cfg.start_new_block()) | |
- .collect(); | |
+ debug!("num_enum_variants: {}", num_enum_variants); | |
+ debug!("options.len(): {}", options.len()); | |
+ debug!("options: {:?}", options); | |
+ let target_blocks: Vec<_> = if num_enum_variants == options.len() { | |
+ (0..num_enum_variants).map(|_| | |
+ self.cfg.start_new_block() | |
+ ) | |
+ .collect() | |
+ } else { | |
+ let otherwise_block = self.cfg.start_new_block(); | |
+ debug!("basic block: {:?} is an otherwise block!", otherwise_block); | |
+ (0..num_enum_variants).map(|i| | |
+ if options.contains(&i) { | |
+ self.cfg.start_new_block() | |
+ } else { | |
+ otherwise_block | |
+ } | |
+ ) | |
+ .collect() | |
+ //(0..num_enum_variants).map(|_| | |
+ // self.cfg.start_new_block() | |
+ //) | |
+ //.collect() | |
+ }; | |
self.cfg.terminate(block, scope_id, test.span, TerminatorKind::Switch { | |
discr: lvalue.clone(), | |
adt_def: adt_def, | |
@@ -168,6 +218,11 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> { | |
.map(|_| self.cfg.start_new_block()) | |
.chain(Some(otherwise)) | |
.collect(); | |
+ // so a SwitchInt will have len(options) + 1 targets always | |
+ // the inner switches must have len(options) == 1 then? | |
+ // why does the first switch have many options | |
+ // but the inner switch only has one? | |
+ // the number of options is determined with the TestKind::SwitchInt | |
self.cfg.terminate(block, | |
scope_id, | |
test.span, | |
@@ -380,10 +435,15 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> { | |
} | |
}; | |
+ // SCOTT | |
+ // this part seems important | |
+ // this is where we modify the candidates based on the test we observed | |
match test.kind { | |
// If we are performing a variant switch, then this | |
// informs variant patterns, but nothing else. | |
- TestKind::Switch { adt_def: tested_adt_def } => { | |
+ TestKind::Switch { adt_def: tested_adt_def , ref options } => { | |
+ // SCOTT I can ignore `options` here? | |
+ // I think so? The SwitchInt case ignores `options` | |
match *match_pair.pattern.kind { | |
PatternKind::Variant { adt_def, variant_index, ref subpatterns } => { | |
assert_eq!(adt_def, tested_adt_def); | |
@@ -411,7 +471,7 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> { | |
match *match_pair.pattern.kind { | |
PatternKind::Constant { ref value } | |
if is_switch_ty(match_pair.pattern.ty) => { | |
- let index = indices[value]; | |
+ let index = indices[value]; // SCOTT this is where it retrieves values from the hash map | |
let new_candidate = self.candidate_without_match_pair(match_pair_index, | |
candidate); | |
resulting_candidates[index].push(new_candidate); |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment