stage2: implement @typeName

* stage1: change the `@typeName` of `@TypeOf(undefined)`,
   `@TypeOf(null)`, and `@TypeOf(.foo)` to match stage2.
 * move passing behavior tests to the passing-for-stage2 section.
This commit is contained in:
Andrew Kelley 2021-11-27 00:23:54 -07:00
parent f0deef1d79
commit 17f057c556
16 changed files with 369 additions and 263 deletions

View File

@ -2771,20 +2771,16 @@ fn zirStr(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air.Ins
// expression of a variable declaration. We need the memory to be in the new
// anonymous Decl's arena.
var new_decl_arena = std.heap.ArenaAllocator.init(sema.gpa);
errdefer new_decl_arena.deinit();
var anon_decl = try block.startAnonDecl();
defer anon_decl.deinit();
const bytes = try new_decl_arena.allocator.dupeZ(u8, zir_bytes);
const bytes = try anon_decl.arena().dupeZ(u8, zir_bytes);
const decl_ty = try Type.Tag.array_u8_sentinel_0.create(&new_decl_arena.allocator, bytes.len);
const decl_val = try Value.Tag.bytes.create(&new_decl_arena.allocator, bytes[0 .. bytes.len + 1]);
const new_decl = try anon_decl.finish(
try Type.Tag.array_u8_sentinel_0.create(anon_decl.arena(), bytes.len),
try Value.Tag.bytes.create(anon_decl.arena(), bytes[0 .. bytes.len + 1]),
);
const new_decl = try sema.mod.createAnonymousDecl(block, .{
.ty = decl_ty,
.val = decl_val,
});
errdefer sema.mod.abortAnonDecl(new_decl);
try new_decl.finalizeNewArena(&new_decl_arena);
return sema.analyzeDeclRef(new_decl);
}
@ -9741,8 +9737,20 @@ fn zirReify(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air.I
fn zirTypeName(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air.Inst.Ref {
const inst_data = sema.code.instructions.items(.data)[inst].un_node;
const src = inst_data.src();
return sema.fail(block, src, "TODO: Sema.zirTypeName", .{});
const ty_src: LazySrcLoc = .{ .node_offset_builtin_call_arg0 = inst_data.src_node };
const ty = try sema.resolveType(block, ty_src, inst_data.operand);
var anon_decl = try block.startAnonDecl();
defer anon_decl.deinit();
const bytes = try ty.nameAlloc(anon_decl.arena());
const new_decl = try anon_decl.finish(
try Type.Tag.array_u8_sentinel_0.create(anon_decl.arena(), bytes.len),
try Value.Tag.bytes.create(anon_decl.arena(), bytes[0 .. bytes.len + 1]),
);
return sema.analyzeDeclRef(new_decl);
}
fn zirFrameType(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air.Inst.Ref {

View File

@ -8755,17 +8755,17 @@ static void define_builtin_types(CodeGen *g) {
}
{
ZigType *entry = new_type_table_entry(ZigTypeIdEnumLiteral);
buf_init_from_str(&entry->name, "(enum literal)");
buf_init_from_str(&entry->name, "@Type(.EnumLiteral)");
g->builtin_types.entry_enum_literal = entry;
}
{
ZigType *entry = new_type_table_entry(ZigTypeIdUndefined);
buf_init_from_str(&entry->name, "(undefined)");
buf_init_from_str(&entry->name, "@Type(.Undefined)");
g->builtin_types.entry_undef = entry;
}
{
ZigType *entry = new_type_table_entry(ZigTypeIdNull);
buf_init_from_str(&entry->name, "(null)");
buf_init_from_str(&entry->name, "@Type(.Null)");
g->builtin_types.entry_null = entry;
}
{

View File

@ -1197,6 +1197,113 @@ pub const Type = extern union {
}
}
/// Returns a name suitable for `@typeName`.
pub fn nameAlloc(ty: Type, arena: *Allocator) Allocator.Error![:0]const u8 {
const t = ty.tag();
switch (t) {
.inferred_alloc_const => unreachable,
.inferred_alloc_mut => unreachable,
.generic_poison => unreachable,
.u1,
.u8,
.i8,
.u16,
.i16,
.u32,
.i32,
.u64,
.i64,
.u128,
.i128,
.usize,
.isize,
.c_short,
.c_ushort,
.c_int,
.c_uint,
.c_long,
.c_ulong,
.c_longlong,
.c_ulonglong,
.c_longdouble,
.c_void,
.f16,
.f32,
.f64,
.f128,
.bool,
.void,
.type,
.anyerror,
.@"anyframe",
.comptime_int,
.comptime_float,
.noreturn,
.var_args_param,
.bound_fn,
=> return @tagName(t),
.enum_literal => return "@Type(.EnumLiteral)",
.@"null" => return "@Type(.Null)",
.@"undefined" => return "@Type(.Undefined)",
.empty_struct, .empty_struct_literal => return "struct {}",
.@"struct" => {
const struct_obj = ty.castTag(.@"struct").?.data;
return try arena.dupeZ(u8, std.mem.sliceTo(struct_obj.owner_decl.name, 0));
},
.@"union", .union_tagged => {
const union_obj = ty.cast(Payload.Union).?.data;
return try arena.dupeZ(u8, std.mem.sliceTo(union_obj.owner_decl.name, 0));
},
.enum_full, .enum_nonexhaustive => {
const enum_full = ty.cast(Payload.EnumFull).?.data;
return try arena.dupeZ(u8, std.mem.sliceTo(enum_full.owner_decl.name, 0));
},
.enum_simple => {
const enum_simple = ty.castTag(.enum_simple).?.data;
return try arena.dupeZ(u8, std.mem.sliceTo(enum_simple.owner_decl.name, 0));
},
.enum_numbered => {
const enum_numbered = ty.castTag(.enum_numbered).?.data;
return try arena.dupeZ(u8, std.mem.sliceTo(enum_numbered.owner_decl.name, 0));
},
.@"opaque" => {
// TODO use declaration name
return "opaque {}";
},
.anyerror_void_error_union => return "anyerror!void",
.const_slice_u8 => return "[]const u8",
.fn_noreturn_no_args => return "fn() noreturn",
.fn_void_no_args => return "fn() void",
.fn_naked_noreturn_no_args => return "fn() callconv(.Naked) noreturn",
.fn_ccc_void_no_args => return "fn() callconv(.C) void",
.single_const_pointer_to_comptime_int => return "*const comptime_int",
.manyptr_u8 => return "[*]u8",
.manyptr_const_u8 => return "[*]const u8",
.atomic_order => return "AtomicOrder",
.atomic_rmw_op => return "AtomicRmwOp",
.calling_convention => return "CallingConvention",
.address_space => return "AddressSpace",
.float_mode => return "FloatMode",
.reduce_op => return "ReduceOp",
.call_options => return "CallOptions",
.export_options => return "ExportOptions",
.extern_options => return "ExternOptions",
.type_info => return "TypeInfo",
else => {
// TODO this is wasteful and also an incorrect implementation of `@typeName`
var buf = std.ArrayList(u8).init(arena);
try buf.writer().print("{}", .{ty});
return try buf.toOwnedSliceSentinel(0);
},
}
}
/// Anything that reports hasCodeGenBits() false returns false here as well.
/// `generic_poison` will return false.
pub fn requiresComptime(ty: Type) bool {

View File

@ -24,11 +24,11 @@ test {
_ = @import("behavior/defer.zig");
_ = @import("behavior/enum.zig");
_ = @import("behavior/error.zig");
_ = @import("behavior/error.zig");
_ = @import("behavior/generics.zig");
_ = @import("behavior/hasdecl.zig");
_ = @import("behavior/hasfield.zig");
_ = @import("behavior/if.zig");
_ = @import("behavior/import.zig");
_ = @import("behavior/int128.zig");
_ = @import("behavior/member_func.zig");
_ = @import("behavior/null.zig");
@ -73,7 +73,9 @@ test {
_ = @import("behavior/slice.zig");
_ = @import("behavior/struct_llvm.zig");
_ = @import("behavior/switch.zig");
_ = @import("behavior/undefined.zig");
_ = @import("behavior/union.zig");
_ = @import("behavior/void.zig");
_ = @import("behavior/widening.zig");
if (builtin.zig_is_stage2) {
@ -151,7 +153,6 @@ test {
_ = @import("behavior/fn_in_struct_in_comptime.zig");
_ = @import("behavior/for_stage1.zig");
_ = @import("behavior/if_stage1.zig");
_ = @import("behavior/import.zig");
_ = @import("behavior/incomplete_struct_param_tld.zig");
_ = @import("behavior/inttoptr.zig");
_ = @import("behavior/ir_block_deps.zig");
@ -183,13 +184,11 @@ test {
_ = @import("behavior/type.zig");
_ = @import("behavior/type_info.zig");
_ = @import("behavior/typename.zig");
_ = @import("behavior/undefined.zig");
_ = @import("behavior/union_stage1.zig");
_ = @import("behavior/union_with_members.zig");
_ = @import("behavior/usingnamespace_stage1.zig");
_ = @import("behavior/var_args.zig");
_ = @import("behavior/vector.zig");
_ = @import("behavior/void.zig");
if (builtin.target.cpu.arch == .wasm32) {
_ = @import("behavior/wasm.zig");
}

View File

@ -583,3 +583,25 @@ test "peer type resolution with enum literal" {
try expect(Items.two == .two);
try expect(.two == Items.two);
}
const MultipleChoice = enum(u32) {
A = 20,
B = 40,
C = 60,
D = 1000,
};
fn testEnumWithSpecifiedTagValues(x: MultipleChoice) !void {
try expect(@enumToInt(x) == 60);
try expect(1234 == switch (x) {
MultipleChoice.A => 1,
MultipleChoice.B => 2,
MultipleChoice.C => @as(u32, 1234),
MultipleChoice.D => 4,
});
}
test "enum with specified tag values" {
try testEnumWithSpecifiedTagValues(MultipleChoice.C);
comptime try testEnumWithSpecifiedTagValues(MultipleChoice.C);
}

View File

@ -2,28 +2,6 @@ const expect = @import("std").testing.expect;
const mem = @import("std").mem;
const Tag = @import("std").meta.Tag;
const MultipleChoice = enum(u32) {
A = 20,
B = 40,
C = 60,
D = 1000,
};
fn testEnumWithSpecifiedTagValues(x: MultipleChoice) !void {
try expect(@enumToInt(x) == 60);
try expect(1234 == switch (x) {
MultipleChoice.A => 1,
MultipleChoice.B => 2,
MultipleChoice.C => @as(u32, 1234),
MultipleChoice.D => 4,
});
}
test "enum with specified tag values" {
try testEnumWithSpecifiedTagValues(MultipleChoice.C);
comptime try testEnumWithSpecifiedTagValues(MultipleChoice.C);
}
test "non-exhaustive enum" {
const S = struct {
const E = enum(u8) {

View File

@ -163,3 +163,84 @@ fn fComplexCallconvRet(x: u32) callconv(blk: {
test "function with complex callconv and return type expressions" {
try expect(fComplexCallconvRet(3).x == 9);
}
test "pass by non-copying value" {
try expect(addPointCoords(Point{ .x = 1, .y = 2 }) == 3);
}
const Point = struct {
x: i32,
y: i32,
};
fn addPointCoords(pt: Point) i32 {
return pt.x + pt.y;
}
test "pass by non-copying value through var arg" {
try expect((try addPointCoordsVar(Point{ .x = 1, .y = 2 })) == 3);
}
fn addPointCoordsVar(pt: anytype) !i32 {
comptime try expect(@TypeOf(pt) == Point);
return pt.x + pt.y;
}
test "pass by non-copying value as method" {
var pt = Point2{ .x = 1, .y = 2 };
try expect(pt.addPointCoords() == 3);
}
const Point2 = struct {
x: i32,
y: i32,
fn addPointCoords(self: Point2) i32 {
return self.x + self.y;
}
};
test "pass by non-copying value as method, which is generic" {
var pt = Point3{ .x = 1, .y = 2 };
try expect(pt.addPointCoords(i32) == 3);
}
const Point3 = struct {
x: i32,
y: i32,
fn addPointCoords(self: Point3, comptime T: type) i32 {
_ = T;
return self.x + self.y;
}
};
test "pass by non-copying value as method, at comptime" {
comptime {
var pt = Point2{ .x = 1, .y = 2 };
try expect(pt.addPointCoords() == 3);
}
}
test "implicit cast fn call result to optional in field result" {
const S = struct {
fn entry() !void {
var x = Foo{
.field = optionalPtr(),
};
try expect(x.field.?.* == 999);
}
const glob: i32 = 999;
fn optionalPtr() *const i32 {
return &glob;
}
const Foo = struct {
field: ?*const i32,
};
};
try S.entry();
comptime try S.entry();
}

View File

@ -56,87 +56,6 @@ fn numberLiteralArg(a: anytype) !void {
try expect(a == 3);
}
test "pass by non-copying value" {
try expect(addPointCoords(Point{ .x = 1, .y = 2 }) == 3);
}
const Point = struct {
x: i32,
y: i32,
};
fn addPointCoords(pt: Point) i32 {
return pt.x + pt.y;
}
test "pass by non-copying value through var arg" {
try expect((try addPointCoordsVar(Point{ .x = 1, .y = 2 })) == 3);
}
fn addPointCoordsVar(pt: anytype) !i32 {
comptime try expect(@TypeOf(pt) == Point);
return pt.x + pt.y;
}
test "pass by non-copying value as method" {
var pt = Point2{ .x = 1, .y = 2 };
try expect(pt.addPointCoords() == 3);
}
const Point2 = struct {
x: i32,
y: i32,
fn addPointCoords(self: Point2) i32 {
return self.x + self.y;
}
};
test "pass by non-copying value as method, which is generic" {
var pt = Point3{ .x = 1, .y = 2 };
try expect(pt.addPointCoords(i32) == 3);
}
const Point3 = struct {
x: i32,
y: i32,
fn addPointCoords(self: Point3, comptime T: type) i32 {
_ = T;
return self.x + self.y;
}
};
test "pass by non-copying value as method, at comptime" {
comptime {
var pt = Point2{ .x = 1, .y = 2 };
try expect(pt.addPointCoords() == 3);
}
}
test "implicit cast fn call result to optional in field result" {
const S = struct {
fn entry() !void {
var x = Foo{
.field = optionalPtr(),
};
try expect(x.field.?.* == 999);
}
const glob: i32 = 999;
fn optionalPtr() *const i32 {
return &glob;
}
const Foo = struct {
field: ?*const i32,
};
};
try S.entry();
comptime try S.entry();
}
test "function call with anon list literal" {
const S = struct {
fn doTheTest() !void {

View File

@ -60,3 +60,59 @@ test "ignore lval with underscore (for loop)" {
break;
}
}
test "basic for loop" {
const expected_result = [_]u8{ 9, 8, 7, 6, 0, 1, 2, 3 } ** 3;
var buffer: [expected_result.len]u8 = undefined;
var buf_index: usize = 0;
const array = [_]u8{ 9, 8, 7, 6 };
for (array) |item| {
buffer[buf_index] = item;
buf_index += 1;
}
for (array) |item, index| {
_ = item;
buffer[buf_index] = @intCast(u8, index);
buf_index += 1;
}
const array_ptr = &array;
for (array_ptr) |item| {
buffer[buf_index] = item;
buf_index += 1;
}
for (array_ptr) |item, index| {
_ = item;
buffer[buf_index] = @intCast(u8, index);
buf_index += 1;
}
const unknown_size: []const u8 = &array;
for (unknown_size) |item| {
buffer[buf_index] = item;
buf_index += 1;
}
for (unknown_size) |_, index| {
buffer[buf_index] = @intCast(u8, index);
buf_index += 1;
}
try expect(mem.eql(u8, buffer[0..buf_index], &expected_result));
}
test "for with null and T peer types and inferred result location type" {
const S = struct {
fn doTheTest(slice: []const u8) !void {
if (for (slice) |item| {
if (item == 10) {
break item;
}
} else null) |v| {
_ = v;
@panic("fail");
}
}
};
try S.doTheTest(&[_]u8{ 1, 2 });
comptime try S.doTheTest(&[_]u8{ 1, 2 });
}

View File

@ -26,45 +26,6 @@ fn mangleString(s: []u8) void {
}
}
test "basic for loop" {
const expected_result = [_]u8{ 9, 8, 7, 6, 0, 1, 2, 3 } ** 3;
var buffer: [expected_result.len]u8 = undefined;
var buf_index: usize = 0;
const array = [_]u8{ 9, 8, 7, 6 };
for (array) |item| {
buffer[buf_index] = item;
buf_index += 1;
}
for (array) |item, index| {
_ = item;
buffer[buf_index] = @intCast(u8, index);
buf_index += 1;
}
const array_ptr = &array;
for (array_ptr) |item| {
buffer[buf_index] = item;
buf_index += 1;
}
for (array_ptr) |item, index| {
_ = item;
buffer[buf_index] = @intCast(u8, index);
buf_index += 1;
}
const unknown_size: []const u8 = &array;
for (unknown_size) |item| {
buffer[buf_index] = item;
buf_index += 1;
}
for (unknown_size) |_, index| {
buffer[buf_index] = @intCast(u8, index);
buf_index += 1;
}
try expect(mem.eql(u8, buffer[0..buf_index], &expected_result));
}
test "2 break statements and an else" {
const S = struct {
fn entry(t: bool, f: bool) !void {
@ -82,23 +43,6 @@ test "2 break statements and an else" {
comptime try S.entry(true, false);
}
test "for with null and T peer types and inferred result location type" {
const S = struct {
fn doTheTest(slice: []const u8) !void {
if (for (slice) |item| {
if (item == 10) {
break item;
}
} else null) |v| {
_ = v;
@panic("fail");
}
}
};
try S.doTheTest(&[_]u8{ 1, 2 });
comptime try S.doTheTest(&[_]u8{ 1, 2 });
}
test "for copies its payload" {
const S = struct {
fn doTheTest() !void {

View File

@ -3,7 +3,7 @@ const expectEqual = @import("std").testing.expectEqual;
const a_namespace = @import("import/a_namespace.zig");
test "call fn via namespace lookup" {
try expectEqual(@as(i32, 1234), a_namespace.foo());
try expect(@as(i32, 1234) == a_namespace.foo());
}
test "importing the same thing gives the same import" {
@ -14,7 +14,7 @@ test "import in non-toplevel scope" {
const S = struct {
usingnamespace @import("import/a_namespace.zig");
};
try expectEqual(@as(i32, 1234), S.foo());
try expect(@as(i32, 1234) == S.foo());
}
test "import empty file" {

View File

@ -115,3 +115,28 @@ test "optional pointer to 0 bit type null value at runtime" {
var x: ?*EmptyStruct = null;
try expect(x == null);
}
test "if var maybe pointer" {
try expect(shouldBeAPlus1(Particle{
.a = 14,
.b = 1,
.c = 1,
.d = 1,
}) == 15);
}
fn shouldBeAPlus1(p: Particle) u64 {
var maybe_particle: ?Particle = p;
if (maybe_particle) |*particle| {
particle.a += 1;
}
if (maybe_particle) |particle| {
return particle.a;
}
return 0;
}
const Particle = struct {
a: u64,
b: u64,
c: u64,
d: u64,
};

View File

@ -65,5 +65,5 @@ test "assign undefined to struct with method" {
test "type name of undefined" {
const x = undefined;
try expect(mem.eql(u8, @typeName(@TypeOf(x)), "(undefined)"));
try expect(mem.eql(u8, @typeName(@TypeOf(x)), "@Type(.Undefined)"));
}

View File

@ -153,6 +153,20 @@ test "while with optional as condition with else" {
try expect(got_else == 1);
}
test "while with error union condition" {
numbers_left = 10;
var sum: i32 = 0;
var got_else: i32 = 0;
while (getNumberOrErr()) |value| {
sum += value;
} else |err| {
try expect(err == error.OutOfNumbers);
got_else += 1;
}
try expect(sum == 45);
try expect(got_else == 1);
}
test "while on bool with else result follow else prong" {
const result = while (returnFalse()) {
break @as(i32, 10);
@ -199,3 +213,26 @@ fn returnFalse() bool {
fn returnTrue() bool {
return true;
}
test "return with implicit cast from while loop" {
returnWithImplicitCastFromWhileLoopTest() catch unreachable;
}
fn returnWithImplicitCastFromWhileLoopTest() anyerror!void {
while (true) {
return;
}
}
test "while on error union with else result follow else prong" {
const result = while (returnError()) |value| {
break value;
} else |_| @as(i32, 2);
try expect(result == 2);
}
test "while on error union with else result follow break prong" {
const result = while (returnSuccess(10)) |value| {
break value;
} else |_| @as(i32, 2);
try expect(result == 10);
}

View File

@ -1,76 +1,6 @@
const std = @import("std");
const expect = std.testing.expect;
test "return with implicit cast from while loop" {
returnWithImplicitCastFromWhileLoopTest() catch unreachable;
}
fn returnWithImplicitCastFromWhileLoopTest() anyerror!void {
while (true) {
return;
}
}
test "while with error union condition" {
numbers_left = 10;
var sum: i32 = 0;
var got_else: i32 = 0;
while (getNumberOrErr()) |value| {
sum += value;
} else |err| {
try expect(err == error.OutOfNumbers);
got_else += 1;
}
try expect(sum == 45);
try expect(got_else == 1);
}
var numbers_left: i32 = undefined;
fn getNumberOrErr() anyerror!i32 {
return if (numbers_left == 0) error.OutOfNumbers else x: {
numbers_left -= 1;
break :x numbers_left;
};
}
fn getNumberOrNull() ?i32 {
return if (numbers_left == 0) null else x: {
numbers_left -= 1;
break :x numbers_left;
};
}
test "while on error union with else result follow else prong" {
const result = while (returnError()) |value| {
break value;
} else |_| @as(i32, 2);
try expect(result == 2);
}
test "while on error union with else result follow break prong" {
const result = while (returnSuccess(10)) |value| {
break value;
} else |_| @as(i32, 2);
try expect(result == 10);
}
fn returnNull() ?i32 {
return null;
}
fn returnOptional(x: i32) ?i32 {
return x;
}
fn returnError() anyerror!i32 {
return error.YouWantedAnError;
}
fn returnSuccess(x: i32) anyerror!i32 {
return x;
}
fn returnFalse() bool {
return false;
}
fn returnTrue() bool {
return true;
}
test "while bool 2 break statements and an else" {
const S = struct {
fn entry(t: bool, f: bool) !void {

View File

@ -2674,7 +2674,7 @@ pub fn addCases(ctx: *TestContext) !void {
\\ }
\\}
, &[_][]const u8{
"tmp.zig:3:9: error: expected type 'error{Hi}', found '(enum literal)'",
"tmp.zig:3:9: error: expected type 'error{Hi}', found '@Type(.EnumLiteral)'",
});
ctx.objErrStage1("@sizeOf bad type",
@ -2682,7 +2682,7 @@ pub fn addCases(ctx: *TestContext) !void {
\\ return @sizeOf(@TypeOf(null));
\\}
, &[_][]const u8{
"tmp.zig:2:20: error: no size available for type '(null)'",
"tmp.zig:2:20: error: no size available for type '@Type(.Null)'",
});
ctx.objErrStage1("generic function where return type is self-referenced",
@ -5783,7 +5783,7 @@ pub fn addCases(ctx: *TestContext) !void {
\\
\\export fn entry() usize { return @sizeOf(@TypeOf(a)); }
, &[_][]const u8{
"tmp.zig:1:16: error: expected type '*u8', found '(null)'",
"tmp.zig:1:16: error: expected type '*u8', found '@Type(.Null)'",
});
ctx.objErrStage1("indexing an array of size zero",
@ -7506,12 +7506,12 @@ pub fn addCases(ctx: *TestContext) !void {
\\};
, &[_][]const u8{
"tmp.zig:2:4: error: variable of type '*const comptime_int' must be const or comptime",
"tmp.zig:6:4: error: variable of type '(undefined)' must be const or comptime",
"tmp.zig:6:4: error: variable of type '@Type(.Undefined)' must be const or comptime",
"tmp.zig:10:4: error: variable of type 'comptime_int' must be const or comptime",
"tmp.zig:10:4: note: to modify this variable at runtime, it must be given an explicit fixed-size number type",
"tmp.zig:14:4: error: variable of type 'comptime_float' must be const or comptime",
"tmp.zig:14:4: note: to modify this variable at runtime, it must be given an explicit fixed-size number type",
"tmp.zig:18:4: error: variable of type '(null)' must be const or comptime",
"tmp.zig:18:4: error: variable of type '@Type(.Null)' must be const or comptime",
"tmp.zig:22:4: error: variable of type 'Opaque' not allowed",
"tmp.zig:26:4: error: variable of type 'type' must be const or comptime",
"tmp.zig:30:4: error: variable of type '(bound fn(*const Foo) void)' must be const or comptime",
@ -8278,8 +8278,8 @@ pub fn addCases(ctx: *TestContext) !void {
, &[_][]const u8{
"tmp.zig:2:18: error: Opaque return type 'FooType' not allowed",
"tmp.zig:1:1: note: type declared here",
"tmp.zig:5:18: error: Null return type '(null)' not allowed",
"tmp.zig:8:18: error: Undefined return type '(undefined)' not allowed",
"tmp.zig:5:18: error: Null return type '@Type(.Null)' not allowed",
"tmp.zig:8:18: error: Undefined return type '@Type(.Undefined)' not allowed",
});
ctx.objErrStage1("generic function returning opaque type",
@ -8300,9 +8300,9 @@ pub fn addCases(ctx: *TestContext) !void {
"tmp.zig:6:16: error: call to generic function with Opaque return type 'FooType' not allowed",
"tmp.zig:2:1: note: function declared here",
"tmp.zig:1:1: note: type declared here",
"tmp.zig:9:16: error: call to generic function with Null return type '(null)' not allowed",
"tmp.zig:9:16: error: call to generic function with Null return type '@Type(.Null)' not allowed",
"tmp.zig:2:1: note: function declared here",
"tmp.zig:12:16: error: call to generic function with Undefined return type '(undefined)' not allowed",
"tmp.zig:12:16: error: call to generic function with Undefined return type '@Type(.Undefined)' not allowed",
"tmp.zig:2:1: note: function declared here",
});
@ -8329,9 +8329,9 @@ pub fn addCases(ctx: *TestContext) !void {
\\}
, &[_][]const u8{
"tmp.zig:3:28: error: parameter of opaque type 'FooType' not allowed",
"tmp.zig:8:28: error: parameter of type '(null)' not allowed",
"tmp.zig:8:28: error: parameter of type '@Type(.Null)' not allowed",
"tmp.zig:12:11: error: parameter of opaque type 'FooType' not allowed",
"tmp.zig:17:11: error: parameter of type '(null)' not allowed",
"tmp.zig:17:11: error: parameter of type '@Type(.Null)' not allowed",
});
ctx.objErrStage1( // fixed bug #2032