Skip to content

Commit adcfd8d

Browse files
Coerce pointer types
1 parent 32c79ce commit adcfd8d

File tree

2 files changed

+279
-32
lines changed

2 files changed

+279
-32
lines changed

src/analysis.zig

Lines changed: 113 additions & 32 deletions
Original file line numberDiff line numberDiff line change
@@ -3480,12 +3480,17 @@ pub const Type = struct {
34803480
return entries[0].type;
34813481

34823482
peer_type_resolution: {
3483-
var chosen = entries[0].type;
3484-
for (entries[1..]) |entry| {
3485-
const candidate = entry.type;
3486-
chosen = try analyser.resolvePeerTypes(chosen, candidate) orelse break :peer_type_resolution;
3483+
const peer_tys = try analyser.gpa.alloc(?Type, entries.len);
3484+
defer analyser.gpa.free(peer_tys);
3485+
3486+
for (entries, peer_tys) |entry, *ty| {
3487+
if (entry.type.is_type_val) break :peer_type_resolution;
3488+
ty.* = try entry.type.typeOf(analyser);
3489+
}
3490+
3491+
if (try analyser.resolvePeerTypesInner(peer_tys)) |ty| {
3492+
return try ty.instanceTypeVal(analyser);
34873493
}
3488-
return chosen;
34893494
}
34903495

34913496
// Note that we don't hash/equate descriptors to remove
@@ -6659,10 +6664,9 @@ fn resolvePeerTypesInner(analyser: *Analyser, peer_tys: []?Type) !?Type {
66596664
continue;
66606665
};
66616666

6662-
if (!ptr_info.elem_ty.eql(peer_info.elem_ty)) {
6663-
// TODO: coerce C pointer types
6667+
ptr_info.elem_ty = try analyser.resolvePairInMemoryCoercible(ptr_info.elem_ty, peer_info.elem_ty) orelse {
66646668
return null;
6665-
}
6669+
};
66666670

66676671
if (ptr_info.flags.alignment != ptr_info.flags.alignment) {
66686672
// TODO: find minimum C pointer alignment
@@ -6771,16 +6775,15 @@ fn resolvePeerTypesInner(analyser: *Analyser, peer_tys: []?Type) !?Type {
67716775
switch (peer_info.flags.size) {
67726776
.one => switch (ptr_info.flags.size) {
67736777
.one => {
6774-
if (ptr_info.elem_ty.eql(peer_info.elem_ty)) {
6778+
if (try analyser.resolvePairInMemoryCoercible(ptr_info.elem_ty, peer_info.elem_ty)) |pointee| {
6779+
ptr_info.elem_ty = pointee;
67756780
break :good;
67766781
}
6777-
// TODO: coerce pointer types
67786782

67796783
const cur_arr = cur_pointee_array orelse return null;
67806784
const peer_arr = peer_pointee_array orelse return null;
67816785

6782-
if (cur_arr.elem_ty.eql(peer_arr.elem_ty)) {
6783-
const elem_ty = peer_arr.elem_ty;
6786+
if (try analyser.resolvePairInMemoryCoercible(cur_arr.elem_ty, peer_arr.elem_ty)) |elem_ty| {
67846787
// *[n:x]T + *[n:y]T = *[n]T
67856788
if (cur_arr.len == peer_arr.len) {
67866789
ptr_info.elem_ty = .{
@@ -6800,7 +6803,6 @@ fn resolvePeerTypesInner(analyser: *Analyser, peer_tys: []?Type) !?Type {
68006803
ptr_info.elem_ty = elem_ty;
68016804
break :good;
68026805
}
6803-
// TODO: coerce array types
68046806

68056807
if (peer_arr.elem_ty.isNoreturnType()) {
68066808
// *struct{} + *[a]T = []T
@@ -6821,19 +6823,19 @@ fn resolvePeerTypesInner(analyser: *Analyser, peer_tys: []?Type) !?Type {
68216823
.many => {
68226824
// Only works for *[n]T + [*]T -> [*]T
68236825
const arr = peer_pointee_array orelse return null;
6824-
if (ptr_info.elem_ty.eql(arr.elem_ty)) {
6826+
if (try analyser.resolvePairInMemoryCoercible(ptr_info.elem_ty, arr.elem_ty)) |pointee| {
6827+
ptr_info.elem_ty = pointee;
68256828
break :good;
68266829
}
6827-
// TODO: coerce array and many-item pointer types
68286830
return null;
68296831
},
68306832
.slice => {
68316833
// Only works for *[n]T + []T -> []T
68326834
const arr = peer_pointee_array orelse return null;
6833-
if (ptr_info.elem_ty.eql(arr.elem_ty)) {
6835+
if (try analyser.resolvePairInMemoryCoercible(ptr_info.elem_ty, arr.elem_ty)) |pointee| {
6836+
ptr_info.elem_ty = pointee;
68346837
break :good;
68356838
}
6836-
// TODO: coerce array and slice types
68376839
if (arr.elem_ty.isNoreturnType()) {
68386840
// *struct{} + []T -> []T
68396841
break :good;
@@ -6846,19 +6848,18 @@ fn resolvePeerTypesInner(analyser: *Analyser, peer_tys: []?Type) !?Type {
68466848
.one => {
68476849
// Only works for [*]T + *[n]T -> [*]T
68486850
const arr = cur_pointee_array orelse return null;
6849-
if (arr.elem_ty.eql(peer_info.elem_ty)) {
6851+
if (try analyser.resolvePairInMemoryCoercible(arr.elem_ty, peer_info.elem_ty)) |pointee| {
68506852
ptr_info.flags.size = .many;
6851-
ptr_info.elem_ty = peer_info.elem_ty;
6853+
ptr_info.elem_ty = pointee;
68526854
break :good;
68536855
}
6854-
// TODO: coerce many-item pointer and array types
68556856
return null;
68566857
},
68576858
.many => {
6858-
if (ptr_info.elem_ty.eql(peer_info.elem_ty)) {
6859+
if (try analyser.resolvePairInMemoryCoercible(ptr_info.elem_ty, peer_info.elem_ty)) |pointee| {
6860+
ptr_info.elem_ty = pointee;
68596861
break :good;
68606862
}
6861-
// TODO: coerce many-item pointer types
68626863
return null;
68636864
},
68646865
.slice => {
@@ -6867,11 +6868,11 @@ fn resolvePeerTypesInner(analyser: *Analyser, peer_tys: []?Type) !?Type {
68676868
return null;
68686869
}
68696870
// Okay, then works for [*]T + "[]T" -> [*]T
6870-
if (ptr_info.elem_ty.eql(peer_info.elem_ty)) {
6871+
if (try analyser.resolvePairInMemoryCoercible(ptr_info.elem_ty, peer_info.elem_ty)) |pointee| {
68716872
ptr_info.flags.size = .many;
6873+
ptr_info.elem_ty = pointee;
68726874
break :good;
68736875
}
6874-
// TODO: coerce many-item pointer and "slice" types
68756876
return null;
68766877
},
68776878
.c => unreachable,
@@ -6880,12 +6881,11 @@ fn resolvePeerTypesInner(analyser: *Analyser, peer_tys: []?Type) !?Type {
68806881
.one => {
68816882
// Only works for []T + *[n]T -> []T
68826883
const arr = cur_pointee_array orelse return null;
6883-
if (arr.elem_ty.eql(peer_info.elem_ty)) {
6884+
if (try analyser.resolvePairInMemoryCoercible(arr.elem_ty, peer_info.elem_ty)) |pointee| {
68846885
ptr_info.flags.size = .slice;
6885-
ptr_info.elem_ty = peer_info.elem_ty;
6886+
ptr_info.elem_ty = pointee;
68866887
break :good;
68876888
}
6888-
// TODO: coerce slice and array types
68896889
if (arr.elem_ty.isNoreturnType()) {
68906890
// []T + *struct{} -> []T
68916891
ptr_info.flags.size = .slice;
@@ -6898,10 +6898,10 @@ fn resolvePeerTypesInner(analyser: *Analyser, peer_tys: []?Type) !?Type {
68986898
return null;
68996899
},
69006900
.slice => {
6901-
if (ptr_info.elem_ty.eql(peer_info.elem_ty)) {
6901+
if (try analyser.resolvePairInMemoryCoercible(ptr_info.elem_ty, peer_info.elem_ty)) |pointee| {
6902+
ptr_info.elem_ty = pointee;
69026903
break :good;
69036904
}
6904-
// TODO: coerce slice types
69056905
return null;
69066906
},
69076907
.c => unreachable,
@@ -7285,6 +7285,22 @@ fn resolvePairInMemoryCoercible(analyser: *Analyser, ty_a: Type, ty_b: Type) !?T
72857285
return null;
72867286
}
72877287

7288+
fn typePointerAllowsZero(analyser: *Analyser, ty: Type) bool {
7289+
if (analyser.typeIsPointerLikeOptional(ty)) {
7290+
return true;
7291+
}
7292+
return analyser.typePointerInfo(ty).?.flags.is_allowzero;
7293+
}
7294+
7295+
fn typeIsPointerLikeOptional(analyser: *Analyser, ty: Type) bool {
7296+
const ptr_info = analyser.typePointerInfo(ty) orelse return false;
7297+
return switch (ptr_info.flags.size) {
7298+
.slice => false,
7299+
.c => !ptr_info.is_optional,
7300+
.many, .one => ptr_info.is_optional and !ptr_info.flags.is_allowzero,
7301+
};
7302+
}
7303+
72887304
fn coerceInMemoryAllowed(
72897305
analyser: *Analyser,
72907306
dest_ty: Type,
@@ -7382,7 +7398,72 @@ fn coerceInMemoryAllowedPtrs(
73827398
src_ptr_ty: Type,
73837399
dest_is_mut: bool,
73847400
) !bool {
7385-
// TODO
7386-
_ = .{ analyser, dest_ty, src_ty, dest_ptr_ty, src_ptr_ty, dest_is_mut };
7387-
return false;
7401+
const dest_info = analyser.typePointerInfo(dest_ptr_ty).?;
7402+
const src_info = analyser.typePointerInfo(src_ptr_ty).?;
7403+
7404+
const ok_ptr_size = src_info.flags.size == dest_info.flags.size or
7405+
src_info.flags.size == .c or dest_info.flags.size == .c;
7406+
if (!ok_ptr_size) {
7407+
return false;
7408+
}
7409+
7410+
const ok_const = src_info.flags.is_const == dest_info.flags.is_const or
7411+
(!dest_is_mut and dest_info.flags.is_const);
7412+
7413+
if (!ok_const) {
7414+
return false;
7415+
}
7416+
7417+
const ok_volatile = src_info.flags.is_volatile == dest_info.flags.is_volatile or
7418+
(!dest_is_mut and dest_info.flags.is_volatile);
7419+
7420+
if (!ok_volatile) {
7421+
return false;
7422+
}
7423+
7424+
const dest_allowzero = analyser.typePointerAllowsZero(dest_ty);
7425+
const src_allowzero = analyser.typePointerAllowsZero(src_ty);
7426+
const ok_allowzero = src_allowzero == dest_allowzero or
7427+
(!dest_is_mut and dest_allowzero);
7428+
7429+
if (!ok_allowzero) {
7430+
return false;
7431+
}
7432+
7433+
if (dest_info.flags.address_space != src_info.flags.address_space) {
7434+
return false;
7435+
}
7436+
7437+
const child_ok = try analyser.coerceInMemoryAllowed(
7438+
dest_info.elem_ty,
7439+
src_info.elem_ty,
7440+
!dest_is_mut and dest_info.flags.is_const,
7441+
);
7442+
if (!child_ok and !dest_is_mut) {
7443+
return false;
7444+
}
7445+
7446+
const sentinel_ok = ok: {
7447+
const ss = src_info.sentinel;
7448+
const ds = dest_info.sentinel;
7449+
if (ss == .none and ds == .none) break :ok true;
7450+
if (ss == ds) break :ok true;
7451+
// TODO: check if src sentinel coerces to dest sentinel
7452+
if (src_info.flags.size == .c) break :ok true;
7453+
if (!dest_is_mut and dest_info.sentinel == .none) break :ok true;
7454+
break :ok false;
7455+
};
7456+
7457+
if (!sentinel_ok) {
7458+
return false;
7459+
}
7460+
7461+
if (src_info.flags.alignment != 0 or dest_info.flags.alignment != 0 or
7462+
!dest_info.elem_ty.eql(src_info.elem_ty))
7463+
{
7464+
// TODO: check pointer alignments
7465+
return false;
7466+
}
7467+
7468+
return true;
73887469
}

0 commit comments

Comments
 (0)