66use TypePHP \Tests \Fixtures \Generics \GenericCollection ;
77
88/**
9- * 1. Function accepting a list of lazy callables
9+ * Function accepting a list of lazy callables
1010 *
1111 * @param list<callable(positive-int): non-empty-string> $formatters
1212 */
@@ -20,14 +20,27 @@ function processFormatterList(array $formatters, int $id): array
2020 return $ results ;
2121}
2222
23+ /**
24+ * Multi-Branch Nested Conditional Return Type
25+ *
26+ * @param string $format
27+ * @param mixed $value
28+ *
29+ * @return ($format is 'int' ? positive-int : ($format is 'float' ? positive-float : non-empty-string))
30+ */
31+ function testNestedConditionalReturn (string $ format , mixed $ value ): mixed
32+ {
33+ return $ value ;
34+ }
35+
2336describe ('Advanced Edge-Case Behaviors ' , function () {
2437 describe ('Skipped and Deeply Nested Array Destructuring with @var ' , function () {
2538 test ('validates variables when skipping elements with empty commas in destructuring ' , function () {
2639 /**
2740 * @var positive-int $id
2841 * @var non-empty-string $username
2942 */
30- [$ id , , $ username ] = [10 , 'skipped_token ' , 'Alice ' ];
43+ [$ id ,, $ username ] = [10 , 'skipped_token ' , 'Alice ' ];
3144
3245 expect ($ id )->toBe (10 )
3346 ->and ($ username )->toBe ('Alice ' )
@@ -38,7 +51,7 @@ function processFormatterList(array $formatters, int $id): array
3851 * @var positive-int $id
3952 * @var non-empty-string $username
4053 */
41- [$ id , , $ username ] = [-5 , 'skipped_token ' , 'Alice ' ];
54+ [$ id ,, $ username ] = [-5 , 'skipped_token ' , 'Alice ' ];
4255 })->toThrow (TypeError::class, 'Variable $id must be of type positive-int ' );
4356 });
4457
@@ -84,17 +97,16 @@ function processFormatterList(array $formatters, int $id): array
8497 /** @var GenericCollection<?positive-int> $collection */
8598 $ collection = new GenericCollection ();
8699
87- expect (fn () => $ collection ->add (-50 ))
88- ->toThrow (TypeError::class, 'Argument $item (template T = ?positive-int) must be of type positive-int, negative int (-50) given ' )
89- ;
100+ expect (fn () => $ collection ->add (-50 ))
101+ ->toThrow (TypeError::class, 'Argument $item (template T = ?positive-int) must be of type positive-int, negative int (-50) given ' );
90102 });
91103 });
92104
93105 describe ('Collections of Lazy Callables ' , function () {
94106 test ('executes and validates a list of lazy callable proxies ' , function () {
95107 $ formatters = [
96- fn (int $ id ): string => "id_ {$ id }" ,
97- fn (int $ id ): string => "user# {$ id }" ,
108+ fn (int $ id ): string => "id_ {$ id }" ,
109+ fn (int $ id ): string => "user# {$ id }" ,
98110 ];
99111
100112 $ results = processFormatterList ($ formatters , 42 );
@@ -103,13 +115,28 @@ function processFormatterList(array $formatters, int $id): array
103115
104116 test ('throws TypeError when a callable in the collection returns an invalid type ' , function () {
105117 $ formatters = [
106- fn (int $ id ): string => "id_ {$ id }" ,
107- fn (int $ id ): string => '' ,
118+ fn (int $ id ): string => "id_ {$ id }" ,
119+ fn (int $ id ): string => '' ,
108120 ];
109121
110- expect (fn () => processFormatterList ($ formatters , 42 ))
111- ->toThrow (TypeError::class, 'Callback $formatters[1] return value must be of type non-empty-string ' )
112- ;
122+ expect (fn () => processFormatterList ($ formatters , 42 ))
123+ ->toThrow (TypeError::class, 'Callback $formatters[1] return value must be of type non-empty-string ' );
124+ });
125+ });
126+
127+ describe ('Multi-Branch Nested Conditional Return Types ' , function () {
128+ test ('throws TypeError when return value violates nested conditional branch ' , function () {
129+ expect (fn () => testNestedConditionalReturn ('float ' , -5.5 ))
130+ ->toThrow (TypeError::class, 'Return value must be of type positive-float ' );
131+ });
132+ });
133+
134+ describe ('Trait Method Aliasing (use Trait { old as new; }) ' , function () {
135+ test ('inherits DocBlock contracts when a Trait method is aliased in a class ' , function () {
136+ $ service = new TypePHP \Tests \Fixtures \Services \ClassUsingAliasedTraitMethod ();
137+
138+ expect (fn () => $ service ->recordAuditLog (-1 , 'audit_ok ' ))
139+ ->toThrow (TypeError::class, 'Argument $level must be of type positive-int ' );
113140 });
114141 });
115142});
0 commit comments