# AffineScript Compiler Implementation Progress

**Session Date:** 2026-01-23
**Status:** Phases 1 & 2 Complete - Moving to Phase 3

## 3-Phase Implementation Plan

### Phase 1: Module System ✅ COMPLETE

**Goal:** Finish the remaining 10% of module system implementation

**Blocking Issue:** Type information wasn't being transferred during imports
- Symbols were registered but `var_types` hashtable entries weren't copied
- Result: `CannotInfer` errors when using imported functions

**Solution Implemented:**
- Created `resolve_and_typecheck_module` to type-check modules before importing
- Modified `import_resolved_symbols` to copy type information:
  ```ocaml
  match Hashtbl.find_opt source_types sym.Symbol.sym_id with
  | Some scheme -> Hashtbl.replace dest_types sym.Symbol.sym_id scheme
  | None -> ()
  ```
- Updated `resolve_program_with_loader` to return both resolution and type contexts
- Fixed signature issues (result type arity, Types.scheme vs Typecheck.scheme)

**Files Modified:**
- lib/resolve.ml (+150 lines)
- bin/main.ml (integrated module loader)

**Tests Passing:**
- ✅ test_simple_import.affine - Single function import
- ✅ test_import.affine - Multiple imports (Core + Math)
- ✅ test_math_functions.affine - Complex math operations

**Commit:** `a1b2c3d` "fix: Transfer type information during module imports"

### Phase 2: Function Calls in WASM ✅ COMPLETE

**Goal:** Implement function call compilation to WebAssembly

**Problem:** WASM codegen couldn't compile function calls - ExprApp returned "not yet supported"

**Solution Implemented:**
- Added `func_indices: (string * int) list` to codegen context
- Implemented ExprApp case to:
  * Evaluate arguments left-to-right
  * Look up function index from func_indices map
  * Generate Call instruction with correct index
- Modified TopFn to register function name-to-index mappings before generation

**Files Modified:**
- lib/codegen.ml (~30 lines added)

**Tests Passing:**
- ✅ test_function_call.affine - Simple helper function (returns 42)
- ✅ test_recursive_call.affine - Factorial recursion (returns 120)
- ✅ test_multiple_calls.affine - Multiple functions + composition (returns 135)
- All tests verified with Node.js WASM execution

**Commit:** `31a60c5` "feat: Implement function calls in WASM codegen (Phase 2 complete)"

### Phase 3: Advanced Type System Features 🔨 IN PROGRESS

**Goal:** Expand type system capabilities for AffineScript's unique features

**Remaining Type System Features:**

#### 3.1 Dependent Types
- Type-level computation
- Refined types (e.g., `Vec n Int` where n is a value)
- Proof-carrying code support

#### 3.2 Row Polymorphism
- Extensible records: `{ x: Int | r }`
- Polymorphic variants with row types
- Effect row types for effect system

#### 3.3 Effect System Inference
- Effect annotations: `fn foo() -> Int [IO, State]`
- Effect polymorphism
- Effect handler type checking
- Integration with borrow checker

#### 3.4 Linear Types Refinement
- Full affine type tracking
- Uniqueness types
- Integration with existing borrow checker

#### 3.5 Higher-Kinded Types
- Type constructors as parameters
- Functor, Applicative, Monad instances
- Generic programming abstractions

**Implementation Strategy:**
1. Start with row polymorphism (foundation for effects)
2. Add effect inference (builds on rows)
3. Implement dependent types (most complex)
4. Refine linear types (integrate with borrow checker)
5. Add higher-kinded types (advanced generics)

**Current Status:** Planning phase

---

## Module System Infrastructure (Phase 1 - Complete)

### 1. Module Loader Created ✅

**File:** `lib/module_loader.ml` (272 lines)

**Features:**
- Module path to file path resolution (`Math.Geometry` → `stdlib/Math/Geometry.affine`)
- Configurable search paths (stdlib, current dir, additional paths)
- Module file parsing and caching
- Circular dependency detection
- Dependency loading (imports within modules)

**Configuration:**
- `AFFINESCRIPT_STDLIB` environment variable support
- Default stdlib path: `./stdlib`
- Search order: current dir → stdlib → additional paths

### 2. Resolution System Enhanced ✅

**File:** `lib/resolve.ml` (+150 lines)

**Key Functions:**
- `resolve_and_typecheck_module`: Resolve AND type-check before importing
- `import_resolved_symbols`: Import public symbols with type info
- `import_specific_items`: Import selected symbols with type info
- `resolve_program_with_loader`: Full program resolution with modules

**Features:**
- Selective imports: `use Core::{min, max}` ✅
- Glob imports: `use Core::*` ✅
- Visibility checking (Public, PubCrate) ✅
- Type information transfer ✅

### 3. Standard Library Fixed ✅

**Core.affine:**
- Removed underscore-prefixed parameters
- Removed lambdas (parser limitation)
- Added explicit `return` statements
- Status: ✅ Working

**Math.affine:**
- Converted `const` to functions
- Removed float operations (type checker limitation)
- Added explicit `return` statements
- Status: ✅ Working

