mirror of
https://github.com/roc-lang/roc.git
synced 2025-10-03 00:24:34 +00:00
create and union fewer Output's
This commit is contained in:
parent
9d17a075d9
commit
e87ca7e4b7
3 changed files with 63 additions and 47 deletions
|
@ -564,9 +564,17 @@ pub fn canonicalize_defs<'a>(
|
||||||
// once we've finished assembling the entire scope.
|
// once we've finished assembling the entire scope.
|
||||||
let mut pending_value_defs = Vec::with_capacity(value_defs.len());
|
let mut pending_value_defs = Vec::with_capacity(value_defs.len());
|
||||||
for loc_def in value_defs.into_iter() {
|
for loc_def in value_defs.into_iter() {
|
||||||
match to_pending_value_def(env, var_store, loc_def.value, &mut scope, pattern_type) {
|
let mut new_output = Output::default();
|
||||||
|
match to_pending_value_def(
|
||||||
|
env,
|
||||||
|
var_store,
|
||||||
|
loc_def.value,
|
||||||
|
&mut scope,
|
||||||
|
&mut new_output,
|
||||||
|
pattern_type,
|
||||||
|
) {
|
||||||
None => { /* skip */ }
|
None => { /* skip */ }
|
||||||
Some((new_output, pending_def)) => {
|
Some(pending_def) => {
|
||||||
// store the top-level defs, used to ensure that closures won't capture them
|
// store the top-level defs, used to ensure that closures won't capture them
|
||||||
if let PatternType::TopLevelDef = pattern_type {
|
if let PatternType::TopLevelDef = pattern_type {
|
||||||
match &pending_def {
|
match &pending_def {
|
||||||
|
@ -1806,41 +1814,46 @@ fn to_pending_value_def<'a>(
|
||||||
var_store: &mut VarStore,
|
var_store: &mut VarStore,
|
||||||
def: &'a ast::ValueDef<'a>,
|
def: &'a ast::ValueDef<'a>,
|
||||||
scope: &mut Scope,
|
scope: &mut Scope,
|
||||||
|
output: &mut Output,
|
||||||
pattern_type: PatternType,
|
pattern_type: PatternType,
|
||||||
) -> Option<(Output, PendingValueDef<'a>)> {
|
) -> Option<PendingValueDef<'a>> {
|
||||||
use ast::ValueDef::*;
|
use ast::ValueDef::*;
|
||||||
|
|
||||||
match def {
|
match def {
|
||||||
Annotation(loc_pattern, loc_ann) => {
|
Annotation(loc_pattern, loc_ann) => {
|
||||||
// This takes care of checking for shadowing and adding idents to scope.
|
// This takes care of checking for shadowing and adding idents to scope.
|
||||||
let (output, loc_can_pattern) = canonicalize_def_header_pattern(
|
let loc_can_pattern = canonicalize_def_header_pattern(
|
||||||
env,
|
env,
|
||||||
var_store,
|
var_store,
|
||||||
scope,
|
scope,
|
||||||
|
output,
|
||||||
pattern_type,
|
pattern_type,
|
||||||
&loc_pattern.value,
|
&loc_pattern.value,
|
||||||
loc_pattern.region,
|
loc_pattern.region,
|
||||||
);
|
);
|
||||||
|
|
||||||
Some((
|
Some(PendingValueDef::AnnotationOnly(
|
||||||
output,
|
loc_pattern,
|
||||||
PendingValueDef::AnnotationOnly(loc_pattern, loc_can_pattern, loc_ann),
|
loc_can_pattern,
|
||||||
|
loc_ann,
|
||||||
))
|
))
|
||||||
}
|
}
|
||||||
Body(loc_pattern, loc_expr) => {
|
Body(loc_pattern, loc_expr) => {
|
||||||
// This takes care of checking for shadowing and adding idents to scope.
|
// This takes care of checking for shadowing and adding idents to scope.
|
||||||
let (output, loc_can_pattern) = canonicalize_def_header_pattern(
|
let loc_can_pattern = canonicalize_def_header_pattern(
|
||||||
env,
|
env,
|
||||||
var_store,
|
var_store,
|
||||||
scope,
|
scope,
|
||||||
|
output,
|
||||||
pattern_type,
|
pattern_type,
|
||||||
&loc_pattern.value,
|
&loc_pattern.value,
|
||||||
loc_pattern.region,
|
loc_pattern.region,
|
||||||
);
|
);
|
||||||
|
|
||||||
Some((
|
Some(PendingValueDef::Body(
|
||||||
output,
|
loc_pattern,
|
||||||
PendingValueDef::Body(loc_pattern, loc_can_pattern, loc_expr),
|
loc_can_pattern,
|
||||||
|
loc_expr,
|
||||||
))
|
))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1859,18 +1872,21 @@ fn to_pending_value_def<'a>(
|
||||||
// { x, y ? False } = rec
|
// { x, y ? False } = rec
|
||||||
//
|
//
|
||||||
// This takes care of checking for shadowing and adding idents to scope.
|
// This takes care of checking for shadowing and adding idents to scope.
|
||||||
let (output, loc_can_pattern) = canonicalize_def_header_pattern(
|
let loc_can_pattern = canonicalize_def_header_pattern(
|
||||||
env,
|
env,
|
||||||
var_store,
|
var_store,
|
||||||
scope,
|
scope,
|
||||||
|
output,
|
||||||
pattern_type,
|
pattern_type,
|
||||||
&body_pattern.value,
|
&body_pattern.value,
|
||||||
body_pattern.region,
|
body_pattern.region,
|
||||||
);
|
);
|
||||||
|
|
||||||
Some((
|
Some(PendingValueDef::TypedBody(
|
||||||
output,
|
body_pattern,
|
||||||
PendingValueDef::TypedBody(body_pattern, loc_can_pattern, ann_type, body_expr),
|
loc_can_pattern,
|
||||||
|
ann_type,
|
||||||
|
body_expr,
|
||||||
))
|
))
|
||||||
} else {
|
} else {
|
||||||
// the pattern of the annotation does not match the pattern of the body direc
|
// the pattern of the annotation does not match the pattern of the body direc
|
||||||
|
|
|
@ -627,25 +627,23 @@ pub fn canonicalize_expr<'a>(
|
||||||
let mut can_args = Vec::with_capacity(loc_arg_patterns.len());
|
let mut can_args = Vec::with_capacity(loc_arg_patterns.len());
|
||||||
let mut output = Output::default();
|
let mut output = Output::default();
|
||||||
|
|
||||||
let mut bound_by_argument_patterns = MutSet::default();
|
|
||||||
|
|
||||||
for loc_pattern in loc_arg_patterns.iter() {
|
for loc_pattern in loc_arg_patterns.iter() {
|
||||||
let (new_output, can_arg) = canonicalize_pattern(
|
let can_argument_pattern = canonicalize_pattern(
|
||||||
env,
|
env,
|
||||||
var_store,
|
var_store,
|
||||||
&mut scope,
|
&mut scope,
|
||||||
|
&mut output,
|
||||||
FunctionArg,
|
FunctionArg,
|
||||||
&loc_pattern.value,
|
&loc_pattern.value,
|
||||||
loc_pattern.region,
|
loc_pattern.region,
|
||||||
);
|
);
|
||||||
|
|
||||||
bound_by_argument_patterns.extend(new_output.references.bound_symbols().copied());
|
can_args.push((var_store.fresh(), can_argument_pattern));
|
||||||
|
|
||||||
output.union(new_output);
|
|
||||||
|
|
||||||
can_args.push((var_store.fresh(), can_arg));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
let bound_by_argument_patterns: Vec<_> =
|
||||||
|
output.references.bound_symbols().copied().collect();
|
||||||
|
|
||||||
let (loc_body_expr, new_output) = canonicalize_expr(
|
let (loc_body_expr, new_output) = canonicalize_expr(
|
||||||
env,
|
env,
|
||||||
var_store,
|
var_store,
|
||||||
|
@ -1034,17 +1032,16 @@ fn canonicalize_when_branch<'a>(
|
||||||
|
|
||||||
// TODO report symbols not bound in all patterns
|
// TODO report symbols not bound in all patterns
|
||||||
for loc_pattern in branch.patterns.iter() {
|
for loc_pattern in branch.patterns.iter() {
|
||||||
let (new_output, can_pattern) = canonicalize_pattern(
|
let can_pattern = canonicalize_pattern(
|
||||||
env,
|
env,
|
||||||
var_store,
|
var_store,
|
||||||
&mut scope,
|
&mut scope,
|
||||||
|
output,
|
||||||
WhenBranch,
|
WhenBranch,
|
||||||
&loc_pattern.value,
|
&loc_pattern.value,
|
||||||
loc_pattern.region,
|
loc_pattern.region,
|
||||||
);
|
);
|
||||||
|
|
||||||
output.union(new_output);
|
|
||||||
|
|
||||||
patterns.push(can_pattern);
|
patterns.push(can_pattern);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -156,13 +156,13 @@ pub fn canonicalize_def_header_pattern<'a>(
|
||||||
env: &mut Env<'a>,
|
env: &mut Env<'a>,
|
||||||
var_store: &mut VarStore,
|
var_store: &mut VarStore,
|
||||||
scope: &mut Scope,
|
scope: &mut Scope,
|
||||||
|
output: &mut Output,
|
||||||
pattern_type: PatternType,
|
pattern_type: PatternType,
|
||||||
pattern: &ast::Pattern<'a>,
|
pattern: &ast::Pattern<'a>,
|
||||||
region: Region,
|
region: Region,
|
||||||
) -> (Output, Loc<Pattern>) {
|
) -> Loc<Pattern> {
|
||||||
use roc_parse::ast::Pattern::*;
|
use roc_parse::ast::Pattern::*;
|
||||||
|
|
||||||
let mut output = Output::default();
|
|
||||||
match pattern {
|
match pattern {
|
||||||
// Identifiers that shadow ability members may appear (and may only appear) at the header of a def.
|
// Identifiers that shadow ability members may appear (and may only appear) at the header of a def.
|
||||||
Identifier(name) => match scope.introduce_or_shadow_ability_member(
|
Identifier(name) => match scope.introduce_or_shadow_ability_member(
|
||||||
|
@ -182,7 +182,7 @@ pub fn canonicalize_def_header_pattern<'a>(
|
||||||
specializes: ability_member_name,
|
specializes: ability_member_name,
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
(output, Loc::at(region, can_pattern))
|
Loc::at(region, can_pattern)
|
||||||
}
|
}
|
||||||
Err((original_region, shadow, new_symbol)) => {
|
Err((original_region, shadow, new_symbol)) => {
|
||||||
env.problem(Problem::RuntimeError(RuntimeError::Shadowing {
|
env.problem(Problem::RuntimeError(RuntimeError::Shadowing {
|
||||||
|
@ -193,10 +193,10 @@ pub fn canonicalize_def_header_pattern<'a>(
|
||||||
output.references.insert_bound(new_symbol);
|
output.references.insert_bound(new_symbol);
|
||||||
|
|
||||||
let can_pattern = Pattern::Shadowed(original_region, shadow, new_symbol);
|
let can_pattern = Pattern::Shadowed(original_region, shadow, new_symbol);
|
||||||
(output, Loc::at(region, can_pattern))
|
Loc::at(region, can_pattern)
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
_ => canonicalize_pattern(env, var_store, scope, pattern_type, pattern, region),
|
_ => canonicalize_pattern(env, var_store, scope, output, pattern_type, pattern, region),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -204,14 +204,14 @@ pub fn canonicalize_pattern<'a>(
|
||||||
env: &mut Env<'a>,
|
env: &mut Env<'a>,
|
||||||
var_store: &mut VarStore,
|
var_store: &mut VarStore,
|
||||||
scope: &mut Scope,
|
scope: &mut Scope,
|
||||||
|
output: &mut Output,
|
||||||
pattern_type: PatternType,
|
pattern_type: PatternType,
|
||||||
pattern: &ast::Pattern<'a>,
|
pattern: &ast::Pattern<'a>,
|
||||||
region: Region,
|
region: Region,
|
||||||
) -> (Output, Loc<Pattern>) {
|
) -> Loc<Pattern> {
|
||||||
use roc_parse::ast::Pattern::*;
|
use roc_parse::ast::Pattern::*;
|
||||||
use PatternType::*;
|
use PatternType::*;
|
||||||
|
|
||||||
let mut output = Output::default();
|
|
||||||
let can_pattern = match pattern {
|
let can_pattern = match pattern {
|
||||||
Identifier(name) => match scope.introduce(
|
Identifier(name) => match scope.introduce(
|
||||||
(*name).into(),
|
(*name).into(),
|
||||||
|
@ -266,17 +266,16 @@ pub fn canonicalize_pattern<'a>(
|
||||||
Apply(tag, patterns) => {
|
Apply(tag, patterns) => {
|
||||||
let mut can_patterns = Vec::with_capacity(patterns.len());
|
let mut can_patterns = Vec::with_capacity(patterns.len());
|
||||||
for loc_pattern in *patterns {
|
for loc_pattern in *patterns {
|
||||||
let (new_output, can_pattern) = canonicalize_pattern(
|
let can_pattern = canonicalize_pattern(
|
||||||
env,
|
env,
|
||||||
var_store,
|
var_store,
|
||||||
scope,
|
scope,
|
||||||
|
output,
|
||||||
pattern_type,
|
pattern_type,
|
||||||
&loc_pattern.value,
|
&loc_pattern.value,
|
||||||
loc_pattern.region,
|
loc_pattern.region,
|
||||||
);
|
);
|
||||||
|
|
||||||
output.union(new_output);
|
|
||||||
|
|
||||||
can_patterns.push((var_store.fresh(), can_pattern));
|
can_patterns.push((var_store.fresh(), can_pattern));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -442,7 +441,15 @@ pub fn canonicalize_pattern<'a>(
|
||||||
}
|
}
|
||||||
|
|
||||||
SpaceBefore(sub_pattern, _) | SpaceAfter(sub_pattern, _) => {
|
SpaceBefore(sub_pattern, _) | SpaceAfter(sub_pattern, _) => {
|
||||||
return canonicalize_pattern(env, var_store, scope, pattern_type, sub_pattern, region)
|
return canonicalize_pattern(
|
||||||
|
env,
|
||||||
|
var_store,
|
||||||
|
scope,
|
||||||
|
output,
|
||||||
|
pattern_type,
|
||||||
|
sub_pattern,
|
||||||
|
region,
|
||||||
|
)
|
||||||
}
|
}
|
||||||
RecordDestructure(patterns) => {
|
RecordDestructure(patterns) => {
|
||||||
let ext_var = var_store.fresh();
|
let ext_var = var_store.fresh();
|
||||||
|
@ -492,17 +499,16 @@ pub fn canonicalize_pattern<'a>(
|
||||||
RequiredField(label, loc_guard) => {
|
RequiredField(label, loc_guard) => {
|
||||||
// a guard does not introduce the label into scope!
|
// a guard does not introduce the label into scope!
|
||||||
let symbol = scope.ignore(label.into(), &mut env.ident_ids);
|
let symbol = scope.ignore(label.into(), &mut env.ident_ids);
|
||||||
let (new_output, can_guard) = canonicalize_pattern(
|
let can_guard = canonicalize_pattern(
|
||||||
env,
|
env,
|
||||||
var_store,
|
var_store,
|
||||||
scope,
|
scope,
|
||||||
|
output,
|
||||||
pattern_type,
|
pattern_type,
|
||||||
&loc_guard.value,
|
&loc_guard.value,
|
||||||
loc_guard.region,
|
loc_guard.region,
|
||||||
);
|
);
|
||||||
|
|
||||||
output.union(new_output);
|
|
||||||
|
|
||||||
destructs.push(Loc {
|
destructs.push(Loc {
|
||||||
region: loc_pattern.region,
|
region: loc_pattern.region,
|
||||||
value: RecordDestruct {
|
value: RecordDestruct {
|
||||||
|
@ -597,13 +603,10 @@ pub fn canonicalize_pattern<'a>(
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
(
|
|
||||||
output,
|
|
||||||
Loc {
|
Loc {
|
||||||
region,
|
region,
|
||||||
value: can_pattern,
|
value: can_pattern,
|
||||||
},
|
}
|
||||||
)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// When we detect an unsupported pattern type (e.g. 5 = 1 + 2 is unsupported because you can't
|
/// When we detect an unsupported pattern type (e.g. 5 = 1 + 2 is unsupported because you can't
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue