feat: add tuple index access, multiline args, and effect unification fix

- Tuple index: `pair.0`, `pair.1` syntax across parser, typechecker,
  interpreter, C/JS backends, formatter, linter, and symbol table
- Multi-line function args: allow newlines inside argument lists
- Fix effect unification for callback parameters (empty expected
  effects means "no constraint", not "must be pure")

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
2026-02-17 16:20:32 -05:00
parent bac63bab2a
commit 542255780d
12 changed files with 176 additions and 8 deletions

View File

@@ -4831,6 +4831,71 @@ c")"#;
}
}
// ============ Multi-line Arguments Tests ============
#[test]
fn test_multiline_function_args() {
let source = r#"
fn add(a: Int, b: Int): Int = a + b
let result = add(
1,
2
)
"#;
assert_eq!(eval(source).unwrap(), "3");
}
#[test]
fn test_multiline_function_args_with_lambda() {
let source = r#"
let xs = List.map(
[1, 2, 3],
fn(x) => x * 2
)
"#;
assert_eq!(eval(source).unwrap(), "[2, 4, 6]");
}
// ============ Tuple Index Tests ============
#[test]
fn test_tuple_index_access() {
let source = r#"
let pair = (42, "hello")
let first = pair.0
"#;
assert_eq!(eval(source).unwrap(), "42");
}
#[test]
fn test_tuple_index_access_second() {
let source = r#"
let pair = (42, "hello")
let second = pair.1
"#;
assert_eq!(eval(source).unwrap(), "\"hello\"");
}
#[test]
fn test_tuple_index_triple() {
let source = r#"
let triple = (1, 2, 3)
let sum = triple.0 + triple.1 + triple.2
"#;
assert_eq!(eval(source).unwrap(), "6");
}
#[test]
fn test_tuple_index_in_function() {
let source = r#"
fn first(pair: (Int, String)): Int = pair.0
fn second(pair: (Int, String)): String = pair.1
let p = (42, "hello")
let result = first(p)
"#;
assert_eq!(eval(source).unwrap(), "42");
}
// Exhaustiveness checking tests
mod exhaustiveness_tests {
use super::*;