Skip to content

Commit 0b75665

Browse files
Resolve peer array/tuple types
1 parent 621ddd1 commit 0b75665

File tree

2 files changed

+127
-1
lines changed

2 files changed

+127
-1
lines changed

src/analysis.zig

Lines changed: 115 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6547,7 +6547,78 @@ fn resolvePeerTypesInner(analyser: *Analyser, peer_tys: []?Type) !?Type {
65476547
};
65486548
},
65496549

6550-
.array => return null, // TODO
6550+
.array => {
6551+
var len: ?u64 = null;
6552+
var sentinel: InternPool.Index = .none;
6553+
var elem_ty: ?Type = null;
6554+
6555+
for (peer_tys) |*ty_ptr| {
6556+
const ty = ty_ptr.* orelse continue;
6557+
6558+
if (ty.data != .array) {
6559+
const arr_like = analyser.typeIsArrayLike(ty) orelse {
6560+
return null;
6561+
};
6562+
6563+
if (len) |cur_len| {
6564+
if (arr_like.len != cur_len) return null;
6565+
} else {
6566+
len = arr_like.len;
6567+
}
6568+
6569+
sentinel = .none;
6570+
6571+
continue;
6572+
}
6573+
6574+
const arr_info = ty.data.array;
6575+
const arr_len = arr_info.elem_count orelse {
6576+
return null;
6577+
};
6578+
6579+
const cur_elem_ty = elem_ty orelse {
6580+
if (len) |cur_len| {
6581+
if (arr_len != cur_len) return null;
6582+
} else {
6583+
len = arr_len;
6584+
sentinel = arr_info.sentinel;
6585+
}
6586+
elem_ty = arr_info.elem_ty.*;
6587+
continue;
6588+
};
6589+
6590+
if (arr_info.elem_count != len) {
6591+
return null;
6592+
}
6593+
6594+
const peer_elem_ty = arr_info.elem_ty.*;
6595+
if (!peer_elem_ty.eql(cur_elem_ty)) {
6596+
// TODO: check if coercible
6597+
return null;
6598+
}
6599+
6600+
if (sentinel != .none) {
6601+
if (arr_info.sentinel != .none) {
6602+
if (arr_info.sentinel != sentinel) sentinel = .none;
6603+
} else {
6604+
sentinel = .none;
6605+
}
6606+
}
6607+
}
6608+
6609+
std.debug.assert(elem_ty != null);
6610+
6611+
return .{
6612+
.data = .{
6613+
.array = .{
6614+
.elem_count = len,
6615+
.sentinel = sentinel,
6616+
.elem_ty = try analyser.allocType(elem_ty.?),
6617+
},
6618+
},
6619+
.is_type_val = true,
6620+
};
6621+
},
65516622

65526623
.vector => return null, // TODO
65536624

@@ -6635,3 +6706,46 @@ fn resolvePeerTypesInner(analyser: *Analyser, peer_tys: []?Type) !?Type {
66356706
},
66366707
}
66376708
}
6709+
6710+
const ArrayLike = struct {
6711+
len: u64,
6712+
/// `noreturn` indicates that this `.{}` so can coerce to anything
6713+
elem_ty: Type,
6714+
};
6715+
fn typeIsArrayLike(analyser: *Analyser, ty: Type) ?ArrayLike {
6716+
std.debug.assert(ty.is_type_val);
6717+
const ip_index = switch (ty.data) {
6718+
.ip_index => |payload| payload.index orelse return null,
6719+
.array => |info| return .{
6720+
.len = info.elem_count orelse return null,
6721+
.elem_ty = info.elem_ty.*,
6722+
},
6723+
.tuple => |field_tys| {
6724+
const elem_ty = field_tys[0];
6725+
for (field_tys[1..]) |field_ty| {
6726+
if (!field_ty.eql(elem_ty)) {
6727+
return null;
6728+
}
6729+
}
6730+
return .{
6731+
.len = field_tys.len,
6732+
.elem_ty = elem_ty,
6733+
};
6734+
},
6735+
else => return null,
6736+
};
6737+
if (ip_index == .empty_struct_type) {
6738+
return .{
6739+
.len = 0,
6740+
.elem_ty = Type.fromIP(analyser, .type_type, .noreturn_type),
6741+
};
6742+
}
6743+
return switch (analyser.ip.indexToKey(ip_index)) {
6744+
.array_type => |info| .{
6745+
.len = info.len,
6746+
.elem_ty = Type.fromIP(analyser, .type_type, info.child),
6747+
},
6748+
.tuple_type => null, // TODO
6749+
else => null,
6750+
};
6751+
}

tests/analysis/peer_type_resolution.zig

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -189,6 +189,18 @@ const f32_and_u32 = if (comptime_bool) @as(f32, 0) else @as(i32, 0);
189189
const u32_and_f32 = if (comptime_bool) @as(u32, 0) else @as(f32, 0);
190190
// ^^^^^^^^^^^ (either type)()
191191

192+
const array_2_and_array_3 = if (comptime_bool) [2]S{ s, s } else [3]S{ s, s, s };
193+
// ^^^^^^^^^^^^^^^^^^^ (either type)()
194+
195+
const tuple_2_and_array_3 = if (comptime_bool) @as(struct { S, S }, .{ s, s }) else [3]S{ s, s, s };
196+
// ^^^^^^^^^^^^^^^^^^^ (either type)()
197+
198+
const array_3_and_tuple_2 = if (comptime_bool) [3]S{ s, s, s } else @as(struct { S, S }, .{ s, s });
199+
// ^^^^^^^^^^^^^^^^^^^ (either type)()
200+
201+
const array_3_and_tuple_3 = if (comptime_bool) [3]S{ s, s, s } else @as(struct { S, S, S }, .{ s, s, s });
202+
// ^^^^^^^^^^^^^^^^^^^ ([3]S)()
203+
192204
const compile_error_0 = if (comptime_bool) s else @compileError("Foo");
193205
// ^^^^^^^^^^^^^^^ (S)()
194206

0 commit comments

Comments
 (0)