Skip to content

Commit 08eae58

Browse files
Resolve peer pointer types
1 parent 7e55f40 commit 08eae58

File tree

3 files changed

+396
-1
lines changed

3 files changed

+396
-1
lines changed

src/analysis.zig

Lines changed: 279 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6682,7 +6682,285 @@ fn resolvePeerTypesInner(analyser: *Analyser, peer_tys: []?Type) !?Type {
66826682
};
66836683
},
66846684

6685-
.ptr => return null, // TODO
6685+
.ptr => {
6686+
var any_slice = false;
6687+
var any_abi_aligned = false;
6688+
var opt_ptr_info: ?PointerInfo = null;
6689+
6690+
for (peer_tys) |opt_ty| {
6691+
const ty = opt_ty orelse continue;
6692+
const peer_info: PointerInfo = switch (ty.zigTypeTag(analyser).?) {
6693+
.pointer => analyser.typePointerInfo(ty).?,
6694+
.@"fn" => .{
6695+
.is_optional = false,
6696+
.elem_ty = ty,
6697+
.sentinel = .none,
6698+
.flags = .{ .size = .one },
6699+
},
6700+
else => return null,
6701+
};
6702+
6703+
switch (peer_info.flags.size) {
6704+
.one, .many => {},
6705+
.slice => any_slice = true,
6706+
.c => return null,
6707+
}
6708+
6709+
var ptr_info = opt_ptr_info orelse {
6710+
opt_ptr_info = peer_info;
6711+
continue;
6712+
};
6713+
6714+
if (peer_info.flags.alignment == 0) {
6715+
any_abi_aligned = true;
6716+
} else if (ptr_info.flags.alignment == 0) {
6717+
any_abi_aligned = true;
6718+
ptr_info.flags.alignment = peer_info.flags.alignment;
6719+
} else {
6720+
ptr_info.flags.alignment = @min(ptr_info.flags.alignment, peer_info.flags.alignment);
6721+
}
6722+
6723+
if (ptr_info.flags.address_space != peer_info.flags.address_space) {
6724+
return null;
6725+
}
6726+
6727+
ptr_info.flags.is_const = ptr_info.flags.is_const or peer_info.flags.is_const;
6728+
ptr_info.flags.is_volatile = ptr_info.flags.is_volatile or peer_info.flags.is_volatile;
6729+
ptr_info.flags.is_allowzero = ptr_info.flags.is_allowzero or peer_info.flags.is_allowzero;
6730+
6731+
const peer_sentinel: InternPool.Index = switch (peer_info.flags.size) {
6732+
.one => switch (peer_info.elem_ty.data) {
6733+
.array => |array_info| array_info.sentinel,
6734+
.ip_index => |payload| switch (analyser.ip.indexToKey(payload.index orelse .unknown_type)) {
6735+
.array_type => |info| info.sentinel,
6736+
else => .none,
6737+
},
6738+
else => .none,
6739+
},
6740+
.many, .slice => peer_info.sentinel,
6741+
.c => unreachable,
6742+
};
6743+
6744+
const cur_sentinel: InternPool.Index = switch (ptr_info.flags.size) {
6745+
.one => switch (ptr_info.elem_ty.data) {
6746+
.array => |array_info| array_info.sentinel,
6747+
.ip_index => |payload| switch (analyser.ip.indexToKey(payload.index orelse .unknown_type)) {
6748+
.array_type => |info| info.sentinel,
6749+
else => .none,
6750+
},
6751+
else => .none,
6752+
},
6753+
.many, .slice => ptr_info.sentinel,
6754+
.c => unreachable,
6755+
};
6756+
6757+
const peer_pointee_array = analyser.typeIsArrayLike(peer_info.elem_ty);
6758+
const cur_pointee_array = analyser.typeIsArrayLike(ptr_info.elem_ty);
6759+
6760+
good: {
6761+
switch (peer_info.flags.size) {
6762+
.one => switch (ptr_info.flags.size) {
6763+
.one => {
6764+
if (ptr_info.elem_ty.eql(peer_info.elem_ty)) {
6765+
break :good;
6766+
}
6767+
// TODO: coerce pointer types
6768+
6769+
const cur_arr = cur_pointee_array orelse return null;
6770+
const peer_arr = peer_pointee_array orelse return null;
6771+
6772+
if (cur_arr.elem_ty.eql(peer_arr.elem_ty)) {
6773+
const elem_ty = peer_arr.elem_ty;
6774+
// *[n:x]T + *[n:y]T = *[n]T
6775+
if (cur_arr.len == peer_arr.len) {
6776+
ptr_info.elem_ty = .{
6777+
.data = .{
6778+
.array = .{
6779+
.elem_count = cur_arr.len,
6780+
.sentinel = .none,
6781+
.elem_ty = try analyser.allocType(elem_ty),
6782+
},
6783+
},
6784+
.is_type_val = true,
6785+
};
6786+
break :good;
6787+
}
6788+
// *[a]T + *[b]T = []T
6789+
ptr_info.flags.size = .slice;
6790+
ptr_info.elem_ty = elem_ty;
6791+
break :good;
6792+
}
6793+
// TODO: coerce array types
6794+
6795+
if (peer_arr.elem_ty.isNoreturnType()) {
6796+
// *struct{} + *[a]T = []T
6797+
ptr_info.flags.size = .slice;
6798+
ptr_info.elem_ty = cur_arr.elem_ty;
6799+
break :good;
6800+
}
6801+
6802+
if (cur_arr.elem_ty.isNoreturnType()) {
6803+
// *[a]T + *struct{} = []T
6804+
ptr_info.flags.size = .slice;
6805+
ptr_info.elem_ty = peer_arr.elem_ty;
6806+
break :good;
6807+
}
6808+
6809+
return null;
6810+
},
6811+
.many => {
6812+
// Only works for *[n]T + [*]T -> [*]T
6813+
const arr = peer_pointee_array orelse return null;
6814+
if (ptr_info.elem_ty.eql(arr.elem_ty)) {
6815+
break :good;
6816+
}
6817+
// TODO: coerce array and many-item pointer types
6818+
return null;
6819+
},
6820+
.slice => {
6821+
// Only works for *[n]T + []T -> []T
6822+
const arr = peer_pointee_array orelse return null;
6823+
if (ptr_info.elem_ty.eql(arr.elem_ty)) {
6824+
break :good;
6825+
}
6826+
// TODO: coerce array and slice types
6827+
if (arr.elem_ty.isNoreturnType()) {
6828+
// *struct{} + []T -> []T
6829+
break :good;
6830+
}
6831+
return null;
6832+
},
6833+
.c => unreachable,
6834+
},
6835+
.many => switch (ptr_info.flags.size) {
6836+
.one => {
6837+
// Only works for [*]T + *[n]T -> [*]T
6838+
const arr = cur_pointee_array orelse return null;
6839+
if (arr.elem_ty.eql(peer_info.elem_ty)) {
6840+
ptr_info.flags.size = .many;
6841+
ptr_info.elem_ty = peer_info.elem_ty;
6842+
break :good;
6843+
}
6844+
// TODO: coerce many-item pointer and array types
6845+
return null;
6846+
},
6847+
.many => {
6848+
if (ptr_info.elem_ty.eql(peer_info.elem_ty)) {
6849+
break :good;
6850+
}
6851+
// TODO: coerce many-item pointer types
6852+
return null;
6853+
},
6854+
.slice => {
6855+
// Only works if no peers are actually slices
6856+
if (any_slice) {
6857+
return null;
6858+
}
6859+
// Okay, then works for [*]T + "[]T" -> [*]T
6860+
if (ptr_info.elem_ty.eql(peer_info.elem_ty)) {
6861+
ptr_info.flags.size = .many;
6862+
break :good;
6863+
}
6864+
// TODO: coerce many-item pointer and "slice" types
6865+
return null;
6866+
},
6867+
.c => unreachable,
6868+
},
6869+
.slice => switch (ptr_info.flags.size) {
6870+
.one => {
6871+
// Only works for []T + *[n]T -> []T
6872+
const arr = cur_pointee_array orelse return null;
6873+
if (arr.elem_ty.eql(peer_info.elem_ty)) {
6874+
ptr_info.flags.size = .slice;
6875+
ptr_info.elem_ty = peer_info.elem_ty;
6876+
break :good;
6877+
}
6878+
// TODO: coerce slice and array types
6879+
if (arr.elem_ty.isNoreturnType()) {
6880+
// []T + *struct{} -> []T
6881+
ptr_info.flags.size = .slice;
6882+
ptr_info.elem_ty = peer_info.elem_ty;
6883+
break :good;
6884+
}
6885+
return null;
6886+
},
6887+
.many => {
6888+
return null;
6889+
},
6890+
.slice => {
6891+
if (ptr_info.elem_ty.eql(peer_info.elem_ty)) {
6892+
break :good;
6893+
}
6894+
// TODO: coerce slice types
6895+
return null;
6896+
},
6897+
.c => unreachable,
6898+
},
6899+
.c => unreachable,
6900+
}
6901+
}
6902+
6903+
sentinel: {
6904+
no_sentinel: {
6905+
if (peer_sentinel == .none) break :no_sentinel;
6906+
if (cur_sentinel == .none) break :no_sentinel;
6907+
if (peer_sentinel != cur_sentinel) {
6908+
// TODO: coerce pointer sentinels
6909+
return null;
6910+
}
6911+
break :sentinel;
6912+
}
6913+
ptr_info.sentinel = .none;
6914+
if (ptr_info.flags.size == .one) switch (ptr_info.elem_ty.data) {
6915+
.array => |*array_info| array_info.sentinel = .none,
6916+
.ip_index => |*payload| switch (analyser.ip.indexToKey(payload.index orelse .unknown_type)) {
6917+
.array_type => |info| {
6918+
payload.index = try analyser.ip.get(analyser.gpa, .{ .array_type = .{
6919+
.len = info.len,
6920+
.child = info.child,
6921+
.sentinel = .none,
6922+
} });
6923+
},
6924+
else => {},
6925+
},
6926+
else => {},
6927+
};
6928+
}
6929+
6930+
opt_ptr_info = ptr_info;
6931+
}
6932+
6933+
const info = opt_ptr_info.?;
6934+
const pointee = info.elem_ty;
6935+
if (pointee.isNoreturnType()) {
6936+
return null;
6937+
}
6938+
switch (pointee.data) {
6939+
.array => |array_info| {
6940+
if (array_info.elem_ty.isNoreturnType()) {
6941+
return null;
6942+
}
6943+
},
6944+
else => {},
6945+
}
6946+
6947+
if (any_abi_aligned and info.flags.alignment != 0) {
6948+
// TODO: find minimum pointer alignment
6949+
return null;
6950+
}
6951+
6952+
return .{
6953+
.data = .{
6954+
.pointer = .{
6955+
.elem_ty = try analyser.allocType(info.elem_ty),
6956+
.sentinel = info.sentinel,
6957+
.size = info.flags.size,
6958+
.is_const = info.flags.is_const,
6959+
},
6960+
},
6961+
.is_type_val = true,
6962+
};
6963+
},
66866964

66876965
.func => return null, // TODO
66886966

tests/analysis/peer_type_resolution.zig

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,6 @@
1+
// Also see:
2+
// - pointer.zig
3+
14
const S = struct {
25
int: i64,
36
float: f32,

0 commit comments

Comments
 (0)