Skip to content

Commit 94ac701

Browse files
Resolve peer types with error set(s) as error union (#2389)
1 parent 0f0771c commit 94ac701

File tree

2 files changed

+81
-15
lines changed

2 files changed

+81
-15
lines changed

src/analysis.zig

Lines changed: 49 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -1512,8 +1512,9 @@ fn resolvePeerTypes(analyser: *Analyser, a: Type, b: Type) error{OutOfMemory}!?T
15121512
if (a.data == .ip_index and b.data == .ip_index) {
15131513
const a_type = a.data.ip_index.type;
15141514
const b_type = b.data.ip_index.type;
1515-
const resolved_type = try analyser.resolvePeerTypesIP(a_type, b_type) orelse return null;
1516-
return Type.fromIP(analyser, resolved_type, null);
1515+
if (try analyser.resolvePeerTypesIP(a_type, b_type)) |resolved_type| {
1516+
return Type.fromIP(analyser, resolved_type, null);
1517+
}
15171518
}
15181519

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

1529+
fn resolvePeerErrorSets(analyser: *Analyser, a: Type, b: Type) !?Type {
1530+
if (a.data != .ip_index) return null;
1531+
if (b.data != .ip_index) return null;
1532+
if (a.data.ip_index.type != .type_type) return null;
1533+
if (b.data.ip_index.type != .type_type) return null;
1534+
const a_index = a.data.ip_index.index orelse return null;
1535+
const b_index = b.data.ip_index.index orelse return null;
1536+
if (analyser.ip.zigTypeTag(a_index) != .error_set) return null;
1537+
if (analyser.ip.zigTypeTag(b_index) != .error_set) return null;
1538+
const resolved_index = try analyser.ip.errorSetMerge(analyser.gpa, a_index, b_index);
1539+
return Type.fromIP(analyser, .type_type, resolved_index);
1540+
}
1541+
15281542
fn resolvePeerTypesInternal(analyser: *Analyser, a: Type, b: Type) error{OutOfMemory}!?Type {
15291543
switch (a.data) {
15301544
.compile_error => return b,
@@ -1559,16 +1573,7 @@ fn resolvePeerTypesInternal(analyser: *Analyser, a: Type, b: Type) error{OutOfMe
15591573
const a_error_set = a_info.error_set orelse break :blk null;
15601574
const b_error_set = b_info.error_set orelse break :blk null;
15611575
if (a_error_set.eql(b_error_set.*)) break :blk a_error_set;
1562-
if (a_error_set.data != .ip_index) return null;
1563-
if (b_error_set.data != .ip_index) return null;
1564-
if (a_error_set.data.ip_index.type != .type_type) return null;
1565-
if (b_error_set.data.ip_index.type != .type_type) return null;
1566-
const a_index = a_error_set.data.ip_index.index orelse return null;
1567-
const b_index = b_error_set.data.ip_index.index orelse return null;
1568-
if (analyser.ip.zigTypeTag(a_index) != .error_set) return null;
1569-
if (analyser.ip.zigTypeTag(b_index) != .error_set) return null;
1570-
const resolved_index = try analyser.ip.errorSetMerge(analyser.gpa, a_index, b_index);
1571-
const resolved_error_set = Type.fromIP(analyser, .type_type, resolved_index);
1576+
const resolved_error_set = try analyser.resolvePeerErrorSets(a_error_set.*, b_error_set.*) orelse break :blk null;
15721577
break :blk try analyser.allocType(resolved_error_set);
15731578
};
15741579
const resolved_payload = blk: {
@@ -1591,9 +1596,9 @@ fn resolvePeerTypesInternal(analyser: *Analyser, a: Type, b: Type) error{OutOfMe
15911596
else => {},
15921597
}
15931598
},
1594-
.ip_index => |a_payload| switch (a_payload.type) {
1595-
.noreturn_type => return b,
1596-
.null_type => switch (b.data) {
1599+
.ip_index => |a_payload| switch (analyser.ip.zigTypeTag(a_payload.type) orelse return null) {
1600+
.noreturn => return b,
1601+
.null => switch (b.data) {
15971602
.optional => return b,
15981603
.error_union => |b_info| {
15991604
return .{
@@ -1614,6 +1619,35 @@ fn resolvePeerTypesInternal(analyser: *Analyser, a: Type, b: Type) error{OutOfMe
16141619
.is_type_val = false,
16151620
},
16161621
},
1622+
.error_set => switch (b.data) {
1623+
.error_union => |b_info| {
1624+
const resolved_error_set = blk: {
1625+
const a_error_set = try a.typeOf(analyser);
1626+
const b_error_set = b_info.error_set orelse break :blk null;
1627+
if (a_error_set.eql(b_error_set.*)) break :blk b_error_set;
1628+
const resolved_error_set = try analyser.resolvePeerErrorSets(a_error_set, b_error_set.*) orelse break :blk null;
1629+
break :blk try analyser.allocType(resolved_error_set);
1630+
};
1631+
return .{
1632+
.data = .{
1633+
.error_union = .{
1634+
.error_set = resolved_error_set,
1635+
.payload = b_info.payload,
1636+
},
1637+
},
1638+
.is_type_val = false,
1639+
};
1640+
},
1641+
else => return .{
1642+
.data = .{
1643+
.error_union = .{
1644+
.error_set = try analyser.allocType(try a.typeOf(analyser)),
1645+
.payload = try analyser.allocType(try b.typeOf(analyser)),
1646+
},
1647+
},
1648+
.is_type_val = false,
1649+
},
1650+
},
16171651
else => {},
16181652
},
16191653
else => {},

tests/analysis/peer_type_resolution.zig

Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -130,6 +130,38 @@ pub fn main() !void {
130130
_ = try try error_union_15;
131131
// ^^^^^^^^^^^^^^ (error{A,B}!error{B,A}!?S)()
132132

133+
const error_union_16 = if (runtime_bool) error.A else s;
134+
_ = error_union_16;
135+
// ^^^^^^^^^^^^^^ (error{A}!S)()
136+
137+
const error_union_17 = if (runtime_bool) s else error.A;
138+
_ = error_union_17;
139+
// ^^^^^^^^^^^^^^ (error{A}!S)()
140+
141+
const error_union_18 = if (runtime_bool) error.A else @as(i32, 0);
142+
_ = error_union_18;
143+
// ^^^^^^^^^^^^^^ (error{A}!i32)()
144+
145+
const error_union_19 = if (runtime_bool) @as(i32, 0) else error.A;
146+
_ = error_union_19;
147+
// ^^^^^^^^^^^^^^ (error{A}!i32)()
148+
149+
const error_union_20 = if (runtime_bool) error.A else @as(error{B}!S, s);
150+
_ = error_union_20;
151+
// ^^^^^^^^^^^^^^ (error{A,B}!S)()
152+
153+
const error_union_21 = if (runtime_bool) @as(error{B}!S, s) else error.A;
154+
_ = error_union_21;
155+
// ^^^^^^^^^^^^^^ (error{A,B}!S)()
156+
157+
const error_union_22 = if (runtime_bool) error.A else @as(error{B}!i32, 0);
158+
_ = error_union_22;
159+
// ^^^^^^^^^^^^^^ (error{A,B}!i32)()
160+
161+
const error_union_23 = if (runtime_bool) @as(error{B}!i32, 0) else error.A;
162+
_ = error_union_23;
163+
// ^^^^^^^^^^^^^^ (error{A,B}!i32)()
164+
133165
const noreturn_0 = if (runtime_bool) s else return;
134166
_ = noreturn_0;
135167
// ^^^^^^^^^^ (S)()

0 commit comments

Comments
 (0)