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

Feature: use return type providers for inferred return types #8721

Open
kkmuffme opened this issue Nov 19, 2022 · 12 comments
Open

Feature: use return type providers for inferred return types #8721

kkmuffme opened this issue Nov 19, 2022 · 12 comments

Comments

@kkmuffme
Copy link
Contributor

https://psalm.dev/r/90304e4579

Ideally psalm would correctly infer that $first and $second are identical

@psalm-github-bot
Copy link

I found these snippets:

https://psalm.dev/r/90304e4579
<?php

/**
 * @param array $a
 * @param array $b
 * @return array
 */
function foo( $a, $b ) {
    $tmp = array_merge( $a, $b );
    /** @psalm-trace $tmp */;
    return $tmp;
}

$y = array( 'foo' => 'bar' );
$z = array( 'hello' => 'world' );

$first = array_merge( $y, $z );
/** @psalm-trace $first */;

$second = foo( $y, $z );
/** @psalm-trace $second */;
Psalm output (using commit 4e17585):

INFO: Trace - 10:29 - $tmp: array<array-key, mixed>

INFO: Trace - 18:27 - $first: array{foo: 'bar', hello: 'world'}

INFO: Trace - 21:28 - $second: array<array-key, mixed>

@danog
Copy link
Collaborator

danog commented Nov 19, 2022

A long-time todo of mine, would really help in legacy codebases especially.

@kkmuffme
Copy link
Contributor Author

Yes, but not only there, since the A&B annotation only works for object-like arrays, so documenting functions that merge 2 arrays with additional custom logic is currently impossible

@danog
Copy link
Collaborator

danog commented Nov 19, 2022

This would be a separate issue regarding template support for intersection of keyed arrays (#7600 is somewhat related), though it might be tricky to implement properly for usecases other than the simple "enhance" example mentioned in #7600 due to the different semantics of array_merge and array_replace.

@danog
Copy link
Collaborator

danog commented Nov 19, 2022

I've been planning to implement something really cool to infer literal types: automatic inlining of functions and full literal type inferring for pure native functions (I actually already submitted a PR once for this last feature #5723, might be worth to re-submit a slightly tweaked version...)

@weirdan
Copy link
Collaborator

weirdan commented Nov 19, 2022

Meanwhile you can do this: https://psalm.dev/r/662034762d

@psalm-github-bot
Copy link

I found these snippets:

https://psalm.dev/r/662034762d
<?php

/**
 * @template TK1 of array-key
 * @template TV1 of mixed
 * @template TK2 of array-key
 * @template TV2 of mixed
 * @param array<TK1,TV1> $a
 * @param array<TK2,TV2> $b
 * @return array<TK1|TK2,TV1|TV2>
 */
function foo( $a, $b ) {
    $tmp = array_merge( $a, $b );
    /** @psalm-trace $tmp */;
    return $tmp;
}

$y = array( 'foo' => 'bar' );
$z = array( 'hello' => 'world' );

$first = array_merge( $y, $z );
/** @psalm-trace $first */;

$second = foo( $y, $z );
/** @psalm-trace $second */;
Psalm output (using commit 6d03c32):

INFO: Trace - 14:29 - $tmp: array<(TK1:fn-foo as array-key)|(TK2:fn-foo as array-key), (TV1:fn-foo as mixed)|(TV2:fn-foo as mixed)>

INFO: Trace - 22:27 - $first: array{foo: 'bar', hello: 'world'}

INFO: Trace - 25:28 - $second: array<'foo'|'hello', 'bar'|'world'>

@kkmuffme
Copy link
Contributor Author

@weirdan this doesn't work correctly if you have arrays with partially identical keys: https://psalm.dev/r/b1dd74bbf1

$second: array<'foo'|'hello', 'bar'|'world'>

is wrong, bc it should be (like $first correctly shows)

$second: array<'foo'|'hello', 'bar'>

@psalm-github-bot
Copy link

I found these snippets:

https://psalm.dev/r/b1dd74bbf1
<?php

/**
 * @template TK1 of array-key
 * @template TV1 of mixed
 * @template TK2 of array-key
 * @template TV2 of mixed
 * @param array<TK1,TV1> $a
 * @param array<TK2,TV2> $b
 * @return array<TK1|TK2,TV1|TV2>
 */
function foo( $a, $b ) {
    $tmp = array_merge( $a, $b );
    /** @psalm-trace $tmp */;
    return $tmp;
}

$y = array( 'foo' => 'bar', 'hello' => 'world' );
$z = array( 'hello' => 'bar' );

$first = array_merge( $y, $z );
/** @psalm-trace $first */;

$second = foo( $y, $z );
/** @psalm-trace $second */;
Psalm output (using commit 7869cb5):

INFO: Trace - 14:29 - $tmp: array<(TK1:fn-foo as array-key)|(TK2:fn-foo as array-key), (TV1:fn-foo as mixed)|(TV2:fn-foo as mixed)>

INFO: Trace - 22:27 - $first: array{foo: 'bar', hello: 'bar'}

INFO: Trace - 25:28 - $second: array<'foo'|'hello', 'bar'|'world'>

@weirdan
Copy link
Collaborator

weirdan commented Nov 21, 2022

The type is not wrong per se, but it's not as tight as it potentially could be. And key-value correspondence is lost too.

@kkmuffme
Copy link
Contributor Author

Not really, bc the value can never be hello in this 2nd example https://psalm.dev/r/b1dd74bbf1

@psalm-github-bot
Copy link

I found these snippets:

https://psalm.dev/r/b1dd74bbf1
<?php

/**
 * @template TK1 of array-key
 * @template TV1 of mixed
 * @template TK2 of array-key
 * @template TV2 of mixed
 * @param array<TK1,TV1> $a
 * @param array<TK2,TV2> $b
 * @return array<TK1|TK2,TV1|TV2>
 */
function foo( $a, $b ) {
    $tmp = array_merge( $a, $b );
    /** @psalm-trace $tmp */;
    return $tmp;
}

$y = array( 'foo' => 'bar', 'hello' => 'world' );
$z = array( 'hello' => 'bar' );

$first = array_merge( $y, $z );
/** @psalm-trace $first */;

$second = foo( $y, $z );
/** @psalm-trace $second */;
Psalm output (using commit 7869cb5):

INFO: Trace - 14:29 - $tmp: array<(TK1:fn-foo as array-key)|(TK2:fn-foo as array-key), (TV1:fn-foo as mixed)|(TV2:fn-foo as mixed)>

INFO: Trace - 22:27 - $first: array{foo: 'bar', hello: 'bar'}

INFO: Trace - 25:28 - $second: array<'foo'|'hello', 'bar'|'world'>

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

No branches or pull requests

3 participants