@@ -3480,12 +3480,17 @@ pub const Type = struct {
3480
3480
return entries [0 ].type ;
3481
3481
3482
3482
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 );
3487
3493
}
3488
- return chosen ;
3489
3494
}
3490
3495
3491
3496
// Note that we don't hash/equate descriptors to remove
@@ -6659,10 +6664,9 @@ fn resolvePeerTypesInner(analyser: *Analyser, peer_tys: []?Type) !?Type {
6659
6664
continue ;
6660
6665
};
6661
6666
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 {
6664
6668
return null ;
6665
- }
6669
+ };
6666
6670
6667
6671
if (ptr_info .flags .alignment != ptr_info .flags .alignment ) {
6668
6672
// TODO: find minimum C pointer alignment
@@ -6771,16 +6775,15 @@ fn resolvePeerTypesInner(analyser: *Analyser, peer_tys: []?Type) !?Type {
6771
6775
switch (peer_info .flags .size ) {
6772
6776
.one = > switch (ptr_info .flags .size ) {
6773
6777
.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 ;
6775
6780
break :good ;
6776
6781
}
6777
- // TODO: coerce pointer types
6778
6782
6779
6783
const cur_arr = cur_pointee_array orelse return null ;
6780
6784
const peer_arr = peer_pointee_array orelse return null ;
6781
6785
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 | {
6784
6787
// *[n:x]T + *[n:y]T = *[n]T
6785
6788
if (cur_arr .len == peer_arr .len ) {
6786
6789
ptr_info .elem_ty = .{
@@ -6800,7 +6803,6 @@ fn resolvePeerTypesInner(analyser: *Analyser, peer_tys: []?Type) !?Type {
6800
6803
ptr_info .elem_ty = elem_ty ;
6801
6804
break :good ;
6802
6805
}
6803
- // TODO: coerce array types
6804
6806
6805
6807
if (peer_arr .elem_ty .isNoreturnType ()) {
6806
6808
// *struct{} + *[a]T = []T
@@ -6821,19 +6823,19 @@ fn resolvePeerTypesInner(analyser: *Analyser, peer_tys: []?Type) !?Type {
6821
6823
.many = > {
6822
6824
// Only works for *[n]T + [*]T -> [*]T
6823
6825
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 ;
6825
6828
break :good ;
6826
6829
}
6827
- // TODO: coerce array and many-item pointer types
6828
6830
return null ;
6829
6831
},
6830
6832
.slice = > {
6831
6833
// Only works for *[n]T + []T -> []T
6832
6834
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 ;
6834
6837
break :good ;
6835
6838
}
6836
- // TODO: coerce array and slice types
6837
6839
if (arr .elem_ty .isNoreturnType ()) {
6838
6840
// *struct{} + []T -> []T
6839
6841
break :good ;
@@ -6846,19 +6848,18 @@ fn resolvePeerTypesInner(analyser: *Analyser, peer_tys: []?Type) !?Type {
6846
6848
.one = > {
6847
6849
// Only works for [*]T + *[n]T -> [*]T
6848
6850
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 | {
6850
6852
ptr_info .flags .size = .many ;
6851
- ptr_info .elem_ty = peer_info . elem_ty ;
6853
+ ptr_info .elem_ty = pointee ;
6852
6854
break :good ;
6853
6855
}
6854
- // TODO: coerce many-item pointer and array types
6855
6856
return null ;
6856
6857
},
6857
6858
.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 ;
6859
6861
break :good ;
6860
6862
}
6861
- // TODO: coerce many-item pointer types
6862
6863
return null ;
6863
6864
},
6864
6865
.slice = > {
@@ -6867,11 +6868,11 @@ fn resolvePeerTypesInner(analyser: *Analyser, peer_tys: []?Type) !?Type {
6867
6868
return null ;
6868
6869
}
6869
6870
// 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 | {
6871
6872
ptr_info .flags .size = .many ;
6873
+ ptr_info .elem_ty = pointee ;
6872
6874
break :good ;
6873
6875
}
6874
- // TODO: coerce many-item pointer and "slice" types
6875
6876
return null ;
6876
6877
},
6877
6878
.c = > unreachable ,
@@ -6880,12 +6881,11 @@ fn resolvePeerTypesInner(analyser: *Analyser, peer_tys: []?Type) !?Type {
6880
6881
.one = > {
6881
6882
// Only works for []T + *[n]T -> []T
6882
6883
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 | {
6884
6885
ptr_info .flags .size = .slice ;
6885
- ptr_info .elem_ty = peer_info . elem_ty ;
6886
+ ptr_info .elem_ty = pointee ;
6886
6887
break :good ;
6887
6888
}
6888
- // TODO: coerce slice and array types
6889
6889
if (arr .elem_ty .isNoreturnType ()) {
6890
6890
// []T + *struct{} -> []T
6891
6891
ptr_info .flags .size = .slice ;
@@ -6898,10 +6898,10 @@ fn resolvePeerTypesInner(analyser: *Analyser, peer_tys: []?Type) !?Type {
6898
6898
return null ;
6899
6899
},
6900
6900
.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 ;
6902
6903
break :good ;
6903
6904
}
6904
- // TODO: coerce slice types
6905
6905
return null ;
6906
6906
},
6907
6907
.c = > unreachable ,
@@ -7285,6 +7285,22 @@ fn resolvePairInMemoryCoercible(analyser: *Analyser, ty_a: Type, ty_b: Type) !?T
7285
7285
return null ;
7286
7286
}
7287
7287
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
+
7288
7304
fn coerceInMemoryAllowed (
7289
7305
analyser : * Analyser ,
7290
7306
dest_ty : Type ,
@@ -7382,7 +7398,72 @@ fn coerceInMemoryAllowedPtrs(
7382
7398
src_ptr_ty : Type ,
7383
7399
dest_is_mut : bool ,
7384
7400
) ! 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 ;
7388
7469
}
0 commit comments