Sema: handle recursive inferred errors better in analyzeIsNonErrComptimeOnly

Closes #15669
This commit is contained in:
Veikka Tuominen 2023-05-12 14:59:26 +03:00
parent 0958d5d7db
commit 5aa9628de3
2 changed files with 29 additions and 23 deletions

View File

@ -29153,8 +29153,6 @@ fn analyzeIsNonErrComptimeOnly(
if (ies.errors.count() != 0) break :blk;
if (maybe_operand_val == null) {
// Try to avoid resolving inferred error set if possible.
if (ies.errors.count() != 0) break :blk;
if (ies.is_anyerror) break :blk;
for (ies.inferred_error_sets.keys()) |other_ies| {
if (ies == other_ies) continue;
try sema.resolveInferredErrorSet(block, src, other_ies);
@ -29166,11 +29164,10 @@ fn analyzeIsNonErrComptimeOnly(
if (other_ies.errors.count() != 0) break :blk;
}
if (ies.func == sema.owner_func) {
// We're checking the inferred errorset of the current function and none of
// its child inferred error sets contained any errors meaning that any value
// so far with this type can't contain errors either.
return Air.Inst.Ref.bool_true;
if (!ies.is_resolved and ies.func.state == .in_progress) {
// Calling resolveInferredErrorSet would immediately fail
// so we'll have to rely on runtime checks.
return Air.Inst.Ref.none;
}
try sema.resolveInferredErrorSet(block, src, ies);
if (ies.is_anyerror) break :blk;

View File

@ -678,22 +678,6 @@ test "error union payload is properly aligned" {
if (blk.a != 1) unreachable;
}
test "ret_ptr doesn't cause own inferred error set to be resolved" {
if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
const S = struct {
fn foo() !void {}
fn doTheTest() !void {
errdefer @compileError("bad");
return try @This().foo();
}
};
try S.doTheTest();
}
test "simple else prong allowed even when all errors handled" {
if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO
if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
@ -889,3 +873,28 @@ test "optional error set return type" {
try expect(null == S.foo(true));
try expect(E.A == S.foo(false).?);
}
test "try used in recursive function with inferred error set" {
if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
const Value = union(enum) {
values: []const @This(),
b,
fn x(value: @This()) !void {
switch (value.values[0]) {
.values => return try x(value.values[0]),
.b => return error.a,
}
}
};
const a = Value{
.values = &[1]Value{
.{
.values = &[1]Value{.{ .b = {} }},
},
},
};
try expectError(error.a, Value.x(a));
}