fix(stdlib): prelude unwrap/unwrap_result diverge via panic (#134)#150
Merged
Conversation
`prelude.affine`'s `unwrap` and `unwrap_result` only `println`'d on the None/Err arm and then fell through, returning Unit from a `-> T` signature (interpreter-era unsoundness; surfaced during #128 triage as `Unify.TypeMismatch (T, Unit)`). Replace the println+fall-through arms with `panic(...)` — the existing `panic(String) -> Never` builtin, exactly as `option.affine` and `result.affine` already do — so the failure arm has type Never and the typed return is sound. Adds two interpreter tests asserting the panic path (`unwrap(None)` and `unwrap_result(Err _)` both raise the documented RuntimeError). Full suite green (216 tests). Closes #134 Refs #128 Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
hyperpolymath
added a commit
that referenced
this pull request
May 17, 2026
Per ADR-011 (#132): one canonical binding per name, module-owned. - prelude.affine: `module prelude;`. Keeps the core sum types `Option`/`Result` (+ constructors) as their canonical home and the generic list/numeric utilities. Removes the 8 duplicate/conflicting Option/Result *operations* it previously also defined (is_some, is_none, unwrap, unwrap_or, is_ok, is_err, unwrap_result, unwrap_or_result). - option.affine: `module option;` + `use prelude::{Option, Some, None, Result, Ok, Err};`. Now the single canonical home for Option ops. - result.affine: `module result;` + `use prelude::{Result, Ok, Err, Option, Some, None};`. Single canonical home for Result ops. The previous flat-namespace conflicts (`prelude.map(arr,f)` vs `option.map(f,opt)`; `prelude.unwrap`(Option) vs `result.unwrap`(Result)) are resolved by module ownership — each is now `module::name`, exactly one definition per owning module. Verified: no leftover dup defs, no prelude util calls a removed op, full suite green (214 tests). Note: this removes the prelude `unwrap`/`unwrap_result` that #134 (PR #150) patched; the sound, panicking versions are `option::unwrap` and `result::unwrap` (already correct). #150's regression tests remain valid against those. Merge-order: if #150 lands first, resolve the modify/delete in prelude.affine in favour of this deletion. Closes #133 Refs #128, #132 Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
hyperpolymath
added a commit
that referenced
this pull request
May 17, 2026
…152) Per ADR-011 (#132): one canonical binding per name, module-owned. - prelude.affine: `module prelude;`. Keeps the core sum types `Option`/`Result` (+ constructors) as their canonical home and the generic list/numeric utilities. Removes the 8 duplicate/conflicting Option/Result *operations* it previously also defined (is_some, is_none, unwrap, unwrap_or, is_ok, is_err, unwrap_result, unwrap_or_result). - option.affine: `module option;` + `use prelude::{Option, Some, None, Result, Ok, Err};`. Now the single canonical home for Option ops. - result.affine: `module result;` + `use prelude::{Result, Ok, Err, Option, Some, None};`. Single canonical home for Result ops. The previous flat-namespace conflicts (`prelude.map(arr,f)` vs `option.map(f,opt)`; `prelude.unwrap`(Option) vs `result.unwrap`(Result)) are resolved by module ownership — each is now `module::name`, exactly one definition per owning module. Verified: no leftover dup defs, no prelude util calls a removed op, full suite green (214 tests). Note: this removes the prelude `unwrap`/`unwrap_result` that #134 (PR #150) patched; the sound, panicking versions are `option::unwrap` and `result::unwrap` (already correct). #150's regression tests remain valid against those. Merge-order: if #150 lands first, resolve the modify/delete in prelude.affine in favour of this deletion. Closes #133 Refs #128, #132 Co-authored-by: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
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.
What
Fixes #134 (independent sub-item of the #128 stdlib-AOT epic).
prelude.affine'sunwrap/unwrap_resultonlyprintln'd on theNone/Errarm then fell through, returning Unit from a-> Tsignature — an interpreter-era soundness bug (theUnify.TypeMismatch (T, Unit)seen during #128 triage).How
Replace the
println+ fall-through arms withpanic(...)— the existingpanic(String) -> Neverbuiltin, matching whatoption.affine/result.affinealready do. The failure arm now has typeNever, so the typed return is sound.Verification
unwrap(None)andunwrap_result(Err _)each raise the documentedRuntimeError.Independent of the other #128 sub-items. Closes #134. Refs #128.
🤖 Generated with Claude Code