Files
bux-lang/docs/superpowers/specs/2026-06-14-drop-operator-generics-fix-design.md
T
dimgigov 06db4926a7 fix(bootstrap): substitute generic type args in operator [] resolution
- Preserve type args on tkNamed in resolveType
- Resolve explicit generic call return types with concrete substitutions
- Substitute method type params when looking up operator_index_get
- Skip strict arg checks for generic function calls (deferred to inference)
- Fix generic struct monomorphization when no caller substitution map exists
- Fix parameter varTypeExprs ordering so pointer params are visible in bodies

Fixes _test_drop_trait and _test_checked_index
2026-06-14 13:15:13 +03:00

5.4 KiB

Fix Drop/Operator [] Generic Type Bug in Bootstrap

Date: 2026-06-14
Status: Approved
Scope: Bootstrap compiler (bootstrap/*.nim) — specifically _test_drop_trait and _test_checked_index

1. Problem Statement

The bootstrap compiler already supports @[Drop] types, auto-drop, and generic operator overloading (operator []), but the interaction between these features produces wrong types or spurious type errors.

Two integration tests currently fail:

  • _test_drop_trait: expected int, got float32 at 9:13 when reading arr[0] from an Array<int>.
  • _test_checked_index: cannot assign int to Array at 11:5 when using the checked index operator on Array<T>.

Both failures suggest that generic type substitution (T -> int) is not applied correctly to the return type of operator [] when the operator is invoked from generated auto-drop or checked-index code paths.

2. Goals

  1. Make _test_drop_trait pass.
  2. Make _test_checked_index pass.
  3. Keep the fix minimal and confined to the bootstrap compiler.
  4. Ensure make test, make selfhost, and make selfhost-loop continue to pass.

3. Non-Goals

  1. Rewriting the apps/ example applications (excluded per user request).
  2. Adding new language features; this is a bug-fix task only.
  3. Changing the selfhost compiler (src/*.bux) unless the same bug exists there and is required for selfhost-loop.
  4. Fixing unrelated for ... in or Slice<T> failures (tracked separately).

4. Investigation Plan

  1. Reproduce both failures with build/buxc run in each _test_* directory.
  2. Read the source of _test_drop_trait/src/Main.bux and _test_checked_index/src/Main.bux.
  3. Trace how the bootstrap compiler resolves operator [] for Array<T>:
    • Parser/AST representation of the call.
    • Semantic analysis (sema.nim) overload resolution and generic substitution.
    • HIR lowering (hir_lower.nim) of operator calls and auto-drop.
    • LIR lowering/C backend (lir_lower.nim, lir_c_backend.nim) type emission.
  4. Identify the exact location where the return type of the selected operator overload retains an unsubstituted generic parameter.

5. Hypothesis

When @[Drop] causes the compiler to synthesize an Array_Drop call (or when @[Checked] synthesizes a bounds-checked operator [] call), the generic substitution context is not threaded into the operator overload resolution. As a result, T remains as the generic parameter instead of being replaced by int, leading to:

  • A fallback/primitive type mismatch (float32 appears when no substitution occurs).
  • A type assignment error because the returned value is treated as Array instead of int.

6. Proposed Fix

Investigation showed the root cause spans both semantic analysis and HIR lowering:

  1. Sema (bootstrap/sema.nim):

    • Preserve generic type arguments on tkNamed in resolveType.
    • Resolve explicit generic-call return types with the concrete type arguments substituted.
    • Substitute method type parameters when looking up operator_index_get, including through pointer receivers.
    • Skip strict argument-type checks for generic function calls; these are deferred to inference/monomorphization.
  2. HIR lowering (bootstrap/hir_lower.nim):

    • Build a local type-parameter substitution map when generating generic struct instances inside substituteType.
    • Register parameter types in varTypeExprs after clearing the per-function table so pointer parameters are visible when lowering operator calls.

The fix should be the smallest change that makes the two tests pass without breaking other tests.

7. Affected Files

File Expected Change
bootstrap/sema.nim Preserve type args, substitute in operator/index lookup, defer generic call arg checks.
bootstrap/hir_lower.nim Fix generic struct monomorphization and parameter visibility.
_test_drop_trait/src/Main.bux No changes.
_test_checked_index/src/Main.bux No changes.

8. Testing Plan

8.1 Target Tests

cd _test_drop_trait && ../../build/buxc run && cd ..
cd _test_checked_index && ../../build/buxc run && cd ..

Expected: both exit 0.

8.2 Regression Tests

make test
make selfhost
make selfhost-loop

Expected: all pass / no changes in selfhost-loop output.

8.3 Optional Cross-Check

Run remaining _test_* packages to confirm no new failures:

for d in _test_*; do
  echo "=== $d ==="
  (cd "$d" && ../../build/buxc run) || true
done

9. Success Criteria

  • _test_drop_trait reports PASS.
  • _test_checked_index reports PASS.
  • make test reports no new failures.
  • make selfhost-loop remains deterministic (identical C + stripped ELF).

10. Risks & Mitigations

Risk Mitigation
Fix touches generic resolution and breaks other tests Run full test suite and selfhost-loop before committing.
Same bug exists in selfhost compiler Selfhost-loop will catch type/output differences; fix selfhost only if required.
Root cause is deeper than operator substitution Time-box investigation; if not resolved in a reasonable number of iterations, escalate to user with findings.

11. Relation to Other Work

  • docs/superpowers/specs/2026-06-10-drop-trait-design.md covers universal auto-drop in the selfhost compiler. This document covers the bootstrap compiler's Drop/operator interaction bug and is independent of the selfhost work.