Skip to content

Commit ad36390

Browse files
Resolve peer types for array and tuple
1 parent 066bd4f commit ad36390

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 {
@@ -6423,7 +6452,78 @@ fn resolvePeerTypesInner(analyser: *Analyser, peer_tys: []?Type) !?Type {
64236452
};
64246453
},
64256454

6426-
.array => return null, // TODO
6455+
.array => {
6456+
var len: ?u64 = null;
6457+
var sentinel: InternPool.Index = .none;
6458+
var elem_ty: ?Type = null;
6459+
6460+
for (peer_tys) |*ty_ptr| {
6461+
const ty = ty_ptr.* orelse continue;
6462+
6463+
if (ty.data != .array) {
6464+
const arr_like = analyser.arrayLikeFromStruct(ty) orelse {
6465+
return null;
6466+
};
6467+
6468+
if (len) |cur_len| {
6469+
if (arr_like.len != cur_len) return null;
6470+
} else {
6471+
len = arr_like.len;
6472+
}
6473+
6474+
sentinel = .none;
6475+
6476+
continue;
6477+
}
6478+
6479+
const arr_info = ty.data.array;
6480+
const arr_len = arr_info.elem_count orelse {
6481+
return null;
6482+
};
6483+
6484+
const cur_elem_ty = elem_ty orelse {
6485+
if (len) |cur_len| {
6486+
if (arr_len != cur_len) return null;
6487+
} else {
6488+
len = arr_len;
6489+
sentinel = arr_info.sentinel;
6490+
}
6491+
elem_ty = arr_info.elem_ty.*;
6492+
continue;
6493+
};
6494+
6495+
if (arr_info.elem_count != len) {
6496+
return null;
6497+
}
6498+
6499+
const peer_elem_ty = arr_info.elem_ty.*;
6500+
if (!peer_elem_ty.eql(cur_elem_ty)) {
6501+
// TODO: check if coercible
6502+
return null;
6503+
}
6504+
6505+
if (sentinel != .none) {
6506+
if (arr_info.sentinel != .none) {
6507+
if (arr_info.sentinel != sentinel) sentinel = .none;
6508+
} else {
6509+
sentinel = .none;
6510+
}
6511+
}
6512+
}
6513+
6514+
std.debug.assert(elem_ty != null);
6515+
6516+
return .{
6517+
.data = .{
6518+
.array = .{
6519+
.elem_count = len,
6520+
.sentinel = sentinel,
6521+
.elem_ty = try analyser.allocType(elem_ty.?),
6522+
},
6523+
},
6524+
.is_type_val = true,
6525+
};
6526+
},
64276527

64286528
.vector => return null, // TODO
64296529

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)