| ... | @@ -132,98 +132,6 @@ pub const Value = struct { | ... | @@ -132,98 +132,6 @@ pub const Value = struct { |
| 132 | return null; | 132 | return null; |
| 133 | } | 133 | } |
| 134 | | 134 | |
| 135 | /// It's intentional that this function is not passed a corresponding Type, so that | | |
| 136 | /// a Value can be copied from a Sema to a Decl prior to resolving struct/union field types. | | |
| 137 | pub fn copy(self: Value, arena: Allocator) error{OutOfMemory}!Value { | | |
| 138 | if (self.ip_index != .none) { | | |
| 139 | return Value{ .ip_index = self.ip_index, .legacy = undefined }; | | |
| 140 | } | | |
| 141 | switch (self.legacy.ptr_otherwise.tag) { | | |
| 142 | .bytes => { | | |
| 143 | const bytes = self.castTag(.bytes).?.data; | | |
| 144 | const new_payload = try arena.create(Payload.Bytes); | | |
| 145 | new_payload.* = .{ | | |
| 146 | .base = .{ .tag = .bytes }, | | |
| 147 | .data = try arena.dupe(u8, bytes), | | |
| 148 | }; | | |
| 149 | return Value{ | | |
| 150 | .ip_index = .none, | | |
| 151 | .legacy = .{ .ptr_otherwise = &new_payload.base }, | | |
| 152 | }; | | |
| 153 | }, | | |
| 154 | .eu_payload, | | |
| 155 | .opt_payload, | | |
| 156 | .repeated, | | |
| 157 | => { | | |
| 158 | const payload = self.cast(Payload.SubValue).?; | | |
| 159 | const new_payload = try arena.create(Payload.SubValue); | | |
| 160 | new_payload.* = .{ | | |
| 161 | .base = payload.base, | | |
| 162 | .data = try payload.data.copy(arena), | | |
| 163 | }; | | |
| 164 | return Value{ | | |
| 165 | .ip_index = .none, | | |
| 166 | .legacy = .{ .ptr_otherwise = &new_payload.base }, | | |
| 167 | }; | | |
| 168 | }, | | |
| 169 | .slice => { | | |
| 170 | const payload = self.castTag(.slice).?; | | |
| 171 | const new_payload = try arena.create(Payload.Slice); | | |
| 172 | new_payload.* = .{ | | |
| 173 | .base = payload.base, | | |
| 174 | .data = .{ | | |
| 175 | .ptr = try payload.data.ptr.copy(arena), | | |
| 176 | .len = try payload.data.len.copy(arena), | | |
| 177 | }, | | |
| 178 | }; | | |
| 179 | return Value{ | | |
| 180 | .ip_index = .none, | | |
| 181 | .legacy = .{ .ptr_otherwise = &new_payload.base }, | | |
| 182 | }; | | |
| 183 | }, | | |
| 184 | .aggregate => { | | |
| 185 | const payload = self.castTag(.aggregate).?; | | |
| 186 | const new_payload = try arena.create(Payload.Aggregate); | | |
| 187 | new_payload.* = .{ | | |
| 188 | .base = payload.base, | | |
| 189 | .data = try arena.alloc(Value, payload.data.len), | | |
| 190 | }; | | |
| 191 | for (new_payload.data, 0..) |*elem, i| { | | |
| 192 | elem.* = try payload.data[i].copy(arena); | | |
| 193 | } | | |
| 194 | return Value{ | | |
| 195 | .ip_index = .none, | | |
| 196 | .legacy = .{ .ptr_otherwise = &new_payload.base }, | | |
| 197 | }; | | |
| 198 | }, | | |
| 199 | .@"union" => { | | |
| 200 | const tag_and_val = self.castTag(.@"union").?.data; | | |
| 201 | const new_payload = try arena.create(Payload.Union); | | |
| 202 | new_payload.* = .{ | | |
| 203 | .base = .{ .tag = .@"union" }, | | |
| 204 | .data = .{ | | |
| 205 | .tag = try tag_and_val.tag.copy(arena), | | |
| 206 | .val = try tag_and_val.val.copy(arena), | | |
| 207 | }, | | |
| 208 | }; | | |
| 209 | return Value{ | | |
| 210 | .ip_index = .none, | | |
| 211 | .legacy = .{ .ptr_otherwise = &new_payload.base }, | | |
| 212 | }; | | |
| 213 | }, | | |
| 214 | } | | |
| 215 | } | | |
| 216 | | | |
| 217 | fn copyPayloadShallow(self: Value, arena: Allocator, comptime T: type) error{OutOfMemory}!Value { | | |
| 218 | const payload = self.cast(T).?; | | |
| 219 | const new_payload = try arena.create(T); | | |
| 220 | new_payload.* = payload.*; | | |
| 221 | return Value{ | | |
| 222 | .ip_index = .none, | | |
| 223 | .legacy = .{ .ptr_otherwise = &new_payload.base }, | | |
| 224 | }; | | |
| 225 | } | | |
| 226 | | | |
| 227 | pub fn format(val: Value, comptime fmt: []const u8, options: std.fmt.FormatOptions, writer: anytype) !void { | 135 | pub fn format(val: Value, comptime fmt: []const u8, options: std.fmt.FormatOptions, writer: anytype) !void { |
| 228 | _ = val; | 136 | _ = val; |
| 229 | _ = fmt; | 137 | _ = fmt; |
| ... | @@ -1494,193 +1402,9 @@ pub const Value = struct { | ... | @@ -1494,193 +1402,9 @@ pub const Value = struct { |
| 1494 | } | 1402 | } |
| 1495 | | 1403 | |
| 1496 | pub fn eql(a: Value, b: Value, ty: Type, mod: *Module) bool { | 1404 | pub fn eql(a: Value, b: Value, ty: Type, mod: *Module) bool { |
| 1497 | return eqlAdvanced(a, ty, b, ty, mod, null) catch unreachable; | 1405 | assert(mod.intern_pool.typeOf(a.toIntern()) == ty.toIntern()); |
| 1498 | } | 1406 | assert(mod.intern_pool.typeOf(b.toIntern()) == ty.toIntern()); |
| 1499 | | 1407 | return a.toIntern() == b.toIntern(); |
| 1500 | /// This function is used by hash maps and so treats floating-point NaNs as equal | | |
| 1501 | /// to each other, and not equal to other floating-point values. | | |
| 1502 | /// Similarly, it treats `undef` as a distinct value from all other values. | | |
| 1503 | /// This function has to be able to support implicit coercion of `a` to `ty`. That is, | | |
| 1504 | /// `ty` will be an exactly correct Type for `b` but it may be a post-coerced Type | | |
| 1505 | /// for `a`. This function must act *as if* `a` has been coerced to `ty`. This complication | | |
| 1506 | /// is required in order to make generic function instantiation efficient - specifically | | |
| 1507 | /// the insertion into the monomorphized function table. | | |
| 1508 | /// If `null` is provided for `opt_sema` then it is guaranteed no error will be returned. | | |
| 1509 | pub fn eqlAdvanced( | | |
| 1510 | a: Value, | | |
| 1511 | a_ty: Type, | | |
| 1512 | b: Value, | | |
| 1513 | ty: Type, | | |
| 1514 | mod: *Module, | | |
| 1515 | opt_sema: ?*Sema, | | |
| 1516 | ) Module.CompileError!bool { | | |
| 1517 | if (a.ip_index != .none or b.ip_index != .none) return a.ip_index == b.ip_index; | | |
| 1518 | | | |
| 1519 | const target = mod.getTarget(); | | |
| 1520 | const a_tag = a.tag(); | | |
| 1521 | const b_tag = b.tag(); | | |
| 1522 | if (a_tag == b_tag) switch (a_tag) { | | |
| 1523 | .aggregate => { | | |
| 1524 | const a_field_vals = a.castTag(.aggregate).?.data; | | |
| 1525 | const b_field_vals = b.castTag(.aggregate).?.data; | | |
| 1526 | assert(a_field_vals.len == b_field_vals.len); | | |
| 1527 | | | |
| 1528 | switch (mod.intern_pool.indexToKey(ty.toIntern())) { | | |
| 1529 | .anon_struct_type => |anon_struct| { | | |
| 1530 | assert(anon_struct.types.len == a_field_vals.len); | | |
| 1531 | for (anon_struct.types, 0..) |field_ty, i| { | | |
| 1532 | if (!(try eqlAdvanced(a_field_vals[i], field_ty.toType(), b_field_vals[i], field_ty.toType(), mod, opt_sema))) { | | |
| 1533 | return false; | | |
| 1534 | } | | |
| 1535 | } | | |
| 1536 | return true; | | |
| 1537 | }, | | |
| 1538 | .struct_type => |struct_type| { | | |
| 1539 | const struct_obj = mod.structPtrUnwrap(struct_type.index).?; | | |
| 1540 | const fields = struct_obj.fields.values(); | | |
| 1541 | assert(fields.len == a_field_vals.len); | | |
| 1542 | for (fields, 0..) |field, i| { | | |
| 1543 | if (!(try eqlAdvanced(a_field_vals[i], field.ty, b_field_vals[i], field.ty, mod, opt_sema))) { | | |
| 1544 | return false; | | |
| 1545 | } | | |
| 1546 | } | | |
| 1547 | return true; | | |
| 1548 | }, | | |
| 1549 | else => {}, | | |
| 1550 | } | | |
| 1551 | | | |
| 1552 | const elem_ty = ty.childType(mod); | | |
| 1553 | for (a_field_vals, 0..) |a_elem, i| { | | |
| 1554 | const b_elem = b_field_vals[i]; | | |
| 1555 | | | |
| 1556 | if (!(try eqlAdvanced(a_elem, elem_ty, b_elem, elem_ty, mod, opt_sema))) { | | |
| 1557 | return false; | | |
| 1558 | } | | |
| 1559 | } | | |
| 1560 | return true; | | |
| 1561 | }, | | |
| 1562 | .@"union" => { | | |
| 1563 | const a_union = a.castTag(.@"union").?.data; | | |
| 1564 | const b_union = b.castTag(.@"union").?.data; | | |
| 1565 | switch (ty.containerLayout(mod)) { | | |
| 1566 | .Packed, .Extern => { | | |
| 1567 | const tag_ty = ty.unionTagTypeHypothetical(mod); | | |
| 1568 | if (!(try eqlAdvanced(a_union.tag, tag_ty, b_union.tag, tag_ty, mod, opt_sema))) { | | |
| 1569 | // In this case, we must disregard mismatching tags and compare | | |
| 1570 | // based on the in-memory bytes of the payloads. | | |
| 1571 | @panic("TODO comptime comparison of extern union values with mismatching tags"); | | |
| 1572 | } | | |
| 1573 | }, | | |
| 1574 | .Auto => { | | |
| 1575 | const tag_ty = ty.unionTagTypeHypothetical(mod); | | |
| 1576 | if (!(try eqlAdvanced(a_union.tag, tag_ty, b_union.tag, tag_ty, mod, opt_sema))) { | | |
| 1577 | return false; | | |
| 1578 | } | | |
| 1579 | }, | | |
| 1580 | } | | |
| 1581 | const active_field_ty = ty.unionFieldType(a_union.tag, mod); | | |
| 1582 | return eqlAdvanced(a_union.val, active_field_ty, b_union.val, active_field_ty, mod, opt_sema); | | |
| 1583 | }, | | |
| 1584 | else => {}, | | |
| 1585 | }; | | |
| 1586 | | | |
| 1587 | if (a.pointerDecl(mod)) |a_decl| { | | |
| 1588 | if (b.pointerDecl(mod)) |b_decl| { | | |
| 1589 | return a_decl == b_decl; | | |
| 1590 | } else { | | |
| 1591 | return false; | | |
| 1592 | } | | |
| 1593 | } else if (b.pointerDecl(mod)) |_| { | | |
| 1594 | return false; | | |
| 1595 | } | | |
| 1596 | | | |
| 1597 | switch (ty.zigTypeTag(mod)) { | | |
| 1598 | .Type => { | | |
| 1599 | const a_type = a.toType(); | | |
| 1600 | const b_type = b.toType(); | | |
| 1601 | return a_type.eql(b_type, mod); | | |
| 1602 | }, | | |
| 1603 | .Enum => { | | |
| 1604 | const a_val = try a.intFromEnum(ty, mod); | | |
| 1605 | const b_val = try b.intFromEnum(ty, mod); | | |
| 1606 | const int_ty = ty.intTagType(mod); | | |
| 1607 | return eqlAdvanced(a_val, int_ty, b_val, int_ty, mod, opt_sema); | | |
| 1608 | }, | | |
| 1609 | .Array, .Vector => { | | |
| 1610 | const len = ty.arrayLen(mod); | | |
| 1611 | const elem_ty = ty.childType(mod); | | |
| 1612 | var i: usize = 0; | | |
| 1613 | while (i < len) : (i += 1) { | | |
| 1614 | const a_elem = try elemValue(a, mod, i); | | |
| 1615 | const b_elem = try elemValue(b, mod, i); | | |
| 1616 | if (!(try eqlAdvanced(a_elem, elem_ty, b_elem, elem_ty, mod, opt_sema))) { | | |
| 1617 | return false; | | |
| 1618 | } | | |
| 1619 | } | | |
| 1620 | return true; | | |
| 1621 | }, | | |
| 1622 | .Pointer => switch (ty.ptrSize(mod)) { | | |
| 1623 | .Slice => { | | |
| 1624 | const a_len = switch (a_ty.ptrSize(mod)) { | | |
| 1625 | .Slice => a.sliceLen(mod), | | |
| 1626 | .One => a_ty.childType(mod).arrayLen(mod), | | |
| 1627 | else => unreachable, | | |
| 1628 | }; | | |
| 1629 | if (a_len != b.sliceLen(mod)) { | | |
| 1630 | return false; | | |
| 1631 | } | | |
| 1632 | | | |
| 1633 | const ptr_ty = ty.slicePtrFieldType(mod); | | |
| 1634 | const a_ptr = switch (a_ty.ptrSize(mod)) { | | |
| 1635 | .Slice => a.slicePtr(mod), | | |
| 1636 | .One => a, | | |
| 1637 | else => unreachable, | | |
| 1638 | }; | | |
| 1639 | return try eqlAdvanced(a_ptr, ptr_ty, b.slicePtr(mod), ptr_ty, mod, opt_sema); | | |
| 1640 | }, | | |
| 1641 | .Many, .C, .One => {}, | | |
| 1642 | }, | | |
| 1643 | .Struct => { | | |
| 1644 | // A struct can be represented with one of: | | |
| 1645 | // .the_one_possible_value, | | |
| 1646 | // .aggregate, | | |
| 1647 | // Note that we already checked above for matching tags, e.g. both .aggregate. | | |
| 1648 | return (try ty.onePossibleValue(mod)) != null; | | |
| 1649 | }, | | |
| 1650 | .Union => { | | |
| 1651 | // Here we have to check for value equality, as-if `a` has been coerced to `ty`. | | |
| 1652 | if ((try ty.onePossibleValue(mod)) != null) { | | |
| 1653 | return true; | | |
| 1654 | } | | |
| 1655 | return false; | | |
| 1656 | }, | | |
| 1657 | .Float => { | | |
| 1658 | switch (ty.floatBits(target)) { | | |
| 1659 | 16 => return @bitCast(u16, a.toFloat(f16, mod)) == @bitCast(u16, b.toFloat(f16, mod)), | | |
| 1660 | 32 => return @bitCast(u32, a.toFloat(f32, mod)) == @bitCast(u32, b.toFloat(f32, mod)), | | |
| 1661 | 64 => return @bitCast(u64, a.toFloat(f64, mod)) == @bitCast(u64, b.toFloat(f64, mod)), | | |
| 1662 | 80 => return @bitCast(u80, a.toFloat(f80, mod)) == @bitCast(u80, b.toFloat(f80, mod)), | | |
| 1663 | 128 => return @bitCast(u128, a.toFloat(f128, mod)) == @bitCast(u128, b.toFloat(f128, mod)), | | |
| 1664 | else => unreachable, | | |
| 1665 | } | | |
| 1666 | }, | | |
| 1667 | .ComptimeFloat => { | | |
| 1668 | const a_float = a.toFloat(f128, mod); | | |
| 1669 | const b_float = b.toFloat(f128, mod); | | |
| 1670 | | | |
| 1671 | const a_nan = std.math.isNan(a_float); | | |
| 1672 | const b_nan = std.math.isNan(b_float); | | |
| 1673 | if (a_nan != b_nan) return false; | | |
| 1674 | if (std.math.signbit(a_float) != std.math.signbit(b_float)) return false; | | |
| 1675 | if (a_nan) return true; | | |
| 1676 | return a_float == b_float; | | |
| 1677 | }, | | |
| 1678 | .Optional, | | |
| 1679 | .ErrorUnion, | | |
| 1680 | => unreachable, // handled by InternPool | | |
| 1681 | else => {}, | | |
| 1682 | } | | |
| 1683 | return (try orderAdvanced(a, b, mod, opt_sema)).compare(.eq); | | |
| 1684 | } | 1408 | } |
| 1685 | | 1409 | |
| 1686 | pub fn isComptimeMutablePtr(val: Value, mod: *Module) bool { | 1410 | pub fn isComptimeMutablePtr(val: Value, mod: *Module) bool { |
| ... | @@ -1736,15 +1460,6 @@ pub const Value = struct { | ... | @@ -1736,15 +1460,6 @@ pub const Value = struct { |
| 1736 | }; | 1460 | }; |
| 1737 | } | 1461 | } |
| 1738 | | 1462 | |
| 1739 | fn hashInt(int_val: Value, hasher: *std.hash.Wyhash, mod: *Module) void { | | |
| 1740 | var buffer: BigIntSpace = undefined; | | |
| 1741 | const big = int_val.toBigInt(&buffer, mod); | | |
| 1742 | std.hash.autoHash(hasher, big.positive); | | |
| 1743 | for (big.limbs) |limb| { | | |
| 1744 | std.hash.autoHash(hasher, limb); | | |
| 1745 | } | | |
| 1746 | } | | |
| 1747 | | | |
| 1748 | pub const slice_ptr_index = 0; | 1463 | pub const slice_ptr_index = 0; |
| 1749 | pub const slice_len_index = 1; | 1464 | pub const slice_len_index = 1; |
| 1750 | | 1465 | |