Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
64 changes: 49 additions & 15 deletions src/analysis.zig
Original file line number Diff line number Diff line change
Expand Up @@ -1512,8 +1512,9 @@ fn resolvePeerTypes(analyser: *Analyser, a: Type, b: Type) error{OutOfMemory}!?T
if (a.data == .ip_index and b.data == .ip_index) {
const a_type = a.data.ip_index.type;
const b_type = b.data.ip_index.type;
const resolved_type = try analyser.resolvePeerTypesIP(a_type, b_type) orelse return null;
return Type.fromIP(analyser, resolved_type, null);
if (try analyser.resolvePeerTypesIP(a_type, b_type)) |resolved_type| {
return Type.fromIP(analyser, resolved_type, null);
}
}

return try analyser.resolvePeerTypesInternal(a, b) orelse try analyser.resolvePeerTypesInternal(b, a);
Expand All @@ -1525,6 +1526,19 @@ fn resolvePeerTypesIP(analyser: *Analyser, a: InternPool.Index, b: InternPool.In
return resolved;
}

fn resolvePeerErrorSets(analyser: *Analyser, a: Type, b: Type) !?Type {
if (a.data != .ip_index) return null;
if (b.data != .ip_index) return null;
if (a.data.ip_index.type != .type_type) return null;
if (b.data.ip_index.type != .type_type) return null;
const a_index = a.data.ip_index.index orelse return null;
const b_index = b.data.ip_index.index orelse return null;
if (analyser.ip.zigTypeTag(a_index) != .error_set) return null;
if (analyser.ip.zigTypeTag(b_index) != .error_set) return null;
const resolved_index = try analyser.ip.errorSetMerge(analyser.gpa, a_index, b_index);
return Type.fromIP(analyser, .type_type, resolved_index);
}

fn resolvePeerTypesInternal(analyser: *Analyser, a: Type, b: Type) error{OutOfMemory}!?Type {
switch (a.data) {
.compile_error => return b,
Expand Down Expand Up @@ -1559,16 +1573,7 @@ fn resolvePeerTypesInternal(analyser: *Analyser, a: Type, b: Type) error{OutOfMe
const a_error_set = a_info.error_set orelse break :blk null;
const b_error_set = b_info.error_set orelse break :blk null;
if (a_error_set.eql(b_error_set.*)) break :blk a_error_set;
if (a_error_set.data != .ip_index) return null;
if (b_error_set.data != .ip_index) return null;
if (a_error_set.data.ip_index.type != .type_type) return null;
if (b_error_set.data.ip_index.type != .type_type) return null;
const a_index = a_error_set.data.ip_index.index orelse return null;
const b_index = b_error_set.data.ip_index.index orelse return null;
if (analyser.ip.zigTypeTag(a_index) != .error_set) return null;
if (analyser.ip.zigTypeTag(b_index) != .error_set) return null;
const resolved_index = try analyser.ip.errorSetMerge(analyser.gpa, a_index, b_index);
const resolved_error_set = Type.fromIP(analyser, .type_type, resolved_index);
const resolved_error_set = try analyser.resolvePeerErrorSets(a_error_set.*, b_error_set.*) orelse break :blk null;
break :blk try analyser.allocType(resolved_error_set);
};
const resolved_payload = blk: {
Expand All @@ -1591,9 +1596,9 @@ fn resolvePeerTypesInternal(analyser: *Analyser, a: Type, b: Type) error{OutOfMe
else => {},
}
},
.ip_index => |a_payload| switch (a_payload.type) {
.noreturn_type => return b,
.null_type => switch (b.data) {
.ip_index => |a_payload| switch (analyser.ip.zigTypeTag(a_payload.type) orelse return null) {
.noreturn => return b,
.null => switch (b.data) {
.optional => return b,
.error_union => |b_info| {
return .{
Expand All @@ -1614,6 +1619,35 @@ fn resolvePeerTypesInternal(analyser: *Analyser, a: Type, b: Type) error{OutOfMe
.is_type_val = false,
},
},
.error_set => switch (b.data) {
.error_union => |b_info| {
const resolved_error_set = blk: {
const a_error_set = try a.typeOf(analyser);
const b_error_set = b_info.error_set orelse break :blk null;
if (a_error_set.eql(b_error_set.*)) break :blk b_error_set;
const resolved_error_set = try analyser.resolvePeerErrorSets(a_error_set, b_error_set.*) orelse break :blk null;
break :blk try analyser.allocType(resolved_error_set);
};
return .{
.data = .{
.error_union = .{
.error_set = resolved_error_set,
.payload = b_info.payload,
},
},
.is_type_val = false,
};
},
else => return .{
.data = .{
.error_union = .{
.error_set = try analyser.allocType(try a.typeOf(analyser)),
.payload = try analyser.allocType(try b.typeOf(analyser)),
},
},
.is_type_val = false,
},
},
else => {},
},
else => {},
Expand Down
32 changes: 32 additions & 0 deletions tests/analysis/peer_type_resolution.zig
Original file line number Diff line number Diff line change
Expand Up @@ -130,6 +130,38 @@ pub fn main() !void {
_ = try try error_union_15;
// ^^^^^^^^^^^^^^ (error{A,B}!error{B,A}!?S)()

const error_union_16 = if (runtime_bool) error.A else s;
_ = error_union_16;
// ^^^^^^^^^^^^^^ (error{A}!S)()

const error_union_17 = if (runtime_bool) s else error.A;
_ = error_union_17;
// ^^^^^^^^^^^^^^ (error{A}!S)()

const error_union_18 = if (runtime_bool) error.A else @as(i32, 0);
_ = error_union_18;
// ^^^^^^^^^^^^^^ (error{A}!i32)()

const error_union_19 = if (runtime_bool) @as(i32, 0) else error.A;
_ = error_union_19;
// ^^^^^^^^^^^^^^ (error{A}!i32)()

const error_union_20 = if (runtime_bool) error.A else @as(error{B}!S, s);
_ = error_union_20;
// ^^^^^^^^^^^^^^ (error{A,B}!S)()

const error_union_21 = if (runtime_bool) @as(error{B}!S, s) else error.A;
_ = error_union_21;
// ^^^^^^^^^^^^^^ (error{A,B}!S)()

const error_union_22 = if (runtime_bool) error.A else @as(error{B}!i32, 0);
_ = error_union_22;
// ^^^^^^^^^^^^^^ (error{A,B}!i32)()

const error_union_23 = if (runtime_bool) @as(error{B}!i32, 0) else error.A;
_ = error_union_23;
// ^^^^^^^^^^^^^^ (error{A,B}!i32)()

const noreturn_0 = if (runtime_bool) s else return;
_ = noreturn_0;
// ^^^^^^^^^^ (S)()
Expand Down
Loading