feat(backpassing): implements multi patterns

The main trick here was transforming Assignment
to contain `Vec<UntypedPattern, Option<Annotation>>`
in a field called patterns. This then meant that I
could remove the `pattern` and `annotation` field
from `Assignment`. The parser handles `=` and `<-`
just fine because in the future `=` with multi
patterns will mean some kind of optimization on tuples.
But, since we don't have that optimization yet, when
someone uses multi patterns with an `=` there will be an
error returned from the type checker right where `infer_seq`
looks for `backpassing`. From there the rest of the work
was in `Project::backpassing` where I only needed to rework
some things to work with a list of patterns instead of just one.
This commit is contained in:
rvcas
2024-03-11 18:23:17 -04:00
committed by Lucas
parent f02b9b0f0c
commit b6b52ba508
26 changed files with 592 additions and 292 deletions

View File

@@ -1383,6 +1383,74 @@ fn backpassing_expect_type_mismatch() {
))
}
#[test]
fn backpassing_multi_args() {
let source_code = r#"
fn fold(list: List<a>, init: b, then: fn(a, b) -> b) -> b {
when list is {
[] -> init
[x, ..rest] -> fold(rest, then(x, init), then)
}
}
fn backpassing() -> Int {
let elem, acc <- fold([1, 2, 3], 0)
elem + acc
}
"#;
assert!(check(parse(source_code)).is_ok())
}
#[test]
fn backpassing_multi_args_expect() {
let source_code = r#"
pub type Bar {
Foo(Int)
Wow(Int)
}
fn fold(list: List<a>, init: b, then: fn(a, b) -> b) -> b {
when list is {
[] -> init
[x, ..rest] -> fold(rest, then(x, init), then)
}
}
pub fn backpassing() -> Bar {
expect Foo(elem), Wow(acc) <- fold([Foo(1), Foo(2), Foo(3)], Wow(0))
Wow(elem + acc)
}
"#;
assert!(matches!(check(parse(source_code)), Ok((warnings, _)) if warnings.is_empty()))
}
#[test]
fn backpassing_multi_args_using_equals() {
let source_code = r#"
fn fold(list: List<a>, init: b, then: fn(a, b) -> b) -> b {
when list is {
[] -> init
[x, ..rest] -> fold(rest, then(x, init), then)
}
}
fn backpassing() -> Int {
let elem, acc = fold([1, 2, 3], 0, fn(elem, acc) { elem + acc })
elem + acc
}
"#;
assert!(matches!(
check(parse(source_code)),
Err((_, Error::UnexpectedMultiPatternAssignment { .. }))
))
}
#[test]
fn trace_if_false_ko() {
let source_code = r#"