authorgravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2022-09-20 22:15:48-07:00
committergravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2023-06-26 15:57:06-07:00
loge70c34cdb7ea7d9b7b6feddb2d8e6194ed1188a4
treead94bd45b4ca65ec72820bed6d5bd7c35f60690f
parent5a8c445779b3b87ba38fbcac0efcc7ebb3787161

stage2: implement async_call

* AstGen emits async_call instruction for variable declarations of async calls. * Sema analyzes async_call instruction. * Liveness handles call_async AIR instruction. * Fix Type.eql for async frame types.

6 files changed, 187 insertions(+), 70 deletions(-)

src/Air.zig+1
...@@ -1075,6 +1075,7 @@ pub const Call = struct {...@@ -1075,6 +1075,7 @@ pub const Call = struct {
10751075
1076/// Trailing is a list of `Inst.Ref` for every `args_len`.1076/// Trailing is a list of `Inst.Ref` for every `args_len`.
1077pub const AsyncCall = struct {1077pub const AsyncCall = struct {
1078 frame_ptr: Inst.Ref,
1078 callee: Inst.Ref,1079 callee: Inst.Ref,
1079 args_len: u32,1080 args_len: u32,
1080};1081};
src/AstGen.zig+99-22
...@@ -2541,6 +2541,8 @@ fn addEnsureResult(gz: *GenZir, maybe_unused_result: Zir.Inst.Ref, statement: As...@@ -2541,6 +2541,8 @@ fn addEnsureResult(gz: *GenZir, maybe_unused_result: Zir.Inst.Ref, statement: As
2541 .alloc_inferred_mut,2541 .alloc_inferred_mut,
2542 .alloc_inferred_comptime,2542 .alloc_inferred_comptime,
2543 .alloc_inferred_comptime_mut,2543 .alloc_inferred_comptime_mut,
2544 .async_call,
2545 .async_field_call,
2544 .make_ptr_const,2546 .make_ptr_const,
2545 .array_cat,2547 .array_cat,
2546 .array_mul,2548 .array_mul,
...@@ -2788,7 +2790,6 @@ fn addEnsureResult(gz: *GenZir, maybe_unused_result: Zir.Inst.Ref, statement: As...@@ -2788,7 +2790,6 @@ fn addEnsureResult(gz: *GenZir, maybe_unused_result: Zir.Inst.Ref, statement: As
2788 .validate_deref,2790 .validate_deref,
2789 .save_err_ret_index,2791 .save_err_ret_index,
2790 .restore_err_ret_index,2792 .restore_err_ret_index,
2791 .async_call,
2792 => break :b true,2793 => break :b true,
27932794
2794 .@"defer" => unreachable,2795 .@"defer" => unreachable,
...@@ -3301,11 +3302,17 @@ fn varDecl(...@@ -3301,11 +3302,17 @@ fn varDecl(
3301 } else a: {3302 } else a: {
3302 const alloc = alloc: {3303 const alloc = alloc: {
3303 if (align_inst == .none) {3304 if (align_inst == .none) {
3304 const tag: Zir.Inst.Tag = if (is_comptime)3305 var params: [1]Ast.Node.Index = undefined;
3305 .alloc_inferred_comptime_mut3306 if (is_comptime) {
3306 else3307 break :alloc try gz.addNode(.alloc_inferred_comptime_mut, node);
3307 .alloc_inferred_mut;3308 } else {
3308 break :alloc try gz.addNode(tag, node);3309 if (nodeGetCall(tree, var_decl.ast.init_node, &params)) |call| {
3310 if (call.async_token != null) {
3311 return asyncCallExpr(gz, scope, node, call, ident_name, block_arena, name_token);
3312 }
3313 }
3314 break :alloc try gz.addNode(.alloc_inferred_mut, node);
3315 }
3309 } else {3316 } else {
3310 break :alloc try gz.addAllocExtended(.{3317 break :alloc try gz.addAllocExtended(.{
3311 .node = node,3318 .node = node,
...@@ -3346,6 +3353,34 @@ fn varDecl(...@@ -3346,6 +3353,34 @@ fn varDecl(
3346 }3353 }
3347}3354}
33483355
3356fn asyncCallExpr(
3357 gz: *GenZir,
3358 scope: *Scope,
3359 node: Ast.Node.Index,
3360 call: Ast.full.Call,
3361 ident_name: u32,
3362 block_arena: Allocator,
3363 name_token: Ast.TokenIndex,
3364) InnerError!*Scope {
3365 gz.rl_ty_inst = .none;
3366
3367 const call_inst = try callExprInner(gz, scope, node, call, .async_kw, false, true);
3368
3369 try gz.addDbgVar(.dbg_var_ptr, ident_name, call_inst);
3370
3371 const sub_scope = try block_arena.create(Scope.LocalPtr);
3372 sub_scope.* = .{
3373 .parent = scope,
3374 .gen_zir = gz,
3375 .name = ident_name,
3376 .ptr = call_inst,
3377 .token_src = name_token,
3378 .maybe_comptime = false,
3379 .id_cat = .@"local variable",
3380 };
3381 return &sub_scope.base;
3382}
3383
3349fn emitDbgNode(gz: *GenZir, node: Ast.Node.Index) !void {3384fn emitDbgNode(gz: *GenZir, node: Ast.Node.Index) !void {
3350 // The instruction emitted here is for debugging runtime code.3385 // The instruction emitted here is for debugging runtime code.
3351 // If the current block will be evaluated only during semantic analysis3386 // If the current block will be evaluated only during semantic analysis
...@@ -9076,9 +9111,6 @@ fn callExpr(...@@ -9076,9 +9111,6 @@ fn callExpr(
9076 node: Ast.Node.Index,9111 node: Ast.Node.Index,
9077 call: Ast.full.Call,9112 call: Ast.full.Call,
9078) InnerError!Zir.Inst.Ref {9113) InnerError!Zir.Inst.Ref {
9079 const astgen = gz.astgen;
9080
9081 const callee = try calleeExpr(gz, scope, call.ast.fn_expr);
9082 const modifier: std.builtin.CallModifier = blk: {9114 const modifier: std.builtin.CallModifier = blk: {
9083 if (gz.is_comptime) {9115 if (gz.is_comptime) {
9084 break :blk .compile_time;9116 break :blk .compile_time;
...@@ -9092,6 +9124,29 @@ fn callExpr(...@@ -9092,6 +9124,29 @@ fn callExpr(
9092 break :blk .auto;9124 break :blk .auto;
9093 };9125 };
90949126
9127 // If our result location is a try/catch/error-union-if/return, a function argument,
9128 // or an initializer for a `const` variable, the error trace propagates.
9129 // Otherwise, it should always be popped (handled in Sema).
9130 const propagate_error_trace = switch (ri.ctx) {
9131 .error_handling_expr, .@"return", .fn_arg, .const_init => true,
9132 else => false,
9133 };
9134 const call_inst = try callExprInner(gz, scope, node, call, modifier, propagate_error_trace, false);
9135 return rvalue(gz, ri, call_inst, node); // TODO function call with result location
9136}
9137
9138fn callExprInner(
9139 gz: *GenZir,
9140 scope: *Scope,
9141 node: Ast.Node.Index,
9142 call: Ast.full.Call,
9143 modifier: std.builtin.CallModifier,
9144 propagate_error_trace: bool,
9145 is_async: bool,
9146) InnerError!Zir.Inst.Ref {
9147 const astgen = gz.astgen;
9148 const callee = try calleeExpr(gz, scope, call.ast.fn_expr);
9149
9095 {9150 {
9096 astgen.advanceSourceCursor(astgen.tree.tokens.items(.start)[call.ast.lparen]);9151 astgen.advanceSourceCursor(astgen.tree.tokens.items(.start)[call.ast.lparen]);
9097 const line = astgen.source_line - gz.decl_line;9152 const line = astgen.source_line - gz.decl_line;
...@@ -9139,17 +9194,12 @@ fn callExpr(...@@ -9139,17 +9194,12 @@ fn callExpr(
9139 scratch_index += 1;9194 scratch_index += 1;
9140 }9195 }
91419196
9142 // If our result location is a try/catch/error-union-if/return, a function argument,
9143 // or an initializer for a `const` variable, the error trace propagates.
9144 // Otherwise, it should always be popped (handled in Sema).
9145 const propagate_error_trace = switch (ri.ctx) {
9146 .error_handling_expr, .@"return", .fn_arg, .const_init => true,
9147 else => false,
9148 };
9149
9150 switch (callee) {9197 switch (callee) {
9151 .direct => |callee_obj| {9198 .direct => |callee_obj| {
9152 const payload_index = try addExtra(astgen, Zir.Inst.Call{9199 const payload_index = if (is_async) try addExtra(astgen, Zir.Inst.AsyncCall{
9200 .callee = callee_obj,
9201 .args_len = @intCast(call.ast.params.len),
9202 }) else try addExtra(astgen, Zir.Inst.Call{
9153 .callee = callee_obj,9203 .callee = callee_obj,
9154 .flags = .{9204 .flags = .{
9155 .pop_error_return_trace = !propagate_error_trace,9205 .pop_error_return_trace = !propagate_error_trace,
...@@ -9161,7 +9211,7 @@ fn callExpr(...@@ -9161,7 +9211,7 @@ fn callExpr(
9161 try astgen.extra.appendSlice(astgen.gpa, astgen.scratch.items[scratch_top..]);9211 try astgen.extra.appendSlice(astgen.gpa, astgen.scratch.items[scratch_top..]);
9162 }9212 }
9163 gz.astgen.instructions.set(call_index, .{9213 gz.astgen.instructions.set(call_index, .{
9164 .tag = .call,9214 .tag = if (is_async) .async_call else .call,
9165 .data = .{ .pl_node = .{9215 .data = .{ .pl_node = .{
9166 .src_node = gz.nodeIndexToRelative(node),9216 .src_node = gz.nodeIndexToRelative(node),
9167 .payload_index = payload_index,9217 .payload_index = payload_index,
...@@ -9169,7 +9219,11 @@ fn callExpr(...@@ -9169,7 +9219,11 @@ fn callExpr(
9169 });9219 });
9170 },9220 },
9171 .field => |callee_field| {9221 .field => |callee_field| {
9172 const payload_index = try addExtra(astgen, Zir.Inst.FieldCall{9222 const payload_index = if (is_async) try addExtra(astgen, Zir.Inst.AsyncFieldCall{
9223 .obj_ptr = callee_field.obj_ptr,
9224 .field_name_start = callee_field.field_name_start,
9225 .args_len = @intCast(call.ast.params.len),
9226 }) else try addExtra(astgen, Zir.Inst.FieldCall{
9173 .obj_ptr = callee_field.obj_ptr,9227 .obj_ptr = callee_field.obj_ptr,
9174 .field_name_start = callee_field.field_name_start,9228 .field_name_start = callee_field.field_name_start,
9175 .flags = .{9229 .flags = .{
...@@ -9182,7 +9236,7 @@ fn callExpr(...@@ -9182,7 +9236,7 @@ fn callExpr(
9182 try astgen.extra.appendSlice(astgen.gpa, astgen.scratch.items[scratch_top..]);9236 try astgen.extra.appendSlice(astgen.gpa, astgen.scratch.items[scratch_top..]);
9183 }9237 }
9184 gz.astgen.instructions.set(call_index, .{9238 gz.astgen.instructions.set(call_index, .{
9185 .tag = .field_call,9239 .tag = if (is_async) .async_field_call else .field_call,
9186 .data = .{ .pl_node = .{9240 .data = .{ .pl_node = .{
9187 .src_node = gz.nodeIndexToRelative(node),9241 .src_node = gz.nodeIndexToRelative(node),
9188 .payload_index = payload_index,9242 .payload_index = payload_index,
...@@ -9190,7 +9244,7 @@ fn callExpr(...@@ -9190,7 +9244,7 @@ fn callExpr(
9190 });9244 });
9191 },9245 },
9192 }9246 }
9193 return rvalue(gz, ri, call_inst, node); // TODO function call with result location9247 return call_inst;
9194}9248}
91959249
9196const Callee = union(enum) {9250const Callee = union(enum) {
...@@ -10321,6 +10375,29 @@ fn nodeUsesAnonNameStrategy(tree: *const Ast, node: Ast.Node.Index) bool {...@@ -10321,6 +10375,29 @@ fn nodeUsesAnonNameStrategy(tree: *const Ast, node: Ast.Node.Index) bool {
10321 }10375 }
10322}10376}
1032310377
10378fn nodeGetCall(
10379 tree: *const Ast,
10380 start_node: Ast.Node.Index,
10381 params: *[1]Ast.Node.Index,
10382) ?Ast.full.Call {
10383 const node_tags = tree.nodes.items(.tag);
10384 const node_datas = tree.nodes.items(.data);
10385
10386 var node = start_node;
10387 while (true) {
10388 switch (node_tags[node]) {
10389 .call_one, .call_one_comma, .async_call_one, .async_call_one_comma => {
10390 return tree.callOne(params, node);
10391 },
10392 .call, .call_comma, .async_call, .async_call_comma => {
10393 return tree.callFull(node);
10394 },
10395 .grouped_expression => node = node_datas[node].lhs,
10396 else => return null,
10397 }
10398 }
10399}
10400
10324/// Applies `rl` semantics to `result`. Expressions which do not do their own handling of10401/// Applies `rl` semantics to `result`. Expressions which do not do their own handling of
10325/// result locations must call this function on their result.10402/// result locations must call this function on their result.
10326/// As an example, if the `ResultLoc` is `ptr`, it will write the result to the pointer.10403/// As an example, if the `ResultLoc` is `ptr`, it will write the result to the pointer.
src/Sema.zig+28-14
...@@ -409,11 +409,7 @@ pub const Block = struct {...@@ -409,11 +409,7 @@ pub const Block = struct {
409 return mod.namespacePtr(block.namespace).file_scope;409 return mod.namespacePtr(block.namespace).file_scope;
410 }410 }
411411
412 fn addTy(412 fn addTy(block: *Block, tag: Air.Inst.Tag, ty: Type) error{OutOfMemory}!Air.Inst.Ref {
413 block: *Block,
414 tag: Air.Inst.Tag,
415 ty: Type,
416 ) error{OutOfMemory}!Air.Inst.Ref {
417 return block.addInst(.{413 return block.addInst(.{
418 .tag = tag,414 .tag = tag,
419 .data = .{ .ty = ty },415 .data = .{ .ty = ty },
...@@ -943,7 +939,8 @@ fn analyzeBodyInner(...@@ -943,7 +939,8 @@ fn analyzeBodyInner(
943 .c_import => try sema.zirCImport(block, inst),939 .c_import => try sema.zirCImport(block, inst),
944 .call => try sema.zirCall(block, inst, Zir.Inst.Call),940 .call => try sema.zirCall(block, inst, Zir.Inst.Call),
945 .field_call => try sema.zirCall(block, inst, Zir.Inst.FieldCall),941 .field_call => try sema.zirCall(block, inst, Zir.Inst.FieldCall),
946 .async_call => try sema.zirAsyncCall(block, inst),942 .async_call => try sema.zirAsyncCall(block, inst, Zir.Inst.AsyncCall),
943 .async_field_call => try sema.zirAsyncCall(block, inst, Zir.Inst.AsyncFieldCall),
947 .closure_get => try sema.zirClosureGet(block, inst),944 .closure_get => try sema.zirClosureGet(block, inst),
948 .cmp_lt => try sema.zirCmp(block, inst, .lt),945 .cmp_lt => try sema.zirCmp(block, inst, .lt),
949 .cmp_lte => try sema.zirCmp(block, inst, .lte),946 .cmp_lte => try sema.zirCmp(block, inst, .lte),
...@@ -6477,18 +6474,33 @@ fn zirCall(...@@ -6477,18 +6474,33 @@ fn zirCall(
6477 );6474 );
6478}6475}
64796476
6480fn zirAsyncCall(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air.Inst.Ref {6477fn zirAsyncCall(
6478 sema: *Sema,
6479 block: *Block,
6480 inst: Zir.Inst.Index,
6481 comptime ExtraType: type,
6482) CompileError!Air.Inst.Ref {
6483 const mod = sema.mod;
6481 const inst_data = sema.code.instructions.items(.data)[inst].pl_node;6484 const inst_data = sema.code.instructions.items(.data)[inst].pl_node;
6482 const func_src: LazySrcLoc = .{ .node_offset_async_call_func = inst_data.src_node };6485 const callee_src: LazySrcLoc = .{ .node_offset_async_call_func = inst_data.src_node };
6483 const call_src: LazySrcLoc = .{ .node_offset_var_decl_init = inst_data.src_node };6486 const call_src: LazySrcLoc = .{ .node_offset_var_decl_init = inst_data.src_node };
6484 const extra = sema.code.extraData(Zir.Inst.AsyncCall, inst_data.payload_index);6487 const extra = sema.code.extraData(ExtraType, inst_data.payload_index);
6485 const args_len = extra.data.args_len;6488 const args_len = extra.data.args_len;
6486 const callee: ResolvedFieldCallee = .{ .direct = try sema.resolveInst(extra.data.callee) };6489 const callee: ResolvedFieldCallee = switch (ExtraType) {
6490 Zir.Inst.AsyncCall => .{ .direct = try sema.resolveInst(extra.data.callee) },
6491 Zir.Inst.AsyncFieldCall => blk: {
6492 const object_ptr = try sema.resolveInst(extra.data.obj_ptr);
6493 const field_name = try mod.intern_pool.getOrPutString(sema.gpa, sema.code.nullTerminatedString(extra.data.field_name_start));
6494 const field_name_src: LazySrcLoc = .{ .node_offset_field_name = inst_data.src_node };
6495 break :blk try sema.fieldCallBind(block, callee_src, object_ptr, field_name, field_name_src);
6496 },
6497 else => @compileError("unreachable"),
6498 };
6487 return callCommon(6499 return callCommon(
6488 sema,6500 sema,
6489 block,6501 block,
6490 inst,6502 inst,
6491 func_src,6503 callee_src,
6492 call_src,6504 call_src,
6493 callee,6505 callee,
6494 args_len,6506 args_len,
...@@ -7286,8 +7298,9 @@ fn addAsyncCallInst(...@@ -7286,8 +7298,9 @@ fn addAsyncCallInst(
7286 args: []const Air.Inst.Ref,7298 args: []const Air.Inst.Ref,
7287) Allocator.Error!Air.Inst.Ref {7299) Allocator.Error!Air.Inst.Ref {
7288 const mod = sema.mod;7300 const mod = sema.mod;
7289 const frame_ty = try mod.asyncFrameType(callee_fn);7301 const ptr_frame_ty = try mod.singleMutPtrType(try mod.asyncFrameType(callee_fn));
7290 const frame_ty_ref = try sema.addType(frame_ty);7302 const frame_ptr = try block.addTy(.alloc, ptr_frame_ty);
7303 const ptr_frame_ty_ref = try sema.addType(ptr_frame_ty);
7291 try sema.air_extra.ensureUnusedCapacity(7304 try sema.air_extra.ensureUnusedCapacity(
7292 sema.gpa,7305 sema.gpa,
7293 @typeInfo(Air.AsyncCall).Struct.fields.len + args.len,7306 @typeInfo(Air.AsyncCall).Struct.fields.len + args.len,
...@@ -7295,8 +7308,9 @@ fn addAsyncCallInst(...@@ -7295,8 +7308,9 @@ fn addAsyncCallInst(
7295 const call_inst = try block.addInst(.{7308 const call_inst = try block.addInst(.{
7296 .tag = .call_async,7309 .tag = .call_async,
7297 .data = .{ .ty_pl = .{7310 .data = .{ .ty_pl = .{
7298 .ty = frame_ty_ref,7311 .ty = ptr_frame_ty_ref,
7299 .payload = sema.addExtraAssumeCapacity(Air.AsyncCall{7312 .payload = sema.addExtraAssumeCapacity(Air.AsyncCall{
7313 .frame_ptr = frame_ptr,
7300 .callee = callee,7314 .callee = callee,
7301 .args_len = @intCast(args.len),7315 .args_len = @intCast(args.len),
7302 }),7316 }),
src/Zir.zig+17-1
...@@ -318,6 +318,11 @@ pub const Inst = struct {...@@ -318,6 +318,11 @@ pub const Inst = struct {
318 /// Uses the `pl_node` union field with payload `AsyncCall`318 /// Uses the `pl_node` union field with payload `AsyncCall`
319 /// AST node is the entire variable declaration, with the init node being a call.319 /// AST node is the entire variable declaration, with the init node being a call.
320 async_call,320 async_call,
321 /// Combination of `field_call` and `async_call`.
322 /// Corresponds with the syntax `var foo = async bar.baz();`.
323 /// Uses the `pl_node` union field with payload `AsyncFieldCall`
324 /// AST node is the entire variable declaration, with the init node being a field call.
325 async_field_call,
321 /// `<`326 /// `<`
322 /// Uses the `pl_node` union field. Payload is `Bin`.327 /// Uses the `pl_node` union field. Payload is `Bin`.
323 cmp_lt,328 cmp_lt,
...@@ -1032,6 +1037,7 @@ pub const Inst = struct {...@@ -1032,6 +1037,7 @@ pub const Inst = struct {
1032 .call,1037 .call,
1033 .field_call,1038 .field_call,
1034 .async_call,1039 .async_call,
1040 .async_field_call,
1035 .cmp_lt,1041 .cmp_lt,
1036 .cmp_lte,1042 .cmp_lte,
1037 .cmp_eq,1043 .cmp_eq,
...@@ -1310,6 +1316,8 @@ pub const Inst = struct {...@@ -1310,6 +1316,8 @@ pub const Inst = struct {
1310 .alloc_inferred_mut,1316 .alloc_inferred_mut,
1311 .alloc_inferred_comptime,1317 .alloc_inferred_comptime,
1312 .alloc_inferred_comptime_mut,1318 .alloc_inferred_comptime_mut,
1319 .async_call,
1320 .async_field_call,
1313 .make_ptr_const,1321 .make_ptr_const,
1314 .array_cat,1322 .array_cat,
1315 .array_mul,1323 .array_mul,
...@@ -1336,7 +1344,6 @@ pub const Inst = struct {...@@ -1336,7 +1344,6 @@ pub const Inst = struct {
1336 .bool_not,1344 .bool_not,
1337 .call,1345 .call,
1338 .field_call,1346 .field_call,
1339 .async_call,
1340 .cmp_lt,1347 .cmp_lt,
1341 .cmp_lte,1348 .cmp_lte,
1342 .cmp_eq,1349 .cmp_eq,
...@@ -1572,6 +1579,7 @@ pub const Inst = struct {...@@ -1572,6 +1579,7 @@ pub const Inst = struct {
1572 .call = .pl_node,1579 .call = .pl_node,
1573 .field_call = .pl_node,1580 .field_call = .pl_node,
1574 .async_call = .pl_node,1581 .async_call = .pl_node,
1582 .async_field_call = .pl_node,
1575 .cmp_lt = .pl_node,1583 .cmp_lt = .pl_node,
1576 .cmp_lte = .pl_node,1584 .cmp_lte = .pl_node,
1577 .cmp_eq = .pl_node,1585 .cmp_eq = .pl_node,
...@@ -2549,6 +2557,14 @@ pub const Inst = struct {...@@ -2549,6 +2557,14 @@ pub const Inst = struct {
2549 args_len: u32,2557 args_len: u32,
2550 };2558 };
25512559
2560 /// Same trailing data as `AsyncCall`, `FieldCall`, and `Call`.
2561 pub const AsyncFieldCall = struct {
2562 args_len: u32,
2563 obj_ptr: Ref,
2564 /// Offset into `string_bytes`.
2565 field_name_start: u32,
2566 };
2567
2552 pub const TypeOfPeer = struct {2568 pub const TypeOfPeer = struct {
2553 src_node: i32,2569 src_node: i32,
2554 body_len: u32,2570 body_len: u32,
src/print_air.zig+14-4
...@@ -701,7 +701,7 @@ const Writer = struct {...@@ -701,7 +701,7 @@ const Writer = struct {
701 const pl_op = w.air.instructions.items(.data)[inst].pl_op;701 const pl_op = w.air.instructions.items(.data)[inst].pl_op;
702 const extra = w.air.extraData(Air.Call, pl_op.payload);702 const extra = w.air.extraData(Air.Call, pl_op.payload);
703 const args: []const Air.Inst.Ref = @ptrCast(w.air.extra[extra.end..][0..extra.data.args_len]);703 const args: []const Air.Inst.Ref = @ptrCast(w.air.extra[extra.end..][0..extra.data.args_len]);
704 return finishWriteCall(w, s, inst, pl_op.operand, args);704 return finishWriteCall(w, s, inst, .none, pl_op.operand, args);
705 }705 }
706706
707 fn writeCallAsync(w: *Writer, s: anytype, inst: Air.Inst.Index) @TypeOf(s).Error!void {707 fn writeCallAsync(w: *Writer, s: anytype, inst: Air.Inst.Index) @TypeOf(s).Error!void {
...@@ -709,21 +709,31 @@ const Writer = struct {...@@ -709,21 +709,31 @@ const Writer = struct {
709 const extra = w.air.extraData(Air.AsyncCall, ty_pl.payload);709 const extra = w.air.extraData(Air.AsyncCall, ty_pl.payload);
710 const callee = extra.data.callee;710 const callee = extra.data.callee;
711 const args: []const Air.Inst.Ref = @ptrCast(w.air.extra[extra.end..][0..extra.data.args_len]);711 const args: []const Air.Inst.Ref = @ptrCast(w.air.extra[extra.end..][0..extra.data.args_len]);
712 return finishWriteCall(w, s, inst, callee, args);712 const frame_ptr = extra.data.frame_ptr;
713 return finishWriteCall(w, s, inst, frame_ptr, callee, args);
713 }714 }
714715
715 fn finishWriteCall(716 fn finishWriteCall(
716 w: *Writer,717 w: *Writer,
717 s: anytype,718 s: anytype,
718 inst: Air.Inst.Index,719 inst: Air.Inst.Index,
720 frame_ptr: Air.Inst.Ref,
719 callee: Air.Inst.Ref,721 callee: Air.Inst.Ref,
720 args: []const Air.Inst.Ref,722 args: []const Air.Inst.Ref,
721 ) @TypeOf(s).Error!void {723 ) @TypeOf(s).Error!void {
722 try w.writeOperand(s, inst, 0, callee);724 var op_index: usize = 0;
725 if (frame_ptr != .none) {
726 try w.writeOperand(s, inst, op_index, frame_ptr);
727 op_index += 1;
728 try s.writeAll(", ");
729 }
730 try w.writeOperand(s, inst, op_index, callee);
731 op_index += 1;
723 try s.writeAll(", [");732 try s.writeAll(", [");
724 for (args, 0..) |arg, i| {733 for (args, 0..) |arg, i| {
725 if (i != 0) try s.writeAll(", ");734 if (i != 0) try s.writeAll(", ");
726 try w.writeOperand(s, inst, 1 + i, arg);735 try w.writeOperand(s, inst, op_index, arg);
736 op_index += 1;
727 }737 }
728 try s.writeAll("]");738 try s.writeAll("]");
729 }739 }
src/print_zir.zig+28-29
...@@ -360,9 +360,10 @@ const Writer = struct {...@@ -360,9 +360,10 @@ const Writer = struct {
360 .@"export" => try self.writePlNodeExport(stream, inst),360 .@"export" => try self.writePlNodeExport(stream, inst),
361 .export_value => try self.writePlNodeExportValue(stream, inst),361 .export_value => try self.writePlNodeExportValue(stream, inst),
362362
363 .call => try self.writeCall(stream, inst, .direct),363 .call => try self.writeCall(stream, inst, Zir.Inst.Call),
364 .field_call => try self.writeCall(stream, inst, .field),364 .field_call => try self.writeCall(stream, inst, Zir.Inst.FieldCall),
365 .async_call => try self.writeAsyncCall(stream, inst),365 .async_call => try self.writeCall(stream, inst, Zir.Inst.AsyncCall),
366 .async_field_call => try self.writeCall(stream, inst, Zir.Inst.AsyncFieldCall),
366367
367 .block,368 .block,
368 .block_comptime,369 .block_comptime,
...@@ -1188,50 +1189,48 @@ const Writer = struct {...@@ -1188,50 +1189,48 @@ const Writer = struct {
1188 try self.writeSrc(stream, src);1189 try self.writeSrc(stream, src);
1189 }1190 }
11901191
1191 const CallKind = enum { direct, field };
1192
1193 fn writeCall(1192 fn writeCall(
1194 self: *Writer,1193 self: *Writer,
1195 stream: anytype,1194 stream: anytype,
1196 inst: Zir.Inst.Index,1195 inst: Zir.Inst.Index,
1197 comptime kind: CallKind,1196 comptime ExtraType: type,
1198 ) !void {1197 ) !void {
1199 const inst_data = self.code.instructions.items(.data)[inst].pl_node;1198 const inst_data = self.code.instructions.items(.data)[inst].pl_node;
1200 const ExtraType = switch (kind) {
1201 .direct => Zir.Inst.Call,
1202 .field => Zir.Inst.FieldCall,
1203 };
1204 const extra = self.code.extraData(ExtraType, inst_data.payload_index);1199 const extra = self.code.extraData(ExtraType, inst_data.payload_index);
1205 const args_len = extra.data.flags.args_len;1200 const args_len = switch (ExtraType) {
1201 Zir.Inst.Call, Zir.Inst.FieldCall => extra.data.flags.args_len,
1202 Zir.Inst.AsyncCall, Zir.Inst.AsyncFieldCall => extra.data.args_len,
1203 else => @compileError("unreachable"),
1204 };
1206 const body = self.code.extra[extra.end..];1205 const body = self.code.extra[extra.end..];
1207 const modifier: std.builtin.CallModifier = @enumFromInt(extra.data.flags.packed_modifier);1206 switch (ExtraType) {
12081207 Zir.Inst.Call, Zir.Inst.FieldCall => if (extra.data.flags.ensure_result_used) {
1209 if (extra.data.flags.ensure_result_used) {1208 try stream.writeAll("nodiscard ");
1210 try stream.writeAll("nodiscard ");1209 },
1210 Zir.Inst.AsyncCall, Zir.Inst.AsyncFieldCall => {},
1211 else => @compileError("unreachable"),
1211 }1212 }
1213
1214 const modifier: std.builtin.CallModifier = switch (ExtraType) {
1215 Zir.Inst.Call, Zir.Inst.FieldCall => @enumFromInt(extra.data.flags.packed_modifier),
1216 Zir.Inst.AsyncCall, Zir.Inst.AsyncFieldCall => std.builtin.CallModifier.async_kw,
1217 else => @compileError("unreachable"),
1218 };
1219
1212 try stream.print(".{s}, ", .{@tagName(modifier)});1220 try stream.print(".{s}, ", .{@tagName(modifier)});
1213 switch (kind) {1221
1214 .direct => try self.writeInstRef(stream, extra.data.callee),1222 switch (ExtraType) {
1215 .field => {1223 Zir.Inst.Call, Zir.Inst.AsyncCall => try self.writeInstRef(stream, extra.data.callee),
1224 Zir.Inst.FieldCall, Zir.Inst.AsyncFieldCall => {
1216 const field_name = self.code.nullTerminatedString(extra.data.field_name_start);1225 const field_name = self.code.nullTerminatedString(extra.data.field_name_start);
1217 try self.writeInstRef(stream, extra.data.obj_ptr);1226 try self.writeInstRef(stream, extra.data.obj_ptr);
1218 try stream.print(", \"{}\"", .{std.zig.fmtEscapes(field_name)});1227 try stream.print(", \"{}\"", .{std.zig.fmtEscapes(field_name)});
1219 },1228 },
1229 else => @compileError("unreachable"),
1220 }1230 }
1221 return finishWriteCall(self, stream, body, args_len, extra.end, inst_data.src());1231 return finishWriteCall(self, stream, body, args_len, extra.end, inst_data.src());
1222 }1232 }
12231233
1224 fn writeAsyncCall(self: *Writer, stream: anytype, inst: Zir.Inst.Index) !void {
1225 const inst_data = self.code.instructions.items(.data)[inst].pl_node;
1226 const extra = self.code.extraData(Zir.Inst.AsyncCall, inst_data.payload_index);
1227 const args_len = extra.data.args_len;
1228 const body = self.code.extra[extra.end..];
1229 const callee = extra.data.callee;
1230 try stream.print(".{s}, ", .{@tagName(std.builtin.CallModifier.async_kw)});
1231 try self.writeInstRef(stream, callee);
1232 return finishWriteCall(self, stream, body, args_len, extra.end, inst_data.src());
1233 }
1234
1235 fn finishWriteCall(1234 fn finishWriteCall(
1236 self: *Writer,1235 self: *Writer,
1237 stream: anytype,1236 stream: anytype,