commit fd43434149658ee482428714e05722e5a12fdecc (tree)
parent 1149e8bb088f48e29f3abc06196b1134f5e1c42f
Author: Mitchell Hashimoto <mitchell.hashimoto@gmail.com>
Date: Tue, 15 Mar 2022 15:53:50 -0700
stage2: TypeInfo for func with generic return type should set null
Prior to these, the return type was non-null but the value was generic
poison which wasn't usable in user-space. This sets the value to null.
This also adds a behavior test for this.
Co-authored-by: InKryption <inkryption07@gmail.com>
Diffstat:
2 files changed, 61 insertions(+), 4 deletions(-)
diff --git a/src/Sema.zig b/src/Sema.zig
@@ -10376,6 +10376,14 @@ fn zirTypeInfo(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Ai
break :v try Value.Tag.decl_ref.create(sema.arena, new_decl);
};
+ const ret_ty_opt = if (info.return_type.tag() != .generic_poison)
+ try Value.Tag.opt_payload.create(
+ sema.arena,
+ try Value.Tag.ty.create(sema.arena, info.return_type),
+ )
+ else
+ Value.@"null";
+
const field_values = try sema.arena.create([6]Value);
field_values.* = .{
// calling_convention: CallingConvention,
@@ -10387,10 +10395,7 @@ fn zirTypeInfo(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Ai
// is_var_args: bool,
Value.makeBool(info.is_var_args),
// return_type: ?type,
- try Value.Tag.opt_payload.create(
- sema.arena,
- try Value.Tag.ty.create(sema.arena, info.return_type),
- ),
+ ret_ty_opt,
// args: []const Fn.Param,
args_val,
};
diff --git a/test/behavior/type_info.zig b/test/behavior/type_info.zig
@@ -384,6 +384,58 @@ fn testFunction() !void {
extern fn foo(a: usize, b: bool, ...) callconv(.C) usize;
extern fn fooAligned(a: usize, b: bool, ...) align(4) callconv(.C) usize;
+test "type info: generic function types" {
+ if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;
+ if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
+ if (builtin.zig_backend == .stage2_c) return error.SkipZigTest;
+
+ if (builtin.zig_backend != .stage1) {
+ // stage1 marks all args/return types as null if the function
+ // is generic at all. stage2 is more specific.
+ const G1 = @typeInfo(@TypeOf(generic1));
+ try expect(G1.Fn.args.len == 1);
+ try expect(G1.Fn.args[0].is_generic == true);
+ try expect(G1.Fn.args[0].arg_type == null);
+ try expect(G1.Fn.return_type == void);
+
+ const G2 = @typeInfo(@TypeOf(generic2));
+ try expect(G2.Fn.args.len == 3);
+ try expect(G2.Fn.args[0].is_generic == false);
+ try expect(G2.Fn.args[0].arg_type == type);
+ try expect(G2.Fn.args[1].is_generic == true);
+ try expect(G2.Fn.args[1].arg_type == null);
+ try expect(G2.Fn.args[2].is_generic == false);
+ try expect(G2.Fn.args[2].arg_type == u8);
+ try expect(G2.Fn.return_type == void);
+ }
+
+ const G3 = @typeInfo(@TypeOf(generic3));
+ try expect(G3.Fn.args.len == 1);
+ try expect(G3.Fn.args[0].is_generic == true);
+ try expect(G3.Fn.args[0].arg_type == null);
+ try expect(G3.Fn.return_type == null);
+
+ const G4 = @typeInfo(@TypeOf(generic4));
+ try expect(G4.Fn.args.len == 1);
+ try expect(G4.Fn.args[0].is_generic == true);
+ try expect(G4.Fn.args[0].arg_type == null);
+ try expect(G4.Fn.return_type == null);
+}
+
+fn generic1(param: anytype) void {
+ _ = param;
+}
+fn generic2(comptime T: type, param: T, param2: u8) void {
+ _ = param;
+ _ = param2;
+}
+fn generic3(param: anytype) @TypeOf(param) {
+ _ = param;
+}
+fn generic4(comptime param: anytype) @TypeOf(param) {
+ _ = param;
+}
+
test "typeInfo with comptime parameter in struct fn def" {
const S = struct {
pub fn func(comptime x: f32) void {