feat(aiken-lang): anonymous functions
@MartinSchere noticed a weird error where an unknown variable wasn't being reported the type checker was incorrectly scoping arguments for anonymous function definitions. Luckily his compilation failed due to a FreeUnique error during code gen which is good. But this may have been the source of other mysterious FreeUnique errors. I also noticed that anonymous function allowed arguments with the same name to be defined. `fn(arg, arg)` This now returns an error.
This commit is contained in:
parent
20edce2146
commit
98c61ca151
|
@ -1,5 +1,12 @@
|
|||
# Changelog
|
||||
|
||||
## [next] - 2023-MM-DD
|
||||
|
||||
### Fixed
|
||||
|
||||
- **aiken-lang**: incorrect scoping for anonymous functions
|
||||
- **aiken-lang**: duplicate arguments were allowed in anonymous functions
|
||||
|
||||
## v1.0.0-alpha - 2023-04-13
|
||||
|
||||
### Added
|
||||
|
|
|
@ -154,6 +154,56 @@ fn multi_validator_warning() {
|
|||
))
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn anonymous_function_scoping() {
|
||||
let source_code = r#"
|
||||
fn reduce(list, f, i) {
|
||||
todo
|
||||
}
|
||||
|
||||
pub fn foo() {
|
||||
let sum =
|
||||
reduce(
|
||||
[1, 2, 3],
|
||||
fn(acc: Int, n: Int) { acc + n },
|
||||
0,
|
||||
)
|
||||
|
||||
sum + acc
|
||||
}
|
||||
"#;
|
||||
|
||||
assert!(matches!(
|
||||
check(parse(source_code)),
|
||||
Err((_, Error::UnknownVariable { name, .. })) if name == "acc"
|
||||
))
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn anonymous_function_dupicate_args() {
|
||||
let source_code = r#"
|
||||
fn reduce(list, f, i) {
|
||||
todo
|
||||
}
|
||||
|
||||
pub fn foo() {
|
||||
let sum =
|
||||
reduce(
|
||||
[1, 2, 3],
|
||||
fn(acc: Int, acc: Int) { acc + acc },
|
||||
0,
|
||||
)
|
||||
|
||||
sum
|
||||
}
|
||||
"#;
|
||||
|
||||
assert!(matches!(
|
||||
check(parse(source_code)),
|
||||
Err((_, Error::DuplicateArgument { label, .. })) if label == "acc"
|
||||
))
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn if_scoping() {
|
||||
let source_code = r#"
|
||||
|
|
|
@ -1480,32 +1480,45 @@ impl<'a, 'b> ExprTyper<'a, 'b> {
|
|||
) -> Result<(Vec<TypedArg>, TypedExpr), Error> {
|
||||
self.assert_no_assignment(&body)?;
|
||||
|
||||
for arg in &args {
|
||||
match &arg.arg_name {
|
||||
ArgName::Named {
|
||||
name,
|
||||
is_validator_param,
|
||||
..
|
||||
} if !is_validator_param => {
|
||||
self.environment.insert_variable(
|
||||
name.to_string(),
|
||||
ValueConstructorVariant::LocalVariable {
|
||||
location: arg.location,
|
||||
},
|
||||
arg.tipo.clone(),
|
||||
);
|
||||
let (body_rigid_names, body_infer) = self.in_new_scope(|body_typer| {
|
||||
let mut argument_names = HashMap::with_capacity(args.len());
|
||||
|
||||
self.environment.init_usage(
|
||||
name.to_string(),
|
||||
EntityKind::Variable,
|
||||
arg.location,
|
||||
);
|
||||
}
|
||||
ArgName::Named { .. } | ArgName::Discarded { .. } => (),
|
||||
};
|
||||
}
|
||||
for arg in &args {
|
||||
match &arg.arg_name {
|
||||
ArgName::Named {
|
||||
name,
|
||||
is_validator_param,
|
||||
location,
|
||||
..
|
||||
} if !is_validator_param => {
|
||||
if let Some(duplicate_location) = argument_names.insert(name, location) {
|
||||
return Err(Error::DuplicateArgument {
|
||||
location: *location,
|
||||
duplicate_location: *duplicate_location,
|
||||
label: name.to_string(),
|
||||
});
|
||||
}
|
||||
|
||||
let (body_rigid_names, body_infer) = (self.hydrator.rigid_names(), self.infer(body));
|
||||
body_typer.environment.insert_variable(
|
||||
name.to_string(),
|
||||
ValueConstructorVariant::LocalVariable {
|
||||
location: arg.location,
|
||||
},
|
||||
arg.tipo.clone(),
|
||||
);
|
||||
|
||||
body_typer.environment.init_usage(
|
||||
name.to_string(),
|
||||
EntityKind::Variable,
|
||||
arg.location,
|
||||
);
|
||||
}
|
||||
ArgName::Named { .. } | ArgName::Discarded { .. } => (),
|
||||
};
|
||||
}
|
||||
|
||||
Ok((body_typer.hydrator.rigid_names(), body_typer.infer(body)))
|
||||
})?;
|
||||
|
||||
let body = body_infer.map_err(|e| e.with_unify_error_rigid_names(&body_rigid_names))?;
|
||||
|
||||
|
|
Loading…
Reference in New Issue