| author | |
| committer | |
| log | 5a8c445779b3b87ba38fbcac0efcc7ebb3787161 |
| tree | f83e02739497a46928bb2c7baa36657f486d2294 |
| parent | 7322aa118376a635ab077ca833dd152639953337 |
This is to be used when the source code looks like this:
var a = async b();
The instruction acts both as an alloc as well as a function call using
that alloc as the result location. This avoids multiple ZIR instructions
as well as complicated "inferred pointer" semantic analysis for a common
case.
AstGen is not yet updated to emit this new instruction.23 files changed, 510 insertions(+), 98 deletions(-)
src/Air.zig+11| ... | ... | @@ -310,6 +310,9 @@ pub const Inst = struct { |
| 310 | 310 | call_never_tail, |
| 311 | 311 | /// Same as `call` except with the `never_inline` attribute. |
| 312 | 312 | call_never_inline, |
| 313 | /// Async function call. | |
| 314 | /// Uses `ty_pl` field with the `AsyncCall` payload. | |
| 315 | call_async, | |
| 313 | 316 | /// Count leading zeroes of an integer according to its representation in twos complement. |
| 314 | 317 | /// Result type will always be an unsigned integer big enough to fit the answer. |
| 315 | 318 | /// Uses the `ty_op` field. |
| ... | ... | @@ -1070,6 +1073,12 @@ pub const Call = struct { |
| 1070 | 1073 | args_len: u32, |
| 1071 | 1074 | }; |
| 1072 | 1075 | |
| 1076 | /// Trailing is a list of `Inst.Ref` for every `args_len`. | |
| 1077 | pub const AsyncCall = struct { | |
| 1078 | callee: Inst.Ref, | |
| 1079 | args_len: u32, | |
| 1080 | }; | |
| 1081 | ||
| 1073 | 1082 | /// This data is stored inside extra, with two sets of trailing `Inst.Ref`: |
| 1074 | 1083 | /// * 0. the then body, according to `then_body_len`. |
| 1075 | 1084 | /// * 1. the else body, according to `else_body_len`. |
| ... | ... | @@ -1340,6 +1349,7 @@ pub fn typeOfIndex(air: *const Air, inst: Air.Inst.Index, ip: *const InternPool) |
| 1340 | 1349 | .ptr_add, |
| 1341 | 1350 | .ptr_sub, |
| 1342 | 1351 | .try_ptr, |
| 1352 | .call_async, | |
| 1343 | 1353 | => return air.getRefType(datas[inst].ty_pl.ty), |
| 1344 | 1354 | |
| 1345 | 1355 | .interned => return ip.typeOf(datas[inst].interned).toType(), |
| ... | ... | @@ -1583,6 +1593,7 @@ pub fn mustLower(air: Air, inst: Air.Inst.Index, ip: *const InternPool) bool { |
| 1583 | 1593 | .call_always_tail, |
| 1584 | 1594 | .call_never_tail, |
| 1585 | 1595 | .call_never_inline, |
| 1596 | .call_async, | |
| 1586 | 1597 | .cond_br, |
| 1587 | 1598 | .switch_br, |
| 1588 | 1599 | .@"try", |
src/AstGen.zig+2-1| ... | ... | @@ -2788,6 +2788,7 @@ fn addEnsureResult(gz: *GenZir, maybe_unused_result: Zir.Inst.Ref, statement: As |
| 2788 | 2788 | .validate_deref, |
| 2789 | 2789 | .save_err_ret_index, |
| 2790 | 2790 | .restore_err_ret_index, |
| 2791 | .async_call, | |
| 2791 | 2792 | => break :b true, |
| 2792 | 2793 | |
| 2793 | 2794 | .@"defer" => unreachable, |
| ... | ... | @@ -8701,7 +8702,7 @@ fn builtinCall( |
| 8701 | 8702 | return rvalue(gz, ri, result, node); |
| 8702 | 8703 | }, |
| 8703 | 8704 | .async_call => { |
| 8704 | const result = try gz.addExtendedPayload(.builtin_async_call, Zir.Inst.AsyncCall{ | |
| 8705 | const result = try gz.addExtendedPayload(.builtin_async_call, Zir.Inst.BuiltinAsyncCall{ | |
| 8705 | 8706 | .node = gz.nodeIndexToRelative(node), |
| 8706 | 8707 | .frame_buffer = try expr(gz, scope, .{ .rl = .none }, params[0]), |
| 8707 | 8708 | .result_ptr = try expr(gz, scope, .{ .rl = .none }, params[1]), |
src/InternPool.zig+24| ... | ... | @@ -209,6 +209,8 @@ pub const Key = union(enum) { |
| 209 | 209 | /// `anyframe->T`. The payload is the child type, which may be `none` to indicate |
| 210 | 210 | /// `anyframe`. |
| 211 | 211 | anyframe_type: Index, |
| 212 | /// The payload is the function whose frame it refers to. | |
| 213 | async_frame_type: Module.Fn.Index, | |
| 212 | 214 | error_union_type: ErrorUnionType, |
| 213 | 215 | simple_type: SimpleType, |
| 214 | 216 | /// This represents a struct that has been explicitly declared in source code, |
| ... | ... | @@ -711,6 +713,7 @@ pub const Key = union(enum) { |
| 711 | 713 | .enum_tag, |
| 712 | 714 | .empty_enum_value, |
| 713 | 715 | .inferred_error_set_type, |
| 716 | .async_frame_type, | |
| 714 | 717 | .un, |
| 715 | 718 | => |x| Hash.hash(seed, asBytes(&x)), |
| 716 | 719 | |
| ... | ... | @@ -930,6 +933,10 @@ pub const Key = union(enum) { |
| 930 | 933 | const b_info = b.error_union_type; |
| 931 | 934 | return std.meta.eql(a_info, b_info); |
| 932 | 935 | }, |
| 936 | .async_frame_type => |a_info| { | |
| 937 | const b_info = b.async_frame_type; | |
| 938 | return a_info == b_info; | |
| 939 | }, | |
| 933 | 940 | .simple_type => |a_info| { |
| 934 | 941 | const b_info = b.simple_type; |
| 935 | 942 | return a_info == b_info; |
| ... | ... | @@ -1192,6 +1199,7 @@ pub const Key = union(enum) { |
| 1192 | 1199 | .enum_type, |
| 1193 | 1200 | .anon_struct_type, |
| 1194 | 1201 | .func_type, |
| 1202 | .async_frame_type, | |
| 1195 | 1203 | => .type_type, |
| 1196 | 1204 | |
| 1197 | 1205 | inline .runtime_value, |
| ... | ... | @@ -1432,6 +1440,7 @@ pub const Index = enum(u32) { |
| 1432 | 1440 | trailing: struct { names: []NullTerminatedString }, |
| 1433 | 1441 | }, |
| 1434 | 1442 | type_inferred_error_set: struct { data: Module.Fn.InferredErrorSet.Index }, |
| 1443 | type_async_frame: Module.Fn.Index, | |
| 1435 | 1444 | type_enum_auto: struct { |
| 1436 | 1445 | const @"data.fields_len" = opaque {}; |
| 1437 | 1446 | data: *EnumAuto, |
| ... | ... | @@ -1869,6 +1878,9 @@ pub const Tag = enum(u8) { |
| 1869 | 1878 | /// An untagged union type which has a safety tag. |
| 1870 | 1879 | /// `data` is `Module.Union.Index`. |
| 1871 | 1880 | type_union_safety, |
| 1881 | /// The async frame type of a function. | |
| 1882 | /// data is `Module.Fn.Index`. | |
| 1883 | type_async_frame, | |
| 1872 | 1884 | /// A function body type. |
| 1873 | 1885 | /// `data` is extra index to `TypeFunction`. |
| 1874 | 1886 | type_function, |
| ... | ... | @@ -2059,6 +2071,7 @@ pub const Tag = enum(u8) { |
| 2059 | 2071 | .type_error_union => ErrorUnionType, |
| 2060 | 2072 | .type_error_set => ErrorSet, |
| 2061 | 2073 | .type_inferred_error_set => unreachable, |
| 2074 | .type_async_frame => unreachable, | |
| 2062 | 2075 | .type_enum_auto => EnumAuto, |
| 2063 | 2076 | .type_enum_explicit => EnumExplicit, |
| 2064 | 2077 | .type_enum_nonexhaustive => EnumExplicit, |
| ... | ... | @@ -2636,6 +2649,7 @@ pub fn indexToKey(ip: *const InternPool, index: Index) Key { |
| 2636 | 2649 | .type_inferred_error_set => .{ |
| 2637 | 2650 | .inferred_error_set_type = @as(Module.Fn.InferredErrorSet.Index, @enumFromInt(data)), |
| 2638 | 2651 | }, |
| 2652 | .type_async_frame => .{ .async_frame_type = @enumFromInt(data) }, | |
| 2639 | 2653 | |
| 2640 | 2654 | .type_opaque => .{ .opaque_type = ip.extraData(Key.OpaqueType, data) }, |
| 2641 | 2655 | .type_struct => { |
| ... | ... | @@ -3240,6 +3254,12 @@ pub fn get(ip: *InternPool, gpa: Allocator, key: Key) Allocator.Error!Index { |
| 3240 | 3254 | .data = @intFromEnum(ies_index), |
| 3241 | 3255 | }); |
| 3242 | 3256 | }, |
| 3257 | .async_frame_type => |fn_index| { | |
| 3258 | ip.items.appendAssumeCapacity(.{ | |
| 3259 | .tag = .type_async_frame, | |
| 3260 | .data = @intFromEnum(fn_index), | |
| 3261 | }); | |
| 3262 | }, | |
| 3243 | 3263 | .simple_type => |simple_type| { |
| 3244 | 3264 | ip.items.appendAssumeCapacity(.{ |
| 3245 | 3265 | .tag = .simple_type, |
| ... | ... | @@ -5053,6 +5073,7 @@ fn dumpStatsFallible(ip: *const InternPool, arena: Allocator) anyerror!void { |
| 5053 | 5073 | break :b @sizeOf(ErrorSet) + (@sizeOf(u32) * info.names_len); |
| 5054 | 5074 | }, |
| 5055 | 5075 | .type_inferred_error_set => @sizeOf(Module.Fn.InferredErrorSet), |
| 5076 | .type_async_frame => 0, | |
| 5056 | 5077 | .type_enum_explicit, .type_enum_nonexhaustive => @sizeOf(EnumExplicit), |
| 5057 | 5078 | .type_enum_auto => @sizeOf(EnumAuto), |
| 5058 | 5079 | .type_opaque => @sizeOf(Key.OpaqueType), |
| ... | ... | @@ -5195,6 +5216,7 @@ fn dumpAllFallible(ip: *const InternPool) anyerror!void { |
| 5195 | 5216 | .type_error_union, |
| 5196 | 5217 | .type_error_set, |
| 5197 | 5218 | .type_inferred_error_set, |
| 5219 | .type_async_frame, | |
| 5198 | 5220 | .type_enum_explicit, |
| 5199 | 5221 | .type_enum_nonexhaustive, |
| 5200 | 5222 | .type_enum_auto, |
| ... | ... | @@ -5578,6 +5600,7 @@ pub fn typeOf(ip: *const InternPool, index: Index) Index { |
| 5578 | 5600 | .type_error_union, |
| 5579 | 5601 | .type_error_set, |
| 5580 | 5602 | .type_inferred_error_set, |
| 5603 | .type_async_frame, | |
| 5581 | 5604 | .type_enum_auto, |
| 5582 | 5605 | .type_enum_explicit, |
| 5583 | 5606 | .type_enum_nonexhaustive, |
| ... | ... | @@ -5926,6 +5949,7 @@ pub fn zigTypeTagOrPoison(ip: *const InternPool, index: Index) error{GenericPois |
| 5926 | 5949 | => .Union, |
| 5927 | 5950 | |
| 5928 | 5951 | .type_function => .Fn, |
| 5952 | .type_async_frame => .Frame, | |
| 5929 | 5953 | |
| 5930 | 5954 | // values, not types |
| 5931 | 5955 | .undef, |
src/Liveness.zig+74-39| ... | ... | @@ -484,28 +484,15 @@ pub fn categorizeOperand( |
| 484 | 484 | const inst_data = air_datas[inst].pl_op; |
| 485 | 485 | const callee = inst_data.operand; |
| 486 | 486 | const extra = air.extraData(Air.Call, inst_data.payload); |
| 487 | const args = @as([]const Air.Inst.Ref, @ptrCast(air.extra[extra.end..][0..extra.data.args_len])); | |
| 488 | if (args.len + 1 <= bpi - 1) { | |
| 489 | if (callee == operand_ref) return matchOperandSmallIndex(l, inst, 0, .write); | |
| 490 | for (args, 0..) |arg, i| { | |
| 491 | if (arg == operand_ref) return matchOperandSmallIndex(l, inst, @as(OperandInt, @intCast(i + 1)), .write); | |
| 492 | } | |
| 493 | return .write; | |
| 494 | } | |
| 495 | var bt = l.iterateBigTomb(inst); | |
| 496 | if (bt.feed()) { | |
| 497 | if (callee == operand_ref) return .tomb; | |
| 498 | } else { | |
| 499 | if (callee == operand_ref) return .write; | |
| 500 | } | |
| 501 | for (args) |arg| { | |
| 502 | if (bt.feed()) { | |
| 503 | if (arg == operand_ref) return .tomb; | |
| 504 | } else { | |
| 505 | if (arg == operand_ref) return .write; | |
| 506 | } | |
| 507 | } | |
| 508 | return .write; | |
| 487 | const args: []const Air.Inst.Ref = @ptrCast(air.extra[extra.end..][0..extra.data.args_len]); | |
| 488 | return categorizeOperandCall(l, inst, operand_ref, callee, args); | |
| 489 | }, | |
| 490 | .call_async => { | |
| 491 | const inst_data = air_datas[inst].ty_pl; | |
| 492 | const extra = air.extraData(Air.AsyncCall, inst_data.payload); | |
| 493 | const callee = extra.data.callee; | |
| 494 | const args: []const Air.Inst.Ref = @ptrCast(air.extra[extra.end..][0..extra.data.args_len]); | |
| 495 | return categorizeOperandCall(l, inst, operand_ref, callee, args); | |
| 509 | 496 | }, |
| 510 | 497 | .select => { |
| 511 | 498 | const pl_op = air_datas[inst].pl_op; |
| ... | ... | @@ -674,6 +661,36 @@ pub fn categorizeOperand( |
| 674 | 661 | } |
| 675 | 662 | } |
| 676 | 663 | |
| 664 | fn categorizeOperandCall( | |
| 665 | l: Liveness, | |
| 666 | inst: Air.Inst.Index, | |
| 667 | operand_ref: Air.Inst.Ref, | |
| 668 | callee: Air.Inst.Ref, | |
| 669 | args: []const Air.Inst.Ref, | |
| 670 | ) OperandCategory { | |
| 671 | if (args.len + 1 <= bpi - 1) { | |
| 672 | if (callee == operand_ref) return matchOperandSmallIndex(l, inst, 0, .write); | |
| 673 | for (args, 0..) |arg, i| { | |
| 674 | if (arg == operand_ref) return matchOperandSmallIndex(l, inst, @intCast(i + 1), .write); | |
| 675 | } | |
| 676 | return .write; | |
| 677 | } | |
| 678 | var bt = l.iterateBigTomb(inst); | |
| 679 | if (bt.feed()) { | |
| 680 | if (callee == operand_ref) return .tomb; | |
| 681 | } else { | |
| 682 | if (callee == operand_ref) return .write; | |
| 683 | } | |
| 684 | for (args) |arg| { | |
| 685 | if (bt.feed()) { | |
| 686 | if (arg == operand_ref) return .tomb; | |
| 687 | } else { | |
| 688 | if (arg == operand_ref) return .write; | |
| 689 | } | |
| 690 | } | |
| 691 | return .write; | |
| 692 | } | |
| 693 | ||
| 677 | 694 | fn matchOperandSmallIndex( |
| 678 | 695 | l: Liveness, |
| 679 | 696 | inst: Air.Inst.Index, |
| ... | ... | @@ -1108,23 +1125,15 @@ fn analyzeInst( |
| 1108 | 1125 | const inst_data = inst_datas[inst].pl_op; |
| 1109 | 1126 | const callee = inst_data.operand; |
| 1110 | 1127 | const extra = a.air.extraData(Air.Call, inst_data.payload); |
| 1111 | const args = @as([]const Air.Inst.Ref, @ptrCast(a.air.extra[extra.end..][0..extra.data.args_len])); | |
| 1112 | if (args.len + 1 <= bpi - 1) { | |
| 1113 | var buf = [1]Air.Inst.Ref{.none} ** (bpi - 1); | |
| 1114 | buf[0] = callee; | |
| 1115 | @memcpy(buf[1..][0..args.len], args); | |
| 1116 | return analyzeOperands(a, pass, data, inst, buf); | |
| 1117 | } | |
| 1118 | ||
| 1119 | var big = try AnalyzeBigOperands(pass).init(a, data, inst, args.len + 1); | |
| 1120 | defer big.deinit(); | |
| 1121 | var i: usize = args.len; | |
| 1122 | while (i > 0) { | |
| 1123 | i -= 1; | |
| 1124 | try big.feed(args[i]); | |
| 1125 | } | |
| 1126 | try big.feed(callee); | |
| 1127 | return big.finish(); | |
| 1128 | const args: []const Air.Inst.Ref = @ptrCast(a.air.extra[extra.end..][0..extra.data.args_len]); | |
| 1129 | return analyzeInstCall(a, pass, data, inst, callee, args); | |
| 1130 | }, | |
| 1131 | .call_async => { | |
| 1132 | const inst_data = inst_datas[inst].ty_pl; | |
| 1133 | const extra = a.air.extraData(Air.AsyncCall, inst_data.payload); | |
| 1134 | const callee = extra.data.callee; | |
| 1135 | const args: []const Air.Inst.Ref = @ptrCast(a.air.extra[extra.end..][0..extra.data.args_len]); | |
| 1136 | return analyzeInstCall(a, pass, data, inst, callee, args); | |
| 1128 | 1137 | }, |
| 1129 | 1138 | .select => { |
| 1130 | 1139 | const pl_op = inst_datas[inst].pl_op; |
| ... | ... | @@ -1253,6 +1262,32 @@ fn analyzeInst( |
| 1253 | 1262 | } |
| 1254 | 1263 | } |
| 1255 | 1264 | |
| 1265 | fn analyzeInstCall( | |
| 1266 | a: *Analysis, | |
| 1267 | comptime pass: LivenessPass, | |
| 1268 | data: *LivenessPassData(pass), | |
| 1269 | inst: Air.Inst.Index, | |
| 1270 | callee: Air.Inst.Ref, | |
| 1271 | args: []const Air.Inst.Ref, | |
| 1272 | ) Allocator.Error!void { | |
| 1273 | if (args.len + 1 <= bpi - 1) { | |
| 1274 | var buf = [1]Air.Inst.Ref{.none} ** (bpi - 1); | |
| 1275 | buf[0] = callee; | |
| 1276 | @memcpy(buf[1..][0..args.len], args); | |
| 1277 | return analyzeOperands(a, pass, data, inst, buf); | |
| 1278 | } | |
| 1279 | ||
| 1280 | var big = try AnalyzeBigOperands(pass).init(a, data, inst, args.len + 1); | |
| 1281 | defer big.deinit(); | |
| 1282 | var i: usize = args.len; | |
| 1283 | while (i > 0) { | |
| 1284 | i -= 1; | |
| 1285 | try big.feed(args[i]); | |
| 1286 | } | |
| 1287 | try big.feed(callee); | |
| 1288 | return big.finish(); | |
| 1289 | } | |
| 1290 | ||
| 1256 | 1291 | /// Every instruction should hit this (after handling any nested bodies), in every pass. In the |
| 1257 | 1292 | /// initial pass, it is responsible for marking deaths of the (first three) operands and noticing |
| 1258 | 1293 | /// immediate deaths. |
src/Liveness/Verify.zig+14| ... | ... | @@ -349,6 +349,20 @@ fn verifyBody(self: *Verify, body: []const Air.Inst.Index) Error!void { |
| 349 | 349 | } |
| 350 | 350 | try self.verifyInst(inst); |
| 351 | 351 | }, |
| 352 | .call_async => { | |
| 353 | const ty_pl = data[inst].ty_pl; | |
| 354 | const extra = self.air.extraData(Air.AsyncCall, ty_pl.payload); | |
| 355 | const args: []const Air.Inst.Ref = @ptrCast( | |
| 356 | self.air.extra[extra.end..][0..extra.data.args_len], | |
| 357 | ); | |
| 358 | ||
| 359 | var bt = self.liveness.iterateBigTomb(inst); | |
| 360 | try self.verifyOperand(inst, extra.data.callee, bt.feed()); | |
| 361 | for (args) |arg| { | |
| 362 | try self.verifyOperand(inst, arg, bt.feed()); | |
| 363 | } | |
| 364 | try self.verifyInst(inst); | |
| 365 | }, | |
| 352 | 366 | .assembly => { |
| 353 | 367 | const ty_pl = data[inst].ty_pl; |
| 354 | 368 | const extra = self.air.extraData(Air.Asm, ty_pl.payload); |
src/Module.zig+58| ... | ... | @@ -1437,6 +1437,7 @@ pub const Fn = struct { |
| 1437 | 1437 | generic_owner_decl: Decl.OptionalIndex, |
| 1438 | 1438 | |
| 1439 | 1439 | state: Analysis, |
| 1440 | async_status: AsyncStatus, | |
| 1440 | 1441 | is_cold: bool = false, |
| 1441 | 1442 | is_noinline: bool, |
| 1442 | 1443 | calls_or_awaits_errorable_fn: bool = false, |
| ... | ... | @@ -1481,6 +1482,12 @@ pub const Fn = struct { |
| 1481 | 1482 | success, |
| 1482 | 1483 | }; |
| 1483 | 1484 | |
| 1485 | pub const AsyncStatus = enum { | |
| 1486 | unknown, | |
| 1487 | yes_async, | |
| 1488 | not_async, | |
| 1489 | }; | |
| 1490 | ||
| 1484 | 1491 | /// This struct is used to keep track of any dependencies related to functions instances |
| 1485 | 1492 | /// that return inferred error sets. Note that a function may be associated to |
| 1486 | 1493 | /// multiple different error sets, for example an inferred error set which |
| ... | ... | @@ -1608,6 +1615,14 @@ pub const Fn = struct { |
| 1608 | 1615 | else => unreachable, |
| 1609 | 1616 | } |
| 1610 | 1617 | } |
| 1618 | ||
| 1619 | pub fn isAsync(func: Fn) bool { | |
| 1620 | return switch (func.async_status) { | |
| 1621 | .unknown => unreachable, | |
| 1622 | .yes_async => true, | |
| 1623 | .not_async => false, | |
| 1624 | }; | |
| 1625 | } | |
| 1611 | 1626 | }; |
| 1612 | 1627 | |
| 1613 | 1628 | pub const DeclAdapter = struct { |
| ... | ... | @@ -2340,6 +2355,36 @@ pub const SrcLoc = struct { |
| 2340 | 2355 | const full = tree.fullCall(&buf, node).?; |
| 2341 | 2356 | return nodeToSpan(tree, full.ast.fn_expr); |
| 2342 | 2357 | }, |
| 2358 | .node_offset_async_call_func => |node_off| { | |
| 2359 | const tree = try src_loc.file_scope.getTree(gpa); | |
| 2360 | const node_tags = tree.nodes.items(.tag); | |
| 2361 | const node = src_loc.declRelativeToNodeIndex(node_off); | |
| 2362 | const var_decl: Ast.full.VarDecl = switch (node_tags[node]) { | |
| 2363 | .global_var_decl => tree.globalVarDecl(node), | |
| 2364 | .local_var_decl => tree.localVarDecl(node), | |
| 2365 | .simple_var_decl => tree.simpleVarDecl(node), | |
| 2366 | .aligned_var_decl => tree.alignedVarDecl(node), | |
| 2367 | else => unreachable, | |
| 2368 | }; | |
| 2369 | const init_node = var_decl.ast.init_node; | |
| 2370 | var params: [1]Ast.Node.Index = undefined; | |
| 2371 | const full = switch (node_tags[init_node]) { | |
| 2372 | .call_one, | |
| 2373 | .call_one_comma, | |
| 2374 | .async_call_one, | |
| 2375 | .async_call_one_comma, | |
| 2376 | => tree.callOne(&params, init_node), | |
| 2377 | ||
| 2378 | .call, | |
| 2379 | .call_comma, | |
| 2380 | .async_call, | |
| 2381 | .async_call_comma, | |
| 2382 | => tree.callFull(init_node), | |
| 2383 | ||
| 2384 | else => unreachable, | |
| 2385 | }; | |
| 2386 | return nodeToSpan(tree, full.ast.fn_expr); | |
| 2387 | }, | |
| 2343 | 2388 | .node_offset_field_name => |node_off| { |
| 2344 | 2389 | const tree = try src_loc.file_scope.getTree(gpa); |
| 2345 | 2390 | const node_datas = tree.nodes.items(.data); |
| ... | ... | @@ -2963,6 +3008,14 @@ pub const LazySrcLoc = union(enum) { |
| 2963 | 3008 | /// to the callee expression. |
| 2964 | 3009 | /// The Decl is determined contextually. |
| 2965 | 3010 | node_offset_call_func: i32, |
| 3011 | /// Example: | |
| 3012 | /// var a = async b(); | |
| 3013 | /// ~ | |
| 3014 | /// The source location points to the callee expression of a function call | |
| 3015 | /// expression of a variable declaration, found by taking this AST node | |
| 3016 | /// index offset from the containing Decl AST node, which points to the | |
| 3017 | /// variable declaration node. The Decl is determined contextually. | |
| 3018 | node_offset_async_call_func: i32, | |
| 2966 | 3019 | /// The payload is offset from the containing Decl AST node. |
| 2967 | 3020 | /// The source location points to the field name of: |
| 2968 | 3021 | /// * a field access expression (`a.b`), or |
| ... | ... | @@ -3192,6 +3245,7 @@ pub const LazySrcLoc = union(enum) { |
| 3192 | 3245 | .node_offset_slice_end, |
| 3193 | 3246 | .node_offset_slice_sentinel, |
| 3194 | 3247 | .node_offset_call_func, |
| 3248 | .node_offset_async_call_func, | |
| 3195 | 3249 | .node_offset_field_name, |
| 3196 | 3250 | .node_offset_deref_ptr, |
| 3197 | 3251 | .node_offset_asm_source, |
| ... | ... | @@ -6869,6 +6923,10 @@ pub fn singleErrorSetType(mod: *Module, name: InternPool.NullTerminatedString) A |
| 6869 | 6923 | return (try mod.intern_pool.get(mod.gpa, .{ .error_set_type = .{ .names = names } })).toType(); |
| 6870 | 6924 | } |
| 6871 | 6925 | |
| 6926 | pub fn asyncFrameType(mod: *Module, func_index: Fn.Index) Allocator.Error!Type { | |
| 6927 | return (try mod.intern_pool.get(mod.gpa, .{ .async_frame_type = func_index })).toType(); | |
| 6928 | } | |
| 6929 | ||
| 6872 | 6930 | /// Sorts `names` in place. |
| 6873 | 6931 | pub fn errorSetFromUnsortedNames( |
| 6874 | 6932 | mod: *Module, |
src/Sema.zig+141-46| ... | ... | @@ -941,8 +941,9 @@ fn analyzeBodyInner( |
| 941 | 941 | .bool_br_and => try sema.zirBoolBr(block, inst, false), |
| 942 | 942 | .bool_br_or => try sema.zirBoolBr(block, inst, true), |
| 943 | 943 | .c_import => try sema.zirCImport(block, inst), |
| 944 | .call => try sema.zirCall(block, inst, .direct), | |
| 945 | .field_call => try sema.zirCall(block, inst, .field), | |
| 944 | .call => try sema.zirCall(block, inst, Zir.Inst.Call), | |
| 945 | .field_call => try sema.zirCall(block, inst, Zir.Inst.FieldCall), | |
| 946 | .async_call => try sema.zirAsyncCall(block, inst), | |
| 946 | 947 | .closure_get => try sema.zirClosureGet(block, inst), |
| 947 | 948 | .cmp_lt => try sema.zirCmp(block, inst, .lt), |
| 948 | 949 | .cmp_lte => try sema.zirCmp(block, inst, .lte), |
| ... | ... | @@ -6435,7 +6436,7 @@ fn zirCall( |
| 6435 | 6436 | sema: *Sema, |
| 6436 | 6437 | block: *Block, |
| 6437 | 6438 | inst: Zir.Inst.Index, |
| 6438 | comptime kind: enum { direct, field }, | |
| 6439 | comptime ExtraType: type, | |
| 6439 | 6440 | ) CompileError!Air.Inst.Ref { |
| 6440 | 6441 | const tracy = trace(@src()); |
| 6441 | 6442 | defer tracy.end(); |
| ... | ... | @@ -6444,10 +6445,6 @@ fn zirCall( |
| 6444 | 6445 | const inst_data = sema.code.instructions.items(.data)[inst].pl_node; |
| 6445 | 6446 | const callee_src: LazySrcLoc = .{ .node_offset_call_func = inst_data.src_node }; |
| 6446 | 6447 | const call_src = inst_data.src(); |
| 6447 | const ExtraType = switch (kind) { | |
| 6448 | .direct => Zir.Inst.Call, | |
| 6449 | .field => Zir.Inst.FieldCall, | |
| 6450 | }; | |
| 6451 | 6448 | const extra = sema.code.extraData(ExtraType, inst_data.payload_index); |
| 6452 | 6449 | const args_len = extra.data.flags.args_len; |
| 6453 | 6450 | |
| ... | ... | @@ -6455,38 +6452,90 @@ fn zirCall( |
| 6455 | 6452 | const ensure_result_used = extra.data.flags.ensure_result_used; |
| 6456 | 6453 | const pop_error_return_trace = extra.data.flags.pop_error_return_trace; |
| 6457 | 6454 | |
| 6458 | const callee: ResolvedFieldCallee = switch (kind) { | |
| 6459 | .direct => .{ .direct = try sema.resolveInst(extra.data.callee) }, | |
| 6460 | .field => blk: { | |
| 6455 | const callee: ResolvedFieldCallee = switch (ExtraType) { | |
| 6456 | Zir.Inst.Call => .{ .direct = try sema.resolveInst(extra.data.callee) }, | |
| 6457 | Zir.Inst.FieldCall => blk: { | |
| 6461 | 6458 | const object_ptr = try sema.resolveInst(extra.data.obj_ptr); |
| 6462 | 6459 | const field_name = try mod.intern_pool.getOrPutString(sema.gpa, sema.code.nullTerminatedString(extra.data.field_name_start)); |
| 6463 | 6460 | const field_name_src: LazySrcLoc = .{ .node_offset_field_name = inst_data.src_node }; |
| 6464 | 6461 | break :blk try sema.fieldCallBind(block, callee_src, object_ptr, field_name, field_name_src); |
| 6465 | 6462 | }, |
| 6463 | else => @compileError("unreachable"), | |
| 6466 | 6464 | }; |
| 6465 | return callCommon( | |
| 6466 | sema, | |
| 6467 | block, | |
| 6468 | inst, | |
| 6469 | callee_src, | |
| 6470 | call_src, | |
| 6471 | callee, | |
| 6472 | args_len, | |
| 6473 | modifier, | |
| 6474 | extra.end, | |
| 6475 | ensure_result_used, | |
| 6476 | pop_error_return_trace, | |
| 6477 | ); | |
| 6478 | } | |
| 6479 | ||
| 6480 | fn zirAsyncCall(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air.Inst.Ref { | |
| 6481 | 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 }; | |
| 6483 | 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); | |
| 6485 | const args_len = extra.data.args_len; | |
| 6486 | const callee: ResolvedFieldCallee = .{ .direct = try sema.resolveInst(extra.data.callee) }; | |
| 6487 | return callCommon( | |
| 6488 | sema, | |
| 6489 | block, | |
| 6490 | inst, | |
| 6491 | func_src, | |
| 6492 | call_src, | |
| 6493 | callee, | |
| 6494 | args_len, | |
| 6495 | .async_kw, | |
| 6496 | extra.end, | |
| 6497 | false, | |
| 6498 | false, | |
| 6499 | ); | |
| 6500 | } | |
| 6501 | ||
| 6502 | fn callCommon( | |
| 6503 | sema: *Sema, | |
| 6504 | block: *Block, | |
| 6505 | inst: Zir.Inst.Index, | |
| 6506 | callee_src: LazySrcLoc, | |
| 6507 | call_src: LazySrcLoc, | |
| 6508 | callee: ResolvedFieldCallee, | |
| 6509 | args_len: u32, | |
| 6510 | modifier: std.builtin.CallModifier, | |
| 6511 | extra_end: usize, | |
| 6512 | ensure_result_used: bool, | |
| 6513 | pop_error_return_trace: bool, | |
| 6514 | ) CompileError!Air.Inst.Ref { | |
| 6515 | const mod = sema.mod; | |
| 6516 | ||
| 6467 | 6517 | var resolved_args: []Air.Inst.Ref = undefined; |
| 6468 | 6518 | var bound_arg_src: ?LazySrcLoc = null; |
| 6469 | var func: Air.Inst.Ref = undefined; | |
| 6470 | 6519 | var arg_index: u32 = 0; |
| 6471 | switch (callee) { | |
| 6472 | .direct => |func_inst| { | |
| 6520 | const func: Air.Inst.Ref = switch (callee) { | |
| 6521 | .direct => |func_inst| f: { | |
| 6473 | 6522 | resolved_args = try sema.arena.alloc(Air.Inst.Ref, args_len); |
| 6474 | func = func_inst; | |
| 6523 | break :f func_inst; | |
| 6475 | 6524 | }, |
| 6476 | .method => |method| { | |
| 6525 | .method => |method| f: { | |
| 6477 | 6526 | resolved_args = try sema.arena.alloc(Air.Inst.Ref, args_len + 1); |
| 6478 | func = method.func_inst; | |
| 6479 | 6527 | resolved_args[0] = method.arg0_inst; |
| 6480 | 6528 | arg_index += 1; |
| 6481 | 6529 | bound_arg_src = callee_src; |
| 6530 | break :f method.func_inst; | |
| 6482 | 6531 | }, |
| 6483 | } | |
| 6532 | }; | |
| 6484 | 6533 | |
| 6485 | 6534 | const callee_ty = sema.typeOf(func); |
| 6486 | 6535 | const total_args = args_len + @intFromBool(bound_arg_src != null); |
| 6487 | 6536 | const func_ty = try sema.checkCallArgumentCount(block, func, callee_src, callee_ty, total_args, bound_arg_src != null); |
| 6488 | 6537 | |
| 6489 | const args_body = sema.code.extra[extra.end..]; | |
| 6538 | const args_body = sema.code.extra[extra_end..]; | |
| 6490 | 6539 | |
| 6491 | 6540 | var input_is_error = false; |
| 6492 | 6541 | const block_index = @as(Air.Inst.Index, @intCast(block.instructions.items.len)); |
| ... | ... | @@ -6501,7 +6550,7 @@ fn zirCall( |
| 6501 | 6550 | arg_index += 1; |
| 6502 | 6551 | }) { |
| 6503 | 6552 | const func_ty_info = mod.typeToFunc(func_ty).?; |
| 6504 | const arg_end = sema.code.extra[extra.end + extra_index]; | |
| 6553 | const arg_end = sema.code.extra[extra_end + extra_index]; | |
| 6505 | 6554 | defer arg_start = arg_end; |
| 6506 | 6555 | |
| 6507 | 6556 | // Generate args to comptime params in comptime block. |
| ... | ... | @@ -6730,8 +6779,7 @@ fn analyzeCall( |
| 6730 | 6779 | .never_tail => Air.Inst.Tag.call_never_tail, |
| 6731 | 6780 | .never_inline => Air.Inst.Tag.call_never_inline, |
| 6732 | 6781 | .always_tail => Air.Inst.Tag.call_always_tail, |
| 6733 | ||
| 6734 | .async_kw => return sema.failWithUseOfAsync(block, call_src), | |
| 6782 | .async_kw => Air.Inst.Tag.call_async, | |
| 6735 | 6783 | }; |
| 6736 | 6784 | |
| 6737 | 6785 | if (modifier == .never_inline and func_ty_info.cc == .Inline) { |
| ... | ... | @@ -7158,18 +7206,20 @@ fn analyzeCall( |
| 7158 | 7206 | } |
| 7159 | 7207 | } |
| 7160 | 7208 | |
| 7161 | try sema.air_extra.ensureUnusedCapacity(gpa, @typeInfo(Air.Call).Struct.fields.len + | |
| 7162 | args.len); | |
| 7163 | const func_inst = try block.addInst(.{ | |
| 7164 | .tag = call_tag, | |
| 7165 | .data = .{ .pl_op = .{ | |
| 7166 | .operand = func, | |
| 7167 | .payload = sema.addExtraAssumeCapacity(Air.Call{ | |
| 7168 | .args_len = @as(u32, @intCast(args.len)), | |
| 7169 | }), | |
| 7170 | } }, | |
| 7171 | }); | |
| 7172 | sema.appendRefsAssumeCapacity(args); | |
| 7209 | if (call_tag == .call_async) { | |
| 7210 | const func_val = sema.resolveConstValue(block, func_src, func, "function is not comptime-known; @asyncCall required") catch |err| { | |
| 7211 | if (err == error.AnalysisFail and comptime_reason != null) try comptime_reason.?.explain(sema, sema.err); | |
| 7212 | return err; | |
| 7213 | }; | |
| 7214 | const module_fn_index = switch (mod.intern_pool.indexToKey(func_val.toIntern())) { | |
| 7215 | .func => |function| function.index, | |
| 7216 | .ptr => |ptr| mod.declPtr(ptr.addr.decl).val.getFunctionIndex(mod).unwrap().?, | |
| 7217 | else => unreachable, | |
| 7218 | }; | |
| 7219 | break :res try addAsyncCallInst(sema, block, func, module_fn_index, args); | |
| 7220 | } | |
| 7221 | ||
| 7222 | const func_inst = try addCallInst(sema, block, func, args, call_tag); | |
| 7173 | 7223 | |
| 7174 | 7224 | if (call_tag == .call_always_tail) { |
| 7175 | 7225 | if (ensure_result_used) { |
| ... | ... | @@ -7206,6 +7256,56 @@ fn analyzeCall( |
| 7206 | 7256 | return result; |
| 7207 | 7257 | } |
| 7208 | 7258 | |
| 7259 | fn addCallInst( | |
| 7260 | sema: *Sema, | |
| 7261 | block: *Block, | |
| 7262 | callee: Air.Inst.Ref, | |
| 7263 | args: []const Air.Inst.Ref, | |
| 7264 | call_tag: Air.Inst.Tag, | |
| 7265 | ) Allocator.Error!Air.Inst.Ref { | |
| 7266 | try sema.air_extra.ensureUnusedCapacity(sema.gpa, @typeInfo(Air.Call).Struct.fields.len + | |
| 7267 | args.len); | |
| 7268 | const call_inst = try block.addInst(.{ | |
| 7269 | .tag = call_tag, | |
| 7270 | .data = .{ .pl_op = .{ | |
| 7271 | .operand = callee, | |
| 7272 | .payload = sema.addExtraAssumeCapacity(Air.Call{ | |
| 7273 | .args_len = @intCast(args.len), | |
| 7274 | }), | |
| 7275 | } }, | |
| 7276 | }); | |
| 7277 | sema.appendRefsAssumeCapacity(args); | |
| 7278 | return call_inst; | |
| 7279 | } | |
| 7280 | ||
| 7281 | fn addAsyncCallInst( | |
| 7282 | sema: *Sema, | |
| 7283 | block: *Block, | |
| 7284 | callee: Air.Inst.Ref, | |
| 7285 | callee_fn: Module.Fn.Index, | |
| 7286 | args: []const Air.Inst.Ref, | |
| 7287 | ) Allocator.Error!Air.Inst.Ref { | |
| 7288 | const mod = sema.mod; | |
| 7289 | const frame_ty = try mod.asyncFrameType(callee_fn); | |
| 7290 | const frame_ty_ref = try sema.addType(frame_ty); | |
| 7291 | try sema.air_extra.ensureUnusedCapacity( | |
| 7292 | sema.gpa, | |
| 7293 | @typeInfo(Air.AsyncCall).Struct.fields.len + args.len, | |
| 7294 | ); | |
| 7295 | const call_inst = try block.addInst(.{ | |
| 7296 | .tag = .call_async, | |
| 7297 | .data = .{ .ty_pl = .{ | |
| 7298 | .ty = frame_ty_ref, | |
| 7299 | .payload = sema.addExtraAssumeCapacity(Air.AsyncCall{ | |
| 7300 | .callee = callee, | |
| 7301 | .args_len = @intCast(args.len), | |
| 7302 | }), | |
| 7303 | } }, | |
| 7304 | }); | |
| 7305 | sema.appendRefsAssumeCapacity(args); | |
| 7306 | return call_inst; | |
| 7307 | } | |
| 7308 | ||
| 7209 | 7309 | fn handleTailCall(sema: *Sema, block: *Block, call_src: LazySrcLoc, func_ty: Type, result: Air.Inst.Ref) !Air.Inst.Ref { |
| 7210 | 7310 | const mod = sema.mod; |
| 7211 | 7311 | const target = mod.getTarget(); |
| ... | ... | @@ -7664,19 +7764,10 @@ fn instantiateGenericCall( |
| 7664 | 7764 | } |
| 7665 | 7765 | |
| 7666 | 7766 | try mod.ensureFuncBodyAnalysisQueued(callee_index); |
| 7667 | ||
| 7668 | try sema.air_extra.ensureUnusedCapacity(sema.gpa, @typeInfo(Air.Call).Struct.fields.len + | |
| 7669 | runtime_args_len); | |
| 7670 | const result = try block.addInst(.{ | |
| 7671 | .tag = call_tag, | |
| 7672 | .data = .{ .pl_op = .{ | |
| 7673 | .operand = callee_inst, | |
| 7674 | .payload = sema.addExtraAssumeCapacity(Air.Call{ | |
| 7675 | .args_len = runtime_args_len, | |
| 7676 | }), | |
| 7677 | } }, | |
| 7678 | }); | |
| 7679 | sema.appendRefsAssumeCapacity(runtime_args); | |
| 7767 | const result = switch (call_tag) { | |
| 7768 | .call_async => try addAsyncCallInst(sema, block, callee_inst, callee_index, runtime_args), | |
| 7769 | else => try addCallInst(sema, block, callee_inst, runtime_args, call_tag), | |
| 7770 | }; | |
| 7680 | 7771 | |
| 7681 | 7772 | if (ensure_result_used) { |
| 7682 | 7773 | try sema.ensureResultUsed(block, sema.typeOf(result), call_src); |
| ... | ... | @@ -9221,6 +9312,7 @@ fn funcCommon( |
| 9221 | 9312 | const generic_owner_decl = if (comptime_args == null) .none else new_func.generic_owner_decl; |
| 9222 | 9313 | new_func.* = .{ |
| 9223 | 9314 | .state = anal_state, |
| 9315 | .async_status = .unknown, | |
| 9224 | 9316 | .zir_body_inst = func_inst, |
| 9225 | 9317 | .owner_decl = sema.owner_decl_index, |
| 9226 | 9318 | .generic_owner_decl = generic_owner_decl, |
| ... | ... | @@ -33730,6 +33822,7 @@ pub fn resolveTypeRequiresComptime(sema: *Sema, ty: Type) CompileError!bool { |
| 33730 | 33822 | .error_set_type, .inferred_error_set_type => false, |
| 33731 | 33823 | |
| 33732 | 33824 | .func_type => true, |
| 33825 | .async_frame_type => false, | |
| 33733 | 33826 | |
| 33734 | 33827 | .simple_type => |t| switch (t) { |
| 33735 | 33828 | .f16, |
| ... | ... | @@ -35271,6 +35364,7 @@ pub fn typeHasOnePossibleValue(sema: *Sema, ty: Type) CompileError!?Value { |
| 35271 | 35364 | .type_inferred_error_set, |
| 35272 | 35365 | .type_opaque, |
| 35273 | 35366 | .type_function, |
| 35367 | .type_async_frame, | |
| 35274 | 35368 | => null, |
| 35275 | 35369 | .simple_type, // handled above |
| 35276 | 35370 | // values, not types |
| ... | ... | @@ -35934,6 +36028,7 @@ pub fn typeRequiresComptime(sema: *Sema, ty: Type) CompileError!bool { |
| 35934 | 36028 | }, |
| 35935 | 36029 | |
| 35936 | 36030 | .opaque_type => false, |
| 36031 | .async_frame_type => false, | |
| 35937 | 36032 | .enum_type => |enum_type| try sema.typeRequiresComptime(enum_type.tag_ty.toType()), |
| 35938 | 36033 | |
| 35939 | 36034 | // values, not types |
src/TypedValue.zig+1| ... | ... | @@ -192,6 +192,7 @@ pub fn print( |
| 192 | 192 | .func_type, |
| 193 | 193 | .error_set_type, |
| 194 | 194 | .inferred_error_set_type, |
| 195 | .async_frame_type, | |
| 195 | 196 | => return Type.print(val.toType(), writer, mod), |
| 196 | 197 | .undef => return writer.writeAll("undefined"), |
| 197 | 198 | .runtime_value => return writer.writeAll("(runtime value)"), |
src/Zir.zig+21-2| ... | ... | @@ -313,6 +313,11 @@ pub const Inst = struct { |
| 313 | 313 | /// Uses the `pl_node` union field with payload `BuiltinCall`. |
| 314 | 314 | /// AST node is the builtin call. |
| 315 | 315 | builtin_call, |
| 316 | /// An async function call that also acts as an alloc. Corresponds with | |
| 317 | /// the syntax `var foo = async bar();`. | |
| 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. | |
| 320 | async_call, | |
| 316 | 321 | /// `<` |
| 317 | 322 | /// Uses the `pl_node` union field. Payload is `Bin`. |
| 318 | 323 | cmp_lt, |
| ... | ... | @@ -1026,6 +1031,7 @@ pub const Inst = struct { |
| 1026 | 1031 | .bool_not, |
| 1027 | 1032 | .call, |
| 1028 | 1033 | .field_call, |
| 1034 | .async_call, | |
| 1029 | 1035 | .cmp_lt, |
| 1030 | 1036 | .cmp_lte, |
| 1031 | 1037 | .cmp_eq, |
| ... | ... | @@ -1330,6 +1336,7 @@ pub const Inst = struct { |
| 1330 | 1336 | .bool_not, |
| 1331 | 1337 | .call, |
| 1332 | 1338 | .field_call, |
| 1339 | .async_call, | |
| 1333 | 1340 | .cmp_lt, |
| 1334 | 1341 | .cmp_lte, |
| 1335 | 1342 | .cmp_eq, |
| ... | ... | @@ -1564,6 +1571,7 @@ pub const Inst = struct { |
| 1564 | 1571 | .for_len = .pl_node, |
| 1565 | 1572 | .call = .pl_node, |
| 1566 | 1573 | .field_call = .pl_node, |
| 1574 | .async_call = .pl_node, | |
| 1567 | 1575 | .cmp_lt = .pl_node, |
| 1568 | 1576 | .cmp_lte = .pl_node, |
| 1569 | 1577 | .cmp_eq = .pl_node, |
| ... | ... | @@ -1944,7 +1952,7 @@ pub const Inst = struct { |
| 1944 | 1952 | /// `small` contains `NameStrategy`. |
| 1945 | 1953 | reify, |
| 1946 | 1954 | /// Implements the `@asyncCall` builtin. |
| 1947 | /// `operand` is payload index to `AsyncCall`. | |
| 1955 | /// `operand` is payload index to `BuiltinAsyncCall`. | |
| 1948 | 1956 | builtin_async_call, |
| 1949 | 1957 | /// Implements the `@cmpxchgStrong` and `@cmpxchgWeak` builtins. |
| 1950 | 1958 | /// `small` 0=>weak 1=>strong |
| ... | ... | @@ -2531,6 +2539,16 @@ pub const Inst = struct { |
| 2531 | 2539 | field_name_start: u32, |
| 2532 | 2540 | }; |
| 2533 | 2541 | |
| 2542 | /// Not to be confused with BuiltinAsyncCall. | |
| 2543 | /// Stored inside extra, with trailing arguments according to `args_len`. | |
| 2544 | /// Implicit 0. arg_0_start: u32, // always same as `args_len` | |
| 2545 | /// 1. arg_end: u32, // for each `args_len` | |
| 2546 | /// arg_N_start is the same as arg_N-1_end | |
| 2547 | pub const AsyncCall = struct { | |
| 2548 | callee: Ref, | |
| 2549 | args_len: u32, | |
| 2550 | }; | |
| 2551 | ||
| 2534 | 2552 | pub const TypeOfPeer = struct { |
| 2535 | 2553 | src_node: i32, |
| 2536 | 2554 | body_len: u32, |
| ... | ... | @@ -3101,7 +3119,8 @@ pub const Inst = struct { |
| 3101 | 3119 | b: Ref, |
| 3102 | 3120 | }; |
| 3103 | 3121 | |
| 3104 | pub const AsyncCall = struct { | |
| 3122 | /// Not to be confused with AsyncCall. | |
| 3123 | pub const BuiltinAsyncCall = struct { | |
| 3105 | 3124 | node: i32, |
| 3106 | 3125 | frame_buffer: Ref, |
| 3107 | 3126 | result_ptr: Ref, |
src/arch/aarch64/CodeGen.zig+2| ... | ... | @@ -819,6 +819,7 @@ fn genBody(self: *Self, body: []const Air.Inst.Index) InnerError!void { |
| 819 | 819 | .call_always_tail => try self.airCall(inst, .always_tail), |
| 820 | 820 | .call_never_tail => try self.airCall(inst, .never_tail), |
| 821 | 821 | .call_never_inline => try self.airCall(inst, .never_inline), |
| 822 | .call_async => try self.airCall(inst, .async_kw), | |
| 822 | 823 | |
| 823 | 824 | .atomic_store_unordered => try self.airAtomicStore(inst, .Unordered), |
| 824 | 825 | .atomic_store_monotonic => try self.airAtomicStore(inst, .Monotonic), |
| ... | ... | @@ -4242,6 +4243,7 @@ fn airFence(self: *Self) !void { |
| 4242 | 4243 | |
| 4243 | 4244 | fn airCall(self: *Self, inst: Air.Inst.Index, modifier: std.builtin.CallModifier) !void { |
| 4244 | 4245 | if (modifier == .always_tail) return self.fail("TODO implement tail calls for aarch64", .{}); |
| 4246 | if (modifier == .async_kw) return self.fail("TODO implement async calls for aarch64", .{}); | |
| 4245 | 4247 | const pl_op = self.air.instructions.items(.data)[inst].pl_op; |
| 4246 | 4248 | const callee = pl_op.operand; |
| 4247 | 4249 | const extra = self.air.extraData(Air.Call, pl_op.payload); |
src/arch/arm/CodeGen.zig+2| ... | ... | @@ -803,6 +803,7 @@ fn genBody(self: *Self, body: []const Air.Inst.Index) InnerError!void { |
| 803 | 803 | .call_always_tail => try self.airCall(inst, .always_tail), |
| 804 | 804 | .call_never_tail => try self.airCall(inst, .never_tail), |
| 805 | 805 | .call_never_inline => try self.airCall(inst, .never_inline), |
| 806 | .call_async => try self.airCall(inst, .async_kw), | |
| 806 | 807 | |
| 807 | 808 | .atomic_store_unordered => try self.airAtomicStore(inst, .Unordered), |
| 808 | 809 | .atomic_store_monotonic => try self.airAtomicStore(inst, .Monotonic), |
| ... | ... | @@ -4215,6 +4216,7 @@ fn airFence(self: *Self) !void { |
| 4215 | 4216 | |
| 4216 | 4217 | fn airCall(self: *Self, inst: Air.Inst.Index, modifier: std.builtin.CallModifier) !void { |
| 4217 | 4218 | if (modifier == .always_tail) return self.fail("TODO implement tail calls for arm", .{}); |
| 4219 | if (modifier == .async_kw) return self.fail("TODO implement async calls for arm", .{}); | |
| 4218 | 4220 | const pl_op = self.air.instructions.items(.data)[inst].pl_op; |
| 4219 | 4221 | const callee = pl_op.operand; |
| 4220 | 4222 | const extra = self.air.extraData(Air.Call, pl_op.payload); |
src/arch/riscv64/CodeGen.zig+2| ... | ... | @@ -638,6 +638,7 @@ fn genBody(self: *Self, body: []const Air.Inst.Index) InnerError!void { |
| 638 | 638 | .call_always_tail => try self.airCall(inst, .always_tail), |
| 639 | 639 | .call_never_tail => try self.airCall(inst, .never_tail), |
| 640 | 640 | .call_never_inline => try self.airCall(inst, .never_inline), |
| 641 | .call_async => try self.airCall(inst, .async_kw), | |
| 641 | 642 | |
| 642 | 643 | .atomic_store_unordered => try self.airAtomicStore(inst, .Unordered), |
| 643 | 644 | .atomic_store_monotonic => try self.airAtomicStore(inst, .Monotonic), |
| ... | ... | @@ -1707,6 +1708,7 @@ fn airFence(self: *Self) !void { |
| 1707 | 1708 | fn airCall(self: *Self, inst: Air.Inst.Index, modifier: std.builtin.CallModifier) !void { |
| 1708 | 1709 | const mod = self.bin_file.options.module.?; |
| 1709 | 1710 | if (modifier == .always_tail) return self.fail("TODO implement tail calls for riscv64", .{}); |
| 1711 | if (modifier == .async_kw) return self.fail("TODO implement async calls for riscv64", .{}); | |
| 1710 | 1712 | const pl_op = self.air.instructions.items(.data)[inst].pl_op; |
| 1711 | 1713 | const fn_ty = self.typeOf(pl_op.operand); |
| 1712 | 1714 | const callee = pl_op.operand; |
src/arch/sparc64/CodeGen.zig+2| ... | ... | @@ -651,6 +651,7 @@ fn genBody(self: *Self, body: []const Air.Inst.Index) InnerError!void { |
| 651 | 651 | .call_always_tail => try self.airCall(inst, .always_tail), |
| 652 | 652 | .call_never_tail => try self.airCall(inst, .never_tail), |
| 653 | 653 | .call_never_inline => try self.airCall(inst, .never_inline), |
| 654 | .call_async => try self.airCall(inst, .async_kw), | |
| 654 | 655 | |
| 655 | 656 | .atomic_store_unordered => @panic("TODO try self.airAtomicStore(inst, .Unordered)"), |
| 656 | 657 | .atomic_store_monotonic => @panic("TODO try self.airAtomicStore(inst, .Monotonic)"), |
| ... | ... | @@ -1293,6 +1294,7 @@ fn airByteSwap(self: *Self, inst: Air.Inst.Index) !void { |
| 1293 | 1294 | |
| 1294 | 1295 | fn airCall(self: *Self, inst: Air.Inst.Index, modifier: std.builtin.CallModifier) !void { |
| 1295 | 1296 | if (modifier == .always_tail) return self.fail("TODO implement tail calls for {}", .{self.target.cpu.arch}); |
| 1297 | if (modifier == .async_kw) return self.fail("TODO implement async calls for {}", .{self.target.cpu.arch}); | |
| 1296 | 1298 | |
| 1297 | 1299 | const pl_op = self.air.instructions.items(.data)[inst].pl_op; |
| 1298 | 1300 | const callee = pl_op.operand; |
src/arch/wasm/CodeGen.zig+3| ... | ... | @@ -1930,6 +1930,7 @@ fn genInst(func: *CodeGen, inst: Air.Inst.Index) InnerError!void { |
| 1930 | 1930 | .call_always_tail => func.airCall(inst, .always_tail), |
| 1931 | 1931 | .call_never_tail => func.airCall(inst, .never_tail), |
| 1932 | 1932 | .call_never_inline => func.airCall(inst, .never_inline), |
| 1933 | .call_async => func.airCall(inst, .async_kw), | |
| 1933 | 1934 | |
| 1934 | 1935 | .is_err => func.airIsErr(inst, .i32_ne), |
| 1935 | 1936 | .is_non_err => func.airIsErr(inst, .i32_eq), |
| ... | ... | @@ -2180,6 +2181,7 @@ fn airRetLoad(func: *CodeGen, inst: Air.Inst.Index) InnerError!void { |
| 2180 | 2181 | |
| 2181 | 2182 | fn airCall(func: *CodeGen, inst: Air.Inst.Index, modifier: std.builtin.CallModifier) InnerError!void { |
| 2182 | 2183 | if (modifier == .always_tail) return func.fail("TODO implement tail calls for wasm", .{}); |
| 2184 | if (modifier == .async_kw) return func.fail("TODO implement async calls for wasm", .{}); | |
| 2183 | 2185 | const pl_op = func.air.instructions.items(.data)[inst].pl_op; |
| 2184 | 2186 | const extra = func.air.extraData(Air.Call, pl_op.payload); |
| 2185 | 2187 | const args = @as([]const Air.Inst.Ref, @ptrCast(func.air.extra[extra.end..][0..extra.data.args_len])); |
| ... | ... | @@ -3125,6 +3127,7 @@ fn lowerConstant(func: *CodeGen, arg_val: Value, ty: Type) InnerError!WValue { |
| 3125 | 3127 | .func_type, |
| 3126 | 3128 | .error_set_type, |
| 3127 | 3129 | .inferred_error_set_type, |
| 3130 | .async_frame_type, | |
| 3128 | 3131 | => unreachable, // types, not values |
| 3129 | 3132 | |
| 3130 | 3133 | .undef, .runtime_value => unreachable, // handled above |
src/arch/x86_64/CodeGen.zig+2| ... | ... | @@ -1901,6 +1901,7 @@ fn genBody(self: *Self, body: []const Air.Inst.Index) InnerError!void { |
| 1901 | 1901 | .call_always_tail => try self.airCall(inst, .always_tail), |
| 1902 | 1902 | .call_never_tail => try self.airCall(inst, .never_tail), |
| 1903 | 1903 | .call_never_inline => try self.airCall(inst, .never_inline), |
| 1904 | .call_async => try self.airCall(inst, .async_kw), | |
| 1904 | 1905 | |
| 1905 | 1906 | .atomic_store_unordered => try self.airAtomicStore(inst, .Unordered), |
| 1906 | 1907 | .atomic_store_monotonic => try self.airAtomicStore(inst, .Monotonic), |
| ... | ... | @@ -8059,6 +8060,7 @@ fn airFence(self: *Self, inst: Air.Inst.Index) !void { |
| 8059 | 8060 | fn airCall(self: *Self, inst: Air.Inst.Index, modifier: std.builtin.CallModifier) !void { |
| 8060 | 8061 | const mod = self.bin_file.options.module.?; |
| 8061 | 8062 | if (modifier == .always_tail) return self.fail("TODO implement tail calls for x86_64", .{}); |
| 8063 | if (modifier == .async_kw) return self.fail("TODO implement async calls for x86_64", .{}); | |
| 8062 | 8064 | const pl_op = self.air.instructions.items(.data)[inst].pl_op; |
| 8063 | 8065 | const callee = pl_op.operand; |
| 8064 | 8066 | const extra = self.air.extraData(Air.Call, pl_op.payload); |
src/codegen.zig+1| ... | ... | @@ -222,6 +222,7 @@ pub fn generateSymbol( |
| 222 | 222 | .func_type, |
| 223 | 223 | .error_set_type, |
| 224 | 224 | .inferred_error_set_type, |
| 225 | .async_frame_type, | |
| 225 | 226 | => unreachable, // types, not values |
| 226 | 227 | |
| 227 | 228 | .undef, .runtime_value => unreachable, // handled above |
src/codegen/c.zig+2| ... | ... | @@ -927,6 +927,7 @@ pub const DeclGen = struct { |
| 927 | 927 | .func_type, |
| 928 | 928 | .error_set_type, |
| 929 | 929 | .inferred_error_set_type, |
| 930 | .async_frame_type, | |
| 930 | 931 | // memoization, not values |
| 931 | 932 | .memoized_call, |
| 932 | 933 | => unreachable, |
| ... | ... | @@ -2999,6 +3000,7 @@ fn genBodyInner(f: *Function, body: []const Air.Inst.Index) error{ AnalysisFail, |
| 2999 | 3000 | .call_always_tail => .none, |
| 3000 | 3001 | .call_never_tail => try airCall(f, inst, .never_tail), |
| 3001 | 3002 | .call_never_inline => try airCall(f, inst, .never_inline), |
| 3003 | .call_async => try airCall(f, inst, .async_kw), | |
| 3002 | 3004 | |
| 3003 | 3005 | .float_from_int, |
| 3004 | 3006 | .int_from_float, |
src/codegen/llvm.zig+56-2| ... | ... | @@ -3017,11 +3017,58 @@ pub const Object = struct { |
| 3017 | 3017 | .Null => unreachable, |
| 3018 | 3018 | .EnumLiteral => unreachable, |
| 3019 | 3019 | |
| 3020 | .Frame => @panic("TODO implement llvmType for Frame types"), | |
| 3021 | .AnyFrame => @panic("TODO implement llvmType for AnyFrame types"), | |
| 3020 | .Frame => { | |
| 3021 | const gop = try o.type_map.getOrPut(gpa, t.toIntern()); | |
| 3022 | if (gop.found_existing) return gop.value_ptr.*; | |
| 3023 | ||
| 3024 | const func_index = mod.intern_pool.indexToKey(t.toIntern()).async_frame_type; | |
| 3025 | const func = mod.funcPtr(func_index); | |
| 3026 | const owner_decl = mod.declPtr(func.owner_decl); | |
| 3027 | ||
| 3028 | var name_buf = std.ArrayList(u8).init(gpa); | |
| 3029 | defer name_buf.deinit(); | |
| 3030 | try name_buf.appendSlice("@Frame("); | |
| 3031 | try owner_decl.renderFullyQualifiedName(mod, name_buf.writer()); | |
| 3032 | try name_buf.appendSlice(")\x00"); | |
| 3033 | const name = name_buf.items[0 .. name_buf.items.len - 1 :0]; | |
| 3034 | ||
| 3035 | const llvm_struct_ty = o.context.structCreateNamed(name); | |
| 3036 | gop.value_ptr.* = llvm_struct_ty; // must be done before any recursive calls | |
| 3037 | ||
| 3038 | return lowerAsyncFrameType(o, func, llvm_struct_ty); | |
| 3039 | //if (func.isAsync()) { | |
| 3040 | // return lowerAsyncFrameType(o, func, llvm_struct_ty); | |
| 3041 | //} else { | |
| 3042 | // @panic("lower llvm @Frame() type of non-async function"); | |
| 3043 | //} | |
| 3044 | }, | |
| 3045 | .AnyFrame => return o.context.pointerType(0), | |
| 3022 | 3046 | } |
| 3023 | 3047 | } |
| 3024 | 3048 | |
| 3049 | fn lowerAsyncFrameType( | |
| 3050 | o: *Object, | |
| 3051 | func: *Module.Fn, | |
| 3052 | llvm_struct_ty: *llvm.Type, | |
| 3053 | ) Allocator.Error!*llvm.Type { | |
| 3054 | const gpa = o.gpa; | |
| 3055 | var llvm_field_types: std.ArrayListUnmanaged(*llvm.Type) = .{}; | |
| 3056 | defer llvm_field_types.deinit(gpa); | |
| 3057 | ||
| 3058 | try llvm_field_types.ensureUnusedCapacity(gpa, 1); | |
| 3059 | _ = func; | |
| 3060 | llvm_field_types.appendAssumeCapacity(o.context.intType(32)); | |
| 3061 | ||
| 3062 | const any_underaligned_fields = false; | |
| 3063 | llvm_struct_ty.structSetBody( | |
| 3064 | llvm_field_types.items.ptr, | |
| 3065 | @intCast(llvm_field_types.items.len), | |
| 3066 | llvm.Bool.fromBool(any_underaligned_fields), | |
| 3067 | ); | |
| 3068 | ||
| 3069 | return llvm_struct_ty; | |
| 3070 | } | |
| 3071 | ||
| 3025 | 3072 | fn lowerTypeFn(o: *Object, fn_ty: Type) Allocator.Error!*llvm.Type { |
| 3026 | 3073 | const mod = o.module; |
| 3027 | 3074 | const fn_info = mod.typeToFunc(fn_ty).?; |
| ... | ... | @@ -3148,6 +3195,7 @@ pub const Object = struct { |
| 3148 | 3195 | .func_type, |
| 3149 | 3196 | .error_set_type, |
| 3150 | 3197 | .inferred_error_set_type, |
| 3198 | .async_frame_type, | |
| 3151 | 3199 | => unreachable, // types, not values |
| 3152 | 3200 | |
| 3153 | 3201 | .undef, .runtime_value => unreachable, // handled above |
| ... | ... | @@ -4474,6 +4522,7 @@ pub const FuncGen = struct { |
| 4474 | 4522 | .call_always_tail => try self.airCall(inst, .AlwaysTail), |
| 4475 | 4523 | .call_never_tail => try self.airCall(inst, .NeverTail), |
| 4476 | 4524 | .call_never_inline => try self.airCall(inst, .NeverInline), |
| 4525 | .call_async => try self.airCallAsync(inst), | |
| 4477 | 4526 | |
| 4478 | 4527 | .ptr_slice_ptr_ptr => try self.airPtrSliceFieldPtr(inst, 0), |
| 4479 | 4528 | .ptr_slice_len_ptr => try self.airPtrSliceFieldPtr(inst, 1), |
| ... | ... | @@ -4939,6 +4988,11 @@ pub const FuncGen = struct { |
| 4939 | 4988 | _ = fg.builder.buildUnreachable(); |
| 4940 | 4989 | } |
| 4941 | 4990 | |
| 4991 | fn airCallAsync(self: *FuncGen, inst: Air.Inst.Index) !?*llvm.Value { | |
| 4992 | _ = inst; | |
| 4993 | return self.todo("lower async call", .{}); | |
| 4994 | } | |
| 4995 | ||
| 4942 | 4996 | fn airRet(self: *FuncGen, inst: Air.Inst.Index) !?*llvm.Value { |
| 4943 | 4997 | const o = self.dg.object; |
| 4944 | 4998 | const mod = o.module; |
src/codegen/spirv.zig+1| ... | ... | @@ -642,6 +642,7 @@ pub const DeclGen = struct { |
| 642 | 642 | .func_type, |
| 643 | 643 | .error_set_type, |
| 644 | 644 | .inferred_error_set_type, |
| 645 | .async_frame_type, | |
| 645 | 646 | => unreachable, // types, not values |
| 646 | 647 | |
| 647 | 648 | .undef, .runtime_value => unreachable, // handled above |
src/print_air.zig+21-2| ... | ... | @@ -329,6 +329,7 @@ const Writer = struct { |
| 329 | 329 | .reduce, .reduce_optimized => try w.writeReduce(s, inst), |
| 330 | 330 | .cmp_vector, .cmp_vector_optimized => try w.writeCmpVector(s, inst), |
| 331 | 331 | .vector_store_elem => try w.writeVectorStoreElem(s, inst), |
| 332 | .call_async => try w.writeCallAsync(s, inst), | |
| 332 | 333 | |
| 333 | 334 | .dbg_block_begin, .dbg_block_end => {}, |
| 334 | 335 | |
| ... | ... | @@ -699,8 +700,26 @@ const Writer = struct { |
| 699 | 700 | fn writeCall(w: *Writer, s: anytype, inst: Air.Inst.Index) @TypeOf(s).Error!void { |
| 700 | 701 | const pl_op = w.air.instructions.items(.data)[inst].pl_op; |
| 701 | 702 | const extra = w.air.extraData(Air.Call, pl_op.payload); |
| 702 | const args = @as([]const Air.Inst.Ref, @ptrCast(w.air.extra[extra.end..][0..extra.data.args_len])); | |
| 703 | try w.writeOperand(s, inst, 0, pl_op.operand); | |
| 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); | |
| 705 | } | |
| 706 | ||
| 707 | fn writeCallAsync(w: *Writer, s: anytype, inst: Air.Inst.Index) @TypeOf(s).Error!void { | |
| 708 | const ty_pl = w.air.instructions.items(.data)[inst].ty_pl; | |
| 709 | const extra = w.air.extraData(Air.AsyncCall, ty_pl.payload); | |
| 710 | const callee = extra.data.callee; | |
| 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); | |
| 713 | } | |
| 714 | ||
| 715 | fn finishWriteCall( | |
| 716 | w: *Writer, | |
| 717 | s: anytype, | |
| 718 | inst: Air.Inst.Index, | |
| 719 | callee: Air.Inst.Ref, | |
| 720 | args: []const Air.Inst.Ref, | |
| 721 | ) @TypeOf(s).Error!void { | |
| 722 | try w.writeOperand(s, inst, 0, callee); | |
| 704 | 723 | try s.writeAll(", ["); |
| 705 | 724 | for (args, 0..) |arg, i| { |
| 706 | 725 | if (i != 0) try s.writeAll(", "); |
src/print_zir.zig+31-5| ... | ... | @@ -362,6 +362,7 @@ const Writer = struct { |
| 362 | 362 | |
| 363 | 363 | .call => try self.writeCall(stream, inst, .direct), |
| 364 | 364 | .field_call => try self.writeCall(stream, inst, .field), |
| 365 | .async_call => try self.writeAsyncCall(stream, inst), | |
| 365 | 366 | |
| 366 | 367 | .block, |
| 367 | 368 | .block_comptime, |
| ... | ... | @@ -837,7 +838,7 @@ const Writer = struct { |
| 837 | 838 | } |
| 838 | 839 | |
| 839 | 840 | fn writeBuiltinAsyncCall(self: *Writer, stream: anytype, extended: Zir.Inst.Extended.InstData) !void { |
| 840 | const extra = self.code.extraData(Zir.Inst.AsyncCall, extended.operand).data; | |
| 841 | const extra = self.code.extraData(Zir.Inst.BuiltinAsyncCall, extended.operand).data; | |
| 841 | 842 | try self.writeInstRef(stream, extra.frame_buffer); |
| 842 | 843 | try stream.writeAll(", "); |
| 843 | 844 | try self.writeInstRef(stream, extra.result_ptr); |
| ... | ... | @@ -1187,11 +1188,13 @@ const Writer = struct { |
| 1187 | 1188 | try self.writeSrc(stream, src); |
| 1188 | 1189 | } |
| 1189 | 1190 | |
| 1191 | const CallKind = enum { direct, field }; | |
| 1192 | ||
| 1190 | 1193 | fn writeCall( |
| 1191 | 1194 | self: *Writer, |
| 1192 | 1195 | stream: anytype, |
| 1193 | 1196 | inst: Zir.Inst.Index, |
| 1194 | comptime kind: enum { direct, field }, | |
| 1197 | comptime kind: CallKind, | |
| 1195 | 1198 | ) !void { |
| 1196 | 1199 | const inst_data = self.code.instructions.items(.data)[inst].pl_node; |
| 1197 | 1200 | const ExtraType = switch (kind) { |
| ... | ... | @@ -1201,11 +1204,12 @@ const Writer = struct { |
| 1201 | 1204 | const extra = self.code.extraData(ExtraType, inst_data.payload_index); |
| 1202 | 1205 | const args_len = extra.data.flags.args_len; |
| 1203 | 1206 | const body = self.code.extra[extra.end..]; |
| 1207 | const modifier: std.builtin.CallModifier = @enumFromInt(extra.data.flags.packed_modifier); | |
| 1204 | 1208 | |
| 1205 | 1209 | if (extra.data.flags.ensure_result_used) { |
| 1206 | 1210 | try stream.writeAll("nodiscard "); |
| 1207 | 1211 | } |
| 1208 | try stream.print(".{s}, ", .{@tagName(@as(std.builtin.CallModifier, @enumFromInt(extra.data.flags.packed_modifier)))}); | |
| 1212 | try stream.print(".{s}, ", .{@tagName(modifier)}); | |
| 1209 | 1213 | switch (kind) { |
| 1210 | 1214 | .direct => try self.writeInstRef(stream, extra.data.callee), |
| 1211 | 1215 | .field => { |
| ... | ... | @@ -1214,6 +1218,28 @@ const Writer = struct { |
| 1214 | 1218 | try stream.print(", \"{}\"", .{std.zig.fmtEscapes(field_name)}); |
| 1215 | 1219 | }, |
| 1216 | 1220 | } |
| 1221 | return finishWriteCall(self, stream, body, args_len, extra.end, inst_data.src()); | |
| 1222 | } | |
| 1223 | ||
| 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( | |
| 1236 | self: *Writer, | |
| 1237 | stream: anytype, | |
| 1238 | body: []const Zir.Inst.Index, | |
| 1239 | args_len: u32, | |
| 1240 | extra_end: usize, | |
| 1241 | src: Module.LazySrcLoc, | |
| 1242 | ) !void { | |
| 1217 | 1243 | try stream.writeAll(", ["); |
| 1218 | 1244 | |
| 1219 | 1245 | self.indent += 2; |
| ... | ... | @@ -1224,7 +1250,7 @@ const Writer = struct { |
| 1224 | 1250 | var arg_start: u32 = args_len; |
| 1225 | 1251 | while (i < args_len) : (i += 1) { |
| 1226 | 1252 | try stream.writeByteNTimes(' ', self.indent); |
| 1227 | const arg_end = self.code.extra[extra.end + i]; | |
| 1253 | const arg_end = self.code.extra[extra_end + i]; | |
| 1228 | 1254 | defer arg_start = arg_end; |
| 1229 | 1255 | const arg_body = body[arg_start..arg_end]; |
| 1230 | 1256 | try self.writeBracedBody(stream, arg_body); |
| ... | ... | @@ -1237,7 +1263,7 @@ const Writer = struct { |
| 1237 | 1263 | } |
| 1238 | 1264 | |
| 1239 | 1265 | try stream.writeAll("]) "); |
| 1240 | try self.writeSrc(stream, inst_data.src()); | |
| 1266 | try self.writeSrc(stream, src); | |
| 1241 | 1267 | } |
| 1242 | 1268 | |
| 1243 | 1269 | fn writeBlock(self: *Writer, stream: anytype, inst: Zir.Inst.Index) !void { |
src/type.zig+38-1| ... | ... | @@ -409,6 +409,13 @@ pub const Type = struct { |
| 409 | 409 | try writer.writeAll("anyframe->"); |
| 410 | 410 | return print(child.toType(), writer, mod); |
| 411 | 411 | }, |
| 412 | .async_frame_type => |func_index| { | |
| 413 | const func = mod.funcPtr(func_index); | |
| 414 | const owner_decl = mod.declPtr(func.owner_decl); | |
| 415 | try writer.writeAll("@Frame("); | |
| 416 | try owner_decl.renderFullyQualifiedName(mod, writer); | |
| 417 | try writer.writeAll(")"); | |
| 418 | }, | |
| 412 | 419 | |
| 413 | 420 | // values, not types |
| 414 | 421 | .undef, |
| ... | ... | @@ -506,6 +513,7 @@ pub const Type = struct { |
| 506 | 513 | .error_union_type, |
| 507 | 514 | .error_set_type, |
| 508 | 515 | .inferred_error_set_type, |
| 516 | .async_frame_type, | |
| 509 | 517 | => true, |
| 510 | 518 | |
| 511 | 519 | // These are function *bodies*, not pointers. |
| ... | ... | @@ -666,6 +674,7 @@ pub const Type = struct { |
| 666 | 674 | .anon_struct_type, |
| 667 | 675 | .opaque_type, |
| 668 | 676 | .anyframe_type, |
| 677 | .async_frame_type, | |
| 669 | 678 | // These are function bodies, not function pointers. |
| 670 | 679 | .func_type, |
| 671 | 680 | => false, |
| ... | ... | @@ -1068,6 +1077,9 @@ pub const Type = struct { |
| 1068 | 1077 | .opaque_type => return AbiAlignmentAdvanced{ .scalar = 1 }, |
| 1069 | 1078 | .enum_type => |enum_type| return AbiAlignmentAdvanced{ .scalar = enum_type.tag_ty.toType().abiAlignment(mod) }, |
| 1070 | 1079 | |
| 1080 | // TODO: revisit this | |
| 1081 | .async_frame_type => return AbiAlignmentAdvanced{ .scalar = 16 }, | |
| 1082 | ||
| 1071 | 1083 | // values, not types |
| 1072 | 1084 | .undef, |
| 1073 | 1085 | .runtime_value, |
| ... | ... | @@ -1484,6 +1496,25 @@ pub const Type = struct { |
| 1484 | 1496 | .opaque_type => unreachable, // no size available |
| 1485 | 1497 | .enum_type => |enum_type| return AbiSizeAdvanced{ .scalar = enum_type.tag_ty.toType().abiSize(mod) }, |
| 1486 | 1498 | |
| 1499 | .async_frame_type => { | |
| 1500 | switch (strat) { | |
| 1501 | .sema => |sema| { | |
| 1502 | _ = sema; | |
| 1503 | @panic("they asked for the size of an async frame from sema"); | |
| 1504 | }, | |
| 1505 | .lazy => { | |
| 1506 | // TODO: sometimes this might already be resolved | |
| 1507 | return .{ .val = (try mod.intern(.{ .int = .{ | |
| 1508 | .ty = .comptime_int_type, | |
| 1509 | .storage = .{ .lazy_size = ty.toIntern() }, | |
| 1510 | } })).toValue() }; | |
| 1511 | }, | |
| 1512 | .eager => { | |
| 1513 | @panic("they eagerly asked for the size of an async frame"); | |
| 1514 | }, | |
| 1515 | } | |
| 1516 | }, | |
| 1517 | ||
| 1487 | 1518 | // values, not types |
| 1488 | 1519 | .undef, |
| 1489 | 1520 | .runtime_value, |
| ... | ... | @@ -1509,7 +1540,7 @@ pub const Type = struct { |
| 1509 | 1540 | } |
| 1510 | 1541 | } |
| 1511 | 1542 | |
| 1512 | pub fn abiSizeAdvancedUnion( | |
| 1543 | fn abiSizeAdvancedUnion( | |
| 1513 | 1544 | ty: Type, |
| 1514 | 1545 | mod: *Module, |
| 1515 | 1546 | strat: AbiAlignmentAdvancedStrat, |
| ... | ... | @@ -1717,6 +1748,9 @@ pub const Type = struct { |
| 1717 | 1748 | }, |
| 1718 | 1749 | .opaque_type => unreachable, |
| 1719 | 1750 | .enum_type => |enum_type| return bitSizeAdvanced(enum_type.tag_ty.toType(), mod, opt_sema), |
| 1751 | .async_frame_type => { | |
| 1752 | @panic("TODO bitSize async_frame_type"); | |
| 1753 | }, | |
| 1720 | 1754 | |
| 1721 | 1755 | // values, not types |
| 1722 | 1756 | .undef, |
| ... | ... | @@ -2263,6 +2297,7 @@ pub const Type = struct { |
| 2263 | 2297 | |
| 2264 | 2298 | .ptr_type => unreachable, |
| 2265 | 2299 | .anyframe_type => unreachable, |
| 2300 | .async_frame_type => unreachable, | |
| 2266 | 2301 | .array_type => unreachable, |
| 2267 | 2302 | |
| 2268 | 2303 | .opt_type => unreachable, |
| ... | ... | @@ -2445,6 +2480,7 @@ pub const Type = struct { |
| 2445 | 2480 | .anyframe_type, |
| 2446 | 2481 | .error_set_type, |
| 2447 | 2482 | .inferred_error_set_type, |
| 2483 | .async_frame_type, | |
| 2448 | 2484 | => return null, |
| 2449 | 2485 | |
| 2450 | 2486 | inline .array_type, .vector_type => |seq_type, seq_tag| { |
| ... | ... | @@ -2760,6 +2796,7 @@ pub const Type = struct { |
| 2760 | 2796 | }, |
| 2761 | 2797 | |
| 2762 | 2798 | .opaque_type => false, |
| 2799 | .async_frame_type => false, | |
| 2763 | 2800 | |
| 2764 | 2801 | .enum_type => |enum_type| enum_type.tag_ty.toType().comptimeOnly(mod), |
| 2765 | 2802 |
src/value.zig+1| ... | ... | @@ -349,6 +349,7 @@ pub const Value = struct { |
| 349 | 349 | .func_type, |
| 350 | 350 | .error_set_type, |
| 351 | 351 | .inferred_error_set_type, |
| 352 | .async_frame_type, | |
| 352 | 353 | |
| 353 | 354 | .undef, |
| 354 | 355 | .runtime_value, |