Skip to content

Commit b895374

Browse files
hyperpolymathclaude
andcommitted
fix(stdlib): seed Some/None/Ok/Err builtins so stdlib/string.affine resolves standalone (Refs #122)
Option/Result were already builtin TYPE constructors and the Deno-ESM backend already shipped the Some/None/Ok/Err runtime; the only gap was the front-end never seeding the VALUE constructors, so char_at's Some(...)/None hit UndefinedVariable in resolution. - lib/resolve.ml: seed Some/None/Ok/Err as SKConstructor builtins - lib/typecheck.ml: generalised schemes + constructor_env entries, mirroring the enum-ctor path; user/prelude type decls still shadow (Hashtbl.replace in Symbol.define) - stdlib/string.affine: fix pre-existing let->let mut borrow errors in repeat/split/join/reverse_string that the now-passing resolve exposed Full codegen-deno suite green; no capitalized-stdlib regression. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
1 parent 46f5003 commit b895374

3 files changed

Lines changed: 60 additions & 11 deletions

File tree

lib/resolve.ml

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -80,6 +80,16 @@ let create_context () : context =
8080
(* Cmd Msg — linear side-effect obligation builtins (Stage 11) *)
8181
def "cmd_none";
8282
def "cmd_perform";
83+
(* Option / Result value constructors — seeded as builtin constructors so
84+
the honest stdlib (stdlib/string.affine `char_at`, stdlib/result.affine,
85+
…) resolves without importing the legacy stdlib/prelude. `Option`/`Result`
86+
are already builtin type constructors; this closes the matching value-side
87+
gap. A user/prelude `type Option`/`type Result` decl cleanly shadows these
88+
(Hashtbl.replace in Symbol.define). Issue #122. *)
89+
let defc name =
90+
let _ = Symbol.define ctx.symbols name SKConstructor Span.dummy Public in ()
91+
in
92+
defc "Some"; defc "None"; defc "Ok"; defc "Err";
8393
ctx
8494

8595
(** Record a use-site reference for a symbol (Phase C: find-references). *)

lib/typecheck.ml

Lines changed: 39 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1225,6 +1225,45 @@ let register_builtins (ctx : context) : unit =
12251225
lowers each to a JS intrinsic. char ::= TCon "Char". *)
12261226
let ty_char = TCon "Char" in
12271227
let opt t = TApp (TCon "Option", [t]) in
1228+
(* Option / Result value constructors — seeded as polymorphic builtin
1229+
schemes so the honest stdlib resolves without the legacy prelude
1230+
(mirrors the Resolve.create_context constructor seeding). Codegen
1231+
(codegen_deno.ml:111-114) already provides the Some/None/Ok/Err
1232+
runtime; this is purely the front-end type side. A user/prelude
1233+
`type Option`/`type Result` decl shadows these. Issue #122. *)
1234+
let res a b = TApp (TCon "Result", [a; b]) in
1235+
let fresh_named () =
1236+
let tv = fresh_tyvar 0 in
1237+
let v = (match tv with
1238+
| TVar r -> (match !r with Unbound (v, _) -> v | _ -> assert false)
1239+
| _ -> assert false) in
1240+
(v, tv)
1241+
in
1242+
let (v_none, t_none) = fresh_named () in
1243+
bind_scheme ctx "None"
1244+
{ sc_tyvars = [(v_none, Types.KType)]; sc_effvars = []; sc_rowvars = [];
1245+
sc_body = opt t_none };
1246+
Hashtbl.replace ctx.constructor_env "None" (opt t_none);
1247+
let (v_some, t_some) = fresh_named () in
1248+
let some_ty = TArrow (t_some, QOmega, opt t_some, EPure) in
1249+
bind_scheme ctx "Some"
1250+
{ sc_tyvars = [(v_some, Types.KType)]; sc_effvars = []; sc_rowvars = [];
1251+
sc_body = some_ty };
1252+
Hashtbl.replace ctx.constructor_env "Some" some_ty;
1253+
let (v_oka, t_oka) = fresh_named () in
1254+
let (v_okb, t_okb) = fresh_named () in
1255+
let ok_ty = TArrow (t_oka, QOmega, res t_oka t_okb, EPure) in
1256+
bind_scheme ctx "Ok"
1257+
{ sc_tyvars = [(v_oka, Types.KType); (v_okb, Types.KType)];
1258+
sc_effvars = []; sc_rowvars = []; sc_body = ok_ty };
1259+
Hashtbl.replace ctx.constructor_env "Ok" ok_ty;
1260+
let (v_erra, t_erra) = fresh_named () in
1261+
let (v_errb, t_errb) = fresh_named () in
1262+
let err_ty = TArrow (t_errb, QOmega, res t_erra t_errb, EPure) in
1263+
bind_scheme ctx "Err"
1264+
{ sc_tyvars = [(v_erra, Types.KType); (v_errb, Types.KType)];
1265+
sc_effvars = []; sc_rowvars = []; sc_body = err_ty };
1266+
Hashtbl.replace ctx.constructor_env "Err" err_ty;
12281267
bind_var ctx "string_get"
12291268
(TArrow (ty_string, QOmega, TArrow (ty_int, QOmega, ty_char, EPure), EPure));
12301269
bind_var ctx "string_sub"

stdlib/string.affine

Lines changed: 11 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -106,8 +106,8 @@ fn substring(s: String, start: Int, end: Int) -> String {
106106

107107
/// Repeat a string n times
108108
fn repeat(s: String, n: Int) -> String {
109-
let result = "";
110-
let i = 0;
109+
let mut result = "";
110+
let mut i = 0;
111111
while i < n {
112112
result = concat(result, s);
113113
i = i + 1;
@@ -122,18 +122,18 @@ fn split(s: String, delimiter: String) -> [String] {
122122

123123
if dlen == 0 {
124124
// Split into individual characters
125-
let result = [];
126-
let i = 0;
125+
let mut result = [];
126+
let mut i = 0;
127127
while i < slen {
128128
result = result ++ [string_sub(s, i, 1)];
129129
i = i + 1;
130130
}
131131
return result;
132132
}
133133

134-
let result = [];
135-
let current_start = 0;
136-
let i = 0;
134+
let mut result = [];
135+
let mut current_start = 0;
136+
let mut i = 0;
137137

138138
while i <= slen - dlen {
139139
if string_sub(s, i, dlen) == delimiter {
@@ -156,8 +156,8 @@ fn join(arr: [String], separator: String) -> String {
156156
return "";
157157
}
158158

159-
let result = arr[0];
160-
let i = 1;
159+
let mut result = arr[0];
160+
let mut i = 1;
161161
while i < len(arr) {
162162
result = concat(result, concat(separator, arr[i]));
163163
i = i + 1;
@@ -173,8 +173,8 @@ fn replace(s: String, from: String, to_str: String) -> String {
173173
/// Reverse a string
174174
fn reverse_string(s: String) -> String {
175175
let slen = len(s);
176-
let result = "";
177-
let i = slen - 1;
176+
let mut result = "";
177+
let mut i = slen - 1;
178178
while i >= 0 {
179179
result = concat(result, string_sub(s, i, 1));
180180
i = i - 1;

0 commit comments

Comments
 (0)