| author | |
| committer | |
| log | 38b83d9d93db400e8103f02eeb77729040bd3666 |
| tree | f88cdbe5603e27aca415071a3f15ef60f4023d2b |
| parent | 7077e90b3f8991c844deb08a16ad3f4e0569398f |
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 | } |
| 171 | 171 | ||
| 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/63350048 | 174 | // - 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 inlining | 175 | // - `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 { |
| 180 | 180 | ||
| 181 | // Acquire barrier ensures grabbing the lock happens before the critical section | 181 | // 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 | } |
| 185 | 186 | ||
| 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. |
| 65 | pub fn hash(hasher: anytype, key: anytype, comptime strat: HashStrategy) void { | 65 | pub 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 | }; | ||
| 67 | 71 | ||
| 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 | } |
| 72 | 76 | ||
| ... | @@ -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 remaining | 98 | // 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 | }, |
| 100 | 104 |
lib/std/hash/wyhash.zig+3-3| ... | @@ -65,7 +65,7 @@ const WyhashStateless = struct { | ... | @@ -65,7 +65,7 @@ const WyhashStateless = struct { |
| 65 | 65 | ||
| 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 | } |
| 70 | 70 | ||
| 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); |
| 122 | 122 | ||
| 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 | }; |
| 128 | 128 |
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 data | 2483 | // 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 | } |
| 8978 | 8977 | ||
| 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); |
| 8981 | 8983 | ||
| 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 | }; |
| 9017 | 9019 | ||
| 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 location | 9063 | return rvalue(gz, ri, call_inst, node); // TODO function call with result location |
| 9037 | } | 9064 | } |
| 9038 | 9065 | ||
| 9039 | /// calleeExpr generates the function part of a call expression (f in f(x)), or the | 9066 | const Callee = union(enum) { |
| 9040 | /// callee argument to the @call() builtin. If the lhs is a field access or the | 9067 | field: struct { |
| 9041 | /// @field() builtin, we need to generate a special field_call_bind instruction | 9068 | /// 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 evaluating | 9070 | obj_ptr: Zir.Inst.Ref, |
| 9044 | /// the other arguments. We need to use .ref here to guarantee we will be able to | 9071 | /// Offset into `string_bytes`. |
| 9045 | /// promote an lvalue to an address if the first parameter requires it. This | 9072 | 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. | ||
| 9047 | fn calleeExpr( | 9082 | fn 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; |
| 9054 | 9089 | ||
| 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; |
| 9068 | 9096 | 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 | }; | ||
| 9085 | 9102 | ||
| 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 | } | ||
| 9097 | 9105 | ||
| 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 | } |
| 9103 | 9114 |
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 the | 2145 | // 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( |
| 2163 | 2163 | ||
| 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 and | 2165 | if (tags[lhs] != .field_val and |
| 2166 | tags[lhs] != .field_call_bind and | ||
| 2167 | tags[lhs] != .field_ptr and | 2166 | 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; |
| 2169 | 2168 | ||
| ... | @@ -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`), or | 3098 | /// * 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(); |
| 6268 | 6268 | ||
| 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; |
| 6274 | 6278 | ||
| 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; |
| 6278 | 6282 | ||
| 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 | } |
| 6298 | 6309 | ||
| 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); |
| 6315 | 6327 | ||
| 6316 | const args_body = sema.code.extra[extra.end..]; | 6328 | const args_body = sema.code.extra[extra.end..]; |
| 6317 | 6329 | ||
| ... | @@ -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 | }; |
| 6374 | 6386 | ||
| 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 | } |
| 6399 | 6411 | ||
| 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); |
| 6402 | 6414 | ||
| 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 | } |
| 6408 | 6420 | ||
| ... | @@ -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 | } |
| 9469 | 9481 | ||
| 9470 | fn 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 | |||
| 9483 | fn zirFieldValNamed(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air.Inst.Ref { | 9482 | fn 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 | } |
| 9508 | 9507 | ||
| 9509 | fn 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 | |||
| 9521 | fn zirIntCast(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air.Inst.Ref { | 9508 | fn 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 | } |
| 21675 | 21662 | ||
| 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()); |
| 21677 | 21664 | for (resolved_args, 0..) |*resolved, i| { | |
| 21678 | // Desugar bound functions here | 21665 | 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 | } |
| 21696 | 21667 | ||
| 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); |
| 21712 | 21683 | ||
| 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 | } |
| 21716 | 21687 | ||
| 21717 | fn zirFieldParentPtr(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air.Inst.Ref { | 21688 | fn 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 | } |
| 24177 | 24148 | ||
| 24149 | const 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 | |||
| 24178 | fn fieldCallBind( | 24159 | fn 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 edited | 24167 | // 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. |
| 24188 | 24169 | ||
| ... | @@ -24202,7 +24183,6 @@ fn fieldCallBind( | ... | @@ -24202,7 +24183,6 @@ fn fieldCallBind( |
| 24202 | else | 24183 | else |
| 24203 | raw_ptr; | 24184 | raw_ptr; |
| 24204 | 24185 | ||
| 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: on | 24254 | // 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 probably | 24258 | // 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 and | 24279 | } else if (child.zigTypeTag() == .Pointer and |
| 24303 | child.ptrSize() == .One and | 24280 | 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 and | 24288 | } 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 | } |
| 24368 | 24341 | ||
| ... | @@ -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 | } |
| 24380 | 24353 | ||
| 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 | } |
| 24385 | 24358 | ||
| 24386 | fn namespaceLookup( | 24359 | fn 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 { |
| 31281 | 31254 | ||
| 31282 | .inferred_alloc_mut => unreachable, | 31255 | .inferred_alloc_mut => unreachable, |
| 31283 | .inferred_alloc_const => unreachable, | 31256 | .inferred_alloc_const => unreachable, |
| 31284 | .bound_fn => unreachable, | ||
| 31285 | 31257 | ||
| 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, |
| 32671 | 32642 | ||
| 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 { |
| 33308 | 33279 | ||
| 33309 | .inferred_alloc_mut => unreachable, | 33280 | .inferred_alloc_mut => unreachable, |
| 33310 | .inferred_alloc_const => unreachable, | 33281 | .inferred_alloc_const => unreachable, |
| 33311 | .bound_fn => unreachable, | ||
| 33312 | 33282 | ||
| 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 function | 499 | // 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 pointer | 443 | /// 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 | }; |
| 2915 | 2904 | ||
| 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 | }; |
| 3189 | 3191 | ||
| 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), |
| 364 | 364 | ||
| 365 | .call => try self.writeCall(stream, inst), | 365 | .call => try self.writeCall(stream, inst, .direct), |
| 366 | .field_call => try self.writeCall(stream, inst, .field), | ||
| 366 | 367 | ||
| 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), |
| 397 | 397 | ||
| 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 | }, |
| 545 | 545 | ||
| 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 | } |
| 1178 | 1169 | ||
| 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..]; |
| 1184 | 1184 | ||
| ... | @@ -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(", ["); |
| 1191 | 1198 | ||
| 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 | } |
| 163 | 161 | ||
| ... | @@ -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 now | 932 | .type_info => unreachable, // needed to resolve the type before now |
| 935 | 933 | ||
| 936 | .bound_fn => unreachable, | ||
| 937 | } | 934 | } |
| 938 | } | 935 | } |
| 939 | 936 | ||
| ... | @@ -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 now | 1240 | .type_info => unreachable, // needed to resolve the type before now |
| 1244 | 1241 | ||
| 1245 | .bound_fn => unreachable, | ||
| 1246 | } | 1242 | } |
| 1247 | } | 1243 | } |
| 1248 | 1244 | ||
| ... | @@ -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, |
| 1354 | 1349 | ||
| 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)), |
| 1618 | 1612 | ||
| 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, | ||
| 1953 | 1946 | ||
| 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 to | 2465 | // 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 { |
| 2703 | 2695 | ||
| 2704 | .inferred_alloc_mut => unreachable, | 2696 | .inferred_alloc_mut => unreachable, |
| 2705 | .inferred_alloc_const => unreachable, | 2697 | .inferred_alloc_const => unreachable, |
| 2706 | .bound_fn => unreachable, | ||
| 2707 | 2698 | ||
| 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, |
| 3187 | 3177 | ||
| 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 pointer | 3272 | .fn_ccc_void_no_args => unreachable, // represents machine code; not a pointer |
| 3283 | .function => unreachable, // represents machine code; not a pointer | 3273 | .function => unreachable, // represents machine code; not a pointer |
| 3284 | .@"opaque" => unreachable, // no size available | 3274 | .@"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, | ||
| 3634 | 3622 | ||
| 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, |
| 5047 | 5034 | ||
| 5048 | .optional => { | 5035 | .optional => { |
| ... | @@ -5245,7 +5232,6 @@ pub const Type = extern union { | ... | @@ -5245,7 +5232,6 @@ pub const Type = extern union { |
| 5245 | 5232 | ||
| 5246 | .inferred_alloc_mut => unreachable, | 5233 | .inferred_alloc_mut => unreachable, |
| 5247 | .inferred_alloc_const => unreachable, | 5234 | .inferred_alloc_const => unreachable, |
| 5248 | .bound_fn => unreachable, | ||
| 5249 | 5235 | ||
| 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. |
| 6086 | 6071 | ||
| 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, |
| 6128 | 6113 | ||
| 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; |
| 6131 | 6116 | ||
| 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"), |
| 6204 | 6188 | ||
| 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_alloc | 183 | /// 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, |
| 482 | 476 | ||
| 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 | } |
| 846 | 836 | ||
| ... | @@ -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 | }; |
| 5671 | 5651 | ||
| 5672 | /// Big enough to fit any non-BigInt value | 5652 | /// 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; |
| 88 | 88 | ||
| 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 | } |
| 9 | pub export fn entry2() void { | ||
| 10 | var s: S = undefined; | ||
| 11 | @call(.auto, s.foo, .{true}); | ||
| 12 | } | ||
| 13 | 9 | ||
| 14 | // error | 10 | // error |
| 15 | // backend=stage2 | 11 | // 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 1 | 14 | // :7:6: error: member function expected 2 argument(s), found 1 |
| 19 | // :3:5: note: function declared here | 15 | // :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 |