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.
let mut pending_value_defs = Vec::with_capacity(value_defs.len());
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 */ }
Some((new_output, pending_def)) => {
Some(pending_def) => {
// store the top-level defs, used to ensure that closures won't capture them
if let PatternType::TopLevelDef = pattern_type {
match &pending_def {
@ -1806,41 +1814,46 @@ fn to_pending_value_def<'a>(
var_store: &mut VarStore,
def: &'a ast::ValueDef<'a>,
scope: &mut Scope,
output: &mut Output,
pattern_type: PatternType,
) -> Option<(Output, PendingValueDef<'a>)> {
) -> Option<PendingValueDef<'a>> {
use ast::ValueDef::*;
match def {
Annotation(loc_pattern, loc_ann) => {
// 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,
var_store,
scope,
output,
pattern_type,
&loc_pattern.value,
loc_pattern.region,
);
Some((
output,
PendingValueDef::AnnotationOnly(loc_pattern, loc_can_pattern, loc_ann),
Some(PendingValueDef::AnnotationOnly(
loc_pattern,
loc_can_pattern,
loc_ann,
))
}
Body(loc_pattern, loc_expr) => {
// 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,
var_store,
scope,
output,
pattern_type,
&loc_pattern.value,
loc_pattern.region,
);
Some((
output,
PendingValueDef::Body(loc_pattern, loc_can_pattern, loc_expr),
Some(PendingValueDef::Body(
loc_pattern,
loc_can_pattern,
loc_expr,
))
}
@ -1859,18 +1872,21 @@ fn to_pending_value_def<'a>(
// { x, y ? False } = rec
//
// 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,
var_store,
scope,
output,
pattern_type,
&body_pattern.value,
body_pattern.region,
);
Some((
output,
PendingValueDef::TypedBody(body_pattern, loc_can_pattern, ann_type, body_expr),
Some(PendingValueDef::TypedBody(
body_pattern,
loc_can_pattern,
ann_type,
body_expr,
))
} else {
// 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 output = Output::default();
let mut bound_by_argument_patterns = MutSet::default();
for loc_pattern in loc_arg_patterns.iter() {
let (new_output, can_arg) = canonicalize_pattern(
let can_argument_pattern = canonicalize_pattern(
env,
var_store,
&mut scope,
&mut output,
FunctionArg,
&loc_pattern.value,
loc_pattern.region,
);
bound_by_argument_patterns.extend(new_output.references.bound_symbols().copied());
output.union(new_output);
can_args.push((var_store.fresh(), can_arg));
can_args.push((var_store.fresh(), can_argument_pattern));
}
let bound_by_argument_patterns: Vec<_> =
output.references.bound_symbols().copied().collect();
let (loc_body_expr, new_output) = canonicalize_expr(
env,
var_store,
@ -1034,17 +1032,16 @@ fn canonicalize_when_branch<'a>(
// TODO report symbols not bound in all patterns
for loc_pattern in branch.patterns.iter() {
let (new_output, can_pattern) = canonicalize_pattern(
let can_pattern = canonicalize_pattern(
env,
var_store,
&mut scope,
output,
WhenBranch,
&loc_pattern.value,
loc_pattern.region,
);
output.union(new_output);
patterns.push(can_pattern);
}

View file

@ -156,13 +156,13 @@ pub fn canonicalize_def_header_pattern<'a>(
env: &mut Env<'a>,
var_store: &mut VarStore,
scope: &mut Scope,
output: &mut Output,
pattern_type: PatternType,
pattern: &ast::Pattern<'a>,
region: Region,
) -> (Output, Loc<Pattern>) {
) -> Loc<Pattern> {
use roc_parse::ast::Pattern::*;
let mut output = Output::default();
match pattern {
// 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(
@ -182,7 +182,7 @@ pub fn canonicalize_def_header_pattern<'a>(
specializes: ability_member_name,
},
};
(output, Loc::at(region, can_pattern))
Loc::at(region, can_pattern)
}
Err((original_region, shadow, new_symbol)) => {
env.problem(Problem::RuntimeError(RuntimeError::Shadowing {
@ -193,10 +193,10 @@ pub fn canonicalize_def_header_pattern<'a>(
output.references.insert_bound(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>,
var_store: &mut VarStore,
scope: &mut Scope,
output: &mut Output,
pattern_type: PatternType,
pattern: &ast::Pattern<'a>,
region: Region,
) -> (Output, Loc<Pattern>) {
) -> Loc<Pattern> {
use roc_parse::ast::Pattern::*;
use PatternType::*;
let mut output = Output::default();
let can_pattern = match pattern {
Identifier(name) => match scope.introduce(
(*name).into(),
@ -266,17 +266,16 @@ pub fn canonicalize_pattern<'a>(
Apply(tag, patterns) => {
let mut can_patterns = Vec::with_capacity(patterns.len());
for loc_pattern in *patterns {
let (new_output, can_pattern) = canonicalize_pattern(
let can_pattern = canonicalize_pattern(
env,
var_store,
scope,
output,
pattern_type,
&loc_pattern.value,
loc_pattern.region,
);
output.union(new_output);
can_patterns.push((var_store.fresh(), can_pattern));
}
@ -442,7 +441,15 @@ pub fn canonicalize_pattern<'a>(
}
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) => {
let ext_var = var_store.fresh();
@ -492,17 +499,16 @@ pub fn canonicalize_pattern<'a>(
RequiredField(label, loc_guard) => {
// a guard does not introduce the label into scope!
let symbol = scope.ignore(label.into(), &mut env.ident_ids);
let (new_output, can_guard) = canonicalize_pattern(
let can_guard = canonicalize_pattern(
env,
var_store,
scope,
output,
pattern_type,
&loc_guard.value,
loc_guard.region,
);
output.union(new_output);
destructs.push(Loc {
region: loc_pattern.region,
value: RecordDestruct {
@ -597,13 +603,10 @@ pub fn canonicalize_pattern<'a>(
}
};
(
output,
Loc {
region,
value: can_pattern,
},
)
}
}
/// When we detect an unsupported pattern type (e.g. 5 = 1 + 2 is unsupported because you can't