mirror of
https://github.com/ziglang/zig.git
synced 2026-02-13 21:08:36 +00:00
Sema: make optional noreturn behave correctly
This commit is contained in:
parent
a12abc6d6c
commit
db0f372da8
15
src/Sema.zig
15
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);
|
||||
|
||||
@ -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);
|
||||
}
|
||||
|
||||
13
test/cases/compile_errors/invalid_optional_payload_type.zig
Normal file
13
test/cases/compile_errors/invalid_optional_payload_type.zig
Normal file
@ -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
|
||||
Loading…
x
Reference in New Issue
Block a user