Commit b40d36c90b
Changed files (7)
src/AstGen.zig
@@ -28,8 +28,6 @@ const BuiltinFn = @import("BuiltinFn.zig");
instructions: std.MultiArrayList(zir.Inst) = .{},
string_bytes: ArrayListUnmanaged(u8) = .{},
extra: ArrayListUnmanaged(u32) = .{},
-decl_map: std.StringArrayHashMapUnmanaged(void) = .{},
-decls: ArrayListUnmanaged(*Decl) = .{},
/// The end of special indexes. `zir.Inst.Ref` subtracts against this number to convert
/// to `zir.Inst.Index`. The default here is correct if there are 0 parameters.
ref_start_index: u32 = zir.Inst.Ref.typed_value_map.len,
@@ -110,8 +108,6 @@ pub fn deinit(astgen: *AstGen) void {
astgen.instructions.deinit(gpa);
astgen.extra.deinit(gpa);
astgen.string_bytes.deinit(gpa);
- astgen.decl_map.deinit(gpa);
- astgen.decls.deinit(gpa);
}
pub const ResultLoc = union(enum) {
@@ -1183,13 +1179,6 @@ fn blockExprStmts(
// in the above while loop.
const zir_tags = gz.astgen.instructions.items(.tag);
switch (zir_tags[inst]) {
- .@"const" => {
- const tv = gz.astgen.instructions.items(.data)[inst].@"const";
- break :b switch (tv.ty.zigTypeTag()) {
- .NoReturn, .Void => true,
- else => false,
- };
- },
// For some instructions, swap in a slightly different ZIR tag
// so we can avoid a separate ensure_result_used instruction.
.call_none_chkused => unreachable,
@@ -1257,6 +1246,8 @@ fn blockExprStmts(
.fn_type_cc,
.fn_type_cc_var_args,
.int,
+ .float,
+ .float128,
.intcast,
.int_type,
.is_non_null,
@@ -1334,7 +1325,10 @@ fn blockExprStmts(
.struct_decl_extern,
.union_decl,
.enum_decl,
+ .enum_decl_nonexhaustive,
.opaque_decl,
+ .int_to_enum,
+ .enum_to_int,
=> break :b false,
// ZIR instructions that are always either `noreturn` or `void`.
@@ -1823,15 +1817,18 @@ fn containerDecl(
defer bit_bag.deinit(gpa);
var cur_bit_bag: u32 = 0;
- var member_index: usize = 0;
- while (true) {
- const member_node = container_decl.ast.members[member_index];
+ var field_index: usize = 0;
+ for (container_decl.ast.members) |member_node| {
const member = switch (node_tags[member_node]) {
.container_field_init => tree.containerFieldInit(member_node),
.container_field_align => tree.containerFieldAlign(member_node),
.container_field => tree.containerField(member_node),
- else => unreachable,
+ else => continue,
};
+ if (field_index % 16 == 0 and field_index != 0) {
+ try bit_bag.append(gpa, cur_bit_bag);
+ cur_bit_bag = 0;
+ }
if (member.comptime_token) |comptime_token| {
return mod.failTok(scope, comptime_token, "TODO implement comptime struct fields", .{});
}
@@ -1858,17 +1855,9 @@ fn containerDecl(
fields_data.appendAssumeCapacity(@enumToInt(default_inst));
}
- member_index += 1;
- if (member_index < container_decl.ast.members.len) {
- if (member_index % 16 == 0) {
- try bit_bag.append(gpa, cur_bit_bag);
- cur_bit_bag = 0;
- }
- } else {
- break;
- }
+ field_index += 1;
}
- const empty_slot_count = 16 - ((member_index - 1) % 16);
+ const empty_slot_count = 16 - ((field_index - 1) % 16);
cur_bit_bag >>= @intCast(u5, empty_slot_count * 2);
const result = try gz.addPlNode(tag, node, zir.Inst.StructDecl{
@@ -1885,7 +1874,172 @@ fn containerDecl(
return mod.failTok(scope, container_decl.ast.main_token, "TODO AstGen for union decl", .{});
},
.keyword_enum => {
- return mod.failTok(scope, container_decl.ast.main_token, "TODO AstGen for enum decl", .{});
+ if (container_decl.layout_token) |t| {
+ return mod.failTok(scope, t, "enums do not support 'packed' or 'extern'; instead provide an explicit integer tag type", .{});
+ }
+ // Count total fields as well as how many have explicitly provided tag values.
+ const counts = blk: {
+ var values: usize = 0;
+ var total_fields: usize = 0;
+ var decls: usize = 0;
+ var nonexhaustive_node: ast.Node.Index = 0;
+ for (container_decl.ast.members) |member_node| {
+ const member = switch (node_tags[member_node]) {
+ .container_field_init => tree.containerFieldInit(member_node),
+ .container_field_align => tree.containerFieldAlign(member_node),
+ .container_field => tree.containerField(member_node),
+ else => {
+ decls += 1;
+ continue;
+ },
+ };
+ if (member.comptime_token) |comptime_token| {
+ return mod.failTok(scope, comptime_token, "enum fields cannot be marked comptime", .{});
+ }
+ if (member.ast.type_expr != 0) {
+ return mod.failNode(scope, member.ast.type_expr, "enum fields do not have types", .{});
+ }
+ if (member.ast.align_expr != 0) {
+ return mod.failNode(scope, member.ast.align_expr, "enum fields do not have alignments", .{});
+ }
+ const name_token = member.ast.name_token;
+ if (mem.eql(u8, tree.tokenSlice(name_token), "_")) {
+ if (nonexhaustive_node != 0) {
+ const msg = msg: {
+ const msg = try mod.errMsg(
+ scope,
+ gz.nodeSrcLoc(member_node),
+ "redundant non-exhaustive enum mark",
+ .{},
+ );
+ errdefer msg.destroy(gpa);
+ const other_src = gz.nodeSrcLoc(nonexhaustive_node);
+ try mod.errNote(scope, other_src, msg, "other mark here", .{});
+ break :msg msg;
+ };
+ return mod.failWithOwnedErrorMsg(scope, msg);
+ }
+ nonexhaustive_node = member_node;
+ if (member.ast.value_expr != 0) {
+ return mod.failNode(scope, member.ast.value_expr, "'_' is used to mark an enum as non-exhaustive and cannot be assigned a value", .{});
+ }
+ continue;
+ }
+ total_fields += 1;
+ if (member.ast.value_expr != 0) {
+ values += 1;
+ }
+ }
+ break :blk .{
+ .total_fields = total_fields,
+ .values = values,
+ .decls = decls,
+ .nonexhaustive_node = nonexhaustive_node,
+ };
+ };
+ if (counts.total_fields == 0) {
+ // One can construct an enum with no tags, and it functions the same as `noreturn`. But
+ // this is only useful for generic code; when explicitly using `enum {}` syntax, there
+ // must be at least one tag.
+ return mod.failNode(scope, node, "enum declarations must have at least one tag", .{});
+ }
+ if (counts.nonexhaustive_node != 0 and arg_inst == .none) {
+ const msg = msg: {
+ const msg = try mod.errMsg(
+ scope,
+ gz.nodeSrcLoc(node),
+ "non-exhaustive enum missing integer tag type",
+ .{},
+ );
+ errdefer msg.destroy(gpa);
+ const other_src = gz.nodeSrcLoc(counts.nonexhaustive_node);
+ try mod.errNote(scope, other_src, msg, "marked non-exhaustive here", .{});
+ break :msg msg;
+ };
+ return mod.failWithOwnedErrorMsg(scope, msg);
+ }
+ if (counts.values == 0 and counts.decls == 0 and arg_inst == .none) {
+ // No explicitly provided tag values and no top level declarations! In this case,
+ // we can construct the enum type in AstGen and it will be correctly shared by all
+ // generic function instantiations and comptime function calls.
+ var new_decl_arena = std.heap.ArenaAllocator.init(gpa);
+ errdefer new_decl_arena.deinit();
+ const arena = &new_decl_arena.allocator;
+
+ var fields_map: std.StringArrayHashMapUnmanaged(void) = .{};
+ try fields_map.ensureCapacity(arena, counts.total_fields);
+ for (container_decl.ast.members) |member_node| {
+ if (member_node == counts.nonexhaustive_node)
+ continue;
+ const member = switch (node_tags[member_node]) {
+ .container_field_init => tree.containerFieldInit(member_node),
+ .container_field_align => tree.containerFieldAlign(member_node),
+ .container_field => tree.containerField(member_node),
+ else => unreachable, // We checked earlier.
+ };
+ const name_token = member.ast.name_token;
+ const tag_name = try mod.identifierTokenStringTreeArena(
+ scope,
+ name_token,
+ tree,
+ arena,
+ );
+ const gop = fields_map.getOrPutAssumeCapacity(tag_name);
+ if (gop.found_existing) {
+ const msg = msg: {
+ const msg = try mod.errMsg(
+ scope,
+ gz.tokSrcLoc(name_token),
+ "duplicate enum tag",
+ .{},
+ );
+ errdefer msg.destroy(gpa);
+ // Iterate to find the other tag. We don't eagerly store it in a hash
+ // map because in the hot path there will be no compile error and we
+ // don't need to waste time with a hash map.
+ const bad_node = for (container_decl.ast.members) |other_member_node| {
+ const other_member = switch (node_tags[other_member_node]) {
+ .container_field_init => tree.containerFieldInit(member_node),
+ .container_field_align => tree.containerFieldAlign(member_node),
+ .container_field => tree.containerField(member_node),
+ else => unreachable, // We checked earlier.
+ };
+ const other_tag_name = try mod.identifierTokenStringTreeArena(
+ scope,
+ name_token,
+ tree,
+ arena,
+ );
+ if (mem.eql(u8, tag_name, other_tag_name))
+ break other_member_node;
+ } else unreachable;
+ const other_src = gz.nodeSrcLoc(bad_node);
+ try mod.errNote(scope, other_src, msg, "other tag here", .{});
+ break :msg msg;
+ };
+ return mod.failWithOwnedErrorMsg(scope, msg);
+ }
+ }
+ const enum_simple = try arena.create(Module.EnumSimple);
+ enum_simple.* = .{
+ .owner_decl = astgen.decl,
+ .node_offset = astgen.decl.nodeIndexToRelative(node),
+ .fields = fields_map,
+ };
+ const enum_ty = try Type.Tag.enum_simple.create(arena, enum_simple);
+ const enum_val = try Value.Tag.ty.create(arena, enum_ty);
+ const new_decl = try mod.createAnonymousDecl(scope, &new_decl_arena, .{
+ .ty = Type.initTag(.type),
+ .val = enum_val,
+ });
+ const decl_index = try mod.declareDeclDependency(astgen.decl, new_decl);
+ const result = try gz.addDecl(.decl_val, decl_index, node);
+ return rvalue(gz, scope, rl, result, node);
+ }
+ // In this case we must generate ZIR code for the tag values, similar to
+ // how structs are handled above. The new anonymous Decl will be created in
+ // Sema, not AstGen.
+ return mod.failNode(scope, node, "TODO AstGen for enum decl with decls or explicitly provided field values", .{});
},
.keyword_opaque => {
const result = try gz.addNode(.opaque_decl, node);
@@ -1901,11 +2055,11 @@ fn errorSetDecl(
rl: ResultLoc,
node: ast.Node.Index,
) InnerError!zir.Inst.Ref {
- const mod = gz.astgen.mod;
+ const astgen = gz.astgen;
+ const mod = astgen.mod;
const tree = gz.tree();
const main_tokens = tree.nodes.items(.main_token);
const token_tags = tree.tokens.items(.tag);
- const arena = gz.astgen.arena;
// Count how many fields there are.
const error_token = main_tokens[node];
@@ -1922,6 +2076,11 @@ fn errorSetDecl(
} else unreachable; // TODO should not need else unreachable here
};
+ const gpa = mod.gpa;
+ var new_decl_arena = std.heap.ArenaAllocator.init(gpa);
+ errdefer new_decl_arena.deinit();
+ const arena = &new_decl_arena.allocator;
+
const fields = try arena.alloc([]const u8, count);
{
var tok_i = error_token + 2;
@@ -1930,7 +2089,7 @@ fn errorSetDecl(
switch (token_tags[tok_i]) {
.doc_comment, .comma => {},
.identifier => {
- fields[field_i] = try mod.identifierTokenString(scope, tok_i);
+ fields[field_i] = try mod.identifierTokenStringTreeArena(scope, tok_i, tree, arena);
field_i += 1;
},
.r_brace => break,
@@ -1940,18 +2099,19 @@ fn errorSetDecl(
}
const error_set = try arena.create(Module.ErrorSet);
error_set.* = .{
- .owner_decl = gz.astgen.decl,
- .node_offset = gz.astgen.decl.nodeIndexToRelative(node),
+ .owner_decl = astgen.decl,
+ .node_offset = astgen.decl.nodeIndexToRelative(node),
.names_ptr = fields.ptr,
.names_len = @intCast(u32, fields.len),
};
const error_set_ty = try Type.Tag.error_set.create(arena, error_set);
- const typed_value = try arena.create(TypedValue);
- typed_value.* = .{
+ const error_set_val = try Value.Tag.ty.create(arena, error_set_ty);
+ const new_decl = try mod.createAnonymousDecl(scope, &new_decl_arena, .{
.ty = Type.initTag(.type),
- .val = try Value.Tag.ty.create(arena, error_set_ty),
- };
- const result = try gz.addConst(typed_value);
+ .val = error_set_val,
+ });
+ const decl_index = try mod.declareDeclDependency(astgen.decl, new_decl);
+ const result = try gz.addDecl(.decl_val, decl_index, node);
return rvalue(gz, scope, rl, result, node);
}
@@ -3426,7 +3586,8 @@ fn identifier(
const tracy = trace(@src());
defer tracy.end();
- const mod = gz.astgen.mod;
+ const astgen = gz.astgen;
+ const mod = astgen.mod;
const tree = gz.tree();
const main_tokens = tree.nodes.items(.main_token);
@@ -3459,7 +3620,7 @@ fn identifier(
const result = try gz.add(.{
.tag = .int_type,
.data = .{ .int_type = .{
- .src_node = gz.astgen.decl.nodeIndexToRelative(ident),
+ .src_node = astgen.decl.nodeIndexToRelative(ident),
.signedness = signedness,
.bit_count = bit_count,
} },
@@ -3497,13 +3658,13 @@ fn identifier(
};
}
- const gop = try gz.astgen.decl_map.getOrPut(mod.gpa, ident_name);
- if (!gop.found_existing) {
- const decl = mod.lookupDeclName(scope, ident_name) orelse
- return mod.failNode(scope, ident, "use of undeclared identifier '{s}'", .{ident_name});
- try gz.astgen.decls.append(mod.gpa, decl);
- }
- const decl_index = @intCast(u32, gop.index);
+ const decl = mod.lookupDeclName(scope, ident_name) orelse {
+ // TODO insert a "dependency on the non-existence of a decl" here to make this
+ // compile error go away when the decl is introduced. This data should be in a global
+ // sparse map since it is only relevant when a compile error occurs.
+ return mod.failNode(scope, ident, "use of undeclared identifier '{s}'", .{ident_name});
+ };
+ const decl_index = try mod.declareDeclDependency(astgen.decl, decl);
switch (rl) {
.ref, .none_or_ref => return gz.addDecl(.decl_ref, decl_index, ident),
else => return rvalue(gz, scope, rl, try gz.addDecl(.decl_val, decl_index, ident), ident),
@@ -3638,12 +3799,23 @@ fn floatLiteral(
const float_number = std.fmt.parseFloat(f128, bytes) catch |e| switch (e) {
error.InvalidCharacter => unreachable, // validated by tokenizer
};
- const typed_value = try arena.create(TypedValue);
- typed_value.* = .{
- .ty = Type.initTag(.comptime_float),
- .val = try Value.Tag.float_128.create(arena, float_number),
- };
- const result = try gz.addConst(typed_value);
+ // If the value fits into a f32 without losing any precision, store it that way.
+ @setFloatMode(.Strict);
+ const smaller_float = @floatCast(f32, float_number);
+ const bigger_again: f128 = smaller_float;
+ if (bigger_again == float_number) {
+ const result = try gz.addFloat(smaller_float, node);
+ return rvalue(gz, scope, rl, result, node);
+ }
+ // We need to use 128 bits. Break the float into 4 u32 values so we can
+ // put it into the `extra` array.
+ const int_bits = @bitCast(u128, float_number);
+ const result = try gz.addPlNode(.float128, node, zir.Inst.Float128{
+ .piece0 = @truncate(u32, int_bits),
+ .piece1 = @truncate(u32, int_bits >> 32),
+ .piece2 = @truncate(u32, int_bits >> 64),
+ .piece3 = @truncate(u32, int_bits >> 96),
+ });
return rvalue(gz, scope, rl, result, node);
}
@@ -3955,6 +4127,20 @@ fn builtinCall(
.bit_cast => return bitCast(gz, scope, rl, node, params[0], params[1]),
.TypeOf => return typeOf(gz, scope, rl, node, params),
+ .int_to_enum => {
+ const result = try gz.addPlNode(.int_to_enum, node, zir.Inst.Bin{
+ .lhs = try typeExpr(gz, scope, params[0]),
+ .rhs = try expr(gz, scope, .none, params[1]),
+ });
+ return rvalue(gz, scope, rl, result, node);
+ },
+
+ .enum_to_int => {
+ const operand = try expr(gz, scope, .none, params[0]);
+ const result = try gz.addUnNode(.enum_to_int, operand, node);
+ return rvalue(gz, scope, rl, result, node);
+ },
+
.add_with_overflow,
.align_cast,
.align_of,
@@ -3981,7 +4167,6 @@ fn builtinCall(
.div_floor,
.div_trunc,
.embed_file,
- .enum_to_int,
.error_name,
.error_return_trace,
.err_set_cast,
@@ -3991,7 +4176,6 @@ fn builtinCall(
.float_to_int,
.has_decl,
.has_field,
- .int_to_enum,
.int_to_float,
.int_to_ptr,
.memcpy,
src/BuiltinFn.zig
@@ -484,7 +484,7 @@ pub const list = list: {
"@intToEnum",
.{
.tag = .int_to_enum,
- .param_count = 1,
+ .param_count = 2,
},
},
.{
src/Module.zig
@@ -290,6 +290,18 @@ pub const Decl = struct {
return decl.container.fullyQualifiedNameHash(mem.spanZ(decl.name));
}
+ pub fn renderFullyQualifiedName(decl: Decl, writer: anytype) !void {
+ const unqualified_name = mem.spanZ(decl.name);
+ return decl.container.renderFullyQualifiedName(unqualified_name, writer);
+ }
+
+ pub fn getFullyQualifiedName(decl: Decl, gpa: *Allocator) ![]u8 {
+ var buffer = std.ArrayList(u8).init(gpa);
+ defer buffer.deinit();
+ try decl.renderFullyQualifiedName(buffer.writer());
+ return buffer.toOwnedSlice();
+ }
+
pub fn typedValue(decl: *Decl) error{AnalysisFail}!TypedValue {
const tvm = decl.typedValueManaged() orelse return error.AnalysisFail;
return tvm.typed_value;
@@ -375,8 +387,7 @@ pub const Struct = struct {
};
pub fn getFullyQualifiedName(s: *Struct, gpa: *Allocator) ![]u8 {
- // TODO this should return e.g. "std.fs.Dir.OpenOptions"
- return gpa.dupe(u8, mem.spanZ(s.owner_decl.name));
+ return s.owner_decl.getFullyQualifiedName(gpa);
}
pub fn srcLoc(s: Struct) SrcLoc {
@@ -387,6 +398,39 @@ pub const Struct = struct {
}
};
+/// Represents the data that an enum declaration provides, when the fields
+/// are auto-numbered, and there are no declarations. The integer tag type
+/// is inferred to be the smallest power of two unsigned int that fits
+/// the number of fields.
+pub const EnumSimple = struct {
+ owner_decl: *Decl,
+ /// Set of field names in declaration order.
+ fields: std.StringArrayHashMapUnmanaged(void),
+ /// Offset from `owner_decl`, points to the enum decl AST node.
+ node_offset: i32,
+};
+
+/// Represents the data that an enum declaration provides, when there is
+/// at least one tag value explicitly specified, or at least one declaration.
+pub const EnumFull = struct {
+ owner_decl: *Decl,
+ /// An integer type which is used for the numerical value of the enum.
+ /// Whether zig chooses this type or the user specifies it, it is stored here.
+ tag_ty: Type,
+ /// Set of field names in declaration order.
+ fields: std.StringArrayHashMapUnmanaged(void),
+ /// Maps integer tag value to field index.
+ /// Entries are in declaration order, same as `fields`.
+ /// If this hash map is empty, it means the enum tags are auto-numbered.
+ values: ValueMap,
+ /// Represents the declarations inside this struct.
+ container: Scope.Container,
+ /// Offset from `owner_decl`, points to the enum decl AST node.
+ node_offset: i32,
+
+ pub const ValueMap = std.ArrayHashMapUnmanaged(Value, void, Value.hash_u32, Value.eql, false);
+};
+
/// Some Fn struct memory is owned by the Decl's TypedValue.Managed arena allocator.
/// Extern functions do not have this data structure; they are represented by
/// the `Decl` only, with a `Value` tag of `extern_fn`.
@@ -634,6 +678,11 @@ pub const Scope = struct {
// TODO container scope qualified names.
return std.zig.hashSrc(name);
}
+
+ pub fn renderFullyQualifiedName(cont: Container, name: []const u8, writer: anytype) !void {
+ // TODO this should render e.g. "std.fs.Dir.OpenOptions"
+ return writer.writeAll(name);
+ }
};
pub const File = struct {
@@ -1030,7 +1079,6 @@ pub const Scope = struct {
.instructions = gz.astgen.instructions.toOwnedSlice(),
.string_bytes = gz.astgen.string_bytes.toOwnedSlice(gpa),
.extra = gz.astgen.extra.toOwnedSlice(gpa),
- .decls = gz.astgen.decls.toOwnedSlice(gpa),
};
}
@@ -1242,6 +1290,16 @@ pub const Scope = struct {
});
}
+ pub fn addFloat(gz: *GenZir, number: f32, src_node: ast.Node.Index) !zir.Inst.Ref {
+ return gz.add(.{
+ .tag = .float,
+ .data = .{ .float = .{
+ .src_node = gz.astgen.decl.nodeIndexToRelative(src_node),
+ .number = number,
+ } },
+ });
+ }
+
pub fn addUnNode(
gz: *GenZir,
tag: zir.Inst.Tag,
@@ -1450,13 +1508,6 @@ pub const Scope = struct {
return new_index;
}
- pub fn addConst(gz: *GenZir, typed_value: *TypedValue) !zir.Inst.Ref {
- return gz.add(.{
- .tag = .@"const",
- .data = .{ .@"const" = typed_value },
- });
- }
-
pub fn add(gz: *GenZir, inst: zir.Inst) !zir.Inst.Ref {
return gz.astgen.indexToRef(try gz.addAsIndex(inst));
}
@@ -3120,12 +3171,14 @@ fn astgenAndSemaVarDecl(
return type_changed;
}
-pub fn declareDeclDependency(mod: *Module, depender: *Decl, dependee: *Decl) !void {
- try depender.dependencies.ensureCapacity(mod.gpa, depender.dependencies.items().len + 1);
- try dependee.dependants.ensureCapacity(mod.gpa, dependee.dependants.items().len + 1);
+/// Returns the depender's index of the dependee.
+pub fn declareDeclDependency(mod: *Module, depender: *Decl, dependee: *Decl) !u32 {
+ try depender.dependencies.ensureCapacity(mod.gpa, depender.dependencies.count() + 1);
+ try dependee.dependants.ensureCapacity(mod.gpa, dependee.dependants.count() + 1);
- depender.dependencies.putAssumeCapacity(dependee, {});
dependee.dependants.putAssumeCapacity(depender, {});
+ const gop = depender.dependencies.getOrPutAssumeCapacity(dependee);
+ return @intCast(u32, gop.index);
}
pub fn getAstTree(mod: *Module, root_scope: *Scope.File) !*const ast.Tree {
@@ -4445,7 +4498,17 @@ pub fn optimizeMode(mod: Module) std.builtin.Mode {
/// Otherwise, returns a reference to the source code bytes directly.
/// See also `appendIdentStr` and `parseStrLit`.
pub fn identifierTokenString(mod: *Module, scope: *Scope, token: ast.TokenIndex) InnerError![]const u8 {
- const tree = scope.tree();
+ return mod.identifierTokenStringTreeArena(scope, token, scope.tree(), scope.arena());
+}
+
+/// `scope` is only used for error reporting.
+pub fn identifierTokenStringTreeArena(
+ mod: *Module,
+ scope: *Scope,
+ token: ast.TokenIndex,
+ tree: *const ast.Tree,
+ arena: *Allocator,
+) InnerError![]const u8 {
const token_tags = tree.tokens.items(.tag);
assert(token_tags[token] == .identifier);
const ident_name = tree.tokenSlice(token);
@@ -4455,7 +4518,8 @@ pub fn identifierTokenString(mod: *Module, scope: *Scope, token: ast.TokenIndex)
var buf: ArrayListUnmanaged(u8) = .{};
defer buf.deinit(mod.gpa);
try parseStrLit(mod, scope, token, &buf, ident_name, 1);
- return buf.toOwnedSlice(mod.gpa);
+ const duped = try arena.dupe(u8, buf.items);
+ return duped;
}
/// Given an identifier token, obtain the string for it (possibly parsing as a string
src/Sema.zig
@@ -168,7 +168,6 @@ pub fn analyzeBody(
.cmp_lte => try sema.zirCmp(block, inst, .lte),
.cmp_neq => try sema.zirCmp(block, inst, .neq),
.coerce_result_ptr => try sema.zirCoerceResultPtr(block, inst),
- .@"const" => try sema.zirConst(block, inst),
.decl_ref => try sema.zirDeclRef(block, inst),
.decl_val => try sema.zirDeclVal(block, inst),
.load => try sema.zirLoad(block, inst),
@@ -179,6 +178,8 @@ pub fn analyzeBody(
.elem_val_node => try sema.zirElemValNode(block, inst),
.enum_literal => try sema.zirEnumLiteral(block, inst),
.enum_literal_small => try sema.zirEnumLiteralSmall(block, inst),
+ .enum_to_int => try sema.zirEnumToInt(block, inst),
+ .int_to_enum => try sema.zirIntToEnum(block, inst),
.err_union_code => try sema.zirErrUnionCode(block, inst),
.err_union_code_ptr => try sema.zirErrUnionCodePtr(block, inst),
.err_union_payload_safe => try sema.zirErrUnionPayload(block, inst, true),
@@ -201,6 +202,8 @@ pub fn analyzeBody(
.import => try sema.zirImport(block, inst),
.indexable_ptr_len => try sema.zirIndexablePtrLen(block, inst),
.int => try sema.zirInt(block, inst),
+ .float => try sema.zirFloat(block, inst),
+ .float128 => try sema.zirFloat128(block, inst),
.int_type => try sema.zirIntType(block, inst),
.intcast => try sema.zirIntcast(block, inst),
.is_err => try sema.zirIsErr(block, inst),
@@ -264,7 +267,8 @@ pub fn analyzeBody(
.struct_decl => try sema.zirStructDecl(block, inst, .Auto),
.struct_decl_packed => try sema.zirStructDecl(block, inst, .Packed),
.struct_decl_extern => try sema.zirStructDecl(block, inst, .Extern),
- .enum_decl => try sema.zirEnumDecl(block, inst),
+ .enum_decl => try sema.zirEnumDecl(block, inst, false),
+ .enum_decl_nonexhaustive => try sema.zirEnumDecl(block, inst, true),
.union_decl => try sema.zirUnionDecl(block, inst),
.opaque_decl => try sema.zirOpaqueDecl(block, inst),
@@ -498,18 +502,6 @@ fn resolveInstConst(
};
}
-fn zirConst(sema: *Sema, block: *Scope.Block, inst: zir.Inst.Index) InnerError!*Inst {
- const tracy = trace(@src());
- defer tracy.end();
-
- const tv_ptr = sema.code.instructions.items(.data)[inst].@"const";
- // Move the TypedValue from old memory to new memory. This allows freeing the ZIR instructions
- // after analysis. This happens, for example, with variable declaration initialization
- // expressions.
- const typed_value_copy = try tv_ptr.copy(sema.arena);
- return sema.mod.constInst(sema.arena, .unneeded, typed_value_copy);
-}
-
fn zirBitcastResultPtr(sema: *Sema, block: *Scope.Block, inst: zir.Inst.Index) InnerError!*Inst {
const tracy = trace(@src());
defer tracy.end();
@@ -617,7 +609,12 @@ fn zirStructDecl(
return sema.analyzeDeclVal(block, src, new_decl);
}
-fn zirEnumDecl(sema: *Sema, block: *Scope.Block, inst: zir.Inst.Index) InnerError!*Inst {
+fn zirEnumDecl(
+ sema: *Sema,
+ block: *Scope.Block,
+ inst: zir.Inst.Index,
+ nonexhaustive: bool,
+) InnerError!*Inst {
const tracy = trace(@src());
defer tracy.end();
@@ -1070,6 +1067,31 @@ fn zirInt(sema: *Sema, block: *Scope.Block, inst: zir.Inst.Index) InnerError!*In
return sema.mod.constIntUnsigned(sema.arena, .unneeded, Type.initTag(.comptime_int), int);
}
+fn zirFloat(sema: *Sema, block: *Scope.Block, inst: zir.Inst.Index) InnerError!*Inst {
+ const arena = sema.arena;
+ const inst_data = sema.code.instructions.items(.data)[inst].float;
+ const src = inst_data.src();
+ const number = inst_data.number;
+
+ return sema.mod.constInst(arena, src, .{
+ .ty = Type.initTag(.comptime_float),
+ .val = try Value.Tag.float_32.create(arena, number),
+ });
+}
+
+fn zirFloat128(sema: *Sema, block: *Scope.Block, inst: zir.Inst.Index) InnerError!*Inst {
+ const arena = sema.arena;
+ const inst_data = sema.code.instructions.items(.data)[inst].pl_node;
+ const extra = sema.code.extraData(zir.Inst.Float128, inst_data.payload_index).data;
+ const src = inst_data.src();
+ const number = extra.get();
+
+ return sema.mod.constInst(arena, src, .{
+ .ty = Type.initTag(.comptime_float),
+ .val = try Value.Tag.float_128.create(arena, number),
+ });
+}
+
fn zirCompileError(sema: *Sema, block: *Scope.Block, inst: zir.Inst.Index) InnerError!zir.Inst.Index {
const tracy = trace(@src());
defer tracy.end();
@@ -1385,7 +1407,7 @@ fn zirDeclRef(sema: *Sema, block: *Scope.Block, inst: zir.Inst.Index) InnerError
const inst_data = sema.code.instructions.items(.data)[inst].pl_node;
const src = inst_data.src();
- const decl = sema.code.decls[inst_data.payload_index];
+ const decl = sema.owner_decl.dependencies.entries.items[inst_data.payload_index].key;
return sema.analyzeDeclRef(block, src, decl);
}
@@ -1395,7 +1417,7 @@ fn zirDeclVal(sema: *Sema, block: *Scope.Block, inst: zir.Inst.Index) InnerError
const inst_data = sema.code.instructions.items(.data)[inst].pl_node;
const src = inst_data.src();
- const decl = sema.code.decls[inst_data.payload_index];
+ const decl = sema.owner_decl.dependencies.entries.items[inst_data.payload_index].key;
return sema.analyzeDeclVal(block, src, decl);
}
@@ -1852,6 +1874,120 @@ fn zirEnumLiteralSmall(sema: *Sema, block: *Scope.Block, inst: zir.Inst.Index) I
});
}
+fn zirEnumToInt(sema: *Sema, block: *Scope.Block, inst: zir.Inst.Index) InnerError!*Inst {
+ const mod = sema.mod;
+ const arena = sema.arena;
+ const inst_data = sema.code.instructions.items(.data)[inst].un_node;
+ const src = inst_data.src();
+ const operand_src: LazySrcLoc = .{ .node_offset_builtin_call_arg0 = inst_data.src_node };
+ const operand = try sema.resolveInst(inst_data.operand);
+
+ const enum_tag: *Inst = switch (operand.ty.zigTypeTag()) {
+ .Enum => operand,
+ .Union => {
+ //if (!operand.ty.unionHasTag()) {
+ // return mod.fail(
+ // &block.base,
+ // operand_src,
+ // "untagged union '{}' cannot be converted to integer",
+ // .{dest_ty_src},
+ // );
+ //}
+ return mod.fail(&block.base, operand_src, "TODO zirEnumToInt for tagged unions", .{});
+ },
+ else => {
+ return mod.fail(&block.base, operand_src, "expected enum or tagged union, found {}", .{
+ operand.ty,
+ });
+ },
+ };
+
+ var int_tag_type_buffer: Type.Payload.Bits = undefined;
+ const int_tag_ty = try enum_tag.ty.intTagType(&int_tag_type_buffer).copy(arena);
+
+ if (enum_tag.ty.onePossibleValue()) |opv| {
+ return mod.constInst(arena, src, .{
+ .ty = int_tag_ty,
+ .val = opv,
+ });
+ }
+
+ if (enum_tag.value()) |enum_tag_val| {
+ if (enum_tag_val.castTag(.enum_field_index)) |enum_field_payload| {
+ const field_index = enum_field_payload.data;
+ switch (enum_tag.ty.tag()) {
+ .enum_full => {
+ const enum_full = enum_tag.ty.castTag(.enum_full).?.data;
+ const val = enum_full.values.entries.items[field_index].key;
+ return mod.constInst(arena, src, .{
+ .ty = int_tag_ty,
+ .val = val,
+ });
+ },
+ .enum_simple => {
+ // Field index and integer values are the same.
+ const val = try Value.Tag.int_u64.create(arena, field_index);
+ return mod.constInst(arena, src, .{
+ .ty = int_tag_ty,
+ .val = val,
+ });
+ },
+ else => unreachable,
+ }
+ } else {
+ // Assume it is already an integer and return it directly.
+ return mod.constInst(arena, src, .{
+ .ty = int_tag_ty,
+ .val = enum_tag_val,
+ });
+ }
+ }
+
+ try sema.requireRuntimeBlock(block, src);
+ return block.addUnOp(src, int_tag_ty, .bitcast, enum_tag);
+}
+
+fn zirIntToEnum(sema: *Sema, block: *Scope.Block, inst: zir.Inst.Index) InnerError!*Inst {
+ const mod = sema.mod;
+ const target = mod.getTarget();
+ const arena = sema.arena;
+ const inst_data = sema.code.instructions.items(.data)[inst].pl_node;
+ const extra = sema.code.extraData(zir.Inst.Bin, inst_data.payload_index).data;
+ const src = inst_data.src();
+ const dest_ty_src: LazySrcLoc = .{ .node_offset_builtin_call_arg0 = inst_data.src_node };
+ const operand_src: LazySrcLoc = .{ .node_offset_builtin_call_arg1 = inst_data.src_node };
+ const dest_ty = try sema.resolveType(block, dest_ty_src, extra.lhs);
+ const operand = try sema.resolveInst(extra.rhs);
+
+ if (dest_ty.zigTypeTag() != .Enum) {
+ return mod.fail(&block.base, dest_ty_src, "expected enum, found {}", .{dest_ty});
+ }
+
+ if (!dest_ty.isExhaustiveEnum()) {
+ if (operand.value()) |int_val| {
+ return mod.constInst(arena, src, .{
+ .ty = dest_ty,
+ .val = int_val,
+ });
+ }
+ }
+
+ if (try sema.resolveDefinedValue(block, operand_src, operand)) |int_val| {
+ if (!dest_ty.enumHasInt(int_val, target)) {
+ return mod.fail(&block.base, src, "enum '{}' has no tag with value {}", .{
+ dest_ty, int_val,
+ });
+ }
+ return mod.constInst(arena, src, .{
+ .ty = dest_ty,
+ .val = int_val,
+ });
+ }
+
+ try sema.requireRuntimeBlock(block, src);
+ return block.addUnOp(src, dest_ty, .bitcast, operand);
+}
+
/// Pointer in, pointer out.
fn zirOptionalPayloadPtr(
sema: *Sema,
@@ -4630,7 +4766,7 @@ fn analyzeDeclVal(sema: *Sema, block: *Scope.Block, src: LazySrcLoc, decl: *Decl
}
fn analyzeDeclRef(sema: *Sema, block: *Scope.Block, src: LazySrcLoc, decl: *Decl) InnerError!*Inst {
- try sema.mod.declareDeclDependency(sema.owner_decl, decl);
+ _ = try sema.mod.declareDeclDependency(sema.owner_decl, decl);
sema.mod.ensureDeclAnalyzed(decl) catch |err| {
if (sema.func) |func| {
func.state = .dependency_failure;
src/type.zig
@@ -93,9 +93,15 @@ pub const Type = extern union {
.anyerror_void_error_union, .error_union => return .ErrorUnion,
- .empty_struct => return .Struct,
- .empty_struct_literal => return .Struct,
- .@"struct" => return .Struct,
+ .empty_struct,
+ .empty_struct_literal,
+ .@"struct",
+ => return .Struct,
+
+ .enum_full,
+ .enum_nonexhaustive,
+ .enum_simple,
+ => return .Enum,
.var_args_param => unreachable, // can be any type
}
@@ -614,6 +620,8 @@ pub const Type = extern union {
.error_set_single => return self.copyPayloadShallow(allocator, Payload.Name),
.empty_struct => return self.copyPayloadShallow(allocator, Payload.ContainerScope),
.@"struct" => return self.copyPayloadShallow(allocator, Payload.Struct),
+ .enum_simple => return self.copyPayloadShallow(allocator, Payload.EnumSimple),
+ .enum_full, .enum_nonexhaustive => return self.copyPayloadShallow(allocator, Payload.EnumFull),
.@"opaque" => return self.copyPayloadShallow(allocator, Payload.Opaque),
}
}
@@ -629,8 +637,8 @@ pub const Type = extern union {
self: Type,
comptime fmt: []const u8,
options: std.fmt.FormatOptions,
- out_stream: anytype,
- ) @TypeOf(out_stream).Error!void {
+ writer: anytype,
+ ) @TypeOf(writer).Error!void {
comptime assert(fmt.len == 0);
var ty = self;
while (true) {
@@ -670,132 +678,149 @@ pub const Type = extern union {
.comptime_float,
.noreturn,
.var_args_param,
- => return out_stream.writeAll(@tagName(t)),
-
- .enum_literal => return out_stream.writeAll("@Type(.EnumLiteral)"),
- .@"null" => return out_stream.writeAll("@Type(.Null)"),
- .@"undefined" => return out_stream.writeAll("@Type(.Undefined)"),
-
- .empty_struct, .empty_struct_literal => return out_stream.writeAll("struct {}"),
- .@"struct" => return out_stream.writeAll("(struct)"),
- .anyerror_void_error_union => return out_stream.writeAll("anyerror!void"),
- .const_slice_u8 => return out_stream.writeAll("[]const u8"),
- .fn_noreturn_no_args => return out_stream.writeAll("fn() noreturn"),
- .fn_void_no_args => return out_stream.writeAll("fn() void"),
- .fn_naked_noreturn_no_args => return out_stream.writeAll("fn() callconv(.Naked) noreturn"),
- .fn_ccc_void_no_args => return out_stream.writeAll("fn() callconv(.C) void"),
- .single_const_pointer_to_comptime_int => return out_stream.writeAll("*const comptime_int"),
+ => return writer.writeAll(@tagName(t)),
+
+ .enum_literal => return writer.writeAll("@Type(.EnumLiteral)"),
+ .@"null" => return writer.writeAll("@Type(.Null)"),
+ .@"undefined" => return writer.writeAll("@Type(.Undefined)"),
+
+ .empty_struct, .empty_struct_literal => return writer.writeAll("struct {}"),
+
+ .@"struct" => {
+ const struct_obj = self.castTag(.@"struct").?.data;
+ return struct_obj.owner_decl.renderFullyQualifiedName(writer);
+ },
+ .enum_full, .enum_nonexhaustive => {
+ const enum_full = self.castTag(.enum_full).?.data;
+ return enum_full.owner_decl.renderFullyQualifiedName(writer);
+ },
+ .enum_simple => {
+ const enum_simple = self.castTag(.enum_simple).?.data;
+ return enum_simple.owner_decl.renderFullyQualifiedName(writer);
+ },
+ .@"opaque" => {
+ // TODO use declaration name
+ return writer.writeAll("opaque {}");
+ },
+
+ .anyerror_void_error_union => return writer.writeAll("anyerror!void"),
+ .const_slice_u8 => return writer.writeAll("[]const u8"),
+ .fn_noreturn_no_args => return writer.writeAll("fn() noreturn"),
+ .fn_void_no_args => return writer.writeAll("fn() void"),
+ .fn_naked_noreturn_no_args => return writer.writeAll("fn() callconv(.Naked) noreturn"),
+ .fn_ccc_void_no_args => return writer.writeAll("fn() callconv(.C) void"),
+ .single_const_pointer_to_comptime_int => return writer.writeAll("*const comptime_int"),
.function => {
const payload = ty.castTag(.function).?.data;
- try out_stream.writeAll("fn(");
+ try writer.writeAll("fn(");
for (payload.param_types) |param_type, i| {
- if (i != 0) try out_stream.writeAll(", ");
- try param_type.format("", .{}, out_stream);
+ if (i != 0) try writer.writeAll(", ");
+ try param_type.format("", .{}, writer);
}
if (payload.is_var_args) {
if (payload.param_types.len != 0) {
- try out_stream.writeAll(", ");
+ try writer.writeAll(", ");
}
- try out_stream.writeAll("...");
+ try writer.writeAll("...");
}
- try out_stream.writeAll(") callconv(.");
- try out_stream.writeAll(@tagName(payload.cc));
- try out_stream.writeAll(")");
+ try writer.writeAll(") callconv(.");
+ try writer.writeAll(@tagName(payload.cc));
+ try writer.writeAll(")");
ty = payload.return_type;
continue;
},
.array_u8 => {
const len = ty.castTag(.array_u8).?.data;
- return out_stream.print("[{d}]u8", .{len});
+ return writer.print("[{d}]u8", .{len});
},
.array_u8_sentinel_0 => {
const len = ty.castTag(.array_u8_sentinel_0).?.data;
- return out_stream.print("[{d}:0]u8", .{len});
+ return writer.print("[{d}:0]u8", .{len});
},
.array => {
const payload = ty.castTag(.array).?.data;
- try out_stream.print("[{d}]", .{payload.len});
+ try writer.print("[{d}]", .{payload.len});
ty = payload.elem_type;
continue;
},
.array_sentinel => {
const payload = ty.castTag(.array_sentinel).?.data;
- try out_stream.print("[{d}:{}]", .{ payload.len, payload.sentinel });
+ try writer.print("[{d}:{}]", .{ payload.len, payload.sentinel });
ty = payload.elem_type;
continue;
},
.single_const_pointer => {
const pointee_type = ty.castTag(.single_const_pointer).?.data;
- try out_stream.writeAll("*const ");
+ try writer.writeAll("*const ");
ty = pointee_type;
continue;
},
.single_mut_pointer => {
const pointee_type = ty.castTag(.single_mut_pointer).?.data;
- try out_stream.writeAll("*");
+ try writer.writeAll("*");
ty = pointee_type;
continue;
},
.many_const_pointer => {
const pointee_type = ty.castTag(.many_const_pointer).?.data;
- try out_stream.writeAll("[*]const ");
+ try writer.writeAll("[*]const ");
ty = pointee_type;
continue;
},
.many_mut_pointer => {
const pointee_type = ty.castTag(.many_mut_pointer).?.data;
- try out_stream.writeAll("[*]");
+ try writer.writeAll("[*]");
ty = pointee_type;
continue;
},
.c_const_pointer => {
const pointee_type = ty.castTag(.c_const_pointer).?.data;
- try out_stream.writeAll("[*c]const ");
+ try writer.writeAll("[*c]const ");
ty = pointee_type;
continue;
},
.c_mut_pointer => {
const pointee_type = ty.castTag(.c_mut_pointer).?.data;
- try out_stream.writeAll("[*c]");
+ try writer.writeAll("[*c]");
ty = pointee_type;
continue;
},
.const_slice => {
const pointee_type = ty.castTag(.const_slice).?.data;
- try out_stream.writeAll("[]const ");
+ try writer.writeAll("[]const ");
ty = pointee_type;
continue;
},
.mut_slice => {
const pointee_type = ty.castTag(.mut_slice).?.data;
- try out_stream.writeAll("[]");
+ try writer.writeAll("[]");
ty = pointee_type;
continue;
},
.int_signed => {
const bits = ty.castTag(.int_signed).?.data;
- return out_stream.print("i{d}", .{bits});
+ return writer.print("i{d}", .{bits});
},
.int_unsigned => {
const bits = ty.castTag(.int_unsigned).?.data;
- return out_stream.print("u{d}", .{bits});
+ return writer.print("u{d}", .{bits});
},
.optional => {
const child_type = ty.castTag(.optional).?.data;
- try out_stream.writeByte('?');
+ try writer.writeByte('?');
ty = child_type;
continue;
},
.optional_single_const_pointer => {
const pointee_type = ty.castTag(.optional_single_const_pointer).?.data;
- try out_stream.writeAll("?*const ");
+ try writer.writeAll("?*const ");
ty = pointee_type;
continue;
},
.optional_single_mut_pointer => {
const pointee_type = ty.castTag(.optional_single_mut_pointer).?.data;
- try out_stream.writeAll("?*");
+ try writer.writeAll("?*");
ty = pointee_type;
continue;
},
@@ -804,48 +829,46 @@ pub const Type = extern union {
const payload = ty.castTag(.pointer).?.data;
if (payload.sentinel) |some| switch (payload.size) {
.One, .C => unreachable,
- .Many => try out_stream.print("[*:{}]", .{some}),
- .Slice => try out_stream.print("[:{}]", .{some}),
+ .Many => try writer.print("[*:{}]", .{some}),
+ .Slice => try writer.print("[:{}]", .{some}),
} else switch (payload.size) {
- .One => try out_stream.writeAll("*"),
- .Many => try out_stream.writeAll("[*]"),
- .C => try out_stream.writeAll("[*c]"),
- .Slice => try out_stream.writeAll("[]"),
+ .One => try writer.writeAll("*"),
+ .Many => try writer.writeAll("[*]"),
+ .C => try writer.writeAll("[*c]"),
+ .Slice => try writer.writeAll("[]"),
}
if (payload.@"align" != 0) {
- try out_stream.print("align({d}", .{payload.@"align"});
+ try writer.print("align({d}", .{payload.@"align"});
if (payload.bit_offset != 0) {
- try out_stream.print(":{d}:{d}", .{ payload.bit_offset, payload.host_size });
+ try writer.print(":{d}:{d}", .{ payload.bit_offset, payload.host_size });
}
- try out_stream.writeAll(") ");
+ try writer.writeAll(") ");
}
- if (!payload.mutable) try out_stream.writeAll("const ");
- if (payload.@"volatile") try out_stream.writeAll("volatile ");
- if (payload.@"allowzero") try out_stream.writeAll("allowzero ");
+ if (!payload.mutable) try writer.writeAll("const ");
+ if (payload.@"volatile") try writer.writeAll("volatile ");
+ if (payload.@"allowzero") try writer.writeAll("allowzero ");
ty = payload.pointee_type;
continue;
},
.error_union => {
const payload = ty.castTag(.error_union).?.data;
- try payload.error_set.format("", .{}, out_stream);
- try out_stream.writeAll("!");
+ try payload.error_set.format("", .{}, writer);
+ try writer.writeAll("!");
ty = payload.payload;
continue;
},
.error_set => {
const error_set = ty.castTag(.error_set).?.data;
- return out_stream.writeAll(std.mem.spanZ(error_set.owner_decl.name));
+ return writer.writeAll(std.mem.spanZ(error_set.owner_decl.name));
},
.error_set_single => {
const name = ty.castTag(.error_set_single).?.data;
- return out_stream.print("error{{{s}}}", .{name});
+ return writer.print("error{{{s}}}", .{name});
},
- .inferred_alloc_const => return out_stream.writeAll("(inferred_alloc_const)"),
- .inferred_alloc_mut => return out_stream.writeAll("(inferred_alloc_mut)"),
- // TODO use declaration name
- .@"opaque" => return out_stream.writeAll("opaque {}"),
+ .inferred_alloc_const => return writer.writeAll("(inferred_alloc_const)"),
+ .inferred_alloc_mut => return writer.writeAll("(inferred_alloc_mut)"),
}
unreachable;
}
@@ -954,6 +977,19 @@ pub const Type = extern union {
return false;
}
},
+ .enum_full => {
+ const enum_full = self.castTag(.enum_full).?.data;
+ return enum_full.fields.count() >= 2;
+ },
+ .enum_simple => {
+ const enum_simple = self.castTag(.enum_simple).?.data;
+ return enum_simple.fields.count() >= 2;
+ },
+ .enum_nonexhaustive => {
+ var buffer: Payload.Bits = undefined;
+ const int_tag_ty = self.intTagType(&buffer);
+ return int_tag_ty.hasCodeGenBits();
+ },
// TODO lazy types
.array => self.elemType().hasCodeGenBits() and self.arrayLen() != 0,
@@ -1112,13 +1148,37 @@ pub const Type = extern union {
} else if (!payload.payload.hasCodeGenBits()) {
return payload.error_set.abiAlignment(target);
}
- @panic("TODO abiAlignment error union");
+ return std.math.max(
+ payload.payload.abiAlignment(target),
+ payload.error_set.abiAlignment(target),
+ );
},
.@"struct" => {
- @panic("TODO abiAlignment struct");
+ // TODO take into account field alignment
+ // also make this possible to fail, and lazy
+ // I think we need to move all the functions from type.zig which can
+ // fail into Sema.
+ // Probably will need to introduce multi-stage struct resolution just
+ // like we have in stage1.
+ const struct_obj = self.castTag(.@"struct").?.data;
+ var biggest: u32 = 0;
+ for (struct_obj.fields.entries.items) |entry| {
+ const field_ty = entry.value.ty;
+ if (!field_ty.hasCodeGenBits()) continue;
+ const field_align = field_ty.abiAlignment(target);
+ if (field_align > biggest) {
+ return field_align;
+ }
+ }
+ assert(biggest != 0);
+ return biggest;
+ },
+ .enum_full, .enum_nonexhaustive, .enum_simple => {
+ var buffer: Payload.Bits = undefined;
+ const int_tag_ty = self.intTagType(&buffer);
+ return int_tag_ty.abiAlignment(target);
},
-
.c_void,
.void,
.type,
@@ -1166,6 +1226,11 @@ pub const Type = extern union {
.@"struct" => {
@panic("TODO abiSize struct");
},
+ .enum_simple, .enum_full, .enum_nonexhaustive => {
+ var buffer: Payload.Bits = undefined;
+ const int_tag_ty = self.intTagType(&buffer);
+ return int_tag_ty.abiSize(target);
+ },
.u8,
.i8,
@@ -1276,76 +1341,25 @@ pub const Type = extern union {
};
}
+ /// Asserts the type is an enum.
+ pub fn intTagType(self: Type, buffer: *Payload.Bits) Type {
+ switch (self.tag()) {
+ .enum_full, .enum_nonexhaustive => return self.castTag(.enum_full).?.data.tag_ty,
+ .enum_simple => {
+ const enum_simple = self.castTag(.enum_simple).?.data;
+ const bits = std.math.log2_int_ceil(usize, enum_simple.fields.count());
+ buffer.* = .{
+ .base = .{ .tag = .int_unsigned },
+ .data = bits,
+ };
+ return Type.initPayload(&buffer.base);
+ },
+ else => unreachable,
+ }
+ }
+
pub fn isSinglePointer(self: Type) bool {
return switch (self.tag()) {
- .u8,
- .i8,
- .u16,
- .i16,
- .u32,
- .i32,
- .u64,
- .i64,
- .u128,
- .i128,
- .usize,
- .isize,
- .c_short,
- .c_ushort,
- .c_int,
- .c_uint,
- .c_long,
- .c_ulong,
- .c_longlong,
- .c_ulonglong,
- .c_longdouble,
- .f16,
- .f32,
- .f64,
- .f128,
- .c_void,
- .bool,
- .void,
- .type,
- .anyerror,
- .comptime_int,
- .comptime_float,
- .noreturn,
- .@"null",
- .@"undefined",
- .array,
- .array_sentinel,
- .array_u8,
- .array_u8_sentinel_0,
- .const_slice_u8,
- .fn_noreturn_no_args,
- .fn_void_no_args,
- .fn_naked_noreturn_no_args,
- .fn_ccc_void_no_args,
- .function,
- .int_unsigned,
- .int_signed,
- .optional,
- .optional_single_mut_pointer,
- .optional_single_const_pointer,
- .enum_literal,
- .many_const_pointer,
- .many_mut_pointer,
- .c_const_pointer,
- .c_mut_pointer,
- .const_slice,
- .mut_slice,
- .error_union,
- .anyerror_void_error_union,
- .error_set,
- .error_set_single,
- .@"struct",
- .empty_struct,
- .empty_struct_literal,
- .@"opaque",
- .var_args_param,
- => false,
-
.single_const_pointer,
.single_mut_pointer,
.single_const_pointer_to_comptime_int,
@@ -1354,73 +1368,14 @@ pub const Type = extern union {
=> true,
.pointer => self.castTag(.pointer).?.data.size == .One,
+
+ else => false,
};
}
/// Asserts the `Type` is a pointer.
pub fn ptrSize(self: Type) std.builtin.TypeInfo.Pointer.Size {
return switch (self.tag()) {
- .u8,
- .i8,
- .u16,
- .i16,
- .u32,
- .i32,
- .u64,
- .i64,
- .u128,
- .i128,
- .usize,
- .isize,
- .c_short,
- .c_ushort,
- .c_int,
- .c_uint,
- .c_long,
- .c_ulong,
- .c_longlong,
- .c_ulonglong,
- .c_longdouble,
- .f16,
- .f32,
- .f64,
- .f128,
- .c_void,
- .bool,
- .void,
- .type,
- .anyerror,
- .comptime_int,
- .comptime_float,
- .noreturn,
- .@"null",
- .@"undefined",
- .array,
- .array_sentinel,
- .array_u8,
- .array_u8_sentinel_0,
- .fn_noreturn_no_args,
- .fn_void_no_args,
- .fn_naked_noreturn_no_args,
- .fn_ccc_void_no_args,
- .function,
- .int_unsigned,
- .int_signed,
- .optional,
- .optional_single_mut_pointer,
- .optional_single_const_pointer,
- .enum_literal,
- .error_union,
- .anyerror_void_error_union,
- .error_set,
- .error_set_single,
- .empty_struct,
- .empty_struct_literal,
- .@"opaque",
- .@"struct",
- .var_args_param,
- => unreachable,
-
.const_slice,
.mut_slice,
.const_slice_u8,
@@ -1442,159 +1397,26 @@ pub const Type = extern union {
=> .One,
.pointer => self.castTag(.pointer).?.data.size,
+
+ else => unreachable,
};
}
pub fn isSlice(self: Type) bool {
return switch (self.tag()) {
- .u8,
- .i8,
- .u16,
- .i16,
- .u32,
- .i32,
- .u64,
- .i64,
- .u128,
- .i128,
- .usize,
- .isize,
- .c_short,
- .c_ushort,
- .c_int,
- .c_uint,
- .c_long,
- .c_ulong,
- .c_longlong,
- .c_ulonglong,
- .c_longdouble,
- .f16,
- .f32,
- .f64,
- .f128,
- .c_void,
- .bool,
- .void,
- .type,
- .anyerror,
- .comptime_int,
- .comptime_float,
- .noreturn,
- .@"null",
- .@"undefined",
- .array,
- .array_sentinel,
- .array_u8,
- .array_u8_sentinel_0,
- .single_const_pointer,
- .single_mut_pointer,
- .many_const_pointer,
- .many_mut_pointer,
- .c_const_pointer,
- .c_mut_pointer,
- .single_const_pointer_to_comptime_int,
- .fn_noreturn_no_args,
- .fn_void_no_args,
- .fn_naked_noreturn_no_args,
- .fn_ccc_void_no_args,
- .function,
- .int_unsigned,
- .int_signed,
- .optional,
- .optional_single_mut_pointer,
- .optional_single_const_pointer,
- .enum_literal,
- .error_union,
- .anyerror_void_error_union,
- .error_set,
- .error_set_single,
- .empty_struct,
- .empty_struct_literal,
- .inferred_alloc_const,
- .inferred_alloc_mut,
- .@"struct",
- .@"opaque",
- .var_args_param,
- => false,
-
.const_slice,
.mut_slice,
.const_slice_u8,
=> true,
.pointer => self.castTag(.pointer).?.data.size == .Slice,
+
+ else => false,
};
}
pub fn isConstPtr(self: Type) bool {
return switch (self.tag()) {
- .u8,
- .i8,
- .u16,
- .i16,
- .u32,
- .i32,
- .u64,
- .i64,
- .u128,
- .i128,
- .usize,
- .isize,
- .c_short,
- .c_ushort,
- .c_int,
- .c_uint,
- .c_long,
- .c_ulong,
- .c_longlong,
- .c_ulonglong,
- .c_longdouble,
- .f16,
- .f32,
- .f64,
- .f128,
- .c_void,
- .bool,
- .void,
- .type,
- .anyerror,
- .comptime_int,
- .comptime_float,
- .noreturn,
- .@"null",
- .@"undefined",
- .array,
- .array_sentinel,
- .array_u8,
- .array_u8_sentinel_0,
- .fn_noreturn_no_args,
- .fn_void_no_args,
- .fn_naked_noreturn_no_args,
- .fn_ccc_void_no_args,
- .function,
- .int_unsigned,
- .int_signed,
- .single_mut_pointer,
- .many_mut_pointer,
- .c_mut_pointer,
- .optional,
- .optional_single_mut_pointer,
- .optional_single_const_pointer,
- .enum_literal,
- .mut_slice,
- .error_union,
- .anyerror_void_error_union,
- .error_set,
- .error_set_single,
- .empty_struct,
- .empty_struct_literal,
- .inferred_alloc_const,
- .inferred_alloc_mut,
- .@"struct",
- .@"opaque",
- .var_args_param,
- => false,
-
.single_const_pointer,
.many_const_pointer,
.c_const_pointer,
@@ -1604,170 +1426,40 @@ pub const Type = extern union {
=> true,
.pointer => !self.castTag(.pointer).?.data.mutable,
+
+ else => false,
};
}
pub fn isVolatilePtr(self: Type) bool {
return switch (self.tag()) {
- .u8,
- .i8,
- .u16,
- .i16,
- .u32,
- .i32,
- .u64,
- .i64,
- .u128,
- .i128,
- .usize,
- .isize,
- .c_short,
- .c_ushort,
- .c_int,
- .c_uint,
- .c_long,
- .c_ulong,
- .c_longlong,
- .c_ulonglong,
- .c_longdouble,
- .f16,
- .f32,
- .f64,
- .f128,
- .c_void,
- .bool,
- .void,
- .type,
- .anyerror,
- .comptime_int,
- .comptime_float,
- .noreturn,
- .@"null",
- .@"undefined",
- .array,
- .array_sentinel,
- .array_u8,
- .array_u8_sentinel_0,
- .fn_noreturn_no_args,
- .fn_void_no_args,
- .fn_naked_noreturn_no_args,
- .fn_ccc_void_no_args,
- .function,
- .int_unsigned,
- .int_signed,
- .single_mut_pointer,
- .single_const_pointer,
- .many_const_pointer,
- .many_mut_pointer,
- .c_const_pointer,
- .c_mut_pointer,
- .const_slice,
- .mut_slice,
- .single_const_pointer_to_comptime_int,
- .const_slice_u8,
- .optional,
- .optional_single_mut_pointer,
- .optional_single_const_pointer,
- .enum_literal,
- .error_union,
- .anyerror_void_error_union,
- .error_set,
- .error_set_single,
- .empty_struct,
- .empty_struct_literal,
- .inferred_alloc_const,
- .inferred_alloc_mut,
- .@"struct",
- .@"opaque",
- .var_args_param,
- => false,
-
.pointer => {
const payload = self.castTag(.pointer).?.data;
return payload.@"volatile";
},
+ else => false,
};
}
pub fn isAllowzeroPtr(self: Type) bool {
return switch (self.tag()) {
- .u8,
- .i8,
- .u16,
- .i16,
- .u32,
- .i32,
- .u64,
- .i64,
- .u128,
- .i128,
- .usize,
- .isize,
- .c_short,
- .c_ushort,
- .c_int,
- .c_uint,
- .c_long,
- .c_ulong,
- .c_longlong,
- .c_ulonglong,
- .c_longdouble,
- .f16,
- .f32,
- .f64,
- .f128,
- .c_void,
- .bool,
- .void,
- .type,
- .anyerror,
- .comptime_int,
- .comptime_float,
- .noreturn,
- .@"null",
- .@"undefined",
- .array,
- .array_sentinel,
- .array_u8,
- .array_u8_sentinel_0,
- .fn_noreturn_no_args,
- .fn_void_no_args,
- .fn_naked_noreturn_no_args,
- .fn_ccc_void_no_args,
- .function,
- .int_unsigned,
- .int_signed,
- .single_mut_pointer,
- .single_const_pointer,
- .many_const_pointer,
- .many_mut_pointer,
- .c_const_pointer,
- .c_mut_pointer,
- .const_slice,
- .mut_slice,
- .single_const_pointer_to_comptime_int,
- .const_slice_u8,
- .optional,
- .optional_single_mut_pointer,
- .optional_single_const_pointer,
- .enum_literal,
- .error_union,
- .anyerror_void_error_union,
- .error_set,
- .error_set_single,
- .empty_struct,
- .empty_struct_literal,
- .inferred_alloc_const,
- .inferred_alloc_mut,
- .@"struct",
- .@"opaque",
- .var_args_param,
- => false,
-
.pointer => {
const payload = self.castTag(.pointer).?.data;
return payload.@"allowzero";
},
+ else => false,
+ };
+ }
+
+ pub fn isCPtr(self: Type) bool {
+ return switch (self.tag()) {
+ .c_const_pointer,
+ .c_mut_pointer,
+ => return true,
+
+ .pointer => self.castTag(.pointer).?.data.size == .C,
+
+ else => return false,
};
}
@@ -1833,64 +1525,6 @@ pub const Type = extern union {
/// Asserts the type is a pointer or array type.
pub fn elemType(self: Type) Type {
return switch (self.tag()) {
- .u8 => unreachable,
- .i8 => unreachable,
- .u16 => unreachable,
- .i16 => unreachable,
- .u32 => unreachable,
- .i32 => unreachable,
- .u64 => unreachable,
- .i64 => unreachable,
- .u128 => unreachable,
- .i128 => unreachable,
- .usize => unreachable,
- .isize => unreachable,
- .c_short => unreachable,
- .c_ushort => unreachable,
- .c_int => unreachable,
- .c_uint => unreachable,
- .c_long => unreachable,
- .c_ulong => unreachable,
- .c_longlong => unreachable,
- .c_ulonglong => unreachable,
- .c_longdouble => unreachable,
- .f16 => unreachable,
- .f32 => unreachable,
- .f64 => unreachable,
- .f128 => unreachable,
- .c_void => unreachable,
- .bool => unreachable,
- .void => unreachable,
- .type => unreachable,
- .anyerror => unreachable,
- .comptime_int => unreachable,
- .comptime_float => unreachable,
- .noreturn => unreachable,
- .@"null" => unreachable,
- .@"undefined" => unreachable,
- .fn_noreturn_no_args => unreachable,
- .fn_void_no_args => unreachable,
- .fn_naked_noreturn_no_args => unreachable,
- .fn_ccc_void_no_args => unreachable,
- .function => unreachable,
- .int_unsigned => unreachable,
- .int_signed => unreachable,
- .optional => unreachable,
- .optional_single_const_pointer => unreachable,
- .optional_single_mut_pointer => unreachable,
- .enum_literal => unreachable,
- .error_union => unreachable,
- .anyerror_void_error_union => unreachable,
- .error_set => unreachable,
- .error_set_single => unreachable,
- .@"struct" => unreachable,
- .empty_struct => unreachable,
- .empty_struct_literal => unreachable,
- .inferred_alloc_const => unreachable,
- .inferred_alloc_mut => unreachable,
- .@"opaque" => unreachable,
- .var_args_param => unreachable,
-
.array => self.castTag(.array).?.data.elem_type,
.array_sentinel => self.castTag(.array_sentinel).?.data.elem_type,
.single_const_pointer,
@@ -1902,9 +1536,12 @@ pub const Type = extern union {
.const_slice,
.mut_slice,
=> self.castPointer().?.data,
+
.array_u8, .array_u8_sentinel_0, .const_slice_u8 => Type.initTag(.u8),
.single_const_pointer_to_comptime_int => Type.initTag(.comptime_int),
.pointer => self.castTag(.pointer).?.data.pointee_type,
+
+ else => unreachable,
};
}
@@ -1972,148 +1609,18 @@ pub const Type = extern union {
/// Asserts the type is an array or vector.
pub fn arrayLen(self: Type) u64 {
return switch (self.tag()) {
- .u8,
- .i8,
- .u16,
- .i16,
- .u32,
- .i32,
- .u64,
- .i64,
- .u128,
- .i128,
- .usize,
- .isize,
- .c_short,
- .c_ushort,
- .c_int,
- .c_uint,
- .c_long,
- .c_ulong,
- .c_longlong,
- .c_ulonglong,
- .c_longdouble,
- .f16,
- .f32,
- .f64,
- .f128,
- .c_void,
- .bool,
- .void,
- .type,
- .anyerror,
- .comptime_int,
- .comptime_float,
- .noreturn,
- .@"null",
- .@"undefined",
- .fn_noreturn_no_args,
- .fn_void_no_args,
- .fn_naked_noreturn_no_args,
- .fn_ccc_void_no_args,
- .function,
- .pointer,
- .single_const_pointer,
- .single_mut_pointer,
- .many_const_pointer,
- .many_mut_pointer,
- .c_const_pointer,
- .c_mut_pointer,
- .const_slice,
- .mut_slice,
- .single_const_pointer_to_comptime_int,
- .const_slice_u8,
- .int_unsigned,
- .int_signed,
- .optional,
- .optional_single_mut_pointer,
- .optional_single_const_pointer,
- .enum_literal,
- .error_union,
- .anyerror_void_error_union,
- .error_set,
- .error_set_single,
- .@"struct",
- .empty_struct,
- .empty_struct_literal,
- .inferred_alloc_const,
- .inferred_alloc_mut,
- .@"opaque",
- .var_args_param,
- => unreachable,
-
.array => self.castTag(.array).?.data.len,
.array_sentinel => self.castTag(.array_sentinel).?.data.len,
.array_u8 => self.castTag(.array_u8).?.data,
.array_u8_sentinel_0 => self.castTag(.array_u8_sentinel_0).?.data,
+
+ else => unreachable,
};
}
/// Asserts the type is an array, pointer or vector.
pub fn sentinel(self: Type) ?Value {
return switch (self.tag()) {
- .u8,
- .i8,
- .u16,
- .i16,
- .u32,
- .i32,
- .u64,
- .i64,
- .u128,
- .i128,
- .usize,
- .isize,
- .c_short,
- .c_ushort,
- .c_int,
- .c_uint,
- .c_long,
- .c_ulong,
- .c_longlong,
- .c_ulonglong,
- .c_longdouble,
- .f16,
- .f32,
- .f64,
- .f128,
- .c_void,
- .bool,
- .void,
- .type,
- .anyerror,
- .comptime_int,
- .comptime_float,
- .noreturn,
- .@"null",
- .@"undefined",
- .fn_noreturn_no_args,
- .fn_void_no_args,
- .fn_naked_noreturn_no_args,
- .fn_ccc_void_no_args,
- .function,
- .const_slice,
- .mut_slice,
- .const_slice_u8,
- .int_unsigned,
- .int_signed,
- .optional,
- .optional_single_mut_pointer,
- .optional_single_const_pointer,
- .enum_literal,
- .error_union,
- .anyerror_void_error_union,
- .error_set,
- .error_set_single,
- .@"struct",
- .empty_struct,
- .empty_struct_literal,
- .inferred_alloc_const,
- .inferred_alloc_mut,
- .@"opaque",
- .var_args_param,
- => unreachable,
-
.single_const_pointer,
.single_mut_pointer,
.many_const_pointer,
@@ -2128,6 +1635,8 @@ pub const Type = extern union {
.pointer => return self.castTag(.pointer).?.data.sentinel,
.array_sentinel => return self.castTag(.array_sentinel).?.data.sentinel,
.array_u8_sentinel_0 => return Value.initTag(.zero),
+
+ else => unreachable,
};
}
@@ -2139,68 +1648,6 @@ pub const Type = extern union {
/// Returns true if and only if the type is a fixed-width, signed integer.
pub fn isSignedInt(self: Type) bool {
return switch (self.tag()) {
- .f16,
- .f32,
- .f64,
- .f128,
- .c_longdouble,
- .c_void,
- .bool,
- .void,
- .type,
- .anyerror,
- .comptime_int,
- .comptime_float,
- .noreturn,
- .@"null",
- .@"undefined",
- .fn_noreturn_no_args,
- .fn_void_no_args,
- .fn_naked_noreturn_no_args,
- .fn_ccc_void_no_args,
- .function,
- .array,
- .array_sentinel,
- .array_u8,
- .array_u8_sentinel_0,
- .pointer,
- .single_const_pointer,
- .single_mut_pointer,
- .many_const_pointer,
- .many_mut_pointer,
- .c_const_pointer,
- .c_mut_pointer,
- .const_slice,
- .mut_slice,
- .single_const_pointer_to_comptime_int,
- .const_slice_u8,
- .int_unsigned,
- .u8,
- .usize,
- .c_ushort,
- .c_uint,
- .c_ulong,
- .c_ulonglong,
- .u16,
- .u32,
- .u64,
- .optional,
- .optional_single_mut_pointer,
- .optional_single_const_pointer,
- .enum_literal,
- .error_union,
- .anyerror_void_error_union,
- .error_set,
- .error_set_single,
- .@"struct",
- .empty_struct,
- .empty_struct_literal,
- .inferred_alloc_const,
- .inferred_alloc_mut,
- .@"opaque",
- .var_args_param,
- => false,
-
.int_signed,
.i8,
.isize,
@@ -2211,79 +1658,16 @@ pub const Type = extern union {
.i16,
.i32,
.i64,
- .u128,
.i128,
=> true,
+
+ else => false,
};
}
/// Returns true if and only if the type is a fixed-width, unsigned integer.
pub fn isUnsignedInt(self: Type) bool {
return switch (self.tag()) {
- .f16,
- .f32,
- .f64,
- .f128,
- .c_longdouble,
- .c_void,
- .bool,
- .void,
- .type,
- .anyerror,
- .comptime_int,
- .comptime_float,
- .noreturn,
- .@"null",
- .@"undefined",
- .fn_noreturn_no_args,
- .fn_void_no_args,
- .fn_naked_noreturn_no_args,
- .fn_ccc_void_no_args,
- .function,
- .array,
- .array_sentinel,
- .array_u8,
- .array_u8_sentinel_0,
- .pointer,
- .single_const_pointer,
- .single_mut_pointer,
- .many_const_pointer,
- .many_mut_pointer,
- .c_const_pointer,
- .c_mut_pointer,
- .const_slice,
- .mut_slice,
- .single_const_pointer_to_comptime_int,
- .const_slice_u8,
- .int_signed,
- .i8,
- .isize,
- .c_short,
- .c_int,
- .c_long,
- .c_longlong,
- .i16,
- .i32,
- .i64,
- .u128,
- .i128,
- .optional,
- .optional_single_mut_pointer,
- .optional_single_const_pointer,
- .enum_literal,
- .error_union,
- .anyerror_void_error_union,
- .error_set,
- .error_set_single,
- .@"struct",
- .empty_struct,
- .empty_struct_literal,
- .inferred_alloc_const,
- .inferred_alloc_mut,
- .@"opaque",
- .var_args_param,
- => false,
-
.int_unsigned,
.u8,
.usize,
@@ -2294,65 +1678,16 @@ pub const Type = extern union {
.u16,
.u32,
.u64,
+ .u128,
=> true,
+
+ else => false,
};
}
/// Asserts the type is an integer.
pub fn intInfo(self: Type, target: Target) struct { signedness: std.builtin.Signedness, bits: u16 } {
return switch (self.tag()) {
- .f16,
- .f32,
- .f64,
- .f128,
- .c_longdouble,
- .c_void,
- .bool,
- .void,
- .type,
- .anyerror,
- .comptime_int,
- .comptime_float,
- .noreturn,
- .@"null",
- .@"undefined",
- .fn_noreturn_no_args,
- .fn_void_no_args,
- .fn_naked_noreturn_no_args,
- .fn_ccc_void_no_args,
- .function,
- .array,
- .array_sentinel,
- .array_u8,
- .array_u8_sentinel_0,
- .pointer,
- .single_const_pointer,
- .single_mut_pointer,
- .many_const_pointer,
- .many_mut_pointer,
- .c_const_pointer,
- .c_mut_pointer,
- .const_slice,
- .mut_slice,
- .single_const_pointer_to_comptime_int,
- .const_slice_u8,
- .optional,
- .optional_single_mut_pointer,
- .optional_single_const_pointer,
- .enum_literal,
- .error_union,
- .anyerror_void_error_union,
- .error_set,
- .error_set_single,
- .@"struct",
- .empty_struct,
- .empty_struct_literal,
- .inferred_alloc_const,
- .inferred_alloc_mut,
- .@"opaque",
- .var_args_param,
- => unreachable,
-
.int_unsigned => .{
.signedness = .unsigned,
.bits = self.castTag(.int_unsigned).?.data,
@@ -2381,75 +1716,13 @@ pub const Type = extern union {
.c_ulong => .{ .signedness = .unsigned, .bits = CType.ulong.sizeInBits(target) },
.c_longlong => .{ .signedness = .signed, .bits = CType.longlong.sizeInBits(target) },
.c_ulonglong => .{ .signedness = .unsigned, .bits = CType.ulonglong.sizeInBits(target) },
+
+ else => unreachable,
};
}
pub fn isNamedInt(self: Type) bool {
return switch (self.tag()) {
- .f16,
- .f32,
- .f64,
- .f128,
- .c_longdouble,
- .c_void,
- .bool,
- .void,
- .type,
- .anyerror,
- .comptime_int,
- .comptime_float,
- .noreturn,
- .@"null",
- .@"undefined",
- .fn_noreturn_no_args,
- .fn_void_no_args,
- .fn_naked_noreturn_no_args,
- .fn_ccc_void_no_args,
- .function,
- .array,
- .array_sentinel,
- .array_u8,
- .array_u8_sentinel_0,
- .pointer,
- .single_const_pointer,
- .single_mut_pointer,
- .many_const_pointer,
- .many_mut_pointer,
- .c_const_pointer,
- .c_mut_pointer,
- .const_slice,
- .mut_slice,
- .single_const_pointer_to_comptime_int,
- .const_slice_u8,
- .int_unsigned,
- .int_signed,
- .u8,
- .i8,
- .u16,
- .i16,
- .u32,
- .i32,
- .u64,
- .i64,
- .u128,
- .i128,
- .optional,
- .optional_single_mut_pointer,
- .optional_single_const_pointer,
- .enum_literal,
- .error_union,
- .anyerror_void_error_union,
- .error_set,
- .error_set_single,
- .@"struct",
- .empty_struct,
- .empty_struct_literal,
- .inferred_alloc_const,
- .inferred_alloc_mut,
- .@"opaque",
- .var_args_param,
- => false,
-
.usize,
.isize,
.c_short,
@@ -2461,6 +1734,8 @@ pub const Type = extern union {
.c_longlong,
.c_ulonglong,
=> true,
+
+ else => false,
};
}
@@ -2499,74 +1774,7 @@ pub const Type = extern union {
.fn_ccc_void_no_args => 0,
.function => self.castTag(.function).?.data.param_types.len,
- .f16,
- .f32,
- .f64,
- .f128,
- .c_longdouble,
- .c_void,
- .bool,
- .void,
- .type,
- .anyerror,
- .comptime_int,
- .comptime_float,
- .noreturn,
- .@"null",
- .@"undefined",
- .array,
- .array_sentinel,
- .array_u8,
- .array_u8_sentinel_0,
- .pointer,
- .single_const_pointer,
- .single_mut_pointer,
- .many_const_pointer,
- .many_mut_pointer,
- .c_const_pointer,
- .c_mut_pointer,
- .const_slice,
- .mut_slice,
- .single_const_pointer_to_comptime_int,
- .const_slice_u8,
- .u8,
- .i8,
- .u16,
- .i16,
- .u32,
- .i32,
- .u64,
- .i64,
- .u128,
- .i128,
- .usize,
- .isize,
- .c_short,
- .c_ushort,
- .c_int,
- .c_uint,
- .c_long,
- .c_ulong,
- .c_longlong,
- .c_ulonglong,
- .int_unsigned,
- .int_signed,
- .optional,
- .optional_single_mut_pointer,
- .optional_single_const_pointer,
- .enum_literal,
- .error_union,
- .anyerror_void_error_union,
- .error_set,
- .error_set_single,
- .@"struct",
- .empty_struct,
- .empty_struct_literal,
- .inferred_alloc_const,
- .inferred_alloc_mut,
- .@"opaque",
- .var_args_param,
- => unreachable,
+ else => unreachable,
};
}
@@ -2583,74 +1791,7 @@ pub const Type = extern union {
std.mem.copy(Type, types, payload.param_types);
},
- .f16,
- .f32,
- .f64,
- .f128,
- .c_longdouble,
- .c_void,
- .bool,
- .void,
- .type,
- .anyerror,
- .comptime_int,
- .comptime_float,
- .noreturn,
- .@"null",
- .@"undefined",
- .array,
- .array_sentinel,
- .array_u8,
- .array_u8_sentinel_0,
- .pointer,
- .single_const_pointer,
- .single_mut_pointer,
- .many_const_pointer,
- .many_mut_pointer,
- .c_const_pointer,
- .c_mut_pointer,
- .const_slice,
- .mut_slice,
- .single_const_pointer_to_comptime_int,
- .const_slice_u8,
- .u8,
- .i8,
- .u16,
- .i16,
- .u32,
- .i32,
- .u64,
- .i64,
- .u128,
- .i128,
- .usize,
- .isize,
- .c_short,
- .c_ushort,
- .c_int,
- .c_uint,
- .c_long,
- .c_ulong,
- .c_longlong,
- .c_ulonglong,
- .int_unsigned,
- .int_signed,
- .optional,
- .optional_single_mut_pointer,
- .optional_single_const_pointer,
- .enum_literal,
- .error_union,
- .anyerror_void_error_union,
- .error_set,
- .error_set_single,
- .@"struct",
- .empty_struct,
- .empty_struct_literal,
- .inferred_alloc_const,
- .inferred_alloc_mut,
- .@"opaque",
- .var_args_param,
- => unreachable,
+ else => unreachable,
}
}
@@ -2662,321 +1803,49 @@ pub const Type = extern union {
return payload.param_types[index];
},
- .fn_noreturn_no_args,
- .fn_void_no_args,
- .fn_naked_noreturn_no_args,
- .fn_ccc_void_no_args,
- .f16,
- .f32,
- .f64,
- .f128,
- .c_longdouble,
- .c_void,
- .bool,
- .void,
- .type,
- .anyerror,
- .comptime_int,
- .comptime_float,
- .noreturn,
- .@"null",
- .@"undefined",
- .array,
- .array_sentinel,
- .array_u8,
- .array_u8_sentinel_0,
- .pointer,
- .single_const_pointer,
- .single_mut_pointer,
- .many_const_pointer,
- .many_mut_pointer,
- .c_const_pointer,
- .c_mut_pointer,
- .const_slice,
- .mut_slice,
- .single_const_pointer_to_comptime_int,
- .const_slice_u8,
- .u8,
- .i8,
- .u16,
- .i16,
- .u32,
- .i32,
- .u64,
- .i64,
- .u128,
- .i128,
- .usize,
- .isize,
- .c_short,
- .c_ushort,
- .c_int,
- .c_uint,
- .c_long,
- .c_ulong,
- .c_longlong,
- .c_ulonglong,
- .int_unsigned,
- .int_signed,
- .optional,
- .optional_single_mut_pointer,
- .optional_single_const_pointer,
- .enum_literal,
- .error_union,
- .anyerror_void_error_union,
- .error_set,
- .error_set_single,
- .@"struct",
- .empty_struct,
- .empty_struct_literal,
- .inferred_alloc_const,
- .inferred_alloc_mut,
- .@"opaque",
- .var_args_param,
- => unreachable,
- }
- }
-
- /// Asserts the type is a function.
- pub fn fnReturnType(self: Type) Type {
- return switch (self.tag()) {
- .fn_noreturn_no_args => Type.initTag(.noreturn),
- .fn_naked_noreturn_no_args => Type.initTag(.noreturn),
-
+ else => unreachable,
+ }
+ }
+
+ /// Asserts the type is a function.
+ pub fn fnReturnType(self: Type) Type {
+ return switch (self.tag()) {
+ .fn_noreturn_no_args => Type.initTag(.noreturn),
+ .fn_naked_noreturn_no_args => Type.initTag(.noreturn),
+
.fn_void_no_args,
.fn_ccc_void_no_args,
=> Type.initTag(.void),
.function => self.castTag(.function).?.data.return_type,
-
- .f16,
- .f32,
- .f64,
- .f128,
- .c_longdouble,
- .c_void,
- .bool,
- .void,
- .type,
- .anyerror,
- .comptime_int,
- .comptime_float,
- .noreturn,
- .@"null",
- .@"undefined",
- .array,
- .array_sentinel,
- .array_u8,
- .array_u8_sentinel_0,
- .pointer,
- .single_const_pointer,
- .single_mut_pointer,
- .many_const_pointer,
- .many_mut_pointer,
- .c_const_pointer,
- .c_mut_pointer,
- .const_slice,
- .mut_slice,
- .single_const_pointer_to_comptime_int,
- .const_slice_u8,
- .u8,
- .i8,
- .u16,
- .i16,
- .u32,
- .i32,
- .u64,
- .i64,
- .u128,
- .i128,
- .usize,
- .isize,
- .c_short,
- .c_ushort,
- .c_int,
- .c_uint,
- .c_long,
- .c_ulong,
- .c_longlong,
- .c_ulonglong,
- .int_unsigned,
- .int_signed,
- .optional,
- .optional_single_mut_pointer,
- .optional_single_const_pointer,
- .enum_literal,
- .error_union,
- .anyerror_void_error_union,
- .error_set,
- .error_set_single,
- .@"struct",
- .empty_struct,
- .empty_struct_literal,
- .inferred_alloc_const,
- .inferred_alloc_mut,
- .@"opaque",
- .var_args_param,
- => unreachable,
- };
- }
-
- /// Asserts the type is a function.
- pub fn fnCallingConvention(self: Type) std.builtin.CallingConvention {
- return switch (self.tag()) {
- .fn_noreturn_no_args => .Unspecified,
- .fn_void_no_args => .Unspecified,
- .fn_naked_noreturn_no_args => .Naked,
- .fn_ccc_void_no_args => .C,
- .function => self.castTag(.function).?.data.cc,
-
- .f16,
- .f32,
- .f64,
- .f128,
- .c_longdouble,
- .c_void,
- .bool,
- .void,
- .type,
- .anyerror,
- .comptime_int,
- .comptime_float,
- .noreturn,
- .@"null",
- .@"undefined",
- .array,
- .array_sentinel,
- .array_u8,
- .array_u8_sentinel_0,
- .pointer,
- .single_const_pointer,
- .single_mut_pointer,
- .many_const_pointer,
- .many_mut_pointer,
- .c_const_pointer,
- .c_mut_pointer,
- .const_slice,
- .mut_slice,
- .single_const_pointer_to_comptime_int,
- .const_slice_u8,
- .u8,
- .i8,
- .u16,
- .i16,
- .u32,
- .i32,
- .u64,
- .i64,
- .u128,
- .i128,
- .usize,
- .isize,
- .c_short,
- .c_ushort,
- .c_int,
- .c_uint,
- .c_long,
- .c_ulong,
- .c_longlong,
- .c_ulonglong,
- .int_unsigned,
- .int_signed,
- .optional,
- .optional_single_mut_pointer,
- .optional_single_const_pointer,
- .enum_literal,
- .error_union,
- .anyerror_void_error_union,
- .error_set,
- .error_set_single,
- .@"struct",
- .empty_struct,
- .empty_struct_literal,
- .inferred_alloc_const,
- .inferred_alloc_mut,
- .@"opaque",
- .var_args_param,
- => unreachable,
- };
- }
-
- /// Asserts the type is a function.
- pub fn fnIsVarArgs(self: Type) bool {
- return switch (self.tag()) {
- .fn_noreturn_no_args => false,
- .fn_void_no_args => false,
- .fn_naked_noreturn_no_args => false,
- .fn_ccc_void_no_args => false,
- .function => self.castTag(.function).?.data.is_var_args,
-
- .f16,
- .f32,
- .f64,
- .f128,
- .c_longdouble,
- .c_void,
- .bool,
- .void,
- .type,
- .anyerror,
- .comptime_int,
- .comptime_float,
- .noreturn,
- .@"null",
- .@"undefined",
- .array,
- .array_sentinel,
- .array_u8,
- .array_u8_sentinel_0,
- .pointer,
- .single_const_pointer,
- .single_mut_pointer,
- .many_const_pointer,
- .many_mut_pointer,
- .c_const_pointer,
- .c_mut_pointer,
- .const_slice,
- .mut_slice,
- .single_const_pointer_to_comptime_int,
- .const_slice_u8,
- .u8,
- .i8,
- .u16,
- .i16,
- .u32,
- .i32,
- .u64,
- .i64,
- .u128,
- .i128,
- .usize,
- .isize,
- .c_short,
- .c_ushort,
- .c_int,
- .c_uint,
- .c_long,
- .c_ulong,
- .c_longlong,
- .c_ulonglong,
- .int_unsigned,
- .int_signed,
- .optional,
- .optional_single_mut_pointer,
- .optional_single_const_pointer,
- .enum_literal,
- .error_union,
- .anyerror_void_error_union,
- .error_set,
- .error_set_single,
- .@"struct",
- .empty_struct,
- .empty_struct_literal,
- .inferred_alloc_const,
- .inferred_alloc_mut,
- .@"opaque",
- .var_args_param,
- => unreachable,
+
+ else => unreachable,
+ };
+ }
+
+ /// Asserts the type is a function.
+ pub fn fnCallingConvention(self: Type) std.builtin.CallingConvention {
+ return switch (self.tag()) {
+ .fn_noreturn_no_args => .Unspecified,
+ .fn_void_no_args => .Unspecified,
+ .fn_naked_noreturn_no_args => .Naked,
+ .fn_ccc_void_no_args => .C,
+ .function => self.castTag(.function).?.data.cc,
+
+ else => unreachable,
+ };
+ }
+
+ /// Asserts the type is a function.
+ pub fn fnIsVarArgs(self: Type) bool {
+ return switch (self.tag()) {
+ .fn_noreturn_no_args => false,
+ .fn_void_no_args => false,
+ .fn_naked_noreturn_no_args => false,
+ .fn_ccc_void_no_args => false,
+ .function => self.castTag(.function).?.data.is_var_args,
+
+ else => unreachable,
};
}
@@ -3013,50 +1882,7 @@ pub const Type = extern union {
.int_signed,
=> true,
- .c_void,
- .bool,
- .void,
- .type,
- .anyerror,
- .noreturn,
- .@"null",
- .@"undefined",
- .fn_noreturn_no_args,
- .fn_void_no_args,
- .fn_naked_noreturn_no_args,
- .fn_ccc_void_no_args,
- .function,
- .array,
- .array_sentinel,
- .array_u8,
- .array_u8_sentinel_0,
- .pointer,
- .single_const_pointer,
- .single_mut_pointer,
- .many_const_pointer,
- .many_mut_pointer,
- .c_const_pointer,
- .c_mut_pointer,
- .const_slice,
- .mut_slice,
- .single_const_pointer_to_comptime_int,
- .const_slice_u8,
- .optional,
- .optional_single_mut_pointer,
- .optional_single_const_pointer,
- .enum_literal,
- .error_union,
- .anyerror_void_error_union,
- .error_set,
- .error_set_single,
- .@"struct",
- .empty_struct,
- .empty_struct_literal,
- .inferred_alloc_const,
- .inferred_alloc_mut,
- .@"opaque",
- .var_args_param,
- => false,
+ else => false,
};
}
@@ -3127,6 +1953,23 @@ pub const Type = extern union {
}
return Value.initTag(.empty_struct_value);
},
+ .enum_full => {
+ const enum_full = self.castTag(.enum_full).?.data;
+ if (enum_full.fields.count() == 1) {
+ return enum_full.values.entries.items[0].key;
+ } else {
+ return null;
+ }
+ },
+ .enum_simple => {
+ const enum_simple = self.castTag(.enum_simple).?.data;
+ if (enum_simple.fields.count() == 1) {
+ return Value.initTag(.zero);
+ } else {
+ return null;
+ }
+ },
+ .enum_nonexhaustive => return self.castTag(.enum_full).?.data.tag_ty.onePossibleValue(),
.empty_struct, .empty_struct_literal => return Value.initTag(.empty_struct_value),
.void => return Value.initTag(.void_value),
@@ -3166,87 +2009,6 @@ pub const Type = extern union {
};
}
- pub fn isCPtr(self: Type) bool {
- return switch (self.tag()) {
- .f16,
- .f32,
- .f64,
- .f128,
- .c_longdouble,
- .comptime_int,
- .comptime_float,
- .u8,
- .i8,
- .u16,
- .i16,
- .u32,
- .i32,
- .u64,
- .i64,
- .u128,
- .i128,
- .usize,
- .isize,
- .c_short,
- .c_ushort,
- .c_int,
- .c_uint,
- .c_long,
- .c_ulong,
- .c_longlong,
- .c_ulonglong,
- .bool,
- .type,
- .anyerror,
- .fn_noreturn_no_args,
- .fn_void_no_args,
- .fn_naked_noreturn_no_args,
- .fn_ccc_void_no_args,
- .function,
- .single_const_pointer_to_comptime_int,
- .const_slice_u8,
- .c_void,
- .void,
- .noreturn,
- .@"null",
- .@"undefined",
- .int_unsigned,
- .int_signed,
- .array,
- .array_sentinel,
- .array_u8,
- .array_u8_sentinel_0,
- .single_const_pointer,
- .single_mut_pointer,
- .many_const_pointer,
- .many_mut_pointer,
- .const_slice,
- .mut_slice,
- .optional,
- .optional_single_mut_pointer,
- .optional_single_const_pointer,
- .enum_literal,
- .error_union,
- .anyerror_void_error_union,
- .error_set,
- .error_set_single,
- .@"struct",
- .empty_struct,
- .empty_struct_literal,
- .inferred_alloc_const,
- .inferred_alloc_mut,
- .@"opaque",
- .var_args_param,
- => return false,
-
- .c_const_pointer,
- .c_mut_pointer,
- => return true,
-
- .pointer => self.castTag(.pointer).?.data.size == .C,
- };
- }
-
pub fn isIndexable(self: Type) bool {
const zig_tag = self.zigTypeTag();
// TODO tuples are indexable
@@ -3257,80 +2019,12 @@ pub const Type = extern union {
/// Asserts that the type is a container. (note: ErrorSet is not a container).
pub fn getContainerScope(self: Type) *Module.Scope.Container {
return switch (self.tag()) {
- .f16,
- .f32,
- .f64,
- .f128,
- .c_longdouble,
- .comptime_int,
- .comptime_float,
- .u8,
- .i8,
- .u16,
- .i16,
- .u32,
- .i32,
- .u64,
- .i64,
- .u128,
- .i128,
- .usize,
- .isize,
- .c_short,
- .c_ushort,
- .c_int,
- .c_uint,
- .c_long,
- .c_ulong,
- .c_longlong,
- .c_ulonglong,
- .bool,
- .type,
- .anyerror,
- .fn_noreturn_no_args,
- .fn_void_no_args,
- .fn_naked_noreturn_no_args,
- .fn_ccc_void_no_args,
- .function,
- .single_const_pointer_to_comptime_int,
- .const_slice_u8,
- .c_void,
- .void,
- .noreturn,
- .@"null",
- .@"undefined",
- .int_unsigned,
- .int_signed,
- .array,
- .array_sentinel,
- .array_u8,
- .array_u8_sentinel_0,
- .single_const_pointer,
- .single_mut_pointer,
- .many_const_pointer,
- .many_mut_pointer,
- .const_slice,
- .mut_slice,
- .optional,
- .optional_single_mut_pointer,
- .optional_single_const_pointer,
- .enum_literal,
- .error_union,
- .anyerror_void_error_union,
- .error_set,
- .error_set_single,
- .c_const_pointer,
- .c_mut_pointer,
- .pointer,
- .inferred_alloc_const,
- .inferred_alloc_mut,
- .var_args_param,
- .empty_struct_literal,
- => unreachable,
-
.@"struct" => &self.castTag(.@"struct").?.data.container,
+ .enum_full => &self.castTag(.enum_full).?.data.container,
.empty_struct => self.castTag(.empty_struct).?.data,
.@"opaque" => &self.castTag(.@"opaque").?.data,
+
+ else => unreachable,
};
}
@@ -3390,7 +2084,43 @@ pub const Type = extern union {
}
pub fn isExhaustiveEnum(ty: Type) bool {
- return false; // TODO
+ return switch (ty.tag()) {
+ .enum_full, .enum_simple => true,
+ else => false,
+ };
+ }
+
+ /// Asserts the type is an enum.
+ pub fn enumHasInt(ty: Type, int: Value, target: Target) bool {
+ const S = struct {
+ fn intInRange(int_val: Value, end: usize) bool {
+ if (int_val.compareWithZero(.lt)) return false;
+ var end_payload: Value.Payload.U64 = .{
+ .base = .{ .tag = .int_u64 },
+ .data = end,
+ };
+ const end_val = Value.initPayload(&end_payload.base);
+ if (int_val.compare(.gte, end_val)) return false;
+ return true;
+ }
+ };
+ switch (ty.tag()) {
+ .enum_nonexhaustive => return int.intFitsInType(ty, target),
+ .enum_full => {
+ const enum_full = ty.castTag(.enum_full).?.data;
+ if (enum_full.values.count() == 0) {
+ return S.intInRange(int, enum_full.fields.count());
+ } else {
+ return enum_full.values.contains(int);
+ }
+ },
+ .enum_simple => {
+ const enum_simple = ty.castTag(.enum_simple).?.data;
+ return S.intInRange(int, enum_simple.fields.count());
+ },
+
+ else => unreachable,
+ }
}
/// This enum does not directly correspond to `std.builtin.TypeId` because
@@ -3482,6 +2212,9 @@ pub const Type = extern union {
empty_struct,
@"opaque",
@"struct",
+ enum_simple,
+ enum_full,
+ enum_nonexhaustive,
pub const last_no_payload_tag = Tag.inferred_alloc_const;
pub const no_payload_count = @enumToInt(last_no_payload_tag) + 1;
@@ -3568,6 +2301,8 @@ pub const Type = extern union {
.error_set_single => Payload.Name,
.@"opaque" => Payload.Opaque,
.@"struct" => Payload.Struct,
+ .enum_full, .enum_nonexhaustive => Payload.EnumFull,
+ .enum_simple => Payload.EnumSimple,
.empty_struct => Payload.ContainerScope,
};
}
@@ -3705,6 +2440,16 @@ pub const Type = extern union {
base: Payload = .{ .tag = .@"struct" },
data: *Module.Struct,
};
+
+ pub const EnumFull = struct {
+ base: Payload,
+ data: *Module.EnumFull,
+ };
+
+ pub const EnumSimple = struct {
+ base: Payload = .{ .tag = .enum_simple },
+ data: *Module.EnumSimple,
+ };
};
};
src/value.zig
@@ -103,6 +103,8 @@ pub const Value = extern union {
float_64,
float_128,
enum_literal,
+ /// A specific enum tag, indicated by the field index (declaration order).
+ enum_field_index,
@"error",
error_union,
/// This is a special value that tracks a set of types that have been stored
@@ -186,6 +188,8 @@ pub const Value = extern union {
.enum_literal,
=> Payload.Bytes,
+ .enum_field_index => Payload.U32,
+
.ty => Payload.Ty,
.int_type => Payload.IntType,
.int_u64 => Payload.U64,
@@ -394,6 +398,7 @@ pub const Value = extern union {
};
return Value{ .ptr_otherwise = &new_payload.base };
},
+ .enum_field_index => return self.copyPayloadShallow(allocator, Payload.U32),
.@"error" => return self.copyPayloadShallow(allocator, Payload.Error),
.error_union => {
const payload = self.castTag(.error_union).?;
@@ -416,6 +421,8 @@ pub const Value = extern union {
return Value{ .ptr_otherwise = &new_payload.base };
}
+ /// TODO this should become a debug dump() function. In order to print values in a meaningful way
+ /// we also need access to the type.
pub fn format(
self: Value,
comptime fmt: []const u8,
@@ -506,6 +513,7 @@ pub const Value = extern union {
},
.empty_array => return out_stream.writeAll(".{}"),
.enum_literal => return out_stream.print(".{}", .{std.zig.fmtId(self.castTag(.enum_literal).?.data)}),
+ .enum_field_index => return out_stream.print("(enum field {d})", .{self.castTag(.enum_field_index).?.data}),
.bytes => return out_stream.print("\"{}\"", .{std.zig.fmtEscapes(self.castTag(.bytes).?.data)}),
.repeated => {
try out_stream.writeAll("(repeated) ");
@@ -626,6 +634,7 @@ pub const Value = extern union {
.float_64,
.float_128,
.enum_literal,
+ .enum_field_index,
.@"error",
.error_union,
.empty_struct_value,
@@ -638,76 +647,6 @@ pub const Value = extern union {
/// Asserts the value is an integer.
pub fn toBigInt(self: Value, space: *BigIntSpace) BigIntConst {
switch (self.tag()) {
- .ty,
- .int_type,
- .u8_type,
- .i8_type,
- .u16_type,
- .i16_type,
- .u32_type,
- .i32_type,
- .u64_type,
- .i64_type,
- .u128_type,
- .i128_type,
- .usize_type,
- .isize_type,
- .c_short_type,
- .c_ushort_type,
- .c_int_type,
- .c_uint_type,
- .c_long_type,
- .c_ulong_type,
- .c_longlong_type,
- .c_ulonglong_type,
- .c_longdouble_type,
- .f16_type,
- .f32_type,
- .f64_type,
- .f128_type,
- .c_void_type,
- .bool_type,
- .void_type,
- .type_type,
- .anyerror_type,
- .comptime_int_type,
- .comptime_float_type,
- .noreturn_type,
- .null_type,
- .undefined_type,
- .fn_noreturn_no_args_type,
- .fn_void_no_args_type,
- .fn_naked_noreturn_no_args_type,
- .fn_ccc_void_no_args_type,
- .single_const_pointer_to_comptime_int_type,
- .const_slice_u8_type,
- .enum_literal_type,
- .null_value,
- .function,
- .extern_fn,
- .variable,
- .ref_val,
- .decl_ref,
- .elem_ptr,
- .bytes,
- .repeated,
- .float_16,
- .float_32,
- .float_64,
- .float_128,
- .void_value,
- .unreachable_value,
- .empty_array,
- .enum_literal,
- .error_union,
- .@"error",
- .empty_struct_value,
- .inferred_alloc,
- .abi_align_default,
- => unreachable,
-
- .undef => unreachable,
-
.zero,
.bool_false,
=> return BigIntMutable.init(&space.limbs, 0).toConst(),
@@ -720,82 +659,15 @@ pub const Value = extern union {
.int_i64 => return BigIntMutable.init(&space.limbs, self.castTag(.int_i64).?.data).toConst(),
.int_big_positive => return self.castTag(.int_big_positive).?.asBigInt(),
.int_big_negative => return self.castTag(.int_big_negative).?.asBigInt(),
+
+ .undef => unreachable,
+ else => unreachable,
}
}
/// Asserts the value is an integer and it fits in a u64
pub fn toUnsignedInt(self: Value) u64 {
switch (self.tag()) {
- .ty,
- .int_type,
- .u8_type,
- .i8_type,
- .u16_type,
- .i16_type,
- .u32_type,
- .i32_type,
- .u64_type,
- .i64_type,
- .u128_type,
- .i128_type,
- .usize_type,
- .isize_type,
- .c_short_type,
- .c_ushort_type,
- .c_int_type,
- .c_uint_type,
- .c_long_type,
- .c_ulong_type,
- .c_longlong_type,
- .c_ulonglong_type,
- .c_longdouble_type,
- .f16_type,
- .f32_type,
- .f64_type,
- .f128_type,
- .c_void_type,
- .bool_type,
- .void_type,
- .type_type,
- .anyerror_type,
- .comptime_int_type,
- .comptime_float_type,
- .noreturn_type,
- .null_type,
- .undefined_type,
- .fn_noreturn_no_args_type,
- .fn_void_no_args_type,
- .fn_naked_noreturn_no_args_type,
- .fn_ccc_void_no_args_type,
- .single_const_pointer_to_comptime_int_type,
- .const_slice_u8_type,
- .enum_literal_type,
- .null_value,
- .function,
- .extern_fn,
- .variable,
- .ref_val,
- .decl_ref,
- .elem_ptr,
- .bytes,
- .repeated,
- .float_16,
- .float_32,
- .float_64,
- .float_128,
- .void_value,
- .unreachable_value,
- .empty_array,
- .enum_literal,
- .@"error",
- .error_union,
- .empty_struct_value,
- .inferred_alloc,
- .abi_align_default,
- => unreachable,
-
- .undef => unreachable,
-
.zero,
.bool_false,
=> return 0,
@@ -808,82 +680,15 @@ pub const Value = extern union {
.int_i64 => return @intCast(u64, self.castTag(.int_i64).?.data),
.int_big_positive => return self.castTag(.int_big_positive).?.asBigInt().to(u64) catch unreachable,
.int_big_negative => return self.castTag(.int_big_negative).?.asBigInt().to(u64) catch unreachable,
+
+ .undef => unreachable,
+ else => unreachable,
}
}
/// Asserts the value is an integer and it fits in a i64
pub fn toSignedInt(self: Value) i64 {
switch (self.tag()) {
- .ty,
- .int_type,
- .u8_type,
- .i8_type,
- .u16_type,
- .i16_type,
- .u32_type,
- .i32_type,
- .u64_type,
- .i64_type,
- .u128_type,
- .i128_type,
- .usize_type,
- .isize_type,
- .c_short_type,
- .c_ushort_type,
- .c_int_type,
- .c_uint_type,
- .c_long_type,
- .c_ulong_type,
- .c_longlong_type,
- .c_ulonglong_type,
- .c_longdouble_type,
- .f16_type,
- .f32_type,
- .f64_type,
- .f128_type,
- .c_void_type,
- .bool_type,
- .void_type,
- .type_type,
- .anyerror_type,
- .comptime_int_type,
- .comptime_float_type,
- .noreturn_type,
- .null_type,
- .undefined_type,
- .fn_noreturn_no_args_type,
- .fn_void_no_args_type,
- .fn_naked_noreturn_no_args_type,
- .fn_ccc_void_no_args_type,
- .single_const_pointer_to_comptime_int_type,
- .const_slice_u8_type,
- .enum_literal_type,
- .null_value,
- .function,
- .extern_fn,
- .variable,
- .ref_val,
- .decl_ref,
- .elem_ptr,
- .bytes,
- .repeated,
- .float_16,
- .float_32,
- .float_64,
- .float_128,
- .void_value,
- .unreachable_value,
- .empty_array,
- .enum_literal,
- .@"error",
- .error_union,
- .empty_struct_value,
- .inferred_alloc,
- .abi_align_default,
- => unreachable,
-
- .undef => unreachable,
-
.zero,
.bool_false,
=> return 0,
@@ -896,6 +701,9 @@ pub const Value = extern union {
.int_i64 => return self.castTag(.int_i64).?.data,
.int_big_positive => return self.castTag(.int_big_positive).?.asBigInt().to(i64) catch unreachable,
.int_big_negative => return self.castTag(.int_big_negative).?.asBigInt().to(i64) catch unreachable,
+
+ .undef => unreachable,
+ else => unreachable,
}
}
@@ -929,75 +737,6 @@ pub const Value = extern union {
/// Returns the number of bits the value requires to represent stored in twos complement form.
pub fn intBitCountTwosComp(self: Value) usize {
switch (self.tag()) {
- .ty,
- .int_type,
- .u8_type,
- .i8_type,
- .u16_type,
- .i16_type,
- .u32_type,
- .i32_type,
- .u64_type,
- .i64_type,
- .u128_type,
- .i128_type,
- .usize_type,
- .isize_type,
- .c_short_type,
- .c_ushort_type,
- .c_int_type,
- .c_uint_type,
- .c_long_type,
- .c_ulong_type,
- .c_longlong_type,
- .c_ulonglong_type,
- .c_longdouble_type,
- .f16_type,
- .f32_type,
- .f64_type,
- .f128_type,
- .c_void_type,
- .bool_type,
- .void_type,
- .type_type,
- .anyerror_type,
- .comptime_int_type,
- .comptime_float_type,
- .noreturn_type,
- .null_type,
- .undefined_type,
- .fn_noreturn_no_args_type,
- .fn_void_no_args_type,
- .fn_naked_noreturn_no_args_type,
- .fn_ccc_void_no_args_type,
- .single_const_pointer_to_comptime_int_type,
- .const_slice_u8_type,
- .enum_literal_type,
- .null_value,
- .function,
- .extern_fn,
- .variable,
- .ref_val,
- .decl_ref,
- .elem_ptr,
- .bytes,
- .undef,
- .repeated,
- .float_16,
- .float_32,
- .float_64,
- .float_128,
- .void_value,
- .unreachable_value,
- .empty_array,
- .enum_literal,
- .@"error",
- .error_union,
- .empty_struct_value,
- .inferred_alloc,
- .abi_align_default,
- => unreachable,
-
.zero,
.bool_false,
=> return 0,
@@ -1016,80 +755,14 @@ pub const Value = extern union {
},
.int_big_positive => return self.castTag(.int_big_positive).?.asBigInt().bitCountTwosComp(),
.int_big_negative => return self.castTag(.int_big_negative).?.asBigInt().bitCountTwosComp(),
+
+ else => unreachable,
}
}
/// Asserts the value is an integer, and the destination type is ComptimeInt or Int.
pub fn intFitsInType(self: Value, ty: Type, target: Target) bool {
switch (self.tag()) {
- .ty,
- .int_type,
- .u8_type,
- .i8_type,
- .u16_type,
- .i16_type,
- .u32_type,
- .i32_type,
- .u64_type,
- .i64_type,
- .u128_type,
- .i128_type,
- .usize_type,
- .isize_type,
- .c_short_type,
- .c_ushort_type,
- .c_int_type,
- .c_uint_type,
- .c_long_type,
- .c_ulong_type,
- .c_longlong_type,
- .c_ulonglong_type,
- .c_longdouble_type,
- .f16_type,
- .f32_type,
- .f64_type,
- .f128_type,
- .c_void_type,
- .bool_type,
- .void_type,
- .type_type,
- .anyerror_type,
- .comptime_int_type,
- .comptime_float_type,
- .noreturn_type,
- .null_type,
- .undefined_type,
- .fn_noreturn_no_args_type,
- .fn_void_no_args_type,
- .fn_naked_noreturn_no_args_type,
- .fn_ccc_void_no_args_type,
- .single_const_pointer_to_comptime_int_type,
- .const_slice_u8_type,
- .enum_literal_type,
- .null_value,
- .function,
- .extern_fn,
- .variable,
- .ref_val,
- .decl_ref,
- .elem_ptr,
- .bytes,
- .repeated,
- .float_16,
- .float_32,
- .float_64,
- .float_128,
- .void_value,
- .unreachable_value,
- .empty_array,
- .enum_literal,
- .@"error",
- .error_union,
- .empty_struct_value,
- .inferred_alloc,
- .abi_align_default,
- => unreachable,
-
.zero,
.undef,
.bool_false,
@@ -1144,6 +817,8 @@ pub const Value = extern union {
.ComptimeInt => return true,
else => unreachable,
},
+
+ else => unreachable,
}
}
@@ -1180,77 +855,6 @@ pub const Value = extern union {
/// Asserts the value is a float
pub fn floatHasFraction(self: Value) bool {
return switch (self.tag()) {
- .ty,
- .int_type,
- .u8_type,
- .i8_type,
- .u16_type,
- .i16_type,
- .u32_type,
- .i32_type,
- .u64_type,
- .i64_type,
- .u128_type,
- .i128_type,
- .usize_type,
- .isize_type,
- .c_short_type,
- .c_ushort_type,
- .c_int_type,
- .c_uint_type,
- .c_long_type,
- .c_ulong_type,
- .c_longlong_type,
- .c_ulonglong_type,
- .c_longdouble_type,
- .f16_type,
- .f32_type,
- .f64_type,
- .f128_type,
- .c_void_type,
- .bool_type,
- .void_type,
- .type_type,
- .anyerror_type,
- .comptime_int_type,
- .comptime_float_type,
- .noreturn_type,
- .null_type,
- .undefined_type,
- .fn_noreturn_no_args_type,
- .fn_void_no_args_type,
- .fn_naked_noreturn_no_args_type,
- .fn_ccc_void_no_args_type,
- .single_const_pointer_to_comptime_int_type,
- .const_slice_u8_type,
- .enum_literal_type,
- .bool_true,
- .bool_false,
- .null_value,
- .function,
- .extern_fn,
- .variable,
- .ref_val,
- .decl_ref,
- .elem_ptr,
- .bytes,
- .repeated,
- .undef,
- .int_u64,
- .int_i64,
- .int_big_positive,
- .int_big_negative,
- .empty_array,
- .void_value,
- .unreachable_value,
- .enum_literal,
- .@"error",
- .error_union,
- .empty_struct_value,
- .inferred_alloc,
- .abi_align_default,
- => unreachable,
-
.zero,
.one,
=> false,
@@ -1260,76 +864,13 @@ pub const Value = extern union {
.float_64 => @rem(self.castTag(.float_64).?.data, 1) != 0,
// .float_128 => @rem(self.castTag(.float_128).?.data, 1) != 0,
.float_128 => @panic("TODO lld: error: undefined symbol: fmodl"),
+
+ else => unreachable,
};
}
pub fn orderAgainstZero(lhs: Value) std.math.Order {
return switch (lhs.tag()) {
- .ty,
- .int_type,
- .u8_type,
- .i8_type,
- .u16_type,
- .i16_type,
- .u32_type,
- .i32_type,
- .u64_type,
- .i64_type,
- .u128_type,
- .i128_type,
- .usize_type,
- .isize_type,
- .c_short_type,
- .c_ushort_type,
- .c_int_type,
- .c_uint_type,
- .c_long_type,
- .c_ulong_type,
- .c_longlong_type,
- .c_ulonglong_type,
- .c_longdouble_type,
- .f16_type,
- .f32_type,
- .f64_type,
- .f128_type,
- .c_void_type,
- .bool_type,
- .void_type,
- .type_type,
- .anyerror_type,
- .comptime_int_type,
- .comptime_float_type,
- .noreturn_type,
- .null_type,
- .undefined_type,
- .fn_noreturn_no_args_type,
- .fn_void_no_args_type,
- .fn_naked_noreturn_no_args_type,
- .fn_ccc_void_no_args_type,
- .single_const_pointer_to_comptime_int_type,
- .const_slice_u8_type,
- .enum_literal_type,
- .null_value,
- .function,
- .extern_fn,
- .variable,
- .ref_val,
- .decl_ref,
- .elem_ptr,
- .bytes,
- .repeated,
- .undef,
- .void_value,
- .unreachable_value,
- .empty_array,
- .enum_literal,
- .@"error",
- .error_union,
- .empty_struct_value,
- .inferred_alloc,
- .abi_align_default,
- => unreachable,
-
.zero,
.bool_false,
=> .eq,
@@ -1347,6 +888,8 @@ pub const Value = extern union {
.float_32 => std.math.order(lhs.castTag(.float_32).?.data, 0),
.float_64 => std.math.order(lhs.castTag(.float_64).?.data, 0),
.float_128 => std.math.order(lhs.castTag(.float_128).?.data, 0),
+
+ else => unreachable,
};
}
@@ -1396,10 +939,12 @@ pub const Value = extern union {
}
pub fn eql(a: Value, b: Value) bool {
- if (a.tag() == b.tag()) {
- if (a.tag() == .void_value or a.tag() == .null_value) {
+ const a_tag = a.tag();
+ const b_tag = b.tag();
+ if (a_tag == b_tag) {
+ if (a_tag == .void_value or a_tag == .null_value) {
return true;
- } else if (a.tag() == .enum_literal) {
+ } else if (a_tag == .enum_literal) {
const a_name = a.castTag(.enum_literal).?.data;
const b_name = b.castTag(.enum_literal).?.data;
return std.mem.eql(u8, a_name, b_name);
@@ -1416,6 +961,10 @@ pub const Value = extern union {
return compare(a, .eq, b);
}
+ pub fn hash_u32(self: Value) u32 {
+ return @truncate(u32, self.hash());
+ }
+
pub fn hash(self: Value) u64 {
var hasher = std.hash.Wyhash.init(0);
@@ -1493,11 +1042,18 @@ pub const Value = extern union {
.zero, .bool_false => std.hash.autoHash(&hasher, @as(u64, 0)),
.one, .bool_true => std.hash.autoHash(&hasher, @as(u64, 1)),
- .float_16, .float_32, .float_64, .float_128 => {},
+ .float_16, .float_32, .float_64, .float_128 => {
+ @panic("TODO implement Value.hash for floats");
+ },
+
.enum_literal => {
const payload = self.castTag(.enum_literal).?;
hasher.update(payload.data);
},
+ .enum_field_index => {
+ const payload = self.castTag(.enum_field_index).?;
+ std.hash.autoHash(&hasher, payload.data);
+ },
.bytes => {
const payload = self.castTag(.bytes).?;
hasher.update(payload.data);
@@ -1573,80 +1129,6 @@ pub const Value = extern union {
/// Returns error.AnalysisFail if the pointer points to a Decl that failed semantic analysis.
pub fn pointerDeref(self: Value, allocator: *Allocator) error{ AnalysisFail, OutOfMemory }!Value {
return switch (self.tag()) {
- .ty,
- .int_type,
- .u8_type,
- .i8_type,
- .u16_type,
- .i16_type,
- .u32_type,
- .i32_type,
- .u64_type,
- .i64_type,
- .u128_type,
- .i128_type,
- .usize_type,
- .isize_type,
- .c_short_type,
- .c_ushort_type,
- .c_int_type,
- .c_uint_type,
- .c_long_type,
- .c_ulong_type,
- .c_longlong_type,
- .c_ulonglong_type,
- .c_longdouble_type,
- .f16_type,
- .f32_type,
- .f64_type,
- .f128_type,
- .c_void_type,
- .bool_type,
- .void_type,
- .type_type,
- .anyerror_type,
- .comptime_int_type,
- .comptime_float_type,
- .noreturn_type,
- .null_type,
- .undefined_type,
- .fn_noreturn_no_args_type,
- .fn_void_no_args_type,
- .fn_naked_noreturn_no_args_type,
- .fn_ccc_void_no_args_type,
- .single_const_pointer_to_comptime_int_type,
- .const_slice_u8_type,
- .enum_literal_type,
- .zero,
- .one,
- .bool_true,
- .bool_false,
- .null_value,
- .function,
- .extern_fn,
- .variable,
- .int_u64,
- .int_i64,
- .int_big_positive,
- .int_big_negative,
- .bytes,
- .undef,
- .repeated,
- .float_16,
- .float_32,
- .float_64,
- .float_128,
- .void_value,
- .unreachable_value,
- .empty_array,
- .enum_literal,
- .@"error",
- .error_union,
- .empty_struct_value,
- .inferred_alloc,
- .abi_align_default,
- => unreachable,
-
.ref_val => self.castTag(.ref_val).?.data,
.decl_ref => self.castTag(.decl_ref).?.data.value(),
.elem_ptr => {
@@ -1654,6 +1136,8 @@ pub const Value = extern union {
const array_val = try elem_ptr.array_ptr.pointerDeref(allocator);
return array_val.elemValue(allocator, elem_ptr.index);
},
+
+ else => unreachable,
};
}
@@ -1661,86 +1145,14 @@ pub const Value = extern union {
/// or an unknown-length pointer, and returns the element value at the index.
pub fn elemValue(self: Value, allocator: *Allocator, index: usize) error{OutOfMemory}!Value {
switch (self.tag()) {
- .ty,
- .int_type,
- .u8_type,
- .i8_type,
- .u16_type,
- .i16_type,
- .u32_type,
- .i32_type,
- .u64_type,
- .i64_type,
- .u128_type,
- .i128_type,
- .usize_type,
- .isize_type,
- .c_short_type,
- .c_ushort_type,
- .c_int_type,
- .c_uint_type,
- .c_long_type,
- .c_ulong_type,
- .c_longlong_type,
- .c_ulonglong_type,
- .c_longdouble_type,
- .f16_type,
- .f32_type,
- .f64_type,
- .f128_type,
- .c_void_type,
- .bool_type,
- .void_type,
- .type_type,
- .anyerror_type,
- .comptime_int_type,
- .comptime_float_type,
- .noreturn_type,
- .null_type,
- .undefined_type,
- .fn_noreturn_no_args_type,
- .fn_void_no_args_type,
- .fn_naked_noreturn_no_args_type,
- .fn_ccc_void_no_args_type,
- .single_const_pointer_to_comptime_int_type,
- .const_slice_u8_type,
- .enum_literal_type,
- .zero,
- .one,
- .bool_true,
- .bool_false,
- .null_value,
- .function,
- .extern_fn,
- .variable,
- .int_u64,
- .int_i64,
- .int_big_positive,
- .int_big_negative,
- .undef,
- .elem_ptr,
- .ref_val,
- .decl_ref,
- .float_16,
- .float_32,
- .float_64,
- .float_128,
- .void_value,
- .unreachable_value,
- .enum_literal,
- .@"error",
- .error_union,
- .empty_struct_value,
- .inferred_alloc,
- .abi_align_default,
- => unreachable,
-
.empty_array => unreachable, // out of bounds array index
.bytes => return Tag.int_u64.create(allocator, self.castTag(.bytes).?.data[index]),
// No matter the index; all the elements are the same!
.repeated => return self.castTag(.repeated).?.data,
+
+ else => unreachable,
}
}
@@ -1766,161 +1178,18 @@ pub const Value = extern union {
/// Valid for all types. Asserts the value is not undefined and not unreachable.
pub fn isNull(self: Value) bool {
return switch (self.tag()) {
- .ty,
- .int_type,
- .u8_type,
- .i8_type,
- .u16_type,
- .i16_type,
- .u32_type,
- .i32_type,
- .u64_type,
- .i64_type,
- .u128_type,
- .i128_type,
- .usize_type,
- .isize_type,
- .c_short_type,
- .c_ushort_type,
- .c_int_type,
- .c_uint_type,
- .c_long_type,
- .c_ulong_type,
- .c_longlong_type,
- .c_ulonglong_type,
- .c_longdouble_type,
- .f16_type,
- .f32_type,
- .f64_type,
- .f128_type,
- .c_void_type,
- .bool_type,
- .void_type,
- .type_type,
- .anyerror_type,
- .comptime_int_type,
- .comptime_float_type,
- .noreturn_type,
- .null_type,
- .undefined_type,
- .fn_noreturn_no_args_type,
- .fn_void_no_args_type,
- .fn_naked_noreturn_no_args_type,
- .fn_ccc_void_no_args_type,
- .single_const_pointer_to_comptime_int_type,
- .const_slice_u8_type,
- .enum_literal_type,
- .zero,
- .one,
- .empty_array,
- .bool_true,
- .bool_false,
- .function,
- .extern_fn,
- .variable,
- .int_u64,
- .int_i64,
- .int_big_positive,
- .int_big_negative,
- .ref_val,
- .decl_ref,
- .elem_ptr,
- .bytes,
- .repeated,
- .float_16,
- .float_32,
- .float_64,
- .float_128,
- .void_value,
- .enum_literal,
- .@"error",
- .error_union,
- .empty_struct_value,
- .abi_align_default,
- => false,
-
.undef => unreachable,
.unreachable_value => unreachable,
.inferred_alloc => unreachable,
.null_value => true,
+
+ else => false,
};
}
/// Valid for all types. Asserts the value is not undefined and not unreachable.
pub fn getError(self: Value) ?[]const u8 {
return switch (self.tag()) {
- .ty,
- .int_type,
- .u8_type,
- .i8_type,
- .u16_type,
- .i16_type,
- .u32_type,
- .i32_type,
- .u64_type,
- .i64_type,
- .u128_type,
- .i128_type,
- .usize_type,
- .isize_type,
- .c_short_type,
- .c_ushort_type,
- .c_int_type,
- .c_uint_type,
- .c_long_type,
- .c_ulong_type,
- .c_longlong_type,
- .c_ulonglong_type,
- .c_longdouble_type,
- .f16_type,
- .f32_type,
- .f64_type,
- .f128_type,
- .c_void_type,
- .bool_type,
- .void_type,
- .type_type,
- .anyerror_type,
- .comptime_int_type,
- .comptime_float_type,
- .noreturn_type,
- .null_type,
- .undefined_type,
- .fn_noreturn_no_args_type,
- .fn_void_no_args_type,
- .fn_naked_noreturn_no_args_type,
- .fn_ccc_void_no_args_type,
- .single_const_pointer_to_comptime_int_type,
- .const_slice_u8_type,
- .enum_literal_type,
- .zero,
- .one,
- .null_value,
- .empty_array,
- .bool_true,
- .bool_false,
- .function,
- .extern_fn,
- .variable,
- .int_u64,
- .int_i64,
- .int_big_positive,
- .int_big_negative,
- .ref_val,
- .decl_ref,
- .elem_ptr,
- .bytes,
- .repeated,
- .float_16,
- .float_32,
- .float_64,
- .float_128,
- .void_value,
- .enum_literal,
- .empty_struct_value,
- .abi_align_default,
- => null,
-
.error_union => {
const data = self.castTag(.error_union).?.data;
return if (data.tag() == .@"error")
@@ -1932,6 +1201,8 @@ pub const Value = extern union {
.undef => unreachable,
.unreachable_value => unreachable,
.inferred_alloc => unreachable,
+
+ else => null,
};
}
/// Valid for all types. Asserts the value is not undefined.
@@ -2021,6 +1292,7 @@ pub const Value = extern union {
.float_128,
.void_value,
.enum_literal,
+ .enum_field_index,
.@"error",
.error_union,
.empty_struct_value,
@@ -2038,6 +1310,11 @@ pub const Value = extern union {
pub const Payload = struct {
tag: Tag,
+ pub const U32 = struct {
+ base: Payload,
+ data: u32,
+ };
+
pub const U64 = struct {
base: Payload,
data: u64,
src/zir.zig
@@ -37,8 +37,6 @@ pub const Code = struct {
string_bytes: []u8,
/// The meaning of this data is determined by `Inst.Tag` value.
extra: []u32,
- /// Used for decl_val and decl_ref instructions.
- decls: []*Module.Decl,
/// Returns the requested data, as well as the new index which is at the start of the
/// trailers for the object.
@@ -78,7 +76,6 @@ pub const Code = struct {
code.instructions.deinit(gpa);
gpa.free(code.string_bytes);
gpa.free(code.extra);
- gpa.free(code.decls);
code.* = undefined;
}
@@ -267,9 +264,6 @@ pub const Inst = struct {
/// only the taken branch is analyzed. The then block and else block must
/// terminate with an "inline" variant of a noreturn instruction.
condbr_inline,
- /// A comptime known value.
- /// Uses the `const` union field.
- @"const",
/// A struct type definition. Contains references to ZIR instructions for
/// the field types, defaults, and alignments.
/// Uses the `pl_node` union field. Payload is `StructDecl`.
@@ -286,6 +280,8 @@ pub const Inst = struct {
/// the field value expressions and optional type tag expression.
/// Uses the `pl_node` union field. Payload is `EnumDecl`.
enum_decl,
+ /// Same as `enum_decl`, except the enum is non-exhaustive.
+ enum_decl_nonexhaustive,
/// An opaque type definition. Provides an AST node only.
/// Uses the `node` union field.
opaque_decl,
@@ -369,6 +365,11 @@ pub const Inst = struct {
import,
/// Integer literal that fits in a u64. Uses the int union value.
int,
+ /// A float literal that fits in a f32. Uses the float union value.
+ float,
+ /// A float literal that fits in a f128. Uses the `pl_node` union value.
+ /// Payload is `Float128`.
+ float128,
/// Convert an integer value to another integer type, asserting that the destination type
/// can hold the same mathematical value.
/// Uses the `pl_node` field. AST is the `@intCast` syntax.
@@ -667,6 +668,12 @@ pub const Inst = struct {
/// A struct literal with a specified type, with no fields.
/// Uses the `un_node` field.
struct_init_empty,
+ /// Converts an integer into an enum value.
+ /// Uses `pl_node` with payload `Bin`. `lhs` is enum type, `rhs` is operand.
+ int_to_enum,
+ /// Converts an enum value into an integer. Resulting type will be the tag type
+ /// of the enum. Uses `un_node`.
+ enum_to_int,
/// Returns whether the instruction is one of the control flow "noreturn" types.
/// Function calls do not count.
@@ -712,12 +719,12 @@ pub const Inst = struct {
.cmp_gt,
.cmp_neq,
.coerce_result_ptr,
- .@"const",
.struct_decl,
.struct_decl_packed,
.struct_decl_extern,
.union_decl,
.enum_decl,
+ .enum_decl_nonexhaustive,
.opaque_decl,
.dbg_stmt_node,
.decl_ref,
@@ -740,6 +747,8 @@ pub const Inst = struct {
.fn_type_cc,
.fn_type_cc_var_args,
.int,
+ .float,
+ .float128,
.intcast,
.int_type,
.is_non_null,
@@ -822,6 +831,8 @@ pub const Inst = struct {
.switch_block_ref_under_multi,
.validate_struct_init_ptr,
.struct_init_empty,
+ .int_to_enum,
+ .enum_to_int,
=> false,
.@"break",
@@ -1184,7 +1195,6 @@ pub const Inst = struct {
}
},
bin: Bin,
- @"const": *TypedValue,
/// For strings which may contain null bytes.
str: struct {
/// Offset into `string_bytes`.
@@ -1226,6 +1236,16 @@ pub const Inst = struct {
/// Offset from Decl AST node index.
node: i32,
int: u64,
+ float: struct {
+ /// Offset from Decl AST node index.
+ /// `Tag` determines which kind of AST node this points to.
+ src_node: i32,
+ number: f32,
+
+ pub fn src(self: @This()) LazySrcLoc {
+ return .{ .node_offset = self.src_node };
+ }
+ },
array_type_sentinel: struct {
len: Ref,
/// index into extra, points to an `ArrayTypeSentinel`
@@ -1507,6 +1527,22 @@ pub const Inst = struct {
tag_type: Ref,
fields_len: u32,
};
+
+ /// A f128 value, broken up into 4 u32 parts.
+ pub const Float128 = struct {
+ piece0: u32,
+ piece1: u32,
+ piece2: u32,
+ piece3: u32,
+
+ pub fn get(self: Float128) f128 {
+ const int_bits = @as(u128, self.piece0) |
+ (@as(u128, self.piece1) << 32) |
+ (@as(u128, self.piece2) << 64) |
+ (@as(u128, self.piece3) << 96);
+ return @bitCast(f128, int_bits);
+ }
+ };
};
pub const SpecialProng = enum { none, @"else", under };
@@ -1581,6 +1617,7 @@ const Writer = struct {
.typeof,
.typeof_elem,
.struct_init_empty,
+ .enum_to_int,
=> try self.writeUnNode(stream, inst),
.ref,
@@ -1594,11 +1631,12 @@ const Writer = struct {
=> try self.writeBoolBr(stream, inst),
.array_type_sentinel => try self.writeArrayTypeSentinel(stream, inst),
- .@"const" => try self.writeConst(stream, inst),
.param_type => try self.writeParamType(stream, inst),
.ptr_type_simple => try self.writePtrTypeSimple(stream, inst),
.ptr_type => try self.writePtrType(stream, inst),
.int => try self.writeInt(stream, inst),
+ .float => try self.writeFloat(stream, inst),
+ .float128 => try self.writeFloat128(stream, inst),
.str => try self.writeStr(stream, inst),
.elided => try stream.writeAll(")"),
.int_type => try self.writeIntType(stream, inst),
@@ -1619,6 +1657,7 @@ const Writer = struct {
.slice_sentinel,
.union_decl,
.enum_decl,
+ .enum_decl_nonexhaustive,
=> try self.writePlNode(stream, inst),
.add,
@@ -1647,6 +1686,7 @@ const Writer = struct {
.merge_error_sets,
.bit_and,
.bit_or,
+ .int_to_enum,
=> try self.writePlNodeBin(stream, inst),
.call,
@@ -1773,15 +1813,6 @@ const Writer = struct {
try stream.writeAll("TODO)");
}
- fn writeConst(
- self: *Writer,
- stream: anytype,
- inst: Inst.Index,
- ) (@TypeOf(stream).Error || error{OutOfMemory})!void {
- const inst_data = self.code.instructions.items(.data)[inst].@"const";
- try stream.writeAll("TODO)");
- }
-
fn writeParamType(
self: *Writer,
stream: anytype,
@@ -1819,6 +1850,23 @@ const Writer = struct {
try stream.print("{d})", .{inst_data});
}
+ fn writeFloat(self: *Writer, stream: anytype, inst: Inst.Index) !void {
+ const inst_data = self.code.instructions.items(.data)[inst].float;
+ const src = inst_data.src();
+ try stream.print("{d}) ", .{inst_data.number});
+ try self.writeSrc(stream, src);
+ }
+
+ fn writeFloat128(self: *Writer, stream: anytype, inst: Inst.Index) !void {
+ const inst_data = self.code.instructions.items(.data)[inst].pl_node;
+ const extra = self.code.extraData(Inst.Float128, inst_data.payload_index).data;
+ const src = inst_data.src();
+ const number = extra.get();
+ // TODO improve std.format to be able to print f128 values
+ try stream.print("{d}) ", .{@floatCast(f64, number)});
+ try self.writeSrc(stream, src);
+ }
+
fn writeStr(
self: *Writer,
stream: anytype,
@@ -2136,7 +2184,8 @@ const Writer = struct {
fn writePlNodeDecl(self: *Writer, stream: anytype, inst: Inst.Index) !void {
const inst_data = self.code.instructions.items(.data)[inst].pl_node;
- const decl = self.code.decls[inst_data.payload_index];
+ const owner_decl = self.scope.ownerDecl().?;
+ const decl = owner_decl.dependencies.entries.items[inst_data.payload_index].key;
try stream.print("{s}) ", .{decl.name});
try self.writeSrc(stream, inst_data.src());
}