Commit 38b83d9d93
Changed files (16)
lib
std
src
test
behavior
cases
compile_errors
lib/std/crypto/siphash.zig
@@ -167,8 +167,8 @@ fn SipHashStateless(comptime T: type, comptime c_rounds: usize, comptime d_round
pub fn hash(msg: []const u8, key: *const [key_length]u8) T {
const aligned_len = msg.len - (msg.len % 8);
var c = Self.init(key);
- @call(.always_inline, c.update, .{msg[0..aligned_len]});
- return @call(.always_inline, c.final, .{msg[aligned_len..]});
+ @call(.always_inline, update, .{ &c, msg[0..aligned_len] });
+ return @call(.always_inline, final, .{ &c, msg[aligned_len..] });
}
};
}
lib/std/hash/auto_hash.zig
@@ -64,9 +64,13 @@ pub fn hashArray(hasher: anytype, key: anytype, comptime strat: HashStrategy) vo
/// Strategy is provided to determine if pointers should be followed or not.
pub fn hash(hasher: anytype, key: anytype, comptime strat: HashStrategy) void {
const Key = @TypeOf(key);
+ const Hasher = switch (@typeInfo(@TypeOf(hasher))) {
+ .Pointer => |ptr| ptr.child,
+ else => @TypeOf(hasher),
+ };
if (strat == .Shallow and comptime meta.trait.hasUniqueRepresentation(Key)) {
- @call(.always_inline, hasher.update, .{mem.asBytes(&key)});
+ @call(.always_inline, Hasher.update, .{ hasher, mem.asBytes(&key) });
return;
}
@@ -89,12 +93,12 @@ pub fn hash(hasher: anytype, key: anytype, comptime strat: HashStrategy) void {
// TODO Check if the situation is better after #561 is resolved.
.Int => {
if (comptime meta.trait.hasUniqueRepresentation(Key)) {
- @call(.always_inline, hasher.update, .{std.mem.asBytes(&key)});
+ @call(.always_inline, Hasher.update, .{ hasher, std.mem.asBytes(&key) });
} else {
// Take only the part containing the key value, the remaining
// bytes are undefined and must not be hashed!
const byte_size = comptime std.math.divCeil(comptime_int, @bitSizeOf(Key), 8) catch unreachable;
- @call(.always_inline, hasher.update, .{std.mem.asBytes(&key)[0..byte_size]});
+ @call(.always_inline, Hasher.update, .{ hasher, std.mem.asBytes(&key)[0..byte_size] });
}
},
lib/std/hash/wyhash.zig
@@ -65,7 +65,7 @@ const WyhashStateless = struct {
var off: usize = 0;
while (off < b.len) : (off += 32) {
- @call(.always_inline, self.round, .{b[off..][0..32]});
+ @call(.always_inline, round, .{ self, b[off..][0..32] });
}
self.msg_len += b.len;
@@ -121,8 +121,8 @@ const WyhashStateless = struct {
const aligned_len = input.len - (input.len % 32);
var c = WyhashStateless.init(seed);
- @call(.always_inline, c.update, .{input[0..aligned_len]});
- return @call(.always_inline, c.final, .{input[aligned_len..]});
+ @call(.always_inline, update, .{ &c, input[0..aligned_len] });
+ return @call(.always_inline, final, .{ &c, input[aligned_len..] });
}
};
lib/std/Thread/Mutex.zig
@@ -169,7 +169,7 @@ const FutexImpl = struct {
}
}
- inline fn lockFast(self: *@This(), comptime casFn: []const u8) bool {
+ inline fn lockFast(self: *@This(), comptime cas_fn_name: []const u8) bool {
// On x86, use `lock bts` instead of `lock cmpxchg` as:
// - they both seem to mark the cache-line as modified regardless: https://stackoverflow.com/a/63350048
// - `lock bts` is smaller instruction-wise which makes it better for inlining
@@ -180,7 +180,8 @@ const FutexImpl = struct {
// Acquire barrier ensures grabbing the lock happens before the critical section
// and that the previous lock holder's critical section happens before we grab the lock.
- return @field(self.state, casFn)(unlocked, locked, .Acquire, .Monotonic) == null;
+ const casFn = @field(@TypeOf(self.state), cas_fn_name);
+ return casFn(&self.state, unlocked, locked, .Acquire, .Monotonic) == null;
}
fn lockSlow(self: *@This()) void {
src/AstGen.zig
@@ -2482,7 +2482,7 @@ fn addEnsureResult(gz: *GenZir, maybe_unused_result: Zir.Inst.Ref, statement: As
switch (zir_tags[inst]) {
// For some instructions, modify the zir data
// so we can avoid a separate ensure_result_used instruction.
- .call => {
+ .call, .field_call => {
const extra_index = gz.astgen.instructions.items(.data)[inst].pl_node.payload_index;
const slot = &gz.astgen.extra.items[extra_index];
var flags = @bitCast(Zir.Inst.Call.Flags, slot.*);
@@ -2557,7 +2557,6 @@ fn addEnsureResult(gz: *GenZir, maybe_unused_result: Zir.Inst.Ref, statement: As
.field_ptr,
.field_ptr_init,
.field_val,
- .field_call_bind,
.field_ptr_named,
.field_val_named,
.func,
@@ -8516,7 +8515,7 @@ fn builtinCall(
},
.call => {
const modifier = try comptimeExpr(gz, scope, .{ .rl = .{ .coerced_ty = .modifier_type } }, params[0]);
- const callee = try calleeExpr(gz, scope, params[1]);
+ const callee = try expr(gz, scope, .{ .rl = .none }, params[1]);
const args = try expr(gz, scope, .{ .rl = .none }, params[2]);
const result = try gz.addPlNode(.builtin_call, node, Zir.Inst.BuiltinCall{
.modifier = modifier,
@@ -8976,7 +8975,10 @@ fn callExpr(
} });
}
- assert(callee != .none);
+ switch (callee) {
+ .direct => |obj| assert(obj != .none),
+ .field => |field| assert(field.obj_ptr != .none),
+ }
assert(node != 0);
const call_index = @intCast(Zir.Inst.Index, astgen.instructions.len);
@@ -9015,89 +9017,98 @@ fn callExpr(
else => false,
};
- const payload_index = try addExtra(astgen, Zir.Inst.Call{
- .callee = callee,
- .flags = .{
- .pop_error_return_trace = !propagate_error_trace,
- .packed_modifier = @intCast(Zir.Inst.Call.Flags.PackedModifier, @enumToInt(modifier)),
- .args_len = @intCast(Zir.Inst.Call.Flags.PackedArgsLen, call.ast.params.len),
+ switch (callee) {
+ .direct => |callee_obj| {
+ const payload_index = try addExtra(astgen, Zir.Inst.Call{
+ .callee = callee_obj,
+ .flags = .{
+ .pop_error_return_trace = !propagate_error_trace,
+ .packed_modifier = @intCast(Zir.Inst.Call.Flags.PackedModifier, @enumToInt(modifier)),
+ .args_len = @intCast(Zir.Inst.Call.Flags.PackedArgsLen, call.ast.params.len),
+ },
+ });
+ if (call.ast.params.len != 0) {
+ try astgen.extra.appendSlice(astgen.gpa, astgen.scratch.items[scratch_top..]);
+ }
+ gz.astgen.instructions.set(call_index, .{
+ .tag = .call,
+ .data = .{ .pl_node = .{
+ .src_node = gz.nodeIndexToRelative(node),
+ .payload_index = payload_index,
+ } },
+ });
+ },
+ .field => |callee_field| {
+ const payload_index = try addExtra(astgen, Zir.Inst.FieldCall{
+ .obj_ptr = callee_field.obj_ptr,
+ .field_name_start = callee_field.field_name_start,
+ .flags = .{
+ .pop_error_return_trace = !propagate_error_trace,
+ .packed_modifier = @intCast(Zir.Inst.Call.Flags.PackedModifier, @enumToInt(modifier)),
+ .args_len = @intCast(Zir.Inst.Call.Flags.PackedArgsLen, call.ast.params.len),
+ },
+ });
+ if (call.ast.params.len != 0) {
+ try astgen.extra.appendSlice(astgen.gpa, astgen.scratch.items[scratch_top..]);
+ }
+ gz.astgen.instructions.set(call_index, .{
+ .tag = .field_call,
+ .data = .{ .pl_node = .{
+ .src_node = gz.nodeIndexToRelative(node),
+ .payload_index = payload_index,
+ } },
+ });
},
- });
- if (call.ast.params.len != 0) {
- try astgen.extra.appendSlice(astgen.gpa, astgen.scratch.items[scratch_top..]);
}
- gz.astgen.instructions.set(call_index, .{
- .tag = .call,
- .data = .{ .pl_node = .{
- .src_node = gz.nodeIndexToRelative(node),
- .payload_index = payload_index,
- } },
- });
return rvalue(gz, ri, call_inst, node); // TODO function call with result location
}
-/// calleeExpr generates the function part of a call expression (f in f(x)), or the
-/// callee argument to the @call() builtin. If the lhs is a field access or the
-/// @field() builtin, we need to generate a special field_call_bind instruction
-/// instead of the normal field_val or field_ptr. If this is a inst.func() call,
-/// this instruction will capture the value of the first argument before evaluating
-/// the other arguments. We need to use .ref here to guarantee we will be able to
-/// promote an lvalue to an address if the first parameter requires it. This
-/// unfortunately also means we need to take a reference to any types on the lhs.
+const Callee = union(enum) {
+ field: struct {
+ /// A *pointer* to the object the field is fetched on, so that we can
+ /// promote the lvalue to an address if the first parameter requires it.
+ obj_ptr: Zir.Inst.Ref,
+ /// Offset into `string_bytes`.
+ field_name_start: u32,
+ },
+ direct: Zir.Inst.Ref,
+};
+
+/// calleeExpr generates the function part of a call expression (f in f(x)), but
+/// *not* the callee argument to the @call() builtin. Its purpose is to
+/// distinguish between standard calls and method call syntax `a.b()`. Thus, if
+/// the lhs is a field access, we return using the `field` union field;
+/// otherwise, we use the `direct` union field.
fn calleeExpr(
gz: *GenZir,
scope: *Scope,
node: Ast.Node.Index,
-) InnerError!Zir.Inst.Ref {
+) InnerError!Callee {
const astgen = gz.astgen;
const tree = astgen.tree;
const tag = tree.nodes.items(.tag)[node];
switch (tag) {
- .field_access => return addFieldAccess(.field_call_bind, gz, scope, .{ .rl = .ref }, node),
-
- .builtin_call_two,
- .builtin_call_two_comma,
- .builtin_call,
- .builtin_call_comma,
- => {
- const node_datas = tree.nodes.items(.data);
+ .field_access => {
const main_tokens = tree.nodes.items(.main_token);
- const builtin_token = main_tokens[node];
- const builtin_name = tree.tokenSlice(builtin_token);
-
- var inline_params: [2]Ast.Node.Index = undefined;
- var params: []Ast.Node.Index = switch (tag) {
- .builtin_call,
- .builtin_call_comma,
- => tree.extra_data[node_datas[node].lhs..node_datas[node].rhs],
-
- .builtin_call_two,
- .builtin_call_two_comma,
- => blk: {
- inline_params = .{ node_datas[node].lhs, node_datas[node].rhs };
- const len: usize = if (inline_params[0] == 0) @as(usize, 0) else if (inline_params[1] == 0) @as(usize, 1) else @as(usize, 2);
- break :blk inline_params[0..len];
- },
-
- else => unreachable,
- };
+ const node_datas = tree.nodes.items(.data);
+ const object_node = node_datas[node].lhs;
+ const dot_token = main_tokens[node];
+ const field_ident = dot_token + 1;
+ const str_index = try astgen.identAsString(field_ident);
+ // Capture the object by reference so we can promote it to an
+ // address in Sema if needed.
+ const lhs = try expr(gz, scope, .{ .rl = .ref }, object_node);
- // If anything is wrong, fall back to builtinCall.
- // It will emit any necessary compile errors and notes.
- if (std.mem.eql(u8, builtin_name, "@field") and params.len == 2) {
- const lhs = try expr(gz, scope, .{ .rl = .ref }, params[0]);
- const field_name = try comptimeExpr(gz, scope, .{ .rl = .{ .ty = .const_slice_u8_type } }, params[1]);
- return gz.addExtendedPayload(.field_call_bind_named, Zir.Inst.FieldNamedNode{
- .node = gz.nodeIndexToRelative(node),
- .lhs = lhs,
- .field_name = field_name,
- });
- }
+ const cursor = maybeAdvanceSourceCursorToMainToken(gz, node);
+ try emitDbgStmt(gz, cursor);
- return builtinCall(gz, scope, .{ .rl = .none }, node, params);
+ return .{ .field = .{
+ .obj_ptr = lhs,
+ .field_name_start = str_index,
+ } };
},
- else => return expr(gz, scope, .{ .rl = .none }, node),
+ else => return .{ .direct = try expr(gz, scope, .{ .rl = .none }, node) },
}
}
src/Autodoc.zig
@@ -2141,7 +2141,7 @@ fn walkInstruction(
.expr = .{ .declRef = decl_status },
};
},
- .field_val, .field_call_bind, .field_ptr, .field_type => {
+ .field_val, .field_ptr, .field_type => {
// TODO: field type uses Zir.Inst.FieldType, it just happens to have the
// same layout as Zir.Inst.Field :^)
const pl_node = data[inst_index].pl_node;
@@ -2163,7 +2163,6 @@ fn walkInstruction(
const lhs = @enumToInt(lhs_extra.data.lhs) - Ref.typed_value_map.len;
if (tags[lhs] != .field_val and
- tags[lhs] != .field_call_bind and
tags[lhs] != .field_ptr and
tags[lhs] != .field_type) break :blk lhs_extra.data.lhs;
@@ -2191,7 +2190,7 @@ fn walkInstruction(
const wr = blk: {
if (@enumToInt(lhs_ref) >= Ref.typed_value_map.len) {
const lhs_inst = @enumToInt(lhs_ref) - Ref.typed_value_map.len;
- if (tags[lhs_inst] == .call) {
+ if (tags[lhs_inst] == .call or tags[lhs_inst] == .field_call) {
break :blk DocData.WalkResult{
.expr = .{
.comptimeExpr = 0,
src/Module.zig
@@ -2489,8 +2489,21 @@ pub const SrcLoc = struct {
const node_datas = tree.nodes.items(.data);
const node_tags = tree.nodes.items(.tag);
const node = src_loc.declRelativeToNodeIndex(node_off);
+ var buf: [1]Ast.Node.Index = undefined;
const tok_index = switch (node_tags[node]) {
.field_access => node_datas[node].rhs,
+ .call_one,
+ .call_one_comma,
+ .async_call_one,
+ .async_call_one_comma,
+ .call,
+ .call_comma,
+ .async_call,
+ .async_call_comma,
+ => blk: {
+ const full = tree.fullCall(&buf, node).?;
+ break :blk tree.lastToken(full.ast.fn_expr);
+ },
else => tree.firstToken(node) - 2,
};
const start = tree.tokens.items(.start)[tok_index];
@@ -3083,7 +3096,8 @@ pub const LazySrcLoc = union(enum) {
/// The payload is offset from the containing Decl AST node.
/// The source location points to the field name of:
/// * a field access expression (`a.b`), or
- /// * the operand ("b" node) of a field initialization expression (`.a = b`)
+ /// * the callee of a method call (`a.b()`), or
+ /// * the operand ("b" node) of a field initialization expression (`.a = b`), or
/// The Decl is determined contextually.
node_offset_field_name: i32,
/// The source location points to the pointer of a pointer deref expression,
src/print_air.zig
@@ -369,7 +369,6 @@ const Writer = struct {
.inferred_alloc_const => try s.writeAll("(inferred_alloc_const)"),
.inferred_alloc_mut => try s.writeAll("(inferred_alloc_mut)"),
.generic_poison => try s.writeAll("(generic_poison)"),
- .bound_fn => try s.writeAll("(bound_fn)"),
else => try ty.print(s, w.module),
}
}
src/print_zir.zig
@@ -362,7 +362,8 @@ const Writer = struct {
.@"export" => try self.writePlNodeExport(stream, inst),
.export_value => try self.writePlNodeExportValue(stream, inst),
- .call => try self.writeCall(stream, inst),
+ .call => try self.writeCall(stream, inst, .direct),
+ .field_call => try self.writeCall(stream, inst, .field),
.block,
.block_comptime,
@@ -392,7 +393,6 @@ const Writer = struct {
.field_ptr,
.field_ptr_init,
.field_val,
- .field_call_bind,
=> try self.writePlNodeField(stream, inst),
.field_ptr_named,
@@ -543,15 +543,6 @@ const Writer = struct {
try self.writeSrc(stream, src);
},
- .field_call_bind_named => {
- const extra = self.code.extraData(Zir.Inst.FieldNamedNode, extended.operand).data;
- const src = LazySrcLoc.nodeOffset(extra.node);
- try self.writeInstRef(stream, extra.lhs);
- try stream.writeAll(", ");
- try self.writeInstRef(stream, extra.field_name);
- try stream.writeAll(") ");
- try self.writeSrc(stream, src);
- },
.builtin_async_call => try self.writeBuiltinAsyncCall(stream, extended),
.cmpxchg => try self.writeCmpxchg(stream, extended),
}
@@ -1176,9 +1167,18 @@ const Writer = struct {
try self.writeSrc(stream, src);
}
- fn writeCall(self: *Writer, stream: anytype, inst: Zir.Inst.Index) !void {
+ fn writeCall(
+ self: *Writer,
+ stream: anytype,
+ inst: Zir.Inst.Index,
+ comptime kind: enum { direct, field },
+ ) !void {
const inst_data = self.code.instructions.items(.data)[inst].pl_node;
- const extra = self.code.extraData(Zir.Inst.Call, inst_data.payload_index);
+ const ExtraType = switch (kind) {
+ .direct => Zir.Inst.Call,
+ .field => Zir.Inst.FieldCall,
+ };
+ const extra = self.code.extraData(ExtraType, inst_data.payload_index);
const args_len = extra.data.flags.args_len;
const body = self.code.extra[extra.end..];
@@ -1186,7 +1186,14 @@ const Writer = struct {
try stream.writeAll("nodiscard ");
}
try stream.print(".{s}, ", .{@tagName(@intToEnum(std.builtin.CallModifier, extra.data.flags.packed_modifier))});
- try self.writeInstRef(stream, extra.data.callee);
+ switch (kind) {
+ .direct => try self.writeInstRef(stream, extra.data.callee),
+ .field => {
+ const field_name = self.code.nullTerminatedString(extra.data.field_name_start);
+ try self.writeInstRef(stream, extra.data.obj_ptr);
+ try stream.print(", {}", .{std.zig.fmtId(field_name)});
+ },
+ }
try stream.writeAll(", [");
self.indent += 2;
src/Sema.zig
@@ -920,7 +920,8 @@ fn analyzeBodyInner(
.bool_br_and => try sema.zirBoolBr(block, inst, false),
.bool_br_or => try sema.zirBoolBr(block, inst, true),
.c_import => try sema.zirCImport(block, inst),
- .call => try sema.zirCall(block, inst),
+ .call => try sema.zirCall(block, inst, .direct),
+ .field_call => try sema.zirCall(block, inst, .field),
.closure_get => try sema.zirClosureGet(block, inst),
.cmp_lt => try sema.zirCmp(block, inst, .lt),
.cmp_lte => try sema.zirCmp(block, inst, .lte),
@@ -952,7 +953,6 @@ fn analyzeBodyInner(
.field_ptr_named => try sema.zirFieldPtrNamed(block, inst),
.field_val => try sema.zirFieldVal(block, inst),
.field_val_named => try sema.zirFieldValNamed(block, inst),
- .field_call_bind => try sema.zirFieldCallBind(block, inst),
.func => try sema.zirFunc(block, inst, false),
.func_inferred => try sema.zirFunc(block, inst, true),
.func_fancy => try sema.zirFuncFancy(block, inst),
@@ -1149,7 +1149,6 @@ fn analyzeBodyInner(
.wasm_memory_size => try sema.zirWasmMemorySize( block, extended),
.wasm_memory_grow => try sema.zirWasmMemoryGrow( block, extended),
.prefetch => try sema.zirPrefetch( block, extended),
- .field_call_bind_named => try sema.zirFieldCallBindNamed(block, extended),
.err_set_cast => try sema.zirErrSetCast( block, extended),
.await_nosuspend => try sema.zirAwaitNosuspend( block, extended),
.select => try sema.zirSelect( block, extended),
@@ -6262,38 +6261,50 @@ fn zirCall(
sema: *Sema,
block: *Block,
inst: Zir.Inst.Index,
+ comptime kind: enum { direct, field },
) CompileError!Air.Inst.Ref {
const tracy = trace(@src());
defer tracy.end();
const inst_data = sema.code.instructions.items(.data)[inst].pl_node;
- const func_src: LazySrcLoc = .{ .node_offset_call_func = inst_data.src_node };
+ const callee_src: LazySrcLoc = .{ .node_offset_call_func = inst_data.src_node };
const call_src = inst_data.src();
- const extra = sema.code.extraData(Zir.Inst.Call, inst_data.payload_index);
+ const ExtraType = switch (kind) {
+ .direct => Zir.Inst.Call,
+ .field => Zir.Inst.FieldCall,
+ };
+ const extra = sema.code.extraData(ExtraType, inst_data.payload_index);
const args_len = extra.data.flags.args_len;
const modifier = @intToEnum(std.builtin.CallModifier, extra.data.flags.packed_modifier);
const ensure_result_used = extra.data.flags.ensure_result_used;
const pop_error_return_trace = extra.data.flags.pop_error_return_trace;
- var func = try sema.resolveInst(extra.data.callee);
+ const callee: ResolvedFieldCallee = switch (kind) {
+ .direct => .{ .direct = try sema.resolveInst(extra.data.callee) },
+ .field => blk: {
+ const object_ptr = try sema.resolveInst(extra.data.obj_ptr);
+ const field_name = sema.code.nullTerminatedString(extra.data.field_name_start);
+ const field_name_src: LazySrcLoc = .{ .node_offset_field_name = inst_data.src_node };
+ break :blk try sema.fieldCallBind(block, callee_src, object_ptr, field_name, field_name_src);
+ },
+ };
var resolved_args: []Air.Inst.Ref = undefined;
- var arg_index: u32 = 0;
-
- const func_type = sema.typeOf(func);
-
- // Desugar bound functions here
var bound_arg_src: ?LazySrcLoc = null;
- if (func_type.tag() == .bound_fn) {
- bound_arg_src = func_src;
- const bound_func = try sema.resolveValue(block, .unneeded, func, "");
- const bound_data = &bound_func.cast(Value.Payload.BoundFn).?.data;
- func = bound_data.func_inst;
- resolved_args = try sema.arena.alloc(Air.Inst.Ref, args_len + 1);
- resolved_args[arg_index] = bound_data.arg0_inst;
- arg_index += 1;
- } else {
- resolved_args = try sema.arena.alloc(Air.Inst.Ref, args_len);
+ var func: Air.Inst.Ref = undefined;
+ var arg_index: u32 = 0;
+ switch (callee) {
+ .direct => |func_inst| {
+ resolved_args = try sema.arena.alloc(Air.Inst.Ref, args_len);
+ func = func_inst;
+ },
+ .method => |method| {
+ resolved_args = try sema.arena.alloc(Air.Inst.Ref, args_len + 1);
+ func = method.func_inst;
+ resolved_args[0] = method.arg0_inst;
+ arg_index += 1;
+ bound_arg_src = callee_src;
+ },
}
const callee_ty = sema.typeOf(func);
@@ -6308,10 +6319,11 @@ fn zirCall(
},
else => {},
}
- return sema.fail(block, func_src, "type '{}' not a function", .{callee_ty.fmt(sema.mod)});
+ return sema.fail(block, callee_src, "type '{}' not a function", .{callee_ty.fmt(sema.mod)});
};
+
const total_args = args_len + @boolToInt(bound_arg_src != null);
- try sema.checkCallArgumentCount(block, func, func_src, func_ty, total_args, bound_arg_src != null);
+ try sema.checkCallArgumentCount(block, func, callee_src, func_ty, total_args, bound_arg_src != null);
const args_body = sema.code.extra[extra.end..];
@@ -6369,7 +6381,7 @@ fn zirCall(
!block.is_comptime and !block.is_typeof and (input_is_error or pop_error_return_trace))
{
const call_inst: Air.Inst.Ref = if (modifier == .always_tail) undefined else b: {
- 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);
+ 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);
};
const return_ty = sema.typeOf(call_inst);
@@ -6398,11 +6410,11 @@ fn zirCall(
}
if (modifier == .always_tail) // Perform the call *after* the restore, so that a tail call is possible.
- return sema.analyzeCall(block, func, func_ty, func_src, call_src, modifier, ensure_result_used, resolved_args, bound_arg_src, call_dbg_node);
+ return sema.analyzeCall(block, func, func_ty, callee_src, call_src, modifier, ensure_result_used, resolved_args, bound_arg_src, call_dbg_node);
return call_inst;
} else {
- return sema.analyzeCall(block, func, func_ty, func_src, call_src, modifier, ensure_result_used, resolved_args, bound_arg_src, call_dbg_node);
+ return sema.analyzeCall(block, func, func_ty, callee_src, call_src, modifier, ensure_result_used, resolved_args, bound_arg_src, call_dbg_node);
}
}
@@ -9467,19 +9479,6 @@ fn zirFieldPtr(sema: *Sema, block: *Block, inst: Zir.Inst.Index, initializing: b
return sema.fieldPtr(block, src, object_ptr, field_name, field_name_src, initializing);
}
-fn zirFieldCallBind(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air.Inst.Ref {
- const tracy = trace(@src());
- defer tracy.end();
-
- const inst_data = sema.code.instructions.items(.data)[inst].pl_node;
- const src = inst_data.src();
- const field_name_src: LazySrcLoc = .{ .node_offset_field_name = inst_data.src_node };
- const extra = sema.code.extraData(Zir.Inst.Field, inst_data.payload_index).data;
- const field_name = sema.code.nullTerminatedString(extra.field_name_start);
- const object_ptr = try sema.resolveInst(extra.lhs);
- return sema.fieldCallBind(block, src, object_ptr, field_name, field_name_src);
-}
-
fn zirFieldValNamed(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air.Inst.Ref {
const tracy = trace(@src());
defer tracy.end();
@@ -9506,18 +9505,6 @@ fn zirFieldPtrNamed(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileErr
return sema.fieldPtr(block, src, object_ptr, field_name, field_name_src, false);
}
-fn zirFieldCallBindNamed(sema: *Sema, block: *Block, extended: Zir.Inst.Extended.InstData) CompileError!Air.Inst.Ref {
- const tracy = trace(@src());
- defer tracy.end();
-
- const extra = sema.code.extraData(Zir.Inst.FieldNamedNode, extended.operand).data;
- const src = LazySrcLoc.nodeOffset(extra.node);
- const field_name_src: LazySrcLoc = .{ .node_offset_builtin_call_arg1 = extra.node };
- const object_ptr = try sema.resolveInst(extra.lhs);
- const field_name = try sema.resolveConstString(block, field_name_src, extra.field_name, "field name must be comptime-known");
- return sema.fieldCallBind(block, src, object_ptr, field_name, field_name_src);
-}
-
fn zirIntCast(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air.Inst.Ref {
const tracy = trace(@src());
defer tracy.end();
@@ -21673,25 +21660,9 @@ fn zirBuiltinCall(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError
return sema.fail(block, args_src, "expected a tuple, found '{}'", .{args_ty.fmt(sema.mod)});
}
- var resolved_args: []Air.Inst.Ref = undefined;
-
- // Desugar bound functions here
- var bound_arg_src: ?LazySrcLoc = null;
- if (sema.typeOf(func).tag() == .bound_fn) {
- bound_arg_src = func_src;
- const bound_func = try sema.resolveValue(block, .unneeded, func, "");
- const bound_data = &bound_func.cast(Value.Payload.BoundFn).?.data;
- func = bound_data.func_inst;
- resolved_args = try sema.arena.alloc(Air.Inst.Ref, args_ty.structFieldCount() + 1);
- resolved_args[0] = bound_data.arg0_inst;
- for (resolved_args[1..], 0..) |*resolved, i| {
- resolved.* = try sema.tupleFieldValByIndex(block, args_src, args, @intCast(u32, i), args_ty);
- }
- } else {
- resolved_args = try sema.arena.alloc(Air.Inst.Ref, args_ty.structFieldCount());
- for (resolved_args, 0..) |*resolved, i| {
- resolved.* = try sema.tupleFieldValByIndex(block, args_src, args, @intCast(u32, i), args_ty);
- }
+ var resolved_args: []Air.Inst.Ref = try sema.arena.alloc(Air.Inst.Ref, args_ty.structFieldCount());
+ for (resolved_args, 0..) |*resolved, i| {
+ resolved.* = try sema.tupleFieldValByIndex(block, args_src, args, @intCast(u32, i), args_ty);
}
const callee_ty = sema.typeOf(func);
@@ -21708,10 +21679,10 @@ fn zirBuiltinCall(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError
}
return sema.fail(block, func_src, "type '{}' not a function", .{callee_ty.fmt(sema.mod)});
};
- try sema.checkCallArgumentCount(block, func, func_src, func_ty, resolved_args.len, bound_arg_src != null);
+ try sema.checkCallArgumentCount(block, func, func_src, func_ty, resolved_args.len, false);
const ensure_result_used = extra.flags.ensure_result_used;
- return sema.analyzeCall(block, func, func_ty, func_src, call_src, modifier, ensure_result_used, resolved_args, bound_arg_src, null);
+ return sema.analyzeCall(block, func, func_ty, func_src, call_src, modifier, ensure_result_used, resolved_args, null, null);
}
fn zirFieldParentPtr(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air.Inst.Ref {
@@ -24175,6 +24146,16 @@ fn fieldPtr(
return sema.failWithInvalidFieldAccess(block, src, object_ty, field_name);
}
+const ResolvedFieldCallee = union(enum) {
+ /// The LHS of the call was an actual field with this value.
+ direct: Air.Inst.Ref,
+ /// This is a method call, with the function and first argument given.
+ method: struct {
+ func_inst: Air.Inst.Ref,
+ arg0_inst: Air.Inst.Ref,
+ },
+};
+
fn fieldCallBind(
sema: *Sema,
block: *Block,
@@ -24182,7 +24163,7 @@ fn fieldCallBind(
raw_ptr: Air.Inst.Ref,
field_name: []const u8,
field_name_src: LazySrcLoc,
-) CompileError!Air.Inst.Ref {
+) CompileError!ResolvedFieldCallee {
// When editing this function, note that there is corresponding logic to be edited
// in `fieldVal`. This function takes a pointer and returns a pointer.
@@ -24202,7 +24183,6 @@ fn fieldCallBind(
else
raw_ptr;
- const arena = sema.arena;
find_field: {
switch (concrete_ty.zigTypeTag()) {
.Struct => {
@@ -24216,7 +24196,7 @@ fn fieldCallBind(
return sema.finishFieldCallBind(block, src, ptr_ty, field.ty, field_index, object_ptr);
} else if (struct_ty.isTuple()) {
if (mem.eql(u8, field_name, "len")) {
- return sema.addIntUnsigned(Type.usize, struct_ty.structFieldCount());
+ return .{ .direct = try sema.addIntUnsigned(Type.usize, struct_ty.structFieldCount()) };
}
if (std.fmt.parseUnsigned(u32, field_name, 10)) |field_index| {
if (field_index >= struct_ty.structFieldCount()) break :find_field;
@@ -24243,7 +24223,7 @@ fn fieldCallBind(
},
.Type => {
const namespace = try sema.analyzeLoad(block, src, object_ptr, src);
- return sema.fieldVal(block, src, namespace, field_name, field_name_src);
+ return .{ .direct = try sema.fieldVal(block, src, namespace, field_name, field_name_src) };
},
else => {},
}
@@ -24272,54 +24252,47 @@ fn fieldCallBind(
first_param_type.childType().eql(concrete_ty, sema.mod)))
{
// zig fmt: on
+ // Note that if the param type is generic poison, we know that it must
+ // specifically be `anytype` since it's the first parameter, meaning we
+ // can safely assume it can be a pointer.
// TODO: bound fn calls on rvalues should probably
// generate a by-value argument somehow.
- const ty = Type.Tag.bound_fn.init();
- const value = try Value.Tag.bound_fn.create(arena, .{
+ return .{ .method = .{
.func_inst = decl_val,
.arg0_inst = object_ptr,
- });
- return sema.addConstant(ty, value);
+ } };
} else if (first_param_type.eql(concrete_ty, sema.mod)) {
const deref = try sema.analyzeLoad(block, src, object_ptr, src);
- const ty = Type.Tag.bound_fn.init();
- const value = try Value.Tag.bound_fn.create(arena, .{
+ return .{ .method = .{
.func_inst = decl_val,
.arg0_inst = deref,
- });
- return sema.addConstant(ty, value);
+ } };
} else if (first_param_type.zigTypeTag() == .Optional) {
var opt_buf: Type.Payload.ElemType = undefined;
const child = first_param_type.optionalChild(&opt_buf);
if (child.eql(concrete_ty, sema.mod)) {
const deref = try sema.analyzeLoad(block, src, object_ptr, src);
- const ty = Type.Tag.bound_fn.init();
- const value = try Value.Tag.bound_fn.create(arena, .{
+ return .{ .method = .{
.func_inst = decl_val,
.arg0_inst = deref,
- });
- return sema.addConstant(ty, value);
+ } };
} else if (child.zigTypeTag() == .Pointer and
child.ptrSize() == .One and
child.childType().eql(concrete_ty, sema.mod))
{
- const ty = Type.Tag.bound_fn.init();
- const value = try Value.Tag.bound_fn.create(arena, .{
+ return .{ .method = .{
.func_inst = decl_val,
.arg0_inst = object_ptr,
- });
- return sema.addConstant(ty, value);
+ } };
}
} else if (first_param_type.zigTypeTag() == .ErrorUnion and
first_param_type.errorUnionPayload().eql(concrete_ty, sema.mod))
{
const deref = try sema.analyzeLoad(block, src, object_ptr, src);
- const ty = Type.Tag.bound_fn.init();
- const value = try Value.Tag.bound_fn.create(arena, .{
+ return .{ .method = .{
.func_inst = decl_val,
.arg0_inst = deref,
- });
- return sema.addConstant(ty, value);
+ } };
}
}
break :found_decl decl_idx;
@@ -24351,7 +24324,7 @@ fn finishFieldCallBind(
field_ty: Type,
field_index: u32,
object_ptr: Air.Inst.Ref,
-) CompileError!Air.Inst.Ref {
+) CompileError!ResolvedFieldCallee {
const arena = sema.arena;
const ptr_field_ty = try Type.ptr(arena, sema.mod, .{
.pointee_type = field_ty,
@@ -24362,7 +24335,7 @@ fn finishFieldCallBind(
const container_ty = ptr_ty.childType();
if (container_ty.zigTypeTag() == .Struct) {
if (container_ty.structFieldValueComptime(field_index)) |default_val| {
- return sema.addConstant(field_ty, default_val);
+ return .{ .direct = try sema.addConstant(field_ty, default_val) };
}
}
@@ -24375,12 +24348,12 @@ fn finishFieldCallBind(
.field_index = field_index,
}),
);
- return sema.analyzeLoad(block, src, pointer, src);
+ return .{ .direct = try sema.analyzeLoad(block, src, pointer, src) };
}
try sema.requireRuntimeBlock(block, src, null);
const ptr_inst = try block.addStructFieldPtr(object_ptr, field_index, ptr_field_ty);
- return sema.analyzeLoad(block, src, ptr_inst, src);
+ return .{ .direct = try sema.analyzeLoad(block, src, ptr_inst, src) };
}
fn namespaceLookup(
@@ -31281,7 +31254,6 @@ pub fn resolveTypeRequiresComptime(sema: *Sema, ty: Type) CompileError!bool {
.inferred_alloc_mut => unreachable,
.inferred_alloc_const => unreachable,
- .bound_fn => unreachable,
.array,
.array_sentinel,
@@ -32666,7 +32638,6 @@ pub fn typeHasOnePossibleValue(sema: *Sema, ty: Type) CompileError!?Value {
.single_const_pointer,
.single_mut_pointer,
.pointer,
- .bound_fn,
=> return null,
.optional => {
@@ -33308,7 +33279,6 @@ pub fn typeRequiresComptime(sema: *Sema, ty: Type) CompileError!bool {
.inferred_alloc_mut => unreachable,
.inferred_alloc_const => unreachable,
- .bound_fn => unreachable,
.array,
.array_sentinel,
src/type.zig
@@ -156,8 +156,6 @@ pub const Type = extern union {
.union_tagged,
.type_info,
=> return .Union,
-
- .bound_fn => unreachable,
}
}
@@ -933,7 +931,6 @@ pub const Type = extern union {
// for example, a was resolved into .union_tagged but b was one of these tags.
.type_info => unreachable, // needed to resolve the type before now
- .bound_fn => unreachable,
}
}
@@ -1242,7 +1239,6 @@ pub const Type = extern union {
// we can't hash these based on tags because they wouldn't match the expanded version.
.type_info => unreachable, // needed to resolve the type before now
- .bound_fn => unreachable,
}
}
@@ -1349,7 +1345,6 @@ pub const Type = extern union {
.type_info,
.@"anyframe",
.generic_poison,
- .bound_fn,
=> unreachable,
.array_u8,
@@ -1613,7 +1608,6 @@ pub const Type = extern union {
.comptime_int,
.comptime_float,
.noreturn,
- .bound_fn,
=> return writer.writeAll(@tagName(t)),
.enum_literal => return writer.writeAll("@Type(.EnumLiteral)"),
@@ -1949,7 +1943,6 @@ pub const Type = extern union {
.inferred_alloc_const => unreachable,
.inferred_alloc_mut => unreachable,
.generic_poison => unreachable,
- .bound_fn => unreachable,
// TODO get rid of these Type.Tag values.
.atomic_order => unreachable,
@@ -2468,7 +2461,6 @@ pub const Type = extern union {
.enum_literal,
.empty_struct,
.empty_struct_literal,
- .bound_fn,
// These are function *bodies*, not pointers.
// Special exceptions have to be made when emitting functions due to
// this returning false.
@@ -2703,7 +2695,6 @@ pub const Type = extern union {
.inferred_alloc_mut => unreachable,
.inferred_alloc_const => unreachable,
- .bound_fn => unreachable,
.array,
.array_sentinel,
@@ -3182,7 +3173,6 @@ pub const Type = extern union {
.noreturn,
.inferred_alloc_const,
.inferred_alloc_mut,
- .bound_fn,
=> unreachable,
.generic_poison => unreachable,
@@ -3282,7 +3272,6 @@ pub const Type = extern union {
.fn_ccc_void_no_args => unreachable, // represents machine code; not a pointer
.function => unreachable, // represents machine code; not a pointer
.@"opaque" => unreachable, // no size available
- .bound_fn => unreachable,
.noreturn => unreachable,
.inferred_alloc_const => unreachable,
.inferred_alloc_mut => unreachable,
@@ -3630,7 +3619,6 @@ pub const Type = extern union {
.inferred_alloc_mut => unreachable,
.@"opaque" => unreachable,
.generic_poison => unreachable,
- .bound_fn => unreachable,
.void => return 0,
.bool, .u1 => return 1,
@@ -5042,7 +5030,6 @@ pub const Type = extern union {
.single_const_pointer,
.single_mut_pointer,
.pointer,
- .bound_fn,
=> return null,
.optional => {
@@ -5245,7 +5232,6 @@ pub const Type = extern union {
.inferred_alloc_mut => unreachable,
.inferred_alloc_const => unreachable,
- .bound_fn => unreachable,
.array,
.array_sentinel,
@@ -6081,7 +6067,6 @@ pub const Type = extern union {
inferred_alloc_mut,
/// Same as `inferred_alloc_mut` but the local is `var` not `const`.
inferred_alloc_const, // See last_no_payload_tag below.
- bound_fn,
// After this, the tag requires a payload.
array_u8,
@@ -6126,7 +6111,7 @@ pub const Type = extern union {
enum_full,
enum_nonexhaustive,
- pub const last_no_payload_tag = Tag.bound_fn;
+ pub const last_no_payload_tag = Tag.inferred_alloc_const;
pub const no_payload_count = @enumToInt(last_no_payload_tag) + 1;
pub fn Type(comptime t: Tag) type {
@@ -6199,7 +6184,6 @@ pub const Type = extern union {
.extern_options,
.type_info,
.@"anyframe",
- .bound_fn,
=> @compileError("Type Tag " ++ @tagName(t) ++ " has no payload"),
.array_u8,
src/TypedValue.zig
@@ -499,10 +499,6 @@ pub fn print(
// TODO these should not appear in this function
.inferred_alloc => return writer.writeAll("(inferred allocation value)"),
.inferred_alloc_comptime => return writer.writeAll("(inferred comptime allocation value)"),
- .bound_fn => {
- const bound_func = val.castTag(.bound_fn).?.data;
- return writer.print("(bound_fn %{}(%{})", .{ bound_func.func_inst, bound_func.arg0_inst });
- },
.generic_poison_type => return writer.writeAll("(generic poison type)"),
.generic_poison => return writer.writeAll("(generic poison)"),
.runtime_value => return writer.writeAll("[runtime value]"),
src/value.zig
@@ -183,10 +183,6 @@ pub const Value = extern union {
/// Used to coordinate alloc_inferred, store_to_inferred_ptr, and resolve_inferred_alloc
/// instructions for comptime code.
inferred_alloc_comptime,
- /// Used sometimes as the result of field_call_bind. This value is always temporary,
- /// and refers directly to the air. It will never be referenced by the air itself.
- /// TODO: This is probably a bad encoding, maybe put temp data in the sema instead.
- bound_fn,
/// The ABI alignment of the payload type.
lazy_align,
/// The ABI size of the payload type.
@@ -326,7 +322,6 @@ pub const Value = extern union {
.inferred_alloc_comptime => Payload.InferredAllocComptime,
.aggregate => Payload.Aggregate,
.@"union" => Payload.Union,
- .bound_fn => Payload.BoundFn,
.comptime_field_ptr => Payload.ComptimeFieldPtr,
};
}
@@ -477,7 +472,6 @@ pub const Value = extern union {
.extern_options_type,
.type_info_type,
.generic_poison,
- .bound_fn,
=> unreachable,
.ty, .lazy_align, .lazy_size => {
@@ -837,10 +831,6 @@ pub const Value = extern union {
try out_stream.writeAll("(opt_payload_ptr)");
val = val.castTag(.opt_payload_ptr).?.data.container_ptr;
},
- .bound_fn => {
- const bound_func = val.castTag(.bound_fn).?.data;
- return out_stream.print("(bound_fn %{}(%{})", .{ bound_func.func_inst, bound_func.arg0_inst });
- },
};
}
@@ -5657,16 +5647,6 @@ pub const Value = extern union {
val: Value,
},
};
-
- pub const BoundFn = struct {
- pub const base_tag = Tag.bound_fn;
-
- base: Payload = Payload{ .tag = base_tag },
- data: struct {
- func_inst: Air.Inst.Ref,
- arg0_inst: Air.Inst.Ref,
- },
- };
};
/// Big enough to fit any non-BigInt value
src/Zir.zig
@@ -297,6 +297,14 @@ pub const Inst = struct {
/// Uses the `pl_node` union field with payload `Call`.
/// AST node is the function call.
call,
+ /// Function call using `a.b()` syntax.
+ /// Uses the named field as the callee. If there is no such field, searches in the type for
+ /// a decl matching the field name. The decl is resolved and we ensure that it's a function
+ /// which can accept the object as the first parameter, with one pointer fixup. This
+ /// function is then used as the callee, with the object as an implicit first parameter.
+ /// Uses the `pl_node` union field with payload `FieldCall`.
+ /// AST node is the function call.
+ field_call,
/// Implements the `@call` builtin.
/// Uses the `pl_node` union field with payload `BuiltinCall`.
/// AST node is the builtin call.
@@ -432,15 +440,6 @@ pub const Inst = struct {
/// This instruction also accepts a pointer.
/// Uses `pl_node` field. The AST node is the a.b syntax. Payload is Field.
field_val,
- /// Given a pointer to a struct or object that contains virtual fields, returns the
- /// named field. If there is no named field, searches in the type for a decl that
- /// matches the field name. The decl is resolved and we ensure that it's a function
- /// which can accept the object as the first parameter, with one pointer fixup. If
- /// all of that works, this instruction produces a special "bound function" value
- /// which contains both the function and the saved first parameter value.
- /// Bound functions may only be used as the function parameter to a `call` or
- /// `builtin_call` instruction. Any other use is invalid zir and may crash the compiler.
- field_call_bind,
/// Given a pointer to a struct or object that contains virtual fields, returns a pointer
/// to the named field. The field name is a comptime instruction. Used by @field.
/// Uses `pl_node` field. The AST node is the builtin call. Payload is FieldNamed.
@@ -1051,6 +1050,7 @@ pub const Inst = struct {
.bool_br_or,
.bool_not,
.call,
+ .field_call,
.cmp_lt,
.cmp_lte,
.cmp_eq,
@@ -1083,7 +1083,6 @@ pub const Inst = struct {
.field_ptr,
.field_ptr_init,
.field_val,
- .field_call_bind,
.field_ptr_named,
.field_val_named,
.func,
@@ -1361,6 +1360,7 @@ pub const Inst = struct {
.bool_br_or,
.bool_not,
.call,
+ .field_call,
.cmp_lt,
.cmp_lte,
.cmp_eq,
@@ -1383,7 +1383,6 @@ pub const Inst = struct {
.field_ptr,
.field_ptr_init,
.field_val,
- .field_call_bind,
.field_ptr_named,
.field_val_named,
.func,
@@ -1601,6 +1600,7 @@ pub const Inst = struct {
.check_comptime_control_flow = .un_node,
.for_len = .pl_node,
.call = .pl_node,
+ .field_call = .pl_node,
.cmp_lt = .pl_node,
.cmp_lte = .pl_node,
.cmp_eq = .pl_node,
@@ -1641,7 +1641,6 @@ pub const Inst = struct {
.field_val = .pl_node,
.field_ptr_named = .pl_node,
.field_val_named = .pl_node,
- .field_call_bind = .pl_node,
.func = .pl_node,
.func_inferred = .pl_node,
.func_fancy = .pl_node,
@@ -1955,16 +1954,6 @@ pub const Inst = struct {
/// The `@prefetch` builtin.
/// `operand` is payload index to `BinNode`.
prefetch,
- /// Given a pointer to a struct or object that contains virtual fields, returns the
- /// named field. If there is no named field, searches in the type for a decl that
- /// matches the field name. The decl is resolved and we ensure that it's a function
- /// which can accept the object as the first parameter, with one pointer fixup. If
- /// all of that works, this instruction produces a special "bound function" value
- /// which contains both the function and the saved first parameter value.
- /// Bound functions may only be used as the function parameter to a `call` or
- /// `builtin_call` instruction. Any other use is invalid zir and may crash the compiler.
- /// Uses `pl_node` field. The AST node is the `@field` builtin. Payload is FieldNamedNode.
- field_call_bind_named,
/// Implements the `@fence` builtin.
/// `operand` is payload index to `UnNode`.
fence,
@@ -2913,6 +2902,19 @@ pub const Inst = struct {
};
};
+ /// Stored inside extra, with trailing arguments according to `args_len`.
+ /// Implicit 0. arg_0_start: u32, // always same as `args_len`
+ /// 1. arg_end: u32, // for each `args_len`
+ /// arg_N_start is the same as arg_N-1_end
+ pub const FieldCall = struct {
+ // Note: Flags *must* come first so that unusedResultExpr
+ // can find it when it goes to modify them.
+ flags: Call.Flags,
+ obj_ptr: Ref,
+ /// Offset into `string_bytes`.
+ field_name_start: u32,
+ };
+
pub const TypeOfPeer = struct {
src_node: i32,
body_len: u32,
@@ -3187,12 +3189,6 @@ pub const Inst = struct {
field_name: Ref,
};
- pub const FieldNamedNode = struct {
- node: i32,
- lhs: Ref,
- field_name: Ref,
- };
-
pub const As = struct {
dest_type: Ref,
operand: Ref,
test/behavior/member_func.zig
@@ -86,18 +86,6 @@ test "@field field calls" {
const pv = &v;
const pcv: *const HasFuncs = pv;
- try expect(@field(v, "get")() == 0);
- @field(v, "inc")();
- try expect(v.state == 1);
- try expect(@field(v, "get")() == 1);
-
- @field(pv, "inc")();
- try expect(v.state == 2);
- try expect(@field(pv, "get")() == 2);
- try expect(@field(v, "getPtr")().* == 2);
- try expect(@field(pcv, "get")() == 2);
- try expect(@field(pcv, "getPtr")().* == 2);
-
v.func_field = HasFuncs.one;
try expect(@field(v, "func_field")(0) == 1);
try expect(@field(pv, "func_field")(0) == 1);
test/cases/compile_errors/member_function_arg_mismatch.zig
@@ -6,10 +6,6 @@ pub export fn entry() void {
var s: S = undefined;
s.foo(true);
}
-pub export fn entry2() void {
- var s: S = undefined;
- @call(.auto, s.foo, .{true});
-}
// error
// backend=stage2
@@ -17,5 +13,3 @@ pub export fn entry2() void {
//
// :7:6: error: member function expected 2 argument(s), found 1
// :3:5: note: function declared here
-// :11:19: error: member function expected 2 argument(s), found 1
-// :3:5: note: function declared here