@@ -1751,7 +1751,7 @@ fn resolveCallsiteReferences(analyser: *Analyser, decl_handle: DeclWithHandle) !
17511751
17521752 if (real_param_idx >= call .ast .params .len ) continue ;
17531753
1754- const ty = resolve_ty : {
1754+ var ty = resolve_ty : {
17551755 // don't resolve callsite references while resolving callsite references
17561756 const old_collect_callsite_references = analyser .collect_callsite_references ;
17571757 defer analyser .collect_callsite_references = old_collect_callsite_references ;
@@ -1767,6 +1767,9 @@ fn resolveCallsiteReferences(analyser: *Analyser, decl_handle: DeclWithHandle) !
17671767 )) orelse continue ;
17681768 };
17691769
1770+ ty = try ty .typeOf (analyser );
1771+ std .debug .assert (ty .is_type_val );
1772+
17701773 const loc = offsets .tokenToPosition (tree , tree .nodeMainToken (call .ast .params [real_param_idx ]), .@"utf-8" );
17711774 try possible .append (analyser .arena , .{
17721775 .type = ty ,
@@ -3681,27 +3684,211 @@ pub const Type = struct {
36813684 };
36823685 }
36833686
3684- /// Resolves possible types of a type (single for all except either)
3687+ /// Resolves all possible types by recursively expanding any conditional types.
36853688 /// Drops duplicates
36863689 pub fn getAllTypesWithHandles (ty : Type , analyser : * Analyser ) error {OutOfMemory }! []const Type {
36873690 var all_types : ArraySet = .empty ;
36883691 try ty .getAllTypesWithHandlesArraySet (analyser , & all_types );
36893692 return all_types .keys ();
36903693 }
36913694
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?
36923735 pub fn getAllTypesWithHandlesArraySet (ty : Type , analyser : * Analyser , all_types : * ArraySet ) ! void {
36933736 const arena = analyser .arena ;
3737+ if (! ty .isConditional ()) {
3738+ try all_types .put (arena , ty , {});
3739+ return ;
3740+ }
36943741 switch (ty .data ) {
3742+ .union_tag ,
3743+ .for_range ,
3744+ .compile_error ,
3745+ .type_parameter ,
3746+ .ip_index ,
3747+ = > unreachable ,
36953748 .either = > | entries | {
36963749 for (entries ) | entry | {
36973750 const entry_ty : Type = .{ .data = entry .type_data , .is_type_val = ty .is_type_val };
36983751 try entry_ty .getAllTypesWithHandlesArraySet (analyser , all_types );
36993752 }
37003753 },
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+ },
37023849 }
37033850 }
37043851
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+
37053892 pub fn instanceTypeVal (self : Type , analyser : * Analyser ) error {OutOfMemory }! ? Type {
37063893 if (! self .is_type_val ) return null ;
37073894 return switch (self .data ) {
@@ -4185,7 +4372,13 @@ pub const Type = struct {
41854372 });
41864373 },
41874374 .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+ },
41894382 .type_parameter = > | token_handle | {
41904383 const token = token_handle .token ;
41914384 const handle = token_handle .handle ;
0 commit comments