authorgravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2023-07-23 17:19:50-07:00
committergravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2023-07-23 17:47:18-07:00
loga7f3c2eab427397846f619dba7abb72378ac2ce9
tree8398c95f4ce6c45ac738c31c4ec2044df49c2103
parent7dcbabef512403382f4647e2c7cc0c900ecae913

InternPool: fix coerced func hash/eql same as uncoerced

Since the same Key.Func data structure is used for coerced function bodies as well as uncoerced function bodies, there is danger of them being hashed and equality-checked as the same. When that happens, the type of a function body value might be wrong, causing lots of problems. In this instance, it causes an assertion failure. This commit fixes it by introducing an `uncoerced_ty` field which is different than `ty` in the case of `func_coerced` and is used to differentiate when doing hashing and equality checking. I have a new behavior test to cover this bug, but it revealed *another* bug at the same time, so I will fix it in the next commit and and add the new test therein.

1 files changed, 21 insertions(+), 2 deletions(-)

src/InternPool.zig+21-2
......@@ -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,