Merge remote-tracking branch 'origin/trunk' into refcount

This commit is contained in:
Folkert 2020-08-08 22:34:14 +02:00
commit 078c6df677
53 changed files with 3604 additions and 2377 deletions

View file

@ -154,9 +154,8 @@ fn to_decision_tree(raw_branches: Vec<Branch>) -> DecisionTree {
match check_for_match(&branches) {
Some(goal) => DecisionTree::Match(goal),
None => {
// TODO remove clone
let path = pick_path(branches.clone());
// must clone here to release the borrow on `branches`
let path = pick_path(&branches).clone();
let (edges, fallback) = gather_edges(branches, &path);
let mut decision_edges: Vec<_> = edges
@ -218,43 +217,47 @@ fn flatten<'a>(
path_pattern: (Path, Guard<'a>, Pattern<'a>),
path_patterns: &mut Vec<(Path, Guard<'a>, Pattern<'a>)>,
) {
match &path_pattern.2 {
match path_pattern.2 {
Pattern::AppliedTag {
union,
arguments,
tag_id,
..
} => {
// TODO do we need to check that guard.is_none() here?
if union.alternatives.len() == 1 {
let path = path_pattern.0;
// Theory: unbox doesn't have any value for us, because one-element tag unions
// don't store the tag anyway.
if arguments.len() == 1 {
path_patterns.push((
Path::Unbox(Box::new(path)),
path_pattern.1.clone(),
path_pattern.2.clone(),
));
} else {
for (index, (arg_pattern, _)) in arguments.iter().enumerate() {
flatten(
(
Path::Index {
index: index as u64,
tag_id: *tag_id,
path: Box::new(path.clone()),
},
// same guard here?
path_pattern.1.clone(),
arg_pattern.clone(),
),
path_patterns,
);
}
}
tag_name,
layout,
} if union.alternatives.len() == 1 => {
// TODO ^ do we need to check that guard.is_none() here?
let path = path_pattern.0;
// Theory: unbox doesn't have any value for us, because one-element tag unions
// don't store the tag anyway.
if arguments.len() == 1 {
path_patterns.push((
Path::Unbox(Box::new(path)),
path_pattern.1.clone(),
Pattern::AppliedTag {
union,
arguments,
tag_id,
tag_name,
layout,
},
));
} else {
path_patterns.push(path_pattern);
for (index, (arg_pattern, _)) in arguments.iter().enumerate() {
flatten(
(
Path::Index {
index: index as u64,
tag_id,
path: Box::new(path.clone()),
},
// same guard here?
path_pattern.1.clone(),
arg_pattern.clone(),
),
path_patterns,
);
}
}
}
@ -289,8 +292,7 @@ fn gather_edges<'a>(
branches: Vec<Branch<'a>>,
path: &Path,
) -> (Vec<(Test<'a>, Vec<Branch<'a>>)>, Vec<Branch<'a>>) {
// TODO remove clone
let relevant_tests = tests_at_path(path, branches.clone());
let relevant_tests = tests_at_path(path, &branches);
let check = is_complete(&relevant_tests);
@ -314,12 +316,12 @@ fn gather_edges<'a>(
/// FIND RELEVANT TESTS
fn tests_at_path<'a>(selected_path: &Path, branches: Vec<Branch<'a>>) -> Vec<Test<'a>> {
fn tests_at_path<'a>(selected_path: &Path, branches: &[Branch<'a>]) -> Vec<Test<'a>> {
// NOTE the ordering of the result is important!
let mut all_tests = Vec::new();
for branch in branches.into_iter() {
for branch in branches {
test_at_path(selected_path, branch, &mut all_tests);
}
@ -348,7 +350,7 @@ fn tests_at_path<'a>(selected_path: &Path, branches: Vec<Branch<'a>>) -> Vec<Tes
unique
}
fn test_at_path<'a>(selected_path: &Path, branch: Branch<'a>, all_tests: &mut Vec<Test<'a>>) {
fn test_at_path<'a>(selected_path: &Path, branch: &Branch<'a>, all_tests: &mut Vec<Test<'a>>) {
use Pattern::*;
use Test::*;
@ -466,7 +468,7 @@ fn edges_for<'a>(
) -> (Test<'a>, Vec<Branch<'a>>) {
let mut new_branches = Vec::new();
for branch in branches.into_iter() {
for branch in branches.iter() {
to_relevant_branch(&test, path, branch, &mut new_branches);
}
@ -476,13 +478,13 @@ fn edges_for<'a>(
fn to_relevant_branch<'a>(
test: &Test<'a>,
path: &Path,
branch: Branch<'a>,
branch: &Branch<'a>,
new_branches: &mut Vec<Branch<'a>>,
) {
// TODO remove clone
match extract(path, branch.patterns.clone()) {
Extract::NotFound => {
new_branches.push(branch);
new_branches.push(branch.clone());
}
Extract::Found {
start,
@ -518,7 +520,7 @@ fn to_relevant_branch_help<'a>(
path: &Path,
mut start: Vec<(Path, Guard<'a>, Pattern<'a>)>,
end: Vec<(Path, Guard<'a>, Pattern<'a>)>,
branch: Branch<'a>,
branch: &Branch<'a>,
guard: Guard<'a>,
pattern: Pattern<'a>,
) -> Option<Branch<'a>> {
@ -526,7 +528,7 @@ fn to_relevant_branch_help<'a>(
use Test::*;
match pattern {
Identifier(_) | Underscore | Shadowed(_, _) | UnsupportedPattern(_) => Some(branch),
Identifier(_) | Underscore | Shadowed(_, _) | UnsupportedPattern(_) => Some(branch.clone()),
RecordDestructure(destructs, _) => match test {
IsCtor {
@ -689,19 +691,14 @@ fn extract<'a>(
) -> Extract<'a> {
let mut start = Vec::new();
// TODO remove this clone
let mut copy = path_patterns.clone();
// TODO potential ordering problem
for (index, current) in path_patterns.into_iter().enumerate() {
let mut it = path_patterns.into_iter();
while let Some(current) = it.next() {
if &current.0 == selected_path {
return Extract::Found {
start,
found_pattern: (current.1, current.2),
end: {
copy.drain(0..=index);
copy
},
end: it.collect::<Vec<_>>(),
};
} else {
start.push(current);
@ -742,22 +739,27 @@ fn needs_tests<'a>(pattern: &Pattern<'a>) -> bool {
/// PICK A PATH
fn pick_path(branches: Vec<Branch>) -> Path {
// TODO remove this clone
let all_paths = branches
.clone()
.into_iter()
.map(|v| v.patterns)
.flatten()
.filter_map(is_choice_path);
fn pick_path<'a>(branches: &'a [Branch]) -> &'a Path {
let mut all_paths = Vec::with_capacity(branches.len());
let mut by_small_defaults = bests_by_small_defaults(&branches, all_paths);
// is choice path
for branch in branches {
for (path, guard, pattern) in &branch.patterns {
if !guard.is_none() || needs_tests(&pattern) {
all_paths.push(path);
} else {
// do nothing
}
}
}
let mut by_small_defaults = bests_by_small_defaults(branches, all_paths.into_iter());
if by_small_defaults.len() == 1 {
by_small_defaults.remove(0)
} else {
debug_assert!(!by_small_defaults.is_empty());
let mut result = bests_by_small_branching_factor(&branches, by_small_defaults.into_iter());
let mut result = bests_by_small_branching_factor(branches, by_small_defaults.into_iter());
match result.pop() {
None => unreachable!("bests_by will always return at least one value in the vec"),
@ -766,33 +768,23 @@ fn pick_path(branches: Vec<Branch>) -> Path {
}
}
fn is_choice_path<'a>(path_and_pattern: (Path, Guard<'a>, Pattern<'a>)) -> Option<Path> {
let (path, guard, pattern) = path_and_pattern;
if !guard.is_none() || needs_tests(&pattern) {
Some(path)
} else {
None
}
}
fn bests_by_small_branching_factor<I>(branches: &Vec<Branch>, mut all_paths: I) -> Vec<Path>
fn bests_by_small_branching_factor<'a, I>(branches: &[Branch], mut all_paths: I) -> Vec<&'a Path>
where
I: Iterator<Item = Path>,
I: Iterator<Item = &'a Path>,
{
match all_paths.next() {
None => panic!("Cannot choose the best of zero paths. This should never happen."),
Some(first_path) => {
let mut min_weight = small_branching_factor(branches, &first_path);
let mut min_weight = small_branching_factor(branches, first_path);
let mut min_paths = vec![first_path];
for path in all_paths {
let weight = small_branching_factor(branches, &path);
let weight = small_branching_factor(branches, path);
use std::cmp::Ordering;
match weight.cmp(&min_weight) {
Ordering::Equal => {
min_paths.push(path.clone());
min_paths.push(path);
}
Ordering::Less => {
min_weight = weight;
@ -808,14 +800,14 @@ where
}
}
fn bests_by_small_defaults<I>(branches: &Vec<Branch>, mut all_paths: I) -> Vec<Path>
fn bests_by_small_defaults<'a, I>(branches: &[Branch], mut all_paths: I) -> Vec<&'a Path>
where
I: Iterator<Item = Path>,
I: Iterator<Item = &'a Path>,
{
match all_paths.next() {
None => panic!("Cannot choose the best of zero paths. This should never happen."),
Some(first_path) => {
let mut min_weight = small_defaults(branches, &first_path);
let mut min_weight = small_defaults(branches, first_path);
let mut min_paths = vec![first_path];
for path in all_paths {
@ -824,7 +816,7 @@ where
use std::cmp::Ordering;
match weight.cmp(&min_weight) {
Ordering::Equal => {
min_paths.push(path.clone());
min_paths.push(path);
}
Ordering::Less => {
min_weight = weight;
@ -842,7 +834,7 @@ where
/// PATH PICKING HEURISTICS
fn small_defaults(branches: &Vec<Branch>, path: &Path) -> usize {
fn small_defaults(branches: &[Branch], path: &Path) -> usize {
branches
.iter()
.filter(|b| is_irrelevant_to(path, b))
@ -850,7 +842,7 @@ fn small_defaults(branches: &Vec<Branch>, path: &Path) -> usize {
.sum()
}
fn small_branching_factor(branches: &Vec<Branch>, path: &Path) -> usize {
fn small_branching_factor(branches: &[Branch], path: &Path) -> usize {
// TODO remove clone
let (edges, fallback) = gather_edges(branches.to_vec(), path);