Type bare unsafe Err as string, not Infer - #108
Merged
Conversation
-(typeck): bare `unsafe { }` now types as Result<Infer, string>. The Err side
was Infer, which accepts any member access, so `Err(e) => e.message`
compiled and evaluated .message on a string at runtime, yielding undefined.
dsc#102 fixed dsc#60 at the payload: the emitter normalizes a bare unsafe Err
to the thrown value string representation, so errors-as-values holds at
runtime. This makes the checker agree with the runtime. That is what turns
the mistake into a check-time error with a span instead of a silent
undefined.
-(call sites): migrate every `Err(e) => e.message` to `Err(e) => e` across
the testsuite, the tour, and the fixtures. Nothing caught these before: they
are all .pass fixtures whose Err arm never executes, so the suite was green
while every one of them would have printed undefined instead of the
diagnostic it exists to surface.
-(annotated form): unchanged. `unsafe<T> { }` keeps Result<T, JsError> and its
Error-object payload, which is sound because the member table (.message,
.name) describes a real Error.
This is one step of the deka#252/#460 mandatory-annotation migration, not the
whole thing.
This was referenced Sep 10, 2026
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 dsc#103. Tracked under dsc#90 — no unchecked value without an explicit boundary contract.
What
Bare
unsafe { }types asResult<Infer, string>instead ofResult<Infer, Infer>.The
Errside wasInfer, which accepts any member access. So this compiled and evaluated.messageon a string:dsc#102 fixed dsc#60 at the payload — the emitter normalizes a bare-unsafe
Errto the thrown value's string representation, so errors-as-values holds at runtime. This makes the checker agree with the runtime, which is what turns the mistake into a check-time error with a span rather than a silentundefined.Call sites
Every
Err(e) => e.messagemigrated toErr(e) => eacross the testsuite, the tour, and the fixtures.Nothing caught these before. They are all
.passfixtures whoseErrarm never executes, so the suite stayed green while every one of them would have printedundefinedinstead of the diagnostic it exists to surface.Unchanged
The annotated form.
unsafe<T> { }keepsResult<T, JsError>and itsError-object payload — sound, because theJsErrormember table (.message,.name) describes a realError.Scope
One step of the deka#252/#460 mandatory-annotation migration, not the whole thing.
Note on authorship
This is kimi's work. Its dispatch ended before it could commit — the second time that has happened — so I reviewed the diff and committed on its behalf. The checker change and all 30 call-site migrations were complete and consistent.
-kimi