authorgravatar for mlugg@mlugg.co.ukMatthew Lugg <mlugg@mlugg.co.uk> 2023-05-13 17:10:05+01:00
committergravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2023-05-20 12:27:48-07:00
log38b83d9d93db400e8103f02eeb77729040bd3666
treef88cdbe5603e27aca415071a3f15ef60f4023d2b
parent7077e90b3f8991c844deb08a16ad3f4e0569398f

Zir: eliminate `field_call_bind` and `field_call_bind_named`

This commit removes the `field_call_bind` and `field_call_bind_named` ZIR instructions, replacing them with a `field_call` instruction which does the bind and call in one. `field_call_bind` is an unfortunate instruction. It's tied into one very specific usage pattern - its result can only be used as a callee. This means that it creates a value of a "pseudo-type" of sorts, `bound_fn` - this type used to exist in Zig, but now we just hide it from the user and have AstGen ensure it's only used in one way. This is quite silly - `Type` and `Value` should, as much as possible, reflect real Zig types and values. It makes sense to instead encode the `a.b()` syntax as its own ZIR instruction, so that's what we do here. This commit introduces a new instruction, `field_call`. It's like `call`, but rather than a callee ref, it contains a ref to the object pointer (`&a` in `a.b()`) and the string field name (`b`). This eliminates `bound_fn` from the language, and slightly decreases the size of generated ZIR - stats below. This commit does remove a few usages which used to be allowed: - `@field(a, "b")()` - `@call(.auto, a.b, .{})` - `@call(.auto, @field(a, "b"), .{})` These forms used to work just like `a.b()`, but are no longer allowed. I believe this is the correct choice for a few reasons: - `a.b()` is a purely *syntactic* form; for instance, `(a.b)()` is not valid. This means it is *not* inconsistent to not allow it in these cases; the special case here isn't "a field access as a callee", but rather this exact syntactic form. - The second argument to `@call` looks much more visually distinct from the callee in standard call syntax. To me, this makes it seem strange for that argument to not work like a normal expression in this context. - A more practical argument: it's confusing! `@field` and `@call` are used in very different contexts to standard function calls: the former normally hints at some comptime machinery, and the latter that you want more precise control over parts of a function call. In these contexts, you don't want implicit arguments adding extra confusion: you want to be very explicit about what you're doing. Lastly, some stats. I mentioned before that this change slightly reduces the size of ZIR - this is due to two instructions (`field_call_bind` then `call`) being replaced with one (`field_call`). Here are some numbers: +--------------+----------+----------+--------+ | File | Before | After | Change | +--------------+----------+----------+--------+ | Sema.zig | 4.72M | 4.53M | -4% | | AstGen.zig | 1.52M | 1.48M | -3% | | hash_map.zig | 283.9K | 276.2K | -3% | | math.zig | 312.6K | 305.3K | -2% | +--------------+----------+----------+--------+

16 files changed, 231 insertions(+), 288 deletions(-)

