Skip to content

Commit 76fa0af

Browse files
Resolve peer types for non-C pointers
1 parent 5762efb commit 76fa0af

File tree

3 files changed

+395
-1
lines changed

3 files changed

+395
-1
lines changed

src/analysis.zig

Lines changed: 278 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6735,7 +6735,284 @@ fn resolvePeerTypesInner(analyser: *Analyser, peer_tys: []?Type) !?Type {
67356735
};
67366736
},
67376737

6738-
.ptr => return null, // TODO
6738+
.ptr => {
6739+
var any_slice = false;
6740+
var any_abi_aligned = false;
6741+
var opt_ptr_info: ?Type.PointerInfo = null;
6742+
6743+
for (peer_tys) |opt_ty| {
6744+
const ty = opt_ty orelse continue;
6745+
const peer_info: Type.PointerInfo = switch (ty.zigTypeTag(analyser).?) {
6746+
.pointer => ty.pointerInfo(analyser).?,
6747+
.@"fn" => .{
6748+
.elem_ty = ty,
6749+
.sentinel = .none,
6750+
.flags = .{ .size = .one },
6751+
},
6752+
else => return null,
6753+
};
6754+
6755+
switch (peer_info.flags.size) {
6756+
.one, .many => {},
6757+
.slice => any_slice = true,
6758+
.c => return null,
6759+
}
6760+
6761+
var ptr_info = opt_ptr_info orelse {
6762+
opt_ptr_info = peer_info;
6763+
continue;
6764+
};
6765+
6766+
if (peer_info.flags.alignment == 0) {
6767+
any_abi_aligned = true;
6768+
} else if (ptr_info.flags.alignment == 0) {
6769+
any_abi_aligned = true;
6770+
ptr_info.flags.alignment = peer_info.flags.alignment;
6771+
} else {
6772+
ptr_info.flags.alignment = @min(ptr_info.flags.alignment, peer_info.flags.alignment);
6773+
}
6774+
6775+
if (ptr_info.flags.address_space != peer_info.flags.address_space) {
6776+
return null;
6777+
}
6778+
6779+
ptr_info.flags.is_const = ptr_info.flags.is_const or peer_info.flags.is_const;
6780+
ptr_info.flags.is_volatile = ptr_info.flags.is_volatile or peer_info.flags.is_volatile;
6781+
ptr_info.flags.is_allowzero = ptr_info.flags.is_allowzero or peer_info.flags.is_allowzero;
6782+
6783+
const peer_sentinel: InternPool.Index = switch (peer_info.flags.size) {
6784+
.one => switch (peer_info.elem_ty.data) {
6785+
.array => |array_info| array_info.sentinel,
6786+
.ip_index => |payload| switch (analyser.ip.indexToKey(payload.index orelse .unknown_type)) {
6787+
.array_type => |info| info.sentinel,
6788+
else => .none,
6789+
},
6790+
else => .none,
6791+
},
6792+
.many, .slice => peer_info.sentinel,
6793+
.c => unreachable,
6794+
};
6795+
6796+
const cur_sentinel: InternPool.Index = switch (ptr_info.flags.size) {
6797+
.one => switch (ptr_info.elem_ty.data) {
6798+
.array => |array_info| array_info.sentinel,
6799+
.ip_index => |payload| switch (analyser.ip.indexToKey(payload.index orelse .unknown_type)) {
6800+
.array_type => |info| info.sentinel,
6801+
else => .none,
6802+
},
6803+
else => .none,
6804+
},
6805+
.many, .slice => ptr_info.sentinel,
6806+
.c => unreachable,
6807+
};
6808+
6809+
const peer_pointee_array = analyser.typeIsArrayLike(peer_info.elem_ty);
6810+
const cur_pointee_array = analyser.typeIsArrayLike(ptr_info.elem_ty);
6811+
6812+
good: {
6813+
switch (peer_info.flags.size) {
6814+
.one => switch (ptr_info.flags.size) {
6815+
.one => {
6816+
if (ptr_info.elem_ty.eql(peer_info.elem_ty)) {
6817+
break :good;
6818+
}
6819+
// TODO: coerce pointer types
6820+
6821+
const cur_arr = cur_pointee_array orelse return null;
6822+
const peer_arr = peer_pointee_array orelse return null;
6823+
6824+
if (cur_arr.elem_ty.eql(peer_arr.elem_ty)) {
6825+
const elem_ty = peer_arr.elem_ty;
6826+
// *[n:x]T + *[n:y]T = *[n]T
6827+
if (cur_arr.len == peer_arr.len) {
6828+
ptr_info.elem_ty = .{
6829+
.data = .{
6830+
.array = .{
6831+
.elem_count = cur_arr.len,
6832+
.sentinel = .none,
6833+
.elem_ty = try analyser.allocType(elem_ty),
6834+
},
6835+
},
6836+
.is_type_val = true,
6837+
};
6838+
break :good;
6839+
}
6840+
// *[a]T + *[b]T = []T
6841+
ptr_info.flags.size = .slice;
6842+
ptr_info.elem_ty = elem_ty;
6843+
break :good;
6844+
}
6845+
// TODO: coerce array types
6846+
6847+
if (peer_arr.elem_ty.isNoreturnType()) {
6848+
// *struct{} + *[a]T = []T
6849+
ptr_info.flags.size = .slice;
6850+
ptr_info.elem_ty = cur_arr.elem_ty;
6851+
break :good;
6852+
}
6853+
6854+
if (cur_arr.elem_ty.isNoreturnType()) {
6855+
// *[a]T + *struct{} = []T
6856+
ptr_info.flags.size = .slice;
6857+
ptr_info.elem_ty = peer_arr.elem_ty;
6858+
break :good;
6859+
}
6860+
6861+
return null;
6862+
},
6863+
.many => {
6864+
// Only works for *[n]T + [*]T -> [*]T
6865+
const arr = peer_pointee_array orelse return null;
6866+
if (ptr_info.elem_ty.eql(arr.elem_ty)) {
6867+
break :good;
6868+
}
6869+
// TODO: coerce array and many-item pointer types
6870+
return null;
6871+
},
6872+
.slice => {
6873+
// Only works for *[n]T + []T -> []T
6874+
const arr = peer_pointee_array orelse return null;
6875+
if (ptr_info.elem_ty.eql(arr.elem_ty)) {
6876+
break :good;
6877+
}
6878+
// TODO: coerce array and slice types
6879+
if (arr.elem_ty.isNoreturnType()) {
6880+
// *struct{} + []T -> []T
6881+
break :good;
6882+
}
6883+
return null;
6884+
},
6885+
.c => unreachable,
6886+
},
6887+
.many => switch (ptr_info.flags.size) {
6888+
.one => {
6889+
// Only works for [*]T + *[n]T -> [*]T
6890+
const arr = cur_pointee_array orelse return null;
6891+
if (arr.elem_ty.eql(peer_info.elem_ty)) {
6892+
ptr_info.flags.size = .many;
6893+
ptr_info.elem_ty = peer_info.elem_ty;
6894+
break :good;
6895+
}
6896+
// TODO: coerce many-item pointer and array types
6897+
return null;
6898+
},
6899+
.many => {
6900+
if (ptr_info.elem_ty.eql(peer_info.elem_ty)) {
6901+
break :good;
6902+
}
6903+
// TODO: coerce many-item pointer types
6904+
return null;
6905+
},
6906+
.slice => {
6907+
// Only works if no peers are actually slices
6908+
if (any_slice) {
6909+
return null;
6910+
}
6911+
// Okay, then works for [*]T + "[]T" -> [*]T
6912+
if (ptr_info.elem_ty.eql(peer_info.elem_ty)) {
6913+
ptr_info.flags.size = .many;
6914+
break :good;
6915+
}
6916+
// TODO: coerce many-item pointer and "slice" types
6917+
return null;
6918+
},
6919+
.c => unreachable,
6920+
},
6921+
.slice => switch (ptr_info.flags.size) {
6922+
.one => {
6923+
// Only works for []T + *[n]T -> []T
6924+
const arr = cur_pointee_array orelse return null;
6925+
if (arr.elem_ty.eql(peer_info.elem_ty)) {
6926+
ptr_info.flags.size = .slice;
6927+
ptr_info.elem_ty = peer_info.elem_ty;
6928+
break :good;
6929+
}
6930+
// TODO: coerce slice and array types
6931+
if (arr.elem_ty.isNoreturnType()) {
6932+
// []T + *struct{} -> []T
6933+
ptr_info.flags.size = .slice;
6934+
ptr_info.elem_ty = peer_info.elem_ty;
6935+
break :good;
6936+
}
6937+
return null;
6938+
},
6939+
.many => {
6940+
return null;
6941+
},
6942+
.slice => {
6943+
if (ptr_info.elem_ty.eql(peer_info.elem_ty)) {
6944+
break :good;
6945+
}
6946+
// TODO: coerce slice types
6947+
return null;
6948+
},
6949+
.c => unreachable,
6950+
},
6951+
.c => unreachable,
6952+
}
6953+
}
6954+
6955+
sentinel: {
6956+
no_sentinel: {
6957+
if (peer_sentinel == .none) break :no_sentinel;
6958+
if (cur_sentinel == .none) break :no_sentinel;
6959+
if (peer_sentinel != cur_sentinel) {
6960+
// TODO: coerce pointer sentinels
6961+
return null;
6962+
}
6963+
break :sentinel;
6964+
}
6965+
ptr_info.sentinel = .none;
6966+
if (ptr_info.flags.size == .one) switch (ptr_info.elem_ty.data) {
6967+
.array => |*array_info| array_info.sentinel = .none,
6968+
.ip_index => |*payload| switch (analyser.ip.indexToKey(payload.index orelse .unknown_type)) {
6969+
.array_type => |info| {
6970+
payload.index = try analyser.ip.get(analyser.gpa, .{ .array_type = .{
6971+
.len = info.len,
6972+
.child = info.child,
6973+
.sentinel = .none,
6974+
} });
6975+
},
6976+
else => {},
6977+
},
6978+
else => {},
6979+
};
6980+
}
6981+
6982+
opt_ptr_info = ptr_info;
6983+
}
6984+
6985+
const info = opt_ptr_info.?;
6986+
const pointee = info.elem_ty;
6987+
if (pointee.isNoreturnType()) {
6988+
return null;
6989+
}
6990+
switch (pointee.data) {
6991+
.array => |array_info| {
6992+
if (array_info.elem_ty.isNoreturnType()) {
6993+
return null;
6994+
}
6995+
},
6996+
else => {},
6997+
}
6998+
6999+
if (any_abi_aligned and info.flags.alignment != 0) {
7000+
// TODO: find minimum pointer alignment
7001+
return null;
7002+
}
7003+
7004+
return .{
7005+
.data = .{
7006+
.pointer = .{
7007+
.elem_ty = try analyser.allocType(info.elem_ty),
7008+
.sentinel = info.sentinel,
7009+
.size = info.flags.size,
7010+
.is_const = info.flags.is_const,
7011+
},
7012+
},
7013+
.is_type_val = true,
7014+
};
7015+
},
67397016

67407017
.func => return null, // TODO
67417018

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)