Commit 2083208f19
Changed files (5)
src/AstGen.zig
@@ -1375,9 +1375,7 @@ fn blockExprStmts(
.field_ptr_named,
.field_val_named,
.func,
- .func_var_args,
- .func_extra,
- .func_extra_var_args,
+ .func_inferred,
.int,
.float,
.float128,
@@ -2129,9 +2127,8 @@ fn fnDecl(
}
const maybe_bang = tree.firstToken(fn_proto.ast.return_type) - 1;
- if (token_tags[maybe_bang] == .bang) {
- return astgen.failTok(maybe_bang, "TODO implement inferred error sets", .{});
- }
+ const is_inferred_error = token_tags[maybe_bang] == .bang;
+
const return_type_inst = try AstGen.expr(
&decl_gz,
&decl_gz.base,
@@ -2153,31 +2150,24 @@ fn fnDecl(
const func_inst: Zir.Inst.Ref = if (body_node == 0) func: {
if (is_extern) {
- return astgen.failNode(fn_proto.ast.fn_token, "non-extern function has no body", .{});
+ return astgen.failTok(fn_proto.ast.fn_token, "non-extern function has no body", .{});
}
-
- if (cc != .none or lib_name != 0) {
- const tag: Zir.Inst.Tag = if (is_var_args) .func_extra_var_args else .func_extra;
- break :func try decl_gz.addFuncExtra(tag, .{
- .src_node = fn_proto.ast.proto_node,
- .ret_ty = return_type_inst,
- .param_types = param_types,
- .cc = cc,
- .lib_name = lib_name,
- .body = &[0]Zir.Inst.Index{},
- });
+ if (is_inferred_error) {
+ return astgen.failTok(maybe_bang, "function prototype requires explicit error set", .{});
}
-
- const tag: Zir.Inst.Tag = if (is_var_args) .func_var_args else .func;
- break :func try decl_gz.addFunc(tag, .{
+ break :func try decl_gz.addFunc(.{
.src_node = fn_proto.ast.proto_node,
.ret_ty = return_type_inst,
.param_types = param_types,
.body = &[0]Zir.Inst.Index{},
+ .cc = cc,
+ .lib_name = lib_name,
+ .is_var_args = is_var_args,
+ .is_inferred_error = false,
});
} else func: {
if (is_var_args) {
- return astgen.failNode(fn_proto.ast.fn_token, "non-extern function is variadic", .{});
+ return astgen.failTok(fn_proto.ast.fn_token, "non-extern function is variadic", .{});
}
var fn_gz: Scope.GenZir = .{
@@ -2224,30 +2214,20 @@ fn fnDecl(
if (fn_gz.instructions.items.len == 0 or
!astgen.instructions.items(.tag)[fn_gz.instructions.items.len - 1].isNoReturn())
{
- // astgen uses result location semantics to coerce return operands.
// Since we are adding the return instruction here, we must handle the coercion.
// We do this by using the `ret_coerce` instruction.
_ = try fn_gz.addUnTok(.ret_coerce, .void_value, tree.lastToken(body_node));
}
- if (cc != .none or lib_name != 0) {
- const tag: Zir.Inst.Tag = if (is_var_args) .func_extra_var_args else .func_extra;
- break :func try decl_gz.addFuncExtra(tag, .{
- .src_node = fn_proto.ast.proto_node,
- .ret_ty = return_type_inst,
- .param_types = param_types,
- .cc = cc,
- .lib_name = lib_name,
- .body = fn_gz.instructions.items,
- });
- }
-
- const tag: Zir.Inst.Tag = if (is_var_args) .func_var_args else .func;
- break :func try decl_gz.addFunc(tag, .{
+ break :func try decl_gz.addFunc(.{
.src_node = fn_proto.ast.proto_node,
.ret_ty = return_type_inst,
.param_types = param_types,
.body = fn_gz.instructions.items,
+ .cc = cc,
+ .lib_name = lib_name,
+ .is_var_args = is_var_args,
+ .is_inferred_error = is_inferred_error,
});
};
src/Module.zig
@@ -1278,79 +1278,90 @@ pub const Scope = struct {
}
}
- pub fn addFuncExtra(gz: *GenZir, tag: Zir.Inst.Tag, args: struct {
+ pub fn addFunc(gz: *GenZir, args: struct {
src_node: ast.Node.Index,
param_types: []const Zir.Inst.Ref,
+ body: []const Zir.Inst.Index,
ret_ty: Zir.Inst.Ref,
cc: Zir.Inst.Ref,
- body: []const Zir.Inst.Index,
lib_name: u32,
+ is_var_args: bool,
+ is_inferred_error: bool,
}) !Zir.Inst.Ref {
assert(args.src_node != 0);
assert(args.ret_ty != .none);
- assert(args.cc != .none);
- const gpa = gz.astgen.gpa;
- try gz.instructions.ensureCapacity(gpa, gz.instructions.items.len + 1);
- try gz.astgen.instructions.ensureCapacity(gpa, gz.astgen.instructions.len + 1);
- try gz.astgen.extra.ensureCapacity(gpa, gz.astgen.extra.items.len +
- @typeInfo(Zir.Inst.FuncExtra).Struct.fields.len + args.param_types.len +
- args.body.len);
-
- const payload_index = gz.astgen.addExtraAssumeCapacity(Zir.Inst.FuncExtra{
- .return_type = args.ret_ty,
- .cc = args.cc,
- .param_types_len = @intCast(u32, args.param_types.len),
- .body_len = @intCast(u32, args.body.len),
- .lib_name = args.lib_name,
- });
- gz.astgen.appendRefsAssumeCapacity(args.param_types);
- gz.astgen.extra.appendSliceAssumeCapacity(args.body);
-
- const new_index = @intCast(Zir.Inst.Index, gz.astgen.instructions.len);
- gz.astgen.instructions.appendAssumeCapacity(.{
- .tag = tag,
- .data = .{ .pl_node = .{
- .src_node = gz.nodeIndexToRelative(args.src_node),
- .payload_index = payload_index,
- } },
- });
- gz.instructions.appendAssumeCapacity(new_index);
- return gz.indexToRef(new_index);
- }
-
- pub fn addFunc(gz: *GenZir, tag: Zir.Inst.Tag, args: struct {
- src_node: ast.Node.Index,
- ret_ty: Zir.Inst.Ref,
- param_types: []const Zir.Inst.Ref,
- body: []const Zir.Inst.Index,
- }) !Zir.Inst.Ref {
- assert(args.src_node != 0);
- assert(args.ret_ty != .none);
- const gpa = gz.astgen.gpa;
- try gz.instructions.ensureCapacity(gpa, gz.instructions.items.len + 1);
- try gz.astgen.instructions.ensureCapacity(gpa, gz.astgen.instructions.len + 1);
- try gz.astgen.extra.ensureCapacity(gpa, gz.astgen.extra.items.len +
- @typeInfo(Zir.Inst.Func).Struct.fields.len + args.param_types.len +
- args.body.len);
-
- const payload_index = gz.astgen.addExtraAssumeCapacity(Zir.Inst.Func{
- .return_type = args.ret_ty,
- .param_types_len = @intCast(u32, args.param_types.len),
- .body_len = @intCast(u32, args.body.len),
- });
- gz.astgen.appendRefsAssumeCapacity(args.param_types);
- gz.astgen.extra.appendSliceAssumeCapacity(args.body);
+ const astgen = gz.astgen;
+ const gpa = astgen.gpa;
- const new_index = @intCast(Zir.Inst.Index, gz.astgen.instructions.len);
- gz.astgen.instructions.appendAssumeCapacity(.{
- .tag = tag,
- .data = .{ .pl_node = .{
+ try gz.instructions.ensureUnusedCapacity(gpa, 1);
+ try astgen.instructions.ensureUnusedCapacity(gpa, 1);
+
+ if (args.cc != .none or args.lib_name != 0 or args.is_var_args) {
+ try astgen.extra.ensureUnusedCapacity(
+ gpa,
+ @typeInfo(Zir.Inst.ExtendedFunc).Struct.fields.len +
+ args.param_types.len + args.body.len +
+ @boolToInt(args.lib_name != 0) +
+ @boolToInt(args.cc != .none),
+ );
+ const payload_index = astgen.addExtraAssumeCapacity(Zir.Inst.ExtendedFunc{
.src_node = gz.nodeIndexToRelative(args.src_node),
- .payload_index = payload_index,
- } },
- });
- gz.instructions.appendAssumeCapacity(new_index);
- return gz.indexToRef(new_index);
+ .return_type = args.ret_ty,
+ .param_types_len = @intCast(u32, args.param_types.len),
+ .body_len = @intCast(u32, args.body.len),
+ });
+ if (args.cc != .none) {
+ astgen.extra.appendAssumeCapacity(@enumToInt(args.cc));
+ }
+ if (args.lib_name != 0) {
+ astgen.extra.appendAssumeCapacity(args.lib_name);
+ }
+ astgen.appendRefsAssumeCapacity(args.param_types);
+ astgen.extra.appendSliceAssumeCapacity(args.body);
+
+ const new_index = @intCast(Zir.Inst.Index, astgen.instructions.len);
+ astgen.instructions.appendAssumeCapacity(.{
+ .tag = .extended,
+ .data = .{ .extended = .{
+ .opcode = .func,
+ .small = @bitCast(u16, Zir.Inst.ExtendedFunc.Small{
+ .is_var_args = args.is_var_args,
+ .is_inferred_error = args.is_inferred_error,
+ .has_lib_name = args.lib_name != 0,
+ .has_cc = args.cc != .none,
+ }),
+ .operand = payload_index,
+ } },
+ });
+ gz.instructions.appendAssumeCapacity(new_index);
+ return gz.indexToRef(new_index);
+ } else {
+ try gz.astgen.extra.ensureUnusedCapacity(
+ gpa,
+ @typeInfo(Zir.Inst.Func).Struct.fields.len +
+ args.param_types.len + args.body.len,
+ );
+
+ const payload_index = gz.astgen.addExtraAssumeCapacity(Zir.Inst.Func{
+ .return_type = args.ret_ty,
+ .param_types_len = @intCast(u32, args.param_types.len),
+ .body_len = @intCast(u32, args.body.len),
+ });
+ gz.astgen.appendRefsAssumeCapacity(args.param_types);
+ gz.astgen.extra.appendSliceAssumeCapacity(args.body);
+
+ const tag: Zir.Inst.Tag = if (args.is_inferred_error) .func_inferred else .func;
+ const new_index = @intCast(Zir.Inst.Index, gz.astgen.instructions.len);
+ gz.astgen.instructions.appendAssumeCapacity(.{
+ .tag = tag,
+ .data = .{ .pl_node = .{
+ .src_node = gz.nodeIndexToRelative(args.src_node),
+ .payload_index = payload_index,
+ } },
+ });
+ gz.instructions.appendAssumeCapacity(new_index);
+ return gz.indexToRef(new_index);
+ }
}
pub fn addCall(
src/Sema.zig
@@ -194,9 +194,7 @@ pub fn analyzeBody(
.field_val => try sema.zirFieldVal(block, inst),
.field_val_named => try sema.zirFieldValNamed(block, inst),
.func => try sema.zirFunc(block, inst, false),
- .func_extra => try sema.zirFuncExtra(block, inst, false),
- .func_extra_var_args => try sema.zirFuncExtra(block, inst, true),
- .func_var_args => try sema.zirFunc(block, inst, true),
+ .func_inferred => try sema.zirFunc(block, inst, true),
.import => try sema.zirImport(block, inst),
.indexable_ptr_len => try sema.zirIndexablePtrLen(block, inst),
.int => try sema.zirInt(block, inst),
@@ -2646,7 +2644,12 @@ fn zirEnsureErrPayloadVoid(sema: *Sema, block: *Scope.Block, inst: Zir.Inst.Inde
}
}
-fn zirFunc(sema: *Sema, block: *Scope.Block, inst: Zir.Inst.Index, var_args: bool) InnerError!*Inst {
+fn zirFunc(
+ sema: *Sema,
+ block: *Scope.Block,
+ inst: Zir.Inst.Index,
+ inferred_error_set: bool,
+) InnerError!*Inst {
const tracy = trace(@src());
defer tracy.end();
@@ -2654,40 +2657,17 @@ fn zirFunc(sema: *Sema, block: *Scope.Block, inst: Zir.Inst.Index, var_args: boo
const src = inst_data.src();
const extra = sema.code.extraData(Zir.Inst.Func, inst_data.payload_index);
const param_types = sema.code.refSlice(extra.end, extra.data.param_types_len);
+ const body = sema.code.extra[extra.end + param_types.len ..][0..extra.data.body_len];
return sema.funcCommon(
block,
inst_data.src_node,
param_types,
+ body,
extra.data.return_type,
.Unspecified,
- var_args,
- );
-}
-
-fn zirFuncExtra(sema: *Sema, block: *Scope.Block, inst: Zir.Inst.Index, var_args: bool) InnerError!*Inst {
- const tracy = trace(@src());
- defer tracy.end();
-
- const inst_data = sema.code.instructions.items(.data)[inst].pl_node;
- const src = inst_data.src();
- const cc_src: LazySrcLoc = .{ .node_offset_fn_type_cc = inst_data.src_node };
- const extra = sema.code.extraData(Zir.Inst.FuncExtra, inst_data.payload_index);
- const param_types = sema.code.refSlice(extra.end, extra.data.param_types_len);
-
- const cc_tv = try sema.resolveInstConst(block, cc_src, extra.data.cc);
- // TODO once we're capable of importing and analyzing decls from
- // std.builtin, this needs to change
- const cc_str = cc_tv.val.castTag(.enum_literal).?.data;
- const cc = std.meta.stringToEnum(std.builtin.CallingConvention, cc_str) orelse
- return sema.mod.fail(&block.base, cc_src, "Unknown calling convention {s}", .{cc_str});
- return sema.funcCommon(
- block,
- inst_data.src_node,
- param_types,
- extra.data.return_type,
- cc,
- var_args,
+ false,
+ inferred_error_set,
);
}
@@ -2696,9 +2676,11 @@ fn funcCommon(
block: *Scope.Block,
src_node_offset: i32,
zir_param_types: []const Zir.Inst.Ref,
+ body: []const Zir.Inst.Index,
zir_return_type: Zir.Inst.Ref,
cc: std.builtin.CallingConvention,
var_args: bool,
+ inferred_error_set: bool,
) InnerError!*Inst {
const src: LazySrcLoc = .{ .node_offset = src_node_offset };
const ret_ty_src: LazySrcLoc = .{ .node_offset_fn_type_ret_ty = src_node_offset };
@@ -5307,15 +5289,68 @@ fn zirExtended(sema: *Sema, block: *Scope.Block, inst: Zir.Inst.Index) InnerErro
const extended = sema.code.instructions.items(.data)[inst].extended;
switch (extended.opcode) {
// zig fmt: off
- .c_undef => return sema.zirCUndef( block, inst, extended),
- .c_include => return sema.zirCInclude( block, inst, extended),
- .c_define => return sema.zirCDefine( block, inst, extended),
- .wasm_memory_size => return sema.zirWasmMemorySize( block, inst, extended),
- .wasm_memory_grow => return sema.zirWasmMemoryGrow( block, inst, extended),
+ .func => return sema.zirFuncExtended( block, inst, extended),
+ .c_undef => return sema.zirCUndef( block, inst, extended),
+ .c_include => return sema.zirCInclude( block, inst, extended),
+ .c_define => return sema.zirCDefine( block, inst, extended),
+ .wasm_memory_size => return sema.zirWasmMemorySize(block, inst, extended),
+ .wasm_memory_grow => return sema.zirWasmMemoryGrow(block, inst, extended),
// zig fmt: on
}
}
+fn zirFuncExtended(
+ sema: *Sema,
+ block: *Scope.Block,
+ inst: Zir.Inst.Index,
+ extended: Zir.Inst.Extended.InstData,
+) InnerError!*Inst {
+ const tracy = trace(@src());
+ defer tracy.end();
+
+ const extra = sema.code.extraData(Zir.Inst.ExtendedFunc, extended.operand);
+ const src: LazySrcLoc = .{ .node_offset = extra.data.src_node };
+ const cc_src: LazySrcLoc = .{ .node_offset_fn_type_cc = extra.data.src_node };
+ const small = @bitCast(Zir.Inst.ExtendedFunc.Small, extended.small);
+
+ var extra_index: usize = extra.end;
+ if (small.has_lib_name) {
+ const lib_name = @intToEnum(Zir.Inst.Ref, sema.code.extra[extra_index]);
+ extra_index += 1;
+ return sema.mod.fail(&block.base, src, "TODO: implement Sema func lib name", .{});
+ }
+ const cc: std.builtin.CallingConvention = if (small.has_cc) blk: {
+ const cc_ref = @intToEnum(Zir.Inst.Ref, sema.code.extra[extra_index]);
+ extra_index += 1;
+ const cc_tv = try sema.resolveInstConst(block, cc_src, cc_ref);
+ // TODO this needs to resolve other kinds of Value tags rather than
+ // assuming the tag will be .enum_field_index.
+ const cc_field_index = cc_tv.val.castTag(.enum_field_index).?.data;
+ // TODO should `@intToEnum` do this `@intCast` for you?
+ const cc = @intToEnum(
+ std.builtin.CallingConvention,
+ @intCast(@typeInfo(std.builtin.CallingConvention).Enum.tag_type, cc_field_index),
+ );
+ break :blk cc;
+ } else .Unspecified;
+
+ const param_types = sema.code.refSlice(extra_index, extra.data.param_types_len);
+ extra_index += 1;
+
+ const body = sema.code.extra[extra_index..][0..extra.data.body_len];
+
+ return sema.funcCommon(
+ block,
+ extra.data.src_node,
+ param_types,
+ body,
+ extra.data.return_type,
+ cc,
+ small.is_var_args,
+ small.is_inferred_error,
+ );
+}
+
fn zirCUndef(
sema: *Sema,
block: *Scope.Block,
src/Zir.zig
@@ -371,15 +371,8 @@ pub const Inst = struct {
/// the body_len is 0. Calling convention is auto.
/// Uses the `pl_node` union field. `payload_index` points to a `Func`.
func,
- /// Same as `func` but the function is variadic.
- func_var_args,
- /// Same as `func` but with extra fields:
- /// * calling convention
- /// * extern lib name
- /// Uses the `pl_node` union field. `payload_index` points to a `FuncExtra`.
- func_extra,
- /// Same as `func_extra` but the function is variadic.
- func_extra_var_args,
+ /// Same as `func` but has an inferred error set.
+ func_inferred,
/// Implements the `@import` builtin.
/// Uses the `str_tok` field.
import,
@@ -1010,9 +1003,7 @@ pub const Inst = struct {
.field_ptr_named,
.field_val_named,
.func,
- .func_var_args,
- .func_extra,
- .func_extra_var_args,
+ .func_inferred,
.has_decl,
.int,
.float,
@@ -1211,6 +1202,11 @@ pub const Inst = struct {
/// Rarer instructions are here; ones that do not fit in the 8-bit `Tag` enum.
/// `noreturn` instructions may not go here; they must be part of the main `Tag` enum.
pub const Extended = enum(u16) {
+ /// Represents a function declaration or function prototype, depending on
+ /// whether body_len is 0.
+ /// `operand` is payload index to `ExtendedFunc`.
+ /// `small` is `ExtendedFunc.Small`.
+ func,
/// `operand` is payload index to `UnNode`.
c_undef,
/// `operand` is payload index to `UnNode`.
@@ -1774,15 +1770,23 @@ pub const Inst = struct {
};
/// Trailing:
- /// 0. param_type: Ref // for each param_types_len
- /// 1. body: Index // for each body_len
- pub const FuncExtra = struct {
- cc: Ref,
- /// null terminated string index, or 0 to mean none.
- lib_name: u32,
+ /// 0. lib_name: u32, // null terminated string index, if has_lib_name is set
+ /// 1. cc: Ref, // if has_cc is set
+ /// 2. param_type: Ref // for each param_types_len
+ /// 3. body: Index // for each body_len
+ pub const ExtendedFunc = struct {
+ src_node: i32,
return_type: Ref,
param_types_len: u32,
body_len: u32,
+
+ pub const Small = packed struct {
+ is_var_args: bool,
+ is_inferred_error: bool,
+ has_lib_name: bool,
+ has_cc: bool,
+ _: u12 = undefined,
+ };
};
/// Trailing:
@@ -2459,9 +2463,7 @@ const Writer = struct {
=> try self.writeStrTok(stream, inst),
.func => try self.writeFunc(stream, inst, false),
- .func_extra => try self.writeFuncExtra(stream, inst, false),
- .func_var_args => try self.writeFunc(stream, inst, true),
- .func_extra_var_args => try self.writeFuncExtra(stream, inst, true),
+ .func_inferred => try self.writeFunc(stream, inst, true),
.@"unreachable" => try self.writeUnreachable(stream, inst),
@@ -3099,7 +3101,7 @@ const Writer = struct {
self: *Writer,
stream: anytype,
inst: Inst.Index,
- var_args: bool,
+ inferred_error_set: bool,
) !void {
const inst_data = self.code.instructions.items(.data)[inst].pl_node;
const src = inst_data.src();
@@ -3110,36 +3112,14 @@ const Writer = struct {
stream,
param_types,
extra.data.return_type,
- var_args,
+ inferred_error_set,
+ false,
.none,
body,
src,
);
}
- fn writeFuncExtra(
- self: *Writer,
- stream: anytype,
- inst: Inst.Index,
- var_args: bool,
- ) !void {
- const inst_data = self.code.instructions.items(.data)[inst].pl_node;
- const src = inst_data.src();
- const extra = self.code.extraData(Inst.FuncExtra, inst_data.payload_index);
- const param_types = self.code.refSlice(extra.end, extra.data.param_types_len);
- const cc = extra.data.cc;
- const body = self.code.extra[extra.end + param_types.len ..][0..extra.data.body_len];
- return self.writeFuncCommon(
- stream,
- param_types,
- extra.data.return_type,
- var_args,
- cc,
- body,
- src,
- );
- }
-
fn writeBoolBr(self: *Writer, stream: anytype, inst: Inst.Index) !void {
const inst_data = self.code.instructions.items(.data)[inst].bool_br;
const extra = self.code.extraData(Inst.Block, inst_data.payload_index);
@@ -3184,6 +3164,7 @@ const Writer = struct {
stream: anytype,
param_types: []const Inst.Ref,
ret_ty: Inst.Ref,
+ inferred_error_set: bool,
var_args: bool,
cc: Inst.Ref,
body: []const Inst.Index,
@@ -3197,7 +3178,8 @@ const Writer = struct {
try stream.writeAll("], ");
try self.writeInstRef(stream, ret_ty);
try self.writeOptionalInstRef(stream, ", cc=", cc);
- try self.writeFlag(stream, ", var_args", var_args);
+ try self.writeFlag(stream, ", vargs", var_args);
+ try self.writeFlag(stream, ", inferror", inferred_error_set);
try stream.writeAll(", {\n");
self.indent += 2;
BRANCH_TODO
@@ -737,3 +737,27 @@ fn errorSetDecl(
try mod.analyzeExport(&decl_scope.base, export_src, name, decl);
}
}
+
+ fn writeFuncExtra(
+ self: *Writer,
+ stream: anytype,
+ inst: Inst.Index,
+ var_args: bool,
+ ) !void {
+ const inst_data = self.code.instructions.items(.data)[inst].pl_node;
+ const src = inst_data.src();
+ const extra = self.code.extraData(Inst.FuncExtra, inst_data.payload_index);
+ const param_types = self.code.refSlice(extra.end, extra.data.param_types_len);
+ const cc = extra.data.cc;
+ const body = self.code.extra[extra.end + param_types.len ..][0..extra.data.body_len];
+ return self.writeFuncCommon(
+ stream,
+ param_types,
+ extra.data.return_type,
+ var_args,
+ cc,
+ body,
+ src,
+ );
+ }
+