Skip to content

Commit 6af52b3

Browse files
committed
fix(stubs): narrow Collection::sum() no-arg return type by TValue #678
Collection<_, int>::sum() now returns int instead of int|float, matching Psalm's array_sum behavior for typed arrays.
1 parent 6507ab0 commit 6af52b3

3 files changed

Lines changed: 40 additions & 3 deletions

File tree

stubs/common/Support/Collection.stubphp

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -203,10 +203,18 @@ class Collection implements ArrayAccess, CanBeEscapedWhenCastToString, Enumerabl
203203
* At runtime, the accumulator starts at 0 and uses the + operator,
204204
* so the result is always int|float (non-numeric values throw TypeError).
205205
*
206+
* When called without arguments, the return type narrows based on TValue:
207+
* - Collection<_, int>::sum() → int (matches array_sum behavior for int arrays)
208+
* - Collection<_, float>::sum() → float
209+
* - Otherwise → int|float
210+
*
206211
* @template TCallbackReturn of int|float
207212
*
208213
* @param (callable(TValue, TKey): TCallbackReturn)|string|null $callback
209-
* @return ($callback is string|null ? int|float : TCallbackReturn)
214+
* @return ($callback is null
215+
* ? (TValue is int ? int : (TValue is float ? float : int|float))
216+
* : ($callback is string ? int|float : TCallbackReturn)
217+
* )
210218
*/
211219
public function sum($callback = null) {}
212220
}

stubs/common/Support/Enumerable.stubphp

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -17,10 +17,15 @@ interface Enumerable extends \Illuminate\Contracts\Support\Arrayable, \Countable
1717
* At runtime, the accumulator starts at 0 and uses the + operator,
1818
* so the result is always int|float (non-numeric values throw TypeError).
1919
*
20+
* When called without arguments, the return type narrows based on TValue:
21+
* - Collection<_, int>::sum() → int (matches array_sum behavior for int arrays)
22+
* - Collection<_, float>::sum() → float
23+
* - Otherwise → int|float
24+
*
2025
* @template TCallbackReturn of int|float
2126
*
2227
* @param (callable(TValue, TKey): TCallbackReturn)|string|null $callback
23-
* @return ($callback is string|null ? int|float : TCallbackReturn)
28+
* @return ($callback is null ? (TValue is int ? int : (TValue is float ? float : int|float)) : ($callback is string ? int|float : TCallbackReturn))
2429
*/
2530
public function sum($callback = null);
2631
}

tests/Type/tests/CollectionMethodsTest.phpt

Lines changed: 25 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -211,11 +211,35 @@ final class CollectionTypes
211211
}
212212

213213
/** @see https://github.com/psalm/psalm-plugin-laravel/issues/678 */
214-
public function sumWithoutArguments(): int|float
214+
public function sumWithoutArguments(): int
215215
{
216216
/** @var Collection<int, int> */
217217
$numbers = new Collection();
218218

219+
/** @psalm-check-type-exact $sum = int */
220+
$sum = $numbers->sum();
221+
222+
return $sum;
223+
}
224+
225+
/** @see https://github.com/psalm/psalm-plugin-laravel/issues/678 */
226+
public function sumWithoutArgumentsFloat(): float
227+
{
228+
/** @var Collection<int, float> */
229+
$numbers = new Collection();
230+
231+
/** @psalm-check-type-exact $sum = float */
232+
$sum = $numbers->sum();
233+
234+
return $sum;
235+
}
236+
237+
/** @see https://github.com/psalm/psalm-plugin-laravel/issues/678 */
238+
public function sumWithoutArgumentsMixed(): int|float
239+
{
240+
/** @var Collection<int, int|float> */
241+
$numbers = new Collection();
242+
219243
/** @psalm-check-type-exact $sum = float|int */
220244
$sum = $numbers->sum();
221245

0 commit comments

Comments
 (0)