vimeo/psalm

Merging of objects with defined properties should yield objects with union of properties

Open

#2,115 opened on Sep 10, 2019

View on GitHub
 (3 comments) (0 reactions) (1 assignee)PHP (668 forks)batch import
Help wantedenhancement

Repository metrics

Stars
 (5,369 stars)
PR merge metrics
 (Avg merge 3d 12h) (5 merged PRs in 30d)

Description

Similar to https://github.com/vimeo/psalm/issues/2105 (declined), so I'm throwing this here for evaluation.

It seems like there's an issue with merging two objects in a declaration like object{foo: string}&object{bar: string}:

<?php

/** @psalm-return object{field1: string}&object{field2: string} */
function combine(object $a, object $b) : object
{
    return (object) \array_merge((array) $a, (array) $b);
}

$a = new \stdClass;
$a->field1 = 'a';

$b = new \stdClass;
$b->field2 = 'b';

echo combine($a, $b)->field1;

This reports (https://psalm.dev/r/a0a96475ab):

Psalm output (using commit deb36e8):

INFO: MixedArgument - 15:6 - Argument 1 of echo cannot be mixed, expecting string

If instead of accessing field1 I do access field2, then no errors occur (https://psalm.dev/r/e01ed36829). Maybe only the second declaration in the intersection is taken into account?

Similarly to the above, using generic types A and B and an intersection of A&B leads to inferring mixed (https://psalm.dev/r/76313da9d0):

<?php

/**
 * @psalm-template A of object
 * @psalm-template B of object
 * @psalm-param A $a
 * @psalm-param B $b
 * @psalm-return A&B
 */
function combine(object $a, object $b) : object
{
    return (object) \array_merge((array) $a, (array) $b);
}

$a = new \stdClass;
$a->field1 = 'a';

$b = new \stdClass;
$b->field2 = 'b';

echo combine($a, $b)->field2;
Psalm output (using commit deb36e8):

INFO: MixedArgument - 21:6 - Argument 1 of echo cannot be mixed, expecting string

Contributor guide