aboutsummaryrefslogtreecommitdiff
path: root/test/behavior
diff options
context:
space:
mode:
authormlugg <mlugg@mlugg.co.uk>2023-08-01 22:42:01 +0100
committermlugg <mlugg@mlugg.co.uk>2023-08-10 10:00:26 +0100
commitf2c8fa769a92eb61c13f2cc0f75c526c8fd729a9 (patch)
tree37f611ef1bd700533987eec239667815a491df6d /test/behavior
parent93e53d1e00793d769d4ee39b3cbfd0c88257687d (diff)
downloadzig-f2c8fa769a92eb61c13f2cc0f75c526c8fd729a9.tar.gz
zig-f2c8fa769a92eb61c13f2cc0f75c526c8fd729a9.zip
Sema: refactor generic calls to interleave argument analysis and parameter type resolution
AstGen provides all function call arguments with a result location, referenced through the call instruction index. The idea is that this should be the parameter type, but for `anytype` parameters, we use generic poison, which is required to be handled correctly. Previously, generic instantiations and inline calls worked by evaluating all args in advance, before resolving generic parameter types. This means any generic parameter (not just `anytype` ones) had generic poison result types. This caused missing result locations in some cases. Additionally, the generic instantiation logic caused `zirParam` to analyze the argument types a second time before coercion. This meant that for nominal types (struct/enum/etc), a *new* type was created, distinct to the result type which was previously forwarded to the argument expression. This commit fixes both of these issues. Generic parameter type resolution is now interleaved with argument analysis, so that we don't have unnecessary generic poison types, and generic instantiation logic now handles parameters itself rather than falling through to the standard zirParam logic, so avoids duplicating the types. Resolves: #16566 Resolves: #16258 Resolves: #16753
Diffstat (limited to 'test/behavior')
-rw-r--r--test/behavior/call.zig61
1 files changed, 61 insertions, 0 deletions
diff --git a/test/behavior/call.zig b/test/behavior/call.zig
index c33c872347..d641d5d5ba 100644
--- a/test/behavior/call.zig
+++ b/test/behavior/call.zig
@@ -430,3 +430,64 @@ test "method call as parameter type" {
try expectEqual(@as(u64, 123), S.foo(S{}, 123));
try expectEqual(@as(u64, 500), S.foo(S{}, 500));
}
+
+test "non-anytype generic parameters provide result type" {
+ if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO
+ if (builtin.zig_backend == .stage2_c) return error.SkipZigTest; // TODO
+ if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
+ if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
+ if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
+ if (builtin.zig_backend == .stage2_spirv64) return error.SkipZigTest; // TODO
+
+ const S = struct {
+ fn f(comptime T: type, y: T) !void {
+ try expectEqual(@as(T, 123), y);
+ }
+
+ fn g(x: anytype, y: @TypeOf(x)) !void {
+ try expectEqual(@as(@TypeOf(x), 0x222), y);
+ }
+ };
+
+ var rt_u16: u16 = 123;
+ var rt_u32: u32 = 0x10000222;
+
+ try S.f(u8, @intCast(rt_u16));
+ try S.f(u8, @intCast(123));
+
+ try S.g(rt_u16, @truncate(rt_u32));
+ try S.g(rt_u16, @truncate(0x10000222));
+
+ try comptime S.f(u8, @intCast(123));
+ try comptime S.g(@as(u16, undefined), @truncate(0x99990222));
+}
+
+test "argument to generic function has correct result type" {
+ if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO
+ if (builtin.zig_backend == .stage2_c) return error.SkipZigTest; // TODO
+ if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
+ if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
+ if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
+ if (builtin.zig_backend == .stage2_spirv64) return error.SkipZigTest; // TODO
+
+ const S = struct {
+ fn foo(_: anytype, e: enum { a, b }) bool {
+ return e == .b;
+ }
+
+ fn doTheTest() !void {
+ var t = true;
+
+ // Since the enum literal passes through a runtime conditional here, these can only
+ // compile if RLS provides the correct result type to the argument
+ try expect(foo({}, if (!t) .a else .b));
+ try expect(!foo("dummy", if (t) .a else .b));
+ try expect(foo({}, if (t) .b else .a));
+ try expect(!foo(123, if (t) .a else .a));
+ try expect(foo(123, if (t) .b else .b));
+ }
+ };
+
+ try S.doTheTest();
+ try comptime S.doTheTest();
+}