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(
39303930 // to emit a jump instruction to after the block when it encounters the break.
39313931 try parent_block.instructions.append(gpa, merges.block_inst);
39323932 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 }
39333950 const ty_inst = try sema.addType(resolved_ty);
39343951 try sema.air_extra.ensureUnusedCapacity(gpa, @typeInfo(Air.Block).Struct.fields.len +
39353952 child_block.instructions.items.len);
......@@ -4191,6 +4208,11 @@ fn zirBreak(sema: *Sema, start_block: *Block, inst: Zir.Inst.Index) CompileError
41914208 const br_ref = try start_block.addBr(label.merges.block_inst, operand);
41924209 try label.merges.results.append(sema.gpa, operand);
41934210 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 }
41944216 return inst;
41954217 }
41964218 }
......@@ -15447,6 +15469,26 @@ fn validateVarType(
1544715469 var_ty: Type,
1544815470 is_extern: bool,
1544915471) 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 {
1545015492 var ty = var_ty;
1545115493 while (true) switch (ty.zigTypeTag()) {
1545215494 .Bool,
......@@ -15457,7 +15499,7 @@ fn validateVarType(
1545715499 .Frame,
1545815500 .AnyFrame,
1545915501 .Void,
15460 => return,
15502 => return true,
1546115503
1546215504 .BoundFn,
1546315505 .ComptimeFloat,
......@@ -15468,21 +15510,21 @@ fn validateVarType(
1546815510 .Undefined,
1546915511 .Null,
1547015512 .Fn,
15471 => break,
15513 => return false,
1547215514
1547315515 .Pointer => {
1547415516 const elem_ty = ty.childType();
1547515517 switch (elem_ty.zigTypeTag()) {
15476 .Opaque, .Fn => return,
15518 .Opaque, .Fn => return true,
1547715519 else => ty = elem_ty,
1547815520 }
1547915521 },
15480 .Opaque => if (is_extern) return else break,
15522 .Opaque => return is_extern,
1548115523
1548215524 .Optional => {
1548315525 var buf: Type.Payload.ElemType = undefined;
1548415526 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);
1548615528 },
1548715529 .Array, .Vector => ty = ty.elemType(),
1548815530
......@@ -15490,23 +15532,10 @@ fn validateVarType(
1549015532
1549115533 .Struct, .Union => {
1549215534 const resolved_ty = try sema.resolveTypeFields(block, src, ty);
15493 if (try sema.typeRequiresComptime(block, src, resolved_ty)) {
15494 break;
15495 } else {
15496 return;
15497 }
15535 const needs_comptime = try sema.typeRequiresComptime(block, src, resolved_ty);
15536 return !needs_comptime;
1549815537 },
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;
1550815538 };
15509 return sema.failWithOwnedErrorMsg(block, msg);
1551015539}
1551115540
1551215541fn explainWhyTypeIsComptime(
......@@ -20351,6 +20380,20 @@ pub fn resolveTypeFully(
2035120380 return resolveTypeFully(sema, block, src, ty.optionalChild(&buf));
2035220381 },
2035320382 .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 },
2035420397 else => {},
2035520398 }
2035620399}
test/behavior/basic.zig+2-1
......@@ -331,6 +331,7 @@ fn copy(src: *const u64, dst: *u64) void {
331331}
332332
333333test "call result of if else expression" {
334 if (builtin.zig_backend == .stage1) return error.SkipZigTest; // stage1 has different function pointers
334335 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
335336 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;
336337 if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest;
......@@ -341,7 +342,7 @@ test "call result of if else expression" {
341342 try expect(mem.eql(u8, f2(false), "b"));
342343}
343344fn f2(x: bool) []const u8 {
344 return (if (x) fA else fB)();
345 return (if (x) &fA else &fB)();
345346}
346347
347348test "memcpy and memset intrinsics" {