Compile branches in the presence of degenerate patterns

Closes #3614
This commit is contained in:
Ayaz Hafiz 2022-07-22 18:15:30 -04:00
parent f2fc6e16ec
commit 59ab1da83f
No known key found for this signature in database
GPG key ID: 0E2A37416A25EF58
4 changed files with 78 additions and 19 deletions

View file

@ -5187,7 +5187,7 @@ pub fn with_hole<'a>(
}
}
TypedHole(_) => Stmt::RuntimeError("Hit a blank"),
RuntimeError(e) => Stmt::RuntimeError(env.arena.alloc(format!("{:?}", e))),
RuntimeError(e) => Stmt::RuntimeError(env.arena.alloc(e.runtime_message())),
}
}
@ -6047,7 +6047,9 @@ fn to_opt_branches<'a>(
for loc_pattern in when_branch.patterns {
match from_can_pattern(env, procs, layout_cache, &loc_pattern.pattern.value) {
Ok((mono_pattern, assignments)) => {
let loc_expr = if !loc_pattern.degenerate {
let mut loc_expr = when_branch.value.clone();
let region = loc_pattern.pattern.region;
for (symbol, variable, expr) in assignments.into_iter().rev() {
let def = roc_can::def::Def {
@ -6065,6 +6067,15 @@ fn to_opt_branches<'a>(
loc_expr = Loc::at(region, new_expr);
}
loc_expr
} else {
// This pattern is degenerate; when it's reached we must emit a runtime
// error.
Loc::at_zero(roc_can::expr::Expr::RuntimeError(
RuntimeError::DegenerateBranch(loc_pattern.pattern.region),
))
};
// TODO remove clone?
opt_branches.push((mono_pattern, when_branch.guard.clone(), loc_expr.value));
}

View file

@ -329,6 +329,24 @@ pub enum RuntimeError {
EmptySingleQuote(Region),
/// where 'aa'
MultipleCharsInSingleQuote(Region),
DegenerateBranch(Region),
}
impl RuntimeError {
pub fn runtime_message(self) -> String {
use RuntimeError::*;
match self {
DegenerateBranch(region) => {
format!(
"Hit a branch pattern that does not bind all symbols its body needs, at {:?}",
region
)
}
err => format!("{:?}", err),
}
}
}
#[derive(Clone, Copy, Debug, PartialEq)]

View file

@ -3690,6 +3690,28 @@ fn symbol_not_bound_in_all_patterns_runs_when_bound_pattern_reached() {
"#
),
15u8,
u8
u8,
|x| x,
true // allow errors
);
}
#[test]
#[cfg(any(feature = "gen-llvm", feature = "gen-wasm"))]
#[should_panic(
expected = r#"Roc failed with message: "Hit a branch pattern that does not bind all symbols its body needs"#
)]
fn runtime_error_when_degenerate_pattern_reached() {
assert_evals_to!(
indoc!(
r#"
when B 15u8 is
A x | B y -> x + 5u8
"#
),
15u8,
u8,
|x| x,
true // allow errors
);
}

View file

@ -1899,6 +1899,14 @@ fn pretty_runtime_error<'b>(
title = OPAQUE_OVER_APPLIED;
}
RuntimeError::DegenerateBranch(region) => {
doc = alloc.stack([
alloc.reflow("This branch pattern does not bind all symbols its body needs:"),
alloc.region(lines.convert_region(region)),
]);
title = "DEGENERATE BRANCH";
}
}
(doc, title)