Skip to content

feat(diagnostics): prelude-hint for UndefinedVariable / Unbound (stdlib #5) - #427

Merged
hyperpolymath merged 3 commits into
mainfrom
feat/stdlib-5-prelude-hint
May 28, 2026
Merged

feat(diagnostics): prelude-hint for UndefinedVariable / Unbound (stdlib #5)#427
hyperpolymath merged 3 commits into
mainfrom
feat/stdlib-5-prelude-hint

Conversation

@hyperpolymath

Copy link
Copy Markdown
Owner

Closes #415. Stdlib roadmap item #5 (docs/stdlib-roadmap.adoc).

TL;DR

The original framing of stdlib #5 was "cross-file `use` resolvability from standalone check". Reproducing the bug turned up something different: cross-module `use` already works (both `use Deno::{Json}` and `use prelude::*` resolve fine from a standalone single-file check).

What actually trips users is discoverability — prelude is NOT auto-opened (deliberate, per issue #138), and the error when an unimported `Some` is referenced was a raw OCaml record dump with no hint about the fix.

Before / after

Before:
```
Resolution error: (Resolve.UndefinedVariable
{ Ast.name = "Some";
span = { Span.start_pos = { Span.line = 1; col = 37; ... }; ... }
})
```

After:
```
Resolution error: undefined value: `Some`
hint: `Some` is defined in `stdlib/prelude.affine` — add
`use prelude::{Some};` (or `use prelude::*;`) at the top of the file.
```

Files

File Change
`lib/face.ml` Canonical face: replace `show_resolve_error` dump with full per-error-class formatter; add `prelude_hint` for UndefinedVariable + UndefinedType
`lib/typecheck.ml` Add same `prelude_hint` on `UnboundVariable` (typecheck-time path; fires for match arms whose constructor reference the resolver missed)

What this does NOT do

  • Does NOT auto-import prelude (that would revert issue cleanup: remove b895374 seeded Some/None/Ok/Err builtins band-aid #138 which intentionally removed the band-aid)
  • Does NOT change resolve behaviour at all — only the error message
  • Does NOT touch the other faces (Python / Js / Pseudocode / Lucid / Cafe) — they already had their own formatted hints; just Canonical was raw-dumping

Test plan

  • codegen-deno suite: 7/7 harnesses green (no behaviour change)
  • Manual: idaptik PR Cross-module imports: TopConst not threaded by gen_imports / flatten_imports #107's case (missing `Some`) now shows the hint
  • Manual: non-prelude names (e.g. `nonexistentFn`) still get a clean error with NO inappropriate prelude hint
  • `dune build bin/main.exe` clean
  • `dune build @runtest` — 340/342 pass; the 2 failures are pre-existing E2E Node-CJS Codegen baseline flakes (CLAUDE.md "Known-failing baseline checks"), unchanged by this PR

Follow-ups

Once this lands, a follow-up PR updates `docs/stdlib-roadmap.adoc` row #5 status `◑` partial → `●` usable (kept out of this PR so the diff stays focused on the diagnostic itself).

🤖 Generated with Claude Code

#5)

Closes #415. Stdlib roadmap item #5 was framed as "cross-file `use`
resolvability from standalone check", but the actual underlying issue
turned out to be **discoverability**: cross-module `use` already works
(both `use Deno::{Json}` and `use prelude::*` resolve from a standalone
single-file check). What trips users is that prelude is NOT auto-opened
(deliberate, per issue #138), and the error when an unimported `Some`
is referenced was a raw OCaml record dump with no hint about the fix.

This change:

1. Replaces face.ml's `Canonical` branch's `show_resolve_error` (raw
   record dump) with a real per-error-class formatter. Other faces
   were already formatted; only Canonical hadn't been touched here.

2. Adds a `prelude_hint` helper in both face.ml and typecheck.ml that,
   when an undefined name matches a known prelude export, appends:

       hint: `Some` is defined in `stdlib/prelude.affine` — add
       `use prelude::{Some};` (or `use prelude::*;`) at the top of
       the file.

   Covers both the resolve-time path (face.ml) and the typecheck-time
   path (typecheck.ml's UnboundVariable — fires e.g. when a match arm
   references an unbound constructor the resolver missed).

3. Hard-codes the prelude export list as the well-known 20 names
   (Option, Result, Some, None, Ok, Err + the function helpers). A
   missing name here means a worse error message, not incorrect
   behaviour. Comment in both files notes the list must mirror
   `stdlib/prelude.affine`.

Effect for users:

- BEFORE: `Resolution error: (Resolve.UndefinedVariable { Ast.name = "Some"; span = {...} })`
- AFTER:
  ```
  Resolution error: undefined value: `Some`
    hint: `Some` is defined in `stdlib/prelude.affine` — add
    `use prelude::{Some};` (or `use prelude::*;`) at the top of
    the file.
  ```

Doesn't auto-import prelude (would revert #138). Doesn't change resolve
behaviour at all — only error rendering.

Test plan:

- [x] codegen-deno suite stays 7/7 green
- [x] Manual reproduction of the idaptik PR #107 case shows the hint
- [x] Non-prelude names (e.g. `nonexistentFn`) still get a clean error
      with NO inappropriate prelude hint
- [x] `dune build bin/main.exe` clean

Updates stdlib roadmap row #5 status `◑` partial → `●` usable in a
follow-up PR (so this PR stays focused on the diagnostic).

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
@hyperpolymath
hyperpolymath enabled auto-merge (squash) May 28, 2026 12:16
@github-actions

Copy link
Copy Markdown

🔍 Hypatia Security Scan

Findings: 81 issues detected

Severity Count
🔴 Critical 4
🟠 High 10
🟡 Medium 67

⚠️ Action Required: Critical security issues found!

View findings
[
  {
    "reason": "Action actions/checkout@v6 needs attention",
    "type": "unpinned_action",
    "file": "publish-jsr.yml",
    "action": "pin_sha",
    "rule_module": "workflow_audit",
    "severity": "medium"
  },
  {
    "reason": "Action denoland/setup-deno@v2 needs attention",
    "type": "unpinned_action",
    "file": "publish-jsr.yml",
    "action": "pin_sha",
    "rule_module": "workflow_audit",
    "severity": "medium"
  },
  {
    "reason": "Issue in affine-vscode-publish.yml",
    "type": "unknown",
    "file": "affine-vscode-publish.yml",
    "action": "flag",
    "rule_module": "workflow_audit",
    "severity": "medium"
  },
  {
    "reason": "Issue in casket-pages.yml",
    "type": "unknown",
    "file": "casket-pages.yml",
    "action": "flag",
    "rule_module": "workflow_audit",
    "severity": "medium"
  },
  {
    "reason": "Issue in casket-pages.yml",
    "type": "unknown",
    "file": "casket-pages.yml",
    "action": "flag",
    "rule_module": "workflow_audit",
    "severity": "medium"
  },
  {
    "reason": "Issue in ci.yml",
    "type": "unknown",
    "file": "ci.yml",
    "action": "flag",
    "rule_module": "workflow_audit",
    "severity": "medium"
  },
  {
    "reason": "Issue in ci.yml",
    "type": "unknown",
    "file": "ci.yml",
    "action": "flag",
    "rule_module": "workflow_audit",
    "severity": "medium"
  },
  {
    "reason": "Issue in ci.yml",
    "type": "unknown",
    "file": "ci.yml",
    "action": "flag",
    "rule_module": "workflow_audit",
    "severity": "medium"
  },
  {
    "reason": "Issue in ci.yml",
    "type": "unknown",
    "file": "ci.yml",
    "action": "flag",
    "rule_module": "workflow_audit",
    "severity": "medium"
  },
  {
    "reason": "Issue in ci.yml",
    "type": "unknown",
    "file": "ci.yml",
    "action": "flag",
    "rule_module": "workflow_audit",
    "severity": "medium"
  }
]

Powered by Hypatia Neurosymbolic CI/CD Intelligence

@github-actions

Copy link
Copy Markdown

🔍 Hypatia Security Scan

Findings: 81 issues detected

Severity Count
🔴 Critical 4
🟠 High 10
🟡 Medium 67

⚠️ Action Required: Critical security issues found!

View findings
[
  {
    "reason": "Action actions/checkout@v6 needs attention",
    "type": "unpinned_action",
    "file": "publish-jsr.yml",
    "action": "pin_sha",
    "rule_module": "workflow_audit",
    "severity": "medium"
  },
  {
    "reason": "Action denoland/setup-deno@v2 needs attention",
    "type": "unpinned_action",
    "file": "publish-jsr.yml",
    "action": "pin_sha",
    "rule_module": "workflow_audit",
    "severity": "medium"
  },
  {
    "reason": "Issue in affine-vscode-publish.yml",
    "type": "unknown",
    "file": "affine-vscode-publish.yml",
    "action": "flag",
    "rule_module": "workflow_audit",
    "severity": "medium"
  },
  {
    "reason": "Issue in casket-pages.yml",
    "type": "unknown",
    "file": "casket-pages.yml",
    "action": "flag",
    "rule_module": "workflow_audit",
    "severity": "medium"
  },
  {
    "reason": "Issue in casket-pages.yml",
    "type": "unknown",
    "file": "casket-pages.yml",
    "action": "flag",
    "rule_module": "workflow_audit",
    "severity": "medium"
  },
  {
    "reason": "Issue in ci.yml",
    "type": "unknown",
    "file": "ci.yml",
    "action": "flag",
    "rule_module": "workflow_audit",
    "severity": "medium"
  },
  {
    "reason": "Issue in ci.yml",
    "type": "unknown",
    "file": "ci.yml",
    "action": "flag",
    "rule_module": "workflow_audit",
    "severity": "medium"
  },
  {
    "reason": "Issue in ci.yml",
    "type": "unknown",
    "file": "ci.yml",
    "action": "flag",
    "rule_module": "workflow_audit",
    "severity": "medium"
  },
  {
    "reason": "Issue in ci.yml",
    "type": "unknown",
    "file": "ci.yml",
    "action": "flag",
    "rule_module": "workflow_audit",
    "severity": "medium"
  },
  {
    "reason": "Issue in ci.yml",
    "type": "unknown",
    "file": "ci.yml",
    "action": "flag",
    "rule_module": "workflow_audit",
    "severity": "medium"
  }
]

Powered by Hypatia Neurosymbolic CI/CD Intelligence

@hyperpolymath
hyperpolymath merged commit cb9704a into main May 28, 2026
24 of 26 checks passed
@hyperpolymath
hyperpolymath deleted the feat/stdlib-5-prelude-hint branch May 28, 2026 13:13
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

1 participant