From 08b02762b7be3318a1493429efdd257781ec4fc0 Mon Sep 17 00:00:00 2001
From: Meghan Denny <meghan@bun.sh>
Date: Mon, 25 Nov 2024 23:12:19 -0800
Subject: [PATCH] zig: eliminate errorUnionToCPP

---
 src/bun.js/bindings/bindings.zig  | 110 ------------------------------
 src/bun.zig                       |   3 -
 src/codegen/generate-js2native.ts |   4 +-
 src/gen_classes_lib.zig           |  52 --------------
 4 files changed, 1 insertion(+), 168 deletions(-)
 delete mode 100644 src/gen_classes_lib.zig

diff --git a/src/bun.js/bindings/bindings.zig b/src/bun.js/bindings/bindings.zig
index a0ca01482c0edd..c141af7d8c1c79 100644
--- a/src/bun.js/bindings/bindings.zig
+++ b/src/bun.js/bindings/bindings.zig
@@ -2995,116 +2995,6 @@ pub const JSGlobalObject = opaque {
         return .zero;
     }
 
-    /// Pass a JSOrMemoryError!JSValue and variants through the C ABI boundary
-    ///
-    /// In C++, WebKit represents a thrown JavaScript expression as
-    /// JSValue.zero/nullptr, and stores the actual exception on the global. In
-    /// Zig, we represent this zero as a distinct Zig error type
-    /// 'error.JSError'. Instead of using JSValue.zero directly, we pass the
-    /// Zig error to this function as "proof" there is an error. In debug, this
-    /// will also assert that an error is actually present.
-    ///
-    /// If .zero is exposed to JS, it will be considered a JSCell but with a
-    /// null pointer and will segfault via null-pointer dereference.
-    ///
-    /// Ideally, we can use this function as little as possible, and instead
-    /// have auto-generated wrappers that do this conversion. It is ugly to use
-    /// on purpose.
-    pub inline fn errorUnionToCPP(global: *JSGlobalObject, result: anytype) RemoveError(@TypeOf(result)) {
-        const T = @TypeOf(result);
-
-        const unwrapped = switch (@typeInfo(T)) {
-            .ErrorUnion => result catch |err| {
-                bun.handleErrorReturnTrace(err, @errorReturnTrace());
-                return global.errorSetToCPP(err, T);
-            },
-            .ErrorSet => return global.errorSetToCPP(result, T),
-            else => result,
-        };
-
-        // Validate exception state aligns with return value.
-        // Currently only enabled for JSValue.
-        const Return = RemoveError(T);
-        if (bun.Environment.isDebug and Return == JSValue) {
-            const null_value: Return = comptime if (Return == JSC.JSValue)
-                .zero
-            else
-                null;
-
-            if (unwrapped == null_value) {
-                std.debug.assert(global.hasException()); // Exception was cleared, yet returned.
-            } else if (Return == JSC.JSValue and unwrapped == .undefined) {
-                // TODO: a lot of our code returns undefined when it throws an error.
-            } else {
-                if (global.tryTakeException()) |exception| {
-                    bun.Output.err("assertion failure", "Pending exception while returning non-empty JSValue", .{});
-                    bun.Output.printErrorln("Exception thrown:", .{});
-                    bun.Output.flush();
-                    global.bunVM().printErrorLikeObjectToConsole(exception);
-                    bun.Output.printErrorln("Value returned:", .{});
-                    bun.Output.flush();
-                    if (Return == JSValue) {
-                        unwrapped.print(global, .Log, .Error);
-                    } else {
-                        bun.Output.printErrorln("  {any}", .{unwrapped});
-                    }
-                    bun.Output.flush();
-                    @panic("Pending exception while returning non-empty JSValue");
-                }
-            }
-        }
-
-        return unwrapped;
-    }
-
-    pub fn RemoveError(T: type) type {
-        return switch (@typeInfo(T)) {
-            .ErrorSet => bun.JSC.JSValue,
-            .ErrorUnion => |eu| if (@typeInfo(eu.payload) == .Pointer)
-                ?eu.payload
-            else
-                eu.payload,
-            else => T,
-        };
-    }
-
-    inline fn errorSetToCPP(global: *JSGlobalObject, err: anytype, T: type) RemoveError(T) {
-        const info = @typeInfo(@TypeOf(err));
-        comptime bun.assert(info == .ErrorSet);
-        const Return = RemoveError(T);
-        const null_value: Return = comptime if (Return == JSC.JSValue)
-            .zero
-        else
-            null;
-
-        const possible_errors = comptime parseErrorSet(
-            T,
-            info.ErrorSet orelse
-                @compileError("host function cannot return 'anyerror!JSValue'"),
-        );
-
-        if (possible_errors.OutOfMemory and err == error.OutOfMemory) {
-            if (global.hasException()) {
-                if (comptime bun.Environment.isDebug) bun.Output.panic("attempted to throw OutOfMemory without an exception", .{});
-            } else {
-                global.throwOutOfMemory();
-            }
-            return null_value;
-        }
-
-        if (possible_errors.JSError and err == error.JSError) {
-            if (!global.hasException()) {
-                if (comptime bun.Environment.isDebug) bun.Output.panic("attempted to throw JSError without an exception", .{});
-                global.throwOutOfMemory();
-            }
-            return null_value;
-        }
-
-        // all errors have now been handled. parseErrorSet will report
-        // a compile error if there is another possible error
-        unreachable;
-    }
-
     pub fn createInvalidArgumentType(
         this: *JSGlobalObject,
         comptime name_: []const u8,
diff --git a/src/bun.zig b/src/bun.zig
index 6bc162224221ca..352c6c9148562c 100644
--- a/src/bun.zig
+++ b/src/bun.zig
@@ -4118,6 +4118,3 @@ pub inline fn isComptimeKnown(x: anytype) bool {
 pub inline fn itemOrNull(comptime T: type, slice: []const T, index: usize) ?T {
     return if (index < slice.len) slice[index] else null;
 }
-
-/// Code used by the classes generator
-pub const gen_classes_lib = @import("gen_classes_lib.zig");
diff --git a/src/codegen/generate-js2native.ts b/src/codegen/generate-js2native.ts
index f1443a2df4d4b1..eb98745618cd13 100644
--- a/src/codegen/generate-js2native.ts
+++ b/src/codegen/generate-js2native.ts
@@ -201,9 +201,7 @@ export function getJS2NativeZig(gs2NativeZigPath: string) {
       .filter(x => x.type === "zig")
       .flatMap(call => [
         `export fn ${symbol(call)}_workaround(global: *JSC.JSGlobalObject) callconv(JSC.conv) JSC.JSValue {`,
-        `  return global.errorUnionToCPP(@import(${JSON.stringify(path.relative(path.dirname(gs2NativeZigPath), call.filename))}).${
-          call.symbol
-        }(global));`,
+        `  return JSC.toJSHostValue(global, @import(${JSON.stringify(path.relative(path.dirname(gs2NativeZigPath), call.filename))}).${call.symbol}(global));`,
         "}",
       ]),
     ...wrapperCalls
diff --git a/src/gen_classes_lib.zig b/src/gen_classes_lib.zig
deleted file mode 100644
index 7533184fd5663b..00000000000000
--- a/src/gen_classes_lib.zig
+++ /dev/null
@@ -1,52 +0,0 @@
-/// Handwritten utility functions for ZigGeneratedClasses.zig
-const bun = @import("root").bun;
-const JSC = bun.JSC;
-const JSValue = JSC.JSValue;
-const JSGlobalObject = JSC.JSGlobalObject;
-
-pub const WrappedMethod = fn (*anyopaque, *JSGlobalObject, *JSC.CallFrame) callconv(JSC.conv) JSValue;
-pub const WrappedMethodWithThis = fn (*anyopaque, *JSGlobalObject, *JSC.CallFrame, JSValue) callconv(JSC.conv) JSValue;
-pub const WrappedConstructor = fn (*JSGlobalObject, *JSC.CallFrame) callconv(JSC.conv) ?*anyopaque;
-pub const WrappedClassGetterCallback = fn (*anyopaque, *JSGlobalObject) callconv(JSC.conv) JSValue;
-
-pub const wrapHostFunction = JSC.toJSHostFunction;
-
-pub fn wrapMethod(comptime T: type, comptime func: anytype) WrappedMethod {
-    return struct {
-        pub fn call(ptr: *anyopaque, global: *JSGlobalObject, call_frame: *JSC.CallFrame) callconv(JSC.conv) JSValue {
-            return global.errorUnionToCPP(func(@as(*T, @alignCast(@ptrCast(ptr))), global, call_frame));
-        }
-    }.call;
-}
-
-pub fn wrapMethodWithThis(comptime T: type, comptime func: anytype) WrappedMethodWithThis {
-    return struct {
-        pub fn call(ptr: *anyopaque, global: *JSGlobalObject, call_frame: *JSC.CallFrame, this_value: JSValue) callconv(JSC.conv) JSValue {
-            return global.errorUnionToCPP(func(@as(*T, @alignCast(@ptrCast(ptr))), global, call_frame, this_value));
-        }
-    }.call;
-}
-
-pub fn wrapConstructor(comptime T: type, comptime func: anytype) WrappedConstructor {
-    return struct {
-        pub fn call(global: *JSGlobalObject, call_frame: *JSC.CallFrame) callconv(JSC.conv) ?*anyopaque {
-            return @as(?*T, global.errorUnionToCPP(func(global, call_frame)));
-        }
-    }.call;
-}
-
-pub fn wrapGetterCallback(comptime T: type, comptime func: anytype) WrappedClassGetterCallback {
-    return struct {
-        pub fn call(ptr: *anyopaque, global: *JSGlobalObject) callconv(JSC.conv) JSValue {
-            return func(@as(*T, @alignCast(@ptrCast(ptr))), global);
-        }
-    }.call;
-}
-
-pub fn wrapGetterWithValueCallback(comptime T: type, comptime func: anytype) WrappedClassGetterCallback {
-    return struct {
-        pub fn call(ptr: *anyopaque, global: *JSGlobalObject) callconv(JSC.conv) JSValue {
-            return func(@as(*T, @alignCast(@ptrCast(ptr))), global);
-        }
-    }.call;
-}