From afd81f62ff3f32ad877b816e1734fdca267471a3 Mon Sep 17 00:00:00 2001 From: Pedro Gomes Branquinho Date: Wed, 14 Oct 2026 19:09:18 -0300 Subject: [PATCH 01/17] test(class): defmethod dispatch on the five inspect* seq class symbols (ADR-0194) tools.reader's inspect* dispatches a multimethod on LazySeq, Cons and the three JVM inner seq classes; a defmethod on a class symbol resolves it at analyze time. Pins that LazySeq and Cons are native exact-tag classes whose methods are reached, and that PersistentVector$ChunkedSeq, PersistentArrayMap$Seq and PersistentHashMap$NodeSeq resolve as opaque class values that no cljw value is an instance of (AD-066 / AD-067). Supersedes the 2026-09-09 WIP b3b332fd, whose Cons-as-opaque assertions predate f8837bcc. Qualified-name assertions checked against JVM Clojure. --- test/clj/suites/class_type_test.clj | 52 +++++++++++++++++++++++++++++ 1 file changed, 52 insertions(+) diff --git a/test/clj/suites/class_type_test.clj b/test/clj/suites/class_type_test.clj index 885e603e3..c8cb9aa9c 100644 --- a/test/clj/suites/class_type_test.clj +++ b/test/clj/suites/class_type_test.clj @@ -135,3 +135,55 @@ (is (= "TransientVector" (pr-str (class (transient [])))))) (testing "class-level isa? still holds after the rename (isCallableClassName)" (is (= true (isa? (class +) clojure.lang.IFn))))) + +;; --- ADR-0194: the five seq class symbols tools.reader's `inspect*` +;; dispatches on. A defmethod on a class symbol resolves it at ANALYZE time, +;; so these forms loading at all is the first assertion. LazySeq and Cons +;; name types cljw has, so they are native exact-tag classes and their +;; methods are reached. The three JVM inner seq classes name types cljw has +;; no values of (its vector seq is ArraySeq, its map seq is PersistentList), +;; so they resolve as OPAQUE class values whose `instance?` is uniformly +;; false and whose methods are never reached (AD-066 / AD-067). +(defmulti inspect-shape + (fn [x] (cond (vector? x) :vector (map? x) :map :else (class x)))) +(defmethod inspect-shape clojure.lang.PersistentVector$ChunkedSeq [_] :vec-seq) +(defmethod inspect-shape clojure.lang.PersistentArrayMap$Seq [_] :map-seq) +(defmethod inspect-shape clojure.lang.PersistentHashMap$NodeSeq [_] :map-seq) +(defmethod inspect-shape clojure.lang.Cons [_] :cons) +(defmethod inspect-shape clojure.lang.LazySeq [_] :lazy-seq) +(defmethod inspect-shape :default [_] :other) + +(deftest native-seq-classes + (testing "LazySeq resolves and is the class of a lazy seq" + (is (= true (class? clojure.lang.LazySeq))) + (is (= true (= clojure.lang.LazySeq (class (map inc [1]))))) + (is (= true (instance? clojure.lang.LazySeq (map inc [1])))) + (is (= false (instance? clojure.lang.LazySeq [1]))) + (is (= false (instance? clojure.lang.LazySeq (range 3))))) + (testing "Cons is a native exact-tag class, as on the JVM" + (is (= true (class? clojure.lang.Cons))) + (is (= true (= clojure.lang.Cons (class (cons 1 [2 3]))))) + (is (= true (instance? clojure.lang.Cons (cons 1 [2 3])))))) + +(deftest opaque-jvm-seq-classes + (testing "each resolves as a class value distinct from the others" + (is (= true (class? clojure.lang.PersistentVector$ChunkedSeq))) + (is (= true (class? clojure.lang.PersistentArrayMap$Seq))) + (is (= true (class? clojure.lang.PersistentHashMap$NodeSeq))) + (is (= false (= clojure.lang.Cons clojure.lang.PersistentVector$ChunkedSeq))) + (is (= false (= clojure.lang.PersistentArrayMap$Seq + clojure.lang.PersistentHashMap$NodeSeq)))) + (testing "no cljw value is an instance of one (AD-066 / AD-067)" + (is (= false (instance? clojure.lang.PersistentVector$ChunkedSeq (seq [1 2 3])))) + (is (= false (instance? clojure.lang.PersistentArrayMap$Seq (seq {:a 1})))) + (is (= false (instance? clojure.lang.PersistentHashMap$NodeSeq + (seq (zipmap (range 20) (range 20)))))))) + +(deftest inspect-multimethod-dispatches + (testing "the native methods are reached" + (is (= :lazy-seq (inspect-shape (map inc [1 2])))) + (is (= :cons (inspect-shape (cons 1 [2 3]))))) + (testing "the opaque methods are dead: cljw seqs fall to :default (AD-066 / AD-067)" + (is (= :other (inspect-shape (seq [1 2 3])))) + (is (= :other (inspect-shape (seq (range 3))))) + (is (= :other (inspect-shape (seq {:a 1})))))) From f60306adc4200d40587b7783d24b8405e54df52b Mon Sep 17 00:00:00 2001 From: Pedro Gomes Branquinho Date: Wed, 14 Oct 2026 20:35:14 -0300 Subject: [PATCH 02/17] fix(vm): raise interop, set! and ctor errors at their form, and check error locations in the diff oracle (ADR-0036) The ADR-0036 dual-backend oracle compared only the Zig error tag for a failing case. It never checked WHERE the error was raised, so the VM could raise at 0:0 while TreeWalk reported the right line:column, and nothing caught it. evaluator.compare keeps the error-identity `equal` (6e1c72fb) and adds tree_walk_loc / vm_loc / loc_equal. Each position is sampled with error_info.peekLastError() right after its own backend run. runOnce does not reset the threadlocal slot, so compare clears it before each run; otherwise a stale payload would be read as this run's position. A run that fails without publishing a payload reports 0:0. Every diff fixture check (check, checkEqual, checkRaises) now asserts loc_equal. The new "error source location survives BOTH backends" test requires a real (non-zero) and equal position for set!, op_method_call, a constructor arity failure, and multi-line forms. The staging binary (b59d3363) raises the set!, .member and ctor cases with no location on the VM, so this test fails without the VM changes below. VM: every error_catalog.raise that passed an empty SourceLocation and has a located TreeWalk twin now uses instr_loc (as D-326 did for callFn): op_set_var, op_set_field, op_method_call, op_static_method_call (and its callFn), op_ctor_call (constructInstance), op_ns_import, the require/refer path, op_invoke_builtin, and the slot_out_of_range guards. The compiler stamps the form's loc before op_set_var, op_set_field, op_method_call, op_static_method_call and op_ctor_call, so the instruction reports the form, not its last argument. The stack_overflow raises keep `.{}` because their TreeWalk twins are unlocated too. Port of 04b0d0bb (worktree-agent-a96eb3d50b10efd45), never landed. Smell-audited: 2: Changes the locations passed to existing raise sites and adds three CompareResult fields plus one assertion helper; no new branching. vm.zig, compiler.zig and diff_test.zig are past the size ceiling; this grows them by a few lines with no new concept. --- src/eval/backend/vm.zig | 42 +++++++++--------- src/eval/backend/vm/compiler.zig | 11 +++++ src/eval/evaluator.zig | 55 ++++++++++++++++++++++- src/lang/diff_test.zig | 76 ++++++++++++++++++++++++++++++-- 4 files changed, 159 insertions(+), 25 deletions(-) diff --git a/src/eval/backend/vm.zig b/src/eval/backend/vm.zig index b8a0551f0..d098f2a00 100644 --- a/src/eval/backend/vm.zig +++ b/src/eval/backend/vm.zig @@ -527,7 +527,7 @@ inline fn stepOnce( }, .op_load_local => { if (instr.operand >= locals.len) - return error_catalog.raise(.slot_out_of_range, .{}, .{ .form = "Local", .index = instr.operand, .max = locals.len }); + return error_catalog.raise(.slot_out_of_range, instr_loc, .{ .form = "Local", .index = instr.operand, .max = locals.len }); if (sp >= stack.len) return operandOverflow(instr_loc); stack[sp] = locals[instr.operand]; @@ -535,7 +535,7 @@ inline fn stepOnce( }, .op_store_local => { if (instr.operand >= locals.len) - return error_catalog.raise(.slot_out_of_range, .{}, .{ .form = "let*", .index = instr.operand, .max = locals.len }); + return error_catalog.raise(.slot_out_of_range, instr_loc, .{ .form = "let*", .index = instr.operand, .max = locals.len }); if (sp == 0) return raiseInternal("vm: op_store_local on empty stack"); sp -= 1; locals[instr.operand] = stack[sp]; @@ -600,7 +600,7 @@ inline fn stepOnce( return raiseInternal("vm: op_ns_import site index out of range"); const imp = chunk.import_sites[instr.operand]; const here = env.current_ns orelse - return error_catalog.raise(.current_namespace_missing, .{}, .{ .sym = imp.simple }); + return error_catalog.raise(.current_namespace_missing, instr_loc, .{ .sym = imp.simple }); try here.addImport(env.alloc, imp.simple, imp.fqcn); if (sp >= stack.len) return operandOverflow(instr_loc); @@ -618,7 +618,7 @@ inline fn stepOnce( if (!env_mod.setBinding(var_ptr, val)) { const full = try std.fmt.allocPrint(rt.gpa, "{s}/{s}", .{ var_ptr.ns.name, var_ptr.name }); defer rt.gpa.free(full); - return error_catalog.raise(.var_set_not_bound, .{}, .{ .@"var" = full }); + return error_catalog.raise(.var_set_not_bound, instr_loc, .{ .@"var" = full }); } }, .op_set_field => { @@ -644,7 +644,7 @@ inline fn stepOnce( break; } } - if (!wrote) return error_catalog.raise(.symbol_unresolved, .{}, .{ .sym = field_name }); + if (!wrote) return error_catalog.raise(.symbol_unresolved, instr_loc, .{ .sym = field_name }); sp -= 2; stack[sp] = value; sp += 1; @@ -860,7 +860,7 @@ inline fn stepOnce( const lslot: usize = instr.operand >> 8; const cidx: usize = instr.operand & 0xFF; if (lslot >= locals.len) - return error_catalog.raise(.slot_out_of_range, .{}, .{ .form = "Local", .index = @as(u16, @intCast(lslot)), .max = locals.len }); + return error_catalog.raise(.slot_out_of_range, instr_loc, .{ .form = "Local", .index = @as(u16, @intCast(lslot)), .max = locals.len }); if (cidx >= chunk.constants.len) return raiseInternal("vm: local_const constant index out of range"); const a = locals[lslot]; @@ -893,7 +893,7 @@ inline fn stepOnce( const sa: usize = instr.operand >> 8; const sb: usize = instr.operand & 0xFF; if (sa >= locals.len or sb >= locals.len) - return error_catalog.raise(.slot_out_of_range, .{}, .{ .form = "Local", .index = @as(u16, @intCast(if (sa >= locals.len) sa else sb)), .max = locals.len }); + return error_catalog.raise(.slot_out_of_range, instr_loc, .{ .form = "Local", .index = @as(u16, @intCast(if (sa >= locals.len) sa else sb)), .max = locals.len }); const a = locals[sa]; const b = locals[sb]; const aop = intrinsic.fromLocalsOpcode(instr_op).?; @@ -931,7 +931,7 @@ inline fn stepOnce( const offset: i16 = @bitCast(chunk.instructions[ip].operand); ip += 1; if (sa >= locals.len) - return error_catalog.raise(.slot_out_of_range, .{}, .{ .form = "Local", .index = @as(u16, @intCast(sa)), .max = locals.len }); + return error_catalog.raise(.slot_out_of_range, instr_loc, .{ .form = "Local", .index = @as(u16, @intCast(sa)), .max = locals.len }); const a = locals[sa]; const b = if (info.b_is_const) bblk: { if (sb >= chunk.constants.len) @@ -939,7 +939,7 @@ inline fn stepOnce( break :bblk chunk.constants[sb]; } else bblk: { if (sb >= locals.len) - return error_catalog.raise(.slot_out_of_range, .{}, .{ .form = "Local", .index = @as(u16, @intCast(sb)), .max = locals.len }); + return error_catalog.raise(.slot_out_of_range, instr_loc, .{ .form = "Local", .index = @as(u16, @intCast(sb)), .max = locals.len }); break :bblk locals[sb]; }; const fast: ?Value = if (rt.core_arith_pristine) @@ -975,7 +975,7 @@ inline fn stepOnce( ip += 1; if (sp < nb) return raiseInternal("vm: op_recur_loop underflow"); if (base + nb > locals.len) - return error_catalog.raise(.slot_out_of_range, .{}, .{ .form = "loop*", .index = @as(u16, @intCast(base + nb)), .max = locals.len }); + return error_catalog.raise(.slot_out_of_range, instr_loc, .{ .form = "loop*", .index = @as(u16, @intCast(base + nb)), .max = locals.len }); const top: u16 = sp - @as(u16, @intCast(nb)); var k: usize = 0; while (k < nb) : (k += 1) { @@ -1096,7 +1096,7 @@ inline fn stepOnce( // through `op_call` + vtable). Per // `no_op_stub_forbidden.md`, raise rather than fall // through silently. - return error_catalog.raise(.feature_not_supported, .{}, .{ .name = "op_invoke_builtin" }); + return error_catalog.raise(.feature_not_supported, instr_loc, .{ .name = "op_invoke_builtin" }); }, .op_push_handler => { const offset: i16 = @bitCast(instr.operand); @@ -1303,7 +1303,7 @@ inline fn stepOnce( // lib_not_found renders the caret (tree_walk parity). const target_ns = try loader.loadOrFindNs(rt, env, spec.ns_name, instr_loc); const here = env.current_ns orelse - return error_catalog.raise(.current_namespace_missing, .{}, .{ .sym = spec.ns_name }); + return error_catalog.raise(.current_namespace_missing, instr_loc, .{ .sym = spec.ns_name }); if (spec.alias) |alias_name| { try env.setAlias(here, alias_name, target_ns); } @@ -1319,7 +1319,7 @@ inline fn stepOnce( .private_blocked => { const full = try std.fmt.allocPrint(rt.gpa, "{s}/{s}", .{ spec.ns_name, refer_name }); defer rt.gpa.free(full); - return error_catalog.raise(.private_access_error, .{}, .{ + return error_catalog.raise(.private_access_error, instr_loc, .{ .sym = full, .ns = spec.ns_name, }); @@ -1327,7 +1327,7 @@ inline fn stepOnce( .not_found => { const full = try std.fmt.allocPrint(rt.gpa, "{s}/{s}", .{ spec.ns_name, refer_name }); defer rt.gpa.free(full); - return error_catalog.raise(.symbol_unresolved, .{}, .{ .sym = full }); + return error_catalog.raise(.symbol_unresolved, instr_loc, .{ .sym = full }); }, } } @@ -1373,7 +1373,7 @@ inline fn stepOnce( // Shared resolver/dispatcher (deftype/record + java-surface // ``) — identical to TreeWalk's evalConstructorCall so a // `(java.io.File. …)` ctor works on both backends. - const new_val = try special_forms.constructInstance(rt, env, type_name, args_slice, .{}); + const new_val = try special_forms.constructInstance(rt, env, type_name, args_slice, instr_loc); sp -= arg_count; stack[sp] = new_val; sp += 1; @@ -1419,11 +1419,11 @@ inline fn stepOnce( stack[sp] = fv; sp += 1; } else if (cs_entry.field_only) { - return error_catalog.raise(.symbol_unresolved, .{}, .{ .sym = cs_entry.method_name }); + return error_catalog.raise(.symbol_unresolved, instr_loc, .{ .sym = cs_entry.method_name }); } else { if (cs_entry.cache.lookupWithCache(td, null, cs_entry.method_name, rt.protocol_generation)) |me| { if (me.method_val.tag() == .nil) - return error_catalog.raise(.feature_not_supported, .{}, .{ .name = "method declared but not implemented" }); + return error_catalog.raise(.feature_not_supported, instr_loc, .{ .name = "method declared but not implemented" }); const args_slice = stack[sp - arg_count .. sp]; const vt = rt.vtable orelse return error.NoVTable; // Frame the user `/` so the interop form @@ -1448,7 +1448,7 @@ inline fn stepOnce( stack[sp] = r; sp += 1; } else { - return error_catalog.raise(.protocol_no_satisfies, .{}, .{ + return error_catalog.raise(.protocol_no_satisfies, instr_loc, .{ .protocol = "<.member>", .method = cs_entry.method_name, .type_name = td.fqcn orelse "", @@ -1470,17 +1470,17 @@ inline fn stepOnce( const td = cs_entry.descriptor orelse return raiseInternal("vm: op_static_method_call missing descriptor (compiler bug)"); const me = td.lookupMethod(null, cs_entry.method_name) orelse { - return error_catalog.raise(.protocol_no_satisfies, .{}, .{ + return error_catalog.raise(.protocol_no_satisfies, instr_loc, .{ .protocol = "", .method = cs_entry.method_name, .type_name = td.fqcn orelse "", }); }; if (me.method_val.tag() == .nil) - return error_catalog.raise(.feature_not_supported, .{}, .{ .name = "static method declared but not implemented" }); + return error_catalog.raise(.feature_not_supported, instr_loc, .{ .name = "static method declared but not implemented" }); const args_slice = stack[sp - arg_count .. sp]; const vt = rt.vtable orelse return error.NoVTable; - const result = try vt.callFn(rt, env, me.method_val, args_slice, .{}); + const result = try vt.callFn(rt, env, me.method_val, args_slice, instr_loc); sp -= arg_count; stack[sp] = result; // Result loc = this call form (pops below sp_entry, so the sweep misses it). diff --git a/src/eval/backend/vm/compiler.zig b/src/eval/backend/vm/compiler.zig index d9f2dda8f..7584fe2bd 100644 --- a/src/eval/backend/vm/compiler.zig +++ b/src/eval/backend/vm/compiler.zig @@ -193,6 +193,9 @@ const Compiler = struct { fn compileSet(self: *Compiler, n: node_mod.SetNode) Error!void { try self.compileNode(n.value_expr); const idx = try self.addConstant(Value.encodeHeapPtr(.var_ref, n.var_ptr)); + // The value expr re-stamped `current_*`; op_set_var raises at the + // set! form itself (TreeWalk evalSet's n.loc, ADR-0036 error half). + self.stampLoc(n.loc); try self.emit(.op_set_var, idx); } @@ -205,6 +208,7 @@ const Compiler = struct { try self.compileNode(n.value_expr); const name_val = try string_mod.alloc(self.rt, n.field_name); const idx = try self.addConstant(name_val); + self.stampLoc(n.loc); try self.emit(.op_set_field, idx); } @@ -740,6 +744,9 @@ const Compiler = struct { .type_name = name_dup, .arg_count = @intCast(n.args.len), }); + // Raise at the ctor form, not its last argument + // (TreeWalk evalConstructorCall's n.loc, ADR-0036 error half). + self.stampLoc(n.loc); try self.emit(.op_ctor_call, ctor_idx); }, .instance_member => { @@ -757,6 +764,9 @@ const Compiler = struct { .arg_count = total_args, .field_only = n.field_only, }); + // Raise at the interop form, not its last argument + // (TreeWalk evalInstanceMember's n.loc, ADR-0036 error half). + self.stampLoc(n.loc); try self.emit(.op_method_call, cs_idx); }, .static_method => { @@ -773,6 +783,7 @@ const Compiler = struct { .arg_count = arg_count, .descriptor = td, }); + self.stampLoc(n.loc); try self.emit(.op_static_method_call, cs_idx); }, } diff --git a/src/eval/evaluator.zig b/src/eval/evaluator.zig index 98f07e7a8..d2ef7609f 100644 --- a/src/eval/evaluator.zig +++ b/src/eval/evaluator.zig @@ -32,6 +32,7 @@ const tree_walk = @import("backend/tree_walk.zig"); const vm = @import("backend/vm.zig"); const vm_compiler = @import("backend/vm/compiler.zig"); const driver = @import("driver.zig"); +const error_info = @import("../runtime/error/info.zig"); pub const CompareResult = struct { tree_walk: anyerror!Value, @@ -39,8 +40,40 @@ pub const CompareResult = struct { /// `true` when both backends produced the same NaN-boxed bit pattern, or /// failed with the same Zig error. equal: bool, + /// Source position of the error each backend raised; null when that + /// backend returned a value. Only `line`/`column` are captured — the + /// `file` field of a fixture-analysed form is "unknown" on both + /// backends and carries no signal. + tree_walk_loc: ?ErrorPos = null, + vm_loc: ?ErrorPos = null, + /// `true` when both backends agree on WHERE the failure is: neither + /// raised, or both raised at the same line:column. The error half of + /// the dual-backend contract (ADR-0036) — a backend that raises the + /// same Kind at 0:0 while the other reports 3:11 is a parity break, + /// invisible to `equal` (which only compares returned Values). + loc_equal: bool = true, }; +/// The comparable part of a raised error's `SourceLocation`. +pub const ErrorPos = struct { + line: u32, + column: u16, +}; + +/// The position of the error a just-finished backend run raised, or null +/// when the run returned a value. Reads the threadlocal payload without +/// clearing it, so the caller's own error handling still sees it; must be +/// called before the next run overwrites the slot. A run that failed +/// without publishing a payload (a user throw, OOM) reports 0:0, the same +/// position a dropped location has, rather than null ("did not raise"). +fn errorPos(result: anyerror!Value) ?ErrorPos { + _ = result catch { + const info = error_info.peekLastError() orelse return .{ .line = 0, .column = 0 }; + return .{ .line = info.location.line, .column = info.location.column }; + }; + return null; +} + pub fn compare( rt: *Runtime, env: *Env, @@ -48,11 +81,20 @@ pub fn compare( arena: std.mem.Allocator, source: []const u8, ) CompareResult { + // runOnce does not reset the threadlocal error slot, so clear it before + // each run: a stale payload from an earlier raise must not be read as + // this run's position. + error_info.clearLastError(); tree_walk.installVTable(rt); const tw_value = runOnce(rt, env, table, arena, source, .tree_walk); + // Read the raise position NOW: the threadlocal payload is a single slot + // that the VM run below overwrites. + const tw_loc = errorPos(tw_value); + error_info.clearLastError(); vm.installVTable(rt); const vm_value = runOnce(rt, env, table, arena, source, .vm); + const vm_loc = errorPos(vm_value); const equal = if (tw_value) |tw| blk: { const vm_v = vm_value catch break :blk false; @@ -61,7 +103,18 @@ pub fn compare( _ = vm_value catch |vm_err| break :blk tw_err == vm_err; break :blk false; }; - return .{ .tree_walk = tw_value, .vm = vm_value, .equal = equal }; + const loc_equal = if (tw_loc) |a| + if (vm_loc) |b| a.line == b.line and a.column == b.column else false + else + vm_loc == null; + return .{ + .tree_walk = tw_value, + .vm = vm_value, + .equal = equal, + .tree_walk_loc = tw_loc, + .vm_loc = vm_loc, + .loc_equal = loc_equal, + }; } pub const BackendChoice = enum { tree_walk, vm }; diff --git a/src/lang/diff_test.zig b/src/lang/diff_test.zig index 1af1c9fea..824992841 100644 --- a/src/lang/diff_test.zig +++ b/src/lang/diff_test.zig @@ -74,20 +74,47 @@ const Fixture = struct { fn check(self: *Fixture, source: []const u8, expected: i64) !void { const r = evaluator.compare(&self.rt, &self.env, &self.table, self.arena.allocator(), source); + try expectLocParity(r, source); try testing.expect(r.equal); try testing.expectEqual(expected, (try r.tree_walk).asInteger()); } + /// Both backends raise the same error at the same source position + /// (ADR-0036 error half). For cases whose contract is the failure itself. + fn checkRaises(self: *Fixture, source: []const u8, expected: anyerror) !void { + const r = evaluator.compare(&self.rt, &self.env, &self.table, self.arena.allocator(), source); + try testing.expectError(expected, r.tree_walk); + try testing.expectError(expected, r.vm); + try expectLocParity(r, source); + } + /// Assert only that both backends agree (VM == TreeWalk) — for results whose /// type is not an inline integer (bigint / float / string), where /// `asInteger()` cannot be used. `r.equal` is the dual-backend parity oracle. fn checkEqual(self: *Fixture, source: []const u8) !void { const r = evaluator.compare(&self.rt, &self.env, &self.table, self.arena.allocator(), source); + try expectLocParity(r, source); _ = try r.tree_walk; // surface an eval error rather than a silent mismatch try testing.expect(r.equal); } }; +/// The shared error-location assertion every fixture check runs (ADR-0036 +/// error half): whenever either backend raises, both must report the same +/// line:column. `loc_equal` is true when neither raised, so value cases pass +/// through; a raise on one backend only, or at a different position, fails +/// here with both positions printed. +fn expectLocParity(r: evaluator.CompareResult, source: []const u8) !void { + if (r.loc_equal) return; + const tw = r.tree_walk_loc orelse evaluator.ErrorPos{ .line = 0, .column = 0 }; + const v = r.vm_loc orelse evaluator.ErrorPos{ .line = 0, .column = 0 }; + std.debug.print( + "error-location parity broken for: {s}\n tree_walk {d}:{d} (raised: {})\n vm {d}:{d} (raised: {})\n", + .{ source, tw.line, tw.column, r.tree_walk_loc != null, v.line, v.column, r.vm_loc != null }, + ); + return error.TestUnexpectedResult; +} + test "diff: D-346 chunked collection literals preserve order and nested evaluation" { var f: Fixture = undefined; try Fixture.init(&f, testing.allocator); @@ -120,9 +147,7 @@ test "diff: D-413 unresolved symbol → clean symbol_unresolved, not a panic" { var f: Fixture = undefined; try Fixture.init(&f, testing.allocator); defer f.deinit(); - const r = evaluator.compare(&f.rt, &f.env, &f.table, f.arena.allocator(), "(re-matcher 1)"); - try testing.expectError(error.NameError, r.tree_walk); - try testing.expectError(error.NameError, r.vm); + try f.checkRaises("(re-matcher 1)", error.NameError); } test "diff: D-563b def meta — user ^meta + compiler :line land on the Var in BOTH backends (op_var_meta ≡ evalDef meta_expr)" { @@ -1800,3 +1825,48 @@ test "diff: op_get / op_nth collection intrinsics (O-043, both backends)" { // fixture's literal-arg quirk in TreeWalk; the value path is what matters). try f.check("(let [v [[1 2] [3 4]]] (count (nth v 0 nil)))", 2); } + +/// Assert the error-location half of the dual-backend contract (ADR-0036): +/// both backends must raise, and both must report the SAME source position. +/// A raise at line 0 is rejected on either side — "both agree on nothing" is +/// vacuous parity, and 0:0 is exactly what a dropped location looks like. +fn checkErrorLoc(f: *Fixture, source: []const u8) !void { + const r = evaluator.compare(&f.rt, &f.env, &f.table, f.arena.allocator(), source); + const tw = r.tree_walk_loc orelse { + std.debug.print("tree_walk did not raise for: {s}\n", .{source}); + return error.TestExpectedRaise; + }; + const vm_pos = r.vm_loc orelse { + std.debug.print("vm did not raise for: {s}\n", .{source}); + return error.TestExpectedRaise; + }; + if (tw.line == 0 or vm_pos.line == 0 or !r.loc_equal) { + std.debug.print( + "error-location parity broken for: {s}\n tree_walk {d}:{d}\n vm {d}:{d}\n", + .{ source, tw.line, tw.column, vm_pos.line, vm_pos.column }, + ); + return error.TestUnexpectedResult; + } +} + +test "diff: error source location survives BOTH backends (ADR-0036 error half)" { + var f: Fixture = undefined; + try Fixture.init(&f, testing.allocator); + defer f.deinit(); + // Control arm: a builtin raising through op_call already threads the call + // form's loc into `vt.callFn`, so this one held before the fix. + try checkErrorLoc(&f, "(/ 1 0)"); + // `set!` on a var with no active thread binding → var_set_not_bound, raised + // by the VM's op_set_var directly rather than through `vt.callFn`. + try checkErrorLoc(&f, "(do (def svl 1) (set! svl 2))"); + // Interop member on a receiver whose type has no such method → raised by + // the VM's op_method_call directly. + try checkErrorLoc(&f, "(.noSuchMember \"s\")"); + // Constructor arity failure → raised inside constructInstance with the + // loc the backend hands it (TreeWalk n.loc, VM op_ctor_call instr_loc). + try checkErrorLoc(&f, "(MapEntry. 1)"); + // Multi-line source: the position must be the inner form's own line and + // column, not the enclosing form's and not the last argument's. + try checkErrorLoc(&f, "(do\n (def svl2 1)\n (set! svl2\n 2))"); + try checkErrorLoc(&f, "(let [x 1]\n (MapEntry. x))"); +} From 75d98e34adf3889df7199dfbc3e086dbf83adc78 Mon Sep 17 00:00:00 2001 From: Pedro Gomes Branquinho Date: Wed, 14 Oct 2026 20:52:51 -0300 Subject: [PATCH 03/17] style(diff): drop em-dashes from the error-location oracle comments Smell-audited: 0: comment punctuation only, no code change. --- src/eval/evaluator.zig | 4 ++-- src/lang/diff_test.zig | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/src/eval/evaluator.zig b/src/eval/evaluator.zig index d2ef7609f..58c84cfeb 100644 --- a/src/eval/evaluator.zig +++ b/src/eval/evaluator.zig @@ -41,14 +41,14 @@ pub const CompareResult = struct { /// failed with the same Zig error. equal: bool, /// Source position of the error each backend raised; null when that - /// backend returned a value. Only `line`/`column` are captured — the + /// backend returned a value. Only `line`/`column` are captured: the /// `file` field of a fixture-analysed form is "unknown" on both /// backends and carries no signal. tree_walk_loc: ?ErrorPos = null, vm_loc: ?ErrorPos = null, /// `true` when both backends agree on WHERE the failure is: neither /// raised, or both raised at the same line:column. The error half of - /// the dual-backend contract (ADR-0036) — a backend that raises the + /// the dual-backend contract (ADR-0036). A backend that raises the /// same Kind at 0:0 while the other reports 3:11 is a parity break, /// invisible to `equal` (which only compares returned Values). loc_equal: bool = true, diff --git a/src/lang/diff_test.zig b/src/lang/diff_test.zig index 824992841..9906b16db 100644 --- a/src/lang/diff_test.zig +++ b/src/lang/diff_test.zig @@ -1828,7 +1828,7 @@ test "diff: op_get / op_nth collection intrinsics (O-043, both backends)" { /// Assert the error-location half of the dual-backend contract (ADR-0036): /// both backends must raise, and both must report the SAME source position. -/// A raise at line 0 is rejected on either side — "both agree on nothing" is +/// A raise at line 0 is rejected on either side: "both agree on nothing" is /// vacuous parity, and 0:0 is exactly what a dropped location looks like. fn checkErrorLoc(f: *Fixture, source: []const u8) !void { const r = evaluator.compare(&f.rt, &f.env, &f.table, f.arena.allocator(), source); From 012f8ee0be8a925243fba8ab6d158fa26376bdc6 Mon Sep 17 00:00:00 2001 From: Pedro Gomes Branquinho Date: Wed, 14 Oct 2026 20:55:21 -0300 Subject: [PATCH 04/17] fix(runtime): a user class is matched by descriptor identity, never by its simple name (ADR-0201) A user class IS its TypeDescriptor. instance?, .isInstance, class isa? and multimethod dispatch now answer by descriptor identity (class_name.isInstanceOfClass / classIsaOf / descriptorIsa), so they agree with (= (class x) C) for a redefined record, a namesake defined in another namespace and a reify class. The record-interface, IFn and clojure.lang.Fn arms route through descriptorIsa instead of bypassing identity. multimethod: an instance dispatch value relates to a Named value only by derive; the D-082 instance-vs-Named simple-name arm is gone. The type_redefinition diff corpus pins every redefinition scenario on both backends. Ported from swarm/td-uaf (94a2ed45, d4d028a3, c0932e99). Smell-audited: 2: replaces name-keyed membership checks with one descriptor-identity predicate and deletes the D-082 name arm; no new branching surface. --- src/lang/primitive/core.zig | 51 +++-- src/runtime/class_name.zig | 167 ++++++++++++-- src/runtime/java/lang/Class.zig | 8 +- src/runtime/multimethod.zig | 129 +++-------- src/runtime/type_descriptor.zig | 33 ++- test/diff/clj_corpus/type_redefinition.txt | 254 +++++++++++++++++++++ 6 files changed, 480 insertions(+), 162 deletions(-) create mode 100644 test/diff/clj_corpus/type_redefinition.txt diff --git a/src/lang/primitive/core.zig b/src/lang/primitive/core.zig index 5c3954a68..96f2a0c7a 100644 --- a/src/lang/primitive/core.zig +++ b/src/lang/primitive/core.zig @@ -51,36 +51,38 @@ const big_int = @import("../../runtime/numeric/big_int.zig"); /// `(map (partial instance? C) …)`, works exactly as in clj). Returns true iff /// `x` is an instance of `c`. /// -/// `runtime/class_name.zig::isInstance` is the COMPLETE membership oracle -/// (native exact / interface multi-tag / Throwable hierarchy / Object-universal / -/// user TypeDescriptor walk; an opaque collapsed class — Integer / BigInteger — -/// is in no table so it returns false, clj-faithful). So this primitive is just -/// `fqcn → isInstance` with no opaque/Object/Number special-case (those dissolved -/// into the oracle per ADR-0128). A non-class `c` raises (clj: ClassCastException). +/// `runtime/class_name.zig` is the COMPLETE membership oracle (native exact / +/// interface multi-tag / Throwable hierarchy / Object-universal / descriptor +/// identity for a user class; an opaque collapsed class, Integer / BigInteger, +/// is in no table so it returns false, clj-faithful). So this primitive only +/// picks the entry point, with no opaque/Object/Number special-case (those +/// dissolved into the oracle per ADR-0128). A non-class `c` raises (clj: +/// ClassCastException). pub fn instanceOf(rt: *Runtime, env: *Env, args: []const Value, loc: SourceLocation) anyerror!Value { _ = rt; _ = env; try error_catalog.checkArity("instance?", args, 2, loc); - // The class arg is either a class VALUE (`.type_descriptor` — String / Number / - // Object / a user deftype / an exception class / `clojure.lang.IFn` FQCN) OR a - // cljw interface-marker PROTOCOL (`.protocol` — bare `IFn`/`ISeq`/`IPersistentMap`/ - // `IDeref`/… resolve to the defprotocol Var, the cljw representation of the clj - // interface). Both name a class in the membership oracle, so dispatch by fqcn. - const fqcn = switch (args[0].tag()) { - .type_descriptor => td_mod.asTypeDescriptorRef(args[0]).fqcn orelse return .false_val, - .protocol => protocol_mod.asProtocol(args[0]).fqcn(), + // The class arg is either a class VALUE (`.type_descriptor`: String / Number / + // Object / a user deftype / an exception class / a `clojure.lang.IFn` FQCN), + // answered through its descriptor so a user class is matched by identity + // (ADR-0201), OR a cljw interface-marker PROTOCOL (`.protocol`: bare `IFn` / + // `ISeq` / `IPersistentMap` / `IDeref` resolve to the defprotocol Var, the + // cljw representation of the clj interface), which names an interface. + const member = switch (args[0].tag()) { + .type_descriptor => class_name.isInstanceOfClass(args[1], td_mod.asTypeDescriptorRef(args[0])), + .protocol => class_name.isInstance(args[1], protocol_mod.asProtocol(args[0]).fqcn()), else => return error_catalog.raise(.type_arg_invalid, loc, .{ .fn_name = "instance?", .expected = "class", .actual = @tagName(args[0].tag()), }), }; - return if (class_name.isInstance(args[1], fqcn)) .true_val else .false_val; + return Value.initBoolean(member); } /// `(-class-isa? child parent)` — true iff both args are class values /// (TypeDescriptor) and `child`'s class is `parent` or a subclass of it, via the -/// shared `class_name.classIsa` (Object/Number/IFn + interface markers + the host +/// shared `class_name.classIsaOf` (Object/Number/IFn + interface markers + the host /// exception/parent hierarchy — shared with multimethod dispatch so the two /// cannot drift, D-464). The class-hierarchy arm of `isa?` (clj's /// `Class.isAssignableFrom` step); equality + the ad-hoc `derive` hierarchy stay @@ -91,13 +93,16 @@ pub fn classIsaPrim(rt: *Runtime, env: *Env, args: []const Value, loc: SourceLoc try error_catalog.checkArity("__class-isa?", args, 2, loc); if (args[0].tag() != .type_descriptor or args[1].tag() != .type_descriptor) return .false_val; - const child = td_mod.asTypeDescriptorRef(args[0]).fqcn orelse return .false_val; - const parent = td_mod.asTypeDescriptorRef(args[1]).fqcn orelse return .false_val; - // The class-vs-class hierarchy step (ADR-0109 Object/Number/IFn + D-293 - // interface markers + the exception/parent hierarchy) lives in the shared - // `class_name.classIsa` so `isa?` and multimethod dispatch cannot drift - // (D-464). The ad-hoc `derive` hierarchy + equality stay in the `.clj` isa?. - return if (class_name.classIsa(child, parent)) .true_val else .false_val; + // The class-vs-class hierarchy step lives in the shared + // `class_name.classIsaOf` so `isa?` and multimethod dispatch cannot drift + // (D-464): a user class by descriptor identity and by what it declares, + // never by its name (ADR-0201); a native class by name (ADR-0109 + // Object/Number/IFn, D-293 interface markers, the exception/parent + // hierarchy). The ad-hoc `derive` hierarchy + equality stay in the `.clj` + // isa?. + const child = td_mod.asTypeDescriptorRef(args[0]); + const parent = td_mod.asTypeDescriptorRef(args[1]); + return Value.initBoolean(class_name.classIsaOf(child, parent)); } /// Java String's immediate interfaces plus Object. JVM's `Class.getInterfaces` diff --git a/src/runtime/class_name.zig b/src/runtime/class_name.zig index bbb736102..30f5df0f3 100644 --- a/src/runtime/class_name.zig +++ b/src/runtime/class_name.zig @@ -28,9 +28,13 @@ //! - **Throwable hierarchy**: delegates to `host_class.matches` //! (covers `Throwable` / `Exception` / `RuntimeException` / //! `ExceptionInfo` etc.). -//! - **User types** (`defrecord` / `deftype` / `reify`): walks the -//! `TypeDescriptor.parent` chain, comparing `fqcn` against the -//! class name. +//! - **User classes** (`defrecord` / `deftype` / `reify`) are NOT matched +//! by name (ADR-0201). A user class is its TypeDescriptor, so membership +//! in one is descriptor identity: `isInstanceOfClass` / `classIsaOf`, +//! which take the class VALUE's descriptor. The name oracle below only +//! answers which host interfaces a user type declares (its +//! `protocol_impls` / `method_table`), and matches a descriptor's own +//! fqcn only for a native host-surface descriptor. //! //! ## DIVERGENCE from cw v0 //! @@ -308,13 +312,14 @@ fn isInterfaceName(simple: []const u8) bool { /// 1. Throwable hierarchy (host_class.matches walks the parent chain). /// 2. Native exact-tag table (`String`, `Long`, etc.). /// 3. Interface-shaped multi-tag set (`IFn`, `Number`, `IPersistent*`). -/// 4. User TypeDescriptor walk for `.typed_instance` / `.reified_instance` -/// receivers — comparing the simple name against each ancestor's -/// `fqcn`. +/// 4. Descriptor walk for `.typed_instance` / `.reified_instance` / +/// `.host_instance` receivers: the interfaces a type declares, plus the +/// own fqcn of a native host-surface descriptor (see `matchUserType`). /// -/// Unknown class names return false here; callers (= the -/// `__instance?` primitive) should pre-check with `isKnown` and raise -/// loud rather than relying on silent false. +/// This is the NAME oracle, for host / native classes. A user class is +/// never answered by name; callers holding a class VALUE go through +/// `isInstanceOfClass`, which routes a user class to descriptor identity. +/// Unknown class names return false here. pub fn isInstance(v: Value, class_name: []const u8) bool { const simple = normalizeClassName(class_name); @@ -339,6 +344,59 @@ pub fn isInstance(v: Value, class_name: []const u8) bool { return false; } +/// `(instance? C v)` for a class VALUE, where `class_td` is the descriptor `C` +/// evaluates to. The entry point for every caller that holds a class rather +/// than a name (`instance?`, `Class.isInstance`). A user class is answered by +/// identity (ADR-0201): `v` is a member iff `class_td` is `v`'s descriptor or on +/// its parent chain, so a redefined `R` and its previous vintage, or `aaa.Point` +/// and `bbb.Point`, never answer for each other. A host / native class has no +/// user descriptor and goes to the name oracle `isInstance`. +pub fn isInstanceOfClass(v: Value, class_td: *const TypeDescriptor) bool { + if (class_td.isUserClass()) { + const own = userInstanceDescriptor(v) orelse return false; + return descendsFrom(own, class_td); + } + const name = class_td.fqcn orelse return false; + return isInstance(v, name); +} + +/// Class-vs-class `isa?` over class VALUES, shared by the `isa?` primitive and +/// multimethod dispatch so the two cannot drift (D-464). Identity first. A +/// user-class PARENT is reached only along `child`'s parent chain. A user-class +/// CHILD under a host parent is a subclass of Object and of what it declares +/// (`descriptorIsa`, the relation `instance?` reads), never of a host class that +/// merely shares its simple name: a `(deftype BigInt [])` is not a Number. Only +/// a native child keeps the name relation `classIsa` (ADR-0201). +pub fn classIsaOf(child: *const TypeDescriptor, parent: *const TypeDescriptor) bool { + if (child == parent) return true; + if (parent.isUserClass()) return descendsFrom(child, parent); + const parent_name = parent.fqcn orelse return false; + if (child.isUserClass()) { + const simple = normalizeClassName(parent_name); + return host_class.isUniversalClass(simple) or descriptorIsa(child, simple); + } + return classIsa(child.fqcn orelse "", parent_name); +} + +/// The descriptor a user-class instance carries, or null for any other value +/// (a host_instance's descriptor is a native surface, never a user class). +fn userInstanceDescriptor(v: Value) ?*const TypeDescriptor { + return switch (v.tag()) { + .typed_instance => v.decodePtr(*const TypedInstance).descriptor, + .reified_instance => v.decodePtr(*const ReifiedInstance).descriptor, + else => null, + }; +} + +/// True iff `ancestor` is `td` itself or on `td`'s parent chain, by pointer. +fn descendsFrom(td: *const TypeDescriptor, ancestor: *const TypeDescriptor) bool { + var cursor: ?*const TypeDescriptor = td; + while (cursor) |t| : (cursor = t.parent) { + if (t == ancestor) return true; + } + return false; +} + fn isThrowableTag(t: Tag) bool { return switch (t) { .ex_info => true, @@ -408,15 +466,15 @@ fn displayClassTag(name: []const u8) ?Tag { return M.get(name); } -/// Class-vs-class `isa?` (the `(isa? )` hierarchy step), by fqcn -/// name. SHARED by `core.classIsaPrim` (the `isa?` primitive) and -/// `multimethod.isaCheck` (method dispatch) so the two cannot drift (D-464 — a -/// `(defmethod f java.lang.Number)` must be found for a `Long` dispatch value -/// exactly as `(isa? Long Number)` is true). Order mirrors clj's isa? class -/// step: identity, universal Object, narrow Number, narrow IFn, interface-marker -/// membership, then the host exception/parent hierarchy. The ad-hoc `derive` -/// hierarchy and non-class isa? stay with the callers. -pub fn classIsa(child: []const u8, parent: []const u8) bool { +/// Class-vs-class `isa?` BY NAME, for a host / native parent: the name half of +/// `classIsaOf`, which is the entry both `core.classIsaPrim` (the `isa?` +/// primitive) and `multimethod.isaCheck` (method dispatch) call so the two +/// cannot drift (D-464: a `(defmethod f java.lang.Number)` must be found for a +/// `Long` dispatch value exactly as `(isa? Long Number)` is true). Order mirrors +/// clj's isa? class step: identity, universal Object, narrow Number, narrow IFn, +/// interface-marker membership, then the host exception/parent hierarchy. The +/// ad-hoc `derive` hierarchy and non-class isa? stay with the callers. +fn classIsa(child: []const u8, parent: []const u8) bool { if (std.mem.eql(u8, child, parent)) return true; if (host_class.isUniversalClass(parent)) return true; if (host_class.isNumberClass(parent)) return host_class.isNumericClass(child); @@ -442,11 +500,27 @@ fn matchUserType(v: Value, simple: []const u8) bool { .host_instance => @import("host_instance.zig").asHostInstance(v).descriptor, else => return false, }; + return descriptorIsa(td, simple); +} + +/// True iff a value whose descriptor is `td` is an instance of the host class +/// named `simple` (normalised). The descriptor-level half of `matchUserType`, +/// shared with `classIsaOf` so `(instance? C x)` and `(isa? (class x) C)` read +/// ONE relation. A user class answers only from what it DECLARES (its +/// interfaces), never from its own name; a native host-surface descriptor also +/// answers to its own fqcn (ADR-0201). +fn descriptorIsa(td: *const TypeDescriptor, simple: []const u8) bool { var cursor: ?*const TypeDescriptor = td; while (cursor) |t| { - if (t.fqcn) |fqcn| { - if (std.mem.eql(u8, fqcn, simple)) return true; - if (std.mem.eql(u8, normalizeClassName(fqcn), simple)) return true; + // Only a native host-surface descriptor is its NAME. A user class's + // fqcn is a display string it may share with a host interface (a + // `(deftype Sorted [])` is not `clojure.lang.Sorted`) or with another + // user class, so it never answers here (ADR-0201). + if (!t.isUserClass()) { + if (t.fqcn) |fqcn| { + if (std.mem.eql(u8, fqcn, simple)) return true; + if (std.mem.eql(u8, normalizeClassName(fqcn), simple)) return true; + } } // The declared interfaces (ADR-0116 Decision B). `protocol_impls` holds // what the type DECLARED; the method table is not consulted, because a @@ -676,3 +750,54 @@ test "isCallableClassName derives from the IFn tag set" { try testing.expect(isClassInterfaceMember("TransientArrayMap", "Counted")); try testing.expect(!isClassInterfaceMember("Cons", "Counted")); } + +test "ADR-0201: a user class is matched by descriptor identity, never by its simple name" { + const Runtime = @import("runtime.zig").Runtime; + const td_mod = @import("type_descriptor.zig"); + var threaded = std.Io.Threaded.init(testing.allocator, .{}); + defer threaded.deinit(); + var rt = Runtime.init(threaded.io(), testing.allocator); + defer rt.deinit(); + + // Two vintages of user.R, plus a namesake in another namespace. + const old = try td_mod.registerType(&rt, "R", "user", &.{"a"}, &.{}, .defrecord); + const old_inst = try td_mod.allocInstance(&rt, old, &.{Value.initInteger(1)}); + const new = try td_mod.registerType(&rt, "R", "user", &.{ "a", "b" }, &.{}, .defrecord); + const namesake = try td_mod.registerType(&rt, "R", "other", &.{"a"}, &.{}, .defrecord); + try testing.expect(old != new); + + try testing.expect(isInstanceOfClass(old_inst, old)); + try testing.expect(!isInstanceOfClass(old_inst, new)); + try testing.expect(!isInstanceOfClass(old_inst, namesake)); + try testing.expect(!isInstanceOfClass(Value.initInteger(1), old)); + try testing.expect(classIsaOf(old, old)); + try testing.expect(!classIsaOf(old, new)); + try testing.expect(!classIsaOf(new, old)); + try testing.expect(!classIsaOf(namesake, old)); + // The name oracle no longer answers for a user class by its display name. + try testing.expect(!isInstance(old_inst, "R")); + + // Under a host parent a user class is an Object, and is NOT the subclass of + // a host class that merely shares its simple name. + const object = try rt.classDescriptor("Object"); + try testing.expect(classIsaOf(old, object)); + try testing.expect(isInstanceOfClass(old_inst, object)); + const user_big_int = try td_mod.registerType(&rt, "BigInt", "user", &.{}, &.{}, .deftype); + try testing.expect(!classIsaOf(user_big_int, try rt.classDescriptor("Number"))); + try testing.expect(classIsaOf(user_big_int, object)); + + // A reify descriptor has no name at all and is still its own class. + const reify_td: TypeDescriptor = .{ + .fqcn = null, + .kind = .reify_anon, + .field_layout = null, + .protocol_impls = &.{}, + .method_table = &.{}, + .parent = null, + .meta = .nil_val, + }; + const reified = try td_mod.allocReifiedInstance(&rt, &reify_td); + try testing.expect(isInstanceOfClass(reified, &reify_td)); + try testing.expect(!isInstanceOfClass(reified, old)); + try testing.expect(classIsaOf(&reify_td, object)); +} diff --git a/src/runtime/java/lang/Class.zig b/src/runtime/java/lang/Class.zig index 8279e9ee2..b064def83 100644 --- a/src/runtime/java/lang/Class.zig +++ b/src/runtime/java/lang/Class.zig @@ -60,16 +60,16 @@ fn getSimpleName(rt: *Runtime, env: *Env, args: []const Value, loc: SourceLocati } /// `(.isInstance klass obj)` — true iff `obj` is an instance of `klass`. Routes -/// through the shared `class_name.isInstance` predicate (native tags + interface -/// sets + Throwable hierarchy + user TypeDescriptor walk). JVM reference: +/// through the same `class_name.isInstanceOfClass` entry `instance?` uses +/// (native tags + interface sets + Throwable hierarchy by name, descriptor +/// identity for a user class per ADR-0201). JVM reference: /// java.lang.Class#isInstance. fn isInstance(rt: *Runtime, env: *Env, args: []const Value, loc: SourceLocation) anyerror!Value { _ = rt; _ = env; try error_catalog.checkArity(".isInstance", args, 2, loc); const td = type_descriptor.asTypeDescriptorRef(args[0]); - const name = td.fqcn orelse return .false_val; - return Value.initBoolean(class_name.isInstance(args[1], name)); + return Value.initBoolean(class_name.isInstanceOfClass(args[1], td)); } /// Populate the per-Runtime `.type_descriptor` native descriptor's method table diff --git a/src/runtime/multimethod.zig b/src/runtime/multimethod.zig index 70dd1d373..1c6a7daf2 100644 --- a/src/runtime/multimethod.zig +++ b/src/runtime/multimethod.zig @@ -153,13 +153,11 @@ pub fn isPreferred(prefer_table: Value, x: Value, y: Value) !bool { return try set_mod.contains(preferred_over, y); } -/// cw v1 `isa?` check: equality + hierarchy ancestors-map lookup + -/// TypeDescriptor parent walk. Mirrors `clojure.core/isa?` steps -/// 1 + 3. Step 2 (`Class.isAssignableFrom`) and step 4 (`supers` -/// walk) have no JVM-direct equivalent in cw v1 per ADR-0007 -/// Option β + `.claude/rules/no_jvm_specific_assumption.md` — the -/// `typeDescriptorIsa` walk is the cw-side replacement (DIVERGENCE -/// from JVM class hierarchy). +/// cw v1 `isa?` check for multimethod dispatch, mirroring `clojure.core/isa?`: +/// equality, element-wise vectors, the class-vs-class step through the shared +/// `class_name.classIsaOf` (clj's `Class.isAssignableFrom` step, the same +/// function the `isa?` primitive calls), then the `derive` hierarchy's +/// ancestors map. /// /// `hierarchy_ancestors` is the `:ancestors` sub-map of a /// hierarchy struct: `{child #{ancestor1 ancestor2 ...}, ...}`. @@ -186,38 +184,22 @@ pub fn isaCheck(hierarchy_ancestors: Value, child: Value, parent: Value) !bool { // D-464: a class VALUE child isa? a class VALUE parent via the class hierarchy // (Long isa? Number, vector-class isa? Sequential), through the SAME shared - // `class_name.classIsa` the `isa?` primitive uses. Only short-circuits on a - // true match; a class can ALSO sit in an ad-hoc `derive` hierarchy, so a + // `class_name.classIsaOf` the `isa?` primitive uses, so a method keyed by a + // user class catches only that class, never a same-named redefinition + // vintage or another namespace's namesake (ADR-0201). Only short-circuits on + // a true match; a class can ALSO sit in an ad-hoc `derive` hierarchy, so a // non-match falls through to the ancestors lookup below. if (child.tag() == .type_descriptor and parent.tag() == .type_descriptor) { - const child_fqcn = td_mod.asTypeDescriptorRef(child).fqcn orelse ""; - const parent_fqcn = td_mod.asTypeDescriptorRef(parent).fqcn orelse ""; - if (class_name_mod.classIsa(child_fqcn, parent_fqcn)) return true; - } - - // Row 7.5 cycle 6 — D-082 discharge: typed_instance + reified_instance - // children walk their descriptor chain. JVM `clojure.core/isa?` step 2 - // (`Class.isAssignableFrom`) + step 4 (`supers` walk) map onto: - // - `descriptor.fqcn` ≡ JVM Class.name - // - `descriptor.protocol_impls` ≡ JVM implementedInterfaces walk - // - `descriptor.parent` ≡ JVM superclass chain - // Parent symbol/keyword name is matched against each. Triggered only - // when child is a TypedInstance / ReifiedInstance and parent is - // a Named (symbol or keyword) — the JVM analogue's input shape. - if ((child.tag() == .typed_instance or child.tag() == .reified_instance) and - (parent.tag() == .symbol or parent.tag() == .keyword)) - { - const parent_name: []const u8 = if (parent.tag() == .symbol) - symbol.asSymbol(parent).name - else - keyword.asKeyword(parent).name; - const child_desc: *const td_mod.TypeDescriptor = if (child.tag() == .typed_instance) - child.decodePtr(*const td_mod.TypedInstance).descriptor - else - child.decodePtr(*const td_mod.ReifiedInstance).descriptor; - if (typeDescriptorIsa(child_desc, parent_name)) return true; + const child_td = td_mod.asTypeDescriptorRef(child); + const parent_td = td_mod.asTypeDescriptorRef(parent); + if (class_name_mod.classIsaOf(child_td, parent_td)) return true; } + // An INSTANCE child (a `(defmulti m identity)` dispatch value) is related + // to a symbol or keyword parent only through the `derive` hierarchy below, + // never by its class's simple name or a protocol its type declares: + // clj's isa? has no such step, and `(isa? (->R 1) 'R)` is false here too + // (ADR-0201). if (hierarchy_ancestors.tag() == .nil) return false; const child_ancestors = try map_mod.get(hierarchy_ancestors, child); @@ -225,22 +207,6 @@ pub fn isaCheck(hierarchy_ancestors: Value, child: Value, parent: Value) !bool { return try set_mod.contains(child_ancestors, parent); } -/// Walk a descriptor's `fqcn` + `protocol_impls` + `parent` chain -/// looking for a match against `parent_name`. Row 7.5 cycle 6 D-082 -/// discharge — replaces JVM `Class.isAssignableFrom` + `supers` walk -/// per `.claude/rules/no_jvm_specific_assumption.md` (cw-side -/// equivalent of class hierarchy via TypeDescriptor). -fn typeDescriptorIsa(td: *const td_mod.TypeDescriptor, parent_name: []const u8) bool { - if (td.fqcn) |fqcn| { - if (std.mem.eql(u8, fqcn, parent_name)) return true; - } - for (td.protocol_impls) |impl| { - if (std.mem.eql(u8, impl, parent_name)) return true; - } - if (td.parent) |p| return typeDescriptorIsa(p, parent_name); - return false; -} - /// Dereference an IRef-shape hierarchy reference to its held map. /// `defmulti` threads the `-global-hierarchy` atom (D-161), so an /// atom ref is deref'd to its current value — and crucially each @@ -545,74 +511,31 @@ test "isaCheck: nil hierarchy falls back to equality only" { try testing.expect(!(try isaCheck(Value.nil_val, a, b))); } -test "isaCheck: typed_instance child matches descriptor.fqcn against Symbol parent (D-082)" { +test "isaCheck: an instance child is not isa? a Named parent spelled like its class (ADR-0201)" { var fix: TestFixture = undefined; fix.init(testing.allocator); defer fix.deinit(); - // Synthetic descriptor with fqcn "Foo". + // clj's isa? relates an INSTANCE only by equality (derive rejects one as a + // child), so neither its class's simple name nor a protocol its type + // declares makes `(defmulti m identity)` catch it under that name. + const impls = [_][]const u8{"Drawable"}; const td = try testing.allocator.create(td_mod.TypeDescriptor); defer testing.allocator.destroy(td); td.* = .{ .fqcn = "Foo", .kind = .defrecord, .field_layout = null, - .protocol_impls = &.{}, - .method_table = &.{}, - .parent = null, - .meta = Value.nil_val, - }; - const inst_val = try td_mod.allocInstance(&fix.rt, td, &.{}); - const foo_sym = try symbol.intern(&fix.rt, null, "Foo"); - const bar_sym = try symbol.intern(&fix.rt, null, "Bar"); - try testing.expect(try isaCheck(Value.nil_val, inst_val, foo_sym)); - try testing.expect(!(try isaCheck(Value.nil_val, inst_val, bar_sym))); -} - -test "isaCheck: typed_instance child walks protocol_impls list (D-082)" { - var fix: TestFixture = undefined; - fix.init(testing.allocator); - defer fix.deinit(); - - const impls = [_][]const u8{ "Drawable", "Serializable" }; - const td = try testing.allocator.create(td_mod.TypeDescriptor); - defer testing.allocator.destroy(td); - td.* = .{ - .fqcn = "Shape", - .kind = .defrecord, - .field_layout = null, .protocol_impls = &impls, .method_table = &.{}, .parent = null, .meta = Value.nil_val, }; const inst_val = try td_mod.allocInstance(&fix.rt, td, &.{}); - const drawable_sym = try symbol.intern(&fix.rt, null, "Drawable"); - const unknown_sym = try symbol.intern(&fix.rt, null, "Unknown"); - try testing.expect(try isaCheck(Value.nil_val, inst_val, drawable_sym)); - try testing.expect(!(try isaCheck(Value.nil_val, inst_val, unknown_sym))); -} - -test "isaCheck: reified_instance child walks descriptor like typed_instance (D-082)" { - var fix: TestFixture = undefined; - fix.init(testing.allocator); - defer fix.deinit(); - - const impls = [_][]const u8{"IProto"}; - const td = try testing.allocator.create(td_mod.TypeDescriptor); - defer testing.allocator.destroy(td); - td.* = .{ - .fqcn = null, - .kind = .reify_anon, - .field_layout = null, - .protocol_impls = &impls, - .method_table = &.{}, - .parent = null, - .meta = Value.nil_val, - }; - const inst_val = try td_mod.allocReifiedInstance(&fix.rt, td); - const iproto_sym = try symbol.intern(&fix.rt, null, "IProto"); - try testing.expect(try isaCheck(Value.nil_val, inst_val, iproto_sym)); + try testing.expect(!(try isaCheck(Value.nil_val, inst_val, try symbol.intern(&fix.rt, null, "Foo")))); + try testing.expect(!(try isaCheck(Value.nil_val, inst_val, try keyword.intern(&fix.rt, null, "Foo")))); + try testing.expect(!(try isaCheck(Value.nil_val, inst_val, try symbol.intern(&fix.rt, null, "Drawable")))); + try testing.expect(try isaCheck(Value.nil_val, inst_val, inst_val)); } test "getMethod: hierarchy walk returns ancestor's method on isa? match" { diff --git a/src/runtime/type_descriptor.zig b/src/runtime/type_descriptor.zig index 8fc5b5389..de2e8a663 100644 --- a/src/runtime/type_descriptor.zig +++ b/src/runtime/type_descriptor.zig @@ -262,6 +262,15 @@ pub const TypeDescriptor = struct { big_decimal: i64, }; + /// True iff this descriptor is a class the USER defined (`deftype`, + /// `defrecord`, `reify`), as opposed to a native / host-surface class. + /// A user class is identified by the descriptor itself, never by its + /// display name (ADR-0201): two vintages of a redefined `R`, or `aaa.Point` + /// and `bbb.Point`, share a simple name and are still different classes. + pub fn isUserClass(self: *const TypeDescriptor) bool { + return self.kind != .native; + } + /// Find a static field by name (ADR-0061). Linear — field tables are /// tiny (≤ 2 today). Parallel to `lookupMethod`; walks the parent /// chain for symmetry though host surfaces have no parent. @@ -662,17 +671,6 @@ pub fn finaliseReifiedInstance(gc_ptr: *anyopaque, header: *HeapHeader) void { _ = header; } -/// Allocate a TypeDescriptor on `rt.gpa` with the declared field -/// layout and register it in `rt.types` under `name`. Re-registering -/// the same name frees the previous descriptor (keeps the REPL -/// re-`def` path clean). `field_names` is borrowed; each entry is -/// `dupe`'d into the descriptor. -/// -/// Shared by the `__deftype!` and `__defrecord!` Layer-2 primitives — -/// both lower to the same Layer-0 surface per F-009 (feature-impl -/// neutrality), differing only in the `kind` argument. Since ADR-0066 -/// both `deftype` and `defrecord` are macros emitting their respective -/// `rt/__…!` registration call (no analyzer Node fork, no backend op). /// Build a defrecord instance from map `m` — clj's `Record/create`: /// declared fields pulled by keyword (nil when absent), every remaining /// key held in the extmap (nil when empty, so the result `=`/hashes as a @@ -700,6 +698,19 @@ pub fn recordFromMap(rt: *Runtime, td: *const TypeDescriptor, m: Value) !Value { return allocInstanceFull(rt, td, fields, Value.nil_val, ext); } +/// Allocate a TypeDescriptor on `rt.gpa` with the declared field layout and +/// register it in `rt.types` under its qualified key `.` +/// (ADR-0198). Re-registering the same key RETIRES the previous descriptor to +/// `rt.retired_types` rather than freeing it: instances, boxed class values +/// and CallSite caches still hold it, and the retired descriptor stays a +/// distinct class from its replacement (ADR-0201). `field_names` is borrowed; +/// each entry is `dupe`'d into the descriptor. +/// +/// Shared by the `__deftype!` and `__defrecord!` Layer-2 primitives, which +/// lower to the same Layer-0 surface per F-009 (feature-impl neutrality) and +/// differ only in the `kind` argument. Since ADR-0066 both `deftype` and +/// `defrecord` are macros emitting their `__deftype!` / `__defrecord!` +/// registration call (no analyzer Node fork, no backend op). pub fn registerType( rt: *Runtime, name: []const u8, diff --git a/test/diff/clj_corpus/type_redefinition.txt b/test/diff/clj_corpus/type_redefinition.txt new file mode 100644 index 000000000..cb7d2cedf --- /dev/null +++ b/test/diff/clj_corpus/type_redefinition.txt @@ -0,0 +1,254 @@ +(do (defprotocol Area (area [s])) :ok) +;;=> :ok +(do (defrecord R [a] Area (area [_] :old-area)) :ok) +;;=> :ok +(do (def r (->R 1)) (def rc (class r)) :ok) +;;=> :ok +(do (defrecord R [a b] Area (area [_] :new-area)) :ok) +;;=> :ok +(:a r) +;;=> 1 +(.-a r) +;;=> 1 +(get r :b :missing) +;;=> :missing +(pr-str r) +;;=> "#user.R{:a 1}" +(pr-str (->R 1 2)) +;;=> "#user.R{:a 1, :b 2}" +(instance? R r) +;;=> false +(instance? rc r) +;;=> true +(instance? user.R r) +;;=> false +(instance? R (->R 1 2)) +;;=> true +(instance? rc (->R 1 2)) +;;=> false +(.isInstance R r) +;;=> false +(.isInstance rc r) +;;=> true +(= rc R) +;;=> false +(identical? rc (class r)) +;;=> true +(= r r) +;;=> true +(= r (->R 1 nil)) +;;=> false +(= (->R 1 2) (->R 1 2)) +;;=> true +(= (hash r) (hash r)) +;;=> true +(integer? (hash r)) +;;=> true +(area r) +;;=> :old-area +(area (->R 1 2)) +;;=> :new-area +(satisfies? Area r) +;;=> true +(extends? Area rc) +;;=> true +(map? r) +;;=> true +(record? r) +;;=> true +(pr-str (assoc r :c 3)) +;;=> "#user.R{:a 1, :c 3}" +(pr-str (assoc r :a 9)) +;;=> "#user.R{:a 9}" +(pr-str (dissoc r :a)) +;;=> "{}" +(keys r) +;;=> (:a) +(vals r) +;;=> (1) +(count r) +;;=> 1 +(isa? rc R) +;;=> false +(isa? R rc) +;;=> false +(isa? rc rc) +;;=> true +(isa? rc Object) +;;=> true +(instance? Object r) +;;=> true +(do (defmulti f class) (defmethod f :default [_] :default) (defmethod f R [_] :new) :ok) +;;=> :ok +(f r) +;;=> :default +(f (->R 1 2)) +;;=> :new +(do (defmethod f rc [_] :old) :ok) +;;=> :ok +(f r) +;;=> :old +(f (->R 1 2)) +;;=> :new +(do (defprotocol P2 (p2 [x])) (extend-protocol P2 R (p2 [_] :new-p2)) :ok) +;;=> :ok +(satisfies? P2 r) +;;=> false +(satisfies? P2 (->R 1 2)) +;;=> true +(extends? P2 rc) +;;=> false +(p2 (->R 1 2)) +;;=> :new-p2 +(do (derive rc ::old-kind) :ok) +;;=> :ok +(isa? rc ::old-kind) +;;=> true +(isa? R ::old-kind) +;;=> false +(do (defrecord S [a]) :ok) +;;=> :ok +(do (def s1 (->S 1)) :ok) +;;=> :ok +(do (defrecord S [a]) :ok) +;;=> :ok +(= s1 (->S 1)) +;;=> false +(= (hash s1) (hash (->S 1))) +;;=> true +(instance? S s1) +;;=> false +(pr-str s1) +;;=> "#user.S{:a 1}" +(do (deftype T [x] Area (area [_] :old-t)) :ok) +;;=> :ok +(do (def t (T. 1)) (def tc (class t)) :ok) +;;=> :ok +(do (deftype T [x y]) :ok) +;;=> :ok +(.-x t) +;;=> 1 +(.-x (T. 1 2)) +;;=> 1 +(.-y (T. 1 2)) +;;=> 2 +(instance? T t) +;;=> false +(instance? tc t) +;;=> true +(instance? T (T. 1 2)) +;;=> true +(.isInstance T t) +;;=> false +(= tc T) +;;=> false +(= t t) +;;=> true +(= t (T. 1 2)) +;;=> false +(= (hash t) (hash t)) +;;=> true +(area t) +;;=> :old-t +(satisfies? Area t) +;;=> true +(satisfies? Area (T. 1 2)) +;;=> false +(isa? tc T) +;;=> false +(isa? tc Object) +;;=> true +(f t) +;;=> :default +(do (defn mk [i] (reify Area (area [_] i))) :ok) +;;=> :ok +(reduce + (map area (map mk (range 1000)))) +;;=> 499500 +(let [xs (doall (map mk (range 200)))] (System/gc) (reduce + (map area xs))) +;;=> 19900 +(let [a (mk 1)] [(instance? (class a) a) (.isInstance (class a) a) (isa? (class a) (class a)) (instance? Object a) (isa? (class a) Object)]) +;;=> [true true true true true] +(do (dotimes [_ 300] (eval '(defrecord Churn [v]))) :ok) +;;=> :ok +(pr-str (->Churn 7)) +;;=> "#user.Churn{:v 7}" +(let [olds (doall (for [i (range 50)] (do (eval '(defrecord Churn2 [v])) (eval (list '->Churn2 i)))))] (System/gc) [(reduce + (map :v olds)) (pr-str (first olds)) (pr-str (last olds)) (count (set (map class olds)))]) +;;=> [1225 "#user.Churn2{:v 0}" "#user.Churn2{:v 49}" 50] +(let [olds (doall (for [i (range 20)] (do (eval '(defrecord Churn3 [v])) (eval (list '->Churn3 i)))))] (count (filter #(= (class %) (class (last olds))) olds))) +;;=> 1 +(do (deftype Sorted []) :ok) +;;=> :ok +(sorted? (Sorted.)) +;;=> false +(instance? clojure.lang.Sorted (Sorted.)) +;;=> false +(isa? Sorted clojure.lang.Sorted) +;;=> false +(do (deftype Keyword []) :ok) +;;=> :ok +(ifn? (Keyword.)) +;;=> false +(instance? clojure.lang.IFn (Keyword.)) +;;=> false +(isa? Keyword clojure.lang.IFn) +;;=> false +(keyword? (Keyword.)) +;;=> false +(do (deftype PersistentVector []) :ok) +;;=> :ok +(vector? (PersistentVector.)) +;;=> false +(isa? PersistentVector clojure.lang.IFn) +;;=> false +(isa? PersistentVector clojure.lang.IPersistentVector) +;;=> false +(do (deftype BigInt []) :ok) +;;=> :ok +(number? (BigInt.)) +;;=> false +(instance? Number (BigInt.)) +;;=> false +(isa? BigInt Number) +;;=> false +(do (deftype Ratio []) :ok) +;;=> :ok +(isa? Ratio Number) +;;=> false +(rational? (Ratio.)) +;;=> false +(do (deftype ExceptionInfo []) :ok) +;;=> :ok +(isa? ExceptionInfo Exception) +;;=> false +(instance? Throwable (ExceptionInfo.)) +;;=> false +(do (deftype LazySeq []) :ok) +;;=> :ok +(isa? LazySeq clojure.lang.Seqable) +;;=> false +(seq? (LazySeq.)) +;;=> false +(do (defmulti g class) (defmethod g Number [_] :number) (defmethod g clojure.lang.IFn [_] :ifn) (defmethod g :default [_] :default) :ok) +;;=> :ok +(g (BigInt.)) +;;=> :default +(g (Keyword.)) +;;=> :default +(g 1) +;;=> :number +(g :k) +;;=> :ifn +(do (defmulti mi identity) (defmethod mi 'R [_] :sym) (defmethod mi :R [_] :kw) (defmethod mi 'Area [_] :protocol) (defmethod mi :default [_] :default) :ok) +;;=> :ok +(mi (->R 1 2)) +;;=> :default +(mi (mk 1)) +;;=> :default +(mi r) +;;=> :default +(isa? (->R 1 2) 'R) +;;=> false +(isa? (->R 1 2) :R) +;;=> false +(isa? (mk 1) 'Area) +;;=> false From ea75de74ec81d9d00f7b590844d2eaf5570dccc0 Mon Sep 17 00:00:00 2001 From: Pedro Gomes Branquinho Date: Wed, 14 Oct 2026 20:55:34 -0300 Subject: [PATCH 05/17] fix(analyzer): a bare constructor binds the class of the namespace it was written in ([CLJW-CTOR-ANALYZE-TIME]) analyzeCtorCall records definer_ns, the namespace a bare, non-imported (Name. args) form is analyzed in. Both backends carry it to constructInstance (tree_walk evalConstructorCall, vm op_ctor_call through CtorEntry.definer_ns), which looks up . before any other reading. So aaa/->Point and a (Point. x y) inside aaa build aaa.Point even after bbb registered a namesake of a different shape (ADR-0198, ADR-0201). The ctor site's definer_ns is serialized: bytecode VERSION 12 -> 13 (docs/spec/formats/chunk-v13.edn). A unit test pins the definer_ns-first lookup. Tests: user_class_identity_test.clj (new) covers instance?, isa?, class equality and dispatch across redefinition and namesakes. The six scenarios of the former type_descriptor_redefinition e2e (never landed) live in type_redefine_test.clj, so the e2e count does not grow. Smell-audited: 2: threads one namespace field from the analyzer to the existing constructor lookup and bumps the chunk format once; no new dispatch path. --- docs/spec/formats/chunk-v13.edn | 17 ++ src/eval/analyzer/analyzer.zig | 21 +++ src/eval/analyzer/special_forms.zig | 46 ++++- src/eval/backend/tree_walk.zig | 2 +- src/eval/backend/vm.zig | 2 +- src/eval/backend/vm/compiler.zig | 1 + src/eval/backend/vm/opcode.zig | 5 +- src/eval/bytecode/serialize.zig | 28 ++- src/eval/node.zig | 6 + test/clj/suites/type_redefine_test.clj | 133 +++++++++++++++ test/clj/suites/user_class_identity_test.clj | 169 +++++++++++++++++++ 11 files changed, 415 insertions(+), 15 deletions(-) create mode 100644 docs/spec/formats/chunk-v13.edn create mode 100644 test/clj/suites/user_class_identity_test.clj diff --git a/docs/spec/formats/chunk-v13.edn b/docs/spec/formats/chunk-v13.edn new file mode 100644 index 000000000..e19d50431 --- /dev/null +++ b/docs/spec/formats/chunk-v13.edn @@ -0,0 +1,17 @@ +;; Add-only bytecode archive amendment, 2026-10-14 (ADR-0034 D11, ADR-0198, +;; ADR-0201, [CLJW-CTOR-ANALYZE-TIME]). Earlier records remain unchanged. +;; v13 keeps the chunk-body framing of chunk-v12.edn except for one field +;; added to each ctor_sites entry, so a decoder of an older version must +;; reject the chunk. +{:chunk-format + {:version 13 + :magic "CLJW" + :base-layout "chunk-v12.edn" + :semantic-history + [{:version 13 + :change "A ctor site carries definer_ns, the namespace its `(Name. args)` form was analyzed in, so a bare user-type name resolves to . before any reading the calling namespace could give it (ADR-0198, ADR-0201)."}] + :ctor-site + {:fields [{:name :type_name :body "u32 length, then bytes"} + {:name :definer_ns :body "u32 length, then bytes; empty when the name was qualified at analysis or no namespace was current"} + {:name :arg_count :body "u16"}]} + :compatibility "The runtime rejects a chunk version unequal to 13; rebuild older payloads."}} diff --git a/src/eval/analyzer/analyzer.zig b/src/eval/analyzer/analyzer.zig index 6a29ac4b3..5723828b2 100644 --- a/src/eval/analyzer/analyzer.zig +++ b/src/eval/analyzer/analyzer.zig @@ -2444,6 +2444,27 @@ test "ctor call (Foo. ...) analyses into interop_call_node .constructor" { try testing.expect(n.interop_call_node.kind == .constructor); try testing.expectEqualStrings("Foo", n.interop_call_node.type_name); try testing.expectEqual(@as(usize, 2), n.interop_call_node.args.len); + // [CLJW-CTOR-ANALYZE-TIME]: a bare type name carries the namespace it was + // analyzed in, so eval-time lookup qualifies it lexically. + try testing.expectEqualStrings(fix.env.current_ns.?.name, n.interop_call_node.definer_ns); +} + +test "constructInstance resolves . before the last-wins simple name" { + const td_mod = @import("../../runtime/type_descriptor.zig"); + var fix: TestFixture = undefined; + try fix.init(testing.allocator); + defer fix.deinit(); + // aaa.Point has two fields; bbb.Point, registered later, has one, so a + // simple-name lookup would pick bbb's and reject two arguments. + const aaa = try td_mod.registerType(&fix.rt, "Point", "aaa", &.{ "x", "y" }, &.{}, .defrecord); + const bbb = try td_mod.registerType(&fix.rt, "Point", "bbb", &.{"q"}, &.{}, .defrecord); + const two = [_]Value{ Value.initInteger(1), Value.initInteger(2) }; + const a = try special_forms.constructInstance(&fix.rt, &fix.env, "Point", "aaa", &two, .{}); + try testing.expect(a.tag() == .typed_instance); + try testing.expect(a.decodePtr(*const td_mod.TypedInstance).descriptor == aaa); + const one = [_]Value{Value.initInteger(9)}; + const b = try special_forms.constructInstance(&fix.rt, &fix.env, "Point", "bbb", &one, .{}); + try testing.expect(b.decodePtr(*const td_mod.TypedInstance).descriptor == bbb); } test "member access (.x inst) analyses into interop_call_node .instance_member" { diff --git a/src/eval/analyzer/special_forms.zig b/src/eval/analyzer/special_forms.zig index ffccaa65c..27681b7d3 100644 --- a/src/eval/analyzer/special_forms.zig +++ b/src/eval/analyzer/special_forms.zig @@ -104,9 +104,22 @@ pub fn constructInstance( rt: *Runtime, env: *Env, type_name: []const u8, + /// The namespace the ctor form was analyzed in ("" when none). A user + /// type registered as `.` wins over every other + /// reading of the bare name, as a class name clj compiled there would. + definer_ns: []const u8, args: []const Value, loc: error_catalog.SourceLocation, ) anyerror!Value { + if (definer_ns.len != 0) { + var qbuf: [512]u8 = undefined; + if (std.fmt.bufPrint(&qbuf, "{s}.{s}", .{ definer_ns, type_name })) |qualified| { + if (rt.types.get(qualified)) |td| return constructFromDescriptor(rt, env, td, type_name, args, loc); + } else |_| { + // Namespace + name longer than the buffer: no registered key + // could match it either, so fall through to the steps below. + } + } // D-284: `(MapEntry. k v)` / `(new clojure.lang.MapEntry k v)` constructs an // entry, so collection libs that build entries explicitly (priority-map, // ordered, …) work. It used to return a plain 2-vector, from when a map entry @@ -151,9 +164,23 @@ pub fn constructInstance( } const td = resolveJavaSurface(rt, env, type_name) orelse return error_catalog.raise(.symbol_unresolved, loc, .{ .sym = type_name }); + return constructFromDescriptor(rt, env, td, type_name, args, loc); +} + +/// The descriptor-driven half of `constructInstance`: a field layout +/// (deftype / record) allocates an instance, a `` entry (java surface) +/// is called through the runtime vtable, anything else takes no constructor. +fn constructFromDescriptor( + rt: *Runtime, + env: *Env, + td: *const type_descriptor_mod.TypeDescriptor, + type_name: []const u8, + args: []const Value, + loc: error_catalog.SourceLocation, +) anyerror!Value { if (td.field_layout) |fl| { if (args.len != fl.len) - return error_catalog.raise(.arity_not_expected, loc, .{ .got = args.len, .fn_name = type_name, .expected = fl.len }); + return error_catalog.raise(.arity_not_expected, loc, .{ .got = args.len, .fn_name = td.fqcn orelse type_name, .expected = fl.len }); return type_descriptor_mod.allocInstance(rt, td, args); } if (td.lookupMethod(null, "")) |me| { @@ -261,14 +288,20 @@ pub fn analyzeCtorCall( // lexically correct one. Eval-time resolution would consult the CALLER's // ns and miss it (hiccup.util's `(URI. s)` inside to-uri, called from // user code). Guarded on the FQCN actually resolving as a registered - // surface. A USER deftype keeps the bare spelling here and resolves on - // the eval-time path (which also allows forward refs to later deftypes); - // since ADR-0198 that path finds it by qualifying the bare name with the - // current ns inside `host_class_resolve.resolve`, rather than by the - // simple-name registry hit this comment used to describe. + // surface. + // + // A USER type keeps the bare spelling and resolves at eval time, which is + // what lets a `(Name. …)` inside the defrecord's own expansion refer to a + // type registered a moment later. The namespace of THIS analysis rides + // along as `definer_ns` so that eval-time lookup qualifies the name + // lexically (ADR-0198): the current ns at eval time is the CALLER's, and + // a bare `Point` there fell to the last-wins simple-name index, so + // `aaa/->Point` built whichever `Point` any namespace registered last. var resolved_name = type_name; + var definer_ns: []const u8 = ""; if (std.mem.findScalar(u8, type_name, '.') == null) { if (env.current_ns) |cur_ns| { + definer_ns = try arena.dupe(u8, cur_ns.name); if (cur_ns.imports.get(type_name)) |fqcn| { if (rt.types.get(fqcn) != null) { resolved_name = fqcn; @@ -288,6 +321,7 @@ pub fn analyzeCtorCall( n.* = .{ .interop_call_node = .{ .kind = .constructor, .type_name = resolved_name, + .definer_ns = if (resolved_name.ptr == type_name.ptr) definer_ns else "", .args = args, .loc = form.location, } }; diff --git a/src/eval/backend/tree_walk.zig b/src/eval/backend/tree_walk.zig index ba3632d82..809fad70e 100644 --- a/src/eval/backend/tree_walk.zig +++ b/src/eval/backend/tree_walk.zig @@ -722,7 +722,7 @@ fn evalConstructorCall(rt: *Runtime, env: *Env, locals: []Value, n: node_mod.Int buf[i] = try eval(rt, env, locals, &arg_node); af.publish(i + 1); } - return special_forms.constructInstance(rt, env, n.type_name, buf[0..n.args.len], n.loc); + return special_forms.constructInstance(rt, env, n.type_name, n.definer_ns, buf[0..n.args.len], n.loc); } /// `(.member recv args...)` / `(.-field recv)` unified instance member diff --git a/src/eval/backend/vm.zig b/src/eval/backend/vm.zig index b8a0551f0..975f5279a 100644 --- a/src/eval/backend/vm.zig +++ b/src/eval/backend/vm.zig @@ -1373,7 +1373,7 @@ inline fn stepOnce( // Shared resolver/dispatcher (deftype/record + java-surface // ``) — identical to TreeWalk's evalConstructorCall so a // `(java.io.File. …)` ctor works on both backends. - const new_val = try special_forms.constructInstance(rt, env, type_name, args_slice, .{}); + const new_val = try special_forms.constructInstance(rt, env, type_name, ctor.definer_ns, args_slice, .{}); sp -= arg_count; stack[sp] = new_val; sp += 1; diff --git a/src/eval/backend/vm/compiler.zig b/src/eval/backend/vm/compiler.zig index d9f2dda8f..50fa32b0a 100644 --- a/src/eval/backend/vm/compiler.zig +++ b/src/eval/backend/vm/compiler.zig @@ -738,6 +738,7 @@ const Compiler = struct { const name_dup = try self.arena.dupe(u8, n.type_name); try self.ctor_sites.append(self.arena, .{ .type_name = name_dup, + .definer_ns = try self.arena.dupe(u8, n.definer_ns), .arg_count = @intCast(n.args.len), }); try self.emit(.op_ctor_call, ctor_idx); diff --git a/src/eval/backend/vm/opcode.zig b/src/eval/backend/vm/opcode.zig index 88d7337d1..a1526d73a 100644 --- a/src/eval/backend/vm/opcode.zig +++ b/src/eval/backend/vm/opcode.zig @@ -682,9 +682,12 @@ pub const LibspecEntry = struct { /// here (not packed into the operand) so it carries full width — the old /// `(name_idx << 8) | arg_count` packing truncated name_idx to 8 bits and /// corrupted ctor calls in chunks with > 255 constants. `type_name` is -/// analyzer-arena-owned, chunk lifetime. +/// analyzer-arena-owned, chunk lifetime. `definer_ns` is the namespace the +/// form was analyzed in (empty when none), which qualifies a bare user-type +/// name at run time, where the current namespace is the caller's. pub const CtorEntry = struct { type_name: []const u8, + definer_ns: []const u8 = "", arg_count: u16, }; diff --git a/src/eval/bytecode/serialize.zig b/src/eval/bytecode/serialize.zig index 336c1c476..7e607f8da 100644 --- a/src/eval/bytecode/serialize.zig +++ b/src/eval/bytecode/serialize.zig @@ -29,7 +29,8 @@ //! + has_only:u8 + (only_count:u32 //! + each: only_len:u32 + bytes)? //! [...] ctor_sites_count (u32 LE) -//! for each entry: type_name_len:u32 + bytes + arg_count:u16 +//! for each entry: type_name_len:u32 + bytes +//! + definer_ns_len:u32 + bytes + arg_count:u16 //! [...] import_sites_count (u32 LE) //! for each entry: simple_len:u32 + bytes + fqcn_len:u32 + bytes //! @@ -78,6 +79,10 @@ const tree_walk = @import("../backend/tree_walk.zig"); const Function = tree_walk.Function; pub const MAGIC: [4]u8 = .{ 'C', 'L', 'J', 'W' }; +// v13: a ctor site carries `definer_ns`, the namespace its form was analyzed +// in, so a bare user-type name is qualified lexically instead of by the +// caller's namespace (ADR-0198, ADR-0201). A v12 ctor site has no such field, +// so v12 is rejected. // v12 (D-346): the op_*_extend opcodes build a large literal in bounded steps, // and a folded constant literal may be a hash_map (new wire tag) or a set past // the array-map threshold. A v11 decoder cannot read either, so v11 is rejected. @@ -89,7 +94,7 @@ pub const MAGIC: [4]u8 = .{ 'C', 'L', 'J', 'W' }; // v10: def operands capture Var constants instead of caller-relative names. // v9 added op_var_meta; v8 unified host-class FQCNs; v7 compacted WireInstr // and interned the name pool; v6 merged rt into clojure.core. -pub const VERSION: u16 = 12; +pub const VERSION: u16 = 13; pub const SerializeError = error{ OutOfMemory, @@ -852,6 +857,7 @@ fn writeChunkBody(ctx: *WriteCtx, w: *std.Io.Writer, chunk: BytecodeChunk) Seria try writeU32(w, @intCast(chunk.ctor_sites.len)); for (chunk.ctor_sites) |ct| { try writeLenPrefixed(w, ct.type_name); + try writeLenPrefixed(w, ct.definer_ns); try writeU16(w, ct.arg_count); } try writeU32(w, @intCast(chunk.import_sites.len)); @@ -1039,8 +1045,10 @@ fn readChunkBody(ctx: *ReadCtx, r: *ByteReader) DeserializeError!BytecodeChunk { while (i < ctor_count) : (i += 1) { const tn_bytes = try r.readLenPrefixed(); const tn_dup = try allocator.dupe(u8, tn_bytes); + const dn_bytes = try r.readLenPrefixed(); + const dn_dup = try allocator.dupe(u8, dn_bytes); const arg_count = try r.readU16(); - ctor_sites[i] = .{ .type_name = tn_dup, .arg_count = arg_count }; + ctor_sites[i] = .{ .type_name = tn_dup, .definer_ns = dn_dup, .arg_count = arg_count }; } const import_count = try r.readU32(); @@ -1132,7 +1140,10 @@ pub fn freeChunk(allocator: std.mem.Allocator, chunk: BytecodeChunk) void { if (nf.doc) |d| allocator.free(d); } allocator.free(chunk.ns_filters); - for (chunk.ctor_sites) |ct| allocator.free(ct.type_name); + for (chunk.ctor_sites) |ct| { + allocator.free(ct.type_name); + allocator.free(ct.definer_ns); + } allocator.free(chunk.ctor_sites); for (chunk.import_sites) |ip| { allocator.free(ip.simple); @@ -2077,7 +2088,7 @@ test "chunk completeness gate: every side-table + entry field round-trips (D-365 } inline for (std.meta.fields(CtorEntry)) |f| { const classified: bool = switch (@field(std.meta.FieldEnum(CtorEntry), f.name)) { - .type_name, .arg_count => true, + .type_name, .definer_ns, .arg_count => true, }; try testing.expect(classified); } @@ -2119,6 +2130,7 @@ test "chunk completeness gate: every side-table + entry field round-trips (D-365 }; const ctor_sites = [_]CtorEntry{ .{ .type_name = "java.io.File", .arg_count = 1 }, + .{ .type_name = "Point", .definer_ns = "app.core", .arg_count = 2 }, }; const import_sites = [_]ImportPair{ .{ .simple = "File", .fqcn = "java.io.File" }, @@ -2179,9 +2191,13 @@ test "chunk completeness gate: every side-table + entry field round-trips (D-365 try testing.expectEqual(@as(u32, 7), round.ns_filters[0].attr_const); // ctor_sites - try testing.expectEqual(@as(usize, 1), round.ctor_sites.len); + try testing.expectEqual(@as(usize, 2), round.ctor_sites.len); try testing.expectEqualStrings("java.io.File", round.ctor_sites[0].type_name); + try testing.expectEqualStrings("", round.ctor_sites[0].definer_ns); try testing.expectEqual(@as(u16, 1), round.ctor_sites[0].arg_count); + try testing.expectEqualStrings("Point", round.ctor_sites[1].type_name); + try testing.expectEqualStrings("app.core", round.ctor_sites[1].definer_ns); + try testing.expectEqual(@as(u16, 2), round.ctor_sites[1].arg_count); // import_sites try testing.expectEqual(@as(usize, 1), round.import_sites.len); diff --git a/src/eval/node.zig b/src/eval/node.zig index a3c8d5c0a..b9a63bd61 100644 --- a/src/eval/node.zig +++ b/src/eval/node.zig @@ -425,6 +425,12 @@ pub const InteropCallNode = struct { /// `.constructor`: type name string for eval-time `resolveJavaSurface` /// lookup. Other kinds: empty string. type_name: []const u8 = "", + /// `.constructor` with a dot-free `type_name`: the namespace the form was + /// ANALYZED in. A user type is keyed `.` (ADR-0198) and clj + /// binds a class name lexically, so the eval-time lookup tries + /// `.` before anything the caller's namespace + /// could answer. Empty when there is none. + definer_ns: []const u8 = "", /// `.static_method` / `.instance_member`: method or field name. /// `.constructor`: ignored. name: []const u8 = "", diff --git a/test/clj/suites/type_redefine_test.clj b/test/clj/suites/type_redefine_test.clj index 8fd4b771c..28b75b858 100644 --- a/test/clj/suites/type_redefine_test.clj +++ b/test/clj/suites/type_redefine_test.clj @@ -19,6 +19,26 @@ (ns suites.type-redefine-test (:require [clojure.test :refer [deftest is]])) +;; --- two namespaces defining the SAME simple name must retain distinct +;; descriptors. Unlike re-evaluation, this is not a redefine: the registry +;; key must include the namespace. The CLI reproduction is the +;; `ns-collision-then-narrowing-redefine` row at the end of this file. +(ns suites.tduafa) +(defrecord Point [x y]) +(def a (->Point 1 2)) + +(ns suites.tduafb) +(defrecord Point [x y]) +(def b (->Point 3 4)) + +(ns suites.type-redefine-test + (:require [clojure.test :refer [deftest is]])) + +(deftest equal-simple-names-in-distinct-namespaces + (is (= "#suites.tduafa.Point{:x 1, :y 2}" (pr-str suites.tduafa/a))) + (is (= "#suites.tduafb.Point{:x 3, :y 4}" (pr-str suites.tduafb/b))) + (is (not (= (class suites.tduafa/a) (class suites.tduafb/b))))) + ;; --- same name, same shape, redefined in one namespace (the REPL re-eval ;; and `require :reload` path) --- @@ -115,3 +135,116 @@ (dotimes [_ 200] (vec (range 64))) (is (some? captured-class)) (is (string? (pr-str captured-class)))) + +;; --- scenarios migrated from the former test/e2e/type_descriptor_redefinition.sh. +;; Every expected value is the JVM's (clojure -M). The printed forms use +;; hyphen-free namespaces because clj munges `-` to `_` in a record class name +;; and cljw does not yet (ADR-0201 Consequences). --- + +;; Same simple name in two namespaces, then a narrowing redefine in the first. +(ns suites.tdra) +(defrecord Point [x y]) +(def a (->Point 1 2)) + +(ns suites.tdrb) +(defrecord Point [x y]) +(def b (->Point 3 4)) + +(ns suites.tdra) +(def a-repr-after-namesake (pr-str a)) +(defrecord Point [x]) +(def a-after (->Point 5)) +(deftype Box [v]) +(def old-box (Box. 7)) +(deftype Box [v]) + +;; defrecord R [a] -> R [a b], each vintage extended separately; a deftype +;; with an inline impl redefined without it; then registration churn under GC. +(ns suites.tdrc) +(defprotocol Area (area [s])) +(defrecord R [a]) +(extend-protocol Area R (area [s] (:a s))) +(def r (->R 1)) +(def rc (class r)) +(defrecord R [a b]) +(extend-protocol Area R (area [s] (+ (:a s) (:b s)))) +(def r-new (->R 2 3)) +(def r-nil (->R 1 nil)) + +(deftype T [x] Area (area [_] x)) +(def t (T. 5)) +(deftype T [x y]) + +(def last-area (atom nil)) +(dotimes [i 3000] + (eval '(defrecord Churn [v])) + (reset! last-area (area (reify Area (area [_] i))))) +(def cs (vec (for [i (range 50)] + (do (eval '(defrecord Churn [v w])) + ((ns-resolve 'suites.tdrc '->Churn) i i))))) +(System/gc) + +;; A constructor form binds the class of the namespace it was WRITTEN in +;; ([CLJW-CTOR-ANALYZE-TIME]). The factories, a `(Point. x y)` in a later fn +;; and one inside the record's own method body all build suites.tdrd.Point when +;; called from another namespace after suites.tdre registered a namesake with a +;; different shape. +(ns suites.tdrd) +(defprotocol Grow (grow [p])) +(defrecord Point [x y] Grow (grow [_] (Point. (inc x) y))) +(deftype Box [v]) +(defn mk [] (Point. 1 2)) + +(ns suites.tdre) +(defrecord Point [q]) +(deftype Box [v w]) + +(ns suites.type-redefine-test + (:require [clojure.test :refer [deftest is]])) + +(deftest ns-collision-then-narrowing-redefine + (is (= "#suites.tdra.Point{:x 1, :y 2}" (pr-str suites.tdra/a))) + (is (= "#suites.tdra.Point{:x 1, :y 2}" suites.tdra/a-repr-after-namesake)) + (is (= "#suites.tdrb.Point{:x 3, :y 4}" (pr-str suites.tdrb/b))) + (is (= "#suites.tdra.Point{:x 5}" (pr-str suites.tdra/a-after))) + (is (= 7 (.-v suites.tdra/old-box)))) + +(deftest widening-redefine-keeps-the-old-vintage-whole + (let [r suites.tdrc/r rc suites.tdrc/rc] + (is (= "#suites.tdrc.R{:a 1}" (pr-str r))) + (is (= 1 (:a r))) + (is (= 1 (.-a r))) + (is (true? (instance? rc r))) + (is (true? (= rc (class r)))) + (is (false? (= (class r) suites.tdrc.R))) + (is (true? (= r r))) + (is (false? (= r suites.tdrc/r-nil))) + (is (= (hash r) (hash r))) + (is (true? (map? r))) + (is (= 1 (suites.tdrc/area r))) + (is (= 5 (suites.tdrc/area suites.tdrc/r-new))))) + +(deftest deftype-redefine-keeps-the-old-method-table + (let [t suites.tdrc/t] + (is (= 5 (.-x t))) + (is (= 5 (suites.tdrc/area t))) + (is (= t t)) + (is (integer? (hash t))))) + +(deftest redefine-churn-under-gc + (let [cs suites.tdrc/cs] + (is (= 1225 (reduce + (map :v cs)))) + (is (= "#suites.tdrc.Churn{:v 0, :w 0}" (pr-str (first cs)))) + (is (= "#suites.tdrc.Churn{:v 49, :w 49}" (pr-str (last cs)))) + (is (= 2999 @suites.tdrc/last-area)))) + +(deftest ctor-binds-its-defining-namespace + (is (= "#suites.tdrd.Point{:x 1, :y 2}" (pr-str (suites.tdrd/->Point 1 2)))) + (is (= "#suites.tdrd.Point{:x 1, :y 2}" (pr-str (suites.tdrd/mk)))) + (is (= "#suites.tdrd.Point{:x 2, :y 2}" (pr-str (suites.tdrd/grow (suites.tdrd/->Point 1 2))))) + (is (= "#suites.tdre.Point{:q 9}" (pr-str (suites.tdre/->Point 9)))) + (is (= "#suites.tdrd.Point{:x 1, :y 2}" (pr-str (suites.tdrd/map->Point {:x 1 :y 2})))) + (is (true? (instance? suites.tdrd.Point (suites.tdrd/mk)))) + (is (false? (instance? suites.tdre.Point (suites.tdrd/mk)))) + (is (= 7 (.-v (suites.tdrd/->Box 7)))) + (is (= 8 (.-w (suites.tdre/->Box 7 8))))) diff --git a/test/clj/suites/user_class_identity_test.clj b/test/clj/suites/user_class_identity_test.clj new file mode 100644 index 000000000..fb4b61a21 --- /dev/null +++ b/test/clj/suites/user_class_identity_test.clj @@ -0,0 +1,169 @@ +;; ADR-0201: a user-defined class (deftype / defrecord / reify) IS its +;; TypeDescriptor, so membership in it is decided by descriptor identity, +;; never by comparing simple-name strings. +;; +;; The simple-name oracle survived ADR-0198 (which gave every other question, +;; `(class x)`, `=` on classes, printing, the registry key, a per-descriptor +;; answer) and so answered `instance?` and `isa?` differently from `=`: +;; after `(defrecord R [a b])` replaced `(defrecord R [a])`, an OLD instance +;; was still `(instance? R old)`, a record from another namespace with the same +;; simple name was an instance of this one, and a deftype named `Sorted` was +;; `sorted?`. Every expected value below is the JVM's (`clojure -M`). +(ns suites.user-class-identity-test + (:require [clojure.test :refer [deftest is testing]])) + +(defprotocol Area (area [s])) + +;; --- same-namespace redefinition: the new class is a DIFFERENT class --- + +(defrecord R [a]) +(def ^:private old-r (->R 1)) +(def ^:private old-r-class (class old-r)) +(defrecord R [a b]) +(def ^:private new-r (->R 1 2)) + +(deftest instance-of-redefined-record + (is (false? (instance? R old-r))) + (is (true? (instance? old-r-class old-r))) + (is (true? (instance? R new-r))) + (is (false? (instance? old-r-class new-r)))) + +(deftest class-isInstance-agrees-with-instance? + (is (false? (.isInstance R old-r))) + (is (true? (.isInstance old-r-class old-r)))) + +(deftest isa?-between-record-vintages + (is (false? (isa? old-r-class R))) + (is (false? (isa? R old-r-class))) + (is (true? (isa? old-r-class old-r-class))) + (is (true? (isa? R R))) + (testing "a user class still sits under Object" + (is (true? (isa? old-r-class Object))) + (is (true? (instance? Object old-r))))) + +(defmulti ^:private by-class class) +(defmethod by-class :default [_] :default) +(defmethod by-class R [_] :new-r) + +(defmulti ^:private by-old-class class) +(defmethod by-old-class old-r-class [_] :old-r) +(defmethod by-old-class :default [_] :default) + +(deftest multimethod-dispatch-on-class-vintage + (testing "a method keyed by the NEW class does not catch an old instance" + (is (= :default (by-class old-r))) + (is (= :new-r (by-class new-r)))) + (testing "a method keyed by the OLD class catches only the old instance" + (is (= :old-r (by-old-class old-r))) + (is (= :default (by-old-class new-r))))) + +(deftype T [x]) +(def ^:private old-t (T. 1)) +(def ^:private old-t-class (class old-t)) +(deftype T [x]) + +(deftest instance-of-redefined-deftype + (is (false? (instance? T old-t))) + (is (true? (instance? old-t-class old-t))) + (is (true? (instance? T (T. 2)))) + (is (false? (= old-t-class T)))) + +;; --- reify: its class value is a class like any other --- + +(defn- mk-area [i] (reify Area (area [_] i))) + +(deftest reify-instance-of-its-own-class + (let [a (mk-area 1)] + (is (true? (instance? (class a) a))) + (is (true? (.isInstance (class a) a))) + (is (true? (isa? (class a) (class a)))) + (is (true? (instance? Object a))) + (is (= 1 (area a))))) + +;; --- a user type named like a host interface is not that interface --- + +(deftype Sorted []) + +(deftest user-type-named-like-an-interface + (is (false? (sorted? (Sorted.)))) + (is (true? (instance? Sorted (Sorted.)))) + (is (false? (instance? clojure.lang.Sorted (Sorted.))))) + +;; --- class-level isa? of a user class against a host class: what the user +;; class DECLARES decides, never its simple name. These names are each a host +;; class's simple name, which the name oracle used to match. --- + +(deftype BigInt []) +(deftype Keyword []) +(deftype PersistentVector []) +(deftype LazySeq []) +(deftype ExceptionInfo []) +(deftype Ratio []) +(deftype Deref [] clojure.lang.IDeref (deref [_] :derefed)) + +(deftest user-class-named-like-a-host-class-is-not-a-subclass-of-it + (is (false? (isa? BigInt Number))) + (is (false? (isa? Ratio Number))) + (is (false? (isa? Keyword clojure.lang.IFn))) + (is (false? (isa? PersistentVector clojure.lang.IFn))) + (is (false? (isa? PersistentVector clojure.lang.IPersistentVector))) + (is (false? (isa? LazySeq clojure.lang.Seqable))) + (is (false? (isa? ExceptionInfo Exception))) + (is (false? (isa? Sorted clojure.lang.Sorted))) + (is (false? (number? (BigInt.)))) + (is (false? (ifn? (Keyword.)))) + (testing "Object and the declared interfaces still answer" + (is (true? (isa? BigInt Object))) + (is (true? (isa? Deref clojure.lang.IDeref))) + (is (= :derefed @(Deref.))))) + +(defmulti ^:private by-host-class class) +(defmethod by-host-class Number [_] :number) +(defmethod by-host-class clojure.lang.IFn [_] :ifn) +(defmethod by-host-class :default [_] :default) + +(deftest multimethod-dispatch-on-a-user-class-named-like-a-host-class + (is (= :default (by-host-class (BigInt.)))) + (is (= :default (by-host-class (Keyword.)))) + (is (= :number (by-host-class 1))) + (is (= :ifn (by-host-class :k)))) + +;; --- two namespaces, one simple name: two classes --- + +(ns suites.ucia) +(defrecord Point [x y]) +(def a (->Point 1 2)) + +(ns suites.ucib) +(defrecord Point [q]) +(def b (->Point 9)) + +(ns suites.user-class-identity-test) + +(deftest same-simple-name-in-two-namespaces + (is (false? (instance? suites.ucia.Point suites.ucib/b))) + (is (true? (instance? suites.ucib.Point suites.ucib/b))) + (is (true? (instance? suites.ucia.Point suites.ucia/a))) + (is (false? (= (class suites.ucia/a) (class suites.ucib/b)))) + (is (false? (isa? (class suites.ucib/b) suites.ucia.Point))) + ;; a factory builds ITS namespace's class, also when called from another + ;; namespace after a namesake was registered later + (is (= [5 6] ((juxt :x :y) (suites.ucia/->Point 5 6)))) + (is (true? (instance? suites.ucia.Point (suites.ucia/->Point 5 6)))) + (is (= {:x 7 :y 8} (into {} (suites.ucia/map->Point {:x 7 :y 8})))) + (is (true? (instance? suites.ucib.Point (suites.ucib/->Point 1))))) + +;; --- an INSTANCE dispatch value is not isa? its class's name, nor a protocol +;; its type declares: clj relates an instance only by equality or derive --- + +(defmulti ^:private by-identity identity) +(defmethod by-identity 'R [_] :sym) +(defmethod by-identity :R [_] :kw) +(defmethod by-identity 'Area [_] :protocol) +(defmethod by-identity :default [_] :default) + +(deftest instance-dispatch-value-is-not-its-class-name + (is (= :default (by-identity new-r))) + (is (= :default (by-identity (mk-area 1)))) + (is (false? (isa? new-r 'R))) + (is (false? (isa? new-r :R)))) From f15ad170afe03304a61c4ef6c390b66f6d558a4d Mon Sep 17 00:00:00 2001 From: Pedro Gomes Branquinho Date: Wed, 14 Oct 2026 20:55:41 -0300 Subject: [PATCH 06/17] docs(debt): discharge D-587 (ADR-0198, ADR-0201) Redefining a deftype/defrecord no longer frees a descriptor live instances still use, namesakes in different namespaces are different classes, and a bare constructor binds its defining namespace. Pinned by type_redefine_test.clj, user_class_identity_test.clj and the type_redefinition corpus. rt.types_by_simple stays for the bare-name paths that are not ctor sites (card 20260909231443-1ba4303c). --- .dev/debt.yaml | 55 ++++++++++---------------------------------------- 1 file changed, 11 insertions(+), 44 deletions(-) diff --git a/.dev/debt.yaml b/.dev/debt.yaml index 547c36fbf..17decb763 100644 --- a/.dev/debt.yaml +++ b/.dev/debt.yaml @@ -24,50 +24,6 @@ # md-table-align no longer pads it to ~800 KB of whitespace. active: - - id: "D-587" - status: |- - open (2026-09-09). USE-AFTER-FREE, user-reachable panic. Re-registering a - deftype/defrecord name frees a TypeDescriptor that live instances still - point at. `type_descriptor.zig registerType` keys `rt.types` by the SIMPLE - name, and on re-registration does `fetchRemove(name)` then frees the old - descriptor (each field_layout entry name, the layout slice, fqcn, - defining_ns, method_table entries, protocol_impls, then - `gpa.destroy(old.value)`). Every constructed instance holds - `inst.descriptor` as a raw pointer to it, so `print.zig - printTypedInstance` then reads `field_layout` out of freed memory: the - symptom is `thread panic: integer overflow` (a garbage field index or - layout length), the defect is the free. - Repro (ReleaseSafe v1.14.3): `(ns aaa) (defrecord Point [x y]) (def a - (->Point 1 2)) (ns bbb) (defrecord Point [x y]) (def b (->Point 1 2)) - (prn (pr-str aaa/a))` panics; printing `bbb/b` is fine. Variants: two ns - with DIFFERENT names is fine; two ns SAME name panics; SAME ns redefining - the same name panics (this is the ordinary REPL / `require :reload` path - `dev/user.clj` depends on); same name with a different field count panics; - the deftype form raises `WriteFailed` instead, same root. - TWO separable defects: (1) the registry is keyed by simple name, so - `aaa/Point` and `bbb/Point` collide with no redefinition at all (clj gives - each ns its own class); (2) re-registration frees a descriptor live - instances reference. - ADR-0019 forbids a panic on a user-reachable path, and this one is reached - by re-evaluating a defrecord form. It also caps the native-suite migration: - `test/clj/suites/` shares ONE image, so no two suites may define the same - type name (worked around 2026-09-09 by renaming defrecord_test's record to - DPoint; 45 type definitions across 103 suites, no other duplicate today). - Found while migrating phase7_defrecord.sh to a native suite. - Card `[CLJW-TD-UAF]` 20260909211032-6471bc49. - category: "correctness" - quality_floor: "correctness: a user-reachable panic from an ordinary redefine" - barrier: |- - Needs an ADR: the free is deliberate (comments cite row 7.7 cycle 5 and - D-190 / ADR-0068) and exists to avoid leaking on redefine, so removing it - trades the leak back. Candidate shapes: key `rt.types` by the qualified - name when `defining_ns` is present and RETIRE rather than free a replaced - descriptor (a leak bounded by redefinition count, which is what clj does - with the old class), or make descriptors GC-managed so a descriptor dies - only when no instance references it. Devil's-advocate fork is mandatory at - this depth. Not blocked on anything external: the repro is one file and the - owning function is ~70 lines. - last_reviewed: "2026-09-09" - id: "D-586" status: |- open (2026-09-05, ADR-0195 trigger). UPSTREAM: zwasm/D-584. zwasm's JIT @@ -7583,6 +7539,17 @@ discharged: refs: |- src/runtime/collection/literal.zig (the one literal construction); src/eval/analyzer/analyzer.zig (the constant fold); src/eval/backend/vm/compiler.zig and vm.zig (the extend opcodes); docs/spec/formats/chunk-v12.edn (bytecode format v12). discharged_at: "2026-10-02" + - id: "D-587" + status: |- + DISCHARGED 2026-10-14 by ADR-0198 plus ADR-0201. Both defects the row named are fixed. (1) rt.types is keyed by ., so aaa.Point and bbb.Point are two classes (ADR-0198), and a bare constructor binds the class of the namespace its form was analyzed in ([CLJW-CTOR-ANALYZE-TIME]: a ctor site carries definer_ns, bytecode v13), so `aaa/->Point` builds aaa.Point even after bbb registered a namesake. (2) A displaced descriptor is retired, never freed, until Runtime.deinit (ADR-0198; ADR-0201 Part B makes that the one lifetime rule for every user descriptor). ADR-0201 also made membership descriptor identity: instance?, .isInstance, isa? and multimethod dispatch agree with (= (class x) C) for a redefined record, a namesake in another namespace and a reify class. The original repro prints both records and the narrowed redefine on both backends. + Was: open (2026-09-09), USE-AFTER-FREE, user-reachable panic. Re-registering a deftype/defrecord name freed a TypeDescriptor that live instances still pointed at, and the registry was keyed by the simple name, so two namespaces defining Point collided with no redefinition at all. Symptom `thread panic: integer overflow` from printTypedInstance, or `WriteFailed` for a deftype. + category: "correctness" + barrier: |- + none, discharged. Pinned by test/clj/suites/type_redefine_test.clj (the six scenarios of the former type_descriptor_redefinition e2e, incl. 3000 redefinitions interleaved with reify under a forced collection and the defining-namespace ctor binding), test/clj/suites/user_class_identity_test.clj, the type_redefinition diff corpus, and the class_name.zig / analyzer.zig unit tests. Still open and separate: rt.types_by_simple still exists for the bare-name paths that are not ctor sites (card 20260909231443-1ba4303c), and D-574 (reify mints a descriptor per evaluation). + last_reviewed: "2026-10-14" + refs: |- + ADR-0198, ADR-0201; src/runtime/type_descriptor.zig (registerType retires), src/runtime/class_name.zig (isInstanceOfClass, classIsaOf, descriptorIsa), src/eval/analyzer/special_forms.zig (constructInstance definer_ns lookup), docs/spec/formats/chunk-v13.edn. + discharged_at: "2026-10-14" conventions: |- - Category vocabulary is a closed set (guarded by scripts/check_debt_category.sh; synonyms were normalized 2026-10-08: structural->structure, tests/test->testing, numerics->numeric, performance->perf). Allowed: app backend bench bootstrap build clj-parity concurrency correctness debt-hygiene demo discipline distribution docs docs-onboarding ecosystem error-system eval eval-semantics feature gc governance host-surface infra interop isolation license macro meta-reorg missing-ns namespace numeric perf polymorphism process project-flow reader refactor regex robustness runtime scope security structure testing tooling wasm. A new category is added here first, in the same commit as the row that needs it. - Structure: two top-level lists — `active:` and `discharged:`. Active entries carry id / status / category / barrier (+ optional quality_floor / last_reviewed); discharged entries carry id / discharged_at / resolution. Edit as YAML (no Markdown table to align). From 39f70b9ebeeea34d806338bd913051c8d4bb75cb Mon Sep 17 00:00:00 2001 From: Pedro Gomes Branquinho Date: Wed, 14 Oct 2026 22:14:57 -0300 Subject: [PATCH 07/17] docs(changelog): record round 7 (type redefinition and identity, VM error locations) under [Unreleased] Smell-audited: 0: release notes only, no source change --- CHANGELOG.md | 19 +++++++++++++++++++ 1 file changed, 19 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index d5bc55917..2fa657829 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -7,6 +7,25 @@ first stable `1.0.0` tag; pre-1.0 `alpha` / `rc` tags may still change surfaces. ## [Unreleased] +### Fixed + +- **Redefining a deftype or defrecord is safe, and a user class is matched by + identity, not by name.** Re-registering a type no longer frees a descriptor + live instances still use (the `thread panic: integer overflow` on printing + an old instance is gone). `aaa.Point` and `bbb.Point` are two classes, and + `instance?`, `.isInstance`, class `isa?` and multimethod dispatch agree with + `(= (class x) C)` for a redefined record, a namesake in another namespace + and a reify class. A bare `(Point. x y)` or `->Point` builds the class of the + namespace the form was written in, even after another namespace registered a + namesake of a different shape. Compiled chunks move to format v13. + +- **The VM reports errors at their form.** `set!` on an unbound var, an + unresolved or unsupported `.member` call, a static method call, a + constructor arity failure, `import` and `require`/`refer` failures raised on + the VM with no source position (`0:0`) while TreeWalk reported line and + column. Both backends now report the same position, and the dual-backend + test oracle checks it for every failing case. + ## [1.15.0] - 2026-10-13 ### Added From 5dadcd16f803de119f71b944e03b01c5b4be3114 Mon Sep 17 00:00:00 2001 From: Pedro Gomes Branquinho Date: Wed, 21 Oct 2026 13:44:27 -0300 Subject: [PATCH 08/17] feat(wasm): wasm/exports lists a core module's exports (ADR-0203) (wasm/exports h) returns a vector of maps in export-section order. A function answers {:name :kind :func :params [...] :results [...]}, any other export {:name :kind :memory|:global|:table}. Signatures come from Loaded.exportSig, the probe wasm/call marshals through, so what is listed is callable at exactly the listed arity. The export list is decoded at load, while the module bytes are alive: zwasm's section view borrows them, and wasm/load frees them right after. Tests: exports.zig unit tests (interp + jit, bytes freed before use) and test/e2e/phase16_wasm_exports.sh (add.wasm, the C kernel, a bad handle). Smell-audited: 1: new builtin in its own file, one registration line, no change to existing call paths --- README.md | 3 + src/runtime/cljw/wasm/engine.zig | 9 ++ src/runtime/cljw/wasm/exports.zig | 155 ++++++++++++++++++++++++++++++ src/runtime/cljw/wasm/surface.zig | 3 +- test/e2e/phase16_wasm_exports.sh | 65 +++++++++++++ test/run_all.sh | 1 + 6 files changed, 235 insertions(+), 1 deletion(-) create mode 100644 src/runtime/cljw/wasm/exports.zig create mode 100755 test/e2e/phase16_wasm_exports.sh diff --git a/README.md b/README.md index 144c7d29e..cc0a7478d 100644 --- a/README.md +++ b/README.md @@ -191,6 +191,9 @@ cljw build script.clj -o app # one self-contained native binary ;; A core module (docs/examples/polyglot/c/kernel.c): numbers in, numbers ;; out, arrays in a buffer the guest owns and hands out by address. (def m (wasm/load "docs/examples/polyglot/c/kernel.wasm" {:fuel 1000000 :max-memory-pages 16})) +(wasm/exports m) ;=> [{:name "memory", :kind :memory} + ; {:name "buf_addr", :kind :func, :params [], :results [:i32]} + ; ... {:name "sum_f64", :kind :func, :params [:i32 :i32], :results [:f64]} ...] (def buf (wasm/call m "buf_addr")) (wasm/mem-write! m :f64 buf [1.0 2.0 3.0 4.0]) (wasm/call m "sum_f64" buf 4) ;=> 10.0 diff --git a/src/runtime/cljw/wasm/engine.zig b/src/runtime/cljw/wasm/engine.zig index 84cc0e593..29b52429e 100644 --- a/src/runtime/cljw/wasm/engine.zig +++ b/src/runtime/cljw/wasm/engine.zig @@ -25,6 +25,8 @@ pub const Value = zwasm.Value; pub const FuncType = zwasm.ir.zir.FuncType; pub const ValType = zwasm.ir.zir.ValType; pub const Memory = zwasm.Memory; +/// Owned export-descriptor list (zwasm `Module.exports`), ADR-0203. +pub const ModuleExports = @typeInfo(@typeInfo(@TypeOf(zwasm.Module.exports)).@"fn".return_type.?).error_union.payload; /// Per-axis runtime budget for a loaded module (re-exported from zwasm's /// `Module.Budget`, ADR-0179). `.unmetered` lifts the cap (trusted modules @@ -80,6 +82,10 @@ pub const Loaded = struct { /// Keys are owned copies; values are slices into the instance's own /// signature storage, valid for the instance's lifetime. sig_cache: std.StringHashMapUnmanaged(FuncType), + /// Export descriptors (name + kind, export order) decoded at `load`, while + /// the module bytes are still alive: zwasm's native section view borrows + /// them, so a later `Module.exports` would decode freed memory (ADR-0203). + export_list: ModuleExports, /// Runtime signature of an exported function (`null` if absent / not a /// func). Drives the marshal: caller sizes its `[]Value` buffers from @@ -120,6 +126,7 @@ pub const Loaded = struct { var keys = self.sig_cache.keyIterator(); while (keys.next()) |k| self.alloc.free(k.*); self.sig_cache.deinit(self.alloc); + self.export_list.deinit(); self.instance.deinit(); self.module.deinit(); self.engine.deinit(); @@ -295,6 +302,8 @@ pub fn load(alloc: std.mem.Allocator, bytes: []const u8, opts: LoadOpts) !*Loade if (opts.fuel) |b| inst_opts.fuel = b; if (opts.max_memory_pages) |b| inst_opts.max_memory_pages = b; inst_opts.engine = opts.engine; + self.export_list = try self.module.exports(alloc); + errdefer self.export_list.deinit(); self.instance = try self.module.instantiate(inst_opts); self.engine_kind = opts.engine; self.alloc = alloc; diff --git a/src/runtime/cljw/wasm/exports.zig b/src/runtime/cljw/wasm/exports.zig new file mode 100644 index 000000000..975eb3c42 --- /dev/null +++ b/src/runtime/cljw/wasm/exports.zig @@ -0,0 +1,155 @@ +// SPDX-License-Identifier: EPL-2.0 +//! `(wasm/exports h)` — list a core module's exports in export-section order +//! (ADR-0203 decision 1). A function answers +//! `{:name "add" :kind :func :params [:i32 :i32] :results [:i32]}`; a memory, +//! global or table answers `{:name "memory" :kind :memory}`. The function +//! signature comes from `Loaded.exportSig`, the same runtime probe `wasm/call` +//! marshals through, so nothing here is declared by hand and a listed function +//! is callable at exactly the listed arity. Compiled ONLY under `-Dwasm`. +//! +//! Backend: impl-only +//! Impl deps: none +//! Clojure peer: wasm/exports +const std = @import("std"); +const zwasm = @import("zwasm"); +const engine = @import("engine.zig"); +const wasm_handle = @import("wasm_handle.zig"); +const Runtime = @import("../../runtime.zig").Runtime; +const Env = @import("../../env.zig").Env; +const Value = @import("../../value/value.zig").Value; +const error_catalog = @import("../../error/catalog.zig"); +const SourceLocation = @import("../../error/info.zig").SourceLocation; +const string_mod = @import("../../collection/string.zig"); +const vector_mod = @import("../../collection/vector.zig"); +const map_mod = @import("../../collection/map.zig"); +const keyword_mod = @import("../../keyword.zig"); + +/// `(wasm/exports handle)` — a vector of export maps, in export order. +pub fn wasmExportsFn(rt: *Runtime, env: *Env, args: []const Value, loc: SourceLocation) anyerror!Value { + _ = env; + try error_catalog.checkArity("wasm/exports", args, 1, loc); + if (!wasm_handle.isHandle(args[0])) + return error_catalog.raise(.wasm_handle_invalid, loc, .{ .fn_name = "wasm/exports" }); + const loaded = wasm_handle.unwrap(args[0]); + + const name_kw = try keyword_mod.intern(rt, null, "name"); + const kind_kw = try keyword_mod.intern(rt, null, "kind"); + const params_kw = try keyword_mod.intern(rt, null, "params"); + const results_kw = try keyword_mod.intern(rt, null, "results"); + + var out = vector_mod.empty(); + for (loaded.export_list.items) |item| { + var m = map_mod.empty(); + m = try map_mod.assoc(rt, m, name_kw, try string_mod.alloc(rt, item.name)); + m = try map_mod.assoc(rt, m, kind_kw, try keyword_mod.intern(rt, null, kindName(item.kind))); + if (item.kind == .func) { + // A func export always has a signature; a miss would mean the + // instance and the export section disagree, so the map simply + // carries no signature rather than inventing one. + if (loaded.exportSig(item.name)) |sig| { + m = try map_mod.assoc(rt, m, params_kw, try typeVector(rt, sig.params)); + m = try map_mod.assoc(rt, m, results_kw, try typeVector(rt, sig.results)); + } + } + out = try vector_mod.conj(rt, out, m); + } + return out; +} + +fn typeVector(rt: *Runtime, types: []const engine.ValType) anyerror!Value { + var v = vector_mod.empty(); + for (types) |t| v = try vector_mod.conj(rt, v, try keyword_mod.intern(rt, null, valTypeName(t))); + return v; +} + +/// The `:kind` keyword name of an export. +pub fn kindName(kind: zwasm.ExternKind) []const u8 { + return switch (kind) { + .func => "func", + .table => "table", + .memory => "memory", + .global => "global", + // The binary format has no tag export; zwasm's enum shares the import side. + .tag => "tag", + }; +} + +/// The keyword name of a value type: `i32 i64 f32 f64 v128`, and for a +/// reference its abstract heap type's text-format shorthand (`funcref`, +/// `externref`, ...). A concrete typed reference `(ref $t)` names as `ref`. +pub fn valTypeName(t: engine.ValType) []const u8 { + return switch (t) { + .i32 => "i32", + .i64 => "i64", + .f32 => "f32", + .f64 => "f64", + .v128 => "v128", + .ref => |r| switch (r.heap_type) { + .concrete => "ref", + .abstract => |a| switch (a) { + .func => "funcref", + .extern_ => "externref", + .any => "anyref", + .eq => "eqref", + .i31 => "i31ref", + .struct_ => "structref", + .array => "arrayref", + .none => "nullref", + .noextern => "nullexternref", + .nofunc => "nullfuncref", + .exn => "exnref", + .noexn => "nullexnref", + }, + }, + }; +} + +test "valTypeName names scalars and the abstract references" { + const VT = engine.ValType; + try std.testing.expectEqualStrings("i32", valTypeName(.i32)); + try std.testing.expectEqualStrings("f64", valTypeName(.f64)); + try std.testing.expectEqualStrings("v128", valTypeName(.v128)); + try std.testing.expectEqualStrings("funcref", valTypeName(VT.funcref)); + try std.testing.expectEqualStrings("externref", valTypeName(VT.externref)); +} + +test "kindName names every export kind" { + try std.testing.expectEqualStrings("func", kindName(.func)); + try std.testing.expectEqualStrings("memory", kindName(.memory)); + try std.testing.expectEqualStrings("global", kindName(.global)); + try std.testing.expectEqualStrings("table", kindName(.table)); +} + +// (module (func (export "add") (param i32 i32) (result i32) +// local.get 0 local.get 1 i32.add) (memory (export "memory") 1)) +const add_mem_wasm = [_]u8{ + 0x00, 0x61, 0x73, 0x6d, 0x01, 0x00, 0x00, 0x00, 0x01, 0x07, 0x01, 0x60, + 0x02, 0x7f, 0x7f, 0x01, 0x7f, 0x03, 0x02, 0x01, 0x00, 0x05, 0x03, 0x01, + 0x00, 0x01, 0x07, 0x10, 0x02, 0x03, 0x61, 0x64, 0x64, 0x00, 0x00, 0x06, + 0x6d, 0x65, 0x6d, 0x6f, 0x72, 0x79, 0x02, 0x00, 0x0a, 0x09, 0x01, 0x07, + 0x00, 0x20, 0x00, 0x20, 0x01, 0x6a, 0x0b, +}; + +test "the export list outlives the module bytes and pairs with exportSig" { + const alloc = std.testing.allocator; + inline for (.{ engine.EngineKind.interp, engine.EngineKind.jit }) |kind| { + // `wasm/load` frees the file bytes right after `load`; mirror that. + const bytes = try alloc.dupe(u8, &add_mem_wasm); + const loaded = try engine.load(alloc, bytes, .{ .engine = kind }); + @memset(bytes, 0); + alloc.free(bytes); + defer { + loaded.deinit(); + alloc.destroy(loaded); + } + const items = loaded.export_list.items; + try std.testing.expectEqual(@as(usize, 2), items.len); + try std.testing.expectEqualStrings("add", items[0].name); + try std.testing.expectEqualStrings("func", kindName(items[0].kind)); + try std.testing.expectEqualStrings("memory", items[1].name); + try std.testing.expectEqualStrings("memory", kindName(items[1].kind)); + const sig = loaded.exportSig("add").?; + try std.testing.expectEqual(@as(usize, 2), sig.params.len); + try std.testing.expectEqualStrings("i32", valTypeName(sig.results[0])); + } +} diff --git a/src/runtime/cljw/wasm/surface.zig b/src/runtime/cljw/wasm/surface.zig index 58c1afc30..c6eb94931 100644 --- a/src/runtime/cljw/wasm/surface.zig +++ b/src/runtime/cljw/wasm/surface.zig @@ -12,7 +12,7 @@ //! //! Backend: impl-only //! Impl deps: none -//! Clojure peer: wasm/load, wasm/call, wasm/engine, wasm/mem-size, wasm/mem-read, wasm/mem-write! +//! Clojure peer: wasm/load, wasm/call, wasm/exports, wasm/engine, wasm/mem-size, wasm/mem-read, wasm/mem-write! const std = @import("std"); const engine = @import("engine.zig"); const run_cache = @import("run_cache.zig"); @@ -604,6 +604,7 @@ pub fn register(env: *Env) !void { _ = try env.intern(ns, "load", Value.initBuiltinFn(&wasmLoadFn), null); _ = try env.intern(ns, "call", Value.initBuiltinFn(&wasmCallFn), null); _ = try env.intern(ns, "engine", Value.initBuiltinFn(&wasmEngineFn), null); + _ = try env.intern(ns, "exports", Value.initBuiltinFn(&@import("exports.zig").wasmExportsFn), null); _ = try env.intern(ns, "run", Value.initBuiltinFn(&wasmRunFn), null); _ = try env.intern(ns, "clear-cache!", Value.initBuiltinFn(&wasmClearCacheFn), null); // ADR-0192: the (ptr,len) half of the FFI — `wasm/call` passes the pointer, diff --git a/test/e2e/phase16_wasm_exports.sh b/test/e2e/phase16_wasm_exports.sh new file mode 100755 index 000000000..f01aa632d --- /dev/null +++ b/test/e2e/phase16_wasm_exports.sh @@ -0,0 +1,65 @@ +#!/usr/bin/env bash +# test/e2e/phase16_wasm_exports.sh — `(wasm/exports h)` lists a core module's +# exports in export order with runtime-probed signatures (ADR-0203 decision 1). +# +# Functions answer {:name :kind :func :params [...] :results [...]}, every other +# export {:name :kind :memory|:global|:table}. The signature comes from the same +# probe `wasm/call` uses, so a function `wasm/exports` describes is callable with +# exactly that arity. A non-handle argument raises the catalogued +# wasm_handle_invalid error, catchable like every other wasm-surface error. +# +# Reuses the shared -Dwasm binary under CLJW_SKIP_BUILD, like the other phase16 +# wasm e2es; standalone it builds -Dwasm ReleaseSafe itself. +set -euo pipefail +cd "$(dirname "$0")/../.." +BIN="zig-out/bin/cljw" +fail() { echo "FAIL $1" >&2; exit 1; } + +if [ -z "${CLJW_SKIP_BUILD:-}" ] && ! zig build -Dwasm -Doptimize="${CLJW_OPT:-ReleaseSafe}" >/dev/null 2>&1; then + fail "zig build -Dwasm failed (zwasm dep unresolved?)" +fi +"$BIN" --version | grep -q wasm || fail "cljw is not wasm-enabled ($("$BIN" --version))" + +check() { # name expected expr + local got + got="$("$BIN" -e "$3" 2>&1)" || fail "$1: cljw exited non-zero: +$got" + got="$(printf '%s\n' "$got" | sed '${/^nil$/d}')" # -e echoes the prn/println result + [ "$got" = "$2" ] || fail "$1: expected + $2 +got + $got" + echo "PASS $1" +} + +# (1) The single-function module: the acceptance shape, verbatim. +check wasm-exports-add \ + '[{:name "add", :kind :func, :params [:i32 :i32], :results [:i32]}]' \ + '(prn (wasm/exports (wasm/load "docs/examples/wasm/add.wasm")))' + +# (2) A C-compiled module: the linear memory and four functions, in export order. +check wasm-exports-c-kernel-names \ + '[["memory" :memory] ["buf_addr" :func] ["buf_cap" :func] ["sum_f64" :func] ["scale_f64" :func]]' \ + '(prn (mapv (juxt :name :kind) (wasm/exports (wasm/load "docs/examples/polyglot/c/kernel.wasm"))))' + +check wasm-exports-c-kernel-sigs \ + '[["buf_addr" [] [:i32]] ["buf_cap" [] [:i32]] ["sum_f64" [:i32 :i32] [:f64]] ["scale_f64" [:i32 :i32 :f64] [:i32]]]' \ + '(prn (vec (for [e (wasm/exports (wasm/load "docs/examples/polyglot/c/kernel.wasm")) :when (= :func (:kind e))] [(:name e) (:params e) (:results e)])))' + +# (3) A non-function export carries no :params / :results. +check wasm-exports-memory-has-no-sig \ + '{:name "memory", :kind :memory}' \ + '(prn (first (filter #(= :memory (:kind %)) (wasm/exports (wasm/load "docs/examples/polyglot/c/kernel.wasm")))))' + +# (4) What exports describes is callable at exactly that arity. +check wasm-exports-drives-call \ + '42' \ + '(let [h (wasm/load "docs/examples/wasm/add.wasm") e (first (wasm/exports h))] (prn (apply wasm/call h (:name e) (take (count (:params e)) [40 2 99]))))' + +# (5) A non-handle is the catalogued wasm_handle_invalid error, catchable. +check wasm-exports-bad-handle \ + 'CAUGHT wasm/exports: the first argument must be a loaded wasm module' \ + '(try (wasm/exports 42) (catch Exception e (println "CAUGHT" (ex-message e))))' + +echo +echo "Phase 16 / wasm/exports introspection: all green." diff --git a/test/run_all.sh b/test/run_all.sh index aa3ff5b00..a2455775d 100644 --- a/test/run_all.sh +++ b/test/run_all.sh @@ -715,6 +715,7 @@ run_step "e2e_bulk_literal" "bash test/e2e/bulk_literal.sh" # cannot resolve zwasm, build_cljw fails first — wasm is a gate prerequisite now. run_step "e2e_phase16_wasm_ffi" "bash test/e2e/phase16_wasm_ffi.sh" run_step "e2e_phase16_wasm_memory" "bash test/e2e/phase16_wasm_memory.sh" +run_step "e2e_phase16_wasm_exports" "bash test/e2e/phase16_wasm_exports.sh" run_step "e2e_phase16_wasm_engine_select" "bash test/e2e/phase16_wasm_engine_select.sh" run_step "e2e_phase16_wasm_run" "bash test/e2e/phase16_wasm_run.sh" # D-349: the third budget axis. Fuel bounds instructions; how many bytes an From d4c0363dffb2eb3fced2eb02c7ad08cea44de95e Mon Sep 17 00:00:00 2001 From: Pedro Gomes Branquinho Date: Wed, 21 Oct 2026 14:00:08 -0300 Subject: [PATCH 09/17] feat(wasm): dot-interop on a core module handle is wasm/call (ADR-0203) (.add h 40 2), (. h add 40 2) and (. h (add 40 2)) on a wasm_module value call the export named by the method symbol, verbatim, so C names such as sum_f64 work as written. Runtime.wasm_member_call is a hook both backends consult on a method-table miss (VM op_method_call, TreeWalk evalInstanceMember). The wasm surface installs it at register, so it exists only under -Dwasm (F-001) and the eval zone never imports a surface. wasm/call and the hook share one callExport path: signature probe, arity check, marshalling, fuel and trap mapping are not duplicated, and errors are identical. Test: test/e2e/phase16_wasm_dot_interop.sh with its fixture (the three spellings, the C kernel, missing export / arity / trap parity with wasm/call, non-wasm receivers unchanged). Smell-audited: 2: one runtime hook field instead of a surface import into eval; shared callExport extracted from wasmCallFn --- docs/examples/wasm/README.md | 16 +++++ src/eval/backend/tree_walk.zig | 3 + src/eval/backend/vm.zig | 7 ++ src/runtime/cljw/wasm/surface.zig | 17 ++++- src/runtime/runtime.zig | 7 ++ test/e2e/fixtures/wasm_dot_interop_probe.clj | 33 ++++++++++ test/e2e/phase16_wasm_dot_interop.sh | 69 ++++++++++++++++++++ test/run_all.sh | 2 + 8 files changed, 151 insertions(+), 3 deletions(-) create mode 100644 test/e2e/fixtures/wasm_dot_interop_probe.clj create mode 100755 test/e2e/phase16_wasm_dot_interop.sh diff --git a/docs/examples/wasm/README.md b/docs/examples/wasm/README.md index 4cd63e458..6d8caa80d 100644 --- a/docs/examples/wasm/README.md +++ b/docs/examples/wasm/README.md @@ -14,6 +14,22 @@ sandboxed `.wasm` and invokes its exports. name, marshalling arguments and results from the export's signature (`i32`/`i64`/`f32`/`f64` today). +A module handle also answers Clojure's host-interop method syntax (ADR-0203): +the method name is the export name, verbatim, and the call is `wasm/call`'s +own path, so results, fuel limits and traps behave the same. + +```clojure +(.add m 40 2) ;=> 42 +(. m add 40 2) ;=> 42 +(. m (add 40 2)) ;=> 42 + +;; A C kernel (../polyglot/c/kernel.c): C names work as written. +(def k (wasm/load "docs/examples/polyglot/c/kernel.wasm")) +(def buf (.buf_addr k)) +(wasm/mem-write! k :f64 buf [1.0 2.0 3.0 4.0]) +(.sum_f64 k buf 4) ;=> 10.0 +``` + ## Run it The **released binaries** (GitHub releases, `brew install diff --git a/src/eval/backend/tree_walk.zig b/src/eval/backend/tree_walk.zig index ba3632d82..af437c45a 100644 --- a/src/eval/backend/tree_walk.zig +++ b/src/eval/backend/tree_walk.zig @@ -777,6 +777,9 @@ fn evalInstanceMember(rt: *Runtime, env: *Env, locals: []Value, n: node_mod.Inte } const me = td.lookupMethod(null, n.name) orelse { + // ADR-0203: a core wasm module handle answers `(.export h …)` through + // wasm/call's path (hook installed only under -Dwasm). + if (receiver.tag() == .wasm_module) if (rt.wasm_member_call) |call| return call(rt, receiver, n.name, args_buf[1..], n.loc); // Universal java.lang.Object method fallback (D-207): str/=/hash/class. if (try object_method.tryObjectMethod(rt, env, receiver, td, n.name, args_buf[1..])) |r| return r; // clojure.lang read/op methods on a NATIVE collection (D-371): `.valAt`/ diff --git a/src/eval/backend/vm.zig b/src/eval/backend/vm.zig index b8a0551f0..6b4729e17 100644 --- a/src/eval/backend/vm.zig +++ b/src/eval/backend/vm.zig @@ -1435,6 +1435,13 @@ inline fn stepOnce( sp -= arg_count; stack[sp] = result; sp += 1; + } else if (receiver.tag() == .wasm_module and rt.wasm_member_call != null) { + // ADR-0203: `(.export h …)` on a core wasm module handle is + // wasm/call's path — mirrors TreeWalk's evalInstanceMember. + const result = try rt.wasm_member_call.?(rt, receiver, cs_entry.method_name, stack[sp - arg_count + 1 .. sp], instr_loc); + sp -= arg_count; + stack[sp] = result; + sp += 1; } else if (try object_method.tryObjectMethod(rt, env, receiver, td, cs_entry.method_name, stack[sp - arg_count + 1 .. sp])) |r| { // Universal java.lang.Object method fallback: // str/=/hash/class — mirrors TreeWalk's evalInstanceMember. diff --git a/src/runtime/cljw/wasm/surface.zig b/src/runtime/cljw/wasm/surface.zig index 58c1afc30..b2806c5ed 100644 --- a/src/runtime/cljw/wasm/surface.zig +++ b/src/runtime/cljw/wasm/surface.zig @@ -138,10 +138,19 @@ pub fn wasmCallFn(rt: *Runtime, env: *Env, args: []const Value, loc: SourceLocat if (!args[1].isString()) return error_catalog.raise(.wasm_export_name_invalid, loc, .{}); - const loaded = wasm_handle.unwrap(args[0]); - const name = string_mod.asString(args[1]); - const call_args = args[2..]; + return callExport(rt, wasm_handle.unwrap(args[0]), string_mod.asString(args[1]), args[2..], loc); +} + +/// `(.export h args…)` on a `.wasm_module` receiver (ADR-0203 decision 2): +/// the method name is the export name verbatim, and the call is `wasm/call`'s +/// own path. Installed on `rt.wasm_member_call` by `register`. +fn memberCallFn(rt: *Runtime, receiver: Value, name: []const u8, args: []const Value, loc: SourceLocation) anyerror!Value { + return callExport(rt, wasm_handle.unwrap(receiver), name, args, loc); +} +/// The one export-invoke path shared by `wasm/call` and dot-interop: signature +/// probe, arity check, marshalling, fuel and trap mapping. +fn callExport(rt: *Runtime, loaded: *engine.Loaded, name: []const u8, call_args: []const Value, loc: SourceLocation) anyerror!Value { const sig = loaded.exportSig(name) orelse return error_catalog.raise(.wasm_export_not_found, loc, .{ .name = name }); if (call_args.len != sig.params.len) @@ -600,6 +609,8 @@ pub fn register(env: *Env) !void { // Register the `.wasm_module` GC finaliser so a swept `(wasm/load …)` handle // tears down its zwasm triple instead of leaking (D-259 (b)). wasm_handle.registerGcHooks(); + // ADR-0203: `.member` dispatch on a handle routes to `callExport`. + env.rt.wasm_member_call = &memberCallFn; const ns = try env.findOrCreateNs("wasm"); _ = try env.intern(ns, "load", Value.initBuiltinFn(&wasmLoadFn), null); _ = try env.intern(ns, "call", Value.initBuiltinFn(&wasmCallFn), null); diff --git a/src/runtime/runtime.zig b/src/runtime/runtime.zig index 32aa1aa67..a508c7c0e 100644 --- a/src/runtime/runtime.zig +++ b/src/runtime/runtime.zig @@ -393,6 +393,13 @@ pub const Runtime = struct { /// the zone direction legal (lang installs into runtime). source_resolver: ?*const fn (*Runtime, []const u8) ?SourceContext = null, + /// ADR-0203 decision 2: `(.export h args…)` on a `.wasm_module` receiver. + /// Both backends' `.member` dispatch call this on a method-table miss; the + /// wasm surface (`runtime/cljw/wasm/surface.zig`) installs it at `register`, + /// so it is set only under `-Dwasm` (F-001) and the eval zone never imports + /// a surface. `args` EXCLUDES the receiver; `name` is the export, verbatim. + wasm_member_call: ?*const fn (rt: *Runtime, receiver: @import("value/value.zig").Value, name: []const u8, args: []const @import("value/value.zig").Value, loc: @import("error/info.zig").SourceLocation) anyerror!@import("value/value.zig").Value = null, + /// Swappable resolver fn for `require`. ADR-0035 D8. `null` at /// `init`; bootstrap installs the embedded resolver. Phase 12+ /// can swap for classpath / build-artifact resolvers; Phase 16+ diff --git a/test/e2e/fixtures/wasm_dot_interop_probe.clj b/test/e2e/fixtures/wasm_dot_interop_probe.clj new file mode 100644 index 000000000..d38d6e06a --- /dev/null +++ b/test/e2e/fixtures/wasm_dot_interop_probe.clj @@ -0,0 +1,33 @@ +;; Dot-interop on a core wasm module handle (ADR-0203 decision 2). Every +;; method-call form on a `wasm_module` value is `wasm/call` with the method +;; symbol's name as the export name, verbatim. Asserted by +;; test/e2e/phase16_wasm_dot_interop.sh. +(def h (wasm/load "docs/examples/wasm/add.wasm")) +(println "dot-method" (.add h 40 2)) +(println "dot-form" (. h add 40 2)) +(println "dot-list" (. h (add 40 2))) +(println "same-as-call" (= (.add h 40 2) (wasm/call h "add" 40 2))) + +;; A C kernel: the export name `sum_f64` works as written (no munging), and the +;; buffer comes from the guest's own allocator. +(def m (wasm/load "docs/examples/polyglot/c/kernel.wasm")) +(def buf (wasm/call m "buf_addr")) +(wasm/mem-write! m :f64 buf [1.0 2.0 3.0 4.0]) +(println "c-sum" (.sum_f64 m buf 4)) +(println "c-scale" (.scale_f64 m buf 4 2.0) (.sum_f64 m buf 4)) + +(defn msg [f] + (try (f) "NOT-RAISED" (catch Throwable e (.getMessage e)))) + +;; A missing export and a trap raise exactly what wasm/call raises. +(println "missing-same" (= (msg #(.nope h 1)) (msg #(wasm/call h "nope" 1)))) +(println "missing" (msg #(.nope h 1))) +(println "arity" (msg #(.add h 1))) +(def t (wasm/load "docs/examples/wasm/trap.wasm")) +(println "trap-same" (= (msg #(.boom t)) (msg #(wasm/call t "boom")))) +(println "trap" (msg #(.boom t))) + +;; Non-wasm receivers are unchanged. +(println "string" (.toUpperCase "abc")) +(println "nonwasm" (msg #(.add 42 1))) +(println "DONE") diff --git a/test/e2e/phase16_wasm_dot_interop.sh b/test/e2e/phase16_wasm_dot_interop.sh new file mode 100755 index 000000000..3bf47d25e --- /dev/null +++ b/test/e2e/phase16_wasm_dot_interop.sh @@ -0,0 +1,69 @@ +#!/usr/bin/env bash +# test/e2e/phase16_wasm_dot_interop.sh — method-call forms on a core wasm +# module handle (ADR-0203 decision 2). `(.add h 40 2)`, `(. h add 40 2)` and +# `(. h (add 40 2))` are `(wasm/call h "add" 40 2)`: the method symbol's name is +# the export name verbatim, and the call takes the SAME path as wasm/call, so a +# missing export, an arity mismatch and a trap raise the same catalogued errors. +# +# OPT-IN for the same reason as phase16_wasm_ffi.sh: it builds `-Dwasm`, so it +# resolves zwasm, which the default gate never does (F-001). +set -euo pipefail +cd "$(dirname "$0")/../.." +BIN="zig-out/bin/cljw" +fail() { echo "FAIL $1" >&2; exit 1; } + +if [ -z "${CLJW_SKIP_BUILD:-}" ] && ! zig build -Dwasm -Doptimize="${CLJW_OPT:-ReleaseSafe}" >/dev/null 2>&1; then + fail "zig build -Dwasm failed (zwasm dep unresolved?)" +fi +"$BIN" --version | grep -q wasm || fail "cljw is not wasm-enabled ($("$BIN" --version)) — zwasm did not resolve" + +FIX="test/e2e/fixtures/wasm_dot_interop_probe.clj" + +run_probe() { + local label="$1"; shift + out="$("$@" "$FIX" 2>&1)" || fail "[$label] cljw exited non-zero running $FIX: +$out" + want() { + grep -qF "$1" <<<"$out" || fail "[$label] expected '$1' in the probe output, got: +$out" + } + + # (1) The three method-call spellings all reach the export. + want "dot-method 42" + want "dot-form 42" + want "dot-list 42" + want "same-as-call true" + echo "PASS wasm-dot-interop-forms [$label] -> (.add h 40 2) / (. h add 40 2) / (. h (add 40 2)) = 42" + + # (2) A C export name is used verbatim; memory written by the host is read. + want "c-sum 10.0" + want "c-scale 4 20.0" + echo "PASS wasm-dot-interop-c-kernel [$label] -> (.sum_f64 m buf 4) = 10.0" + + # (3) Errors are wasm/call's, not a '<.member>' miss. + grep -q "NOT-RAISED" <<<"$out" && fail "[$label] a wasm dot-call error was not raised: +$out" + grep -q "<.member>.*wasm_module" <<<"$out" && fail "[$label] wasm receiver fell through to <.member> dispatch: +$out" + want "missing-same true" + want "missing wasm/call: no exported function named 'nope'" + want "arity wasm/call:" + want "trap-same true" + want "trap wasm/call: 'boom' () -> (i32) trapped" + echo "PASS wasm-dot-interop-errors [$label] -> missing export / arity / trap raise wasm/call's errors" + + # (4) Non-wasm receivers are unchanged. + want "string ABC" + want "nonwasm No implementation of method 'add' on protocol '<.member>'" + echo "PASS wasm-dot-interop-nonwasm [$label] -> other receivers keep <.member> dispatch" + + grep -q "^DONE$" <<<"$out" || fail "[$label] the probe did not run to completion: +$out" +} + +# The backend is a build option (-Dbackend, vm by default); both arms +# (VM op_method_call, TreeWalk evalInstanceMember) carry the wasm case. +run_probe "${CLJW_BACKEND:-vm}" "$BIN" + +echo +echo "phase16_wasm_dot_interop: all PASS" diff --git a/test/run_all.sh b/test/run_all.sh index aa3ff5b00..762cff1d4 100644 --- a/test/run_all.sh +++ b/test/run_all.sh @@ -730,6 +730,8 @@ run_step "e2e_phase16_wasm_component_budget" "bash test/e2e/phase16_wasm_compone # as committed AND rebuilt from their source headers (each toolchain on PATH), # plus hosts.cljc on every Clojure host present. A README claim with a gate. run_step "e2e_phase16_wasm_polyglot" "bash test/e2e/phase16_wasm_polyglot.sh" +# ADR-0203: `(.export h …)` on a core module handle is wasm/call's path. +run_step "e2e_phase16_wasm_dot_interop" "bash test/e2e/phase16_wasm_dot_interop.sh" # The reswap coverage moved to suites/wasm-require-component-reswap-test: it # asserts values, not the process boundary, so it runs in-process now. run_step "e2e_phase15_ns_import" "bash test/e2e/phase15_ns_import.sh" From 8239bc2030f17ce44fc7be5e2620674064fb1169 Mon Sep 17 00:00:00 2001 From: Pedro Gomes Branquinho Date: Wed, 21 Oct 2026 14:49:00 -0300 Subject: [PATCH 10/17] test(wasm): move the ADR-0203 tests into in-process suites wasm/exports and dot-interop are value assertions, not process-boundary behaviour, so per decision 20260911144411-22d9cd94 they are deftests in test/clj/suites/ (wasm_exports_test, wasm_dot_interop_test) instead of two new e2e scripts. That keeps check_e2e_count at its 322 baseline. data/placement.yaml is regenerated for the new wasm/exports var. --- data/placement.yaml | 5 +- test/clj/suites/wasm_dot_interop_test.clj | 48 ++++++++++++++ test/clj/suites/wasm_exports_test.clj | 42 ++++++++++++ test/e2e/fixtures/wasm_dot_interop_probe.clj | 33 ---------- test/e2e/phase16_wasm_dot_interop.sh | 69 -------------------- test/e2e/phase16_wasm_exports.sh | 65 ------------------ test/run_all.sh | 3 - 7 files changed, 93 insertions(+), 172 deletions(-) create mode 100644 test/clj/suites/wasm_dot_interop_test.clj create mode 100644 test/clj/suites/wasm_exports_test.clj delete mode 100644 test/e2e/fixtures/wasm_dot_interop_probe.clj delete mode 100755 test/e2e/phase16_wasm_dot_interop.sh delete mode 100755 test/e2e/phase16_wasm_exports.sh diff --git a/data/placement.yaml b/data/placement.yaml index baf8a5848..04d946bb4 100644 --- a/data/placement.yaml +++ b/data/placement.yaml @@ -24,8 +24,8 @@ schema_version: "2.0" summary: namespaces_required: 36 - total: 1455 - zig: 423 + total: 1456 + zig: 424 clj: 806 value: 220 unbound: 6 @@ -1478,6 +1478,7 @@ vars: "wasm/component-exports": { impl: zig, flags: "-" } "wasm/component-invoke": { impl: zig, flags: "-" } "wasm/engine": { impl: zig, flags: "-" } + "wasm/exports": { impl: zig, flags: "-" } "wasm/load": { impl: zig, flags: "-" } "wasm/load-component": { impl: zig, flags: "-" } "wasm/mem-read": { impl: zig, flags: "-" } diff --git a/test/clj/suites/wasm_dot_interop_test.clj b/test/clj/suites/wasm_dot_interop_test.clj new file mode 100644 index 000000000..964de3867 --- /dev/null +++ b/test/clj/suites/wasm_dot_interop_test.clj @@ -0,0 +1,48 @@ +;; Dot-interop on a core wasm module handle (ADR-0203 decision 2). +;; `(.add h 40 2)`, `(. h add 40 2)` and `(. h (add 40 2))` are +;; `(wasm/call h "add" 40 2)`: the method symbol's name is the export name +;; verbatim, and the call takes the same path as wasm/call, so a missing +;; export, an arity mismatch and a trap raise the same catalogued errors. +;; Both backends carry the case (VM op_method_call, TreeWalk +;; evalInstanceMember). Needs the -Dwasm binary (the gate configuration). +(ns suites.wasm-dot-interop-test + (:require [clojure.test :refer [deftest is testing]])) + +(def ^:private add-wasm "docs/examples/wasm/add.wasm") +(def ^:private kernel-wasm "docs/examples/polyglot/c/kernel.wasm") +(def ^:private trap-wasm "docs/examples/wasm/trap.wasm") + +(defn- msg [f] + (try (f) :not-raised (catch Throwable e (.getMessage e)))) + +(deftest three-spellings + (let [h (wasm/load add-wasm)] + (is (= 42 (.add h 40 2))) + (is (= 42 (. h add 40 2))) + (is (= 42 (. h (add 40 2)))) + (is (= (wasm/call h "add" 40 2) (.add h 40 2))))) + +(deftest c-export-names-verbatim + (let [m (wasm/load kernel-wasm) + buf (.buf_addr m)] + (wasm/mem-write! m :f64 buf [1.0 2.0 3.0 4.0]) + (is (= 10.0 (.sum_f64 m buf 4))) + (is (= 4 (.scale_f64 m buf 4 2.0))) + (is (= 20.0 (.sum_f64 m buf 4))))) + +(deftest errors-are-wasm-call-errors + (let [h (wasm/load add-wasm) + t (wasm/load trap-wasm)] + (testing "missing export" + (is (= (msg #(wasm/call h "nope" 1)) (msg #(.nope h 1)))) + (is (= "wasm/call: no exported function named 'nope'" (msg #(.nope h 1))))) + (testing "arity" + (is (= "wasm/call: 'add' expects 2 argument(s), got 1" (msg #(.add h 1))))) + (testing "trap" + (is (= (msg #(wasm/call t "boom")) (msg #(.boom t)))) + (is (re-find #"^wasm/call: 'boom' \(\) -> \(i32\) trapped" (msg #(.boom t))))))) + +(deftest non-wasm-receivers-unchanged + (is (= "ABC" (.toUpperCase "abc"))) + (is (re-find #"No implementation of method 'add' on protocol '<\.member>'" + (str (msg #(.add 42 1)))))) diff --git a/test/clj/suites/wasm_exports_test.clj b/test/clj/suites/wasm_exports_test.clj new file mode 100644 index 000000000..8cdfb6b8a --- /dev/null +++ b/test/clj/suites/wasm_exports_test.clj @@ -0,0 +1,42 @@ +;; `(wasm/exports h)` lists a core module's exports in export order with +;; runtime-probed signatures (ADR-0203 decision 1). A function answers +;; {:name :kind :func :params [...] :results [...]}, any other export +;; {:name :kind :memory|:global|:table}. The signature comes from the probe +;; `wasm/call` marshals through, so a listed function is callable at exactly +;; the listed arity. Needs the -Dwasm binary (the gate configuration). +(ns suites.wasm-exports-test + (:require [clojure.test :refer [deftest is testing]])) + +(def ^:private add-wasm "docs/examples/wasm/add.wasm") +(def ^:private kernel-wasm "docs/examples/polyglot/c/kernel.wasm") + +(deftest single-function-module + (is (= [{:name "add" :kind :func :params [:i32 :i32] :results [:i32]}] + (wasm/exports (wasm/load add-wasm))))) + +(deftest c-kernel-exports + (let [es (wasm/exports (wasm/load kernel-wasm))] + (testing "the linear memory and four functions, in export order" + (is (= [["memory" :memory] ["buf_addr" :func] ["buf_cap" :func] + ["sum_f64" :func] ["scale_f64" :func]] + (mapv (juxt :name :kind) es)))) + (testing "function signatures" + (is (= [["buf_addr" [] [:i32]] + ["buf_cap" [] [:i32]] + ["sum_f64" [:i32 :i32] [:f64]] + ["scale_f64" [:i32 :i32 :f64] [:i32]]] + (vec (for [e es :when (= :func (:kind e))] + [(:name e) (:params e) (:results e)]))))) + (testing "a non-function export carries no :params / :results" + (is (= {:name "memory" :kind :memory} + (first (filter #(= :memory (:kind %)) es))))))) + +(deftest exports-drive-call + (let [h (wasm/load add-wasm) + e (first (wasm/exports h))] + (is (= 42 (apply wasm/call h (:name e) (take (count (:params e)) [40 2 99])))))) + +(deftest bad-handle-is-catalogued + (is (= "wasm/exports: the first argument must be a loaded wasm module" + (try (wasm/exports 42) nil + (catch Exception e (ex-message e)))))) diff --git a/test/e2e/fixtures/wasm_dot_interop_probe.clj b/test/e2e/fixtures/wasm_dot_interop_probe.clj deleted file mode 100644 index d38d6e06a..000000000 --- a/test/e2e/fixtures/wasm_dot_interop_probe.clj +++ /dev/null @@ -1,33 +0,0 @@ -;; Dot-interop on a core wasm module handle (ADR-0203 decision 2). Every -;; method-call form on a `wasm_module` value is `wasm/call` with the method -;; symbol's name as the export name, verbatim. Asserted by -;; test/e2e/phase16_wasm_dot_interop.sh. -(def h (wasm/load "docs/examples/wasm/add.wasm")) -(println "dot-method" (.add h 40 2)) -(println "dot-form" (. h add 40 2)) -(println "dot-list" (. h (add 40 2))) -(println "same-as-call" (= (.add h 40 2) (wasm/call h "add" 40 2))) - -;; A C kernel: the export name `sum_f64` works as written (no munging), and the -;; buffer comes from the guest's own allocator. -(def m (wasm/load "docs/examples/polyglot/c/kernel.wasm")) -(def buf (wasm/call m "buf_addr")) -(wasm/mem-write! m :f64 buf [1.0 2.0 3.0 4.0]) -(println "c-sum" (.sum_f64 m buf 4)) -(println "c-scale" (.scale_f64 m buf 4 2.0) (.sum_f64 m buf 4)) - -(defn msg [f] - (try (f) "NOT-RAISED" (catch Throwable e (.getMessage e)))) - -;; A missing export and a trap raise exactly what wasm/call raises. -(println "missing-same" (= (msg #(.nope h 1)) (msg #(wasm/call h "nope" 1)))) -(println "missing" (msg #(.nope h 1))) -(println "arity" (msg #(.add h 1))) -(def t (wasm/load "docs/examples/wasm/trap.wasm")) -(println "trap-same" (= (msg #(.boom t)) (msg #(wasm/call t "boom")))) -(println "trap" (msg #(.boom t))) - -;; Non-wasm receivers are unchanged. -(println "string" (.toUpperCase "abc")) -(println "nonwasm" (msg #(.add 42 1))) -(println "DONE") diff --git a/test/e2e/phase16_wasm_dot_interop.sh b/test/e2e/phase16_wasm_dot_interop.sh deleted file mode 100755 index 3bf47d25e..000000000 --- a/test/e2e/phase16_wasm_dot_interop.sh +++ /dev/null @@ -1,69 +0,0 @@ -#!/usr/bin/env bash -# test/e2e/phase16_wasm_dot_interop.sh — method-call forms on a core wasm -# module handle (ADR-0203 decision 2). `(.add h 40 2)`, `(. h add 40 2)` and -# `(. h (add 40 2))` are `(wasm/call h "add" 40 2)`: the method symbol's name is -# the export name verbatim, and the call takes the SAME path as wasm/call, so a -# missing export, an arity mismatch and a trap raise the same catalogued errors. -# -# OPT-IN for the same reason as phase16_wasm_ffi.sh: it builds `-Dwasm`, so it -# resolves zwasm, which the default gate never does (F-001). -set -euo pipefail -cd "$(dirname "$0")/../.." -BIN="zig-out/bin/cljw" -fail() { echo "FAIL $1" >&2; exit 1; } - -if [ -z "${CLJW_SKIP_BUILD:-}" ] && ! zig build -Dwasm -Doptimize="${CLJW_OPT:-ReleaseSafe}" >/dev/null 2>&1; then - fail "zig build -Dwasm failed (zwasm dep unresolved?)" -fi -"$BIN" --version | grep -q wasm || fail "cljw is not wasm-enabled ($("$BIN" --version)) — zwasm did not resolve" - -FIX="test/e2e/fixtures/wasm_dot_interop_probe.clj" - -run_probe() { - local label="$1"; shift - out="$("$@" "$FIX" 2>&1)" || fail "[$label] cljw exited non-zero running $FIX: -$out" - want() { - grep -qF "$1" <<<"$out" || fail "[$label] expected '$1' in the probe output, got: -$out" - } - - # (1) The three method-call spellings all reach the export. - want "dot-method 42" - want "dot-form 42" - want "dot-list 42" - want "same-as-call true" - echo "PASS wasm-dot-interop-forms [$label] -> (.add h 40 2) / (. h add 40 2) / (. h (add 40 2)) = 42" - - # (2) A C export name is used verbatim; memory written by the host is read. - want "c-sum 10.0" - want "c-scale 4 20.0" - echo "PASS wasm-dot-interop-c-kernel [$label] -> (.sum_f64 m buf 4) = 10.0" - - # (3) Errors are wasm/call's, not a '<.member>' miss. - grep -q "NOT-RAISED" <<<"$out" && fail "[$label] a wasm dot-call error was not raised: -$out" - grep -q "<.member>.*wasm_module" <<<"$out" && fail "[$label] wasm receiver fell through to <.member> dispatch: -$out" - want "missing-same true" - want "missing wasm/call: no exported function named 'nope'" - want "arity wasm/call:" - want "trap-same true" - want "trap wasm/call: 'boom' () -> (i32) trapped" - echo "PASS wasm-dot-interop-errors [$label] -> missing export / arity / trap raise wasm/call's errors" - - # (4) Non-wasm receivers are unchanged. - want "string ABC" - want "nonwasm No implementation of method 'add' on protocol '<.member>'" - echo "PASS wasm-dot-interop-nonwasm [$label] -> other receivers keep <.member> dispatch" - - grep -q "^DONE$" <<<"$out" || fail "[$label] the probe did not run to completion: -$out" -} - -# The backend is a build option (-Dbackend, vm by default); both arms -# (VM op_method_call, TreeWalk evalInstanceMember) carry the wasm case. -run_probe "${CLJW_BACKEND:-vm}" "$BIN" - -echo -echo "phase16_wasm_dot_interop: all PASS" diff --git a/test/e2e/phase16_wasm_exports.sh b/test/e2e/phase16_wasm_exports.sh deleted file mode 100755 index f01aa632d..000000000 --- a/test/e2e/phase16_wasm_exports.sh +++ /dev/null @@ -1,65 +0,0 @@ -#!/usr/bin/env bash -# test/e2e/phase16_wasm_exports.sh — `(wasm/exports h)` lists a core module's -# exports in export order with runtime-probed signatures (ADR-0203 decision 1). -# -# Functions answer {:name :kind :func :params [...] :results [...]}, every other -# export {:name :kind :memory|:global|:table}. The signature comes from the same -# probe `wasm/call` uses, so a function `wasm/exports` describes is callable with -# exactly that arity. A non-handle argument raises the catalogued -# wasm_handle_invalid error, catchable like every other wasm-surface error. -# -# Reuses the shared -Dwasm binary under CLJW_SKIP_BUILD, like the other phase16 -# wasm e2es; standalone it builds -Dwasm ReleaseSafe itself. -set -euo pipefail -cd "$(dirname "$0")/../.." -BIN="zig-out/bin/cljw" -fail() { echo "FAIL $1" >&2; exit 1; } - -if [ -z "${CLJW_SKIP_BUILD:-}" ] && ! zig build -Dwasm -Doptimize="${CLJW_OPT:-ReleaseSafe}" >/dev/null 2>&1; then - fail "zig build -Dwasm failed (zwasm dep unresolved?)" -fi -"$BIN" --version | grep -q wasm || fail "cljw is not wasm-enabled ($("$BIN" --version))" - -check() { # name expected expr - local got - got="$("$BIN" -e "$3" 2>&1)" || fail "$1: cljw exited non-zero: -$got" - got="$(printf '%s\n' "$got" | sed '${/^nil$/d}')" # -e echoes the prn/println result - [ "$got" = "$2" ] || fail "$1: expected - $2 -got - $got" - echo "PASS $1" -} - -# (1) The single-function module: the acceptance shape, verbatim. -check wasm-exports-add \ - '[{:name "add", :kind :func, :params [:i32 :i32], :results [:i32]}]' \ - '(prn (wasm/exports (wasm/load "docs/examples/wasm/add.wasm")))' - -# (2) A C-compiled module: the linear memory and four functions, in export order. -check wasm-exports-c-kernel-names \ - '[["memory" :memory] ["buf_addr" :func] ["buf_cap" :func] ["sum_f64" :func] ["scale_f64" :func]]' \ - '(prn (mapv (juxt :name :kind) (wasm/exports (wasm/load "docs/examples/polyglot/c/kernel.wasm"))))' - -check wasm-exports-c-kernel-sigs \ - '[["buf_addr" [] [:i32]] ["buf_cap" [] [:i32]] ["sum_f64" [:i32 :i32] [:f64]] ["scale_f64" [:i32 :i32 :f64] [:i32]]]' \ - '(prn (vec (for [e (wasm/exports (wasm/load "docs/examples/polyglot/c/kernel.wasm")) :when (= :func (:kind e))] [(:name e) (:params e) (:results e)])))' - -# (3) A non-function export carries no :params / :results. -check wasm-exports-memory-has-no-sig \ - '{:name "memory", :kind :memory}' \ - '(prn (first (filter #(= :memory (:kind %)) (wasm/exports (wasm/load "docs/examples/polyglot/c/kernel.wasm")))))' - -# (4) What exports describes is callable at exactly that arity. -check wasm-exports-drives-call \ - '42' \ - '(let [h (wasm/load "docs/examples/wasm/add.wasm") e (first (wasm/exports h))] (prn (apply wasm/call h (:name e) (take (count (:params e)) [40 2 99]))))' - -# (5) A non-handle is the catalogued wasm_handle_invalid error, catchable. -check wasm-exports-bad-handle \ - 'CAUGHT wasm/exports: the first argument must be a loaded wasm module' \ - '(try (wasm/exports 42) (catch Exception e (println "CAUGHT" (ex-message e))))' - -echo -echo "Phase 16 / wasm/exports introspection: all green." diff --git a/test/run_all.sh b/test/run_all.sh index 46861060b..aa3ff5b00 100644 --- a/test/run_all.sh +++ b/test/run_all.sh @@ -715,7 +715,6 @@ run_step "e2e_bulk_literal" "bash test/e2e/bulk_literal.sh" # cannot resolve zwasm, build_cljw fails first — wasm is a gate prerequisite now. run_step "e2e_phase16_wasm_ffi" "bash test/e2e/phase16_wasm_ffi.sh" run_step "e2e_phase16_wasm_memory" "bash test/e2e/phase16_wasm_memory.sh" -run_step "e2e_phase16_wasm_exports" "bash test/e2e/phase16_wasm_exports.sh" run_step "e2e_phase16_wasm_engine_select" "bash test/e2e/phase16_wasm_engine_select.sh" run_step "e2e_phase16_wasm_run" "bash test/e2e/phase16_wasm_run.sh" # D-349: the third budget axis. Fuel bounds instructions; how many bytes an @@ -731,8 +730,6 @@ run_step "e2e_phase16_wasm_component_budget" "bash test/e2e/phase16_wasm_compone # as committed AND rebuilt from their source headers (each toolchain on PATH), # plus hosts.cljc on every Clojure host present. A README claim with a gate. run_step "e2e_phase16_wasm_polyglot" "bash test/e2e/phase16_wasm_polyglot.sh" -# ADR-0203: `(.export h …)` on a core module handle is wasm/call's path. -run_step "e2e_phase16_wasm_dot_interop" "bash test/e2e/phase16_wasm_dot_interop.sh" # The reswap coverage moved to suites/wasm-require-component-reswap-test: it # asserts values, not the process boundary, so it runs in-process now. run_step "e2e_phase15_ns_import" "bash test/e2e/phase15_ns_import.sh" From 7dc4fd143cc2d0df8156ac4847b9f93ab56ae397 Mon Sep 17 00:00:00 2001 From: Pedro Gomes Branquinho Date: Wed, 21 Oct 2026 14:25:05 -0300 Subject: [PATCH 11/17] docs(readme): apply the agora d666cca9 review Six changes agreed by the newcomer, clojurist and editor reviewers in agora d666cca9: 1. Order and navigation: Install and Quickstart follow the intro, a one-line table of contents is added, News shrinks to one paragraph, and License and credit carries the full handover account. 2. Quickstart keeps the wasm/call line and adds the ADR-0203 dot form (.add m 40 2), marked as arriving in the next release. 3. Wasm FFI section: wasm/exports as the discovery step and (.sum_f64 m buf 4), both marked next release, with the dot-interop semantics (ADR-0203); every elided output replaced by the real one. 4. Accuracy: startup figures only under Numbers; string-path :require marked cljw-only; "What does not" names core.async, java.time.format, the permissive clojure.edn/read-string and (clojure-version) "1.12.0". 5. Where it shines trimmed: the sandbox example runs a shipped module (kernel.wasm with a cap, trap.wasm caught); Native tools shows a real sh result; padding closer dropped. 6. What runs trimmed: the Maven resolver paragraph is two sentences plus a CHANGELOG link; "test.check, ..." becomes "test.check and more". --- README.md | 190 ++++++++++++++++++++++++++++-------------------------- 1 file changed, 99 insertions(+), 91 deletions(-) diff --git a/README.md b/README.md index cc0a7478d..0cdbd7f6b 100644 --- a/README.md +++ b/README.md @@ -23,21 +23,50 @@ WebAssembly engine so a `.wasm` compiled from Rust, Go, C or Zig can be required like a namespace and called like a function, inside a sandbox whose fuel and memory the caller sets. -## News +[Install](#install) · [Quickstart](#quickstart) · [News](#news) · +[Where it shines](#where-it-shines) · [How it is put together](#how-it-is-put-together) · +[Wasm FFI](#the-wasm-ffi-in-one-screen) · [Numbers](#numbers) · +[What runs](#what-runs) · [Documentation](#documentation) · +[License](#license-and-credit) -**2026-10: the project has a new maintainer.** -[@chaploud](https://github.com/chaploud), who created ClojureWasm and released -it through v1.10.1, has handed the [clojurewasm](https://github.com/clojurewasm) -organization over to [@BuddhiLW](https://github.com/BuddhiLW). The fork's work -(v1.11 through v1.15.0) is merged back into -[clojurewasm/ClojureWasm](https://github.com/clojurewasm/ClojureWasm), so the -original repository is active again. Releases and the Homebrew tap keep -publishing from [BuddhiLW/ClojureWasm](https://github.com/BuddhiLW/ClojureWasm) -for now; existing install commands and version pins keep working. +## Install + +```sh +brew install buddhilw/tap/cljw # macOS arm64, Linux x86_64 +``` + +Binaries are also on the [Releases](https://github.com/BuddhiLW/ClojureWasm/releases) +page. The binary is not code-signed; if macOS blocks it once, clear the +quarantine flag: `xattr -d com.apple.quarantine "$(which cljw)"`. + +From source (Zig 0.16; `direnv allow` or `nix develop` provides it): + +```sh +zig build -Dwasm -Doptimize=ReleaseSafe # → ./zig-out/bin/cljw +``` + +## Quickstart + +```sh +cljw -e '(->> (range) (filter even?) (take 5))' # (0 2 4 6 8) +cljw -e '(wasm/call (wasm/load "docs/examples/wasm/add.wasm") "add" 40 2)' # 42 +cljw -e '(.add (wasm/load "docs/examples/wasm/add.wasm") 40 2)' # 42, next release +cljw script.clj # run a file +cljw # REPL +cljw nrepl --port 7888 # nREPL, CIDER-compatible +cljw build script.clj -o app # one self-contained native binary +``` -[Issues](https://github.com/BuddhiLW/ClojureWasm/issues) and PRs are open, and -the most useful report is Clojure code that behaves differently here than on -the JVM (there is an issue template for it). +## News + +**2026-10:** [@chaploud](https://github.com/chaploud) handed the project to +[@BuddhiLW](https://github.com/BuddhiLW); the fork's work is merged back into +[clojurewasm/ClojureWasm](https://github.com/clojurewasm/ClojureWasm), releases +and the Homebrew tap still publish from +[BuddhiLW/ClojureWasm](https://github.com/BuddhiLW/ClojureWasm), and install +commands and version pins are unchanged. +[Issues](https://github.com/BuddhiLW/ClojureWasm/issues) and PRs are open; the +most useful report is Clojure code that behaves differently here than on the JVM. ## Where it shines @@ -49,9 +78,10 @@ runs in-process: plugin systems, MCP tool servers, request handlers that evaluate user code. ```clojure -(def zk (wasm/load-component "zk_groth16.wasm" {:fuel 5000000 :max-memory-pages 64})) -(wasm/component-call zk "verify" proof 35) ;=> [:ok true] -(wasm/component-call zk "spin") ; throws: exhausted its fuel budget +(def k (wasm/load "docs/examples/polyglot/c/kernel.wasm" {:fuel 1000000 :max-memory-pages 16})) +(wasm/call k "buf_cap") ;=> 256 +(try (wasm/call (wasm/load "docs/examples/wasm/trap.wasm") "boom") + (catch Exception e (re-find #"trapped" (ex-message e)))) ;=> "trapped" ``` **Other languages' libraries, from Clojure.** JVM Clojure calls Java; @@ -68,6 +98,9 @@ vectors, `result` as `[:ok v]` / `[:err e]`. (:arglists (meta #'tp/process)) ;; => ([input]) ``` +A string path in `:require` is cljw-only; in a `.cljc`, write it as +`#?(:cljw ["./typed_payload.wasm" :as tp])`. + Each guest language has a natural shape, and cljw has an entry point for each: | guest | built with | crosses the boundary as | entry point | @@ -82,30 +115,26 @@ All five run in [`docs/examples/polyglot`](./docs/examples/polyglot/README.md), sources and build lines included; CI rebuilds them from source and runs them on every push. -**Native tools, unchanged.** When the tool already exists as a native binary, -nothing needs recompiling to Wasm and nothing needs bindings: its seam is its -command line. `clojure.java.shell/sh` runs any program by argv (never through a -shell) and returns `{:exit :out :err}`, with a non-zero exit as data. The same -call runs on the JVM and on clojurust, so the client that wraps the tool is one -`.cljc`. +**Native tools, unchanged.** A tool that already exists as a native binary +needs no Wasm build and no bindings. `clojure.java.shell/sh`, the same API the +JVM and babashka ship, runs it by argv (never through a shell) and returns +`{:exit :out :err}`, with a non-zero exit as data. ```clojure (require '[clojure.java.shell :refer [sh]]) -(sh "autopdf" "build" "invoice.tex" "invoice.json" "clean" :dir "examples") -;; => {:exit 0, :out "...", :err "..."} ; a Go binary, driven as is +(sh "echo" "hi") ;=> {:exit 0, :out "hi\n", :err ""} ``` [AutoPDF's Clojure client](https://github.com/BuddhiLW/AutoPDF/tree/main/clients/clojure) -drives the unmodified Go `autopdf` CLI this way and renders the same PDF, -byte for byte, on cljw, clojurust and the JVM. A child process escapes every -in-process containment, so `sh` is refused under a filesystem root -(`CLJW_FS_ROOT`) or inside `cljw.eval/with-budget`: pick Wasm when the guest -must be confined, the process seam when the tool is trusted. +drives the unmodified Go `autopdf` CLI this way and renders the same PDF on +cljw, clojurust and the JVM. A child process escapes in-process containment, so +`sh` is refused under a filesystem root (`CLJW_FS_ROOT`) or inside +`cljw.eval/with-budget`. -**Short-lived processes.** 8.1 MB on disk, about 6 ms from process start to -first eval, and `cljw build app.clj -o app` produces a self-contained -executable. CLI tools, serverless handlers, scripts that run a thousand times -a day. +**Short-lived processes.** One 8.1 MB binary that starts in milliseconds +([Numbers](#numbers)), and `cljw build app.clj -o app` produces a +self-contained executable. CLI tools, serverless handlers, scripts that run a +thousand times a day. **One program, two runtimes.** `cljw` reads `.cljc` under the feature set `{:cljw :clj :default}`, and its sibling [clojurust](https://github.com/BuddhiLW/clojurust) @@ -136,9 +165,6 @@ crate and feature set on both sides): | file read | granted | denied | | wall clock | granted | trap | -Same proof bytes; the only thing that differs is how much authority the prover -holds while it runs. - ## How it is put together ```mermaid @@ -158,58 +184,43 @@ from-scratch runtime keeps Clojure semantics honest without a reference implementation in the process. [`docs/architecture.md`](./docs/architecture.md) has the map. -## Install - -```sh -brew install buddhilw/tap/cljw # macOS arm64, Linux x86_64 -``` - -Binaries are also on the [Releases](https://github.com/BuddhiLW/ClojureWasm/releases) -page. The binary is not code-signed; if macOS blocks it once, clear the -quarantine flag: `xattr -d com.apple.quarantine "$(which cljw)"`. - -From source (Zig 0.16; `direnv allow` or `nix develop` provides it): - -```sh -zig build -Dwasm -Doptimize=ReleaseSafe # → ./zig-out/bin/cljw -``` - -## Quickstart - -```sh -cljw -e '(->> (range) (filter even?) (take 5))' # (0 2 4 6 8) -cljw -e '(wasm/call (wasm/load "docs/examples/wasm/add.wasm") "add" 40 2)' # 42 -cljw script.clj # run a file -cljw # REPL -cljw nrepl --port 7888 # nREPL, CIDER-compatible -cljw build script.clj -o app # one self-contained native binary -``` - ## The Wasm FFI in one screen ```clojure ;; A core module (docs/examples/polyglot/c/kernel.c): numbers in, numbers ;; out, arrays in a buffer the guest owns and hands out by address. (def m (wasm/load "docs/examples/polyglot/c/kernel.wasm" {:fuel 1000000 :max-memory-pages 16})) -(wasm/exports m) ;=> [{:name "memory", :kind :memory} - ; {:name "buf_addr", :kind :func, :params [], :results [:i32]} - ; ... {:name "sum_f64", :kind :func, :params [:i32 :i32], :results [:f64]} ...] + +;; Next release: list the exports before calling any. +(mapv (juxt :name :kind) (wasm/exports m)) +;=> [["memory" :memory] ["buf_addr" :func] ["buf_cap" :func] ["sum_f64" :func] ["scale_f64" :func]] + (def buf (wasm/call m "buf_addr")) (wasm/mem-write! m :f64 buf [1.0 2.0 3.0 4.0]) (wasm/call m "sum_f64" buf 4) ;=> 10.0 +(.sum_f64 m buf 4) ;=> 10.0, next release (wasm/mem-read m :f64 buf 4) ;=> [1.0 2.0 3.0 4.0] ;; A WIT component: typed, so arguments and results are plain Clojure data. (def g "test/e2e/fixtures/wasm/greet_component.wasm") -(wasm/component-exports g) ;=> ({:name "greet", ...}) +(wasm/component-exports g) ;=> [{:name "greet", :params [["name" "string"]], :result "string"}] (def c (wasm/load-component g {:fuel 100000})) (wasm/component-call c "greet" "zwasm") ;=> "Hello, zwasm!" ;; A fault in the guest is a catchable Clojure exception, never a host crash. (try (wasm/call (wasm/load "docs/examples/wasm/trap.wasm") "boom") - (catch Exception e (ex-message e))) ;=> "wasm/call: 'boom' ... trapped ..." + (catch Exception e (ex-message e))) +;=> "wasm/call: 'boom' () -> (i32) trapped on the auto (JIT-first) engine +; (divide-by-zero, out-of-bounds, unreachable, or a call shape the engine +; cannot dispatch)" ``` +Dot interop (ADR-0203, next release): on a module handle, `(.sum_f64 m buf 4)`, +`(. m sum_f64 buf 4)` and `(. m (sum_f64 buf 4))` are `wasm/call` with the +method name as the export name, verbatim, so results, fuel and errors are the +same. It is cljw-only (use a `:cljw` reader conditional in a `.cljc`), and an +export whose name is not a valid symbol still goes through `wasm/call`. + Budgets: a missing axis keeps the engine's finite default (1e9 fuel, 4096 pages), `0` removes a cap for a trusted guest, and fuel is per instance, so an exhausted handle stays exhausted until you load again. The engine is JIT by @@ -264,32 +275,26 @@ multimethods, `deftype` / `reify`, the full numeric tower (`Ratio`, `BigInt`, coordinates, and a CIDER-compatible nREPL. Real libraries that load and run today (medley, tools.cli, data.json, -core.cache, malli, hiccup, honeysql, test.check, ...) are tracked in +core.cache, malli, hiccup, honeysql, test.check and more) are tracked in [`docs/works/ladder.md`](./docs/works/ladder.md). -Maven `:mvn/version` coordinates resolve Clojure source entries in cached JARs -from `$M2_REPO` (default `~/.m2/repository`). Missing artifacts are downloaded -from Clojars, then Maven Central via HTTPS (`curl`); extracted source roots are -cached under `$CLJW_HOME/mvn` (default `~/.cljw/mvn`). Compile/runtime POM -coordinates are traversed; `org.clojure/clojure` and JARs with no Clojure -sources are omitted. Remote JARs and POMs must match their repository's SHA-1 -sidecar before installation; a missing or mismatched checksum fails closed. -`CLJW_MVN_REPOS` overrides the ordered repository bases as comma-separated URLs -(default Clojars, then Maven Central; `file://` is useful for hermetic tests). -Artifacts already in `$M2_REPO` are trusted. `curl` and `unzip` are required on the host. POM traversal -supports direct compile/runtime dependencies with literal versions or local -properties; it does not implement BOM imports, inherited dependencyManagement, -classifiers, exclusions, or Maven version mediation. JVM-only jars provide no -source path (native Java classes remain unavailable). For example: +`:mvn/version` coordinates load Clojure sources from JARs in +`~/.m2/repository`, fetching missing ones from Clojars, then Maven Central; +every fetched JAR and POM must match its SHA-1 sidecar or the load fails +closed. `curl` and `unzip` must be on the host, and the +[CHANGELOG](./CHANGELOG.md) entry for 1.15.0 lists the limits. ```clojure {:deps {metosin/malli {:mvn/version "0.20.2"}}} ``` -What does not: `core.async` is not bundled, and JVM -interop that exists only to reach the JVM (`gen-class`, `proxy` over arbitrary -classes, reflection, `import` of arbitrary Java classes) is out of scope by -design. The full picture, including the intentional divergences, is +What does not: `core.async` is not bundled, `java.time.format` is not +implemented, and `clojure.edn/read-string` reuses the permissive Clojure +reader, so some EDN-invalid input (such as `#(inc %)`) is accepted. +`(clojure-version)` reports `"1.12.0"`, the semantics target. JVM interop that +exists only to reach the JVM (`gen-class`, `proxy` over arbitrary classes, +reflection, `import` of arbitrary Java classes) is out of scope by design. The +full picture, including the intentional divergences, is [`docs/clojure_vs_clojurewasm.md`](./docs/clojure_vs_clojurewasm.md). ## Documentation @@ -315,7 +320,10 @@ Eclipse Public License 2.0, see [LICENSE](./LICENSE) and ClojureWasm was created by [Shota Kudo (@chaploud)](https://github.com/chaploud), who took it from nothing to a working JVM-free Clojure runtime with a Wasm FFI -through v1.10, and in 2026-10 passed the project on to -[@BuddhiLW](https://github.com/BuddhiLW). Everything shipped since is built on -that work. The embedded -engine is [zwasm](https://github.com/zwasm/zwasm). +through v1.10.1, and in 2026-10 handed the +[clojurewasm](https://github.com/clojurewasm) organization over to +[@BuddhiLW](https://github.com/BuddhiLW). The fork's work (v1.11 through +v1.15.0) is merged back into +[clojurewasm/ClojureWasm](https://github.com/clojurewasm/ClojureWasm), so the +original repository is active again. Everything shipped since is built on +that work. The embedded engine is [zwasm](https://github.com/zwasm/zwasm). From 088264967254f24f72b8936d06a7600316016c9e Mon Sep 17 00:00:00 2001 From: Pedro Gomes Branquinho Date: Wed, 21 Oct 2026 16:04:03 -0300 Subject: [PATCH 12/17] docs(readme): a shorter README led by C-to-Clojure and the graphs 329 lines to 219. The page now opens with install, then the C function compiled to Wasm and called with dot interop, then the architecture diagram, the size and startup charts, and the one-program-two-runtimes diagram with the Groth16 table compressed to three rows. Use cases are five bullets; what runs, docs and credit are each one short block. Every figure and link carried over unchanged; nav anchors match headings. --- README.md | 364 +++++++++++++++++++----------------------------------- 1 file changed, 127 insertions(+), 237 deletions(-) diff --git a/README.md b/README.md index 0cdbd7f6b..255dc6e3d 100644 --- a/README.md +++ b/README.md @@ -13,159 +13,97 @@ CI Homebrew tap Zig 0.16.0 - Clojure runtime License: EPL 2.0

-ClojureWasm (`cljw`) runs Clojure without a JVM. It is written in Zig and -Clojure, ships as one static binary, starts in milliseconds, and embeds a -WebAssembly engine so a `.wasm` compiled from Rust, Go, C or Zig can be -required like a namespace and called like a function, inside a sandbox whose -fuel and memory the caller sets. +

+ Install · + Call C from Clojure · + How it works · + Numbers · + Where it fits · + What runs · + Docs +

-[Install](#install) · [Quickstart](#quickstart) · [News](#news) · -[Where it shines](#where-it-shines) · [How it is put together](#how-it-is-put-together) · -[Wasm FFI](#the-wasm-ffi-in-one-screen) · [Numbers](#numbers) · -[What runs](#what-runs) · [Documentation](#documentation) · -[License](#license-and-credit) +`cljw` runs Clojure without a JVM. It ships as one static binary, starts in +milliseconds, and embeds a WebAssembly engine: a `.wasm` built from C, Rust, +Go or Zig loads like a library and runs inside a sandbox whose fuel and memory +you set. ## Install ```sh -brew install buddhilw/tap/cljw # macOS arm64, Linux x86_64 -``` - -Binaries are also on the [Releases](https://github.com/BuddhiLW/ClojureWasm/releases) -page. The binary is not code-signed; if macOS blocks it once, clear the -quarantine flag: `xattr -d com.apple.quarantine "$(which cljw)"`. - -From source (Zig 0.16; `direnv allow` or `nix develop` provides it): - -```sh -zig build -Dwasm -Doptimize=ReleaseSafe # → ./zig-out/bin/cljw +brew install buddhilw/tap/cljw # macOS arm64, Linux x86_64 +zig build -Dwasm -Doptimize=ReleaseSafe # or from source (Zig 0.16) ``` -## Quickstart +Prebuilt binaries are on [Releases](https://github.com/BuddhiLW/ClojureWasm/releases). +They are not code-signed; on macOS, `xattr -d com.apple.quarantine "$(which cljw)"` +once. ```sh -cljw -e '(->> (range) (filter even?) (take 5))' # (0 2 4 6 8) -cljw -e '(wasm/call (wasm/load "docs/examples/wasm/add.wasm") "add" 40 2)' # 42 -cljw -e '(.add (wasm/load "docs/examples/wasm/add.wasm") 40 2)' # 42, next release -cljw script.clj # run a file -cljw # REPL -cljw nrepl --port 7888 # nREPL, CIDER-compatible -cljw build script.clj -o app # one self-contained native binary +cljw -e '(->> (range) (filter even?) (take 5))' # (0 2 4 6 8) +cljw script.clj # run a file +cljw # REPL +cljw nrepl --port 7888 # nREPL, CIDER-compatible +cljw build script.clj -o app # self-contained native binary ``` -## News +## Call C from Clojure -**2026-10:** [@chaploud](https://github.com/chaploud) handed the project to -[@BuddhiLW](https://github.com/BuddhiLW); the fork's work is merged back into -[clojurewasm/ClojureWasm](https://github.com/clojurewasm/ClojureWasm), releases -and the Homebrew tap still publish from -[BuddhiLW/ClojureWasm](https://github.com/BuddhiLW/ClojureWasm), and install -commands and version pins are unchanged. -[Issues](https://github.com/BuddhiLW/ClojureWasm/issues) and PRs are open; the -most useful report is Clojure code that behaves differently here than on the JVM. +A C function, compiled to Wasm, called with ordinary Clojure interop. -## Where it shines +```c +// docs/examples/polyglot/c/kernel.c +EXPORT("sum_f64") double sum_f64(int off, int n) { + const double *p = (const double *)(long)off; + double s = 0.0; + for (int i = 0; i < n; i++) s += p[i]; + return s; +} +``` -**Sandboxed plugins and tools.** A module instantiates with an empty import -object, so a guest reaches nothing the host did not grant, and every load takes -a budget. A tool that spins burns its fuel and returns an error; the host -process keeps running. That makes `cljw` a fit for hosts where untrusted code -runs in-process: plugin systems, MCP tool servers, request handlers that -evaluate user code. +```sh +zig cc -target wasm32-freestanding -O2 -nostdlib \ + -Wl,--no-entry -Wl,--export-memory -Wl,-z,stack-size=65536 kernel.c -o kernel.wasm +``` ```clojure (def k (wasm/load "docs/examples/polyglot/c/kernel.wasm" {:fuel 1000000 :max-memory-pages 16})) -(wasm/call k "buf_cap") ;=> 256 -(try (wasm/call (wasm/load "docs/examples/wasm/trap.wasm") "boom") - (catch Exception e (re-find #"trapped" (ex-message e)))) ;=> "trapped" -``` - -**Other languages' libraries, from Clojure.** JVM Clojure calls Java; -ClojureScript calls JavaScript; here the host is a language-neutral `.wasm`. -A WIT-typed component is a namespace: records arrive as maps, lists as -vectors, `result` as `[:ok v]` / `[:err e]`. -```clojure -(ns my.app - (:require ["./typed_payload.wasm" :as tp])) ; Rust + wit-bindgen, 51 KB +(mapv :name (wasm/exports k)) ;=> ["memory" "buf_addr" "buf_cap" "sum_f64" "scale_f64"] -(tp/process {:xs [3 4 5] :label "data"}) ;; => [:ok {:xs [3 4 5 12], :label "data!"}] -(tp/process {:xs [] :label "fail"}) ;; => [:err "boom: fail"] -(:arglists (meta #'tp/process)) ;; => ([input]) +(def buf (.buf_addr k)) +(wasm/mem-write! k :f64 buf [1.0 2.0 3.0 4.0]) +(.sum_f64 k buf 4) ;=> 10.0 ``` -A string path in `:require` is cljw-only; in a `.cljc`, write it as -`#?(:cljw ["./typed_payload.wasm" :as tp])`. +`wasm/exports` and the dot form arrive in the next release; on the current +one, write `(wasm/call k "sum_f64" buf 4)`. A guest fault is a catchable +exception, never a host crash, and a guest that runs out of fuel stops with an +error while your process keeps going. -Each guest language has a natural shape, and cljw has an entry point for each: - -| guest | built with | crosses the boundary as | entry point | -|---|---|---|---| -| C | `zig cc -target wasm32-freestanding` | scalars, arrays in a guest-owned buffer | `wasm/load`, `wasm/call`, `wasm/mem-*` | -| Zig | `zig build-exe -target wasm32-freestanding` | scalars | `wasm/load`, `wasm/call` | -| Rust, `no_std` | `rustc --target wasm32-unknown-unknown` | scalars | `wasm/load`, `wasm/call` | -| Rust, wit-bindgen | `cargo build --target wasm32-wasip2` | records, lists, strings, results | `(:require ["x.wasm" :as x])` | -| Go | `GOOS=wasip1 GOARCH=wasm go build` | argv, env, stdin, stdout, exit code | `wasm/run` | - -All five run in [`docs/examples/polyglot`](./docs/examples/polyglot/README.md), -sources and build lines included; CI rebuilds them from source and runs them on -every push. - -**Native tools, unchanged.** A tool that already exists as a native binary -needs no Wasm build and no bindings. `clojure.java.shell/sh`, the same API the -JVM and babashka ship, runs it by argv (never through a shell) and returns -`{:exit :out :err}`, with a non-zero exit as data. +A WIT component goes further: it is required like a namespace, and records, +lists and `result` cross as plain Clojure data. ```clojure -(require '[clojure.java.shell :refer [sh]]) -(sh "echo" "hi") ;=> {:exit 0, :out "hi\n", :err ""} -``` - -[AutoPDF's Clojure client](https://github.com/BuddhiLW/AutoPDF/tree/main/clients/clojure) -drives the unmodified Go `autopdf` CLI this way and renders the same PDF on -cljw, clojurust and the JVM. A child process escapes in-process containment, so -`sh` is refused under a filesystem root (`CLJW_FS_ROOT`) or inside -`cljw.eval/with-budget`. - -**Short-lived processes.** One 8.1 MB binary that starts in milliseconds -([Numbers](#numbers)), and `cljw build app.clj -o app` produces a -self-contained executable. CLI tools, serverless handlers, scripts that run a -thousand times a day. - -**One program, two runtimes.** `cljw` reads `.cljc` under the feature set -`{:cljw :clj :default}`, and its sibling [clojurust](https://github.com/BuddhiLW/clojurust) -(`cljrs`, Rust-hosted, Cranelift JIT) reads `{:rust}`. A host-free `.cljc` -runs unchanged on the JVM, on `cljw` and on `cljrs` -([`hosts.cljc`](./docs/examples/polyglot/hosts.cljc) prints the same map on -all three, ratios and bigints included, and CI checks that), and the same Rust -crate can serve both: as a zero-import Wasm component on `cljw`, as a native -`cdylib` on `cljrs`. The program picks confinement or speed without a rewrite. +(ns my.app (:require ["./typed_payload.wasm" :as tp])) ; Rust + wit-bindgen -```mermaid -flowchart LR - P["demo.cljc
one Clojure program"] --> A["cljw
Wasm component, zero imports"] - P --> B["cljrs
native cdylib"] - A --> L[("arkworks Groth16
the same Rust crate")] - B --> L +(tp/process {:xs [3 4 5] :label "data"}) ;=> [:ok {:xs [3 4 5 12], :label "data!"}] +(tp/process {:xs [] :label "fail"}) ;=> [:err "boom: fail"] ``` -Measured on that exact shape (a Groth16 prover over BN254, 2026-09-12, same -crate and feature set on both sides): - -| | cljrs (native) | cljw (Wasm) | +| guest | crosses the boundary as | entry point | |---|---|---| -| proof | 128 bytes | 128 bytes | -| verify, correct / wrong statement | true / false | true / false | -| wall time | 1.29 s (debug build) | 9.17 s | -| env vars visible to the prover | 212 | 0 | -| file read | granted | denied | -| wall clock | granted | trap | +| C, Zig, Rust `no_std` | scalars, arrays in guest memory | `wasm/load`, `wasm/call`, `(.f m args)`, `wasm/mem-*` | +| Rust + wit-bindgen | records, lists, strings, results | `(:require ["x.wasm" :as x])` | +| Go (`wasip1`) | argv, env, stdin, stdout, exit code | `wasm/run` | + +All of them build and run in [`docs/examples/polyglot`](./docs/examples/polyglot/README.md), +rebuilt from source by CI on every push. -## How it is put together +## How it works ```mermaid flowchart LR @@ -175,65 +113,15 @@ flowchart LR TW --> RT["runtime: NaN-boxed values, mark-sweep GC,
persistent collections, STM, agents, nREPL"] VM --> RT RT --> Z["zwasm engine
interpreter + JIT, fuel and memory budgets"] - Z --> W[".wasm modules and WIT components
from Rust, Go, C, Zig"] + Z --> W[".wasm modules and WIT components
from C, Rust, Go, Zig"] ``` -Both backends evaluate the same analyzer output, and the test suite runs every -case on both and fails on a mismatch. That differential oracle is how a -from-scratch runtime keeps Clojure semantics honest without a reference -implementation in the process. [`docs/architecture.md`](./docs/architecture.md) +Two backends evaluate the same analyzer output, and every test runs on both: +a mismatch fails the build. [`docs/architecture.md`](./docs/architecture.md) has the map. -## The Wasm FFI in one screen - -```clojure -;; A core module (docs/examples/polyglot/c/kernel.c): numbers in, numbers -;; out, arrays in a buffer the guest owns and hands out by address. -(def m (wasm/load "docs/examples/polyglot/c/kernel.wasm" {:fuel 1000000 :max-memory-pages 16})) - -;; Next release: list the exports before calling any. -(mapv (juxt :name :kind) (wasm/exports m)) -;=> [["memory" :memory] ["buf_addr" :func] ["buf_cap" :func] ["sum_f64" :func] ["scale_f64" :func]] - -(def buf (wasm/call m "buf_addr")) -(wasm/mem-write! m :f64 buf [1.0 2.0 3.0 4.0]) -(wasm/call m "sum_f64" buf 4) ;=> 10.0 -(.sum_f64 m buf 4) ;=> 10.0, next release -(wasm/mem-read m :f64 buf 4) ;=> [1.0 2.0 3.0 4.0] - -;; A WIT component: typed, so arguments and results are plain Clojure data. -(def g "test/e2e/fixtures/wasm/greet_component.wasm") -(wasm/component-exports g) ;=> [{:name "greet", :params [["name" "string"]], :result "string"}] -(def c (wasm/load-component g {:fuel 100000})) -(wasm/component-call c "greet" "zwasm") ;=> "Hello, zwasm!" - -;; A fault in the guest is a catchable Clojure exception, never a host crash. -(try (wasm/call (wasm/load "docs/examples/wasm/trap.wasm") "boom") - (catch Exception e (ex-message e))) -;=> "wasm/call: 'boom' () -> (i32) trapped on the auto (JIT-first) engine -; (divide-by-zero, out-of-bounds, unreachable, or a call shape the engine -; cannot dispatch)" -``` - -Dot interop (ADR-0203, next release): on a module handle, `(.sum_f64 m buf 4)`, -`(. m sum_f64 buf 4)` and `(. m (sum_f64 buf 4))` are `wasm/call` with the -method name as the export name, verbatim, so results, fuel and errors are the -same. It is cljw-only (use a `:cljw` reader conditional in a `.cljc`), and an -export whose name is not a valid symbol still goes through `wasm/call`. - -Budgets: a missing axis keeps the engine's finite default (1e9 fuel, 4096 -pages), `0` removes a cap for a trusted guest, and fuel is per instance, so an -exhausted handle stays exhausted until you load again. The engine is JIT by -default for modules (`:engine :interp` to force the interpreter); components -run on the interpreter. Element types for memory access are the guest's -layout: `:i8 :u8 :i16 :u16 :i32 :u32 :i64 :f32 :f64`. - ## Numbers -Every figure below is generated from a committed measurement file under -[`bench/`](./bench/README.md), not typed by hand, and the release size is -checked against the built binary by a gate on every push. - ```mermaid xychart-beta title "Binary size, MB (cljw 8.14 MB, others measured 2026-07-16)" @@ -250,80 +138,82 @@ xychart-beta bar [1.4, 3.2, 3.2, 10.0, 13.6, 18.8, 28.0, 33.7, 46.4, 231.9] ``` -Persistent collections trade wins with JVM Clojure op by op (20 000 ops at -n = 16 000, Clojure 1.12.4): `assoc` on a map is 3.9× faster on cljw, `conj` -on a vector 4.4× slower; `seq` / `rest` / `next` over a vector are O(1) views -on both and cljw's are about 2× faster. The interpreter is where the JVM wins: -an empty loop iteration costs ~45 ns here against ~2 ns under the JVM JIT, so -tight numeric Clojure loops belong in a Wasm guest or on the JVM. -[Measured, both sides.](./docs/works/collection_performance.md) +- Persistent collections trade wins with JVM Clojure op by op: map `assoc` + 3.9× faster, vector `conj` 4.4× slower ([measured](./docs/works/collection_performance.md)). +- Tight numeric loops are the JVM's: about 45 ns per empty iteration here + against 2 ns under its JIT. Put a hot kernel in a Wasm guest. +- In a guest, the engine runs 2× to 3× behind wasmtime, and one call costs + about 1 µs ([bench](./bench/README.md)). + +The release size is checked against the built binary on every push. + +## Where it fits + +- **Untrusted code in-process.** Plugins, MCP tool servers, handlers that run + user code: a module sees only what you pass it, under a fuel and memory budget. +- **Other languages' libraries.** Reach Rust, C, Go or Zig code through Wasm + instead of a JVM. +- **Existing native tools.** `clojure.java.shell/sh` runs a binary by argv and + returns `{:exit :out :err}`, as on the JVM and babashka. +- **Short-lived processes.** CLIs, scripts and serverless handlers that pay + for startup thousands of times a day. +- **One program, two runtimes.** A host-free `.cljc` runs unchanged on the + JVM, on `cljw` and on its Rust-hosted sibling + [clojurust](https://github.com/BuddhiLW/clojurust) (`cljrs`). -Inside a Wasm guest the embedded engine runs 2× to 3× behind wasmtime on -compute-bound loops (fib: 1.29 s vs 0.49 s, same module, 2026-09-04) and one -`wasm/call` crossing costs about 1 µs. The FFI is for keeping a hot kernel -native, not for beating a standalone runtime; -[the comparison is published as measured](./bench/README.md). - -## What runs +```mermaid +flowchart LR + P["demo.cljc
one Clojure program"] --> A["cljw
Wasm component, zero imports"] + P --> B["cljrs
native cdylib"] + A --> L[("arkworks Groth16
the same Rust crate")] + B --> L +``` -`clojure.core` and the everyday standard library: `string`, `set`, `walk`, -`zip`, `edn`, `data.json`, `data.csv`, `math`, `pprint`, `test`, `repl`, -`template`, `tools.cli`, `spec`. STM, atoms, agents, futures, promises, -watches, real threads. Lazy and chunked seqs, transducers, protocols, records, -multimethods, `deftype` / `reify`, the full numeric tower (`Ratio`, `BigInt`, -`BigDecimal`). A `deps.edn`-aware classpath with `:local/root` and `:git` -coordinates, and a CIDER-compatible nREPL. +| Groth16 over BN254, same crate | cljrs (native) | cljw (Wasm) | +|---|---|---| +| proof, verify | 128 bytes, true / false | 128 bytes, true / false | +| wall time | 1.29 s (debug build) | 9.17 s | +| env vars / file read / clock | 212 / granted / granted | 0 / denied / trap | -Real libraries that load and run today (medley, tools.cli, data.json, -core.cache, malli, hiccup, honeysql, test.check and more) are tracked in -[`docs/works/ladder.md`](./docs/works/ladder.md). +Confinement or speed, chosen per deployment, without a rewrite. -`:mvn/version` coordinates load Clojure sources from JARs in -`~/.m2/repository`, fetching missing ones from Clojars, then Maven Central; -every fetched JAR and POM must match its SHA-1 sidecar or the load fails -closed. `curl` and `unzip` must be on the host, and the -[CHANGELOG](./CHANGELOG.md) entry for 1.15.0 lists the limits. +## What runs -```clojure -{:deps {metosin/malli {:mvn/version "0.20.2"}}} -``` +`clojure.core` and the everyday library (`string`, `set`, `walk`, `zip`, +`edn`, `data.json`, `data.csv`, `pprint`, `test`, `spec`, `tools.cli` and more), +STM, agents, futures, real threads, transducers, protocols, records, +multimethods, `deftype` / `reify` and the full numeric tower. `deps.edn` with +`:local/root`, `:git` and `:mvn/version` coordinates; libraries such as malli, +hiccup, honeysql and test.check load today ([ladder](./docs/works/ladder.md)). -What does not: `core.async` is not bundled, `java.time.format` is not -implemented, and `clojure.edn/read-string` reuses the permissive Clojure -reader, so some EDN-invalid input (such as `#(inc %)`) is accepted. -`(clojure-version)` reports `"1.12.0"`, the semantics target. JVM interop that -exists only to reach the JVM (`gen-class`, `proxy` over arbitrary classes, -reflection, `import` of arbitrary Java classes) is out of scope by design. The -full picture, including the intentional divergences, is +Not yet: `core.async`, `java.time.format`, and a strict `clojure.edn` reader. +JVM-only interop (`gen-class`, `proxy` over arbitrary classes, reflection) is +out of scope by design. Details: [`docs/clojure_vs_clojurewasm.md`](./docs/clojure_vs_clojurewasm.md). ## Documentation -[`docs/`](./docs/README.md) is the index. The pieces most people want: +[`docs/`](./docs/README.md) · +[CHANGELOG](./CHANGELOG.md) · +[vs JVM Clojure](./docs/clojure_vs_clojurewasm.md) · +[landscape](./docs/landscape.md) · +[testing](./docs/testing.md) · +[demos](./docs/works/demos.md) · +[roadmap](./.dev/ROADMAP.md) -- [`CHANGELOG.md`](./CHANGELOG.md), every release, newest first. -- [`docs/clojure_vs_clojurewasm.md`](./docs/clojure_vs_clojurewasm.md), what - matches JVM Clojure, what deliberately does not, what is missing. -- [`docs/landscape.md`](./docs/landscape.md), where cljw sits among Clojure - runtimes, `cljrs` included. -- [`docs/testing.md`](./docs/testing.md), the eight test layers and where a - new test belongs. Read it before sending a patch. -- [`docs/works/demos.md`](./docs/works/demos.md), two real applications - (a browser playground and a bookshelf with SQLite as `sqlite3.wasm`) whose - source still builds. -- [`.dev/ROADMAP.md`](./.dev/ROADMAP.md), the plan. +Issues and PRs are welcome at +[BuddhiLW/ClojureWasm](https://github.com/BuddhiLW/ClojureWasm/issues); the most +useful report is Clojure code that behaves differently here than on the JVM. ## License and credit -Eclipse Public License 2.0, see [LICENSE](./LICENSE) and -[NOTICE](./legal/NOTICE). - -ClojureWasm was created by [Shota Kudo (@chaploud)](https://github.com/chaploud), -who took it from nothing to a working JVM-free Clojure runtime with a Wasm FFI -through v1.10.1, and in 2026-10 handed the -[clojurewasm](https://github.com/clojurewasm) organization over to -[@BuddhiLW](https://github.com/BuddhiLW). The fork's work (v1.11 through -v1.15.0) is merged back into -[clojurewasm/ClojureWasm](https://github.com/clojurewasm/ClojureWasm), so the -original repository is active again. Everything shipped since is built on -that work. The embedded engine is [zwasm](https://github.com/zwasm/zwasm). +Eclipse Public License 2.0 ([LICENSE](./LICENSE), [NOTICE](./legal/NOTICE)). + +Created by [Shota Kudo (@chaploud)](https://github.com/chaploud), who built it +from nothing to a working JVM-free Clojure with a Wasm FFI through v1.10.1. In +2026-10 the project passed to [@BuddhiLW](https://github.com/BuddhiLW); the +fork's work (v1.11 to v1.15.0) is merged back into +[clojurewasm/ClojureWasm](https://github.com/clojurewasm/ClojureWasm), while +releases and the Homebrew tap publish from +[BuddhiLW/ClojureWasm](https://github.com/BuddhiLW/ClojureWasm). The engine is +[zwasm](https://github.com/zwasm/zwasm). From 6b7f50dd83b307677c19a2379c15644605f4dd0d Mon Sep 17 00:00:00 2001 From: Pedro Gomes Branquinho Date: Wed, 21 Oct 2026 16:07:41 -0300 Subject: [PATCH 13/17] fix(wasm): wasm/exports builds its result inside a fabrication bracket The partial result vector and each export map lived only in Zig locals while the builder allocated, so a collection mid-build swept them: under CLJW_GC_TORTURE_ALLOC=1 the call panicked with "@memcpy arguments alias", and in a long suite run the vector came back as one map plus nil entries. rt.gc.enterFabrication defers collection until the builder returns, the same bracket every other multi-alloc builder uses (ADR-0150). Smell-audited: 1: missing GC bracket in a new builtin, fixed with the existing idiom --- src/runtime/cljw/wasm/exports.zig | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/src/runtime/cljw/wasm/exports.zig b/src/runtime/cljw/wasm/exports.zig index 975eb3c42..322061da5 100644 --- a/src/runtime/cljw/wasm/exports.zig +++ b/src/runtime/cljw/wasm/exports.zig @@ -37,6 +37,11 @@ pub fn wasmExportsFn(rt: *Runtime, env: *Env, args: []const Value, loc: SourceLo const params_kw = try keyword_mod.intern(rt, null, "params"); const results_kw = try keyword_mod.intern(rt, null, "results"); + // The partial `out` vector and each `m` live only in Zig locals until + // return, so no collection may run while they are built. + rt.gc.enterFabrication(); + defer rt.gc.exitFabrication(); + var out = vector_mod.empty(); for (loaded.export_list.items) |item| { var m = map_mod.empty(); From fd388b28d4e75e7ce385caae6a6c6dbccbb57da4 Mon Sep 17 00:00:00 2001 From: Pedro Gomes Branquinho Date: Wed, 21 Oct 2026 16:07:41 -0300 Subject: [PATCH 14/17] chore(deps): pin zwasm to fork main d74e63b4 (upstream main, 2026-10-21) Fork main is fast-forwarded to upstream zwasm/zwasm main. Upstream now carries all three fixes the fork's `cljw` branch existed for (851cd0e7 component re-export, f3067d03 wasip2 metadata-hash, 767b808a PreparedWasi), so the pin leaves `cljw` for main. The version string is still 2.7.0 and no newer tag exists; the pin returns to a tag when one is cut. Smell-audited: 0: dependency pin bump, no source change --- build.zig.zon | 14 +++++++++++--- 1 file changed, 11 insertions(+), 3 deletions(-) diff --git a/build.zig.zon b/build.zig.zon index 9b041366a..a05c8ca4b 100644 --- a/build.zig.zon +++ b/build.zig.zon @@ -14,7 +14,15 @@ // zwasm v2 embedding API (F-001 / D-037). `lazy` so the DEFAULT build + // gate never resolve it — only `-Dwasm` (b.lazyDependency) does. // - // PINNED to the `cljw` branch of THIS FORK, BuddhiLW/zwasm + // 2026-10-21: PINNED to `main` of THIS FORK, BuddhiLW/zwasm, at + // d74e63b4 (fork main fast-forwarded to upstream zwasm/zwasm main, + // version string still 2.7.0, no newer tag). Upstream now carries all + // three cljw fixes listed below (851cd0e7 component re-export, + // f3067d03 metadata-hash, 767b808a PreparedWasi), so the `cljw` + // branch's patches are no longer needed. The pin returns to a + // zwasm/zwasm tag when the next one is cut. + // + // Before 2026-10-21: PINNED to the `cljw` branch of THIS FORK, BuddhiLW/zwasm // (2026-09-14, user direction: "use our zwasm for now"). That branch // is upstream v2.7.0 (d09d9248) plus two fixes found from cljw that // upstream does not carry yet: every exported interface of a @@ -60,8 +68,8 @@ // moment anything else claims that name. The `.hash` is // content-addressed, so the host of the URL never changes it. .zwasm = .{ - .url = "git+https://github.com/BuddhiLW/zwasm.git?ref=cljw#70c8b7ee60e66115e3bf1030e1d657f772e7b99f", - .hash = "zwasm-2.7.0-FT1FvzKOnADpIAKlkOhKgEpJcG6LFoKrWsUAjd-jSCid", + .url = "git+https://github.com/BuddhiLW/zwasm.git?ref=main#d74e63b4aac1c7d392fc7e562467232945788dfe", + .hash = "zwasm-2.7.0-FT1Fv-zingBTL0it1Jtud_E9LvRZ6jkeZWH66zgwYpsw", .lazy = true, }, }, From cfa627094b98e20a3239130889c4f69349d1b53f Mon Sep 17 00:00:00 2001 From: Pedro Gomes Branquinho Date: Wed, 21 Oct 2026 16:20:27 -0300 Subject: [PATCH 15/17] docs: BuddhiLW logo in the README header, changelog for the next release The header shows the ClojureWasm logo beside the maintainer's (linked to github.com/BuddhiLW). [Unreleased] records wasm/exports and dot interop (ADR-0203), the zwasm pin move to fork main d74e63b4, and the shorter README; the README now says those features need v1.15.1, the patch the release preflight cuts from 1.15.0. --- CHANGELOG.md | 24 ++++++++++++++++++++++++ README.md | 8 +++++--- docs/assets/buddhilw_logo.png | Bin 0 -> 79816 bytes 3 files changed, 29 insertions(+), 3 deletions(-) create mode 100644 docs/assets/buddhilw_logo.png diff --git a/CHANGELOG.md b/CHANGELOG.md index d5bc55917..00746db19 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -7,6 +7,30 @@ first stable `1.0.0` tag; pre-1.0 `alpha` / `rc` tags may still change surfaces. ## [Unreleased] +### Added + +- **`wasm/exports` lists a core module's exports.** `(wasm/exports m)` returns + a vector in export order: a function as `{:name "sum_f64" :kind :func + :params [:i32 :i32] :results [:f64]}`, a memory, global or table as + `{:name "memory" :kind :memory}`. Signatures come from the same runtime probe + `wasm/call` uses (ADR-0203). + +- **Dot interop on a Wasm module handle.** `(.sum_f64 m buf 4)`, + `(. m sum_f64 buf 4)` and `(. m (sum_f64 buf 4))` call the export named by + the method symbol, verbatim, through `wasm/call`'s own path, so results, + fuel and errors are identical. A C function compiled to Wasm is called like a + host method (ADR-0203). + +### Changed + +- **zwasm pinned to the fork's `main` (d74e63b4, upstream main of + 2026-10-21).** Upstream now carries the component re-export, wasip2 + `metadata-hash` and `PreparedWasi` fixes the fork's `cljw` branch existed + for. + +- **A shorter README** led by calling C from Clojure, with the architecture, + size and startup charts kept. + ## [1.15.0] - 2026-10-13 ### Added diff --git a/README.md b/README.md index 255dc6e3d..dd7e248a4 100644 --- a/README.md +++ b/README.md @@ -1,5 +1,7 @@

- ClojureWasm + ClojureWasm +     + BuddhiLW

ClojureWasm

@@ -79,8 +81,8 @@ zig cc -target wasm32-freestanding -O2 -nostdlib \ (.sum_f64 k buf 4) ;=> 10.0 ``` -`wasm/exports` and the dot form arrive in the next release; on the current -one, write `(wasm/call k "sum_f64" buf 4)`. A guest fault is a catchable +`wasm/exports` and the dot form need v1.15.1 or later; `(wasm/call k "sum_f64" +buf 4)` works on every version. A guest fault is a catchable exception, never a host crash, and a guest that runs out of fuel stops with an error while your process keeps going. diff --git a/docs/assets/buddhilw_logo.png b/docs/assets/buddhilw_logo.png new file mode 100644 index 0000000000000000000000000000000000000000..3c9be0bc83057669b1c4a4b1ebec11349de9ac5f GIT binary patch literal 79816 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%0Dxlx5jA)+=S>LR882bCIUlDy0RRBo`SaN-)$pk0 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 z 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 literal 0 HcmV?d00001 From e87aba6d92175c8514042dae59a345befa76e41f Mon Sep 17 00:00:00 2001 From: Pedro Gomes Branquinho Date: Wed, 21 Oct 2026 16:26:22 -0300 Subject: [PATCH 16/17] docs(readme): use the plain BuddhiLW mark, without the PGB lettering The same mark the presentations use (pgb-logo.svg, exported as ~/PP/logo/logo.png). The PNG keeps its white background so it stays visible on GitHub's dark theme. --- docs/assets/buddhilw_logo.png | Bin 79816 -> 76514 bytes 1 file changed, 0 insertions(+), 0 deletions(-) diff --git a/docs/assets/buddhilw_logo.png b/docs/assets/buddhilw_logo.png index 3c9be0bc83057669b1c4a4b1ebec11349de9ac5f..51e078de316afd907c57421d65ec4bffa29e668e 100644 GIT binary patch literal 76514 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 literal 79816 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%0Dxlx5jA)+=S>LR882bCIUlDy0RRBo`SaN-)$pk0 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 z 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 From 9adabd295d582ca245c9673b42913c5cc157f44d Mon Sep 17 00:00:00 2001 From: clojurewasm-release Date: Wed, 21 Oct 2026 20:24:03 +0000 Subject: [PATCH 17/17] chore(release): v1.15.1 --- CHANGELOG.md | 2 ++ build.zig.zon | 2 +- 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 35db71f9d..084d6f929 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -7,6 +7,8 @@ first stable `1.0.0` tag; pre-1.0 `alpha` / `rc` tags may still change surfaces. ## [Unreleased] +## [1.15.1] - 2026-10-21 + ### Added - **`wasm/exports` lists a core module's exports.** `(wasm/exports m)` returns diff --git a/build.zig.zon b/build.zig.zon index a05c8ca4b..8bea727f0 100644 --- a/build.zig.zon +++ b/build.zig.zon @@ -1,6 +1,6 @@ .{ .name = .cljw, - .version = "1.15.0", + .version = "1.15.1", .fingerprint = 0x1869d207073beffa, .minimum_zig_version = "0.16.0", .dependencies = .{