mirror of
https://github.com/ziglang/zig.git
synced 2026-02-20 00:08:56 +00:00
stage2: improve handling of 0-bit types and arrays
* Make `alloc` AIR instructions call `resolveTypeLayout`. * `Sema.zirResolveInferredAlloc` now calls `requireRuntimeBlock` in the case that it operates on a non-comptime instruction. * `Type.abiSize` and `Type.abiAlignment` now return 0 for `void` * Sema: implement `resolveTypeFields` for unions. * LLVM Backend: support `ptr_elem_ptr` when the element type is 0-bit. * Type: improve `abiAlignment` implementation for structs to properly handle fields with non-default alignment. * Value: implement hashing array, vector, and structs.
This commit is contained in:
parent
b0f80ef0d5
commit
0d4a94f32f
120
src/Sema.zig
120
src/Sema.zig
@ -2035,6 +2035,7 @@ fn zirAllocExtended(
|
||||
.@"addrspace" = target_util.defaultAddressSpace(sema.mod.getTarget(), .local),
|
||||
});
|
||||
try sema.requireRuntimeBlock(block, src);
|
||||
try sema.resolveTypeLayout(block, src, var_ty);
|
||||
return block.addTy(.alloc, ptr_type);
|
||||
}
|
||||
|
||||
@ -2044,8 +2045,8 @@ fn zirAllocComptime(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileErr
|
||||
|
||||
const inst_data = sema.code.instructions.items(.data)[inst].un_node;
|
||||
const ty_src: LazySrcLoc = .{ .node_offset_var_decl_ty = inst_data.src_node };
|
||||
const var_type = try sema.resolveType(block, ty_src, inst_data.operand);
|
||||
return sema.analyzeComptimeAlloc(block, var_type);
|
||||
const var_ty = try sema.resolveType(block, ty_src, inst_data.operand);
|
||||
return sema.analyzeComptimeAlloc(block, var_ty);
|
||||
}
|
||||
|
||||
fn zirAllocInferredComptime(sema: *Sema, inst: Zir.Inst.Index) CompileError!Air.Inst.Ref {
|
||||
@ -2065,15 +2066,16 @@ fn zirAlloc(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air.I
|
||||
const inst_data = sema.code.instructions.items(.data)[inst].un_node;
|
||||
const ty_src: LazySrcLoc = .{ .node_offset_var_decl_ty = inst_data.src_node };
|
||||
const var_decl_src = inst_data.src();
|
||||
const var_type = try sema.resolveType(block, ty_src, inst_data.operand);
|
||||
const var_ty = try sema.resolveType(block, ty_src, inst_data.operand);
|
||||
if (block.is_comptime) {
|
||||
return sema.analyzeComptimeAlloc(block, var_type);
|
||||
return sema.analyzeComptimeAlloc(block, var_ty);
|
||||
}
|
||||
const ptr_type = try Type.ptr(sema.arena, .{
|
||||
.pointee_type = var_type,
|
||||
.pointee_type = var_ty,
|
||||
.@"addrspace" = target_util.defaultAddressSpace(sema.mod.getTarget(), .local),
|
||||
});
|
||||
try sema.requireRuntimeBlock(block, var_decl_src);
|
||||
try sema.resolveTypeLayout(block, ty_src, var_ty);
|
||||
return block.addTy(.alloc, ptr_type);
|
||||
}
|
||||
|
||||
@ -2084,16 +2086,17 @@ fn zirAllocMut(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Ai
|
||||
const inst_data = sema.code.instructions.items(.data)[inst].un_node;
|
||||
const var_decl_src = inst_data.src();
|
||||
const ty_src: LazySrcLoc = .{ .node_offset_var_decl_ty = inst_data.src_node };
|
||||
const var_type = try sema.resolveType(block, ty_src, inst_data.operand);
|
||||
const var_ty = try sema.resolveType(block, ty_src, inst_data.operand);
|
||||
if (block.is_comptime) {
|
||||
return sema.analyzeComptimeAlloc(block, var_type);
|
||||
return sema.analyzeComptimeAlloc(block, var_ty);
|
||||
}
|
||||
try sema.validateVarType(block, ty_src, var_type, false);
|
||||
try sema.validateVarType(block, ty_src, var_ty, false);
|
||||
const ptr_type = try Type.ptr(sema.arena, .{
|
||||
.pointee_type = var_type,
|
||||
.pointee_type = var_ty,
|
||||
.@"addrspace" = target_util.defaultAddressSpace(sema.mod.getTarget(), .local),
|
||||
});
|
||||
try sema.requireRuntimeBlock(block, var_decl_src);
|
||||
try sema.resolveTypeLayout(block, ty_src, var_ty);
|
||||
return block.addTy(.alloc, ptr_type);
|
||||
}
|
||||
|
||||
@ -2135,6 +2138,7 @@ fn zirResolveInferredAlloc(sema: *Sema, block: *Block, inst: Zir.Inst.Index) Com
|
||||
defer tracy.end();
|
||||
|
||||
const inst_data = sema.code.instructions.items(.data)[inst].un_node;
|
||||
const src = inst_data.src();
|
||||
const ty_src: LazySrcLoc = .{ .node_offset_var_decl_ty = inst_data.src_node };
|
||||
const ptr = sema.resolveInst(inst_data.operand);
|
||||
const ptr_inst = Air.refToIndex(ptr).?;
|
||||
@ -2146,46 +2150,53 @@ fn zirResolveInferredAlloc(sema: *Sema, block: *Block, inst: Zir.Inst.Index) Com
|
||||
.inferred_alloc_mut => true,
|
||||
else => unreachable,
|
||||
};
|
||||
const target = sema.mod.getTarget();
|
||||
|
||||
if (ptr_val.castTag(.inferred_alloc_comptime)) |iac| {
|
||||
const decl = iac.data;
|
||||
try sema.mod.declareDeclDependency(sema.owner_decl, decl);
|
||||
switch (ptr_val.tag()) {
|
||||
.inferred_alloc_comptime => {
|
||||
const iac = ptr_val.castTag(.inferred_alloc_comptime).?;
|
||||
const decl = iac.data;
|
||||
try sema.mod.declareDeclDependency(sema.owner_decl, decl);
|
||||
|
||||
const final_elem_ty = try decl.ty.copy(sema.arena);
|
||||
const final_ptr_ty = try Type.ptr(sema.arena, .{
|
||||
.pointee_type = final_elem_ty,
|
||||
.@"addrspace" = target_util.defaultAddressSpace(sema.mod.getTarget(), .local),
|
||||
});
|
||||
const final_ptr_ty_inst = try sema.addType(final_ptr_ty);
|
||||
sema.air_instructions.items(.data)[ptr_inst].ty_pl.ty = final_ptr_ty_inst;
|
||||
|
||||
if (var_is_mut) {
|
||||
sema.air_values.items[value_index] = try Value.Tag.decl_ref_mut.create(sema.arena, .{
|
||||
.decl = decl,
|
||||
.runtime_index = block.runtime_index,
|
||||
const final_elem_ty = try decl.ty.copy(sema.arena);
|
||||
const final_ptr_ty = try Type.ptr(sema.arena, .{
|
||||
.pointee_type = final_elem_ty,
|
||||
.@"addrspace" = target_util.defaultAddressSpace(target, .local),
|
||||
});
|
||||
} else {
|
||||
sema.air_values.items[value_index] = try Value.Tag.decl_ref.create(sema.arena, decl);
|
||||
}
|
||||
return;
|
||||
}
|
||||
const final_ptr_ty_inst = try sema.addType(final_ptr_ty);
|
||||
sema.air_instructions.items(.data)[ptr_inst].ty_pl.ty = final_ptr_ty_inst;
|
||||
|
||||
if (ptr_val.castTag(.inferred_alloc)) |inferred_alloc| {
|
||||
const peer_inst_list = inferred_alloc.data.stored_inst_list.items;
|
||||
const final_elem_ty = try sema.resolvePeerTypes(block, ty_src, peer_inst_list, .none);
|
||||
if (var_is_mut) {
|
||||
try sema.validateVarType(block, ty_src, final_elem_ty, false);
|
||||
}
|
||||
// Change it to a normal alloc.
|
||||
const final_ptr_ty = try Type.ptr(sema.arena, .{
|
||||
.pointee_type = final_elem_ty,
|
||||
.@"addrspace" = target_util.defaultAddressSpace(sema.mod.getTarget(), .local),
|
||||
});
|
||||
sema.air_instructions.set(ptr_inst, .{
|
||||
.tag = .alloc,
|
||||
.data = .{ .ty = final_ptr_ty },
|
||||
});
|
||||
return;
|
||||
if (var_is_mut) {
|
||||
sema.air_values.items[value_index] = try Value.Tag.decl_ref_mut.create(sema.arena, .{
|
||||
.decl = decl,
|
||||
.runtime_index = block.runtime_index,
|
||||
});
|
||||
} else {
|
||||
sema.air_values.items[value_index] = try Value.Tag.decl_ref.create(sema.arena, decl);
|
||||
}
|
||||
},
|
||||
.inferred_alloc => {
|
||||
const inferred_alloc = ptr_val.castTag(.inferred_alloc).?;
|
||||
const peer_inst_list = inferred_alloc.data.stored_inst_list.items;
|
||||
const final_elem_ty = try sema.resolvePeerTypes(block, ty_src, peer_inst_list, .none);
|
||||
|
||||
try sema.requireRuntimeBlock(block, src);
|
||||
try sema.resolveTypeLayout(block, ty_src, final_elem_ty);
|
||||
|
||||
if (var_is_mut) {
|
||||
try sema.validateVarType(block, ty_src, final_elem_ty, false);
|
||||
}
|
||||
// Change it to a normal alloc.
|
||||
const final_ptr_ty = try Type.ptr(sema.arena, .{
|
||||
.pointee_type = final_elem_ty,
|
||||
.@"addrspace" = target_util.defaultAddressSpace(target, .local),
|
||||
});
|
||||
sema.air_instructions.set(ptr_inst, .{
|
||||
.tag = .alloc,
|
||||
.data = .{ .ty = final_ptr_ty },
|
||||
});
|
||||
},
|
||||
else => unreachable,
|
||||
}
|
||||
}
|
||||
|
||||
@ -8844,6 +8855,7 @@ fn zirArrayInit(
|
||||
};
|
||||
|
||||
try sema.requireRuntimeBlock(block, runtime_src);
|
||||
try sema.resolveTypeLayout(block, src, elem_ty);
|
||||
|
||||
const alloc_ty = try Type.ptr(sema.arena, .{
|
||||
.pointee_type = array_ty,
|
||||
@ -10194,6 +10206,7 @@ fn validateVarType(
|
||||
.Enum,
|
||||
.Frame,
|
||||
.AnyFrame,
|
||||
.Void,
|
||||
=> return,
|
||||
|
||||
.BoundFn,
|
||||
@ -10202,7 +10215,6 @@ fn validateVarType(
|
||||
.EnumLiteral,
|
||||
.NoReturn,
|
||||
.Type,
|
||||
.Void,
|
||||
.Undefined,
|
||||
.Null,
|
||||
=> break,
|
||||
@ -12585,6 +12597,22 @@ pub fn resolveTypeLayout(
|
||||
}
|
||||
struct_obj.status = .have_layout;
|
||||
},
|
||||
.Union => {
|
||||
const resolved_ty = try sema.resolveTypeFields(block, src, ty);
|
||||
const union_obj = resolved_ty.cast(Type.Payload.Union).?.data;
|
||||
switch (union_obj.status) {
|
||||
.none, .have_field_types => {},
|
||||
.field_types_wip, .layout_wip => {
|
||||
return sema.fail(block, src, "union {} depends on itself", .{ty});
|
||||
},
|
||||
.have_layout => return,
|
||||
}
|
||||
union_obj.status = .layout_wip;
|
||||
for (union_obj.fields.values()) |field| {
|
||||
try sema.resolveTypeLayout(block, src, field.ty);
|
||||
}
|
||||
union_obj.status = .have_layout;
|
||||
},
|
||||
else => {},
|
||||
}
|
||||
}
|
||||
|
||||
@ -1863,14 +1863,16 @@ pub const FuncGen = struct {
|
||||
}
|
||||
|
||||
fn airPtrElemPtr(self: *FuncGen, inst: Air.Inst.Index) !?*const llvm.Value {
|
||||
if (self.liveness.isUnused(inst))
|
||||
return null;
|
||||
if (self.liveness.isUnused(inst)) return null;
|
||||
|
||||
const ty_pl = self.air.instructions.items(.data)[inst].ty_pl;
|
||||
const bin_op = self.air.extraData(Air.Bin, ty_pl.payload).data;
|
||||
const lhs_ty = self.air.typeOf(bin_op.lhs);
|
||||
if (!lhs_ty.hasCodeGenBits()) return null;
|
||||
|
||||
const base_ptr = try self.resolveInst(bin_op.lhs);
|
||||
const rhs = try self.resolveInst(bin_op.rhs);
|
||||
if (self.air.typeOf(bin_op.lhs).isSinglePointer()) {
|
||||
if (lhs_ty.isSinglePointer()) {
|
||||
// If this is a single-item pointer to an array, we need another index in the GEP.
|
||||
const indices: [2]*const llvm.Value = .{ self.context.intType(32).constNull(), rhs };
|
||||
return self.builder.buildInBoundsGEP(base_ptr, &indices, indices.len, "");
|
||||
|
||||
68
src/type.zig
68
src/type.zig
@ -1579,7 +1579,7 @@ pub const Type = extern union {
|
||||
};
|
||||
}
|
||||
|
||||
/// Asserts that hasCodeGenBits() is true.
|
||||
/// Returns 0 for 0-bit types.
|
||||
pub fn abiAlignment(self: Type, target: Target) u32 {
|
||||
return switch (self.tag()) {
|
||||
.u1,
|
||||
@ -1667,6 +1667,7 @@ pub const Type = extern union {
|
||||
|
||||
.int_signed, .int_unsigned => {
|
||||
const bits: u16 = self.cast(Payload.Bits).?.data;
|
||||
if (bits == 0) return 0;
|
||||
if (bits <= 8) return 1;
|
||||
if (bits <= 16) return 2;
|
||||
if (bits <= 32) return 4;
|
||||
@ -1699,23 +1700,27 @@ pub const Type = extern union {
|
||||
},
|
||||
|
||||
.@"struct" => {
|
||||
// TODO take into account field alignment
|
||||
// also make this possible to fail, and lazy
|
||||
// I think we need to move all the functions from type.zig which can
|
||||
// fail into Sema.
|
||||
// Probably will need to introduce multi-stage struct resolution just
|
||||
// like we have in stage1.
|
||||
const struct_obj = self.castTag(.@"struct").?.data;
|
||||
var biggest: u32 = 0;
|
||||
for (struct_obj.fields.values()) |field| {
|
||||
if (!field.ty.hasCodeGenBits()) continue;
|
||||
const field_align = field.ty.abiAlignment(target);
|
||||
if (field_align > biggest) {
|
||||
return field_align;
|
||||
}
|
||||
const fields = self.structFields();
|
||||
if (self.castTag(.@"struct")) |payload| {
|
||||
const struct_obj = payload.data;
|
||||
assert(struct_obj.status == .have_layout);
|
||||
const is_packed = struct_obj.layout == .Packed;
|
||||
if (is_packed) @panic("TODO packed structs");
|
||||
}
|
||||
assert(biggest != 0);
|
||||
return biggest;
|
||||
var big_align: u32 = 0;
|
||||
for (fields.values()) |field| {
|
||||
if (!field.ty.hasCodeGenBits()) continue;
|
||||
|
||||
const field_align = a: {
|
||||
if (field.abi_align.tag() == .abi_align_default) {
|
||||
break :a field.ty.abiAlignment(target);
|
||||
} else {
|
||||
break :a @intCast(u32, field.abi_align.toUnsignedInt());
|
||||
}
|
||||
};
|
||||
big_align = @maximum(big_align, field_align);
|
||||
}
|
||||
return big_align;
|
||||
},
|
||||
.enum_full, .enum_nonexhaustive, .enum_simple, .enum_numbered => {
|
||||
var buffer: Payload.Bits = undefined;
|
||||
@ -1726,8 +1731,12 @@ pub const Type = extern union {
|
||||
.@"union" => return self.castTag(.@"union").?.data.abiAlignment(target, false),
|
||||
.union_tagged => return self.castTag(.union_tagged).?.data.abiAlignment(target, true),
|
||||
|
||||
.c_void,
|
||||
.empty_struct,
|
||||
.void,
|
||||
=> return 0,
|
||||
|
||||
.empty_struct_literal,
|
||||
.c_void,
|
||||
.type,
|
||||
.comptime_int,
|
||||
.comptime_float,
|
||||
@ -1735,8 +1744,6 @@ pub const Type = extern union {
|
||||
.@"null",
|
||||
.@"undefined",
|
||||
.enum_literal,
|
||||
.empty_struct,
|
||||
.empty_struct_literal,
|
||||
.inferred_alloc_const,
|
||||
.inferred_alloc_mut,
|
||||
.@"opaque",
|
||||
@ -1758,7 +1765,6 @@ pub const Type = extern union {
|
||||
.fn_ccc_void_no_args => unreachable, // represents machine code; not a pointer
|
||||
.function => unreachable, // represents machine code; not a pointer
|
||||
.c_void => unreachable,
|
||||
.void => unreachable,
|
||||
.type => unreachable,
|
||||
.comptime_int => unreachable,
|
||||
.comptime_float => unreachable,
|
||||
@ -1767,7 +1773,6 @@ pub const Type = extern union {
|
||||
.@"undefined" => unreachable,
|
||||
.enum_literal => unreachable,
|
||||
.single_const_pointer_to_comptime_int => unreachable,
|
||||
.empty_struct => unreachable,
|
||||
.empty_struct_literal => unreachable,
|
||||
.inferred_alloc_const => unreachable,
|
||||
.inferred_alloc_mut => unreachable,
|
||||
@ -1777,14 +1782,19 @@ pub const Type = extern union {
|
||||
.type_info => unreachable,
|
||||
.bound_fn => unreachable,
|
||||
|
||||
.empty_struct, .void => 0,
|
||||
|
||||
.@"struct" => {
|
||||
const s = self.castTag(.@"struct").?.data;
|
||||
assert(s.status == .have_layout);
|
||||
const is_packed = s.layout == .Packed;
|
||||
if (is_packed) @panic("TODO packed structs");
|
||||
const fields = self.structFields();
|
||||
if (self.castTag(.@"struct")) |payload| {
|
||||
const struct_obj = payload.data;
|
||||
assert(struct_obj.status == .have_layout);
|
||||
const is_packed = struct_obj.layout == .Packed;
|
||||
if (is_packed) @panic("TODO packed structs");
|
||||
}
|
||||
var size: u64 = 0;
|
||||
var big_align: u32 = 0;
|
||||
for (s.fields.values()) |field| {
|
||||
for (fields.values()) |field| {
|
||||
if (!field.ty.hasCodeGenBits()) continue;
|
||||
|
||||
const field_align = a: {
|
||||
@ -1829,7 +1839,7 @@ pub const Type = extern union {
|
||||
.array_u8_sentinel_0 => self.castTag(.array_u8_sentinel_0).?.data + 1,
|
||||
.array, .vector => {
|
||||
const payload = self.cast(Payload.Array).?.data;
|
||||
const elem_size = std.math.max(payload.elem_type.abiAlignment(target), payload.elem_type.abiSize(target));
|
||||
const elem_size = @maximum(payload.elem_type.abiAlignment(target), payload.elem_type.abiSize(target));
|
||||
return payload.len * elem_size;
|
||||
},
|
||||
.array_sentinel => {
|
||||
@ -3331,6 +3341,7 @@ pub const Type = extern union {
|
||||
|
||||
pub fn structFields(ty: Type) Module.Struct.Fields {
|
||||
switch (ty.tag()) {
|
||||
.empty_struct => return .{},
|
||||
.@"struct" => {
|
||||
const struct_obj = ty.castTag(.@"struct").?.data;
|
||||
return struct_obj.fields;
|
||||
@ -3345,6 +3356,7 @@ pub const Type = extern union {
|
||||
const struct_obj = ty.castTag(.@"struct").?.data;
|
||||
return struct_obj.fields.count();
|
||||
},
|
||||
.empty_struct => return 0,
|
||||
else => unreachable,
|
||||
}
|
||||
}
|
||||
|
||||
@ -1399,6 +1399,7 @@ pub const Value = extern union {
|
||||
|
||||
switch (zig_ty_tag) {
|
||||
.BoundFn => unreachable, // TODO remove this from the language
|
||||
.Opaque => unreachable, // Cannot hash opaque types
|
||||
|
||||
.Void,
|
||||
.NoReturn,
|
||||
@ -1451,10 +1452,22 @@ pub const Value = extern union {
|
||||
else => unreachable,
|
||||
},
|
||||
.Array, .Vector => {
|
||||
@panic("TODO implement hashing array/vector values");
|
||||
const len = ty.arrayLen();
|
||||
const elem_ty = ty.childType();
|
||||
var index: usize = 0;
|
||||
var elem_value_buf: ElemValueBuffer = undefined;
|
||||
while (index < len) : (index += 1) {
|
||||
const elem_val = val.elemValueBuffer(index, &elem_value_buf);
|
||||
elem_val.hash(elem_ty, hasher);
|
||||
}
|
||||
},
|
||||
.Struct => {
|
||||
@panic("TODO implement hashing struct values");
|
||||
const fields = ty.structFields().values();
|
||||
if (fields.len == 0) return;
|
||||
const field_values = val.castTag(.@"struct").?.data;
|
||||
for (field_values) |field_val, i| {
|
||||
field_val.hash(fields[i].ty, hasher);
|
||||
}
|
||||
},
|
||||
.Optional => {
|
||||
if (val.castTag(.opt_payload)) |payload| {
|
||||
@ -1486,7 +1499,7 @@ pub const Value = extern union {
|
||||
}
|
||||
},
|
||||
.Union => {
|
||||
const union_obj = val.castTag(.@"union").?.data;
|
||||
const union_obj = val.cast(Payload.Union).?.data;
|
||||
if (ty.unionTagType()) |tag_ty| {
|
||||
union_obj.tag.hash(tag_ty, hasher);
|
||||
}
|
||||
@ -1496,9 +1509,6 @@ pub const Value = extern union {
|
||||
.Fn => {
|
||||
@panic("TODO implement hashing function values");
|
||||
},
|
||||
.Opaque => {
|
||||
@panic("TODO implement hashing opaque values");
|
||||
},
|
||||
.Frame => {
|
||||
@panic("TODO implement hashing frame values");
|
||||
},
|
||||
@ -1633,7 +1643,22 @@ pub const Value = extern union {
|
||||
|
||||
/// Asserts the value is a single-item pointer to an array, or an array,
|
||||
/// or an unknown-length pointer, and returns the element value at the index.
|
||||
pub fn elemValue(val: Value, arena: *Allocator, index: usize) error{OutOfMemory}!Value {
|
||||
pub fn elemValue(val: Value, arena: *Allocator, index: usize) !Value {
|
||||
return elemValueAdvanced(val, index, arena, undefined);
|
||||
}
|
||||
|
||||
pub const ElemValueBuffer = Payload.U64;
|
||||
|
||||
pub fn elemValueBuffer(val: Value, index: usize, buffer: *ElemValueBuffer) Value {
|
||||
return elemValueAdvanced(val, index, null, buffer) catch unreachable;
|
||||
}
|
||||
|
||||
pub fn elemValueAdvanced(
|
||||
val: Value,
|
||||
index: usize,
|
||||
arena: ?*Allocator,
|
||||
buffer: *ElemValueBuffer,
|
||||
) error{OutOfMemory}!Value {
|
||||
switch (val.tag()) {
|
||||
.empty_array => unreachable, // out of bounds array index
|
||||
.empty_struct_value => unreachable, // out of bounds array index
|
||||
@ -1643,16 +1668,27 @@ pub const Value = extern union {
|
||||
return val.castTag(.empty_array_sentinel).?.data;
|
||||
},
|
||||
|
||||
.bytes => return Tag.int_u64.create(arena, val.castTag(.bytes).?.data[index]),
|
||||
.bytes => {
|
||||
const byte = val.castTag(.bytes).?.data[index];
|
||||
if (arena) |a| {
|
||||
return Tag.int_u64.create(a, byte);
|
||||
} else {
|
||||
buffer.* = .{
|
||||
.base = .{ .tag = .int_u64 },
|
||||
.data = byte,
|
||||
};
|
||||
return initPayload(&buffer.base);
|
||||
}
|
||||
},
|
||||
|
||||
// No matter the index; all the elements are the same!
|
||||
.repeated => return val.castTag(.repeated).?.data,
|
||||
|
||||
.array => return val.castTag(.array).?.data[index],
|
||||
.slice => return val.castTag(.slice).?.data.ptr.elemValue(arena, index),
|
||||
.slice => return val.castTag(.slice).?.data.ptr.elemValueAdvanced(index, arena, buffer),
|
||||
|
||||
.decl_ref => return val.castTag(.decl_ref).?.data.val.elemValue(arena, index),
|
||||
.decl_ref_mut => return val.castTag(.decl_ref_mut).?.data.decl.val.elemValue(arena, index),
|
||||
.decl_ref => return val.castTag(.decl_ref).?.data.val.elemValueAdvanced(index, arena, buffer),
|
||||
.decl_ref_mut => return val.castTag(.decl_ref_mut).?.data.decl.val.elemValueAdvanced(index, arena, buffer),
|
||||
|
||||
else => unreachable,
|
||||
}
|
||||
|
||||
@ -104,3 +104,11 @@ test "array with sentinels" {
|
||||
try S.doTheTest(false);
|
||||
comptime try S.doTheTest(true);
|
||||
}
|
||||
|
||||
test "void arrays" {
|
||||
var array: [4]void = undefined;
|
||||
array[0] = void{};
|
||||
array[1] = array[2];
|
||||
try expect(@sizeOf(@TypeOf(array)) == 0);
|
||||
try expect(array.len == 4);
|
||||
}
|
||||
|
||||
@ -4,14 +4,6 @@ const mem = std.mem;
|
||||
const expect = testing.expect;
|
||||
const expectEqual = testing.expectEqual;
|
||||
|
||||
test "void arrays" {
|
||||
var array: [4]void = undefined;
|
||||
array[0] = void{};
|
||||
array[1] = array[2];
|
||||
try expect(@sizeOf(@TypeOf(array)) == 0);
|
||||
try expect(array.len == 4);
|
||||
}
|
||||
|
||||
test "nested arrays" {
|
||||
const array_of_strings = [_][]const u8{ "hello", "this", "is", "my", "thing" };
|
||||
for (array_of_strings) |s, i| {
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user