diff options
| author | Andrew Kelley <andrew@ziglang.org> | 2022-04-14 00:36:54 -0700 |
|---|---|---|
| committer | Andrew Kelley <andrew@ziglang.org> | 2022-04-14 06:08:28 -0700 |
| commit | 2a00df9c091498268b58dd671f646a5590439b7a (patch) | |
| tree | d1fe5b80b9180bd32a75c13e9d3f9ca7700817f3 /src/value.zig | |
| parent | 9b82e7f558d5aa66ac1dc285af2345d46cc3d4d6 (diff) | |
| download | zig-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.zig | 21 |
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 |
