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

Projects

None yet

Development

Successfully merging this pull request may close these issues.

stdlib #5: cross-file use resolvability from standalone check

1 participant