aboutsummaryrefslogtreecommitdiff
path: root/src/value.zig
diff options
context:
space:
mode:
authorAndrew Kelley <andrew@ziglang.org>2022-04-14 00:36:54 -0700
committerAndrew Kelley <andrew@ziglang.org>2022-04-14 06:08:28 -0700
commit2a00df9c091498268b58dd671f646a5590439b7a (patch)
treed1fe5b80b9180bd32a75c13e9d3f9ca7700817f3 /src/value.zig
parent9b82e7f558d5aa66ac1dc285af2345d46cc3d4d6 (diff)
downloadzig-2a00df9c091498268b58dd671f646a5590439b7a.tar.gz
zig-2a00df9c091498268b58dd671f646a5590439b7a.zip
Sema: fix generic instantiation false negatives
The problem was that types of non-anytype parameters were being included as part of the check to see if generic function instantiations were equal. Now, Module.Fn additionally stores the information for whether each parameter is anytype or not. `generic_poison` cannot be used to signal this because the type is still needed for comptime arguments; in such case the type will not be present in the newly generated function prototype. This presented one additional challenge: we need to compare equality of two values where one of them is post-coercion and the other is not. So we make some minor adjustments to `Type.eql` to support this. I think this small complexity tradeoff is worth it because it means the compiler does much less work on the hot path that a generic function is called and there is already an existing matching instantiation. closes #11146
Diffstat (limited to 'src/value.zig')
-rw-r--r--src/value.zig21
1 files changed, 20 insertions, 1 deletions
diff --git a/src/value.zig b/src/value.zig
index beb8bc7620..713cacb7b0 100644
--- a/src/value.zig
+++ b/src/value.zig
@@ -954,6 +954,10 @@ pub const Value = extern union {
assert(ty.enumFieldCount() == 1);
break :blk 0;
},
+ .enum_literal => i: {
+ const name = val.castTag(.enum_literal).?.data;
+ break :i ty.enumFieldIndex(name).?;
+ },
// Assume it is already an integer and return it directly.
else => return val,
};
@@ -2023,6 +2027,11 @@ pub const Value = extern union {
/// This function is used by hash maps and so treats floating-point NaNs as equal
/// to each other, and not equal to other floating-point values.
/// Similarly, it treats `undef` as a distinct value from all other values.
+ /// This function has to be able to support implicit coercion of `a` to `ty`. That is,
+ /// `ty` will be an exactly correct Type for `b` but it may be a post-coerced Type
+ /// for `a`. This function must act *as if* `a` has been coerced to `ty`. This complication
+ /// is required in order to make generic function instantiation effecient - specifically
+ /// the insertion into the monomorphized function table.
pub fn eql(a: Value, b: Value, ty: Type, target: Target) bool {
const a_tag = a.tag();
const b_tag = b.tag();
@@ -2200,8 +2209,18 @@ pub const Value = extern union {
}
return order(a, b, target).compare(.eq);
},
- else => return order(a, b, target).compare(.eq),
+ .Optional => {
+ if (a.tag() != .opt_payload and b.tag() == .opt_payload) {
+ var buffer: Payload.SubValue = .{
+ .base = .{ .tag = .opt_payload },
+ .data = a,
+ };
+ return eql(Value.initPayload(&buffer.base), b, ty, target);
+ }
+ },
+ else => {},
}
+ return order(a, b, target).compare(.eq);
}
/// This function is used by hash maps and so treats floating-point NaNs as equal