authorgravatar for jacobly@ziglang.orgJacob Young <jacobly@ziglang.org> 2023-05-20 09:35:11-04:00
committergravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2023-06-10 20:47:53-07:00
log115c08956278b79c848e04c2f4eefca40e6cd8a3
tree8dfdced9bc1ba7499f7660e986bd82d0ae772347
parentbe78a12d7d5ac0a711fdf7237d7ccefba42be83c

Value: add `intern` and `unintern` to facilitate code conversion

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,6 +100,16 @@ pub const MapIndex = enum(u32) {
100 }100 }
101};101};
102102
103pub 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/// An index into `string_bytes`.113/// An index into `string_bytes`.
104pub const NullTerminatedString = enum(u32) {114pub const NullTerminatedString = enum(u32) {
105 _,115 _,
...@@ -478,11 +488,27 @@ pub const Key = union(enum) {...@@ -478,11 +488,27 @@ pub const Key = union(enum) {
478 };488 };
479489
480 pub const Ptr = struct {490 pub const Ptr = struct {
491 /// This is the pointer type, not the element type.
481 ty: Index,492 ty: Index,
493 /// The value of the address that the pointer points to.
482 addr: Addr,494 addr: Addr,
495 /// This could be `none` if size is not a slice.
496 len: Index = .none,
483497
484 pub const Addr = union(enum) {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 decl: Module.Decl.Index,507 decl: Module.Decl.Index,
508 mut_decl: struct {
509 decl: Module.Decl.Index,
510 runtime_index: RuntimeIndex,
511 },
486 int: Index,512 int: Index,
487 };513 };
488 };514 };
...@@ -577,7 +603,9 @@ pub const Key = union(enum) {...@@ -577,7 +603,9 @@ pub const Key = union(enum) {
577 // This is sound due to pointer provenance rules.603 // This is sound due to pointer provenance rules.
578 std.hash.autoHash(hasher, @as(@typeInfo(Key.Ptr.Addr).Union.tag_type.?, ptr.addr));604 std.hash.autoHash(hasher, @as(@typeInfo(Key.Ptr.Addr).Union.tag_type.?, ptr.addr));
579 switch (ptr.addr) {605 switch (ptr.addr) {
606 .@"var" => |@"var"| std.hash.autoHash(hasher, @"var".owner_decl),
580 .decl => |decl| std.hash.autoHash(hasher, decl),607 .decl => |decl| std.hash.autoHash(hasher, decl),
608 .mut_decl => |mut_decl| std.hash.autoHash(hasher, mut_decl),
581 .int => |int| std.hash.autoHash(hasher, int),609 .int => |int| std.hash.autoHash(hasher, int),
582 }610 }
583 },611 },
...@@ -697,7 +725,9 @@ pub const Key = union(enum) {...@@ -697,7 +725,9 @@ pub const Key = union(enum) {
697 if (@as(AddrTag, a_info.addr) != @as(AddrTag, b_info.addr)) return false;725 if (@as(AddrTag, a_info.addr) != @as(AddrTag, b_info.addr)) return false;
698726
699 return switch (a_info.addr) {727 return switch (a_info.addr) {
728 .@"var" => |a_var| a_var.owner_decl == b_info.addr.@"var".owner_decl,
700 .decl => |a_decl| a_decl == b_info.addr.decl,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 .int => |a_int| a_int == b_info.addr.int,731 .int => |a_int| a_int == b_info.addr.int,
702 };732 };
703 },733 },
...@@ -1330,6 +1360,12 @@ pub const Tag = enum(u8) {...@@ -1330,6 +1360,12 @@ pub const Tag = enum(u8) {
1330 /// A value that can be represented with only an enum tag.1360 /// A value that can be represented with only an enum tag.
1331 /// data is SimpleValue enum value.1361 /// data is SimpleValue enum value.
1332 simple_value,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 /// A pointer to a decl.1369 /// A pointer to a decl.
1334 /// data is extra index of PtrDecl, which contains the type and address.1370 /// data is extra index of PtrDecl, which contains the type and address.
1335 ptr_decl,1371 ptr_decl,
...@@ -1338,6 +1374,11 @@ pub const Tag = enum(u8) {...@@ -1338,6 +1374,11 @@ pub const Tag = enum(u8) {
1338 /// Only pointer types are allowed to have this encoding. Optional types must use1374 /// Only pointer types are allowed to have this encoding. Optional types must use
1339 /// `opt_payload` or `opt_null`.1375 /// `opt_payload` or `opt_null`.
1340 ptr_int,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 /// An optional value that is non-null.1382 /// An optional value that is non-null.
1342 /// data is Index of the payload value.1383 /// data is Index of the payload value.
1343 /// In order to use this encoding, one must ensure that the `InternPool`1384 /// In order to use this encoding, one must ensure that the `InternPool`
...@@ -1672,16 +1713,45 @@ pub const PackedU64 = packed struct(u64) {...@@ -1672,16 +1713,45 @@ pub const PackedU64 = packed struct(u64) {
1672 }1713 }
1673};1714};
16741715
1716pub 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
1675pub const PtrDecl = struct {1734pub const PtrDecl = struct {
1676 ty: Index,1735 ty: Index,
1677 decl: Module.Decl.Index,1736 decl: Module.Decl.Index,
1678};1737};
16791738
1739pub const PtrMutDecl = struct {
1740 ty: Index,
1741 decl: Module.Decl.Index,
1742 runtime_index: RuntimeIndex,
1743};
1744
1680pub const PtrInt = struct {1745pub const PtrInt = struct {
1681 ty: Index,1746 ty: Index,
1682 addr: Index,1747 addr: Index,
1683};1748};
16841749
1750pub const PtrSlice = struct {
1751 ptr: Index,
1752 len: Index,
1753};
1754
1685/// Trailing: Limb for every limbs_len1755/// Trailing: Limb for every limbs_len
1686pub const Int = struct {1756pub const Int = struct {
1687 ty: Index,1757 ty: Index,
...@@ -1994,6 +2064,30 @@ pub fn indexToKey(ip: InternPool, index: Index) Key {...@@ -1994,6 +2064,30 @@ pub fn indexToKey(ip: InternPool, index: Index) Key {
1994 .val = payload_val,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 .ptr_decl => {2091 .ptr_decl => {
1998 const info = ip.extraData(PtrDecl, data);2092 const info = ip.extraData(PtrDecl, data);
1999 return .{ .ptr = .{2093 return .{ .ptr = .{
...@@ -2008,6 +2102,18 @@ pub fn indexToKey(ip: InternPool, index: Index) Key {...@@ -2008,6 +2102,18 @@ pub fn indexToKey(ip: InternPool, index: Index) Key {
2008 .addr = .{ .int = info.addr },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 .int_u8 => .{ .int = .{2117 .int_u8 => .{ .int = .{
2012 .ty = .u8_type,2118 .ty = .u8_type,
2013 .storage = .{ .u64 = data },2119 .storage = .{ .u64 = data },
...@@ -2472,31 +2578,67 @@ pub fn get(ip: *InternPool, gpa: Allocator, key: Key) Allocator.Error!Index {...@@ -2472,31 +2578,67 @@ pub fn get(ip: *InternPool, gpa: Allocator, key: Key) Allocator.Error!Index {
24722578
2473 .extern_func => @panic("TODO"),2579 .extern_func => @panic("TODO"),
24742580
2475 .ptr => |ptr| switch (ptr.addr) {2581 .ptr => |ptr| switch (ip.items.items(.tag)[@enumToInt(ptr.ty)]) {
2476 .decl => |decl| {2582 .type_pointer => {
2477 assert(ptr.ty != .none);2583 assert(ptr.len == .none);
2478 ip.items.appendAssumeCapacity(.{2584 switch (ptr.addr) {
2479 .tag = .ptr_decl,2585 .@"var" => |@"var"| ip.items.appendAssumeCapacity(.{
2480 .data = try ip.addExtra(gpa, PtrDecl{2586 .tag = .ptr_var,
2481 .ty = ptr.ty,2587 .data = try ip.addExtra(gpa, PtrVar{
2482 .decl = decl,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| {2623 .type_slice => {
2487 assert(ptr.ty != .none);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 ip.items.appendAssumeCapacity(.{2630 ip.items.appendAssumeCapacity(.{
2489 .tag = .ptr_int,2631 .tag = .ptr_slice,
2490 .data = try ip.addExtra(gpa, PtrInt{2632 .data = try ip.addExtra(gpa, PtrSlice{
2491 .ty = ptr.ty,2633 .ptr = ptr_index,
2492 .addr = int,2634 .len = ptr.len,
2493 }),2635 }),
2494 });2636 });
2495 },2637 },
2638 else => unreachable,
2496 },2639 },
24972640
2498 .opt => |opt| {2641 .opt => |opt| {
2499 assert(opt.ty != .none);
2500 assert(ip.isOptionalType(opt.ty));2642 assert(ip.isOptionalType(opt.ty));
2501 ip.items.appendAssumeCapacity(if (opt.val == .none) .{2643 ip.items.appendAssumeCapacity(if (opt.val == .none) .{
2502 .tag = .opt_null,2644 .tag = .opt_null,
...@@ -3087,11 +3229,15 @@ fn addExtraAssumeCapacity(ip: *InternPool, extra: anytype) u32 {...@@ -3087,11 +3229,15 @@ fn addExtraAssumeCapacity(ip: *InternPool, extra: anytype) u32 {
3087 Module.Namespace.OptionalIndex => @enumToInt(@field(extra, field.name)),3229 Module.Namespace.OptionalIndex => @enumToInt(@field(extra, field.name)),
3088 MapIndex => @enumToInt(@field(extra, field.name)),3230 MapIndex => @enumToInt(@field(extra, field.name)),
3089 OptionalMapIndex => @enumToInt(@field(extra, field.name)),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 i32 => @bitCast(u32, @field(extra, field.name)),3235 i32 => @bitCast(u32, @field(extra, field.name)),
3091 Pointer.Flags => @bitCast(u32, @field(extra, field.name)),3236 Pointer.Flags => @bitCast(u32, @field(extra, field.name)),
3092 TypeFunction.Flags => @bitCast(u32, @field(extra, field.name)),3237 TypeFunction.Flags => @bitCast(u32, @field(extra, field.name)),
3093 Pointer.PackedOffset => @bitCast(u32, @field(extra, field.name)),3238 Pointer.PackedOffset => @bitCast(u32, @field(extra, field.name)),
3094 Pointer.VectorIndex => @enumToInt(@field(extra, field.name)),3239 Pointer.VectorIndex => @enumToInt(@field(extra, field.name)),
3240 PtrVar.Flags => @bitCast(u32, @field(extra, field.name)),
3095 else => @compileError("bad field type: " ++ @typeName(field.type)),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,11 +3295,15 @@ fn extraDataTrail(ip: InternPool, comptime T: type, index: usize) struct { data:
3149 Module.Namespace.OptionalIndex => @intToEnum(Module.Namespace.OptionalIndex, int32),3295 Module.Namespace.OptionalIndex => @intToEnum(Module.Namespace.OptionalIndex, int32),
3150 MapIndex => @intToEnum(MapIndex, int32),3296 MapIndex => @intToEnum(MapIndex, int32),
3151 OptionalMapIndex => @intToEnum(OptionalMapIndex, int32),3297 OptionalMapIndex => @intToEnum(OptionalMapIndex, int32),
3298 RuntimeIndex => @intToEnum(RuntimeIndex, int32),
3299 NullTerminatedString => @intToEnum(NullTerminatedString, int32),
3300 OptionalNullTerminatedString => @intToEnum(OptionalNullTerminatedString, int32),
3152 i32 => @bitCast(i32, int32),3301 i32 => @bitCast(i32, int32),
3153 Pointer.Flags => @bitCast(Pointer.Flags, int32),3302 Pointer.Flags => @bitCast(Pointer.Flags, int32),
3154 TypeFunction.Flags => @bitCast(TypeFunction.Flags, int32),3303 TypeFunction.Flags => @bitCast(TypeFunction.Flags, int32),
3155 Pointer.PackedOffset => @bitCast(Pointer.PackedOffset, int32),3304 Pointer.PackedOffset => @bitCast(Pointer.PackedOffset, int32),
3156 Pointer.VectorIndex => @intToEnum(Pointer.VectorIndex, int32),3305 Pointer.VectorIndex => @intToEnum(Pointer.VectorIndex, int32),
3306 PtrVar.Flags => @bitCast(PtrVar.Flags, int32),
3157 else => @compileError("bad field type: " ++ @typeName(field.type)),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,7 +3424,7 @@ pub fn childType(ip: InternPool, i: Index) Index {
3274 };3424 };
3275}3425}
32763426
3277/// Given a slice type, returns the type of the pointer field.3427/// Given a slice type, returns the type of the ptr field.
3278pub fn slicePtrType(ip: InternPool, i: Index) Index {3428pub fn slicePtrType(ip: InternPool, i: Index) Index {
3279 switch (i) {3429 switch (i) {
3280 .const_slice_u8_type => return .manyptr_const_u8_type,3430 .const_slice_u8_type => return .manyptr_const_u8_type,
...@@ -3288,10 +3438,29 @@ pub fn slicePtrType(ip: InternPool, i: Index) Index {...@@ -3288,10 +3438,29 @@ pub fn slicePtrType(ip: InternPool, i: Index) Index {
3288 }3438 }
3289}3439}
32903440
3441/// Given a slice value, returns the value of the ptr field.
3442pub 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.
3451pub 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/// Given an existing value, returns the same value but with the supplied type.3459/// Given an existing value, returns the same value but with the supplied type.
3292/// Only some combinations are allowed:3460/// Only some combinations are allowed:
3293/// * int <=> int3461/// * int <=> int
3294/// * int <=> enum3462/// * int <=> enum
3463/// * ptr <=> ptr
3295pub fn getCoerced(ip: *InternPool, gpa: Allocator, val: Index, new_ty: Index) Allocator.Error!Index {3464pub fn getCoerced(ip: *InternPool, gpa: Allocator, val: Index, new_ty: Index) Allocator.Error!Index {
3296 switch (ip.indexToKey(val)) {3465 switch (ip.indexToKey(val)) {
3297 .int => |int| switch (ip.indexToKey(new_ty)) {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,6 +3474,13 @@ pub fn getCoerced(ip: *InternPool, gpa: Allocator, val: Index, new_ty: Index) Al
3305 // Assume new_ty is an integer type.3474 // Assume new_ty is an integer type.
3306 return getCoercedInts(ip, gpa, ip.indexToKey(enum_tag.int).int, new_ty);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 else => unreachable,3484 else => unreachable,
3309 }3485 }
3310}3486}
...@@ -3380,6 +3556,15 @@ pub fn indexToInferredErrorSetType(ip: InternPool, val: Index) Module.Fn.Inferre...@@ -3380,6 +3556,15 @@ pub fn indexToInferredErrorSetType(ip: InternPool, val: Index) Module.Fn.Inferre
3380 return @intToEnum(Module.Fn.InferredErrorSet.Index, datas[@enumToInt(val)]).toOptional();3556 return @intToEnum(Module.Fn.InferredErrorSet.Index, datas[@enumToInt(val)]).toOptional();
3381}3557}
33823558
3559pub 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
3383pub fn isOptionalType(ip: InternPool, ty: Index) bool {3568pub fn isOptionalType(ip: InternPool, ty: Index) bool {
3384 const tags = ip.items.items(.tag);3569 const tags = ip.items.items(.tag);
3385 if (ty == .none) return false;3570 if (ty == .none) return false;
...@@ -3485,8 +3670,11 @@ fn dumpFallible(ip: InternPool, arena: Allocator) anyerror!void {...@@ -3485,8 +3670,11 @@ fn dumpFallible(ip: InternPool, arena: Allocator) anyerror!void {
3485 .undef => 0,3670 .undef => 0,
3486 .simple_type => 0,3671 .simple_type => 0,
3487 .simple_value => 0,3672 .simple_value => 0,
3673 .ptr_var => @sizeOf(PtrVar),
3488 .ptr_decl => @sizeOf(PtrDecl),3674 .ptr_decl => @sizeOf(PtrDecl),
3675 .ptr_mut_decl => @sizeOf(PtrMutDecl),
3489 .ptr_int => @sizeOf(PtrInt),3676 .ptr_int => @sizeOf(PtrInt),
3677 .ptr_slice => @sizeOf(PtrSlice),
3490 .opt_null => 0,3678 .opt_null => 0,
3491 .opt_payload => 0,3679 .opt_payload => 0,
3492 .int_u8 => 0,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,7 +5762,7 @@ pub fn analyzeFnBody(mod: *Module, func: *Fn, arena: Allocator) SemaError!Air {
5762 // Crucially, this happens *after* we set the function state to success above,5762 // Crucially, this happens *after* we set the function state to success above,
5763 // so that dependencies on the function body will now be satisfied rather than5763 // so that dependencies on the function body will now be satisfied rather than
5764 // result in circular dependency errors.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 error.NeededSourceLocation => unreachable,5766 error.NeededSourceLocation => unreachable,
5767 error.GenericPoison => unreachable,5767 error.GenericPoison => unreachable,
5768 error.ComptimeReturn => unreachable,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,25 +13072,32 @@ fn zirArrayMul(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Ai
13072 // as zero-filling a byte array.13072 // as zero-filling a byte array.
13073 if (lhs_len == 1) {13073 if (lhs_len == 1) {
13074 const elem_val = try lhs_sub_val.elemValue(mod, 0);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 }
1307713080
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 var elem_i: usize = 0;13082 var elem_i: usize = 0;
13080 while (elem_i < result_len) {13083 while (elem_i < result_len) {
13081 var lhs_i: usize = 0;13084 var lhs_i: usize = 0;
13082 while (lhs_i < lhs_len) : (lhs_i += 1) {13085 while (lhs_i < lhs_len) : (lhs_i += 1) {
13083 const elem_val = try lhs_sub_val.elemValue(mod, lhs_i);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 elem_i += 1;13089 elem_i += 1;
13086 }13090 }
13087 }13091 }
13088 if (lhs_info.sentinel) |sent_val| {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 }
1309513102
13096 try sema.requireRuntimeBlock(block, src, lhs_src);13103 try sema.requireRuntimeBlock(block, src, lhs_src);
...@@ -18111,12 +18118,16 @@ fn finishStructInit(...@@ -18111,12 +18118,16 @@ fn finishStructInit(
18111 } else null;18118 } else null;
1811218119
18113 const runtime_index = opt_runtime_index orelse {18120 const runtime_index = opt_runtime_index orelse {
18114 const values = try sema.arena.alloc(Value, field_inits.len);18121 const elems = try sema.arena.alloc(InternPool.Index, field_inits.len);
18115 for (field_inits, 0..) |field_init, i| {18122 for (elems, field_inits, 0..) |*elem, field_init, field_i| {
18116 values[i] = (sema.resolveMaybeUndefVal(field_init) catch unreachable).?;18123 elem.* = try (sema.resolveMaybeUndefVal(field_init) catch unreachable).?
18117 }18124 .intern(struct_ty.structFieldType(field_i, mod), mod);
18118 const struct_val = try Value.Tag.aggregate.create(sema.arena, values);18125 }
18119 return sema.addConstantMaybeRef(block, struct_ty, struct_val, is_ref);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 };
1812118132
18122 if (is_ref) {18133 if (is_ref) {
...@@ -18195,21 +18206,20 @@ fn zirStructInitAnon(...@@ -18195,21 +18206,20 @@ fn zirStructInitAnon(
1819518206
18196 const init = try sema.resolveInst(item.data.init);18207 const init = try sema.resolveInst(item.data.init);
18197 field_ty.* = sema.typeOf(init).ip_index;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 const msg = msg: {18210 const msg = msg: {
18200 const decl = sema.mod.declPtr(block.src_decl);18211 const decl = sema.mod.declPtr(block.src_decl);
18201 const field_src = mod.initSrc(src.node_offset.x, decl, i);18212 const field_src = mod.initSrc(src.node_offset.x, decl, i);
18202 const msg = try sema.errMsg(block, field_src, "opaque types have unknown size and therefore cannot be directly embedded in structs", .{});18213 const msg = try sema.errMsg(block, field_src, "opaque types have unknown size and therefore cannot be directly embedded in structs", .{});
18203 errdefer msg.destroy(sema.gpa);18214 errdefer msg.destroy(sema.gpa);
1820418215
18205 try sema.addDeclaredHereNote(msg, types[i].toType());18216 try sema.addDeclaredHereNote(msg, field_ty.toType());
18206 break :msg msg;18217 break :msg msg;
18207 };18218 };
18208 return sema.failWithOwnedErrorMsg(msg);18219 return sema.failWithOwnedErrorMsg(msg);
18209 }18220 }
18210 if (try sema.resolveMaybeUndefVal(init)) |init_val| {18221 if (try sema.resolveMaybeUndefVal(init)) |init_val| {
18211 assert(init_val.ip_index != .none);18222 values[i] = try init_val.intern(field_ty.toType(), mod);
18212 values[i] = init_val.ip_index;
18213 } else {18223 } else {
18214 values[i] = .none;18224 values[i] = .none;
18215 runtime_index = i;18225 runtime_index = i;
...@@ -24891,9 +24901,7 @@ fn structFieldVal(...@@ -24891,9 +24901,7 @@ fn structFieldVal(
24891 if ((try sema.typeHasOnePossibleValue(field.ty))) |opv| {24901 if ((try sema.typeHasOnePossibleValue(field.ty))) |opv| {
24892 return sema.addConstant(field.ty, opv);24902 return sema.addConstant(field.ty, opv);
24893 }24903 }
2489424904 return sema.addConstant(field.ty, try struct_val.fieldValue(field.ty, mod, field_index));
24895 const field_values = struct_val.castTag(.aggregate).?.data;
24896 return sema.addConstant(field.ty, field_values[field_index]);
24897 }24905 }
2489824906
24899 try sema.requireRuntimeBlock(block, src, null);24907 try sema.requireRuntimeBlock(block, src, null);
...@@ -27925,7 +27933,24 @@ fn beginComptimePtrMutation(...@@ -27925,7 +27933,24 @@ fn beginComptimePtrMutation(
27925 ptr_elem_ty,27933 ptr_elem_ty,
27926 parent.decl_ref_mut,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);
2792827943
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 .@"union" => {27954 .@"union" => {
27930 // We need to set the active field of the union.27955 // We need to set the active field of the union.
27931 const union_tag_ty = field_ptr.container_ty.unionTagTypeHypothetical(mod);27956 const union_tag_ty = field_ptr.container_ty.unionTagTypeHypothetical(mod);
...@@ -28107,6 +28132,13 @@ fn beginComptimePtrMutationInner(...@@ -28107,6 +28132,13 @@ fn beginComptimePtrMutationInner(
28107 const mod = sema.mod;28132 const mod = sema.mod;
28108 const target = mod.getTarget();28133 const target = mod.getTarget();
28109 const coerce_ok = (try sema.coerceInMemoryAllowed(block, ptr_elem_ty, decl_ty, true, target, src, src)) == .ok;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 if (coerce_ok) {28142 if (coerce_ok) {
28111 return ComptimePtrMutationKit{28143 return ComptimePtrMutationKit{
28112 .decl_ref_mut = decl_ref_mut,28144 .decl_ref_mut = decl_ref_mut,
...@@ -28412,6 +28444,27 @@ fn beginComptimePtrLoad(...@@ -28412,6 +28444,27 @@ fn beginComptimePtrLoad(
28412 },28444 },
28413 else => switch (mod.intern_pool.indexToKey(ptr_val.ip_index)) {28445 else => switch (mod.intern_pool.indexToKey(ptr_val.ip_index)) {
28414 .int => return error.RuntimeLoad,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 else => unreachable,28468 else => unreachable,
28416 },28469 },
28417 };28470 };
...@@ -29425,7 +29478,7 @@ fn analyzeSlicePtr(...@@ -29425,7 +29478,7 @@ fn analyzeSlicePtr(
29425 const result_ty = slice_ty.slicePtrFieldType(mod);29478 const result_ty = slice_ty.slicePtrFieldType(mod);
29426 if (try sema.resolveMaybeUndefVal(slice)) |val| {29479 if (try sema.resolveMaybeUndefVal(slice)) |val| {
29427 if (val.isUndef(mod)) return sema.addConstUndef(result_ty);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 try sema.requireRuntimeBlock(block, slice_src, null);29483 try sema.requireRuntimeBlock(block, slice_src, null);
29431 return block.addTyOp(.slice_ptr, result_ty, slice);29484 return block.addTyOp(.slice_ptr, result_ty, slice);
src/codegen/c.zig+1-1
...@@ -566,7 +566,7 @@ pub const DeclGen = struct {...@@ -566,7 +566,7 @@ pub const DeclGen = struct {
566 try writer.writeAll("){ .ptr = ");566 try writer.writeAll("){ .ptr = ");
567 }567 }
568568
569 try dg.renderValue(writer, ty.slicePtrFieldType(mod), val.slicePtr(), .Initializer);569 try dg.renderValue(writer, ty.slicePtrFieldType(mod), val.slicePtr(mod), .Initializer);
570570
571 const len_val = try mod.intValue(Type.usize, val.sliceLen(mod));571 const len_val = try mod.intValue(Type.usize, val.sliceLen(mod));
572572
src/codegen/llvm.zig+231-122
...@@ -3363,125 +3363,223 @@ pub const DeclGen = struct {...@@ -3363,125 +3363,223 @@ pub const DeclGen = struct {
3363 },3363 },
3364 else => switch (mod.intern_pool.indexToKey(tv.val.ip_index)) {3364 else => switch (mod.intern_pool.indexToKey(tv.val.ip_index)) {
3365 .int => |int| return lowerIntAsPtr(dg, int),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 else => unreachable,3397 else => unreachable,
3367 },3398 },
3368 },3399 },
3369 .Array => switch (tv.val.tag()) {3400 .Array => switch (tv.val.ip_index) {
3370 .bytes => {3401 .none => switch (tv.val.tag()) {
3371 const bytes = tv.val.castTag(.bytes).?.data;3402 .bytes => {
3372 return dg.context.constString(3403 const bytes = tv.val.castTag(.bytes).?.data;
3373 bytes.ptr,3404 return dg.context.constString(
3374 @intCast(c_uint, tv.ty.arrayLenIncludingSentinel(mod)),3405 bytes.ptr,
3375 .True, // Don't null terminate. Bytes has the sentinel, if any.3406 @intCast(c_uint, tv.ty.arrayLenIncludingSentinel(mod)),
3376 );3407 .True, // Don't null terminate. Bytes has the sentinel, if any.
3377 },3408 );
3378 .str_lit => {3409 },
3379 const str_lit = tv.val.castTag(.str_lit).?.data;3410 .str_lit => {
3380 const bytes = dg.module.string_literal_bytes.items[str_lit.index..][0..str_lit.len];3411 const str_lit = tv.val.castTag(.str_lit).?.data;
3381 if (tv.ty.sentinel(mod)) |sent_val| {3412 const bytes = dg.module.string_literal_bytes.items[str_lit.index..][0..str_lit.len];
3382 const byte = @intCast(u8, sent_val.toUnsignedInt(mod));3413 if (tv.ty.sentinel(mod)) |sent_val| {
3383 if (byte == 0 and bytes.len > 0) {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 return dg.context.constString(3433 return dg.context.constString(
3385 bytes.ptr,3434 bytes.ptr,
3386 @intCast(c_uint, bytes.len),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);3439 },
3391 defer array.deinit();3440 .aggregate => {
3392 try array.ensureUnusedCapacity(bytes.len + 1);3441 const elem_vals = tv.val.castTag(.aggregate).?.data;
3393 array.appendSliceAssumeCapacity(bytes);3442 const elem_ty = tv.ty.childType(mod);
3394 array.appendAssumeCapacity(byte);3443 const gpa = dg.gpa;
3395 return dg.context.constString(3444 const len = @intCast(usize, tv.ty.arrayLenIncludingSentinel(mod));
3396 array.items.ptr,3445 const llvm_elems = try gpa.alloc(*llvm.Value, len);
3397 @intCast(c_uint, array.items.len),3446 defer gpa.free(llvm_elems);
3398 .True, // Don't null terminate.3447 var need_unnamed = false;
3399 );3448 for (elem_vals[0..len], 0..) |elem_val, i| {
3400 } else {3449 llvm_elems[i] = try dg.lowerValue(.{ .ty = elem_ty, .val = elem_val });
3401 return dg.context.constString(3450 need_unnamed = need_unnamed or dg.isUnnamedType(elem_ty, llvm_elems[i]);
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 });
3448 }3451 }
3449 need_unnamed = need_unnamed or dg.isUnnamedType(elem_ty, llvm_elems[0]);3452 if (need_unnamed) {
3450 }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);
34513475
3452 if (sentinel) |sent| {3476 var need_unnamed = false;
3453 llvm_elems[len] = try dg.lowerValue(.{ .ty = elem_ty, .val = sent });3477 if (len != 0) {
3454 need_unnamed = need_unnamed or dg.isUnnamedType(elem_ty, llvm_elems[len]);3478 for (llvm_elems[0..len]) |*elem| {
3455 }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 }
34563483
3457 if (need_unnamed) {3484 if (sentinel) |sent| {
3458 return dg.context.constStruct(3485 llvm_elems[len] = try dg.lowerValue(.{ .ty = elem_ty, .val = sent });
3459 llvm_elems.ptr,3486 need_unnamed = need_unnamed or dg.isUnnamedType(elem_ty, llvm_elems[len]);
3460 @intCast(c_uint, llvm_elems.len),3487 }
3461 .True,3488
3462 );3489 if (need_unnamed) {
3463 } else {3490 return dg.context.constStruct(
3464 const llvm_elem_ty = try dg.lowerType(elem_ty);3491 llvm_elems.ptr,
3465 return llvm_elem_ty.constArray(3492 @intCast(c_uint, llvm_elems.len),
3466 llvm_elems.ptr,3493 .True,
3467 @intCast(c_uint, llvm_elems.len),3494 );
3468 );3495 } else {
3469 }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 => {3518 else => switch (mod.intern_pool.indexToKey(tv.val.ip_index)) {
3472 const elem_ty = tv.ty.childType(mod);3519 .aggregate => |aggregate| switch (aggregate.storage) {
3473 const sent_val = tv.ty.sentinel(mod).?;3520 .elems => |elem_vals| {
3474 const sentinel = try dg.lowerValue(.{ .ty = elem_ty, .val = sent_val });3521 const elem_ty = tv.ty.childType(mod);
3475 const llvm_elems: [1]*llvm.Value = .{sentinel};3522 const gpa = dg.gpa;
3476 const need_unnamed = dg.isUnnamedType(elem_ty, llvm_elems[0]);3523 const llvm_elems = try gpa.alloc(*llvm.Value, elem_vals.len);
3477 if (need_unnamed) {3524 defer gpa.free(llvm_elems);
3478 return dg.context.constStruct(&llvm_elems, llvm_elems.len, .True);3525 var need_unnamed = false;
3479 } else {3526 for (elem_vals, 0..) |elem_val, i| {
3480 const llvm_elem_ty = try dg.lowerType(elem_ty);3527 llvm_elems[i] = try dg.lowerValue(.{ .ty = elem_ty, .val = elem_val.toValue() });
3481 return llvm_elem_ty.constArray(&llvm_elems, llvm_elems.len);3528 need_unnamed = need_unnamed or dg.isUnnamedType(elem_ty, llvm_elems[i]);
3482 }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 .Optional => {3584 .Optional => {
3487 comptime assert(optional_layout_version == 3);3585 comptime assert(optional_layout_version == 3);
...@@ -3494,15 +3592,22 @@ pub const DeclGen = struct {...@@ -3494,15 +3592,22 @@ pub const DeclGen = struct {
3494 return non_null_bit;3592 return non_null_bit;
3495 }3593 }
3496 const llvm_ty = try dg.lowerType(tv.ty);3594 const llvm_ty = try dg.lowerType(tv.ty);
3497 if (tv.ty.optionalReprIsPayload(mod)) {3595 if (tv.ty.optionalReprIsPayload(mod)) return switch (tv.val.ip_index) {
3498 if (tv.val.castTag(.opt_payload)) |payload| {3596 .none => if (tv.val.castTag(.opt_payload)) |payload|
3499 return dg.lowerValue(.{ .ty = payload_ty, .val = payload.data });3597 try dg.lowerValue(.{ .ty = payload_ty, .val = payload.data })
3500 } else if (is_pl) {3598 else if (is_pl)
3501 return dg.lowerValue(.{ .ty = payload_ty, .val = tv.val });3599 try dg.lowerValue(.{ .ty = payload_ty, .val = tv.val })
3502 } else {3600 else
3503 return llvm_ty.constNull();3601 llvm_ty.constNull(),
3504 }3602 .null_value => llvm_ty.constNull(),
3505 }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 assert(payload_ty.zigTypeTag(mod) != .Fn);3611 assert(payload_ty.zigTypeTag(mod) != .Fn);
35073612
3508 const llvm_field_count = llvm_ty.countStructElementTypes();3613 const llvm_field_count = llvm_ty.countStructElementTypes();
...@@ -3589,7 +3694,6 @@ pub const DeclGen = struct {...@@ -3589,7 +3694,6 @@ pub const DeclGen = struct {
3589 },3694 },
3590 .Struct => {3695 .Struct => {
3591 const llvm_struct_ty = try dg.lowerType(tv.ty);3696 const llvm_struct_ty = try dg.lowerType(tv.ty);
3592 const field_vals = tv.val.castTag(.aggregate).?.data;
3593 const gpa = dg.gpa;3697 const gpa = dg.gpa;
35943698
3595 const struct_type = switch (mod.intern_pool.indexToKey(tv.ty.ip_index)) {3699 const struct_type = switch (mod.intern_pool.indexToKey(tv.ty.ip_index)) {
...@@ -3623,7 +3727,7 @@ pub const DeclGen = struct {...@@ -3623,7 +3727,7 @@ pub const DeclGen = struct {
36233727
3624 const field_llvm_val = try dg.lowerValue(.{3728 const field_llvm_val = try dg.lowerValue(.{
3625 .ty = field_ty.toType(),3729 .ty = field_ty.toType(),
3626 .val = field_vals[i],3730 .val = try tv.val.fieldValue(field_ty.toType(), mod, i),
3627 });3731 });
36283732
3629 need_unnamed = need_unnamed or dg.isUnnamedType(field_ty.toType(), field_llvm_val);3733 need_unnamed = need_unnamed or dg.isUnnamedType(field_ty.toType(), field_llvm_val);
...@@ -3669,13 +3773,12 @@ pub const DeclGen = struct {...@@ -3669,13 +3773,12 @@ pub const DeclGen = struct {
3669 comptime assert(Type.packed_struct_layout_version == 2);3773 comptime assert(Type.packed_struct_layout_version == 2);
3670 var running_int: *llvm.Value = int_llvm_ty.constNull();3774 var running_int: *llvm.Value = int_llvm_ty.constNull();
3671 var running_bits: u16 = 0;3775 var running_bits: u16 = 0;
3672 for (field_vals, 0..) |field_val, i| {3776 for (fields, 0..) |field, i| {
3673 const field = fields[i];
3674 if (!field.ty.hasRuntimeBitsIgnoreComptime(mod)) continue;3777 if (!field.ty.hasRuntimeBitsIgnoreComptime(mod)) continue;
36753778
3676 const non_int_val = try dg.lowerValue(.{3779 const non_int_val = try dg.lowerValue(.{
3677 .ty = field.ty,3780 .ty = field.ty,
3678 .val = field_val,3781 .val = try tv.val.fieldValue(field.ty, mod, i),
3679 });3782 });
3680 const ty_bit_size = @intCast(u16, field.ty.bitSize(mod));3783 const ty_bit_size = @intCast(u16, field.ty.bitSize(mod));
3681 const small_int_ty = dg.context.intType(ty_bit_size);3784 const small_int_ty = dg.context.intType(ty_bit_size);
...@@ -3722,7 +3825,7 @@ pub const DeclGen = struct {...@@ -3722,7 +3825,7 @@ pub const DeclGen = struct {
37223825
3723 const field_llvm_val = try dg.lowerValue(.{3826 const field_llvm_val = try dg.lowerValue(.{
3724 .ty = field.ty,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 });
37273830
3728 need_unnamed = need_unnamed or dg.isUnnamedType(field.ty, field_llvm_val);3831 need_unnamed = need_unnamed or dg.isUnnamedType(field.ty, field_llvm_val);
...@@ -3756,7 +3859,13 @@ pub const DeclGen = struct {...@@ -3756,7 +3859,13 @@ pub const DeclGen = struct {
3756 },3859 },
3757 .Union => {3860 .Union => {
3758 const llvm_union_ty = try dg.lowerType(tv.ty);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 };
37603869
3761 const layout = tv.ty.unionGetLayout(mod);3870 const layout = tv.ty.unionGetLayout(mod);
37623871
src/value.zig+92-16
...@@ -602,6 +602,73 @@ pub const Value = struct {...@@ -602,6 +602,73 @@ pub const Value = struct {
602 return result;602 return result;
603 }603 }
604604
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 pub fn toIntern(val: Value) InternPool.Index {672 pub fn toIntern(val: Value) InternPool.Index {
606 assert(val.ip_index != .none);673 assert(val.ip_index != .none);
607 return val.ip_index;674 return val.ip_index;
...@@ -2002,11 +2069,11 @@ pub const Value = struct {...@@ -2002,11 +2069,11 @@ pub const Value = struct {
20022069
2003 const ptr_ty = ty.slicePtrFieldType(mod);2070 const ptr_ty = ty.slicePtrFieldType(mod);
2004 const a_ptr = switch (a_ty.ptrSize(mod)) {2071 const a_ptr = switch (a_ty.ptrSize(mod)) {
2005 .Slice => a.slicePtr(),2072 .Slice => a.slicePtr(mod),
2006 .One => a,2073 .One => a,
2007 else => unreachable,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 .Many, .C, .One => {},2078 .Many, .C, .One => {},
2012 },2079 },
...@@ -2429,7 +2496,8 @@ pub const Value = struct {...@@ -2429,7 +2496,8 @@ pub const Value = struct {
2429 }2496 }
2430 }2497 }
24312498
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 return switch (val.tag()) {2501 return switch (val.tag()) {
2434 .slice => val.castTag(.slice).?.data.ptr,2502 .slice => val.castTag(.slice).?.data.ptr,
2435 // TODO this should require being a slice tag, and not allow decl_ref, field_ptr, etc.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,6 +2507,7 @@ pub const Value = struct {
2439 }2507 }
24402508
2441 pub fn sliceLen(val: Value, mod: *Module) u64 {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 return switch (val.tag()) {2511 return switch (val.tag()) {
2443 .slice => val.castTag(.slice).?.data.len.toUnsignedInt(mod),2512 .slice => val.castTag(.slice).?.data.len.toUnsignedInt(mod),
2444 .decl_ref => {2513 .decl_ref => {
...@@ -2531,7 +2600,19 @@ pub const Value = struct {...@@ -2531,7 +2600,19 @@ pub const Value = struct {
25312600
2532 else => unreachable,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 }
25372618
...@@ -2675,6 +2756,7 @@ pub const Value = struct {...@@ -2675,6 +2756,7 @@ pub const Value = struct {
2675 }2756 }
26762757
2677 pub fn unionTag(val: Value, mod: *Module) Value {2758 pub fn unionTag(val: Value, mod: *Module) Value {
2759 if (val.ip_index == .none) return val.castTag(.@"union").?.data.tag;
2678 return switch (mod.intern_pool.indexToKey(val.ip_index)) {2760 return switch (mod.intern_pool.indexToKey(val.ip_index)) {
2679 .undef, .enum_tag => val,2761 .undef, .enum_tag => val,
2680 .un => |un| un.tag.toValue(),2762 .un => |un| un.tag.toValue(),
...@@ -2696,7 +2778,7 @@ pub const Value = struct {...@@ -2696,7 +2778,7 @@ pub const Value = struct {
2696 else => val,2778 else => val,
2697 };2779 };
26982780
2699 if (ptr_val.tag() == .elem_ptr) {2781 if (ptr_val.ip_index == .none and ptr_val.tag() == .elem_ptr) {
2700 const elem_ptr = ptr_val.castTag(.elem_ptr).?.data;2782 const elem_ptr = ptr_val.castTag(.elem_ptr).?.data;
2701 if (elem_ptr.elem_ty.eql(elem_ty, mod)) {2783 if (elem_ptr.elem_ty.eql(elem_ty, mod)) {
2702 return Tag.elem_ptr.create(arena, .{2784 return Tag.elem_ptr.create(arena, .{
...@@ -4809,10 +4891,12 @@ pub const Value = struct {...@@ -4809,10 +4891,12 @@ pub const Value = struct {
4809 pub const base_tag = Tag.@"union";4891 pub const base_tag = Tag.@"union";
48104892
4811 base: Payload = .{ .tag = base_tag },4893 base: Payload = .{ .tag = base_tag },
4812 data: struct {4894 data: Data,
4895
4896 pub const Data = struct {
4813 tag: Value,4897 tag: Value,
4814 val: Value,4898 val: Value,
4815 },4899 };
4816 };4900 };
4817 };4901 };
48184902
...@@ -4844,15 +4928,7 @@ pub const Value = struct {...@@ -4844,15 +4928,7 @@ pub const Value = struct {
4844 return if (x) one else zero;4928 return if (x) one else zero;
4845 }4929 }
48464930
4847 pub const RuntimeIndex = enum(u32) {4931 pub const RuntimeIndex = InternPool.RuntimeIndex;
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 };
48564932
4857 /// This function is used in the debugger pretty formatters in tools/ to fetch the4933 /// This function is used in the debugger pretty formatters in tools/ to fetch the
4858 /// Tag to Payload mapping to facilitate fancy debug printing for this type.4934 /// Tag to Payload mapping to facilitate fancy debug printing for this type.