authorgravatar for git@vexu.euVeikka Tuominen <git@vexu.eu> 2022-03-19 13:36:16+02:00
committergravatar for git@vexu.euVeikka Tuominen <git@vexu.eu> 2022-03-19 13:36:16+02:00
log27572373325b22b06767bc42cb7e270bf619f0a9
tree9329be499d9d3d81da86d7b7e52a33ee6c925b80
parentad5770eba40e0cc425c7a1eab4d37c6f9788d670

Sema: add error for runtime block peer type being comptime only


2 files changed, 65 insertions(+), 21 deletions(-)

src/Sema.zig+63-20
...@@ -3930,6 +3930,23 @@ fn analyzeBlockBody(...@@ -3930,6 +3930,23 @@ fn analyzeBlockBody(
3930 // to emit a jump instruction to after the block when it encounters the break.3930 // to emit a jump instruction to after the block when it encounters the break.
3931 try parent_block.instructions.append(gpa, merges.block_inst);3931 try parent_block.instructions.append(gpa, merges.block_inst);
3932 const resolved_ty = try sema.resolvePeerTypes(parent_block, src, merges.results.items, .none);3932 const resolved_ty = try sema.resolvePeerTypes(parent_block, src, merges.results.items, .none);
3933
3934 const type_src = src; // TODO: better source location
3935 const valid_rt = try sema.validateRunTimeType(child_block, type_src, resolved_ty, false);
3936 if (!valid_rt) {
3937 const msg = msg: {
3938 const msg = try sema.errMsg(child_block, type_src, "value with comptime only type '{}' depends on runtime control flow", .{resolved_ty});
3939 errdefer msg.destroy(sema.gpa);
3940
3941 const runtime_src = child_block.runtime_cond orelse child_block.runtime_loop.?;
3942 try sema.errNote(child_block, runtime_src, msg, "runtime control flow here", .{});
3943
3944 try sema.explainWhyTypeIsComptime(child_block, type_src, msg, type_src.toSrcLoc(child_block.src_decl), resolved_ty);
3945
3946 break :msg msg;
3947 };
3948 return sema.failWithOwnedErrorMsg(child_block, msg);
3949 }
3933 const ty_inst = try sema.addType(resolved_ty);3950 const ty_inst = try sema.addType(resolved_ty);
3934 try sema.air_extra.ensureUnusedCapacity(gpa, @typeInfo(Air.Block).Struct.fields.len +3951 try sema.air_extra.ensureUnusedCapacity(gpa, @typeInfo(Air.Block).Struct.fields.len +
3935 child_block.instructions.items.len);3952 child_block.instructions.items.len);
...@@ -4191,6 +4208,11 @@ fn zirBreak(sema: *Sema, start_block: *Block, inst: Zir.Inst.Index) CompileError...@@ -4191,6 +4208,11 @@ fn zirBreak(sema: *Sema, start_block: *Block, inst: Zir.Inst.Index) CompileError
4191 const br_ref = try start_block.addBr(label.merges.block_inst, operand);4208 const br_ref = try start_block.addBr(label.merges.block_inst, operand);
4192 try label.merges.results.append(sema.gpa, operand);4209 try label.merges.results.append(sema.gpa, operand);
4193 try label.merges.br_list.append(sema.gpa, Air.refToIndex(br_ref).?);4210 try label.merges.br_list.append(sema.gpa, Air.refToIndex(br_ref).?);
4211 block.runtime_index += 1;
4212 if (block.runtime_cond == null and block.runtime_loop == null) {
4213 block.runtime_cond = start_block.runtime_cond orelse start_block.runtime_loop;
4214 block.runtime_loop = start_block.runtime_loop;
4215 }
4194 return inst;4216 return inst;
4195 }4217 }
4196 }4218 }
...@@ -15447,6 +15469,26 @@ fn validateVarType(...@@ -15447,6 +15469,26 @@ fn validateVarType(
15447 var_ty: Type,15469 var_ty: Type,
15448 is_extern: bool,15470 is_extern: bool,
15449) CompileError!void {15471) CompileError!void {
15472 if (try sema.validateRunTimeType(block, src, var_ty, is_extern)) return;
15473
15474 const msg = msg: {
15475 const msg = try sema.errMsg(block, src, "variable of type '{}' must be const or comptime", .{var_ty});
15476 errdefer msg.destroy(sema.gpa);
15477
15478 try sema.explainWhyTypeIsComptime(block, src, msg, src.toSrcLoc(block.src_decl), var_ty);
15479
15480 break :msg msg;
15481 };
15482 return sema.failWithOwnedErrorMsg(block, msg);
15483}
15484
15485fn validateRunTimeType(
15486 sema: *Sema,
15487 block: *Block,
15488 src: LazySrcLoc,
15489 var_ty: Type,
15490 is_extern: bool,
15491) CompileError!bool {
15450 var ty = var_ty;15492 var ty = var_ty;
15451 while (true) switch (ty.zigTypeTag()) {15493 while (true) switch (ty.zigTypeTag()) {
15452 .Bool,15494 .Bool,
...@@ -15457,7 +15499,7 @@ fn validateVarType(...@@ -15457,7 +15499,7 @@ fn validateVarType(
15457 .Frame,15499 .Frame,
15458 .AnyFrame,15500 .AnyFrame,
15459 .Void,15501 .Void,
15460 => return,15502 => return true,
1546115503
15462 .BoundFn,15504 .BoundFn,
15463 .ComptimeFloat,15505 .ComptimeFloat,
...@@ -15468,21 +15510,21 @@ fn validateVarType(...@@ -15468,21 +15510,21 @@ fn validateVarType(
15468 .Undefined,15510 .Undefined,
15469 .Null,15511 .Null,
15470 .Fn,15512 .Fn,
15471 => break,15513 => return false,
1547215514
15473 .Pointer => {15515 .Pointer => {
15474 const elem_ty = ty.childType();15516 const elem_ty = ty.childType();
15475 switch (elem_ty.zigTypeTag()) {15517 switch (elem_ty.zigTypeTag()) {
15476 .Opaque, .Fn => return,15518 .Opaque, .Fn => return true,
15477 else => ty = elem_ty,15519 else => ty = elem_ty,
15478 }15520 }
15479 },15521 },
15480 .Opaque => if (is_extern) return else break,15522 .Opaque => return is_extern,
1548115523
15482 .Optional => {15524 .Optional => {
15483 var buf: Type.Payload.ElemType = undefined;15525 var buf: Type.Payload.ElemType = undefined;
15484 const child_ty = ty.optionalChild(&buf);15526 const child_ty = ty.optionalChild(&buf);
15485 return validateVarType(sema, block, src, child_ty, is_extern);15527 return validateRunTimeType(sema, block, src, child_ty, is_extern);
15486 },15528 },
15487 .Array, .Vector => ty = ty.elemType(),15529 .Array, .Vector => ty = ty.elemType(),
1548815530
...@@ -15490,23 +15532,10 @@ fn validateVarType(...@@ -15490,23 +15532,10 @@ fn validateVarType(
1549015532
15491 .Struct, .Union => {15533 .Struct, .Union => {
15492 const resolved_ty = try sema.resolveTypeFields(block, src, ty);15534 const resolved_ty = try sema.resolveTypeFields(block, src, ty);
15493 if (try sema.typeRequiresComptime(block, src, resolved_ty)) {15535 const needs_comptime = try sema.typeRequiresComptime(block, src, resolved_ty);
15494 break;15536 return !needs_comptime;
15495 } else {
15496 return;
15497 }
15498 },15537 },
15499 } else unreachable; // TODO should not need else unreachable
15500
15501 const msg = msg: {
15502 const msg = try sema.errMsg(block, src, "variable of type '{}' must be const or comptime", .{var_ty});
15503 errdefer msg.destroy(sema.gpa);
15504
15505 try sema.explainWhyTypeIsComptime(block, src, msg, src.toSrcLoc(block.src_decl), var_ty);
15506
15507 break :msg msg;
15508 };15538 };
15509 return sema.failWithOwnedErrorMsg(block, msg);
15510}15539}
1551115540
15512fn explainWhyTypeIsComptime(15541fn explainWhyTypeIsComptime(
...@@ -20351,6 +20380,20 @@ pub fn resolveTypeFully(...@@ -20351,6 +20380,20 @@ pub fn resolveTypeFully(
20351 return resolveTypeFully(sema, block, src, ty.optionalChild(&buf));20380 return resolveTypeFully(sema, block, src, ty.optionalChild(&buf));
20352 },20381 },
20353 .ErrorUnion => return resolveTypeFully(sema, block, src, ty.errorUnionPayload()),20382 .ErrorUnion => return resolveTypeFully(sema, block, src, ty.errorUnionPayload()),
20383 .Fn => {
20384 const info = ty.fnInfo();
20385 if (info.is_generic) {
20386 // Resolving of generic function types is defeerred to when
20387 // the function is instantiated.
20388 return;
20389 }
20390 for (info.param_types) |param_ty| {
20391 const param_ty_src = src; // TODO better source location
20392 try sema.resolveTypeFully(block, param_ty_src, param_ty);
20393 }
20394 const return_ty_src = src; // TODO better source location
20395 try sema.resolveTypeFully(block, return_ty_src, info.return_type);
20396 },
20354 else => {},20397 else => {},
20355 }20398 }
20356}20399}
test/behavior/basic.zig+2-1
...@@ -331,6 +331,7 @@ fn copy(src: *const u64, dst: *u64) void {...@@ -331,6 +331,7 @@ fn copy(src: *const u64, dst: *u64) void {
331}331}
332332
333test "call result of if else expression" {333test "call result of if else expression" {
334 if (builtin.zig_backend == .stage1) return error.SkipZigTest; // stage1 has different function pointers
334 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;335 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
335 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;336 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;
336 if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest;337 if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest;
...@@ -341,7 +342,7 @@ test "call result of if else expression" {...@@ -341,7 +342,7 @@ test "call result of if else expression" {
341 try expect(mem.eql(u8, f2(false), "b"));342 try expect(mem.eql(u8, f2(false), "b"));
342}343}
343fn f2(x: bool) []const u8 {344fn f2(x: bool) []const u8 {
344 return (if (x) fA else fB)();345 return (if (x) &fA else &fB)();
345}346}
346347
347test "memcpy and memset intrinsics" {348test "memcpy and memset intrinsics" {