From 67db992cf7fedc37adf6e8d177fbd4c0242f93d9 Mon Sep 17 00:00:00 2001 From: zhuyadong Date: Fri, 20 Sep 2024 22:37:57 +0800 Subject: [PATCH] fix bug when finding default method --- README.CN.md | 9 ++++----- README.md | 9 ++++----- src/zoop.zig | 34 +++++++++++++++++++++++++++++----- 3 files changed, 37 insertions(+), 15 deletions(-) diff --git a/README.CN.md b/README.CN.md index b4c4098..249af5b 100644 --- a/README.CN.md +++ b/README.CN.md @@ -269,12 +269,11 @@ try t.expectEqualStrings(zoop.vcall(phuman, IName.getName, .{}), "override"); `vcall`的性能说明: `vcall`会在能使用`cast`的情况下使用`cast`,否则使用`as` -## 调试用接口 `zoop.IFormat` -`zoop.IFormat`能方便通过 `std.fmt` 的 `format(...)`机制来输出对象的字符串形式内容。 +## 调试用接口 `IObject.formatAny` +`zoop.IObject`能方便通过 `std.fmt` 的 `format(...)`机制来输出对象的字符串形式内容。 ```zig -// 定义一个实现 `zoop.IFormat`的类 +// 定义一个实现 `zoop.IObject.formatAny`的类 pub const SomeClass = struct { - pub const extends = .{zoop.IFormat}; name:[]const u8 align(zoop.alignment) = "some"; pub fn formatAny(self: *SomeClass, writer: std.io.AnyWriter) anyerror!void { @@ -284,6 +283,6 @@ pub const SomeClass = struct { // 下面代码就能输出 `SomeClass.formatAny` 的内容 const psome = try zoop.new(t.allocator, SomeClass, null); -std.debug.print("{}\n", .{zoop.cast(psome, zoop.IFormat)}); +std.debug.print("{}\n", .{zoop.cast(psome, zoop.IObject)}); // output: SomeClass.name = some ``` \ No newline at end of file diff --git a/README.md b/README.md index 16784a0..38ba8b1 100644 --- a/README.md +++ b/README.md @@ -281,12 +281,11 @@ try t.expectEqualStrings(zoop.vcall(phuman, IName.getName, .{}), "override"); Performance notes for `vcall`: `vcall` will use `cast` when possible, and `as` otherwise -## Interface `zoop.IFormat` for print -`zoop.IFormat` can conveniently output the string content of the object through the `format(...)` mechanism of `std.fmt`. +## `zoop.IObject.formatAny` for print +`zoop.IObject` can conveniently output the string content of the object through the `format(...)` mechanism of `std.fmt`. ```zig -// define a class that implemented `zoop.IFormat` +// define a class that implemented `zoop.IObject.formatAny` pub const SomeClass = struct { - pub const extends = .{zoop.IFormat}; name:[]const u8 align(zoop.alignment) = "some"; pub fn formatAny(self: *SomeClass, writer: std.io.AnyWriter) anyerror!void { @@ -296,6 +295,6 @@ pub const SomeClass = struct { // print string from `SomeClass.formatAny` const psome = try zoop.new(t.allocator, SomeClass, null); -std.debug.print("{}\n", .{zoop.cast(psome, zoop.IFormat)}); +std.debug.print("{}\n", .{zoop.cast(psome, zoop.IObject)}); // output: SomeClass.name = some ``` \ No newline at end of file diff --git a/src/zoop.zig b/src/zoop.zig index 500d955..7751e80 100644 --- a/src/zoop.zig +++ b/src/zoop.zig @@ -751,17 +751,41 @@ fn RealType(comptime T: type) type { fn DefaultMethodType(comptime T: type, comptime I: type, comptime name: []const u8) type { comptime { - if (@hasDecl(I, "Default")) { - const def = I.Default(T); - if (@hasDecl(def, name)) { - return @TypeOf(@field(def, name)); + const ifaces = interfaces(I); + var all = tupleInit(.{}); + for (ifaces.items) |iface| { + if (@hasDecl(iface, "Default")) { + const def = iface.Default(T); + if (@hasDecl(def, name)) { + all = tupleAppend(all, iface); + } } } + switch (all.items.len) { + 0 => {}, + 1 => return @TypeOf(@field(all.items[0].Default(T), name)), + else => @compileError(compfmt("multi default method '{s}' found in: {}", .{ name, all.items })), + } return void; } } +fn defaultMethod(comptime T: type, comptime I: type, comptime name: []const u8) DefaultMethodType(T, I, name) { + comptime { + const ifaces = interfaces(I); + for (ifaces.items) |iface| { + if (@hasDecl(iface, "Default")) { + const def = iface.Default(T); + if (@hasDecl(def, name)) { + return @field(def, name); + } + } + } + unreachable; + } +} + fn MethodType(comptime T: type, comptime name: []const u8) type { comptime { var Cur = if (isKlassType(T)) T.Class else T; @@ -1091,7 +1115,7 @@ fn makeVtable(comptime T: type, comptime I: type) *anyopaque { @field(val, field.name) = @ptrCast(&getMethod(T, field.name)); } else if (DefaultMethodType(T, I, field.name) != void) { checkInterface(I); - @field(val, field.name) = &@field(I.Default(T), field.name); + @field(val, field.name) = @ptrCast(&defaultMethod(T, I, field.name)); } else { @compileError(compfmt("{s} must implement method '{s}: {}'", .{ @typeName(T), field.name, field.type })); }