@@ -1751,7 +1751,7 @@ fn resolveCallsiteReferences(analyser: *Analyser, decl_handle: DeclWithHandle) !
1751
1751
1752
1752
if (real_param_idx >= call .ast .params .len ) continue ;
1753
1753
1754
- const ty = resolve_ty : {
1754
+ var ty = resolve_ty : {
1755
1755
// don't resolve callsite references while resolving callsite references
1756
1756
const old_collect_callsite_references = analyser .collect_callsite_references ;
1757
1757
defer analyser .collect_callsite_references = old_collect_callsite_references ;
@@ -1767,6 +1767,9 @@ fn resolveCallsiteReferences(analyser: *Analyser, decl_handle: DeclWithHandle) !
1767
1767
)) orelse continue ;
1768
1768
};
1769
1769
1770
+ ty = try ty .typeOf (analyser );
1771
+ std .debug .assert (ty .is_type_val );
1772
+
1770
1773
const loc = offsets .tokenToPosition (tree , tree .nodeMainToken (call .ast .params [real_param_idx ]), .@"utf-8" );
1771
1774
try possible .append (analyser .arena , .{
1772
1775
.type = ty ,
@@ -3681,27 +3684,211 @@ pub const Type = struct {
3681
3684
};
3682
3685
}
3683
3686
3684
- /// Resolves possible types of a type (single for all except either)
3687
+ /// Resolves all possible types by recursively expanding any conditional types.
3685
3688
/// Drops duplicates
3686
3689
pub fn getAllTypesWithHandles (ty : Type , analyser : * Analyser ) error {OutOfMemory }! []const Type {
3687
3690
var all_types : ArraySet = .empty ;
3688
3691
try ty .getAllTypesWithHandlesArraySet (analyser , & all_types );
3689
3692
return all_types .keys ();
3690
3693
}
3691
3694
3695
+ fn isConditional (ty : Type ) bool {
3696
+ return switch (ty .data ) {
3697
+ .either = > true ,
3698
+ .anytype_parameter = > true ,
3699
+ .optional = > | child_ty | child_ty .isConditional (),
3700
+ .pointer = > | info | info .elem_ty .isConditional (),
3701
+ .array = > | info | info .elem_ty .isConditional (),
3702
+ .tuple = > | types | {
3703
+ for (types ) | t |
3704
+ if (t .isConditional ()) return true ;
3705
+ return false ;
3706
+ },
3707
+ .container = > | info | {
3708
+ for (info .bound_params .values ()) | t |
3709
+ if (t .isConditional ()) return true ;
3710
+ return false ;
3711
+ },
3712
+ .error_union = > | info | {
3713
+ if (info .payload .isConditional ()) return true ;
3714
+ if (info .error_set ) | e |
3715
+ if (e .isConditional ()) return true ;
3716
+ return false ;
3717
+ },
3718
+ .function = > | info | {
3719
+ if (info .container_type .isConditional ()) return true ;
3720
+ if (info .return_value .isConditional ()) return true ;
3721
+ for (info .parameters ) | param |
3722
+ if (param .type .isConditional ()) return true ;
3723
+ return false ;
3724
+ },
3725
+ .union_tag ,
3726
+ .for_range ,
3727
+ .compile_error ,
3728
+ .type_parameter ,
3729
+ .ip_index ,
3730
+ = > false ,
3731
+ };
3732
+ }
3733
+
3734
+ // is infinite recursion possible here?
3692
3735
pub fn getAllTypesWithHandlesArraySet (ty : Type , analyser : * Analyser , all_types : * ArraySet ) ! void {
3693
3736
const arena = analyser .arena ;
3737
+ if (! ty .isConditional ()) {
3738
+ try all_types .put (arena , ty , {});
3739
+ return ;
3740
+ }
3694
3741
switch (ty .data ) {
3742
+ .union_tag ,
3743
+ .for_range ,
3744
+ .compile_error ,
3745
+ .type_parameter ,
3746
+ .ip_index ,
3747
+ = > unreachable ,
3695
3748
.either = > | entries | {
3696
3749
for (entries ) | entry | {
3697
3750
const entry_ty : Type = .{ .data = entry .type_data , .is_type_val = ty .is_type_val };
3698
3751
try entry_ty .getAllTypesWithHandlesArraySet (analyser , all_types );
3699
3752
}
3700
3753
},
3701
- else = > try all_types .put (arena , ty , {}),
3754
+ .anytype_parameter = > | info | {
3755
+ if (info .type_from_callsite_references ) | t | {
3756
+ try t .getAllTypesWithHandlesArraySet (analyser , all_types );
3757
+ } else {
3758
+ try all_types .put (arena , ty , {});
3759
+ }
3760
+ },
3761
+ .optional = > | child_ty | {
3762
+ for (try child_ty .getAllTypesWithHandles (analyser )) | t | {
3763
+ const new_child_ty = try analyser .allocType (t );
3764
+ try all_types .put (arena , .{ .data = .{ .optional = new_child_ty }, .is_type_val = ty .is_type_val }, {});
3765
+ }
3766
+ },
3767
+ inline .pointer , .array = > | info , tag | {
3768
+ for (try info .elem_ty .getAllTypesWithHandles (analyser )) | t | {
3769
+ var new_info = info ;
3770
+ new_info .elem_ty = try analyser .allocType (t );
3771
+ const data = @unionInit (Type .Data , @tagName (tag ), new_info );
3772
+ try all_types .put (arena , .{ .data = data , .is_type_val = ty .is_type_val }, {});
3773
+ }
3774
+ },
3775
+ .tuple = > | types | {
3776
+ var possible_types : ArrayMap ([]const Type ) = .empty ;
3777
+ for (types ) | t | {
3778
+ try possible_types .put (arena , t , try t .getAllTypesWithHandles (analyser ));
3779
+ }
3780
+ var iter : ComboIterator = try .init (arena , & possible_types );
3781
+ while (iter .next ()) | combo | {
3782
+ const new_types = try arena .alloc (Type , types .len );
3783
+ for (new_types , types ) | * new , old | new .* = combo .get (old ).? ;
3784
+ try all_types .put (arena , .{ .data = .{ .tuple = new_types }, .is_type_val = ty .is_type_val }, {});
3785
+ }
3786
+ },
3787
+ .container = > | info | {
3788
+ var possible_types : ArrayMap ([]const Type ) = .empty ;
3789
+ const types = info .bound_params .values ();
3790
+ for (types ) | t | {
3791
+ try possible_types .put (arena , t , try t .getAllTypesWithHandles (analyser ));
3792
+ }
3793
+ var iter : ComboIterator = try .init (arena , & possible_types );
3794
+ while (iter .next ()) | combo | {
3795
+ const new_types = try arena .alloc (Type , types .len );
3796
+ for (new_types , types ) | * new , old | new .* = combo .get (old ).? ;
3797
+ var new_info = info ;
3798
+ new_info .bound_params = try .init (arena , info .bound_params .keys (), new_types );
3799
+ try all_types .put (arena , .{ .data = .{ .container = new_info }, .is_type_val = ty .is_type_val }, {});
3800
+ }
3801
+ },
3802
+ .error_union = > | info | {
3803
+ var possible_types : ArrayMap ([]const Type ) = .empty ;
3804
+ try possible_types .put (arena , info .payload .* , try info .payload .getAllTypesWithHandles (analyser ));
3805
+ if (info .error_set ) | t | {
3806
+ try possible_types .put (arena , t .* , try t .getAllTypesWithHandles (analyser ));
3807
+ }
3808
+ var iter : ComboIterator = try .init (arena , & possible_types );
3809
+ while (iter .next ()) | combo | {
3810
+ var new_info = info ;
3811
+ new_info .payload = try analyser .allocType (combo .get (info .payload .* ).? );
3812
+ if (info .error_set ) | t | {
3813
+ new_info .error_set = try analyser .allocType (combo .get (t .* ).? );
3814
+ }
3815
+ try all_types .put (arena , .{ .data = .{ .error_union = new_info }, .is_type_val = ty .is_type_val }, {});
3816
+ }
3817
+ },
3818
+ .function = > | info | {
3819
+ var possible_types : ArrayMap ([]const Type ) = .empty ;
3820
+ try possible_types .put (arena , info .container_type .* , try info .container_type .getAllTypesWithHandles (analyser ));
3821
+ for (info .parameters ) | param | {
3822
+ try possible_types .put (arena , param .type , try param .type .getAllTypesWithHandles (analyser ));
3823
+ }
3824
+ if (info .return_value .is_type_val ) {
3825
+ try possible_types .put (arena , info .return_value .* , try info .return_value .getAllTypesWithHandles (analyser ));
3826
+ } else {
3827
+ const return_type = try info .return_value .typeOf (analyser );
3828
+ try possible_types .put (arena , return_type , try return_type .getAllTypesWithHandles (analyser ));
3829
+ }
3830
+ var iter : ComboIterator = try .init (arena , & possible_types );
3831
+ while (iter .next ()) | combo | {
3832
+ var new_info = info ;
3833
+ new_info .container_type = try analyser .allocType (combo .get (info .container_type .* ).? );
3834
+ new_info .parameters = try arena .alloc (Data .Parameter , info .parameters .len );
3835
+ @memcpy (new_info .parameters , info .parameters );
3836
+ for (new_info .parameters , info .parameters ) | * new , old | {
3837
+ new .type = combo .get (old .type ).? ;
3838
+ }
3839
+ if (info .return_value .is_type_val ) {
3840
+ new_info .return_value = try analyser .allocType (combo .get (info .return_value .* ).? );
3841
+ } else {
3842
+ const return_type = try info .return_value .typeOf (analyser );
3843
+ const return_value = try combo .get (return_type ).? .instanceTypeVal (analyser );
3844
+ new_info .return_value = try analyser .allocType (return_value .? );
3845
+ }
3846
+ try all_types .put (arena , .{ .data = .{ .function = new_info }, .is_type_val = ty .is_type_val }, {});
3847
+ }
3848
+ },
3702
3849
}
3703
3850
}
3704
3851
3852
+ const ComboIterator = struct {
3853
+ possible_types : * const ArrayMap ([]const Type ),
3854
+ current_combo : ArrayMap (Type ),
3855
+ total_combos : usize ,
3856
+ counter : usize ,
3857
+
3858
+ fn init (
3859
+ arena : std.mem.Allocator ,
3860
+ possible_types : * const ArrayMap ([]const Type ),
3861
+ ) ! ComboIterator {
3862
+ var current_combo : ArrayMap (Type ) = .empty ;
3863
+ try current_combo .entries .resize (arena , possible_types .count ());
3864
+ @memcpy (current_combo .keys (), possible_types .keys ());
3865
+ try current_combo .reIndex (arena );
3866
+
3867
+ var total_combos : usize = 1 ;
3868
+ for (possible_types .values ()) | types | {
3869
+ total_combos *= types .len ;
3870
+ }
3871
+
3872
+ return .{
3873
+ .possible_types = possible_types ,
3874
+ .current_combo = current_combo ,
3875
+ .total_combos = total_combos ,
3876
+ .counter = 0 ,
3877
+ };
3878
+ }
3879
+
3880
+ fn next (iter : * ComboIterator ) ? * const ArrayMap (Type ) {
3881
+ if (iter .counter == iter .total_combos ) return null ;
3882
+ var x = iter .counter ;
3883
+ for (iter .current_combo .values (), iter .possible_types .values ()) | * t , types | {
3884
+ t .* = types [x % types .len ];
3885
+ x /= types .len ;
3886
+ }
3887
+ iter .counter += 1 ;
3888
+ return & iter .current_combo ;
3889
+ }
3890
+ };
3891
+
3705
3892
pub fn instanceTypeVal (self : Type , analyser : * Analyser ) error {OutOfMemory }! ? Type {
3706
3893
if (! self .is_type_val ) return null ;
3707
3894
return switch (self .data ) {
@@ -4185,7 +4372,13 @@ pub const Type = struct {
4185
4372
});
4186
4373
},
4187
4374
.either = > try writer .writeAll ("either type" ), // TODO
4188
- .compile_error = > | node_handle | try writer .writeAll (offsets .nodeToSlice (node_handle .handle .tree , node_handle .node )),
4375
+ .compile_error = > | node_handle | {
4376
+ if (options .truncate_container_decls ) {
4377
+ try writer .writeAll ("@compileError(...)" );
4378
+ } else {
4379
+ try writer .writeAll (offsets .nodeToSlice (node_handle .handle .tree , node_handle .node ));
4380
+ }
4381
+ },
4189
4382
.type_parameter = > | token_handle | {
4190
4383
const token = token_handle .token ;
4191
4384
const handle = token_handle .handle ;
0 commit comments