mirror of
https://github.com/roc-lang/roc.git
synced 2025-09-29 14:54:47 +00:00
move Guard into the Branch
This commit is contained in:
parent
60311fc7ce
commit
0fbf540d69
3 changed files with 91 additions and 70 deletions
|
@ -22,7 +22,8 @@ fn compile<'a>(raw_branches: Vec<(Guard<'a>, Pattern<'a>, u64)>) -> DecisionTree
|
||||||
.into_iter()
|
.into_iter()
|
||||||
.map(|(guard, pattern, index)| Branch {
|
.map(|(guard, pattern, index)| Branch {
|
||||||
goal: index,
|
goal: index,
|
||||||
patterns: vec![(Vec::new(), guard, pattern)],
|
guard,
|
||||||
|
patterns: vec![(Vec::new(), pattern)],
|
||||||
})
|
})
|
||||||
.collect();
|
.collect();
|
||||||
|
|
||||||
|
@ -156,7 +157,8 @@ impl<'a> Hash for GuardedTest<'a> {
|
||||||
#[derive(Clone, Debug, PartialEq)]
|
#[derive(Clone, Debug, PartialEq)]
|
||||||
struct Branch<'a> {
|
struct Branch<'a> {
|
||||||
goal: Label,
|
goal: Label,
|
||||||
patterns: Vec<(Vec<PathInstruction>, Guard<'a>, Pattern<'a>)>,
|
guard: Guard<'a>,
|
||||||
|
patterns: Vec<(Vec<PathInstruction>, Pattern<'a>)>,
|
||||||
}
|
}
|
||||||
|
|
||||||
fn to_decision_tree(raw_branches: Vec<Branch>) -> DecisionTree {
|
fn to_decision_tree(raw_branches: Vec<Branch>) -> DecisionTree {
|
||||||
|
@ -231,16 +233,16 @@ fn flatten_patterns(branch: Branch) -> Branch {
|
||||||
}
|
}
|
||||||
|
|
||||||
Branch {
|
Branch {
|
||||||
goal: branch.goal,
|
|
||||||
patterns: result,
|
patterns: result,
|
||||||
|
..branch
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn flatten<'a>(
|
fn flatten<'a>(
|
||||||
path_pattern: (Vec<PathInstruction>, Guard<'a>, Pattern<'a>),
|
path_pattern: (Vec<PathInstruction>, Pattern<'a>),
|
||||||
path_patterns: &mut Vec<(Vec<PathInstruction>, Guard<'a>, Pattern<'a>)>,
|
path_patterns: &mut Vec<(Vec<PathInstruction>, Pattern<'a>)>,
|
||||||
) {
|
) {
|
||||||
match path_pattern.2 {
|
match path_pattern.1 {
|
||||||
Pattern::AppliedTag {
|
Pattern::AppliedTag {
|
||||||
union,
|
union,
|
||||||
arguments,
|
arguments,
|
||||||
|
@ -257,7 +259,6 @@ fn flatten<'a>(
|
||||||
// NOTE here elm will unbox, but we don't use that
|
// NOTE here elm will unbox, but we don't use that
|
||||||
path_patterns.push((
|
path_patterns.push((
|
||||||
path,
|
path,
|
||||||
path_pattern.1.clone(),
|
|
||||||
Pattern::AppliedTag {
|
Pattern::AppliedTag {
|
||||||
union,
|
union,
|
||||||
arguments,
|
arguments,
|
||||||
|
@ -274,15 +275,7 @@ fn flatten<'a>(
|
||||||
tag_id,
|
tag_id,
|
||||||
});
|
});
|
||||||
|
|
||||||
flatten(
|
flatten((new_path, arg_pattern.clone()), path_patterns);
|
||||||
(
|
|
||||||
new_path,
|
|
||||||
// same guard here?
|
|
||||||
path_pattern.1.clone(),
|
|
||||||
arg_pattern.clone(),
|
|
||||||
),
|
|
||||||
path_patterns,
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -301,11 +294,11 @@ fn flatten<'a>(
|
||||||
/// us something like ("x" => value.0.0)
|
/// us something like ("x" => value.0.0)
|
||||||
fn check_for_match(branches: &[Branch]) -> Option<Label> {
|
fn check_for_match(branches: &[Branch]) -> Option<Label> {
|
||||||
match branches.get(0) {
|
match branches.get(0) {
|
||||||
Some(Branch { goal, patterns })
|
Some(Branch {
|
||||||
if patterns
|
goal,
|
||||||
.iter()
|
guard,
|
||||||
.all(|(_, guard, pattern)| guard.is_none() && !needs_tests(pattern)) =>
|
patterns,
|
||||||
{
|
}) if guard.is_none() && patterns.iter().all(|(_, pattern)| !needs_tests(pattern)) => {
|
||||||
Some(*goal)
|
Some(*goal)
|
||||||
}
|
}
|
||||||
_ => None,
|
_ => None,
|
||||||
|
@ -389,13 +382,13 @@ fn test_at_path<'a>(
|
||||||
match branch
|
match branch
|
||||||
.patterns
|
.patterns
|
||||||
.iter()
|
.iter()
|
||||||
.find(|(path, _, _)| path == selected_path)
|
.find(|(path, _)| path == selected_path)
|
||||||
{
|
{
|
||||||
None => None,
|
None => None,
|
||||||
Some((_, guard, pattern)) => {
|
Some((_, pattern)) => {
|
||||||
let test = match pattern {
|
let test = match pattern {
|
||||||
Identifier(_) | Underscore => {
|
Identifier(_) | Underscore => {
|
||||||
if let Guard::Guard { id, stmt, .. } = guard {
|
if let Guard::Guard { id, stmt, .. } = &branch.guard {
|
||||||
return Some(GuardedTest::GuardedNoTest {
|
return Some(GuardedTest::GuardedNoTest {
|
||||||
stmt: stmt.clone(),
|
stmt: stmt.clone(),
|
||||||
id: *id,
|
id: *id,
|
||||||
|
@ -474,7 +467,7 @@ fn test_at_path<'a>(
|
||||||
StrLiteral(v) => IsStr(v.clone()),
|
StrLiteral(v) => IsStr(v.clone()),
|
||||||
};
|
};
|
||||||
|
|
||||||
let guarded_test = if let Guard::Guard { id, stmt, .. } = guard {
|
let guarded_test = if let Guard::Guard { id, stmt, .. } = &branch.guard {
|
||||||
GuardedTest::TestGuarded {
|
GuardedTest::TestGuarded {
|
||||||
test,
|
test,
|
||||||
stmt: stmt.clone(),
|
stmt: stmt.clone(),
|
||||||
|
@ -518,7 +511,7 @@ fn to_relevant_branch<'a>(
|
||||||
}
|
}
|
||||||
Extract::Found {
|
Extract::Found {
|
||||||
start,
|
start,
|
||||||
found_pattern: (guard, pattern),
|
found_pattern: pattern,
|
||||||
end,
|
end,
|
||||||
} => {
|
} => {
|
||||||
let actual_test = match guarded_test {
|
let actual_test = match guarded_test {
|
||||||
|
@ -526,29 +519,21 @@ fn to_relevant_branch<'a>(
|
||||||
GuardedTest::GuardedNoTest { .. } => {
|
GuardedTest::GuardedNoTest { .. } => {
|
||||||
let mut new_branch = branch.clone();
|
let mut new_branch = branch.clone();
|
||||||
|
|
||||||
// guards can/should only occur at the top level. When we recurse on these
|
|
||||||
// branches, the guard is not relevant any more. Not setthing the guard to None
|
|
||||||
// leads to infinite recursion.
|
|
||||||
new_branch.patterns.iter_mut().for_each(|(_, guard, _)| {
|
|
||||||
*guard = Guard::NoGuard;
|
|
||||||
});
|
|
||||||
|
|
||||||
new_branches.push(new_branch);
|
new_branches.push(new_branch);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
GuardedTest::TestNotGuarded { test } => test,
|
GuardedTest::TestNotGuarded { test } => test,
|
||||||
};
|
};
|
||||||
|
|
||||||
if let Some(mut new_branch) =
|
if let Some(mut new_branch) = to_relevant_branch_help(
|
||||||
to_relevant_branch_help(actual_test, path, start, end, branch, guard, pattern)
|
actual_test,
|
||||||
{
|
path,
|
||||||
// guards can/should only occur at the top level. When we recurse on these
|
start,
|
||||||
// branches, the guard is not relevant any more. Not setthing the guard to None
|
end,
|
||||||
// leads to infinite recursion.
|
branch,
|
||||||
new_branch.patterns.iter_mut().for_each(|(_, guard, _)| {
|
branch.guard.clone(),
|
||||||
*guard = Guard::NoGuard;
|
pattern,
|
||||||
});
|
) {
|
||||||
|
|
||||||
new_branches.push(new_branch);
|
new_branches.push(new_branch);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -558,8 +543,8 @@ fn to_relevant_branch<'a>(
|
||||||
fn to_relevant_branch_help<'a>(
|
fn to_relevant_branch_help<'a>(
|
||||||
test: &Test<'a>,
|
test: &Test<'a>,
|
||||||
path: &[PathInstruction],
|
path: &[PathInstruction],
|
||||||
mut start: Vec<(Vec<PathInstruction>, Guard<'a>, Pattern<'a>)>,
|
mut start: Vec<(Vec<PathInstruction>, Pattern<'a>)>,
|
||||||
end: Vec<(Vec<PathInstruction>, Guard<'a>, Pattern<'a>)>,
|
end: Vec<(Vec<PathInstruction>, Pattern<'a>)>,
|
||||||
branch: &Branch<'a>,
|
branch: &Branch<'a>,
|
||||||
guard: Guard<'a>,
|
guard: Guard<'a>,
|
||||||
pattern: Pattern<'a>,
|
pattern: Pattern<'a>,
|
||||||
|
@ -589,13 +574,14 @@ fn to_relevant_branch_help<'a>(
|
||||||
tag_id: *tag_id,
|
tag_id: *tag_id,
|
||||||
});
|
});
|
||||||
|
|
||||||
(new_path, Guard::NoGuard, pattern)
|
(new_path, pattern)
|
||||||
});
|
});
|
||||||
start.extend(sub_positions);
|
start.extend(sub_positions);
|
||||||
start.extend(end);
|
start.extend(end);
|
||||||
|
|
||||||
Some(Branch {
|
Some(Branch {
|
||||||
goal: branch.goal,
|
goal: branch.goal,
|
||||||
|
guard: branch.guard.clone(),
|
||||||
patterns: start,
|
patterns: start,
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
@ -625,13 +611,14 @@ fn to_relevant_branch_help<'a>(
|
||||||
index: index as u64,
|
index: index as u64,
|
||||||
tag_id,
|
tag_id,
|
||||||
});
|
});
|
||||||
(new_path, Guard::NoGuard, pattern)
|
(new_path, pattern)
|
||||||
});
|
});
|
||||||
start.extend(sub_positions);
|
start.extend(sub_positions);
|
||||||
start.extend(end);
|
start.extend(end);
|
||||||
|
|
||||||
Some(Branch {
|
Some(Branch {
|
||||||
goal: branch.goal,
|
goal: branch.goal,
|
||||||
|
guard: branch.guard.clone(),
|
||||||
patterns: start,
|
patterns: start,
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
@ -664,7 +651,7 @@ fn to_relevant_branch_help<'a>(
|
||||||
{
|
{
|
||||||
// NOTE here elm unboxes, but we ignore that
|
// NOTE here elm unboxes, but we ignore that
|
||||||
// Path::Unbox(Box::new(path.clone()))
|
// Path::Unbox(Box::new(path.clone()))
|
||||||
start.push((path.to_vec(), guard, arg.0));
|
start.push((path.to_vec(), arg.0));
|
||||||
start.extend(end);
|
start.extend(end);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -679,7 +666,7 @@ fn to_relevant_branch_help<'a>(
|
||||||
index: index as u64,
|
index: index as u64,
|
||||||
tag_id,
|
tag_id,
|
||||||
});
|
});
|
||||||
(new_path, Guard::NoGuard, pattern)
|
(new_path, pattern)
|
||||||
});
|
});
|
||||||
start.extend(sub_positions);
|
start.extend(sub_positions);
|
||||||
start.extend(end);
|
start.extend(end);
|
||||||
|
@ -698,7 +685,7 @@ fn to_relevant_branch_help<'a>(
|
||||||
index: index as u64,
|
index: index as u64,
|
||||||
tag_id,
|
tag_id,
|
||||||
});
|
});
|
||||||
(new_path, Guard::NoGuard, pattern)
|
(new_path, pattern)
|
||||||
});
|
});
|
||||||
start.extend(sub_positions);
|
start.extend(sub_positions);
|
||||||
start.extend(end);
|
start.extend(end);
|
||||||
|
@ -707,6 +694,7 @@ fn to_relevant_branch_help<'a>(
|
||||||
|
|
||||||
Some(Branch {
|
Some(Branch {
|
||||||
goal: branch.goal,
|
goal: branch.goal,
|
||||||
|
guard: branch.guard.clone(),
|
||||||
patterns: start,
|
patterns: start,
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
@ -718,6 +706,7 @@ fn to_relevant_branch_help<'a>(
|
||||||
start.extend(end);
|
start.extend(end);
|
||||||
Some(Branch {
|
Some(Branch {
|
||||||
goal: branch.goal,
|
goal: branch.goal,
|
||||||
|
guard: branch.guard.clone(),
|
||||||
patterns: start,
|
patterns: start,
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
@ -729,6 +718,7 @@ fn to_relevant_branch_help<'a>(
|
||||||
start.extend(end);
|
start.extend(end);
|
||||||
Some(Branch {
|
Some(Branch {
|
||||||
goal: branch.goal,
|
goal: branch.goal,
|
||||||
|
guard: branch.guard.clone(),
|
||||||
patterns: start,
|
patterns: start,
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
@ -740,6 +730,7 @@ fn to_relevant_branch_help<'a>(
|
||||||
start.extend(end);
|
start.extend(end);
|
||||||
Some(Branch {
|
Some(Branch {
|
||||||
goal: branch.goal,
|
goal: branch.goal,
|
||||||
|
guard: branch.guard.clone(),
|
||||||
patterns: start,
|
patterns: start,
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
@ -751,6 +742,7 @@ fn to_relevant_branch_help<'a>(
|
||||||
start.extend(end);
|
start.extend(end);
|
||||||
Some(Branch {
|
Some(Branch {
|
||||||
goal: branch.goal,
|
goal: branch.goal,
|
||||||
|
guard: branch.guard.clone(),
|
||||||
patterns: start,
|
patterns: start,
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
@ -764,6 +756,7 @@ fn to_relevant_branch_help<'a>(
|
||||||
start.extend(end);
|
start.extend(end);
|
||||||
Some(Branch {
|
Some(Branch {
|
||||||
goal: branch.goal,
|
goal: branch.goal,
|
||||||
|
guard: branch.guard.clone(),
|
||||||
patterns: start,
|
patterns: start,
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
@ -776,15 +769,15 @@ fn to_relevant_branch_help<'a>(
|
||||||
enum Extract<'a> {
|
enum Extract<'a> {
|
||||||
NotFound,
|
NotFound,
|
||||||
Found {
|
Found {
|
||||||
start: Vec<(Vec<PathInstruction>, Guard<'a>, Pattern<'a>)>,
|
start: Vec<(Vec<PathInstruction>, Pattern<'a>)>,
|
||||||
found_pattern: (Guard<'a>, Pattern<'a>),
|
found_pattern: Pattern<'a>,
|
||||||
end: Vec<(Vec<PathInstruction>, Guard<'a>, Pattern<'a>)>,
|
end: Vec<(Vec<PathInstruction>, Pattern<'a>)>,
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
fn extract<'a>(
|
fn extract<'a>(
|
||||||
selected_path: &[PathInstruction],
|
selected_path: &[PathInstruction],
|
||||||
path_patterns: Vec<(Vec<PathInstruction>, Guard<'a>, Pattern<'a>)>,
|
path_patterns: Vec<(Vec<PathInstruction>, Pattern<'a>)>,
|
||||||
) -> Extract<'a> {
|
) -> Extract<'a> {
|
||||||
let mut start = Vec::new();
|
let mut start = Vec::new();
|
||||||
|
|
||||||
|
@ -794,7 +787,7 @@ fn extract<'a>(
|
||||||
if current.0 == selected_path {
|
if current.0 == selected_path {
|
||||||
return Extract::Found {
|
return Extract::Found {
|
||||||
start,
|
start,
|
||||||
found_pattern: (current.1, current.2),
|
found_pattern: current.1,
|
||||||
end: it.collect::<Vec<_>>(),
|
end: it.collect::<Vec<_>>(),
|
||||||
};
|
};
|
||||||
} else {
|
} else {
|
||||||
|
@ -811,10 +804,10 @@ fn is_irrelevant_to<'a>(selected_path: &[PathInstruction], branch: &Branch<'a>)
|
||||||
match branch
|
match branch
|
||||||
.patterns
|
.patterns
|
||||||
.iter()
|
.iter()
|
||||||
.find(|(path, _, _)| path == selected_path)
|
.find(|(path, _)| path == selected_path)
|
||||||
{
|
{
|
||||||
None => true,
|
None => true,
|
||||||
Some((_, guard, pattern)) => guard.is_none() && !needs_tests(pattern),
|
Some((_, pattern)) => branch.guard.is_none() && !needs_tests(pattern),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -842,8 +835,8 @@ fn pick_path<'a>(branches: &'a [Branch]) -> &'a Vec<PathInstruction> {
|
||||||
|
|
||||||
// is choice path
|
// is choice path
|
||||||
for branch in branches {
|
for branch in branches {
|
||||||
for (path, guard, pattern) in &branch.patterns {
|
for (path, pattern) in &branch.patterns {
|
||||||
if !guard.is_none() || needs_tests(&pattern) {
|
if !branch.guard.is_none() || needs_tests(&pattern) {
|
||||||
all_paths.push(path);
|
all_paths.push(path);
|
||||||
} else {
|
} else {
|
||||||
// do nothing
|
// do nothing
|
||||||
|
|
|
@ -19,7 +19,7 @@ use roc_types::subs::{Content, FlatType, Subs, Variable};
|
||||||
use std::collections::HashMap;
|
use std::collections::HashMap;
|
||||||
use ven_pretty::{BoxAllocator, DocAllocator, DocBuilder};
|
use ven_pretty::{BoxAllocator, DocAllocator, DocBuilder};
|
||||||
|
|
||||||
pub const PRETTY_PRINT_IR_SYMBOLS: bool = false;
|
pub const PRETTY_PRINT_IR_SYMBOLS: bool = true;
|
||||||
|
|
||||||
macro_rules! return_on_layout_error {
|
macro_rules! return_on_layout_error {
|
||||||
($env:expr, $layout_result:expr) => {
|
($env:expr, $layout_result:expr) => {
|
||||||
|
|
|
@ -486,17 +486,45 @@ fn if_guard_vanilla() {
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn if_guard_constructor() {
|
fn if_guard_constructor() {
|
||||||
|
if false {
|
||||||
assert_evals_to!(
|
assert_evals_to!(
|
||||||
indoc!(
|
indoc!(
|
||||||
r#"
|
r#"
|
||||||
when Identity "foobar" is
|
when Identity 0 is
|
||||||
Identity s if s == "foo" -> 0
|
Identity 0 -> 0
|
||||||
Identity s -> List.len (Str.toBytes s)
|
Identity s -> s
|
||||||
"#
|
"#
|
||||||
),
|
),
|
||||||
6,
|
6,
|
||||||
i64
|
i64
|
||||||
);
|
);
|
||||||
|
} else {
|
||||||
|
// assert_evals_to!(
|
||||||
|
// indoc!(
|
||||||
|
// r#"
|
||||||
|
// when Identity "foobar" is
|
||||||
|
// Identity s if s == "foo" -> 0
|
||||||
|
// Identity z -> List.len (Str.toBytes z)
|
||||||
|
// "#
|
||||||
|
// ),
|
||||||
|
// 6,
|
||||||
|
// i64
|
||||||
|
// );
|
||||||
|
|
||||||
|
assert_evals_to!(
|
||||||
|
indoc!(
|
||||||
|
r#"
|
||||||
|
when Identity 42 is
|
||||||
|
Identity 41 -> 0
|
||||||
|
Identity s if s == 3 -> 0
|
||||||
|
# Identity 43 -> 0
|
||||||
|
Identity z -> z
|
||||||
|
"#
|
||||||
|
),
|
||||||
|
42,
|
||||||
|
i64
|
||||||
|
);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue