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>
This commit is contained in:
Mitchell Hashimoto 2022-03-15 15:53:50 -07:00 committed by Andrew Kelley
parent 1149e8bb08
commit fd43434149
2 changed files with 61 additions and 4 deletions

View file

@ -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); 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); const field_values = try sema.arena.create([6]Value);
field_values.* = .{ field_values.* = .{
// calling_convention: CallingConvention, // calling_convention: CallingConvention,
@ -10387,10 +10395,7 @@ fn zirTypeInfo(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Ai
// is_var_args: bool, // is_var_args: bool,
Value.makeBool(info.is_var_args), Value.makeBool(info.is_var_args),
// return_type: ?type, // return_type: ?type,
try Value.Tag.opt_payload.create( ret_ty_opt,
sema.arena,
try Value.Tag.ty.create(sema.arena, info.return_type),
),
// args: []const Fn.Param, // args: []const Fn.Param,
args_val, args_val,
}; };

View file

@ -384,6 +384,58 @@ fn testFunction() !void {
extern fn foo(a: usize, b: bool, ...) callconv(.C) usize; extern fn foo(a: usize, b: bool, ...) callconv(.C) usize;
extern fn fooAligned(a: usize, b: bool, ...) align(4) 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" { test "typeInfo with comptime parameter in struct fn def" {
const S = struct { const S = struct {
pub fn func(comptime x: f32) void { pub fn func(comptime x: f32) void {