authorgravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2023-07-23 22:57:11-07:00
committergravatar for noreply@github.comGitHub <noreply@github.com> 2023-07-23 22:57:11-07:00
log98c7aec4e4ae7deac5e802a8c592c2d91b6b77af
treebfd94bd10785c542396a8c341b9bca8614719133
parent23a806102a5a3d5b28b2e5ab5ec30e191daea6f4
parentd92cca9324e71705af9134de70e1e995ba8aa57a
signaturebadge-question-mark Signed by PGP key 4AEE18F83AFDEB23

Merge pull request #16518 from ziglang/fix-func-body

InternPool: fix handling of coerced function bodies

2 files changed, 56 insertions(+), 4 deletions(-)

src/InternPool.zig+36-4
......@@ -594,6 +594,13 @@ pub const Key = union(enum) {
594594 /// In the case of a generic function, this type will potentially have fewer parameters
595595 /// than the generic owner's type, because the comptime parameters will be deleted.
596596 ty: Index,
597 /// If this is a function body that has been coerced to a different type, for example
598 /// ```
599 /// fn f2() !void {}
600 /// const f: fn()anyerror!void = f2;
601 /// ```
602 /// then it contains the original type of the function body.
603 uncoerced_ty: Index,
597604 /// Index into extra array of the `FuncAnalysis` corresponding to this function.
598605 /// Used for mutating that data.
599606 analysis_extra_index: u32,
......@@ -990,11 +997,15 @@ pub const Key = union(enum) {
990997 // otherwise we would get false negatives for interning generic
991998 // function instances which have inferred error sets.
992999
993 if (func.generic_owner == .none and func.resolved_error_set_extra_index == 0)
994 return Hash.hash(seed, asBytes(&func.owner_decl) ++ asBytes(&func.ty));
1000 if (func.generic_owner == .none and func.resolved_error_set_extra_index == 0) {
1001 const bytes = asBytes(&func.owner_decl) ++ asBytes(&func.ty) ++
1002 [1]u8{@intFromBool(func.uncoerced_ty == func.ty)};
1003 return Hash.hash(seed, bytes);
1004 }
9951005
9961006 var hasher = Hash.init(seed);
9971007 std.hash.autoHash(&hasher, func.generic_owner);
1008 std.hash.autoHash(&hasher, func.uncoerced_ty == func.ty);
9981009 for (func.comptime_args.get(ip)) |arg| std.hash.autoHash(&hasher, arg);
9991010 if (func.resolved_error_set_extra_index == 0) {
10001011 std.hash.autoHash(&hasher, func.ty);
......@@ -1122,6 +1133,12 @@ pub const Key = union(enum) {
11221133 )) return false;
11231134 }
11241135
1136 if ((a_info.ty == a_info.uncoerced_ty) !=
1137 (b_info.ty == b_info.uncoerced_ty))
1138 {
1139 return false;
1140 }
1141
11251142 if (a_info.ty == b_info.ty)
11261143 return true;
11271144
......@@ -3371,6 +3388,7 @@ fn extraFuncDecl(ip: *const InternPool, extra_index: u32) Key.Func {
33713388 const func_decl = ip.extraDataTrail(P, extra_index);
33723389 return .{
33733390 .ty = func_decl.data.ty,
3391 .uncoerced_ty = func_decl.data.ty,
33743392 .analysis_extra_index = extra_index + std.meta.fieldIndex(P, "analysis").?,
33753393 .zir_body_inst_extra_index = extra_index + std.meta.fieldIndex(P, "zir_body_inst").?,
33763394 .resolved_error_set_extra_index = if (func_decl.data.analysis.inferred_error_set) func_decl.end else 0,
......@@ -3392,6 +3410,7 @@ fn extraFuncInstance(ip: *const InternPool, extra_index: u32) Key.Func {
33923410 const func_decl = ip.funcDeclInfo(fi.data.generic_owner);
33933411 return .{
33943412 .ty = fi.data.ty,
3413 .uncoerced_ty = fi.data.ty,
33953414 .analysis_extra_index = extra_index + std.meta.fieldIndex(P, "analysis").?,
33963415 .zir_body_inst_extra_index = func_decl.zir_body_inst_extra_index,
33973416 .resolved_error_set_extra_index = if (fi.data.analysis.inferred_error_set) fi.end else 0,
......@@ -4800,6 +4819,8 @@ pub fn getFuncInstanceIes(
48004819 assert(arg.bare_return_type != .none);
48014820 for (arg.param_types) |param_type| assert(param_type != .none);
48024821
4822 const generic_owner = unwrapCoercedFunc(ip, arg.generic_owner);
4823
48034824 // The strategy here is to add the function decl unconditionally, then to
48044825 // ask if it already exists, and if so, revert the lengths of the mutated
48054826 // arrays. This is similar to what `getOrPutTrailingString` does.
......@@ -4835,7 +4856,7 @@ pub fn getFuncInstanceIes(
48354856 .owner_decl = undefined,
48364857 .ty = func_ty,
48374858 .branch_quota = 0,
4838 .generic_owner = arg.generic_owner,
4859 .generic_owner = generic_owner,
48394860 });
48404861 ip.extra.appendAssumeCapacity(@intFromEnum(Index.none)); // resolved error set
48414862 ip.extra.appendSliceAssumeCapacity(@ptrCast(arg.comptime_args));
......@@ -4908,7 +4929,7 @@ pub fn getFuncInstanceIes(
49084929 return finishFuncInstance(
49094930 ip,
49104931 gpa,
4911 arg.generic_owner,
4932 generic_owner,
49124933 func_index,
49134934 func_extra_index,
49144935 arg.generation,
......@@ -7050,6 +7071,17 @@ pub fn funcIesResolved(ip: *const InternPool, func_index: Index) *Index {
70507071 const extra_index = switch (tags[@intFromEnum(func_index)]) {
70517072 .func_decl => func_start + @typeInfo(Tag.FuncDecl).Struct.fields.len,
70527073 .func_instance => func_start + @typeInfo(Tag.FuncInstance).Struct.fields.len,
7074 .func_coerced => i: {
7075 const uncoerced_func_index: Index = @enumFromInt(ip.extra.items[
7076 func_start + std.meta.fieldIndex(Tag.FuncCoerced, "func").?
7077 ]);
7078 const uncoerced_func_start = datas[@intFromEnum(uncoerced_func_index)];
7079 break :i switch (tags[@intFromEnum(uncoerced_func_index)]) {
7080 .func_decl => uncoerced_func_start + @typeInfo(Tag.FuncDecl).Struct.fields.len,
7081 .func_instance => uncoerced_func_start + @typeInfo(Tag.FuncInstance).Struct.fields.len,
7082 else => unreachable,
7083 };
7084 },
70537085 else => unreachable,
70547086 };
70557087 return @ptrCast(&ip.extra.items[extra_index]);
test/behavior/generics.zig+20
......@@ -456,3 +456,23 @@ test "return type of generic function is function pointer" {
456456
457457 try expect(null == S.b(void));
458458}
459
460test "coerced function body has inequal value with its uncoerced body" {
461 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
462 if (builtin.zig_backend == .stage2_spirv64) return error.SkipZigTest;
463
464 const S = struct {
465 const A = B(i32, c);
466 fn c() !i32 {
467 return 1234;
468 }
469 fn B(comptime T: type, comptime d: ?fn () anyerror!T) type {
470 return struct {
471 fn do() T {
472 return d.?() catch @panic("fail");
473 }
474 };
475 }
476 };
477 try expect(S.A.do() == 1234);
478}