| author | |
| committer | |
| log | db0f372da8b25f4a911cd8e0b7f8e5cdfc64f940 |
| tree | 1258577ea70114ad891b917d25eecc0cf958d19b |
| parent | a12abc6d6c8b89a09befdcbd9019247ccc3bd641 |
3 files changed, 62 insertions(+), 2 deletions(-)
src/Sema.zig+13-2| ... | ... | @@ -6684,8 +6684,13 @@ fn zirOptionalType(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileErro |
| 6684 | 6684 | defer tracy.end(); |
| 6685 | 6685 | |
| 6686 | 6686 | const inst_data = sema.code.instructions.items(.data)[inst].un_node; |
| 6687 | const src = inst_data.src(); | |
| 6688 | const child_type = try sema.resolveType(block, src, inst_data.operand); | |
| 6687 | const operand_src: LazySrcLoc = .{ .node_offset_un_op = inst_data.src_node }; | |
| 6688 | const child_type = try sema.resolveType(block, operand_src, inst_data.operand); | |
| 6689 | if (child_type.zigTypeTag() == .Opaque) { | |
| 6690 | return sema.fail(block, operand_src, "opaque type '{}' cannot be optional", .{child_type.fmt(sema.mod)}); | |
| 6691 | } else if (child_type.zigTypeTag() == .Null) { | |
| 6692 | return sema.fail(block, operand_src, "type '{}' cannot be optional", .{child_type.fmt(sema.mod)}); | |
| 6693 | } | |
| 6689 | 6694 | const opt_type = try Type.optional(sema.arena, child_type); |
| 6690 | 6695 | |
| 6691 | 6696 | return sema.addType(opt_type); |
| ... | ... | @@ -25714,6 +25719,12 @@ fn analyzeIsNull( |
| 25714 | 25719 | return Air.Inst.Ref.bool_false; |
| 25715 | 25720 | } |
| 25716 | 25721 | } |
| 25722 | ||
| 25723 | const operand_ty = sema.typeOf(operand); | |
| 25724 | var buf: Type.Payload.ElemType = undefined; | |
| 25725 | if (operand_ty.zigTypeTag() == .Optional and operand_ty.optionalChild(&buf).zigTypeTag() == .NoReturn) { | |
| 25726 | return Air.Inst.Ref.bool_true; | |
| 25727 | } | |
| 25717 | 25728 | try sema.requireRuntimeBlock(block, src, null); |
| 25718 | 25729 | const air_tag: Air.Inst.Tag = if (invert_logic) .is_non_null else .is_null; |
| 25719 | 25730 | return block.addUnOp(air_tag, operand); |
test/behavior/optional.zig+36| ... | ... | @@ -369,3 +369,39 @@ test "optional pointer to zero bit error union payload" { |
| 369 | 369 | some.foo(); |
| 370 | 370 | } else |_| {} |
| 371 | 371 | } |
| 372 | ||
| 373 | const NoReturn = struct { | |
| 374 | var a: u32 = undefined; | |
| 375 | fn someData() bool { | |
| 376 | a -= 1; | |
| 377 | return a == 0; | |
| 378 | } | |
| 379 | fn loop() ?noreturn { | |
| 380 | while (true) { | |
| 381 | if (someData()) return null; | |
| 382 | } | |
| 383 | } | |
| 384 | fn testOrelse() u32 { | |
| 385 | loop() orelse return 123; | |
| 386 | @compileError("bad"); | |
| 387 | } | |
| 388 | }; | |
| 389 | ||
| 390 | test "optional of noreturn used with if" { | |
| 391 | if (builtin.zig_backend == .stage1) return error.SkipZigTest; | |
| 392 | ||
| 393 | NoReturn.a = 64; | |
| 394 | if (NoReturn.loop()) |_| { | |
| 395 | @compileError("bad"); | |
| 396 | } else { | |
| 397 | try expect(true); | |
| 398 | } | |
| 399 | } | |
| 400 | ||
| 401 | test "optional of noreturn used with orelse" { | |
| 402 | if (builtin.zig_backend == .stage1) return error.SkipZigTest; | |
| 403 | ||
| 404 | NoReturn.a = 64; | |
| 405 | const val = NoReturn.testOrelse(); | |
| 406 | try expect(val == 123); | |
| 407 | } |
test/cases/compile_errors/invalid_optional_payload_type.zig created+13| ... | ... | @@ -0,0 +1,13 @@ |
| 1 | comptime { | |
| 2 | _ = ?anyopaque; | |
| 3 | } | |
| 4 | comptime { | |
| 5 | _ = ?@TypeOf(null); | |
| 6 | } | |
| 7 | ||
| 8 | // error | |
| 9 | // backend=stage2 | |
| 10 | // target=native | |
| 11 | // | |
| 12 | // :2:10: error: opaque type 'anyopaque' cannot be optional | |
| 13 | // :5:10: error: type '@TypeOf(null)' cannot be optional |