authorgravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2021-04-23 21:12:29-07:00
committergravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2021-04-23 21:12:29-07:00
logfbfae832eaf520f7fcc632580b4b4a7fb171f90f
tree1a8b34df8132e7bffc336235cfdae17f261f41c9
parent49be88859d3cef22c5cc27c908264a235c78a4d0

AstGen: emit nosuspend function calls

Inside a nosuspend block, emit function calls as nosuspend calls. Also inside a comptime block, emit function calls as comptime calls. Also emit `async foo()` calls as async calls. Remove compile error for `nosuspend` block inside `suspend` block. Instead of implicitly treating every `suspend` block also as a `nosuspend` block (which would make sense), we leave suspension points as compile errors, to hint to the programmer about accidents. Of course they may then assert `nosuspend` by introducing a block within their suspend block. To make room in `Zir.Inst.Tag` I moved `typeof_peer` and `compile_log` to `Extended`.

5 files changed, 118 insertions(+), 69 deletions(-)

BRANCH_TODO-1
......@@ -37,7 +37,6 @@
3737 * when handling decls, catch the error and continue, so that
3838 AstGen can report more than one compile error.
3939
40 * AstGen: inside a nosuspend block, emit function calls as nosuspend calls
4140 * AstGen: add result location pointers to function calls
4241
4342 const container_name_hash: Scope.NameHash = if (found_pkg) |pkg|
src/AstGen.zig+17-24
......@@ -900,11 +900,6 @@ pub fn nosuspendExpr(
900900 try astgen.errNoteNode(gz.nosuspend_node, "other nosuspend block here", .{}),
901901 });
902902 }
903 if (gz.suspend_node != 0) {
904 return astgen.failNodeNotes(node, "inside a suspend block, nosuspend is implied", .{}, &[_]u32{
905 try astgen.errNoteNode(gz.suspend_node, "suspend block here", .{}),
906 });
907 }
908903 gz.nosuspend_node = node;
909904 const result = try expr(gz, scope, rl, body_node);
910905 gz.nosuspend_node = 0;
......@@ -1803,6 +1798,8 @@ fn unusedResultExpr(gz: *GenZir, scope: *Scope, statement: ast.Node.Index) Inner
18031798 .bool_and,
18041799 .bool_or,
18051800 .call_compile_time,
1801 .call_nosuspend,
1802 .call_async,
18061803 .cmp_lt,
18071804 .cmp_lte,
18081805 .cmp_eq,
......@@ -1876,7 +1873,6 @@ fn unusedResultExpr(gz: *GenZir, scope: *Scope, statement: ast.Node.Index) Inner
18761873 .slice_end,
18771874 .slice_sentinel,
18781875 .import,
1879 .typeof_peer,
18801876 .switch_block,
18811877 .switch_block_multi,
18821878 .switch_block_else,
......@@ -2001,7 +1997,6 @@ fn unusedResultExpr(gz: *GenZir, scope: *Scope, statement: ast.Node.Index) Inner
20011997 .ensure_result_non_error,
20021998 .@"export",
20031999 .set_eval_branch_quota,
2004 .compile_log,
20052000 .ensure_err_payload_void,
20062001 .@"break",
20072002 .break_inline,
......@@ -6074,11 +6069,7 @@ fn typeOf(
60746069 items[param_i] = try expr(gz, scope, .none, param);
60756070 }
60766071
6077 const result = try gz.addPlNode(.typeof_peer, node, Zir.Inst.MultiOp{
6078 .operands_len = @intCast(u32, params.len),
6079 });
6080 try gz.astgen.appendRefs(items);
6081
6072 const result = try gz.addExtendedMultiOp(.typeof_peer, node, items);
60826073 return rvalue(gz, scope, rl, result, node);
60836074}
60846075
......@@ -6138,10 +6129,7 @@ fn builtinCall(
61386129
61396130 for (params) |param, i| arg_refs[i] = try expr(gz, scope, .none, param);
61406131
6141 const result = try gz.addPlNode(.compile_log, node, Zir.Inst.MultiOp{
6142 .operands_len = @intCast(u32, params.len),
6143 });
6144 try gz.astgen.appendRefs(arg_refs);
6132 const result = try gz.addExtendedMultiOp(.compile_log, node, arg_refs);
61456133 return rvalue(gz, scope, rl, result, node);
61466134 },
61476135 .field => {
......@@ -6745,9 +6733,6 @@ fn callExpr(
67456733 call: ast.full.Call,
67466734) InnerError!Zir.Inst.Ref {
67476735 const astgen = gz.astgen;
6748 if (call.async_token) |async_token| {
6749 return astgen.failTok(async_token, "async and related features are not yet supported", .{});
6750 }
67516736 const lhs = try expr(gz, scope, .none, call.ast.fn_expr);
67526737
67536738 const args = try astgen.gpa.alloc(Zir.Inst.Ref, call.ast.params.len);
......@@ -6764,9 +6749,17 @@ fn callExpr(
67646749 args[i] = try expr(gz, scope, .{ .ty = param_type }, param_node);
67656750 }
67666751
6767 const modifier: std.builtin.CallOptions.Modifier = switch (call.async_token != null) {
6768 true => .async_kw,
6769 false => .auto,
6752 const modifier: std.builtin.CallOptions.Modifier = blk: {
6753 if (gz.force_comptime) {
6754 break :blk .compile_time;
6755 }
6756 if (call.async_token != null) {
6757 break :blk .async_kw;
6758 }
6759 if (gz.nosuspend_node != 0) {
6760 break :blk .no_async;
6761 }
6762 break :blk .auto;
67706763 };
67716764 const result: Zir.Inst.Ref = res: {
67726765 const tag: Zir.Inst.Tag = switch (modifier) {
......@@ -6774,10 +6767,10 @@ fn callExpr(
67746767 true => break :res try gz.addUnNode(.call_none, lhs, node),
67756768 false => .call,
67766769 },
6777 .async_kw => return astgen.failNode(node, "async and related features are not yet supported", .{}),
6770 .async_kw => .call_async,
67786771 .never_tail => unreachable,
67796772 .never_inline => unreachable,
6780 .no_async => return astgen.failNode(node, "async and related features are not yet supported", .{}),
6773 .no_async => .call_nosuspend,
67816774 .always_tail => unreachable,
67826775 .always_inline => unreachable,
67836776 .compile_time => .call_compile_time,
src/Module.zig+33
......@@ -1533,6 +1533,39 @@ pub const Scope = struct {
15331533 return gz.indexToRef(new_index);
15341534 }
15351535
1536 pub fn addExtendedMultiOp(
1537 gz: *GenZir,
1538 opcode: Zir.Inst.Extended,
1539 node: ast.Node.Index,
1540 operands: []const Zir.Inst.Ref,
1541 ) !Zir.Inst.Ref {
1542 const astgen = gz.astgen;
1543 const gpa = astgen.gpa;
1544
1545 try gz.instructions.ensureUnusedCapacity(gpa, 1);
1546 try astgen.instructions.ensureUnusedCapacity(gpa, 1);
1547 try astgen.extra.ensureUnusedCapacity(
1548 gpa,
1549 @typeInfo(Zir.Inst.NodeMultiOp).Struct.fields.len + operands.len,
1550 );
1551
1552 const payload_index = astgen.addExtraAssumeCapacity(Zir.Inst.NodeMultiOp{
1553 .src_node = gz.nodeIndexToRelative(node),
1554 });
1555 const new_index = @intCast(Zir.Inst.Index, astgen.instructions.len);
1556 astgen.instructions.appendAssumeCapacity(.{
1557 .tag = .extended,
1558 .data = .{ .extended = .{
1559 .opcode = opcode,
1560 .small = @intCast(u16, operands.len),
1561 .operand = payload_index,
1562 } },
1563 });
1564 gz.instructions.appendAssumeCapacity(new_index);
1565 astgen.appendRefsAssumeCapacity(operands);
1566 return gz.indexToRef(new_index);
1567 }
1568
15361569 pub fn addArrayTypeSentinel(
15371570 gz: *GenZir,
15381571 len: Zir.Inst.Ref,
src/Sema.zig+26-16
......@@ -161,6 +161,8 @@ pub fn analyzeBody(
161161 .call => try sema.zirCall(block, inst, .auto, false),
162162 .call_chkused => try sema.zirCall(block, inst, .auto, true),
163163 .call_compile_time => try sema.zirCall(block, inst, .compile_time, false),
164 .call_nosuspend => try sema.zirCall(block, inst, .no_async, false),
165 .call_async => try sema.zirCall(block, inst, .async_kw, false),
164166 .call_none => try sema.zirCallNone(block, inst, false),
165167 .call_none_chkused => try sema.zirCallNone(block, inst, true),
166168 .cmp_eq => try sema.zirCmp(block, inst, .eq),
......@@ -254,7 +256,6 @@ pub fn analyzeBody(
254256 .bit_size_of => try sema.zirBitSizeOf(block, inst),
255257 .typeof => try sema.zirTypeof(block, inst),
256258 .typeof_elem => try sema.zirTypeofElem(block, inst),
257 .typeof_peer => try sema.zirTypeofPeer(block, inst),
258259 .log2_int_type => try sema.zirLog2IntType(block, inst),
259260 .typeof_log2_int_type => try sema.zirTypeofLog2IntType(block, inst),
260261 .xor => try sema.zirBitwise(block, inst, .xor),
......@@ -403,10 +404,6 @@ pub fn analyzeBody(
403404 try sema.zirEnsureResultUsed(block, inst);
404405 continue;
405406 },
406 .compile_log => {
407 try sema.zirCompileLog(block, inst);
408 continue;
409 },
410407 .set_eval_branch_quota => {
411408 try sema.zirSetEvalBranchQuota(block, inst);
412409 continue;
......@@ -519,6 +516,8 @@ fn zirExtended(sema: *Sema, block: *Scope.Block, inst: Zir.Inst.Index) InnerErro
519516 .alloc => return sema.zirAllocExtended( block, extended),
520517 .builtin_extern => return sema.zirBuiltinExtern( block, extended),
521518 .@"asm" => return sema.zirAsm( block, extended),
519 .typeof_peer => return sema.zirTypeofPeer( block, extended),
520 .compile_log => return sema.zirCompileLog( block, extended),
522521 .c_undef => return sema.zirCUndef( block, extended),
523522 .c_include => return sema.zirCInclude( block, extended),
524523 .c_define => return sema.zirCDefine( block, extended),
......@@ -1533,14 +1532,18 @@ fn zirCompileError(sema: *Sema, block: *Scope.Block, inst: Zir.Inst.Index) Inner
15331532 return sema.mod.fail(&block.base, src, "{s}", .{msg});
15341533}
15351534
1536fn zirCompileLog(sema: *Sema, block: *Scope.Block, inst: Zir.Inst.Index) InnerError!void {
1535fn zirCompileLog(
1536 sema: *Sema,
1537 block: *Scope.Block,
1538 extended: Zir.Inst.Extended.InstData,
1539) InnerError!*Inst {
15371540 var managed = sema.mod.compile_log_text.toManaged(sema.gpa);
15381541 defer sema.mod.compile_log_text = managed.moveToUnmanaged();
15391542 const writer = managed.writer();
15401543
1541 const inst_data = sema.code.instructions.items(.data)[inst].pl_node;
1542 const extra = sema.code.extraData(Zir.Inst.MultiOp, inst_data.payload_index);
1543 const args = sema.code.refSlice(extra.end, extra.data.operands_len);
1544 const extra = sema.code.extraData(Zir.Inst.NodeMultiOp, extended.operand);
1545 const src: LazySrcLoc = .{ .node_offset = extra.data.src_node };
1546 const args = sema.code.refSlice(extra.end, extended.small);
15441547
15451548 for (args) |arg_ref, i| {
15461549 if (i != 0) try writer.print(", ", .{});
......@@ -1556,8 +1559,12 @@ fn zirCompileLog(sema: *Sema, block: *Scope.Block, inst: Zir.Inst.Index) InnerEr
15561559
15571560 const gop = try sema.mod.compile_log_decls.getOrPut(sema.gpa, sema.owner_decl);
15581561 if (!gop.found_existing) {
1559 gop.entry.value = inst_data.src().toSrcLoc(&block.base);
1562 gop.entry.value = src.toSrcLoc(&block.base);
15601563 }
1564 return sema.mod.constInst(sema.arena, src, .{
1565 .ty = Type.initTag(.void),
1566 .val = Value.initTag(.void_value),
1567 });
15611568}
15621569
15631570fn zirRepeat(sema: *Sema, block: *Scope.Block, inst: Zir.Inst.Index) InnerError!Zir.Inst.Index {
......@@ -4680,16 +4687,19 @@ fn zirLog2IntType(sema: *Sema, block: *Scope.Block, inst: Zir.Inst.Index) InnerE
46804687 return sema.mod.fail(&block.base, src, "TODO: implement Sema.zirLog2IntType", .{});
46814688}
46824689
4683fn zirTypeofPeer(sema: *Sema, block: *Scope.Block, inst: Zir.Inst.Index) InnerError!*Inst {
4690fn zirTypeofPeer(
4691 sema: *Sema,
4692 block: *Scope.Block,
4693 extended: Zir.Inst.Extended.InstData,
4694) InnerError!*Inst {
46844695 const tracy = trace(@src());
46854696 defer tracy.end();
46864697
4687 const inst_data = sema.code.instructions.items(.data)[inst].pl_node;
4688 const src = inst_data.src();
4689 const extra = sema.code.extraData(Zir.Inst.MultiOp, inst_data.payload_index);
4690 const args = sema.code.refSlice(extra.end, extra.data.operands_len);
4698 const extra = sema.code.extraData(Zir.Inst.NodeMultiOp, extended.operand);
4699 const src: LazySrcLoc = .{ .node_offset = extra.data.src_node };
4700 const args = sema.code.refSlice(extra.end, extended.small);
46914701
4692 const inst_list = try sema.gpa.alloc(*ir.Inst, extra.data.operands_len);
4702 const inst_list = try sema.gpa.alloc(*ir.Inst, args.len);
46934703 defer sema.gpa.free(inst_list);
46944704
46954705 for (args) |arg_ref, i| {
src/Zir.zig+42-28
......@@ -238,6 +238,10 @@ pub const Inst = struct {
238238 call_chkused,
239239 /// Same as `call` but with modifier `.compile_time`.
240240 call_compile_time,
241 /// Same as `call` but with modifier `.no_suspend`.
242 call_nosuspend,
243 /// Same as `call` but with modifier `.async_kw`.
244 call_async,
241245 /// Function call with modifier `.auto`, empty parameter list.
242246 /// Uses the `un_node` field. Operand is callee. AST node is the function call.
243247 call_none,
......@@ -266,10 +270,6 @@ pub const Inst = struct {
266270 /// Uses the `bin` union field.
267271 /// LHS is destination element type, RHS is result pointer.
268272 coerce_result_ptr,
269 /// Log compile time variables and emit an error message.
270 /// Uses the `pl_node` union field. The AST node is the compile log builtin call.
271 /// The payload is `MultiOp`.
272 compile_log,
273273 /// Conditional branch. Splits control flow based on a boolean condition value.
274274 /// Uses the `pl_node` union field. AST node is an if, while, for, etc.
275275 /// Payload is `CondBr`.
......@@ -523,10 +523,6 @@ pub const Inst = struct {
523523 /// Given a value which is a pointer, returns the element type.
524524 /// Uses the `un_node` field.
525525 typeof_elem,
526 /// The builtin `@TypeOf` which returns the type after Peer Type Resolution
527 /// of one or more params.
528 /// Uses the `pl_node` field. AST node is the `@TypeOf` call. Payload is `MultiOp`.
529 typeof_peer,
530526 /// Given a value, look at the type of it, which must be an integer type.
531527 /// Returns the integer type for the RHS of a shift operation.
532528 /// Uses the `un_node` field.
......@@ -990,6 +986,8 @@ pub const Inst = struct {
990986 .call,
991987 .call_chkused,
992988 .call_compile_time,
989 .call_nosuspend,
990 .call_async,
993991 .call_none,
994992 .call_none_chkused,
995993 .cmp_lt,
......@@ -1085,12 +1083,10 @@ pub const Inst = struct {
10851083 .slice_end,
10861084 .slice_sentinel,
10871085 .import,
1088 .typeof_peer,
10891086 .typeof_log2_int_type,
10901087 .log2_int_type,
10911088 .resolve_inferred_alloc,
10921089 .set_eval_branch_quota,
1093 .compile_log,
10941090 .switch_capture,
10951091 .switch_capture_ref,
10961092 .switch_capture_multi,
......@@ -1268,6 +1264,17 @@ pub const Inst = struct {
12681264 /// * 0bX0000000_00000000 - is volatile
12691265 /// `operand` is payload index to `Asm`.
12701266 @"asm",
1267 /// Log compile time variables and emit an error message.
1268 /// `operand` is payload index to `NodeMultiOp`.
1269 /// `small` is `operands_len`.
1270 /// The AST node is the compile log builtin call.
1271 compile_log,
1272 /// The builtin `@TypeOf` which returns the type after Peer Type Resolution
1273 /// of one or more params.
1274 /// `operand` is payload index to `NodeMultiOp`.
1275 /// `small` is `operands_len`.
1276 /// The AST node is the builtin call.
1277 typeof_peer,
12711278 /// `operand` is payload index to `UnNode`.
12721279 c_undef,
12731280 /// `operand` is payload index to `UnNode`.
......@@ -1897,6 +1904,11 @@ pub const Inst = struct {
18971904 operands_len: u32,
18981905 };
18991906
1907 /// Trailing: operand: Ref, // for each `operands_len` (stored in `small`).
1908 pub const NodeMultiOp = struct {
1909 src_node: i32,
1910 };
1911
19001912 /// This data is stored inside extra, with trailing operands according to `body_len`.
19011913 /// Each operand is an `Index`.
19021914 pub const Block = struct {
......@@ -2540,6 +2552,8 @@ const Writer = struct {
25402552 .call,
25412553 .call_chkused,
25422554 .call_compile_time,
2555 .call_nosuspend,
2556 .call_async,
25432557 => try self.writePlNodeCall(stream, inst),
25442558
25452559 .block,
......@@ -2584,10 +2598,6 @@ const Writer = struct {
25842598 .switch_block_ref_else_multi => try self.writePlNodeSwitchBlockMulti(stream, inst, .@"else"),
25852599 .switch_block_ref_under_multi => try self.writePlNodeSwitchBlockMulti(stream, inst, .under),
25862600
2587 .compile_log,
2588 .typeof_peer,
2589 => try self.writePlNodeMultiOp(stream, inst),
2590
25912601 .field_ptr,
25922602 .field_val,
25932603 => try self.writePlNodeField(stream, inst),
......@@ -2646,6 +2656,10 @@ const Writer = struct {
26462656 .@"asm" => try self.writeAsm(stream, extended),
26472657 .func => try self.writeFuncExtended(stream, extended),
26482658
2659 .compile_log,
2660 .typeof_peer,
2661 => try self.writeNodeMultiOp(stream, extended),
2662
26492663 .alloc,
26502664 .builtin_extern,
26512665 .c_undef,
......@@ -2836,6 +2850,19 @@ const Writer = struct {
28362850 try self.writeSrc(stream, inst_data.src());
28372851 }
28382852
2853 fn writeNodeMultiOp(self: *Writer, stream: anytype, extended: Inst.Extended.InstData) !void {
2854 const extra = self.code.extraData(Inst.NodeMultiOp, extended.operand);
2855 const src: LazySrcLoc = .{ .node_offset = extra.data.src_node };
2856 const operands = self.code.refSlice(extra.end, extended.small);
2857
2858 for (operands) |operand, i| {
2859 if (i != 0) try stream.writeAll(", ");
2860 try self.writeInstRef(stream, operand);
2861 }
2862 try stream.writeAll(")) ");
2863 try self.writeSrc(stream, src);
2864 }
2865
28392866 fn writeAsm(self: *Writer, stream: anytype, extended: Inst.Extended.InstData) !void {
28402867 const extra = self.code.extraData(Inst.Asm, extended.operand);
28412868 const src: LazySrcLoc = .{ .node_offset = extra.data.src_node };
......@@ -2902,7 +2929,7 @@ const Writer = struct {
29022929 }
29032930 }
29042931 }
2905 try stream.writeAll(") ");
2932 try stream.writeAll(")) ");
29062933 try self.writeSrc(stream, src);
29072934 }
29082935
......@@ -3457,19 +3484,6 @@ const Writer = struct {
34573484 try self.writeSrc(stream, inst_data.src());
34583485 }
34593486
3460 fn writePlNodeMultiOp(self: *Writer, stream: anytype, inst: Inst.Index) !void {
3461 const inst_data = self.code.instructions.items(.data)[inst].pl_node;
3462 const extra = self.code.extraData(Inst.MultiOp, inst_data.payload_index);
3463 const operands = self.code.refSlice(extra.end, extra.data.operands_len);
3464
3465 for (operands) |operand, i| {
3466 if (i != 0) try stream.writeAll(", ");
3467 try self.writeInstRef(stream, operand);
3468 }
3469 try stream.writeAll(") ");
3470 try self.writeSrc(stream, inst_data.src());
3471 }
3472
34733487 fn writePlNodeField(self: *Writer, stream: anytype, inst: Inst.Index) !void {
34743488 const inst_data = self.code.instructions.items(.data)[inst].pl_node;
34753489 const extra = self.code.extraData(Inst.Field, inst_data.payload_index).data;