Skip to content

Commit e69bc6d

Browse files
Resolve peer types for non-C pointers
1 parent 6511560 commit e69bc6d

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
@@ -6776,7 +6776,284 @@ fn resolvePeerTypesInner(analyser: *Analyser, peer_tys: []?Type) !?Type {
67766776
};
67776777
},
67786778

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

67817058
.func => return null, // TODO
67827059

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)