feat(diagnostics): prelude-hint for UndefinedVariable / Unbound (stdlib #5)#427
Merged
Conversation
#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>
🔍 Hypatia Security ScanFindings: 81 issues detected
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 |
🔍 Hypatia Security ScanFindings: 81 issues detected
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 |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
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
What this does NOT do
Test plan
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