Skip to content

Instantly share code, notes, and snippets.

@scottcarr
Created May 31, 2016 21:57
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save scottcarr/ba1900b83f00123a609782358409bc92 to your computer and use it in GitHub Desktop.
Save scottcarr/ba1900b83f00123a609782358409bc92 to your computer and use it in GitHub Desktop.
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