@@ -2004,6 +2004,10 @@ pub const Value = extern union {
2004
2004
return (try orderAgainstZeroAdvanced (lhs , sema_kit )).compare (op );
2005
2005
}
2006
2006
2007
+ pub fn eql (a : Value , b : Value , ty : Type , mod : * Module ) bool {
2008
+ return eqlAdvanced (a , ty , b , ty , mod , null ) catch unreachable ;
2009
+ }
2010
+
2007
2011
/// This function is used by hash maps and so treats floating-point NaNs as equal
2008
2012
/// to each other, and not equal to other floating-point values.
2009
2013
/// Similarly, it treats `undef` as a distinct value from all other values.
@@ -2012,13 +2016,10 @@ pub const Value = extern union {
2012
2016
/// for `a`. This function must act *as if* `a` has been coerced to `ty`. This complication
2013
2017
/// is required in order to make generic function instantiation efficient - specifically
2014
2018
/// the insertion into the monomorphized function table.
2015
- pub fn eql (a : Value , b : Value , ty : Type , mod : * Module ) bool {
2016
- return eqlAdvanced (a , b , ty , mod , null ) catch unreachable ;
2017
- }
2018
-
2019
2019
/// If `null` is provided for `sema_kit` then it is guaranteed no error will be returned.
2020
2020
pub fn eqlAdvanced (
2021
2021
a : Value ,
2022
+ a_ty : Type ,
2022
2023
b : Value ,
2023
2024
ty : Type ,
2024
2025
mod : * Module ,
@@ -2044,33 +2045,34 @@ pub const Value = extern union {
2044
2045
const a_payload = a .castTag (.opt_payload ).? .data ;
2045
2046
const b_payload = b .castTag (.opt_payload ).? .data ;
2046
2047
var buffer : Type.Payload.ElemType = undefined ;
2047
- return eqlAdvanced (a_payload , b_payload , ty .optionalChild (& buffer ), mod , sema_kit );
2048
+ const payload_ty = ty .optionalChild (& buffer );
2049
+ return eqlAdvanced (a_payload , payload_ty , b_payload , payload_ty , mod , sema_kit );
2048
2050
},
2049
2051
.slice = > {
2050
2052
const a_payload = a .castTag (.slice ).? .data ;
2051
2053
const b_payload = b .castTag (.slice ).? .data ;
2052
- if (! (try eqlAdvanced (a_payload .len , b_payload .len , Type .usize , mod , sema_kit ))) {
2054
+ if (! (try eqlAdvanced (a_payload .len , Type . usize , b_payload .len , Type .usize , mod , sema_kit ))) {
2053
2055
return false ;
2054
2056
}
2055
2057
2056
2058
var ptr_buf : Type.SlicePtrFieldTypeBuffer = undefined ;
2057
2059
const ptr_ty = ty .slicePtrFieldType (& ptr_buf );
2058
2060
2059
- return eqlAdvanced (a_payload .ptr , b_payload .ptr , ptr_ty , mod , sema_kit );
2061
+ return eqlAdvanced (a_payload .ptr , ptr_ty , b_payload .ptr , ptr_ty , mod , sema_kit );
2060
2062
},
2061
2063
.elem_ptr = > {
2062
2064
const a_payload = a .castTag (.elem_ptr ).? .data ;
2063
2065
const b_payload = b .castTag (.elem_ptr ).? .data ;
2064
2066
if (a_payload .index != b_payload .index ) return false ;
2065
2067
2066
- return eqlAdvanced (a_payload .array_ptr , b_payload .array_ptr , ty , mod , sema_kit );
2068
+ return eqlAdvanced (a_payload .array_ptr , ty , b_payload .array_ptr , ty , mod , sema_kit );
2067
2069
},
2068
2070
.field_ptr = > {
2069
2071
const a_payload = a .castTag (.field_ptr ).? .data ;
2070
2072
const b_payload = b .castTag (.field_ptr ).? .data ;
2071
2073
if (a_payload .field_index != b_payload .field_index ) return false ;
2072
2074
2073
- return eqlAdvanced (a_payload .container_ptr , b_payload .container_ptr , ty , mod , sema_kit );
2075
+ return eqlAdvanced (a_payload .container_ptr , ty , b_payload .container_ptr , ty , mod , sema_kit );
2074
2076
},
2075
2077
.@"error" = > {
2076
2078
const a_name = a .castTag (.@"error" ).? .data .name ;
@@ -2080,7 +2082,8 @@ pub const Value = extern union {
2080
2082
.eu_payload = > {
2081
2083
const a_payload = a .castTag (.eu_payload ).? .data ;
2082
2084
const b_payload = b .castTag (.eu_payload ).? .data ;
2083
- return eqlAdvanced (a_payload , b_payload , ty .errorUnionPayload (), mod , sema_kit );
2085
+ const payload_ty = ty .errorUnionPayload ();
2086
+ return eqlAdvanced (a_payload , payload_ty , b_payload , payload_ty , mod , sema_kit );
2084
2087
},
2085
2088
.eu_payload_ptr = > @panic ("TODO: Implement more pointer eql cases" ),
2086
2089
.opt_payload_ptr = > @panic ("TODO: Implement more pointer eql cases" ),
@@ -2098,7 +2101,7 @@ pub const Value = extern union {
2098
2101
const types = ty .tupleFields ().types ;
2099
2102
assert (types .len == a_field_vals .len );
2100
2103
for (types ) | field_ty , i | {
2101
- if (! (try eqlAdvanced (a_field_vals [i ], b_field_vals [i ], field_ty , mod , sema_kit ))) {
2104
+ if (! (try eqlAdvanced (a_field_vals [i ], field_ty , b_field_vals [i ], field_ty , mod , sema_kit ))) {
2102
2105
return false ;
2103
2106
}
2104
2107
}
@@ -2109,7 +2112,7 @@ pub const Value = extern union {
2109
2112
const fields = ty .structFields ().values ();
2110
2113
assert (fields .len == a_field_vals .len );
2111
2114
for (fields ) | field , i | {
2112
- if (! (try eqlAdvanced (a_field_vals [i ], b_field_vals [i ], field .ty , mod , sema_kit ))) {
2115
+ if (! (try eqlAdvanced (a_field_vals [i ], field . ty , b_field_vals [i ], field .ty , mod , sema_kit ))) {
2113
2116
return false ;
2114
2117
}
2115
2118
}
@@ -2120,7 +2123,7 @@ pub const Value = extern union {
2120
2123
for (a_field_vals ) | a_elem , i | {
2121
2124
const b_elem = b_field_vals [i ];
2122
2125
2123
- if (! (try eqlAdvanced (a_elem , b_elem , elem_ty , mod , sema_kit ))) {
2126
+ if (! (try eqlAdvanced (a_elem , elem_ty , b_elem , elem_ty , mod , sema_kit ))) {
2124
2127
return false ;
2125
2128
}
2126
2129
}
@@ -2132,21 +2135,21 @@ pub const Value = extern union {
2132
2135
switch (ty .containerLayout ()) {
2133
2136
.Packed , .Extern = > {
2134
2137
const tag_ty = ty .unionTagTypeHypothetical ();
2135
- if (! (try a_union .tag . eqlAdvanced ( b_union .tag , tag_ty , mod , sema_kit ))) {
2138
+ if (! (try eqlAdvanced ( a_union .tag , tag_ty , b_union .tag , tag_ty , mod , sema_kit ))) {
2136
2139
// In this case, we must disregard mismatching tags and compare
2137
2140
// based on the in-memory bytes of the payloads.
2138
2141
@panic ("TODO comptime comparison of extern union values with mismatching tags" );
2139
2142
}
2140
2143
},
2141
2144
.Auto = > {
2142
2145
const tag_ty = ty .unionTagTypeHypothetical ();
2143
- if (! (try a_union .tag . eqlAdvanced ( b_union .tag , tag_ty , mod , sema_kit ))) {
2146
+ if (! (try eqlAdvanced ( a_union .tag , tag_ty , b_union .tag , tag_ty , mod , sema_kit ))) {
2144
2147
return false ;
2145
2148
}
2146
2149
},
2147
2150
}
2148
2151
const active_field_ty = ty .unionFieldType (a_union .tag , mod );
2149
- return a_union .val . eqlAdvanced ( b_union .val , active_field_ty , mod , sema_kit );
2152
+ return eqlAdvanced ( a_union .val , active_field_ty , b_union .val , active_field_ty , mod , sema_kit );
2150
2153
},
2151
2154
else = > {},
2152
2155
} else if (a_tag == .null_value or b_tag == .null_value ) {
@@ -2180,7 +2183,7 @@ pub const Value = extern union {
2180
2183
const b_val = b .enumToInt (ty , & buf_b );
2181
2184
var buf_ty : Type.Payload.Bits = undefined ;
2182
2185
const int_ty = ty .intTagType (& buf_ty );
2183
- return eqlAdvanced (a_val , b_val , int_ty , mod , sema_kit );
2186
+ return eqlAdvanced (a_val , int_ty , b_val , int_ty , mod , sema_kit );
2184
2187
},
2185
2188
.Array , .Vector = > {
2186
2189
const len = ty .arrayLen ();
@@ -2191,17 +2194,44 @@ pub const Value = extern union {
2191
2194
while (i < len ) : (i += 1 ) {
2192
2195
const a_elem = elemValueBuffer (a , mod , i , & a_buf );
2193
2196
const b_elem = elemValueBuffer (b , mod , i , & b_buf );
2194
- if (! (try eqlAdvanced (a_elem , b_elem , elem_ty , mod , sema_kit ))) {
2197
+ if (! (try eqlAdvanced (a_elem , elem_ty , b_elem , elem_ty , mod , sema_kit ))) {
2195
2198
return false ;
2196
2199
}
2197
2200
}
2198
2201
return true ;
2199
2202
},
2200
2203
.Struct = > {
2201
- // A tuple can be represented with .empty_struct_value,
2202
- // the_one_possible_value, .aggregate in which case we could
2203
- // end up here and the values are equal if the type has zero fields.
2204
- return ty .isTupleOrAnonStruct () and ty .structFieldCount () != 0 ;
2204
+ // A struct can be represented with one of:
2205
+ // .empty_struct_value,
2206
+ // .the_one_possible_value,
2207
+ // .aggregate,
2208
+ // Note that we already checked above for matching tags, e.g. both .aggregate.
2209
+ return ty .onePossibleValue () != null ;
2210
+ },
2211
+ .Union = > {
2212
+ // Here we have to check for value equality, as-if `a` has been coerced to `ty`.
2213
+ if (ty .onePossibleValue () != null ) {
2214
+ return true ;
2215
+ }
2216
+ if (a_ty .castTag (.anon_struct )) | payload | {
2217
+ const tuple = payload .data ;
2218
+ if (tuple .values .len != 1 ) {
2219
+ return false ;
2220
+ }
2221
+ const field_name = tuple .names [0 ];
2222
+ const union_obj = ty .cast (Type .Payload .Union ).? .data ;
2223
+ const field_index = union_obj .fields .getIndex (field_name ) orelse return false ;
2224
+ const tag_and_val = b .castTag (.@"union" ).? .data ;
2225
+ var field_tag_buf : Value.Payload.U32 = .{
2226
+ .base = .{ .tag = .enum_field_index },
2227
+ .data = @intCast (u32 , field_index ),
2228
+ };
2229
+ const field_tag = Value .initPayload (& field_tag_buf .base );
2230
+ const tag_matches = tag_and_val .tag .eql (field_tag , union_obj .tag_ty , mod );
2231
+ if (! tag_matches ) return false ;
2232
+ return eqlAdvanced (tag_and_val .val , union_obj .tag_ty , tuple .values [0 ], tuple .types [0 ], mod , sema_kit );
2233
+ }
2234
+ return false ;
2205
2235
},
2206
2236
.Float = > {
2207
2237
switch (ty .floatBits (target )) {
@@ -2230,7 +2260,8 @@ pub const Value = extern union {
2230
2260
.base = .{ .tag = .opt_payload },
2231
2261
.data = a ,
2232
2262
};
2233
- return eqlAdvanced (Value .initPayload (& buffer .base ), b , ty , mod , sema_kit );
2263
+ const opt_val = Value .initPayload (& buffer .base );
2264
+ return eqlAdvanced (opt_val , ty , b , ty , mod , sema_kit );
2234
2265
}
2235
2266
},
2236
2267
else = > {},
0 commit comments