psalm icon indicating copy to clipboard operation
psalm copied to clipboard

Object union not setting possibly undefined properties.

Open rzvc opened this issue 2 years ago • 6 comments

Object unions behave exactly the same as object intersections. Array unions work fine.

https://psalm.dev/r/7ff2a0f6a3

rzvc avatar Jun 11 '22 15:06 rzvc

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}

psalm-github-bot[bot] avatar Jun 11 '22 15:06 psalm-github-bot[bot]

@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.

SCIF avatar Sep 12 '22 06:09 SCIF

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}

psalm-github-bot[bot] avatar Sep 12 '22 06:09 psalm-github-bot[bot]

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

AndrolGenhald avatar Sep 12 '22 15:09 AndrolGenhald

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}

psalm-github-bot[bot] avatar Sep 12 '22 15:09 psalm-github-bot[bot]

@AndrolGenhald , thanks for correcting me, yes, I meant exactly unions :)

SCIF avatar Sep 12 '22 19:09 SCIF