wip: progress towards compiling tests

This commit is contained in:
mlugg 2023-05-07 15:23:12 +01:00 committed by Andrew Kelley
parent 9d9e1a2991
commit c1ca16d779
5 changed files with 213 additions and 134 deletions

View file

@ -934,9 +934,12 @@ pub const Decl = struct {
pub fn isExtern(decl: Decl) bool { pub fn isExtern(decl: Decl) bool {
assert(decl.has_tv); assert(decl.has_tv);
return switch (decl.val.tag()) { return switch (decl.val.ip_index) {
.extern_fn => true, .none => switch (decl.val.tag()) {
.variable => decl.val.castTag(.variable).?.data.init.ip_index == .unreachable_value, .extern_fn => true,
.variable => decl.val.castTag(.variable).?.data.init.ip_index == .unreachable_value,
else => false,
},
else => false, else => false,
}; };
} }
@ -6833,6 +6836,10 @@ pub fn intType(mod: *Module, signedness: std.builtin.Signedness, bits: u16) Allo
} }
pub fn arrayType(mod: *Module, info: InternPool.Key.ArrayType) Allocator.Error!Type { pub fn arrayType(mod: *Module, info: InternPool.Key.ArrayType) Allocator.Error!Type {
if (std.debug.runtime_safety and info.sentinel != .none) {
const sent_ty = mod.intern_pool.indexToKey(info.sentinel).typeOf();
assert(sent_ty == info.child);
}
const i = try intern(mod, .{ .array_type = info }); const i = try intern(mod, .{ .array_type = info });
return i.toType(); return i.toType();
} }
@ -6848,6 +6855,10 @@ pub fn optionalType(mod: *Module, child_type: InternPool.Index) Allocator.Error!
} }
pub fn ptrType(mod: *Module, info: InternPool.Key.PtrType) Allocator.Error!Type { pub fn ptrType(mod: *Module, info: InternPool.Key.PtrType) Allocator.Error!Type {
if (std.debug.runtime_safety and info.sentinel != .none) {
const sent_ty = mod.intern_pool.indexToKey(info.sentinel).typeOf();
assert(sent_ty == info.elem_type);
}
const i = try intern(mod, .{ .ptr_type = info }); const i = try intern(mod, .{ .ptr_type = info });
return i.toType(); return i.toType();
} }

View file