lib/std/Thread/Mutex.zig+3-2
......@@ -169,7 +169,7 @@ const FutexImpl = struct {
169169 }
170170 }
171171
172 inline fn lockFast(self: *@This(), comptime casFn: []const u8) bool {
172 inline fn lockFast(self: *@This(), comptime cas_fn_name: []const u8) bool {
173173 // On x86, use `lock bts` instead of `lock cmpxchg` as:
174174 // - they both seem to mark the cache-line as modified regardless: https://stackoverflow.com/a/63350048
175175 // - `lock bts` is smaller instruction-wise which makes it better for inlining
......@@ -180,7 +180,8 @@ const FutexImpl = struct {
180180
181181 // Acquire barrier ensures grabbing the lock happens before the critical section
182182 // and that the previous lock holder's critical section happens before we grab the lock.
183 return @field(self.state, casFn)(unlocked, locked, .Acquire, .Monotonic) == null;
183 const casFn = @field(@TypeOf(self.state), cas_fn_name);
184 return casFn(&self.state, unlocked, locked, .Acquire, .Monotonic) == null;
184185 }
185186
186187 fn lockSlow(self: *@This()) void {
lib/std/crypto/siphash.zig+2-2
......@@ -167,8 +167,8 @@ fn SipHashStateless(comptime T: type, comptime c_rounds: usize, comptime d_round
167167 pub fn hash(msg: []const u8, key: *const [key_length]u8) T {
168168 const aligned_len = msg.len - (msg.len % 8);
169169 var c = Self.init(key);
170 @call(.always_inline, c.update, .{msg[0..aligned_len]});
171 return @call(.always_inline, c.final, .{msg[aligned_len..]});
170 @call(.always_inline, update, .{ &c, msg[0..aligned_len] });
171 return @call(.always_inline, final, .{ &c, msg[aligned_len..] });
172172 }
173173 };
174174}
lib/std/hash/auto_hash.zig+7-3
......@@ -64,9 +64,13 @@ pub fn hashArray(hasher: anytype, key: anytype, comptime strat: HashStrategy) vo
6464/// Strategy is provided to determine if pointers should be followed or not.
6565pub fn hash(hasher: anytype, key: anytype, comptime strat: HashStrategy) void {
6666 const Key = @TypeOf(key);
67 const Hasher = switch (@typeInfo(@TypeOf(hasher))) {
68 .Pointer => |ptr| ptr.child,
69 else => @TypeOf(hasher),
70 };
6771
6872 if (strat == .Shallow and comptime meta.trait.hasUniqueRepresentation(Key)) {
69 @call(.always_inline, hasher.update, .{mem.asBytes(&key)});
73 @call(.always_inline, Hasher.update, .{ hasher, mem.asBytes(&key) });
7074 return;
7175 }
7276
......@@ -89,12 +93,12 @@ pub fn hash(hasher: anytype, key: anytype, comptime strat: HashStrategy) void {
8993 // TODO Check if the situation is better after #561 is resolved.
9094 .Int => {
9195 if (comptime meta.trait.hasUniqueRepresentation(Key)) {
92 @call(.always_inline, hasher.update, .{std.mem.asBytes(&key)});
96 @call(.always_inline, Hasher.update, .{ hasher, std.mem.asBytes(&key) });
9397 } else {
9498 // Take only the part containing the key value, the remaining
9599 // bytes are undefined and must not be hashed!
96100 const byte_size = comptime std.math.divCeil(comptime_int, @bitSizeOf(Key), 8) catch unreachable;
97 @call(.always_inline, hasher.update, .{std.mem.asBytes(&key)[0..byte_size]});
101 @call(.always_inline, Hasher.update, .{ hasher, std.mem.asBytes(&key)[0..byte_size] });
98102 }
99103 },
100104
lib/std/hash/wyhash.zig+3-3
......@@ -65,7 +65,7 @@ const WyhashStateless = struct {
6565
6666 var off: usize = 0;
6767 while (off < b.len) : (off += 32) {
68 @call(.always_inline, self.round, .{b[off..][0..32]});
68 @call(.always_inline, round, .{ self, b[off..][0..32] });
6969 }
7070
7171 self.msg_len += b.len;
......@@ -121,8 +121,8 @@ const WyhashStateless = struct {
121121 const aligned_len = input.len - (input.len % 32);
122122
123123 var c = WyhashStateless.init(seed);
124 @call(.always_inline, c.update, .{input[0..aligned_len]});
125 return @call(.always_inline, c.final, .{input[aligned_len..]});
124 @call(.always_inline, update, .{ &c, input[0..aligned_len] });
125 return @call(.always_inline, final, .{ &c, input[aligned_len..] });
126126 }
127127};
128128
src/AstGen.zig+80-69
......@@ -2482,7 +2482,7 @@ fn addEnsureResult(gz: *GenZir, maybe_unused_result: Zir.Inst.Ref, statement: As
24822482 switch (zir_tags[inst]) {
24832483 // For some instructions, modify the zir data
24842484 // so we can avoid a separate ensure_result_used instruction.
2485 .call => {
2485 .call, .field_call => {
24862486 const extra_index = gz.astgen.instructions.items(.data)[inst].pl_node.payload_index;
24872487 const slot = &gz.astgen.extra.items[extra_index];
24882488 var flags = @bitCast(Zir.Inst.Call.Flags, slot.*);
......@@ -2557,7 +2557,6 @@ fn addEnsureResult(gz: *GenZir, maybe_unused_result: Zir.Inst.Ref, statement: As
25572557 .field_ptr,
25582558 .field_ptr_init,
25592559 .field_val,
2560 .field_call_bind,
25612560 .field_ptr_named,
25622561 .field_val_named,
25632562 .func,
......@@ -8516,7 +8515,7 @@ fn builtinCall(
85168515 },
85178516 .call => {
85188517 const modifier = try comptimeExpr(gz, scope, .{ .rl = .{ .coerced_ty = .modifier_type } }, params[0]);
8519 const callee = try calleeExpr(gz, scope, params[1]);
8518 const callee = try expr(gz, scope, .{ .rl = .none }, params[1]);
85208519 const args = try expr(gz, scope, .{ .rl = .none }, params[2]);
85218520 const result = try gz.addPlNode(.builtin_call, node, Zir.Inst.BuiltinCall{
85228521 .modifier = modifier,
......@@ -8976,7 +8975,10 @@ fn callExpr(
89768975 } });
89778976 }
89788977
8979 assert(callee != .none);
8978 switch (callee) {
8979 .direct => |obj| assert(obj != .none),
8980 .field => |field| assert(field.obj_ptr != .none),
8981 }
89808982 assert(node != 0);
89818983
89828984 const call_index = @intCast(Zir.Inst.Index, astgen.instructions.len);
......@@ -9015,89 +9017,98 @@ fn callExpr(
90159017 else => false,
90169018 };
90179019
9018 const payload_index = try addExtra(astgen, Zir.Inst.Call{
9019 .callee = callee,
9020 .flags = .{
9021 .pop_error_return_trace = !propagate_error_trace,
9022 .packed_modifier = @intCast(Zir.Inst.Call.Flags.PackedModifier, @enumToInt(modifier)),
9023 .args_len = @intCast(Zir.Inst.Call.Flags.PackedArgsLen, call.ast.params.len),
9020 switch (callee) {
9021 .direct => |callee_obj| {
9022 const payload_index = try addExtra(astgen, Zir.Inst.Call{
9023 .callee = callee_obj,
9024 .flags = .{
9025 .pop_error_return_trace = !propagate_error_trace,
9026 .packed_modifier = @intCast(Zir.Inst.Call.Flags.PackedModifier, @enumToInt(modifier)),
9027 .args_len = @intCast(Zir.Inst.Call.Flags.PackedArgsLen, call.ast.params.len),
9028 },
9029 });
9030 if (call.ast.params.len != 0) {
9031 try astgen.extra.appendSlice(astgen.gpa, astgen.scratch.items[scratch_top..]);
9032 }
9033 gz.astgen.instructions.set(call_index, .{
9034 .tag = .call,
9035 .data = .{ .pl_node = .{
9036 .src_node = gz.nodeIndexToRelative(node),
9037 .payload_index = payload_index,
9038 } },
9039 });
9040 },
9041 .field => |callee_field| {
9042 const payload_index = try addExtra(astgen, Zir.Inst.FieldCall{
9043 .obj_ptr = callee_field.obj_ptr,
9044 .field_name_start = callee_field.field_name_start,
9045 .flags = .{
9046 .pop_error_return_trace = !propagate_error_trace,
9047 .packed_modifier = @intCast(Zir.Inst.Call.Flags.PackedModifier, @enumToInt(modifier)),
9048 .args_len = @intCast(Zir.Inst.Call.Flags.PackedArgsLen, call.ast.params.len),
9049 },
9050 });
9051 if (call.ast.params.len != 0) {
9052 try astgen.extra.appendSlice(astgen.gpa, astgen.scratch.items[scratch_top..]);
9053 }
9054 gz.astgen.instructions.set(call_index, .{
9055 .tag = .field_call,
9056 .data = .{ .pl_node = .{
9057 .src_node = gz.nodeIndexToRelative(node),
9058 .payload_index = payload_index,
9059 } },
9060 });
90249061 },
9025 });
9026 if (call.ast.params.len != 0) {
9027 try astgen.extra.appendSlice(astgen.gpa, astgen.scratch.items[scratch_top..]);
90289062 }
9029 gz.astgen.instructions.set(call_index, .{
9030 .tag = .call,
9031 .data = .{ .pl_node = .{
9032 .src_node = gz.nodeIndexToRelative(node),
9033 .payload_index = payload_index,
9034 } },
9035 });
90369063 return rvalue(gz, ri, call_inst, node); // TODO function call with result location
90379064}
90389065
9039/// calleeExpr generates the function part of a call expression (f in f(x)), or the
9040/// callee argument to the @call() builtin. If the lhs is a field access or the
9041/// @field() builtin, we need to generate a special field_call_bind instruction
9042/// instead of the normal field_val or field_ptr. If this is a inst.func() call,
9043/// this instruction will capture the value of the first argument before evaluating
9044/// the other arguments. We need to use .ref here to guarantee we will be able to
9045/// promote an lvalue to an address if the first parameter requires it. This
9046/// unfortunately also means we need to take a reference to any types on the lhs.
9066const Callee = union(enum) {
9067 field: struct {
9068 /// A *pointer* to the object the field is fetched on, so that we can
9069 /// promote the lvalue to an address if the first parameter requires it.
9070 obj_ptr: Zir.Inst.Ref,
9071 /// Offset into `string_bytes`.
9072 field_name_start: u32,
9073 },
9074 direct: Zir.Inst.Ref,
9075};
9076
9077/// calleeExpr generates the function part of a call expression (f in f(x)), but
9078/// *not* the callee argument to the @call() builtin. Its purpose is to
9079/// distinguish between standard calls and method call syntax `a.b()`. Thus, if
9080/// the lhs is a field access, we return using the `field` union field;
9081/// otherwise, we use the `direct` union field.
90479082fn calleeExpr(
90489083 gz: *GenZir,
90499084 scope: *Scope,
90509085 node: Ast.Node.Index,
9051) InnerError!Zir.Inst.Ref {
9086) InnerError!Callee {
90529087 const astgen = gz.astgen;
90539088 const tree = astgen.tree;
90549089
90559090 const tag = tree.nodes.items(.tag)[node];
90569091 switch (tag) {
9057 .field_access => return addFieldAccess(.field_call_bind, gz, scope, .{ .rl = .ref }, node),
9058
9059 .builtin_call_two,
9060 .builtin_call_two_comma,
9061 .builtin_call,
9062 .builtin_call_comma,
9063 => {
9064 const node_datas = tree.nodes.items(.data);
9092 .field_access => {
90659093 const main_tokens = tree.nodes.items(.main_token);
9066 const builtin_token = main_tokens[node];
9067 const builtin_name = tree.tokenSlice(builtin_token);
9068
9069 var inline_params: [2]Ast.Node.Index = undefined;
9070 var params: []Ast.Node.Index = switch (tag) {
9071 .builtin_call,
9072 .builtin_call_comma,
9073 => tree.extra_data[node_datas[node].lhs..node_datas[node].rhs],
9074
9075 .builtin_call_two,
9076 .builtin_call_two_comma,
9077 => blk: {
9078 inline_params = .{ node_datas[node].lhs, node_datas[node].rhs };
9079 const len: usize = if (inline_params[0] == 0) @as(usize, 0) else if (inline_params[1] == 0) @as(usize, 1) else @as(usize, 2);
9080 break :blk inline_params[0..len];
9081 },
9082
9083 else => unreachable,
9084 };
9094 const node_datas = tree.nodes.items(.data);
9095 const object_node = node_datas[node].lhs;
9096 const dot_token = main_tokens[node];
9097 const field_ident = dot_token + 1;
9098 const str_index = try astgen.identAsString(field_ident);
9099 // Capture the object by reference so we can promote it to an
9100 // address in Sema if needed.
9101 const lhs = try expr(gz, scope, .{ .rl = .ref }, object_node);
90859102
9086 // If anything is wrong, fall back to builtinCall.
9087 // It will emit any necessary compile errors and notes.
9088 if (std.mem.eql(u8, builtin_name, "@field") and params.len == 2) {
9089 const lhs = try expr(gz, scope, .{ .rl = .ref }, params[0]);
9090 const field_name = try comptimeExpr(gz, scope, .{ .rl = .{ .ty = .const_slice_u8_type } }, params[1]);
9091 return gz.addExtendedPayload(.field_call_bind_named, Zir.Inst.FieldNamedNode{
9092 .node = gz.nodeIndexToRelative(node),
9093 .lhs = lhs,
9094 .field_name = field_name,
9095 });
9096 }
9103 const cursor = maybeAdvanceSourceCursorToMainToken(gz, node);
9104 try emitDbgStmt(gz, cursor);
90979105
9098 return builtinCall(gz, scope, .{ .rl = .none }, node, params);
9106 return .{ .field = .{
9107 .obj_ptr = lhs,
9108 .field_name_start = str_index,
9109 } };
90999110 },
9100 else => return expr(gz, scope, .{ .rl = .none }, node),
9111 else => return .{ .direct = try expr(gz, scope, .{ .rl = .none }, node) },
91019112 }
91029113}
91039114
src/Autodoc.zig+2-3
......@@ -2141,7 +2141,7 @@ fn walkInstruction(
21412141 .expr = .{ .declRef = decl_status },
21422142 };
21432143 },
2144 .field_val, .field_call_bind, .field_ptr, .field_type => {
2144 .field_val, .field_ptr, .field_type => {
21452145 // TODO: field type uses Zir.Inst.FieldType, it just happens to have the
21462146 // same layout as Zir.Inst.Field :^)
21472147 const pl_node = data[inst_index].pl_node;
......@@ -2163,7 +2163,6 @@ fn walkInstruction(
21632163
21642164 const lhs = @enumToInt(lhs_extra.data.lhs) - Ref.typed_value_map.len;
21652165 if (tags[lhs] != .field_val and
2166 tags[lhs] != .field_call_bind and
21672166 tags[lhs] != .field_ptr and
21682167 tags[lhs] != .field_type) break :blk lhs_extra.data.lhs;
21692168
......@@ -2191,7 +2190,7 @@ fn walkInstruction(
21912190 const wr = blk: {
21922191 if (@enumToInt(lhs_ref) >= Ref.typed_value_map.len) {
21932192 const lhs_inst = @enumToInt(lhs_ref) - Ref.typed_value_map.len;
2194 if (tags[lhs_inst] == .call) {
2193 if (tags[lhs_inst] == .call or tags[lhs_inst] == .field_call) {
21952194 break :blk DocData.WalkResult{
21962195 .expr = .{
21972196 .comptimeExpr = 0,
src/Module.zig+15-1
......@@ -2489,8 +2489,21 @@ pub const SrcLoc = struct {
24892489 const node_datas = tree.nodes.items(.data);
24902490 const node_tags = tree.nodes.items(.tag);
24912491 const node = src_loc.declRelativeToNodeIndex(node_off);
2492 var buf: [1]Ast.Node.Index = undefined;
24922493 const tok_index = switch (node_tags[node]) {
24932494 .field_access => node_datas[node].rhs,
2495 .call_one,
2496 .call_one_comma,
2497 .async_call_one,
2498 .async_call_one_comma,
2499 .call,
2500 .call_comma,
2501 .async_call,
2502 .async_call_comma,
2503 => blk: {
2504 const full = tree.fullCall(&buf, node).?;
2505 break :blk tree.lastToken(full.ast.fn_expr);
2506 },
24942507 else => tree.firstToken(node) - 2,
24952508 };
24962509 const start = tree.tokens.items(.start)[tok_index];
......@@ -3083,7 +3096,8 @@ pub const LazySrcLoc = union(enum) {
30833096 /// The payload is offset from the containing Decl AST node.
30843097 /// The source location points to the field name of:
30853098 /// * a field access expression (`a.b`), or
3086 /// * the operand ("b" node) of a field initialization expression (`.a = b`)
3099 /// * the callee of a method call (`a.b()`), or
3100 /// * the operand ("b" node) of a field initialization expression (`.a = b`), or
30873101 /// The Decl is determined contextually.
30883102 node_offset_field_name: i32,
30893103 /// The source location points to the pointer of a pointer deref expression,
src/Sema.zig+73-103
......@@ -920,7 +920,8 @@ fn analyzeBodyInner(
920920 .bool_br_and => try sema.zirBoolBr(block, inst, false),
921921 .bool_br_or => try sema.zirBoolBr(block, inst, true),
922922 .c_import => try sema.zirCImport(block, inst),
923 .call => try sema.zirCall(block, inst),
923 .call => try sema.zirCall(block, inst, .direct),
924 .field_call => try sema.zirCall(block, inst, .field),
924925 .closure_get => try sema.zirClosureGet(block, inst),
925926 .cmp_lt => try sema.zirCmp(block, inst, .lt),
926927 .cmp_lte => try sema.zirCmp(block, inst, .lte),
......@@ -952,7 +953,6 @@ fn analyzeBodyInner(
952953 .field_ptr_named => try sema.zirFieldPtrNamed(block, inst),
953954 .field_val => try sema.zirFieldVal(block, inst),
954955 .field_val_named => try sema.zirFieldValNamed(block, inst),
955 .field_call_bind => try sema.zirFieldCallBind(block, inst),
956956 .func => try sema.zirFunc(block, inst, false),
957957 .func_inferred => try sema.zirFunc(block, inst, true),
958958 .func_fancy => try sema.zirFuncFancy(block, inst),
......@@ -1149,7 +1149,6 @@ fn analyzeBodyInner(
11491149 .wasm_memory_size => try sema.zirWasmMemorySize( block, extended),
11501150 .wasm_memory_grow => try sema.zirWasmMemoryGrow( block, extended),
11511151 .prefetch => try sema.zirPrefetch( block, extended),
1152 .field_call_bind_named => try sema.zirFieldCallBindNamed(block, extended),
11531152 .err_set_cast => try sema.zirErrSetCast( block, extended),
11541153 .await_nosuspend => try sema.zirAwaitNosuspend( block, extended),
11551154 .select => try sema.zirSelect( block, extended),
......@@ -6262,38 +6261,50 @@ fn zirCall(
62626261 sema: *Sema,
62636262 block: *Block,
62646263 inst: Zir.Inst.Index,
6264 comptime kind: enum { direct, field },
62656265) CompileError!Air.Inst.Ref {
62666266 const tracy = trace(@src());
62676267 defer tracy.end();
62686268
62696269 const inst_data = sema.code.instructions.items(.data)[inst].pl_node;
6270 const func_src: LazySrcLoc = .{ .node_offset_call_func = inst_data.src_node };
6270 const callee_src: LazySrcLoc = .{ .node_offset_call_func = inst_data.src_node };
62716271 const call_src = inst_data.src();
6272 const extra = sema.code.extraData(Zir.Inst.Call, inst_data.payload_index);
6272 const ExtraType = switch (kind) {
6273 .direct => Zir.Inst.Call,
6274 .field => Zir.Inst.FieldCall,
6275 };
6276 const extra = sema.code.extraData(ExtraType, inst_data.payload_index);
62736277 const args_len = extra.data.flags.args_len;
62746278
62756279 const modifier = @intToEnum(std.builtin.CallModifier, extra.data.flags.packed_modifier);
62766280 const ensure_result_used = extra.data.flags.ensure_result_used;
62776281 const pop_error_return_trace = extra.data.flags.pop_error_return_trace;
62786282
6279 var func = try sema.resolveInst(extra.data.callee);
6283 const callee: ResolvedFieldCallee = switch (kind) {
6284 .direct => .{ .direct = try sema.resolveInst(extra.data.callee) },
6285 .field => blk: {
6286 const object_ptr = try sema.resolveInst(extra.data.obj_ptr);
6287 const field_name = sema.code.nullTerminatedString(extra.data.field_name_start);
6288 const field_name_src: LazySrcLoc = .{ .node_offset_field_name = inst_data.src_node };
6289 break :blk try sema.fieldCallBind(block, callee_src, object_ptr, field_name, field_name_src);
6290 },
6291 };
62806292 var resolved_args: []Air.Inst.Ref = undefined;
6281 var arg_index: u32 = 0;
6282
6283 const func_type = sema.typeOf(func);
6284
6285 // Desugar bound functions here
62866293 var bound_arg_src: ?LazySrcLoc = null;
6287 if (func_type.tag() == .bound_fn) {
6288 bound_arg_src = func_src;
6289 const bound_func = try sema.resolveValue(block, .unneeded, func, "");
6290 const bound_data = &bound_func.cast(Value.Payload.BoundFn).?.data;
6291 func = bound_data.func_inst;
6292 resolved_args = try sema.arena.alloc(Air.Inst.Ref, args_len + 1);
6293 resolved_args[arg_index] = bound_data.arg0_inst;
6294 arg_index += 1;
6295 } else {
6296 resolved_args = try sema.arena.alloc(Air.Inst.Ref, args_len);
6294 var func: Air.Inst.Ref = undefined;
6295 var arg_index: u32 = 0;
6296 switch (callee) {
6297 .direct => |func_inst| {
6298 resolved_args = try sema.arena.alloc(Air.Inst.Ref, args_len);
6299 func = func_inst;
6300 },
6301 .method => |method| {
6302 resolved_args = try sema.arena.alloc(Air.Inst.Ref, args_len + 1);
6303 func = method.func_inst;
6304 resolved_args[0] = method.arg0_inst;
6305 arg_index += 1;
6306 bound_arg_src = callee_src;
6307 },
62976308 }
62986309
62996310 const callee_ty = sema.typeOf(func);
......@@ -6308,10 +6319,11 @@ fn zirCall(
63086319 },
63096320 else => {},
63106321 }
6311 return sema.fail(block, func_src, "type '{}' not a function", .{callee_ty.fmt(sema.mod)});
6322 return sema.fail(block, callee_src, "type '{}' not a function", .{callee_ty.fmt(sema.mod)});
63126323 };
6324
63136325 const total_args = args_len + @boolToInt(bound_arg_src != null);
6314 try sema.checkCallArgumentCount(block, func, func_src, func_ty, total_args, bound_arg_src != null);
6326 try sema.checkCallArgumentCount(block, func, callee_src, func_ty, total_args, bound_arg_src != null);
63156327
63166328 const args_body = sema.code.extra[extra.end..];
63176329
......@@ -6369,7 +6381,7 @@ fn zirCall(
63696381 !block.is_comptime and !block.is_typeof and (input_is_error or pop_error_return_trace))
63706382 {
63716383 const call_inst: Air.Inst.Ref = if (modifier == .always_tail) undefined else b: {
6372 break :b try sema.analyzeCall(block, func, func_ty, func_src, call_src, modifier, ensure_result_used, resolved_args, bound_arg_src, call_dbg_node);
6384 break :b try sema.analyzeCall(block, func, func_ty, callee_src, call_src, modifier, ensure_result_used, resolved_args, bound_arg_src, call_dbg_node);
63736385 };
63746386
63756387 const return_ty = sema.typeOf(call_inst);
......@@ -6398,11 +6410,11 @@ fn zirCall(
63986410 }
63996411
64006412 if (modifier == .always_tail) // Perform the call *after* the restore, so that a tail call is possible.
6401 return sema.analyzeCall(block, func, func_ty, func_src, call_src, modifier, ensure_result_used, resolved_args, bound_arg_src, call_dbg_node);
6413 return sema.analyzeCall(block, func, func_ty, callee_src, call_src, modifier, ensure_result_used, resolved_args, bound_arg_src, call_dbg_node);
64026414
64036415 return call_inst;
64046416 } else {
6405 return sema.analyzeCall(block, func, func_ty, func_src, call_src, modifier, ensure_result_used, resolved_args, bound_arg_src, call_dbg_node);
6417 return sema.analyzeCall(block, func, func_ty, callee_src, call_src, modifier, ensure_result_used, resolved_args, bound_arg_src, call_dbg_node);
64066418 }
64076419}
64086420
......@@ -9467,19 +9479,6 @@ fn zirFieldPtr(sema: *Sema, block: *Block, inst: Zir.Inst.Index, initializing: b
94679479 return sema.fieldPtr(block, src, object_ptr, field_name, field_name_src, initializing);
94689480}
94699481
9470fn zirFieldCallBind(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air.Inst.Ref {
9471 const tracy = trace(@src());
9472 defer tracy.end();
9473
9474 const inst_data = sema.code.instructions.items(.data)[inst].pl_node;
9475 const src = inst_data.src();
9476 const field_name_src: LazySrcLoc = .{ .node_offset_field_name = inst_data.src_node };
9477 const extra = sema.code.extraData(Zir.Inst.Field, inst_data.payload_index).data;
9478 const field_name = sema.code.nullTerminatedString(extra.field_name_start);
9479 const object_ptr = try sema.resolveInst(extra.lhs);
9480 return sema.fieldCallBind(block, src, object_ptr, field_name, field_name_src);
9481}
9482
94839482fn zirFieldValNamed(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air.Inst.Ref {
94849483 const tracy = trace(@src());
94859484 defer tracy.end();
......@@ -9506,18 +9505,6 @@ fn zirFieldPtrNamed(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileErr
95069505 return sema.fieldPtr(block, src, object_ptr, field_name, field_name_src, false);
95079506}
95089507
9509fn zirFieldCallBindNamed(sema: *Sema, block: *Block, extended: Zir.Inst.Extended.InstData) CompileError!Air.Inst.Ref {
9510 const tracy = trace(@src());
9511 defer tracy.end();
9512
9513 const extra = sema.code.extraData(Zir.Inst.FieldNamedNode, extended.operand).data;
9514 const src = LazySrcLoc.nodeOffset(extra.node);
9515 const field_name_src: LazySrcLoc = .{ .node_offset_builtin_call_arg1 = extra.node };
9516 const object_ptr = try sema.resolveInst(extra.lhs);
9517 const field_name = try sema.resolveConstString(block, field_name_src, extra.field_name, "field name must be comptime-known");
9518 return sema.fieldCallBind(block, src, object_ptr, field_name, field_name_src);
9519}
9520
95219508fn zirIntCast(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air.Inst.Ref {
95229509 const tracy = trace(@src());
95239510 defer tracy.end();
......@@ -21673,25 +21660,9 @@ fn zirBuiltinCall(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError
2167321660 return sema.fail(block, args_src, "expected a tuple, found '{}'", .{args_ty.fmt(sema.mod)});
2167421661 }
2167521662
21676 var resolved_args: []Air.Inst.Ref = undefined;
21677
21678 // Desugar bound functions here
21679 var bound_arg_src: ?LazySrcLoc = null;
21680 if (sema.typeOf(func).tag() == .bound_fn) {
21681 bound_arg_src = func_src;
21682 const bound_func = try sema.resolveValue(block, .unneeded, func, "");
21683 const bound_data = &bound_func.cast(Value.Payload.BoundFn).?.data;
21684 func = bound_data.func_inst;
21685 resolved_args = try sema.arena.alloc(Air.Inst.Ref, args_ty.structFieldCount() + 1);
21686 resolved_args[0] = bound_data.arg0_inst;
21687 for (resolved_args[1..], 0..) |*resolved, i| {
21688 resolved.* = try sema.tupleFieldValByIndex(block, args_src, args, @intCast(u32, i), args_ty);
21689 }
21690 } else {
21691 resolved_args = try sema.arena.alloc(Air.Inst.Ref, args_ty.structFieldCount());
21692 for (resolved_args, 0..) |*resolved, i| {
21693 resolved.* = try sema.tupleFieldValByIndex(block, args_src, args, @intCast(u32, i), args_ty);
21694 }
21663 var resolved_args: []Air.Inst.Ref = try sema.arena.alloc(Air.Inst.Ref, args_ty.structFieldCount());
21664 for (resolved_args, 0..) |*resolved, i| {
21665 resolved.* = try sema.tupleFieldValByIndex(block, args_src, args, @intCast(u32, i), args_ty);
2169521666 }
2169621667
2169721668 const callee_ty = sema.typeOf(func);
......@@ -21708,10 +21679,10 @@ fn zirBuiltinCall(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError
2170821679 }
2170921680 return sema.fail(block, func_src, "type '{}' not a function", .{callee_ty.fmt(sema.mod)});
2171021681 };
21711 try sema.checkCallArgumentCount(block, func, func_src, func_ty, resolved_args.len, bound_arg_src != null);
21682 try sema.checkCallArgumentCount(block, func, func_src, func_ty, resolved_args.len, false);
2171221683
2171321684 const ensure_result_used = extra.flags.ensure_result_used;
21714 return sema.analyzeCall(block, func, func_ty, func_src, call_src, modifier, ensure_result_used, resolved_args, bound_arg_src, null);
21685 return sema.analyzeCall(block, func, func_ty, func_src, call_src, modifier, ensure_result_used, resolved_args, null, null);
2171521686}
2171621687
2171721688fn zirFieldParentPtr(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air.Inst.Ref {
......@@ -24175,6 +24146,16 @@ fn fieldPtr(
2417524146 return sema.failWithInvalidFieldAccess(block, src, object_ty, field_name);
2417624147}
2417724148
24149const ResolvedFieldCallee = union(enum) {
24150 /// The LHS of the call was an actual field with this value.
24151 direct: Air.Inst.Ref,
24152 /// This is a method call, with the function and first argument given.
24153 method: struct {
24154 func_inst: Air.Inst.Ref,
24155 arg0_inst: Air.Inst.Ref,
24156 },
24157};
24158
2417824159fn fieldCallBind(
2417924160 sema: *Sema,
2418024161 block: *Block,
......@@ -24182,7 +24163,7 @@ fn fieldCallBind(
2418224163 raw_ptr: Air.Inst.Ref,
2418324164 field_name: []const u8,
2418424165 field_name_src: LazySrcLoc,
24185) CompileError!Air.Inst.Ref {
24166) CompileError!ResolvedFieldCallee {
2418624167 // When editing this function, note that there is corresponding logic to be edited
2418724168 // in `fieldVal`. This function takes a pointer and returns a pointer.
2418824169
......@@ -24202,7 +24183,6 @@ fn fieldCallBind(
2420224183 else
2420324184 raw_ptr;
2420424185
24205 const arena = sema.arena;
2420624186 find_field: {
2420724187 switch (concrete_ty.zigTypeTag()) {
2420824188 .Struct => {
......@@ -24216,7 +24196,7 @@ fn fieldCallBind(
2421624196 return sema.finishFieldCallBind(block, src, ptr_ty, field.ty, field_index, object_ptr);
2421724197 } else if (struct_ty.isTuple()) {
2421824198 if (mem.eql(u8, field_name, "len")) {
24219 return sema.addIntUnsigned(Type.usize, struct_ty.structFieldCount());
24199 return .{ .direct = try sema.addIntUnsigned(Type.usize, struct_ty.structFieldCount()) };
2422024200 }
2422124201 if (std.fmt.parseUnsigned(u32, field_name, 10)) |field_index| {
2422224202 if (field_index >= struct_ty.structFieldCount()) break :find_field;
......@@ -24243,7 +24223,7 @@ fn fieldCallBind(
2424324223 },
2424424224 .Type => {
2424524225 const namespace = try sema.analyzeLoad(block, src, object_ptr, src);
24246 return sema.fieldVal(block, src, namespace, field_name, field_name_src);
24226 return .{ .direct = try sema.fieldVal(block, src, namespace, field_name, field_name_src) };
2424724227 },
2424824228 else => {},
2424924229 }
......@@ -24272,54 +24252,47 @@ fn fieldCallBind(
2427224252 first_param_type.childType().eql(concrete_ty, sema.mod)))
2427324253 {
2427424254 // zig fmt: on
24255 // Note that if the param type is generic poison, we know that it must
24256 // specifically be `anytype` since it's the first parameter, meaning we
24257 // can safely assume it can be a pointer.
2427524258 // TODO: bound fn calls on rvalues should probably
2427624259 // generate a by-value argument somehow.
24277 const ty = Type.Tag.bound_fn.init();
24278 const value = try Value.Tag.bound_fn.create(arena, .{
24260 return .{ .method = .{
2427924261 .func_inst = decl_val,
2428024262 .arg0_inst = object_ptr,
24281 });
24282 return sema.addConstant(ty, value);
24263 } };
2428324264 } else if (first_param_type.eql(concrete_ty, sema.mod)) {
2428424265 const deref = try sema.analyzeLoad(block, src, object_ptr, src);
24285 const ty = Type.Tag.bound_fn.init();
24286 const value = try Value.Tag.bound_fn.create(arena, .{
24266 return .{ .method = .{
2428724267 .func_inst = decl_val,
2428824268 .arg0_inst = deref,
24289 });
24290 return sema.addConstant(ty, value);
24269 } };
2429124270 } else if (first_param_type.zigTypeTag() == .Optional) {
2429224271 var opt_buf: Type.Payload.ElemType = undefined;
2429324272 const child = first_param_type.optionalChild(&opt_buf);
2429424273 if (child.eql(concrete_ty, sema.mod)) {
2429524274 const deref = try sema.analyzeLoad(block, src, object_ptr, src);
24296 const ty = Type.Tag.bound_fn.init();
24297 const value = try Value.Tag.bound_fn.create(arena, .{
24275 return .{ .method = .{
2429824276 .func_inst = decl_val,
2429924277 .arg0_inst = deref,
24300 });
24301 return sema.addConstant(ty, value);
24278 } };
2430224279 } else if (child.zigTypeTag() == .Pointer and
2430324280 child.ptrSize() == .One and
2430424281 child.childType().eql(concrete_ty, sema.mod))
2430524282 {
24306 const ty = Type.Tag.bound_fn.init();
24307 const value = try Value.Tag.bound_fn.create(arena, .{
24283 return .{ .method = .{
2430824284 .func_inst = decl_val,
2430924285 .arg0_inst = object_ptr,
24310 });
24311 return sema.addConstant(ty, value);
24286 } };
2431224287 }
2431324288 } else if (first_param_type.zigTypeTag() == .ErrorUnion and
2431424289 first_param_type.errorUnionPayload().eql(concrete_ty, sema.mod))
2431524290 {
2431624291 const deref = try sema.analyzeLoad(block, src, object_ptr, src);
24317 const ty = Type.Tag.bound_fn.init();
24318 const value = try Value.Tag.bound_fn.create(arena, .{
24292 return .{ .method = .{
2431924293 .func_inst = decl_val,
2432024294 .arg0_inst = deref,
24321 });
24322 return sema.addConstant(ty, value);
24295 } };
2432324296 }
2432424297 }
2432524298 break :found_decl decl_idx;
......@@ -24351,7 +24324,7 @@ fn finishFieldCallBind(
2435124324 field_ty: Type,
2435224325 field_index: u32,
2435324326 object_ptr: Air.Inst.Ref,
24354) CompileError!Air.Inst.Ref {
24327) CompileError!ResolvedFieldCallee {
2435524328 const arena = sema.arena;
2435624329 const ptr_field_ty = try Type.ptr(arena, sema.mod, .{
2435724330 .pointee_type = field_ty,
......@@ -24362,7 +24335,7 @@ fn finishFieldCallBind(
2436224335 const container_ty = ptr_ty.childType();
2436324336 if (container_ty.zigTypeTag() == .Struct) {
2436424337 if (container_ty.structFieldValueComptime(field_index)) |default_val| {
24365 return sema.addConstant(field_ty, default_val);
24338 return .{ .direct = try sema.addConstant(field_ty, default_val) };
2436624339 }
2436724340 }
2436824341
......@@ -24375,12 +24348,12 @@ fn finishFieldCallBind(
2437524348 .field_index = field_index,
2437624349 }),
2437724350 );
24378 return sema.analyzeLoad(block, src, pointer, src);
24351 return .{ .direct = try sema.analyzeLoad(block, src, pointer, src) };
2437924352 }
2438024353
2438124354 try sema.requireRuntimeBlock(block, src, null);
2438224355 const ptr_inst = try block.addStructFieldPtr(object_ptr, field_index, ptr_field_ty);
24383 return sema.analyzeLoad(block, src, ptr_inst, src);
24356 return .{ .direct = try sema.analyzeLoad(block, src, ptr_inst, src) };
2438424357}
2438524358
2438624359fn namespaceLookup(
......@@ -31281,7 +31254,6 @@ pub fn resolveTypeRequiresComptime(sema: *Sema, ty: Type) CompileError!bool {
3128131254
3128231255 .inferred_alloc_mut => unreachable,
3128331256 .inferred_alloc_const => unreachable,
31284 .bound_fn => unreachable,
3128531257
3128631258 .array,
3128731259 .array_sentinel,
......@@ -32666,7 +32638,6 @@ pub fn typeHasOnePossibleValue(sema: *Sema, ty: Type) CompileError!?Value {
3266632638 .single_const_pointer,
3266732639 .single_mut_pointer,
3266832640 .pointer,
32669 .bound_fn,
3267032641 => return null,
3267132642
3267232643 .optional => {
......@@ -33308,7 +33279,6 @@ pub fn typeRequiresComptime(sema: *Sema, ty: Type) CompileError!bool {
3330833279
3330933280 .inferred_alloc_mut => unreachable,
3331033281 .inferred_alloc_const => unreachable,
33311 .bound_fn => unreachable,
3331233282
3331333283 .array,
3331433284 .array_sentinel,
src/TypedValue.zig-4
......@@ -499,10 +499,6 @@ pub fn print(
499499 // TODO these should not appear in this function
500500 .inferred_alloc => return writer.writeAll("(inferred allocation value)"),
501501 .inferred_alloc_comptime => return writer.writeAll("(inferred comptime allocation value)"),
502 .bound_fn => {
503 const bound_func = val.castTag(.bound_fn).?.data;
504 return writer.print("(bound_fn %{}(%{})", .{ bound_func.func_inst, bound_func.arg0_inst });
505 },
506502 .generic_poison_type => return writer.writeAll("(generic poison type)"),
507503 .generic_poison => return writer.writeAll("(generic poison)"),
508504 .runtime_value => return writer.writeAll("[runtime value]"),
src/Zir.zig+24-28
......@@ -297,6 +297,14 @@ pub const Inst = struct {
297297 /// Uses the `pl_node` union field with payload `Call`.
298298 /// AST node is the function call.
299299 call,
300 /// Function call using `a.b()` syntax.
301 /// Uses the named field as the callee. If there is no such field, searches in the type for
302 /// a decl matching the field name. The decl is resolved and we ensure that it's a function
303 /// which can accept the object as the first parameter, with one pointer fixup. This
304 /// function is then used as the callee, with the object as an implicit first parameter.
305 /// Uses the `pl_node` union field with payload `FieldCall`.
306 /// AST node is the function call.
307 field_call,
300308 /// Implements the `@call` builtin.
301309 /// Uses the `pl_node` union field with payload `BuiltinCall`.
302310 /// AST node is the builtin call.
......@@ -432,15 +440,6 @@ pub const Inst = struct {
432440 /// This instruction also accepts a pointer.
433441 /// Uses `pl_node` field. The AST node is the a.b syntax. Payload is Field.
434442 field_val,
435 /// Given a pointer to a struct or object that contains virtual fields, returns the
436 /// named field. If there is no named field, searches in the type for a decl that
437 /// matches the field name. The decl is resolved and we ensure that it's a function
438 /// which can accept the object as the first parameter, with one pointer fixup. If
439 /// all of that works, this instruction produces a special "bound function" value
440 /// which contains both the function and the saved first parameter value.
441 /// Bound functions may only be used as the function parameter to a `call` or
442 /// `builtin_call` instruction. Any other use is invalid zir and may crash the compiler.
443 field_call_bind,
444443 /// Given a pointer to a struct or object that contains virtual fields, returns a pointer
445444 /// to the named field. The field name is a comptime instruction. Used by @field.
446445 /// Uses `pl_node` field. The AST node is the builtin call. Payload is FieldNamed.
......@@ -1051,6 +1050,7 @@ pub const Inst = struct {
10511050 .bool_br_or,
10521051 .bool_not,
10531052 .call,
1053 .field_call,
10541054 .cmp_lt,
10551055 .cmp_lte,
10561056 .cmp_eq,
......@@ -1083,7 +1083,6 @@ pub const Inst = struct {
10831083 .field_ptr,
10841084 .field_ptr_init,
10851085 .field_val,
1086 .field_call_bind,
10871086 .field_ptr_named,
10881087 .field_val_named,
10891088 .func,
......@@ -1361,6 +1360,7 @@ pub const Inst = struct {
13611360 .bool_br_or,
13621361 .bool_not,
13631362 .call,
1363 .field_call,
13641364 .cmp_lt,
13651365 .cmp_lte,
13661366 .cmp_eq,
......@@ -1383,7 +1383,6 @@ pub const Inst = struct {
13831383 .field_ptr,
13841384 .field_ptr_init,
13851385 .field_val,
1386 .field_call_bind,
13871386 .field_ptr_named,
13881387 .field_val_named,
13891388 .func,
......@@ -1601,6 +1600,7 @@ pub const Inst = struct {
16011600 .check_comptime_control_flow = .un_node,
16021601 .for_len = .pl_node,
16031602 .call = .pl_node,
1603 .field_call = .pl_node,
16041604 .cmp_lt = .pl_node,
16051605 .cmp_lte = .pl_node,
16061606 .cmp_eq = .pl_node,
......@@ -1641,7 +1641,6 @@ pub const Inst = struct {
16411641 .field_val = .pl_node,
16421642 .field_ptr_named = .pl_node,
16431643 .field_val_named = .pl_node,
1644 .field_call_bind = .pl_node,
16451644 .func = .pl_node,
16461645 .func_inferred = .pl_node,
16471646 .func_fancy = .pl_node,
......@@ -1955,16 +1954,6 @@ pub const Inst = struct {
19551954 /// The `@prefetch` builtin.
19561955 /// `operand` is payload index to `BinNode`.
19571956 prefetch,
1958 /// Given a pointer to a struct or object that contains virtual fields, returns the
1959 /// named field. If there is no named field, searches in the type for a decl that
1960 /// matches the field name. The decl is resolved and we ensure that it's a function
1961 /// which can accept the object as the first parameter, with one pointer fixup. If
1962 /// all of that works, this instruction produces a special "bound function" value
1963 /// which contains both the function and the saved first parameter value.
1964 /// Bound functions may only be used as the function parameter to a `call` or
1965 /// `builtin_call` instruction. Any other use is invalid zir and may crash the compiler.
1966 /// Uses `pl_node` field. The AST node is the `@field` builtin. Payload is FieldNamedNode.
1967 field_call_bind_named,
19681957 /// Implements the `@fence` builtin.
19691958 /// `operand` is payload index to `UnNode`.
19701959 fence,
......@@ -2913,6 +2902,19 @@ pub const Inst = struct {
29132902 };
29142903 };
29152904
2905 /// Stored inside extra, with trailing arguments according to `args_len`.
2906 /// Implicit 0. arg_0_start: u32, // always same as `args_len`
2907 /// 1. arg_end: u32, // for each `args_len`
2908 /// arg_N_start is the same as arg_N-1_end
2909 pub const FieldCall = struct {
2910 // Note: Flags *must* come first so that unusedResultExpr
2911 // can find it when it goes to modify them.
2912 flags: Call.Flags,
2913 obj_ptr: Ref,
2914 /// Offset into `string_bytes`.
2915 field_name_start: u32,
2916 };
2917
29162918 pub const TypeOfPeer = struct {
29172919 src_node: i32,
29182920 body_len: u32,
......@@ -3187,12 +3189,6 @@ pub const Inst = struct {
31873189 field_name: Ref,
31883190 };
31893191
3190 pub const FieldNamedNode = struct {
3191 node: i32,
3192 lhs: Ref,
3193 field_name: Ref,
3194 };
3195
31963192 pub const As = struct {
31973193 dest_type: Ref,
31983194 operand: Ref,
src/print_air.zig-1
......@@ -369,7 +369,6 @@ const Writer = struct {
369369 .inferred_alloc_const => try s.writeAll("(inferred_alloc_const)"),
370370 .inferred_alloc_mut => try s.writeAll("(inferred_alloc_mut)"),
371371 .generic_poison => try s.writeAll("(generic_poison)"),
372 .bound_fn => try s.writeAll("(bound_fn)"),
373372 else => try ty.print(s, w.module),
374373 }
375374 }
src/print_zir.zig+21-14
......@@ -362,7 +362,8 @@ const Writer = struct {
362362 .@"export" => try self.writePlNodeExport(stream, inst),
363363 .export_value => try self.writePlNodeExportValue(stream, inst),
364364
365 .call => try self.writeCall(stream, inst),
365 .call => try self.writeCall(stream, inst, .direct),
366 .field_call => try self.writeCall(stream, inst, .field),
366367
367368 .block,
368369 .block_comptime,
......@@ -392,7 +393,6 @@ const Writer = struct {
392393 .field_ptr,
393394 .field_ptr_init,
394395 .field_val,
395 .field_call_bind,
396396 => try self.writePlNodeField(stream, inst),
397397
398398 .field_ptr_named,
......@@ -543,15 +543,6 @@ const Writer = struct {
543543 try self.writeSrc(stream, src);
544544 },
545545
546 .field_call_bind_named => {
547 const extra = self.code.extraData(Zir.Inst.FieldNamedNode, extended.operand).data;
548 const src = LazySrcLoc.nodeOffset(extra.node);
549 try self.writeInstRef(stream, extra.lhs);
550 try stream.writeAll(", ");
551 try self.writeInstRef(stream, extra.field_name);
552 try stream.writeAll(") ");
553 try self.writeSrc(stream, src);
554 },
555546 .builtin_async_call => try self.writeBuiltinAsyncCall(stream, extended),
556547 .cmpxchg => try self.writeCmpxchg(stream, extended),
557548 }
......@@ -1176,9 +1167,18 @@ const Writer = struct {
11761167 try self.writeSrc(stream, src);
11771168 }
11781169
1179 fn writeCall(self: *Writer, stream: anytype, inst: Zir.Inst.Index) !void {
1170 fn writeCall(
1171 self: *Writer,
1172 stream: anytype,
1173 inst: Zir.Inst.Index,
1174 comptime kind: enum { direct, field },
1175 ) !void {
11801176 const inst_data = self.code.instructions.items(.data)[inst].pl_node;
1181 const extra = self.code.extraData(Zir.Inst.Call, inst_data.payload_index);
1177 const ExtraType = switch (kind) {
1178 .direct => Zir.Inst.Call,
1179 .field => Zir.Inst.FieldCall,
1180 };
1181 const extra = self.code.extraData(ExtraType, inst_data.payload_index);
11821182 const args_len = extra.data.flags.args_len;
11831183 const body = self.code.extra[extra.end..];
11841184
......@@ -1186,7 +1186,14 @@ const Writer = struct {
11861186 try stream.writeAll("nodiscard ");
11871187 }
11881188 try stream.print(".{s}, ", .{@tagName(@intToEnum(std.builtin.CallModifier, extra.data.flags.packed_modifier))});
1189 try self.writeInstRef(stream, extra.data.callee);
1189 switch (kind) {
1190 .direct => try self.writeInstRef(stream, extra.data.callee),
1191 .field => {
1192 const field_name = self.code.nullTerminatedString(extra.data.field_name_start);
1193 try self.writeInstRef(stream, extra.data.obj_ptr);
1194 try stream.print(", {}", .{std.zig.fmtId(field_name)});
1195 },
1196 }
11901197 try stream.writeAll(", [");
11911198
11921199 self.indent += 2;
src/type.zig+1-17
......@@ -156,8 +156,6 @@ pub const Type = extern union {
156156 .union_tagged,
157157 .type_info,
158158 => return .Union,
159
160 .bound_fn => unreachable,
161159 }
162160 }
163161
......@@ -933,7 +931,6 @@ pub const Type = extern union {
933931 // for example, a was resolved into .union_tagged but b was one of these tags.
934932 .type_info => unreachable, // needed to resolve the type before now
935933
936 .bound_fn => unreachable,
937934 }
938935 }
939936
......@@ -1242,7 +1239,6 @@ pub const Type = extern union {
12421239 // we can't hash these based on tags because they wouldn't match the expanded version.
12431240 .type_info => unreachable, // needed to resolve the type before now
12441241
1245 .bound_fn => unreachable,
12461242 }
12471243 }
12481244
......@@ -1349,7 +1345,6 @@ pub const Type = extern union {
13491345 .type_info,
13501346 .@"anyframe",
13511347 .generic_poison,
1352 .bound_fn,
13531348 => unreachable,
13541349
13551350 .array_u8,
......@@ -1613,7 +1608,6 @@ pub const Type = extern union {
16131608 .comptime_int,
16141609 .comptime_float,
16151610 .noreturn,
1616 .bound_fn,
16171611 => return writer.writeAll(@tagName(t)),
16181612
16191613 .enum_literal => return writer.writeAll("@Type(.EnumLiteral)"),
......@@ -1949,7 +1943,6 @@ pub const Type = extern union {
19491943 .inferred_alloc_const => unreachable,
19501944 .inferred_alloc_mut => unreachable,
19511945 .generic_poison => unreachable,
1952 .bound_fn => unreachable,
19531946
19541947 // TODO get rid of these Type.Tag values.
19551948 .atomic_order => unreachable,
......@@ -2468,7 +2461,6 @@ pub const Type = extern union {
24682461 .enum_literal,
24692462 .empty_struct,
24702463 .empty_struct_literal,
2471 .bound_fn,
24722464 // These are function *bodies*, not pointers.
24732465 // Special exceptions have to be made when emitting functions due to
24742466 // this returning false.
......@@ -2703,7 +2695,6 @@ pub const Type = extern union {
27032695
27042696 .inferred_alloc_mut => unreachable,
27052697 .inferred_alloc_const => unreachable,
2706 .bound_fn => unreachable,
27072698
27082699 .array,
27092700 .array_sentinel,
......@@ -3182,7 +3173,6 @@ pub const Type = extern union {
31823173 .noreturn,
31833174 .inferred_alloc_const,
31843175 .inferred_alloc_mut,
3185 .bound_fn,
31863176 => unreachable,
31873177
31883178 .generic_poison => unreachable,
......@@ -3282,7 +3272,6 @@ pub const Type = extern union {
32823272 .fn_ccc_void_no_args => unreachable, // represents machine code; not a pointer
32833273 .function => unreachable, // represents machine code; not a pointer
32843274 .@"opaque" => unreachable, // no size available
3285 .bound_fn => unreachable,
32863275 .noreturn => unreachable,
32873276 .inferred_alloc_const => unreachable,
32883277 .inferred_alloc_mut => unreachable,
......@@ -3630,7 +3619,6 @@ pub const Type = extern union {
36303619 .inferred_alloc_mut => unreachable,
36313620 .@"opaque" => unreachable,
36323621 .generic_poison => unreachable,
3633 .bound_fn => unreachable,
36343622
36353623 .void => return 0,
36363624 .bool, .u1 => return 1,
......@@ -5042,7 +5030,6 @@ pub const Type = extern union {
50425030 .single_const_pointer,
50435031 .single_mut_pointer,
50445032 .pointer,
5045 .bound_fn,
50465033 => return null,
50475034
50485035 .optional => {
......@@ -5245,7 +5232,6 @@ pub const Type = extern union {
52455232
52465233 .inferred_alloc_mut => unreachable,
52475234 .inferred_alloc_const => unreachable,
5248 .bound_fn => unreachable,
52495235
52505236 .array,
52515237 .array_sentinel,
......@@ -6081,7 +6067,6 @@ pub const Type = extern union {
60816067 inferred_alloc_mut,
60826068 /// Same as `inferred_alloc_mut` but the local is `var` not `const`.
60836069 inferred_alloc_const, // See last_no_payload_tag below.
6084 bound_fn,
60856070 // After this, the tag requires a payload.
60866071
60876072 array_u8,
......@@ -6126,7 +6111,7 @@ pub const Type = extern union {
61266111 enum_full,
61276112 enum_nonexhaustive,
61286113
6129 pub const last_no_payload_tag = Tag.bound_fn;
6114 pub const last_no_payload_tag = Tag.inferred_alloc_const;
61306115 pub const no_payload_count = @enumToInt(last_no_payload_tag) + 1;
61316116
61326117 pub fn Type(comptime t: Tag) type {
......@@ -6199,7 +6184,6 @@ pub const Type = extern union {
61996184 .extern_options,
62006185 .type_info,
62016186 .@"anyframe",
6202 .bound_fn,
62036187 => @compileError("Type Tag " ++ @tagName(t) ++ " has no payload"),
62046188
62056189 .array_u8,
src/value.zig-20
......@@ -183,10 +183,6 @@ pub const Value = extern union {
183183 /// Used to coordinate alloc_inferred, store_to_inferred_ptr, and resolve_inferred_alloc
184184 /// instructions for comptime code.
185185 inferred_alloc_comptime,
186 /// Used sometimes as the result of field_call_bind. This value is always temporary,
187 /// and refers directly to the air. It will never be referenced by the air itself.
188 /// TODO: This is probably a bad encoding, maybe put temp data in the sema instead.
189 bound_fn,
190186 /// The ABI alignment of the payload type.
191187 lazy_align,
192188 /// The ABI size of the payload type.
......@@ -326,7 +322,6 @@ pub const Value = extern union {
326322 .inferred_alloc_comptime => Payload.InferredAllocComptime,
327323 .aggregate => Payload.Aggregate,
328324 .@"union" => Payload.Union,
329 .bound_fn => Payload.BoundFn,
330325 .comptime_field_ptr => Payload.ComptimeFieldPtr,
331326 };
332327 }
......@@ -477,7 +472,6 @@ pub const Value = extern union {
477472 .extern_options_type,
478473 .type_info_type,
479474 .generic_poison,
480 .bound_fn,
481475 => unreachable,
482476
483477 .ty, .lazy_align, .lazy_size => {
......@@ -837,10 +831,6 @@ pub const Value = extern union {
837831 try out_stream.writeAll("(opt_payload_ptr)");
838832 val = val.castTag(.opt_payload_ptr).?.data.container_ptr;
839833 },
840 .bound_fn => {
841 const bound_func = val.castTag(.bound_fn).?.data;
842 return out_stream.print("(bound_fn %{}(%{})", .{ bound_func.func_inst, bound_func.arg0_inst });
843 },
844834 };
845835 }
846836
......@@ -5657,16 +5647,6 @@ pub const Value = extern union {
56575647 val: Value,
56585648 },
56595649 };
5660
5661 pub const BoundFn = struct {
5662 pub const base_tag = Tag.bound_fn;
5663
5664 base: Payload = Payload{ .tag = base_tag },
5665 data: struct {
5666 func_inst: Air.Inst.Ref,
5667 arg0_inst: Air.Inst.Ref,
5668 },
5669 };
56705650 };
56715651
56725652 /// Big enough to fit any non-BigInt value
test/behavior/member_func.zig-12
......@@ -86,18 +86,6 @@ test "@field field calls" {
8686 const pv = &v;
8787 const pcv: *const HasFuncs = pv;
8888
89 try expect(@field(v, "get")() == 0);
90 @field(v, "inc")();
91 try expect(v.state == 1);
92 try expect(@field(v, "get")() == 1);
93
94 @field(pv, "inc")();
95 try expect(v.state == 2);
96 try expect(@field(pv, "get")() == 2);
97 try expect(@field(v, "getPtr")().* == 2);
98 try expect(@field(pcv, "get")() == 2);
99 try expect(@field(pcv, "getPtr")().* == 2);
100
10189 v.func_field = HasFuncs.one;
10290 try expect(@field(v, "func_field")(0) == 1);
10391 try expect(@field(pv, "func_field")(0) == 1);
test/cases/compile_errors/member_function_arg_mismatch.zig-6
......@@ -6,10 +6,6 @@ pub export fn entry() void {
66 var s: S = undefined;
77 s.foo(true);
88}
9pub export fn entry2() void {
10 var s: S = undefined;
11 @call(.auto, s.foo, .{true});
12}
139
1410// error
1511// backend=stage2
......@@ -17,5 +13,3 @@ pub export fn entry2() void {
1713//
1814// :7:6: error: member function expected 2 argument(s), found 1
1915// :3:5: note: function declared here
20// :11:19: error: member function expected 2 argument(s), found 1
21// :3:5: note: function declared here