mirror of
https://github.com/ziglang/zig.git
synced 2025-12-16 03:03:09 +00:00
stage2: peer resolve error sets and unions, add more tests
This commit is contained in:
parent
bfada7c514
commit
38aae2cb7c
72
src/Sema.zig
72
src/Sema.zig
@ -17635,20 +17635,8 @@ fn resolvePeerTypes(
|
||||
if (candidate_ty.eql(chosen_ty))
|
||||
continue;
|
||||
|
||||
// If the candidate can coerce into our chosen type, we're done.
|
||||
// If the chosen type can coerce into the candidate, use that.
|
||||
if ((try sema.coerceInMemoryAllowed(block, chosen_ty, candidate_ty, false, target, src, src)) == .ok) {
|
||||
continue;
|
||||
}
|
||||
if ((try sema.coerceInMemoryAllowed(block, candidate_ty, chosen_ty, false, target, src, src)) == .ok) {
|
||||
chosen = candidate;
|
||||
chosen_i = candidate_i + 1;
|
||||
continue;
|
||||
}
|
||||
|
||||
const candidate_ty_tag = candidate_ty.zigTypeTag();
|
||||
const chosen_ty_tag = chosen_ty.zigTypeTag();
|
||||
|
||||
switch (candidate_ty_tag) {
|
||||
.NoReturn, .Undefined => continue,
|
||||
|
||||
@ -17780,6 +17768,51 @@ fn resolvePeerTypes(
|
||||
chosen_i = candidate_i + 1;
|
||||
continue;
|
||||
}
|
||||
|
||||
// At this point, we must resolve any inferred error sets
|
||||
if (candidate_ty.castTag(.error_set_inferred)) |inferred| {
|
||||
try sema.resolveInferredErrorSet(inferred.data);
|
||||
}
|
||||
|
||||
// If anything is anyerror, we use anyerror always
|
||||
if (candidate_ty.isAnyError()) {
|
||||
err_set_ty = candidate_ty;
|
||||
continue;
|
||||
}
|
||||
if (err_set_ty) |ty|
|
||||
if (ty.isAnyError()) continue;
|
||||
|
||||
if (err_set_ty == null) {
|
||||
// Error unions are lazy, we're forced to resolve now.
|
||||
// Otherwise, our candidate type cause we've never seen
|
||||
// error sets up to this point
|
||||
if (chosen_ty_tag == .ErrorUnion) {
|
||||
err_set_ty = chosen_ty.errorUnionSet();
|
||||
|
||||
if (err_set_ty.?.castTag(.error_set_inferred)) |inferred| {
|
||||
try sema.resolveInferredErrorSet(inferred.data);
|
||||
}
|
||||
|
||||
if (err_set_ty.?.isAnyError()) continue;
|
||||
} else {
|
||||
err_set_ty = candidate_ty;
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
// If previous is superset, keep the previous
|
||||
var prev_is_superset = true;
|
||||
for (candidate_ty.errorSetNames()) |name| {
|
||||
if (!err_set_ty.?.errorSetHasField(name)) {
|
||||
prev_is_superset = false;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (prev_is_superset) continue; // use previous
|
||||
|
||||
// Merge
|
||||
err_set_ty = try err_set_ty.?.errorSetMerge(sema.arena, candidate_ty);
|
||||
continue;
|
||||
},
|
||||
.ErrorUnion => {
|
||||
if (chosen_ty_tag == .ErrorSet) {
|
||||
@ -17803,14 +17836,14 @@ fn resolvePeerTypes(
|
||||
// If candidate is a superset of the error type, then use it.
|
||||
var cand_is_superset = true;
|
||||
for (err_set_ty.?.errorSetNames()) |name| {
|
||||
if (!candidate_ty.errorSetHasField(name)) {
|
||||
if (!eu_set_ty.errorSetHasField(name)) {
|
||||
cand_is_superset = false;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (cand_is_superset) {
|
||||
// Swap to candidate
|
||||
err_set_ty = candidate_ty;
|
||||
err_set_ty = eu_set_ty;
|
||||
chosen = candidate;
|
||||
chosen_i = candidate_i + 1;
|
||||
continue;
|
||||
@ -18085,6 +18118,17 @@ fn resolvePeerTypes(
|
||||
else => {},
|
||||
}
|
||||
|
||||
// If the candidate can coerce into our chosen type, we're done.
|
||||
// If the chosen type can coerce into the candidate, use that.
|
||||
if ((try sema.coerceInMemoryAllowed(block, chosen_ty, candidate_ty, false, target, src, src)) == .ok) {
|
||||
continue;
|
||||
}
|
||||
if ((try sema.coerceInMemoryAllowed(block, candidate_ty, chosen_ty, false, target, src, src)) == .ok) {
|
||||
chosen = candidate;
|
||||
chosen_i = candidate_i + 1;
|
||||
continue;
|
||||
}
|
||||
|
||||
// At this point, we hit a compile error. We need to recover
|
||||
// the source locations.
|
||||
const chosen_src = candidate_srcs.resolve(
|
||||
|
||||
@ -615,6 +615,96 @@ test "peer type resolution: unreachable, error set, unreachable" {
|
||||
try expect(transformed_err == error.SystemResources);
|
||||
}
|
||||
|
||||
test "peer cast: error set any anyerror" {
|
||||
const a: error{ One, Two } = undefined;
|
||||
const b: anyerror = undefined;
|
||||
try expect(@TypeOf(a, b) == anyerror);
|
||||
try expect(@TypeOf(b, a) == anyerror);
|
||||
}
|
||||
|
||||
test "peer type resolution: error set supersets" {
|
||||
const a: error{ One, Two } = undefined;
|
||||
const b: error{One} = undefined;
|
||||
|
||||
// A superset of B
|
||||
{
|
||||
const ty = @TypeOf(a, b);
|
||||
const error_set_info = @typeInfo(ty);
|
||||
try expect(error_set_info == .ErrorSet);
|
||||
try expect(error_set_info.ErrorSet.?.len == 2);
|
||||
try expect(mem.eql(u8, error_set_info.ErrorSet.?[0].name, "One"));
|
||||
try expect(mem.eql(u8, error_set_info.ErrorSet.?[1].name, "Two"));
|
||||
}
|
||||
|
||||
// B superset of A
|
||||
{
|
||||
const ty = @TypeOf(b, a);
|
||||
const error_set_info = @typeInfo(ty);
|
||||
try expect(error_set_info == .ErrorSet);
|
||||
try expect(error_set_info.ErrorSet.?.len == 2);
|
||||
try expect(mem.eql(u8, error_set_info.ErrorSet.?[0].name, "One"));
|
||||
try expect(mem.eql(u8, error_set_info.ErrorSet.?[1].name, "Two"));
|
||||
}
|
||||
}
|
||||
|
||||
test "peer type resolution: disjoint error sets" {
|
||||
const a: error{ One, Two } = undefined;
|
||||
const b: error{Three} = undefined;
|
||||
|
||||
// note: order of error set members doesn't member, may want to sort
|
||||
|
||||
{
|
||||
const ty = @TypeOf(a, b);
|
||||
const error_set_info = @typeInfo(ty);
|
||||
try expect(error_set_info == .ErrorSet);
|
||||
try expect(error_set_info.ErrorSet.?.len == 3);
|
||||
try expect(mem.eql(u8, error_set_info.ErrorSet.?[0].name, "One"));
|
||||
try expect(mem.eql(u8, error_set_info.ErrorSet.?[1].name, "Two"));
|
||||
try expect(mem.eql(u8, error_set_info.ErrorSet.?[2].name, "Three"));
|
||||
}
|
||||
|
||||
{
|
||||
const ty = @TypeOf(b, a);
|
||||
const error_set_info = @typeInfo(ty);
|
||||
try expect(error_set_info == .ErrorSet);
|
||||
try expect(error_set_info.ErrorSet.?.len == 3);
|
||||
try expect(mem.eql(u8, error_set_info.ErrorSet.?[0].name, "Three"));
|
||||
try expect(mem.eql(u8, error_set_info.ErrorSet.?[1].name, "One"));
|
||||
try expect(mem.eql(u8, error_set_info.ErrorSet.?[2].name, "Two"));
|
||||
}
|
||||
}
|
||||
|
||||
test "peer type resolution: error union and error set" {
|
||||
const a: error{Three} = undefined;
|
||||
const b: error{ One, Two }!u32 = undefined;
|
||||
|
||||
// note: order of error set members doesn't member, may want to sort
|
||||
|
||||
{
|
||||
const ty = @TypeOf(a, b);
|
||||
const info = @typeInfo(ty);
|
||||
try expect(info == .ErrorUnion);
|
||||
|
||||
const error_set_info = @typeInfo(info.ErrorUnion.error_set);
|
||||
try expect(error_set_info.ErrorSet.?.len == 3);
|
||||
try expect(mem.eql(u8, error_set_info.ErrorSet.?[0].name, "Three"));
|
||||
try expect(mem.eql(u8, error_set_info.ErrorSet.?[1].name, "One"));
|
||||
try expect(mem.eql(u8, error_set_info.ErrorSet.?[2].name, "Two"));
|
||||
}
|
||||
|
||||
{
|
||||
const ty = @TypeOf(b, a);
|
||||
const info = @typeInfo(ty);
|
||||
try expect(info == .ErrorUnion);
|
||||
|
||||
const error_set_info = @typeInfo(info.ErrorUnion.error_set);
|
||||
try expect(error_set_info.ErrorSet.?.len == 3);
|
||||
try expect(mem.eql(u8, error_set_info.ErrorSet.?[0].name, "One"));
|
||||
try expect(mem.eql(u8, error_set_info.ErrorSet.?[1].name, "Two"));
|
||||
try expect(mem.eql(u8, error_set_info.ErrorSet.?[2].name, "Three"));
|
||||
}
|
||||
}
|
||||
|
||||
test "peer cast *[0]T to E![]const T" {
|
||||
if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
|
||||
if (builtin.zig_backend == .stage2_c) return error.SkipZigTest; // TODO
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user