Count default exprs as having used things

This commit is contained in:
Richard Feldman 2020-07-20 21:56:16 -04:00
parent 81a1111cae
commit 71f929aba2
3 changed files with 75 additions and 43 deletions

View file

@ -148,7 +148,7 @@ pub fn canonicalize_defs<'a>(
// Any time we have an Annotation followed immediately by a Body,
// check to see if their patterns are equivalent. If they are,
// turn it into a TypedBody. Otherwise, give an error.
let pending_def = match &loc_def.value {
let (new_output, pending_def) = match &loc_def.value {
Annotation(pattern, annotation) | Nested(Annotation(pattern, annotation)) => {
match iter.peek() {
Some(Located {
@ -189,6 +189,8 @@ pub fn canonicalize_defs<'a>(
_ => to_pending_def(env, var_store, &loc_def.value, &mut scope, pattern_type),
};
output.union(new_output);
// Record the ast::Expr for later. We'll do another pass through these
// once we have the entire scope assembled. If we were to canonicalize
// the exprs right now, they wouldn't have symbols in scope from defs
@ -212,8 +214,8 @@ pub fn canonicalize_defs<'a>(
let mut can_vars: Vec<Located<(Lowercase, Variable)>> =
Vec::with_capacity(vars.len());
let mut is_phantom = false;
for loc_lowercase in vars {
if let Some(var) = can_ann
.introduced_variables
@ -1288,13 +1290,13 @@ fn to_pending_def<'a>(
def: &'a ast::Def<'a>,
scope: &mut Scope,
pattern_type: PatternType,
) -> PendingDef<'a> {
) -> (Output, PendingDef<'a>) {
use roc_parse::ast::Def::*;
match def {
Annotation(loc_pattern, loc_ann) => {
// This takes care of checking for shadowing and adding idents to scope.
let loc_can_pattern = canonicalize_pattern(
let (output, loc_can_pattern) = canonicalize_pattern(
env,
var_store,
scope,
@ -1303,11 +1305,14 @@ fn to_pending_def<'a>(
loc_pattern.region,
);
PendingDef::AnnotationOnly(loc_pattern, loc_can_pattern, loc_ann)
(
output,
PendingDef::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 loc_can_pattern = canonicalize_pattern(
let (output, loc_can_pattern) = canonicalize_pattern(
env,
var_store,
scope,
@ -1316,7 +1321,10 @@ fn to_pending_def<'a>(
loc_pattern.region,
);
PendingDef::Body(loc_pattern, loc_can_pattern, loc_expr)
(
output,
PendingDef::Body(loc_pattern, loc_can_pattern, loc_expr),
)
}
TypedBody(loc_pattern, loc_ann, loc_expr) => pending_typed_body(
env,
@ -1358,19 +1366,22 @@ fn to_pending_def<'a>(
region: loc_var.region,
});
return PendingDef::InvalidAlias;
return (Output::default(), PendingDef::InvalidAlias);
}
}
}
PendingDef::Alias {
name: Located {
region: name.region,
value: symbol,
(
Output::default(),
PendingDef::Alias {
name: Located {
region: name.region,
value: symbol,
},
vars: can_rigids,
ann,
},
vars: can_rigids,
ann,
}
)
}
Err((original_region, loc_shadowed_symbol)) => {
@ -1379,7 +1390,7 @@ fn to_pending_def<'a>(
shadow: loc_shadowed_symbol,
});
PendingDef::InvalidAlias
(Output::default(), PendingDef::InvalidAlias)
}
}
}
@ -1398,9 +1409,9 @@ fn pending_typed_body<'a>(
var_store: &mut VarStore,
scope: &mut Scope,
pattern_type: PatternType,
) -> PendingDef<'a> {
) -> (Output, PendingDef<'a>) {
// This takes care of checking for shadowing and adding idents to scope.
let loc_can_pattern = canonicalize_pattern(
let (output, loc_can_pattern) = canonicalize_pattern(
env,
var_store,
scope,
@ -1409,7 +1420,10 @@ fn pending_typed_body<'a>(
loc_pattern.region,
);
PendingDef::TypedBody(loc_pattern, loc_can_pattern, loc_ann, loc_expr)
(
output,
PendingDef::TypedBody(loc_pattern, loc_can_pattern, loc_ann, loc_expr),
)
}
/// Make aliases recursive

View file

@ -427,9 +427,10 @@ pub fn canonicalize_expr<'a>(
let original_scope = scope;
let mut scope = original_scope.clone();
let mut can_args = Vec::with_capacity(loc_arg_patterns.len());
let mut output = Output::default();
for loc_pattern in loc_arg_patterns.into_iter() {
let can_arg = canonicalize_pattern(
let (new_output, can_arg) = canonicalize_pattern(
env,
var_store,
&mut scope,
@ -438,16 +439,21 @@ pub fn canonicalize_expr<'a>(
loc_pattern.region,
);
output.union(new_output);
can_args.push((var_store.fresh(), can_arg));
}
let (loc_body_expr, mut output) = canonicalize_expr(
let (loc_body_expr, new_output) = canonicalize_expr(
env,
var_store,
&mut scope,
loc_body_expr.region,
&loc_body_expr.value,
);
output.union(new_output);
// Now that we've collected all the references, check to see if any of the args we defined
// went unreferenced. If any did, report them as unused arguments.
for (sub_symbol, region) in scope.symbols() {
@ -713,14 +719,18 @@ fn canonicalize_when_branch<'a>(
// TODO report symbols not bound in all patterns
for loc_pattern in &branch.patterns {
patterns.push(canonicalize_pattern(
let (new_output, can_pattern) = canonicalize_pattern(
env,
var_store,
&mut scope,
WhenBranch,
&loc_pattern.value,
loc_pattern.region,
));
);
output.union(new_output);
patterns.push(can_pattern);
}
let (value, mut branch_output) = canonicalize_expr(

View file

@ -1,5 +1,5 @@
use crate::env::Env;
use crate::expr::{canonicalize_expr, Expr};
use crate::expr::{canonicalize_expr, Expr, Output};
use crate::num::{finish_parsing_base, finish_parsing_float, finish_parsing_int};
use crate::scope::Scope;
use roc_module::ident::{Ident, Lowercase, TagName};
@ -100,10 +100,11 @@ pub fn canonicalize_pattern<'a>(
pattern_type: PatternType,
pattern: &ast::Pattern<'a>,
region: Region,
) -> Located<Pattern> {
) -> (Output, Located<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(),
@ -154,17 +155,18 @@ pub fn canonicalize_pattern<'a>(
let mut can_patterns = Vec::with_capacity(patterns.len());
for loc_pattern in *patterns {
can_patterns.push((
var_store.fresh(),
canonicalize_pattern(
env,
var_store,
scope,
pattern_type,
&loc_pattern.value,
loc_pattern.region,
),
));
let (new_output, can_pattern) = canonicalize_pattern(
env,
var_store,
scope,
pattern_type,
&loc_pattern.value,
loc_pattern.region,
);
output.union(new_output);
can_patterns.push((var_store.fresh(), can_pattern));
}
Pattern::AppliedTag {
@ -283,7 +285,7 @@ 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 can_guard = canonicalize_pattern(
let (new_output, can_guard) = canonicalize_pattern(
env,
var_store,
scope,
@ -292,6 +294,8 @@ pub fn canonicalize_pattern<'a>(
loc_guard.region,
);
output.union(new_output);
destructs.push(Located {
region: loc_pattern.region,
value: RecordDestruct {
@ -311,8 +315,7 @@ pub fn canonicalize_pattern<'a>(
region,
) {
Ok(symbol) => {
// TODO use output?
let (can_default, _output) = canonicalize_expr(
let (can_default, expr_output) = canonicalize_expr(
env,
var_store,
scope,
@ -320,6 +323,8 @@ pub fn canonicalize_pattern<'a>(
&loc_default.value,
);
output.union(expr_output);
destructs.push(Located {
region: loc_pattern.region,
value: RecordDestruct {
@ -375,10 +380,13 @@ pub fn canonicalize_pattern<'a>(
}
};
Located {
region,
value: can_pattern,
}
(
output,
Located {
region,
value: can_pattern,
},
)
}
/// When we detect an unsupported pattern type (e.g. 5 = 1 + 2 is unsupported because you can't