Skip to content

Commit b593e78

Browse files
Resolve peer pointer types
1 parent 12b262e commit b593e78

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
@@ -6687,7 +6687,285 @@ fn resolvePeerTypesInner(analyser: *Analyser, peer_tys: []?Type) !?Type {
66876687
};
66886688
},
66896689

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

66926970
.func => return null, // TODO
66936971

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)