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) {...@@ -594,6 +594,13 @@ pub const Key = union(enum) {
594 /// In the case of a generic function, this type will potentially have fewer parameters594 /// In the case of a generic function, this type will potentially have fewer parameters
595 /// than the generic owner's type, because the comptime parameters will be deleted.595 /// than the generic owner's type, because the comptime parameters will be deleted.
596 ty: Index,596 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,
597 /// Index into extra array of the `FuncAnalysis` corresponding to this function.604 /// Index into extra array of the `FuncAnalysis` corresponding to this function.
598 /// Used for mutating that data.605 /// Used for mutating that data.
599 analysis_extra_index: u32,606 analysis_extra_index: u32,
...@@ -990,11 +997,15 @@ pub const Key = union(enum) {...@@ -990,11 +997,15 @@ pub const Key = union(enum) {
990 // otherwise we would get false negatives for interning generic997 // otherwise we would get false negatives for interning generic
991 // function instances which have inferred error sets.998 // function instances which have inferred error sets.
992999
993 if (func.generic_owner == .none and func.resolved_error_set_extra_index == 0)1000 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));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
996 var hasher = Hash.init(seed);1006 var hasher = Hash.init(seed);
997 std.hash.autoHash(&hasher, func.generic_owner);1007 std.hash.autoHash(&hasher, func.generic_owner);
1008 std.hash.autoHash(&hasher, func.uncoerced_ty == func.ty);
998 for (func.comptime_args.get(ip)) |arg| std.hash.autoHash(&hasher, arg);1009 for (func.comptime_args.get(ip)) |arg| std.hash.autoHash(&hasher, arg);
999 if (func.resolved_error_set_extra_index == 0) {1010 if (func.resolved_error_set_extra_index == 0) {
1000 std.hash.autoHash(&hasher, func.ty);1011 std.hash.autoHash(&hasher, func.ty);
...@@ -1122,6 +1133,12 @@ pub const Key = union(enum) {...@@ -1122,6 +1133,12 @@ pub const Key = union(enum) {
1122 )) return false;1133 )) return false;
1123 }1134 }
11241135
1136 if ((a_info.ty == a_info.uncoerced_ty) !=
1137 (b_info.ty == b_info.uncoerced_ty))
1138 {
1139 return false;
1140 }
1141
1125 if (a_info.ty == b_info.ty)1142 if (a_info.ty == b_info.ty)
1126 return true;1143 return true;
11271144
...@@ -3371,6 +3388,7 @@ fn extraFuncDecl(ip: *const InternPool, extra_index: u32) Key.Func {...@@ -3371,6 +3388,7 @@ fn extraFuncDecl(ip: *const InternPool, extra_index: u32) Key.Func {
3371 const func_decl = ip.extraDataTrail(P, extra_index);3388 const func_decl = ip.extraDataTrail(P, extra_index);
3372 return .{3389 return .{
3373 .ty = func_decl.data.ty,3390 .ty = func_decl.data.ty,
3391 .uncoerced_ty = func_decl.data.ty,
3374 .analysis_extra_index = extra_index + std.meta.fieldIndex(P, "analysis").?,3392 .analysis_extra_index = extra_index + std.meta.fieldIndex(P, "analysis").?,
3375 .zir_body_inst_extra_index = extra_index + std.meta.fieldIndex(P, "zir_body_inst").?,3393 .zir_body_inst_extra_index = extra_index + std.meta.fieldIndex(P, "zir_body_inst").?,
3376 .resolved_error_set_extra_index = if (func_decl.data.analysis.inferred_error_set) func_decl.end else 0,3394 .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 {...@@ -3392,6 +3410,7 @@ fn extraFuncInstance(ip: *const InternPool, extra_index: u32) Key.Func {
3392 const func_decl = ip.funcDeclInfo(fi.data.generic_owner);3410 const func_decl = ip.funcDeclInfo(fi.data.generic_owner);
3393 return .{3411 return .{
3394 .ty = fi.data.ty,3412 .ty = fi.data.ty,
3413 .uncoerced_ty = fi.data.ty,
3395 .analysis_extra_index = extra_index + std.meta.fieldIndex(P, "analysis").?,3414 .analysis_extra_index = extra_index + std.meta.fieldIndex(P, "analysis").?,
3396 .zir_body_inst_extra_index = func_decl.zir_body_inst_extra_index,3415 .zir_body_inst_extra_index = func_decl.zir_body_inst_extra_index,
3397 .resolved_error_set_extra_index = if (fi.data.analysis.inferred_error_set) fi.end else 0,3416 .resolved_error_set_extra_index = if (fi.data.analysis.inferred_error_set) fi.end else 0,
...@@ -4800,6 +4819,8 @@ pub fn getFuncInstanceIes(...@@ -4800,6 +4819,8 @@ pub fn getFuncInstanceIes(
4800 assert(arg.bare_return_type != .none);4819 assert(arg.bare_return_type != .none);
4801 for (arg.param_types) |param_type| assert(param_type != .none);4820 for (arg.param_types) |param_type| assert(param_type != .none);
48024821
4822 const generic_owner = unwrapCoercedFunc(ip, arg.generic_owner);
4823
4803 // The strategy here is to add the function decl unconditionally, then to4824 // The strategy here is to add the function decl unconditionally, then to
4804 // ask if it already exists, and if so, revert the lengths of the mutated4825 // ask if it already exists, and if so, revert the lengths of the mutated
4805 // arrays. This is similar to what `getOrPutTrailingString` does.4826 // arrays. This is similar to what `getOrPutTrailingString` does.
...@@ -4835,7 +4856,7 @@ pub fn getFuncInstanceIes(...@@ -4835,7 +4856,7 @@ pub fn getFuncInstanceIes(
4835 .owner_decl = undefined,4856 .owner_decl = undefined,
4836 .ty = func_ty,4857 .ty = func_ty,
4837 .branch_quota = 0,4858 .branch_quota = 0,
4838 .generic_owner = arg.generic_owner,4859 .generic_owner = generic_owner,
4839 });4860 });
4840 ip.extra.appendAssumeCapacity(@intFromEnum(Index.none)); // resolved error set4861 ip.extra.appendAssumeCapacity(@intFromEnum(Index.none)); // resolved error set
4841 ip.extra.appendSliceAssumeCapacity(@ptrCast(arg.comptime_args));4862 ip.extra.appendSliceAssumeCapacity(@ptrCast(arg.comptime_args));
...@@ -4908,7 +4929,7 @@ pub fn getFuncInstanceIes(...@@ -4908,7 +4929,7 @@ pub fn getFuncInstanceIes(
4908 return finishFuncInstance(4929 return finishFuncInstance(
4909 ip,4930 ip,
4910 gpa,4931 gpa,
4911 arg.generic_owner,4932 generic_owner,
4912 func_index,4933 func_index,
4913 func_extra_index,4934 func_extra_index,
4914 arg.generation,4935 arg.generation,
...@@ -7050,6 +7071,17 @@ pub fn funcIesResolved(ip: *const InternPool, func_index: Index) *Index {...@@ -7050,6 +7071,17 @@ pub fn funcIesResolved(ip: *const InternPool, func_index: Index) *Index {
7050 const extra_index = switch (tags[@intFromEnum(func_index)]) {7071 const extra_index = switch (tags[@intFromEnum(func_index)]) {
7051 .func_decl => func_start + @typeInfo(Tag.FuncDecl).Struct.fields.len,7072 .func_decl => func_start + @typeInfo(Tag.FuncDecl).Struct.fields.len,
7052 .func_instance => func_start + @typeInfo(Tag.FuncInstance).Struct.fields.len,7073 .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 },
7053 else => unreachable,7085 else => unreachable,
7054 };7086 };
7055 return @ptrCast(&ip.extra.items[extra_index]);7087 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" {...@@ -456,3 +456,23 @@ test "return type of generic function is function pointer" {
456456
457 try expect(null == S.b(void));457 try expect(null == S.b(void));
458}458}
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}