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

@@ -3237,6 +3237,11 @@ impl CBackend {
Ok(format!("{}.{}", obj, field.name))
}
Expr::TupleIndex { object, index, .. } => {
let obj = self.emit_expr(object)?;
Ok(format!("{}.__{}", obj, index))
}
Expr::Match { scrutinee, arms, .. } => {
self.emit_match(scrutinee, arms)
}
@@ -4518,7 +4523,7 @@ impl CBackend {
|| self.expr_uses_rc_vars_from_scope(right)
}
Expr::UnaryOp { operand, .. } => self.expr_uses_rc_vars_from_scope(operand),
Expr::Field { object, .. } => self.expr_uses_rc_vars_from_scope(object),
Expr::Field { object, .. } | Expr::TupleIndex { object, .. } => self.expr_uses_rc_vars_from_scope(object),
Expr::EffectOp { args, .. } => {
args.iter().any(|a| self.expr_uses_rc_vars_from_scope(a))
}
@@ -4707,7 +4712,7 @@ impl CBackend {
self.collect_free_vars(val, bound, free);
}
}
Expr::Field { object, .. } => {
Expr::Field { object, .. } | Expr::TupleIndex { object, .. } => {
self.collect_free_vars(object, bound, free);
}
Expr::Match { scrutinee, arms, .. } => {

View File

@@ -1268,6 +1268,11 @@ impl JsBackend {
Ok(format!("{}.{}", obj, field.name))
}
Expr::TupleIndex { object, index, .. } => {
let obj = self.emit_expr(object)?;
Ok(format!("{}[{}]", obj, index))
}
Expr::Run {
expr, handlers, ..
} => {