zig/test/behavior/call.zig
Andrew Kelley bae35bdf2d stage2: result location types for function call arguments
* AstGen: restore the param_type ZIR instruction and pass it to the
   expression for function call arguments. This does not solve the
   problem for generic function parameters, but it catches stage2 up to
   stage1 which also does not solve the problem for generic function
   parameters.
   - Most of the enhancements in this commit will still be needed for a
     more sophisticated further improvement to handle generic function
     types.
   - In Sema, handling of `as` coercion recognizes the `var_args_param`
     Type Tag and passes the operand through doing no coercion.
   - That was the last ZIR tag and we are now using all 256 ZIR tags.
 * AstGen: array init and struct init expressions use the anon form even
   when the result location has a type. Prevents the type system
   incorrectly believing, for example, that a tuple is actually an array
   when the result location is a param_type of a function with `anytype`
   parameter.
 * Sema: add missing coercion in `unionInit` to coerce the init to the
   corresponding union field type.
 * `Value.fieldValue` now takes a type and does not take an allocator.

closes #11293

After this commit, stage2 passes all the parser tests.
2022-03-26 00:27:12 -04:00

121 lines
4.1 KiB
Zig

const builtin = @import("builtin");
const std = @import("std");
const expect = std.testing.expect;
const expectEqual = std.testing.expectEqual;
test "super basic invocations" {
const foo = struct {
fn foo() i32 {
return 1234;
}
}.foo;
try expect(@call(.{}, foo, .{}) == 1234);
comptime try expect(@call(.{ .modifier = .always_inline }, foo, .{}) == 1234);
{
// comptime call without comptime keyword
const result = @call(.{ .modifier = .compile_time }, foo, .{}) == 1234;
comptime try expect(result);
}
}
test "basic invocations" {
if (builtin.zig_backend != .stage1) return error.SkipZigTest; // TODO
const foo = struct {
fn foo() i32 {
return 1234;
}
}.foo;
try expect(@call(.{}, foo, .{}) == 1234);
comptime {
// modifiers that allow comptime calls
try expect(@call(.{}, foo, .{}) == 1234);
try expect(@call(.{ .modifier = .no_async }, foo, .{}) == 1234);
try expect(@call(.{ .modifier = .always_tail }, foo, .{}) == 1234);
try expect(@call(.{ .modifier = .always_inline }, foo, .{}) == 1234);
}
{
// comptime call without comptime keyword
const result = @call(.{ .modifier = .compile_time }, foo, .{}) == 1234;
comptime try expect(result);
}
{
// call of non comptime-known function
var alias_foo = foo;
try expect(@call(.{ .modifier = .no_async }, alias_foo, .{}) == 1234);
try expect(@call(.{ .modifier = .never_tail }, alias_foo, .{}) == 1234);
try expect(@call(.{ .modifier = .never_inline }, alias_foo, .{}) == 1234);
}
}
test "tuple parameters" {
if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
if (builtin.zig_backend == .stage2_c) return error.SkipZigTest; // TODO
if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; // TODO
const add = struct {
fn add(a: i32, b: i32) i32 {
return a + b;
}
}.add;
var a: i32 = 12;
var b: i32 = 34;
try expect(@call(.{}, add, .{ a, 34 }) == 46);
try expect(@call(.{}, add, .{ 12, b }) == 46);
try expect(@call(.{}, add, .{ a, b }) == 46);
try expect(@call(.{}, add, .{ 12, 34 }) == 46);
if (builtin.zig_backend == .stage1) comptime try expect(@call(.{}, add, .{ 12, 34 }) == 46); // TODO
try expect(comptime @call(.{}, add, .{ 12, 34 }) == 46);
{
const separate_args0 = .{ a, b };
const separate_args1 = .{ a, 34 };
const separate_args2 = .{ 12, 34 };
const separate_args3 = .{ 12, b };
try expect(@call(.{ .modifier = .always_inline }, add, separate_args0) == 46);
try expect(@call(.{ .modifier = .always_inline }, add, separate_args1) == 46);
try expect(@call(.{ .modifier = .always_inline }, add, separate_args2) == 46);
try expect(@call(.{ .modifier = .always_inline }, add, separate_args3) == 46);
}
}
test "comptime call with bound function as parameter" {
if (builtin.zig_backend != .stage1) return error.SkipZigTest; // TODO
const S = struct {
fn ReturnType(func: anytype) type {
return switch (@typeInfo(@TypeOf(func))) {
.BoundFn => |info| info,
else => unreachable,
}.return_type orelse void;
}
fn call_me_maybe() ?i32 {
return 123;
}
};
var inst: S = undefined;
try expectEqual(?i32, S.ReturnType(inst.call_me_maybe));
}
test "result location of function call argument through runtime condition and struct init" {
if (builtin.zig_backend == .stage2_c) return error.SkipZigTest; // TODO
if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
const E = enum { a, b };
const S = struct {
e: E,
};
const namespace = struct {
fn foo(s: S) !void {
try expect(s.e == .b);
}
};
var runtime = true;
try namespace.foo(.{
.e = if (!runtime) .a else .b,
});
}