psalm
psalm copied to clipboard
Object union not setting possibly undefined properties.
Object unions behave exactly the same as object intersections. Array unions work fine.
https://psalm.dev/r/7ff2a0f6a3
I found these snippets:
https://psalm.dev/r/7ff2a0f6a3
<?php
/**
* @psalm-type FooA = array{a: string}
* @psalm-type BarA = array{a: string, b: int}
* @psalm-type FooO = object{a: string}
* @psalm-type BarO = object{a: string, b: int}
*/
/**
* @var FooA|BarA $arr
* @psalm-trace $arr
*/
print_r($arr);
/**
* @var FooA&BarA $arr
* @psalm-trace $arr
*/
print_r($arr);
/**
* !!! Here I expect object{a: string, b?: int}. Instead we get object{a:string, b:int}.
* @var FooO|BarO $obj
* @psalm-trace $obj
*/
print_r($obj);
/**
* @var FooO&BarO $obj
* @psalm-trace $obj
*/
print_r($obj);
Psalm output (using commit a9775c6):
INFO: Trace - 14:1 - $arr: array{a: string, b?: int}
INFO: Trace - 21:1 - $arr: array{a: string, b: int}
INFO: Trace - 28:1 - $obj: object{a:string, b:int}
ERROR: UnnecessaryVarAnnotation - 31:8 - The @var object{a:string, b:int} annotation for $obj is unnecessary
INFO: Trace - 34:1 - $obj: object{a:string, b:int}
@orklah , @rzvc , I assume the real issue here is «not working» intersection for objects. Consult https://psalm.dev/r/5fc421461b @orklah , please advise if I'm wrong.
I found these snippets:
https://psalm.dev/r/5fc421461b
<?php
/**
* @param object{val: int} $o
**/
function objectValPrint(object $o): void
{
echo $o->val;
}
/** @return \DateTime|object{val: int}|B */
function getData(): object {
return new \stdClass;
};
$d = getData();
/** @psalm-trace $d */;
objectValPrint($d);
/** @psalm-trace $d */;
Psalm output (using commit afe85fa):
INFO: Trace - 15:23 - $d: object{val:int}
INFO: Trace - 17:23 - $d: object{val:int}
I assume the real issue here is «not working» intersection for objects.
If you actually mean that unions aren't working for objects in some cases, then yes, that does seem to be the problem. Indeed, flipping the union around on the third trace from the OP causes the type to change: https://psalm.dev/r/bb16ad2be1
I found these snippets:
https://psalm.dev/r/bb16ad2be1
<?php
/**
* @psalm-type FooA = array{a: string}
* @psalm-type BarA = array{a: string, b: int}
* @psalm-type FooO = object{a: string}
* @psalm-type BarO = object{a: string, b: int}
*/
/**
* @var FooA|BarA $arr
* @psalm-trace $arr
*/
print_r($arr);
/**
* @var FooA&BarA $arr
* @psalm-trace $arr
*/
print_r($arr);
/**
* !!! Here I expect object{a: string, b?: int}. Instead we get object{a:string, b:int}.
* @var BarO|FooO $obj
* @psalm-trace $obj
*/
print_r($obj);
/**
* @var FooO&BarO $obj
* @psalm-trace $obj
*/
print_r($obj);
Psalm output (using commit afe85fa):
INFO: Trace - 14:1 - $arr: array{a: string, b?: int}
INFO: Trace - 21:1 - $arr: array{a: string, b: int}
INFO: Trace - 28:1 - $obj: object{a:string}
INFO: Trace - 34:1 - $obj: object{a:string, b:int}
@AndrolGenhald , thanks for correcting me, yes, I meant exactly unions :)