authorgravatar for git@vexu.euVeikka Tuominen <git@vexu.eu> 2022-08-21 18:04:46+03:00
committergravatar for git@vexu.euVeikka Tuominen <git@vexu.eu> 2022-08-22 11:16:36+03:00
logb55a5007faad1de054e86e00bfdc9a58e5fc4ff8
treee0c0713b6056b24f48e614805225739e8069f420
parentb2f02a820f1ed46721ed55243cead52efed055d7

Sema: fix parameter of type 'T' must be comptime error

Closes #12519 Closes #12505

14 files changed, 51 insertions(+), 22 deletions(-)

doc/langref.html.in+2-2
...@@ -5023,8 +5023,8 @@ fn shiftLeftOne(a: u32) callconv(.Inline) u32 {...@@ -5023,8 +5023,8 @@ fn shiftLeftOne(a: u32) callconv(.Inline) u32 {
5023// Another file can use @import and call sub25023// Another file can use @import and call sub2
5024pub fn sub2(a: i8, b: i8) i8 { return a - b; }5024pub fn sub2(a: i8, b: i8) i8 { return a - b; }
50255025
5026// Functions can be used as values and are equivalent to pointers.5026// Function pointers are prefixed with `*const `.
5027const call2_op = fn (a: i8, b: i8) i8;5027const call2_op = *const fn (a: i8, b: i8) i8;
5028fn do_op(fn_call: call2_op, op1: i8, op2: i8) i8 {5028fn do_op(fn_call: call2_op, op1: i8, op2: i8) i8 {
5029 return fn_call(op1, op2);5029 return fn_call(op1, op2);
5030}5030}
lib/std/fs/path.zig+1-1
...@@ -42,7 +42,7 @@ pub fn isSep(byte: u8) bool {...@@ -42,7 +42,7 @@ pub fn isSep(byte: u8) bool {
4242
43/// This is different from mem.join in that the separator will not be repeated if43/// This is different from mem.join in that the separator will not be repeated if
44/// it is found at the end or beginning of a pair of consecutive paths.44/// it is found at the end or beginning of a pair of consecutive paths.
45fn joinSepMaybeZ(allocator: Allocator, separator: u8, sepPredicate: fn (u8) bool, paths: []const []const u8, zero: bool) ![]u8 {45fn joinSepMaybeZ(allocator: Allocator, separator: u8, comptime sepPredicate: fn (u8) bool, paths: []const []const u8, zero: bool) ![]u8 {
46 if (paths.len == 0) return if (zero) try allocator.dupe(u8, &[1]u8{0}) else &[0]u8{};46 if (paths.len == 0) return if (zero) try allocator.dupe(u8, &[1]u8{0}) else &[0]u8{};
4747
48 // Find first non-empty path index.48 // Find first non-empty path index.
lib/std/math.zig+1-1
...@@ -1548,7 +1548,7 @@ test "boolMask" {...@@ -1548,7 +1548,7 @@ test "boolMask" {
1548}1548}
15491549
1550/// Return the mod of `num` with the smallest integer type1550/// Return the mod of `num` with the smallest integer type
1551pub fn comptimeMod(num: anytype, denom: comptime_int) IntFittingRange(0, denom - 1) {1551pub fn comptimeMod(num: anytype, comptime denom: comptime_int) IntFittingRange(0, denom - 1) {
1552 return @intCast(IntFittingRange(0, denom - 1), @mod(num, denom));1552 return @intCast(IntFittingRange(0, denom - 1), @mod(num, denom));
1553}1553}
15541554
lib/std/math/float.zig+1-1
...@@ -8,7 +8,7 @@ inline fn mantissaOne(comptime T: type) comptime_int {...@@ -8,7 +8,7 @@ inline fn mantissaOne(comptime T: type) comptime_int {
8}8}
99
10/// Creates floating point type T from an unbiased exponent and raw mantissa.10/// Creates floating point type T from an unbiased exponent and raw mantissa.
11inline fn reconstructFloat(comptime T: type, exponent: comptime_int, mantissa: comptime_int) T {11inline fn reconstructFloat(comptime T: type, comptime exponent: comptime_int, comptime mantissa: comptime_int) T {
12 const TBits = @Type(.{ .Int = .{ .signedness = .unsigned, .bits = @bitSizeOf(T) } });12 const TBits = @Type(.{ .Int = .{ .signedness = .unsigned, .bits = @bitSizeOf(T) } });
13 const biased_exponent = @as(TBits, exponent + floatExponentMax(T));13 const biased_exponent = @as(TBits, exponent + floatExponentMax(T));
14 return @bitCast(T, (biased_exponent << floatMantissaBits(T)) | @as(TBits, mantissa));14 return @bitCast(T, (biased_exponent << floatMantissaBits(T)) | @as(TBits, mantissa));
lib/std/zig/c_translation.zig+1-1
...@@ -349,7 +349,7 @@ test "shuffleVectorIndex" {...@@ -349,7 +349,7 @@ test "shuffleVectorIndex" {
349349
350/// Constructs a [*c] pointer with the const and volatile annotations350/// Constructs a [*c] pointer with the const and volatile annotations
351/// from SelfType for pointing to a C flexible array of ElementType.351/// from SelfType for pointing to a C flexible array of ElementType.
352pub fn FlexibleArrayType(comptime SelfType: type, ElementType: type) type {352pub fn FlexibleArrayType(comptime SelfType: type, comptime ElementType: type) type {
353 switch (@typeInfo(SelfType)) {353 switch (@typeInfo(SelfType)) {
354 .Pointer => |ptr| {354 .Pointer => |ptr| {
355 return @Type(.{ .Pointer = .{355 return @Type(.{ .Pointer = .{
lib/std/zig/parse.zig+1-1
...@@ -3670,7 +3670,7 @@ const Parser = struct {...@@ -3670,7 +3670,7 @@ const Parser = struct {
3670 }3670 }
36713671
3672 /// KEYWORD_if LPAREN Expr RPAREN PtrPayload? Body (KEYWORD_else Payload? Body)?3672 /// KEYWORD_if LPAREN Expr RPAREN PtrPayload? Body (KEYWORD_else Payload? Body)?
3673 fn parseIf(p: *Parser, bodyParseFn: fn (p: *Parser) Error!Node.Index) !Node.Index {3673 fn parseIf(p: *Parser, comptime bodyParseFn: fn (p: *Parser) Error!Node.Index) !Node.Index {
3674 const if_token = p.eatToken(.keyword_if) orelse return null_node;3674 const if_token = p.eatToken(.keyword_if) orelse return null_node;
3675 _ = try p.expectToken(.l_paren);3675 _ = try p.expectToken(.l_paren);
3676 const condition = try p.expectExpr();3676 const condition = try p.expectExpr();
src/Module.zig+4-4
...@@ -6072,17 +6072,17 @@ pub fn paramSrc(...@@ -6072,17 +6072,17 @@ pub fn paramSrc(
6072 else => unreachable,6072 else => unreachable,
6073 };6073 };
6074 var it = full.iterate(tree);6074 var it = full.iterate(tree);
6075 while (true) {6075 var i: usize = 0;
6076 if (it.param_i == param_i) {6076 while (it.next()) |param| : (i += 1) {
6077 const param = it.next().?;6077 if (i == param_i) {
6078 if (param.anytype_ellipsis3) |some| {6078 if (param.anytype_ellipsis3) |some| {
6079 const main_token = tree.nodes.items(.main_token)[decl.src_node];6079 const main_token = tree.nodes.items(.main_token)[decl.src_node];
6080 return .{ .token_offset_param = @bitCast(i32, some) - @bitCast(i32, main_token) };6080 return .{ .token_offset_param = @bitCast(i32, some) - @bitCast(i32, main_token) };
6081 }6081 }
6082 return .{ .node_offset_param = decl.nodeIndexToRelative(param.type_expr) };6082 return .{ .node_offset_param = decl.nodeIndexToRelative(param.type_expr) };
6083 }6083 }
6084 _ = it.next();
6085 }6084 }
6085 unreachable;
6086}6086}
60876087
6088pub fn argSrc(6088pub fn argSrc(
src/Sema.zig+12-6
...@@ -76,6 +76,8 @@ types_to_resolve: std.ArrayListUnmanaged(Air.Inst.Ref) = .{},...@@ -76,6 +76,8 @@ types_to_resolve: std.ArrayListUnmanaged(Air.Inst.Ref) = .{},
76post_hoc_blocks: std.AutoHashMapUnmanaged(Air.Inst.Index, *LabeledBlock) = .{},76post_hoc_blocks: std.AutoHashMapUnmanaged(Air.Inst.Index, *LabeledBlock) = .{},
77/// Populated with the last compile error created.77/// Populated with the last compile error created.
78err: ?*Module.ErrorMsg = null,78err: ?*Module.ErrorMsg = null,
79/// True when analyzing a generic instantiation. Used to suppress some errors.
80is_generic_instantiation: bool = false,
7981
80const std = @import("std");82const std = @import("std");
81const math = std.math;83const math = std.math;
...@@ -6495,6 +6497,7 @@ fn instantiateGenericCall(...@@ -6495,6 +6497,7 @@ fn instantiateGenericCall(
6495 .comptime_args = try new_decl_arena_allocator.alloc(TypedValue, uncasted_args.len),6497 .comptime_args = try new_decl_arena_allocator.alloc(TypedValue, uncasted_args.len),
6496 .comptime_args_fn_inst = module_fn.zir_body_inst,6498 .comptime_args_fn_inst = module_fn.zir_body_inst,
6497 .preallocated_new_func = new_module_func,6499 .preallocated_new_func = new_module_func,
6500 .is_generic_instantiation = true,
6498 };6501 };
6499 defer child_sema.deinit();6502 defer child_sema.deinit();
65006503
...@@ -7789,6 +7792,7 @@ fn funcCommon(...@@ -7789,6 +7792,7 @@ fn funcCommon(
7789 &is_generic,7792 &is_generic,
7790 is_extern,7793 is_extern,
7791 cc_workaround,7794 cc_workaround,
7795 has_body,
7792 ) catch |err| switch (err) {7796 ) catch |err| switch (err) {
7793 error.NeededSourceLocation => {7797 error.NeededSourceLocation => {
7794 const decl = sema.mod.declPtr(block.src_decl);7798 const decl = sema.mod.declPtr(block.src_decl);
...@@ -7802,6 +7806,7 @@ fn funcCommon(...@@ -7802,6 +7806,7 @@ fn funcCommon(
7802 &is_generic,7806 &is_generic,
7803 is_extern,7807 is_extern,
7804 cc_workaround,7808 cc_workaround,
7809 has_body,
7805 );7810 );
7806 return error.AnalysisFail;7811 return error.AnalysisFail;
7807 },7812 },
...@@ -8005,6 +8010,7 @@ fn analyzeParameter(...@@ -8005,6 +8010,7 @@ fn analyzeParameter(
8005 is_generic: *bool,8010 is_generic: *bool,
8006 is_extern: bool,8011 is_extern: bool,
8007 cc: std.builtin.CallingConvention,8012 cc: std.builtin.CallingConvention,
8013 has_body: bool,
8008) !void {8014) !void {
8009 const requires_comptime = try sema.typeRequiresComptime(block, param_src, param.ty);8015 const requires_comptime = try sema.typeRequiresComptime(block, param_src, param.ty);
8010 comptime_params[i] = param.is_comptime or requires_comptime;8016 comptime_params[i] = param.is_comptime or requires_comptime;
...@@ -8053,9 +8059,9 @@ fn analyzeParameter(...@@ -8053,9 +8059,9 @@ fn analyzeParameter(
8053 };8059 };
8054 return sema.failWithOwnedErrorMsg(msg);8060 return sema.failWithOwnedErrorMsg(msg);
8055 }8061 }
8056 if (requires_comptime and !param.is_comptime) {8062 if (!sema.is_generic_instantiation and requires_comptime and !param.is_comptime and has_body) {
8057 const msg = msg: {8063 const msg = msg: {
8058 const msg = try sema.errMsg(block, param_src, "parametter of type '{}' must be declared comptime", .{8064 const msg = try sema.errMsg(block, param_src, "parameter of type '{}' must be declared comptime", .{
8059 param.ty.fmt(sema.mod),8065 param.ty.fmt(sema.mod),
8060 });8066 });
8061 errdefer msg.destroy(sema.gpa);8067 errdefer msg.destroy(sema.gpa);
...@@ -8153,7 +8159,7 @@ fn zirParam(...@@ -8153,7 +8159,7 @@ fn zirParam(
81538159
8154 try block.params.append(sema.gpa, .{8160 try block.params.append(sema.gpa, .{
8155 .ty = param_ty,8161 .ty = param_ty,
8156 .is_comptime = is_comptime,8162 .is_comptime = comptime_syntax,
8157 .name = param_name,8163 .name = param_name,
8158 });8164 });
8159 const result = try sema.addConstant(param_ty, Value.initTag(.generic_poison));8165 const result = try sema.addConstant(param_ty, Value.initTag(.generic_poison));
...@@ -16318,7 +16324,7 @@ fn zirUnaryMath(...@@ -16318,7 +16324,7 @@ fn zirUnaryMath(
16318 block: *Block,16324 block: *Block,
16319 inst: Zir.Inst.Index,16325 inst: Zir.Inst.Index,
16320 air_tag: Air.Inst.Tag,16326 air_tag: Air.Inst.Tag,
16321 eval: fn (Value, Type, Allocator, std.Target) Allocator.Error!Value,16327 comptime eval: fn (Value, Type, Allocator, std.Target) Allocator.Error!Value,
16322) CompileError!Air.Inst.Ref {16328) CompileError!Air.Inst.Ref {
16323 const tracy = trace(@src());16329 const tracy = trace(@src());
16324 defer tracy.end();16330 defer tracy.end();
...@@ -17777,7 +17783,7 @@ fn zirBitCount(...@@ -17777,7 +17783,7 @@ fn zirBitCount(
17777 block: *Block,17783 block: *Block,
17778 inst: Zir.Inst.Index,17784 inst: Zir.Inst.Index,
17779 air_tag: Air.Inst.Tag,17785 air_tag: Air.Inst.Tag,
17780 comptimeOp: fn (val: Value, ty: Type, target: std.Target) u64,17786 comptime comptimeOp: fn (val: Value, ty: Type, target: std.Target) u64,
17781) CompileError!Air.Inst.Ref {17787) CompileError!Air.Inst.Ref {
17782 const inst_data = sema.code.instructions.items(.data)[inst].un_node;17788 const inst_data = sema.code.instructions.items(.data)[inst].un_node;
17783 const src = inst_data.src();17789 const src = inst_data.src();
...@@ -29491,7 +29497,7 @@ pub fn typeRequiresComptime(sema: *Sema, block: *Block, src: LazySrcLoc, ty: Typ...@@ -29491,7 +29497,7 @@ pub fn typeRequiresComptime(sema: *Sema, block: *Block, src: LazySrcLoc, ty: Typ
29491 => {29497 => {
29492 const child_ty = ty.childType();29498 const child_ty = ty.childType();
29493 if (child_ty.zigTypeTag() == .Fn) {29499 if (child_ty.zigTypeTag() == .Fn) {
29494 return false;29500 return child_ty.fnInfo().is_generic;
29495 } else {29501 } else {
29496 return sema.typeRequiresComptime(block, src, child_ty);29502 return sema.typeRequiresComptime(block, src, child_ty);
29497 }29503 }
src/type.zig+1-1
...@@ -2394,7 +2394,7 @@ pub const Type = extern union {...@@ -2394,7 +2394,7 @@ pub const Type = extern union {
2394 if (ignore_comptime_only) {2394 if (ignore_comptime_only) {
2395 return true;2395 return true;
2396 } else if (ty.childType().zigTypeTag() == .Fn) {2396 } else if (ty.childType().zigTypeTag() == .Fn) {
2397 return true;2397 return !ty.childType().fnInfo().is_generic;
2398 } else if (sema_kit) |sk| {2398 } else if (sema_kit) |sk| {
2399 return !(try sk.sema.typeRequiresComptime(sk.block, sk.src, ty));2399 return !(try sk.sema.typeRequiresComptime(sk.block, sk.src, ty));
2400 } else {2400 } else {
test/behavior/cast.zig+1-1
...@@ -1281,7 +1281,7 @@ test "*const [N]null u8 to ?[]const u8" {...@@ -1281,7 +1281,7 @@ test "*const [N]null u8 to ?[]const u8" {
1281test "cast between [*c]T and ?[*:0]T on fn parameter" {1281test "cast between [*c]T and ?[*:0]T on fn parameter" {
1282 const S = struct {1282 const S = struct {
1283 const Handler = ?fn ([*c]const u8) callconv(.C) void;1283 const Handler = ?fn ([*c]const u8) callconv(.C) void;
1284 fn addCallback(handler: Handler) void {1284 fn addCallback(comptime handler: Handler) void {
1285 _ = handler;1285 _ = handler;
1286 }1286 }
12871287
test/behavior/error.zig+1-1
...@@ -168,7 +168,7 @@ fn entryPtr() void {...@@ -168,7 +168,7 @@ fn entryPtr() void {
168 fooPtr(ptr);168 fooPtr(ptr);
169}169}
170170
171fn foo2(f: fn () anyerror!void) void {171fn foo2(comptime f: fn () anyerror!void) void {
172 const x = f();172 const x = f();
173 x catch {173 x catch {
174 @panic("fail");174 @panic("fail");
test/behavior/fn.zig+1-1
...@@ -137,7 +137,7 @@ test "implicit cast function unreachable return" {...@@ -137,7 +137,7 @@ test "implicit cast function unreachable return" {
137 wantsFnWithVoid(fnWithUnreachable);137 wantsFnWithVoid(fnWithUnreachable);
138}138}
139139
140fn wantsFnWithVoid(f: fn () void) void {140fn wantsFnWithVoid(comptime f: fn () void) void {
141 _ = f;141 _ = f;
142}142}
143143
test/behavior/struct.zig+1-1
...@@ -147,7 +147,7 @@ test "fn call of struct field" {...@@ -147,7 +147,7 @@ test "fn call of struct field" {
147 return 13;147 return 13;
148 }148 }
149149
150 fn callStructField(foo: Foo) i32 {150 fn callStructField(comptime foo: Foo) i32 {
151 return foo.ptr();151 return foo.ptr();
152 }152 }
153 };153 };
test/cases/compile_errors/comptime_parameter_not_declared_as_such.zig created+23
...@@ -0,0 +1,23 @@
1fn f(_: anytype) void {}
2fn g(h: *const fn (anytype) void) void {
3 h({});
4}
5pub export fn entry() void {
6 g(f);
7}
8
9pub fn comptimeMod(num: anytype, denom: comptime_int) void {
10 _ = num;
11 _ = denom;
12}
13
14pub export fn entry1() void {
15 _ = comptimeMod(1, 2);
16}
17
18// error
19// backend=stage2
20// target=native
21//
22// :2:6: error: parameter of type '*const fn(anytype) void' must be declared comptime
23// :9:34: error: parameter of type 'comptime_int' must be declared comptime