mirror of
https://codeberg.org/ziglang/zig.git
synced 2025-12-06 05:44:20 +00:00
stage2: move undef, unreach, null values to InternPool
This commit is contained in:
parent
773fabf361
commit
6ab8b6f8b2
10 changed files with 1492 additions and 1385 deletions
|
|
@ -932,7 +932,7 @@ pub const Decl = struct {
|
|||
assert(decl.has_tv);
|
||||
return switch (decl.val.tag()) {
|
||||
.extern_fn => true,
|
||||
.variable => decl.val.castTag(.variable).?.data.init.tag() == .unreachable_value,
|
||||
.variable => decl.val.castTag(.variable).?.data.init.ip_index == .unreachable_value,
|
||||
else => false,
|
||||
};
|
||||
}
|
||||
|
|
@ -4849,6 +4849,8 @@ fn semaDecl(mod: *Module, decl_index: Decl.Index) !bool {
|
|||
var is_extern = false;
|
||||
switch (decl_tv.val.ip_index) {
|
||||
.generic_poison => unreachable,
|
||||
.unreachable_value => unreachable,
|
||||
|
||||
.none => switch (decl_tv.val.tag()) {
|
||||
.variable => {
|
||||
const variable = decl_tv.val.castTag(.variable).?.data;
|
||||
|
|
@ -4869,8 +4871,6 @@ fn semaDecl(mod: *Module, decl_index: Decl.Index) !bool {
|
|||
}
|
||||
},
|
||||
|
||||
.unreachable_value => unreachable,
|
||||
|
||||
.function => {},
|
||||
|
||||
else => {
|
||||
|
|
@ -6592,7 +6592,7 @@ pub fn populateTestFunctions(
|
|||
.len = try Value.Tag.int_u64.create(arena, test_name_slice.len),
|
||||
}), // name
|
||||
try Value.Tag.decl_ref.create(arena, test_decl_index), // func
|
||||
Value.initTag(.null_value), // async_frame_size
|
||||
Value.null, // async_frame_size
|
||||
};
|
||||
test_fn_vals[i] = try Value.Tag.aggregate.create(arena, field_vals);
|
||||
}
|
||||
|
|
|
|||
1170
src/Sema.zig
1170
src/Sema.zig
File diff suppressed because it is too large
Load diff
|
|
@ -76,34 +76,236 @@ pub fn print(
|
|||
if (val.isVariable(mod))
|
||||
return writer.writeAll("(variable)");
|
||||
|
||||
while (true) switch (val.tag()) {
|
||||
.empty_struct_value, .aggregate => {
|
||||
if (level == 0) {
|
||||
return writer.writeAll(".{ ... }");
|
||||
}
|
||||
if (ty.zigTypeTag(mod) == .Struct) {
|
||||
try writer.writeAll(".{");
|
||||
const max_len = std.math.min(ty.structFieldCount(), max_aggregate_items);
|
||||
while (true) switch (val.ip_index) {
|
||||
.none => switch (val.tag()) {
|
||||
.empty_struct_value, .aggregate => {
|
||||
if (level == 0) {
|
||||
return writer.writeAll(".{ ... }");
|
||||
}
|
||||
if (ty.zigTypeTag(mod) == .Struct) {
|
||||
try writer.writeAll(".{");
|
||||
const max_len = std.math.min(ty.structFieldCount(), max_aggregate_items);
|
||||
|
||||
var i: u32 = 0;
|
||||
while (i < max_len) : (i += 1) {
|
||||
if (i != 0) try writer.writeAll(", ");
|
||||
switch (ty.tag()) {
|
||||
.anon_struct, .@"struct" => try writer.print(".{s} = ", .{ty.structFieldName(i)}),
|
||||
else => {},
|
||||
var i: u32 = 0;
|
||||
while (i < max_len) : (i += 1) {
|
||||
if (i != 0) try writer.writeAll(", ");
|
||||
switch (ty.tag()) {
|
||||
.anon_struct, .@"struct" => try writer.print(".{s} = ", .{ty.structFieldName(i)}),
|
||||
else => {},
|
||||
}
|
||||
try print(.{
|
||||
.ty = ty.structFieldType(i),
|
||||
.val = val.fieldValue(ty, mod, i),
|
||||
}, writer, level - 1, mod);
|
||||
}
|
||||
if (ty.structFieldCount() > max_aggregate_items) {
|
||||
try writer.writeAll(", ...");
|
||||
}
|
||||
return writer.writeAll("}");
|
||||
} else {
|
||||
const elem_ty = ty.elemType2(mod);
|
||||
const len = ty.arrayLen(mod);
|
||||
|
||||
if (elem_ty.eql(Type.u8, mod)) str: {
|
||||
const max_len = @intCast(usize, std.math.min(len, max_string_len));
|
||||
var buf: [max_string_len]u8 = undefined;
|
||||
|
||||
var i: u32 = 0;
|
||||
while (i < max_len) : (i += 1) {
|
||||
const elem = val.fieldValue(ty, mod, i);
|
||||
if (elem.isUndef()) break :str;
|
||||
buf[i] = std.math.cast(u8, elem.toUnsignedInt(mod)) orelse break :str;
|
||||
}
|
||||
|
||||
const truncated = if (len > max_string_len) " (truncated)" else "";
|
||||
return writer.print("\"{}{s}\"", .{ std.zig.fmtEscapes(buf[0..max_len]), truncated });
|
||||
}
|
||||
|
||||
try writer.writeAll(".{ ");
|
||||
|
||||
const max_len = std.math.min(len, max_aggregate_items);
|
||||
var i: u32 = 0;
|
||||
while (i < max_len) : (i += 1) {
|
||||
if (i != 0) try writer.writeAll(", ");
|
||||
try print(.{
|
||||
.ty = elem_ty,
|
||||
.val = val.fieldValue(ty, mod, i),
|
||||
}, writer, level - 1, mod);
|
||||
}
|
||||
if (len > max_aggregate_items) {
|
||||
try writer.writeAll(", ...");
|
||||
}
|
||||
return writer.writeAll(" }");
|
||||
}
|
||||
},
|
||||
.@"union" => {
|
||||
if (level == 0) {
|
||||
return writer.writeAll(".{ ... }");
|
||||
}
|
||||
const union_val = val.castTag(.@"union").?.data;
|
||||
try writer.writeAll(".{ ");
|
||||
|
||||
try print(.{
|
||||
.ty = ty.cast(Type.Payload.Union).?.data.tag_ty,
|
||||
.val = union_val.tag,
|
||||
}, writer, level - 1, mod);
|
||||
try writer.writeAll(" = ");
|
||||
try print(.{
|
||||
.ty = ty.unionFieldType(union_val.tag, mod),
|
||||
.val = union_val.val,
|
||||
}, writer, level - 1, mod);
|
||||
|
||||
return writer.writeAll(" }");
|
||||
},
|
||||
.zero => return writer.writeAll("0"),
|
||||
.one => return writer.writeAll("1"),
|
||||
.the_only_possible_value => return writer.writeAll("0"),
|
||||
.ty => return val.castTag(.ty).?.data.print(writer, mod),
|
||||
.int_u64 => return std.fmt.formatIntValue(val.castTag(.int_u64).?.data, "", .{}, writer),
|
||||
.int_i64 => return std.fmt.formatIntValue(val.castTag(.int_i64).?.data, "", .{}, writer),
|
||||
.int_big_positive => return writer.print("{}", .{val.castTag(.int_big_positive).?.asBigInt()}),
|
||||
.int_big_negative => return writer.print("{}", .{val.castTag(.int_big_negative).?.asBigInt()}),
|
||||
.lazy_align => {
|
||||
const sub_ty = val.castTag(.lazy_align).?.data;
|
||||
const x = sub_ty.abiAlignment(mod);
|
||||
return writer.print("{d}", .{x});
|
||||
},
|
||||
.lazy_size => {
|
||||
const sub_ty = val.castTag(.lazy_size).?.data;
|
||||
const x = sub_ty.abiSize(mod);
|
||||
return writer.print("{d}", .{x});
|
||||
},
|
||||
.function => return writer.print("(function '{s}')", .{
|
||||
mod.declPtr(val.castTag(.function).?.data.owner_decl).name,
|
||||
}),
|
||||
.extern_fn => return writer.writeAll("(extern function)"),
|
||||
.variable => unreachable,
|
||||
.decl_ref_mut => {
|
||||
const decl_index = val.castTag(.decl_ref_mut).?.data.decl_index;
|
||||
const decl = mod.declPtr(decl_index);
|
||||
if (level == 0) {
|
||||
return writer.print("(decl ref mut '{s}')", .{decl.name});
|
||||
}
|
||||
return print(.{
|
||||
.ty = decl.ty,
|
||||
.val = decl.val,
|
||||
}, writer, level - 1, mod);
|
||||
},
|
||||
.decl_ref => {
|
||||
const decl_index = val.castTag(.decl_ref).?.data;
|
||||
const decl = mod.declPtr(decl_index);
|
||||
if (level == 0) {
|
||||
return writer.print("(decl ref '{s}')", .{decl.name});
|
||||
}
|
||||
return print(.{
|
||||
.ty = decl.ty,
|
||||
.val = decl.val,
|
||||
}, writer, level - 1, mod);
|
||||
},
|
||||
.comptime_field_ptr => {
|
||||
const payload = val.castTag(.comptime_field_ptr).?.data;
|
||||
if (level == 0) {
|
||||
return writer.writeAll("(comptime field ptr)");
|
||||
}
|
||||
return print(.{
|
||||
.ty = payload.field_ty,
|
||||
.val = payload.field_val,
|
||||
}, writer, level - 1, mod);
|
||||
},
|
||||
.elem_ptr => {
|
||||
const elem_ptr = val.castTag(.elem_ptr).?.data;
|
||||
try writer.writeAll("&");
|
||||
if (level == 0) {
|
||||
try writer.writeAll("(ptr)");
|
||||
} else {
|
||||
try print(.{
|
||||
.ty = ty.structFieldType(i),
|
||||
.val = val.fieldValue(ty, mod, i),
|
||||
.ty = elem_ptr.elem_ty,
|
||||
.val = elem_ptr.array_ptr,
|
||||
}, writer, level - 1, mod);
|
||||
}
|
||||
if (ty.structFieldCount() > max_aggregate_items) {
|
||||
return writer.print("[{}]", .{elem_ptr.index});
|
||||
},
|
||||
.field_ptr => {
|
||||
const field_ptr = val.castTag(.field_ptr).?.data;
|
||||
try writer.writeAll("&");
|
||||
if (level == 0) {
|
||||
try writer.writeAll("(ptr)");
|
||||
} else {
|
||||
try print(.{
|
||||
.ty = field_ptr.container_ty,
|
||||
.val = field_ptr.container_ptr,
|
||||
}, writer, level - 1, mod);
|
||||
}
|
||||
|
||||
if (field_ptr.container_ty.zigTypeTag(mod) == .Struct) {
|
||||
switch (field_ptr.container_ty.tag()) {
|
||||
.tuple => return writer.print(".@\"{d}\"", .{field_ptr.field_index}),
|
||||
else => {
|
||||
const field_name = field_ptr.container_ty.structFieldName(field_ptr.field_index);
|
||||
return writer.print(".{s}", .{field_name});
|
||||
},
|
||||
}
|
||||
} else if (field_ptr.container_ty.zigTypeTag(mod) == .Union) {
|
||||
const field_name = field_ptr.container_ty.unionFields().keys()[field_ptr.field_index];
|
||||
return writer.print(".{s}", .{field_name});
|
||||
} else if (field_ptr.container_ty.isSlice(mod)) {
|
||||
switch (field_ptr.field_index) {
|
||||
Value.Payload.Slice.ptr_index => return writer.writeAll(".ptr"),
|
||||
Value.Payload.Slice.len_index => return writer.writeAll(".len"),
|
||||
else => unreachable,
|
||||
}
|
||||
}
|
||||
},
|
||||
.empty_array => return writer.writeAll(".{}"),
|
||||
.enum_literal => return writer.print(".{}", .{std.zig.fmtId(val.castTag(.enum_literal).?.data)}),
|
||||
.enum_field_index => {
|
||||
return writer.print(".{s}", .{ty.enumFieldName(val.castTag(.enum_field_index).?.data)});
|
||||
},
|
||||
.bytes => return writer.print("\"{}\"", .{std.zig.fmtEscapes(val.castTag(.bytes).?.data)}),
|
||||
.str_lit => {
|
||||
const str_lit = val.castTag(.str_lit).?.data;
|
||||
const bytes = mod.string_literal_bytes.items[str_lit.index..][0..str_lit.len];
|
||||
return writer.print("\"{}\"", .{std.zig.fmtEscapes(bytes)});
|
||||
},
|
||||
.repeated => {
|
||||
if (level == 0) {
|
||||
return writer.writeAll(".{ ... }");
|
||||
}
|
||||
var i: u32 = 0;
|
||||
try writer.writeAll(".{ ");
|
||||
const elem_tv = TypedValue{
|
||||
.ty = ty.elemType2(mod),
|
||||
.val = val.castTag(.repeated).?.data,
|
||||
};
|
||||
const len = ty.arrayLen(mod);
|
||||
const max_len = std.math.min(len, max_aggregate_items);
|
||||
while (i < max_len) : (i += 1) {
|
||||
if (i != 0) try writer.writeAll(", ");
|
||||
try print(elem_tv, writer, level - 1, mod);
|
||||
}
|
||||
if (len > max_aggregate_items) {
|
||||
try writer.writeAll(", ...");
|
||||
}
|
||||
return writer.writeAll("}");
|
||||
} else {
|
||||
return writer.writeAll(" }");
|
||||
},
|
||||
.empty_array_sentinel => {
|
||||
if (level == 0) {
|
||||
return writer.writeAll(".{ (sentinel) }");
|
||||
}
|
||||
try writer.writeAll(".{ ");
|
||||
try print(.{
|
||||
.ty = ty.elemType2(mod),
|
||||
.val = ty.sentinel(mod).?,
|
||||
}, writer, level - 1, mod);
|
||||
return writer.writeAll(" }");
|
||||
},
|
||||
.slice => {
|
||||
if (level == 0) {
|
||||
return writer.writeAll(".{ ... }");
|
||||
}
|
||||
const payload = val.castTag(.slice).?.data;
|
||||
const elem_ty = ty.elemType2(mod);
|
||||
const len = ty.arrayLen(mod);
|
||||
const len = payload.len.toUnsignedInt(mod);
|
||||
|
||||
if (elem_ty.eql(Type.u8, mod)) str: {
|
||||
const max_len = @intCast(usize, std.math.min(len, max_string_len));
|
||||
|
|
@ -111,11 +313,13 @@ pub fn print(
|
|||
|
||||
var i: u32 = 0;
|
||||
while (i < max_len) : (i += 1) {
|
||||
const elem = val.fieldValue(ty, mod, i);
|
||||
if (elem.isUndef()) break :str;
|
||||
buf[i] = std.math.cast(u8, elem.toUnsignedInt(mod)) orelse break :str;
|
||||
var elem_buf: Value.ElemValueBuffer = undefined;
|
||||
const elem_val = payload.ptr.elemValueBuffer(mod, i, &elem_buf);
|
||||
if (elem_val.isUndef()) break :str;
|
||||
buf[i] = std.math.cast(u8, elem_val.toUnsignedInt(mod)) orelse break :str;
|
||||
}
|
||||
|
||||
// TODO would be nice if this had a bit of unicode awareness.
|
||||
const truncated = if (len > max_string_len) " (truncated)" else "";
|
||||
return writer.print("\"{}{s}\"", .{ std.zig.fmtEscapes(buf[0..max_len]), truncated });
|
||||
}
|
||||
|
|
@ -126,292 +330,91 @@ pub fn print(
|
|||
var i: u32 = 0;
|
||||
while (i < max_len) : (i += 1) {
|
||||
if (i != 0) try writer.writeAll(", ");
|
||||
var buf: Value.ElemValueBuffer = undefined;
|
||||
try print(.{
|
||||
.ty = elem_ty,
|
||||
.val = val.fieldValue(ty, mod, i),
|
||||
.val = payload.ptr.elemValueBuffer(mod, i, &buf),
|
||||
}, writer, level - 1, mod);
|
||||
}
|
||||
if (len > max_aggregate_items) {
|
||||
try writer.writeAll(", ...");
|
||||
}
|
||||
return writer.writeAll(" }");
|
||||
}
|
||||
},
|
||||
.@"union" => {
|
||||
if (level == 0) {
|
||||
return writer.writeAll(".{ ... }");
|
||||
}
|
||||
const union_val = val.castTag(.@"union").?.data;
|
||||
try writer.writeAll(".{ ");
|
||||
},
|
||||
.float_16 => return writer.print("{d}", .{val.castTag(.float_16).?.data}),
|
||||
.float_32 => return writer.print("{d}", .{val.castTag(.float_32).?.data}),
|
||||
.float_64 => return writer.print("{d}", .{val.castTag(.float_64).?.data}),
|
||||
.float_80 => return writer.print("{d}", .{@floatCast(f64, val.castTag(.float_80).?.data)}),
|
||||
.float_128 => return writer.print("{d}", .{@floatCast(f64, val.castTag(.float_128).?.data)}),
|
||||
.@"error" => return writer.print("error.{s}", .{val.castTag(.@"error").?.data.name}),
|
||||
.eu_payload => {
|
||||
val = val.castTag(.eu_payload).?.data;
|
||||
ty = ty.errorUnionPayload();
|
||||
},
|
||||
.opt_payload => {
|
||||
val = val.castTag(.opt_payload).?.data;
|
||||
ty = ty.optionalChild(mod);
|
||||
return print(.{ .ty = ty, .val = val }, writer, level, mod);
|
||||
},
|
||||
.eu_payload_ptr => {
|
||||
try writer.writeAll("&");
|
||||
|
||||
try print(.{
|
||||
.ty = ty.cast(Type.Payload.Union).?.data.tag_ty,
|
||||
.val = union_val.tag,
|
||||
}, writer, level - 1, mod);
|
||||
try writer.writeAll(" = ");
|
||||
try print(.{
|
||||
.ty = ty.unionFieldType(union_val.tag, mod),
|
||||
.val = union_val.val,
|
||||
}, writer, level - 1, mod);
|
||||
const data = val.castTag(.eu_payload_ptr).?.data;
|
||||
|
||||
return writer.writeAll(" }");
|
||||
},
|
||||
.null_value => return writer.writeAll("null"),
|
||||
.undef => return writer.writeAll("undefined"),
|
||||
.zero => return writer.writeAll("0"),
|
||||
.one => return writer.writeAll("1"),
|
||||
.unreachable_value => return writer.writeAll("unreachable"),
|
||||
.the_only_possible_value => return writer.writeAll("0"),
|
||||
.ty => return val.castTag(.ty).?.data.print(writer, mod),
|
||||
.int_u64 => return std.fmt.formatIntValue(val.castTag(.int_u64).?.data, "", .{}, writer),
|
||||
.int_i64 => return std.fmt.formatIntValue(val.castTag(.int_i64).?.data, "", .{}, writer),
|
||||
.int_big_positive => return writer.print("{}", .{val.castTag(.int_big_positive).?.asBigInt()}),
|
||||
.int_big_negative => return writer.print("{}", .{val.castTag(.int_big_negative).?.asBigInt()}),
|
||||
.lazy_align => {
|
||||
const sub_ty = val.castTag(.lazy_align).?.data;
|
||||
const x = sub_ty.abiAlignment(mod);
|
||||
return writer.print("{d}", .{x});
|
||||
},
|
||||
.lazy_size => {
|
||||
const sub_ty = val.castTag(.lazy_size).?.data;
|
||||
const x = sub_ty.abiSize(mod);
|
||||
return writer.print("{d}", .{x});
|
||||
},
|
||||
.function => return writer.print("(function '{s}')", .{
|
||||
mod.declPtr(val.castTag(.function).?.data.owner_decl).name,
|
||||
}),
|
||||
.extern_fn => return writer.writeAll("(extern function)"),
|
||||
.variable => unreachable,
|
||||
.decl_ref_mut => {
|
||||
const decl_index = val.castTag(.decl_ref_mut).?.data.decl_index;
|
||||
const decl = mod.declPtr(decl_index);
|
||||
if (level == 0) {
|
||||
return writer.print("(decl ref mut '{s}')", .{decl.name});
|
||||
}
|
||||
return print(.{
|
||||
.ty = decl.ty,
|
||||
.val = decl.val,
|
||||
}, writer, level - 1, mod);
|
||||
},
|
||||
.decl_ref => {
|
||||
const decl_index = val.castTag(.decl_ref).?.data;
|
||||
const decl = mod.declPtr(decl_index);
|
||||
if (level == 0) {
|
||||
return writer.print("(decl ref '{s}')", .{decl.name});
|
||||
}
|
||||
return print(.{
|
||||
.ty = decl.ty,
|
||||
.val = decl.val,
|
||||
}, writer, level - 1, mod);
|
||||
},
|
||||
.comptime_field_ptr => {
|
||||
const payload = val.castTag(.comptime_field_ptr).?.data;
|
||||
if (level == 0) {
|
||||
return writer.writeAll("(comptime field ptr)");
|
||||
}
|
||||
return print(.{
|
||||
.ty = payload.field_ty,
|
||||
.val = payload.field_val,
|
||||
}, writer, level - 1, mod);
|
||||
},
|
||||
.elem_ptr => {
|
||||
const elem_ptr = val.castTag(.elem_ptr).?.data;
|
||||
try writer.writeAll("&");
|
||||
if (level == 0) {
|
||||
try writer.writeAll("(ptr)");
|
||||
} else {
|
||||
var ty_val: Value.Payload.Ty = .{
|
||||
.base = .{ .tag = .ty },
|
||||
.data = ty,
|
||||
};
|
||||
|
||||
try writer.writeAll("@as(");
|
||||
try print(.{
|
||||
.ty = elem_ptr.elem_ty,
|
||||
.val = elem_ptr.array_ptr,
|
||||
.ty = Type.type,
|
||||
.val = Value.initPayload(&ty_val.base),
|
||||
}, writer, level - 1, mod);
|
||||
}
|
||||
return writer.print("[{}]", .{elem_ptr.index});
|
||||
},
|
||||
.field_ptr => {
|
||||
const field_ptr = val.castTag(.field_ptr).?.data;
|
||||
try writer.writeAll("&");
|
||||
if (level == 0) {
|
||||
try writer.writeAll("(ptr)");
|
||||
} else {
|
||||
|
||||
try writer.writeAll(", &(payload of ");
|
||||
|
||||
try print(.{
|
||||
.ty = field_ptr.container_ty,
|
||||
.val = field_ptr.container_ptr,
|
||||
.ty = mod.singleMutPtrType(data.container_ty) catch @panic("OOM"),
|
||||
.val = data.container_ptr,
|
||||
}, writer, level - 1, mod);
|
||||
}
|
||||
|
||||
if (field_ptr.container_ty.zigTypeTag(mod) == .Struct) {
|
||||
switch (field_ptr.container_ty.tag()) {
|
||||
.tuple => return writer.print(".@\"{d}\"", .{field_ptr.field_index}),
|
||||
else => {
|
||||
const field_name = field_ptr.container_ty.structFieldName(field_ptr.field_index);
|
||||
return writer.print(".{s}", .{field_name});
|
||||
},
|
||||
}
|
||||
} else if (field_ptr.container_ty.zigTypeTag(mod) == .Union) {
|
||||
const field_name = field_ptr.container_ty.unionFields().keys()[field_ptr.field_index];
|
||||
return writer.print(".{s}", .{field_name});
|
||||
} else if (field_ptr.container_ty.isSlice(mod)) {
|
||||
switch (field_ptr.field_index) {
|
||||
Value.Payload.Slice.ptr_index => return writer.writeAll(".ptr"),
|
||||
Value.Payload.Slice.len_index => return writer.writeAll(".len"),
|
||||
else => unreachable,
|
||||
}
|
||||
}
|
||||
},
|
||||
.empty_array => return writer.writeAll(".{}"),
|
||||
.enum_literal => return writer.print(".{}", .{std.zig.fmtId(val.castTag(.enum_literal).?.data)}),
|
||||
.enum_field_index => {
|
||||
return writer.print(".{s}", .{ty.enumFieldName(val.castTag(.enum_field_index).?.data)});
|
||||
},
|
||||
.bytes => return writer.print("\"{}\"", .{std.zig.fmtEscapes(val.castTag(.bytes).?.data)}),
|
||||
.str_lit => {
|
||||
const str_lit = val.castTag(.str_lit).?.data;
|
||||
const bytes = mod.string_literal_bytes.items[str_lit.index..][0..str_lit.len];
|
||||
return writer.print("\"{}\"", .{std.zig.fmtEscapes(bytes)});
|
||||
},
|
||||
.repeated => {
|
||||
if (level == 0) {
|
||||
return writer.writeAll(".{ ... }");
|
||||
}
|
||||
var i: u32 = 0;
|
||||
try writer.writeAll(".{ ");
|
||||
const elem_tv = TypedValue{
|
||||
.ty = ty.elemType2(mod),
|
||||
.val = val.castTag(.repeated).?.data,
|
||||
};
|
||||
const len = ty.arrayLen(mod);
|
||||
const max_len = std.math.min(len, max_aggregate_items);
|
||||
while (i < max_len) : (i += 1) {
|
||||
if (i != 0) try writer.writeAll(", ");
|
||||
try print(elem_tv, writer, level - 1, mod);
|
||||
}
|
||||
if (len > max_aggregate_items) {
|
||||
try writer.writeAll(", ...");
|
||||
}
|
||||
return writer.writeAll(" }");
|
||||
},
|
||||
.empty_array_sentinel => {
|
||||
if (level == 0) {
|
||||
return writer.writeAll(".{ (sentinel) }");
|
||||
}
|
||||
try writer.writeAll(".{ ");
|
||||
try print(.{
|
||||
.ty = ty.elemType2(mod),
|
||||
.val = ty.sentinel(mod).?,
|
||||
}, writer, level - 1, mod);
|
||||
return writer.writeAll(" }");
|
||||
},
|
||||
.slice => {
|
||||
if (level == 0) {
|
||||
return writer.writeAll(".{ ... }");
|
||||
}
|
||||
const payload = val.castTag(.slice).?.data;
|
||||
const elem_ty = ty.elemType2(mod);
|
||||
const len = payload.len.toUnsignedInt(mod);
|
||||
try writer.writeAll("))");
|
||||
return;
|
||||
},
|
||||
.opt_payload_ptr => {
|
||||
const data = val.castTag(.opt_payload_ptr).?.data;
|
||||
|
||||
if (elem_ty.eql(Type.u8, mod)) str: {
|
||||
const max_len = @intCast(usize, std.math.min(len, max_string_len));
|
||||
var buf: [max_string_len]u8 = undefined;
|
||||
var ty_val: Value.Payload.Ty = .{
|
||||
.base = .{ .tag = .ty },
|
||||
.data = ty,
|
||||
};
|
||||
|
||||
var i: u32 = 0;
|
||||
while (i < max_len) : (i += 1) {
|
||||
var elem_buf: Value.ElemValueBuffer = undefined;
|
||||
const elem_val = payload.ptr.elemValueBuffer(mod, i, &elem_buf);
|
||||
if (elem_val.isUndef()) break :str;
|
||||
buf[i] = std.math.cast(u8, elem_val.toUnsignedInt(mod)) orelse break :str;
|
||||
}
|
||||
|
||||
// TODO would be nice if this had a bit of unicode awareness.
|
||||
const truncated = if (len > max_string_len) " (truncated)" else "";
|
||||
return writer.print("\"{}{s}\"", .{ std.zig.fmtEscapes(buf[0..max_len]), truncated });
|
||||
}
|
||||
|
||||
try writer.writeAll(".{ ");
|
||||
|
||||
const max_len = std.math.min(len, max_aggregate_items);
|
||||
var i: u32 = 0;
|
||||
while (i < max_len) : (i += 1) {
|
||||
if (i != 0) try writer.writeAll(", ");
|
||||
var buf: Value.ElemValueBuffer = undefined;
|
||||
try writer.writeAll("@as(");
|
||||
try print(.{
|
||||
.ty = elem_ty,
|
||||
.val = payload.ptr.elemValueBuffer(mod, i, &buf),
|
||||
.ty = Type.type,
|
||||
.val = Value.initPayload(&ty_val.base),
|
||||
}, writer, level - 1, mod);
|
||||
}
|
||||
if (len > max_aggregate_items) {
|
||||
try writer.writeAll(", ...");
|
||||
}
|
||||
return writer.writeAll(" }");
|
||||
|
||||
try writer.writeAll(", &(payload of ");
|
||||
|
||||
try print(.{
|
||||
.ty = mod.singleMutPtrType(data.container_ty) catch @panic("OOM"),
|
||||
.val = data.container_ptr,
|
||||
}, writer, level - 1, mod);
|
||||
|
||||
try writer.writeAll("))");
|
||||
return;
|
||||
},
|
||||
|
||||
// TODO these should not appear in this function
|
||||
.inferred_alloc => return writer.writeAll("(inferred allocation value)"),
|
||||
.inferred_alloc_comptime => return writer.writeAll("(inferred comptime allocation value)"),
|
||||
.runtime_value => return writer.writeAll("[runtime value]"),
|
||||
},
|
||||
.float_16 => return writer.print("{d}", .{val.castTag(.float_16).?.data}),
|
||||
.float_32 => return writer.print("{d}", .{val.castTag(.float_32).?.data}),
|
||||
.float_64 => return writer.print("{d}", .{val.castTag(.float_64).?.data}),
|
||||
.float_80 => return writer.print("{d}", .{@floatCast(f64, val.castTag(.float_80).?.data)}),
|
||||
.float_128 => return writer.print("{d}", .{@floatCast(f64, val.castTag(.float_128).?.data)}),
|
||||
.@"error" => return writer.print("error.{s}", .{val.castTag(.@"error").?.data.name}),
|
||||
.eu_payload => {
|
||||
val = val.castTag(.eu_payload).?.data;
|
||||
ty = ty.errorUnionPayload();
|
||||
},
|
||||
.opt_payload => {
|
||||
val = val.castTag(.opt_payload).?.data;
|
||||
ty = ty.optionalChild(mod);
|
||||
return print(.{ .ty = ty, .val = val }, writer, level, mod);
|
||||
},
|
||||
.eu_payload_ptr => {
|
||||
try writer.writeAll("&");
|
||||
|
||||
const data = val.castTag(.eu_payload_ptr).?.data;
|
||||
|
||||
var ty_val: Value.Payload.Ty = .{
|
||||
.base = .{ .tag = .ty },
|
||||
.data = ty,
|
||||
};
|
||||
|
||||
try writer.writeAll("@as(");
|
||||
try print(.{
|
||||
.ty = Type.type,
|
||||
.val = Value.initPayload(&ty_val.base),
|
||||
}, writer, level - 1, mod);
|
||||
|
||||
try writer.writeAll(", &(payload of ");
|
||||
|
||||
try print(.{
|
||||
.ty = mod.singleMutPtrType(data.container_ty) catch @panic("OOM"),
|
||||
.val = data.container_ptr,
|
||||
}, writer, level - 1, mod);
|
||||
|
||||
try writer.writeAll("))");
|
||||
else => {
|
||||
try writer.print("(interned: {})", .{val.ip_index});
|
||||
return;
|
||||
},
|
||||
.opt_payload_ptr => {
|
||||
const data = val.castTag(.opt_payload_ptr).?.data;
|
||||
|
||||
var ty_val: Value.Payload.Ty = .{
|
||||
.base = .{ .tag = .ty },
|
||||
.data = ty,
|
||||
};
|
||||
|
||||
try writer.writeAll("@as(");
|
||||
try print(.{
|
||||
.ty = Type.type,
|
||||
.val = Value.initPayload(&ty_val.base),
|
||||
}, writer, level - 1, mod);
|
||||
|
||||
try writer.writeAll(", &(payload of ");
|
||||
|
||||
try print(.{
|
||||
.ty = mod.singleMutPtrType(data.container_ty) catch @panic("OOM"),
|
||||
.val = data.container_ptr,
|
||||
}, writer, level - 1, mod);
|
||||
|
||||
try writer.writeAll("))");
|
||||
return;
|
||||
},
|
||||
|
||||
// TODO these should not appear in this function
|
||||
.inferred_alloc => return writer.writeAll("(inferred allocation value)"),
|
||||
.inferred_alloc_comptime => return writer.writeAll("(inferred comptime allocation value)"),
|
||||
.runtime_value => return writer.writeAll("[runtime value]"),
|
||||
};
|
||||
}
|
||||
|
|
|
|||
|
|
@ -3088,11 +3088,15 @@ fn lowerConstant(func: *CodeGen, arg_val: Value, ty: Type) InnerError!WValue {
|
|||
64 => return WValue{ .float64 = val.toFloat(f64) },
|
||||
else => unreachable,
|
||||
},
|
||||
.Pointer => switch (val.tag()) {
|
||||
.field_ptr, .elem_ptr, .opt_payload_ptr => return func.lowerParentPtr(val, 0),
|
||||
.int_u64, .one => return WValue{ .imm32 = @intCast(u32, val.toUnsignedInt(mod)) },
|
||||
.zero, .null_value => return WValue{ .imm32 = 0 },
|
||||
else => return func.fail("Wasm TODO: lowerConstant for other const pointer tag {}", .{val.tag()}),
|
||||
.Pointer => switch (val.ip_index) {
|
||||
.null_value => return WValue{ .imm32 = 0 },
|
||||
.none => switch (val.tag()) {
|
||||
.field_ptr, .elem_ptr, .opt_payload_ptr => return func.lowerParentPtr(val, 0),
|
||||
.int_u64, .one => return WValue{ .imm32 = @intCast(u32, val.toUnsignedInt(mod)) },
|
||||
.zero => return WValue{ .imm32 = 0 },
|
||||
else => return func.fail("Wasm TODO: lowerConstant for other const pointer tag {}", .{val.tag()}),
|
||||
},
|
||||
else => unreachable,
|
||||
},
|
||||
.Enum => {
|
||||
if (val.castTag(.enum_field_index)) |field_index| {
|
||||
|
|
|
|||
156
src/codegen.zig
156
src/codegen.zig
|
|
@ -312,7 +312,7 @@ pub fn generateSymbol(
|
|||
),
|
||||
},
|
||||
},
|
||||
.Pointer => switch (typed_value.val.tag()) {
|
||||
.Pointer => switch (typed_value.val.ip_index) {
|
||||
.null_value => {
|
||||
switch (target.ptrBitWidth()) {
|
||||
32 => {
|
||||
|
|
@ -327,76 +327,79 @@ pub fn generateSymbol(
|
|||
}
|
||||
return Result.ok;
|
||||
},
|
||||
.zero, .one, .int_u64, .int_big_positive => {
|
||||
switch (target.ptrBitWidth()) {
|
||||
32 => {
|
||||
const x = typed_value.val.toUnsignedInt(mod);
|
||||
mem.writeInt(u32, try code.addManyAsArray(4), @intCast(u32, x), endian);
|
||||
},
|
||||
64 => {
|
||||
const x = typed_value.val.toUnsignedInt(mod);
|
||||
mem.writeInt(u64, try code.addManyAsArray(8), x, endian);
|
||||
},
|
||||
else => unreachable,
|
||||
}
|
||||
return Result.ok;
|
||||
},
|
||||
.variable, .decl_ref, .decl_ref_mut => |tag| return lowerDeclRef(
|
||||
bin_file,
|
||||
src_loc,
|
||||
typed_value,
|
||||
switch (tag) {
|
||||
.variable => typed_value.val.castTag(.variable).?.data.owner_decl,
|
||||
.decl_ref => typed_value.val.castTag(.decl_ref).?.data,
|
||||
.decl_ref_mut => typed_value.val.castTag(.decl_ref_mut).?.data.decl_index,
|
||||
else => unreachable,
|
||||
.none => switch (typed_value.val.tag()) {
|
||||
.zero, .one, .int_u64, .int_big_positive => {
|
||||
switch (target.ptrBitWidth()) {
|
||||
32 => {
|
||||
const x = typed_value.val.toUnsignedInt(mod);
|
||||
mem.writeInt(u32, try code.addManyAsArray(4), @intCast(u32, x), endian);
|
||||
},
|
||||
64 => {
|
||||
const x = typed_value.val.toUnsignedInt(mod);
|
||||
mem.writeInt(u64, try code.addManyAsArray(8), x, endian);
|
||||
},
|
||||
else => unreachable,
|
||||
}
|
||||
return Result.ok;
|
||||
},
|
||||
code,
|
||||
debug_output,
|
||||
reloc_info,
|
||||
),
|
||||
.slice => {
|
||||
const slice = typed_value.val.castTag(.slice).?.data;
|
||||
|
||||
// generate ptr
|
||||
var buf: Type.SlicePtrFieldTypeBuffer = undefined;
|
||||
const slice_ptr_field_type = typed_value.ty.slicePtrFieldType(&buf);
|
||||
switch (try generateSymbol(bin_file, src_loc, .{
|
||||
.ty = slice_ptr_field_type,
|
||||
.val = slice.ptr,
|
||||
}, code, debug_output, reloc_info)) {
|
||||
.ok => {},
|
||||
.fail => |em| return Result{ .fail = em },
|
||||
}
|
||||
|
||||
// generate length
|
||||
switch (try generateSymbol(bin_file, src_loc, .{
|
||||
.ty = Type.usize,
|
||||
.val = slice.len,
|
||||
}, code, debug_output, reloc_info)) {
|
||||
.ok => {},
|
||||
.fail => |em| return Result{ .fail = em },
|
||||
}
|
||||
|
||||
return Result.ok;
|
||||
},
|
||||
.field_ptr, .elem_ptr, .opt_payload_ptr => return lowerParentPtr(
|
||||
bin_file,
|
||||
src_loc,
|
||||
typed_value,
|
||||
typed_value.val,
|
||||
code,
|
||||
debug_output,
|
||||
reloc_info,
|
||||
),
|
||||
else => return Result{
|
||||
.fail = try ErrorMsg.create(
|
||||
bin_file.allocator,
|
||||
.variable, .decl_ref, .decl_ref_mut => |tag| return lowerDeclRef(
|
||||
bin_file,
|
||||
src_loc,
|
||||
"TODO implement generateSymbol for pointer type value: '{s}'",
|
||||
.{@tagName(typed_value.val.tag())},
|
||||
typed_value,
|
||||
switch (tag) {
|
||||
.variable => typed_value.val.castTag(.variable).?.data.owner_decl,
|
||||
.decl_ref => typed_value.val.castTag(.decl_ref).?.data,
|
||||
.decl_ref_mut => typed_value.val.castTag(.decl_ref_mut).?.data.decl_index,
|
||||
else => unreachable,
|
||||
},
|
||||
code,
|
||||
debug_output,
|
||||
reloc_info,
|
||||
),
|
||||
.slice => {
|
||||
const slice = typed_value.val.castTag(.slice).?.data;
|
||||
|
||||
// generate ptr
|
||||
var buf: Type.SlicePtrFieldTypeBuffer = undefined;
|
||||
const slice_ptr_field_type = typed_value.ty.slicePtrFieldType(&buf);
|
||||
switch (try generateSymbol(bin_file, src_loc, .{
|
||||
.ty = slice_ptr_field_type,
|
||||
.val = slice.ptr,
|
||||
}, code, debug_output, reloc_info)) {
|
||||
.ok => {},
|
||||
.fail => |em| return Result{ .fail = em },
|
||||
}
|
||||
|
||||
// generate length
|
||||
switch (try generateSymbol(bin_file, src_loc, .{
|
||||
.ty = Type.usize,
|
||||
.val = slice.len,
|
||||
}, code, debug_output, reloc_info)) {
|
||||
.ok => {},
|
||||
.fail => |em| return Result{ .fail = em },
|
||||
}
|
||||
|
||||
return Result.ok;
|
||||
},
|
||||
.field_ptr, .elem_ptr, .opt_payload_ptr => return lowerParentPtr(
|
||||
bin_file,
|
||||
src_loc,
|
||||
typed_value,
|
||||
typed_value.val,
|
||||
code,
|
||||
debug_output,
|
||||
reloc_info,
|
||||
),
|
||||
else => return Result{
|
||||
.fail = try ErrorMsg.create(
|
||||
bin_file.allocator,
|
||||
src_loc,
|
||||
"TODO implement generateSymbol for pointer type value: '{s}'",
|
||||
.{@tagName(typed_value.val.tag())},
|
||||
),
|
||||
},
|
||||
},
|
||||
else => unreachable,
|
||||
},
|
||||
.Int => {
|
||||
const info = typed_value.ty.intInfo(mod);
|
||||
|
|
@ -652,7 +655,7 @@ pub fn generateSymbol(
|
|||
}
|
||||
|
||||
const padding = abi_size - (math.cast(usize, payload_type.abiSize(mod)) orelse return error.Overflow) - 1;
|
||||
const value = if (typed_value.val.castTag(.opt_payload)) |payload| payload.data else Value.initTag(.undef);
|
||||
const value = if (typed_value.val.castTag(.opt_payload)) |payload| payload.data else Value.undef;
|
||||
switch (try generateSymbol(bin_file, src_loc, .{
|
||||
.ty = payload_type,
|
||||
.val = value,
|
||||
|
|
@ -696,7 +699,7 @@ pub fn generateSymbol(
|
|||
// emit payload part of the error union
|
||||
{
|
||||
const begin = code.items.len;
|
||||
const payload_val = if (typed_value.val.castTag(.eu_payload)) |val| val.data else Value.initTag(.undef);
|
||||
const payload_val = if (typed_value.val.castTag(.eu_payload)) |val| val.data else Value.undef;
|
||||
switch (try generateSymbol(bin_file, src_loc, .{
|
||||
.ty = payload_ty,
|
||||
.val = payload_val,
|
||||
|
|
@ -1189,16 +1192,17 @@ pub fn genTypedValue(
|
|||
.Void => return GenResult.mcv(.none),
|
||||
.Pointer => switch (typed_value.ty.ptrSize(mod)) {
|
||||
.Slice => {},
|
||||
else => {
|
||||
switch (typed_value.val.tag()) {
|
||||
.null_value => {
|
||||
return GenResult.mcv(.{ .immediate = 0 });
|
||||
},
|
||||
else => switch (typed_value.val.ip_index) {
|
||||
.null_value => {
|
||||
return GenResult.mcv(.{ .immediate = 0 });
|
||||
},
|
||||
.none => switch (typed_value.val.tag()) {
|
||||
.int_u64 => {
|
||||
return GenResult.mcv(.{ .immediate = typed_value.val.toUnsignedInt(mod) });
|
||||
},
|
||||
else => {},
|
||||
}
|
||||
},
|
||||
else => {},
|
||||
},
|
||||
},
|
||||
.Int => {
|
||||
|
|
@ -1216,7 +1220,7 @@ pub fn genTypedValue(
|
|||
},
|
||||
.Optional => {
|
||||
if (typed_value.ty.isPtrLikeOptional(mod)) {
|
||||
if (typed_value.val.tag() == .null_value) return GenResult.mcv(.{ .immediate = 0 });
|
||||
if (typed_value.val.ip_index == .null_value) return GenResult.mcv(.{ .immediate = 0 });
|
||||
|
||||
return genTypedValue(bin_file, src_loc, .{
|
||||
.ty = typed_value.ty.optionalChild(mod),
|
||||
|
|
|
|||
|
|
@ -1045,8 +1045,8 @@ pub const DeclGen = struct {
|
|||
if (!empty) try writer.writeByte(')');
|
||||
return;
|
||||
},
|
||||
.Pointer => switch (val.tag()) {
|
||||
.null_value, .zero => if (ty.isSlice(mod)) {
|
||||
.Pointer => switch (val.ip_index) {
|
||||
.null_value => if (ty.isSlice(mod)) {
|
||||
var slice_pl = Value.Payload.Slice{
|
||||
.base = .{ .tag = .slice },
|
||||
.data = .{ .ptr = val, .len = Value.undef },
|
||||
|
|
@ -1059,46 +1059,63 @@ pub const DeclGen = struct {
|
|||
try dg.renderType(writer, ty);
|
||||
try writer.writeAll(")NULL)");
|
||||
},
|
||||
.variable => {
|
||||
const decl = val.castTag(.variable).?.data.owner_decl;
|
||||
return dg.renderDeclValue(writer, ty, val, decl, location);
|
||||
},
|
||||
.slice => {
|
||||
if (!location.isInitializer()) {
|
||||
try writer.writeByte('(');
|
||||
.none => switch (val.tag()) {
|
||||
.zero => if (ty.isSlice(mod)) {
|
||||
var slice_pl = Value.Payload.Slice{
|
||||
.base = .{ .tag = .slice },
|
||||
.data = .{ .ptr = val, .len = Value.undef },
|
||||
};
|
||||
const slice_val = Value.initPayload(&slice_pl.base);
|
||||
|
||||
return dg.renderValue(writer, ty, slice_val, location);
|
||||
} else {
|
||||
try writer.writeAll("((");
|
||||
try dg.renderType(writer, ty);
|
||||
try writer.writeByte(')');
|
||||
}
|
||||
try writer.writeAll(")NULL)");
|
||||
},
|
||||
.variable => {
|
||||
const decl = val.castTag(.variable).?.data.owner_decl;
|
||||
return dg.renderDeclValue(writer, ty, val, decl, location);
|
||||
},
|
||||
.slice => {
|
||||
if (!location.isInitializer()) {
|
||||
try writer.writeByte('(');
|
||||
try dg.renderType(writer, ty);
|
||||
try writer.writeByte(')');
|
||||
}
|
||||
|
||||
const slice = val.castTag(.slice).?.data;
|
||||
var buf: Type.SlicePtrFieldTypeBuffer = undefined;
|
||||
const slice = val.castTag(.slice).?.data;
|
||||
var buf: Type.SlicePtrFieldTypeBuffer = undefined;
|
||||
|
||||
try writer.writeByte('{');
|
||||
try dg.renderValue(writer, ty.slicePtrFieldType(&buf), slice.ptr, initializer_type);
|
||||
try writer.writeAll(", ");
|
||||
try dg.renderValue(writer, Type.usize, slice.len, initializer_type);
|
||||
try writer.writeByte('}');
|
||||
try writer.writeByte('{');
|
||||
try dg.renderValue(writer, ty.slicePtrFieldType(&buf), slice.ptr, initializer_type);
|
||||
try writer.writeAll(", ");
|
||||
try dg.renderValue(writer, Type.usize, slice.len, initializer_type);
|
||||
try writer.writeByte('}');
|
||||
},
|
||||
.function => {
|
||||
const func = val.castTag(.function).?.data;
|
||||
try dg.renderDeclName(writer, func.owner_decl, 0);
|
||||
},
|
||||
.extern_fn => {
|
||||
const extern_fn = val.castTag(.extern_fn).?.data;
|
||||
try dg.renderDeclName(writer, extern_fn.owner_decl, 0);
|
||||
},
|
||||
.int_u64, .one, .int_big_positive, .lazy_align, .lazy_size => {
|
||||
try writer.writeAll("((");
|
||||
try dg.renderType(writer, ty);
|
||||
return writer.print("){x})", .{try dg.fmtIntLiteral(Type.usize, val, .Other)});
|
||||
},
|
||||
.field_ptr,
|
||||
.elem_ptr,
|
||||
.opt_payload_ptr,
|
||||
.eu_payload_ptr,
|
||||
.decl_ref_mut,
|
||||
.decl_ref,
|
||||
=> try dg.renderParentPtr(writer, val, ty, location),
|
||||
|
||||
else => unreachable,
|
||||
},
|
||||
.function => {
|
||||
const func = val.castTag(.function).?.data;
|
||||
try dg.renderDeclName(writer, func.owner_decl, 0);
|
||||
},
|
||||
.extern_fn => {
|
||||
const extern_fn = val.castTag(.extern_fn).?.data;
|
||||
try dg.renderDeclName(writer, extern_fn.owner_decl, 0);
|
||||
},
|
||||
.int_u64, .one, .int_big_positive, .lazy_align, .lazy_size => {
|
||||
try writer.writeAll("((");
|
||||
try dg.renderType(writer, ty);
|
||||
return writer.print("){x})", .{try dg.fmtIntLiteral(Type.usize, val, .Other)});
|
||||
},
|
||||
.field_ptr,
|
||||
.elem_ptr,
|
||||
.opt_payload_ptr,
|
||||
.eu_payload_ptr,
|
||||
.decl_ref_mut,
|
||||
.decl_ref,
|
||||
=> try dg.renderParentPtr(writer, val, ty, location),
|
||||
else => unreachable,
|
||||
},
|
||||
.Array, .Vector => {
|
||||
|
|
@ -1109,8 +1126,8 @@ pub const DeclGen = struct {
|
|||
}
|
||||
|
||||
// First try specific tag representations for more efficiency.
|
||||
switch (val.tag()) {
|
||||
.undef, .empty_struct_value, .empty_array => {
|
||||
switch (val.ip_index) {
|
||||
.undef => {
|
||||
const ai = ty.arrayInfo(mod);
|
||||
try writer.writeByte('{');
|
||||
if (ai.sentinel) |s| {
|
||||
|
|
@ -1119,76 +1136,91 @@ pub const DeclGen = struct {
|
|||
try writer.writeByte('0');
|
||||
}
|
||||
try writer.writeByte('}');
|
||||
return;
|
||||
},
|
||||
.bytes, .str_lit => |t| {
|
||||
const bytes = switch (t) {
|
||||
.bytes => val.castTag(.bytes).?.data,
|
||||
.str_lit => bytes: {
|
||||
const str_lit = val.castTag(.str_lit).?.data;
|
||||
break :bytes dg.module.string_literal_bytes.items[str_lit.index..][0..str_lit.len];
|
||||
},
|
||||
else => unreachable,
|
||||
};
|
||||
const sentinel = if (ty.sentinel(mod)) |sentinel| @intCast(u8, sentinel.toUnsignedInt(mod)) else null;
|
||||
try writer.print("{s}", .{
|
||||
fmtStringLiteral(bytes[0..@intCast(usize, ty.arrayLen(mod))], sentinel),
|
||||
});
|
||||
},
|
||||
else => {
|
||||
// Fall back to generic implementation.
|
||||
var arena = std.heap.ArenaAllocator.init(dg.gpa);
|
||||
defer arena.deinit();
|
||||
const arena_allocator = arena.allocator();
|
||||
|
||||
// MSVC throws C2078 if an array of size 65536 or greater is initialized with a string literal
|
||||
const max_string_initializer_len = 65535;
|
||||
|
||||
const ai = ty.arrayInfo(mod);
|
||||
if (ai.elem_type.eql(Type.u8, dg.module)) {
|
||||
if (ai.len <= max_string_initializer_len) {
|
||||
var literal = stringLiteral(writer);
|
||||
try literal.start();
|
||||
var index: usize = 0;
|
||||
while (index < ai.len) : (index += 1) {
|
||||
const elem_val = try val.elemValue(dg.module, arena_allocator, index);
|
||||
const elem_val_u8 = if (elem_val.isUndef()) undefPattern(u8) else @intCast(u8, elem_val.toUnsignedInt(mod));
|
||||
try literal.writeChar(elem_val_u8);
|
||||
}
|
||||
if (ai.sentinel) |s| {
|
||||
const s_u8 = @intCast(u8, s.toUnsignedInt(mod));
|
||||
if (s_u8 != 0) try literal.writeChar(s_u8);
|
||||
}
|
||||
try literal.end();
|
||||
} else {
|
||||
try writer.writeByte('{');
|
||||
var index: usize = 0;
|
||||
while (index < ai.len) : (index += 1) {
|
||||
if (index != 0) try writer.writeByte(',');
|
||||
const elem_val = try val.elemValue(dg.module, arena_allocator, index);
|
||||
const elem_val_u8 = if (elem_val.isUndef()) undefPattern(u8) else @intCast(u8, elem_val.toUnsignedInt(mod));
|
||||
try writer.print("'\\x{x}'", .{elem_val_u8});
|
||||
}
|
||||
if (ai.sentinel) |s| {
|
||||
if (index != 0) try writer.writeByte(',');
|
||||
try dg.renderValue(writer, ai.elem_type, s, initializer_type);
|
||||
}
|
||||
try writer.writeByte('}');
|
||||
}
|
||||
} else {
|
||||
.none => switch (val.tag()) {
|
||||
.empty_struct_value, .empty_array => {
|
||||
const ai = ty.arrayInfo(mod);
|
||||
try writer.writeByte('{');
|
||||
var index: usize = 0;
|
||||
while (index < ai.len) : (index += 1) {
|
||||
if (index != 0) try writer.writeByte(',');
|
||||
const elem_val = try val.elemValue(dg.module, arena_allocator, index);
|
||||
try dg.renderValue(writer, ai.elem_type, elem_val, initializer_type);
|
||||
}
|
||||
if (ai.sentinel) |s| {
|
||||
if (index != 0) try writer.writeByte(',');
|
||||
try dg.renderValue(writer, ai.elem_type, s, initializer_type);
|
||||
} else {
|
||||
try writer.writeByte('0');
|
||||
}
|
||||
try writer.writeByte('}');
|
||||
}
|
||||
return;
|
||||
},
|
||||
.bytes, .str_lit => |t| {
|
||||
const bytes = switch (t) {
|
||||
.bytes => val.castTag(.bytes).?.data,
|
||||
.str_lit => bytes: {
|
||||
const str_lit = val.castTag(.str_lit).?.data;
|
||||
break :bytes dg.module.string_literal_bytes.items[str_lit.index..][0..str_lit.len];
|
||||
},
|
||||
else => unreachable,
|
||||
};
|
||||
const sentinel = if (ty.sentinel(mod)) |sentinel| @intCast(u8, sentinel.toUnsignedInt(mod)) else null;
|
||||
try writer.print("{s}", .{
|
||||
fmtStringLiteral(bytes[0..@intCast(usize, ty.arrayLen(mod))], sentinel),
|
||||
});
|
||||
return;
|
||||
},
|
||||
else => {},
|
||||
},
|
||||
else => {},
|
||||
}
|
||||
// Fall back to generic implementation.
|
||||
var arena = std.heap.ArenaAllocator.init(dg.gpa);
|
||||
defer arena.deinit();
|
||||
const arena_allocator = arena.allocator();
|
||||
|
||||
// MSVC throws C2078 if an array of size 65536 or greater is initialized with a string literal
|
||||
const max_string_initializer_len = 65535;
|
||||
|
||||
const ai = ty.arrayInfo(mod);
|
||||
if (ai.elem_type.eql(Type.u8, dg.module)) {
|
||||
if (ai.len <= max_string_initializer_len) {
|
||||
var literal = stringLiteral(writer);
|
||||
try literal.start();
|
||||
var index: usize = 0;
|
||||
while (index < ai.len) : (index += 1) {
|
||||
const elem_val = try val.elemValue(dg.module, arena_allocator, index);
|
||||
const elem_val_u8 = if (elem_val.isUndef()) undefPattern(u8) else @intCast(u8, elem_val.toUnsignedInt(mod));
|
||||
try literal.writeChar(elem_val_u8);
|
||||
}
|
||||
if (ai.sentinel) |s| {
|
||||
const s_u8 = @intCast(u8, s.toUnsignedInt(mod));
|
||||
if (s_u8 != 0) try literal.writeChar(s_u8);
|
||||
}
|
||||
try literal.end();
|
||||
} else {
|
||||
try writer.writeByte('{');
|
||||
var index: usize = 0;
|
||||
while (index < ai.len) : (index += 1) {
|
||||
if (index != 0) try writer.writeByte(',');
|
||||
const elem_val = try val.elemValue(dg.module, arena_allocator, index);
|
||||
const elem_val_u8 = if (elem_val.isUndef()) undefPattern(u8) else @intCast(u8, elem_val.toUnsignedInt(mod));
|
||||
try writer.print("'\\x{x}'", .{elem_val_u8});
|
||||
}
|
||||
if (ai.sentinel) |s| {
|
||||
if (index != 0) try writer.writeByte(',');
|
||||
try dg.renderValue(writer, ai.elem_type, s, initializer_type);
|
||||
}
|
||||
try writer.writeByte('}');
|
||||
}
|
||||
} else {
|
||||
try writer.writeByte('{');
|
||||
var index: usize = 0;
|
||||
while (index < ai.len) : (index += 1) {
|
||||
if (index != 0) try writer.writeByte(',');
|
||||
const elem_val = try val.elemValue(dg.module, arena_allocator, index);
|
||||
try dg.renderValue(writer, ai.elem_type, elem_val, initializer_type);
|
||||
}
|
||||
if (ai.sentinel) |s| {
|
||||
if (index != 0) try writer.writeByte(',');
|
||||
try dg.renderValue(writer, ai.elem_type, s, initializer_type);
|
||||
}
|
||||
try writer.writeByte('}');
|
||||
}
|
||||
},
|
||||
.Bool => {
|
||||
|
|
@ -1201,7 +1233,7 @@ pub const DeclGen = struct {
|
|||
.Optional => {
|
||||
const payload_ty = ty.optionalChild(mod);
|
||||
|
||||
const is_null_val = Value.makeBool(val.tag() == .null_value);
|
||||
const is_null_val = Value.makeBool(val.ip_index == .null_value);
|
||||
if (!payload_ty.hasRuntimeBitsIgnoreComptime(mod))
|
||||
return dg.renderValue(writer, Type.bool, is_null_val, location);
|
||||
|
||||
|
|
@ -7765,7 +7797,7 @@ fn lowerFnRetTy(ret_ty: Type, buffer: *LowerFnRetTyBuffer, mod: *const Module) T
|
|||
if (lowersToArray(ret_ty, mod)) {
|
||||
buffer.names = [1][]const u8{"array"};
|
||||
buffer.types = [1]Type{ret_ty};
|
||||
buffer.values = [1]Value{Value.initTag(.unreachable_value)};
|
||||
buffer.values = [1]Value{Value.@"unreachable"};
|
||||
buffer.payload = .{ .data = .{
|
||||
.names = &buffer.names,
|
||||
.types = &buffer.types,
|
||||
|
|
|
|||
|
|
@ -2028,7 +2028,7 @@ pub const Object = struct {
|
|||
|
||||
for (tuple.types, 0..) |field_ty, i| {
|
||||
const field_val = tuple.values[i];
|
||||
if (field_val.tag() != .unreachable_value or !field_ty.hasRuntimeBits(mod)) continue;
|
||||
if (field_val.ip_index != .unreachable_value or !field_ty.hasRuntimeBits(mod)) continue;
|
||||
|
||||
const field_size = field_ty.abiSize(mod);
|
||||
const field_align = field_ty.abiAlignment(mod);
|
||||
|
|
@ -2498,7 +2498,7 @@ pub const DeclGen = struct {
|
|||
global.setGlobalConstant(.True);
|
||||
break :init_val decl.val;
|
||||
};
|
||||
if (init_val.tag() != .unreachable_value) {
|
||||
if (init_val.ip_index != .unreachable_value) {
|
||||
const llvm_init = try dg.lowerValue(.{ .ty = decl.ty, .val = init_val });
|
||||
if (global.globalGetValueType() == llvm_init.typeOf()) {
|
||||
global.setInitializer(llvm_init);
|
||||
|
|
@ -2954,7 +2954,7 @@ pub const DeclGen = struct {
|
|||
|
||||
for (tuple.types, 0..) |field_ty, i| {
|
||||
const field_val = tuple.values[i];
|
||||
if (field_val.tag() != .unreachable_value or !field_ty.hasRuntimeBits(mod)) continue;
|
||||
if (field_val.ip_index != .unreachable_value or !field_ty.hasRuntimeBits(mod)) continue;
|
||||
|
||||
const field_align = field_ty.abiAlignment(mod);
|
||||
big_align = @max(big_align, field_align);
|
||||
|
|
@ -3359,58 +3359,65 @@ pub const DeclGen = struct {
|
|||
else => unreachable,
|
||||
}
|
||||
},
|
||||
.Pointer => switch (tv.val.tag()) {
|
||||
.decl_ref_mut => return lowerDeclRefValue(dg, tv, tv.val.castTag(.decl_ref_mut).?.data.decl_index),
|
||||
.decl_ref => return lowerDeclRefValue(dg, tv, tv.val.castTag(.decl_ref).?.data),
|
||||
.variable => {
|
||||
const decl_index = tv.val.castTag(.variable).?.data.owner_decl;
|
||||
const decl = dg.module.declPtr(decl_index);
|
||||
dg.module.markDeclAlive(decl);
|
||||
|
||||
const llvm_wanted_addrspace = toLlvmAddressSpace(decl.@"addrspace", target);
|
||||
const llvm_actual_addrspace = toLlvmGlobalAddressSpace(decl.@"addrspace", target);
|
||||
|
||||
const val = try dg.resolveGlobalDecl(decl_index);
|
||||
const addrspace_casted_ptr = if (llvm_actual_addrspace != llvm_wanted_addrspace)
|
||||
val.constAddrSpaceCast(dg.context.pointerType(llvm_wanted_addrspace))
|
||||
else
|
||||
val;
|
||||
return addrspace_casted_ptr;
|
||||
},
|
||||
.slice => {
|
||||
const slice = tv.val.castTag(.slice).?.data;
|
||||
var buf: Type.SlicePtrFieldTypeBuffer = undefined;
|
||||
const fields: [2]*llvm.Value = .{
|
||||
try dg.lowerValue(.{
|
||||
.ty = tv.ty.slicePtrFieldType(&buf),
|
||||
.val = slice.ptr,
|
||||
}),
|
||||
try dg.lowerValue(.{
|
||||
.ty = Type.usize,
|
||||
.val = slice.len,
|
||||
}),
|
||||
};
|
||||
return dg.context.constStruct(&fields, fields.len, .False);
|
||||
},
|
||||
.int_u64, .one, .int_big_positive, .lazy_align, .lazy_size => {
|
||||
const llvm_usize = try dg.lowerType(Type.usize);
|
||||
const llvm_int = llvm_usize.constInt(tv.val.toUnsignedInt(mod), .False);
|
||||
return llvm_int.constIntToPtr(try dg.lowerType(tv.ty));
|
||||
},
|
||||
.field_ptr, .opt_payload_ptr, .eu_payload_ptr, .elem_ptr => {
|
||||
return dg.lowerParentPtr(tv.val, tv.ty.ptrInfo(mod).bit_offset % 8 == 0);
|
||||
},
|
||||
.null_value, .zero => {
|
||||
.Pointer => switch (tv.val.ip_index) {
|
||||
.null_value => {
|
||||
const llvm_type = try dg.lowerType(tv.ty);
|
||||
return llvm_type.constNull();
|
||||
},
|
||||
.opt_payload => {
|
||||
const payload = tv.val.castTag(.opt_payload).?.data;
|
||||
return dg.lowerParentPtr(payload, tv.ty.ptrInfo(mod).bit_offset % 8 == 0);
|
||||
.none => switch (tv.val.tag()) {
|
||||
.decl_ref_mut => return lowerDeclRefValue(dg, tv, tv.val.castTag(.decl_ref_mut).?.data.decl_index),
|
||||
.decl_ref => return lowerDeclRefValue(dg, tv, tv.val.castTag(.decl_ref).?.data),
|
||||
.variable => {
|
||||
const decl_index = tv.val.castTag(.variable).?.data.owner_decl;
|
||||
const decl = dg.module.declPtr(decl_index);
|
||||
dg.module.markDeclAlive(decl);
|
||||
|
||||
const llvm_wanted_addrspace = toLlvmAddressSpace(decl.@"addrspace", target);
|
||||
const llvm_actual_addrspace = toLlvmGlobalAddressSpace(decl.@"addrspace", target);
|
||||
|
||||
const val = try dg.resolveGlobalDecl(decl_index);
|
||||
const addrspace_casted_ptr = if (llvm_actual_addrspace != llvm_wanted_addrspace)
|
||||
val.constAddrSpaceCast(dg.context.pointerType(llvm_wanted_addrspace))
|
||||
else
|
||||
val;
|
||||
return addrspace_casted_ptr;
|
||||
},
|
||||
.slice => {
|
||||
const slice = tv.val.castTag(.slice).?.data;
|
||||
var buf: Type.SlicePtrFieldTypeBuffer = undefined;
|
||||
const fields: [2]*llvm.Value = .{
|
||||
try dg.lowerValue(.{
|
||||
.ty = tv.ty.slicePtrFieldType(&buf),
|
||||
.val = slice.ptr,
|
||||
}),
|
||||
try dg.lowerValue(.{
|
||||
.ty = Type.usize,
|
||||
.val = slice.len,
|
||||
}),
|
||||
};
|
||||
return dg.context.constStruct(&fields, fields.len, .False);
|
||||
},
|
||||
.int_u64, .one, .int_big_positive, .lazy_align, .lazy_size => {
|
||||
const llvm_usize = try dg.lowerType(Type.usize);
|
||||
const llvm_int = llvm_usize.constInt(tv.val.toUnsignedInt(mod), .False);
|
||||
return llvm_int.constIntToPtr(try dg.lowerType(tv.ty));
|
||||
},
|
||||
.field_ptr, .opt_payload_ptr, .eu_payload_ptr, .elem_ptr => {
|
||||
return dg.lowerParentPtr(tv.val, tv.ty.ptrInfo(mod).bit_offset % 8 == 0);
|
||||
},
|
||||
.zero => {
|
||||
const llvm_type = try dg.lowerType(tv.ty);
|
||||
return llvm_type.constNull();
|
||||
},
|
||||
.opt_payload => {
|
||||
const payload = tv.val.castTag(.opt_payload).?.data;
|
||||
return dg.lowerParentPtr(payload, tv.ty.ptrInfo(mod).bit_offset % 8 == 0);
|
||||
},
|
||||
else => |tag| return dg.todo("implement const of pointer type '{}' ({})", .{
|
||||
tv.ty.fmtDebug(), tag,
|
||||
}),
|
||||
},
|
||||
else => |tag| return dg.todo("implement const of pointer type '{}' ({})", .{
|
||||
tv.ty.fmtDebug(), tag,
|
||||
}),
|
||||
else => unreachable,
|
||||
},
|
||||
.Array => switch (tv.val.tag()) {
|
||||
.bytes => {
|
||||
|
|
@ -3555,7 +3562,7 @@ pub const DeclGen = struct {
|
|||
var fields_buf: [3]*llvm.Value = undefined;
|
||||
fields_buf[0] = try dg.lowerValue(.{
|
||||
.ty = payload_ty,
|
||||
.val = if (tv.val.castTag(.opt_payload)) |pl| pl.data else Value.initTag(.undef),
|
||||
.val = if (tv.val.castTag(.opt_payload)) |pl| pl.data else Value.undef,
|
||||
});
|
||||
fields_buf[1] = non_null_bit;
|
||||
if (llvm_field_count > 2) {
|
||||
|
|
@ -3606,7 +3613,7 @@ pub const DeclGen = struct {
|
|||
});
|
||||
const llvm_payload_value = try dg.lowerValue(.{
|
||||
.ty = payload_type,
|
||||
.val = if (tv.val.castTag(.eu_payload)) |pl| pl.data else Value.initTag(.undef),
|
||||
.val = if (tv.val.castTag(.eu_payload)) |pl| pl.data else Value.undef,
|
||||
});
|
||||
var fields_buf: [3]*llvm.Value = undefined;
|
||||
|
||||
|
|
@ -3645,7 +3652,7 @@ pub const DeclGen = struct {
|
|||
var need_unnamed = false;
|
||||
|
||||
for (tuple.types, 0..) |field_ty, i| {
|
||||
if (tuple.values[i].tag() != .unreachable_value) continue;
|
||||
if (tuple.values[i].ip_index != .unreachable_value) continue;
|
||||
if (!field_ty.hasRuntimeBitsIgnoreComptime(mod)) continue;
|
||||
|
||||
const field_align = field_ty.abiAlignment(mod);
|
||||
|
|
@ -10501,7 +10508,7 @@ fn llvmFieldIndex(
|
|||
const tuple = ty.tupleFields();
|
||||
var llvm_field_index: c_uint = 0;
|
||||
for (tuple.types, 0..) |field_ty, i| {
|
||||
if (tuple.values[i].tag() != .unreachable_value or !field_ty.hasRuntimeBits(mod)) continue;
|
||||
if (tuple.values[i].ip_index != .unreachable_value or !field_ty.hasRuntimeBits(mod)) continue;
|
||||
|
||||
const field_align = field_ty.abiAlignment(mod);
|
||||
big_align = @max(big_align, field_align);
|
||||
|
|
@ -11117,7 +11124,7 @@ fn isByRef(ty: Type, mod: *const Module) bool {
|
|||
const tuple = ty.tupleFields();
|
||||
var count: usize = 0;
|
||||
for (tuple.values, 0..) |field_val, i| {
|
||||
if (field_val.tag() != .unreachable_value or !tuple.types[i].hasRuntimeBits(mod)) continue;
|
||||
if (field_val.ip_index != .unreachable_value or !tuple.types[i].hasRuntimeBits(mod)) continue;
|
||||
|
||||
count += 1;
|
||||
if (count > max_fields_byval) return true;
|
||||
|
|
|
|||
|
|
@ -674,7 +674,7 @@ pub const DeclGen = struct {
|
|||
try self.lower(ptr_ty, slice.ptr);
|
||||
try self.addInt(Type.usize, slice.len);
|
||||
},
|
||||
.null_value, .zero => try self.addNullPtr(try dg.resolveType(ty, .indirect)),
|
||||
.zero => try self.addNullPtr(try dg.resolveType(ty, .indirect)),
|
||||
.int_u64, .one, .int_big_positive, .lazy_align, .lazy_size => {
|
||||
try self.addInt(Type.usize, val);
|
||||
},
|
||||
|
|
@ -813,7 +813,8 @@ pub const DeclGen = struct {
|
|||
const error_size = Type.anyerror.abiAlignment(mod);
|
||||
const ty_size = ty.abiSize(mod);
|
||||
const padding = ty_size - payload_size - error_size;
|
||||
const payload_val = if (val.castTag(.eu_payload)) |pl| pl.data else Value.initTag(.undef);
|
||||
|
||||
const payload_val = if (val.castTag(.eu_payload)) |pl| pl.data else Value.undef;
|
||||
|
||||
if (eu_layout.error_first) {
|
||||
try self.lower(Type.anyerror, error_val);
|
||||
|
|
@ -1021,7 +1022,7 @@ pub const DeclGen = struct {
|
|||
return try self.constant(Type.anyerror, error_val, repr);
|
||||
}
|
||||
|
||||
const payload_val = if (val.castTag(.eu_payload)) |pl| pl.data else Value.initTag(.undef);
|
||||
const payload_val = if (val.castTag(.eu_payload)) |pl| pl.data else Value.undef;
|
||||
|
||||
var members: [2]IdRef = undefined;
|
||||
if (eu_layout.error_first) {
|
||||
|
|
@ -1292,7 +1293,7 @@ pub const DeclGen = struct {
|
|||
var member_index: usize = 0;
|
||||
for (tuple.types, 0..) |field_ty, i| {
|
||||
const field_val = tuple.values[i];
|
||||
if (field_val.tag() != .unreachable_value or !field_ty.hasRuntimeBits(mod)) continue;
|
||||
if (field_val.ip_index != .unreachable_value or !field_ty.hasRuntimeBits(mod)) continue;
|
||||
|
||||
member_types[member_index] = try self.resolveType(field_ty, .indirect);
|
||||
member_index += 1;
|
||||
|
|
@ -1596,7 +1597,7 @@ pub const DeclGen = struct {
|
|||
else
|
||||
decl.val;
|
||||
|
||||
if (init_val.tag() == .unreachable_value) {
|
||||
if (init_val.ip_index == .unreachable_value) {
|
||||
return self.todo("importing extern variables", .{});
|
||||
}
|
||||
|
||||
|
|
|
|||
58
src/type.zig
58
src/type.zig
|
|
@ -533,14 +533,14 @@ pub const Type = struct {
|
|||
for (a_tuple.values, 0..) |a_val, i| {
|
||||
const ty = a_tuple.types[i];
|
||||
const b_val = b_tuple.values[i];
|
||||
if (a_val.tag() == .unreachable_value) {
|
||||
if (b_val.tag() == .unreachable_value) {
|
||||
if (a_val.ip_index == .unreachable_value) {
|
||||
if (b_val.ip_index == .unreachable_value) {
|
||||
continue;
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
} else {
|
||||
if (b_val.tag() == .unreachable_value) {
|
||||
if (b_val.ip_index == .unreachable_value) {
|
||||
return false;
|
||||
} else {
|
||||
if (!Value.eql(a_val, b_val, ty, mod)) return false;
|
||||
|
|
@ -569,14 +569,14 @@ pub const Type = struct {
|
|||
for (a_struct_obj.values, 0..) |a_val, i| {
|
||||
const ty = a_struct_obj.types[i];
|
||||
const b_val = b_struct_obj.values[i];
|
||||
if (a_val.tag() == .unreachable_value) {
|
||||
if (b_val.tag() == .unreachable_value) {
|
||||
if (a_val.ip_index == .unreachable_value) {
|
||||
if (b_val.ip_index == .unreachable_value) {
|
||||
continue;
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
} else {
|
||||
if (b_val.tag() == .unreachable_value) {
|
||||
if (b_val.ip_index == .unreachable_value) {
|
||||
return false;
|
||||
} else {
|
||||
if (!Value.eql(a_val, b_val, ty, mod)) return false;
|
||||
|
|
@ -750,7 +750,7 @@ pub const Type = struct {
|
|||
for (tuple.types, 0..) |field_ty, i| {
|
||||
hashWithHasher(field_ty, hasher, mod);
|
||||
const field_val = tuple.values[i];
|
||||
if (field_val.tag() == .unreachable_value) continue;
|
||||
if (field_val.ip_index == .unreachable_value) continue;
|
||||
field_val.hash(field_ty, hasher, mod);
|
||||
}
|
||||
},
|
||||
|
|
@ -764,7 +764,7 @@ pub const Type = struct {
|
|||
const field_val = struct_obj.values[i];
|
||||
hasher.update(field_name);
|
||||
hashWithHasher(field_ty, hasher, mod);
|
||||
if (field_val.tag() == .unreachable_value) continue;
|
||||
if (field_val.ip_index == .unreachable_value) continue;
|
||||
field_val.hash(field_ty, hasher, mod);
|
||||
}
|
||||
},
|
||||
|
|
@ -1139,11 +1139,11 @@ pub const Type = struct {
|
|||
for (tuple.types, 0..) |field_ty, i| {
|
||||
if (i != 0) try writer.writeAll(", ");
|
||||
const val = tuple.values[i];
|
||||
if (val.tag() != .unreachable_value) {
|
||||
if (val.ip_index != .unreachable_value) {
|
||||
try writer.writeAll("comptime ");
|
||||
}
|
||||
try field_ty.dump("", .{}, writer);
|
||||
if (val.tag() != .unreachable_value) {
|
||||
if (val.ip_index != .unreachable_value) {
|
||||
try writer.print(" = {}", .{val.fmtDebug()});
|
||||
}
|
||||
}
|
||||
|
|
@ -1156,13 +1156,13 @@ pub const Type = struct {
|
|||
for (anon_struct.types, 0..) |field_ty, i| {
|
||||
if (i != 0) try writer.writeAll(", ");
|
||||
const val = anon_struct.values[i];
|
||||
if (val.tag() != .unreachable_value) {
|
||||
if (val.ip_index != .unreachable_value) {
|
||||
try writer.writeAll("comptime ");
|
||||
}
|
||||
try writer.writeAll(anon_struct.names[i]);
|
||||
try writer.writeAll(": ");
|
||||
try field_ty.dump("", .{}, writer);
|
||||
if (val.tag() != .unreachable_value) {
|
||||
if (val.ip_index != .unreachable_value) {
|
||||
try writer.print(" = {}", .{val.fmtDebug()});
|
||||
}
|
||||
}
|
||||
|
|
@ -1408,11 +1408,11 @@ pub const Type = struct {
|
|||
for (tuple.types, 0..) |field_ty, i| {
|
||||
if (i != 0) try writer.writeAll(", ");
|
||||
const val = tuple.values[i];
|
||||
if (val.tag() != .unreachable_value) {
|
||||
if (val.ip_index != .unreachable_value) {
|
||||
try writer.writeAll("comptime ");
|
||||
}
|
||||
try print(field_ty, writer, mod);
|
||||
if (val.tag() != .unreachable_value) {
|
||||
if (val.ip_index != .unreachable_value) {
|
||||
try writer.print(" = {}", .{val.fmtValue(field_ty, mod)});
|
||||
}
|
||||
}
|
||||
|
|
@ -1425,7 +1425,7 @@ pub const Type = struct {
|
|||
for (anon_struct.types, 0..) |field_ty, i| {
|
||||
if (i != 0) try writer.writeAll(", ");
|
||||
const val = anon_struct.values[i];
|
||||
if (val.tag() != .unreachable_value) {
|
||||
if (val.ip_index != .unreachable_value) {
|
||||
try writer.writeAll("comptime ");
|
||||
}
|
||||
try writer.writeAll(anon_struct.names[i]);
|
||||
|
|
@ -1433,7 +1433,7 @@ pub const Type = struct {
|
|||
|
||||
try print(field_ty, writer, mod);
|
||||
|
||||
if (val.tag() != .unreachable_value) {
|
||||
if (val.ip_index != .unreachable_value) {
|
||||
try writer.print(" = {}", .{val.fmtValue(field_ty, mod)});
|
||||
}
|
||||
}
|
||||
|
|
@ -1770,7 +1770,7 @@ pub const Type = struct {
|
|||
const tuple = ty.tupleFields();
|
||||
for (tuple.types, 0..) |field_ty, i| {
|
||||
const val = tuple.values[i];
|
||||
if (val.tag() != .unreachable_value) continue; // comptime field
|
||||
if (val.ip_index != .unreachable_value) continue; // comptime field
|
||||
if (try field_ty.hasRuntimeBitsAdvanced(mod, ignore_comptime_only, strat)) return true;
|
||||
}
|
||||
return false;
|
||||
|
|
@ -2283,7 +2283,7 @@ pub const Type = struct {
|
|||
var big_align: u32 = 0;
|
||||
for (tuple.types, 0..) |field_ty, i| {
|
||||
const val = tuple.values[i];
|
||||
if (val.tag() != .unreachable_value) continue; // comptime field
|
||||
if (val.ip_index != .unreachable_value) continue; // comptime field
|
||||
if (!(field_ty.hasRuntimeBits(mod))) continue;
|
||||
|
||||
switch (try field_ty.abiAlignmentAdvanced(mod, strat)) {
|
||||
|
|
@ -3845,7 +3845,7 @@ pub const Type = struct {
|
|||
=> return null,
|
||||
|
||||
.void => return Value.void,
|
||||
.noreturn => return Value.initTag(.unreachable_value),
|
||||
.noreturn => return Value.@"unreachable",
|
||||
.null => return Value.null,
|
||||
.undefined => return Value.undef,
|
||||
|
||||
|
|
@ -3896,7 +3896,7 @@ pub const Type = struct {
|
|||
.tuple, .anon_struct => {
|
||||
const tuple = ty.tupleFields();
|
||||
for (tuple.values, 0..) |val, i| {
|
||||
const is_comptime = val.tag() != .unreachable_value;
|
||||
const is_comptime = val.ip_index != .unreachable_value;
|
||||
if (is_comptime) continue;
|
||||
if (tuple.types[i].onePossibleValue(mod) != null) continue;
|
||||
return null;
|
||||
|
|
@ -3919,7 +3919,7 @@ pub const Type = struct {
|
|||
return null;
|
||||
}
|
||||
switch (enum_full.fields.count()) {
|
||||
0 => return Value.initTag(.unreachable_value),
|
||||
0 => return Value.@"unreachable",
|
||||
1 => if (enum_full.values.count() == 0) {
|
||||
return Value.zero; // auto-numbered
|
||||
} else {
|
||||
|
|
@ -3931,7 +3931,7 @@ pub const Type = struct {
|
|||
.enum_simple => {
|
||||
const enum_simple = ty.castTag(.enum_simple).?.data;
|
||||
switch (enum_simple.fields.count()) {
|
||||
0 => return Value.initTag(.unreachable_value),
|
||||
0 => return Value.@"unreachable",
|
||||
1 => return Value.zero,
|
||||
else => return null,
|
||||
}
|
||||
|
|
@ -3947,7 +3947,7 @@ pub const Type = struct {
|
|||
.@"union", .union_safety_tagged, .union_tagged => {
|
||||
const union_obj = ty.cast(Payload.Union).?.data;
|
||||
const tag_val = union_obj.tag_ty.onePossibleValue(mod) orelse return null;
|
||||
if (union_obj.fields.count() == 0) return Value.initTag(.unreachable_value);
|
||||
if (union_obj.fields.count() == 0) return Value.@"unreachable";
|
||||
const only_field = union_obj.fields.values()[0];
|
||||
const val_val = only_field.ty.onePossibleValue(mod) orelse return null;
|
||||
_ = tag_val;
|
||||
|
|
@ -4075,7 +4075,7 @@ pub const Type = struct {
|
|||
.tuple, .anon_struct => {
|
||||
const tuple = ty.tupleFields();
|
||||
for (tuple.types, 0..) |field_ty, i| {
|
||||
const have_comptime_val = tuple.values[i].tag() != .unreachable_value;
|
||||
const have_comptime_val = tuple.values[i].ip_index != .unreachable_value;
|
||||
if (!have_comptime_val and field_ty.comptimeOnly(mod)) return true;
|
||||
}
|
||||
return false;
|
||||
|
|
@ -4514,7 +4514,7 @@ pub const Type = struct {
|
|||
.tuple => {
|
||||
const tuple = ty.castTag(.tuple).?.data;
|
||||
const val = tuple.values[index];
|
||||
if (val.tag() == .unreachable_value) {
|
||||
if (val.ip_index == .unreachable_value) {
|
||||
return tuple.types[index].onePossibleValue(mod);
|
||||
} else {
|
||||
return val;
|
||||
|
|
@ -4523,7 +4523,7 @@ pub const Type = struct {
|
|||
.anon_struct => {
|
||||
const anon_struct = ty.castTag(.anon_struct).?.data;
|
||||
const val = anon_struct.values[index];
|
||||
if (val.tag() == .unreachable_value) {
|
||||
if (val.ip_index == .unreachable_value) {
|
||||
return anon_struct.types[index].onePossibleValue(mod);
|
||||
} else {
|
||||
return val;
|
||||
|
|
@ -4544,12 +4544,12 @@ pub const Type = struct {
|
|||
.tuple => {
|
||||
const tuple = ty.castTag(.tuple).?.data;
|
||||
const val = tuple.values[index];
|
||||
return val.tag() != .unreachable_value;
|
||||
return val.ip_index != .unreachable_value;
|
||||
},
|
||||
.anon_struct => {
|
||||
const anon_struct = ty.castTag(.anon_struct).?.data;
|
||||
const val = anon_struct.values[index];
|
||||
return val.tag() != .unreachable_value;
|
||||
return val.ip_index != .unreachable_value;
|
||||
},
|
||||
else => unreachable,
|
||||
}
|
||||
|
|
@ -4647,7 +4647,7 @@ pub const Type = struct {
|
|||
|
||||
for (tuple.types, 0..) |field_ty, i| {
|
||||
const field_val = tuple.values[i];
|
||||
if (field_val.tag() != .unreachable_value or !field_ty.hasRuntimeBits(mod)) {
|
||||
if (field_val.ip_index != .unreachable_value or !field_ty.hasRuntimeBits(mod)) {
|
||||
// comptime field
|
||||
if (i == index) return offset;
|
||||
continue;
|
||||
|
|
|
|||
520
src/value.zig
520
src/value.zig
|
|
@ -33,13 +33,10 @@ pub const Value = struct {
|
|||
// Keep in sync with tools/stage2_pretty_printers_common.py
|
||||
pub const Tag = enum(usize) {
|
||||
// The first section of this enum are tags that require no payload.
|
||||
undef,
|
||||
zero,
|
||||
one,
|
||||
unreachable_value,
|
||||
/// The only possible value for a particular type, which is stored externally.
|
||||
the_only_possible_value,
|
||||
null_value,
|
||||
|
||||
empty_struct_value,
|
||||
empty_array, // See last_no_payload_tag below.
|
||||
|
|
@ -132,14 +129,11 @@ pub const Value = struct {
|
|||
|
||||
pub fn Type(comptime t: Tag) type {
|
||||
return switch (t) {
|
||||
.undef,
|
||||
.zero,
|
||||
.one,
|
||||
.unreachable_value,
|
||||
.the_only_possible_value,
|
||||
.empty_struct_value,
|
||||
.empty_array,
|
||||
.null_value,
|
||||
=> @compileError("Value Tag " ++ @tagName(t) ++ " has no payload"),
|
||||
|
||||
.int_big_positive,
|
||||
|
|
@ -287,13 +281,10 @@ pub const Value = struct {
|
|||
.legacy = .{ .tag_if_small_enough = self.legacy.tag_if_small_enough },
|
||||
};
|
||||
} else switch (self.legacy.ptr_otherwise.tag) {
|
||||
.undef,
|
||||
.zero,
|
||||
.one,
|
||||
.unreachable_value,
|
||||
.the_only_possible_value,
|
||||
.empty_array,
|
||||
.null_value,
|
||||
.empty_struct_value,
|
||||
=> unreachable,
|
||||
|
||||
|
|
@ -522,7 +513,7 @@ pub const Value = struct {
|
|||
) !void {
|
||||
comptime assert(fmt.len == 0);
|
||||
if (start_val.ip_index != .none) {
|
||||
try out_stream.print("(interned {d})", .{@enumToInt(start_val.ip_index)});
|
||||
try out_stream.print("(interned: {})", .{start_val.ip_index});
|
||||
return;
|
||||
}
|
||||
var val = start_val;
|
||||
|
|
@ -534,11 +525,8 @@ pub const Value = struct {
|
|||
.@"union" => {
|
||||
return out_stream.writeAll("(union value)");
|
||||
},
|
||||
.null_value => return out_stream.writeAll("null"),
|
||||
.undef => return out_stream.writeAll("undefined"),
|
||||
.zero => return out_stream.writeAll("0"),
|
||||
.one => return out_stream.writeAll("1"),
|
||||
.unreachable_value => return out_stream.writeAll("unreachable"),
|
||||
.the_only_possible_value => return out_stream.writeAll("(the only possible value)"),
|
||||
.ty => return val.castTag(.ty).?.data.dump("", options, out_stream),
|
||||
.lazy_align => {
|
||||
|
|
@ -811,8 +799,9 @@ pub const Value = struct {
|
|||
switch (val.ip_index) {
|
||||
.bool_false => return BigIntMutable.init(&space.limbs, 0).toConst(),
|
||||
.bool_true => return BigIntMutable.init(&space.limbs, 1).toConst(),
|
||||
.undef => unreachable,
|
||||
.null_value => return BigIntMutable.init(&space.limbs, 0).toConst(),
|
||||
.none => switch (val.tag()) {
|
||||
.null_value,
|
||||
.zero,
|
||||
.the_only_possible_value, // i0, u0
|
||||
=> return BigIntMutable.init(&space.limbs, 0).toConst(),
|
||||
|
|
@ -832,8 +821,6 @@ pub const Value = struct {
|
|||
.int_big_positive => return val.castTag(.int_big_positive).?.asBigInt(),
|
||||
.int_big_negative => return val.castTag(.int_big_negative).?.asBigInt(),
|
||||
|
||||
.undef => unreachable,
|
||||
|
||||
.lazy_align => {
|
||||
const ty = val.castTag(.lazy_align).?.data;
|
||||
if (opt_sema) |sema| {
|
||||
|
|
@ -880,6 +867,7 @@ pub const Value = struct {
|
|||
switch (val.ip_index) {
|
||||
.bool_false => return 0,
|
||||
.bool_true => return 1,
|
||||
.undef => unreachable,
|
||||
.none => switch (val.tag()) {
|
||||
.zero,
|
||||
.the_only_possible_value, // i0, u0
|
||||
|
|
@ -892,8 +880,6 @@ pub const Value = struct {
|
|||
.int_big_positive => return val.castTag(.int_big_positive).?.asBigInt().to(u64) catch null,
|
||||
.int_big_negative => return val.castTag(.int_big_negative).?.asBigInt().to(u64) catch null,
|
||||
|
||||
.undef => unreachable,
|
||||
|
||||
.lazy_align => {
|
||||
const ty = val.castTag(.lazy_align).?.data;
|
||||
if (opt_sema) |sema| {
|
||||
|
|
@ -913,9 +899,9 @@ pub const Value = struct {
|
|||
|
||||
else => return null,
|
||||
},
|
||||
else => switch (mod.intern_pool.indexToKey(val.ip_index)) {
|
||||
.int => |int| return int.big_int.to(u64) catch null,
|
||||
else => unreachable,
|
||||
else => return switch (mod.intern_pool.indexToKey(val.ip_index)) {
|
||||
.int => |int| int.big_int.to(u64) catch null,
|
||||
else => null,
|
||||
},
|
||||
}
|
||||
}
|
||||
|
|
@ -930,6 +916,7 @@ pub const Value = struct {
|
|||
switch (val.ip_index) {
|
||||
.bool_false => return 0,
|
||||
.bool_true => return 1,
|
||||
.undef => unreachable,
|
||||
.none => switch (val.tag()) {
|
||||
.zero,
|
||||
.the_only_possible_value, // i0, u0
|
||||
|
|
@ -951,7 +938,6 @@ pub const Value = struct {
|
|||
return @intCast(i64, ty.abiSize(mod));
|
||||
},
|
||||
|
||||
.undef => unreachable,
|
||||
else => unreachable,
|
||||
},
|
||||
else => switch (mod.intern_pool.indexToKey(val.ip_index)) {
|
||||
|
|
@ -2032,8 +2018,7 @@ pub const Value = struct {
|
|||
const a_tag = a.tag();
|
||||
const b_tag = b.tag();
|
||||
if (a_tag == b_tag) switch (a_tag) {
|
||||
.undef => return true,
|
||||
.null_value, .the_only_possible_value, .empty_struct_value => return true,
|
||||
.the_only_possible_value, .empty_struct_value => return true,
|
||||
.enum_literal => {
|
||||
const a_name = a.castTag(.enum_literal).?.data;
|
||||
const b_name = b.castTag(.enum_literal).?.data;
|
||||
|
|
@ -2162,9 +2147,7 @@ pub const Value = struct {
|
|||
return eqlAdvanced(a_union.val, active_field_ty, b_union.val, active_field_ty, mod, opt_sema);
|
||||
},
|
||||
else => {},
|
||||
} else if (b_tag == .null_value or b_tag == .@"error") {
|
||||
return false;
|
||||
} else if (a_tag == .undef or b_tag == .undef) {
|
||||
} else if (b_tag == .@"error") {
|
||||
return false;
|
||||
}
|
||||
|
||||
|
|
@ -2283,7 +2266,7 @@ pub const Value = struct {
|
|||
if (a_nan) return true;
|
||||
return a_float == b_float;
|
||||
},
|
||||
.Optional => if (a_tag != .null_value and b_tag == .opt_payload) {
|
||||
.Optional => if (b_tag == .opt_payload) {
|
||||
var sub_pl: Payload.SubValue = .{
|
||||
.base = .{ .tag = b.tag() },
|
||||
.data = a,
|
||||
|
|
@ -2301,7 +2284,7 @@ pub const Value = struct {
|
|||
},
|
||||
else => {},
|
||||
}
|
||||
if (a_tag == .null_value or a_tag == .@"error") return false;
|
||||
if (a_tag == .@"error") return false;
|
||||
return (try orderAdvanced(a, b, mod, opt_sema)).compare(.eq);
|
||||
}
|
||||
|
||||
|
|
@ -2642,7 +2625,6 @@ pub const Value = struct {
|
|||
|
||||
.zero,
|
||||
.one,
|
||||
.null_value,
|
||||
.int_u64,
|
||||
.int_i64,
|
||||
.int_big_positive,
|
||||
|
|
@ -2717,102 +2699,108 @@ pub const Value = struct {
|
|||
arena: ?Allocator,
|
||||
buffer: *ElemValueBuffer,
|
||||
) error{OutOfMemory}!Value {
|
||||
switch (val.tag()) {
|
||||
// This is the case of accessing an element of an undef array.
|
||||
switch (val.ip_index) {
|
||||
.undef => return Value.undef,
|
||||
.empty_array => unreachable, // out of bounds array index
|
||||
.empty_struct_value => unreachable, // out of bounds array index
|
||||
.none => switch (val.tag()) {
|
||||
// This is the case of accessing an element of an undef array.
|
||||
.empty_array => unreachable, // out of bounds array index
|
||||
.empty_struct_value => unreachable, // out of bounds array index
|
||||
|
||||
.empty_array_sentinel => {
|
||||
assert(index == 0); // The only valid index for an empty array with sentinel.
|
||||
return val.castTag(.empty_array_sentinel).?.data;
|
||||
.empty_array_sentinel => {
|
||||
assert(index == 0); // The only valid index for an empty array with sentinel.
|
||||
return val.castTag(.empty_array_sentinel).?.data;
|
||||
},
|
||||
|
||||
.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);
|
||||
}
|
||||
},
|
||||
.str_lit => {
|
||||
const str_lit = val.castTag(.str_lit).?.data;
|
||||
const bytes = mod.string_literal_bytes.items[str_lit.index..][0..str_lit.len];
|
||||
const byte = bytes[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,
|
||||
|
||||
.aggregate => return val.castTag(.aggregate).?.data[index],
|
||||
.slice => return val.castTag(.slice).?.data.ptr.elemValueAdvanced(mod, index, arena, buffer),
|
||||
|
||||
.decl_ref => return mod.declPtr(val.castTag(.decl_ref).?.data).val.elemValueAdvanced(mod, index, arena, buffer),
|
||||
.decl_ref_mut => return mod.declPtr(val.castTag(.decl_ref_mut).?.data.decl_index).val.elemValueAdvanced(mod, index, arena, buffer),
|
||||
.comptime_field_ptr => return val.castTag(.comptime_field_ptr).?.data.field_val.elemValueAdvanced(mod, index, arena, buffer),
|
||||
.elem_ptr => {
|
||||
const data = val.castTag(.elem_ptr).?.data;
|
||||
return data.array_ptr.elemValueAdvanced(mod, index + data.index, arena, buffer);
|
||||
},
|
||||
.field_ptr => {
|
||||
const data = val.castTag(.field_ptr).?.data;
|
||||
if (data.container_ptr.pointerDecl()) |decl_index| {
|
||||
const container_decl = mod.declPtr(decl_index);
|
||||
const field_type = data.container_ty.structFieldType(data.field_index);
|
||||
const field_val = container_decl.val.fieldValue(field_type, mod, data.field_index);
|
||||
return field_val.elemValueAdvanced(mod, index, arena, buffer);
|
||||
} else unreachable;
|
||||
},
|
||||
|
||||
// The child type of arrays which have only one possible value need
|
||||
// to have only one possible value itself.
|
||||
.the_only_possible_value => return val,
|
||||
|
||||
.opt_payload_ptr => return val.castTag(.opt_payload_ptr).?.data.container_ptr.elemValueAdvanced(mod, index, arena, buffer),
|
||||
.eu_payload_ptr => return val.castTag(.eu_payload_ptr).?.data.container_ptr.elemValueAdvanced(mod, index, arena, buffer),
|
||||
|
||||
.opt_payload => return val.castTag(.opt_payload).?.data.elemValueAdvanced(mod, index, arena, buffer),
|
||||
.eu_payload => return val.castTag(.eu_payload).?.data.elemValueAdvanced(mod, index, arena, buffer),
|
||||
|
||||
else => unreachable,
|
||||
},
|
||||
|
||||
.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);
|
||||
}
|
||||
},
|
||||
.str_lit => {
|
||||
const str_lit = val.castTag(.str_lit).?.data;
|
||||
const bytes = mod.string_literal_bytes.items[str_lit.index..][0..str_lit.len];
|
||||
const byte = bytes[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,
|
||||
|
||||
.aggregate => return val.castTag(.aggregate).?.data[index],
|
||||
.slice => return val.castTag(.slice).?.data.ptr.elemValueAdvanced(mod, index, arena, buffer),
|
||||
|
||||
.decl_ref => return mod.declPtr(val.castTag(.decl_ref).?.data).val.elemValueAdvanced(mod, index, arena, buffer),
|
||||
.decl_ref_mut => return mod.declPtr(val.castTag(.decl_ref_mut).?.data.decl_index).val.elemValueAdvanced(mod, index, arena, buffer),
|
||||
.comptime_field_ptr => return val.castTag(.comptime_field_ptr).?.data.field_val.elemValueAdvanced(mod, index, arena, buffer),
|
||||
.elem_ptr => {
|
||||
const data = val.castTag(.elem_ptr).?.data;
|
||||
return data.array_ptr.elemValueAdvanced(mod, index + data.index, arena, buffer);
|
||||
},
|
||||
.field_ptr => {
|
||||
const data = val.castTag(.field_ptr).?.data;
|
||||
if (data.container_ptr.pointerDecl()) |decl_index| {
|
||||
const container_decl = mod.declPtr(decl_index);
|
||||
const field_type = data.container_ty.structFieldType(data.field_index);
|
||||
const field_val = container_decl.val.fieldValue(field_type, mod, data.field_index);
|
||||
return field_val.elemValueAdvanced(mod, index, arena, buffer);
|
||||
} else unreachable;
|
||||
},
|
||||
|
||||
// The child type of arrays which have only one possible value need
|
||||
// to have only one possible value itself.
|
||||
.the_only_possible_value => return val,
|
||||
|
||||
.opt_payload_ptr => return val.castTag(.opt_payload_ptr).?.data.container_ptr.elemValueAdvanced(mod, index, arena, buffer),
|
||||
.eu_payload_ptr => return val.castTag(.eu_payload_ptr).?.data.container_ptr.elemValueAdvanced(mod, index, arena, buffer),
|
||||
|
||||
.opt_payload => return val.castTag(.opt_payload).?.data.elemValueAdvanced(mod, index, arena, buffer),
|
||||
.eu_payload => return val.castTag(.eu_payload).?.data.elemValueAdvanced(mod, index, arena, buffer),
|
||||
|
||||
else => unreachable,
|
||||
}
|
||||
}
|
||||
|
||||
/// Returns true if a Value is backed by a variable
|
||||
pub fn isVariable(val: Value, mod: *Module) bool {
|
||||
return switch (val.tag()) {
|
||||
.slice => val.castTag(.slice).?.data.ptr.isVariable(mod),
|
||||
.comptime_field_ptr => val.castTag(.comptime_field_ptr).?.data.field_val.isVariable(mod),
|
||||
.elem_ptr => val.castTag(.elem_ptr).?.data.array_ptr.isVariable(mod),
|
||||
.field_ptr => val.castTag(.field_ptr).?.data.container_ptr.isVariable(mod),
|
||||
.eu_payload_ptr => val.castTag(.eu_payload_ptr).?.data.container_ptr.isVariable(mod),
|
||||
.opt_payload_ptr => val.castTag(.opt_payload_ptr).?.data.container_ptr.isVariable(mod),
|
||||
.decl_ref => {
|
||||
const decl = mod.declPtr(val.castTag(.decl_ref).?.data);
|
||||
assert(decl.has_tv);
|
||||
return decl.val.isVariable(mod);
|
||||
},
|
||||
.decl_ref_mut => {
|
||||
const decl = mod.declPtr(val.castTag(.decl_ref_mut).?.data.decl_index);
|
||||
assert(decl.has_tv);
|
||||
return decl.val.isVariable(mod);
|
||||
},
|
||||
return switch (val.ip_index) {
|
||||
.none => switch (val.tag()) {
|
||||
.slice => val.castTag(.slice).?.data.ptr.isVariable(mod),
|
||||
.comptime_field_ptr => val.castTag(.comptime_field_ptr).?.data.field_val.isVariable(mod),
|
||||
.elem_ptr => val.castTag(.elem_ptr).?.data.array_ptr.isVariable(mod),
|
||||
.field_ptr => val.castTag(.field_ptr).?.data.container_ptr.isVariable(mod),
|
||||
.eu_payload_ptr => val.castTag(.eu_payload_ptr).?.data.container_ptr.isVariable(mod),
|
||||
.opt_payload_ptr => val.castTag(.opt_payload_ptr).?.data.container_ptr.isVariable(mod),
|
||||
.decl_ref => {
|
||||
const decl = mod.declPtr(val.castTag(.decl_ref).?.data);
|
||||
assert(decl.has_tv);
|
||||
return decl.val.isVariable(mod);
|
||||
},
|
||||
.decl_ref_mut => {
|
||||
const decl = mod.declPtr(val.castTag(.decl_ref_mut).?.data.decl_index);
|
||||
assert(decl.has_tv);
|
||||
return decl.val.isVariable(mod);
|
||||
},
|
||||
|
||||
.variable => true,
|
||||
.variable => true,
|
||||
else => false,
|
||||
},
|
||||
else => false,
|
||||
};
|
||||
}
|
||||
|
|
@ -2878,39 +2866,46 @@ pub const Value = struct {
|
|||
}
|
||||
|
||||
pub fn fieldValue(val: Value, ty: Type, mod: *const Module, index: usize) Value {
|
||||
switch (val.tag()) {
|
||||
.aggregate => {
|
||||
const field_values = val.castTag(.aggregate).?.data;
|
||||
return field_values[index];
|
||||
},
|
||||
.@"union" => {
|
||||
const payload = val.castTag(.@"union").?.data;
|
||||
// TODO assert the tag is correct
|
||||
return payload.val;
|
||||
},
|
||||
|
||||
.the_only_possible_value => return ty.onePossibleValue(mod).?,
|
||||
|
||||
.empty_struct_value => {
|
||||
if (ty.isSimpleTupleOrAnonStruct()) {
|
||||
const tuple = ty.tupleFields();
|
||||
return tuple.values[index];
|
||||
}
|
||||
if (ty.structFieldValueComptime(mod, index)) |some| {
|
||||
return some;
|
||||
}
|
||||
unreachable;
|
||||
},
|
||||
switch (val.ip_index) {
|
||||
.undef => return Value.undef,
|
||||
.none => switch (val.tag()) {
|
||||
.aggregate => {
|
||||
const field_values = val.castTag(.aggregate).?.data;
|
||||
return field_values[index];
|
||||
},
|
||||
.@"union" => {
|
||||
const payload = val.castTag(.@"union").?.data;
|
||||
// TODO assert the tag is correct
|
||||
return payload.val;
|
||||
},
|
||||
|
||||
.the_only_possible_value => return ty.onePossibleValue(mod).?,
|
||||
|
||||
.empty_struct_value => {
|
||||
if (ty.isSimpleTupleOrAnonStruct()) {
|
||||
const tuple = ty.tupleFields();
|
||||
return tuple.values[index];
|
||||
}
|
||||
if (ty.structFieldValueComptime(mod, index)) |some| {
|
||||
return some;
|
||||
}
|
||||
unreachable;
|
||||
},
|
||||
|
||||
else => unreachable,
|
||||
},
|
||||
else => unreachable,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn unionTag(val: Value) Value {
|
||||
switch (val.tag()) {
|
||||
.undef, .enum_field_index => return val,
|
||||
.@"union" => return val.castTag(.@"union").?.data.tag,
|
||||
switch (val.ip_index) {
|
||||
.undef => return val,
|
||||
.none => switch (val.tag()) {
|
||||
.enum_field_index => return val,
|
||||
.@"union" => return val.castTag(.@"union").?.data.tag,
|
||||
else => unreachable,
|
||||
},
|
||||
else => unreachable,
|
||||
}
|
||||
}
|
||||
|
|
@ -2946,15 +2941,15 @@ pub const Value = struct {
|
|||
});
|
||||
}
|
||||
|
||||
pub fn isUndef(self: Value) bool {
|
||||
return self.tag() == .undef;
|
||||
pub fn isUndef(val: Value) bool {
|
||||
return val.ip_index == .undef;
|
||||
}
|
||||
|
||||
/// TODO: check for cases such as array that is not marked undef but all the element
|
||||
/// values are marked undef, or struct that is not marked undef but all fields are marked
|
||||
/// undef, etc.
|
||||
pub fn isUndefDeep(self: Value) bool {
|
||||
return self.isUndef();
|
||||
pub fn isUndefDeep(val: Value) bool {
|
||||
return val.isUndef();
|
||||
}
|
||||
|
||||
/// Returns true if any value contained in `self` is undefined.
|
||||
|
|
@ -2962,27 +2957,29 @@ pub const Value = struct {
|
|||
/// values are marked undef, or struct that is not marked undef but all fields are marked
|
||||
/// undef, etc.
|
||||
pub fn anyUndef(self: Value, mod: *Module) bool {
|
||||
switch (self.tag()) {
|
||||
.slice => {
|
||||
const payload = self.castTag(.slice).?;
|
||||
const len = payload.data.len.toUnsignedInt(mod);
|
||||
|
||||
var elem_value_buf: ElemValueBuffer = undefined;
|
||||
var i: usize = 0;
|
||||
while (i < len) : (i += 1) {
|
||||
const elem_val = payload.data.ptr.elemValueBuffer(mod, i, &elem_value_buf);
|
||||
if (elem_val.anyUndef(mod)) return true;
|
||||
}
|
||||
},
|
||||
|
||||
.aggregate => {
|
||||
const payload = self.castTag(.aggregate).?;
|
||||
for (payload.data) |val| {
|
||||
if (val.anyUndef(mod)) return true;
|
||||
}
|
||||
},
|
||||
|
||||
switch (self.ip_index) {
|
||||
.undef => return true,
|
||||
.none => switch (self.tag()) {
|
||||
.slice => {
|
||||
const payload = self.castTag(.slice).?;
|
||||
const len = payload.data.len.toUnsignedInt(mod);
|
||||
|
||||
var elem_value_buf: ElemValueBuffer = undefined;
|
||||
var i: usize = 0;
|
||||
while (i < len) : (i += 1) {
|
||||
const elem_val = payload.data.ptr.elemValueBuffer(mod, i, &elem_value_buf);
|
||||
if (elem_val.anyUndef(mod)) return true;
|
||||
}
|
||||
},
|
||||
|
||||
.aggregate => {
|
||||
const payload = self.castTag(.aggregate).?;
|
||||
for (payload.data) |val| {
|
||||
if (val.anyUndef(mod)) return true;
|
||||
}
|
||||
},
|
||||
else => {},
|
||||
},
|
||||
else => {},
|
||||
}
|
||||
|
||||
|
|
@ -2992,30 +2989,33 @@ pub const Value = struct {
|
|||
/// Asserts the value is not undefined and not unreachable.
|
||||
/// Integer value 0 is considered null because of C pointers.
|
||||
pub fn isNull(self: Value, mod: *const Module) bool {
|
||||
return switch (self.tag()) {
|
||||
.null_value => true,
|
||||
.opt_payload => false,
|
||||
|
||||
// If it's not one of those two tags then it must be a C pointer value,
|
||||
// in which case the value 0 is null and other values are non-null.
|
||||
|
||||
.zero,
|
||||
.the_only_possible_value,
|
||||
=> true,
|
||||
|
||||
.one => false,
|
||||
|
||||
.int_u64,
|
||||
.int_i64,
|
||||
.int_big_positive,
|
||||
.int_big_negative,
|
||||
=> self.orderAgainstZero(mod).compare(.eq),
|
||||
|
||||
return switch (self.ip_index) {
|
||||
.undef => unreachable,
|
||||
.unreachable_value => unreachable,
|
||||
.inferred_alloc => unreachable,
|
||||
.inferred_alloc_comptime => unreachable,
|
||||
.null_value => true,
|
||||
.none => switch (self.tag()) {
|
||||
.opt_payload => false,
|
||||
|
||||
// If it's not one of those two tags then it must be a C pointer value,
|
||||
// in which case the value 0 is null and other values are non-null.
|
||||
|
||||
.zero,
|
||||
.the_only_possible_value,
|
||||
=> true,
|
||||
|
||||
.one => false,
|
||||
|
||||
.int_u64,
|
||||
.int_i64,
|
||||
.int_big_positive,
|
||||
.int_big_negative,
|
||||
=> self.orderAgainstZero(mod).compare(.eq),
|
||||
|
||||
.inferred_alloc => unreachable,
|
||||
.inferred_alloc_comptime => unreachable,
|
||||
|
||||
else => false,
|
||||
},
|
||||
else => false,
|
||||
};
|
||||
}
|
||||
|
|
@ -3025,18 +3025,21 @@ pub const Value = struct {
|
|||
/// something is an error or not because it works without having to figure out the
|
||||
/// string.
|
||||
pub fn getError(self: Value) ?[]const u8 {
|
||||
return switch (self.tag()) {
|
||||
.@"error" => self.castTag(.@"error").?.data.name,
|
||||
.int_u64 => @panic("TODO"),
|
||||
.int_i64 => @panic("TODO"),
|
||||
.int_big_positive => @panic("TODO"),
|
||||
.int_big_negative => @panic("TODO"),
|
||||
.one => @panic("TODO"),
|
||||
return switch (self.ip_index) {
|
||||
.undef => unreachable,
|
||||
.unreachable_value => unreachable,
|
||||
.inferred_alloc => unreachable,
|
||||
.inferred_alloc_comptime => unreachable,
|
||||
.none => switch (self.tag()) {
|
||||
.@"error" => self.castTag(.@"error").?.data.name,
|
||||
.int_u64 => @panic("TODO"),
|
||||
.int_i64 => @panic("TODO"),
|
||||
.int_big_positive => @panic("TODO"),
|
||||
.int_big_negative => @panic("TODO"),
|
||||
.one => @panic("TODO"),
|
||||
.inferred_alloc => unreachable,
|
||||
.inferred_alloc_comptime => unreachable,
|
||||
|
||||
else => null,
|
||||
},
|
||||
else => null,
|
||||
};
|
||||
}
|
||||
|
|
@ -3044,13 +3047,16 @@ pub const Value = struct {
|
|||
/// Assumes the type is an error union. Returns true if and only if the value is
|
||||
/// the error union payload, not an error.
|
||||
pub fn errorUnionIsPayload(val: Value) bool {
|
||||
return switch (val.tag()) {
|
||||
.eu_payload => true,
|
||||
else => false,
|
||||
|
||||
return switch (val.ip_index) {
|
||||
.undef => unreachable,
|
||||
.inferred_alloc => unreachable,
|
||||
.inferred_alloc_comptime => unreachable,
|
||||
.none => switch (val.tag()) {
|
||||
.eu_payload => true,
|
||||
else => false,
|
||||
|
||||
.inferred_alloc => unreachable,
|
||||
.inferred_alloc_comptime => unreachable,
|
||||
},
|
||||
else => false,
|
||||
};
|
||||
}
|
||||
|
||||
|
|
@ -3065,17 +3071,20 @@ pub const Value = struct {
|
|||
|
||||
/// Valid for all types. Asserts the value is not undefined.
|
||||
pub fn isFloat(self: Value) bool {
|
||||
return switch (self.tag()) {
|
||||
return switch (self.ip_index) {
|
||||
.undef => unreachable,
|
||||
.inferred_alloc => unreachable,
|
||||
.inferred_alloc_comptime => unreachable,
|
||||
.none => switch (self.tag()) {
|
||||
.inferred_alloc => unreachable,
|
||||
.inferred_alloc_comptime => unreachable,
|
||||
|
||||
.float_16,
|
||||
.float_32,
|
||||
.float_64,
|
||||
.float_80,
|
||||
.float_128,
|
||||
=> true,
|
||||
.float_16,
|
||||
.float_32,
|
||||
.float_64,
|
||||
.float_80,
|
||||
.float_128,
|
||||
=> true,
|
||||
else => false,
|
||||
},
|
||||
else => false,
|
||||
};
|
||||
}
|
||||
|
|
@ -3102,40 +3111,44 @@ pub const Value = struct {
|
|||
|
||||
pub fn intToFloatScalar(val: Value, arena: Allocator, float_ty: Type, mod: *Module, opt_sema: ?*Sema) !Value {
|
||||
const target = mod.getTarget();
|
||||
switch (val.tag()) {
|
||||
.undef, .zero, .one => return val,
|
||||
.the_only_possible_value => return Value.initTag(.zero), // for i0, u0
|
||||
.int_u64 => {
|
||||
return intToFloatInner(val.castTag(.int_u64).?.data, arena, float_ty, target);
|
||||
},
|
||||
.int_i64 => {
|
||||
return intToFloatInner(val.castTag(.int_i64).?.data, arena, float_ty, target);
|
||||
},
|
||||
.int_big_positive => {
|
||||
const limbs = val.castTag(.int_big_positive).?.data;
|
||||
const float = bigIntToFloat(limbs, true);
|
||||
return floatToValue(float, arena, float_ty, target);
|
||||
},
|
||||
.int_big_negative => {
|
||||
const limbs = val.castTag(.int_big_negative).?.data;
|
||||
const float = bigIntToFloat(limbs, false);
|
||||
return floatToValue(float, arena, float_ty, target);
|
||||
},
|
||||
.lazy_align => {
|
||||
const ty = val.castTag(.lazy_align).?.data;
|
||||
if (opt_sema) |sema| {
|
||||
return intToFloatInner((try ty.abiAlignmentAdvanced(mod, .{ .sema = sema })).scalar, arena, float_ty, target);
|
||||
} else {
|
||||
return intToFloatInner(ty.abiAlignment(mod), arena, float_ty, target);
|
||||
}
|
||||
},
|
||||
.lazy_size => {
|
||||
const ty = val.castTag(.lazy_size).?.data;
|
||||
if (opt_sema) |sema| {
|
||||
return intToFloatInner((try ty.abiSizeAdvanced(mod, .{ .sema = sema })).scalar, arena, float_ty, target);
|
||||
} else {
|
||||
return intToFloatInner(ty.abiSize(mod), arena, float_ty, target);
|
||||
}
|
||||
switch (val.ip_index) {
|
||||
.undef => return val,
|
||||
.none => switch (val.tag()) {
|
||||
.zero, .one => return val,
|
||||
.the_only_possible_value => return Value.initTag(.zero), // for i0, u0
|
||||
.int_u64 => {
|
||||
return intToFloatInner(val.castTag(.int_u64).?.data, arena, float_ty, target);
|
||||
},
|
||||
.int_i64 => {
|
||||
return intToFloatInner(val.castTag(.int_i64).?.data, arena, float_ty, target);
|
||||
},
|
||||
.int_big_positive => {
|
||||
const limbs = val.castTag(.int_big_positive).?.data;
|
||||
const float = bigIntToFloat(limbs, true);
|
||||
return floatToValue(float, arena, float_ty, target);
|
||||
},
|
||||
.int_big_negative => {
|
||||
const limbs = val.castTag(.int_big_negative).?.data;
|
||||
const float = bigIntToFloat(limbs, false);
|
||||
return floatToValue(float, arena, float_ty, target);
|
||||
},
|
||||
.lazy_align => {
|
||||
const ty = val.castTag(.lazy_align).?.data;
|
||||
if (opt_sema) |sema| {
|
||||
return intToFloatInner((try ty.abiAlignmentAdvanced(mod, .{ .sema = sema })).scalar, arena, float_ty, target);
|
||||
} else {
|
||||
return intToFloatInner(ty.abiAlignment(mod), arena, float_ty, target);
|
||||
}
|
||||
},
|
||||
.lazy_size => {
|
||||
const ty = val.castTag(.lazy_size).?.data;
|
||||
if (opt_sema) |sema| {
|
||||
return intToFloatInner((try ty.abiSizeAdvanced(mod, .{ .sema = sema })).scalar, arena, float_ty, target);
|
||||
} else {
|
||||
return intToFloatInner(ty.abiSize(mod), arena, float_ty, target);
|
||||
}
|
||||
},
|
||||
else => unreachable,
|
||||
},
|
||||
else => unreachable,
|
||||
}
|
||||
|
|
@ -3381,7 +3394,7 @@ pub const Value = struct {
|
|||
arena: Allocator,
|
||||
mod: *Module,
|
||||
) !Value {
|
||||
if (lhs.isUndef() or rhs.isUndef()) return Value.initTag(.undef);
|
||||
if (lhs.isUndef() or rhs.isUndef()) return Value.undef;
|
||||
|
||||
if (ty.zigTypeTag(mod) == .ComptimeInt) {
|
||||
return intMul(lhs, rhs, ty, arena, mod);
|
||||
|
|
@ -3492,7 +3505,7 @@ pub const Value = struct {
|
|||
|
||||
/// operands must be integers; handles undefined.
|
||||
pub fn bitwiseNotScalar(val: Value, ty: Type, arena: Allocator, mod: *Module) !Value {
|
||||
if (val.isUndef()) return Value.initTag(.undef);
|
||||
if (val.isUndef()) return Value.undef;
|
||||
|
||||
const info = ty.intInfo(mod);
|
||||
|
||||
|
|
@ -3532,7 +3545,7 @@ pub const Value = struct {
|
|||
|
||||
/// operands must be integers; handles undefined.
|
||||
pub fn bitwiseAndScalar(lhs: Value, rhs: Value, arena: Allocator, mod: *Module) !Value {
|
||||
if (lhs.isUndef() or rhs.isUndef()) return Value.initTag(.undef);
|
||||
if (lhs.isUndef() or rhs.isUndef()) return Value.undef;
|
||||
|
||||
// TODO is this a performance issue? maybe we should try the operation without
|
||||
// resorting to BigInt first.
|
||||
|
|
@ -3568,7 +3581,7 @@ pub const Value = struct {
|
|||
|
||||
/// operands must be integers; handles undefined.
|
||||
pub fn bitwiseNandScalar(lhs: Value, rhs: Value, ty: Type, arena: Allocator, mod: *Module) !Value {
|
||||
if (lhs.isUndef() or rhs.isUndef()) return Value.initTag(.undef);
|
||||
if (lhs.isUndef() or rhs.isUndef()) return Value.undef;
|
||||
|
||||
const anded = try bitwiseAnd(lhs, rhs, ty, arena, mod);
|
||||
|
||||
|
|
@ -3598,7 +3611,7 @@ pub const Value = struct {
|
|||
|
||||
/// operands must be integers; handles undefined.
|
||||
pub fn bitwiseOrScalar(lhs: Value, rhs: Value, arena: Allocator, mod: *Module) !Value {
|
||||
if (lhs.isUndef() or rhs.isUndef()) return Value.initTag(.undef);
|
||||
if (lhs.isUndef() or rhs.isUndef()) return Value.undef;
|
||||
|
||||
// TODO is this a performance issue? maybe we should try the operation without
|
||||
// resorting to BigInt first.
|
||||
|
|
@ -3633,7 +3646,7 @@ pub const Value = struct {
|
|||
|
||||
/// operands must be integers; handles undefined.
|
||||
pub fn bitwiseXorScalar(lhs: Value, rhs: Value, arena: Allocator, mod: *Module) !Value {
|
||||
if (lhs.isUndef() or rhs.isUndef()) return Value.initTag(.undef);
|
||||
if (lhs.isUndef() or rhs.isUndef()) return Value.undef;
|
||||
|
||||
// TODO is this a performance issue? maybe we should try the operation without
|
||||
// resorting to BigInt first.
|
||||
|
|
@ -5393,11 +5406,12 @@ pub const Value = struct {
|
|||
.ip_index = .none,
|
||||
.legacy = .{ .ptr_otherwise = &negative_one_payload.base },
|
||||
};
|
||||
pub const undef = initTag(.undef);
|
||||
pub const undef: Value = .{ .ip_index = .undef, .legacy = undefined };
|
||||
pub const @"void": Value = .{ .ip_index = .void_value, .legacy = undefined };
|
||||
pub const @"null" = initTag(.null_value);
|
||||
pub const @"null": Value = .{ .ip_index = .null_value, .legacy = undefined };
|
||||
pub const @"false": Value = .{ .ip_index = .bool_false, .legacy = undefined };
|
||||
pub const @"true": Value = .{ .ip_index = .bool_true, .legacy = undefined };
|
||||
pub const @"unreachable": Value = .{ .ip_index = .unreachable_value, .legacy = undefined };
|
||||
|
||||
pub const generic_poison: Value = .{ .ip_index = .generic_poison, .legacy = undefined };
|
||||
pub const generic_poison_type: Value = .{ .ip_index = .generic_poison_type, .legacy = undefined };
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue