Commit db0f372da8
Changed files (3)
src
test
behavior
cases
compile_errors
src/Sema.zig
@@ -6684,8 +6684,13 @@ fn zirOptionalType(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileErro
defer tracy.end();
const inst_data = sema.code.instructions.items(.data)[inst].un_node;
- const src = inst_data.src();
- const child_type = try sema.resolveType(block, src, inst_data.operand);
+ const operand_src: LazySrcLoc = .{ .node_offset_un_op = inst_data.src_node };
+ const child_type = try sema.resolveType(block, operand_src, inst_data.operand);
+ if (child_type.zigTypeTag() == .Opaque) {
+ return sema.fail(block, operand_src, "opaque type '{}' cannot be optional", .{child_type.fmt(sema.mod)});
+ } else if (child_type.zigTypeTag() == .Null) {
+ return sema.fail(block, operand_src, "type '{}' cannot be optional", .{child_type.fmt(sema.mod)});
+ }
const opt_type = try Type.optional(sema.arena, child_type);
return sema.addType(opt_type);
@@ -25714,6 +25719,12 @@ fn analyzeIsNull(
return Air.Inst.Ref.bool_false;
}
}
+
+ const operand_ty = sema.typeOf(operand);
+ var buf: Type.Payload.ElemType = undefined;
+ if (operand_ty.zigTypeTag() == .Optional and operand_ty.optionalChild(&buf).zigTypeTag() == .NoReturn) {
+ return Air.Inst.Ref.bool_true;
+ }
try sema.requireRuntimeBlock(block, src, null);
const air_tag: Air.Inst.Tag = if (invert_logic) .is_non_null else .is_null;
return block.addUnOp(air_tag, operand);
test/behavior/optional.zig
@@ -369,3 +369,39 @@ test "optional pointer to zero bit error union payload" {
some.foo();
} else |_| {}
}
+
+const NoReturn = struct {
+ var a: u32 = undefined;
+ fn someData() bool {
+ a -= 1;
+ return a == 0;
+ }
+ fn loop() ?noreturn {
+ while (true) {
+ if (someData()) return null;
+ }
+ }
+ fn testOrelse() u32 {
+ loop() orelse return 123;
+ @compileError("bad");
+ }
+};
+
+test "optional of noreturn used with if" {
+ if (builtin.zig_backend == .stage1) return error.SkipZigTest;
+
+ NoReturn.a = 64;
+ if (NoReturn.loop()) |_| {
+ @compileError("bad");
+ } else {
+ try expect(true);
+ }
+}
+
+test "optional of noreturn used with orelse" {
+ if (builtin.zig_backend == .stage1) return error.SkipZigTest;
+
+ NoReturn.a = 64;
+ const val = NoReturn.testOrelse();
+ try expect(val == 123);
+}
test/cases/compile_errors/invalid_optional_payload_type.zig
@@ -0,0 +1,13 @@
+comptime {
+ _ = ?anyopaque;
+}
+comptime {
+ _ = ?@TypeOf(null);
+}
+
+// error
+// backend=stage2
+// target=native
+//
+// :2:10: error: opaque type 'anyopaque' cannot be optional
+// :5:10: error: type '@TypeOf(null)' cannot be optional