callExpr
Function parameters
Parameters
- gz:*GenZir
- scope:*Scope
- override_decl_literal_type:Zir.Inst.Ref
- If this is not `.none` and this call is a decl literal form (`.foo(...)`), then this
- node:Ast.Node.Index
- call:Ast.full.Call
Functions in this namespace
Functions
Source
Implementation
fn callExpr(
gz: *GenZir,
scope: *Scope,
ri: ResultInfo,
/// If this is not `.none` and this call is a decl literal form (`.foo(...)`), then this
/// type is used as the decl literal result type instead of the result type from `ri.rl`.
override_decl_literal_type: Zir.Inst.Ref,
node: Ast.Node.Index,
call: Ast.full.Call,
) InnerError!Zir.Inst.Ref {
const astgen = gz.astgen;
const callee = try calleeExpr(gz, scope, ri.rl, override_decl_literal_type, call.ast.fn_expr);
const modifier: std.builtin.CallModifier = blk: {
if (gz.nosuspend_node != .none) {
break :blk .no_suspend;
}
break :blk .auto;
};
{
astgen.advanceSourceCursor(astgen.tree.tokenStart(call.ast.lparen));
const line = astgen.source_line - gz.decl_line;
const column = astgen.source_column;
// Sema expects a dbg_stmt immediately before call,
try emitDbgStmtForceCurrentIndex(gz, .{ line, column });
}
switch (callee) {
.direct => |obj| assert(obj != .none),
.field => |field| assert(field.obj_ptr != .none),
}
const call_index: Zir.Inst.Index = @enumFromInt(astgen.instructions.len);
const call_inst = call_index.toRef();
try gz.astgen.instructions.append(astgen.gpa, undefined);
try gz.instructions.append(astgen.gpa, call_index);
const scratch_top = astgen.scratch.items.len;
defer astgen.scratch.items.len = scratch_top;
var scratch_index = scratch_top;
try astgen.scratch.resize(astgen.gpa, scratch_top + call.ast.params.len);
for (call.ast.params) |param_node| {
var arg_block = gz.makeSubBlock(scope);
defer arg_block.unstack();
// `call_inst` is reused to provide the param type.
const arg_ref = try fullBodyExpr(&arg_block, &arg_block.base, .{ .rl = .{ .coerced_ty = call_inst }, .ctx = .fn_arg }, param_node, .normal);
_ = try arg_block.addBreakWithSrcNode(.break_inline, call_index, arg_ref, param_node);
const body = arg_block.instructionsSlice();
try astgen.scratch.ensureUnusedCapacity(astgen.gpa, countBodyLenAfterFixups(astgen, body));
appendBodyWithFixupsArrayList(astgen, &astgen.scratch, body);
astgen.scratch.items[scratch_index] = @intCast(astgen.scratch.items.len - scratch_top);
scratch_index += 1;
}
// If our result location is a try/catch/error-union-if/return, a function argument,
// or an initializer for a `const` variable, the error trace propagates.
// Otherwise, it should always be popped (handled in Sema).
const propagate_error_trace = switch (ri.ctx) {
.error_handling_expr, .@"return", .fn_arg, .const_init => true,
else => false,
};
switch (callee) {
.direct => |callee_obj| {
const payload_index = try addExtra(astgen, Zir.Inst.Call{
.callee = callee_obj,
.flags = .{
.pop_error_return_trace = !propagate_error_trace,
.packed_modifier = @intCast(@intFromEnum(modifier)),
.args_len = @intCast(call.ast.params.len),
},
});
if (call.ast.params.len != 0) {
try astgen.extra.appendSlice(astgen.gpa, astgen.scratch.items[scratch_top..]);
}
gz.astgen.instructions.set(@intFromEnum(call_index), .{
.tag = .call,
.data = .{ .pl_node = .{
.src_node = gz.nodeIndexToRelative(node),
.payload_index = payload_index,
} },
});
},
.field => |callee_field| {
const payload_index = try addExtra(astgen, Zir.Inst.FieldCall{
.obj_ptr = callee_field.obj_ptr,
.field_name_start = callee_field.field_name_start,
.flags = .{
.pop_error_return_trace = !propagate_error_trace,
.packed_modifier = @intCast(@intFromEnum(modifier)),
.args_len = @intCast(call.ast.params.len),
},
});
if (call.ast.params.len != 0) {
try astgen.extra.appendSlice(astgen.gpa, astgen.scratch.items[scratch_top..]);
}
gz.astgen.instructions.set(@intFromEnum(call_index), .{
.tag = .field_call,
.data = .{ .pl_node = .{
.src_node = gz.nodeIndexToRelative(node),
.payload_index = payload_index,
} },
});
},
}
return rvalue(gz, ri, call_inst, node); // TODO function call with result location
}