authorgravatar for git@vexu.euVeikka Tuominen <git@vexu.eu> 2022-12-15 21:18:42+02:00
committergravatar for git@vexu.euVeikka Tuominen <git@vexu.eu> 2022-12-17 13:22:09+02:00
log58caed1c71179f48c4e7bffadef0392fa8381e72
tree7dec9c4a86979d129d824ac3124054d89eb1c849
parent90477e5c10c9c263a3c0038e1ae7b814d2c5397e

Sema: make is_non_{null,err} stricter about types

Closes #13023

5 files changed, 50 insertions(+), 12 deletions(-)

src/AstGen.zig+2-2
...@@ -6071,7 +6071,7 @@ fn whileExpr(...@@ -6071,7 +6071,7 @@ fn whileExpr(
6071 const tag: Zir.Inst.Tag = if (payload_is_ref) .is_non_err_ptr else .is_non_err;6071 const tag: Zir.Inst.Tag = if (payload_is_ref) .is_non_err_ptr else .is_non_err;
6072 break :c .{6072 break :c .{
6073 .inst = err_union,6073 .inst = err_union,
6074 .bool_bit = try cond_scope.addUnNode(tag, err_union, while_full.ast.then_expr),6074 .bool_bit = try cond_scope.addUnNode(tag, err_union, while_full.ast.cond_expr),
6075 };6075 };
6076 } else if (while_full.payload_token) |_| {6076 } else if (while_full.payload_token) |_| {
6077 const cond_ri: ResultInfo = .{ .rl = if (payload_is_ref) .ref else .none };6077 const cond_ri: ResultInfo = .{ .rl = if (payload_is_ref) .ref else .none };
...@@ -6079,7 +6079,7 @@ fn whileExpr(...@@ -6079,7 +6079,7 @@ fn whileExpr(
6079 const tag: Zir.Inst.Tag = if (payload_is_ref) .is_non_null_ptr else .is_non_null;6079 const tag: Zir.Inst.Tag = if (payload_is_ref) .is_non_null_ptr else .is_non_null;
6080 break :c .{6080 break :c .{
6081 .inst = optional,6081 .inst = optional,
6082 .bool_bit = try cond_scope.addUnNode(tag, optional, while_full.ast.then_expr),6082 .bool_bit = try cond_scope.addUnNode(tag, optional, while_full.ast.cond_expr),
6083 };6083 };
6084 } else {6084 } else {
6085 const cond = try expr(&cond_scope, &cond_scope.base, bool_ri, while_full.ast.cond_expr);6085 const cond = try expr(&cond_scope, &cond_scope.base, bool_ri, while_full.ast.cond_expr);
src/Sema.zig+23
...@@ -16356,6 +16356,15 @@ fn finishCondBr(...@@ -16356,6 +16356,15 @@ fn finishCondBr(
16356 return Air.indexToRef(block_inst);16356 return Air.indexToRef(block_inst);
16357}16357}
1635816358
16359fn checkNullableType(sema: *Sema, block: *Block, src: LazySrcLoc, ty: Type) !void {
16360 switch (ty.zigTypeTag()) {
16361 .Optional, .Null, .Undefined => return,
16362 .Pointer => if (ty.isPtrLikeOptional()) return,
16363 else => {},
16364 }
16365 return sema.failWithExpectedOptionalType(block, src, ty);
16366}
16367
16359fn zirIsNonNull(16368fn zirIsNonNull(
16360 sema: *Sema,16369 sema: *Sema,
16361 block: *Block,16370 block: *Block,
...@@ -16367,6 +16376,7 @@ fn zirIsNonNull(...@@ -16367,6 +16376,7 @@ fn zirIsNonNull(
16367 const inst_data = sema.code.instructions.items(.data)[inst].un_node;16376 const inst_data = sema.code.instructions.items(.data)[inst].un_node;
16368 const src = inst_data.src();16377 const src = inst_data.src();
16369 const operand = try sema.resolveInst(inst_data.operand);16378 const operand = try sema.resolveInst(inst_data.operand);
16379 try sema.checkNullableType(block, src, sema.typeOf(operand));
16370 return sema.analyzeIsNull(block, src, operand, true);16380 return sema.analyzeIsNull(block, src, operand, true);
16371}16381}
1637216382
...@@ -16381,6 +16391,7 @@ fn zirIsNonNullPtr(...@@ -16381,6 +16391,7 @@ fn zirIsNonNullPtr(
16381 const inst_data = sema.code.instructions.items(.data)[inst].un_node;16391 const inst_data = sema.code.instructions.items(.data)[inst].un_node;
16382 const src = inst_data.src();16392 const src = inst_data.src();
16383 const ptr = try sema.resolveInst(inst_data.operand);16393 const ptr = try sema.resolveInst(inst_data.operand);
16394 try sema.checkNullableType(block, src, sema.typeOf(ptr).elemType2());
16384 if ((try sema.resolveMaybeUndefVal(ptr)) == null) {16395 if ((try sema.resolveMaybeUndefVal(ptr)) == null) {
16385 return block.addUnOp(.is_non_null_ptr, ptr);16396 return block.addUnOp(.is_non_null_ptr, ptr);
16386 }16397 }
...@@ -16388,12 +16399,23 @@ fn zirIsNonNullPtr(...@@ -16388,12 +16399,23 @@ fn zirIsNonNullPtr(
16388 return sema.analyzeIsNull(block, src, loaded, true);16399 return sema.analyzeIsNull(block, src, loaded, true);
16389}16400}
1639016401
16402fn checkErrorType(sema: *Sema, block: *Block, src: LazySrcLoc, ty: Type) !void {
16403 switch (ty.zigTypeTag()) {
16404 .ErrorSet, .ErrorUnion, .Undefined => return,
16405 else => return sema.fail(block, src, "expected error union type, found '{}'", .{
16406 ty.fmt(sema.mod),
16407 }),
16408 }
16409}
16410
16391fn zirIsNonErr(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air.Inst.Ref {16411fn zirIsNonErr(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air.Inst.Ref {
16392 const tracy = trace(@src());16412 const tracy = trace(@src());
16393 defer tracy.end();16413 defer tracy.end();
1639416414
16395 const inst_data = sema.code.instructions.items(.data)[inst].un_node;16415 const inst_data = sema.code.instructions.items(.data)[inst].un_node;
16416 const src = inst_data.src();
16396 const operand = try sema.resolveInst(inst_data.operand);16417 const operand = try sema.resolveInst(inst_data.operand);
16418 try sema.checkErrorType(block, src, sema.typeOf(operand));
16397 return sema.analyzeIsNonErr(block, inst_data.src(), operand);16419 return sema.analyzeIsNonErr(block, inst_data.src(), operand);
16398}16420}
1639916421
...@@ -16404,6 +16426,7 @@ fn zirIsNonErrPtr(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError...@@ -16404,6 +16426,7 @@ fn zirIsNonErrPtr(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError
16404 const inst_data = sema.code.instructions.items(.data)[inst].un_node;16426 const inst_data = sema.code.instructions.items(.data)[inst].un_node;
16405 const src = inst_data.src();16427 const src = inst_data.src();
16406 const ptr = try sema.resolveInst(inst_data.operand);16428 const ptr = try sema.resolveInst(inst_data.operand);
16429 try sema.checkErrorType(block, src, sema.typeOf(ptr).elemType2());
16407 const loaded = try sema.analyzeLoad(block, src, ptr, src);16430 const loaded = try sema.analyzeLoad(block, src, ptr, src);
16408 return sema.analyzeIsNonErr(block, src, loaded);16431 return sema.analyzeIsNonErr(block, src, loaded);
16409}16432}
src/link/MachO/load_commands.zig+1-1
...@@ -36,7 +36,7 @@ fn calcLCsSize(gpa: Allocator, options: *const link.Options, ctx: CalcLCsSizeCtx...@@ -36,7 +36,7 @@ fn calcLCsSize(gpa: Allocator, options: *const link.Options, ctx: CalcLCsSizeCtx
36 // LC_DYLD_INFO_ONLY36 // LC_DYLD_INFO_ONLY
37 sizeofcmds += @sizeOf(macho.dyld_info_command);37 sizeofcmds += @sizeOf(macho.dyld_info_command);
38 // LC_FUNCTION_STARTS38 // LC_FUNCTION_STARTS
39 if (has_text_segment and ctx.wants_function_starts) |_| {39 if (has_text_segment and ctx.wants_function_starts) {
40 sizeofcmds += @sizeOf(macho.linkedit_data_command);40 sizeofcmds += @sizeOf(macho.linkedit_data_command);
41 }41 }
42 // LC_DATA_IN_CODE42 // LC_DATA_IN_CODE
test/cases/compile_errors/invalid_capture_type.zig created+24
...@@ -0,0 +1,24 @@
1export fn f1() void {
2 if (true) |x| { _ = x; }
3}
4export fn f2() void {
5 if (@as(usize, 5)) |_| {}
6}
7export fn f3() void {
8 if (@as(usize, 5)) |_| {} else |_| {}
9}
10export fn f4() void {
11 if (null) |_| {}
12}
13export fn f5() void {
14 if (error.Foo) |_| {} else |_| {}
15}
16
17// error
18// backend=stage2
19// target=native
20//
21// :2:9: error: expected optional type, found 'bool'
22// :5:9: error: expected optional type, found 'usize'
23// :8:9: error: expected error union type, found 'usize'
24// :14:9: error: expected error union type, found 'error{Foo}'
test/cases/compile_errors/stage1/obj/invalid_maybe_type.zig deleted-9
...@@ -1,9 +0,0 @@
1export fn f() void {
2 if (true) |x| { _ = x; }
3}
4
5// error
6// backend=stage1
7// target=native
8//
9// tmp.zig:2:9: error: expected optional type, found 'bool'