Skip to content
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

User defined assertions works incorrectly for generic iterable types #5294

Closed
klimick opened this issue Feb 27, 2021 · 6 comments · Fixed by #7076
Closed

User defined assertions works incorrectly for generic iterable types #5294

klimick opened this issue Feb 27, 2021 · 6 comments · Fixed by #7076
Labels

Comments

@klimick
Copy link
Contributor

klimick commented Feb 27, 2021

Lets take a look at this https://psalm.dev/r/12ed2787e9
or this https://psalm.dev/r/a4ab076a44
example.

Works fine. As expected.

But if go deeper and try to assert generic type like list<int> then psalm lose types:

psalm-assert-if-true: https://psalm.dev/r/58dbc19d8a
psalm-assert: https://psalm.dev/r/4c25ed702c

@psalm-github-bot
Copy link

I found these snippets:

https://psalm.dev/r/12ed2787e9
<?php

/**
 * @template A
 */
final class Type {}

/**
 * @template T
 *
 * @param Type<T> $t
 * @psalm-assert-if-true T $toCheck
 */
function isTypeOf(Type $t, mixed $toCheck): bool
{
    throw new RuntimeException('???');
}

/** @var Type<int> $numberT */
$numberT = null;

/** @var mixed $mixed */
$mixed = null;

if (isTypeOf($numberT, $mixed)) {
    /** @psalm-trace $number */
	$number = $mixed; // is int. awesome.
}
Psalm output (using commit 44f8d71):

INFO: Trace - 27:2 - $number: int
https://psalm.dev/r/a4ab076a44
<?php

/**
 * @template A
 */
final class Type {}

/**
 * @template T
 *
 * @param Type<T> $t
 * @psalm-assert T $toCheck
 */
function assertTypeOf(Type $t, mixed $toCheck): void
{
    throw new RuntimeException('???');
}

/** @var Type<int> $numberT */
$numberT = null;

/** @var mixed $mixed */
$mixed = null;

assertTypeOf($numberT, $mixed);

/** @psalm-trace $number */
$number = $mixed; // is int. awesome.
Psalm output (using commit 44f8d71):

INFO: Trace - 28:1 - $number: int
https://psalm.dev/r/58dbc19d8a
<?php

/**
 * @template A
 */
final class Type {}

/**
 * @template T
 *
 * @param Type<T> $t
 * @psalm-assert-if-true T $toCheck
 */
function isTypeOf(Type $t, mixed $toCheck): bool
{
    throw new RuntimeException('???');
}

/** @var Type<list<int>> $numbersT */
$numbersT = null;

/** @var mixed $mixed */
$mixed = null;

if (isTypeOf($numbersT, $mixed)) {
    /** @psalm-trace $numbers */
	$numbers = $mixed; // is array<array-key, mixed>. but should be list<int>.
}
Psalm output (using commit 44f8d71):

INFO: Trace - 27:2 - $numbers: array<array-key, mixed>
https://psalm.dev/r/4c25ed702c
<?php

/**
 * @template A
 */
final class Type {}

/**
 * @template T
 *
 * @param Type<T> $t
 * @psalm-assert T $toCheck
 */
function assertTypeOf(Type $t, mixed $toCheck): void
{
    throw new RuntimeException('???');
}

/** @var Type<list<int>> $numbersT */
$numbersT = null;

/** @var mixed $mixed */
$mixed = null;

assertTypeOf($numbersT, $mixed);

/** @psalm-trace $numbers */
$numbers = $mixed; // is mixed. Not even array<array-key, int>.
Psalm output (using commit 44f8d71):

INFO: MixedAssignment - 28:1 - Unable to determine the type that $numbers is being assigned to

INFO: Trace - 28:1 - $numbers: mixed

@weirdan weirdan added the bug label Feb 27, 2021
@klimick
Copy link
Contributor Author

klimick commented Mar 2, 2021

Hmmmmm.

This example https://psalm.dev/r/205e1d64ea contains generic assertion too. But it is working.

It seems issue only with iterable type.

@psalm-github-bot
Copy link

I found these snippets:

https://psalm.dev/r/205e1d64ea
<?php

/**
 * @template A
 */
final class Type {}

/**
 * @template T
 *
 * @param Type<T> $t
 * @psalm-assert-if-true T $toCheck
 */
function isTypeOf(Type $t, mixed $toCheck): bool
{
    throw new RuntimeException('???');
}

/**
 * @template T
 */
final class Foo {}

/** @var Type<Foo<int>> $fooT */
$fooT = null;

/** @var mixed $mixed */
$mixed = null;

if (isTypeOf($fooT, $mixed)) {
    /** @psalm-trace $number */
	$number = $mixed; // is int. awesome.
}
Psalm output (using commit 594ef4f):

INFO: Trace - 32:2 - $number: Foo<int>

@klimick klimick changed the title User defined assertions works incorrectly for generic types User defined assertions works incorrectly for generic iterable types Mar 2, 2021
@weirdan
Copy link
Collaborator

weirdan commented Mar 2, 2021

Then it's possibly related to #5310

@klimick
Copy link
Contributor Author

klimick commented May 21, 2021

Seems a problem at this place:

$rule_token[0] = $first_type->getKey();

getKey returns list instead of list<T>

Can we change it to getId? @weirdan

@orklah
Copy link
Collaborator

orklah commented Oct 24, 2021

@klimick please try it in a PR, we'll see how CI reacts :)

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Projects
None yet
Development

Successfully merging a pull request may close this issue.

3 participants