mirror of
https://github.com/roc-lang/roc.git
synced 2025-09-29 14:54:47 +00:00
type inference for pattern guards
This commit is contained in:
parent
655dc32098
commit
920928399a
9 changed files with 230 additions and 57 deletions
|
@ -30,6 +30,19 @@ pub struct Output {
|
|||
pub aliases: SendMap<Symbol, Alias>,
|
||||
}
|
||||
|
||||
impl Output {
|
||||
pub fn union(&mut self, other: Self) {
|
||||
self.references.union_mut(other.references);
|
||||
|
||||
if let (None, Some(later)) = (self.tail_call, other.tail_call) {
|
||||
self.tail_call = Some(later);
|
||||
}
|
||||
|
||||
self.introduced_variables.union(&other.introduced_variables);
|
||||
self.aliases.extend(other.aliases);
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug, PartialEq)]
|
||||
pub enum Expr {
|
||||
// Literals
|
||||
|
@ -55,7 +68,7 @@ pub enum Expr {
|
|||
cond_var: Variable,
|
||||
expr_var: Variable,
|
||||
loc_cond: Box<Located<Expr>>,
|
||||
branches: Vec<(Located<Pattern>, Located<Expr>)>,
|
||||
branches: Vec<WhenBranch>,
|
||||
},
|
||||
If {
|
||||
cond_var: Variable,
|
||||
|
@ -145,6 +158,13 @@ pub enum Recursive {
|
|||
NotRecursive,
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug, PartialEq)]
|
||||
pub struct WhenBranch {
|
||||
pub patterns: Vec<Located<Pattern>>,
|
||||
pub value: Located<Expr>,
|
||||
pub guard: Option<Located<Expr>>,
|
||||
}
|
||||
|
||||
pub fn canonicalize_expr<'a>(
|
||||
env: &mut Env<'a>,
|
||||
var_store: &VarStore,
|
||||
|
@ -453,19 +473,12 @@ pub fn canonicalize_expr<'a>(
|
|||
let mut can_branches = Vec::with_capacity(branches.len());
|
||||
|
||||
for branch in branches {
|
||||
let (can_when_pattern, loc_can_expr, branch_references) = canonicalize_when_branch(
|
||||
env,
|
||||
var_store,
|
||||
scope,
|
||||
region,
|
||||
branch.patterns.first().unwrap(),
|
||||
&branch.value,
|
||||
&mut output,
|
||||
);
|
||||
let (can_when_branch, branch_references) =
|
||||
canonicalize_when_branch(env, var_store, scope, region, *branch, &mut output);
|
||||
|
||||
output.references = output.references.union(branch_references);
|
||||
|
||||
can_branches.push((can_when_pattern, loc_can_expr));
|
||||
can_branches.push(can_when_branch);
|
||||
}
|
||||
|
||||
// A "when" with no branches is a runtime error, but it will mess things up
|
||||
|
@ -654,6 +667,77 @@ pub fn canonicalize_expr<'a>(
|
|||
}
|
||||
|
||||
#[inline(always)]
|
||||
fn canonicalize_when_branch<'a>(
|
||||
env: &mut Env<'a>,
|
||||
var_store: &VarStore,
|
||||
scope: &mut Scope,
|
||||
region: Region,
|
||||
branch: &'a ast::WhenBranch<'a>,
|
||||
output: &mut Output,
|
||||
) -> (WhenBranch, References) {
|
||||
let mut patterns = Vec::with_capacity(branch.patterns.len());
|
||||
|
||||
let original_scope = scope;
|
||||
let mut scope = original_scope.clone();
|
||||
|
||||
// TODO report symbols not bound in all patterns
|
||||
for loc_pattern in &branch.patterns {
|
||||
patterns.push(canonicalize_pattern(
|
||||
env,
|
||||
var_store,
|
||||
&mut scope,
|
||||
WhenBranch,
|
||||
&loc_pattern.value,
|
||||
loc_pattern.region,
|
||||
));
|
||||
}
|
||||
|
||||
let (value, mut branch_output) = canonicalize_expr(
|
||||
env,
|
||||
var_store,
|
||||
&mut scope,
|
||||
branch.value.region,
|
||||
&branch.value.value,
|
||||
);
|
||||
|
||||
let guard = match &branch.guard {
|
||||
None => None,
|
||||
Some(loc_expr) => {
|
||||
let (can_guard, guard_branch_output) =
|
||||
canonicalize_expr(env, var_store, &mut scope, region, &loc_expr.value);
|
||||
|
||||
branch_output.union(guard_branch_output);
|
||||
Some(can_guard)
|
||||
}
|
||||
};
|
||||
|
||||
// Now that we've collected all the references for this branch, check to see if
|
||||
// any of the new idents it defined were unused. If any were, report it.
|
||||
for (symbol, region) in scope.symbols() {
|
||||
let symbol = *symbol;
|
||||
|
||||
if !output.references.has_lookup(symbol)
|
||||
&& !branch_output.references.has_lookup(symbol)
|
||||
&& !original_scope.contains_symbol(symbol)
|
||||
{
|
||||
env.problem(Problem::UnusedDef(symbol, *region));
|
||||
}
|
||||
}
|
||||
|
||||
let references = branch_output.references.clone();
|
||||
output.union(branch_output);
|
||||
|
||||
(
|
||||
WhenBranch {
|
||||
patterns,
|
||||
value,
|
||||
guard,
|
||||
},
|
||||
references,
|
||||
)
|
||||
}
|
||||
|
||||
/*
|
||||
fn canonicalize_when_branch<'a>(
|
||||
env: &mut Env<'a>,
|
||||
var_store: &VarStore,
|
||||
|
@ -702,6 +786,7 @@ fn canonicalize_when_branch<'a>(
|
|||
|
||||
(loc_can_pattern, can_expr, branch_output.references)
|
||||
}
|
||||
*/
|
||||
|
||||
pub fn local_successors<'a>(
|
||||
references: &'a References,
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue