| author | |
| committer | |
| log | 115c08956278b79c848e04c2f4eefca40e6cd8a3 |
| tree | 8dfdced9bc1ba7499f7660e986bd82d0ae772347 |
| parent | be78a12d7d5ac0a711fdf7237d7ccefba42be83c |
This allows some code (like struct initializers) to use interned types
while other code (such as comptime mutation) continues to use legacy
types.
With these changes, an `zig build-obj empty.zig` gets to a crash on
missing interned error union types.6 files changed, 603 insertions(+), 177 deletions(-)
src/InternPool.zig+205-17| ... | ... | @@ -100,6 +100,16 @@ pub const MapIndex = enum(u32) { |
| 100 | 100 | } |
| 101 | 101 | }; |
| 102 | 102 | |
| 103 | pub const RuntimeIndex = enum(u32) { | |
| 104 | zero = 0, | |
| 105 | comptime_field_ptr = std.math.maxInt(u32), | |
| 106 | _, | |
| 107 | ||
| 108 | pub fn increment(ri: *RuntimeIndex) void { | |
| 109 | ri.* = @intToEnum(RuntimeIndex, @enumToInt(ri.*) + 1); | |
| 110 | } | |
| 111 | }; | |
| 112 | ||
| 103 | 113 | /// An index into `string_bytes`. |
| 104 | 114 | pub const NullTerminatedString = enum(u32) { |
| 105 | 115 | _, |
| ... | ... | @@ -478,11 +488,27 @@ pub const Key = union(enum) { |
| 478 | 488 | }; |
| 479 | 489 | |
| 480 | 490 | pub const Ptr = struct { |
| 491 | /// This is the pointer type, not the element type. | |
| 481 | 492 | ty: Index, |
| 493 | /// The value of the address that the pointer points to. | |
| 482 | 494 | addr: Addr, |
| 495 | /// This could be `none` if size is not a slice. | |
| 496 | len: Index = .none, | |
| 483 | 497 | |
| 484 | 498 | pub const Addr = union(enum) { |
| 499 | @"var": struct { | |
| 500 | init: Index, | |
| 501 | owner_decl: Module.Decl.Index, | |
| 502 | lib_name: OptionalNullTerminatedString, | |
| 503 | is_const: bool, | |
| 504 | is_threadlocal: bool, | |
| 505 | is_weak_linkage: bool, | |
| 506 | }, | |
| 485 | 507 | decl: Module.Decl.Index, |
| 508 | mut_decl: struct { | |
| 509 | decl: Module.Decl.Index, | |
| 510 | runtime_index: RuntimeIndex, | |
| 511 | }, | |
| 486 | 512 | int: Index, |
| 487 | 513 | }; |
| 488 | 514 | }; |
| ... | ... | @@ -577,7 +603,9 @@ pub const Key = union(enum) { |
| 577 | 603 | // This is sound due to pointer provenance rules. |
| 578 | 604 | std.hash.autoHash(hasher, @as(@typeInfo(Key.Ptr.Addr).Union.tag_type.?, ptr.addr)); |
| 579 | 605 | switch (ptr.addr) { |
| 606 | .@"var" => |@"var"| std.hash.autoHash(hasher, @"var".owner_decl), | |
| 580 | 607 | .decl => |decl| std.hash.autoHash(hasher, decl), |
| 608 | .mut_decl => |mut_decl| std.hash.autoHash(hasher, mut_decl), | |
| 581 | 609 | .int => |int| std.hash.autoHash(hasher, int), |
| 582 | 610 | } |
| 583 | 611 | }, |
| ... | ... | @@ -697,7 +725,9 @@ pub const Key = union(enum) { |
| 697 | 725 | if (@as(AddrTag, a_info.addr) != @as(AddrTag, b_info.addr)) return false; |
| 698 | 726 | |
| 699 | 727 | return switch (a_info.addr) { |
| 728 | .@"var" => |a_var| a_var.owner_decl == b_info.addr.@"var".owner_decl, | |
| 700 | 729 | .decl => |a_decl| a_decl == b_info.addr.decl, |
| 730 | .mut_decl => |a_mut_decl| std.meta.eql(a_mut_decl, b_info.addr.mut_decl), | |
| 701 | 731 | .int => |a_int| a_int == b_info.addr.int, |
| 702 | 732 | }; |
| 703 | 733 | }, |
| ... | ... | @@ -1330,6 +1360,12 @@ pub const Tag = enum(u8) { |
| 1330 | 1360 | /// A value that can be represented with only an enum tag. |
| 1331 | 1361 | /// data is SimpleValue enum value. |
| 1332 | 1362 | simple_value, |
| 1363 | /// A pointer to a var. | |
| 1364 | /// data is extra index of PtrVal, which contains the type and address. | |
| 1365 | ptr_var, | |
| 1366 | /// A pointer to a decl that can be mutated at comptime. | |
| 1367 | /// data is extra index of PtrMutDecl, which contains the type and address. | |
| 1368 | ptr_mut_decl, | |
| 1333 | 1369 | /// A pointer to a decl. |
| 1334 | 1370 | /// data is extra index of PtrDecl, which contains the type and address. |
| 1335 | 1371 | ptr_decl, |
| ... | ... | @@ -1338,6 +1374,11 @@ pub const Tag = enum(u8) { |
| 1338 | 1374 | /// Only pointer types are allowed to have this encoding. Optional types must use |
| 1339 | 1375 | /// `opt_payload` or `opt_null`. |
| 1340 | 1376 | ptr_int, |
| 1377 | /// A slice. | |
| 1378 | /// data is extra index of PtrSlice, which contains the ptr and len values | |
| 1379 | /// In order to use this encoding, one must ensure that the `InternPool` | |
| 1380 | /// already contains the slice type corresponding to this payload. | |
| 1381 | ptr_slice, | |
| 1341 | 1382 | /// An optional value that is non-null. |
| 1342 | 1383 | /// data is Index of the payload value. |
| 1343 | 1384 | /// In order to use this encoding, one must ensure that the `InternPool` |
| ... | ... | @@ -1672,16 +1713,45 @@ pub const PackedU64 = packed struct(u64) { |
| 1672 | 1713 | } |
| 1673 | 1714 | }; |
| 1674 | 1715 | |
| 1716 | pub const PtrVar = struct { | |
| 1717 | ty: Index, | |
| 1718 | /// If flags.is_extern == true this is `none`. | |
| 1719 | init: Index, | |
| 1720 | owner_decl: Module.Decl.Index, | |
| 1721 | /// Library name if specified. | |
| 1722 | /// For example `extern "c" var stderrp = ...` would have 'c' as library name. | |
| 1723 | lib_name: OptionalNullTerminatedString, | |
| 1724 | flags: Flags, | |
| 1725 | ||
| 1726 | pub const Flags = packed struct(u32) { | |
| 1727 | is_const: bool, | |
| 1728 | is_threadlocal: bool, | |
| 1729 | is_weak_linkage: bool, | |
| 1730 | unused: u29 = undefined, | |
| 1731 | }; | |
| 1732 | }; | |
| 1733 | ||
| 1675 | 1734 | pub const PtrDecl = struct { |
| 1676 | 1735 | ty: Index, |
| 1677 | 1736 | decl: Module.Decl.Index, |
| 1678 | 1737 | }; |
| 1679 | 1738 | |
| 1739 | pub const PtrMutDecl = struct { | |
| 1740 | ty: Index, | |
| 1741 | decl: Module.Decl.Index, | |
| 1742 | runtime_index: RuntimeIndex, | |
| 1743 | }; | |
| 1744 | ||
| 1680 | 1745 | pub const PtrInt = struct { |
| 1681 | 1746 | ty: Index, |
| 1682 | 1747 | addr: Index, |
| 1683 | 1748 | }; |
| 1684 | 1749 | |
| 1750 | pub const PtrSlice = struct { | |
| 1751 | ptr: Index, | |
| 1752 | len: Index, | |
| 1753 | }; | |
| 1754 | ||
| 1685 | 1755 | /// Trailing: Limb for every limbs_len |
| 1686 | 1756 | pub const Int = struct { |
| 1687 | 1757 | ty: Index, |
| ... | ... | @@ -1994,6 +2064,30 @@ pub fn indexToKey(ip: InternPool, index: Index) Key { |
| 1994 | 2064 | .val = payload_val, |
| 1995 | 2065 | } }; |
| 1996 | 2066 | }, |
| 2067 | .ptr_var => { | |
| 2068 | const info = ip.extraData(PtrVar, data); | |
| 2069 | return .{ .ptr = .{ | |
| 2070 | .ty = info.ty, | |
| 2071 | .addr = .{ .@"var" = .{ | |
| 2072 | .init = info.init, | |
| 2073 | .owner_decl = info.owner_decl, | |
| 2074 | .lib_name = info.lib_name, | |
| 2075 | .is_const = info.flags.is_const, | |
| 2076 | .is_threadlocal = info.flags.is_threadlocal, | |
| 2077 | .is_weak_linkage = info.flags.is_weak_linkage, | |
| 2078 | } }, | |
| 2079 | } }; | |
| 2080 | }, | |
| 2081 | .ptr_mut_decl => { | |
| 2082 | const info = ip.extraData(PtrMutDecl, data); | |
| 2083 | return .{ .ptr = .{ | |
| 2084 | .ty = info.ty, | |
| 2085 | .addr = .{ .mut_decl = .{ | |
| 2086 | .decl = info.decl, | |
| 2087 | .runtime_index = info.runtime_index, | |
| 2088 | } }, | |
| 2089 | } }; | |
| 2090 | }, | |
| 1997 | 2091 | .ptr_decl => { |
| 1998 | 2092 | const info = ip.extraData(PtrDecl, data); |
| 1999 | 2093 | return .{ .ptr = .{ |
| ... | ... | @@ -2008,6 +2102,18 @@ pub fn indexToKey(ip: InternPool, index: Index) Key { |
| 2008 | 2102 | .addr = .{ .int = info.addr }, |
| 2009 | 2103 | } }; |
| 2010 | 2104 | }, |
| 2105 | .ptr_slice => { | |
| 2106 | const info = ip.extraData(PtrSlice, data); | |
| 2107 | const ptr = ip.indexToKey(info.ptr).ptr; | |
| 2108 | var ptr_ty = ip.indexToKey(ptr.ty); | |
| 2109 | assert(ptr_ty.ptr_type.size == .Many); | |
| 2110 | ptr_ty.ptr_type.size = .Slice; | |
| 2111 | return .{ .ptr = .{ | |
| 2112 | .ty = ip.getAssumeExists(ptr_ty), | |
| 2113 | .addr = ptr.addr, | |
| 2114 | .len = info.len, | |
| 2115 | } }; | |
| 2116 | }, | |
| 2011 | 2117 | .int_u8 => .{ .int = .{ |
| 2012 | 2118 | .ty = .u8_type, |
| 2013 | 2119 | .storage = .{ .u64 = data }, |
| ... | ... | @@ -2472,31 +2578,67 @@ pub fn get(ip: *InternPool, gpa: Allocator, key: Key) Allocator.Error!Index { |
| 2472 | 2578 | |
| 2473 | 2579 | .extern_func => @panic("TODO"), |
| 2474 | 2580 | |
| 2475 | .ptr => |ptr| switch (ptr.addr) { | |
| 2476 | .decl => |decl| { | |
| 2477 | assert(ptr.ty != .none); | |
| 2478 | ip.items.appendAssumeCapacity(.{ | |
| 2479 | .tag = .ptr_decl, | |
| 2480 | .data = try ip.addExtra(gpa, PtrDecl{ | |
| 2481 | .ty = ptr.ty, | |
| 2482 | .decl = decl, | |
| 2581 | .ptr => |ptr| switch (ip.items.items(.tag)[@enumToInt(ptr.ty)]) { | |
| 2582 | .type_pointer => { | |
| 2583 | assert(ptr.len == .none); | |
| 2584 | switch (ptr.addr) { | |
| 2585 | .@"var" => |@"var"| ip.items.appendAssumeCapacity(.{ | |
| 2586 | .tag = .ptr_var, | |
| 2587 | .data = try ip.addExtra(gpa, PtrVar{ | |
| 2588 | .ty = ptr.ty, | |
| 2589 | .init = @"var".init, | |
| 2590 | .owner_decl = @"var".owner_decl, | |
| 2591 | .lib_name = @"var".lib_name, | |
| 2592 | .flags = .{ | |
| 2593 | .is_const = @"var".is_const, | |
| 2594 | .is_threadlocal = @"var".is_threadlocal, | |
| 2595 | .is_weak_linkage = @"var".is_weak_linkage, | |
| 2596 | }, | |
| 2597 | }), | |
| 2483 | 2598 | }), |
| 2484 | }); | |
| 2599 | .decl => |decl| ip.items.appendAssumeCapacity(.{ | |
| 2600 | .tag = .ptr_decl, | |
| 2601 | .data = try ip.addExtra(gpa, PtrDecl{ | |
| 2602 | .ty = ptr.ty, | |
| 2603 | .decl = decl, | |
| 2604 | }), | |
| 2605 | }), | |
| 2606 | .mut_decl => |mut_decl| ip.items.appendAssumeCapacity(.{ | |
| 2607 | .tag = .ptr_mut_decl, | |
| 2608 | .data = try ip.addExtra(gpa, PtrMutDecl{ | |
| 2609 | .ty = ptr.ty, | |
| 2610 | .decl = mut_decl.decl, | |
| 2611 | .runtime_index = mut_decl.runtime_index, | |
| 2612 | }), | |
| 2613 | }), | |
| 2614 | .int => |int| ip.items.appendAssumeCapacity(.{ | |
| 2615 | .tag = .ptr_int, | |
| 2616 | .data = try ip.addExtra(gpa, PtrInt{ | |
| 2617 | .ty = ptr.ty, | |
| 2618 | .addr = int, | |
| 2619 | }), | |
| 2620 | }), | |
| 2621 | } | |
| 2485 | 2622 | }, |
| 2486 | .int => |int| { | |
| 2487 | assert(ptr.ty != .none); | |
| 2623 | .type_slice => { | |
| 2624 | assert(ptr.len != .none); | |
| 2625 | var new_key = key; | |
| 2626 | new_key.ptr.ty = @intToEnum(Index, ip.items.items(.data)[@enumToInt(ptr.ty)]); | |
| 2627 | new_key.ptr.len = .none; | |
| 2628 | const ptr_index = try get(ip, gpa, new_key); | |
| 2629 | try ip.items.ensureUnusedCapacity(gpa, 1); | |
| 2488 | 2630 | ip.items.appendAssumeCapacity(.{ |
| 2489 | .tag = .ptr_int, | |
| 2490 | .data = try ip.addExtra(gpa, PtrInt{ | |
| 2491 | .ty = ptr.ty, | |
| 2492 | .addr = int, | |
| 2631 | .tag = .ptr_slice, | |
| 2632 | .data = try ip.addExtra(gpa, PtrSlice{ | |
| 2633 | .ptr = ptr_index, | |
| 2634 | .len = ptr.len, | |
| 2493 | 2635 | }), |
| 2494 | 2636 | }); |
| 2495 | 2637 | }, |
| 2638 | else => unreachable, | |
| 2496 | 2639 | }, |
| 2497 | 2640 | |
| 2498 | 2641 | .opt => |opt| { |
| 2499 | assert(opt.ty != .none); | |
| 2500 | 2642 | assert(ip.isOptionalType(opt.ty)); |
| 2501 | 2643 | ip.items.appendAssumeCapacity(if (opt.val == .none) .{ |
| 2502 | 2644 | .tag = .opt_null, |
| ... | ... | @@ -3087,11 +3229,15 @@ fn addExtraAssumeCapacity(ip: *InternPool, extra: anytype) u32 { |
| 3087 | 3229 | Module.Namespace.OptionalIndex => @enumToInt(@field(extra, field.name)), |
| 3088 | 3230 | MapIndex => @enumToInt(@field(extra, field.name)), |
| 3089 | 3231 | OptionalMapIndex => @enumToInt(@field(extra, field.name)), |
| 3232 | RuntimeIndex => @enumToInt(@field(extra, field.name)), | |
| 3233 | NullTerminatedString => @enumToInt(@field(extra, field.name)), | |
| 3234 | OptionalNullTerminatedString => @enumToInt(@field(extra, field.name)), | |
| 3090 | 3235 | i32 => @bitCast(u32, @field(extra, field.name)), |
| 3091 | 3236 | Pointer.Flags => @bitCast(u32, @field(extra, field.name)), |
| 3092 | 3237 | TypeFunction.Flags => @bitCast(u32, @field(extra, field.name)), |
| 3093 | 3238 | Pointer.PackedOffset => @bitCast(u32, @field(extra, field.name)), |
| 3094 | 3239 | Pointer.VectorIndex => @enumToInt(@field(extra, field.name)), |
| 3240 | PtrVar.Flags => @bitCast(u32, @field(extra, field.name)), | |
| 3095 | 3241 | else => @compileError("bad field type: " ++ @typeName(field.type)), |
| 3096 | 3242 | }); |
| 3097 | 3243 | } |
| ... | ... | @@ -3149,11 +3295,15 @@ fn extraDataTrail(ip: InternPool, comptime T: type, index: usize) struct { data: |
| 3149 | 3295 | Module.Namespace.OptionalIndex => @intToEnum(Module.Namespace.OptionalIndex, int32), |
| 3150 | 3296 | MapIndex => @intToEnum(MapIndex, int32), |
| 3151 | 3297 | OptionalMapIndex => @intToEnum(OptionalMapIndex, int32), |
| 3298 | RuntimeIndex => @intToEnum(RuntimeIndex, int32), | |
| 3299 | NullTerminatedString => @intToEnum(NullTerminatedString, int32), | |
| 3300 | OptionalNullTerminatedString => @intToEnum(OptionalNullTerminatedString, int32), | |
| 3152 | 3301 | i32 => @bitCast(i32, int32), |
| 3153 | 3302 | Pointer.Flags => @bitCast(Pointer.Flags, int32), |
| 3154 | 3303 | TypeFunction.Flags => @bitCast(TypeFunction.Flags, int32), |
| 3155 | 3304 | Pointer.PackedOffset => @bitCast(Pointer.PackedOffset, int32), |
| 3156 | 3305 | Pointer.VectorIndex => @intToEnum(Pointer.VectorIndex, int32), |
| 3306 | PtrVar.Flags => @bitCast(PtrVar.Flags, int32), | |
| 3157 | 3307 | else => @compileError("bad field type: " ++ @typeName(field.type)), |
| 3158 | 3308 | }; |
| 3159 | 3309 | } |
| ... | ... | @@ -3274,7 +3424,7 @@ pub fn childType(ip: InternPool, i: Index) Index { |
| 3274 | 3424 | }; |
| 3275 | 3425 | } |
| 3276 | 3426 | |
| 3277 | /// Given a slice type, returns the type of the pointer field. | |
| 3427 | /// Given a slice type, returns the type of the ptr field. | |
| 3278 | 3428 | pub fn slicePtrType(ip: InternPool, i: Index) Index { |
| 3279 | 3429 | switch (i) { |
| 3280 | 3430 | .const_slice_u8_type => return .manyptr_const_u8_type, |
| ... | ... | @@ -3288,10 +3438,29 @@ pub fn slicePtrType(ip: InternPool, i: Index) Index { |
| 3288 | 3438 | } |
| 3289 | 3439 | } |
| 3290 | 3440 | |
| 3441 | /// Given a slice value, returns the value of the ptr field. | |
| 3442 | pub fn slicePtr(ip: InternPool, i: Index) Index { | |
| 3443 | const item = ip.items.get(@enumToInt(i)); | |
| 3444 | switch (item.tag) { | |
| 3445 | .ptr_slice => return ip.extraData(PtrSlice, item.data).ptr, | |
| 3446 | else => unreachable, // not a slice value | |
| 3447 | } | |
| 3448 | } | |
| 3449 | ||
| 3450 | /// Given a slice value, returns the value of the len field. | |
| 3451 | pub fn sliceLen(ip: InternPool, i: Index) Index { | |
| 3452 | const item = ip.items.get(@enumToInt(i)); | |
| 3453 | switch (item.tag) { | |
| 3454 | .ptr_slice => return ip.extraData(PtrSlice, item.data).len, | |
| 3455 | else => unreachable, // not a slice value | |
| 3456 | } | |
| 3457 | } | |
| 3458 | ||
| 3291 | 3459 | /// Given an existing value, returns the same value but with the supplied type. |
| 3292 | 3460 | /// Only some combinations are allowed: |
| 3293 | 3461 | /// * int <=> int |
| 3294 | 3462 | /// * int <=> enum |
| 3463 | /// * ptr <=> ptr | |
| 3295 | 3464 | pub fn getCoerced(ip: *InternPool, gpa: Allocator, val: Index, new_ty: Index) Allocator.Error!Index { |
| 3296 | 3465 | switch (ip.indexToKey(val)) { |
| 3297 | 3466 | .int => |int| switch (ip.indexToKey(new_ty)) { |
| ... | ... | @@ -3305,6 +3474,13 @@ pub fn getCoerced(ip: *InternPool, gpa: Allocator, val: Index, new_ty: Index) Al |
| 3305 | 3474 | // Assume new_ty is an integer type. |
| 3306 | 3475 | return getCoercedInts(ip, gpa, ip.indexToKey(enum_tag.int).int, new_ty); |
| 3307 | 3476 | }, |
| 3477 | .ptr => |ptr| switch (ip.indexToKey(new_ty)) { | |
| 3478 | .ptr_type => return ip.get(gpa, .{ .ptr = .{ | |
| 3479 | .ty = new_ty, | |
| 3480 | .addr = ptr.addr, | |
| 3481 | } }), | |
| 3482 | else => unreachable, | |
| 3483 | }, | |
| 3308 | 3484 | else => unreachable, |
| 3309 | 3485 | } |
| 3310 | 3486 | } |
| ... | ... | @@ -3380,6 +3556,15 @@ pub fn indexToInferredErrorSetType(ip: InternPool, val: Index) Module.Fn.Inferre |
| 3380 | 3556 | return @intToEnum(Module.Fn.InferredErrorSet.Index, datas[@enumToInt(val)]).toOptional(); |
| 3381 | 3557 | } |
| 3382 | 3558 | |
| 3559 | pub fn isPointerType(ip: InternPool, ty: Index) bool { | |
| 3560 | const tags = ip.items.items(.tag); | |
| 3561 | if (ty == .none) return false; | |
| 3562 | return switch (tags[@enumToInt(ty)]) { | |
| 3563 | .type_pointer, .type_slice => true, | |
| 3564 | else => false, | |
| 3565 | }; | |
| 3566 | } | |
| 3567 | ||
| 3383 | 3568 | pub fn isOptionalType(ip: InternPool, ty: Index) bool { |
| 3384 | 3569 | const tags = ip.items.items(.tag); |
| 3385 | 3570 | if (ty == .none) return false; |
| ... | ... | @@ -3485,8 +3670,11 @@ fn dumpFallible(ip: InternPool, arena: Allocator) anyerror!void { |
| 3485 | 3670 | .undef => 0, |
| 3486 | 3671 | .simple_type => 0, |
| 3487 | 3672 | .simple_value => 0, |
| 3673 | .ptr_var => @sizeOf(PtrVar), | |
| 3488 | 3674 | .ptr_decl => @sizeOf(PtrDecl), |
| 3675 | .ptr_mut_decl => @sizeOf(PtrMutDecl), | |
| 3489 | 3676 | .ptr_int => @sizeOf(PtrInt), |
| 3677 | .ptr_slice => @sizeOf(PtrSlice), | |
| 3490 | 3678 | .opt_null => 0, |
| 3491 | 3679 | .opt_payload => 0, |
| 3492 | 3680 | .int_u8 => 0, |
src/Module.zig+1-1| ... | ... | @@ -5762,7 +5762,7 @@ pub fn analyzeFnBody(mod: *Module, func: *Fn, arena: Allocator) SemaError!Air { |
| 5762 | 5762 | // Crucially, this happens *after* we set the function state to success above, |
| 5763 | 5763 | // so that dependencies on the function body will now be satisfied rather than |
| 5764 | 5764 | // result in circular dependency errors. |
| 5765 | sema.resolveFnTypes(fn_ty_info) catch |err| switch (err) { | |
| 5765 | sema.resolveFnTypes(mod.typeToFunc(fn_ty).?) catch |err| switch (err) { | |
| 5766 | 5766 | error.NeededSourceLocation => unreachable, |
| 5767 | 5767 | error.GenericPoison => unreachable, |
| 5768 | 5768 | error.ComptimeReturn => unreachable, |
src/Sema.zig+73-20| ... | ... | @@ -13072,25 +13072,32 @@ fn zirArrayMul(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Ai |
| 13072 | 13072 | // as zero-filling a byte array. |
| 13073 | 13073 | if (lhs_len == 1) { |
| 13074 | 13074 | const elem_val = try lhs_sub_val.elemValue(mod, 0); |
| 13075 | break :v try Value.Tag.repeated.create(sema.arena, elem_val); | |
| 13075 | break :v try mod.intern(.{ .aggregate = .{ | |
| 13076 | .ty = result_ty.ip_index, | |
| 13077 | .storage = .{ .repeated_elem = elem_val.ip_index }, | |
| 13078 | } }); | |
| 13076 | 13079 | } |
| 13077 | 13080 | |
| 13078 | const element_vals = try sema.arena.alloc(Value, final_len_including_sent); | |
| 13081 | const element_vals = try sema.arena.alloc(InternPool.Index, final_len_including_sent); | |
| 13079 | 13082 | var elem_i: usize = 0; |
| 13080 | 13083 | while (elem_i < result_len) { |
| 13081 | 13084 | var lhs_i: usize = 0; |
| 13082 | 13085 | while (lhs_i < lhs_len) : (lhs_i += 1) { |
| 13083 | 13086 | const elem_val = try lhs_sub_val.elemValue(mod, lhs_i); |
| 13084 | element_vals[elem_i] = elem_val; | |
| 13087 | assert(elem_val.ip_index != .none); | |
| 13088 | element_vals[elem_i] = elem_val.ip_index; | |
| 13085 | 13089 | elem_i += 1; |
| 13086 | 13090 | } |
| 13087 | 13091 | } |
| 13088 | 13092 | if (lhs_info.sentinel) |sent_val| { |
| 13089 | element_vals[result_len] = sent_val; | |
| 13093 | element_vals[result_len] = sent_val.ip_index; | |
| 13090 | 13094 | } |
| 13091 | break :v try Value.Tag.aggregate.create(sema.arena, element_vals); | |
| 13095 | break :v try mod.intern(.{ .aggregate = .{ | |
| 13096 | .ty = result_ty.ip_index, | |
| 13097 | .storage = .{ .elems = element_vals }, | |
| 13098 | } }); | |
| 13092 | 13099 | }; |
| 13093 | return sema.addConstantMaybeRef(block, result_ty, val, ptr_addrspace != null); | |
| 13100 | return sema.addConstantMaybeRef(block, result_ty, val.toValue(), ptr_addrspace != null); | |
| 13094 | 13101 | } |
| 13095 | 13102 | |
| 13096 | 13103 | try sema.requireRuntimeBlock(block, src, lhs_src); |
| ... | ... | @@ -18111,12 +18118,16 @@ fn finishStructInit( |
| 18111 | 18118 | } else null; |
| 18112 | 18119 | |
| 18113 | 18120 | const runtime_index = opt_runtime_index orelse { |
| 18114 | const values = try sema.arena.alloc(Value, field_inits.len); | |
| 18115 | for (field_inits, 0..) |field_init, i| { | |
| 18116 | values[i] = (sema.resolveMaybeUndefVal(field_init) catch unreachable).?; | |
| 18117 | } | |
| 18118 | const struct_val = try Value.Tag.aggregate.create(sema.arena, values); | |
| 18119 | return sema.addConstantMaybeRef(block, struct_ty, struct_val, is_ref); | |
| 18121 | const elems = try sema.arena.alloc(InternPool.Index, field_inits.len); | |
| 18122 | for (elems, field_inits, 0..) |*elem, field_init, field_i| { | |
| 18123 | elem.* = try (sema.resolveMaybeUndefVal(field_init) catch unreachable).? | |
| 18124 | .intern(struct_ty.structFieldType(field_i, mod), mod); | |
| 18125 | } | |
| 18126 | const struct_val = try mod.intern(.{ .aggregate = .{ | |
| 18127 | .ty = struct_ty.ip_index, | |
| 18128 | .storage = .{ .elems = elems }, | |
| 18129 | } }); | |
| 18130 | return sema.addConstantMaybeRef(block, struct_ty, struct_val.toValue(), is_ref); | |
| 18120 | 18131 | }; |
| 18121 | 18132 | |
| 18122 | 18133 | if (is_ref) { |
| ... | ... | @@ -18195,21 +18206,20 @@ fn zirStructInitAnon( |
| 18195 | 18206 | |
| 18196 | 18207 | const init = try sema.resolveInst(item.data.init); |
| 18197 | 18208 | field_ty.* = sema.typeOf(init).ip_index; |
| 18198 | if (types[i].toType().zigTypeTag(mod) == .Opaque) { | |
| 18209 | if (field_ty.toType().zigTypeTag(mod) == .Opaque) { | |
| 18199 | 18210 | const msg = msg: { |
| 18200 | 18211 | const decl = sema.mod.declPtr(block.src_decl); |
| 18201 | 18212 | const field_src = mod.initSrc(src.node_offset.x, decl, i); |
| 18202 | 18213 | const msg = try sema.errMsg(block, field_src, "opaque types have unknown size and therefore cannot be directly embedded in structs", .{}); |
| 18203 | 18214 | errdefer msg.destroy(sema.gpa); |
| 18204 | 18215 | |
| 18205 | try sema.addDeclaredHereNote(msg, types[i].toType()); | |
| 18216 | try sema.addDeclaredHereNote(msg, field_ty.toType()); | |
| 18206 | 18217 | break :msg msg; |
| 18207 | 18218 | }; |
| 18208 | 18219 | return sema.failWithOwnedErrorMsg(msg); |
| 18209 | 18220 | } |
| 18210 | 18221 | if (try sema.resolveMaybeUndefVal(init)) |init_val| { |
| 18211 | assert(init_val.ip_index != .none); | |
| 18212 | values[i] = init_val.ip_index; | |
| 18222 | values[i] = try init_val.intern(field_ty.toType(), mod); | |
| 18213 | 18223 | } else { |
| 18214 | 18224 | values[i] = .none; |
| 18215 | 18225 | runtime_index = i; |
| ... | ... | @@ -24891,9 +24901,7 @@ fn structFieldVal( |
| 24891 | 24901 | if ((try sema.typeHasOnePossibleValue(field.ty))) |opv| { |
| 24892 | 24902 | return sema.addConstant(field.ty, opv); |
| 24893 | 24903 | } |
| 24894 | ||
| 24895 | const field_values = struct_val.castTag(.aggregate).?.data; | |
| 24896 | return sema.addConstant(field.ty, field_values[field_index]); | |
| 24904 | return sema.addConstant(field.ty, try struct_val.fieldValue(field.ty, mod, field_index)); | |
| 24897 | 24905 | } |
| 24898 | 24906 | |
| 24899 | 24907 | try sema.requireRuntimeBlock(block, src, null); |
| ... | ... | @@ -27925,7 +27933,24 @@ fn beginComptimePtrMutation( |
| 27925 | 27933 | ptr_elem_ty, |
| 27926 | 27934 | parent.decl_ref_mut, |
| 27927 | 27935 | ), |
| 27936 | .repeated => { | |
| 27937 | const arena = parent.beginArena(sema.mod); | |
| 27938 | defer parent.finishArena(sema.mod); | |
| 27939 | ||
| 27940 | const elems = try arena.alloc(Value, parent.ty.structFieldCount(mod)); | |
| 27941 | @memset(elems, val_ptr.castTag(.repeated).?.data); | |
| 27942 | val_ptr.* = try Value.Tag.aggregate.create(arena, elems); | |
| 27928 | 27943 | |
| 27944 | return beginComptimePtrMutationInner( | |
| 27945 | sema, | |
| 27946 | block, | |
| 27947 | src, | |
| 27948 | parent.ty.structFieldType(field_index, mod), | |
| 27949 | &elems[field_index], | |
| 27950 | ptr_elem_ty, | |
| 27951 | parent.decl_ref_mut, | |
| 27952 | ); | |
| 27953 | }, | |
| 27929 | 27954 | .@"union" => { |
| 27930 | 27955 | // We need to set the active field of the union. |
| 27931 | 27956 | const union_tag_ty = field_ptr.container_ty.unionTagTypeHypothetical(mod); |
| ... | ... | @@ -28107,6 +28132,13 @@ fn beginComptimePtrMutationInner( |
| 28107 | 28132 | const mod = sema.mod; |
| 28108 | 28133 | const target = mod.getTarget(); |
| 28109 | 28134 | const coerce_ok = (try sema.coerceInMemoryAllowed(block, ptr_elem_ty, decl_ty, true, target, src, src)) == .ok; |
| 28135 | ||
| 28136 | const decl = mod.declPtr(decl_ref_mut.decl_index); | |
| 28137 | var decl_arena: std.heap.ArenaAllocator = undefined; | |
| 28138 | const allocator = decl.value_arena.?.acquire(mod.gpa, &decl_arena); | |
| 28139 | defer decl.value_arena.?.release(&decl_arena); | |
| 28140 | decl_val.* = try decl_val.unintern(allocator, mod); | |
| 28141 | ||
| 28110 | 28142 | if (coerce_ok) { |
| 28111 | 28143 | return ComptimePtrMutationKit{ |
| 28112 | 28144 | .decl_ref_mut = decl_ref_mut, |
| ... | ... | @@ -28412,6 +28444,27 @@ fn beginComptimePtrLoad( |
| 28412 | 28444 | }, |
| 28413 | 28445 | else => switch (mod.intern_pool.indexToKey(ptr_val.ip_index)) { |
| 28414 | 28446 | .int => return error.RuntimeLoad, |
| 28447 | .ptr => |ptr| switch (ptr.addr) { | |
| 28448 | .@"var", .int => return error.RuntimeLoad, | |
| 28449 | .decl, .mut_decl => blk: { | |
| 28450 | const decl_index = switch (ptr.addr) { | |
| 28451 | .decl => |decl| decl, | |
| 28452 | .mut_decl => |mut_decl| mut_decl.decl, | |
| 28453 | else => unreachable, | |
| 28454 | }; | |
| 28455 | const decl = mod.declPtr(decl_index); | |
| 28456 | const decl_tv = try decl.typedValue(); | |
| 28457 | if (decl_tv.val.tagIsVariable()) return error.RuntimeLoad; | |
| 28458 | ||
| 28459 | const layout_defined = decl.ty.hasWellDefinedLayout(mod); | |
| 28460 | break :blk ComptimePtrLoadKit{ | |
| 28461 | .parent = if (layout_defined) .{ .tv = decl_tv, .byte_offset = 0 } else null, | |
| 28462 | .pointee = decl_tv, | |
| 28463 | .is_mutable = false, | |
| 28464 | .ty_without_well_defined_layout = if (!layout_defined) decl.ty else null, | |
| 28465 | }; | |
| 28466 | }, | |
| 28467 | }, | |
| 28415 | 28468 | else => unreachable, |
| 28416 | 28469 | }, |
| 28417 | 28470 | }; |
| ... | ... | @@ -29425,7 +29478,7 @@ fn analyzeSlicePtr( |
| 29425 | 29478 | const result_ty = slice_ty.slicePtrFieldType(mod); |
| 29426 | 29479 | if (try sema.resolveMaybeUndefVal(slice)) |val| { |
| 29427 | 29480 | if (val.isUndef(mod)) return sema.addConstUndef(result_ty); |
| 29428 | return sema.addConstant(result_ty, val.slicePtr()); | |
| 29481 | return sema.addConstant(result_ty, val.slicePtr(mod)); | |
| 29429 | 29482 | } |
| 29430 | 29483 | try sema.requireRuntimeBlock(block, slice_src, null); |
| 29431 | 29484 | return block.addTyOp(.slice_ptr, result_ty, slice); |
src/codegen/c.zig+1-1| ... | ... | @@ -566,7 +566,7 @@ pub const DeclGen = struct { |
| 566 | 566 | try writer.writeAll("){ .ptr = "); |
| 567 | 567 | } |
| 568 | 568 | |
| 569 | try dg.renderValue(writer, ty.slicePtrFieldType(mod), val.slicePtr(), .Initializer); | |
| 569 | try dg.renderValue(writer, ty.slicePtrFieldType(mod), val.slicePtr(mod), .Initializer); | |
| 570 | 570 | |
| 571 | 571 | const len_val = try mod.intValue(Type.usize, val.sliceLen(mod)); |
| 572 | 572 |
src/codegen/llvm.zig+231-122| ... | ... | @@ -3363,125 +3363,223 @@ pub const DeclGen = struct { |
| 3363 | 3363 | }, |
| 3364 | 3364 | else => switch (mod.intern_pool.indexToKey(tv.val.ip_index)) { |
| 3365 | 3365 | .int => |int| return lowerIntAsPtr(dg, int), |
| 3366 | .ptr => |ptr| { | |
| 3367 | const ptr_val = switch (ptr.addr) { | |
| 3368 | .@"var" => |@"var"| ptr: { | |
| 3369 | const decl = dg.module.declPtr(@"var".owner_decl); | |
| 3370 | dg.module.markDeclAlive(decl); | |
| 3371 | ||
| 3372 | const llvm_wanted_addrspace = toLlvmAddressSpace(decl.@"addrspace", target); | |
| 3373 | const llvm_actual_addrspace = toLlvmGlobalAddressSpace(decl.@"addrspace", target); | |
| 3374 | ||
| 3375 | const val = try dg.resolveGlobalDecl(@"var".owner_decl); | |
| 3376 | const addrspace_casted_ptr = if (llvm_actual_addrspace != llvm_wanted_addrspace) | |
| 3377 | val.constAddrSpaceCast(dg.context.pointerType(llvm_wanted_addrspace)) | |
| 3378 | else | |
| 3379 | val; | |
| 3380 | break :ptr addrspace_casted_ptr; | |
| 3381 | }, | |
| 3382 | .decl => |decl| try lowerDeclRefValue(dg, tv, decl), | |
| 3383 | .mut_decl => |mut_decl| try lowerDeclRefValue(dg, tv, mut_decl.decl), | |
| 3384 | .int => |int| lowerIntAsPtr(dg, mod.intern_pool.indexToKey(int).int), | |
| 3385 | }; | |
| 3386 | switch (ptr.len) { | |
| 3387 | .none => return ptr_val, | |
| 3388 | else => { | |
| 3389 | const fields: [2]*llvm.Value = .{ | |
| 3390 | ptr_val, | |
| 3391 | try dg.lowerValue(.{ .ty = Type.usize, .val = ptr.len.toValue() }), | |
| 3392 | }; | |
| 3393 | return dg.context.constStruct(&fields, fields.len, .False); | |
| 3394 | }, | |
| 3395 | } | |
| 3396 | }, | |
| 3366 | 3397 | else => unreachable, |
| 3367 | 3398 | }, |
| 3368 | 3399 | }, |
| 3369 | .Array => switch (tv.val.tag()) { | |
| 3370 | .bytes => { | |
| 3371 | const bytes = tv.val.castTag(.bytes).?.data; | |
| 3372 | return dg.context.constString( | |
| 3373 | bytes.ptr, | |
| 3374 | @intCast(c_uint, tv.ty.arrayLenIncludingSentinel(mod)), | |
| 3375 | .True, // Don't null terminate. Bytes has the sentinel, if any. | |
| 3376 | ); | |
| 3377 | }, | |
| 3378 | .str_lit => { | |
| 3379 | const str_lit = tv.val.castTag(.str_lit).?.data; | |
| 3380 | const bytes = dg.module.string_literal_bytes.items[str_lit.index..][0..str_lit.len]; | |
| 3381 | if (tv.ty.sentinel(mod)) |sent_val| { | |
| 3382 | const byte = @intCast(u8, sent_val.toUnsignedInt(mod)); | |
| 3383 | if (byte == 0 and bytes.len > 0) { | |
| 3400 | .Array => switch (tv.val.ip_index) { | |
| 3401 | .none => switch (tv.val.tag()) { | |
| 3402 | .bytes => { | |
| 3403 | const bytes = tv.val.castTag(.bytes).?.data; | |
| 3404 | return dg.context.constString( | |
| 3405 | bytes.ptr, | |
| 3406 | @intCast(c_uint, tv.ty.arrayLenIncludingSentinel(mod)), | |
| 3407 | .True, // Don't null terminate. Bytes has the sentinel, if any. | |
| 3408 | ); | |
| 3409 | }, | |
| 3410 | .str_lit => { | |
| 3411 | const str_lit = tv.val.castTag(.str_lit).?.data; | |
| 3412 | const bytes = dg.module.string_literal_bytes.items[str_lit.index..][0..str_lit.len]; | |
| 3413 | if (tv.ty.sentinel(mod)) |sent_val| { | |
| 3414 | const byte = @intCast(u8, sent_val.toUnsignedInt(mod)); | |
| 3415 | if (byte == 0 and bytes.len > 0) { | |
| 3416 | return dg.context.constString( | |
| 3417 | bytes.ptr, | |
| 3418 | @intCast(c_uint, bytes.len), | |
| 3419 | .False, // Yes, null terminate. | |
| 3420 | ); | |
| 3421 | } | |
| 3422 | var array = std.ArrayList(u8).init(dg.gpa); | |
| 3423 | defer array.deinit(); | |
| 3424 | try array.ensureUnusedCapacity(bytes.len + 1); | |
| 3425 | array.appendSliceAssumeCapacity(bytes); | |
| 3426 | array.appendAssumeCapacity(byte); | |
| 3427 | return dg.context.constString( | |
| 3428 | array.items.ptr, | |
| 3429 | @intCast(c_uint, array.items.len), | |
| 3430 | .True, // Don't null terminate. | |
| 3431 | ); | |
| 3432 | } else { | |
| 3384 | 3433 | return dg.context.constString( |
| 3385 | 3434 | bytes.ptr, |
| 3386 | 3435 | @intCast(c_uint, bytes.len), |
| 3387 | .False, // Yes, null terminate. | |
| 3436 | .True, // Don't null terminate. `bytes` has the sentinel, if any. | |
| 3388 | 3437 | ); |
| 3389 | 3438 | } |
| 3390 | var array = std.ArrayList(u8).init(dg.gpa); | |
| 3391 | defer array.deinit(); | |
| 3392 | try array.ensureUnusedCapacity(bytes.len + 1); | |
| 3393 | array.appendSliceAssumeCapacity(bytes); | |
| 3394 | array.appendAssumeCapacity(byte); | |
| 3395 | return dg.context.constString( | |
| 3396 | array.items.ptr, | |
| 3397 | @intCast(c_uint, array.items.len), | |
| 3398 | .True, // Don't null terminate. | |
| 3399 | ); | |
| 3400 | } else { | |
| 3401 | return dg.context.constString( | |
| 3402 | bytes.ptr, | |
| 3403 | @intCast(c_uint, bytes.len), | |
| 3404 | .True, // Don't null terminate. `bytes` has the sentinel, if any. | |
| 3405 | ); | |
| 3406 | } | |
| 3407 | }, | |
| 3408 | .aggregate => { | |
| 3409 | const elem_vals = tv.val.castTag(.aggregate).?.data; | |
| 3410 | const elem_ty = tv.ty.childType(mod); | |
| 3411 | const gpa = dg.gpa; | |
| 3412 | const len = @intCast(usize, tv.ty.arrayLenIncludingSentinel(mod)); | |
| 3413 | const llvm_elems = try gpa.alloc(*llvm.Value, len); | |
| 3414 | defer gpa.free(llvm_elems); | |
| 3415 | var need_unnamed = false; | |
| 3416 | for (elem_vals[0..len], 0..) |elem_val, i| { | |
| 3417 | llvm_elems[i] = try dg.lowerValue(.{ .ty = elem_ty, .val = elem_val }); | |
| 3418 | need_unnamed = need_unnamed or dg.isUnnamedType(elem_ty, llvm_elems[i]); | |
| 3419 | } | |
| 3420 | if (need_unnamed) { | |
| 3421 | return dg.context.constStruct( | |
| 3422 | llvm_elems.ptr, | |
| 3423 | @intCast(c_uint, llvm_elems.len), | |
| 3424 | .True, | |
| 3425 | ); | |
| 3426 | } else { | |
| 3427 | const llvm_elem_ty = try dg.lowerType(elem_ty); | |
| 3428 | return llvm_elem_ty.constArray( | |
| 3429 | llvm_elems.ptr, | |
| 3430 | @intCast(c_uint, llvm_elems.len), | |
| 3431 | ); | |
| 3432 | } | |
| 3433 | }, | |
| 3434 | .repeated => { | |
| 3435 | const val = tv.val.castTag(.repeated).?.data; | |
| 3436 | const elem_ty = tv.ty.childType(mod); | |
| 3437 | const sentinel = tv.ty.sentinel(mod); | |
| 3438 | const len = @intCast(usize, tv.ty.arrayLen(mod)); | |
| 3439 | const len_including_sent = len + @boolToInt(sentinel != null); | |
| 3440 | const gpa = dg.gpa; | |
| 3441 | const llvm_elems = try gpa.alloc(*llvm.Value, len_including_sent); | |
| 3442 | defer gpa.free(llvm_elems); | |
| 3443 | ||
| 3444 | var need_unnamed = false; | |
| 3445 | if (len != 0) { | |
| 3446 | for (llvm_elems[0..len]) |*elem| { | |
| 3447 | elem.* = try dg.lowerValue(.{ .ty = elem_ty, .val = val }); | |
| 3439 | }, | |
| 3440 | .aggregate => { | |
| 3441 | const elem_vals = tv.val.castTag(.aggregate).?.data; | |
| 3442 | const elem_ty = tv.ty.childType(mod); | |
| 3443 | const gpa = dg.gpa; | |
| 3444 | const len = @intCast(usize, tv.ty.arrayLenIncludingSentinel(mod)); | |
| 3445 | const llvm_elems = try gpa.alloc(*llvm.Value, len); | |
| 3446 | defer gpa.free(llvm_elems); | |
| 3447 | var need_unnamed = false; | |
| 3448 | for (elem_vals[0..len], 0..) |elem_val, i| { | |
| 3449 | llvm_elems[i] = try dg.lowerValue(.{ .ty = elem_ty, .val = elem_val }); | |
| 3450 | need_unnamed = need_unnamed or dg.isUnnamedType(elem_ty, llvm_elems[i]); | |
| 3448 | 3451 | } |
| 3449 | need_unnamed = need_unnamed or dg.isUnnamedType(elem_ty, llvm_elems[0]); | |
| 3450 | } | |
| 3452 | if (need_unnamed) { | |
| 3453 | return dg.context.constStruct( | |
| 3454 | llvm_elems.ptr, | |
| 3455 | @intCast(c_uint, llvm_elems.len), | |
| 3456 | .True, | |
| 3457 | ); | |
| 3458 | } else { | |
| 3459 | const llvm_elem_ty = try dg.lowerType(elem_ty); | |
| 3460 | return llvm_elem_ty.constArray( | |
| 3461 | llvm_elems.ptr, | |
| 3462 | @intCast(c_uint, llvm_elems.len), | |
| 3463 | ); | |
| 3464 | } | |
| 3465 | }, | |
| 3466 | .repeated => { | |
| 3467 | const val = tv.val.castTag(.repeated).?.data; | |
| 3468 | const elem_ty = tv.ty.childType(mod); | |
| 3469 | const sentinel = tv.ty.sentinel(mod); | |
| 3470 | const len = @intCast(usize, tv.ty.arrayLen(mod)); | |
| 3471 | const len_including_sent = len + @boolToInt(sentinel != null); | |
| 3472 | const gpa = dg.gpa; | |
| 3473 | const llvm_elems = try gpa.alloc(*llvm.Value, len_including_sent); | |
| 3474 | defer gpa.free(llvm_elems); | |
| 3451 | 3475 | |
| 3452 | if (sentinel) |sent| { | |
| 3453 | llvm_elems[len] = try dg.lowerValue(.{ .ty = elem_ty, .val = sent }); | |
| 3454 | need_unnamed = need_unnamed or dg.isUnnamedType(elem_ty, llvm_elems[len]); | |
| 3455 | } | |
| 3476 | var need_unnamed = false; | |
| 3477 | if (len != 0) { | |
| 3478 | for (llvm_elems[0..len]) |*elem| { | |
| 3479 | elem.* = try dg.lowerValue(.{ .ty = elem_ty, .val = val }); | |
| 3480 | } | |
| 3481 | need_unnamed = need_unnamed or dg.isUnnamedType(elem_ty, llvm_elems[0]); | |
| 3482 | } | |
| 3456 | 3483 | |
| 3457 | if (need_unnamed) { | |
| 3458 | return dg.context.constStruct( | |
| 3459 | llvm_elems.ptr, | |
| 3460 | @intCast(c_uint, llvm_elems.len), | |
| 3461 | .True, | |
| 3462 | ); | |
| 3463 | } else { | |
| 3464 | const llvm_elem_ty = try dg.lowerType(elem_ty); | |
| 3465 | return llvm_elem_ty.constArray( | |
| 3466 | llvm_elems.ptr, | |
| 3467 | @intCast(c_uint, llvm_elems.len), | |
| 3468 | ); | |
| 3469 | } | |
| 3484 | if (sentinel) |sent| { | |
| 3485 | llvm_elems[len] = try dg.lowerValue(.{ .ty = elem_ty, .val = sent }); | |
| 3486 | need_unnamed = need_unnamed or dg.isUnnamedType(elem_ty, llvm_elems[len]); | |
| 3487 | } | |
| 3488 | ||
| 3489 | if (need_unnamed) { | |
| 3490 | return dg.context.constStruct( | |
| 3491 | llvm_elems.ptr, | |
| 3492 | @intCast(c_uint, llvm_elems.len), | |
| 3493 | .True, | |
| 3494 | ); | |
| 3495 | } else { | |
| 3496 | const llvm_elem_ty = try dg.lowerType(elem_ty); | |
| 3497 | return llvm_elem_ty.constArray( | |
| 3498 | llvm_elems.ptr, | |
| 3499 | @intCast(c_uint, llvm_elems.len), | |
| 3500 | ); | |
| 3501 | } | |
| 3502 | }, | |
| 3503 | .empty_array_sentinel => { | |
| 3504 | const elem_ty = tv.ty.childType(mod); | |
| 3505 | const sent_val = tv.ty.sentinel(mod).?; | |
| 3506 | const sentinel = try dg.lowerValue(.{ .ty = elem_ty, .val = sent_val }); | |
| 3507 | const llvm_elems: [1]*llvm.Value = .{sentinel}; | |
| 3508 | const need_unnamed = dg.isUnnamedType(elem_ty, llvm_elems[0]); | |
| 3509 | if (need_unnamed) { | |
| 3510 | return dg.context.constStruct(&llvm_elems, llvm_elems.len, .True); | |
| 3511 | } else { | |
| 3512 | const llvm_elem_ty = try dg.lowerType(elem_ty); | |
| 3513 | return llvm_elem_ty.constArray(&llvm_elems, llvm_elems.len); | |
| 3514 | } | |
| 3515 | }, | |
| 3516 | else => unreachable, | |
| 3470 | 3517 | }, |
| 3471 | .empty_array_sentinel => { | |
| 3472 | const elem_ty = tv.ty.childType(mod); | |
| 3473 | const sent_val = tv.ty.sentinel(mod).?; | |
| 3474 | const sentinel = try dg.lowerValue(.{ .ty = elem_ty, .val = sent_val }); | |
| 3475 | const llvm_elems: [1]*llvm.Value = .{sentinel}; | |
| 3476 | const need_unnamed = dg.isUnnamedType(elem_ty, llvm_elems[0]); | |
| 3477 | if (need_unnamed) { | |
| 3478 | return dg.context.constStruct(&llvm_elems, llvm_elems.len, .True); | |
| 3479 | } else { | |
| 3480 | const llvm_elem_ty = try dg.lowerType(elem_ty); | |
| 3481 | return llvm_elem_ty.constArray(&llvm_elems, llvm_elems.len); | |
| 3482 | } | |
| 3518 | else => switch (mod.intern_pool.indexToKey(tv.val.ip_index)) { | |
| 3519 | .aggregate => |aggregate| switch (aggregate.storage) { | |
| 3520 | .elems => |elem_vals| { | |
| 3521 | const elem_ty = tv.ty.childType(mod); | |
| 3522 | const gpa = dg.gpa; | |
| 3523 | const llvm_elems = try gpa.alloc(*llvm.Value, elem_vals.len); | |
| 3524 | defer gpa.free(llvm_elems); | |
| 3525 | var need_unnamed = false; | |
| 3526 | for (elem_vals, 0..) |elem_val, i| { | |
| 3527 | llvm_elems[i] = try dg.lowerValue(.{ .ty = elem_ty, .val = elem_val.toValue() }); | |
| 3528 | need_unnamed = need_unnamed or dg.isUnnamedType(elem_ty, llvm_elems[i]); | |
| 3529 | } | |
| 3530 | if (need_unnamed) { | |
| 3531 | return dg.context.constStruct( | |
| 3532 | llvm_elems.ptr, | |
| 3533 | @intCast(c_uint, llvm_elems.len), | |
| 3534 | .True, | |
| 3535 | ); | |
| 3536 | } else { | |
| 3537 | const llvm_elem_ty = try dg.lowerType(elem_ty); | |
| 3538 | return llvm_elem_ty.constArray( | |
| 3539 | llvm_elems.ptr, | |
| 3540 | @intCast(c_uint, llvm_elems.len), | |
| 3541 | ); | |
| 3542 | } | |
| 3543 | }, | |
| 3544 | .repeated_elem => |val| { | |
| 3545 | const elem_ty = tv.ty.childType(mod); | |
| 3546 | const sentinel = tv.ty.sentinel(mod); | |
| 3547 | const len = @intCast(usize, tv.ty.arrayLen(mod)); | |
| 3548 | const len_including_sent = len + @boolToInt(sentinel != null); | |
| 3549 | const gpa = dg.gpa; | |
| 3550 | const llvm_elems = try gpa.alloc(*llvm.Value, len_including_sent); | |
| 3551 | defer gpa.free(llvm_elems); | |
| 3552 | ||
| 3553 | var need_unnamed = false; | |
| 3554 | if (len != 0) { | |
| 3555 | for (llvm_elems[0..len]) |*elem| { | |
| 3556 | elem.* = try dg.lowerValue(.{ .ty = elem_ty, .val = val.toValue() }); | |
| 3557 | } | |
| 3558 | need_unnamed = need_unnamed or dg.isUnnamedType(elem_ty, llvm_elems[0]); | |
| 3559 | } | |
| 3560 | ||
| 3561 | if (sentinel) |sent| { | |
| 3562 | llvm_elems[len] = try dg.lowerValue(.{ .ty = elem_ty, .val = sent }); | |
| 3563 | need_unnamed = need_unnamed or dg.isUnnamedType(elem_ty, llvm_elems[len]); | |
| 3564 | } | |
| 3565 | ||
| 3566 | if (need_unnamed) { | |
| 3567 | return dg.context.constStruct( | |
| 3568 | llvm_elems.ptr, | |
| 3569 | @intCast(c_uint, llvm_elems.len), | |
| 3570 | .True, | |
| 3571 | ); | |
| 3572 | } else { | |
| 3573 | const llvm_elem_ty = try dg.lowerType(elem_ty); | |
| 3574 | return llvm_elem_ty.constArray( | |
| 3575 | llvm_elems.ptr, | |
| 3576 | @intCast(c_uint, llvm_elems.len), | |
| 3577 | ); | |
| 3578 | } | |
| 3579 | }, | |
| 3580 | }, | |
| 3581 | else => unreachable, | |
| 3483 | 3582 | }, |
| 3484 | else => unreachable, | |
| 3485 | 3583 | }, |
| 3486 | 3584 | .Optional => { |
| 3487 | 3585 | comptime assert(optional_layout_version == 3); |
| ... | ... | @@ -3494,15 +3592,22 @@ pub const DeclGen = struct { |
| 3494 | 3592 | return non_null_bit; |
| 3495 | 3593 | } |
| 3496 | 3594 | const llvm_ty = try dg.lowerType(tv.ty); |
| 3497 | if (tv.ty.optionalReprIsPayload(mod)) { | |
| 3498 | if (tv.val.castTag(.opt_payload)) |payload| { | |
| 3499 | return dg.lowerValue(.{ .ty = payload_ty, .val = payload.data }); | |
| 3500 | } else if (is_pl) { | |
| 3501 | return dg.lowerValue(.{ .ty = payload_ty, .val = tv.val }); | |
| 3502 | } else { | |
| 3503 | return llvm_ty.constNull(); | |
| 3504 | } | |
| 3505 | } | |
| 3595 | if (tv.ty.optionalReprIsPayload(mod)) return switch (tv.val.ip_index) { | |
| 3596 | .none => if (tv.val.castTag(.opt_payload)) |payload| | |
| 3597 | try dg.lowerValue(.{ .ty = payload_ty, .val = payload.data }) | |
| 3598 | else if (is_pl) | |
| 3599 | try dg.lowerValue(.{ .ty = payload_ty, .val = tv.val }) | |
| 3600 | else | |
| 3601 | llvm_ty.constNull(), | |
| 3602 | .null_value => llvm_ty.constNull(), | |
| 3603 | else => switch (mod.intern_pool.indexToKey(tv.val.ip_index)) { | |
| 3604 | .opt => |opt| switch (opt.val) { | |
| 3605 | .none => llvm_ty.constNull(), | |
| 3606 | else => dg.lowerValue(.{ .ty = payload_ty, .val = opt.val.toValue() }), | |
| 3607 | }, | |
| 3608 | else => unreachable, | |
| 3609 | }, | |
| 3610 | }; | |
| 3506 | 3611 | assert(payload_ty.zigTypeTag(mod) != .Fn); |
| 3507 | 3612 | |
| 3508 | 3613 | const llvm_field_count = llvm_ty.countStructElementTypes(); |
| ... | ... | @@ -3589,7 +3694,6 @@ pub const DeclGen = struct { |
| 3589 | 3694 | }, |
| 3590 | 3695 | .Struct => { |
| 3591 | 3696 | const llvm_struct_ty = try dg.lowerType(tv.ty); |
| 3592 | const field_vals = tv.val.castTag(.aggregate).?.data; | |
| 3593 | 3697 | const gpa = dg.gpa; |
| 3594 | 3698 | |
| 3595 | 3699 | const struct_type = switch (mod.intern_pool.indexToKey(tv.ty.ip_index)) { |
| ... | ... | @@ -3623,7 +3727,7 @@ pub const DeclGen = struct { |
| 3623 | 3727 | |
| 3624 | 3728 | const field_llvm_val = try dg.lowerValue(.{ |
| 3625 | 3729 | .ty = field_ty.toType(), |
| 3626 | .val = field_vals[i], | |
| 3730 | .val = try tv.val.fieldValue(field_ty.toType(), mod, i), | |
| 3627 | 3731 | }); |
| 3628 | 3732 | |
| 3629 | 3733 | need_unnamed = need_unnamed or dg.isUnnamedType(field_ty.toType(), field_llvm_val); |
| ... | ... | @@ -3669,13 +3773,12 @@ pub const DeclGen = struct { |
| 3669 | 3773 | comptime assert(Type.packed_struct_layout_version == 2); |
| 3670 | 3774 | var running_int: *llvm.Value = int_llvm_ty.constNull(); |
| 3671 | 3775 | var running_bits: u16 = 0; |
| 3672 | for (field_vals, 0..) |field_val, i| { | |
| 3673 | const field = fields[i]; | |
| 3776 | for (fields, 0..) |field, i| { | |
| 3674 | 3777 | if (!field.ty.hasRuntimeBitsIgnoreComptime(mod)) continue; |
| 3675 | 3778 | |
| 3676 | 3779 | const non_int_val = try dg.lowerValue(.{ |
| 3677 | 3780 | .ty = field.ty, |
| 3678 | .val = field_val, | |
| 3781 | .val = try tv.val.fieldValue(field.ty, mod, i), | |
| 3679 | 3782 | }); |
| 3680 | 3783 | const ty_bit_size = @intCast(u16, field.ty.bitSize(mod)); |
| 3681 | 3784 | const small_int_ty = dg.context.intType(ty_bit_size); |
| ... | ... | @@ -3722,7 +3825,7 @@ pub const DeclGen = struct { |
| 3722 | 3825 | |
| 3723 | 3826 | const field_llvm_val = try dg.lowerValue(.{ |
| 3724 | 3827 | .ty = field.ty, |
| 3725 | .val = field_vals[field_and_index.index], | |
| 3828 | .val = try tv.val.fieldValue(field.ty, mod, field_and_index.index), | |
| 3726 | 3829 | }); |
| 3727 | 3830 | |
| 3728 | 3831 | need_unnamed = need_unnamed or dg.isUnnamedType(field.ty, field_llvm_val); |
| ... | ... | @@ -3756,7 +3859,13 @@ pub const DeclGen = struct { |
| 3756 | 3859 | }, |
| 3757 | 3860 | .Union => { |
| 3758 | 3861 | const llvm_union_ty = try dg.lowerType(tv.ty); |
| 3759 | const tag_and_val = tv.val.castTag(.@"union").?.data; | |
| 3862 | const tag_and_val: Value.Payload.Union.Data = switch (tv.val.ip_index) { | |
| 3863 | .none => tv.val.castTag(.@"union").?.data, | |
| 3864 | else => switch (mod.intern_pool.indexToKey(tv.val.ip_index)) { | |
| 3865 | .un => |un| .{ .tag = un.tag.toValue(), .val = un.val.toValue() }, | |
| 3866 | else => unreachable, | |
| 3867 | }, | |
| 3868 | }; | |
| 3760 | 3869 | |
| 3761 | 3870 | const layout = tv.ty.unionGetLayout(mod); |
| 3762 | 3871 |
src/value.zig+92-16| ... | ... | @@ -602,6 +602,73 @@ pub const Value = struct { |
| 602 | 602 | return result; |
| 603 | 603 | } |
| 604 | 604 | |
| 605 | pub fn intern(val: Value, ty: Type, mod: *Module) Allocator.Error!InternPool.Index { | |
| 606 | if (val.ip_index != .none) return val.ip_index; | |
| 607 | switch (val.tag()) { | |
| 608 | .slice => { | |
| 609 | const pl = val.castTag(.slice).?.data; | |
| 610 | const ptr = try pl.ptr.intern(ty.slicePtrFieldType(mod), mod); | |
| 611 | return mod.intern(.{ .ptr = .{ | |
| 612 | .ty = ty.ip_index, | |
| 613 | .addr = mod.intern_pool.indexToKey(ptr).ptr.addr, | |
| 614 | .len = try pl.len.intern(Type.usize, mod), | |
| 615 | } }); | |
| 616 | }, | |
| 617 | .opt_payload => return mod.intern(.{ .opt = .{ | |
| 618 | .ty = ty.ip_index, | |
| 619 | .val = try val.castTag(.opt_payload).?.data.intern(ty.childType(mod), mod), | |
| 620 | } }), | |
| 621 | .aggregate => { | |
| 622 | const old_elems = val.castTag(.aggregate).?.data; | |
| 623 | const new_elems = try mod.gpa.alloc(InternPool.Index, old_elems.len); | |
| 624 | defer mod.gpa.free(new_elems); | |
| 625 | const ty_key = mod.intern_pool.indexToKey(ty.ip_index); | |
| 626 | for (new_elems, old_elems, 0..) |*new_elem, old_elem, field_i| | |
| 627 | new_elem.* = try old_elem.intern(switch (ty_key) { | |
| 628 | .struct_type => ty.structFieldType(field_i, mod), | |
| 629 | .anon_struct_type => |info| info.types[field_i].toType(), | |
| 630 | inline .array_type, .vector_type => |info| info.child.toType(), | |
| 631 | else => unreachable, | |
| 632 | }, mod); | |
| 633 | return mod.intern(.{ .aggregate = .{ | |
| 634 | .ty = ty.ip_index, | |
| 635 | .storage = .{ .elems = new_elems }, | |
| 636 | } }); | |
| 637 | }, | |
| 638 | .repeated => return mod.intern(.{ .aggregate = .{ | |
| 639 | .ty = ty.ip_index, | |
| 640 | .storage = .{ .repeated_elem = try val.castTag(.repeated).?.data.intern( | |
| 641 | ty.structFieldType(0, mod), | |
| 642 | mod, | |
| 643 | ) }, | |
| 644 | } }), | |
| 645 | .@"union" => { | |
| 646 | const pl = val.castTag(.@"union").?.data; | |
| 647 | return mod.intern(.{ .un = .{ | |
| 648 | .ty = ty.ip_index, | |
| 649 | .tag = try pl.tag.intern(ty.unionTagTypeHypothetical(mod), mod), | |
| 650 | .val = try pl.val.intern(ty.unionFieldType(pl.tag, mod), mod), | |
| 651 | } }); | |
| 652 | }, | |
| 653 | else => unreachable, | |
| 654 | } | |
| 655 | } | |
| 656 | ||
| 657 | pub fn unintern(val: Value, arena: Allocator, mod: *Module) Allocator.Error!Value { | |
| 658 | if (val.ip_index == .none) return val; | |
| 659 | switch (mod.intern_pool.indexToKey(val.ip_index)) { | |
| 660 | .aggregate => |aggregate| switch (aggregate.storage) { | |
| 661 | .elems => |old_elems| { | |
| 662 | const new_elems = try arena.alloc(Value, old_elems.len); | |
| 663 | for (new_elems, old_elems) |*new_elem, old_elem| new_elem.* = old_elem.toValue(); | |
| 664 | return Tag.aggregate.create(arena, new_elems); | |
| 665 | }, | |
| 666 | .repeated_elem => |elem| return Tag.repeated.create(arena, elem.toValue()), | |
| 667 | }, | |
| 668 | else => return val, | |
| 669 | } | |
| 670 | } | |
| 671 | ||
| 605 | 672 | pub fn toIntern(val: Value) InternPool.Index { |
| 606 | 673 | assert(val.ip_index != .none); |
| 607 | 674 | return val.ip_index; |
| ... | ... | @@ -2002,11 +2069,11 @@ pub const Value = struct { |
| 2002 | 2069 | |
| 2003 | 2070 | const ptr_ty = ty.slicePtrFieldType(mod); |
| 2004 | 2071 | const a_ptr = switch (a_ty.ptrSize(mod)) { |
| 2005 | .Slice => a.slicePtr(), | |
| 2072 | .Slice => a.slicePtr(mod), | |
| 2006 | 2073 | .One => a, |
| 2007 | 2074 | else => unreachable, |
| 2008 | 2075 | }; |
| 2009 | return try eqlAdvanced(a_ptr, ptr_ty, b.slicePtr(), ptr_ty, mod, opt_sema); | |
| 2076 | return try eqlAdvanced(a_ptr, ptr_ty, b.slicePtr(mod), ptr_ty, mod, opt_sema); | |
| 2010 | 2077 | }, |
| 2011 | 2078 | .Many, .C, .One => {}, |
| 2012 | 2079 | }, |
| ... | ... | @@ -2429,7 +2496,8 @@ pub const Value = struct { |
| 2429 | 2496 | } |
| 2430 | 2497 | } |
| 2431 | 2498 | |
| 2432 | pub fn slicePtr(val: Value) Value { | |
| 2499 | pub fn slicePtr(val: Value, mod: *Module) Value { | |
| 2500 | if (val.ip_index != .none) return mod.intern_pool.slicePtr(val.ip_index).toValue(); | |
| 2433 | 2501 | return switch (val.tag()) { |
| 2434 | 2502 | .slice => val.castTag(.slice).?.data.ptr, |
| 2435 | 2503 | // TODO this should require being a slice tag, and not allow decl_ref, field_ptr, etc. |
| ... | ... | @@ -2439,6 +2507,7 @@ pub const Value = struct { |
| 2439 | 2507 | } |
| 2440 | 2508 | |
| 2441 | 2509 | pub fn sliceLen(val: Value, mod: *Module) u64 { |
| 2510 | if (val.ip_index != .none) return mod.intern_pool.sliceLen(val.ip_index).toValue().toUnsignedInt(mod); | |
| 2442 | 2511 | return switch (val.tag()) { |
| 2443 | 2512 | .slice => val.castTag(.slice).?.data.len.toUnsignedInt(mod), |
| 2444 | 2513 | .decl_ref => { |
| ... | ... | @@ -2531,7 +2600,19 @@ pub const Value = struct { |
| 2531 | 2600 | |
| 2532 | 2601 | else => unreachable, |
| 2533 | 2602 | }, |
| 2534 | else => unreachable, | |
| 2603 | else => return switch (mod.intern_pool.indexToKey(val.ip_index)) { | |
| 2604 | .ptr => |ptr| switch (ptr.addr) { | |
| 2605 | .@"var" => unreachable, | |
| 2606 | .decl => |decl| mod.declPtr(decl).val.elemValue(mod, index), | |
| 2607 | .mut_decl => |mut_decl| mod.declPtr(mut_decl.decl).val.elemValue(mod, index), | |
| 2608 | .int => unreachable, | |
| 2609 | }, | |
| 2610 | .aggregate => |aggregate| switch (aggregate.storage) { | |
| 2611 | .elems => |elems| elems[index].toValue(), | |
| 2612 | .repeated_elem => |elem| elem.toValue(), | |
| 2613 | }, | |
| 2614 | else => unreachable, | |
| 2615 | }, | |
| 2535 | 2616 | } |
| 2536 | 2617 | } |
| 2537 | 2618 | |
| ... | ... | @@ -2675,6 +2756,7 @@ pub const Value = struct { |
| 2675 | 2756 | } |
| 2676 | 2757 | |
| 2677 | 2758 | pub fn unionTag(val: Value, mod: *Module) Value { |
| 2759 | if (val.ip_index == .none) return val.castTag(.@"union").?.data.tag; | |
| 2678 | 2760 | return switch (mod.intern_pool.indexToKey(val.ip_index)) { |
| 2679 | 2761 | .undef, .enum_tag => val, |
| 2680 | 2762 | .un => |un| un.tag.toValue(), |
| ... | ... | @@ -2696,7 +2778,7 @@ pub const Value = struct { |
| 2696 | 2778 | else => val, |
| 2697 | 2779 | }; |
| 2698 | 2780 | |
| 2699 | if (ptr_val.tag() == .elem_ptr) { | |
| 2781 | if (ptr_val.ip_index == .none and ptr_val.tag() == .elem_ptr) { | |
| 2700 | 2782 | const elem_ptr = ptr_val.castTag(.elem_ptr).?.data; |
| 2701 | 2783 | if (elem_ptr.elem_ty.eql(elem_ty, mod)) { |
| 2702 | 2784 | return Tag.elem_ptr.create(arena, .{ |
| ... | ... | @@ -4809,10 +4891,12 @@ pub const Value = struct { |
| 4809 | 4891 | pub const base_tag = Tag.@"union"; |
| 4810 | 4892 | |
| 4811 | 4893 | base: Payload = .{ .tag = base_tag }, |
| 4812 | data: struct { | |
| 4894 | data: Data, | |
| 4895 | ||
| 4896 | pub const Data = struct { | |
| 4813 | 4897 | tag: Value, |
| 4814 | 4898 | val: Value, |
| 4815 | }, | |
| 4899 | }; | |
| 4816 | 4900 | }; |
| 4817 | 4901 | }; |
| 4818 | 4902 | |
| ... | ... | @@ -4844,15 +4928,7 @@ pub const Value = struct { |
| 4844 | 4928 | return if (x) one else zero; |
| 4845 | 4929 | } |
| 4846 | 4930 | |
| 4847 | pub const RuntimeIndex = enum(u32) { | |
| 4848 | zero = 0, | |
| 4849 | comptime_field_ptr = std.math.maxInt(u32), | |
| 4850 | _, | |
| 4851 | ||
| 4852 | pub fn increment(ri: *RuntimeIndex) void { | |
| 4853 | ri.* = @intToEnum(RuntimeIndex, @enumToInt(ri.*) + 1); | |
| 4854 | } | |
| 4855 | }; | |
| 4931 | pub const RuntimeIndex = InternPool.RuntimeIndex; | |
| 4856 | 4932 | |
| 4857 | 4933 | /// This function is used in the debugger pretty formatters in tools/ to fetch the |
| 4858 | 4934 | /// Tag to Payload mapping to facilitate fancy debug printing for this type. |