Commit c5383173a0
Changed files (16)
doc/langref.html.in
@@ -638,7 +638,7 @@
{#syntax#}i7{#endsyntax#} refers to a signed 7-bit integer. The maximum allowed bit-width of an
integer type is {#syntax#}65535{#endsyntax#}.
</p>
- {#see_also|Integers|Floats|void|Errors|@Type#}
+ {#see_also|Integers|Floats|void|Errors|@Int#}
{#header_close#}
{#header_open|Primitive Values#}
<div class="table-wrapper">
@@ -3723,9 +3723,9 @@ void do_a_thing(struct Foo *foo) {
<td>{#syntax#}x{#endsyntax#} is a {#syntax#}@FieldType(T, "a"){#endsyntax#}</td>
</tr>
<tr>
- <th scope="row">{#syntax#}@Type(x){#endsyntax#}</th>
+ <th scope="row">{#syntax#}@Int(x, y){#endsyntax#}</th>
<td>-</td>
- <td>{#syntax#}x{#endsyntax#} is a {#syntax#}std.builtin.Type{#endsyntax#}</td>
+ <td>{#syntax#}x{#endsyntax#} is a {#syntax#}std.builtin.Signedness{#endsyntax#}, {#syntax#}y{#endsyntax#} is a {#syntax#}u16{#endsyntax#}</td>
</tr>
<tr>
<th scope="row">{#syntax#}@typeInfo(x){#endsyntax#}</th>
@@ -3839,9 +3839,9 @@ void do_a_thing(struct Foo *foo) {
<td>{#syntax#}x{#endsyntax#} has no result location (typed initializers do not propagate result locations)</td>
</tr>
<tr>
- <th scope="row">{#syntax#}@Type(x){#endsyntax#}</th>
- <td>{#syntax#}ptr{#endsyntax#}</td>
- <td>{#syntax#}x{#endsyntax#} has no result location</td>
+ <th scope="row">{#syntax#}@Int(x, y){#endsyntax#}</th>
+ <td>-</td>
+ <td>{#syntax#}x{#endsyntax#} and {#syntax#}y{#endsyntax#} do not have result locations</td>
</tr>
<tr>
<th scope="row">{#syntax#}@typeInfo(x){#endsyntax#}</th>
@@ -5755,41 +5755,75 @@ fn cmpxchgWeakButNotAtomic(comptime T: type, ptr: *T, expected_value: T, new_val
</p>
{#header_close#}
- {#header_open|@Type#}
- <pre>{#syntax#}@Type(comptime info: std.builtin.Type) type{#endsyntax#}</pre>
- <p>
- This function is the inverse of {#link|@typeInfo#}. It reifies type information
- into a {#syntax#}type{#endsyntax#}.
- </p>
- <p>
- It is available for the following types:
- </p>
- <ul>
- <li>{#syntax#}type{#endsyntax#}</li>
- <li>{#syntax#}noreturn{#endsyntax#}</li>
- <li>{#syntax#}void{#endsyntax#}</li>
- <li>{#syntax#}bool{#endsyntax#}</li>
- <li>{#link|Integers#} - The maximum bit count for an integer type is {#syntax#}65535{#endsyntax#}.</li>
- <li>{#link|Floats#}</li>
- <li>{#link|Pointers#}</li>
- <li>{#syntax#}comptime_int{#endsyntax#}</li>
- <li>{#syntax#}comptime_float{#endsyntax#}</li>
- <li>{#syntax#}@TypeOf(undefined){#endsyntax#}</li>
- <li>{#syntax#}@TypeOf(null){#endsyntax#}</li>
- <li>{#link|Arrays#}</li>
- <li>{#link|Optionals#}</li>
- <li>{#link|Error Set Type#}</li>
- <li>{#link|Error Union Type#}</li>
- <li>{#link|Vectors#}</li>
- <li>{#link|opaque#}</li>
- <li>{#syntax#}anyframe{#endsyntax#}</li>
- <li>{#link|struct#}</li>
- <li>{#link|enum#}</li>
- <li>{#link|Enum Literals#}</li>
- <li>{#link|union#}</li>
- <li>{#link|Functions#}</li>
- </ul>
+ {#header_open|@EnumLiteral#}
+ <pre>{#syntax#}@EnumLiteral() type{#endsyntax#}</pre>
+ <p>Returns the comptime-only "enum literal" type. This is the type of uncoerced {#link|Enum Literals#}. Values of this type can coerce to any {#link|enum#} with a matching field.</p>
+ {#header_close#}
+
+ {#header_open|@Int#}
+ <pre>{#syntax#}@Int(comptime signedness: std.builtin.Signedness, comptime bits: u16) type{#endsyntax#}</pre>
+ <p>Returns an integer type with the given signedness and bit width.</p>
+ <p>For instance, {#syntax#}@Int(.unsigned, 18){#endsyntax#} returns the type {#syntax#}u18{#endsyntax#}.</p>
{#header_close#}
+
+ {#header_open|@Tuple#}
+ <pre>{#syntax#}@Tuple(comptime field_types: []const type) type{#endsyntax#}</pre>
+ <p>Returns a {#link|tuple|Tuples#} type with the given field types.</p>
+ {#header_close#}
+
+ {#header_open|@Pointer#}
+ <pre>{#syntax#}@Pointer(
+ comptime size: std.builtin.Type.Pointer.Size,
+ comptime attrs: std.builtin.Type.Pointer.Attributes,
+ comptime Element: type,
+ comptime sentinel: ?Element,
+) type{#endsyntax#}</pre>
+ <p>Returns a {#link|pointer|Pointers#} type with the properties specified by the arguments.</p>
+ {#header_close#}
+
+ {#header_open|@Fn#}
+ <pre>{#syntax#}@Fn(
+ comptime param_types: []const type,
+ comptime param_attrs: *const [param_types.len]std.builtin.Type.Fn.Param.Attributes,
+ comptime ReturnType: type,
+ comptime attrs: std.builtin.Type.Fn.Attributes,
+) type{#endsyntax#}</pre>
+ <p>Returns a {#link|function|Functions#} type with the properties specified by the arguments.</p>
+ {#header_close#}
+
+ {#header_open|@Struct#}
+ <pre>{#syntax#}@Struct(
+ comptime layout: std.builtin.Type.ContainerLayout,
+ comptime BackingInt: ?type,
+ comptime field_names: []const []const u8,
+ comptime field_types: *const [field_names.len]type,
+ comptime field_attrs: *const [field_names.len]std.builtin.Type.StructField.Attributes,
+) type{#endsyntax#}</pre>
+ <p>Returns a {#link|struct#} type with the properties specified by the arguments.</p>
+ {#header_close#}
+
+ {#header_open|@Union#}
+ <pre>{#syntax#}@Union(
+ comptime layout: std.builtin.Type.ContainerLayout,
+ /// Either the integer tag type, or the integer backing type, depending on `layout`.
+ comptime ArgType: ?type,
+ comptime field_names: []const []const u8,
+ comptime field_types: *const [field_names.len]type,
+ comptime field_attrs: *const [field_names.len]std.builtin.Type.UnionField.Attributes,
+) type{#endsyntax#}</pre>
+ <p>Returns a {#link|union#} type with the properties specified by the arguments.</p>
+ {#header_close#}
+
+ {#header_open|@Enum#}
+ <pre>{#syntax#}@Enum(
+ comptime TagInt: type,
+ comptime mode: std.builtin.Type.Enum.Mode,
+ comptime field_names: []const []const u8,
+ comptime field_values: *const [field_names.len]TagInt,
+) type{#endsyntax#}</pre>
+ <p>Returns an {#link|enum#} type with the properties specified by the arguments.</p>
+ {#header_close#}
+
{#header_open|@typeInfo#}
<pre>{#syntax#}@typeInfo(comptime T: type) std.builtin.Type{#endsyntax#}</pre>
<p>
lib/std/zig/AstGen.zig
@@ -833,7 +833,7 @@ fn expr(gz: *GenZir, scope: *Scope, ri: ResultInfo, node: Ast.Node.Index) InnerE
=> {
var buf: [2]Ast.Node.Index = undefined;
const params = tree.builtinCallParams(&buf, node).?;
- return builtinCall(gz, scope, ri, node, params, false);
+ return builtinCall(gz, scope, ri, node, params, false, .anon);
},
.call_one,
@@ -1194,14 +1194,20 @@ fn nameStratExpr(
},
.builtin_call_two,
.builtin_call_two_comma,
+ .builtin_call,
+ .builtin_call_comma,
=> {
const builtin_token = tree.nodeMainToken(node);
const builtin_name = tree.tokenSlice(builtin_token);
- if (!std.mem.eql(u8, builtin_name, "@Type")) return null;
- var buf: [2]Ast.Node.Index = undefined;
- const params = tree.builtinCallParams(&buf, node).?;
- if (params.len != 1) return null; // let `builtinCall` error
- return try builtinReify(gz, scope, ri, node, params[0], name_strat);
+ const info = BuiltinFn.list.get(builtin_name) orelse return null;
+ switch (info.tag) {
+ .Enum, .Struct, .Union => {
+ var buf: [2]Ast.Node.Index = undefined;
+ const params = tree.builtinCallParams(&buf, node).?;
+ return try builtinCall(gz, scope, ri, node, params, false, name_strat);
+ },
+ else => return null,
+ }
},
else => return null,
}
@@ -1406,7 +1412,7 @@ fn fnProtoExprInner(
.none;
const ret_ty_node = fn_proto.ast.return_type.unwrap().?;
- const ret_ty = try comptimeExpr(&block_scope, scope, coerced_type_ri, ret_ty_node, .function_ret_ty);
+ const ret_ty = try comptimeExpr(&block_scope, scope, coerced_type_ri, ret_ty_node, .fn_ret_ty);
const result = try block_scope.addFunc(.{
.src_node = fn_proto.ast.proto_node,
@@ -2629,7 +2635,7 @@ fn blockExprStmts(gz: *GenZir, parent_scope: *Scope, statements: []const Ast.Nod
const params = tree.builtinCallParams(&buf, inner_node).?;
try emitDbgNode(gz, inner_node);
- const result = try builtinCall(gz, scope, .{ .rl = .none }, inner_node, params, allow_branch_hint);
+ const result = try builtinCall(gz, scope, .{ .rl = .none }, inner_node, params, allow_branch_hint, .anon);
noreturn_src_node = try addEnsureResult(gz, result, inner_node);
},
@@ -2707,6 +2713,7 @@ fn addEnsureResult(gz: *GenZir, maybe_unused_result: Zir.Inst.Ref, statement: As
.elem_type,
.indexable_ptr_elem_type,
.splat_op_result_ty,
+ .reify_int,
.vector_type,
.indexable_ptr_len,
.anyframe_type,
@@ -8942,7 +8949,7 @@ fn unionInit(
params: []const Ast.Node.Index,
) InnerError!Zir.Inst.Ref {
const union_type = try typeExpr(gz, scope, params[0]);
- const field_name = try comptimeExpr(gz, scope, .{ .rl = .{ .coerced_ty = .slice_const_u8_type } }, params[1], .union_field_name);
+ const field_name = try comptimeExpr(gz, scope, .{ .rl = .{ .coerced_ty = .slice_const_u8_type } }, params[1], .union_field_names);
const field_type = try gz.addPlNode(.field_type_ref, node, Zir.Inst.FieldTypeRef{
.container_type = union_type,
.field_name = field_name,
@@ -9210,6 +9217,7 @@ fn builtinCall(
node: Ast.Node.Index,
params: []const Ast.Node.Index,
allow_branch_hint: bool,
+ reify_name_strat: Zir.Inst.NameStrategy,
) InnerError!Zir.Inst.Ref {
const astgen = gz.astgen;
const tree = astgen.tree;
@@ -9443,9 +9451,140 @@ fn builtinCall(
return rvalue(gz, ri, try gz.addNodeExtended(.in_comptime, node), node);
},
- .Type => {
- return builtinReify(gz, scope, ri, node, params[0], .anon);
+ .EnumLiteral => return rvalue(gz, ri, .enum_literal_type, node),
+ .Int => {
+ const signedness_ty = try gz.addBuiltinValue(node, .signedness);
+ const result = try gz.addPlNode(.reify_int, node, Zir.Inst.Bin{
+ .lhs = try comptimeExpr(gz, scope, .{ .rl = .{ .coerced_ty = signedness_ty } }, params[0], .int_signedness),
+ .rhs = try comptimeExpr(gz, scope, .{ .rl = .{ .coerced_ty = .u16_type } }, params[1], .int_bit_width),
+ });
+ return rvalue(gz, ri, result, node);
+ },
+ .Tuple => {
+ const result = try gz.addExtendedPayload(.reify_tuple, Zir.Inst.UnNode{
+ .node = gz.nodeIndexToRelative(node),
+ .operand = try comptimeExpr(gz, scope, .{ .rl = .{ .coerced_ty = .slice_const_type_type } }, params[0], .tuple_field_types),
+ });
+ return rvalue(gz, ri, result, node);
+ },
+ .Pointer => {
+ const ptr_size_ty = try gz.addBuiltinValue(node, .pointer_size);
+ const ptr_attrs_ty = try gz.addBuiltinValue(node, .pointer_attributes);
+ const size = try comptimeExpr(gz, scope, .{ .rl = .{ .coerced_ty = ptr_size_ty } }, params[0], .pointer_size);
+ const attrs = try comptimeExpr(gz, scope, .{ .rl = .{ .coerced_ty = ptr_attrs_ty } }, params[1], .pointer_attrs);
+ const elem_ty = try typeExpr(gz, scope, params[2]);
+ const sentinel_ty = try gz.addExtendedPayload(.reify_pointer_sentinel_ty, Zir.Inst.UnNode{
+ .node = gz.nodeIndexToRelative(params[2]),
+ .operand = elem_ty,
+ });
+ const sentinel = try comptimeExpr(gz, scope, .{ .rl = .{ .coerced_ty = sentinel_ty } }, params[3], .pointer_sentinel);
+ const result = try gz.addExtendedPayload(.reify_pointer, Zir.Inst.ReifyPointer{
+ .node = gz.nodeIndexToRelative(node),
+ .size = size,
+ .attrs = attrs,
+ .elem_ty = elem_ty,
+ .sentinel = sentinel,
+ });
+ return rvalue(gz, ri, result, node);
},
+ .Fn => {
+ const fn_attrs_ty = try gz.addBuiltinValue(node, .fn_attributes);
+ const param_types = try comptimeExpr(gz, scope, .{ .rl = .{ .coerced_ty = .slice_const_type_type } }, params[0], .fn_param_types);
+ const param_attrs_ty = try gz.addExtendedPayloadSmall(
+ .reify_slice_arg_ty,
+ @intFromEnum(Zir.Inst.ReifySliceArgInfo.type_to_fn_param_attrs),
+ Zir.Inst.UnNode{ .node = gz.nodeIndexToRelative(params[0]), .operand = param_types },
+ );
+ const param_attrs = try comptimeExpr(gz, scope, .{ .rl = .{ .coerced_ty = param_attrs_ty } }, params[1], .fn_param_attrs);
+ const ret_ty = try comptimeExpr(gz, scope, coerced_type_ri, params[2], .fn_ret_ty);
+ const fn_attrs = try comptimeExpr(gz, scope, .{ .rl = .{ .coerced_ty = fn_attrs_ty } }, params[3], .fn_attrs);
+ const result = try gz.addExtendedPayload(.reify_fn, Zir.Inst.ReifyFn{
+ .node = gz.nodeIndexToRelative(node),
+ .param_types = param_types,
+ .param_attrs = param_attrs,
+ .ret_ty = ret_ty,
+ .fn_attrs = fn_attrs,
+ });
+ return rvalue(gz, ri, result, node);
+ },
+ .Struct => {
+ const container_layout_ty = try gz.addBuiltinValue(node, .container_layout);
+ const layout = try comptimeExpr(gz, scope, .{ .rl = .{ .coerced_ty = container_layout_ty } }, params[0], .struct_layout);
+ const backing_ty = try comptimeExpr(gz, scope, .{ .rl = .{ .coerced_ty = .optional_type_type } }, params[1], .type);
+ const field_names = try comptimeExpr(gz, scope, .{ .rl = .{ .coerced_ty = .slice_const_slice_const_u8_type } }, params[2], .struct_field_names);
+ const field_types_ty = try gz.addExtendedPayloadSmall(
+ .reify_slice_arg_ty,
+ @intFromEnum(Zir.Inst.ReifySliceArgInfo.string_to_struct_field_type),
+ Zir.Inst.UnNode{ .node = gz.nodeIndexToRelative(params[2]), .operand = field_names },
+ );
+ const field_attrs_ty = try gz.addExtendedPayloadSmall(
+ .reify_slice_arg_ty,
+ @intFromEnum(Zir.Inst.ReifySliceArgInfo.string_to_struct_field_attrs),
+ Zir.Inst.UnNode{ .node = gz.nodeIndexToRelative(params[2]), .operand = field_names },
+ );
+ const field_types = try comptimeExpr(gz, scope, .{ .rl = .{ .coerced_ty = field_types_ty } }, params[3], .struct_field_types);
+ const field_attrs = try comptimeExpr(gz, scope, .{ .rl = .{ .coerced_ty = field_attrs_ty } }, params[4], .struct_field_attrs);
+ const result = try gz.addExtendedPayloadSmall(.reify_struct, @intFromEnum(reify_name_strat), Zir.Inst.ReifyStruct{
+ .src_line = gz.astgen.source_line,
+ .node = node,
+ .layout = layout,
+ .backing_ty = backing_ty,
+ .field_names = field_names,
+ .field_types = field_types,
+ .field_attrs = field_attrs,
+ });
+ return rvalue(gz, ri, result, node);
+ },
+ .Union => {
+ const container_layout_ty = try gz.addBuiltinValue(node, .container_layout);
+ const layout = try comptimeExpr(gz, scope, .{ .rl = .{ .coerced_ty = container_layout_ty } }, params[0], .union_layout);
+ const arg_ty = try comptimeExpr(gz, scope, .{ .rl = .{ .coerced_ty = .optional_type_type } }, params[1], .type);
+ const field_names = try comptimeExpr(gz, scope, .{ .rl = .{ .coerced_ty = .slice_const_slice_const_u8_type } }, params[2], .union_field_names);
+ const field_types_ty = try gz.addExtendedPayloadSmall(
+ .reify_slice_arg_ty,
+ @intFromEnum(Zir.Inst.ReifySliceArgInfo.string_to_union_field_type),
+ Zir.Inst.UnNode{ .node = gz.nodeIndexToRelative(params[2]), .operand = field_names },
+ );
+ const field_attrs_ty = try gz.addExtendedPayloadSmall(
+ .reify_slice_arg_ty,
+ @intFromEnum(Zir.Inst.ReifySliceArgInfo.string_to_union_field_attrs),
+ Zir.Inst.UnNode{ .node = gz.nodeIndexToRelative(params[2]), .operand = field_names },
+ );
+ const field_types = try comptimeExpr(gz, scope, .{ .rl = .{ .coerced_ty = field_types_ty } }, params[3], .union_field_types);
+ const field_attrs = try comptimeExpr(gz, scope, .{ .rl = .{ .coerced_ty = field_attrs_ty } }, params[4], .union_field_attrs);
+ const result = try gz.addExtendedPayloadSmall(.reify_union, @intFromEnum(reify_name_strat), Zir.Inst.ReifyUnion{
+ .src_line = gz.astgen.source_line,
+ .node = node,
+ .layout = layout,
+ .arg_ty = arg_ty,
+ .field_names = field_names,
+ .field_types = field_types,
+ .field_attrs = field_attrs,
+ });
+ return rvalue(gz, ri, result, node);
+ },
+ .Enum => {
+ const enum_mode_ty = try gz.addBuiltinValue(node, .enum_mode);
+ const tag_ty = try typeExpr(gz, scope, params[0]);
+ const mode = try comptimeExpr(gz, scope, .{ .rl = .{ .coerced_ty = enum_mode_ty } }, params[1], .type);
+ const field_names = try comptimeExpr(gz, scope, .{ .rl = .{ .coerced_ty = .slice_const_slice_const_u8_type } }, params[2], .enum_field_names);
+ const field_values_ty = try gz.addExtendedPayload(.reify_enum_value_slice_ty, Zir.Inst.BinNode{
+ .node = gz.nodeIndexToRelative(node),
+ .lhs = tag_ty,
+ .rhs = field_names,
+ });
+ const field_values = try comptimeExpr(gz, scope, .{ .rl = .{ .coerced_ty = field_values_ty } }, params[3], .enum_field_values);
+ const result = try gz.addExtendedPayloadSmall(.reify_enum, @intFromEnum(reify_name_strat), Zir.Inst.ReifyEnum{
+ .src_line = gz.astgen.source_line,
+ .node = node,
+ .tag_ty = tag_ty,
+ .mode = mode,
+ .field_names = field_names,
+ .field_values = field_values,
+ });
+ return rvalue(gz, ri, result, node);
+ },
+
.panic => {
try emitDbgNode(gz, node);
return simpleUnOp(gz, scope, ri, node, .{ .rl = .{ .coerced_ty = .slice_const_u8_type } }, params[0], .panic);
@@ -9764,41 +9903,6 @@ fn builtinCall(
},
}
}
-fn builtinReify(
- gz: *GenZir,
- scope: *Scope,
- ri: ResultInfo,
- node: Ast.Node.Index,
- arg_node: Ast.Node.Index,
- name_strat: Zir.Inst.NameStrategy,
-) InnerError!Zir.Inst.Ref {
- const astgen = gz.astgen;
- const gpa = astgen.gpa;
-
- const type_info_ty = try gz.addBuiltinValue(node, .type_info);
- const operand = try expr(gz, scope, .{ .rl = .{ .coerced_ty = type_info_ty } }, arg_node);
-
- try gz.instructions.ensureUnusedCapacity(gpa, 1);
- try astgen.instructions.ensureUnusedCapacity(gpa, 1);
-
- const payload_index = try astgen.addExtra(Zir.Inst.Reify{
- .node = node, // Absolute node index -- see the definition of `Reify`.
- .operand = operand,
- .src_line = astgen.source_line,
- });
- const new_index: Zir.Inst.Index = @enumFromInt(astgen.instructions.len);
- astgen.instructions.appendAssumeCapacity(.{
- .tag = .extended,
- .data = .{ .extended = .{
- .opcode = .reify,
- .small = @intFromEnum(name_strat),
- .operand = payload_index,
- } },
- });
- gz.instructions.appendAssumeCapacity(new_index);
- const result = new_index.toRef();
- return rvalue(gz, ri, result, node);
-}
fn hasDeclOrField(
gz: *GenZir,
lib/std/zig/AstRlAnnotate.zig
@@ -866,6 +866,7 @@ fn builtinCall(astrl: *AstRlAnnotate, block: ?*Block, ri: ResultInfo, node: Ast.
// These builtins take no args and do not consume the result pointer.
.src,
.This,
+ .EnumLiteral,
.return_address,
.error_return_trace,
.frame,
@@ -906,7 +907,7 @@ fn builtinCall(astrl: *AstRlAnnotate, block: ?*Block, ri: ResultInfo, node: Ast.
.embed_file,
.error_name,
.set_runtime_safety,
- .Type,
+ .Tuple,
.c_undef,
.c_include,
.wasm_memory_size,
@@ -1058,6 +1059,48 @@ fn builtinCall(astrl: *AstRlAnnotate, block: ?*Block, ri: ResultInfo, node: Ast.
_ = try astrl.expr(args[3], block, ResultInfo.none);
return false;
},
+ .Int => {
+ _ = try astrl.expr(args[0], block, ResultInfo.type_only);
+ _ = try astrl.expr(args[1], block, ResultInfo.type_only);
+ return false;
+ },
+ .Pointer => {
+ _ = try astrl.expr(args[0], block, ResultInfo.type_only);
+ _ = try astrl.expr(args[1], block, ResultInfo.type_only);
+ _ = try astrl.expr(args[2], block, ResultInfo.type_only);
+ _ = try astrl.expr(args[3], block, ResultInfo.type_only);
+ return false;
+ },
+ .Fn => {
+ _ = try astrl.expr(args[0], block, ResultInfo.type_only);
+ _ = try astrl.expr(args[1], block, ResultInfo.type_only);
+ _ = try astrl.expr(args[2], block, ResultInfo.type_only);
+ _ = try astrl.expr(args[3], block, ResultInfo.type_only);
+ return false;
+ },
+ .Struct => {
+ _ = try astrl.expr(args[0], block, ResultInfo.type_only);
+ _ = try astrl.expr(args[1], block, ResultInfo.type_only);
+ _ = try astrl.expr(args[2], block, ResultInfo.type_only);
+ _ = try astrl.expr(args[3], block, ResultInfo.type_only);
+ _ = try astrl.expr(args[4], block, ResultInfo.type_only);
+ return false;
+ },
+ .Union => {
+ _ = try astrl.expr(args[0], block, ResultInfo.type_only);
+ _ = try astrl.expr(args[1], block, ResultInfo.type_only);
+ _ = try astrl.expr(args[2], block, ResultInfo.type_only);
+ _ = try astrl.expr(args[3], block, ResultInfo.type_only);
+ _ = try astrl.expr(args[4], block, ResultInfo.type_only);
+ return false;
+ },
+ .Enum => {
+ _ = try astrl.expr(args[0], block, ResultInfo.type_only);
+ _ = try astrl.expr(args[1], block, ResultInfo.type_only);
+ _ = try astrl.expr(args[2], block, ResultInfo.type_only);
+ _ = try astrl.expr(args[3], block, ResultInfo.type_only);
+ return false;
+ },
.Vector => {
_ = try astrl.expr(args[0], block, ResultInfo.type_only);
_ = try astrl.expr(args[1], block, ResultInfo.type_only);
lib/std/zig/BuiltinFn.zig
@@ -110,7 +110,14 @@ pub const Tag = enum {
This,
trap,
truncate,
- Type,
+ EnumLiteral,
+ Int,
+ Tuple,
+ Pointer,
+ Fn,
+ Struct,
+ Union,
+ Enum,
type_info,
type_name,
TypeOf,
@@ -937,12 +944,61 @@ pub const list = list: {
},
},
.{
- "@Type",
+ "@EnumLiteral",
.{
- .tag = .Type,
+ .tag = .EnumLiteral,
+ .param_count = 0,
+ },
+ },
+ .{
+ "@Int",
+ .{
+ .tag = .Int,
+ .param_count = 2,
+ },
+ },
+ .{
+ "@Tuple",
+ .{
+ .tag = .Tuple,
.param_count = 1,
},
},
+ .{
+ "@Pointer",
+ .{
+ .tag = .Pointer,
+ .param_count = 4,
+ },
+ },
+ .{
+ "@Fn",
+ .{
+ .tag = .Fn,
+ .param_count = 4,
+ },
+ },
+ .{
+ "@Struct",
+ .{
+ .tag = .Struct,
+ .param_count = 5,
+ },
+ },
+ .{
+ "@Union",
+ .{
+ .tag = .Union,
+ .param_count = 5,
+ },
+ },
+ .{
+ "@Enum",
+ .{
+ .tag = .Enum,
+ .param_count = 4,
+ },
+ },
.{
"@typeInfo",
.{
lib/std/zig/Zir.zig
@@ -260,6 +260,10 @@ pub const Inst = struct {
/// `[N:S]T` syntax. Source location is the array type expression node.
/// Uses the `pl_node` union field. Payload is `ArrayTypeSentinel`.
array_type_sentinel,
+ /// `@Int` builtin.
+ /// Uses the `pl_node` union field with `Bin` payload.
+ /// lhs is signedness, rhs is bit count.
+ reify_int,
/// `@Vector` builtin.
/// Uses the `pl_node` union field with `Bin` payload.
/// lhs is length, rhs is element type.
@@ -1112,6 +1116,7 @@ pub const Inst = struct {
.array_mul,
.array_type,
.array_type_sentinel,
+ .reify_int,
.vector_type,
.elem_type,
.indexable_ptr_elem_type,
@@ -1409,6 +1414,7 @@ pub const Inst = struct {
.array_mul,
.array_type,
.array_type_sentinel,
+ .reify_int,
.vector_type,
.elem_type,
.indexable_ptr_elem_type,
@@ -1644,6 +1650,7 @@ pub const Inst = struct {
.array_mul = .pl_node,
.array_type = .pl_node,
.array_type_sentinel = .pl_node,
+ .reify_int = .pl_node,
.vector_type = .pl_node,
.elem_type = .un_node,
.indexable_ptr_elem_type = .un_node,
@@ -2035,10 +2042,43 @@ pub const Inst = struct {
/// Implement builtin `@errorFromInt`.
/// `operand` is payload index to `UnNode`.
error_from_int,
- /// Implement builtin `@Type`.
- /// `operand` is payload index to `Reify`.
+ /// Given a comptime-known operand of type `[]const A`, returns the type `*const [operand.len]B`.
+ /// The types `A` and `B` are determined from `ReifySliceArgInfo`.
+ /// This instruction is used to provide result types to arguments of `@Fn`, `@Struct`, etc.
+ /// `operand` is payload index to `UnNode`.
+ /// `small` is a bitcast `ReifySliceArgInfo`.
+ reify_slice_arg_ty,
+ /// Like `reify_slice_arg_ty` for the specific case of `[]const []const u8` to `[]const TagInt`,
+ /// as needed for `@Enum`.
+ /// `operand` is payload index to `BinNode`. lhs is the type `TagInt`. rhs is the `[]const []const u8` value.
+ /// `small` is unused.
+ reify_enum_value_slice_ty,
+ /// Given a comptime-known operand of type `type`, returns the type `?operand` if possible, otherwise `?noreturn`.
+ /// Used for the final arg of `@Pointer` to allow reifying pointers to opaque types.
+ /// `operand` is payload index to `UnNode`.
+ /// `small` is unused.
+ reify_pointer_sentinel_ty,
+ /// Implements builtin `@Tuple`.
+ /// `operand` is payload index to `UnNode`.
+ reify_tuple,
+ /// Implements builtin `@Pointer`.
+ /// `operand` is payload index to `ReifyPointer`.
+ reify_pointer,
+ /// Implements builtin `@Fn`.
+ /// `operand` is payload index to `ReifyFn`.
+ reify_fn,
+ /// Implements builtin `@Struct`.
+ /// `operand` is payload index to `ReifyStruct`.
+ /// `small` contains `NameStrategy`.
+ reify_struct,
+ /// Implements builtin `@Union`.
+ /// `operand` is payload index to `ReifyUnion`.
+ /// `small` contains `NameStrategy`.
+ reify_union,
+ /// Implements builtin `@Enum`.
+ /// `operand` is payload index to `ReifyEnum`.
/// `small` contains `NameStrategy`.
- reify,
+ reify_enum,
/// Implements the `@cmpxchgStrong` and `@cmpxchgWeak` builtins.
/// `small` 0=>weak 1=>strong
/// `operand` is payload index to `Cmpxchg`.
@@ -2226,6 +2266,11 @@ pub const Inst = struct {
manyptr_const_u8_sentinel_0_type,
slice_const_u8_type,
slice_const_u8_sentinel_0_type,
+ manyptr_const_slice_const_u8_type,
+ slice_const_slice_const_u8_type,
+ optional_type_type,
+ manyptr_const_type_type,
+ slice_const_type_type,
vector_8_i8_type,
vector_16_i8_type,
vector_32_i8_type,
@@ -3169,6 +3214,23 @@ pub const Inst = struct {
rhs: Ref,
};
+ pub const ReifySliceArgInfo = enum(u16) {
+ /// Input element type is `type`.
+ /// Output element type is `std.builtin.Type.Fn.Param.Attributes`.
+ type_to_fn_param_attrs,
+ /// Input element type is `[]const u8`.
+ /// Output element type is `type`.
+ string_to_struct_field_type,
+ /// Identical to `string_to_struct_field_type` aside from emitting slightly different error messages.
+ string_to_union_field_type,
+ /// Input element type is `[]const u8`.
+ /// Output element type is `std.builtin.Type.StructField.Attributes`.
+ string_to_struct_field_attrs,
+ /// Input element type is `[]const u8`.
+ /// Output element type is `std.builtin.Type.UnionField.Attributes`.
+ string_to_union_field_attrs,
+ };
+
pub const UnNode = struct {
node: Ast.Node.Offset,
operand: Ref,
@@ -3179,12 +3241,55 @@ pub const Inst = struct {
index: u32,
};
- pub const Reify = struct {
+ pub const ReifyPointer = struct {
+ node: Ast.Node.Offset,
+ size: Ref,
+ attrs: Ref,
+ elem_ty: Ref,
+ sentinel: Ref,
+ };
+
+ pub const ReifyFn = struct {
+ node: Ast.Node.Offset,
+ param_types: Ref,
+ param_attrs: Ref,
+ ret_ty: Ref,
+ fn_attrs: Ref,
+ };
+
+ pub const ReifyStruct = struct {
+ src_line: u32,
/// This node is absolute, because `reify` instructions are tracked across updates, and
/// this simplifies the logic for getting source locations for types.
node: Ast.Node.Index,
- operand: Ref,
+ layout: Ref,
+ backing_ty: Ref,
+ field_names: Ref,
+ field_types: Ref,
+ field_attrs: Ref,
+ };
+
+ pub const ReifyUnion = struct {
src_line: u32,
+ /// This node is absolute, because `reify` instructions are tracked across updates, and
+ /// this simplifies the logic for getting source locations for types.
+ node: Ast.Node.Index,
+ layout: Ref,
+ arg_ty: Ref,
+ field_names: Ref,
+ field_types: Ref,
+ field_attrs: Ref,
+ };
+
+ pub const ReifyEnum = struct {
+ src_line: u32,
+ /// This node is absolute, because `reify` instructions are tracked across updates, and
+ /// this simplifies the logic for getting source locations for types.
+ node: Ast.Node.Index,
+ tag_ty: Ref,
+ mode: Ref,
+ field_names: Ref,
+ field_values: Ref,
};
/// Trailing:
@@ -3496,14 +3601,19 @@ pub const Inst = struct {
calling_convention,
address_space,
float_mode,
+ signedness,
reduce_op,
call_modifier,
prefetch_options,
export_options,
extern_options,
- type_info,
branch_hint,
clobbers,
+ pointer_size,
+ pointer_attributes,
+ fn_attributes,
+ container_layout,
+ enum_mode,
// Values
calling_convention_c,
calling_convention_inline,
@@ -4190,6 +4300,7 @@ fn findTrackableInner(
.array_mul,
.array_type,
.array_type_sentinel,
+ .reify_int,
.vector_type,
.elem_type,
.indexable_ptr_elem_type,
@@ -4432,6 +4543,12 @@ fn findTrackableInner(
.select,
.int_from_error,
.error_from_int,
+ .reify_slice_arg_ty,
+ .reify_enum_value_slice_ty,
+ .reify_pointer_sentinel_ty,
+ .reify_tuple,
+ .reify_pointer,
+ .reify_fn,
.cmpxchg,
.c_va_arg,
.c_va_copy,
@@ -4463,7 +4580,11 @@ fn findTrackableInner(
},
// Reifications and opaque declarations need tracking, but have no body.
- .reify, .opaque_decl => return contents.other.append(gpa, inst),
+ .reify_enum,
+ .reify_struct,
+ .reify_union,
+ .opaque_decl,
+ => return contents.other.append(gpa, inst),
// Struct declarations need tracking and have bodies.
.struct_decl => {
@@ -5246,7 +5367,9 @@ pub fn assertTrackable(zir: Zir, inst_idx: Zir.Inst.Index) void {
.union_decl,
.enum_decl,
.opaque_decl,
- .reify,
+ .reify_enum,
+ .reify_struct,
+ .reify_union,
=> {}, // tracked in order, as the owner instructions of explicit container types
else => unreachable, // assertion failure; not trackable
},
lib/std/builtin.zig
@@ -548,19 +548,19 @@ pub const TypeId = std.meta.Tag(Type);
/// This data structure is used by the Zig language code generation and
/// therefore must be kept in sync with the compiler implementation.
pub const Type = union(enum) {
- type: void,
- void: void,
- bool: void,
- noreturn: void,
+ type,
+ void,
+ bool,
+ noreturn,
int: Int,
float: Float,
pointer: Pointer,
array: Array,
@"struct": Struct,
- comptime_float: void,
- comptime_int: void,
- undefined: void,
- null: void,
+ comptime_float,
+ comptime_int,
+ undefined,
+ null,
optional: Optional,
error_union: ErrorUnion,
error_set: ErrorSet,
@@ -571,7 +571,7 @@ pub const Type = union(enum) {
frame: Frame,
@"anyframe": AnyFrame,
vector: Vector,
- enum_literal: void,
+ enum_literal,
/// This data structure is used by the Zig language code generation and
/// therefore must be kept in sync with the compiler implementation.
@@ -619,6 +619,16 @@ pub const Type = union(enum) {
slice,
c,
};
+
+ /// This data structure is used by the Zig language code generation and
+ /// therefore must be kept in sync with the compiler implementation.
+ pub const Attributes = struct {
+ @"const": bool = false,
+ @"volatile": bool = false,
+ @"allowzero": bool = false,
+ @"addrspace": ?AddressSpace = null,
+ @"align": ?usize = null,
+ };
};
/// This data structure is used by the Zig language code generation and
@@ -668,6 +678,14 @@ pub const Type = union(enum) {
const dp: *const sf.type = @ptrCast(@alignCast(sf.default_value_ptr orelse return null));
return dp.*;
}
+
+ /// This data structure is used by the Zig language code generation and
+ /// therefore must be kept in sync with the compiler implementation.
+ pub const Attributes = struct {
+ @"comptime": bool = false,
+ @"align": ?usize = null,
+ default_value_ptr: ?*const anyopaque = null,
+ };
};
/// This data structure is used by the Zig language code generation and
@@ -718,6 +736,10 @@ pub const Type = union(enum) {
fields: []const EnumField,
decls: []const Declaration,
is_exhaustive: bool,
+
+ /// This data structure is used by the Zig language code generation and
+ /// therefore must be kept in sync with the compiler implementation.
+ pub const Mode = enum { exhaustive, nonexhaustive };
};
/// This data structure is used by the Zig language code generation and
@@ -726,6 +748,12 @@ pub const Type = union(enum) {
name: [:0]const u8,
type: type,
alignment: comptime_int,
+
+ /// This data structure is used by the Zig language code generation and
+ /// therefore must be kept in sync with the compiler implementation.
+ pub const Attributes = struct {
+ @"align": ?usize = null,
+ };
};
/// This data structure is used by the Zig language code generation and
@@ -753,6 +781,19 @@ pub const Type = union(enum) {
is_generic: bool,
is_noalias: bool,
type: ?type,
+
+ /// This data structure is used by the Zig language code generation and
+ /// therefore must be kept in sync with the compiler implementation.
+ pub const Attributes = struct {
+ @"noalias": bool = false,
+ };
+ };
+
+ /// This data structure is used by the Zig language code generation and
+ /// therefore must be kept in sync with the compiler implementation.
+ pub const Attributes = struct {
+ @"callconv": CallingConvention = .auto,
+ varargs: bool = false,
};
};
lib/std/zig.zig
@@ -773,7 +773,6 @@ pub const EnvVar = enum {
pub const SimpleComptimeReason = enum(u32) {
// Evaluating at comptime because a builtin operand must be comptime-known.
// These messages all mention a specific builtin.
- operand_Type,
operand_setEvalBranchQuota,
operand_setFloatMode,
operand_branchHint,
@@ -809,25 +808,34 @@ pub const SimpleComptimeReason = enum(u32) {
// Evaluating at comptime because types must be comptime-known.
// Reasons other than `.type` are just more specific messages.
type,
+ int_signedness,
+ int_bit_width,
array_sentinel,
+ array_length,
+ pointer_size,
+ pointer_attrs,
pointer_sentinel,
slice_sentinel,
- array_length,
vector_length,
- error_set_contents,
- struct_fields,
- enum_fields,
- union_fields,
- function_ret_ty,
- function_parameters,
+ fn_ret_ty,
+ fn_param_types,
+ fn_param_attrs,
+ fn_attrs,
+ struct_layout,
+ struct_field_names,
+ struct_field_types,
+ struct_field_attrs,
+ union_layout,
+ union_field_names,
+ union_field_types,
+ union_field_attrs,
+ tuple_field_types,
+ enum_field_names,
+ enum_field_values,
// Evaluating at comptime because decl/field name must be comptime-known.
decl_name,
field_name,
- struct_field_name,
- enum_field_name,
- union_field_name,
- tuple_field_name,
tuple_field_index,
// Evaluating at comptime because it is an attribute of a global declaration.
@@ -856,7 +864,6 @@ pub const SimpleComptimeReason = enum(u32) {
pub fn message(r: SimpleComptimeReason) []const u8 {
return switch (r) {
// zig fmt: off
- .operand_Type => "operand to '@Type' must be comptime-known",
.operand_setEvalBranchQuota => "operand to '@setEvalBranchQuota' must be comptime-known",
.operand_setFloatMode => "operand to '@setFloatMode' must be comptime-known",
.operand_branchHint => "operand to '@branchHint' must be comptime-known",
@@ -888,24 +895,33 @@ pub const SimpleComptimeReason = enum(u32) {
.clobber => "clobber must be comptime-known",
.type => "types must be comptime-known",
+ .int_signedness => "integer signedness must be comptime-known",
+ .int_bit_width => "integer bit width must be comptime-known",
.array_sentinel => "array sentinel value must be comptime-known",
+ .array_length => "array length must be comptime-known",
+ .pointer_size => "pointer size must be comptime-known",
+ .pointer_attrs => "pointer attributes must be comptime-known",
.pointer_sentinel => "pointer sentinel value must be comptime-known",
.slice_sentinel => "slice sentinel value must be comptime-known",
- .array_length => "array length must be comptime-known",
.vector_length => "vector length must be comptime-known",
- .error_set_contents => "error set contents must be comptime-known",
- .struct_fields => "struct fields must be comptime-known",
- .enum_fields => "enum fields must be comptime-known",
- .union_fields => "union fields must be comptime-known",
- .function_ret_ty => "function return type must be comptime-known",
- .function_parameters => "function parameters must be comptime-known",
+ .fn_ret_ty => "function return type must be comptime-known",
+ .fn_param_types => "function parameter types must be comptime-known",
+ .fn_param_attrs => "function parameter attributes must be comptime-known",
+ .fn_attrs => "function attributes must be comptime-known",
+ .struct_layout => "struct layout must be comptime-known",
+ .struct_field_names => "struct field names must be comptime-known",
+ .struct_field_types => "struct field types must be comptime-known",
+ .struct_field_attrs => "struct field attributes must be comptime-known",
+ .union_layout => "union layout must be comptime-known",
+ .union_field_names => "union field names must be comptime-known",
+ .union_field_types => "union field types must be comptime-known",
+ .union_field_attrs => "union field attributes must be comptime-known",
+ .tuple_field_types => "tuple field types must be comptime-known",
+ .enum_field_names => "enum field names must be comptime-known",
+ .enum_field_values => "enum field values must be comptime-known",
.decl_name => "declaration name must be comptime-known",
.field_name => "field name must be comptime-known",
- .struct_field_name => "struct field name must be comptime-known",
- .enum_field_name => "enum field name must be comptime-known",
- .union_field_name => "union field name must be comptime-known",
- .tuple_field_name => "tuple field name must be comptime-known",
.tuple_field_index => "tuple field index must be comptime-known",
.container_var_init => "initializer of container-level variable must be comptime-known",
src/codegen/c/Type.zig
@@ -1416,6 +1416,9 @@ pub const Pool = struct {
.null_type,
.undefined_type,
.enum_literal_type,
+ .optional_type_type,
+ .manyptr_const_type_type,
+ .slice_const_type_type,
=> return .void,
.u1_type, .u8_type => return .u8,
.i8_type => return .i8,
@@ -1525,6 +1528,73 @@ pub const Pool = struct {
return pool.fromFields(allocator, .@"struct", &fields, kind);
},
+ .manyptr_const_slice_const_u8_type => {
+ const target = &mod.resolved_target.result;
+ var fields: [2]Info.Field = .{
+ .{
+ .name = .{ .index = .ptr },
+ .ctype = try pool.getPointer(allocator, .{
+ .elem_ctype = .u8,
+ .@"const" = true,
+ .nonstring = true,
+ }),
+ .alignas = AlignAs.fromAbiAlignment(Type.ptrAbiAlignment(target)),
+ },
+ .{
+ .name = .{ .index = .len },
+ .ctype = .usize,
+ .alignas = AlignAs.fromAbiAlignment(
+ .fromByteUnits(std.zig.target.intAlignment(target, target.ptrBitWidth())),
+ ),
+ },
+ };
+ const slice_const_u8 = try pool.fromFields(allocator, .@"struct", &fields, kind);
+ return pool.getPointer(allocator, .{
+ .elem_ctype = slice_const_u8,
+ .@"const" = true,
+ });
+ },
+ .slice_const_slice_const_u8_type => {
+ const target = &mod.resolved_target.result;
+ var fields: [2]Info.Field = .{
+ .{
+ .name = .{ .index = .ptr },
+ .ctype = try pool.getPointer(allocator, .{
+ .elem_ctype = .u8,
+ .@"const" = true,
+ .nonstring = true,
+ }),
+ .alignas = AlignAs.fromAbiAlignment(Type.ptrAbiAlignment(target)),
+ },
+ .{
+ .name = .{ .index = .len },
+ .ctype = .usize,
+ .alignas = AlignAs.fromAbiAlignment(
+ .fromByteUnits(std.zig.target.intAlignment(target, target.ptrBitWidth())),
+ ),
+ },
+ };
+ const slice_const_u8 = try pool.fromFields(allocator, .@"struct", &fields, .forward);
+ fields = .{
+ .{
+ .name = .{ .index = .ptr },
+ .ctype = try pool.getPointer(allocator, .{
+ .elem_ctype = slice_const_u8,
+ .@"const" = true,
+ }),
+ .alignas = AlignAs.fromAbiAlignment(Type.ptrAbiAlignment(target)),
+ },
+ .{
+ .name = .{ .index = .len },
+ .ctype = .usize,
+ .alignas = AlignAs.fromAbiAlignment(
+ .fromByteUnits(std.zig.target.intAlignment(target, target.ptrBitWidth())),
+ ),
+ },
+ };
+ return pool.fromFields(allocator, .@"struct", &fields, kind);
+ },
+
.vector_8_i8_type => {
const vector_ctype = try pool.getVector(allocator, .{
.elem_ctype = .i8,
src/link/Dwarf.zig
@@ -4490,7 +4490,12 @@ fn updateContainerTypeWriterError(
.enum_decl => @as(Zir.Inst.EnumDecl.Small, @bitCast(decl_inst.data.extended.small)).name_strategy,
.union_decl => @as(Zir.Inst.UnionDecl.Small, @bitCast(decl_inst.data.extended.small)).name_strategy,
.opaque_decl => @as(Zir.Inst.OpaqueDecl.Small, @bitCast(decl_inst.data.extended.small)).name_strategy,
- .reify => @as(Zir.Inst.NameStrategy, @enumFromInt(decl_inst.data.extended.small)),
+
+ .reify_enum,
+ .reify_struct,
+ .reify_union,
+ => @enumFromInt(decl_inst.data.extended.small),
+
else => unreachable,
},
else => unreachable,
src/Air.zig
@@ -1062,6 +1062,11 @@ pub const Inst = struct {
manyptr_const_u8_sentinel_0_type = @intFromEnum(InternPool.Index.manyptr_const_u8_sentinel_0_type),
slice_const_u8_type = @intFromEnum(InternPool.Index.slice_const_u8_type),
slice_const_u8_sentinel_0_type = @intFromEnum(InternPool.Index.slice_const_u8_sentinel_0_type),
+ manyptr_const_slice_const_u8_type = @intFromEnum(InternPool.Index.manyptr_const_slice_const_u8_type),
+ slice_const_slice_const_u8_type = @intFromEnum(InternPool.Index.slice_const_slice_const_u8_type),
+ optional_type_type = @intFromEnum(InternPool.Index.optional_type_type),
+ manyptr_const_type_type = @intFromEnum(InternPool.Index.manyptr_const_type_type),
+ slice_const_type_type = @intFromEnum(InternPool.Index.slice_const_type_type),
vector_8_i8_type = @intFromEnum(InternPool.Index.vector_8_i8_type),
vector_16_i8_type = @intFromEnum(InternPool.Index.vector_16_i8_type),
vector_32_i8_type = @intFromEnum(InternPool.Index.vector_32_i8_type),
src/InternPool.zig
@@ -2017,8 +2017,7 @@ pub const Key = union(enum) {
error_union_type: ErrorUnionType,
simple_type: SimpleType,
/// This represents a struct that has been explicitly declared in source code,
- /// or was created with `@Type`. It is unique and based on a declaration.
- /// It may be a tuple, if declared like this: `struct {A, B, C}`.
+ /// or was created with `@Struct`. It is unique and based on a declaration.
struct_type: NamespaceType,
/// This is a tuple type. Tuples are logically similar to structs, but have some
/// important differences in semantics; they do not undergo staged type resolution,
@@ -2175,7 +2174,7 @@ pub const Key = union(enum) {
/// The union for which this is a tag type.
union_type: Index,
},
- /// This type originates from a reification via `@Type`, or from an anonymous initialization.
+ /// This type originates from a reification via `@Enum`, `@Struct`, `@Union` or from an anonymous initialization.
/// It is hashed based on its ZIR instruction index and fields, attributes, etc.
/// To avoid making this key overly complex, the type-specific data is hashed by Sema.
reified: struct {
@@ -4641,6 +4640,13 @@ pub const Index = enum(u32) {
slice_const_u8_type,
slice_const_u8_sentinel_0_type,
+ manyptr_const_slice_const_u8_type,
+ slice_const_slice_const_u8_type,
+
+ optional_type_type,
+ manyptr_const_type_type,
+ slice_const_type_type,
+
vector_8_i8_type,
vector_16_i8_type,
vector_32_i8_type,
@@ -5201,6 +5207,45 @@ pub const static_keys: [static_len]Key = .{
},
} },
+ // [*]const []const u8
+ .{ .ptr_type = .{
+ .child = .slice_const_u8_type,
+ .flags = .{
+ .size = .many,
+ .is_const = true,
+ },
+ } },
+
+ // []const []const u8
+ .{ .ptr_type = .{
+ .child = .slice_const_u8_type,
+ .flags = .{
+ .size = .slice,
+ .is_const = true,
+ },
+ } },
+
+ // ?type
+ .{ .opt_type = .type_type },
+
+ // [*]const type
+ .{ .ptr_type = .{
+ .child = .type_type,
+ .flags = .{
+ .size = .many,
+ .is_const = true,
+ },
+ } },
+
+ // []const type
+ .{ .ptr_type = .{
+ .child = .type_type,
+ .flags = .{
+ .size = .slice,
+ .is_const = true,
+ },
+ } },
+
// @Vector(8, i8)
.{ .vector_type = .{ .len = 8, .child = .i8_type } },
// @Vector(16, i8)
@@ -10225,16 +10270,8 @@ pub fn getGeneratedTagEnumType(
}
pub const OpaqueTypeInit = struct {
- key: union(enum) {
- declared: struct {
- zir_index: TrackedInst.Index,
- captures: []const CaptureValue,
- },
- reified: struct {
- zir_index: TrackedInst.Index,
- // No type hash since reifid opaques have no data other than the `@Type` location
- },
- },
+ zir_index: TrackedInst.Index,
+ captures: []const CaptureValue,
};
pub fn getOpaqueType(
@@ -10243,16 +10280,10 @@ pub fn getOpaqueType(
tid: Zcu.PerThread.Id,
ini: OpaqueTypeInit,
) Allocator.Error!WipNamespaceType.Result {
- var gop = try ip.getOrPutKey(gpa, tid, .{ .opaque_type = switch (ini.key) {
- .declared => |d| .{ .declared = .{
- .zir_index = d.zir_index,
- .captures = .{ .external = d.captures },
- } },
- .reified => |r| .{ .reified = .{
- .zir_index = r.zir_index,
- .type_hash = 0,
- } },
- } });
+ var gop = try ip.getOrPutKey(gpa, tid, .{ .opaque_type = .{ .declared = .{
+ .zir_index = ini.zir_index,
+ .captures = .{ .external = ini.captures },
+ } } });
defer gop.deinit();
if (gop == .existing) return .{ .existing = gop.existing };
@@ -10261,30 +10292,19 @@ pub fn getOpaqueType(
const extra = local.getMutableExtra(gpa);
try items.ensureUnusedCapacity(1);
- try extra.ensureUnusedCapacity(@typeInfo(Tag.TypeOpaque).@"struct".fields.len + switch (ini.key) {
- .declared => |d| d.captures.len,
- .reified => 0,
- });
+ try extra.ensureUnusedCapacity(@typeInfo(Tag.TypeOpaque).@"struct".fields.len + ini.captures.len);
const extra_index = addExtraAssumeCapacity(extra, Tag.TypeOpaque{
.name = undefined, // set by `finish`
.name_nav = undefined, // set by `finish`
.namespace = undefined, // set by `finish`
- .zir_index = switch (ini.key) {
- inline else => |x| x.zir_index,
- },
- .captures_len = switch (ini.key) {
- .declared => |d| @intCast(d.captures.len),
- .reified => std.math.maxInt(u32),
- },
+ .zir_index = ini.zir_index,
+ .captures_len = @intCast(ini.captures.len),
});
items.appendAssumeCapacity(.{
.tag = .type_opaque,
.data = extra_index,
});
- switch (ini.key) {
- .declared => |d| extra.appendSliceAssumeCapacity(.{@ptrCast(d.captures)}),
- .reified => {},
- }
+ extra.appendSliceAssumeCapacity(.{@ptrCast(ini.captures)});
return .{
.wip = .{
.tid = tid,
@@ -10555,6 +10575,8 @@ pub fn slicePtrType(ip: *const InternPool, index: Index) Index {
switch (index) {
.slice_const_u8_type => return .manyptr_const_u8_type,
.slice_const_u8_sentinel_0_type => return .manyptr_const_u8_sentinel_0_type,
+ .slice_const_slice_const_u8_type => return .manyptr_const_slice_const_u8_type,
+ .slice_const_type_type => return .manyptr_const_type_type,
else => {},
}
const item = index.unwrap(ip).getItem(ip);
@@ -12013,8 +12035,13 @@ pub fn typeOf(ip: *const InternPool, index: Index) Index {
.manyptr_u8_type,
.manyptr_const_u8_type,
.manyptr_const_u8_sentinel_0_type,
+ .manyptr_const_slice_const_u8_type,
.slice_const_u8_type,
.slice_const_u8_sentinel_0_type,
+ .slice_const_slice_const_u8_type,
+ .optional_type_type,
+ .manyptr_const_type_type,
+ .slice_const_type_type,
.vector_8_i8_type,
.vector_16_i8_type,
.vector_32_i8_type,
@@ -12355,8 +12382,12 @@ pub fn zigTypeTag(ip: *const InternPool, index: Index) std.builtin.TypeId {
.manyptr_u8_type,
.manyptr_const_u8_type,
.manyptr_const_u8_sentinel_0_type,
+ .manyptr_const_slice_const_u8_type,
.slice_const_u8_type,
.slice_const_u8_sentinel_0_type,
+ .slice_const_slice_const_u8_type,
+ .manyptr_const_type_type,
+ .slice_const_type_type,
=> .pointer,
.vector_8_i8_type,
@@ -12408,6 +12439,7 @@ pub fn zigTypeTag(ip: *const InternPool, index: Index) std.builtin.TypeId {
.vector_8_f64_type,
=> .vector,
+ .optional_type_type => .optional,
.optional_noreturn_type => .optional,
.anyerror_void_error_union_type => .error_union,
.empty_tuple_type => .@"struct",
src/print_zir.zig
@@ -399,6 +399,7 @@ const Writer = struct {
.splat,
.reduce,
.bitcast,
+ .reify_int,
.vector_type,
.max,
.min,
@@ -568,6 +569,8 @@ const Writer = struct {
.work_group_id,
.branch_hint,
.float_op_result_ty,
+ .reify_tuple,
+ .reify_pointer_sentinel_ty,
=> {
const inst_data = self.code.extraData(Zir.Inst.UnNode, extended.operand).data;
try self.writeInstRef(stream, inst_data.operand);
@@ -575,23 +578,13 @@ const Writer = struct {
try self.writeSrcNode(stream, inst_data.node);
},
- .reify => {
- const inst_data = self.code.extraData(Zir.Inst.Reify, extended.operand).data;
- try stream.print("line({d}), ", .{inst_data.src_line});
- try self.writeInstRef(stream, inst_data.operand);
- try stream.writeAll(")) ");
- const prev_parent_decl_node = self.parent_decl_node;
- self.parent_decl_node = inst_data.node;
- defer self.parent_decl_node = prev_parent_decl_node;
- try self.writeSrcNode(stream, .zero);
- },
-
.builtin_extern,
.c_define,
.error_cast,
.wasm_memory_grow,
.prefetch,
.c_va_arg,
+ .reify_enum_value_slice_ty,
=> {
const inst_data = self.code.extraData(Zir.Inst.BinNode, extended.operand).data;
try self.writeInstRef(stream, inst_data.lhs);
@@ -601,6 +594,95 @@ const Writer = struct {
try self.writeSrcNode(stream, inst_data.node);
},
+ .reify_slice_arg_ty => {
+ const reify_slice_arg_info: Zir.Inst.ReifySliceArgInfo = @enumFromInt(extended.operand);
+ const extra = self.code.extraData(Zir.Inst.UnNode, extended.operand).data;
+ try stream.print("{t}, ", .{reify_slice_arg_info});
+ try self.writeInstRef(stream, extra.operand);
+ try stream.writeAll(")) ");
+ try self.writeSrcNode(stream, extra.node);
+ },
+
+ .reify_pointer => {
+ const extra = self.code.extraData(Zir.Inst.ReifyPointer, extended.operand).data;
+ try self.writeInstRef(stream, extra.size);
+ try stream.writeAll(", ");
+ try self.writeInstRef(stream, extra.attrs);
+ try stream.writeAll(", ");
+ try self.writeInstRef(stream, extra.elem_ty);
+ try stream.writeAll(", ");
+ try self.writeInstRef(stream, extra.sentinel);
+ try stream.writeAll(")) ");
+ try self.writeSrcNode(stream, extra.node);
+ },
+ .reify_fn => {
+ const extra = self.code.extraData(Zir.Inst.ReifyFn, extended.operand).data;
+ try self.writeInstRef(stream, extra.param_types);
+ try stream.writeAll(", ");
+ try self.writeInstRef(stream, extra.param_attrs);
+ try stream.writeAll(", ");
+ try self.writeInstRef(stream, extra.ret_ty);
+ try stream.writeAll(", ");
+ try self.writeInstRef(stream, extra.fn_attrs);
+ try stream.writeAll(")) ");
+ try self.writeSrcNode(stream, extra.node);
+ },
+ .reify_struct => {
+ const extra = self.code.extraData(Zir.Inst.ReifyStruct, extended.operand).data;
+ const name_strat: Zir.Inst.NameStrategy = @enumFromInt(extended.small);
+ try stream.print("line({d}), {t}, ", .{ extra.src_line, name_strat });
+ try self.writeInstRef(stream, extra.layout);
+ try stream.writeAll(", ");
+ try self.writeInstRef(stream, extra.backing_ty);
+ try stream.writeAll(", ");
+ try self.writeInstRef(stream, extra.field_names);
+ try stream.writeAll(", ");
+ try self.writeInstRef(stream, extra.field_types);
+ try stream.writeAll(", ");
+ try self.writeInstRef(stream, extra.field_attrs);
+ try stream.writeAll(")) ");
+ const prev_parent_decl_node = self.parent_decl_node;
+ self.parent_decl_node = extra.node;
+ defer self.parent_decl_node = prev_parent_decl_node;
+ try self.writeSrcNode(stream, .zero);
+ },
+ .reify_union => {
+ const extra = self.code.extraData(Zir.Inst.ReifyUnion, extended.operand).data;
+ const name_strat: Zir.Inst.NameStrategy = @enumFromInt(extended.small);
+ try stream.print("line({d}), {t}, ", .{ extra.src_line, name_strat });
+ try self.writeInstRef(stream, extra.layout);
+ try stream.writeAll(", ");
+ try self.writeInstRef(stream, extra.arg_ty);
+ try stream.writeAll(", ");
+ try self.writeInstRef(stream, extra.field_names);
+ try stream.writeAll(", ");
+ try self.writeInstRef(stream, extra.field_types);
+ try stream.writeAll(", ");
+ try self.writeInstRef(stream, extra.field_attrs);
+ try stream.writeAll(")) ");
+ const prev_parent_decl_node = self.parent_decl_node;
+ self.parent_decl_node = extra.node;
+ defer self.parent_decl_node = prev_parent_decl_node;
+ try self.writeSrcNode(stream, .zero);
+ },
+ .reify_enum => {
+ const extra = self.code.extraData(Zir.Inst.ReifyEnum, extended.operand).data;
+ const name_strat: Zir.Inst.NameStrategy = @enumFromInt(extended.small);
+ try stream.print("line({d}), {t}, ", .{ extra.src_line, name_strat });
+ try self.writeInstRef(stream, extra.tag_ty);
+ try stream.writeAll(", ");
+ try self.writeInstRef(stream, extra.mode);
+ try stream.writeAll(", ");
+ try self.writeInstRef(stream, extra.field_names);
+ try stream.writeAll(", ");
+ try self.writeInstRef(stream, extra.field_values);
+ try stream.writeAll(")) ");
+ const prev_parent_decl_node = self.parent_decl_node;
+ self.parent_decl_node = extra.node;
+ defer self.parent_decl_node = prev_parent_decl_node;
+ try self.writeSrcNode(stream, .zero);
+ },
+
.cmpxchg => try self.writeCmpxchg(stream, extended),
.ptr_cast_full => try self.writePtrCastFull(stream, extended),
.ptr_cast_no_dest => try self.writePtrCastNoDest(stream, extended),
src/Sema.zig
@@ -1167,6 +1167,7 @@ fn analyzeBodyInner(
.array_mul => try sema.zirArrayMul(block, inst),
.array_type => try sema.zirArrayType(block, inst),
.array_type_sentinel => try sema.zirArrayTypeSentinel(block, inst),
+ .reify_int => try sema.zirReifyInt(block, inst),
.vector_type => try sema.zirVectorType(block, inst),
.as_node => try sema.zirAsNode(block, inst),
.as_shift_operand => try sema.zirAsShiftOperand(block, inst),
@@ -1411,7 +1412,6 @@ fn analyzeBodyInner(
.select => try sema.zirSelect( block, extended),
.int_from_error => try sema.zirIntFromError( block, extended),
.error_from_int => try sema.zirErrorFromInt( block, extended),
- .reify => try sema.zirReify( block, extended, inst),
.cmpxchg => try sema.zirCmpxchg( block, extended),
.c_va_arg => try sema.zirCVaArg( block, extended),
.c_va_copy => try sema.zirCVaCopy( block, extended),
@@ -1424,6 +1424,16 @@ fn analyzeBodyInner(
.work_group_id => try sema.zirWorkItem( block, extended, extended.opcode),
.in_comptime => try sema.zirInComptime( block),
.closure_get => try sema.zirClosureGet( block, extended),
+
+ .reify_slice_arg_ty => try sema.zirReifySliceArgTy( block, extended),
+ .reify_enum_value_slice_ty => try sema.zirReifyEnumValueSliceTy(block, extended),
+ .reify_pointer_sentinel_ty => try sema.zirReifyPointerSentinelTy(block, extended),
+ .reify_tuple => try sema.zirReifyTuple( block, extended),
+ .reify_pointer => try sema.zirReifyPointer( block, extended),
+ .reify_fn => try sema.zirReifyFn( block, extended),
+ .reify_struct => try sema.zirReifyStruct( block, extended, inst),
+ .reify_union => try sema.zirReifyUnion( block, extended, inst),
+ .reify_enum => try sema.zirReifyEnum( block, extended, inst),
// zig fmt: on
.set_float_mode => {
@@ -3517,10 +3527,8 @@ fn zirOpaqueDecl(
extra_index += captures_len * 2;
const opaque_init: InternPool.OpaqueTypeInit = .{
- .key = .{ .declared = .{
- .zir_index = tracked_inst,
- .captures = captures,
- } },
+ .zir_index = tracked_inst,
+ .captures = captures,
};
const wip_ty = switch (try ip.getOpaqueType(gpa, pt.tid, opaque_init)) {
.existing => |ty| {
@@ -7386,7 +7394,7 @@ fn analyzeCall(
const body = sema.code.bodySlice(extra.end, extra.data.type.body_len);
generic_block.comptime_reason = .{ .reason = .{
- .r = .{ .simple = .function_parameters },
+ .r = .{ .simple = .fn_param_types },
.src = param_src,
} };
@@ -7470,7 +7478,7 @@ fn analyzeCall(
sema.inst_map = generic_inst_map;
generic_block.comptime_reason = .{ .reason = .{
- .r = .{ .simple = .function_ret_ty },
+ .r = .{ .simple = .fn_ret_ty },
.src = func_ret_ty_src,
} };
@@ -8927,7 +8935,7 @@ fn zirFunc(
const ret_ty_body = sema.code.bodySlice(extra_index, extra.data.ret_ty.body_len);
extra_index += ret_ty_body.len;
- const ret_ty_val = try sema.resolveGenericBody(block, ret_ty_src, ret_ty_body, inst, .type, .{ .simple = .function_ret_ty });
+ const ret_ty_val = try sema.resolveGenericBody(block, ret_ty_src, ret_ty_body, inst, .type, .{ .simple = .fn_ret_ty });
break :blk ret_ty_val.toType();
},
};
@@ -9171,6 +9179,181 @@ fn checkCallConvSupportsVarArgs(sema: *Sema, block: *Block, src: LazySrcLoc, cc:
}
}
+fn checkParamTypeCommon(
+ sema: *Sema,
+ block: *Block,
+ param_idx: u32,
+ param_ty: Type,
+ param_is_noalias: bool,
+ param_src: LazySrcLoc,
+ cc: std.builtin.CallingConvention,
+) CompileError!void {
+ const pt = sema.pt;
+ const zcu = pt.zcu;
+ const target = zcu.getTarget();
+
+ if (!param_ty.isValidParamType(zcu)) {
+ const opaque_str = if (param_ty.zigTypeTag(zcu) == .@"opaque") "opaque " else "";
+ return sema.fail(block, param_src, "parameter of {s}type '{f}' not allowed", .{
+ opaque_str, param_ty.fmt(pt),
+ });
+ }
+ if (!param_ty.isGenericPoison() and
+ !target_util.fnCallConvAllowsZigTypes(cc) and
+ !try sema.validateExternType(param_ty, .param_ty))
+ {
+ return sema.failWithOwnedErrorMsg(block, msg: {
+ const msg = try sema.errMsg(param_src, "parameter of type '{f}' not allowed in function with calling convention '{s}'", .{
+ param_ty.fmt(pt), @tagName(cc),
+ });
+ errdefer msg.destroy(sema.gpa);
+
+ try sema.explainWhyTypeIsNotExtern(msg, param_src, param_ty, .param_ty);
+
+ try sema.addDeclaredHereNote(msg, param_ty);
+ break :msg msg;
+ });
+ }
+ switch (cc) {
+ .x86_64_interrupt, .x86_interrupt => {
+ const err_code_size = target.ptrBitWidth();
+ switch (param_idx) {
+ 0 => if (param_ty.zigTypeTag(zcu) != .pointer) return sema.fail(block, param_src, "first parameter of function with '{s}' calling convention must be a pointer type", .{@tagName(cc)}),
+ 1 => if (param_ty.bitSize(zcu) != err_code_size) return sema.fail(block, param_src, "second parameter of function with '{s}' calling convention must be a {d}-bit integer", .{ @tagName(cc), err_code_size }),
+ else => return sema.fail(block, param_src, "'{s}' calling convention supports up to 2 parameters, found {d}", .{ @tagName(cc), param_idx + 1 }),
+ }
+ },
+ .arc_interrupt,
+ .arm_interrupt,
+ .microblaze_interrupt,
+ .mips64_interrupt,
+ .mips_interrupt,
+ .riscv64_interrupt,
+ .riscv32_interrupt,
+ .sh_interrupt,
+ .avr_interrupt,
+ .csky_interrupt,
+ .m68k_interrupt,
+ .msp430_interrupt,
+ .avr_signal,
+ => return sema.fail(block, param_src, "parameters are not allowed with '{s}' calling convention", .{@tagName(cc)}),
+ else => {},
+ }
+ if (param_is_noalias and !param_ty.isGenericPoison() and !param_ty.isPtrAtRuntime(zcu) and !param_ty.isSliceAtRuntime(zcu)) {
+ return sema.fail(block, param_src, "non-pointer parameter declared noalias", .{});
+ }
+}
+
+fn checkReturnTypeAndCallConvCommon(
+ sema: *Sema,
+ block: *Block,
+ bare_ret_ty: Type,
+ ret_ty_src: LazySrcLoc,
+ @"callconv": std.builtin.CallingConvention,
+ callconv_src: LazySrcLoc,
+ /// non-`null` only if the function is varargs.
+ opt_varargs_src: ?LazySrcLoc,
+ inferred_error_set: bool,
+ is_noinline: bool,
+) CompileError!void {
+ const pt = sema.pt;
+ const zcu = pt.zcu;
+ const gpa = zcu.gpa;
+ if (opt_varargs_src) |varargs_src| {
+ try sema.checkCallConvSupportsVarArgs(block, varargs_src, @"callconv");
+ }
+ if (inferred_error_set and !bare_ret_ty.isGenericPoison()) {
+ try sema.validateErrorUnionPayloadType(block, bare_ret_ty, ret_ty_src);
+ }
+ const ies_ret_ty_prefix: []const u8 = if (inferred_error_set) "!" else "";
+ if (!bare_ret_ty.isValidReturnType(zcu)) {
+ const opaque_str = if (bare_ret_ty.zigTypeTag(zcu) == .@"opaque") "opaque " else "";
+ return sema.fail(block, ret_ty_src, "{s}return type '{s}{f}' not allowed", .{
+ opaque_str, ies_ret_ty_prefix, bare_ret_ty.fmt(pt),
+ });
+ }
+ if (!bare_ret_ty.isGenericPoison() and
+ !target_util.fnCallConvAllowsZigTypes(@"callconv") and
+ (inferred_error_set or !try sema.validateExternType(bare_ret_ty, .ret_ty)))
+ {
+ return sema.failWithOwnedErrorMsg(block, msg: {
+ const msg = try sema.errMsg(ret_ty_src, "return type '{s}{f}' not allowed in function with calling convention '{s}'", .{
+ ies_ret_ty_prefix, bare_ret_ty.fmt(pt), @tagName(@"callconv"),
+ });
+ errdefer msg.destroy(gpa);
+ if (!inferred_error_set) {
+ try sema.explainWhyTypeIsNotExtern(msg, ret_ty_src, bare_ret_ty, .ret_ty);
+ try sema.addDeclaredHereNote(msg, bare_ret_ty);
+ }
+ break :msg msg;
+ });
+ }
+ validate_incoming_stack_align: {
+ const a: u64 = switch (@"callconv") {
+ inline else => |payload| if (@TypeOf(payload) != void and @hasField(@TypeOf(payload), "incoming_stack_alignment"))
+ payload.incoming_stack_alignment orelse break :validate_incoming_stack_align
+ else
+ break :validate_incoming_stack_align,
+ };
+ if (!std.math.isPowerOfTwo(a)) {
+ return sema.fail(block, callconv_src, "calling convention incoming stack alignment '{d}' is not a power of two", .{a});
+ }
+ }
+ switch (@"callconv") {
+ .x86_64_interrupt,
+ .x86_interrupt,
+ .arm_interrupt,
+ .mips64_interrupt,
+ .mips_interrupt,
+ .riscv64_interrupt,
+ .riscv32_interrupt,
+ .sh_interrupt,
+ .arc_interrupt,
+ .avr_interrupt,
+ .csky_interrupt,
+ .m68k_interrupt,
+ .microblaze_interrupt,
+ .msp430_interrupt,
+ .avr_signal,
+ => {
+ const ret_ok = !inferred_error_set and switch (bare_ret_ty.toIntern()) {
+ .void_type, .noreturn_type => true,
+ else => false,
+ };
+ if (!ret_ok) {
+ return sema.fail(block, ret_ty_src, "function with calling convention '{s}' must return 'void' or 'noreturn'", .{@tagName(@"callconv")});
+ }
+ },
+ .@"inline" => if (is_noinline) {
+ return sema.fail(block, callconv_src, "'noinline' function cannot have calling convention 'inline'", .{});
+ },
+ else => {},
+ }
+ switch (zcu.callconvSupported(@"callconv")) {
+ .ok => {},
+ .bad_arch => |allowed_archs| {
+ const ArchListFormatter = struct {
+ archs: []const std.Target.Cpu.Arch,
+ pub fn format(formatter: @This(), w: *std.Io.Writer) std.Io.Writer.Error!void {
+ for (formatter.archs, 0..) |arch, i| {
+ if (i != 0)
+ try w.writeAll(", ");
+ try w.print("'{s}'", .{@tagName(arch)});
+ }
+ }
+ };
+ return sema.fail(block, callconv_src, "calling convention '{s}' only available on architectures {f}", .{
+ @tagName(@"callconv"),
+ ArchListFormatter{ .archs = allowed_archs },
+ });
+ },
+ .bad_backend => |bad_backend| return sema.fail(block, callconv_src, "calling convention '{s}' not supported by compiler backend '{s}'", .{
+ @tagName(@"callconv"),
+ @tagName(bad_backend),
+ }),
+ }
+}
+
fn callConvIsCallable(cc: std.builtin.CallingConvention.Tag) bool {
return switch (cc) {
.naked,
@@ -9259,7 +9442,6 @@ fn funcCommon(
const pt = sema.pt;
const zcu = pt.zcu;
const gpa = sema.gpa;
- const target = zcu.getTarget();
const ip = &zcu.intern_pool;
const ret_ty_src = block.src(.{ .node_offset_fn_type_ret_ty = src_node_offset });
const cc_src = block.src(.{ .node_offset_fn_type_cc = src_node_offset });
@@ -9293,26 +9475,14 @@ fn funcCommon(
if (param_ty_generic and !target_util.fnCallConvAllowsZigTypes(cc)) {
return sema.fail(block, param_src, "generic parameters not allowed in function with calling convention '{s}'", .{@tagName(cc)});
}
- if (!param_ty.isValidParamType(zcu)) {
- const opaque_str = if (param_ty.zigTypeTag(zcu) == .@"opaque") "opaque " else "";
- return sema.fail(block, param_src, "parameter of {s}type '{f}' not allowed", .{
- opaque_str, param_ty.fmt(pt),
- });
- }
- if (!param_ty_generic and !target_util.fnCallConvAllowsZigTypes(cc) and !try sema.validateExternType(param_ty, .param_ty)) {
- const msg = msg: {
- const msg = try sema.errMsg(param_src, "parameter of type '{f}' not allowed in function with calling convention '{s}'", .{
- param_ty.fmt(pt), @tagName(cc),
- });
- errdefer msg.destroy(sema.gpa);
-
- try sema.explainWhyTypeIsNotExtern(msg, param_src, param_ty, .param_ty);
-
- try sema.addDeclaredHereNote(msg, param_ty);
- break :msg msg;
- };
- return sema.failWithOwnedErrorMsg(block, msg);
- }
+ try sema.checkParamTypeCommon(
+ block,
+ @intCast(i),
+ param_ty,
+ is_noalias,
+ param_src,
+ cc,
+ );
if (param_ty_comptime and !param_is_comptime and has_body and !block.isComptime()) {
const msg = msg: {
const msg = try sema.errMsg(param_src, "parameter of type '{f}' must be declared comptime", .{
@@ -9327,209 +9497,40 @@ fn funcCommon(
};
return sema.failWithOwnedErrorMsg(block, msg);
}
- if (!param_ty_generic and is_noalias and
- !(param_ty.zigTypeTag(zcu) == .pointer or param_ty.isPtrLikeOptional(zcu)))
- {
- return sema.fail(block, param_src, "non-pointer parameter declared noalias", .{});
- }
- switch (cc) {
- .x86_64_interrupt, .x86_interrupt => {
- const err_code_size = target.ptrBitWidth();
- switch (i) {
- 0 => if (param_ty.zigTypeTag(zcu) != .pointer) return sema.fail(block, param_src, "first parameter of function with '{s}' calling convention must be a pointer type", .{@tagName(cc)}),
- 1 => if (param_ty.bitSize(zcu) != err_code_size) return sema.fail(block, param_src, "second parameter of function with '{s}' calling convention must be a {d}-bit integer", .{ @tagName(cc), err_code_size }),
- else => return sema.fail(block, param_src, "'{s}' calling convention supports up to 2 parameters, found {d}", .{ @tagName(cc), i + 1 }),
- }
- },
- .arc_interrupt,
- .arm_interrupt,
- .microblaze_interrupt,
- .mips64_interrupt,
- .mips_interrupt,
- .riscv64_interrupt,
- .riscv32_interrupt,
- .sh_interrupt,
- .avr_interrupt,
- .csky_interrupt,
- .m68k_interrupt,
- .msp430_interrupt,
- .avr_signal,
- => return sema.fail(block, param_src, "parameters are not allowed with '{s}' calling convention", .{@tagName(cc)}),
- else => {},
- }
- }
-
- if (var_args) {
- if (is_generic) {
- return sema.fail(block, func_src, "generic function cannot be variadic", .{});
- }
- const va_args_src = block.src(.{
- .fn_proto_param = .{
- .fn_proto_node_offset = src_node_offset,
- .param_index = @intCast(block.params.len), // va_arg must be the last parameter
- },
- });
- try sema.checkCallConvSupportsVarArgs(block, va_args_src, cc);
- }
-
- const ret_poison = bare_return_type.isGenericPoison();
-
- const param_types = block.params.items(.ty);
-
- if (inferred_error_set) {
- assert(has_body);
- if (!ret_poison)
- try sema.validateErrorUnionPayloadType(block, bare_return_type, ret_ty_src);
- const func_index = try ip.getFuncDeclIes(gpa, pt.tid, .{
- .owner_nav = sema.owner.unwrap().nav_val,
-
- .param_types = param_types,
- .noalias_bits = noalias_bits,
- .comptime_bits = comptime_bits,
- .bare_return_type = bare_return_type.toIntern(),
- .cc = cc,
- .is_var_args = var_args,
- .is_generic = is_generic,
- .is_noinline = is_noinline,
-
- .zir_body_inst = try block.trackZir(func_inst),
- .lbrace_line = src_locs.lbrace_line,
- .rbrace_line = src_locs.rbrace_line,
- .lbrace_column = @as(u16, @truncate(src_locs.columns)),
- .rbrace_column = @as(u16, @truncate(src_locs.columns >> 16)),
- });
- return finishFunc(
- sema,
- block,
- func_index,
- .none,
- ret_poison,
- bare_return_type,
- ret_ty_src,
- cc,
- ret_ty_requires_comptime,
- func_inst,
- cc_src,
- is_noinline,
- );
}
- const func_ty = try ip.getFuncType(gpa, pt.tid, .{
- .param_types = param_types,
- .noalias_bits = noalias_bits,
- .comptime_bits = comptime_bits,
- .return_type = bare_return_type.toIntern(),
- .cc = cc,
- .is_var_args = var_args,
- .is_generic = is_generic,
- .is_noinline = is_noinline,
- });
-
- if (has_body) {
- const func_index = try ip.getFuncDecl(gpa, pt.tid, .{
- .owner_nav = sema.owner.unwrap().nav_val,
- .ty = func_ty,
- .cc = cc,
- .is_noinline = is_noinline,
- .zir_body_inst = try block.trackZir(func_inst),
- .lbrace_line = src_locs.lbrace_line,
- .rbrace_line = src_locs.rbrace_line,
- .lbrace_column = @as(u16, @truncate(src_locs.columns)),
- .rbrace_column = @as(u16, @truncate(src_locs.columns >> 16)),
- });
- return finishFunc(
- sema,
- block,
- func_index,
- func_ty,
- ret_poison,
- bare_return_type,
- ret_ty_src,
- cc,
- ret_ty_requires_comptime,
- func_inst,
- cc_src,
- is_noinline,
- );
+ if (var_args and is_generic) {
+ return sema.fail(block, func_src, "generic function cannot be variadic", .{});
}
- return finishFunc(
- sema,
+ try sema.checkReturnTypeAndCallConvCommon(
block,
- .none,
- func_ty,
- ret_poison,
bare_return_type,
ret_ty_src,
cc,
- ret_ty_requires_comptime,
- func_inst,
cc_src,
+ if (var_args) block.src(.{ .fn_proto_param = .{
+ .fn_proto_node_offset = src_node_offset,
+ .param_index = @intCast(block.params.len),
+ } }) else null,
+ inferred_error_set,
is_noinline,
);
-}
-
-fn finishFunc(
- sema: *Sema,
- block: *Block,
- opt_func_index: InternPool.Index,
- func_ty: InternPool.Index,
- ret_poison: bool,
- bare_return_type: Type,
- ret_ty_src: LazySrcLoc,
- cc_resolved: std.builtin.CallingConvention,
- ret_ty_requires_comptime: bool,
- func_inst: Zir.Inst.Index,
- cc_src: LazySrcLoc,
- is_noinline: bool,
-) CompileError!Air.Inst.Ref {
- const pt = sema.pt;
- const zcu = pt.zcu;
- const ip = &zcu.intern_pool;
- const gpa = sema.gpa;
-
- const return_type: Type = if (opt_func_index == .none or ret_poison)
- bare_return_type
- else
- .fromInterned(ip.funcTypeReturnType(ip.typeOf(opt_func_index)));
-
- if (!return_type.isValidReturnType(zcu)) {
- const opaque_str = if (return_type.zigTypeTag(zcu) == .@"opaque") "opaque " else "";
- return sema.fail(block, ret_ty_src, "{s}return type '{f}' not allowed", .{
- opaque_str, return_type.fmt(pt),
- });
- }
- if (!ret_poison and !target_util.fnCallConvAllowsZigTypes(cc_resolved) and
- !try sema.validateExternType(return_type, .ret_ty))
- {
- const msg = msg: {
- const msg = try sema.errMsg(ret_ty_src, "return type '{f}' not allowed in function with calling convention '{s}'", .{
- return_type.fmt(pt), @tagName(cc_resolved),
- });
- errdefer msg.destroy(gpa);
-
- try sema.explainWhyTypeIsNotExtern(msg, ret_ty_src, return_type, .ret_ty);
-
- try sema.addDeclaredHereNote(msg, return_type);
- break :msg msg;
- };
- return sema.failWithOwnedErrorMsg(block, msg);
- }
// If the return type is comptime-only but not dependent on parameters then
// all parameter types also need to be comptime.
- if (opt_func_index != .none and ret_ty_requires_comptime and !block.isComptime()) comptime_check: {
+ if (has_body and ret_ty_requires_comptime and !block.isComptime()) comptime_check: {
for (block.params.items(.is_comptime)) |is_comptime| {
if (!is_comptime) break;
} else break :comptime_check;
-
+ const ies_ret_ty_prefix: []const u8 = if (inferred_error_set) "!" else "";
const msg = try sema.errMsg(
ret_ty_src,
- "function with comptime-only return type '{f}' requires all parameters to be comptime",
- .{return_type.fmt(pt)},
+ "function with comptime-only return type '{s}{f}' requires all parameters to be comptime",
+ .{ ies_ret_ty_prefix, bare_return_type.fmt(pt) },
);
errdefer msg.destroy(sema.gpa);
- try sema.explainWhyTypeIsComptime(msg, ret_ty_src, return_type);
+ try sema.explainWhyTypeIsComptime(msg, ret_ty_src, bare_return_type);
const tags = sema.code.instructions.items(.tag);
const data = sema.code.instructions.items(.data);
@@ -9556,68 +9557,56 @@ fn finishFunc(
return sema.failWithOwnedErrorMsg(block, msg);
}
- validate_incoming_stack_align: {
- const a: u64 = switch (cc_resolved) {
- inline else => |payload| if (@TypeOf(payload) != void and @hasField(@TypeOf(payload), "incoming_stack_alignment"))
- payload.incoming_stack_alignment orelse break :validate_incoming_stack_align
- else
- break :validate_incoming_stack_align,
- };
- if (!std.math.isPowerOfTwo(a)) {
- return sema.fail(block, cc_src, "calling convention incoming stack alignment '{d}' is not a power of two", .{a});
- }
- }
+ const param_types = block.params.items(.ty);
- switch (cc_resolved) {
- .x86_64_interrupt,
- .x86_interrupt,
- .arm_interrupt,
- .mips64_interrupt,
- .mips_interrupt,
- .riscv64_interrupt,
- .riscv32_interrupt,
- .sh_interrupt,
- .arc_interrupt,
- .avr_interrupt,
- .csky_interrupt,
- .m68k_interrupt,
- .microblaze_interrupt,
- .msp430_interrupt,
- .avr_signal,
- => if (return_type.zigTypeTag(zcu) != .void and return_type.zigTypeTag(zcu) != .noreturn) {
- return sema.fail(block, ret_ty_src, "function with calling convention '{s}' must return 'void' or 'noreturn'", .{@tagName(cc_resolved)});
- },
- .@"inline" => if (is_noinline) {
- return sema.fail(block, cc_src, "'noinline' function cannot have calling convention 'inline'", .{});
- },
- else => {},
+ if (inferred_error_set) {
+ assert(has_body);
+ return .fromIntern(try ip.getFuncDeclIes(gpa, pt.tid, .{
+ .owner_nav = sema.owner.unwrap().nav_val,
+
+ .param_types = param_types,
+ .noalias_bits = noalias_bits,
+ .comptime_bits = comptime_bits,
+ .bare_return_type = bare_return_type.toIntern(),
+ .cc = cc,
+ .is_var_args = var_args,
+ .is_generic = is_generic,
+ .is_noinline = is_noinline,
+
+ .zir_body_inst = try block.trackZir(func_inst),
+ .lbrace_line = src_locs.lbrace_line,
+ .rbrace_line = src_locs.rbrace_line,
+ .lbrace_column = @as(u16, @truncate(src_locs.columns)),
+ .rbrace_column = @as(u16, @truncate(src_locs.columns >> 16)),
+ }));
}
- switch (zcu.callconvSupported(cc_resolved)) {
- .ok => {},
- .bad_arch => |allowed_archs| {
- const ArchListFormatter = struct {
- archs: []const std.Target.Cpu.Arch,
- pub fn format(formatter: @This(), w: *std.Io.Writer) std.Io.Writer.Error!void {
- for (formatter.archs, 0..) |arch, i| {
- if (i != 0)
- try w.writeAll(", ");
- try w.print("'{s}'", .{@tagName(arch)});
- }
- }
- };
- return sema.fail(block, cc_src, "calling convention '{s}' only available on architectures {f}", .{
- @tagName(cc_resolved),
- ArchListFormatter{ .archs = allowed_archs },
- });
- },
- .bad_backend => |bad_backend| return sema.fail(block, cc_src, "calling convention '{s}' not supported by compiler backend '{s}'", .{
- @tagName(cc_resolved),
- @tagName(bad_backend),
- }),
+ const func_ty = try ip.getFuncType(gpa, pt.tid, .{
+ .param_types = param_types,
+ .noalias_bits = noalias_bits,
+ .comptime_bits = comptime_bits,
+ .return_type = bare_return_type.toIntern(),
+ .cc = cc,
+ .is_var_args = var_args,
+ .is_generic = is_generic,
+ .is_noinline = is_noinline,
+ });
+
+ if (has_body) {
+ return .fromIntern(try ip.getFuncDecl(gpa, pt.tid, .{
+ .owner_nav = sema.owner.unwrap().nav_val,
+ .ty = func_ty,
+ .cc = cc,
+ .is_noinline = is_noinline,
+ .zir_body_inst = try block.trackZir(func_inst),
+ .lbrace_line = src_locs.lbrace_line,
+ .rbrace_line = src_locs.rbrace_line,
+ .lbrace_column = @as(u16, @truncate(src_locs.columns)),
+ .rbrace_column = @as(u16, @truncate(src_locs.columns >> 16)),
+ }));
}
- return Air.internedToRef(if (opt_func_index != .none) opt_func_index else func_ty);
+ return .fromIntern(func_ty);
}
fn zirParam(
@@ -19395,7 +19384,7 @@ fn zirUnionInit(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!A
if (union_ty.zigTypeTag(pt.zcu) != .@"union") {
return sema.fail(block, ty_src, "expected union type, found '{f}'", .{union_ty.fmt(pt)});
}
- const field_name = try sema.resolveConstStringIntern(block, field_src, extra.field_name, .{ .simple = .union_field_name });
+ const field_name = try sema.resolveConstStringIntern(block, field_src, extra.field_name, .{ .simple = .union_field_names });
const init = try sema.resolveInst(extra.init);
return sema.unionInit(block, init, init_src, union_ty, ty_src, field_name, field_src);
}
@@ -20553,589 +20542,529 @@ fn zirTagName(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air
return block.addUnOp(.tag_name, casted_operand);
}
-fn zirReify(
+fn zirReifyInt(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air.Inst.Ref {
+ const inst_data = sema.code.instructions.items(.data)[@intFromEnum(inst)].pl_node;
+ const signedness_src = block.builtinCallArgSrc(inst_data.src_node, 0);
+ const bits_src = block.builtinCallArgSrc(inst_data.src_node, 1);
+ const extra = sema.code.extraData(Zir.Inst.Bin, inst_data.payload_index).data;
+ const signedness = try sema.resolveBuiltinEnum(block, signedness_src, extra.lhs, .Signedness, .{ .simple = .int_signedness });
+ const bits: u16 = @intCast(try sema.resolveInt(block, bits_src, extra.rhs, .u16, .{ .simple = .int_bit_width }));
+ return .fromType(try sema.pt.intType(signedness, bits));
+}
+
+fn zirReifySliceArgTy(
sema: *Sema,
block: *Block,
extended: Zir.Inst.Extended.InstData,
- inst: Zir.Inst.Index,
) CompileError!Air.Inst.Ref {
const pt = sema.pt;
const zcu = pt.zcu;
- const gpa = sema.gpa;
- const ip = &zcu.intern_pool;
- const name_strategy: Zir.Inst.NameStrategy = @enumFromInt(extended.small);
- const extra = sema.code.extraData(Zir.Inst.Reify, extended.operand).data;
- const tracked_inst = try block.trackZir(inst);
- const src: LazySrcLoc = .{
- .base_node_inst = tracked_inst,
- .offset = LazySrcLoc.Offset.nodeOffset(.zero),
- };
- const operand_src: LazySrcLoc = .{
- .base_node_inst = tracked_inst,
- .offset = .{
- .node_offset_builtin_call_arg = .{
- .builtin_call_node = .zero, // `tracked_inst` is precisely the `reify` instruction, so offset is 0
- .arg_index = 0,
- },
- },
+
+ const extra = sema.code.extraData(Zir.Inst.UnNode, extended.operand).data;
+ const info: Zir.Inst.ReifySliceArgInfo = @enumFromInt(extended.small);
+
+ const src = block.nodeOffset(extra.node);
+
+ const comptime_reason: std.zig.SimpleComptimeReason, const in_scalar_ty: Type, const out_scalar_ty: Type = switch (info) {
+ // zig fmt: off
+ .type_to_fn_param_attrs => .{ .fn_param_attrs, .type, try sema.getBuiltinType(src, .@"Type.Fn.Param.Attributes") },
+ .string_to_struct_field_type => .{ .struct_field_types, .slice_const_u8, .type },
+ .string_to_union_field_type => .{ .union_field_types, .slice_const_u8, .type },
+ .string_to_struct_field_attrs => .{ .struct_field_attrs, .slice_const_u8, try sema.getBuiltinType(src, .@"Type.StructField.Attributes") },
+ .string_to_union_field_attrs => .{ .union_field_attrs, .slice_const_u8, try sema.getBuiltinType(src, .@"Type.UnionField.Attributes") },
+ // zig fmt: on
};
- const type_info_ty = try sema.getBuiltinType(src, .Type);
- const uncasted_operand = try sema.resolveInst(extra.operand);
- const type_info = try sema.coerce(block, type_info_ty, uncasted_operand, operand_src);
- const val = try sema.resolveConstDefinedValue(block, operand_src, type_info, .{ .simple = .operand_Type });
- const union_val = ip.indexToKey(val.toIntern()).un;
- if (try sema.anyUndef(block, operand_src, Value.fromInterned(union_val.val))) {
- return sema.failWithUseOfUndef(block, operand_src, null);
- }
- const tag_index = type_info_ty.unionTagFieldIndex(Value.fromInterned(union_val.tag), zcu).?;
- switch (@as(std.builtin.TypeId, @enumFromInt(tag_index))) {
- .type => return .type_type,
- .void => return .void_type,
- .bool => return .bool_type,
- .noreturn => return .noreturn_type,
- .comptime_float => return .comptime_float_type,
- .comptime_int => return .comptime_int_type,
- .undefined => return .undefined_type,
- .null => return .null_type,
- .@"anyframe" => return sema.failWithUseOfAsync(block, src),
- .enum_literal => return .enum_literal_type,
- .int => {
- const int = try sema.interpretBuiltinType(block, operand_src, .fromInterned(union_val.val), std.builtin.Type.Int);
- const ty = try pt.intType(int.signedness, int.bits);
- return Air.internedToRef(ty.toIntern());
- },
- .vector => {
- const struct_type = ip.loadStructType(ip.typeOf(union_val.val));
- const len_val = try Value.fromInterned(union_val.val).fieldValue(pt, struct_type.nameIndex(
- ip,
- try ip.getOrPutString(gpa, pt.tid, "len", .no_embedded_nulls),
- ).?);
- const child_val = try Value.fromInterned(union_val.val).fieldValue(pt, struct_type.nameIndex(
- ip,
- try ip.getOrPutString(gpa, pt.tid, "child", .no_embedded_nulls),
- ).?);
-
- const len: u32 = @intCast(try len_val.toUnsignedIntSema(pt));
- const child_ty = child_val.toType();
-
- try sema.checkVectorElemType(block, src, child_ty);
-
- const ty = try pt.vectorType(.{
- .len = len,
- .child = child_ty.toIntern(),
- });
- return Air.internedToRef(ty.toIntern());
- },
- .float => {
- const float = try sema.interpretBuiltinType(block, operand_src, .fromInterned(union_val.val), std.builtin.Type.Float);
-
- const ty: Type = switch (float.bits) {
- 16 => .f16,
- 32 => .f32,
- 64 => .f64,
- 80 => .f80,
- 128 => .f128,
- else => return sema.fail(block, src, "{d}-bit float unsupported", .{float.bits}),
- };
- return Air.internedToRef(ty.toIntern());
- },
- .pointer => {
- const struct_type = ip.loadStructType(ip.typeOf(union_val.val));
- const size_val = try Value.fromInterned(union_val.val).fieldValue(pt, struct_type.nameIndex(
- ip,
- try ip.getOrPutString(gpa, pt.tid, "size", .no_embedded_nulls),
- ).?);
- const is_const_val = try Value.fromInterned(union_val.val).fieldValue(pt, struct_type.nameIndex(
- ip,
- try ip.getOrPutString(gpa, pt.tid, "is_const", .no_embedded_nulls),
- ).?);
- const is_volatile_val = try Value.fromInterned(union_val.val).fieldValue(pt, struct_type.nameIndex(
- ip,
- try ip.getOrPutString(gpa, pt.tid, "is_volatile", .no_embedded_nulls),
- ).?);
- const alignment_val = try Value.fromInterned(union_val.val).fieldValue(pt, struct_type.nameIndex(
- ip,
- try ip.getOrPutString(gpa, pt.tid, "alignment", .no_embedded_nulls),
- ).?);
- const address_space_val = try Value.fromInterned(union_val.val).fieldValue(pt, struct_type.nameIndex(
- ip,
- try ip.getOrPutString(gpa, pt.tid, "address_space", .no_embedded_nulls),
- ).?);
- const child_val = try Value.fromInterned(union_val.val).fieldValue(pt, struct_type.nameIndex(
- ip,
- try ip.getOrPutString(gpa, pt.tid, "child", .no_embedded_nulls),
- ).?);
- const is_allowzero_val = try Value.fromInterned(union_val.val).fieldValue(pt, struct_type.nameIndex(
- ip,
- try ip.getOrPutString(gpa, pt.tid, "is_allowzero", .no_embedded_nulls),
- ).?);
- const sentinel_val = try Value.fromInterned(union_val.val).fieldValue(pt, struct_type.nameIndex(
- ip,
- try ip.getOrPutString(gpa, pt.tid, "sentinel_ptr", .no_embedded_nulls),
- ).?);
-
- if (!try sema.intFitsInType(alignment_val, align_ty, null)) {
- return sema.fail(block, src, "alignment must fit in '{f}'", .{align_ty.fmt(pt)});
- }
- const alignment_val_int = try alignment_val.toUnsignedIntSema(pt);
- const abi_align = try sema.validateAlign(block, src, alignment_val_int);
-
- const elem_ty = child_val.toType();
- if (abi_align != .none) {
- try elem_ty.resolveLayout(pt);
- }
-
- const ptr_size = try sema.interpretBuiltinType(block, operand_src, size_val, std.builtin.Type.Pointer.Size);
-
- const actual_sentinel: InternPool.Index = s: {
- if (!sentinel_val.isNull(zcu)) {
- if (ptr_size == .one or ptr_size == .c) {
- return sema.fail(block, src, "sentinels are only allowed on slices and unknown-length pointers", .{});
- }
- const sentinel_ptr_val = sentinel_val.optionalValue(zcu).?;
- const ptr_ty = try pt.singleMutPtrType(elem_ty);
- const sent_val = (try sema.pointerDeref(block, src, sentinel_ptr_val, ptr_ty)).?;
- try sema.checkSentinelType(block, src, elem_ty);
- if (sent_val.canMutateComptimeVarState(zcu)) {
- const sentinel_name = try ip.getOrPutString(gpa, pt.tid, "sentinel_ptr", .no_embedded_nulls);
- return sema.failWithContainsReferenceToComptimeVar(block, src, sentinel_name, "sentinel", sent_val);
- }
- break :s sent_val.toIntern();
- }
- break :s .none;
- };
- if (elem_ty.zigTypeTag(zcu) == .noreturn) {
- return sema.fail(block, src, "pointer to noreturn not allowed", .{});
- } else if (elem_ty.zigTypeTag(zcu) == .@"fn") {
- if (ptr_size != .one) {
- return sema.fail(block, src, "function pointers must be single pointers", .{});
- }
- } else if (ptr_size != .one and elem_ty.zigTypeTag(zcu) == .@"opaque") {
- return sema.fail(block, src, "indexable pointer to opaque type '{f}' not allowed", .{elem_ty.fmt(pt)});
- } else if (ptr_size == .c) {
- if (!try sema.validateExternType(elem_ty, .other)) {
- const msg = msg: {
- const msg = try sema.errMsg(src, "C pointers cannot point to non-C-ABI-compatible type '{f}'", .{elem_ty.fmt(pt)});
- errdefer msg.destroy(gpa);
+ const operand_ty = try pt.ptrTypeSema(.{
+ .child = in_scalar_ty.toIntern(),
+ .flags = .{ .size = .slice, .is_const = true },
+ });
- try sema.explainWhyTypeIsNotExtern(msg, src, elem_ty, .other);
+ const operand_uncoerced = try sema.resolveInst(extra.operand);
+ const operand_coerced = try sema.coerce(block, operand_ty, operand_uncoerced, src);
+ const operand_val = try sema.resolveConstDefinedValue(block, src, operand_coerced, .{ .simple = comptime_reason });
+ const len_val: Value = .fromInterned(zcu.intern_pool.indexToKey(operand_val.toIntern()).slice.len);
+ if (len_val.isUndef(zcu)) return sema.failWithUseOfUndef(block, src, null);
+ const len = try len_val.toUnsignedIntSema(pt);
- try sema.addDeclaredHereNote(msg, elem_ty);
- break :msg msg;
- };
- return sema.failWithOwnedErrorMsg(block, msg);
- }
- }
+ return .fromType(try pt.singleConstPtrType(try pt.arrayType(.{
+ .len = len,
+ .child = out_scalar_ty.toIntern(),
+ })));
+}
- const ty = try pt.ptrTypeSema(.{
- .child = elem_ty.toIntern(),
- .sentinel = actual_sentinel,
- .flags = .{
- .size = ptr_size,
- .is_const = is_const_val.toBool(),
- .is_volatile = is_volatile_val.toBool(),
- .alignment = abi_align,
- .address_space = try sema.interpretBuiltinType(block, operand_src, address_space_val, std.builtin.AddressSpace),
- .is_allowzero = is_allowzero_val.toBool(),
- },
- });
- return Air.internedToRef(ty.toIntern());
- },
- .array => {
- const struct_type = ip.loadStructType(ip.typeOf(union_val.val));
- const len_val = try Value.fromInterned(union_val.val).fieldValue(pt, struct_type.nameIndex(
- ip,
- try ip.getOrPutString(gpa, pt.tid, "len", .no_embedded_nulls),
- ).?);
- const child_val = try Value.fromInterned(union_val.val).fieldValue(pt, struct_type.nameIndex(
- ip,
- try ip.getOrPutString(gpa, pt.tid, "child", .no_embedded_nulls),
- ).?);
- const sentinel_val = try Value.fromInterned(union_val.val).fieldValue(pt, struct_type.nameIndex(
- ip,
- try ip.getOrPutString(gpa, pt.tid, "sentinel_ptr", .no_embedded_nulls),
- ).?);
-
- const len = try len_val.toUnsignedIntSema(pt);
- const child_ty = child_val.toType();
- const sentinel = if (sentinel_val.optionalValue(zcu)) |p| blk: {
- const ptr_ty = try pt.singleMutPtrType(child_ty);
- try sema.checkSentinelType(block, src, child_ty);
- const sentinel = (try sema.pointerDeref(block, src, p, ptr_ty)).?;
- if (sentinel.canMutateComptimeVarState(zcu)) {
- const sentinel_name = try ip.getOrPutString(gpa, pt.tid, "sentinel_ptr", .no_embedded_nulls);
- return sema.failWithContainsReferenceToComptimeVar(block, src, sentinel_name, "sentinel", sentinel);
- }
- break :blk sentinel;
- } else null;
-
- const ty = try pt.arrayType(.{
- .len = len,
- .sentinel = if (sentinel) |s| s.toIntern() else .none,
- .child = child_ty.toIntern(),
- });
- return Air.internedToRef(ty.toIntern());
- },
- .optional => {
- const struct_type = ip.loadStructType(ip.typeOf(union_val.val));
- const child_val = try Value.fromInterned(union_val.val).fieldValue(pt, struct_type.nameIndex(
- ip,
- try ip.getOrPutString(gpa, pt.tid, "child", .no_embedded_nulls),
- ).?);
+fn zirReifyEnumValueSliceTy(
+ sema: *Sema,
+ block: *Block,
+ extended: Zir.Inst.Extended.InstData,
+) CompileError!Air.Inst.Ref {
+ const pt = sema.pt;
+ const zcu = pt.zcu;
- const child_ty = child_val.toType();
+ const extra = sema.code.extraData(Zir.Inst.BinNode, extended.operand).data;
- const ty = try pt.optionalType(child_ty.toIntern());
- return Air.internedToRef(ty.toIntern());
- },
- .error_union => {
- const struct_type = ip.loadStructType(ip.typeOf(union_val.val));
- const error_set_val = try Value.fromInterned(union_val.val).fieldValue(pt, struct_type.nameIndex(
- ip,
- try ip.getOrPutString(gpa, pt.tid, "error_set", .no_embedded_nulls),
- ).?);
- const payload_val = try Value.fromInterned(union_val.val).fieldValue(pt, struct_type.nameIndex(
- ip,
- try ip.getOrPutString(gpa, pt.tid, "payload", .no_embedded_nulls),
- ).?);
+ const int_tag_ty_src = block.builtinCallArgSrc(extra.node, 0);
+ const field_names_src = block.builtinCallArgSrc(extra.node, 2);
- const error_set_ty = error_set_val.toType();
- const payload_ty = payload_val.toType();
+ const int_tag_ty = try sema.resolveType(block, int_tag_ty_src, extra.lhs);
- if (error_set_ty.zigTypeTag(zcu) != .error_set) {
- return sema.fail(block, src, "Type.ErrorUnion.error_set must be an error set type", .{});
- }
+ const operand_uncoerced = try sema.resolveInst(extra.rhs);
+ const operand_coerced = try sema.coerce(block, .slice_const_slice_const_u8, operand_uncoerced, field_names_src);
+ const operand_val = try sema.resolveConstDefinedValue(block, field_names_src, operand_coerced, .{ .simple = .enum_field_names });
+ const len_val: Value = .fromInterned(zcu.intern_pool.indexToKey(operand_val.toIntern()).slice.len);
+ if (len_val.isUndef(zcu)) return sema.failWithUseOfUndef(block, field_names_src, null);
+ const len = try len_val.toUnsignedIntSema(pt);
- const ty = try pt.errorUnionType(error_set_ty, payload_ty);
- return Air.internedToRef(ty.toIntern());
- },
- .error_set => {
- const payload_val = Value.fromInterned(union_val.val).optionalValue(zcu) orelse
- return .anyerror_type;
+ return .fromType(try pt.singleConstPtrType(try pt.arrayType(.{
+ .len = len,
+ .child = int_tag_ty.toIntern(),
+ })));
+}
+
+fn zirReifyPointerSentinelTy(
+ sema: *Sema,
+ block: *Block,
+ extended: Zir.Inst.Extended.InstData,
+) CompileError!Air.Inst.Ref {
+ const pt = sema.pt;
+ const zcu = pt.zcu;
+ const extra = sema.code.extraData(Zir.Inst.UnNode, extended.operand).data;
+ const src = block.nodeOffset(extra.node);
+ const elem_ty = try sema.resolveType(block, src, extra.operand);
+ return .fromType(switch (elem_ty.zigTypeTag(zcu)) {
+ else => try pt.optionalType(elem_ty.toIntern()),
+ // These types cannot be the child of an optional. To allow reifying pointers to them still,
+ // we treat the "sentinel" argument to `@Pointer` as `?noreturn` instead of `?T`.
+ .@"opaque", .null => .optional_noreturn,
+ });
+}
- const names_val = try sema.derefSliceAsArray(block, src, payload_val, .{ .simple = .error_set_contents });
+fn zirReifyTuple(
+ sema: *Sema,
+ block: *Block,
+ extended: Zir.Inst.Extended.InstData,
+) CompileError!Air.Inst.Ref {
+ const pt = sema.pt;
+ const zcu = pt.zcu;
- const len = try sema.usizeCast(block, src, names_val.typeOf(zcu).arrayLen(zcu));
- var names: InferredErrorSet.NameMap = .{};
- try names.ensureUnusedCapacity(sema.arena, len);
- for (0..len) |i| {
- const elem_val = try names_val.elemValue(pt, i);
- const elem_struct_type = ip.loadStructType(ip.typeOf(elem_val.toIntern()));
- const name_val = try elem_val.fieldValue(pt, elem_struct_type.nameIndex(
- ip,
- try ip.getOrPutString(gpa, pt.tid, "name", .no_embedded_nulls),
- ).?);
-
- const name = try sema.sliceToIpString(block, src, name_val, .{ .simple = .error_set_contents });
- _ = try pt.getErrorValue(name);
- const gop = names.getOrPutAssumeCapacity(name);
- if (gop.found_existing) {
- return sema.fail(block, src, "duplicate error '{f}'", .{
- name.fmt(ip),
- });
- }
- }
+ const extra = sema.code.extraData(Zir.Inst.UnNode, extended.operand).data;
+ const operand_src = block.builtinCallArgSrc(extra.node, 0);
- const ty = try pt.errorSetFromUnsortedNames(names.keys());
- return Air.internedToRef(ty.toIntern());
- },
- .@"struct" => {
- const struct_type = ip.loadStructType(ip.typeOf(union_val.val));
- const layout_val = try Value.fromInterned(union_val.val).fieldValue(pt, struct_type.nameIndex(
- ip,
- try ip.getOrPutString(gpa, pt.tid, "layout", .no_embedded_nulls),
- ).?);
- const backing_integer_val = try Value.fromInterned(union_val.val).fieldValue(pt, struct_type.nameIndex(
- ip,
- try ip.getOrPutString(gpa, pt.tid, "backing_integer", .no_embedded_nulls),
- ).?);
- const fields_val = try Value.fromInterned(union_val.val).fieldValue(pt, struct_type.nameIndex(
- ip,
- try ip.getOrPutString(gpa, pt.tid, "fields", .no_embedded_nulls),
- ).?);
- const decls_val = try Value.fromInterned(union_val.val).fieldValue(pt, struct_type.nameIndex(
- ip,
- try ip.getOrPutString(gpa, pt.tid, "decls", .no_embedded_nulls),
- ).?);
- const is_tuple_val = try Value.fromInterned(union_val.val).fieldValue(pt, struct_type.nameIndex(
- ip,
- try ip.getOrPutString(gpa, pt.tid, "is_tuple", .no_embedded_nulls),
- ).?);
-
- const layout = try sema.interpretBuiltinType(block, operand_src, layout_val, std.builtin.Type.ContainerLayout);
-
- // Decls
- if (try decls_val.sliceLen(pt) > 0) {
- return sema.fail(block, src, "reified structs must have no decls", .{});
- }
-
- if (layout != .@"packed" and !backing_integer_val.isNull(zcu)) {
- return sema.fail(block, src, "non-packed struct does not support backing integer type", .{});
- }
-
- const fields_arr = try sema.derefSliceAsArray(block, operand_src, fields_val, .{ .simple = .struct_fields });
-
- if (is_tuple_val.toBool()) {
- switch (layout) {
- .@"extern" => return sema.fail(block, src, "extern tuples are not supported", .{}),
- .@"packed" => return sema.fail(block, src, "packed tuples are not supported", .{}),
- .auto => {},
- }
- return sema.reifyTuple(block, src, fields_arr);
- } else {
- return sema.reifyStruct(block, inst, src, layout, backing_integer_val, fields_arr, name_strategy);
- }
- },
- .@"enum" => {
- const struct_type = ip.loadStructType(ip.typeOf(union_val.val));
- const tag_type_val = try Value.fromInterned(union_val.val).fieldValue(pt, struct_type.nameIndex(
- ip,
- try ip.getOrPutString(gpa, pt.tid, "tag_type", .no_embedded_nulls),
- ).?);
- const fields_val = try Value.fromInterned(union_val.val).fieldValue(pt, struct_type.nameIndex(
- ip,
- try ip.getOrPutString(gpa, pt.tid, "fields", .no_embedded_nulls),
- ).?);
- const decls_val = try Value.fromInterned(union_val.val).fieldValue(pt, struct_type.nameIndex(
- ip,
- try ip.getOrPutString(gpa, pt.tid, "decls", .no_embedded_nulls),
- ).?);
- const is_exhaustive_val = try Value.fromInterned(union_val.val).fieldValue(pt, struct_type.nameIndex(
- ip,
- try ip.getOrPutString(gpa, pt.tid, "is_exhaustive", .no_embedded_nulls),
- ).?);
-
- if (try decls_val.sliceLen(pt) > 0) {
- return sema.fail(block, src, "reified enums must have no decls", .{});
- }
-
- const fields_arr = try sema.derefSliceAsArray(block, operand_src, fields_val, .{ .simple = .enum_fields });
-
- return sema.reifyEnum(block, inst, src, tag_type_val.toType(), is_exhaustive_val.toBool(), fields_arr, name_strategy);
- },
- .@"opaque" => {
- const struct_type = ip.loadStructType(ip.typeOf(union_val.val));
- const decls_val = try Value.fromInterned(union_val.val).fieldValue(pt, struct_type.nameIndex(
- ip,
- try ip.getOrPutString(gpa, pt.tid, "decls", .no_embedded_nulls),
- ).?);
+ const types_uncoerced = try sema.resolveInst(extra.operand);
+ const types_coerced = try sema.coerce(block, .slice_const_type, types_uncoerced, operand_src);
+ const types_slice_val = try sema.resolveConstDefinedValue(block, operand_src, types_coerced, .{ .simple = .tuple_field_types });
+ const types_array_val = try sema.derefSliceAsArray(block, operand_src, types_slice_val, .{ .simple = .tuple_field_types });
+ const fields_len: u32 = @intCast(types_array_val.typeOf(zcu).arrayLen(zcu));
- // Decls
- if (try decls_val.sliceLen(pt) > 0) {
- return sema.fail(block, src, "reified opaque must have no decls", .{});
- }
+ const field_types = try sema.arena.alloc(InternPool.Index, fields_len);
+ for (field_types, 0..) |*field_ty, field_idx| {
+ const field_ty_val = try types_array_val.elemValue(pt, field_idx);
+ if (field_ty_val.isUndef(zcu)) {
+ return sema.failWithUseOfUndef(block, operand_src, null);
+ }
+ field_ty.* = field_ty_val.toIntern();
+ }
- const wip_ty = switch (try ip.getOpaqueType(gpa, pt.tid, .{
- .key = .{ .reified = .{
- .zir_index = try block.trackZir(inst),
- } },
- })) {
- .existing => |ty| {
- try sema.addTypeReferenceEntry(src, ty);
- return Air.internedToRef(ty);
- },
- .wip => |wip| wip,
- };
- errdefer wip_ty.cancel(ip, pt.tid);
+ const field_values = try sema.arena.alloc(InternPool.Index, fields_len);
+ @memset(field_values, .none);
- const type_name = try sema.createTypeName(
- block,
- name_strategy,
- "opaque",
- inst,
- wip_ty.index,
- );
- wip_ty.setName(ip, type_name.name, type_name.nav);
+ return .fromIntern(try zcu.intern_pool.getTupleType(zcu.gpa, pt.tid, .{
+ .types = field_types,
+ .values = field_values,
+ }));
+}
- const new_namespace_index = try pt.createNamespace(.{
- .parent = block.namespace.toOptional(),
- .owner_type = wip_ty.index,
- .file_scope = block.getFileScopeIndex(zcu),
- .generation = zcu.generation,
- });
+fn zirReifyPointer(
+ sema: *Sema,
+ block: *Block,
+ extended: Zir.Inst.Extended.InstData,
+) CompileError!Air.Inst.Ref {
+ const pt = sema.pt;
+ const zcu = pt.zcu;
+ const gpa = zcu.gpa;
+ const ip = &zcu.intern_pool;
- try sema.addTypeReferenceEntry(src, wip_ty.index);
- if (zcu.comp.debugIncremental()) try zcu.incremental_debug_state.newType(zcu, wip_ty.index);
- return Air.internedToRef(wip_ty.finish(ip, new_namespace_index));
- },
- .@"union" => {
- const struct_type = ip.loadStructType(ip.typeOf(union_val.val));
- const layout_val = try Value.fromInterned(union_val.val).fieldValue(pt, struct_type.nameIndex(
- ip,
- try ip.getOrPutString(gpa, pt.tid, "layout", .no_embedded_nulls),
- ).?);
- const tag_type_val = try Value.fromInterned(union_val.val).fieldValue(pt, struct_type.nameIndex(
- ip,
- try ip.getOrPutString(gpa, pt.tid, "tag_type", .no_embedded_nulls),
- ).?);
- const fields_val = try Value.fromInterned(union_val.val).fieldValue(pt, struct_type.nameIndex(
- ip,
- try ip.getOrPutString(gpa, pt.tid, "fields", .no_embedded_nulls),
- ).?);
- const decls_val = try Value.fromInterned(union_val.val).fieldValue(pt, struct_type.nameIndex(
- ip,
- try ip.getOrPutString(gpa, pt.tid, "decls", .no_embedded_nulls),
- ).?);
+ const extra = sema.code.extraData(Zir.Inst.ReifyPointer, extended.operand).data;
+ const src = block.nodeOffset(extra.node);
+ const size_src = block.builtinCallArgSrc(extra.node, 0);
+ const attrs_src = block.builtinCallArgSrc(extra.node, 1);
+ const elem_ty_src = block.builtinCallArgSrc(extra.node, 2);
+ const sentinel_src = block.builtinCallArgSrc(extra.node, 3);
+
+ const size_ty = try sema.getBuiltinType(size_src, .@"Type.Pointer.Size");
+ const attrs_ty = try sema.getBuiltinType(attrs_src, .@"Type.Pointer.Attributes");
+
+ const size_uncoerced = try sema.resolveInst(extra.size);
+ const size_coerced = try sema.coerce(block, size_ty, size_uncoerced, size_src);
+ const size_val = try sema.resolveConstDefinedValue(block, size_src, size_coerced, .{ .simple = .pointer_size });
+ const size = try sema.interpretBuiltinType(block, size_src, size_val, std.builtin.Type.Pointer.Size);
+
+ const attrs_uncoerced = try sema.resolveInst(extra.attrs);
+ const attrs_coerced = try sema.coerce(block, attrs_ty, attrs_uncoerced, attrs_src);
+ const attrs_val = try sema.resolveConstDefinedValue(block, attrs_src, attrs_coerced, .{ .simple = .pointer_attrs });
+ const attrs = try sema.interpretBuiltinType(block, attrs_src, attrs_val, std.builtin.Type.Pointer.Attributes);
+
+ const @"align": Alignment = if (attrs.@"align") |bytes| a: {
+ break :a try sema.validateAlign(block, attrs_src, bytes);
+ } else .none;
- if (try decls_val.sliceLen(pt) > 0) {
- return sema.fail(block, src, "reified unions must have no decls", .{});
- }
- const layout = try sema.interpretBuiltinType(block, operand_src, layout_val, std.builtin.Type.ContainerLayout);
+ const elem_ty = try sema.resolveType(block, elem_ty_src, extra.elem_ty);
- const has_tag = tag_type_val.optionalValue(zcu) != null;
+ switch (elem_ty.zigTypeTag(zcu)) {
+ .noreturn => return sema.fail(block, elem_ty_src, "pointer to noreturn not allowed", .{}),
+ // This needs to be disallowed, because the sentinel parameter would otherwise have type
+ // `?@TypeOf(null)`, which is not a valid type because you cannot differentiate between
+ // constructing the "inner" null value and the "outer" null value.
+ .null => return sema.fail(block, elem_ty_src, "cannot reify pointer to '@TypeOf(null)'", .{}),
+ .@"fn" => switch (size) {
+ .one => {},
+ .many, .c, .slice => return sema.fail(block, src, "function pointers must be single pointers", .{}),
+ },
+ .@"opaque" => switch (size) {
+ .one => {},
+ .many, .c, .slice => return sema.fail(block, src, "indexable pointer to opaque type '{f}' not allowed", .{elem_ty.fmt(pt)}),
+ },
+ else => {},
+ }
- if (has_tag) {
- switch (layout) {
- .@"extern" => return sema.fail(block, src, "extern union does not support enum tag type", .{}),
- .@"packed" => return sema.fail(block, src, "packed union does not support enum tag type", .{}),
- .auto => {},
- }
- }
+ if (size == .c and !try sema.validateExternType(elem_ty, .other)) {
+ return sema.failWithOwnedErrorMsg(block, msg: {
+ const msg = try sema.errMsg(src, "C pointers cannot point to non-C-ABI-compatible type '{f}'", .{elem_ty.fmt(pt)});
+ errdefer msg.destroy(gpa);
+ try sema.explainWhyTypeIsNotExtern(msg, elem_ty_src, elem_ty, .other);
+ try sema.addDeclaredHereNote(msg, elem_ty);
+ break :msg msg;
+ });
+ }
- const fields_arr = try sema.derefSliceAsArray(block, operand_src, fields_val, .{ .simple = .union_fields });
+ const sentinel_ty = try pt.optionalType(elem_ty.toIntern());
+ const sentinel_uncoerced = try sema.resolveInst(extra.sentinel);
+ const sentinel_coerced = try sema.coerce(block, sentinel_ty, sentinel_uncoerced, sentinel_src);
+ const sentinel_val = try sema.resolveConstDefinedValue(block, sentinel_src, sentinel_coerced, .{ .simple = .pointer_sentinel });
+ const opt_sentinel = sentinel_val.optionalValue(zcu);
+ if (opt_sentinel) |sentinel| {
+ switch (size) {
+ .many, .slice => {},
+ .one, .c => return sema.fail(block, sentinel_src, "sentinels are only allowed on slices and unknown-length pointers", .{}),
+ }
+ try checkSentinelType(sema, block, sentinel_src, elem_ty);
+ if (sentinel.canMutateComptimeVarState(zcu)) {
+ const sentinel_name = try ip.getOrPutString(gpa, pt.tid, "sentinel", .no_embedded_nulls);
+ return sema.failWithContainsReferenceToComptimeVar(block, sentinel_src, sentinel_name, "sentinel", sentinel);
+ }
+ }
- return sema.reifyUnion(block, inst, src, layout, tag_type_val, fields_arr, name_strategy);
+ return .fromType(try pt.ptrTypeSema(.{
+ .child = elem_ty.toIntern(),
+ .sentinel = if (opt_sentinel) |s| s.toIntern() else .none,
+ .flags = .{
+ .size = size,
+ .is_const = attrs.@"const",
+ .is_volatile = attrs.@"volatile",
+ .is_allowzero = attrs.@"allowzero",
+ .address_space = attrs.@"addrspace" orelse as: {
+ if (elem_ty.zigTypeTag(zcu) == .@"fn" and zcu.getTarget().cpu.arch == .avr) break :as .flash;
+ break :as .generic;
+ },
+ .alignment = @"align",
},
- .@"fn" => {
- const struct_type = ip.loadStructType(ip.typeOf(union_val.val));
- const calling_convention_val = try Value.fromInterned(union_val.val).fieldValue(pt, struct_type.nameIndex(
- ip,
- try ip.getOrPutString(gpa, pt.tid, "calling_convention", .no_embedded_nulls),
- ).?);
- const is_generic_val = try Value.fromInterned(union_val.val).fieldValue(pt, struct_type.nameIndex(
- ip,
- try ip.getOrPutString(gpa, pt.tid, "is_generic", .no_embedded_nulls),
- ).?);
- const is_var_args_val = try Value.fromInterned(union_val.val).fieldValue(pt, struct_type.nameIndex(
- ip,
- try ip.getOrPutString(gpa, pt.tid, "is_var_args", .no_embedded_nulls),
- ).?);
- const return_type_val = try Value.fromInterned(union_val.val).fieldValue(pt, struct_type.nameIndex(
- ip,
- try ip.getOrPutString(gpa, pt.tid, "return_type", .no_embedded_nulls),
- ).?);
- const params_slice_val = try Value.fromInterned(union_val.val).fieldValue(pt, struct_type.nameIndex(
- ip,
- try ip.getOrPutString(gpa, pt.tid, "params", .no_embedded_nulls),
- ).?);
-
- const is_generic = is_generic_val.toBool();
- if (is_generic) {
- return sema.fail(block, src, "Type.Fn.is_generic must be false for @Type", .{});
- }
-
- const is_var_args = is_var_args_val.toBool();
- const cc = try sema.analyzeValueAsCallconv(block, src, calling_convention_val);
- if (is_var_args) {
- try sema.checkCallConvSupportsVarArgs(block, src, cc);
- }
-
- const return_type = return_type_val.optionalValue(zcu) orelse
- return sema.fail(block, src, "Type.Fn.return_type must be non-null for @Type", .{});
-
- const params_val = try sema.derefSliceAsArray(block, operand_src, params_slice_val, .{ .simple = .function_parameters });
-
- const args_len = try sema.usizeCast(block, src, params_val.typeOf(zcu).arrayLen(zcu));
- const param_types = try sema.arena.alloc(InternPool.Index, args_len);
+ }));
+}
- var noalias_bits: u32 = 0;
- for (param_types, 0..) |*param_type, i| {
- const elem_val = try params_val.elemValue(pt, i);
- const elem_struct_type = ip.loadStructType(ip.typeOf(elem_val.toIntern()));
- const param_is_generic_val = try elem_val.fieldValue(pt, elem_struct_type.nameIndex(
- ip,
- try ip.getOrPutString(gpa, pt.tid, "is_generic", .no_embedded_nulls),
- ).?);
- const param_is_noalias_val = try elem_val.fieldValue(pt, elem_struct_type.nameIndex(
- ip,
- try ip.getOrPutString(gpa, pt.tid, "is_noalias", .no_embedded_nulls),
- ).?);
- const opt_param_type_val = try elem_val.fieldValue(pt, elem_struct_type.nameIndex(
- ip,
- try ip.getOrPutString(gpa, pt.tid, "type", .no_embedded_nulls),
- ).?);
-
- if (param_is_generic_val.toBool()) {
- return sema.fail(block, src, "Type.Fn.Param.is_generic must be false for @Type", .{});
- }
-
- const param_type_val = opt_param_type_val.optionalValue(zcu) orelse
- return sema.fail(block, src, "Type.Fn.Param.type must be non-null for @Type", .{});
- param_type.* = param_type_val.toIntern();
-
- if (param_is_noalias_val.toBool()) {
- if (!Type.fromInterned(param_type.*).isPtrAtRuntime(zcu)) {
- return sema.fail(block, src, "non-pointer parameter declared noalias", .{});
- }
- noalias_bits |= @as(u32, 1) << (std.math.cast(u5, i) orelse
- return sema.fail(block, src, "this compiler implementation only supports 'noalias' on the first 32 parameters", .{}));
- }
+fn zirReifyFn(
+ sema: *Sema,
+ block: *Block,
+ extended: Zir.Inst.Extended.InstData,
+) CompileError!Air.Inst.Ref {
+ const pt = sema.pt;
+ const zcu = pt.zcu;
+ const gpa = zcu.gpa;
+ const ip = &zcu.intern_pool;
+
+ const extra = sema.code.extraData(Zir.Inst.ReifyFn, extended.operand).data;
+ const param_types_src = block.builtinCallArgSrc(extra.node, 0);
+ const param_attrs_src = block.builtinCallArgSrc(extra.node, 1);
+ const ret_ty_src = block.builtinCallArgSrc(extra.node, 2);
+ const fn_attrs_src = block.builtinCallArgSrc(extra.node, 3);
+
+ const single_param_attrs_ty = try sema.getBuiltinType(param_attrs_src, .@"Type.Fn.Param.Attributes");
+ const fn_attrs_ty = try sema.getBuiltinType(fn_attrs_src, .@"Type.Fn.Attributes");
+
+ const param_types_uncoerced = try sema.resolveInst(extra.param_types);
+ const param_types_coerced = try sema.coerce(block, .slice_const_type, param_types_uncoerced, param_types_src);
+ const param_types_slice = try sema.resolveConstDefinedValue(block, param_types_src, param_types_coerced, .{ .simple = .fn_param_types });
+ const param_types_arr = try sema.derefSliceAsArray(block, param_types_src, param_types_slice, .{ .simple = .fn_param_types });
+
+ const params_len = param_types_arr.typeOf(zcu).arrayLen(zcu);
+
+ const param_attrs_ty = try pt.singleConstPtrType(try pt.arrayType(.{
+ .len = params_len,
+ .child = single_param_attrs_ty.toIntern(),
+ }));
+ const param_attrs_uncoerced = try sema.resolveInst(extra.param_attrs);
+ const param_attrs_coerced = try sema.coerce(block, param_attrs_ty, param_attrs_uncoerced, param_attrs_src);
+ const param_attrs_slice = try sema.resolveConstDefinedValue(block, param_attrs_src, param_attrs_coerced, .{ .simple = .fn_param_attrs });
+ const param_attrs_arr = try sema.derefSliceAsArray(block, param_attrs_src, param_attrs_slice, .{ .simple = .fn_param_attrs });
+
+ const ret_ty = try sema.resolveType(block, ret_ty_src, extra.ret_ty);
+
+ const fn_attrs_uncoerced = try sema.resolveInst(extra.fn_attrs);
+ const fn_attrs_coerced = try sema.coerce(block, fn_attrs_ty, fn_attrs_uncoerced, fn_attrs_src);
+ const fn_attrs_val = try sema.resolveConstDefinedValue(block, fn_attrs_src, fn_attrs_coerced, .{ .simple = .fn_attrs });
+ const fn_attrs = try sema.interpretBuiltinType(block, fn_attrs_src, fn_attrs_val, std.builtin.Type.Fn.Attributes);
+
+ var noalias_bits: u32 = 0;
+ const param_types_ip = try sema.arena.alloc(InternPool.Index, @intCast(params_len));
+ for (param_types_ip, 0..@intCast(params_len)) |*param_ty_ip, param_idx| {
+ const param_ty: Type = (try param_types_arr.elemValue(pt, param_idx)).toType();
+ const param_attrs = try sema.interpretBuiltinType(
+ block,
+ param_attrs_src,
+ try param_attrs_arr.elemValue(pt, param_idx),
+ std.builtin.Type.Fn.Param.Attributes,
+ );
+ try sema.checkParamTypeCommon(
+ block,
+ @intCast(param_idx),
+ param_ty,
+ param_attrs.@"noalias",
+ param_types_src,
+ fn_attrs.@"callconv",
+ );
+ if (try param_ty.comptimeOnlySema(pt)) {
+ return sema.fail(block, param_attrs_src, "cannot reify function type with comptime-only parameter type '{f}'", .{param_ty.fmt(pt)});
+ }
+ if (param_attrs.@"noalias") {
+ if (param_idx > 31) {
+ return sema.fail(block, param_attrs_src, "this compiler implementation only supports 'noalias' on the first 32 parameters", .{});
}
+ noalias_bits |= @as(u32, 1) << @intCast(param_idx);
+ }
+ param_ty_ip.* = param_ty.toIntern();
+ }
- const ty = try pt.funcType(.{
- .param_types = param_types,
- .noalias_bits = noalias_bits,
- .return_type = return_type.toIntern(),
- .cc = cc,
- .is_var_args = is_var_args,
- });
- return Air.internedToRef(ty.toIntern());
- },
- .frame => return sema.failWithUseOfAsync(block, src),
+ if (fn_attrs.varargs) {
+ try sema.checkCallConvSupportsVarArgs(block, fn_attrs_src, fn_attrs.@"callconv");
}
+
+ try sema.checkReturnTypeAndCallConvCommon(
+ block,
+ ret_ty,
+ ret_ty_src,
+ fn_attrs.@"callconv",
+ fn_attrs_src,
+ if (fn_attrs.varargs) fn_attrs_src else null,
+ false,
+ false,
+ );
+ if (try ret_ty.comptimeOnlySema(pt)) {
+ return sema.fail(block, param_attrs_src, "cannot reify function type with comptime-only return type '{f}'", .{ret_ty.fmt(pt)});
+ }
+
+ return .fromIntern(try ip.getFuncType(gpa, pt.tid, .{
+ .param_types = param_types_ip,
+ .noalias_bits = noalias_bits,
+ .comptime_bits = 0,
+ .return_type = ret_ty.toIntern(),
+ .cc = fn_attrs.@"callconv",
+ .is_var_args = fn_attrs.varargs,
+ .is_generic = false,
+ .is_noinline = false,
+ }));
}
-fn reifyEnum(
+fn zirReifyStruct(
sema: *Sema,
block: *Block,
+ extended: Zir.Inst.Extended.InstData,
inst: Zir.Inst.Index,
- src: LazySrcLoc,
- tag_ty: Type,
- is_exhaustive: bool,
- fields_val: Value,
- name_strategy: Zir.Inst.NameStrategy,
) CompileError!Air.Inst.Ref {
const pt = sema.pt;
const zcu = pt.zcu;
const gpa = sema.gpa;
const ip = &zcu.intern_pool;
- // This logic must stay in sync with the structure of `std.builtin.Type.Enum` - search for `fieldValue`.
+ const name_strategy: Zir.Inst.NameStrategy = @enumFromInt(extended.small);
+ const extra = sema.code.extraData(Zir.Inst.ReifyStruct, extended.operand).data;
+ const tracked_inst = try block.trackZir(inst);
+ const src: LazySrcLoc = .{
+ .base_node_inst = tracked_inst,
+ .offset = .nodeOffset(.zero),
+ };
+
+ const layout_src: LazySrcLoc = .{
+ .base_node_inst = tracked_inst,
+ .offset = .{ .node_offset_builtin_call_arg = .{
+ .builtin_call_node = .zero,
+ .arg_index = 0,
+ } },
+ };
+ const backing_ty_src: LazySrcLoc = .{
+ .base_node_inst = tracked_inst,
+ .offset = .{ .node_offset_builtin_call_arg = .{
+ .builtin_call_node = .zero,
+ .arg_index = 1,
+ } },
+ };
+ const field_names_src: LazySrcLoc = .{
+ .base_node_inst = tracked_inst,
+ .offset = .{ .node_offset_builtin_call_arg = .{
+ .builtin_call_node = .zero,
+ .arg_index = 2,
+ } },
+ };
+ const field_types_src: LazySrcLoc = .{
+ .base_node_inst = tracked_inst,
+ .offset = .{ .node_offset_builtin_call_arg = .{
+ .builtin_call_node = .zero,
+ .arg_index = 3,
+ } },
+ };
+ const field_attrs_src: LazySrcLoc = .{
+ .base_node_inst = tracked_inst,
+ .offset = .{ .node_offset_builtin_call_arg = .{
+ .builtin_call_node = .zero,
+ .arg_index = 4,
+ } },
+ };
+
+ const container_layout_ty = try sema.getBuiltinType(layout_src, .@"Type.ContainerLayout");
+ const single_field_attrs_ty = try sema.getBuiltinType(field_attrs_src, .@"Type.StructField.Attributes");
+
+ const layout_uncoerced = try sema.resolveInst(extra.layout);
+ const layout_coerced = try sema.coerce(block, container_layout_ty, layout_uncoerced, layout_src);
+ const layout_val = try sema.resolveConstDefinedValue(block, layout_src, layout_coerced, .{ .simple = .struct_layout });
+ const layout = try sema.interpretBuiltinType(block, layout_src, layout_val, std.builtin.Type.ContainerLayout);
+
+ const backing_int_ty_uncoerced = try sema.resolveInst(extra.backing_ty);
+ const backing_int_ty_coerced = try sema.coerce(block, .optional_type, backing_int_ty_uncoerced, backing_ty_src);
+ const backing_int_ty_val = try sema.resolveConstDefinedValue(block, backing_ty_src, backing_int_ty_coerced, .{ .simple = .type });
+
+ const field_names_uncoerced = try sema.resolveInst(extra.field_names);
+ const field_names_coerced = try sema.coerce(block, .slice_const_slice_const_u8, field_names_uncoerced, field_names_src);
+ const field_names_slice = try sema.resolveConstDefinedValue(block, field_names_src, field_names_coerced, .{ .simple = .struct_field_names });
+ const field_names_arr = try sema.derefSliceAsArray(block, field_names_src, field_names_slice, .{ .simple = .struct_field_names });
+
+ const fields_len = try sema.usizeCast(block, src, field_names_arr.typeOf(zcu).arrayLen(zcu));
+
+ const field_types_ty = try pt.singleConstPtrType(try pt.arrayType(.{
+ .len = fields_len,
+ .child = .type_type,
+ }));
+ const field_attrs_ty = try pt.singleConstPtrType(try pt.arrayType(.{
+ .len = fields_len,
+ .child = single_field_attrs_ty.toIntern(),
+ }));
+
+ const field_types_uncoerced = try sema.resolveInst(extra.field_types);
+ const field_types_coerced = try sema.coerce(block, field_types_ty, field_types_uncoerced, field_types_src);
+ const field_types_slice = try sema.resolveConstDefinedValue(block, field_types_src, field_types_coerced, .{ .simple = .struct_field_types });
+ const field_types_arr = try sema.derefSliceAsArray(block, field_types_src, field_types_slice, .{ .simple = .struct_field_types });
- const fields_len: u32 = @intCast(fields_val.typeOf(zcu).arrayLen(zcu));
+ const field_attrs_uncoerced = try sema.resolveInst(extra.field_attrs);
+ const field_attrs_coerced = try sema.coerce(block, field_attrs_ty, field_attrs_uncoerced, field_attrs_src);
+ const field_attrs_slice = try sema.resolveConstDefinedValue(block, field_attrs_src, field_attrs_coerced, .{ .simple = .struct_field_attrs });
+ const field_attrs_arr = try sema.derefSliceAsArray(block, field_attrs_src, field_attrs_slice, .{ .simple = .struct_field_attrs });
+
+ // Before we begin, check for undefs...
+ if (try sema.anyUndef(block, field_attrs_src, field_attrs_arr)) {
+ return sema.failWithUseOfUndef(block, field_attrs_src, null);
+ }
+ if (try sema.anyUndef(block, field_types_src, field_types_arr)) {
+ return sema.failWithUseOfUndef(block, field_types_src, null);
+ }
+ // We don't need to check `field_names_arr`, because `sliceToIpString` will check that for us.
+ if (try sema.anyUndef(block, backing_ty_src, backing_int_ty_val)) {
+ return sema.failWithUseOfUndef(block, backing_ty_src, null);
+ }
// The validation work here is non-trivial, and it's possible the type already exists.
// So in this first pass, let's just construct a hash to optimize for this case. If the
// inputs turn out to be invalid, we can cancel the WIP type later.
+ var any_comptime_fields = false;
+ var any_default_inits = false;
+ var any_aligned_fields = false;
+
// For deduplication purposes, we must create a hash including all details of this type.
// TODO: use a longer hash!
var hasher = std.hash.Wyhash.init(0);
- std.hash.autoHash(&hasher, tag_ty.toIntern());
- std.hash.autoHash(&hasher, is_exhaustive);
- std.hash.autoHash(&hasher, fields_len);
-
+ std.hash.autoHash(&hasher, layout);
+ std.hash.autoHash(&hasher, backing_int_ty_val);
+ // The field *type* array has already been deduplicated for us thanks to the InternPool!
+ std.hash.autoHash(&hasher, field_types_arr);
+ // However, for field names and attributes, we need to actually iterate the individual fields,
+ // because the presence of pointers (the `[]const u8` for the name and the `*const anyopaque`
+ // for the default value) means that distinct interned values could ultimately result in the
+ // same struct type.
for (0..fields_len) |field_idx| {
- const field_info = try fields_val.elemValue(pt, field_idx);
+ const field_name_val = try field_names_arr.elemValue(pt, field_idx);
+ const field_attrs_val = try field_attrs_arr.elemValue(pt, field_idx);
+
+ const field_name = try sema.sliceToIpString(block, field_names_src, field_name_val, .{ .simple = .struct_field_names });
+
+ const field_attr_comptime = try field_attrs_val.fieldValue(pt, std.meta.fieldIndex(
+ std.builtin.Type.StructField.Attributes,
+ "comptime",
+ ).?);
+ const field_attr_align = try field_attrs_val.fieldValue(pt, std.meta.fieldIndex(
+ std.builtin.Type.StructField.Attributes,
+ "align",
+ ).?);
+ const field_attr_default_value_ptr = try field_attrs_val.fieldValue(pt, std.meta.fieldIndex(
+ std.builtin.Type.StructField.Attributes,
+ "default_value_ptr",
+ ).?);
- const field_name_val = try field_info.fieldValue(pt, 0);
- const field_value_val = try sema.resolveLazyValue(try field_info.fieldValue(pt, 1));
-
- const field_name = try sema.sliceToIpString(block, src, field_name_val, .{ .simple = .enum_field_name });
+ const field_default: InternPool.Index = d: {
+ const ptr_val = field_attr_default_value_ptr.optionalValue(zcu) orelse break :d .none;
+ const field_ty = (try field_types_arr.elemValue(pt, field_idx)).toType();
+ const ptr_ty = try pt.singleConstPtrType(field_ty);
+ const deref_val = try sema.pointerDeref(block, field_attrs_src, ptr_val, ptr_ty) orelse return sema.failWithNeededComptime(
+ block,
+ field_attrs_src,
+ .{ .simple = .struct_field_default_value },
+ );
+ // Resolve the value so that lazy values do not create distinct types.
+ break :d (try sema.resolveLazyValue(deref_val)).toIntern();
+ };
std.hash.autoHash(&hasher, .{
field_name,
- field_value_val.toIntern(),
+ field_attr_comptime,
+ field_attr_align,
+ field_default,
});
+
+ if (field_attr_comptime.toBool()) any_comptime_fields = true;
+ if (field_attr_align.optionalValue(zcu)) |_| any_aligned_fields = true;
+ if (field_default != .none) any_default_inits = true;
}
- const tracked_inst = try block.trackZir(inst);
+ // Some basic validation to avoid a bogus `getStructType` call...
+ const backing_int_ty: ?Type = if (backing_int_ty_val.optionalValue(zcu)) |backing| ty: {
+ switch (layout) {
+ .auto, .@"extern" => return sema.fail(block, backing_ty_src, "non-packed struct does not support backing integer type", .{}),
+ .@"packed" => {},
+ }
+ break :ty backing.toType();
+ } else null;
+ if (any_aligned_fields and layout == .@"packed") {
+ return sema.fail(block, field_attrs_src, "packed struct fields cannot be aligned", .{});
+ }
+ if (any_comptime_fields and layout != .auto) {
+ return sema.fail(block, field_attrs_src, "{t} struct fields cannot be marked comptime", .{layout});
+ }
- const wip_ty = switch (try ip.getEnumType(gpa, pt.tid, .{
- .has_values = true,
- .tag_mode = if (is_exhaustive) .explicit else .nonexhaustive,
- .fields_len = fields_len,
+ const wip_ty = switch (try ip.getStructType(gpa, pt.tid, .{
+ .layout = layout,
+ .fields_len = @intCast(fields_len),
+ .known_non_opv = false,
+ .requires_comptime = .unknown,
+ .any_comptime_fields = any_comptime_fields,
+ .any_default_inits = any_default_inits,
+ .any_aligned_fields = any_aligned_fields,
+ .inits_resolved = true,
.key = .{ .reified = .{
.zir_index = tracked_inst,
.type_hash = hasher.final(),
@@ -21148,79 +21077,144 @@ fn reifyEnum(
return Air.internedToRef(ty);
},
};
- var done = false;
- errdefer if (!done) wip_ty.cancel(ip, pt.tid);
-
- if (tag_ty.zigTypeTag(zcu) != .int) {
- return sema.fail(block, src, "Type.Enum.tag_type must be an integer type", .{});
- }
+ errdefer wip_ty.cancel(ip, pt.tid);
const type_name = try sema.createTypeName(
block,
name_strategy,
- "enum",
+ "struct",
inst,
wip_ty.index,
);
wip_ty.setName(ip, type_name.name, type_name.nav);
- const new_namespace_index = try pt.createNamespace(.{
- .parent = block.namespace.toOptional(),
- .owner_type = wip_ty.index,
- .file_scope = block.getFileScopeIndex(zcu),
- .generation = zcu.generation,
- });
-
- try sema.declareDependency(.{ .interned = wip_ty.index });
- try sema.addTypeReferenceEntry(src, wip_ty.index);
- if (zcu.comp.debugIncremental()) try zcu.incremental_debug_state.newType(zcu, wip_ty.index);
- wip_ty.prepare(ip, new_namespace_index);
- wip_ty.setTagTy(ip, tag_ty.toIntern());
- done = true;
+ const wip_struct_type = ip.loadStructType(wip_ty.index);
for (0..fields_len) |field_idx| {
- const field_info = try fields_val.elemValue(pt, field_idx);
+ const field_name_val = try field_names_arr.elemValue(pt, field_idx);
+ const field_attrs_val = try field_attrs_arr.elemValue(pt, field_idx);
- const field_name_val = try field_info.fieldValue(pt, 0);
- const field_value_val = try sema.resolveLazyValue(try field_info.fieldValue(pt, 1));
+ const field_ty = (try field_types_arr.elemValue(pt, field_idx)).toType();
- // Don't pass a reason; first loop acts as an assertion that this is valid.
- const field_name = try sema.sliceToIpString(block, src, field_name_val, undefined);
+ // Don't pass a reason; first loop acts as a check that this is valid.
+ const field_name = try sema.sliceToIpString(block, field_names_src, field_name_val, undefined);
+ if (wip_struct_type.addFieldName(ip, field_name)) |prev_index| {
+ _ = prev_index; // TODO: better source location
+ return sema.fail(block, field_names_src, "duplicate struct field name {f}", .{field_name.fmt(ip)});
+ }
+
+ const field_attr_comptime = try field_attrs_val.fieldValue(pt, std.meta.fieldIndex(
+ std.builtin.Type.StructField.Attributes,
+ "comptime",
+ ).?);
+ const field_attr_align = try field_attrs_val.fieldValue(pt, std.meta.fieldIndex(
+ std.builtin.Type.StructField.Attributes,
+ "align",
+ ).?);
+ const field_attr_default_value_ptr = try field_attrs_val.fieldValue(pt, std.meta.fieldIndex(
+ std.builtin.Type.StructField.Attributes,
+ "default_value_ptr",
+ ).?);
+
+ if (field_attr_align.optionalValue(zcu)) |field_align_val| {
+ assert(layout != .@"packed");
+ const bytes = try field_align_val.toUnsignedIntSema(pt);
+ const a = try sema.validateAlign(block, field_attrs_src, bytes);
+ wip_struct_type.field_aligns.get(ip)[field_idx] = a;
+ } else if (any_aligned_fields) {
+ assert(layout != .@"packed");
+ wip_struct_type.field_aligns.get(ip)[field_idx] = .none;
+ }
- if (!try sema.intFitsInType(field_value_val, tag_ty, null)) {
- // TODO: better source location
- return sema.fail(block, src, "field '{f}' with enumeration value '{f}' is too large for backing int type '{f}'", .{
- field_name.fmt(ip),
- field_value_val.fmtValueSema(pt, sema),
- tag_ty.fmt(pt),
- });
+ const field_default: InternPool.Index = d: {
+ const ptr_val = field_attr_default_value_ptr.optionalValue(zcu) orelse break :d .none;
+ assert(any_default_inits);
+ const ptr_ty = try pt.singleConstPtrType(field_ty);
+ // The first loop checked that this is comptime-dereferencable.
+ const deref_val = (try sema.pointerDeref(block, field_attrs_src, ptr_val, ptr_ty)).?;
+ // ...but we've not checked this yet!
+ if (deref_val.canMutateComptimeVarState(zcu)) {
+ return sema.failWithContainsReferenceToComptimeVar(block, field_attrs_src, field_name, "field default value", deref_val);
+ }
+ break :d (try sema.resolveLazyValue(deref_val)).toIntern();
+ };
+
+ if (field_attr_comptime.toBool()) {
+ assert(layout == .auto);
+ if (field_default == .none) {
+ return sema.fail(block, field_attrs_src, "comptime field without default initialization value", .{});
+ }
+ wip_struct_type.setFieldComptime(ip, field_idx);
}
- const coerced_field_val = try pt.getCoerced(field_value_val, tag_ty);
- if (wip_ty.nextField(ip, field_name, coerced_field_val.toIntern())) |conflict| {
- return sema.failWithOwnedErrorMsg(block, switch (conflict.kind) {
- .name => msg: {
- const msg = try sema.errMsg(src, "duplicate enum field '{f}'", .{field_name.fmt(ip)});
+ wip_struct_type.field_types.get(ip)[field_idx] = field_ty.toIntern();
+ if (field_default != .none) {
+ wip_struct_type.field_inits.get(ip)[field_idx] = field_default;
+ }
+
+ switch (field_ty.zigTypeTag(zcu)) {
+ .@"opaque" => return sema.failWithOwnedErrorMsg(block, msg: {
+ const msg = try sema.errMsg(field_types_src, "opaque types have unknown size and therefore cannot be directly embedded in structs", .{});
+ errdefer msg.destroy(gpa);
+ try sema.addDeclaredHereNote(msg, field_ty);
+ break :msg msg;
+ }),
+ .noreturn => return sema.failWithOwnedErrorMsg(block, msg: {
+ const msg = try sema.errMsg(field_types_src, "struct fields cannot be 'noreturn'", .{});
+ errdefer msg.destroy(gpa);
+ try sema.addDeclaredHereNote(msg, field_ty);
+ break :msg msg;
+ }),
+ else => {},
+ }
+
+ switch (layout) {
+ .auto => {},
+ .@"extern" => if (!try sema.validateExternType(field_ty, .struct_field)) {
+ return sema.failWithOwnedErrorMsg(block, msg: {
+ const msg = try sema.errMsg(field_types_src, "extern structs cannot contain fields of type '{f}'", .{field_ty.fmt(pt)});
errdefer msg.destroy(gpa);
- _ = conflict.prev_field_idx; // TODO: this note is incorrect
- try sema.errNote(src, msg, "other field here", .{});
+ try sema.explainWhyTypeIsNotExtern(msg, field_types_src, field_ty, .struct_field);
+ try sema.addDeclaredHereNote(msg, field_ty);
break :msg msg;
- },
- .value => msg: {
- const msg = try sema.errMsg(src, "enum tag value {f} already taken", .{field_value_val.fmtValueSema(pt, sema)});
+ });
+ },
+ .@"packed" => if (!try sema.validatePackedType(field_ty)) {
+ return sema.failWithOwnedErrorMsg(block, msg: {
+ const msg = try sema.errMsg(field_types_src, "packed structs cannot contain fields of type '{f}'", .{field_ty.fmt(pt)});
errdefer msg.destroy(gpa);
- _ = conflict.prev_field_idx; // TODO: this note is incorrect
- try sema.errNote(src, msg, "other enum tag value here", .{});
+ try sema.explainWhyTypeIsNotPacked(msg, field_types_src, field_ty);
+ try sema.addDeclaredHereNote(msg, field_ty);
break :msg msg;
- },
- });
+ });
+ },
}
}
- if (!is_exhaustive and fields_len > 1 and std.math.log2_int(u64, fields_len) == tag_ty.bitSize(zcu)) {
- return sema.fail(block, src, "non-exhaustive enum specified every value", .{});
+ if (layout == .@"packed") {
+ var fields_bit_sum: u64 = 0;
+ for (0..wip_struct_type.field_types.len) |field_idx| {
+ const field_ty: Type = .fromInterned(wip_struct_type.field_types.get(ip)[field_idx]);
+ try field_ty.resolveLayout(pt);
+ fields_bit_sum += field_ty.bitSize(zcu);
+ }
+ if (backing_int_ty) |ty| {
+ try sema.checkBackingIntType(block, src, ty, fields_bit_sum);
+ wip_struct_type.setBackingIntType(ip, ty.toIntern());
+ } else {
+ const ty = try pt.intType(.unsigned, @intCast(fields_bit_sum));
+ wip_struct_type.setBackingIntType(ip, ty.toIntern());
+ }
}
+ const new_namespace_index = try pt.createNamespace(.{
+ .parent = block.namespace.toOptional(),
+ .owner_type = wip_ty.index,
+ .file_scope = block.getFileScopeIndex(zcu),
+ .generation = zcu.generation,
+ });
+
+ try zcu.comp.queueJob(.{ .resolve_type_fully = wip_ty.index });
codegen_type: {
if (zcu.comp.config.use_llvm) break :codegen_type;
if (block.ownerModule().strip) break :codegen_type;
@@ -21228,75 +21222,177 @@ fn reifyEnum(
zcu.comp.link_prog_node.increaseEstimatedTotalItems(1);
try zcu.comp.queueJob(.{ .link_type = wip_ty.index });
}
- return Air.internedToRef(wip_ty.index);
+ try sema.declareDependency(.{ .interned = wip_ty.index });
+ try sema.addTypeReferenceEntry(src, wip_ty.index);
+ if (zcu.comp.debugIncremental()) try zcu.incremental_debug_state.newType(zcu, wip_ty.index);
+ return .fromIntern(wip_ty.finish(ip, new_namespace_index));
}
-fn reifyUnion(
+fn zirReifyUnion(
sema: *Sema,
block: *Block,
+ extended: Zir.Inst.Extended.InstData,
inst: Zir.Inst.Index,
- src: LazySrcLoc,
- layout: std.builtin.Type.ContainerLayout,
- opt_tag_type_val: Value,
- fields_val: Value,
- name_strategy: Zir.Inst.NameStrategy,
) CompileError!Air.Inst.Ref {
const pt = sema.pt;
const zcu = pt.zcu;
const gpa = sema.gpa;
const ip = &zcu.intern_pool;
- // This logic must stay in sync with the structure of `std.builtin.Type.Union` - search for `fieldValue`.
+ const name_strategy: Zir.Inst.NameStrategy = @enumFromInt(extended.small);
+ const extra = sema.code.extraData(Zir.Inst.ReifyUnion, extended.operand).data;
+ const tracked_inst = try block.trackZir(inst);
+ const src: LazySrcLoc = .{
+ .base_node_inst = tracked_inst,
+ .offset = .nodeOffset(.zero),
+ };
+
+ const layout_src: LazySrcLoc = .{
+ .base_node_inst = tracked_inst,
+ .offset = .{ .node_offset_builtin_call_arg = .{
+ .builtin_call_node = .zero,
+ .arg_index = 0,
+ } },
+ };
+ const arg_ty_src: LazySrcLoc = .{
+ .base_node_inst = tracked_inst,
+ .offset = .{ .node_offset_builtin_call_arg = .{
+ .builtin_call_node = .zero,
+ .arg_index = 1,
+ } },
+ };
+ const field_names_src: LazySrcLoc = .{
+ .base_node_inst = tracked_inst,
+ .offset = .{ .node_offset_builtin_call_arg = .{
+ .builtin_call_node = .zero,
+ .arg_index = 2,
+ } },
+ };
+ const field_types_src: LazySrcLoc = .{
+ .base_node_inst = tracked_inst,
+ .offset = .{ .node_offset_builtin_call_arg = .{
+ .builtin_call_node = .zero,
+ .arg_index = 3,
+ } },
+ };
+ const field_attrs_src: LazySrcLoc = .{
+ .base_node_inst = tracked_inst,
+ .offset = .{ .node_offset_builtin_call_arg = .{
+ .builtin_call_node = .zero,
+ .arg_index = 4,
+ } },
+ };
+
+ const container_layout_ty = try sema.getBuiltinType(layout_src, .@"Type.ContainerLayout");
+ const single_field_attrs_ty = try sema.getBuiltinType(field_attrs_src, .@"Type.UnionField.Attributes");
+
+ const layout_uncoerced = try sema.resolveInst(extra.layout);
+ const layout_coerced = try sema.coerce(block, container_layout_ty, layout_uncoerced, layout_src);
+ const layout_val = try sema.resolveConstDefinedValue(block, layout_src, layout_coerced, .{ .simple = .union_layout });
+ const layout = try sema.interpretBuiltinType(block, layout_src, layout_val, std.builtin.Type.ContainerLayout);
+
+ const arg_ty_uncoerced = try sema.resolveInst(extra.arg_ty);
+ const arg_ty_coerced = try sema.coerce(block, .optional_type, arg_ty_uncoerced, arg_ty_src);
+ const arg_ty_val = try sema.resolveConstDefinedValue(block, arg_ty_src, arg_ty_coerced, .{ .simple = .type });
+
+ const field_names_uncoerced = try sema.resolveInst(extra.field_names);
+ const field_names_coerced = try sema.coerce(block, .slice_const_slice_const_u8, field_names_uncoerced, field_names_src);
+ const field_names_slice = try sema.resolveConstDefinedValue(block, field_names_src, field_names_coerced, .{ .simple = .union_field_names });
+ const field_names_arr = try sema.derefSliceAsArray(block, field_names_src, field_names_slice, .{ .simple = .union_field_names });
+
+ const fields_len = try sema.usizeCast(block, src, field_names_arr.typeOf(zcu).arrayLen(zcu));
+
+ const field_types_ty = try pt.singleConstPtrType(try pt.arrayType(.{
+ .len = fields_len,
+ .child = .type_type,
+ }));
+ const field_attrs_ty = try pt.singleConstPtrType(try pt.arrayType(.{
+ .len = fields_len,
+ .child = single_field_attrs_ty.toIntern(),
+ }));
+
+ const field_types_uncoerced = try sema.resolveInst(extra.field_types);
+ const field_types_coerced = try sema.coerce(block, field_types_ty, field_types_uncoerced, field_types_src);
+ const field_types_slice = try sema.resolveConstDefinedValue(block, field_types_src, field_types_coerced, .{ .simple = .union_field_types });
+ const field_types_arr = try sema.derefSliceAsArray(block, field_types_src, field_types_slice, .{ .simple = .union_field_types });
- const fields_len: u32 = @intCast(fields_val.typeOf(zcu).arrayLen(zcu));
+ const field_attrs_uncoerced = try sema.resolveInst(extra.field_attrs);
+ const field_attrs_coerced = try sema.coerce(block, field_attrs_ty, field_attrs_uncoerced, field_attrs_src);
+ const field_attrs_slice = try sema.resolveConstDefinedValue(block, field_attrs_src, field_attrs_coerced, .{ .simple = .union_field_attrs });
+ const field_attrs_arr = try sema.derefSliceAsArray(block, field_attrs_src, field_attrs_slice, .{ .simple = .union_field_attrs });
+
+ // Before we begin, check for undefs...
+ if (try sema.anyUndef(block, field_attrs_src, field_attrs_arr)) {
+ return sema.failWithUseOfUndef(block, field_attrs_src, null);
+ }
+ if (try sema.anyUndef(block, field_types_src, field_types_arr)) {
+ return sema.failWithUseOfUndef(block, field_types_src, null);
+ }
+ // We don't need to check `field_names_arr`, because `sliceToIpString` will check that for us.
+ if (try sema.anyUndef(block, arg_ty_src, arg_ty_val)) {
+ return sema.failWithUseOfUndef(block, arg_ty_src, null);
+ }
// The validation work here is non-trivial, and it's possible the type already exists.
// So in this first pass, let's just construct a hash to optimize for this case. If the
// inputs turn out to be invalid, we can cancel the WIP type later.
+ var any_aligned_fields = false;
+
// For deduplication purposes, we must create a hash including all details of this type.
// TODO: use a longer hash!
var hasher = std.hash.Wyhash.init(0);
std.hash.autoHash(&hasher, layout);
- std.hash.autoHash(&hasher, opt_tag_type_val.toIntern());
- std.hash.autoHash(&hasher, fields_len);
-
+ std.hash.autoHash(&hasher, arg_ty_val);
+ // `field_types_arr` and `field_attrs_arr` are already deduplicated by the InternPool!
+ std.hash.autoHash(&hasher, field_types_arr);
+ std.hash.autoHash(&hasher, field_attrs_arr);
+ // However, for field names, we need to iterate the individual fields, because the pointers (the
+ // names are slices) mean that distinct values could ultimately result in the same union type.
for (0..fields_len) |field_idx| {
- const field_info = try fields_val.elemValue(pt, field_idx);
-
- const field_name_val = try field_info.fieldValue(pt, 0);
- const field_type_val = try field_info.fieldValue(pt, 1);
- const field_align_val = try sema.resolveLazyValue(try field_info.fieldValue(pt, 2));
+ const field_name_val = try field_names_arr.elemValue(pt, field_idx);
+ const field_name = try sema.sliceToIpString(block, field_names_src, field_name_val, .{ .simple = .union_field_names });
+ std.hash.autoHash(&hasher, field_name);
- const field_name = try sema.sliceToIpString(block, src, field_name_val, .{ .simple = .union_field_name });
- std.hash.autoHash(&hasher, .{
- field_name,
- field_type_val.toIntern(),
- field_align_val.toIntern(),
- });
+ const field_attrs = try sema.interpretBuiltinType(
+ block,
+ field_attrs_src,
+ try field_attrs_arr.elemValue(pt, field_idx),
+ std.builtin.Type.UnionField.Attributes,
+ );
+ if (field_attrs.@"align" != null) {
+ any_aligned_fields = true;
+ }
}
- const tracked_inst = try block.trackZir(inst);
+ // Some basic validation to avoid a bogus `getUnionType` call...
+ const explicit_tag_ty: ?Type = if (arg_ty_val.optionalValue(zcu)) |arg_ty| ty: {
+ switch (layout) {
+ .@"extern", .@"packed" => return sema.fail(block, arg_ty_src, "{t} union does not support enum tag type", .{layout}),
+ .auto => {},
+ }
+ break :ty arg_ty.toType();
+ } else null;
+ if (any_aligned_fields and layout == .@"packed") {
+ return sema.fail(block, field_attrs_src, "packed union fields cannot be aligned", .{});
+ }
const wip_ty = switch (try ip.getUnionType(gpa, pt.tid, .{
.flags = .{
.layout = layout,
.status = .none,
- .runtime_tag = if (opt_tag_type_val.optionalValue(zcu) != null)
- .tagged
- else if (layout != .auto)
- .none
- else switch (block.wantSafeTypes()) {
- true => .safety,
- false => .none,
+ .runtime_tag = rt: {
+ if (explicit_tag_ty != null) break :rt .tagged;
+ if (layout == .auto and block.wantSafeTypes()) break :rt .safety;
+ break :rt .none;
},
- .any_aligned_fields = layout != .@"packed",
+ .any_aligned_fields = any_aligned_fields,
.requires_comptime = .unknown,
.assumed_runtime_bits = false,
.assumed_pointer_aligned = false,
.alignment = .none,
},
- .fields_len = fields_len,
+ .fields_len = @intCast(fields_len),
.enum_tag_ty = .none, // set later because not yet validated
.field_types = &.{}, // set later
.field_aligns = &.{}, // set later
@@ -21325,128 +21421,117 @@ fn reifyUnion(
const loaded_union = ip.loadUnionType(wip_ty.index);
- const enum_tag_ty, const has_explicit_tag = if (opt_tag_type_val.optionalValue(zcu)) |tag_type_val| tag_ty: {
- switch (ip.indexToKey(tag_type_val.toIntern())) {
- .enum_type => {},
- else => return sema.fail(block, src, "Type.Union.tag_type must be an enum type", .{}),
+ const enum_tag_ty, const has_explicit_tag = if (explicit_tag_ty) |enum_tag_ty| tag: {
+ if (enum_tag_ty.zigTypeTag(zcu) != .@"enum") {
+ return sema.fail(block, arg_ty_src, "tag type must be an enum type", .{});
}
- const enum_tag_ty = tag_type_val.toType();
- // We simply track which fields of the tag type have been seen.
const tag_ty_fields_len = enum_tag_ty.enumFieldCount(zcu);
- var seen_tags = try std.DynamicBitSetUnmanaged.initEmpty(sema.arena, tag_ty_fields_len);
for (0..fields_len) |field_idx| {
- const field_info = try fields_val.elemValue(pt, field_idx);
+ const field_name_val = try field_names_arr.elemValue(pt, field_idx);
+ // Don't pass a reason; first loop acts as a check that this is valid.
+ const field_name = try sema.sliceToIpString(block, field_names_src, field_name_val, undefined);
- const field_name_val = try field_info.fieldValue(pt, 0);
- const field_type_val = try field_info.fieldValue(pt, 1);
- const field_alignment_val = try field_info.fieldValue(pt, 2);
-
- // Don't pass a reason; first loop acts as an assertion that this is valid.
- const field_name = try sema.sliceToIpString(block, src, field_name_val, undefined);
-
- const enum_index = enum_tag_ty.enumFieldIndex(field_name, zcu) orelse {
- // TODO: better source location
- return sema.fail(block, src, "no field named '{f}' in enum '{f}'", .{
+ if (field_idx >= tag_ty_fields_len) {
+ return sema.fail(block, field_names_src, "no field named '{f}' in enum '{f}'", .{
field_name.fmt(ip), enum_tag_ty.fmt(pt),
});
- };
- if (seen_tags.isSet(enum_index)) {
- // TODO: better source location
- return sema.fail(block, src, "duplicate union field {f}", .{field_name.fmt(ip)});
}
- seen_tags.set(enum_index);
- loaded_union.field_types.get(ip)[field_idx] = field_type_val.toIntern();
- const byte_align = try field_alignment_val.toUnsignedIntSema(pt);
- if (layout == .@"packed") {
- if (byte_align != 0) return sema.fail(block, src, "alignment of a packed union field must be set to 0", .{});
- } else {
- loaded_union.field_aligns.get(ip)[field_idx] = try sema.validateAlign(block, src, byte_align);
+ const enum_field_name = enum_tag_ty.enumFieldName(field_idx, zcu);
+ if (enum_field_name != field_name) {
+ return sema.fail(block, field_names_src, "union field name '{f}' does not match enum field name '{f}'", .{
+ field_name.fmt(ip), enum_field_name.fmt(ip),
+ });
}
}
-
if (tag_ty_fields_len > fields_len) return sema.failWithOwnedErrorMsg(block, msg: {
- const msg = try sema.errMsg(src, "enum fields missing in union", .{});
+ const msg = try sema.errMsg(field_names_src, "{d} enum fields missing in union", .{
+ tag_ty_fields_len - fields_len,
+ });
errdefer msg.destroy(gpa);
- var it = seen_tags.iterator(.{ .kind = .unset });
- while (it.next()) |enum_index| {
- const field_name = enum_tag_ty.enumFieldName(enum_index, zcu);
- try sema.addFieldErrNote(enum_tag_ty, enum_index, msg, "field '{f}' missing, declared here", .{
- field_name.fmt(ip),
+ for (fields_len..tag_ty_fields_len) |enum_field_idx| {
+ try sema.addFieldErrNote(enum_tag_ty, enum_field_idx, msg, "field '{f}' missing, declared here", .{
+ enum_tag_ty.enumFieldName(enum_field_idx, zcu).fmt(ip),
});
}
try sema.addDeclaredHereNote(msg, enum_tag_ty);
break :msg msg;
});
-
- break :tag_ty .{ enum_tag_ty.toIntern(), true };
- } else tag_ty: {
+ break :tag .{ enum_tag_ty.toIntern(), true };
+ } else tag: {
// We must track field names and set up the tag type ourselves.
var field_names: std.AutoArrayHashMapUnmanaged(InternPool.NullTerminatedString, void) = .empty;
try field_names.ensureTotalCapacity(sema.arena, fields_len);
for (0..fields_len) |field_idx| {
- const field_info = try fields_val.elemValue(pt, field_idx);
-
- const field_name_val = try field_info.fieldValue(pt, 0);
- const field_type_val = try field_info.fieldValue(pt, 1);
- const field_alignment_val = try field_info.fieldValue(pt, 2);
-
- // Don't pass a reason; first loop acts as an assertion that this is valid.
- const field_name = try sema.sliceToIpString(block, src, field_name_val, undefined);
+ const field_name_val = try field_names_arr.elemValue(pt, field_idx);
+ // Don't pass a reason; first loop acts as a check that this is valid.
+ const field_name = try sema.sliceToIpString(block, field_names_src, field_name_val, undefined);
const gop = field_names.getOrPutAssumeCapacity(field_name);
if (gop.found_existing) {
// TODO: better source location
- return sema.fail(block, src, "duplicate union field {f}", .{field_name.fmt(ip)});
- }
-
- loaded_union.field_types.get(ip)[field_idx] = field_type_val.toIntern();
- const byte_align = try field_alignment_val.toUnsignedIntSema(pt);
- if (layout == .@"packed") {
- if (byte_align != 0) return sema.fail(block, src, "alignment of a packed union field must be set to 0", .{});
- } else {
- loaded_union.field_aligns.get(ip)[field_idx] = try sema.validateAlign(block, src, byte_align);
+ return sema.fail(block, field_names_src, "duplicate union field {f}", .{field_name.fmt(ip)});
}
}
-
const enum_tag_ty = try sema.generateUnionTagTypeSimple(block, field_names.keys(), wip_ty.index, type_name.name);
- break :tag_ty .{ enum_tag_ty, false };
+ break :tag .{ enum_tag_ty, false };
};
errdefer if (!has_explicit_tag) ip.remove(pt.tid, enum_tag_ty); // remove generated tag type on error
- for (loaded_union.field_types.get(ip)) |field_ty_ip| {
- const field_ty: Type = .fromInterned(field_ty_ip);
+ for (0..fields_len) |field_idx| {
+ const field_ty = (try field_types_arr.elemValue(pt, field_idx)).toType();
+ const field_attrs = try sema.interpretBuiltinType(
+ block,
+ field_attrs_src,
+ try field_attrs_arr.elemValue(pt, field_idx),
+ std.builtin.Type.UnionField.Attributes,
+ );
+
if (field_ty.zigTypeTag(zcu) == .@"opaque") {
return sema.failWithOwnedErrorMsg(block, msg: {
- const msg = try sema.errMsg(src, "opaque types have unknown size and therefore cannot be directly embedded in unions", .{});
+ const msg = try sema.errMsg(field_types_src, "opaque types have unknown size and therefore cannot be directly embedded in unions", .{});
errdefer msg.destroy(gpa);
-
try sema.addDeclaredHereNote(msg, field_ty);
break :msg msg;
});
}
- if (layout == .@"extern" and !try sema.validateExternType(field_ty, .union_field)) {
- return sema.failWithOwnedErrorMsg(block, msg: {
- const msg = try sema.errMsg(src, "extern unions cannot contain fields of type '{f}'", .{field_ty.fmt(pt)});
- errdefer msg.destroy(gpa);
- try sema.explainWhyTypeIsNotExtern(msg, src, field_ty, .union_field);
+ switch (layout) {
+ .auto => {},
+ .@"extern" => if (!try sema.validateExternType(field_ty, .union_field)) {
+ return sema.failWithOwnedErrorMsg(block, msg: {
+ const msg = try sema.errMsg(field_types_src, "extern unions cannot contain fields of type '{f}'", .{field_ty.fmt(pt)});
+ errdefer msg.destroy(gpa);
+
+ try sema.explainWhyTypeIsNotExtern(msg, field_types_src, field_ty, .union_field);
- try sema.addDeclaredHereNote(msg, field_ty);
- break :msg msg;
- });
- } else if (layout == .@"packed" and !try sema.validatePackedType(field_ty)) {
- return sema.failWithOwnedErrorMsg(block, msg: {
- const msg = try sema.errMsg(src, "packed unions cannot contain fields of type '{f}'", .{field_ty.fmt(pt)});
- errdefer msg.destroy(gpa);
+ try sema.addDeclaredHereNote(msg, field_ty);
+ break :msg msg;
+ });
+ },
+ .@"packed" => if (!try sema.validatePackedType(field_ty)) {
+ return sema.failWithOwnedErrorMsg(block, msg: {
+ const msg = try sema.errMsg(field_types_src, "packed unions cannot contain fields of type '{f}'", .{field_ty.fmt(pt)});
+ errdefer msg.destroy(gpa);
- try sema.explainWhyTypeIsNotPacked(msg, src, field_ty);
+ try sema.explainWhyTypeIsNotPacked(msg, field_types_src, field_ty);
- try sema.addDeclaredHereNote(msg, field_ty);
- break :msg msg;
- });
+ try sema.addDeclaredHereNote(msg, field_ty);
+ break :msg msg;
+ });
+ },
+ }
+
+ loaded_union.field_types.get(ip)[field_idx] = field_ty.toIntern();
+ if (field_attrs.@"align") |bytes| {
+ assert(layout != .@"packed");
+ const a = try sema.validateAlign(block, field_attrs_src, bytes);
+ loaded_union.field_aligns.get(ip)[field_idx] = a;
+ } else if (any_aligned_fields) {
+ assert(layout != .@"packed");
+ loaded_union.field_aligns.get(ip)[field_idx] = .none;
}
}
@@ -21471,116 +21556,94 @@ fn reifyUnion(
try sema.declareDependency(.{ .interned = wip_ty.index });
try sema.addTypeReferenceEntry(src, wip_ty.index);
if (zcu.comp.debugIncremental()) try zcu.incremental_debug_state.newType(zcu, wip_ty.index);
- return Air.internedToRef(wip_ty.finish(ip, new_namespace_index));
+ return .fromIntern(wip_ty.finish(ip, new_namespace_index));
}
-fn reifyTuple(
+fn zirReifyEnum(
sema: *Sema,
block: *Block,
- src: LazySrcLoc,
- fields_val: Value,
+ extended: Zir.Inst.Extended.InstData,
+ inst: Zir.Inst.Index,
) CompileError!Air.Inst.Ref {
const pt = sema.pt;
const zcu = pt.zcu;
const gpa = sema.gpa;
const ip = &zcu.intern_pool;
- const fields_len: u32 = @intCast(fields_val.typeOf(zcu).arrayLen(zcu));
-
- const types = try sema.arena.alloc(InternPool.Index, fields_len);
- const inits = try sema.arena.alloc(InternPool.Index, fields_len);
-
- for (types, inits, 0..) |*field_ty, *field_init, field_idx| {
- const field_info = try fields_val.elemValue(pt, field_idx);
-
- const field_name_val = try field_info.fieldValue(pt, 0);
- const field_type_val = try field_info.fieldValue(pt, 1);
- const field_default_value_val = try field_info.fieldValue(pt, 2);
- const field_is_comptime_val = try field_info.fieldValue(pt, 3);
- const field_alignment_val = try sema.resolveLazyValue(try field_info.fieldValue(pt, 4));
-
- const field_name = try sema.sliceToIpString(block, src, field_name_val, .{ .simple = .tuple_field_name });
- const field_type = field_type_val.toType();
- const field_default_value: InternPool.Index = if (field_default_value_val.optionalValue(zcu)) |ptr_val| d: {
- const ptr_ty = try pt.singleConstPtrType(field_type_val.toType());
- // We need to do this deref here, so we won't check for this error case later on.
- const val = try sema.pointerDeref(block, src, ptr_val, ptr_ty) orelse return sema.failWithNeededComptime(
- block,
- src,
- .{ .simple = .tuple_field_default_value },
- );
- if (val.canMutateComptimeVarState(zcu)) {
- return sema.failWithContainsReferenceToComptimeVar(block, src, field_name, "field default value", val);
- }
- // Resolve the value so that lazy values do not create distinct types.
- break :d (try sema.resolveLazyValue(val)).toIntern();
- } else .none;
+ const name_strategy: Zir.Inst.NameStrategy = @enumFromInt(extended.small);
+ const extra = sema.code.extraData(Zir.Inst.ReifyEnum, extended.operand).data;
+ const tracked_inst = try block.trackZir(inst);
+ const src: LazySrcLoc = .{
+ .base_node_inst = tracked_inst,
+ .offset = .nodeOffset(.zero),
+ };
- const field_name_index = field_name.toUnsigned(ip) orelse return sema.fail(
- block,
- src,
- "tuple cannot have non-numeric field '{f}'",
- .{field_name.fmt(ip)},
- );
- if (field_name_index != field_idx) {
- return sema.fail(
- block,
- src,
- "tuple field name '{d}' does not match field index {d}",
- .{ field_name_index, field_idx },
- );
- }
+ const tag_ty_src: LazySrcLoc = .{
+ .base_node_inst = tracked_inst,
+ .offset = .{ .node_offset_builtin_call_arg = .{
+ .builtin_call_node = .zero,
+ .arg_index = 0,
+ } },
+ };
+ const mode_src: LazySrcLoc = .{
+ .base_node_inst = tracked_inst,
+ .offset = .{ .node_offset_builtin_call_arg = .{
+ .builtin_call_node = .zero,
+ .arg_index = 1,
+ } },
+ };
+ const field_names_src: LazySrcLoc = .{
+ .base_node_inst = tracked_inst,
+ .offset = .{ .node_offset_builtin_call_arg = .{
+ .builtin_call_node = .zero,
+ .arg_index = 2,
+ } },
+ };
+ const field_values_src: LazySrcLoc = .{
+ .base_node_inst = tracked_inst,
+ .offset = .{ .node_offset_builtin_call_arg = .{
+ .builtin_call_node = .zero,
+ .arg_index = 3,
+ } },
+ };
- try sema.validateTupleFieldType(block, field_type, src);
+ const enum_mode_ty = try sema.getBuiltinType(mode_src, .@"Type.Enum.Mode");
- {
- const alignment_ok = ok: {
- if (field_alignment_val.toIntern() == .zero) break :ok true;
- const given_align = try field_alignment_val.getUnsignedIntSema(pt) orelse break :ok false;
- const abi_align = (try field_type.abiAlignmentSema(pt)).toByteUnits() orelse 0;
- break :ok abi_align == given_align;
- };
- if (!alignment_ok) {
- return sema.fail(block, src, "tuple fields cannot specify alignment", .{});
- }
- }
+ const tag_ty = try sema.resolveType(block, tag_ty_src, extra.tag_ty);
+ if (tag_ty.zigTypeTag(zcu) != .int) {
+ return sema.fail(block, tag_ty_src, "tag type must be an integer type", .{});
+ }
- if (field_is_comptime_val.toBool() and field_default_value == .none) {
- return sema.fail(block, src, "comptime field without default initialization value", .{});
- }
+ const mode_uncoerced = try sema.resolveInst(extra.mode);
+ const mode_coerced = try sema.coerce(block, enum_mode_ty, mode_uncoerced, mode_src);
+ const mode_val = try sema.resolveConstDefinedValue(block, mode_src, mode_coerced, .{ .simple = .type });
+ const nonexhaustive = switch (try sema.interpretBuiltinType(block, mode_src, mode_val, std.builtin.Type.Enum.Mode)) {
+ .exhaustive => false,
+ .nonexhaustive => true,
+ };
- if (!field_is_comptime_val.toBool() and field_default_value != .none) {
- return sema.fail(block, src, "non-comptime tuple fields cannot specify default initialization value", .{});
- }
+ const field_names_uncoerced = try sema.resolveInst(extra.field_names);
+ const field_names_coerced = try sema.coerce(block, .slice_const_slice_const_u8, field_names_uncoerced, field_names_src);
+ const field_names_slice = try sema.resolveConstDefinedValue(block, field_names_src, field_names_coerced, .{ .simple = .enum_field_names });
+ const field_names_arr = try sema.derefSliceAsArray(block, field_names_src, field_names_slice, .{ .simple = .enum_field_names });
- field_ty.* = field_type.toIntern();
- field_init.* = field_default_value;
- }
+ const fields_len = try sema.usizeCast(block, src, field_names_arr.typeOf(zcu).arrayLen(zcu));
- return Air.internedToRef(try zcu.intern_pool.getTupleType(gpa, pt.tid, .{
- .types = types,
- .values = inits,
+ const field_values_ty = try pt.singleConstPtrType(try pt.arrayType(.{
+ .len = fields_len,
+ .child = tag_ty.toIntern(),
}));
-}
-
-fn reifyStruct(
- sema: *Sema,
- block: *Block,
- inst: Zir.Inst.Index,
- src: LazySrcLoc,
- layout: std.builtin.Type.ContainerLayout,
- opt_backing_int_val: Value,
- fields_val: Value,
- name_strategy: Zir.Inst.NameStrategy,
-) CompileError!Air.Inst.Ref {
- const pt = sema.pt;
- const zcu = pt.zcu;
- const gpa = sema.gpa;
- const ip = &zcu.intern_pool;
- // This logic must stay in sync with the structure of `std.builtin.Type.Struct` - search for `fieldValue`.
+ const field_values_uncoerced = try sema.resolveInst(extra.field_values);
+ const field_values_coerced = try sema.coerce(block, field_values_ty, field_values_uncoerced, field_values_src);
+ const field_values_slice = try sema.resolveConstDefinedValue(block, field_values_src, field_values_coerced, .{ .simple = .enum_field_values });
+ const field_values_arr = try sema.derefSliceAsArray(block, field_values_src, field_values_slice, .{ .simple = .enum_field_values });
- const fields_len: u32 = @intCast(fields_val.typeOf(zcu).arrayLen(zcu));
+ // Before we begin, check for undefs...
+ if (try sema.anyUndef(block, field_values_src, field_values_arr)) {
+ return sema.failWithUseOfUndef(block, field_values_src, null);
+ }
+ // We don't need to check `field_names_arr`, because `sliceToIpString` will check that for us.
// The validation work here is non-trivial, and it's possible the type already exists.
// So in this first pass, let's just construct a hash to optimize for this case. If the
@@ -21589,62 +21652,23 @@ fn reifyStruct(
// For deduplication purposes, we must create a hash including all details of this type.
// TODO: use a longer hash!
var hasher = std.hash.Wyhash.init(0);
- std.hash.autoHash(&hasher, layout);
- std.hash.autoHash(&hasher, opt_backing_int_val.toIntern());
+ std.hash.autoHash(&hasher, tag_ty.toIntern());
+ std.hash.autoHash(&hasher, nonexhaustive);
std.hash.autoHash(&hasher, fields_len);
-
- var any_comptime_fields = false;
- var any_default_inits = false;
-
+ // `field_values_arr` is already deduplicated by the InternPool!
+ std.hash.autoHash(&hasher, field_values_arr);
+ // However, for field names, we need to iterate the individual fields, because the pointers (the
+ // names are slices) mean that distinct values could ultimately result in the same enum type.
for (0..fields_len) |field_idx| {
- const field_info = try fields_val.elemValue(pt, field_idx);
-
- const field_name_val = try field_info.fieldValue(pt, 0);
- const field_type_val = try field_info.fieldValue(pt, 1);
- const field_default_value_val = try field_info.fieldValue(pt, 2);
- const field_is_comptime_val = try field_info.fieldValue(pt, 3);
- const field_alignment_val = try sema.resolveLazyValue(try field_info.fieldValue(pt, 4));
-
- const field_name = try sema.sliceToIpString(block, src, field_name_val, .{ .simple = .struct_field_name });
- const field_is_comptime = field_is_comptime_val.toBool();
- const field_default_value: InternPool.Index = if (field_default_value_val.optionalValue(zcu)) |ptr_val| d: {
- const ptr_ty = try pt.singleConstPtrType(field_type_val.toType());
- // We need to do this deref here, so we won't check for this error case later on.
- const val = try sema.pointerDeref(block, src, ptr_val, ptr_ty) orelse return sema.failWithNeededComptime(
- block,
- src,
- .{ .simple = .struct_field_default_value },
- );
- if (val.canMutateComptimeVarState(zcu)) {
- return sema.failWithContainsReferenceToComptimeVar(block, src, field_name, "field default value", val);
- }
- // Resolve the value so that lazy values do not create distinct types.
- break :d (try sema.resolveLazyValue(val)).toIntern();
- } else .none;
-
- std.hash.autoHash(&hasher, .{
- field_name,
- field_type_val.toIntern(),
- field_default_value,
- field_is_comptime,
- field_alignment_val.toIntern(),
- });
-
- if (field_is_comptime) any_comptime_fields = true;
- if (field_default_value != .none) any_default_inits = true;
+ const field_name_val = try field_names_arr.elemValue(pt, field_idx);
+ const field_name = try sema.sliceToIpString(block, field_names_src, field_name_val, .{ .simple = .enum_field_names });
+ std.hash.autoHash(&hasher, field_name);
}
- const tracked_inst = try block.trackZir(inst);
-
- const wip_ty = switch (try ip.getStructType(gpa, pt.tid, .{
- .layout = layout,
- .fields_len = fields_len,
- .known_non_opv = false,
- .requires_comptime = .unknown,
- .any_comptime_fields = any_comptime_fields,
- .any_default_inits = any_default_inits,
- .any_aligned_fields = layout != .@"packed",
- .inits_resolved = true,
+ const wip_ty = switch (try ip.getEnumType(gpa, pt.tid, .{
+ .has_values = true,
+ .tag_mode = if (nonexhaustive) .nonexhaustive else .explicit,
+ .fields_len = @intCast(fields_len),
.key = .{ .reified = .{
.zir_index = tracked_inst,
.type_hash = hasher.final(),
@@ -21654,152 +21678,66 @@ fn reifyStruct(
.existing => |ty| {
try sema.declareDependency(.{ .interned = ty });
try sema.addTypeReferenceEntry(src, ty);
- return Air.internedToRef(ty);
+ return .fromIntern(ty);
},
};
- errdefer wip_ty.cancel(ip, pt.tid);
+ var done = false;
+ errdefer if (!done) wip_ty.cancel(ip, pt.tid);
const type_name = try sema.createTypeName(
block,
name_strategy,
- "struct",
+ "enum",
inst,
wip_ty.index,
);
wip_ty.setName(ip, type_name.name, type_name.nav);
- const struct_type = ip.loadStructType(wip_ty.index);
-
- for (0..fields_len) |field_idx| {
- const field_info = try fields_val.elemValue(pt, field_idx);
-
- const field_name_val = try field_info.fieldValue(pt, 0);
- const field_type_val = try field_info.fieldValue(pt, 1);
- const field_default_value_val = try field_info.fieldValue(pt, 2);
- const field_is_comptime_val = try field_info.fieldValue(pt, 3);
- const field_alignment_val = try field_info.fieldValue(pt, 4);
-
- const field_ty = field_type_val.toType();
- // Don't pass a reason; first loop acts as an assertion that this is valid.
- const field_name = try sema.sliceToIpString(block, src, field_name_val, undefined);
- if (struct_type.addFieldName(ip, field_name)) |prev_index| {
- _ = prev_index; // TODO: better source location
- return sema.fail(block, src, "duplicate struct field name {f}", .{field_name.fmt(ip)});
- }
-
- if (!try sema.intFitsInType(field_alignment_val, align_ty, null)) {
- return sema.fail(block, src, "alignment must fit in '{f}'", .{align_ty.fmt(pt)});
- }
- const byte_align = try field_alignment_val.toUnsignedIntSema(pt);
- if (layout == .@"packed") {
- if (byte_align != 0) return sema.fail(block, src, "alignment of a packed struct field must be set to 0", .{});
- } else {
- struct_type.field_aligns.get(ip)[field_idx] = try sema.validateAlign(block, src, byte_align);
- }
-
- const field_is_comptime = field_is_comptime_val.toBool();
- if (field_is_comptime) {
- assert(any_comptime_fields);
- switch (layout) {
- .@"extern" => return sema.fail(block, src, "extern struct fields cannot be marked comptime", .{}),
- .@"packed" => return sema.fail(block, src, "packed struct fields cannot be marked comptime", .{}),
- .auto => struct_type.setFieldComptime(ip, field_idx),
- }
- }
-
- const field_default: InternPool.Index = d: {
- if (!any_default_inits) break :d .none;
- const ptr_val = field_default_value_val.optionalValue(zcu) orelse break :d .none;
- const ptr_ty = try pt.singleConstPtrType(field_ty);
- // Asserted comptime-dereferencable above.
- const val = (try sema.pointerDeref(block, src, ptr_val, ptr_ty)).?;
- // We already resolved this for deduplication, so we may as well do it now.
- break :d (try sema.resolveLazyValue(val)).toIntern();
- };
-
- if (field_is_comptime and field_default == .none) {
- return sema.fail(block, src, "comptime field without default initialization value", .{});
- }
-
- struct_type.field_types.get(ip)[field_idx] = field_type_val.toIntern();
- if (field_default != .none) {
- struct_type.field_inits.get(ip)[field_idx] = field_default;
- }
-
- if (field_ty.zigTypeTag(zcu) == .@"opaque") {
- return sema.failWithOwnedErrorMsg(block, msg: {
- const msg = try sema.errMsg(src, "opaque types have unknown size and therefore cannot be directly embedded in structs", .{});
- errdefer msg.destroy(gpa);
-
- try sema.addDeclaredHereNote(msg, field_ty);
- break :msg msg;
- });
- }
- if (field_ty.zigTypeTag(zcu) == .noreturn) {
- return sema.failWithOwnedErrorMsg(block, msg: {
- const msg = try sema.errMsg(src, "struct fields cannot be 'noreturn'", .{});
- errdefer msg.destroy(gpa);
-
- try sema.addDeclaredHereNote(msg, field_ty);
- break :msg msg;
- });
- }
- if (layout == .@"extern" and !try sema.validateExternType(field_ty, .struct_field)) {
- return sema.failWithOwnedErrorMsg(block, msg: {
- const msg = try sema.errMsg(src, "extern structs cannot contain fields of type '{f}'", .{field_ty.fmt(pt)});
- errdefer msg.destroy(gpa);
+ const new_namespace_index = try pt.createNamespace(.{
+ .parent = block.namespace.toOptional(),
+ .owner_type = wip_ty.index,
+ .file_scope = block.getFileScopeIndex(zcu),
+ .generation = zcu.generation,
+ });
- try sema.explainWhyTypeIsNotExtern(msg, src, field_ty, .struct_field);
+ try sema.declareDependency(.{ .interned = wip_ty.index });
+ try sema.addTypeReferenceEntry(src, wip_ty.index);
+ if (zcu.comp.debugIncremental()) try zcu.incremental_debug_state.newType(zcu, wip_ty.index);
+ wip_ty.prepare(ip, new_namespace_index);
+ wip_ty.setTagTy(ip, tag_ty.toIntern());
+ done = true;
- try sema.addDeclaredHereNote(msg, field_ty);
- break :msg msg;
- });
- } else if (layout == .@"packed" and !try sema.validatePackedType(field_ty)) {
- return sema.failWithOwnedErrorMsg(block, msg: {
- const msg = try sema.errMsg(src, "packed structs cannot contain fields of type '{f}'", .{field_ty.fmt(pt)});
- errdefer msg.destroy(gpa);
+ for (0..fields_len) |field_idx| {
+ const field_name_val = try field_names_arr.elemValue(pt, field_idx);
+ // Don't pass a reason; first loop acts as a check that this is valid.
+ const field_name = try sema.sliceToIpString(block, field_names_src, field_name_val, undefined);
- try sema.explainWhyTypeIsNotPacked(msg, src, field_ty);
+ const field_val = try field_values_arr.elemValue(pt, field_idx);
- try sema.addDeclaredHereNote(msg, field_ty);
- break :msg msg;
+ if (wip_ty.nextField(ip, field_name, field_val.toIntern())) |conflict| {
+ return sema.failWithOwnedErrorMsg(block, switch (conflict.kind) {
+ .name => msg: {
+ const msg = try sema.errMsg(field_names_src, "duplicate enum field '{f}'", .{field_name.fmt(ip)});
+ errdefer msg.destroy(gpa);
+ _ = conflict.prev_field_idx; // TODO: this note is incorrect
+ try sema.errNote(field_names_src, msg, "other field here", .{});
+ break :msg msg;
+ },
+ .value => msg: {
+ const msg = try sema.errMsg(field_values_src, "enum tag value {f} already taken", .{field_val.fmtValueSema(pt, sema)});
+ errdefer msg.destroy(gpa);
+ _ = conflict.prev_field_idx; // TODO: this note is incorrect
+ try sema.errNote(field_values_src, msg, "other enum tag value here", .{});
+ break :msg msg;
+ },
});
}
}
- if (layout == .@"packed") {
- var fields_bit_sum: u64 = 0;
- for (0..struct_type.field_types.len) |field_idx| {
- const field_ty: Type = .fromInterned(struct_type.field_types.get(ip)[field_idx]);
- field_ty.resolveLayout(pt) catch |err| switch (err) {
- error.AnalysisFail => {
- const msg = sema.err orelse return err;
- try sema.errNote(src, msg, "while checking a field of this struct", .{});
- return err;
- },
- else => return err,
- };
- fields_bit_sum += field_ty.bitSize(zcu);
- }
-
- if (opt_backing_int_val.optionalValue(zcu)) |backing_int_val| {
- const backing_int_ty = backing_int_val.toType();
- try sema.checkBackingIntType(block, src, backing_int_ty, fields_bit_sum);
- struct_type.setBackingIntType(ip, backing_int_ty.toIntern());
- } else {
- const backing_int_ty = try pt.intType(.unsigned, @intCast(fields_bit_sum));
- struct_type.setBackingIntType(ip, backing_int_ty.toIntern());
- }
+ if (nonexhaustive and fields_len > 1 and std.math.log2_int(u64, fields_len) == tag_ty.bitSize(zcu)) {
+ return sema.fail(block, src, "non-exhaustive enum specified every value", .{});
}
- const new_namespace_index = try pt.createNamespace(.{
- .parent = block.namespace.toOptional(),
- .owner_type = wip_ty.index,
- .file_scope = block.getFileScopeIndex(zcu),
- .generation = zcu.generation,
- });
-
- try zcu.comp.queueJob(.{ .resolve_type_fully = wip_ty.index });
codegen_type: {
if (zcu.comp.config.use_llvm) break :codegen_type;
if (block.ownerModule().strip) break :codegen_type;
@@ -21807,10 +21745,7 @@ fn reifyStruct(
zcu.comp.link_prog_node.increaseEstimatedTotalItems(1);
try zcu.comp.queueJob(.{ .link_type = wip_ty.index });
}
- try sema.declareDependency(.{ .interned = wip_ty.index });
- try sema.addTypeReferenceEntry(src, wip_ty.index);
- if (zcu.comp.debugIncremental()) try zcu.incremental_debug_state.newType(zcu, wip_ty.index);
- return Air.internedToRef(wip_ty.finish(ip, new_namespace_index));
+ return Air.internedToRef(wip_ty.index);
}
fn resolveVaListRef(sema: *Sema, block: *Block, src: LazySrcLoc, zir_ref: Zir.Inst.Ref) CompileError!Air.Inst.Ref {
@@ -25541,7 +25476,7 @@ fn zirFuncFancy(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!A
extra_index += body.len;
if (extra.data.bits.ret_ty_is_generic) break :blk .generic_poison;
- const val = try sema.resolveGenericBody(block, ret_src, body, inst, .type, .{ .simple = .function_ret_ty });
+ const val = try sema.resolveGenericBody(block, ret_src, body, inst, .type, .{ .simple = .fn_ret_ty });
const ty = val.toType();
break :blk ty;
} else if (extra.data.bits.has_ret_ty_ref) blk: {
@@ -25968,21 +25903,26 @@ fn zirBuiltinValue(sema: *Sema, block: *Block, extended: Zir.Inst.Extended.InstD
const src = block.nodeOffset(src_node);
const value: Zir.Inst.BuiltinValue = @enumFromInt(extended.small);
- const ty = switch (value) {
+ const builtin_type: Zcu.BuiltinDecl = switch (value) {
// zig fmt: off
- .atomic_order => try sema.getBuiltinType(src, .AtomicOrder),
- .atomic_rmw_op => try sema.getBuiltinType(src, .AtomicRmwOp),
- .calling_convention => try sema.getBuiltinType(src, .CallingConvention),
- .address_space => try sema.getBuiltinType(src, .AddressSpace),
- .float_mode => try sema.getBuiltinType(src, .FloatMode),
- .reduce_op => try sema.getBuiltinType(src, .ReduceOp),
- .call_modifier => try sema.getBuiltinType(src, .CallModifier),
- .prefetch_options => try sema.getBuiltinType(src, .PrefetchOptions),
- .export_options => try sema.getBuiltinType(src, .ExportOptions),
- .extern_options => try sema.getBuiltinType(src, .ExternOptions),
- .type_info => try sema.getBuiltinType(src, .Type),
- .branch_hint => try sema.getBuiltinType(src, .BranchHint),
- .clobbers => try sema.getBuiltinType(src, .@"assembly.Clobbers"),
+ .atomic_order => .AtomicOrder,
+ .atomic_rmw_op => .AtomicRmwOp,
+ .calling_convention => .CallingConvention,
+ .address_space => .AddressSpace,
+ .float_mode => .FloatMode,
+ .signedness => .Signedness,
+ .reduce_op => .ReduceOp,
+ .call_modifier => .CallModifier,
+ .prefetch_options => .PrefetchOptions,
+ .export_options => .ExportOptions,
+ .extern_options => .ExternOptions,
+ .branch_hint => .BranchHint,
+ .clobbers => .@"assembly.Clobbers",
+ .pointer_size => .@"Type.Pointer.Size",
+ .pointer_attributes => .@"Type.Pointer.Attributes",
+ .fn_attributes, => .@"Type.Fn.Attributes",
+ .container_layout => .@"Type.ContainerLayout",
+ .enum_mode => .@"Type.Enum.Mode",
// zig fmt: on
// Values are handled here.
@@ -26009,7 +25949,7 @@ fn zirBuiltinValue(sema: *Sema, block: *Block, extended: Zir.Inst.Extended.InstD
return sema.coerce(block, callconv_ty, Air.internedToRef(inline_tag_val.toIntern()), src);
},
};
- return Air.internedToRef(ty.toIntern());
+ return .fromType(try sema.getBuiltinType(src, builtin_type));
}
fn zirInplaceArithResultTy(sema: *Sema, extended: Zir.Inst.Extended.InstData) CompileError!Air.Inst.Ref {
@@ -35259,7 +35199,7 @@ fn structFields(
.base_node_inst = struct_type.zir_index,
.offset = .nodeOffset(.zero),
},
- .r = .{ .simple = .struct_fields },
+ .r = .{ .simple = .type },
} },
.src_base_inst = struct_type.zir_index,
.type_name_ctx = struct_type.name,
@@ -35614,7 +35554,7 @@ fn unionFields(
.inlining = null,
.comptime_reason = .{ .reason = .{
.src = src,
- .r = .{ .simple = .union_fields },
+ .r = .{ .simple = .type },
} },
.src_base_inst = union_type.zir_index,
.type_name_ctx = union_type.name,
@@ -36077,8 +36017,13 @@ pub fn typeHasOnePossibleValue(sema: *Sema, ty: Type) CompileError!?Value {
.manyptr_u8_type,
.manyptr_const_u8_type,
.manyptr_const_u8_sentinel_0_type,
+ .manyptr_const_slice_const_u8_type,
.slice_const_u8_type,
.slice_const_u8_sentinel_0_type,
+ .slice_const_slice_const_u8_type,
+ .optional_type_type,
+ .manyptr_const_type_type,
+ .slice_const_type_type,
.vector_8_i8_type,
.vector_16_i8_type,
.vector_32_i8_type,
@@ -37230,7 +37175,7 @@ fn sliceToIpString(
/// Given a slice value, attempts to dereference it into a comptime-known array.
/// Emits a compile error if the contents of the slice are not comptime-known.
-/// Asserts that `slice_val` is a slice.
+/// Asserts that `slice_val` is a slice or a pointer to an array.
fn derefSliceAsArray(
sema: *Sema,
block: *Block,
@@ -37247,7 +37192,7 @@ fn derefSliceAsArray(
/// Given a slice value, attempts to dereference it into a comptime-known array.
/// Returns `null` if the contents of the slice are not comptime-known.
-/// Asserts that `slice_val` is a slice.
+/// Asserts that `slice_val` is a slice or a pointer to an array.
fn maybeDerefSliceAsArray(
sema: *Sema,
block: *Block,
@@ -37257,7 +37202,13 @@ fn maybeDerefSliceAsArray(
const pt = sema.pt;
const zcu = pt.zcu;
const ip = &zcu.intern_pool;
- assert(slice_val.typeOf(zcu).isSlice(zcu));
+ const slice_ty = slice_val.typeOf(zcu);
+ assert(slice_ty.zigTypeTag(zcu) == .pointer);
+ switch (slice_ty.ptrInfo(zcu).flags.size) {
+ .slice => {},
+ .one => return sema.pointerDeref(block, src, slice_val, slice_ty),
+ .many, .c => unreachable,
+ }
const slice = switch (ip.indexToKey(slice_val.toIntern())) {
.undef => return sema.failWithUseOfUndef(block, src, null),
.slice => |slice| slice,
@@ -37393,7 +37344,7 @@ pub fn resolveDeclaredEnum(
.inlining = null,
.comptime_reason = .{ .reason = .{
.src = src,
- .r = .{ .simple = .enum_fields },
+ .r = .{ .simple = .enum_field_values },
} },
.src_base_inst = tracked_inst,
.type_name_ctx = type_name,
src/Type.zig
@@ -317,7 +317,7 @@ pub fn print(ty: Type, writer: *std.Io.Writer, pt: Zcu.PerThread, ctx: ?*Compari
.undefined,
=> try writer.print("@TypeOf({s})", .{@tagName(s)}),
- .enum_literal => try writer.writeAll("@Type(.enum_literal)"),
+ .enum_literal => try writer.writeAll("@EnumLiteral()"),
.generic_poison => unreachable,
},
@@ -3509,7 +3509,9 @@ pub fn typeDeclSrcLine(ty: Type, zcu: *Zcu) ?u32 {
.union_decl => zir.extraData(Zir.Inst.UnionDecl, inst.data.extended.operand).data.src_line,
.enum_decl => zir.extraData(Zir.Inst.EnumDecl, inst.data.extended.operand).data.src_line,
.opaque_decl => zir.extraData(Zir.Inst.OpaqueDecl, inst.data.extended.operand).data.src_line,
- .reify => zir.extraData(Zir.Inst.Reify, inst.data.extended.operand).data.src_line,
+ .reify_enum => zir.extraData(Zir.Inst.ReifyEnum, inst.data.extended.operand).data.src_line,
+ .reify_struct => zir.extraData(Zir.Inst.ReifyStruct, inst.data.extended.operand).data.src_line,
+ .reify_union => zir.extraData(Zir.Inst.ReifyUnion, inst.data.extended.operand).data.src_line,
else => unreachable,
},
else => unreachable,
@@ -4280,6 +4282,10 @@ pub const manyptr_const_u8: Type = .{ .ip_index = .manyptr_const_u8_type };
pub const manyptr_const_u8_sentinel_0: Type = .{ .ip_index = .manyptr_const_u8_sentinel_0_type };
pub const slice_const_u8: Type = .{ .ip_index = .slice_const_u8_type };
pub const slice_const_u8_sentinel_0: Type = .{ .ip_index = .slice_const_u8_sentinel_0_type };
+pub const slice_const_slice_const_u8: Type = .{ .ip_index = .slice_const_slice_const_u8_type };
+pub const slice_const_type: Type = .{ .ip_index = .slice_const_type_type };
+pub const optional_type: Type = .{ .ip_index = .optional_type_type };
+pub const optional_noreturn: Type = .{ .ip_index = .optional_noreturn_type };
pub const vector_8_i8: Type = .{ .ip_index = .vector_8_i8_type };
pub const vector_16_i8: Type = .{ .ip_index = .vector_16_i8_type };
src/Value.zig
@@ -2824,6 +2824,29 @@ pub fn resolveLazy(
.val = resolved_val,
}));
},
+ .error_union => |eu| switch (eu.val) {
+ .err_name => return val,
+ .payload => |payload| {
+ const resolved_payload = try Value.fromInterned(payload).resolveLazy(arena, pt);
+ if (resolved_payload.toIntern() == payload) return val;
+ return .fromInterned(try pt.intern(.{ .error_union = .{
+ .ty = eu.ty,
+ .val = .{ .payload = resolved_payload.toIntern() },
+ } }));
+ },
+ },
+ .opt => |opt| switch (opt.val) {
+ .none => return val,
+ else => |payload| {
+ const resolved_payload = try Value.fromInterned(payload).resolveLazy(arena, pt);
+ if (resolved_payload.toIntern() == payload) return val;
+ return .fromInterned(try pt.intern(.{ .opt = .{
+ .ty = opt.ty,
+ .val = resolved_payload.toIntern(),
+ } }));
+ },
+ },
+
else => return val,
}
}
src/Zcu.zig
@@ -416,10 +416,13 @@ pub const BuiltinDecl = enum {
Type,
@"Type.Fn",
@"Type.Fn.Param",
+ @"Type.Fn.Param.Attributes",
+ @"Type.Fn.Attributes",
@"Type.Int",
@"Type.Float",
@"Type.Pointer",
@"Type.Pointer.Size",
+ @"Type.Pointer.Attributes",
@"Type.Array",
@"Type.Vector",
@"Type.Optional",
@@ -427,10 +430,13 @@ pub const BuiltinDecl = enum {
@"Type.ErrorUnion",
@"Type.EnumField",
@"Type.Enum",
+ @"Type.Enum.Mode",
@"Type.Union",
@"Type.UnionField",
+ @"Type.UnionField.Attributes",
@"Type.Struct",
@"Type.StructField",
+ @"Type.StructField.Attributes",
@"Type.ContainerLayout",
@"Type.Opaque",
@"Type.Declaration",
@@ -495,10 +501,13 @@ pub const BuiltinDecl = enum {
.Type,
.@"Type.Fn",
.@"Type.Fn.Param",
+ .@"Type.Fn.Param.Attributes",
+ .@"Type.Fn.Attributes",
.@"Type.Int",
.@"Type.Float",
.@"Type.Pointer",
.@"Type.Pointer.Size",
+ .@"Type.Pointer.Attributes",
.@"Type.Array",
.@"Type.Vector",
.@"Type.Optional",
@@ -506,10 +515,13 @@ pub const BuiltinDecl = enum {
.@"Type.ErrorUnion",
.@"Type.EnumField",
.@"Type.Enum",
+ .@"Type.Enum.Mode",
.@"Type.Union",
.@"Type.UnionField",
+ .@"Type.UnionField.Attributes",
.@"Type.Struct",
.@"Type.StructField",
+ .@"Type.StructField.Attributes",
.@"Type.ContainerLayout",
.@"Type.Opaque",
.@"Type.Declaration",
@@ -1745,28 +1757,28 @@ pub const SrcLoc = struct {
const node = node_off.toAbsolute(src_loc.base_node);
var buf: [1]Ast.Node.Index = undefined;
const full = tree.fullFnProto(&buf, node).?;
- return tree.nodeToSpan(full.ast.align_expr.unwrap().?);
+ return tree.nodeToSpan(full.ast.align_expr.unwrap() orelse node);
},
.node_offset_fn_type_addrspace => |node_off| {
const tree = try src_loc.file_scope.getTree(zcu);
const node = node_off.toAbsolute(src_loc.base_node);
var buf: [1]Ast.Node.Index = undefined;
const full = tree.fullFnProto(&buf, node).?;
- return tree.nodeToSpan(full.ast.addrspace_expr.unwrap().?);
+ return tree.nodeToSpan(full.ast.addrspace_expr.unwrap() orelse node);
},
.node_offset_fn_type_section => |node_off| {
const tree = try src_loc.file_scope.getTree(zcu);
const node = node_off.toAbsolute(src_loc.base_node);
var buf: [1]Ast.Node.Index = undefined;
const full = tree.fullFnProto(&buf, node).?;
- return tree.nodeToSpan(full.ast.section_expr.unwrap().?);
+ return tree.nodeToSpan(full.ast.section_expr.unwrap() orelse node);
},
.node_offset_fn_type_cc => |node_off| {
const tree = try src_loc.file_scope.getTree(zcu);
const node = node_off.toAbsolute(src_loc.base_node);
var buf: [1]Ast.Node.Index = undefined;
const full = tree.fullFnProto(&buf, node).?;
- return tree.nodeToSpan(full.ast.callconv_expr.unwrap().?);
+ return tree.nodeToSpan(full.ast.callconv_expr.unwrap() orelse node);
},
.node_offset_fn_type_ret_ty => |node_off| {
@@ -2684,7 +2696,9 @@ pub const LazySrcLoc = struct {
.union_decl => zir.extraData(Zir.Inst.UnionDecl, inst.data.extended.operand).data.src_node,
.enum_decl => zir.extraData(Zir.Inst.EnumDecl, inst.data.extended.operand).data.src_node,
.opaque_decl => zir.extraData(Zir.Inst.OpaqueDecl, inst.data.extended.operand).data.src_node,
- .reify => zir.extraData(Zir.Inst.Reify, inst.data.extended.operand).data.node,
+ .reify_enum => zir.extraData(Zir.Inst.ReifyEnum, inst.data.extended.operand).data.node,
+ .reify_struct => zir.extraData(Zir.Inst.ReifyStruct, inst.data.extended.operand).data.node,
+ .reify_union => zir.extraData(Zir.Inst.ReifyUnion, inst.data.extended.operand).data.node,
else => unreachable,
},
else => unreachable,