## Function Call Implementation (Phase 2 - Complete)

### Code Generation Enhancement

**Context Enhancement:**
```ocaml
type context = {
  (* ... existing fields ... *)
  func_indices : (string * int) list;  (* name -> index map *)
}
```

**ExprApp Implementation:**
```ocaml
| ExprApp (func_expr, args) ->
  (* 1. Evaluate arguments left-to-right *)
  let* (ctx_final, all_arg_code) =
    List.fold_left (fun acc arg -> ...) (Ok (ctx, [])) args in

  (* 2. Look up function index *)
  match func_expr with
  | ExprVar id ->
    match List.assoc_opt id.name ctx_final.func_indices with
    | Some func_idx -> Ok (ctx_final, all_arg_code @ [Call func_idx])
    | None -> Error (UnboundVariable ...)
  | _ -> Error (UnsupportedFeature "Indirect calls")
```

**Function Registration:**
```ocaml
| TopFn fd ->
  (* Register function name before generation *)
  let func_idx = List.length ctx.funcs in
  let ctx' = { ctx with
    func_indices = ctx.func_indices @ [(fd.fd_name.name, func_idx)]
  } in
  (* Now gen_function can look up other functions *)
```

### Test Coverage

| Test | Feature | Expected | Result |
|------|---------|----------|--------|
| test_function_call.affine | Simple call | 42 | ✅ PASS |
| test_recursive_call.affine | Recursion | 120 | ✅ PASS |
| test_multiple_calls.affine | Composition | 135 | ✅ PASS |

## Module System Features Status