@ -5146,7 +5146,7 @@ fn addStrLit(sema: *Sema, block: *Block, zir_bytes: []const u8) CompileError!Air
defer anon_decl.deinit(); defer anon_decl.deinit();
const decl_index = try anon_decl.finish( const decl_index = try anon_decl.finish(
try Type.array(anon_decl.arena(), gop.key_ptr.len, Value.zero, Type.u8, mod), try Type.array(anon_decl.arena(), gop.key_ptr.len, try mod.intValue(Type.u8, 0), Type.u8, mod),
try Value.Tag.str_lit.create(anon_decl.arena(), gop.key_ptr.*), try Value.Tag.str_lit.create(anon_decl.arena(), gop.key_ptr.*),
0, // default alignment 0, // default alignment
); );
@ -15567,7 +15567,7 @@ fn zirSizeOf(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air.
=> {}, => {},
} }
const val = try ty.lazyAbiSize(mod, sema.arena); const val = try ty.lazyAbiSize(mod, sema.arena);
if (val.tag() == .lazy_size) { if (val.ip_index == .none and val.tag() == .lazy_size) {
try sema.queueFullTypeResolution(ty); try sema.queueFullTypeResolution(ty);
} }
return sema.addConstant(Type.comptime_int, val); return sema.addConstant(Type.comptime_int, val);
@ -16006,8 +16006,8 @@ fn zirTypeInfo(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Ai
sema.arena, sema.arena,
@enumToInt(info.signedness), @enumToInt(info.signedness),
); );
// bits: comptime_int, // bits: u16,
field_values[1] = try mod.intValue(Type.comptime_int, info.bits); field_values[1] = try mod.intValue(Type.u16, info.bits);
return sema.addConstant( return sema.addConstant(
type_info_ty, type_info_ty,
@ -16019,8 +16019,8 @@ fn zirTypeInfo(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Ai
}, },
.Float => { .Float => {
const field_values = try sema.arena.alloc(Value, 1); const field_values = try sema.arena.alloc(Value, 1);
// bits: comptime_int, // bits: u16,
field_values[0] = try mod.intValue(Type.comptime_int, ty.bitSize(mod)); field_values[0] = try mod.intValue(Type.u16, ty.bitSize(mod));
return sema.addConstant( return sema.addConstant(
type_info_ty, type_info_ty,
@ -25957,7 +25957,21 @@ fn coerceExtra(
if (!opts.report_err) return error.NotCoercible; if (!opts.report_err) return error.NotCoercible;
return sema.fail(block, inst_src, "type '{}' cannot represent integer value '{}'", .{ dest_ty.fmt(sema.mod), val.fmtValue(inst_ty, sema.mod) }); return sema.fail(block, inst_src, "type '{}' cannot represent integer value '{}'", .{ dest_ty.fmt(sema.mod), val.fmtValue(inst_ty, sema.mod) });
} }
return try sema.addConstant(dest_ty, val); const key = mod.intern_pool.indexToKey(val.ip_index);
// If the int is represented as a bigint, copy it so we can safely pass it to `mod.intern`
const int_storage: InternPool.Key.Int.Storage = switch (key.int.storage) {
.u64 => |x| .{ .u64 = x },
.i64 => |x| .{ .i64 = x },
.big_int => |big_int| .{ .big_int = .{
.limbs = try sema.arena.dupe(std.math.big.Limb, big_int.limbs),
.positive = big_int.positive,
} },
};
const new_val = try mod.intern(.{ .int = .{
.ty = dest_ty.ip_index,
.storage = int_storage,
} });
return try sema.addConstant(dest_ty, new_val.toValue());
} }
if (dest_ty.zigTypeTag(mod) == .ComptimeInt) { if (dest_ty.zigTypeTag(mod) == .ComptimeInt) {
if (!opts.report_err) return error.NotCoercible; if (!opts.report_err) return error.NotCoercible;
@ -31061,39 +31075,42 @@ pub fn resolveFnTypes(sema: *Sema, fn_info: Type.Payload.Function.Data) CompileE
/// Make it so that calling hash() and eql() on `val` will not assert due /// Make it so that calling hash() and eql() on `val` will not assert due
/// to a type not having its layout resolved. /// to a type not having its layout resolved.
fn resolveLazyValue(sema: *Sema, val: Value) CompileError!void { fn resolveLazyValue(sema: *Sema, val: Value) CompileError!void {
switch (val.tag()) { switch (val.ip_index) {
.lazy_align => { .none => switch (val.tag()) {
const ty = val.castTag(.lazy_align).?.data; .lazy_align => {
return sema.resolveTypeLayout(ty); const ty = val.castTag(.lazy_align).?.data;
}, return sema.resolveTypeLayout(ty);
.lazy_size => { },
const ty = val.castTag(.lazy_size).?.data; .lazy_size => {
return sema.resolveTypeLayout(ty); const ty = val.castTag(.lazy_size).?.data;
}, return sema.resolveTypeLayout(ty);
.comptime_field_ptr => { },
const field_ptr = val.castTag(.comptime_field_ptr).?.data; .comptime_field_ptr => {
return sema.resolveLazyValue(field_ptr.field_val); const field_ptr = val.castTag(.comptime_field_ptr).?.data;
}, return sema.resolveLazyValue(field_ptr.field_val);
.eu_payload, },
.opt_payload, .eu_payload,
=> { .opt_payload,
const sub_val = val.cast(Value.Payload.SubValue).?.data; => {
return sema.resolveLazyValue(sub_val); const sub_val = val.cast(Value.Payload.SubValue).?.data;
}, return sema.resolveLazyValue(sub_val);
.@"union" => { },
const union_val = val.castTag(.@"union").?.data; .@"union" => {
return sema.resolveLazyValue(union_val.val); const union_val = val.castTag(.@"union").?.data;
}, return sema.resolveLazyValue(union_val.val);
.aggregate => { },
const aggregate = val.castTag(.aggregate).?.data; .aggregate => {
for (aggregate) |elem_val| { const aggregate = val.castTag(.aggregate).?.data;
try sema.resolveLazyValue(elem_val); for (aggregate) |elem_val| {
} try sema.resolveLazyValue(elem_val);
}, }
.slice => { },
const slice = val.castTag(.slice).?.data; .slice => {
try sema.resolveLazyValue(slice.ptr); const slice = val.castTag(.slice).?.data;
return sema.resolveLazyValue(slice.len); try sema.resolveLazyValue(slice.ptr);
return sema.resolveLazyValue(slice.len);
},
else => return,
}, },
else => return, else => return,
} }
@ -31200,7 +31217,7 @@ fn resolveStructLayout(sema: *Sema, ty: Type) CompileError!void {
}; };
for (struct_obj.fields.values(), 0..) |field, i| { for (struct_obj.fields.values(), 0..) |field, i| {
optimized_order[i] = if (!(try sema.typeHasRuntimeBits(field.ty))) optimized_order[i] = if (try sema.typeHasRuntimeBits(field.ty))
@intCast(u32, i) @intCast(u32, i)
else else
Module.Struct.omitted_field; Module.Struct.omitted_field;

View file

@ -2481,7 +2481,7 @@ pub const DeclGen = struct {
log.debug("gen: {s} type: {}, value: {}", .{ log.debug("gen: {s} type: {}, value: {}", .{
decl.name, decl.ty.fmtDebug(), decl.val.fmtDebug(), decl.name, decl.ty.fmtDebug(), decl.val.fmtDebug(),
}); });
assert(decl.val.tag() != .function); assert(decl.val.ip_index != .none or decl.val.tag() != .function);
if (decl.val.castTag(.extern_fn)) |extern_fn| { if (decl.val.castTag(.extern_fn)) |extern_fn| {
_ = try dg.resolveLlvmFunction(extern_fn.data.owner_decl); _ = try dg.resolveLlvmFunction(extern_fn.data.owner_decl);
} else { } else {

View file

@ -2471,7 +2471,7 @@ pub const Type = struct {
pub fn lazyAbiSize(ty: Type, mod: *Module, arena: Allocator) !Value { pub fn lazyAbiSize(ty: Type, mod: *Module, arena: Allocator) !Value {
switch (try ty.abiSizeAdvanced(mod, .{ .lazy = arena })) { switch (try ty.abiSizeAdvanced(mod, .{ .lazy = arena })) {
.val => |val| return val, .val => |val| return val,
.scalar => |x| return mod.intValue(ty, x), .scalar => |x| return mod.intValue(Type.comptime_int, x),
} }
} }
@ -2504,8 +2504,20 @@ pub const Type = struct {
if (int_type.bits == 0) return AbiSizeAdvanced{ .scalar = 0 }; if (int_type.bits == 0) return AbiSizeAdvanced{ .scalar = 0 };
return AbiSizeAdvanced{ .scalar = intAbiSize(int_type.bits, target) }; return AbiSizeAdvanced{ .scalar = intAbiSize(int_type.bits, target) };
}, },
.ptr_type => @panic("TODO"), .ptr_type => |ptr_type| switch (ptr_type.size) {
.array_type => @panic("TODO"), .Slice => return .{ .scalar = @divExact(target.ptrBitWidth(), 8) * 2 },
else => return .{ .scalar = @divExact(target.ptrBitWidth(), 8) },
},
.array_type => |array_type| {
const len = array_type.len + @boolToInt(array_type.sentinel != .none);
switch (try array_type.child.toType().abiSizeAdvanced(mod, strat)) {
.scalar => |elem_size| return .{ .scalar = len * elem_size },
.val => switch (strat) {
.sema, .eager => unreachable,
.lazy => |arena| return .{ .val = try Value.Tag.lazy_size.create(arena, ty) },
},
}
},
.vector_type => |vector_type| { .vector_type => |vector_type| {
const opt_sema = switch (strat) { const opt_sema = switch (strat) {
.sema => |sema| sema, .sema => |sema| sema,
@ -2528,7 +2540,7 @@ pub const Type = struct {
return AbiSizeAdvanced{ .scalar = result }; return AbiSizeAdvanced{ .scalar = result };
}, },
.opt_type => @panic("TODO"), .opt_type => return ty.abiSizeAdvancedOptional(mod, strat),
.error_union_type => @panic("TODO"), .error_union_type => @panic("TODO"),
.simple_type => |t| switch (t) { .simple_type => |t| switch (t) {
.bool, .bool,
@ -2698,39 +2710,7 @@ pub const Type = struct {
.error_set_single, .error_set_single,
=> return AbiSizeAdvanced{ .scalar = 2 }, => return AbiSizeAdvanced{ .scalar = 2 },
.optional => { .optional => return ty.abiSizeAdvancedOptional(mod, strat),
const child_type = ty.optionalChild(mod);
if (child_type.isNoReturn()) {
return AbiSizeAdvanced{ .scalar = 0 };
}
if (!(child_type.hasRuntimeBitsAdvanced(mod, false, strat) catch |err| switch (err) {
error.NeedLazy => return AbiSizeAdvanced{ .val = try Value.Tag.lazy_size.create(strat.lazy, ty) },
else => |e| return e,
})) return AbiSizeAdvanced{ .scalar = 1 };
if (ty.optionalReprIsPayload(mod)) {
return abiSizeAdvanced(child_type, mod, strat);
}
const payload_size = switch (try child_type.abiSizeAdvanced(mod, strat)) {
.scalar => |elem_size| elem_size,
.val => switch (strat) {
.sema => unreachable,
.eager => unreachable,
.lazy => |arena| return AbiSizeAdvanced{ .val = try Value.Tag.lazy_size.create(arena, ty) },
},
};
// Optional types are represented as a struct with the child type as the first
// field and a boolean as the second. Since the child type's abi alignment is
// guaranteed to be >= that of bool's (1 byte) the added size is exactly equal
// to the child type's ABI alignment.
return AbiSizeAdvanced{
.scalar = child_type.abiAlignment(mod) + payload_size,
};
},
.error_union => { .error_union => {
// This code needs to be kept in sync with the equivalent switch prong // This code needs to be kept in sync with the equivalent switch prong
@ -2791,6 +2771,44 @@ pub const Type = struct {
return AbiSizeAdvanced{ .scalar = union_obj.abiSize(mod, have_tag) }; return AbiSizeAdvanced{ .scalar = union_obj.abiSize(mod, have_tag) };
} }
fn abiSizeAdvancedOptional(
ty: Type,
mod: *const Module,
strat: AbiAlignmentAdvancedStrat,
) Module.CompileError!AbiSizeAdvanced {
const child_ty = ty.optionalChild(mod);
if (child_ty.isNoReturn()) {
return AbiSizeAdvanced{ .scalar = 0 };
}
if (!(child_ty.hasRuntimeBitsAdvanced(mod, false, strat) catch |err| switch (err) {
error.NeedLazy => return AbiSizeAdvanced{ .val = try Value.Tag.lazy_size.create(strat.lazy, ty) },
else => |e| return e,
})) return AbiSizeAdvanced{ .scalar = 1 };
if (ty.optionalReprIsPayload(mod)) {
return abiSizeAdvanced(child_ty, mod, strat);
}
const payload_size = switch (try child_ty.abiSizeAdvanced(mod, strat)) {
.scalar => |elem_size| elem_size,
.val => switch (strat) {
.sema => unreachable,
.eager => unreachable,
.lazy => |arena| return AbiSizeAdvanced{ .val = try Value.Tag.lazy_size.create(arena, ty) },
},
};
// Optional types are represented as a struct with the child type as the first
// field and a boolean as the second. Since the child type's abi alignment is
// guaranteed to be >= that of bool's (1 byte) the added size is exactly equal
// to the child type's ABI alignment.
return AbiSizeAdvanced{
.scalar = child_ty.abiAlignment(mod) + payload_size,
};
}
fn intAbiSize(bits: u16, target: Target) u64 { fn intAbiSize(bits: u16, target: Target) u64 {
const alignment = intAbiAlignment(bits, target); const alignment = intAbiAlignment(bits, target);
return std.mem.alignForwardGeneric(u64, @intCast(u16, (@as(u17, bits) + 7) / 8), alignment); return std.mem.alignForwardGeneric(u64, @intCast(u16, (@as(u17, bits) + 7) / 8), alignment);
@ -2819,8 +2837,19 @@ pub const Type = struct {
if (ty.ip_index != .none) switch (mod.intern_pool.indexToKey(ty.ip_index)) { if (ty.ip_index != .none) switch (mod.intern_pool.indexToKey(ty.ip_index)) {
.int_type => |int_type| return int_type.bits, .int_type => |int_type| return int_type.bits,
.ptr_type => @panic("TODO"), .ptr_type => |ptr_type| switch (ptr_type.size) {
.array_type => @panic("TODO"), .Slice => return target.ptrBitWidth() * 2,
else => return target.ptrBitWidth() * 2,
},
.array_type => |array_type| {
const len = array_type.len + @boolToInt(array_type.sentinel != .none);
if (len == 0) return 0;
const elem_ty = array_type.child.toType();
const elem_size = std.math.max(elem_ty.abiAlignment(mod), elem_ty.abiSize(mod));
if (elem_size == 0) return 0;
const elem_bit_size = try bitSizeAdvanced(elem_ty, mod, opt_sema);
return (len - 1) * 8 * elem_size + elem_bit_size;
},
.vector_type => |vector_type| { .vector_type => |vector_type| {
const child_ty = vector_type.child.toType(); const child_ty = vector_type.child.toType();
const elem_bit_size = try bitSizeAdvanced(child_ty, mod, opt_sema); const elem_bit_size = try bitSizeAdvanced(child_ty, mod, opt_sema);
@ -3208,6 +3237,20 @@ pub const Type = struct {
/// See also `isPtrLikeOptional`. /// See also `isPtrLikeOptional`.
pub fn optionalReprIsPayload(ty: Type, mod: *const Module) bool { pub fn optionalReprIsPayload(ty: Type, mod: *const Module) bool {
if (ty.ip_index != .none) return switch (mod.intern_pool.indexToKey(ty.ip_index)) {
.opt_type => |child| switch (child.toType().zigTypeTag(mod)) {
.Pointer => {
const info = child.toType().ptrInfo(mod);
switch (info.size) {
.C => return false,
else => return !info.@"allowzero",
}
},
.ErrorSet => true,
else => false,
},
else => false,
};
switch (ty.tag()) { switch (ty.tag()) {
.optional => { .optional => {
const child_ty = ty.castTag(.optional).?.data; const child_ty = ty.castTag(.optional).?.data;

View file

@ -1832,35 +1832,37 @@ pub const Value = struct {
} }
} }
switch (lhs.tag()) { switch (lhs.ip_index) {
.repeated => return lhs.castTag(.repeated).?.data.compareAllWithZeroAdvancedExtra(op, mod, opt_sema), .none => switch (lhs.tag()) {
.aggregate => { .repeated => return lhs.castTag(.repeated).?.data.compareAllWithZeroAdvancedExtra(op, mod, opt_sema),
for (lhs.castTag(.aggregate).?.data) |elem_val| { .aggregate => {
if (!(try elem_val.compareAllWithZeroAdvancedExtra(op, mod, opt_sema))) return false; for (lhs.castTag(.aggregate).?.data) |elem_val| {
} if (!(try elem_val.compareAllWithZeroAdvancedExtra(op, mod, opt_sema))) return false;
return true; }
return true;
},
.str_lit => {
const str_lit = lhs.castTag(.str_lit).?.data;
const bytes = mod.string_literal_bytes.items[str_lit.index..][0..str_lit.len];
for (bytes) |byte| {
if (!std.math.compare(byte, op, 0)) return false;
}
return true;
},
.bytes => {
const bytes = lhs.castTag(.bytes).?.data;
for (bytes) |byte| {
if (!std.math.compare(byte, op, 0)) return false;
}
return true;
},
.float_16 => if (std.math.isNan(lhs.castTag(.float_16).?.data)) return op == .neq,
.float_32 => if (std.math.isNan(lhs.castTag(.float_32).?.data)) return op == .neq,
.float_64 => if (std.math.isNan(lhs.castTag(.float_64).?.data)) return op == .neq,
.float_80 => if (std.math.isNan(lhs.castTag(.float_80).?.data)) return op == .neq,
.float_128 => if (std.math.isNan(lhs.castTag(.float_128).?.data)) return op == .neq,
else => {},
}, },
.empty_array => return true,
.str_lit => {
const str_lit = lhs.castTag(.str_lit).?.data;
const bytes = mod.string_literal_bytes.items[str_lit.index..][0..str_lit.len];
for (bytes) |byte| {
if (!std.math.compare(byte, op, 0)) return false;
}
return true;
},
.bytes => {
const bytes = lhs.castTag(.bytes).?.data;
for (bytes) |byte| {
if (!std.math.compare(byte, op, 0)) return false;
}
return true;
},
.float_16 => if (std.math.isNan(lhs.castTag(.float_16).?.data)) return op == .neq,
.float_32 => if (std.math.isNan(lhs.castTag(.float_32).?.data)) return op == .neq,
.float_64 => if (std.math.isNan(lhs.castTag(.float_64).?.data)) return op == .neq,
.float_80 => if (std.math.isNan(lhs.castTag(.float_80).?.data)) return op == .neq,
.float_128 => if (std.math.isNan(lhs.castTag(.float_128).?.data)) return op == .neq,
else => {}, else => {},
} }
return (try orderAgainstZeroAdvanced(lhs, mod, opt_sema)).compare(op); return (try orderAgainstZeroAdvanced(lhs, mod, opt_sema)).compare(op);
@ -2404,37 +2406,43 @@ pub const Value = struct {
}; };
pub fn isComptimeMutablePtr(val: Value) bool { pub fn isComptimeMutablePtr(val: Value) bool {
return switch (val.tag()) { return switch (val.ip_index) {
.decl_ref_mut, .comptime_field_ptr => true, .none => switch (val.tag()) {
.elem_ptr => isComptimeMutablePtr(val.castTag(.elem_ptr).?.data.array_ptr), .decl_ref_mut, .comptime_field_ptr => true,
.field_ptr => isComptimeMutablePtr(val.castTag(.field_ptr).?.data.container_ptr), .elem_ptr => isComptimeMutablePtr(val.castTag(.elem_ptr).?.data.array_ptr),
.eu_payload_ptr => isComptimeMutablePtr(val.castTag(.eu_payload_ptr).?.data.container_ptr), .field_ptr => isComptimeMutablePtr(val.castTag(.field_ptr).?.data.container_ptr),
.opt_payload_ptr => isComptimeMutablePtr(val.castTag(.opt_payload_ptr).?.data.container_ptr), .eu_payload_ptr => isComptimeMutablePtr(val.castTag(.eu_payload_ptr).?.data.container_ptr),
.slice => isComptimeMutablePtr(val.castTag(.slice).?.data.ptr), .opt_payload_ptr => isComptimeMutablePtr(val.castTag(.opt_payload_ptr).?.data.container_ptr),
.slice => isComptimeMutablePtr(val.castTag(.slice).?.data.ptr),
else => false,
},
else => false, else => false,
}; };
} }
pub fn canMutateComptimeVarState(val: Value) bool { pub fn canMutateComptimeVarState(val: Value) bool {
if (val.isComptimeMutablePtr()) return true; if (val.isComptimeMutablePtr()) return true;
switch (val.tag()) { return switch (val.ip_index) {
.repeated => return val.castTag(.repeated).?.data.canMutateComptimeVarState(), .none => switch (val.tag()) {
.eu_payload => return val.castTag(.eu_payload).?.data.canMutateComptimeVarState(), .repeated => return val.castTag(.repeated).?.data.canMutateComptimeVarState(),
.eu_payload_ptr => return val.castTag(.eu_payload_ptr).?.data.container_ptr.canMutateComptimeVarState(), .eu_payload => return val.castTag(.eu_payload).?.data.canMutateComptimeVarState(),
.opt_payload => return val.castTag(.opt_payload).?.data.canMutateComptimeVarState(), .eu_payload_ptr => return val.castTag(.eu_payload_ptr).?.data.container_ptr.canMutateComptimeVarState(),
.opt_payload_ptr => return val.castTag(.opt_payload_ptr).?.data.container_ptr.canMutateComptimeVarState(), .opt_payload => return val.castTag(.opt_payload).?.data.canMutateComptimeVarState(),
.aggregate => { .opt_payload_ptr => return val.castTag(.opt_payload_ptr).?.data.container_ptr.canMutateComptimeVarState(),
const fields = val.castTag(.aggregate).?.data; .aggregate => {
for (fields) |field| { const fields = val.castTag(.aggregate).?.data;
if (field.canMutateComptimeVarState()) return true; for (fields) |field| {
} if (field.canMutateComptimeVarState()) return true;
return false; }
return false;
},
.@"union" => return val.cast(Payload.Union).?.data.val.canMutateComptimeVarState(),
.slice => return val.castTag(.slice).?.data.ptr.canMutateComptimeVarState(),
else => return false,
}, },
.@"union" => return val.cast(Payload.Union).?.data.val.canMutateComptimeVarState(),
.slice => return val.castTag(.slice).?.data.ptr.canMutateComptimeVarState(),
else => return false, else => return false,
} };
} }
/// Gets the decl referenced by this pointer. If the pointer does not point /// Gets the decl referenced by this pointer. If the pointer does not point