Skip to content

fix(typecheck): instantiate generic fn type params (#135 slice 7)#163

Merged
hyperpolymath merged 1 commit into
mainfrom
fix/135i-module-resolve
May 17, 2026
Merged

fix(typecheck): instantiate generic fn type params (#135 slice 7)#163
hyperpolymath merged 1 commit into
mainfrom
fix/135i-module-resolve

Conversation

@hyperpolymath
Copy link
Copy Markdown
Owner

What

#135 slice 7 — the root cause was not empty-array literals (those compile). It was a fundamental let-polymorphism bug.

check_fn_decl never registered a function's explicit <T> type parameters, so an uppercase param x: T lowered (via lower_type_expr TyCon fallthrough) to a rigid TCon "T". generalize ignores TCon, so every generic top-level function got sc_tyvars = [] — effectively monomorphic. The first call pinned T; any further instantiation failed Unify.TypeMismatch (T, Int), and use prelude::{…} import-checks failed transitively across result/option/collections.

How

Mirrors the existing let-generalization discipline: in check_fn_decl, before lowering, enter_level and register each fd_type_params name in ctx.type_env as a fresh tyvar at the deeper level; exit_level before the existing generalize so those vars become the scheme's quantified sc_tyvars. Scoped save/restore of type_env. Both extern and normal branches.

Plus genuine stdlib bugs surfaced once typecheck passed: prelude.affine map/filter/range/repeat/fold reassigned immutable let bindings → let mut.

Result

prelude.affine now compiles end-to-end (resolve→typecheck→codegen).

Verification

  • id<T> at Int+Bool, generic fold from monomorphic sum, monomorphic fns — all compile.
  • The fundamental typecheck change regressed none of the suite.
  • 2 regression tests; full suite green (230 tests).

High-leverage: unblocks the typecheck wall; result/option/collections follow once slice 8 (module visibility) lands. Advances #135 (does not close). Refs #128, #135.

🤖 Generated with Claude Code

… slice 7)

#135 slice 7 — root cause was NOT empty-array literals (those compile).
It was a fundamental let-polymorphism bug: `check_fn_decl` never
registered a function's explicit `<T>` type parameters, so an uppercase
param `x: T` lowered via `lower_type_expr`'s `TyCon` fallthrough to a
*rigid* `TCon "T"`. `generalize` ignores `TCon`, so every generic
top-level function got `sc_tyvars = []` — effectively monomorphic.
The first call pinned `T`; any second instantiation (or the very first
against a concrete arg) failed `Unify.TypeMismatch (T, Int)`, and
`use prelude::{…}` import-checks failed transitively (result/option/…).

Fix (mirrors the existing let-generalization discipline): in
`check_fn_decl`, before lowering, `enter_level` and register each
`fd_type_params` name in `ctx.type_env` as a fresh tyvar at the deeper
level; `exit_level` before the existing `generalize`, so those vars
(level > ctx.level) become the scheme's quantified `sc_tyvars`. Scoped
save/restore of `type_env` so params don't leak. Applied to both the
extern and normal branches.

Also fixes genuine stdlib bugs surfaced once typecheck passed:
prelude.affine `map`/`filter`/`range`/`repeat`/`fold` reassigned
immutable `let` bindings (`result`/`i`/`acc`) → `let mut`. With both,
**prelude.affine now compiles end-to-end** (resolve→typecheck→codegen).

Verification: `id<T>` instantiated at Int+Bool, generic `fold` from a
monomorphic Int `sum`, monomorphic fns — all compile; the fundamental
change regressed **none** of the suite. 2 regression tests; full suite
green (230). Unblocks the typecheck wall for prelude (and, once
visibility/slice 8 lands, result/option/collections via `use prelude`).

Advances #135. Refs #128, #135.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
@hyperpolymath hyperpolymath merged commit e950dbc into main May 17, 2026
@hyperpolymath hyperpolymath deleted the fix/135i-module-resolve branch May 17, 2026 12:01
@github-actions
Copy link
Copy Markdown

🔍 Hypatia Security Scan

Findings: 44 issues detected

Severity Count
🔴 Critical 12
🟠 High 21
🟡 Medium 11

⚠️ Action Required: Critical security issues found!

View findings
[
  {
    "reason": "Stray AI.a2ml in root -- use 0-AI-MANIFEST.a2ml only",
    "type": "banned",
    "file": "AI.a2ml",
    "action": "delete",
    "rule_module": "root_hygiene",
    "severity": "high"
  },
  {
    "reason": "Superseded by 0-AI-MANIFEST.a2ml",
    "type": "banned",
    "file": "AI.djot",
    "action": "delete",
    "rule_module": "root_hygiene",
    "severity": "high"
  },
  {
    "reason": "Issue in quality.yml",
    "type": "missing_workflow",
    "file": "quality.yml",
    "action": "create",
    "rule_module": "workflow_audit",
    "severity": "high"
  },
  {
    "reason": "Issue in security-policy.yml",
    "type": "missing_workflow",
    "file": "security-policy.yml",
    "action": "create",
    "rule_module": "workflow_audit",
    "severity": "medium"
  },
  {
    "reason": "Action hyperpolymath/standards/.github/workflows/governance-reusable.yml@main needs attention",
    "type": "unpinned_action",
    "file": "governance.yml",
    "action": "pin_sha",
    "rule_module": "workflow_audit",
    "severity": "high"
  },
  {
    "reason": "TypeScript file detected -- banned language",
    "type": "banned_language_file",
    "file": "/home/runner/work/affinescript/affinescript/affinescript-deno-test/example/smoke_driver.ts",
    "action": "flag",
    "rule_module": "cicd_rules",
    "severity": "critical"
  },
  {
    "reason": "TypeScript file detected -- banned language",
    "type": "banned_language_file",
    "file": "/home/runner/work/affinescript/affinescript/affinescript-deno-test/cli.ts",
    "action": "flag",
    "rule_module": "cicd_rules",
    "severity": "critical"
  },
  {
    "reason": "TypeScript file detected -- banned language",
    "type": "banned_language_file",
    "file": "/home/runner/work/affinescript/affinescript/affinescript-deno-test/mod.ts",
    "action": "flag",
    "rule_module": "cicd_rules",
    "severity": "critical"
  },
  {
    "reason": "TypeScript file detected -- banned language",
    "type": "banned_language_file",
    "file": "/home/runner/work/affinescript/affinescript/affinescript-deno-test/lib/compile.ts",
    "action": "flag",
    "rule_module": "cicd_rules",
    "severity": "critical"
  },
  {
    "reason": "TypeScript file detected -- banned language",
    "type": "banned_language_file",
    "file": "/home/runner/work/affinescript/affinescript/affinescript-deno-test/lib/runner.ts",
    "action": "flag",
    "rule_module": "cicd_rules",
    "severity": "critical"
  }
]

Powered by Hypatia Neurosymbolic CI/CD Intelligence

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant