diff --git a/src/analysis.zig b/src/analysis.zig index 8d12790e0..2bbbc3d67 100644 --- a/src/analysis.zig +++ b/src/analysis.zig @@ -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); @@ -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, @@ -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: { @@ -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 .{ @@ -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 => {}, diff --git a/tests/analysis/peer_type_resolution.zig b/tests/analysis/peer_type_resolution.zig index b19fae191..ed9e87d56 100644 --- a/tests/analysis/peer_type_resolution.zig +++ b/tests/analysis/peer_type_resolution.zig @@ -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)()