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 {...@@ -169,7 +169,7 @@ const FutexImpl = struct {
169 }169 }
170 }170 }
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 {
173 // On x86, use `lock bts` instead of `lock cmpxchg` as:173 // On x86, use `lock bts` instead of `lock cmpxchg` as:
174 // - they both seem to mark the cache-line as modified regardless: https://stackoverflow.com/a/63350048174 // - they both seem to mark the cache-line as modified regardless: https://stackoverflow.com/a/63350048
175 // - `lock bts` is smaller instruction-wise which makes it better for inlining175 // - `lock bts` is smaller instruction-wise which makes it better for inlining
...@@ -180,7 +180,8 @@ const FutexImpl = struct {...@@ -180,7 +180,8 @@ const FutexImpl = struct {
180180
181 // Acquire barrier ensures grabbing the lock happens before the critical section181 // Acquire barrier ensures grabbing the lock happens before the critical section
182 // and that the previous lock holder's critical section happens before we grab the lock.182 // 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;
184 }185 }
185186
186 fn lockSlow(self: *@This()) void {187 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...@@ -167,8 +167,8 @@ fn SipHashStateless(comptime T: type, comptime c_rounds: usize, comptime d_round
167 pub fn hash(msg: []const u8, key: *const [key_length]u8) T {167 pub fn hash(msg: []const u8, key: *const [key_length]u8) T {
168 const aligned_len = msg.len - (msg.len % 8);168 const aligned_len = msg.len - (msg.len % 8);
169 var c = Self.init(key);169 var c = Self.init(key);
170 @call(.always_inline, c.update, .{msg[0..aligned_len]});170 @call(.always_inline, update, .{ &c, msg[0..aligned_len] });
171 return @call(.always_inline, c.final, .{msg[aligned_len..]});171 return @call(.always_inline, final, .{ &c, msg[aligned_len..] });
172 }172 }
173 };173 };
174}174}
lib/std/hash/auto_hash.zig+7-3
...@@ -64,9 +64,13 @@ pub fn hashArray(hasher: anytype, key: anytype, comptime strat: HashStrategy) vo...@@ -64,9 +64,13 @@ pub fn hashArray(hasher: anytype, key: anytype, comptime strat: HashStrategy) vo
64/// Strategy is provided to determine if pointers should be followed or not.64/// Strategy is provided to determine if pointers should be followed or not.
65pub fn hash(hasher: anytype, key: anytype, comptime strat: HashStrategy) void {65pub fn hash(hasher: anytype, key: anytype, comptime strat: HashStrategy) void {
66 const Key = @TypeOf(key);66 const Key = @TypeOf(key);
67 const Hasher = switch (@typeInfo(@TypeOf(hasher))) {
68 .Pointer => |ptr| ptr.child,
69 else => @TypeOf(hasher),
70 };
6771
68 if (strat == .Shallow and comptime meta.trait.hasUniqueRepresentation(Key)) {72 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) });
70 return;74 return;
71 }75 }
7276
...@@ -89,12 +93,12 @@ pub fn hash(hasher: anytype, key: anytype, comptime strat: HashStrategy) void {...@@ -89,12 +93,12 @@ pub fn hash(hasher: anytype, key: anytype, comptime strat: HashStrategy) void {
89 // TODO Check if the situation is better after #561 is resolved.93 // TODO Check if the situation is better after #561 is resolved.
90 .Int => {94 .Int => {
91 if (comptime meta.trait.hasUniqueRepresentation(Key)) {95 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) });
93 } else {97 } else {
94 // Take only the part containing the key value, the remaining98 // Take only the part containing the key value, the remaining
95 // bytes are undefined and must not be hashed!99 // bytes are undefined and must not be hashed!
96 const byte_size = comptime std.math.divCeil(comptime_int, @bitSizeOf(Key), 8) catch unreachable;100 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] });
98 }102 }
99 },103 },
100104
lib/std/hash/wyhash.zig+3-3
...@@ -65,7 +65,7 @@ const WyhashStateless = struct {...@@ -65,7 +65,7 @@ const WyhashStateless = struct {
6565
66 var off: usize = 0;66 var off: usize = 0;
67 while (off < b.len) : (off += 32) {67 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] });
69 }69 }
7070
71 self.msg_len += b.len;71 self.msg_len += b.len;
...@@ -121,8 +121,8 @@ const WyhashStateless = struct {...@@ -121,8 +121,8 @@ const WyhashStateless = struct {
121 const aligned_len = input.len - (input.len % 32);121 const aligned_len = input.len - (input.len % 32);
122122
123 var c = WyhashStateless.init(seed);123 var c = WyhashStateless.init(seed);
124 @call(.always_inline, c.update, .{input[0..aligned_len]});124 @call(.always_inline, update, .{ &c, input[0..aligned_len] });
125 return @call(.always_inline, c.final, .{input[aligned_len..]});125 return @call(.always_inline, final, .{ &c, input[aligned_len..] });
126 }126 }
127};127};
128128
src/AstGen.zig+80-69
...@@ -2482,7 +2482,7 @@ fn addEnsureResult(gz: *GenZir, maybe_unused_result: Zir.Inst.Ref, statement: As...@@ -2482,7 +2482,7 @@ fn addEnsureResult(gz: *GenZir, maybe_unused_result: Zir.Inst.Ref, statement: As
2482 switch (zir_tags[inst]) {2482 switch (zir_tags[inst]) {
2483 // For some instructions, modify the zir data2483 // For some instructions, modify the zir data
2484 // so we can avoid a separate ensure_result_used instruction.2484 // so we can avoid a separate ensure_result_used instruction.
2485 .call => {2485 .call, .field_call => {
2486 const extra_index = gz.astgen.instructions.items(.data)[inst].pl_node.payload_index;2486 const extra_index = gz.astgen.instructions.items(.data)[inst].pl_node.payload_index;
2487 const slot = &gz.astgen.extra.items[extra_index];2487 const slot = &gz.astgen.extra.items[extra_index];
2488 var flags = @bitCast(Zir.Inst.Call.Flags, slot.*);2488 var flags = @bitCast(Zir.Inst.Call.Flags, slot.*);
...@@ -2557,7 +2557,6 @@ fn addEnsureResult(gz: *GenZir, maybe_unused_result: Zir.Inst.Ref, statement: As...@@ -2557,7 +2557,6 @@ fn addEnsureResult(gz: *GenZir, maybe_unused_result: Zir.Inst.Ref, statement: As
2557 .field_ptr,2557 .field_ptr,
2558 .field_ptr_init,2558 .field_ptr_init,
2559 .field_val,2559 .field_val,
2560 .field_call_bind,
2561 .field_ptr_named,2560 .field_ptr_named,
2562 .field_val_named,2561 .field_val_named,
2563 .func,2562 .func,
...@@ -8516,7 +8515,7 @@ fn builtinCall(...@@ -8516,7 +8515,7 @@ fn builtinCall(
8516 },8515 },
8517 .call => {8516 .call => {
8518 const modifier = try comptimeExpr(gz, scope, .{ .rl = .{ .coerced_ty = .modifier_type } }, params[0]);8517 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]);
8520 const args = try expr(gz, scope, .{ .rl = .none }, params[2]);8519 const args = try expr(gz, scope, .{ .rl = .none }, params[2]);
8521 const result = try gz.addPlNode(.builtin_call, node, Zir.Inst.BuiltinCall{8520 const result = try gz.addPlNode(.builtin_call, node, Zir.Inst.BuiltinCall{
8522 .modifier = modifier,8521 .modifier = modifier,
...@@ -8976,7 +8975,10 @@ fn callExpr(...@@ -8976,7 +8975,10 @@ fn callExpr(
8976 } });8975 } });
8977 }8976 }
89788977
8979 assert(callee != .none);8978 switch (callee) {
8979 .direct => |obj| assert(obj != .none),
8980 .field => |field| assert(field.obj_ptr != .none),
8981 }
8980 assert(node != 0);8982 assert(node != 0);
89818983
8982 const call_index = @intCast(Zir.Inst.Index, astgen.instructions.len);8984 const call_index = @intCast(Zir.Inst.Index, astgen.instructions.len);
...@@ -9015,89 +9017,98 @@ fn callExpr(...@@ -9015,89 +9017,98 @@ fn callExpr(
9015 else => false,9017 else => false,
9016 };9018 };
90179019
9018 const payload_index = try addExtra(astgen, Zir.Inst.Call{9020 switch (callee) {
9019 .callee = callee,9021 .direct => |callee_obj| {
9020 .flags = .{9022 const payload_index = try addExtra(astgen, Zir.Inst.Call{
9021 .pop_error_return_trace = !propagate_error_trace,9023 .callee = callee_obj,
9022 .packed_modifier = @intCast(Zir.Inst.Call.Flags.PackedModifier, @enumToInt(modifier)),9024 .flags = .{
9023 .args_len = @intCast(Zir.Inst.Call.Flags.PackedArgsLen, call.ast.params.len),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 });
9024 },9061 },
9025 });
9026 if (call.ast.params.len != 0) {
9027 try astgen.extra.appendSlice(astgen.gpa, astgen.scratch.items[scratch_top..]);
9028 }9062 }
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 });
9036 return rvalue(gz, ri, call_inst, node); // TODO function call with result location9063 return rvalue(gz, ri, call_inst, node); // TODO function call with result location
9037}9064}
90389065
9039/// calleeExpr generates the function part of a call expression (f in f(x)), or the9066const Callee = union(enum) {
9040/// callee argument to the @call() builtin. If the lhs is a field access or the9067 field: struct {
9041/// @field() builtin, we need to generate a special field_call_bind instruction9068 /// A *pointer* to the object the field is fetched on, so that we can
9042/// instead of the normal field_val or field_ptr. If this is a inst.func() call,9069 /// promote the lvalue to an address if the first parameter requires it.
9043/// this instruction will capture the value of the first argument before evaluating9070 obj_ptr: Zir.Inst.Ref,
9044/// the other arguments. We need to use .ref here to guarantee we will be able to9071 /// Offset into `string_bytes`.
9045/// promote an lvalue to an address if the first parameter requires it. This9072 field_name_start: u32,
9046/// unfortunately also means we need to take a reference to any types on the lhs.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.
9047fn calleeExpr(9082fn calleeExpr(
9048 gz: *GenZir,9083 gz: *GenZir,
9049 scope: *Scope,9084 scope: *Scope,
9050 node: Ast.Node.Index,9085 node: Ast.Node.Index,
9051) InnerError!Zir.Inst.Ref {9086) InnerError!Callee {
9052 const astgen = gz.astgen;9087 const astgen = gz.astgen;
9053 const tree = astgen.tree;9088 const tree = astgen.tree;
90549089
9055 const tag = tree.nodes.items(.tag)[node];9090 const tag = tree.nodes.items(.tag)[node];
9056 switch (tag) {9091 switch (tag) {
9057 .field_access => return addFieldAccess(.field_call_bind, gz, scope, .{ .rl = .ref }, node),9092 .field_access => {
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);
9065 const main_tokens = tree.nodes.items(.main_token);9093 const main_tokens = tree.nodes.items(.main_token);
9066 const builtin_token = main_tokens[node];9094 const node_datas = tree.nodes.items(.data);
9067 const builtin_name = tree.tokenSlice(builtin_token);9095 const object_node = node_datas[node].lhs;
90689096 const dot_token = main_tokens[node];
9069 var inline_params: [2]Ast.Node.Index = undefined;9097 const field_ident = dot_token + 1;
9070 var params: []Ast.Node.Index = switch (tag) {9098 const str_index = try astgen.identAsString(field_ident);
9071 .builtin_call,9099 // Capture the object by reference so we can promote it to an
9072 .builtin_call_comma,9100 // address in Sema if needed.
9073 => tree.extra_data[node_datas[node].lhs..node_datas[node].rhs],9101 const lhs = try expr(gz, scope, .{ .rl = .ref }, object_node);
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 };
90859102
9086 // If anything is wrong, fall back to builtinCall.9103 const cursor = maybeAdvanceSourceCursorToMainToken(gz, node);
9087 // It will emit any necessary compile errors and notes.9104 try emitDbgStmt(gz, cursor);
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 }
90979105
9098 return builtinCall(gz, scope, .{ .rl = .none }, node, params);9106 return .{ .field = .{
9107 .obj_ptr = lhs,
9108 .field_name_start = str_index,
9109 } };
9099 },9110 },
9100 else => return expr(gz, scope, .{ .rl = .none }, node),9111 else => return .{ .direct = try expr(gz, scope, .{ .rl = .none }, node) },
9101 }9112 }
9102}9113}
91039114
src/Autodoc.zig+2-3
...@@ -2141,7 +2141,7 @@ fn walkInstruction(...@@ -2141,7 +2141,7 @@ fn walkInstruction(
2141 .expr = .{ .declRef = decl_status },2141 .expr = .{ .declRef = decl_status },
2142 };2142 };
2143 },2143 },
2144 .field_val, .field_call_bind, .field_ptr, .field_type => {2144 .field_val, .field_ptr, .field_type => {
2145 // TODO: field type uses Zir.Inst.FieldType, it just happens to have the2145 // TODO: field type uses Zir.Inst.FieldType, it just happens to have the
2146 // same layout as Zir.Inst.Field :^)2146 // same layout as Zir.Inst.Field :^)
2147 const pl_node = data[inst_index].pl_node;2147 const pl_node = data[inst_index].pl_node;
...@@ -2163,7 +2163,6 @@ fn walkInstruction(...@@ -2163,7 +2163,6 @@ fn walkInstruction(
21632163
2164 const lhs = @enumToInt(lhs_extra.data.lhs) - Ref.typed_value_map.len;2164 const lhs = @enumToInt(lhs_extra.data.lhs) - Ref.typed_value_map.len;
2165 if (tags[lhs] != .field_val and2165 if (tags[lhs] != .field_val and
2166 tags[lhs] != .field_call_bind and
2167 tags[lhs] != .field_ptr and2166 tags[lhs] != .field_ptr and
2168 tags[lhs] != .field_type) break :blk lhs_extra.data.lhs;2167 tags[lhs] != .field_type) break :blk lhs_extra.data.lhs;
21692168
...@@ -2191,7 +2190,7 @@ fn walkInstruction(...@@ -2191,7 +2190,7 @@ fn walkInstruction(
2191 const wr = blk: {2190 const wr = blk: {
2192 if (@enumToInt(lhs_ref) >= Ref.typed_value_map.len) {2191 if (@enumToInt(lhs_ref) >= Ref.typed_value_map.len) {
2193 const lhs_inst = @enumToInt(lhs_ref) - Ref.typed_value_map.len;2192 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) {
2195 break :blk DocData.WalkResult{2194 break :blk DocData.WalkResult{
2196 .expr = .{2195 .expr = .{
2197 .comptimeExpr = 0,2196 .comptimeExpr = 0,
src/Module.zig+15-1
...@@ -2489,8 +2489,21 @@ pub const SrcLoc = struct {...@@ -2489,8 +2489,21 @@ pub const SrcLoc = struct {
2489 const node_datas = tree.nodes.items(.data);2489 const node_datas = tree.nodes.items(.data);
2490 const node_tags = tree.nodes.items(.tag);2490 const node_tags = tree.nodes.items(.tag);
2491 const node = src_loc.declRelativeToNodeIndex(node_off);2491 const node = src_loc.declRelativeToNodeIndex(node_off);
2492 var buf: [1]Ast.Node.Index = undefined;
2492 const tok_index = switch (node_tags[node]) {2493 const tok_index = switch (node_tags[node]) {
2493 .field_access => node_datas[node].rhs,2494 .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 },
2494 else => tree.firstToken(node) - 2,2507 else => tree.firstToken(node) - 2,
2495 };2508 };
2496 const start = tree.tokens.items(.start)[tok_index];2509 const start = tree.tokens.items(.start)[tok_index];
...@@ -3083,7 +3096,8 @@ pub const LazySrcLoc = union(enum) {...@@ -3083,7 +3096,8 @@ pub const LazySrcLoc = union(enum) {
3083 /// The payload is offset from the containing Decl AST node.3096 /// The payload is offset from the containing Decl AST node.
3084 /// The source location points to the field name of:3097 /// The source location points to the field name of:
3085 /// * a field access expression (`a.b`), or3098 /// * 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
3087 /// The Decl is determined contextually.3101 /// The Decl is determined contextually.
3088 node_offset_field_name: i32,3102 node_offset_field_name: i32,
3089 /// The source location points to the pointer of a pointer deref expression,3103 /// The source location points to the pointer of a pointer deref expression,
src/Sema.zig+73-103
...@@ -920,7 +920,8 @@ fn analyzeBodyInner(...@@ -920,7 +920,8 @@ fn analyzeBodyInner(
920 .bool_br_and => try sema.zirBoolBr(block, inst, false),920 .bool_br_and => try sema.zirBoolBr(block, inst, false),
921 .bool_br_or => try sema.zirBoolBr(block, inst, true),921 .bool_br_or => try sema.zirBoolBr(block, inst, true),
922 .c_import => try sema.zirCImport(block, inst),922 .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),
924 .closure_get => try sema.zirClosureGet(block, inst),925 .closure_get => try sema.zirClosureGet(block, inst),
925 .cmp_lt => try sema.zirCmp(block, inst, .lt),926 .cmp_lt => try sema.zirCmp(block, inst, .lt),
926 .cmp_lte => try sema.zirCmp(block, inst, .lte),927 .cmp_lte => try sema.zirCmp(block, inst, .lte),
...@@ -952,7 +953,6 @@ fn analyzeBodyInner(...@@ -952,7 +953,6 @@ fn analyzeBodyInner(
952 .field_ptr_named => try sema.zirFieldPtrNamed(block, inst),953 .field_ptr_named => try sema.zirFieldPtrNamed(block, inst),
953 .field_val => try sema.zirFieldVal(block, inst),954 .field_val => try sema.zirFieldVal(block, inst),
954 .field_val_named => try sema.zirFieldValNamed(block, inst),955 .field_val_named => try sema.zirFieldValNamed(block, inst),
955 .field_call_bind => try sema.zirFieldCallBind(block, inst),
956 .func => try sema.zirFunc(block, inst, false),956 .func => try sema.zirFunc(block, inst, false),
957 .func_inferred => try sema.zirFunc(block, inst, true),957 .func_inferred => try sema.zirFunc(block, inst, true),
958 .func_fancy => try sema.zirFuncFancy(block, inst),958 .func_fancy => try sema.zirFuncFancy(block, inst),
...@@ -1149,7 +1149,6 @@ fn analyzeBodyInner(...@@ -1149,7 +1149,6 @@ fn analyzeBodyInner(
1149 .wasm_memory_size => try sema.zirWasmMemorySize( block, extended),1149 .wasm_memory_size => try sema.zirWasmMemorySize( block, extended),
1150 .wasm_memory_grow => try sema.zirWasmMemoryGrow( block, extended),1150 .wasm_memory_grow => try sema.zirWasmMemoryGrow( block, extended),
1151 .prefetch => try sema.zirPrefetch( block, extended),1151 .prefetch => try sema.zirPrefetch( block, extended),
1152 .field_call_bind_named => try sema.zirFieldCallBindNamed(block, extended),
1153 .err_set_cast => try sema.zirErrSetCast( block, extended),1152 .err_set_cast => try sema.zirErrSetCast( block, extended),
1154 .await_nosuspend => try sema.zirAwaitNosuspend( block, extended),1153 .await_nosuspend => try sema.zirAwaitNosuspend( block, extended),
1155 .select => try sema.zirSelect( block, extended),1154 .select => try sema.zirSelect( block, extended),
...@@ -6262,38 +6261,50 @@ fn zirCall(...@@ -6262,38 +6261,50 @@ fn zirCall(
6262 sema: *Sema,6261 sema: *Sema,
6263 block: *Block,6262 block: *Block,
6264 inst: Zir.Inst.Index,6263 inst: Zir.Inst.Index,
6264 comptime kind: enum { direct, field },
6265) CompileError!Air.Inst.Ref {6265) CompileError!Air.Inst.Ref {
6266 const tracy = trace(@src());6266 const tracy = trace(@src());
6267 defer tracy.end();6267 defer tracy.end();
62686268
6269 const inst_data = sema.code.instructions.items(.data)[inst].pl_node;6269 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 };
6271 const call_src = inst_data.src();6271 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);
6273 const args_len = extra.data.flags.args_len;6277 const args_len = extra.data.flags.args_len;
62746278
6275 const modifier = @intToEnum(std.builtin.CallModifier, extra.data.flags.packed_modifier);6279 const modifier = @intToEnum(std.builtin.CallModifier, extra.data.flags.packed_modifier);
6276 const ensure_result_used = extra.data.flags.ensure_result_used;6280 const ensure_result_used = extra.data.flags.ensure_result_used;
6277 const pop_error_return_trace = extra.data.flags.pop_error_return_trace;6281 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 };
6280 var resolved_args: []Air.Inst.Ref = undefined;6292 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
6286 var bound_arg_src: ?LazySrcLoc = null;6293 var bound_arg_src: ?LazySrcLoc = null;
6287 if (func_type.tag() == .bound_fn) {6294 var func: Air.Inst.Ref = undefined;
6288 bound_arg_src = func_src;6295 var arg_index: u32 = 0;
6289 const bound_func = try sema.resolveValue(block, .unneeded, func, "");6296 switch (callee) {
6290 const bound_data = &bound_func.cast(Value.Payload.BoundFn).?.data;6297 .direct => |func_inst| {
6291 func = bound_data.func_inst;6298 resolved_args = try sema.arena.alloc(Air.Inst.Ref, args_len);
6292 resolved_args = try sema.arena.alloc(Air.Inst.Ref, args_len + 1);6299 func = func_inst;
6293 resolved_args[arg_index] = bound_data.arg0_inst;6300 },
6294 arg_index += 1;6301 .method => |method| {
6295 } else {6302 resolved_args = try sema.arena.alloc(Air.Inst.Ref, args_len + 1);
6296 resolved_args = try sema.arena.alloc(Air.Inst.Ref, args_len);6303 func = method.func_inst;
6304 resolved_args[0] = method.arg0_inst;
6305 arg_index += 1;
6306 bound_arg_src = callee_src;
6307 },
6297 }6308 }
62986309
6299 const callee_ty = sema.typeOf(func);6310 const callee_ty = sema.typeOf(func);
...@@ -6308,10 +6319,11 @@ fn zirCall(...@@ -6308,10 +6319,11 @@ fn zirCall(
6308 },6319 },
6309 else => {},6320 else => {},
6310 }6321 }
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)});
6312 };6323 };
6324
6313 const total_args = args_len + @boolToInt(bound_arg_src != null);6325 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
6316 const args_body = sema.code.extra[extra.end..];6328 const args_body = sema.code.extra[extra.end..];
63176329
...@@ -6369,7 +6381,7 @@ fn zirCall(...@@ -6369,7 +6381,7 @@ fn zirCall(
6369 !block.is_comptime and !block.is_typeof and (input_is_error or pop_error_return_trace))6381 !block.is_comptime and !block.is_typeof and (input_is_error or pop_error_return_trace))
6370 {6382 {
6371 const call_inst: Air.Inst.Ref = if (modifier == .always_tail) undefined else b: {6383 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);
6373 };6385 };
63746386
6375 const return_ty = sema.typeOf(call_inst);6387 const return_ty = sema.typeOf(call_inst);
...@@ -6398,11 +6410,11 @@ fn zirCall(...@@ -6398,11 +6410,11 @@ fn zirCall(
6398 }6410 }
63996411
6400 if (modifier == .always_tail) // Perform the call *after* the restore, so that a tail call is possible.6412 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
6403 return call_inst;6415 return call_inst;
6404 } else {6416 } 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);
6406 }6418 }
6407}6419}
64086420
...@@ -9467,19 +9479,6 @@ fn zirFieldPtr(sema: *Sema, block: *Block, inst: Zir.Inst.Index, initializing: b...@@ -9467,19 +9479,6 @@ fn zirFieldPtr(sema: *Sema, block: *Block, inst: Zir.Inst.Index, initializing: b
9467 return sema.fieldPtr(block, src, object_ptr, field_name, field_name_src, initializing);9479 return sema.fieldPtr(block, src, object_ptr, field_name, field_name_src, initializing);
9468}9480}
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
9483fn zirFieldValNamed(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air.Inst.Ref {9482fn zirFieldValNamed(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air.Inst.Ref {
9484 const tracy = trace(@src());9483 const tracy = trace(@src());
9485 defer tracy.end();9484 defer tracy.end();
...@@ -9506,18 +9505,6 @@ fn zirFieldPtrNamed(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileErr...@@ -9506,18 +9505,6 @@ fn zirFieldPtrNamed(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileErr
9506 return sema.fieldPtr(block, src, object_ptr, field_name, field_name_src, false);9505 return sema.fieldPtr(block, src, object_ptr, field_name, field_name_src, false);
9507}9506}
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
9521fn zirIntCast(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air.Inst.Ref {9508fn zirIntCast(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air.Inst.Ref {
9522 const tracy = trace(@src());9509 const tracy = trace(@src());
9523 defer tracy.end();9510 defer tracy.end();
...@@ -21673,25 +21660,9 @@ fn zirBuiltinCall(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError...@@ -21673,25 +21660,9 @@ fn zirBuiltinCall(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError
21673 return sema.fail(block, args_src, "expected a tuple, found '{}'", .{args_ty.fmt(sema.mod)});21660 return sema.fail(block, args_src, "expected a tuple, found '{}'", .{args_ty.fmt(sema.mod)});
21674 }21661 }
2167521662
21676 var resolved_args: []Air.Inst.Ref = undefined;21663 var resolved_args: []Air.Inst.Ref = try sema.arena.alloc(Air.Inst.Ref, args_ty.structFieldCount());
2167721664 for (resolved_args, 0..) |*resolved, i| {
21678 // Desugar bound functions here21665 resolved.* = try sema.tupleFieldValByIndex(block, args_src, args, @intCast(u32, i), args_ty);
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 }
21695 }21666 }
2169621667
21697 const callee_ty = sema.typeOf(func);21668 const callee_ty = sema.typeOf(func);
...@@ -21708,10 +21679,10 @@ fn zirBuiltinCall(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError...@@ -21708,10 +21679,10 @@ fn zirBuiltinCall(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError
21708 }21679 }
21709 return sema.fail(block, func_src, "type '{}' not a function", .{callee_ty.fmt(sema.mod)});21680 return sema.fail(block, func_src, "type '{}' not a function", .{callee_ty.fmt(sema.mod)});
21710 };21681 };
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
21713 const ensure_result_used = extra.flags.ensure_result_used;21684 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);
21715}21686}
2171621687
21717fn zirFieldParentPtr(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air.Inst.Ref {21688fn zirFieldParentPtr(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air.Inst.Ref {
...@@ -24175,6 +24146,16 @@ fn fieldPtr(...@@ -24175,6 +24146,16 @@ fn fieldPtr(
24175 return sema.failWithInvalidFieldAccess(block, src, object_ty, field_name);24146 return sema.failWithInvalidFieldAccess(block, src, object_ty, field_name);
24176}24147}
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
24178fn fieldCallBind(24159fn fieldCallBind(
24179 sema: *Sema,24160 sema: *Sema,
24180 block: *Block,24161 block: *Block,
...@@ -24182,7 +24163,7 @@ fn fieldCallBind(...@@ -24182,7 +24163,7 @@ fn fieldCallBind(
24182 raw_ptr: Air.Inst.Ref,24163 raw_ptr: Air.Inst.Ref,
24183 field_name: []const u8,24164 field_name: []const u8,
24184 field_name_src: LazySrcLoc,24165 field_name_src: LazySrcLoc,
24185) CompileError!Air.Inst.Ref {24166) CompileError!ResolvedFieldCallee {
24186 // When editing this function, note that there is corresponding logic to be edited24167 // When editing this function, note that there is corresponding logic to be edited
24187 // in `fieldVal`. This function takes a pointer and returns a pointer.24168 // in `fieldVal`. This function takes a pointer and returns a pointer.
2418824169
...@@ -24202,7 +24183,6 @@ fn fieldCallBind(...@@ -24202,7 +24183,6 @@ fn fieldCallBind(
24202 else24183 else
24203 raw_ptr;24184 raw_ptr;
2420424185
24205 const arena = sema.arena;
24206 find_field: {24186 find_field: {
24207 switch (concrete_ty.zigTypeTag()) {24187 switch (concrete_ty.zigTypeTag()) {
24208 .Struct => {24188 .Struct => {
...@@ -24216,7 +24196,7 @@ fn fieldCallBind(...@@ -24216,7 +24196,7 @@ fn fieldCallBind(
24216 return sema.finishFieldCallBind(block, src, ptr_ty, field.ty, field_index, object_ptr);24196 return sema.finishFieldCallBind(block, src, ptr_ty, field.ty, field_index, object_ptr);
24217 } else if (struct_ty.isTuple()) {24197 } else if (struct_ty.isTuple()) {
24218 if (mem.eql(u8, field_name, "len")) {24198 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()) };
24220 }24200 }
24221 if (std.fmt.parseUnsigned(u32, field_name, 10)) |field_index| {24201 if (std.fmt.parseUnsigned(u32, field_name, 10)) |field_index| {
24222 if (field_index >= struct_ty.structFieldCount()) break :find_field;24202 if (field_index >= struct_ty.structFieldCount()) break :find_field;
...@@ -24243,7 +24223,7 @@ fn fieldCallBind(...@@ -24243,7 +24223,7 @@ fn fieldCallBind(
24243 },24223 },
24244 .Type => {24224 .Type => {
24245 const namespace = try sema.analyzeLoad(block, src, object_ptr, src);24225 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) };
24247 },24227 },
24248 else => {},24228 else => {},
24249 }24229 }
...@@ -24272,54 +24252,47 @@ fn fieldCallBind(...@@ -24272,54 +24252,47 @@ fn fieldCallBind(
24272 first_param_type.childType().eql(concrete_ty, sema.mod)))24252 first_param_type.childType().eql(concrete_ty, sema.mod)))
24273 {24253 {
24274 // zig fmt: on24254 // 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.
24275 // TODO: bound fn calls on rvalues should probably24258 // TODO: bound fn calls on rvalues should probably
24276 // generate a by-value argument somehow.24259 // generate a by-value argument somehow.
24277 const ty = Type.Tag.bound_fn.init();24260 return .{ .method = .{
24278 const value = try Value.Tag.bound_fn.create(arena, .{
24279 .func_inst = decl_val,24261 .func_inst = decl_val,
24280 .arg0_inst = object_ptr,24262 .arg0_inst = object_ptr,
24281 });24263 } };
24282 return sema.addConstant(ty, value);
24283 } else if (first_param_type.eql(concrete_ty, sema.mod)) {24264 } else if (first_param_type.eql(concrete_ty, sema.mod)) {
24284 const deref = try sema.analyzeLoad(block, src, object_ptr, src);24265 const deref = try sema.analyzeLoad(block, src, object_ptr, src);
24285 const ty = Type.Tag.bound_fn.init();24266 return .{ .method = .{
24286 const value = try Value.Tag.bound_fn.create(arena, .{
24287 .func_inst = decl_val,24267 .func_inst = decl_val,
24288 .arg0_inst = deref,24268 .arg0_inst = deref,
24289 });24269 } };
24290 return sema.addConstant(ty, value);
24291 } else if (first_param_type.zigTypeTag() == .Optional) {24270 } else if (first_param_type.zigTypeTag() == .Optional) {
24292 var opt_buf: Type.Payload.ElemType = undefined;24271 var opt_buf: Type.Payload.ElemType = undefined;
24293 const child = first_param_type.optionalChild(&opt_buf);24272 const child = first_param_type.optionalChild(&opt_buf);
24294 if (child.eql(concrete_ty, sema.mod)) {24273 if (child.eql(concrete_ty, sema.mod)) {
24295 const deref = try sema.analyzeLoad(block, src, object_ptr, src);24274 const deref = try sema.analyzeLoad(block, src, object_ptr, src);
24296 const ty = Type.Tag.bound_fn.init();24275 return .{ .method = .{
24297 const value = try Value.Tag.bound_fn.create(arena, .{
24298 .func_inst = decl_val,24276 .func_inst = decl_val,
24299 .arg0_inst = deref,24277 .arg0_inst = deref,
24300 });24278 } };
24301 return sema.addConstant(ty, value);
24302 } else if (child.zigTypeTag() == .Pointer and24279 } else if (child.zigTypeTag() == .Pointer and
24303 child.ptrSize() == .One and24280 child.ptrSize() == .One and
24304 child.childType().eql(concrete_ty, sema.mod))24281 child.childType().eql(concrete_ty, sema.mod))
24305 {24282 {
24306 const ty = Type.Tag.bound_fn.init();24283 return .{ .method = .{
24307 const value = try Value.Tag.bound_fn.create(arena, .{
24308 .func_inst = decl_val,24284 .func_inst = decl_val,
24309 .arg0_inst = object_ptr,24285 .arg0_inst = object_ptr,
24310 });24286 } };
24311 return sema.addConstant(ty, value);
24312 }24287 }
24313 } else if (first_param_type.zigTypeTag() == .ErrorUnion and24288 } else if (first_param_type.zigTypeTag() == .ErrorUnion and
24314 first_param_type.errorUnionPayload().eql(concrete_ty, sema.mod))24289 first_param_type.errorUnionPayload().eql(concrete_ty, sema.mod))
24315 {24290 {
24316 const deref = try sema.analyzeLoad(block, src, object_ptr, src);24291 const deref = try sema.analyzeLoad(block, src, object_ptr, src);
24317 const ty = Type.Tag.bound_fn.init();24292 return .{ .method = .{
24318 const value = try Value.Tag.bound_fn.create(arena, .{
24319 .func_inst = decl_val,24293 .func_inst = decl_val,
24320 .arg0_inst = deref,24294 .arg0_inst = deref,
24321 });24295 } };
24322 return sema.addConstant(ty, value);
24323 }24296 }
24324 }24297 }
24325 break :found_decl decl_idx;24298 break :found_decl decl_idx;
...@@ -24351,7 +24324,7 @@ fn finishFieldCallBind(...@@ -24351,7 +24324,7 @@ fn finishFieldCallBind(
24351 field_ty: Type,24324 field_ty: Type,
24352 field_index: u32,24325 field_index: u32,
24353 object_ptr: Air.Inst.Ref,24326 object_ptr: Air.Inst.Ref,
24354) CompileError!Air.Inst.Ref {24327) CompileError!ResolvedFieldCallee {
24355 const arena = sema.arena;24328 const arena = sema.arena;
24356 const ptr_field_ty = try Type.ptr(arena, sema.mod, .{24329 const ptr_field_ty = try Type.ptr(arena, sema.mod, .{
24357 .pointee_type = field_ty,24330 .pointee_type = field_ty,
...@@ -24362,7 +24335,7 @@ fn finishFieldCallBind(...@@ -24362,7 +24335,7 @@ fn finishFieldCallBind(
24362 const container_ty = ptr_ty.childType();24335 const container_ty = ptr_ty.childType();
24363 if (container_ty.zigTypeTag() == .Struct) {24336 if (container_ty.zigTypeTag() == .Struct) {
24364 if (container_ty.structFieldValueComptime(field_index)) |default_val| {24337 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) };
24366 }24339 }
24367 }24340 }
2436824341
...@@ -24375,12 +24348,12 @@ fn finishFieldCallBind(...@@ -24375,12 +24348,12 @@ fn finishFieldCallBind(
24375 .field_index = field_index,24348 .field_index = field_index,
24376 }),24349 }),
24377 );24350 );
24378 return sema.analyzeLoad(block, src, pointer, src);24351 return .{ .direct = try sema.analyzeLoad(block, src, pointer, src) };
24379 }24352 }
2438024353
24381 try sema.requireRuntimeBlock(block, src, null);24354 try sema.requireRuntimeBlock(block, src, null);
24382 const ptr_inst = try block.addStructFieldPtr(object_ptr, field_index, ptr_field_ty);24355 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) };
24384}24357}
2438524358
24386fn namespaceLookup(24359fn namespaceLookup(
...@@ -31281,7 +31254,6 @@ pub fn resolveTypeRequiresComptime(sema: *Sema, ty: Type) CompileError!bool {...@@ -31281,7 +31254,6 @@ pub fn resolveTypeRequiresComptime(sema: *Sema, ty: Type) CompileError!bool {
3128131254
31282 .inferred_alloc_mut => unreachable,31255 .inferred_alloc_mut => unreachable,
31283 .inferred_alloc_const => unreachable,31256 .inferred_alloc_const => unreachable,
31284 .bound_fn => unreachable,
3128531257
31286 .array,31258 .array,
31287 .array_sentinel,31259 .array_sentinel,
...@@ -32666,7 +32638,6 @@ pub fn typeHasOnePossibleValue(sema: *Sema, ty: Type) CompileError!?Value {...@@ -32666,7 +32638,6 @@ pub fn typeHasOnePossibleValue(sema: *Sema, ty: Type) CompileError!?Value {
32666 .single_const_pointer,32638 .single_const_pointer,
32667 .single_mut_pointer,32639 .single_mut_pointer,
32668 .pointer,32640 .pointer,
32669 .bound_fn,
32670 => return null,32641 => return null,
3267132642
32672 .optional => {32643 .optional => {
...@@ -33308,7 +33279,6 @@ pub fn typeRequiresComptime(sema: *Sema, ty: Type) CompileError!bool {...@@ -33308,7 +33279,6 @@ pub fn typeRequiresComptime(sema: *Sema, ty: Type) CompileError!bool {
3330833279
33309 .inferred_alloc_mut => unreachable,33280 .inferred_alloc_mut => unreachable,
33310 .inferred_alloc_const => unreachable,33281 .inferred_alloc_const => unreachable,
33311 .bound_fn => unreachable,
3331233282
33313 .array,33283 .array,
33314 .array_sentinel,33284 .array_sentinel,
src/TypedValue.zig-4
...@@ -499,10 +499,6 @@ pub fn print(...@@ -499,10 +499,6 @@ pub fn print(
499 // TODO these should not appear in this function499 // TODO these should not appear in this function
500 .inferred_alloc => return writer.writeAll("(inferred allocation value)"),500 .inferred_alloc => return writer.writeAll("(inferred allocation value)"),
501 .inferred_alloc_comptime => return writer.writeAll("(inferred comptime allocation value)"),501 .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 },
506 .generic_poison_type => return writer.writeAll("(generic poison type)"),502 .generic_poison_type => return writer.writeAll("(generic poison type)"),
507 .generic_poison => return writer.writeAll("(generic poison)"),503 .generic_poison => return writer.writeAll("(generic poison)"),
508 .runtime_value => return writer.writeAll("[runtime value]"),504 .runtime_value => return writer.writeAll("[runtime value]"),
src/Zir.zig+24-28
...@@ -297,6 +297,14 @@ pub const Inst = struct {...@@ -297,6 +297,14 @@ pub const Inst = struct {
297 /// Uses the `pl_node` union field with payload `Call`.297 /// Uses the `pl_node` union field with payload `Call`.
298 /// AST node is the function call.298 /// AST node is the function call.
299 call,299 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,
300 /// Implements the `@call` builtin.308 /// Implements the `@call` builtin.
301 /// Uses the `pl_node` union field with payload `BuiltinCall`.309 /// Uses the `pl_node` union field with payload `BuiltinCall`.
302 /// AST node is the builtin call.310 /// AST node is the builtin call.
...@@ -432,15 +440,6 @@ pub const Inst = struct {...@@ -432,15 +440,6 @@ pub const Inst = struct {
432 /// This instruction also accepts a pointer.440 /// This instruction also accepts a pointer.
433 /// Uses `pl_node` field. The AST node is the a.b syntax. Payload is Field.441 /// Uses `pl_node` field. The AST node is the a.b syntax. Payload is Field.
434 field_val,442 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,
444 /// Given a pointer to a struct or object that contains virtual fields, returns a pointer443 /// Given a pointer to a struct or object that contains virtual fields, returns a pointer
445 /// to the named field. The field name is a comptime instruction. Used by @field.444 /// to the named field. The field name is a comptime instruction. Used by @field.
446 /// Uses `pl_node` field. The AST node is the builtin call. Payload is FieldNamed.445 /// Uses `pl_node` field. The AST node is the builtin call. Payload is FieldNamed.
...@@ -1051,6 +1050,7 @@ pub const Inst = struct {...@@ -1051,6 +1050,7 @@ pub const Inst = struct {
1051 .bool_br_or,1050 .bool_br_or,
1052 .bool_not,1051 .bool_not,
1053 .call,1052 .call,
1053 .field_call,
1054 .cmp_lt,1054 .cmp_lt,
1055 .cmp_lte,1055 .cmp_lte,
1056 .cmp_eq,1056 .cmp_eq,
...@@ -1083,7 +1083,6 @@ pub const Inst = struct {...@@ -1083,7 +1083,6 @@ pub const Inst = struct {
1083 .field_ptr,1083 .field_ptr,
1084 .field_ptr_init,1084 .field_ptr_init,
1085 .field_val,1085 .field_val,
1086 .field_call_bind,
1087 .field_ptr_named,1086 .field_ptr_named,
1088 .field_val_named,1087 .field_val_named,
1089 .func,1088 .func,
...@@ -1361,6 +1360,7 @@ pub const Inst = struct {...@@ -1361,6 +1360,7 @@ pub const Inst = struct {
1361 .bool_br_or,1360 .bool_br_or,
1362 .bool_not,1361 .bool_not,
1363 .call,1362 .call,
1363 .field_call,
1364 .cmp_lt,1364 .cmp_lt,
1365 .cmp_lte,1365 .cmp_lte,
1366 .cmp_eq,1366 .cmp_eq,
...@@ -1383,7 +1383,6 @@ pub const Inst = struct {...@@ -1383,7 +1383,6 @@ pub const Inst = struct {
1383 .field_ptr,1383 .field_ptr,
1384 .field_ptr_init,1384 .field_ptr_init,
1385 .field_val,1385 .field_val,
1386 .field_call_bind,
1387 .field_ptr_named,1386 .field_ptr_named,
1388 .field_val_named,1387 .field_val_named,
1389 .func,1388 .func,
...@@ -1601,6 +1600,7 @@ pub const Inst = struct {...@@ -1601,6 +1600,7 @@ pub const Inst = struct {
1601 .check_comptime_control_flow = .un_node,1600 .check_comptime_control_flow = .un_node,
1602 .for_len = .pl_node,1601 .for_len = .pl_node,
1603 .call = .pl_node,1602 .call = .pl_node,
1603 .field_call = .pl_node,
1604 .cmp_lt = .pl_node,1604 .cmp_lt = .pl_node,
1605 .cmp_lte = .pl_node,1605 .cmp_lte = .pl_node,
1606 .cmp_eq = .pl_node,1606 .cmp_eq = .pl_node,
...@@ -1641,7 +1641,6 @@ pub const Inst = struct {...@@ -1641,7 +1641,6 @@ pub const Inst = struct {
1641 .field_val = .pl_node,1641 .field_val = .pl_node,
1642 .field_ptr_named = .pl_node,1642 .field_ptr_named = .pl_node,
1643 .field_val_named = .pl_node,1643 .field_val_named = .pl_node,
1644 .field_call_bind = .pl_node,
1645 .func = .pl_node,1644 .func = .pl_node,
1646 .func_inferred = .pl_node,1645 .func_inferred = .pl_node,
1647 .func_fancy = .pl_node,1646 .func_fancy = .pl_node,
...@@ -1955,16 +1954,6 @@ pub const Inst = struct {...@@ -1955,16 +1954,6 @@ pub const Inst = struct {
1955 /// The `@prefetch` builtin.1954 /// The `@prefetch` builtin.
1956 /// `operand` is payload index to `BinNode`.1955 /// `operand` is payload index to `BinNode`.
1957 prefetch,1956 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,
1968 /// Implements the `@fence` builtin.1957 /// Implements the `@fence` builtin.
1969 /// `operand` is payload index to `UnNode`.1958 /// `operand` is payload index to `UnNode`.
1970 fence,1959 fence,
...@@ -2913,6 +2902,19 @@ pub const Inst = struct {...@@ -2913,6 +2902,19 @@ pub const Inst = struct {
2913 };2902 };
2914 };2903 };
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
2916 pub const TypeOfPeer = struct {2918 pub const TypeOfPeer = struct {
2917 src_node: i32,2919 src_node: i32,
2918 body_len: u32,2920 body_len: u32,
...@@ -3187,12 +3189,6 @@ pub const Inst = struct {...@@ -3187,12 +3189,6 @@ pub const Inst = struct {
3187 field_name: Ref,3189 field_name: Ref,
3188 };3190 };
31893191
3190 pub const FieldNamedNode = struct {
3191 node: i32,
3192 lhs: Ref,
3193 field_name: Ref,
3194 };
3195
3196 pub const As = struct {3192 pub const As = struct {
3197 dest_type: Ref,3193 dest_type: Ref,
3198 operand: Ref,3194 operand: Ref,
src/print_air.zig-1
...@@ -369,7 +369,6 @@ const Writer = struct {...@@ -369,7 +369,6 @@ const Writer = struct {
369 .inferred_alloc_const => try s.writeAll("(inferred_alloc_const)"),369 .inferred_alloc_const => try s.writeAll("(inferred_alloc_const)"),
370 .inferred_alloc_mut => try s.writeAll("(inferred_alloc_mut)"),370 .inferred_alloc_mut => try s.writeAll("(inferred_alloc_mut)"),
371 .generic_poison => try s.writeAll("(generic_poison)"),371 .generic_poison => try s.writeAll("(generic_poison)"),
372 .bound_fn => try s.writeAll("(bound_fn)"),
373 else => try ty.print(s, w.module),372 else => try ty.print(s, w.module),
374 }373 }
375 }374 }
src/print_zir.zig+21-14
...@@ -362,7 +362,8 @@ const Writer = struct {...@@ -362,7 +362,8 @@ const Writer = struct {
362 .@"export" => try self.writePlNodeExport(stream, inst),362 .@"export" => try self.writePlNodeExport(stream, inst),
363 .export_value => try self.writePlNodeExportValue(stream, inst),363 .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
367 .block,368 .block,
368 .block_comptime,369 .block_comptime,
...@@ -392,7 +393,6 @@ const Writer = struct {...@@ -392,7 +393,6 @@ const Writer = struct {
392 .field_ptr,393 .field_ptr,
393 .field_ptr_init,394 .field_ptr_init,
394 .field_val,395 .field_val,
395 .field_call_bind,
396 => try self.writePlNodeField(stream, inst),396 => try self.writePlNodeField(stream, inst),
397397
398 .field_ptr_named,398 .field_ptr_named,
...@@ -543,15 +543,6 @@ const Writer = struct {...@@ -543,15 +543,6 @@ const Writer = struct {
543 try self.writeSrc(stream, src);543 try self.writeSrc(stream, src);
544 },544 },
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 },
555 .builtin_async_call => try self.writeBuiltinAsyncCall(stream, extended),546 .builtin_async_call => try self.writeBuiltinAsyncCall(stream, extended),
556 .cmpxchg => try self.writeCmpxchg(stream, extended),547 .cmpxchg => try self.writeCmpxchg(stream, extended),
557 }548 }
...@@ -1176,9 +1167,18 @@ const Writer = struct {...@@ -1176,9 +1167,18 @@ const Writer = struct {
1176 try self.writeSrc(stream, src);1167 try self.writeSrc(stream, src);
1177 }1168 }
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 {
1180 const inst_data = self.code.instructions.items(.data)[inst].pl_node;1176 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);
1182 const args_len = extra.data.flags.args_len;1182 const args_len = extra.data.flags.args_len;
1183 const body = self.code.extra[extra.end..];1183 const body = self.code.extra[extra.end..];
11841184
...@@ -1186,7 +1186,14 @@ const Writer = struct {...@@ -1186,7 +1186,14 @@ const Writer = struct {
1186 try stream.writeAll("nodiscard ");1186 try stream.writeAll("nodiscard ");
1187 }1187 }
1188 try stream.print(".{s}, ", .{@tagName(@intToEnum(std.builtin.CallModifier, extra.data.flags.packed_modifier))});1188 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 }
1190 try stream.writeAll(", [");1197 try stream.writeAll(", [");
11911198
1192 self.indent += 2;1199 self.indent += 2;
src/type.zig+1-17
...@@ -156,8 +156,6 @@ pub const Type = extern union {...@@ -156,8 +156,6 @@ pub const Type = extern union {
156 .union_tagged,156 .union_tagged,
157 .type_info,157 .type_info,
158 => return .Union,158 => return .Union,
159
160 .bound_fn => unreachable,
161 }159 }
162 }160 }
163161
...@@ -933,7 +931,6 @@ pub const Type = extern union {...@@ -933,7 +931,6 @@ pub const Type = extern union {
933 // for example, a was resolved into .union_tagged but b was one of these tags.931 // for example, a was resolved into .union_tagged but b was one of these tags.
934 .type_info => unreachable, // needed to resolve the type before now932 .type_info => unreachable, // needed to resolve the type before now
935933
936 .bound_fn => unreachable,
937 }934 }
938 }935 }
939936
...@@ -1242,7 +1239,6 @@ pub const Type = extern union {...@@ -1242,7 +1239,6 @@ pub const Type = extern union {
1242 // we can't hash these based on tags because they wouldn't match the expanded version.1239 // we can't hash these based on tags because they wouldn't match the expanded version.
1243 .type_info => unreachable, // needed to resolve the type before now1240 .type_info => unreachable, // needed to resolve the type before now
12441241
1245 .bound_fn => unreachable,
1246 }1242 }
1247 }1243 }
12481244
...@@ -1349,7 +1345,6 @@ pub const Type = extern union {...@@ -1349,7 +1345,6 @@ pub const Type = extern union {
1349 .type_info,1345 .type_info,
1350 .@"anyframe",1346 .@"anyframe",
1351 .generic_poison,1347 .generic_poison,
1352 .bound_fn,
1353 => unreachable,1348 => unreachable,
13541349
1355 .array_u8,1350 .array_u8,
...@@ -1613,7 +1608,6 @@ pub const Type = extern union {...@@ -1613,7 +1608,6 @@ pub const Type = extern union {
1613 .comptime_int,1608 .comptime_int,
1614 .comptime_float,1609 .comptime_float,
1615 .noreturn,1610 .noreturn,
1616 .bound_fn,
1617 => return writer.writeAll(@tagName(t)),1611 => return writer.writeAll(@tagName(t)),
16181612
1619 .enum_literal => return writer.writeAll("@Type(.EnumLiteral)"),1613 .enum_literal => return writer.writeAll("@Type(.EnumLiteral)"),
...@@ -1949,7 +1943,6 @@ pub const Type = extern union {...@@ -1949,7 +1943,6 @@ pub const Type = extern union {
1949 .inferred_alloc_const => unreachable,1943 .inferred_alloc_const => unreachable,
1950 .inferred_alloc_mut => unreachable,1944 .inferred_alloc_mut => unreachable,
1951 .generic_poison => unreachable,1945 .generic_poison => unreachable,
1952 .bound_fn => unreachable,
19531946
1954 // TODO get rid of these Type.Tag values.1947 // TODO get rid of these Type.Tag values.
1955 .atomic_order => unreachable,1948 .atomic_order => unreachable,
...@@ -2468,7 +2461,6 @@ pub const Type = extern union {...@@ -2468,7 +2461,6 @@ pub const Type = extern union {
2468 .enum_literal,2461 .enum_literal,
2469 .empty_struct,2462 .empty_struct,
2470 .empty_struct_literal,2463 .empty_struct_literal,
2471 .bound_fn,
2472 // These are function *bodies*, not pointers.2464 // These are function *bodies*, not pointers.
2473 // Special exceptions have to be made when emitting functions due to2465 // Special exceptions have to be made when emitting functions due to
2474 // this returning false.2466 // this returning false.
...@@ -2703,7 +2695,6 @@ pub const Type = extern union {...@@ -2703,7 +2695,6 @@ pub const Type = extern union {
27032695
2704 .inferred_alloc_mut => unreachable,2696 .inferred_alloc_mut => unreachable,
2705 .inferred_alloc_const => unreachable,2697 .inferred_alloc_const => unreachable,
2706 .bound_fn => unreachable,
27072698
2708 .array,2699 .array,
2709 .array_sentinel,2700 .array_sentinel,
...@@ -3182,7 +3173,6 @@ pub const Type = extern union {...@@ -3182,7 +3173,6 @@ pub const Type = extern union {
3182 .noreturn,3173 .noreturn,
3183 .inferred_alloc_const,3174 .inferred_alloc_const,
3184 .inferred_alloc_mut,3175 .inferred_alloc_mut,
3185 .bound_fn,
3186 => unreachable,3176 => unreachable,
31873177
3188 .generic_poison => unreachable,3178 .generic_poison => unreachable,
...@@ -3282,7 +3272,6 @@ pub const Type = extern union {...@@ -3282,7 +3272,6 @@ pub const Type = extern union {
3282 .fn_ccc_void_no_args => unreachable, // represents machine code; not a pointer3272 .fn_ccc_void_no_args => unreachable, // represents machine code; not a pointer
3283 .function => unreachable, // represents machine code; not a pointer3273 .function => unreachable, // represents machine code; not a pointer
3284 .@"opaque" => unreachable, // no size available3274 .@"opaque" => unreachable, // no size available
3285 .bound_fn => unreachable,
3286 .noreturn => unreachable,3275 .noreturn => unreachable,
3287 .inferred_alloc_const => unreachable,3276 .inferred_alloc_const => unreachable,
3288 .inferred_alloc_mut => unreachable,3277 .inferred_alloc_mut => unreachable,
...@@ -3630,7 +3619,6 @@ pub const Type = extern union {...@@ -3630,7 +3619,6 @@ pub const Type = extern union {
3630 .inferred_alloc_mut => unreachable,3619 .inferred_alloc_mut => unreachable,
3631 .@"opaque" => unreachable,3620 .@"opaque" => unreachable,
3632 .generic_poison => unreachable,3621 .generic_poison => unreachable,
3633 .bound_fn => unreachable,
36343622
3635 .void => return 0,3623 .void => return 0,
3636 .bool, .u1 => return 1,3624 .bool, .u1 => return 1,
...@@ -5042,7 +5030,6 @@ pub const Type = extern union {...@@ -5042,7 +5030,6 @@ pub const Type = extern union {
5042 .single_const_pointer,5030 .single_const_pointer,
5043 .single_mut_pointer,5031 .single_mut_pointer,
5044 .pointer,5032 .pointer,
5045 .bound_fn,
5046 => return null,5033 => return null,
50475034
5048 .optional => {5035 .optional => {
...@@ -5245,7 +5232,6 @@ pub const Type = extern union {...@@ -5245,7 +5232,6 @@ pub const Type = extern union {
52455232
5246 .inferred_alloc_mut => unreachable,5233 .inferred_alloc_mut => unreachable,
5247 .inferred_alloc_const => unreachable,5234 .inferred_alloc_const => unreachable,
5248 .bound_fn => unreachable,
52495235
5250 .array,5236 .array,
5251 .array_sentinel,5237 .array_sentinel,
...@@ -6081,7 +6067,6 @@ pub const Type = extern union {...@@ -6081,7 +6067,6 @@ pub const Type = extern union {
6081 inferred_alloc_mut,6067 inferred_alloc_mut,
6082 /// Same as `inferred_alloc_mut` but the local is `var` not `const`.6068 /// Same as `inferred_alloc_mut` but the local is `var` not `const`.
6083 inferred_alloc_const, // See last_no_payload_tag below.6069 inferred_alloc_const, // See last_no_payload_tag below.
6084 bound_fn,
6085 // After this, the tag requires a payload.6070 // After this, the tag requires a payload.
60866071
6087 array_u8,6072 array_u8,
...@@ -6126,7 +6111,7 @@ pub const Type = extern union {...@@ -6126,7 +6111,7 @@ pub const Type = extern union {
6126 enum_full,6111 enum_full,
6127 enum_nonexhaustive,6112 enum_nonexhaustive,
61286113
6129 pub const last_no_payload_tag = Tag.bound_fn;6114 pub const last_no_payload_tag = Tag.inferred_alloc_const;
6130 pub const no_payload_count = @enumToInt(last_no_payload_tag) + 1;6115 pub const no_payload_count = @enumToInt(last_no_payload_tag) + 1;
61316116
6132 pub fn Type(comptime t: Tag) type {6117 pub fn Type(comptime t: Tag) type {
...@@ -6199,7 +6184,6 @@ pub const Type = extern union {...@@ -6199,7 +6184,6 @@ pub const Type = extern union {
6199 .extern_options,6184 .extern_options,
6200 .type_info,6185 .type_info,
6201 .@"anyframe",6186 .@"anyframe",
6202 .bound_fn,
6203 => @compileError("Type Tag " ++ @tagName(t) ++ " has no payload"),6187 => @compileError("Type Tag " ++ @tagName(t) ++ " has no payload"),
62046188
6205 .array_u8,6189 .array_u8,
src/value.zig-20
...@@ -183,10 +183,6 @@ pub const Value = extern union {...@@ -183,10 +183,6 @@ pub const Value = extern union {
183 /// Used to coordinate alloc_inferred, store_to_inferred_ptr, and resolve_inferred_alloc183 /// Used to coordinate alloc_inferred, store_to_inferred_ptr, and resolve_inferred_alloc
184 /// instructions for comptime code.184 /// instructions for comptime code.
185 inferred_alloc_comptime,185 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,
190 /// The ABI alignment of the payload type.186 /// The ABI alignment of the payload type.
191 lazy_align,187 lazy_align,
192 /// The ABI size of the payload type.188 /// The ABI size of the payload type.
...@@ -326,7 +322,6 @@ pub const Value = extern union {...@@ -326,7 +322,6 @@ pub const Value = extern union {
326 .inferred_alloc_comptime => Payload.InferredAllocComptime,322 .inferred_alloc_comptime => Payload.InferredAllocComptime,
327 .aggregate => Payload.Aggregate,323 .aggregate => Payload.Aggregate,
328 .@"union" => Payload.Union,324 .@"union" => Payload.Union,
329 .bound_fn => Payload.BoundFn,
330 .comptime_field_ptr => Payload.ComptimeFieldPtr,325 .comptime_field_ptr => Payload.ComptimeFieldPtr,
331 };326 };
332 }327 }
...@@ -477,7 +472,6 @@ pub const Value = extern union {...@@ -477,7 +472,6 @@ pub const Value = extern union {
477 .extern_options_type,472 .extern_options_type,
478 .type_info_type,473 .type_info_type,
479 .generic_poison,474 .generic_poison,
480 .bound_fn,
481 => unreachable,475 => unreachable,
482476
483 .ty, .lazy_align, .lazy_size => {477 .ty, .lazy_align, .lazy_size => {
...@@ -837,10 +831,6 @@ pub const Value = extern union {...@@ -837,10 +831,6 @@ pub const Value = extern union {
837 try out_stream.writeAll("(opt_payload_ptr)");831 try out_stream.writeAll("(opt_payload_ptr)");
838 val = val.castTag(.opt_payload_ptr).?.data.container_ptr;832 val = val.castTag(.opt_payload_ptr).?.data.container_ptr;
839 },833 },
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 },
844 };834 };
845 }835 }
846836
...@@ -5657,16 +5647,6 @@ pub const Value = extern union {...@@ -5657,16 +5647,6 @@ pub const Value = extern union {
5657 val: Value,5647 val: Value,
5658 },5648 },
5659 };5649 };
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 };
5670 };5650 };
56715651
5672 /// Big enough to fit any non-BigInt value5652 /// Big enough to fit any non-BigInt value
test/behavior/member_func.zig-12
...@@ -86,18 +86,6 @@ test "@field field calls" {...@@ -86,18 +86,6 @@ test "@field field calls" {
86 const pv = &v;86 const pv = &v;
87 const pcv: *const HasFuncs = pv;87 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
101 v.func_field = HasFuncs.one;89 v.func_field = HasFuncs.one;
102 try expect(@field(v, "func_field")(0) == 1);90 try expect(@field(v, "func_field")(0) == 1);
103 try expect(@field(pv, "func_field")(0) == 1);91 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 {...@@ -6,10 +6,6 @@ pub export fn entry() void {
6 var s: S = undefined;6 var s: S = undefined;
7 s.foo(true);7 s.foo(true);
8}8}
9pub export fn entry2() void {
10 var s: S = undefined;
11 @call(.auto, s.foo, .{true});
12}
139
14// error10// error
15// backend=stage211// backend=stage2
...@@ -17,5 +13,3 @@ pub export fn entry2() void {...@@ -17,5 +13,3 @@ pub export fn entry2() void {
17//13//
18// :7:6: error: member function expected 2 argument(s), found 114// :7:6: error: member function expected 2 argument(s), found 1
19// :3:5: note: function declared here15// :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