Commit d40b83de45
Changed files (6)
src/codegen/llvm.zig
@@ -3396,7 +3396,7 @@ pub const DeclGen = struct {
const llvm_ptr_val = switch (ptr.addr) {
.decl => |decl| try dg.lowerDeclRefValue(ptr_tv, decl),
.mut_decl => |mut_decl| try dg.lowerDeclRefValue(ptr_tv, mut_decl.decl),
- .int => |int| dg.lowerIntAsPtr(mod.intern_pool.indexToKey(int).int),
+ .int => |int| try dg.lowerIntAsPtr(mod.intern_pool.indexToKey(int)),
.eu_payload,
.opt_payload,
.elem,
@@ -3796,11 +3796,20 @@ pub const DeclGen = struct {
}
}
- fn lowerIntAsPtr(dg: *DeclGen, int: InternPool.Key.Int) *llvm.Value {
- var bigint_space: Value.BigIntSpace = undefined;
- const bigint = int.storage.toBigInt(&bigint_space);
- const llvm_int = lowerBigInt(dg, Type.usize, bigint);
- return llvm_int.constIntToPtr(dg.context.pointerType(0));
+ fn lowerIntAsPtr(dg: *DeclGen, int_key: InternPool.Key) Error!*llvm.Value {
+ switch (int_key) {
+ .undef => {
+ const llvm_usize = try dg.lowerType(Type.usize);
+ return llvm_usize.getUndef();
+ },
+ .int => |int| {
+ var bigint_space: Value.BigIntSpace = undefined;
+ const bigint = int.storage.toBigInt(&bigint_space);
+ const llvm_int = lowerBigInt(dg, Type.usize, bigint);
+ return llvm_int.constIntToPtr(dg.context.pointerType(0));
+ },
+ else => unreachable,
+ }
}
fn lowerBigInt(dg: *DeclGen, ty: Type, bigint: std.math.big.int.Const) *llvm.Value {
@@ -3848,11 +3857,11 @@ pub const DeclGen = struct {
const mod = dg.module;
const target = mod.getTarget();
return switch (mod.intern_pool.indexToKey(ptr_val.toIntern())) {
- .int => |int| dg.lowerIntAsPtr(int),
+ .int => |int| dg.lowerIntAsPtr(.{ .int = int }),
.ptr => |ptr| switch (ptr.addr) {
.decl => |decl| dg.lowerParentPtrDecl(ptr_val, decl),
.mut_decl => |mut_decl| dg.lowerParentPtrDecl(ptr_val, mut_decl.decl),
- .int => |int| dg.lowerIntAsPtr(mod.intern_pool.indexToKey(int).int),
+ .int => |int| dg.lowerIntAsPtr(mod.intern_pool.indexToKey(int)),
.eu_payload => |eu_ptr| {
const parent_llvm_ptr = try dg.lowerParentPtr(eu_ptr.toValue(), true);
src/InternPool.zig
@@ -4250,6 +4250,8 @@ pub fn sliceLen(ip: InternPool, i: Index) Index {
/// * int <=> enum
/// * enum_literal => enum
/// * ptr <=> ptr
+/// * opt ptr <=> ptr
+/// * opt ptr <=> opt ptr
/// * int => ptr
/// * null_value => opt
/// * payload => opt
@@ -4258,9 +4260,6 @@ pub fn sliceLen(ip: InternPool, i: Index) Index {
/// * error set => error union
/// * payload => error union
/// * fn <=> fn
-/// * array <=> array
-/// * array <=> vector
-/// * vector <=> vector
pub fn getCoerced(ip: *InternPool, gpa: Allocator, val: Index, new_ty: Index) Allocator.Error!Index {
const old_ty = ip.typeOf(val);
if (old_ty == new_ty) return val;
@@ -4270,6 +4269,15 @@ pub fn getCoerced(ip: *InternPool, gpa: Allocator, val: Index, new_ty: Index) Al
return ip.get(gpa, .{ .opt = .{
.ty = new_ty,
.val = .none,
+ } })
+ else if (ip.isPointerType(new_ty))
+ return ip.get(gpa, .{ .ptr = .{
+ .ty = new_ty,
+ .addr = .{ .int = .zero_usize },
+ .len = switch (ip.indexToKey(new_ty).ptr_type.size) {
+ .One, .Many, .C => .none,
+ .Slice => try ip.get(gpa, .{ .undef = .usize_type }),
+ },
} }),
else => switch (ip.indexToKey(val)) {
.undef => return ip.get(gpa, .{ .undef = new_ty }),
@@ -4320,6 +4328,18 @@ pub fn getCoerced(ip: *InternPool, gpa: Allocator, val: Index, new_ty: Index) Al
.addr = ptr.addr,
.len = ptr.len,
} }),
+ .opt => |opt| if (ip.isPointerType(new_ty))
+ return switch (opt.val) {
+ .none => try ip.get(gpa, .{ .ptr = .{
+ .ty = new_ty,
+ .addr = .{ .int = .zero_usize },
+ .len = switch (ip.indexToKey(new_ty).ptr_type.size) {
+ .One, .Many, .C => .none,
+ .Slice => try ip.get(gpa, .{ .undef = .usize_type }),
+ },
+ } }),
+ else => try ip.getCoerced(gpa, opt.val, new_ty),
+ },
.err => |err| if (ip.isErrorSetType(new_ty))
return ip.get(gpa, .{ .err = .{
.ty = new_ty,
@@ -4335,14 +4355,6 @@ pub fn getCoerced(ip: *InternPool, gpa: Allocator, val: Index, new_ty: Index) Al
.ty = new_ty,
.val = error_union.val,
} }),
- .aggregate => |aggregate| return ip.get(gpa, .{ .aggregate = .{
- .ty = new_ty,
- .storage = switch (aggregate.storage) {
- .bytes => |bytes| .{ .bytes = bytes[0..@intCast(usize, ip.aggregateTypeLen(new_ty))] },
- .elems => |elems| .{ .elems = elems[0..@intCast(usize, ip.aggregateTypeLen(new_ty))] },
- .repeated_elem => |elem| .{ .repeated_elem = elem },
- },
- } }),
else => {},
},
}
@@ -4364,8 +4376,10 @@ pub fn getCoerced(ip: *InternPool, gpa: Allocator, val: Index, new_ty: Index) Al
else => {},
}
if (std.debug.runtime_safety) {
- std.debug.panic("val={any} new_ty={any}\n", .{
- ip.items.get(@enumToInt(val)), ip.items.get(@enumToInt(new_ty)),
+ std.debug.panic("InternPool.getCoerced of {s} not implemented from {s} to {s}", .{
+ @tagName(ip.indexToKey(val)),
+ @tagName(ip.indexToKey(old_ty)),
+ @tagName(ip.indexToKey(new_ty)),
});
}
unreachable;
@@ -4507,6 +4521,13 @@ pub fn isErrorUnionType(ip: InternPool, ty: Index) bool {
return ip.indexToKey(ty) == .error_union_type;
}
+pub fn isAggregateType(ip: InternPool, ty: Index) bool {
+ return switch (ip.indexToKey(ty)) {
+ .array_wype, .vector_type, .anon_struct_type, .struct_type => true,
+ else => false,
+ };
+}
+
/// The is only legal because the initializer is not part of the hash.
pub fn mutateVarInit(ip: *InternPool, index: Index, init_index: Index) void {
assert(ip.items.items(.tag)[@enumToInt(index)] == .variable);
src/Sema.zig
@@ -6381,8 +6381,7 @@ fn zirCall(
var input_is_error = false;
const block_index = @intCast(Air.Inst.Index, block.instructions.items.len);
- const func_ty_info = mod.typeToFunc(func_ty).?;
- const fn_params_len = func_ty_info.param_types.len;
+ const fn_params_len = mod.typeToFunc(func_ty).?.param_types.len;
const parent_comptime = block.is_comptime;
// `extra_index` and `arg_index` are separate since the bound function is passed as the first argument.
var extra_index: usize = 0;
@@ -6391,6 +6390,7 @@ fn zirCall(
extra_index += 1;
arg_index += 1;
}) {
+ const func_ty_info = mod.typeToFunc(func_ty).?;
const arg_end = sema.code.extra[extra.end + extra_index];
defer arg_start = arg_end;
@@ -6876,7 +6876,11 @@ fn analyzeCall(
.args_count = @intCast(u32, func_ty_info.param_types.len),
};
var delete_memoized_call_key = false;
- defer if (delete_memoized_call_key) mod.memoized_call_args.shrinkRetainingCapacity(memoized_call_key.args_index);
+ defer if (delete_memoized_call_key) {
+ assert(mod.memoized_call_args.items.len >= memoized_call_key.args_index and
+ mod.memoized_call_args.items.len < memoized_call_key.args_index + memoized_call_key.args_count);
+ mod.memoized_call_args.shrinkRetainingCapacity(memoized_call_key.args_index);
+ };
if (is_comptime_call) {
try mod.memoized_call_args.ensureUnusedCapacity(gpa, memoized_call_key.args_count);
delete_memoized_call_key = true;
@@ -6990,14 +6994,22 @@ fn analyzeCall(
.{ .args = &mod.memoized_call_args },
);
if (gop.found_existing) {
+ assert(mod.memoized_call_args.items.len == memoized_call_key.args_index + memoized_call_key.args_count);
+ mod.memoized_call_args.shrinkRetainingCapacity(memoized_call_key.args_index);
+ delete_memoized_call_key = false;
+
// We need to use the original memoized error set instead of fn_ret_ty.
const result = gop.value_ptr.*;
assert(result != .none); // recursive memoization?
+
break :res2 try sema.addConstant(mod.intern_pool.typeOf(result).toType(), result.toValue());
}
gop.value_ptr.* = .none;
- delete_memoized_call_key = false;
+ } else if (delete_memoized_call_key) {
+ assert(mod.memoized_call_args.items.len == memoized_call_key.args_index + memoized_call_key.args_count);
+ mod.memoized_call_args.shrinkRetainingCapacity(memoized_call_key.args_index);
}
+ delete_memoized_call_key = false;
const new_func_resolved_ty = try mod.funcType(new_fn_info);
if (!is_comptime_call and !block.is_typeof) {
@@ -14324,13 +14336,14 @@ fn zirOverflowArithmetic(
const maybe_rhs_val = try sema.resolveMaybeUndefVal(rhs);
const tuple_ty = try sema.overflowArithmeticTupleType(dest_ty);
+ const overflow_ty = mod.intern_pool.indexToKey(tuple_ty.toIntern()).anon_struct_type.types[1].toType();
var result: struct {
inst: Air.Inst.Ref = .none,
wrapped: Value = Value.@"unreachable",
overflow_bit: Value,
} = result: {
- const zero = try mod.intValue(dest_ty.scalarType(mod), 0);
+ const zero_bit = try mod.intValue(Type.u1, 0);
switch (zir_tag) {
.add_with_overflow => {
// If either of the arguments is zero, `false` is returned and the other is stored
@@ -14338,12 +14351,12 @@ fn zirOverflowArithmetic(
// Otherwise, if either of the argument is undefined, undefined is returned.
if (maybe_lhs_val) |lhs_val| {
if (!lhs_val.isUndef(mod) and (try lhs_val.compareAllWithZeroAdvanced(.eq, sema))) {
- break :result .{ .overflow_bit = try sema.splat(dest_ty, zero), .inst = rhs };
+ break :result .{ .overflow_bit = try sema.splat(overflow_ty, zero_bit), .inst = rhs };
}
}
if (maybe_rhs_val) |rhs_val| {
if (!rhs_val.isUndef(mod) and (try rhs_val.compareAllWithZeroAdvanced(.eq, sema))) {
- break :result .{ .overflow_bit = try sema.splat(dest_ty, zero), .inst = lhs };
+ break :result .{ .overflow_bit = try sema.splat(overflow_ty, zero_bit), .inst = lhs };
}
}
if (maybe_lhs_val) |lhs_val| {
@@ -14364,7 +14377,7 @@ fn zirOverflowArithmetic(
if (rhs_val.isUndef(mod)) {
break :result .{ .overflow_bit = Value.undef, .wrapped = Value.undef };
} else if (try rhs_val.compareAllWithZeroAdvanced(.eq, sema)) {
- break :result .{ .overflow_bit = try sema.splat(dest_ty, zero), .inst = lhs };
+ break :result .{ .overflow_bit = try sema.splat(overflow_ty, zero_bit), .inst = lhs };
} else if (maybe_lhs_val) |lhs_val| {
if (lhs_val.isUndef(mod)) {
break :result .{ .overflow_bit = Value.undef, .wrapped = Value.undef };
@@ -14383,9 +14396,9 @@ fn zirOverflowArithmetic(
if (maybe_lhs_val) |lhs_val| {
if (!lhs_val.isUndef(mod)) {
if (try lhs_val.compareAllWithZeroAdvanced(.eq, sema)) {
- break :result .{ .overflow_bit = try sema.splat(dest_ty, zero), .inst = lhs };
+ break :result .{ .overflow_bit = try sema.splat(overflow_ty, zero_bit), .inst = lhs };
} else if (try sema.compareAll(lhs_val, .eq, try sema.splat(dest_ty, scalar_one), dest_ty)) {
- break :result .{ .overflow_bit = try sema.splat(dest_ty, zero), .inst = rhs };
+ break :result .{ .overflow_bit = try sema.splat(overflow_ty, zero_bit), .inst = rhs };
}
}
}
@@ -14393,9 +14406,9 @@ fn zirOverflowArithmetic(
if (maybe_rhs_val) |rhs_val| {
if (!rhs_val.isUndef(mod)) {
if (try rhs_val.compareAllWithZeroAdvanced(.eq, sema)) {
- break :result .{ .overflow_bit = try sema.splat(dest_ty, zero), .inst = rhs };
+ break :result .{ .overflow_bit = try sema.splat(overflow_ty, zero_bit), .inst = rhs };
} else if (try sema.compareAll(rhs_val, .eq, try sema.splat(dest_ty, scalar_one), dest_ty)) {
- break :result .{ .overflow_bit = try sema.splat(dest_ty, zero), .inst = lhs };
+ break :result .{ .overflow_bit = try sema.splat(overflow_ty, zero_bit), .inst = lhs };
}
}
}
@@ -14417,12 +14430,12 @@ fn zirOverflowArithmetic(
// Oterhwise if either of the arguments is undefined, both results are undefined.
if (maybe_lhs_val) |lhs_val| {
if (!lhs_val.isUndef(mod) and (try lhs_val.compareAllWithZeroAdvanced(.eq, sema))) {
- break :result .{ .overflow_bit = try sema.splat(dest_ty, zero), .inst = lhs };
+ break :result .{ .overflow_bit = try sema.splat(overflow_ty, zero_bit), .inst = lhs };
}
}
if (maybe_rhs_val) |rhs_val| {
if (!rhs_val.isUndef(mod) and (try rhs_val.compareAllWithZeroAdvanced(.eq, sema))) {
- break :result .{ .overflow_bit = try sema.splat(dest_ty, zero), .inst = lhs };
+ break :result .{ .overflow_bit = try sema.splat(overflow_ty, zero_bit), .inst = lhs };
}
}
if (maybe_lhs_val) |lhs_val| {
@@ -14922,13 +14935,18 @@ fn analyzeArithmetic(
.ComptimeInt, .Int => try mod.intValue(scalar_type, 0),
else => unreachable,
};
+ const scalar_one = switch (scalar_tag) {
+ .ComptimeFloat, .Float => try mod.floatValue(scalar_type, 1.0),
+ .ComptimeInt, .Int => try mod.intValue(scalar_type, 1),
+ else => unreachable,
+ };
if (maybe_lhs_val) |lhs_val| {
if (!lhs_val.isUndef(mod)) {
if (try lhs_val.compareAllWithZeroAdvanced(.eq, sema)) {
const zero_val = try sema.splat(resolved_type, scalar_zero);
return sema.addConstant(resolved_type, zero_val);
}
- if (try sema.compareAll(lhs_val, .eq, try mod.intValue(resolved_type, 1), resolved_type)) {
+ if (try sema.compareAll(lhs_val, .eq, try sema.splat(resolved_type, scalar_one), resolved_type)) {
return casted_rhs;
}
}
@@ -14941,7 +14959,7 @@ fn analyzeArithmetic(
const zero_val = try sema.splat(resolved_type, scalar_zero);
return sema.addConstant(resolved_type, zero_val);
}
- if (try sema.compareAll(rhs_val, .eq, try mod.intValue(resolved_type, 1), resolved_type)) {
+ if (try sema.compareAll(rhs_val, .eq, try sema.splat(resolved_type, scalar_one), resolved_type)) {
return casted_lhs;
}
if (maybe_lhs_val) |lhs_val| {
@@ -19219,10 +19237,9 @@ fn zirReify(
try names.ensureUnusedCapacity(sema.arena, len);
for (0..len) |i| {
const elem_val = try payload_val.elemValue(mod, i);
- const struct_val = elem_val.castTag(.aggregate).?.data;
- // TODO use reflection instead of magic numbers here
- // error_set: type,
- const name_val = struct_val[0];
+ const elem_fields = ip.typeOf(elem_val.toIntern()).toType().structFields(mod);
+ const name_val = try elem_val.fieldValue(mod, elem_fields.getIndex("name").?);
+
const name_str = try name_val.toAllocatedBytes(Type.slice_const_u8, sema.arena, mod);
const name_ip = try mod.intern_pool.getOrPutString(gpa, name_str);
const gop = names.getOrPutAssumeCapacity(name_ip);
@@ -19303,12 +19320,9 @@ fn zirReify(
for (0..fields_len) |field_i| {
const elem_val = try fields_val.elemValue(mod, field_i);
- const field_struct_val: []const Value = elem_val.castTag(.aggregate).?.data;
- // TODO use reflection instead of magic numbers here
- // name: []const u8
- const name_val = field_struct_val[0];
- // value: comptime_int
- const value_val = field_struct_val[1];
+ const elem_fields = ip.typeOf(elem_val.toIntern()).toType().structFields(mod);
+ const name_val = try elem_val.fieldValue(mod, elem_fields.getIndex("name").?);
+ const value_val = try elem_val.fieldValue(mod, elem_fields.getIndex("value").?);
const field_name = try name_val.toAllocatedBytes(
Type.slice_const_u8,
@@ -19485,14 +19499,10 @@ fn zirReify(
for (0..fields_len) |i| {
const elem_val = try fields_val.elemValue(mod, i);
- const field_struct_val = elem_val.castTag(.aggregate).?.data;
- // TODO use reflection instead of magic numbers here
- // name: []const u8
- const name_val = field_struct_val[0];
- // type: type,
- const type_val = field_struct_val[1];
- // alignment: comptime_int,
- const alignment_val = field_struct_val[2];
+ const elem_fields = ip.typeOf(elem_val.toIntern()).toType().structFields(mod);
+ const name_val = try elem_val.fieldValue(mod, elem_fields.getIndex("name").?);
+ const type_val = try elem_val.fieldValue(mod, elem_fields.getIndex("type").?);
+ const alignment_val = try elem_val.fieldValue(mod, elem_fields.getIndex("alignment").?);
const field_name = try name_val.toAllocatedBytes(
Type.slice_const_u8,
@@ -19635,25 +19645,21 @@ fn zirReify(
var noalias_bits: u32 = 0;
for (param_types, 0..) |*param_type, i| {
- const arg = try params_val.elemValue(mod, i);
- const arg_val = arg.castTag(.aggregate).?.data;
- // TODO use reflection instead of magic numbers here
- // is_generic: bool,
- const arg_is_generic = arg_val[0].toBool();
- // is_noalias: bool,
- const arg_is_noalias = arg_val[1].toBool();
- // type: ?type,
- const param_type_opt_val = arg_val[2];
+ const elem_val = try params_val.elemValue(mod, i);
+ const elem_fields = ip.typeOf(elem_val.toIntern()).toType().structFields(mod);
+ const param_is_generic_val = try elem_val.fieldValue(mod, elem_fields.getIndex("is_generic").?);
+ const param_is_noalias_val = try elem_val.fieldValue(mod, elem_fields.getIndex("is_noalias").?);
+ const opt_param_type_val = try elem_val.fieldValue(mod, elem_fields.getIndex("type").?);
- if (arg_is_generic) {
+ if (param_is_generic_val.toBool()) {
return sema.fail(block, src, "Type.Fn.Param.is_generic must be false for @Type", .{});
}
- const param_type_val = param_type_opt_val.optionalValue(mod) orelse
+ const param_type_val = opt_param_type_val.optionalValue(mod) orelse
return sema.fail(block, src, "Type.Fn.Param.arg_type must be non-null for @Type", .{});
param_type.* = param_type_val.toIntern();
- if (arg_is_noalias) {
+ if (param_is_noalias_val.toBool()) {
if (!param_type.toType().isPtrAtRuntime(mod)) {
return sema.fail(block, src, "non-pointer parameter declared noalias", .{});
}
@@ -19748,19 +19754,13 @@ fn reifyStruct(
try struct_obj.fields.ensureTotalCapacity(new_decl_arena_allocator, fields_len);
var i: usize = 0;
while (i < fields_len) : (i += 1) {
- const elem_val = try fields_val.elemValue(sema.mod, i);
- const field_struct_val = elem_val.castTag(.aggregate).?.data;
- // TODO use reflection instead of magic numbers here
- // name: []const u8
- const name_val = field_struct_val[0];
- // type: type,
- const type_val = field_struct_val[1];
- // default_value: ?*const anyopaque,
- const default_value_val = field_struct_val[2];
- // is_comptime: bool,
- const is_comptime_val = field_struct_val[3];
- // alignment: comptime_int,
- const alignment_val = field_struct_val[4];
+ const elem_val = try fields_val.elemValue(mod, i);
+ const elem_fields = mod.intern_pool.typeOf(elem_val.toIntern()).toType().structFields(mod);
+ const name_val = try elem_val.fieldValue(mod, elem_fields.getIndex("name").?);
+ const type_val = try elem_val.fieldValue(mod, elem_fields.getIndex("type").?);
+ const default_value_val = try elem_val.fieldValue(mod, elem_fields.getIndex("default_value").?);
+ const is_comptime_val = try elem_val.fieldValue(mod, elem_fields.getIndex("is_comptime").?);
+ const alignment_val = try elem_val.fieldValue(mod, elem_fields.getIndex("alignment").?);
if (!try sema.intFitsInType(alignment_val, Type.u32, null)) {
return sema.fail(block, src, "alignment must fit in 'u32'", .{});
@@ -19806,18 +19806,16 @@ fn reifyStruct(
return sema.fail(block, src, "duplicate struct field {s}", .{field_name});
}
- const default_val = if (default_value_val.optionalValue(mod)) |opt_val| blk: {
- const payload_val = if (opt_val.pointerDecl(mod)) |opt_decl|
- mod.declPtr(opt_decl).val
- else
- opt_val;
- break :blk try payload_val.copy(new_decl_arena_allocator);
- } else Value.@"unreachable";
+ const field_ty = type_val.toType();
+ const default_val = if (default_value_val.optionalValue(mod)) |opt_val|
+ try sema.pointerDeref(block, src, opt_val, try mod.singleConstPtrType(field_ty)) orelse
+ return sema.failWithNeededComptime(block, src, "struct field default value must be comptime-known")
+ else
+ Value.@"unreachable";
if (is_comptime_val.toBool() and default_val.toIntern() == .unreachable_value) {
return sema.fail(block, src, "comptime field without default initialization value", .{});
}
- const field_ty = type_val.toType();
gop.value_ptr.* = .{
.ty = field_ty,
.abi_align = abi_align,
@@ -20386,17 +20384,7 @@ fn zirPtrCast(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air
if (!dest_ty.ptrAllowsZero(mod) and operand_val.isNull(mod)) {
return sema.fail(block, operand_src, "null pointer casted to type '{}'", .{dest_ty.fmt(mod)});
}
- return sema.addConstant(aligned_dest_ty, try mod.getCoerced(switch (mod.intern_pool.indexToKey(operand_val.toIntern())) {
- .undef, .ptr => operand_val,
- .opt => |opt| switch (opt.val) {
- .none => if (dest_ty.ptrAllowsZero(mod))
- Value.zero_usize
- else
- return sema.fail(block, operand_src, "null pointer casted to type '{}'", .{dest_ty.fmt(mod)}),
- else => opt.val.toValue(),
- },
- else => unreachable,
- }, aligned_dest_ty));
+ return sema.addConstant(aligned_dest_ty, try mod.getCoerced(operand_val, aligned_dest_ty));
}
try sema.requireRuntimeBlock(block, src, null);
@@ -20569,7 +20557,7 @@ fn zirAlignCast(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!A
return sema.fail(block, ptr_src, "pointer address 0x{X} is not aligned to {d} bytes", .{ addr, dest_align });
}
}
- return sema.addConstant(dest_ty, val);
+ return sema.addConstant(dest_ty, try mod.getCoerced(val, dest_ty));
}
try sema.requireRuntimeBlock(block, inst_data.src(), ptr_src);
@@ -20700,7 +20688,7 @@ fn zirByteSwap(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Ai
const elems = try sema.arena.alloc(InternPool.Index, vec_len);
for (elems, 0..) |*elem, i| {
const elem_val = try val.elemValue(mod, i);
- elem.* = try (try elem_val.byteSwap(operand_ty, mod, sema.arena)).intern(scalar_ty, mod);
+ elem.* = try (try elem_val.byteSwap(scalar_ty, mod, sema.arena)).intern(scalar_ty, mod);
}
return sema.addConstant(operand_ty, (try mod.intern(.{ .aggregate = .{
.ty = operand_ty.toIntern(),
@@ -25128,12 +25116,18 @@ fn tupleFieldValByIndex(
}
if (try sema.resolveMaybeUndefVal(tuple_byval)) |tuple_val| {
- if (tuple_val.isUndef(mod)) return sema.addConstUndef(field_ty);
if ((try sema.typeHasOnePossibleValue(field_ty))) |opv| {
return sema.addConstant(field_ty, opv);
}
- const field_values = tuple_val.castTag(.aggregate).?.data;
- return sema.addConstant(field_ty, field_values[field_index]);
+ return switch (mod.intern_pool.indexToKey(tuple_val.toIntern())) {
+ .undef => sema.addConstUndef(field_ty),
+ .aggregate => |aggregate| sema.addConstant(field_ty, switch (aggregate.storage) {
+ .bytes => |bytes| try mod.intValue(Type.u8, bytes[0]),
+ .elems => |elems| elems[field_index].toValue(),
+ .repeated_elem => |elem| elem.toValue(),
+ }),
+ else => unreachable,
+ };
}
if (try tuple_ty.structFieldValueComptime(mod, field_index)) |default_val| {
@@ -25883,7 +25877,7 @@ fn coerceExtra(
var in_memory_result = try sema.coerceInMemoryAllowed(block, dest_ty, inst_ty, false, target, dest_ty_src, inst_src);
if (in_memory_result == .ok) {
if (maybe_inst_val) |val| {
- return sema.addConstant(dest_ty, try mod.getCoerced(val, dest_ty));
+ return sema.coerceInMemory(block, val, inst_ty, dest_ty, dest_ty_src);
}
try sema.requireRuntimeBlock(block, inst_src, null);
return block.addBitCast(dest_ty, inst);
@@ -26072,7 +26066,7 @@ fn coerceExtra(
// coercion to C pointer
.C => switch (inst_ty.zigTypeTag(mod)) {
.Null => {
- return sema.addConstant(dest_ty, Value.null);
+ return sema.addConstant(dest_ty, try mod.getCoerced(Value.null, dest_ty));
},
.ComptimeInt => {
const addr = sema.coerceExtra(block, Type.usize, inst, inst_src, .{ .report_err = false }) catch |err| switch (err) {
@@ -26548,6 +26542,68 @@ fn coerceExtra(
return sema.failWithOwnedErrorMsg(msg);
}
+fn coerceInMemory(
+ sema: *Sema,
+ block: *Block,
+ val: Value,
+ src_ty: Type,
+ dst_ty: Type,
+ dst_ty_src: LazySrcLoc,
+) CompileError!Air.Inst.Ref {
+ const mod = sema.mod;
+ switch (mod.intern_pool.indexToKey(val.toIntern())) {
+ .aggregate => |aggregate| {
+ const dst_ty_key = mod.intern_pool.indexToKey(dst_ty.toIntern());
+ const dest_len = try sema.usizeCast(
+ block,
+ dst_ty_src,
+ mod.intern_pool.aggregateTypeLen(dst_ty.toIntern()),
+ );
+ direct: {
+ const src_ty_child = switch (mod.intern_pool.indexToKey(src_ty.toIntern())) {
+ inline .array_type, .vector_type => |seq_type| seq_type.child,
+ .anon_struct_type, .struct_type => break :direct,
+ else => unreachable,
+ };
+ const dst_ty_child = switch (dst_ty_key) {
+ inline .array_type, .vector_type => |seq_type| seq_type.child,
+ .anon_struct_type, .struct_type => break :direct,
+ else => unreachable,
+ };
+ if (src_ty_child != dst_ty_child) break :direct;
+ return try sema.addConstant(dst_ty, (try mod.intern(.{ .aggregate = .{
+ .ty = dst_ty.toIntern(),
+ .storage = switch (aggregate.storage) {
+ .bytes => |bytes| .{ .bytes = bytes[0..dest_len] },
+ .elems => |elems| .{ .elems = elems[0..dest_len] },
+ .repeated_elem => |elem| .{ .repeated_elem = elem },
+ },
+ } })).toValue());
+ }
+ const dest_elems = try sema.arena.alloc(InternPool.Index, dest_len);
+ for (dest_elems, 0..) |*dest_elem, i| {
+ const elem_ty = switch (dst_ty_key) {
+ inline .array_type, .vector_type => |seq_type| seq_type.child,
+ .anon_struct_type => |anon_struct_type| anon_struct_type.types[i],
+ .struct_type => |struct_type| mod.structPtrUnwrap(struct_type.index).?
+ .fields.values()[i].ty.toIntern(),
+ else => unreachable,
+ };
+ dest_elem.* = try mod.intern_pool.getCoerced(mod.gpa, switch (aggregate.storage) {
+ .bytes => |bytes| (try mod.intValue(Type.u8, bytes[i])).toIntern(),
+ .elems => |elems| elems[i],
+ .repeated_elem => |elem| elem,
+ }, elem_ty);
+ }
+ return sema.addConstant(dst_ty, (try mod.intern(.{ .aggregate = .{
+ .ty = dst_ty.toIntern(),
+ .storage = .{ .elems = dest_elems },
+ } })).toValue());
+ },
+ else => return sema.addConstant(dst_ty, try mod.getCoerced(val, dst_ty)),
+ }
+}
+
const InMemoryCoercionResult = union(enum) {
ok,
no_match: Pair,
@@ -28619,7 +28675,11 @@ fn coerceArrayPtrToSlice(
const array_ty = ptr_array_ty.childType(mod);
const slice_val = try mod.intern(.{ .ptr = .{
.ty = dest_ty.toIntern(),
- .addr = mod.intern_pool.indexToKey(val.toIntern()).ptr.addr,
+ .addr = switch (mod.intern_pool.indexToKey(val.toIntern())) {
+ .undef => .{ .int = try mod.intern(.{ .undef = .usize_type }) },
+ .ptr => |ptr| ptr.addr,
+ else => unreachable,
+ },
.len = (try mod.intValue(Type.usize, array_ty.arrayLen(mod))).toIntern(),
} });
return sema.addConstant(dest_ty, slice_val.toValue());
@@ -28962,7 +29022,7 @@ fn coerceArrayLike(
if (in_memory_result == .ok) {
if (try sema.resolveMaybeUndefVal(inst)) |inst_val| {
// These types share the same comptime value representation.
- return sema.addConstant(dest_ty, try mod.getCoerced(inst_val, dest_ty));
+ return sema.coerceInMemory(block, inst_val, inst_ty, dest_ty, dest_ty_src);
}
try sema.requireRuntimeBlock(block, inst_src, null);
return block.addBitCast(dest_ty, inst);
@@ -33599,9 +33659,8 @@ fn typePtrOrOptionalPtrTy(sema: *Sema, ty: Type) !?Type {
const mod = sema.mod;
return switch (mod.intern_pool.indexToKey(ty.toIntern())) {
.ptr_type => |ptr_type| switch (ptr_type.size) {
+ .One, .Many, .C => ty,
.Slice => null,
- .C => ptr_type.elem_type.toType(),
- .One, .Many => ty,
},
.opt_type => |opt_child| switch (mod.intern_pool.indexToKey(opt_child)) {
.ptr_type => |ptr_type| switch (ptr_type.size) {
src/type.zig
@@ -2788,7 +2788,7 @@ pub const Type = struct {
// Works for vectors and vectors of integers.
pub fn minInt(ty: Type, mod: *Module, dest_ty: Type) !Value {
- const scalar = try minIntScalar(ty.scalarType(mod), mod, dest_ty);
+ const scalar = try minIntScalar(ty.scalarType(mod), mod, dest_ty.scalarType(mod));
return if (ty.zigTypeTag(mod) == .Vector) (try mod.intern(.{ .aggregate = .{
.ty = dest_ty.toIntern(),
.storage = .{ .repeated_elem = scalar.toIntern() },
@@ -2817,7 +2817,7 @@ pub const Type = struct {
// Works for vectors and vectors of integers.
/// The returned Value will have type dest_ty.
pub fn maxInt(ty: Type, mod: *Module, dest_ty: Type) !Value {
- const scalar = try maxIntScalar(ty.scalarType(mod), mod, dest_ty);
+ const scalar = try maxIntScalar(ty.scalarType(mod), mod, dest_ty.scalarType(mod));
return if (ty.zigTypeTag(mod) == .Vector) (try mod.intern(.{ .aggregate = .{
.ty = dest_ty.toIntern(),
.storage = .{ .repeated_elem = scalar.toIntern() },
src/value.zig
@@ -2340,16 +2340,16 @@ pub const Value = struct {
const lhs_elem = try lhs.elemValue(mod, i);
const rhs_elem = try rhs.elemValue(mod, i);
const of_math_result = try intMulWithOverflowScalar(lhs_elem, rhs_elem, scalar_ty, arena, mod);
- of.* = try of_math_result.overflow_bit.intern(Type.bool, mod);
+ of.* = try of_math_result.overflow_bit.intern(Type.u1, mod);
scalar.* = try of_math_result.wrapped_result.intern(scalar_ty, mod);
}
return OverflowArithmeticResult{
.overflow_bit = (try mod.intern(.{ .aggregate = .{
- .ty = ty.toIntern(),
+ .ty = (try mod.vectorType(.{ .len = vec_len, .child = .u1_type })).toIntern(),
.storage = .{ .elems = overflowed_data },
} })).toValue(),
.wrapped_result = (try mod.intern(.{ .aggregate = .{
- .ty = (try mod.vectorType(.{ .len = vec_len, .child = .u1_type })).toIntern(),
+ .ty = ty.toIntern(),
.storage = .{ .elems = result_data },
} })).toValue(),
};
@@ -3090,16 +3090,16 @@ pub const Value = struct {
const lhs_elem = try lhs.elemValue(mod, i);
const rhs_elem = try rhs.elemValue(mod, i);
const of_math_result = try shlWithOverflowScalar(lhs_elem, rhs_elem, scalar_ty, allocator, mod);
- of.* = try of_math_result.overflow_bit.intern(Type.bool, mod);
+ of.* = try of_math_result.overflow_bit.intern(Type.u1, mod);
scalar.* = try of_math_result.wrapped_result.intern(scalar_ty, mod);
}
return OverflowArithmeticResult{
.overflow_bit = (try mod.intern(.{ .aggregate = .{
- .ty = ty.toIntern(),
+ .ty = (try mod.vectorType(.{ .len = vec_len, .child = .u1_type })).toIntern(),
.storage = .{ .elems = overflowed_data },
} })).toValue(),
.wrapped_result = (try mod.intern(.{ .aggregate = .{
- .ty = (try mod.vectorType(.{ .len = vec_len, .child = .u1_type })).toIntern(),
+ .ty = ty.toIntern(),
.storage = .{ .elems = result_data },
} })).toValue(),
};
test/behavior/bugs/6456.zig
@@ -24,7 +24,7 @@ test "issue 6456" {
.alignment = 0,
.name = name,
.type = usize,
- .default_value = &@as(?usize, null),
+ .default_value = null,
.is_comptime = false,
}};
}