feature. See also
. The project being documented here (as the example) is the Zig library itself.
AstGen.fnProtoExprInner
fn fnProtoExprInner(
gz: *GenZir,
scope: *Scope,
ri: ResultInfo,
node: Ast.Node.Index,
fn_proto: Ast.full.FnProto,
implicit_ccc: bool,
) InnerError!Zir.Inst.Ref
File
Code
fn fnProtoExprInner(
gz: *GenZir,
scope: *Scope,
ri: ResultInfo,
node: Ast.Node.Index,
fn_proto: Ast.full.FnProto,
implicit_ccc: bool,
) InnerError!Zir.Inst.Ref {
const astgen = gz.astgen;
const tree = astgen.tree;
var block_scope = gz.makeSubBlock(scope);
defer block_scope.unstack();
const block_inst = try gz.makeBlockInst(.block_inline, node);
var noalias_bits: u32 = 0;
const is_var_args = is_var_args: {
var param_type_i: usize = 0;
var it = fn_proto.iterate(tree);
while (it.next()) |param| : (param_type_i += 1) {
const is_comptime = if (param.comptime_noalias) |token| switch (tree.tokenTag(token)) {
.keyword_noalias => is_comptime: {
noalias_bits |= @as(u32, 1) << (std.math.cast(u5, param_type_i) orelse
return astgen.failTok(token, "this compiler implementation only supports 'noalias' on the first 32 parameters", .{}));
break :is_comptime false;
},
.keyword_comptime => true,
else => false,
} else false;
const is_anytype = if (param.anytype_ellipsis3) |token| blk: {
switch (tree.tokenTag(token)) {
.keyword_anytype => break :blk true,
.ellipsis3 => break :is_var_args true,
else => unreachable,
}
} else false;
const param_name = if (param.name_token) |name_token| blk: {
if (mem.eql(u8, "_", tree.tokenSlice(name_token)))
break :blk .empty;
break :blk try astgen.identAsString(name_token);
} else .empty;
if (is_anytype) {
const name_token = param.name_token orelse param.anytype_ellipsis3.?;
const tag: Zir.Inst.Tag = if (is_comptime)
.param_anytype_comptime
else
.param_anytype;
_ = try block_scope.addStrTok(tag, param_name, name_token);
} else {
const param_type_node = param.type_expr.?;
var param_gz = block_scope.makeSubBlock(scope);
defer param_gz.unstack();
param_gz.is_comptime = true;
const param_type = try fullBodyExpr(¶m_gz, scope, coerced_type_ri, param_type_node, .normal);
const param_inst_expected: Zir.Inst.Index = @fromBackingInt(@intCast(astgen.instructions.len + 1));
_ = try param_gz.addBreakWithSrcNode(.break_inline, param_inst_expected, param_type, param_type_node);
const name_token = param.name_token orelse tree.nodeMainToken(param_type_node);
const tag: Zir.Inst.Tag = if (is_comptime) .param_comptime else .param;
// arguments (we haven't set up scopes here).
const param_inst = try block_scope.addParam(¶m_gz, &.{}, false, tag, name_token, param_name);
assert(param_inst_expected == param_inst);
}
}
break :is_var_args false;
};
const cc: Zir.Inst.Ref = if (fn_proto.ast.callconv_expr.unwrap()) |callconv_expr|
try comptimeExpr(
&block_scope,
scope,
.{ .rl = .{ .coerced_ty = try block_scope.addStdLangValue(callconv_expr, .calling_convention) } },
callconv_expr,
.@"callconv",
)
else if (implicit_ccc)
try block_scope.addStdLangValue(node, .calling_convention_c)
else
.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, .fn_ret_ty);
const result = try block_scope.addFunc(.{
.src_node = fn_proto.ast.proto_node,
.cc_ref = cc,
.cc_gz = null,
.ret_ref = ret_ty,
.ret_gz = null,
.ret_param_refs = &.{},
.param_insts = &.{},
.ret_ty_is_generic = false,
.param_block = block_inst,
.body_gz = null,
.is_var_args = is_var_args,
.is_inferred_error = false,
.is_noinline = false,
.noalias_bits = noalias_bits,
.proto_hash = undefined,
});
_ = try block_scope.addBreak(.break_inline, block_inst, result);
try block_scope.setBlockBody(block_inst);
try gz.instructions.append(astgen.gpa, block_inst);
return rvalue(gz, ri, block_inst.toRef(), fn_proto.ast.proto_node);
}