mirror of
https://github.com/ziglang/zig.git
synced 2026-02-13 04:48:20 +00:00
Sema: fix anytype parameters whose types require comptime
This commit is contained in:
parent
fc1a5cd9e7
commit
6ed7850972
22
src/Sema.zig
22
src/Sema.zig
@ -4187,10 +4187,17 @@ fn analyzeCall(
|
||||
return sema.failWithNeededComptime(block, arg_src);
|
||||
}
|
||||
} else if (is_anytype) {
|
||||
// We insert into the map an instruction which is runtime-known
|
||||
// but has the type of the argument.
|
||||
const child_arg = try child_block.addArg(sema.typeOf(arg), 0);
|
||||
child_sema.inst_map.putAssumeCapacityNoClobber(inst, child_arg);
|
||||
const arg_ty = sema.typeOf(arg);
|
||||
if (arg_ty.requiresComptime()) {
|
||||
const arg_val = try sema.resolveConstValue(block, arg_src, arg);
|
||||
const child_arg = try child_sema.addConstant(arg_ty, arg_val);
|
||||
child_sema.inst_map.putAssumeCapacityNoClobber(inst, child_arg);
|
||||
} else {
|
||||
// We insert into the map an instruction which is runtime-known
|
||||
// but has the type of the argument.
|
||||
const child_arg = try child_block.addArg(arg_ty, 0);
|
||||
child_sema.inst_map.putAssumeCapacityNoClobber(inst, child_arg);
|
||||
}
|
||||
}
|
||||
arg_i += 1;
|
||||
}
|
||||
@ -5130,9 +5137,8 @@ fn funcCommon(
|
||||
const comptime_params = try sema.arena.alloc(bool, block.params.items.len);
|
||||
for (block.params.items) |param, i| {
|
||||
param_types[i] = param.ty;
|
||||
comptime_params[i] = param.is_comptime;
|
||||
is_generic = is_generic or param.is_comptime or
|
||||
param.ty.tag() == .generic_poison or param.ty.requiresComptime();
|
||||
comptime_params[i] = param.is_comptime or param.ty.requiresComptime();
|
||||
is_generic = is_generic or comptime_params[i] or param.ty.tag() == .generic_poison;
|
||||
}
|
||||
|
||||
if (align_val.tag() != .null_value) {
|
||||
@ -13146,7 +13152,7 @@ fn coerceInMemoryAllowedFns(
|
||||
return .no_match;
|
||||
}
|
||||
|
||||
// TODO: nolias
|
||||
// TODO: noalias
|
||||
|
||||
// Note: Cast direction is reversed here.
|
||||
const param = try sema.coerceInMemoryAllowed(block, src_param_ty, dest_param_ty, false, target, dest_src, src_src);
|
||||
|
||||
@ -4275,7 +4275,6 @@ pub const Type = extern union {
|
||||
is_generic: bool,
|
||||
|
||||
pub fn paramIsComptime(self: @This(), i: usize) bool {
|
||||
if (!self.is_generic) return false;
|
||||
assert(i < self.param_types.len);
|
||||
return self.comptime_params[i];
|
||||
}
|
||||
|
||||
@ -67,6 +67,7 @@ test {
|
||||
_ = @import("behavior/bugs/394.zig");
|
||||
_ = @import("behavior/bugs/656.zig");
|
||||
_ = @import("behavior/bugs/1277.zig");
|
||||
_ = @import("behavior/bugs/1310.zig");
|
||||
_ = @import("behavior/bugs/1381.zig");
|
||||
_ = @import("behavior/bugs/1500.zig");
|
||||
_ = @import("behavior/bugs/1741.zig");
|
||||
@ -74,7 +75,9 @@ test {
|
||||
_ = @import("behavior/bugs/2578.zig");
|
||||
_ = @import("behavior/bugs/3007.zig");
|
||||
_ = @import("behavior/bugs/3112.zig");
|
||||
_ = @import("behavior/bugs/3367.zig");
|
||||
_ = @import("behavior/bugs/7250.zig");
|
||||
_ = @import("behavior/bugs/9584.zig");
|
||||
_ = @import("behavior/cast_llvm.zig");
|
||||
_ = @import("behavior/enum_llvm.zig");
|
||||
_ = @import("behavior/eval.zig");
|
||||
@ -121,7 +124,6 @@ test {
|
||||
_ = @import("behavior/bugs/1025.zig");
|
||||
_ = @import("behavior/bugs/1076.zig");
|
||||
_ = @import("behavior/bugs/1120.zig");
|
||||
_ = @import("behavior/bugs/1310.zig");
|
||||
_ = @import("behavior/bugs/1322.zig");
|
||||
_ = @import("behavior/bugs/1421.zig");
|
||||
_ = @import("behavior/bugs/1442.zig");
|
||||
@ -130,7 +132,6 @@ test {
|
||||
_ = @import("behavior/bugs/1851.zig");
|
||||
_ = @import("behavior/bugs/1914.zig");
|
||||
_ = @import("behavior/bugs/2114.zig");
|
||||
_ = @import("behavior/bugs/3367.zig");
|
||||
_ = @import("behavior/bugs/3384.zig");
|
||||
_ = @import("behavior/bugs/3742.zig");
|
||||
_ = @import("behavior/bugs/3779.zig");
|
||||
@ -144,7 +145,6 @@ test {
|
||||
_ = @import("behavior/bugs/7003.zig");
|
||||
_ = @import("behavior/bugs/7027.zig");
|
||||
_ = @import("behavior/bugs/7047.zig");
|
||||
_ = @import("behavior/bugs/9584.zig");
|
||||
_ = @import("behavior/bugs/10147.zig");
|
||||
_ = @import("behavior/byteswap.zig");
|
||||
_ = @import("behavior/call_stage1.zig");
|
||||
|
||||
@ -822,3 +822,51 @@ test "enum with one member default to u0 tag type" {
|
||||
const E0 = enum { X };
|
||||
comptime try expect(Tag(E0) == u0);
|
||||
}
|
||||
|
||||
const EnumWithOneMember = enum { Eof };
|
||||
|
||||
fn doALoopThing(id: EnumWithOneMember) void {
|
||||
while (true) {
|
||||
if (id == EnumWithOneMember.Eof) {
|
||||
break;
|
||||
}
|
||||
@compileError("above if condition should be comptime");
|
||||
}
|
||||
}
|
||||
|
||||
test "comparison operator on enum with one member is comptime known" {
|
||||
doALoopThing(EnumWithOneMember.Eof);
|
||||
}
|
||||
|
||||
const State = enum { Start };
|
||||
test "switch on enum with one member is comptime known" {
|
||||
var state = State.Start;
|
||||
switch (state) {
|
||||
State.Start => return,
|
||||
}
|
||||
@compileError("analysis should not reach here");
|
||||
}
|
||||
|
||||
test "method call on an enum" {
|
||||
const S = struct {
|
||||
const E = enum {
|
||||
one,
|
||||
two,
|
||||
|
||||
fn method(self: *E) bool {
|
||||
return self.* == .two;
|
||||
}
|
||||
|
||||
fn generic_method(self: *E, foo: anytype) bool {
|
||||
return self.* == .two and foo == bool;
|
||||
}
|
||||
};
|
||||
fn doTheTest() !void {
|
||||
var e = E.two;
|
||||
try expect(e.method());
|
||||
try expect(e.generic_method(bool));
|
||||
}
|
||||
};
|
||||
try S.doTheTest();
|
||||
comptime try S.doTheTest();
|
||||
}
|
||||
|
||||
@ -96,30 +96,6 @@ fn getC(data: *const BitFieldOfEnums) C {
|
||||
return data.c;
|
||||
}
|
||||
|
||||
const EnumWithOneMember = enum { Eof };
|
||||
|
||||
fn doALoopThing(id: EnumWithOneMember) void {
|
||||
while (true) {
|
||||
if (id == EnumWithOneMember.Eof) {
|
||||
break;
|
||||
}
|
||||
@compileError("above if condition should be comptime");
|
||||
}
|
||||
}
|
||||
|
||||
test "comparison operator on enum with one member is comptime known" {
|
||||
doALoopThing(EnumWithOneMember.Eof);
|
||||
}
|
||||
|
||||
const State = enum { Start };
|
||||
test "switch on enum with one member is comptime known" {
|
||||
var state = State.Start;
|
||||
switch (state) {
|
||||
State.Start => return,
|
||||
}
|
||||
@compileError("analysis should not reach here");
|
||||
}
|
||||
|
||||
test "enum literal in array literal" {
|
||||
const Items = enum { one, two };
|
||||
const array = [_]Items{ .one, .two };
|
||||
|
||||
@ -43,30 +43,6 @@ test "enum literal casting to error union with payload enum" {
|
||||
try expect((try bar) == Bar.B);
|
||||
}
|
||||
|
||||
test "method call on an enum" {
|
||||
const S = struct {
|
||||
const E = enum {
|
||||
one,
|
||||
two,
|
||||
|
||||
fn method(self: *E) bool {
|
||||
return self.* == .two;
|
||||
}
|
||||
|
||||
fn generic_method(self: *E, foo: anytype) bool {
|
||||
return self.* == .two and foo == bool;
|
||||
}
|
||||
};
|
||||
fn doTheTest() !void {
|
||||
var e = E.two;
|
||||
try expect(e.method());
|
||||
try expect(e.generic_method(bool));
|
||||
}
|
||||
};
|
||||
try S.doTheTest();
|
||||
comptime try S.doTheTest();
|
||||
}
|
||||
|
||||
test "exporting enum type and value" {
|
||||
const S = struct {
|
||||
const E = enum(c_int) { one, two };
|
||||
@ -80,3 +56,41 @@ test "exporting enum type and value" {
|
||||
};
|
||||
try expect(S.e == .two);
|
||||
}
|
||||
|
||||
test "constant enum initialization with differing sizes" {
|
||||
try test3_1(test3_foo);
|
||||
try test3_2(test3_bar);
|
||||
}
|
||||
const Test3Foo = union(enum) {
|
||||
One: void,
|
||||
Two: f32,
|
||||
Three: Test3Point,
|
||||
};
|
||||
const Test3Point = struct {
|
||||
x: i32,
|
||||
y: i32,
|
||||
};
|
||||
const test3_foo = Test3Foo{
|
||||
.Three = Test3Point{
|
||||
.x = 3,
|
||||
.y = 4,
|
||||
},
|
||||
};
|
||||
const test3_bar = Test3Foo{ .Two = 13 };
|
||||
fn test3_1(f: Test3Foo) !void {
|
||||
switch (f) {
|
||||
Test3Foo.Three => |pt| {
|
||||
try expect(pt.x == 3);
|
||||
try expect(pt.y == 4);
|
||||
},
|
||||
else => unreachable,
|
||||
}
|
||||
}
|
||||
fn test3_2(f: Test3Foo) !void {
|
||||
switch (f) {
|
||||
Test3Foo.Two => |x| {
|
||||
try expect(x == 13);
|
||||
},
|
||||
else => unreachable,
|
||||
}
|
||||
}
|
||||
|
||||
@ -34,44 +34,6 @@ test "explicit cast optional pointers" {
|
||||
_ = b;
|
||||
}
|
||||
|
||||
test "constant enum initialization with differing sizes" {
|
||||
try test3_1(test3_foo);
|
||||
try test3_2(test3_bar);
|
||||
}
|
||||
const Test3Foo = union(enum) {
|
||||
One: void,
|
||||
Two: f32,
|
||||
Three: Test3Point,
|
||||
};
|
||||
const Test3Point = struct {
|
||||
x: i32,
|
||||
y: i32,
|
||||
};
|
||||
const test3_foo = Test3Foo{
|
||||
.Three = Test3Point{
|
||||
.x = 3,
|
||||
.y = 4,
|
||||
},
|
||||
};
|
||||
const test3_bar = Test3Foo{ .Two = 13 };
|
||||
fn test3_1(f: Test3Foo) !void {
|
||||
switch (f) {
|
||||
Test3Foo.Three => |pt| {
|
||||
try expect(pt.x == 3);
|
||||
try expect(pt.y == 4);
|
||||
},
|
||||
else => unreachable,
|
||||
}
|
||||
}
|
||||
fn test3_2(f: Test3Foo) !void {
|
||||
switch (f) {
|
||||
Test3Foo.Two => |x| {
|
||||
try expect(x == 13);
|
||||
},
|
||||
else => unreachable,
|
||||
}
|
||||
}
|
||||
|
||||
test "pointer comparison" {
|
||||
const a = @as([]const u8, "a");
|
||||
const b = &a;
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user