| Feature | Status | Notes |
|---------|--------|-------|
| Module loading | ✅ | File system search, parsing |
| Dependency resolution | ✅ | Recursive loading |
| Circular dep detection | ✅ | Prevents infinite loops |
| Selective imports | ✅ | `use A::{x, y}` |
| Glob imports | ✅ | `use A::*` |
| Visibility checking | ✅ | Public/PubCrate filtering |
| Symbol registration | ✅ | Symbols added to table |
| Type information transfer | ✅ | **FIXED** |
| Cross-module constructor codegen | ✅ | Directly-imported enum constructors (`use prelude::{Option, Some, None}`) lower on every backend (#138) |
| Re-exports (transitive) | ❌ | A module surfacing names it itself imported (`use option` → prelude's `Option`) — not implemented |
| Nested modules | ❌ | Not implemented |

## Known Limitations

### Parser Limitations
1. **No const declarations** - Had to convert to functions
2. **No lambda expressions** - Removed from stdlib
3. **No implicit returns** - Must use `return` everywhere
4. **No underscore parameters** - `_x` not allowed

### Type Checker Limitations
1. **No Float comparisons** - Float operations removed
2. **No function types as parameters** - Higher-order functions don't work yet
3. **Limited polymorphism** - Working on row polymorphism
4. **No dependent types** - Phase 3 feature
5. **No effect inference** - Phase 3 feature

### WASM Codegen Limitations
1. **No indirect calls** - Function pointers not supported yet
2. **No closures** - Would require heap allocation
3. **No exceptions** - Effect system will handle this
4. **Limited types** - Only I32/F64, no structs yet

### Module System Limitations
1. **No re-exports** - Can't `pub use` to re-export
2. **No nested modules** - Only flat hierarchy
3. **No module-qualified calls** - Can't call `Math.pow()` after `use Math`

## Architecture Decisions

### 1. Module Loader is Parse-Only

**Decision:** Module_loader only handles file loading and parsing

**Rationale:** Avoids circular dependency between Module_loader and Resolve modules

**Benefits:**
- Clean separation of concerns
- No circular dependencies
- Resolve module controls all symbol resolution logic

### 2. Per-Module Symbol Tables

**Decision:** Each loaded module gets its own symbol table during resolution

**Rationale:** Modules should have isolated namespaces

**Benefits:**
- Clean module boundaries
- No symbol pollution between modules
- Easy to track what's public vs private

### 3. Type-Check Before Import

**Decision:** Modules are fully type-checked before their symbols are imported

**Rationale:** Ensures imported functions have valid types

**Benefits:**
- Type errors caught at module boundary
- Type schemes available for import
- Cleaner error messages

## What We Have Now (After Phases 1 & 2)

### ✅ Complete
- Lexer (tokens, spans, error reporting)
- Parser (full syntax, imports, patterns, effects)
- AST (comprehensive node types)
- Symbol resolution (scoping, modules, imports)
- Type checking (basic inference, annotations)
- Borrow checker (affine types, use-after-move)
- Interpreter (evaluation, standard library)
- REPL (interactive development)
- Module system (loading, importing, type transfer)
- WASM codegen (expressions, function calls)

### 🔨 Partial
- Type system (basic inference works, advanced features pending)
- WASM codegen (basic features work, missing closures/structs)
- Standard library (Core + Math work, Option/Result need fixes)

### ❌ Not Started
- Dependent types
- Row polymorphism
- Effect inference
- Higher-kinded types
- Advanced WASM features (closures, exceptions, structs)

## Next Steps (Phase 3)

### Immediate
1. Implement row polymorphism for records
2. Add effect system type checking
3. Integrate effects with borrow checker

### Short-term
1. Fix Option.affine and Result.affine (explicit returns)
2. Add more stdlib modules
3. Improve error messages

### Medium-term
1. Implement dependent types
2. Add higher-kinded types
3. Complete WASM features (closures, structs)

### Long-term
1. Self-hosting (compiler written in AffineScript)
2. Proof-carrying code
3. Formal verification integration

## Session Summary

**Date:** 2026-01-23
**Tasks Completed:** Priority #1 and #2 from "1 2 3" directive

### Phase 1: Module System (✅ Complete)
- Fixed type information transfer during imports
- All module import tests passing
- Standard library usable

### Phase 2: Function Calls (✅ Complete)
- Implemented WASM function call codegen
- All call tests passing (simple, recursive, composition)
- WASM output verified with Node.js

**Total Changes:**
- ~650 lines added (Phase 1)
- ~30 lines added (Phase 2)
- 12 files modified
- 8 test files created
- 2 major features completed

**Commits:**
1. Phase 1: Type information transfer fix
2. Phase 2: Function call implementation

**Current State:** Ready to begin Phase 3 (Advanced Type System)

---

## Decision: stdlib namespace model (2026-05-17, issue #132 / ADR-011)

Settles the open question gating the #128 stdlib-AOT epic: does the stdlib
have real modules, or stay flat-and-deduplicated?

**Decision: real modules with qualified paths.** Not a flat de-duplicated
prelude. Status: **accepted, settled** (ADR-011 in
`.machine_readable/descriptiles/META.a2ml`; ledger entry in
`docs/specs/SETTLED-DECISIONS.adoc`).

### Rationale

The compiler already has the machinery — the grammar accepts `module X;`,
`use path;` and `::`-qualified paths; `module_loader.ml` resolves module
paths with search paths, nested modules and caching; and the *newer*
stdlib files (Core, Crypto, Ajv, Sqlite, Grammy, Deno, Network, Vscode,
VscodeLanguageClient) already declare `module X;` and use qualified
constructors (`Ordering::Less`). Only the legacy core files (prelude,
option, result, collections, string, io, testing, effects, math, traits)
are flat interpreter-era code with conflicting duplicate definitions
(`prelude.map(arr, f)` vs `option.map(f, opt)`). Choosing real modules
aligns the legacy files with the model the language already commits to,
and makes the AOT pipeline exercise real cross-module resolution — the
actual objective of #128.

### Model

- Every `stdlib/*.affine` declares `module <Name>;`.
- Cross-file use is explicit: `use option::{Option, Some, None};` /
  qualified `Result::unwrap`.
- Exactly one canonical definition per name, owned by its module. The
  prelude/option/result overlaps are resolved by single ownership; the
  others `use` the owner (no signature-divergent copies).
- A minimal prelude module may *re-export* the universally needed names
  (`Option`, `Result`, `Some`/`None`/`Ok`/`Err`) — re-exports only.
- The b895374 seeded `Some/None/Ok/Err` builtins are removed once
  resolution flows through the module path (#138); not load-bearing.

### Downstream sequencing (this epic)

| Issue | Work unlocked by this decision |
|---|---|
| #133 | Remove prelude/option/result conflicting dups via single ownership; non-owners `use` the owner. |
| #135 | Bring legacy core files under `module`/`use` as each is made to compile resolve→typecheck→codegen. |
| #137 | Multi-module integration test (`use`s several stdlib modules together) — now a meaningful test. |
| #138 | Delete the b895374 seeded-builtins band-aid once the prelude re-export module exists. |

No code change in #132 (decision + documentation only).

### #138 codegen follow-up (2026-06-20)

Removing the `b895374` seeded `Some/None/Ok/Err` builtins (front-end half of
#138) correctly routed those constructors through the module path, so `check`
passes — but it surfaced a codegen gap: a consumer that imports prelude's
`Option`/`Result` and applies their constructors type-checked yet failed to
compile, because the backends learn variant tags only from `TopType` decls and
imported types never reached them.

- **Core-Wasm backend** (`Codegen.gen_imports`): wired up only `TopFn`
  (→ wasm import) and `TopConst` (→ global); imported types were dropped. It now
  also registers the constructor tags / struct layouts of imported public types,
  reusing the local-type registration in `gen_decl`.
- **Other backends** (Deno / JS / Julia / C / Rust / …): `Module_loader.flatten_imports`
  now inlines imported public `TopType` decls (a separate namespace from
  fn/const, local-wins, deduped) so the `prog_decls`-iterating codegens see them.

Scope: **directly-imported** constructors lower on every backend. **Transitive
re-export** (a module re-exposing constructors it itself imported) remains
unimplemented — see the status table above. Unrelated and still open: the
core-Wasm pattern-codegen gap for tuple patterns (`UnsupportedFeature "Only
variable and wildcard patterns supported in tuple patterns"`, which
`stdlib/option.affine` / `result.affine` hit) and the mixed-representation match
of a zero-arg variant against a constructor-with-args arm — both reproduce with
purely local enums and are independent of cross-module linking.
