| 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 | 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 | 173 | // On x86, use `lock bts` instead of `lock cmpxchg` as: |
| 174 | 174 | // - they both seem to mark the cache-line as modified regardless: https://stackoverflow.com/a/63350048 |
| 175 | 175 | // - `lock bts` is smaller instruction-wise which makes it better for inlining |
| ... | ... | @@ -180,7 +180,8 @@ const FutexImpl = struct { |
| 180 | 180 | |
| 181 | 181 | // Acquire barrier ensures grabbing the lock happens before the critical section |
| 182 | 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 | 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 | 167 | pub fn hash(msg: []const u8, key: *const [key_length]u8) T { |
| 168 | 168 | const aligned_len = msg.len - (msg.len % 8); |
| 169 | 169 | var c = Self.init(key); |
| 170 | @call(.always_inline, c.update, .{msg[0..aligned_len]}); | |
| 171 | return @call(.always_inline, c.final, .{msg[aligned_len..]}); | |
| 170 | @call(.always_inline, update, .{ &c, msg[0..aligned_len] }); | |
| 171 | return @call(.always_inline, final, .{ &c, msg[aligned_len..] }); | |
| 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 | 64 | /// Strategy is provided to determine if pointers should be followed or not. |
| 65 | 65 | pub fn hash(hasher: anytype, key: anytype, comptime strat: HashStrategy) void { |
| 66 | 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 | 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 | 74 | return; |
| 71 | 75 | } |
| 72 | 76 | |
| ... | ... | @@ -89,12 +93,12 @@ pub fn hash(hasher: anytype, key: anytype, comptime strat: HashStrategy) void { |
| 89 | 93 | // TODO Check if the situation is better after #561 is resolved. |
| 90 | 94 | .Int => { |
| 91 | 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 | 97 | } else { |
| 94 | 98 | // Take only the part containing the key value, the remaining |
| 95 | 99 | // bytes are undefined and must not be hashed! |
| 96 | 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 | 65 | |
| 66 | 66 | var off: usize = 0; |
| 67 | 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 | 71 | self.msg_len += b.len; |
| ... | ... | @@ -121,8 +121,8 @@ const WyhashStateless = struct { |
| 121 | 121 | const aligned_len = input.len - (input.len % 32); |
| 122 | 122 | |
| 123 | 123 | var c = WyhashStateless.init(seed); |
| 124 | @call(.always_inline, c.update, .{input[0..aligned_len]}); | |
| 125 | return @call(.always_inline, c.final, .{input[aligned_len..]}); | |
| 124 | @call(.always_inline, update, .{ &c, input[0..aligned_len] }); | |
| 125 | return @call(.always_inline, final, .{ &c, input[aligned_len..] }); | |
| 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 | 2482 | switch (zir_tags[inst]) { |
| 2483 | 2483 | // For some instructions, modify the zir data |
| 2484 | 2484 | // so we can avoid a separate ensure_result_used instruction. |
| 2485 | .call => { | |
| 2485 | .call, .field_call => { | |
| 2486 | 2486 | const extra_index = gz.astgen.instructions.items(.data)[inst].pl_node.payload_index; |
| 2487 | 2487 | const slot = &gz.astgen.extra.items[extra_index]; |
| 2488 | 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 | 2557 | .field_ptr, |
| 2558 | 2558 | .field_ptr_init, |
| 2559 | 2559 | .field_val, |
| 2560 | .field_call_bind, | |
| 2561 | 2560 | .field_ptr_named, |
| 2562 | 2561 | .field_val_named, |
| 2563 | 2562 | .func, |
| ... | ... | @@ -8516,7 +8515,7 @@ fn builtinCall( |
| 8516 | 8515 | }, |
| 8517 | 8516 | .call => { |
| 8518 | 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 | 8519 | const args = try expr(gz, scope, .{ .rl = .none }, params[2]); |
| 8521 | 8520 | const result = try gz.addPlNode(.builtin_call, node, Zir.Inst.BuiltinCall{ |
| 8522 | 8521 | .modifier = modifier, |
| ... | ... | @@ -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 | 8982 | assert(node != 0); |
| 8981 | 8983 | |
| 8982 | 8984 | const call_index = @intCast(Zir.Inst.Index, astgen.instructions.len); |
| ... | ... | @@ -9015,89 +9017,98 @@ fn callExpr( |
| 9015 | 9017 | else => false, |
| 9016 | 9018 | }; |
| 9017 | 9019 | |
| 9018 | const payload_index = try addExtra(astgen, Zir.Inst.Call{ | |
| 9019 | .callee = callee, | |
| 9020 | .flags = .{ | |
| 9021 | .pop_error_return_trace = !propagate_error_trace, | |
| 9022 | .packed_modifier = @intCast(Zir.Inst.Call.Flags.PackedModifier, @enumToInt(modifier)), | |
| 9023 | .args_len = @intCast(Zir.Inst.Call.Flags.PackedArgsLen, call.ast.params.len), | |
| 9020 | switch (callee) { | |
| 9021 | .direct => |callee_obj| { | |
| 9022 | const payload_index = try addExtra(astgen, Zir.Inst.Call{ | |
| 9023 | .callee = callee_obj, | |
| 9024 | .flags = .{ | |
| 9025 | .pop_error_return_trace = !propagate_error_trace, | |
| 9026 | .packed_modifier = @intCast(Zir.Inst.Call.Flags.PackedModifier, @enumToInt(modifier)), | |
| 9027 | .args_len = @intCast(Zir.Inst.Call.Flags.PackedArgsLen, call.ast.params.len), | |
| 9028 | }, | |
| 9029 | }); | |
| 9030 | if (call.ast.params.len != 0) { | |
| 9031 | try astgen.extra.appendSlice(astgen.gpa, astgen.scratch.items[scratch_top..]); | |
| 9032 | } | |
| 9033 | gz.astgen.instructions.set(call_index, .{ | |
| 9034 | .tag = .call, | |
| 9035 | .data = .{ .pl_node = .{ | |
| 9036 | .src_node = gz.nodeIndexToRelative(node), | |
| 9037 | .payload_index = payload_index, | |
| 9038 | } }, | |
| 9039 | }); | |
| 9040 | }, | |
| 9041 | .field => |callee_field| { | |
| 9042 | const payload_index = try addExtra(astgen, Zir.Inst.FieldCall{ | |
| 9043 | .obj_ptr = callee_field.obj_ptr, | |
| 9044 | .field_name_start = callee_field.field_name_start, | |
| 9045 | .flags = .{ | |
| 9046 | .pop_error_return_trace = !propagate_error_trace, | |
| 9047 | .packed_modifier = @intCast(Zir.Inst.Call.Flags.PackedModifier, @enumToInt(modifier)), | |
| 9048 | .args_len = @intCast(Zir.Inst.Call.Flags.PackedArgsLen, call.ast.params.len), | |
| 9049 | }, | |
| 9050 | }); | |
| 9051 | if (call.ast.params.len != 0) { | |
| 9052 | try astgen.extra.appendSlice(astgen.gpa, astgen.scratch.items[scratch_top..]); | |
| 9053 | } | |
| 9054 | gz.astgen.instructions.set(call_index, .{ | |
| 9055 | .tag = .field_call, | |
| 9056 | .data = .{ .pl_node = .{ | |
| 9057 | .src_node = gz.nodeIndexToRelative(node), | |
| 9058 | .payload_index = payload_index, | |
| 9059 | } }, | |
| 9060 | }); | |
| 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 | 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 | |
| 9040 | /// callee argument to the @call() builtin. If the lhs is a field access or the | |
| 9041 | /// @field() builtin, we need to generate a special field_call_bind instruction | |
| 9042 | /// instead of the normal field_val or field_ptr. If this is a inst.func() call, | |
| 9043 | /// this instruction will capture the value of the first argument before evaluating | |
| 9044 | /// the other arguments. We need to use .ref here to guarantee we will be able to | |
| 9045 | /// promote an lvalue to an address if the first parameter requires it. This | |
| 9046 | /// unfortunately also means we need to take a reference to any types on the lhs. | |
| 9066 | const Callee = union(enum) { | |
| 9067 | field: struct { | |
| 9068 | /// A *pointer* to the object the field is fetched on, so that we can | |
| 9069 | /// promote the lvalue to an address if the first parameter requires it. | |
| 9070 | obj_ptr: Zir.Inst.Ref, | |
| 9071 | /// Offset into `string_bytes`. | |
| 9072 | field_name_start: u32, | |
| 9073 | }, | |
| 9074 | direct: Zir.Inst.Ref, | |
| 9075 | }; | |
| 9076 | ||
| 9077 | /// calleeExpr generates the function part of a call expression (f in f(x)), but | |
| 9078 | /// *not* the callee argument to the @call() builtin. Its purpose is to | |
| 9079 | /// distinguish between standard calls and method call syntax `a.b()`. Thus, if | |
| 9080 | /// the lhs is a field access, we return using the `field` union field; | |
| 9081 | /// otherwise, we use the `direct` union field. | |
| 9047 | 9082 | fn calleeExpr( |
| 9048 | 9083 | gz: *GenZir, |
| 9049 | 9084 | scope: *Scope, |
| 9050 | 9085 | node: Ast.Node.Index, |
| 9051 | ) InnerError!Zir.Inst.Ref { | |
| 9086 | ) InnerError!Callee { | |
| 9052 | 9087 | const astgen = gz.astgen; |
| 9053 | 9088 | const tree = astgen.tree; |
| 9054 | 9089 | |
| 9055 | 9090 | const tag = tree.nodes.items(.tag)[node]; |
| 9056 | 9091 | switch (tag) { |
| 9057 | .field_access => return addFieldAccess(.field_call_bind, gz, scope, .{ .rl = .ref }, node), | |
| 9058 | ||
| 9059 | .builtin_call_two, | |
| 9060 | .builtin_call_two_comma, | |
| 9061 | .builtin_call, | |
| 9062 | .builtin_call_comma, | |
| 9063 | => { | |
| 9064 | const node_datas = tree.nodes.items(.data); | |
| 9092 | .field_access => { | |
| 9065 | 9093 | const main_tokens = tree.nodes.items(.main_token); |
| 9066 | const builtin_token = main_tokens[node]; | |
| 9067 | const builtin_name = tree.tokenSlice(builtin_token); | |
| 9068 | ||
| 9069 | var inline_params: [2]Ast.Node.Index = undefined; | |
| 9070 | var params: []Ast.Node.Index = switch (tag) { | |
| 9071 | .builtin_call, | |
| 9072 | .builtin_call_comma, | |
| 9073 | => tree.extra_data[node_datas[node].lhs..node_datas[node].rhs], | |
| 9074 | ||
| 9075 | .builtin_call_two, | |
| 9076 | .builtin_call_two_comma, | |
| 9077 | => blk: { | |
| 9078 | inline_params = .{ node_datas[node].lhs, node_datas[node].rhs }; | |
| 9079 | const len: usize = if (inline_params[0] == 0) @as(usize, 0) else if (inline_params[1] == 0) @as(usize, 1) else @as(usize, 2); | |
| 9080 | break :blk inline_params[0..len]; | |
| 9081 | }, | |
| 9082 | ||
| 9083 | else => unreachable, | |
| 9084 | }; | |
| 9094 | const node_datas = tree.nodes.items(.data); | |
| 9095 | const object_node = node_datas[node].lhs; | |
| 9096 | const dot_token = main_tokens[node]; | |
| 9097 | const field_ident = dot_token + 1; | |
| 9098 | const str_index = try astgen.identAsString(field_ident); | |
| 9099 | // Capture the object by reference so we can promote it to an | |
| 9100 | // address in Sema if needed. | |
| 9101 | const lhs = try expr(gz, scope, .{ .rl = .ref }, object_node); | |
| 9085 | 9102 | |
| 9086 | // If anything is wrong, fall back to builtinCall. | |
| 9087 | // It will emit any necessary compile errors and notes. | |
| 9088 | if (std.mem.eql(u8, builtin_name, "@field") and params.len == 2) { | |
| 9089 | const lhs = try expr(gz, scope, .{ .rl = .ref }, params[0]); | |
| 9090 | const field_name = try comptimeExpr(gz, scope, .{ .rl = .{ .ty = .const_slice_u8_type } }, params[1]); | |
| 9091 | return gz.addExtendedPayload(.field_call_bind_named, Zir.Inst.FieldNamedNode{ | |
| 9092 | .node = gz.nodeIndexToRelative(node), | |
| 9093 | .lhs = lhs, | |
| 9094 | .field_name = field_name, | |
| 9095 | }); | |
| 9096 | } | |
| 9103 | const cursor = maybeAdvanceSourceCursorToMainToken(gz, node); | |
| 9104 | try emitDbgStmt(gz, cursor); | |
| 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 | 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 | 2145 | // TODO: field type uses Zir.Inst.FieldType, it just happens to have the |
| 2146 | 2146 | // same layout as Zir.Inst.Field :^) |
| 2147 | 2147 | const pl_node = data[inst_index].pl_node; |
| ... | ... | @@ -2163,7 +2163,6 @@ fn walkInstruction( |
| 2163 | 2163 | |
| 2164 | 2164 | const lhs = @enumToInt(lhs_extra.data.lhs) - Ref.typed_value_map.len; |
| 2165 | 2165 | if (tags[lhs] != .field_val and |
| 2166 | tags[lhs] != .field_call_bind and | |
| 2167 | 2166 | tags[lhs] != .field_ptr and |
| 2168 | 2167 | tags[lhs] != .field_type) break :blk lhs_extra.data.lhs; |
| 2169 | 2168 | |
| ... | ... | @@ -2191,7 +2190,7 @@ fn walkInstruction( |
| 2191 | 2190 | const wr = blk: { |
| 2192 | 2191 | if (@enumToInt(lhs_ref) >= Ref.typed_value_map.len) { |
| 2193 | 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 | 2194 | break :blk DocData.WalkResult{ |
| 2196 | 2195 | .expr = .{ |
| 2197 | 2196 | .comptimeExpr = 0, |
src/Module.zig+15-1| ... | ... | @@ -2489,8 +2489,21 @@ pub const SrcLoc = struct { |
| 2489 | 2489 | const node_datas = tree.nodes.items(.data); |
| 2490 | 2490 | const node_tags = tree.nodes.items(.tag); |
| 2491 | 2491 | const node = src_loc.declRelativeToNodeIndex(node_off); |
| 2492 | var buf: [1]Ast.Node.Index = undefined; | |
| 2492 | 2493 | const tok_index = switch (node_tags[node]) { |
| 2493 | 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 | 2507 | else => tree.firstToken(node) - 2, |
| 2495 | 2508 | }; |
| 2496 | 2509 | const start = tree.tokens.items(.start)[tok_index]; |
| ... | ... | @@ -3083,7 +3096,8 @@ pub const LazySrcLoc = union(enum) { |
| 3083 | 3096 | /// The payload is offset from the containing Decl AST node. |
| 3084 | 3097 | /// The source location points to the field name of: |
| 3085 | 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 | 3101 | /// The Decl is determined contextually. |
| 3088 | 3102 | node_offset_field_name: i32, |
| 3089 | 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 | 920 | .bool_br_and => try sema.zirBoolBr(block, inst, false), |
| 921 | 921 | .bool_br_or => try sema.zirBoolBr(block, inst, true), |
| 922 | 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 | 925 | .closure_get => try sema.zirClosureGet(block, inst), |
| 925 | 926 | .cmp_lt => try sema.zirCmp(block, inst, .lt), |
| 926 | 927 | .cmp_lte => try sema.zirCmp(block, inst, .lte), |
| ... | ... | @@ -952,7 +953,6 @@ fn analyzeBodyInner( |
| 952 | 953 | .field_ptr_named => try sema.zirFieldPtrNamed(block, inst), |
| 953 | 954 | .field_val => try sema.zirFieldVal(block, inst), |
| 954 | 955 | .field_val_named => try sema.zirFieldValNamed(block, inst), |
| 955 | .field_call_bind => try sema.zirFieldCallBind(block, inst), | |
| 956 | 956 | .func => try sema.zirFunc(block, inst, false), |
| 957 | 957 | .func_inferred => try sema.zirFunc(block, inst, true), |
| 958 | 958 | .func_fancy => try sema.zirFuncFancy(block, inst), |
| ... | ... | @@ -1149,7 +1149,6 @@ fn analyzeBodyInner( |
| 1149 | 1149 | .wasm_memory_size => try sema.zirWasmMemorySize( block, extended), |
| 1150 | 1150 | .wasm_memory_grow => try sema.zirWasmMemoryGrow( block, extended), |
| 1151 | 1151 | .prefetch => try sema.zirPrefetch( block, extended), |
| 1152 | .field_call_bind_named => try sema.zirFieldCallBindNamed(block, extended), | |
| 1153 | 1152 | .err_set_cast => try sema.zirErrSetCast( block, extended), |
| 1154 | 1153 | .await_nosuspend => try sema.zirAwaitNosuspend( block, extended), |
| 1155 | 1154 | .select => try sema.zirSelect( block, extended), |
| ... | ... | @@ -6262,38 +6261,50 @@ fn zirCall( |
| 6262 | 6261 | sema: *Sema, |
| 6263 | 6262 | block: *Block, |
| 6264 | 6263 | inst: Zir.Inst.Index, |
| 6264 | comptime kind: enum { direct, field }, | |
| 6265 | 6265 | ) CompileError!Air.Inst.Ref { |
| 6266 | 6266 | const tracy = trace(@src()); |
| 6267 | 6267 | defer tracy.end(); |
| 6268 | 6268 | |
| 6269 | 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 | 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 | 6277 | const args_len = extra.data.flags.args_len; |
| 6274 | 6278 | |
| 6275 | 6279 | const modifier = @intToEnum(std.builtin.CallModifier, extra.data.flags.packed_modifier); |
| 6276 | 6280 | const ensure_result_used = extra.data.flags.ensure_result_used; |
| 6277 | 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 | 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 | 6293 | var bound_arg_src: ?LazySrcLoc = null; |
| 6287 | if (func_type.tag() == .bound_fn) { | |
| 6288 | bound_arg_src = func_src; | |
| 6289 | const bound_func = try sema.resolveValue(block, .unneeded, func, ""); | |
| 6290 | const bound_data = &bound_func.cast(Value.Payload.BoundFn).?.data; | |
| 6291 | func = bound_data.func_inst; | |
| 6292 | resolved_args = try sema.arena.alloc(Air.Inst.Ref, args_len + 1); | |
| 6293 | resolved_args[arg_index] = bound_data.arg0_inst; | |
| 6294 | arg_index += 1; | |
| 6295 | } else { | |
| 6296 | resolved_args = try sema.arena.alloc(Air.Inst.Ref, args_len); | |
| 6294 | var func: Air.Inst.Ref = undefined; | |
| 6295 | var arg_index: u32 = 0; | |
| 6296 | switch (callee) { | |
| 6297 | .direct => |func_inst| { | |
| 6298 | resolved_args = try sema.arena.alloc(Air.Inst.Ref, args_len); | |
| 6299 | func = func_inst; | |
| 6300 | }, | |
| 6301 | .method => |method| { | |
| 6302 | resolved_args = try sema.arena.alloc(Air.Inst.Ref, args_len + 1); | |
| 6303 | func = method.func_inst; | |
| 6304 | resolved_args[0] = method.arg0_inst; | |
| 6305 | arg_index += 1; | |
| 6306 | bound_arg_src = callee_src; | |
| 6307 | }, | |
| 6297 | 6308 | } |
| 6298 | 6309 | |
| 6299 | 6310 | const callee_ty = sema.typeOf(func); |
| ... | ... | @@ -6308,10 +6319,11 @@ fn zirCall( |
| 6308 | 6319 | }, |
| 6309 | 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 | 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 | 6328 | const args_body = sema.code.extra[extra.end..]; |
| 6317 | 6329 | |
| ... | ... | @@ -6369,7 +6381,7 @@ fn zirCall( |
| 6369 | 6381 | !block.is_comptime and !block.is_typeof and (input_is_error or pop_error_return_trace)) |
| 6370 | 6382 | { |
| 6371 | 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 | 6387 | const return_ty = sema.typeOf(call_inst); |
| ... | ... | @@ -6398,11 +6410,11 @@ fn zirCall( |
| 6398 | 6410 | } |
| 6399 | 6411 | |
| 6400 | 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 | 6415 | return call_inst; |
| 6404 | 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 | 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 | 9482 | fn zirFieldValNamed(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air.Inst.Ref { |
| 9484 | 9483 | const tracy = trace(@src()); |
| 9485 | 9484 | defer tracy.end(); |
| ... | ... | @@ -9506,18 +9505,6 @@ fn zirFieldPtrNamed(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileErr |
| 9506 | 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 | 9508 | fn zirIntCast(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air.Inst.Ref { |
| 9522 | 9509 | const tracy = trace(@src()); |
| 9523 | 9510 | defer tracy.end(); |
| ... | ... | @@ -21673,25 +21660,9 @@ fn zirBuiltinCall(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError |
| 21673 | 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; | |
| 21677 | ||
| 21678 | // Desugar bound functions here | |
| 21679 | var bound_arg_src: ?LazySrcLoc = null; | |
| 21680 | if (sema.typeOf(func).tag() == .bound_fn) { | |
| 21681 | bound_arg_src = func_src; | |
| 21682 | const bound_func = try sema.resolveValue(block, .unneeded, func, ""); | |
| 21683 | const bound_data = &bound_func.cast(Value.Payload.BoundFn).?.data; | |
| 21684 | func = bound_data.func_inst; | |
| 21685 | resolved_args = try sema.arena.alloc(Air.Inst.Ref, args_ty.structFieldCount() + 1); | |
| 21686 | resolved_args[0] = bound_data.arg0_inst; | |
| 21687 | for (resolved_args[1..], 0..) |*resolved, i| { | |
| 21688 | resolved.* = try sema.tupleFieldValByIndex(block, args_src, args, @intCast(u32, i), args_ty); | |
| 21689 | } | |
| 21690 | } else { | |
| 21691 | resolved_args = try sema.arena.alloc(Air.Inst.Ref, args_ty.structFieldCount()); | |
| 21692 | for (resolved_args, 0..) |*resolved, i| { | |
| 21693 | resolved.* = try sema.tupleFieldValByIndex(block, args_src, args, @intCast(u32, i), args_ty); | |
| 21694 | } | |
| 21663 | var resolved_args: []Air.Inst.Ref = try sema.arena.alloc(Air.Inst.Ref, args_ty.structFieldCount()); | |
| 21664 | for (resolved_args, 0..) |*resolved, i| { | |
| 21665 | resolved.* = try sema.tupleFieldValByIndex(block, args_src, args, @intCast(u32, i), args_ty); | |
| 21695 | 21666 | } |
| 21696 | 21667 | |
| 21697 | 21668 | const callee_ty = sema.typeOf(func); |
| ... | ... | @@ -21708,10 +21679,10 @@ fn zirBuiltinCall(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError |
| 21708 | 21679 | } |
| 21709 | 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 | 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 | 21688 | fn zirFieldParentPtr(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air.Inst.Ref { |
| ... | ... | @@ -24175,6 +24146,16 @@ fn fieldPtr( |
| 24175 | 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 | 24159 | fn fieldCallBind( |
| 24179 | 24160 | sema: *Sema, |
| 24180 | 24161 | block: *Block, |
| ... | ... | @@ -24182,7 +24163,7 @@ fn fieldCallBind( |
| 24182 | 24163 | raw_ptr: Air.Inst.Ref, |
| 24183 | 24164 | field_name: []const u8, |
| 24184 | 24165 | field_name_src: LazySrcLoc, |
| 24185 | ) CompileError!Air.Inst.Ref { | |
| 24166 | ) CompileError!ResolvedFieldCallee { | |
| 24186 | 24167 | // When editing this function, note that there is corresponding logic to be edited |
| 24187 | 24168 | // in `fieldVal`. This function takes a pointer and returns a pointer. |
| 24188 | 24169 | |
| ... | ... | @@ -24202,7 +24183,6 @@ fn fieldCallBind( |
| 24202 | 24183 | else |
| 24203 | 24184 | raw_ptr; |
| 24204 | 24185 | |
| 24205 | const arena = sema.arena; | |
| 24206 | 24186 | find_field: { |
| 24207 | 24187 | switch (concrete_ty.zigTypeTag()) { |
| 24208 | 24188 | .Struct => { |
| ... | ... | @@ -24216,7 +24196,7 @@ fn fieldCallBind( |
| 24216 | 24196 | return sema.finishFieldCallBind(block, src, ptr_ty, field.ty, field_index, object_ptr); |
| 24217 | 24197 | } else if (struct_ty.isTuple()) { |
| 24218 | 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 | 24201 | if (std.fmt.parseUnsigned(u32, field_name, 10)) |field_index| { |
| 24222 | 24202 | if (field_index >= struct_ty.structFieldCount()) break :find_field; |
| ... | ... | @@ -24243,7 +24223,7 @@ fn fieldCallBind( |
| 24243 | 24223 | }, |
| 24244 | 24224 | .Type => { |
| 24245 | 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 | 24228 | else => {}, |
| 24249 | 24229 | } |
| ... | ... | @@ -24272,54 +24252,47 @@ fn fieldCallBind( |
| 24272 | 24252 | first_param_type.childType().eql(concrete_ty, sema.mod))) |
| 24273 | 24253 | { |
| 24274 | 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 | 24258 | // TODO: bound fn calls on rvalues should probably |
| 24276 | 24259 | // generate a by-value argument somehow. |
| 24277 | const ty = Type.Tag.bound_fn.init(); | |
| 24278 | const value = try Value.Tag.bound_fn.create(arena, .{ | |
| 24260 | return .{ .method = .{ | |
| 24279 | 24261 | .func_inst = decl_val, |
| 24280 | 24262 | .arg0_inst = object_ptr, |
| 24281 | }); | |
| 24282 | return sema.addConstant(ty, value); | |
| 24263 | } }; | |
| 24283 | 24264 | } else if (first_param_type.eql(concrete_ty, sema.mod)) { |
| 24284 | 24265 | const deref = try sema.analyzeLoad(block, src, object_ptr, src); |
| 24285 | const ty = Type.Tag.bound_fn.init(); | |
| 24286 | const value = try Value.Tag.bound_fn.create(arena, .{ | |
| 24266 | return .{ .method = .{ | |
| 24287 | 24267 | .func_inst = decl_val, |
| 24288 | 24268 | .arg0_inst = deref, |
| 24289 | }); | |
| 24290 | return sema.addConstant(ty, value); | |
| 24269 | } }; | |
| 24291 | 24270 | } else if (first_param_type.zigTypeTag() == .Optional) { |
| 24292 | 24271 | var opt_buf: Type.Payload.ElemType = undefined; |
| 24293 | 24272 | const child = first_param_type.optionalChild(&opt_buf); |
| 24294 | 24273 | if (child.eql(concrete_ty, sema.mod)) { |
| 24295 | 24274 | const deref = try sema.analyzeLoad(block, src, object_ptr, src); |
| 24296 | const ty = Type.Tag.bound_fn.init(); | |
| 24297 | const value = try Value.Tag.bound_fn.create(arena, .{ | |
| 24275 | return .{ .method = .{ | |
| 24298 | 24276 | .func_inst = decl_val, |
| 24299 | 24277 | .arg0_inst = deref, |
| 24300 | }); | |
| 24301 | return sema.addConstant(ty, value); | |
| 24278 | } }; | |
| 24302 | 24279 | } else if (child.zigTypeTag() == .Pointer and |
| 24303 | 24280 | child.ptrSize() == .One and |
| 24304 | 24281 | child.childType().eql(concrete_ty, sema.mod)) |
| 24305 | 24282 | { |
| 24306 | const ty = Type.Tag.bound_fn.init(); | |
| 24307 | const value = try Value.Tag.bound_fn.create(arena, .{ | |
| 24283 | return .{ .method = .{ | |
| 24308 | 24284 | .func_inst = decl_val, |
| 24309 | 24285 | .arg0_inst = object_ptr, |
| 24310 | }); | |
| 24311 | return sema.addConstant(ty, value); | |
| 24286 | } }; | |
| 24312 | 24287 | } |
| 24313 | 24288 | } else if (first_param_type.zigTypeTag() == .ErrorUnion and |
| 24314 | 24289 | first_param_type.errorUnionPayload().eql(concrete_ty, sema.mod)) |
| 24315 | 24290 | { |
| 24316 | 24291 | const deref = try sema.analyzeLoad(block, src, object_ptr, src); |
| 24317 | const ty = Type.Tag.bound_fn.init(); | |
| 24318 | const value = try Value.Tag.bound_fn.create(arena, .{ | |
| 24292 | return .{ .method = .{ | |
| 24319 | 24293 | .func_inst = decl_val, |
| 24320 | 24294 | .arg0_inst = deref, |
| 24321 | }); | |
| 24322 | return sema.addConstant(ty, value); | |
| 24295 | } }; | |
| 24323 | 24296 | } |
| 24324 | 24297 | } |
| 24325 | 24298 | break :found_decl decl_idx; |
| ... | ... | @@ -24351,7 +24324,7 @@ fn finishFieldCallBind( |
| 24351 | 24324 | field_ty: Type, |
| 24352 | 24325 | field_index: u32, |
| 24353 | 24326 | object_ptr: Air.Inst.Ref, |
| 24354 | ) CompileError!Air.Inst.Ref { | |
| 24327 | ) CompileError!ResolvedFieldCallee { | |
| 24355 | 24328 | const arena = sema.arena; |
| 24356 | 24329 | const ptr_field_ty = try Type.ptr(arena, sema.mod, .{ |
| 24357 | 24330 | .pointee_type = field_ty, |
| ... | ... | @@ -24362,7 +24335,7 @@ fn finishFieldCallBind( |
| 24362 | 24335 | const container_ty = ptr_ty.childType(); |
| 24363 | 24336 | if (container_ty.zigTypeTag() == .Struct) { |
| 24364 | 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 | 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 | 24354 | try sema.requireRuntimeBlock(block, src, null); |
| 24382 | 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 | 24359 | fn namespaceLookup( |
| ... | ... | @@ -31281,7 +31254,6 @@ pub fn resolveTypeRequiresComptime(sema: *Sema, ty: Type) CompileError!bool { |
| 31281 | 31254 | |
| 31282 | 31255 | .inferred_alloc_mut => unreachable, |
| 31283 | 31256 | .inferred_alloc_const => unreachable, |
| 31284 | .bound_fn => unreachable, | |
| 31285 | 31257 | |
| 31286 | 31258 | .array, |
| 31287 | 31259 | .array_sentinel, |
| ... | ... | @@ -32666,7 +32638,6 @@ pub fn typeHasOnePossibleValue(sema: *Sema, ty: Type) CompileError!?Value { |
| 32666 | 32638 | .single_const_pointer, |
| 32667 | 32639 | .single_mut_pointer, |
| 32668 | 32640 | .pointer, |
| 32669 | .bound_fn, | |
| 32670 | 32641 | => return null, |
| 32671 | 32642 | |
| 32672 | 32643 | .optional => { |
| ... | ... | @@ -33308,7 +33279,6 @@ pub fn typeRequiresComptime(sema: *Sema, ty: Type) CompileError!bool { |
| 33308 | 33279 | |
| 33309 | 33280 | .inferred_alloc_mut => unreachable, |
| 33310 | 33281 | .inferred_alloc_const => unreachable, |
| 33311 | .bound_fn => unreachable, | |
| 33312 | 33282 | |
| 33313 | 33283 | .array, |
| 33314 | 33284 | .array_sentinel, |
src/TypedValue.zig-4| ... | ... | @@ -499,10 +499,6 @@ pub fn print( |
| 499 | 499 | // TODO these should not appear in this function |
| 500 | 500 | .inferred_alloc => return writer.writeAll("(inferred allocation value)"), |
| 501 | 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 | 502 | .generic_poison_type => return writer.writeAll("(generic poison type)"), |
| 507 | 503 | .generic_poison => return writer.writeAll("(generic poison)"), |
| 508 | 504 | .runtime_value => return writer.writeAll("[runtime value]"), |
src/Zir.zig+24-28| ... | ... | @@ -297,6 +297,14 @@ pub const Inst = struct { |
| 297 | 297 | /// Uses the `pl_node` union field with payload `Call`. |
| 298 | 298 | /// AST node is the function call. |
| 299 | 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 | 308 | /// Implements the `@call` builtin. |
| 301 | 309 | /// Uses the `pl_node` union field with payload `BuiltinCall`. |
| 302 | 310 | /// AST node is the builtin call. |
| ... | ... | @@ -432,15 +440,6 @@ pub const Inst = struct { |
| 432 | 440 | /// This instruction also accepts a pointer. |
| 433 | 441 | /// Uses `pl_node` field. The AST node is the a.b syntax. Payload is Field. |
| 434 | 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 | 443 | /// Given a pointer to a struct or object that contains virtual fields, returns a pointer |
| 445 | 444 | /// to the named field. The field name is a comptime instruction. Used by @field. |
| 446 | 445 | /// Uses `pl_node` field. The AST node is the builtin call. Payload is FieldNamed. |
| ... | ... | @@ -1051,6 +1050,7 @@ pub const Inst = struct { |
| 1051 | 1050 | .bool_br_or, |
| 1052 | 1051 | .bool_not, |
| 1053 | 1052 | .call, |
| 1053 | .field_call, | |
| 1054 | 1054 | .cmp_lt, |
| 1055 | 1055 | .cmp_lte, |
| 1056 | 1056 | .cmp_eq, |
| ... | ... | @@ -1083,7 +1083,6 @@ pub const Inst = struct { |
| 1083 | 1083 | .field_ptr, |
| 1084 | 1084 | .field_ptr_init, |
| 1085 | 1085 | .field_val, |
| 1086 | .field_call_bind, | |
| 1087 | 1086 | .field_ptr_named, |
| 1088 | 1087 | .field_val_named, |
| 1089 | 1088 | .func, |
| ... | ... | @@ -1361,6 +1360,7 @@ pub const Inst = struct { |
| 1361 | 1360 | .bool_br_or, |
| 1362 | 1361 | .bool_not, |
| 1363 | 1362 | .call, |
| 1363 | .field_call, | |
| 1364 | 1364 | .cmp_lt, |
| 1365 | 1365 | .cmp_lte, |
| 1366 | 1366 | .cmp_eq, |
| ... | ... | @@ -1383,7 +1383,6 @@ pub const Inst = struct { |
| 1383 | 1383 | .field_ptr, |
| 1384 | 1384 | .field_ptr_init, |
| 1385 | 1385 | .field_val, |
| 1386 | .field_call_bind, | |
| 1387 | 1386 | .field_ptr_named, |
| 1388 | 1387 | .field_val_named, |
| 1389 | 1388 | .func, |
| ... | ... | @@ -1601,6 +1600,7 @@ pub const Inst = struct { |
| 1601 | 1600 | .check_comptime_control_flow = .un_node, |
| 1602 | 1601 | .for_len = .pl_node, |
| 1603 | 1602 | .call = .pl_node, |
| 1603 | .field_call = .pl_node, | |
| 1604 | 1604 | .cmp_lt = .pl_node, |
| 1605 | 1605 | .cmp_lte = .pl_node, |
| 1606 | 1606 | .cmp_eq = .pl_node, |
| ... | ... | @@ -1641,7 +1641,6 @@ pub const Inst = struct { |
| 1641 | 1641 | .field_val = .pl_node, |
| 1642 | 1642 | .field_ptr_named = .pl_node, |
| 1643 | 1643 | .field_val_named = .pl_node, |
| 1644 | .field_call_bind = .pl_node, | |
| 1645 | 1644 | .func = .pl_node, |
| 1646 | 1645 | .func_inferred = .pl_node, |
| 1647 | 1646 | .func_fancy = .pl_node, |
| ... | ... | @@ -1955,16 +1954,6 @@ pub const Inst = struct { |
| 1955 | 1954 | /// The `@prefetch` builtin. |
| 1956 | 1955 | /// `operand` is payload index to `BinNode`. |
| 1957 | 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 | 1957 | /// Implements the `@fence` builtin. |
| 1969 | 1958 | /// `operand` is payload index to `UnNode`. |
| 1970 | 1959 | fence, |
| ... | ... | @@ -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 | 2918 | pub const TypeOfPeer = struct { |
| 2917 | 2919 | src_node: i32, |
| 2918 | 2920 | body_len: u32, |
| ... | ... | @@ -3187,12 +3189,6 @@ pub const Inst = struct { |
| 3187 | 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 | 3192 | pub const As = struct { |
| 3197 | 3193 | dest_type: Ref, |
| 3198 | 3194 | operand: Ref, |
src/print_air.zig-1| ... | ... | @@ -369,7 +369,6 @@ const Writer = struct { |
| 369 | 369 | .inferred_alloc_const => try s.writeAll("(inferred_alloc_const)"), |
| 370 | 370 | .inferred_alloc_mut => try s.writeAll("(inferred_alloc_mut)"), |
| 371 | 371 | .generic_poison => try s.writeAll("(generic_poison)"), |
| 372 | .bound_fn => try s.writeAll("(bound_fn)"), | |
| 373 | 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 | 362 | .@"export" => try self.writePlNodeExport(stream, inst), |
| 363 | 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 | 368 | .block, |
| 368 | 369 | .block_comptime, |
| ... | ... | @@ -392,7 +393,6 @@ const Writer = struct { |
| 392 | 393 | .field_ptr, |
| 393 | 394 | .field_ptr_init, |
| 394 | 395 | .field_val, |
| 395 | .field_call_bind, | |
| 396 | 396 | => try self.writePlNodeField(stream, inst), |
| 397 | 397 | |
| 398 | 398 | .field_ptr_named, |
| ... | ... | @@ -543,15 +543,6 @@ const Writer = struct { |
| 543 | 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 | 546 | .builtin_async_call => try self.writeBuiltinAsyncCall(stream, extended), |
| 556 | 547 | .cmpxchg => try self.writeCmpxchg(stream, extended), |
| 557 | 548 | } |
| ... | ... | @@ -1176,9 +1167,18 @@ const Writer = struct { |
| 1176 | 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 | 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 | 1182 | const args_len = extra.data.flags.args_len; |
| 1183 | 1183 | const body = self.code.extra[extra.end..]; |
| 1184 | 1184 | |
| ... | ... | @@ -1186,7 +1186,14 @@ const Writer = struct { |
| 1186 | 1186 | try stream.writeAll("nodiscard "); |
| 1187 | 1187 | } |
| 1188 | 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 | 1197 | try stream.writeAll(", ["); |
| 1191 | 1198 | |
| 1192 | 1199 | self.indent += 2; |
src/type.zig+1-17| ... | ... | @@ -156,8 +156,6 @@ pub const Type = extern union { |
| 156 | 156 | .union_tagged, |
| 157 | 157 | .type_info, |
| 158 | 158 | => return .Union, |
| 159 | ||
| 160 | .bound_fn => unreachable, | |
| 161 | 159 | } |
| 162 | 160 | } |
| 163 | 161 | |
| ... | ... | @@ -933,7 +931,6 @@ pub const Type = extern union { |
| 933 | 931 | // for example, a was resolved into .union_tagged but b was one of these tags. |
| 934 | 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 | 1239 | // we can't hash these based on tags because they wouldn't match the expanded version. |
| 1243 | 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 | 1345 | .type_info, |
| 1350 | 1346 | .@"anyframe", |
| 1351 | 1347 | .generic_poison, |
| 1352 | .bound_fn, | |
| 1353 | 1348 | => unreachable, |
| 1354 | 1349 | |
| 1355 | 1350 | .array_u8, |
| ... | ... | @@ -1613,7 +1608,6 @@ pub const Type = extern union { |
| 1613 | 1608 | .comptime_int, |
| 1614 | 1609 | .comptime_float, |
| 1615 | 1610 | .noreturn, |
| 1616 | .bound_fn, | |
| 1617 | 1611 | => return writer.writeAll(@tagName(t)), |
| 1618 | 1612 | |
| 1619 | 1613 | .enum_literal => return writer.writeAll("@Type(.EnumLiteral)"), |
| ... | ... | @@ -1949,7 +1943,6 @@ pub const Type = extern union { |
| 1949 | 1943 | .inferred_alloc_const => unreachable, |
| 1950 | 1944 | .inferred_alloc_mut => unreachable, |
| 1951 | 1945 | .generic_poison => unreachable, |
| 1952 | .bound_fn => unreachable, | |
| 1953 | 1946 | |
| 1954 | 1947 | // TODO get rid of these Type.Tag values. |
| 1955 | 1948 | .atomic_order => unreachable, |
| ... | ... | @@ -2468,7 +2461,6 @@ pub const Type = extern union { |
| 2468 | 2461 | .enum_literal, |
| 2469 | 2462 | .empty_struct, |
| 2470 | 2463 | .empty_struct_literal, |
| 2471 | .bound_fn, | |
| 2472 | 2464 | // These are function *bodies*, not pointers. |
| 2473 | 2465 | // Special exceptions have to be made when emitting functions due to |
| 2474 | 2466 | // this returning false. |
| ... | ... | @@ -2703,7 +2695,6 @@ pub const Type = extern union { |
| 2703 | 2695 | |
| 2704 | 2696 | .inferred_alloc_mut => unreachable, |
| 2705 | 2697 | .inferred_alloc_const => unreachable, |
| 2706 | .bound_fn => unreachable, | |
| 2707 | 2698 | |
| 2708 | 2699 | .array, |
| 2709 | 2700 | .array_sentinel, |
| ... | ... | @@ -3182,7 +3173,6 @@ pub const Type = extern union { |
| 3182 | 3173 | .noreturn, |
| 3183 | 3174 | .inferred_alloc_const, |
| 3184 | 3175 | .inferred_alloc_mut, |
| 3185 | .bound_fn, | |
| 3186 | 3176 | => unreachable, |
| 3187 | 3177 | |
| 3188 | 3178 | .generic_poison => unreachable, |
| ... | ... | @@ -3282,7 +3272,6 @@ pub const Type = extern union { |
| 3282 | 3272 | .fn_ccc_void_no_args => unreachable, // represents machine code; not a pointer |
| 3283 | 3273 | .function => unreachable, // represents machine code; not a pointer |
| 3284 | 3274 | .@"opaque" => unreachable, // no size available |
| 3285 | .bound_fn => unreachable, | |
| 3286 | 3275 | .noreturn => unreachable, |
| 3287 | 3276 | .inferred_alloc_const => unreachable, |
| 3288 | 3277 | .inferred_alloc_mut => unreachable, |
| ... | ... | @@ -3630,7 +3619,6 @@ pub const Type = extern union { |
| 3630 | 3619 | .inferred_alloc_mut => unreachable, |
| 3631 | 3620 | .@"opaque" => unreachable, |
| 3632 | 3621 | .generic_poison => unreachable, |
| 3633 | .bound_fn => unreachable, | |
| 3634 | 3622 | |
| 3635 | 3623 | .void => return 0, |
| 3636 | 3624 | .bool, .u1 => return 1, |
| ... | ... | @@ -5042,7 +5030,6 @@ pub const Type = extern union { |
| 5042 | 5030 | .single_const_pointer, |
| 5043 | 5031 | .single_mut_pointer, |
| 5044 | 5032 | .pointer, |
| 5045 | .bound_fn, | |
| 5046 | 5033 | => return null, |
| 5047 | 5034 | |
| 5048 | 5035 | .optional => { |
| ... | ... | @@ -5245,7 +5232,6 @@ pub const Type = extern union { |
| 5245 | 5232 | |
| 5246 | 5233 | .inferred_alloc_mut => unreachable, |
| 5247 | 5234 | .inferred_alloc_const => unreachable, |
| 5248 | .bound_fn => unreachable, | |
| 5249 | 5235 | |
| 5250 | 5236 | .array, |
| 5251 | 5237 | .array_sentinel, |
| ... | ... | @@ -6081,7 +6067,6 @@ pub const Type = extern union { |
| 6081 | 6067 | inferred_alloc_mut, |
| 6082 | 6068 | /// Same as `inferred_alloc_mut` but the local is `var` not `const`. |
| 6083 | 6069 | inferred_alloc_const, // See last_no_payload_tag below. |
| 6084 | bound_fn, | |
| 6085 | 6070 | // After this, the tag requires a payload. |
| 6086 | 6071 | |
| 6087 | 6072 | array_u8, |
| ... | ... | @@ -6126,7 +6111,7 @@ pub const Type = extern union { |
| 6126 | 6111 | enum_full, |
| 6127 | 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 | 6115 | pub const no_payload_count = @enumToInt(last_no_payload_tag) + 1; |
| 6131 | 6116 | |
| 6132 | 6117 | pub fn Type(comptime t: Tag) type { |
| ... | ... | @@ -6199,7 +6184,6 @@ pub const Type = extern union { |
| 6199 | 6184 | .extern_options, |
| 6200 | 6185 | .type_info, |
| 6201 | 6186 | .@"anyframe", |
| 6202 | .bound_fn, | |
| 6203 | 6187 | => @compileError("Type Tag " ++ @tagName(t) ++ " has no payload"), |
| 6204 | 6188 | |
| 6205 | 6189 | .array_u8, |
src/value.zig-20| ... | ... | @@ -183,10 +183,6 @@ pub const Value = extern union { |
| 183 | 183 | /// Used to coordinate alloc_inferred, store_to_inferred_ptr, and resolve_inferred_alloc |
| 184 | 184 | /// instructions for comptime code. |
| 185 | 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 | 186 | /// The ABI alignment of the payload type. |
| 191 | 187 | lazy_align, |
| 192 | 188 | /// The ABI size of the payload type. |
| ... | ... | @@ -326,7 +322,6 @@ pub const Value = extern union { |
| 326 | 322 | .inferred_alloc_comptime => Payload.InferredAllocComptime, |
| 327 | 323 | .aggregate => Payload.Aggregate, |
| 328 | 324 | .@"union" => Payload.Union, |
| 329 | .bound_fn => Payload.BoundFn, | |
| 330 | 325 | .comptime_field_ptr => Payload.ComptimeFieldPtr, |
| 331 | 326 | }; |
| 332 | 327 | } |
| ... | ... | @@ -477,7 +472,6 @@ pub const Value = extern union { |
| 477 | 472 | .extern_options_type, |
| 478 | 473 | .type_info_type, |
| 479 | 474 | .generic_poison, |
| 480 | .bound_fn, | |
| 481 | 475 | => unreachable, |
| 482 | 476 | |
| 483 | 477 | .ty, .lazy_align, .lazy_size => { |
| ... | ... | @@ -837,10 +831,6 @@ pub const Value = extern union { |
| 837 | 831 | try out_stream.writeAll("(opt_payload_ptr)"); |
| 838 | 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 | 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 | 5652 | /// Big enough to fit any non-BigInt value |
test/behavior/member_func.zig-12| ... | ... | @@ -86,18 +86,6 @@ test "@field field calls" { |
| 86 | 86 | const pv = &v; |
| 87 | 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 | 89 | v.func_field = HasFuncs.one; |
| 102 | 90 | try expect(@field(v, "func_field")(0) == 1); |
| 103 | 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 | 6 | var s: S = undefined; |
| 7 | 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 | 10 | // error |
| 15 | 11 | // backend=stage2 |
| ... | ... | @@ -17,5 +13,3 @@ pub export fn entry2() void { |
| 17 | 13 | // |
| 18 | 14 | // :7:6: error: member function expected 2 argument(s), found 1 |
| 19 | 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 |