Skip to content

Commit ece585d

Browse files
Resolve peer array/tuple types
1 parent 532450c commit ece585d

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
@@ -6552,7 +6552,78 @@ fn resolvePeerTypesInner(analyser: *Analyser, peer_tys: []?Type) !?Type {
65526552
};
65536553
},
65546554

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

65576628
.vector => return null, // TODO
65586629

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

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)