From fd43434149658ee482428714e05722e5a12fdecc Mon Sep 17 00:00:00 2001 From: Mitchell Hashimoto Date: Tue, 15 Mar 2022 15:53:50 -0700 Subject: [PATCH] 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 --- src/Sema.zig | 13 +++++++--- test/behavior/type_info.zig | 52 +++++++++++++++++++++++++++++++++++++ 2 files changed, 61 insertions(+), 4 deletions(-) diff --git a/src/Sema.zig b/src/Sema.zig index 2ee64ca73d..fb2b187c60 100644 --- 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 index 4231803ecd..1789bf13ca 100644 --- 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 {