mirror of
https://github.com/roc-lang/roc.git
synced 2025-09-28 14:24:45 +00:00
make bound variables available in guards
This commit is contained in:
parent
1f3b8f7d68
commit
9a0234e5dd
3 changed files with 140 additions and 42 deletions
|
@ -1040,13 +1040,7 @@ fn from_can_when<'a>(
|
|||
for when_branch in branches {
|
||||
let mono_expr = from_can(env, when_branch.value.value, procs, None);
|
||||
|
||||
let mono_guard = if let Some(loc_guard) = when_branch.guard {
|
||||
Some(from_can(env, loc_guard.value, procs, None))
|
||||
} else {
|
||||
None
|
||||
};
|
||||
|
||||
let guard = if mono_guard.is_some() {
|
||||
let exhaustive_guard = if when_branch.guard.is_some() {
|
||||
Guard::HasGuard
|
||||
} else {
|
||||
Guard::NoGuard
|
||||
|
@ -1057,12 +1051,12 @@ fn from_can_when<'a>(
|
|||
|
||||
loc_branches.push((
|
||||
Located::at(loc_pattern.region, mono_pattern.clone()),
|
||||
guard.clone(),
|
||||
exhaustive_guard.clone(),
|
||||
));
|
||||
|
||||
let mut stores = Vec::with_capacity_in(1, env.arena);
|
||||
|
||||
let mono_expr = match store_pattern(
|
||||
let (mono_guard, expr_with_stores) = match store_pattern(
|
||||
env,
|
||||
&mono_pattern,
|
||||
cond_symbol,
|
||||
|
@ -1070,12 +1064,52 @@ fn from_can_when<'a>(
|
|||
&mut stores,
|
||||
) {
|
||||
Ok(_) => {
|
||||
Expr::Store(stores.into_bump_slice(), env.arena.alloc(mono_expr.clone()))
|
||||
// if the branch is guarded, the guard can use variables bound in the
|
||||
// pattern. They must be available, so we give the stores to the
|
||||
// decision_tree. A branch with guard can only be entered with the guard
|
||||
// evaluated, so variables will also be loaded in the branch's body expr.
|
||||
//
|
||||
// otherwise, we modify the branch's expression to include the stores
|
||||
if let Some(loc_guard) = when_branch.guard.clone() {
|
||||
let expr = from_can(env, loc_guard.value, procs, None);
|
||||
(
|
||||
crate::decision_tree::Guard::Guard {
|
||||
stores: stores.into_bump_slice(),
|
||||
expr,
|
||||
},
|
||||
mono_expr.clone(),
|
||||
)
|
||||
} else {
|
||||
(
|
||||
crate::decision_tree::Guard::NoGuard,
|
||||
Expr::Store(
|
||||
stores.into_bump_slice(),
|
||||
env.arena.alloc(mono_expr.clone()),
|
||||
),
|
||||
)
|
||||
}
|
||||
}
|
||||
Err(message) => {
|
||||
// when the pattern is invalid, a guard must give a runtime error too
|
||||
if when_branch.guard.is_some() {
|
||||
(
|
||||
crate::decision_tree::Guard::Guard {
|
||||
stores: &[],
|
||||
expr: Expr::RuntimeError(env.arena.alloc(message)),
|
||||
},
|
||||
// we can never hit this
|
||||
Expr::RuntimeError(&"invalid pattern with guard: unreachable"),
|
||||
)
|
||||
} else {
|
||||
(
|
||||
crate::decision_tree::Guard::NoGuard,
|
||||
Expr::RuntimeError(env.arena.alloc(message)),
|
||||
)
|
||||
}
|
||||
}
|
||||
Err(message) => Expr::RuntimeError(env.arena.alloc(message)),
|
||||
};
|
||||
|
||||
opt_branches.push((mono_pattern, mono_guard.clone(), mono_expr));
|
||||
opt_branches.push((mono_pattern, mono_guard, expr_with_stores));
|
||||
}
|
||||
}
|
||||
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue