New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
False positive TypeDoesNotContainType introduced recently (4.15 maybe) #7109
Comments
Hey @VincentLanglet, can you reproduce the issue on https://psalm.dev ? |
Psalm seem to reduce the class-string in the offset to a simple string, and then complains that the string is not a class-string. I'm not sure what could have triggered this in recent versions. Are you able to create a reproducer on psalm.dev? |
Like 2-3 days ago there was no error, so it's pretty recent.
There is no error in https://psalm.dev/r/e62634509f |
I found these snippets: https://psalm.dev/r/e62634509f<?php
/**
* @return array<class-string, array<array-key, string>>
*/
function getArray() {
return [];
}
function test(): bool {
$class = \stdClass::class;
/** @psalm-trace $a */
$a = [$class => ['sonata.user.admin.group1']];
/** @psalm-trace $b */
$b = getArray();
return $a === $b;
}
|
@orklah Changing the code to
solve the issue. so I don't know what's the weird interaction with |
Can be reproduced by https://psalm.dev/r/0482bc5bc7 Seems to be caused by #7076 @klimick mind taking a look? |
I found these snippets: https://psalm.dev/r/0482bc5bc7<?php
class A
{
function test(): void
{
$a = [stdClass::class => ''];
/** @var array<class-string, mixed> $b */
$b = [];
$this->assertSame($a, $b);
}
/**
* @template T
* @param T $expected
* @psalm-assert =T $actual
*/
public function assertSame(mixed $expected, mixed $actual): void
{
return;
}
}
|
Before #7076 next code was valid: class A
{
public function test(): void
{
// array{stdClass: ""}
$a = [stdClass::class => ''];
// array{Traversable: ""}
$b = [Traversable::class => ''];
$this->assertSame($a, $b);
}
/**
* @template T
*
* @param T $expected
* @param mixed $actual
* @psalm-assert =T $actual
*/
public function assertSame($expected, $actual): void
{
return;
}
} But is it really valid? Now Psalm tries to compare As I know @orklah what should we do? |
Oh, nice so this isn't an issue with the assertion system itself.
subtypes of those two works as well, for example, you can have So it seems like Psalm resolves |
Psalm already preserves info about For me, extending the parser seems like a bit of a challenge) |
It doesn't have to touch the parser part, if we accept the ambiguity of Wouldn't be the first time we do this either - e.g. there are a quite a few flags on |
Sorry. I don't understand how it can help. |
If the class-string is actually preserved in the TKeyedArray, then the fault must be in the comparison of the two types |
Before the actual type is compared, it will be serialized to a string with the
Information about
Why problem not with |
Oh, yeah, you're right, I missed the fact that it was serialized here. I'd go for changing the way we display class-strings in keyed array then. One of those two syntaxes: https://psalm.dev/r/f780ccaa84 |
I found these snippets: https://psalm.dev/r/f780ccaa84<?php
class A
{
function test(): void
{
/** @var array{stdClass::class: mixed} $a */
$a = [];
/** @var array{class-string<stdClass>: mixed} $a */
$a = [];
/** @var array<class-string, mixed> $b */
$b = [];
$this->assertSame($a, $b);
}
/**
* @template T
* @param T $expected
* @psalm-assert =T $actual
*/
public function assertSame(mixed $expected, mixed $actual): void
{
return;
}
}
|
It would be interesting to explore what it would take to avoid type -> text -> type roundtrip though. |
Yeah, I thought about that too, but going full |
Re proposed syntax options: both are used in Psalm type system, so they not necessarily alternatives: https://psalm.dev/r/6e690bd75f |
I found these snippets: https://psalm.dev/r/6e690bd75f<?php
/** @param stdClass::class $_c */
function a(string $_c): void {}
/** @param class-string<stdClass> $_c */
function b(string $_c): void {}
class z extends stdClass {}
a(stdClass::class);
a(z::class);
// c.f.
b(stdClass::class);
b(z::class); // ok for class-string<stdClass>, but not for stdClass::class
|
So for keyed array, where key names have to be known, |
yeah, you're right, EDIT: no, I'm actually wrong on that, I mistook this for something else |
It's |
I'm not sure to understand. Is there a "quick" solution or should #7076 be reverted ? It's better to have false negative like #7109 (comment) than having false positive. |
I tried to look at it yesterday, it seems the class-string doesn't make it to the TKeyedArray. I'll have to check what can be done about that. Ideally, I'd like to avoid reverting because the change is legit. We'll try to get it fixed for the next release, in the meantime, feel free to go back to the previous version |
Ok, the class-string do make it to the TKeyedArray, I was not expecting it to be stored like that. I'm able to change the output, I'm now trying to check the parser |
An example can be found with this PR: sonata-project/SonataAdminBundle#7643
Code like
is reported
But to me
array<class-string, array<array-key, string>>
containsarray{stdClass: array{"sonata.user.admin.group1"}}
.The text was updated successfully, but these errors were encountered: