create and union fewer Output's

This commit is contained in:
Folkert 2022-04-20 21:20:59 +02:00
parent 9d17a075d9
commit e87ca7e4b7
No known key found for this signature in database
GPG key ID: 1F17F6FFD112B97C
3 changed files with 63 additions and 47 deletions

View file

@ -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

View file

@ -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);
} }

View file

@ -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