Skip to content

Commit b4d8db5

Browse files
Resolve peer types for array and tuple
1 parent 025c497 commit b4d8db5

File tree

2 files changed

+121
-1
lines changed

2 files changed

+121
-1
lines changed

src/analysis.zig

Lines changed: 101 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6298,6 +6298,35 @@ pub const ReferencedType = struct {
62986298
};
62996299
};
63006300

6301+
const ArrayLike = struct {
6302+
len: u64,
6303+
/// `noreturn` indicates that this type is `struct{}` so can coerce to anything
6304+
elem_ty: Type,
6305+
};
6306+
fn arrayLikeFromStruct(analyser: *Analyser, ty: Type) ?ArrayLike {
6307+
std.debug.assert(ty.is_type_val);
6308+
return switch (ty.zigTypeTag(analyser).?) {
6309+
.@"struct" => {
6310+
if (ty.isNamespace()) return .{
6311+
.len = 0,
6312+
.elem_ty = Type.fromIP(analyser, .type_type, .noreturn_type),
6313+
};
6314+
if (ty.data != .tuple) return null;
6315+
const elem_ty = ty.data.tuple[0];
6316+
for (ty.data.tuple[1..]) |field_ty| {
6317+
if (!field_ty.eql(elem_ty)) {
6318+
return null;
6319+
}
6320+
}
6321+
return .{
6322+
.len = ty.data.tuple.len,
6323+
.elem_ty = elem_ty,
6324+
};
6325+
},
6326+
else => null,
6327+
};
6328+
}
6329+
63016330
// Based on src/Sema.zig from the zig codebase
63026331
// https://github.com/ziglang/zig/blob/master/src/Sema.zig
63036332
fn resolvePeerTypesInner(analyser: *Analyser, peer_tys: []?Type) !?Type {
@@ -6544,7 +6573,78 @@ fn resolvePeerTypesInner(analyser: *Analyser, peer_tys: []?Type) !?Type {
65446573
};
65456574
},
65466575

6547-
.array => return null, // TODO
6576+
.array => {
6577+
var len: ?u64 = null;
6578+
var sentinel: InternPool.Index = .none;
6579+
var elem_ty: ?Type = null;
6580+
6581+
for (peer_tys) |*ty_ptr| {
6582+
const ty = ty_ptr.* orelse continue;
6583+
6584+
if (ty.data != .array) {
6585+
const arr_like = analyser.arrayLikeFromStruct(ty) orelse {
6586+
return null;
6587+
};
6588+
6589+
if (len) |cur_len| {
6590+
if (arr_like.len != cur_len) return null;
6591+
} else {
6592+
len = arr_like.len;
6593+
}
6594+
6595+
sentinel = .none;
6596+
6597+
continue;
6598+
}
6599+
6600+
const arr_info = ty.data.array;
6601+
const arr_len = arr_info.elem_count orelse {
6602+
return null;
6603+
};
6604+
6605+
const cur_elem_ty = elem_ty orelse {
6606+
if (len) |cur_len| {
6607+
if (arr_len != cur_len) return null;
6608+
} else {
6609+
len = arr_len;
6610+
sentinel = arr_info.sentinel;
6611+
}
6612+
elem_ty = arr_info.elem_ty.*;
6613+
continue;
6614+
};
6615+
6616+
if (arr_info.elem_count != len) {
6617+
return null;
6618+
}
6619+
6620+
const peer_elem_ty = arr_info.elem_ty.*;
6621+
if (!peer_elem_ty.eql(cur_elem_ty)) {
6622+
// TODO: check if coercible
6623+
return null;
6624+
}
6625+
6626+
if (sentinel != .none) {
6627+
if (arr_info.sentinel != .none) {
6628+
if (arr_info.sentinel != sentinel) sentinel = .none;
6629+
} else {
6630+
sentinel = .none;
6631+
}
6632+
}
6633+
}
6634+
6635+
std.debug.assert(elem_ty != null);
6636+
6637+
return .{
6638+
.data = .{
6639+
.array = .{
6640+
.elem_count = len,
6641+
.sentinel = sentinel,
6642+
.elem_ty = try analyser.allocType(elem_ty.?),
6643+
},
6644+
},
6645+
.is_type_val = true,
6646+
};
6647+
},
65486648

65496649
.vector => return null, // TODO
65506650

tests/analysis/peer_type_resolution.zig

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -218,6 +218,14 @@ pub fn main() !void {
218218
_ = noreturn_1;
219219
// ^^^^^^^^^^ (S)()
220220

221+
const coercible_array_0 = if (runtime_bool) [2]*const S{ &s, &s } else [2]?*const S{ &s, null };
222+
_ = coercible_array_0;
223+
// ^^^^^^^^^^^^^^^^^ (either type)() TODO this should be `[2]?*const S`
224+
225+
const coercible_array_1 = if (runtime_bool) [2]?*const S{ &s, null } else [2]*const S{ &s, &s };
226+
_ = coercible_array_1;
227+
// ^^^^^^^^^^^^^^^^^ (either type)() TODO this should be `[2]?*const S`
228+
221229
// Use @compileLog to verify the expected type with the compiler:
222230
// @compileLog(error_union_0);
223231

@@ -238,6 +246,18 @@ const comptime_float_error_union = if (comptime_bool) @as(error{A}!comptime_floa
238246
const null_error_union = if (comptime_bool) @as(error{A}!@TypeOf(null), null) else null;
239247
// ^^^^^^^^^^^^^^^^ (error{A}!@TypeOf(null))()
240248

249+
const array_2_and_array_3 = if (comptime_bool) [2]S{ s, s } else [3]S{ s, s, s };
250+
// ^^^^^^^^^^^^^^^^^^^ (either type)()
251+
252+
const tuple_2_and_array_3 = if (comptime_bool) @as(struct { S, S }, .{ s, s }) else [3]S{ s, s, s };
253+
// ^^^^^^^^^^^^^^^^^^^ (either type)()
254+
255+
const array_3_and_tuple_2 = if (comptime_bool) [3]S{ s, s, s } else @as(struct { S, S }, .{ s, s });
256+
// ^^^^^^^^^^^^^^^^^^^ (either type)()
257+
258+
const array_3_and_tuple_3 = if (comptime_bool) [3]S{ s, s, s } else @as(struct { S, S, S }, .{ s, s, s });
259+
// ^^^^^^^^^^^^^^^^^^^ ([3]S)()
260+
241261
const compile_error_0 = if (comptime_bool) s else @compileError("Foo");
242262
// ^^^^^^^^^^^^^^^ (S)()
243263

0 commit comments

Comments
 (0)