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

[3.x] Add template annotations #188

Closed
wants to merge 1 commit into from
Closed

Conversation

simPod
Copy link

@simPod simPod commented Mar 15, 2021

I was considering adapting this lib for promises though it's currently impossible to be type-safe with it.

I found this psalm plugin https://github.com/Bocmah/psalm-reactphp-promise-plugin that only includes stubs for psalm. So I was thinking it can be simply ported into this promise lib so it's also supported by phpstan and by any static analysis overall without need for any additional setup.

Copy link
Member

@clue clue left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@simPod Thanks for bringing this up!

I think this feature makes perfect sense, but I'd like to make sure this is complete before merging this.

In particular, can you add some automated tests to verify this works as expected?

On top of this, phpstan also supports generics, does it make sense to address this as part of the PR?

@simPod
Copy link
Author

simPod commented Apr 5, 2021

@clue thanks for input. I'll look into how to test this.

Also note this is only partial implementation (for happy path) as both psalm and phpstan do not support default template types yet (it's impossible to resolve template to a type when null is passed).

This is resolving onFulfilled's type but not onRejected's one. I thought it might be a good start anyway to support at least one side for now. Or we keep it here and build up as the support emerges.

Crosslinks:
vimeo/psalm#5407
phpstan/phpstan#4801

On top of this, phpstan also supports generics, does it make sense to address this as part of the PR?

phpstan reads @psalm- annotations so this should be addressed if you meant this.
(personally, I don't use prefixes at all in my code but as I ported the initial implementation from psalm plugin, I kept them)

@@ -44,7 +48,7 @@ public function then(?callable $onFulfilled = null, ?callable $onRejected = null
* Since the purpose of `done()` is consumption rather than transformation,
* `done()` always returns `null`.
*
* @param callable|null $onFulfilled
* @param callable(mixed):TResolve|null $onFulfilled
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'd think this should be TResolved, but it's not defined on this method so I don't think that would work? Not sure what this is supposed to do here.

@simPod
Copy link
Author

simPod commented Jan 4, 2022

I'll wait for default promise value support in SA since it's fairly useless without it

@simPod simPod marked this pull request as draft January 4, 2022 15:50
@SimonFrings
Copy link
Member

@simPod thanks for your work on this so far 👍

To keep you updated:
@WyriHaximus, @clue and I are currently looking into this, we'll have a call later this day to discuss the details. There's also a discussion in pslam with more information on this: #7559.

@simPod
Copy link
Author

simPod commented Feb 7, 2022

Thank you for update and pushing it forward!

@WyriHaximus
Copy link
Member

One major thing for me was to tackle the bigger picture, so not just this promise package. But also async and await and observables plus await with observables and get it right as a whole.

@WyriHaximus
Copy link
Member

WyriHaximus commented Mar 25, 2022

@simPod Just a heads up: I'm going to make a bunch of suggested changes based on https://psalm.dev/r/22a9692a97 later today. But want thank you for your work so far on this and for pushing it forward so far 👍

Copy link
Member

@WyriHaximus WyriHaximus left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

When making the suggestions, I realized I forgot about the other methods, will update vimeo/psalm#7559 and this PR's suggestions soon

src/PromiseInterface.php Outdated Show resolved Hide resolved
src/PromiseInterface.php Outdated Show resolved Hide resolved
src/PromisorInterface.php Outdated Show resolved Hide resolved
@WyriHaximus WyriHaximus changed the title Add template annotations [3.x] Add template annotations May 19, 2022
@WyriHaximus
Copy link
Member

FYI just put up #223 as a draft for the 2.x branch so I can pull it in through composer and test it out again in a project without having to manually edit files again. Will try to get back shortly and hope live doesn't get in between again

Comment on lines +6 to +7
* @psalm-template T
* @psalm-template R
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Any reason this can not just use @template?

@WyriHaximus
Copy link
Member

FYI just filed #227 and #228 those will not have any direct affect on this PR as it's for the upcoming v3 release. We want basic support out there and then work on getting near to a 100% support out there through this PR and PR's for 1.x and 2.x.

@WyriHaximus
Copy link
Member

@simPod Hey if you don't mind I'm going to use your commit as a base to get template annotations + some additional type insurance in.

@simPod
Copy link
Author

simPod commented Jun 23, 2023 via email

WyriHaximus pushed a commit to WyriHaximus-secret-labs/promise that referenced this pull request Jun 28, 2023
Adds template annotations turning the `PromiseInterface` into a generic.

Variables `$p1` and `$p2` in the following code example both are `PromiseInterface<int|string>`.

```php
$f = function (): int|string {
    return time() % 2 ? 'string' : time();
};

/**
 * @return PromiseInterface<int|string>
 */
$fp = function (): PromiseInterface {
    return resolve(time() % 2 ? 'string' : time());
};

$p1 = resolve($f());
$p2 = $fp();
```

When calling `then` on `$p1` or `$p2`, PHPStan understand that function `$f1` is type hinting its parameter fine, but `$f2` will throw during runtime:

```php
$p2->then(static function (int|string $a) {});
$p2->then(static function (bool $a) {});
```

Builds on top of reactphp#246 and reactphp#188 and is a requirement for reactphp/async#40
@WyriHaximus
Copy link
Member

PR is up at: #247

WyriHaximus pushed a commit to WyriHaximus-secret-labs/promise that referenced this pull request Jul 5, 2023
Adds template annotations turning the `PromiseInterface` into a generic.

Variables `$p1` and `$p2` in the following code example both are `PromiseInterface<int|string>`.

```php
$f = function (): int|string {
    return time() % 2 ? 'string' : time();
};

/**
 * @return PromiseInterface<int|string>
 */
$fp = function (): PromiseInterface {
    return resolve(time() % 2 ? 'string' : time());
};

$p1 = resolve($f());
$p2 = $fp();
```

When calling `then` on `$p1` or `$p2`, PHPStan understand that function `$f1` is type hinting its parameter fine, but `$f2` will throw during runtime:

```php
$p2->then(static function (int|string $a) {});
$p2->then(static function (bool $a) {});
```

Builds on top of reactphp#246 and reactphp#188 and is a requirement for reactphp/async#40
WyriHaximus pushed a commit to WyriHaximus-secret-labs/promise that referenced this pull request Jul 5, 2023
Adds template annotations turning the `PromiseInterface` into a generic.

Variables `$p1` and `$p2` in the following code example both are `PromiseInterface<int|string>`.

```php
$f = function (): int|string {
    return time() % 2 ? 'string' : time();
};

/**
 * @return PromiseInterface<int|string>
 */
$fp = function (): PromiseInterface {
    return resolve(time() % 2 ? 'string' : time());
};

$p1 = resolve($f());
$p2 = $fp();
```

When calling `then` on `$p1` or `$p2`, PHPStan understand that function `$f1` is type hinting its parameter fine, but `$f2` will throw during runtime:

```php
$p2->then(static function (int|string $a) {});
$p2->then(static function (bool $a) {});
```

Builds on top of reactphp#246 and reactphp#188 and is a requirement for reactphp/async#40
WyriHaximus pushed a commit to WyriHaximus-secret-labs/promise that referenced this pull request Jul 5, 2023
Adds template annotations turning the `PromiseInterface` into a generic.

Variables `$p1` and `$p2` in the following code example both are `PromiseInterface<int|string>`.

```php
$f = function (): int|string {
    return time() % 2 ? 'string' : time();
};

/**
 * @return PromiseInterface<int|string>
 */
$fp = function (): PromiseInterface {
    return resolve(time() % 2 ? 'string' : time());
};

$p1 = resolve($f());
$p2 = $fp();
```

When calling `then` on `$p1` or `$p2`, PHPStan understand that function `$f1` is type hinting its parameter fine, but `$f2` will throw during runtime:

```php
$p2->then(static function (int|string $a) {});
$p2->then(static function (bool $a) {});
```

Builds on top of reactphp#246 and reactphp#188 and is a requirement for reactphp/async#40
WyriHaximus pushed a commit to WyriHaximus-secret-labs/promise that referenced this pull request Jul 7, 2023
Adds template annotations turning the `PromiseInterface` into a generic.

Variables `$p1` and `$p2` in the following code example both are `PromiseInterface<int|string>`.

```php
$f = function (): int|string {
    return time() % 2 ? 'string' : time();
};

/**
 * @return PromiseInterface<int|string>
 */
$fp = function (): PromiseInterface {
    return resolve(time() % 2 ? 'string' : time());
};

$p1 = resolve($f());
$p2 = $fp();
```

When calling `then` on `$p1` or `$p2`, PHPStan understand that function `$f1` is type hinting its parameter fine, but `$f2` will throw during runtime:

```php
$p2->then(static function (int|string $a) {});
$p2->then(static function (bool $a) {});
```

Builds on top of reactphp#246 and reactphp#188 and is a requirement for reactphp/async#40
WyriHaximus pushed a commit to WyriHaximus-secret-labs/promise that referenced this pull request Jul 8, 2023
Adds template annotations turning the `PromiseInterface` into a generic.

Variables `$p1` and `$p2` in the following code example both are `PromiseInterface<int|string>`.

```php
$f = function (): int|string {
    return time() % 2 ? 'string' : time();
};

/**
 * @return PromiseInterface<int|string>
 */
$fp = function (): PromiseInterface {
    return resolve(time() % 2 ? 'string' : time());
};

$p1 = resolve($f());
$p2 = $fp();
```

When calling `then` on `$p1` or `$p2`, PHPStan understand that function `$f1` is type hinting its parameter fine, but `$f2` will throw during runtime:

```php
$p2->then(static function (int|string $a) {});
$p2->then(static function (bool $a) {});
```

Builds on top of reactphp#246 and reactphp#188 and is a requirement for reactphp/async#40
WyriHaximus pushed a commit to WyriHaximus-secret-labs/promise that referenced this pull request Jul 8, 2023
Adds template annotations turning the `PromiseInterface` into a generic.

Variables `$p1` and `$p2` in the following code example both are `PromiseInterface<int|string>`.

```php
$f = function (): int|string {
    return time() % 2 ? 'string' : time();
};

/**
 * @return PromiseInterface<int|string>
 */
$fp = function (): PromiseInterface {
    return resolve(time() % 2 ? 'string' : time());
};

$p1 = resolve($f());
$p2 = $fp();
```

When calling `then` on `$p1` or `$p2`, PHPStan understand that function `$f1` is type hinting its parameter fine, but `$f2` will throw during runtime:

```php
$p2->then(static function (int|string $a) {});
$p2->then(static function (bool $a) {});
```

Builds on top of reactphp#246 and reactphp#188 and is a requirement for reactphp/async#40
WyriHaximus pushed a commit to WyriHaximus-secret-labs/promise that referenced this pull request Jul 8, 2023
Adds template annotations turning the `PromiseInterface` into a generic.

Variables `$p1` and `$p2` in the following code example both are `PromiseInterface<int|string>`.

```php
$f = function (): int|string {
    return time() % 2 ? 'string' : time();
};

/**
 * @return PromiseInterface<int|string>
 */
$fp = function (): PromiseInterface {
    return resolve(time() % 2 ? 'string' : time());
};

$p1 = resolve($f());
$p2 = $fp();
```

When calling `then` on `$p1` or `$p2`, PHPStan understand that function `$f1` is type hinting its parameter fine, but `$f2` will throw during runtime:

```php
$p2->then(static function (int|string $a) {});
$p2->then(static function (bool $a) {});
```

Builds on top of reactphp#246 and reactphp#188 and is a requirement for reactphp/async#40
WyriHaximus pushed a commit to WyriHaximus-secret-labs/promise that referenced this pull request Jul 8, 2023
Adds template annotations turning the `PromiseInterface` into a generic.

Variables `$p1` and `$p2` in the following code example both are `PromiseInterface<int|string>`.

```php
$f = function (): int|string {
    return time() % 2 ? 'string' : time();
};

/**
 * @return PromiseInterface<int|string>
 */
$fp = function (): PromiseInterface {
    return resolve(time() % 2 ? 'string' : time());
};

$p1 = resolve($f());
$p2 = $fp();
```

When calling `then` on `$p1` or `$p2`, PHPStan understand that function `$f1` is type hinting its parameter fine, but `$f2` will throw during runtime:

```php
$p2->then(static function (int|string $a) {});
$p2->then(static function (bool $a) {});
```

Builds on top of reactphp#246 and reactphp#188 and is a requirement for reactphp/async#40
WyriHaximus pushed a commit to WyriHaximus-secret-labs/promise that referenced this pull request Jul 8, 2023
Adds template annotations turning the `PromiseInterface` into a generic.

Variables `$p1` and `$p2` in the following code example both are `PromiseInterface<int|string>`.

```php
$f = function (): int|string {
    return time() % 2 ? 'string' : time();
};

/**
 * @return PromiseInterface<int|string>
 */
$fp = function (): PromiseInterface {
    return resolve(time() % 2 ? 'string' : time());
};

$p1 = resolve($f());
$p2 = $fp();
```

When calling `then` on `$p1` or `$p2`, PHPStan understand that function `$f1` is type hinting its parameter fine, but `$f2` will throw during runtime:

```php
$p2->then(static function (int|string $a) {});
$p2->then(static function (bool $a) {});
```

Builds on top of reactphp#246 and reactphp#188 and is a requirement for reactphp/async#40
WyriHaximus pushed a commit to WyriHaximus-secret-labs/promise that referenced this pull request Jul 8, 2023
Adds template annotations turning the `PromiseInterface` into a generic.

Variables `$p1` and `$p2` in the following code example both are `PromiseInterface<int|string>`.

```php
$f = function (): int|string {
    return time() % 2 ? 'string' : time();
};

/**
 * @return PromiseInterface<int|string>
 */
$fp = function (): PromiseInterface {
    return resolve(time() % 2 ? 'string' : time());
};

$p1 = resolve($f());
$p2 = $fp();
```

When calling `then` on `$p1` or `$p2`, PHPStan understand that function `$f1` is type hinting its parameter fine, but `$f2` will throw during runtime:

```php
$p2->then(static function (int|string $a) {});
$p2->then(static function (bool $a) {});
```

Builds on top of reactphp#246 and reactphp#188 and is a requirement for reactphp/async#40
WyriHaximus pushed a commit to WyriHaximus-secret-labs/promise that referenced this pull request Jul 8, 2023
Adds template annotations turning the `PromiseInterface` into a generic.

Variables `$p1` and `$p2` in the following code example both are `PromiseInterface<int|string>`.

```php
$f = function (): int|string {
    return time() % 2 ? 'string' : time();
};

/**
 * @return PromiseInterface<int|string>
 */
$fp = function (): PromiseInterface {
    return resolve(time() % 2 ? 'string' : time());
};

$p1 = resolve($f());
$p2 = $fp();
```

When calling `then` on `$p1` or `$p2`, PHPStan understand that function `$f1` is type hinting its parameter fine, but `$f2` will throw during runtime:

```php
$p2->then(static function (int|string $a) {});
$p2->then(static function (bool $a) {});
```

Builds on top of reactphp#246 and reactphp#188 and is a requirement for reactphp/async#40
WyriHaximus pushed a commit to WyriHaximus-secret-labs/promise that referenced this pull request Jul 9, 2023
Adds template annotations turning the `PromiseInterface` into a generic.

Variables `$p1` and `$p2` in the following code example both are `PromiseInterface<int|string>`.

```php
$f = function (): int|string {
    return time() % 2 ? 'string' : time();
};

/**
 * @return PromiseInterface<int|string>
 */
$fp = function (): PromiseInterface {
    return resolve(time() % 2 ? 'string' : time());
};

$p1 = resolve($f());
$p2 = $fp();
```

When calling `then` on `$p1` or `$p2`, PHPStan understand that function `$f1` is type hinting its parameter fine, but `$f2` will throw during runtime:

```php
$p2->then(static function (int|string $a) {});
$p2->then(static function (bool $a) {});
```

Builds on top of reactphp#246 and reactphp#188 and is a requirement for reactphp/async#40
WyriHaximus pushed a commit to WyriHaximus-secret-labs/promise that referenced this pull request Jul 9, 2023
Adds template annotations turning the `PromiseInterface` into a generic.

Variables `$p1` and `$p2` in the following code example both are `PromiseInterface<int|string>`.

```php
$f = function (): int|string {
    return time() % 2 ? 'string' : time();
};

/**
 * @return PromiseInterface<int|string>
 */
$fp = function (): PromiseInterface {
    return resolve(time() % 2 ? 'string' : time());
};

$p1 = resolve($f());
$p2 = $fp();
```

When calling `then` on `$p1` or `$p2`, PHPStan understand that function `$f1` is type hinting its parameter fine, but `$f2` will throw during runtime:

```php
$p2->then(static function (int|string $a) {});
$p2->then(static function (bool $a) {});
```

Builds on top of reactphp#246 and reactphp#188 and is a requirement for reactphp/async#40
WyriHaximus pushed a commit to WyriHaximus-secret-labs/promise that referenced this pull request Jul 9, 2023
Adds template annotations turning the `PromiseInterface` into a generic.

Variables `$p1` and `$p2` in the following code example both are `PromiseInterface<int|string>`.

```php
$f = function (): int|string {
    return time() % 2 ? 'string' : time();
};

/**
 * @return PromiseInterface<int|string>
 */
$fp = function (): PromiseInterface {
    return resolve(time() % 2 ? 'string' : time());
};

$p1 = resolve($f());
$p2 = $fp();
```

When calling `then` on `$p1` or `$p2`, PHPStan understand that function `$f1` is type hinting its parameter fine, but `$f2` will throw during runtime:

```php
$p2->then(static function (int|string $a) {});
$p2->then(static function (bool $a) {});
```

Builds on top of reactphp#246 and reactphp#188 and is a requirement for reactphp/async#40
WyriHaximus pushed a commit to WyriHaximus-secret-labs/promise that referenced this pull request Jul 9, 2023
Adds template annotations turning the `PromiseInterface` into a generic.

Variables `$p1` and `$p2` in the following code example both are `PromiseInterface<int|string>`.

```php
$f = function (): int|string {
    return time() % 2 ? 'string' : time();
};

/**
 * @return PromiseInterface<int|string>
 */
$fp = function (): PromiseInterface {
    return resolve(time() % 2 ? 'string' : time());
};

$p1 = resolve($f());
$p2 = $fp();
```

When calling `then` on `$p1` or `$p2`, PHPStan understand that function `$f1` is type hinting its parameter fine, but `$f2` will throw during runtime:

```php
$p2->then(static function (int|string $a) {});
$p2->then(static function (bool $a) {});
```

Builds on top of reactphp#246 and reactphp#188 and is a requirement for reactphp/async#40
WyriHaximus pushed a commit to WyriHaximus-secret-labs/promise that referenced this pull request Jul 9, 2023
Adds template annotations turning the `PromiseInterface` into a generic.

Variables `$p1` and `$p2` in the following code example both are `PromiseInterface<int|string>`.

```php
$f = function (): int|string {
    return time() % 2 ? 'string' : time();
};

/**
 * @return PromiseInterface<int|string>
 */
$fp = function (): PromiseInterface {
    return resolve(time() % 2 ? 'string' : time());
};

$p1 = resolve($f());
$p2 = $fp();
```

When calling `then` on `$p1` or `$p2`, PHPStan understand that function `$f1` is type hinting its parameter fine, but `$f2` will throw during runtime:

```php
$p2->then(static function (int|string $a) {});
$p2->then(static function (bool $a) {});
```

Builds on top of reactphp#246 and reactphp#188 and is a requirement for reactphp/async#40
WyriHaximus pushed a commit to WyriHaximus-secret-labs/promise that referenced this pull request Jul 9, 2023
Adds template annotations turning the `PromiseInterface` into a generic.

Variables `$p1` and `$p2` in the following code example both are `PromiseInterface<int|string>`.

```php
$f = function (): int|string {
    return time() % 2 ? 'string' : time();
};

/**
 * @return PromiseInterface<int|string>
 */
$fp = function (): PromiseInterface {
    return resolve(time() % 2 ? 'string' : time());
};

$p1 = resolve($f());
$p2 = $fp();
```

When calling `then` on `$p1` or `$p2`, PHPStan understand that function `$f1` is type hinting its parameter fine, but `$f2` will throw during runtime:

```php
$p2->then(static function (int|string $a) {});
$p2->then(static function (bool $a) {});
```

Builds on top of reactphp#246 and reactphp#188 and is a requirement for reactphp/async#40
WyriHaximus pushed a commit to WyriHaximus-secret-labs/promise that referenced this pull request Jul 9, 2023
Adds template annotations turning the `PromiseInterface` into a generic.

Variables `$p1` and `$p2` in the following code example both are `PromiseInterface<int|string>`.

```php
$f = function (): int|string {
    return time() % 2 ? 'string' : time();
};

/**
 * @return PromiseInterface<int|string>
 */
$fp = function (): PromiseInterface {
    return resolve(time() % 2 ? 'string' : time());
};

$p1 = resolve($f());
$p2 = $fp();
```

When calling `then` on `$p1` or `$p2`, PHPStan understand that function `$f1` is type hinting its parameter fine, but `$f2` will throw during runtime:

```php
$p2->then(static function (int|string $a) {});
$p2->then(static function (bool $a) {});
```

Builds on top of reactphp#246 and reactphp#188 and is a requirement for reactphp/async#40
WyriHaximus pushed a commit to WyriHaximus-secret-labs/promise that referenced this pull request Jul 9, 2023
Adds template annotations turning the `PromiseInterface` into a generic.

Variables `$p1` and `$p2` in the following code example both are `PromiseInterface<int|string>`.

```php
$f = function (): int|string {
    return time() % 2 ? 'string' : time();
};

/**
 * @return PromiseInterface<int|string>
 */
$fp = function (): PromiseInterface {
    return resolve(time() % 2 ? 'string' : time());
};

$p1 = resolve($f());
$p2 = $fp();
```

When calling `then` on `$p1` or `$p2`, PHPStan understand that function `$f1` is type hinting its parameter fine, but `$f2` will throw during runtime:

```php
$p2->then(static function (int|string $a) {});
$p2->then(static function (bool $a) {});
```

Builds on top of reactphp#246 and reactphp#188 and is a requirement for reactphp/async#40
WyriHaximus pushed a commit to WyriHaximus-secret-labs/promise that referenced this pull request Jul 9, 2023
Adds template annotations turning the `PromiseInterface` into a generic.

Variables `$p1` and `$p2` in the following code example both are `PromiseInterface<int|string>`.

```php
$f = function (): int|string {
    return time() % 2 ? 'string' : time();
};

/**
 * @return PromiseInterface<int|string>
 */
$fp = function (): PromiseInterface {
    return resolve(time() % 2 ? 'string' : time());
};

$p1 = resolve($f());
$p2 = $fp();
```

When calling `then` on `$p1` or `$p2`, PHPStan understand that function `$f1` is type hinting its parameter fine, but `$f2` will throw during runtime:

```php
$p2->then(static function (int|string $a) {});
$p2->then(static function (bool $a) {});
```

Builds on top of reactphp#246 and reactphp#188 and is a requirement for reactphp/async#40
WyriHaximus pushed a commit to WyriHaximus-secret-labs/promise that referenced this pull request Jul 9, 2023
Adds template annotations turning the `PromiseInterface` into a generic.

Variables `$p1` and `$p2` in the following code example both are `PromiseInterface<int|string>`.

```php
$f = function (): int|string {
    return time() % 2 ? 'string' : time();
};

/**
 * @return PromiseInterface<int|string>
 */
$fp = function (): PromiseInterface {
    return resolve(time() % 2 ? 'string' : time());
};

$p1 = resolve($f());
$p2 = $fp();
```

When calling `then` on `$p1` or `$p2`, PHPStan understand that function `$f1` is type hinting its parameter fine, but `$f2` will throw during runtime:

```php
$p2->then(static function (int|string $a) {});
$p2->then(static function (bool $a) {});
```

Builds on top of reactphp#246 and reactphp#188 and is a requirement for reactphp/async#40
WyriHaximus pushed a commit to WyriHaximus-secret-labs/promise that referenced this pull request Jul 9, 2023
Adds template annotations turning the `PromiseInterface` into a generic.

Variables `$p1` and `$p2` in the following code example both are `PromiseInterface<int|string>`.

```php
$f = function (): int|string {
    return time() % 2 ? 'string' : time();
};

/**
 * @return PromiseInterface<int|string>
 */
$fp = function (): PromiseInterface {
    return resolve(time() % 2 ? 'string' : time());
};

$p1 = resolve($f());
$p2 = $fp();
```

When calling `then` on `$p1` or `$p2`, PHPStan understand that function `$f1` is type hinting its parameter fine, but `$f2` will throw during runtime:

```php
$p2->then(static function (int|string $a) {});
$p2->then(static function (bool $a) {});
```

Builds on top of reactphp#246 and reactphp#188 and is a requirement for reactphp/async#40
WyriHaximus pushed a commit to WyriHaximus-secret-labs/promise that referenced this pull request Jul 9, 2023
Adds template annotations turning the `PromiseInterface` into a generic.

Variables `$p1` and `$p2` in the following code example both are `PromiseInterface<int|string>`.

```php
$f = function (): int|string {
    return time() % 2 ? 'string' : time();
};

/**
 * @return PromiseInterface<int|string>
 */
$fp = function (): PromiseInterface {
    return resolve(time() % 2 ? 'string' : time());
};

$p1 = resolve($f());
$p2 = $fp();
```

When calling `then` on `$p1` or `$p2`, PHPStan understand that function `$f1` is type hinting its parameter fine, but `$f2` will throw during runtime:

```php
$p2->then(static function (int|string $a) {});
$p2->then(static function (bool $a) {});
```

Builds on top of reactphp#246 and reactphp#188 and is a requirement for reactphp/async#40
WyriHaximus pushed a commit to WyriHaximus-secret-labs/promise that referenced this pull request Jul 9, 2023
Adds template annotations turning the `PromiseInterface` into a generic.

Variables `$p1` and `$p2` in the following code example both are `PromiseInterface<int|string>`.

```php
$f = function (): int|string {
    return time() % 2 ? 'string' : time();
};

/**
 * @return PromiseInterface<int|string>
 */
$fp = function (): PromiseInterface {
    return resolve(time() % 2 ? 'string' : time());
};

$p1 = resolve($f());
$p2 = $fp();
```

When calling `then` on `$p1` or `$p2`, PHPStan understand that function `$f1` is type hinting its parameter fine, but `$f2` will throw during runtime:

```php
$p2->then(static function (int|string $a) {});
$p2->then(static function (bool $a) {});
```

Builds on top of reactphp#246 and reactphp#188 and is a requirement for reactphp/async#40
WyriHaximus pushed a commit to WyriHaximus-secret-labs/promise that referenced this pull request Jul 10, 2023
Adds template annotations turning the `PromiseInterface` into a generic.

Variables `$p1` and `$p2` in the following code example both are `PromiseInterface<int|string>`.

```php
$f = function (): int|string {
    return time() % 2 ? 'string' : time();
};

/**
 * @return PromiseInterface<int|string>
 */
$fp = function (): PromiseInterface {
    return resolve(time() % 2 ? 'string' : time());
};

$p1 = resolve($f());
$p2 = $fp();
```

When calling `then` on `$p1` or `$p2`, PHPStan understand that function `$f1` is type hinting its parameter fine, but `$f2` will throw during runtime:

```php
$p2->then(static function (int|string $a) {});
$p2->then(static function (bool $a) {});
```

Builds on top of reactphp#246 and reactphp#188 and is a requirement for reactphp/async#40
WyriHaximus pushed a commit to WyriHaximus-secret-labs/promise that referenced this pull request Jul 10, 2023
Adds template annotations turning the `PromiseInterface` into a generic.

Variables `$p1` and `$p2` in the following code example both are `PromiseInterface<int|string>`.

```php
$f = function (): int|string {
    return time() % 2 ? 'string' : time();
};

/**
 * @return PromiseInterface<int|string>
 */
$fp = function (): PromiseInterface {
    return resolve(time() % 2 ? 'string' : time());
};

$p1 = resolve($f());
$p2 = $fp();
```

When calling `then` on `$p1` or `$p2`, PHPStan understand that function `$f1` is type hinting its parameter fine, but `$f2` will throw during runtime:

```php
$p2->then(static function (int|string $a) {});
$p2->then(static function (bool $a) {});
```

Builds on top of reactphp#246 and reactphp#188 and is a requirement for reactphp/async#40
WyriHaximus pushed a commit to WyriHaximus-secret-labs/promise that referenced this pull request Jul 10, 2023
Adds template annotations turning the `PromiseInterface` into a generic.

Variables `$p1` and `$p2` in the following code example both are `PromiseInterface<int|string>`.

```php
$f = function (): int|string {
    return time() % 2 ? 'string' : time();
};

/**
 * @return PromiseInterface<int|string>
 */
$fp = function (): PromiseInterface {
    return resolve(time() % 2 ? 'string' : time());
};

$p1 = resolve($f());
$p2 = $fp();
```

When calling `then` on `$p1` or `$p2`, PHPStan understand that function `$f1` is type hinting its parameter fine, but `$f2` will throw during runtime:

```php
$p2->then(static function (int|string $a) {});
$p2->then(static function (bool $a) {});
```

Builds on top of reactphp#246 and reactphp#188 and is a requirement for reactphp/async#40
WyriHaximus pushed a commit to WyriHaximus-secret-labs/promise that referenced this pull request Jul 11, 2023
Adds template annotations turning the `PromiseInterface` into a generic.

Variables `$p1` and `$p2` in the following code example both are `PromiseInterface<int|string>`.

```php
$f = function (): int|string {
    return time() % 2 ? 'string' : time();
};

/**
 * @return PromiseInterface<int|string>
 */
$fp = function (): PromiseInterface {
    return resolve(time() % 2 ? 'string' : time());
};

$p1 = resolve($f());
$p2 = $fp();
```

When calling `then` on `$p1` or `$p2`, PHPStan understand that function `$f1` is type hinting its parameter fine, but `$f2` will throw during runtime:

```php
$p2->then(static function (int|string $a) {});
$p2->then(static function (bool $a) {});
```

Builds on top of reactphp#246 and reactphp#188 and is a requirement for reactphp/async#40
clue pushed a commit to WyriHaximus-secret-labs/promise that referenced this pull request Jul 11, 2023
Adds template annotations turning the `PromiseInterface` into a generic.

Variables `$p1` and `$p2` in the following code example both are
`PromiseInterface<int|string>`.

```php
$f = function (): int|string {
    return time() % 2 ? 'string' : time();
};

/**
 * @return PromiseInterface<int|string>
 */
$fp = function (): PromiseInterface {
    return resolve(time() % 2 ? 'string' : time());
};

$p1 = resolve($f());
$p2 = $fp();
```

When calling `then` on `$p1` or `$p2`, PHPStan understand that function
`$f1` is type hinting its parameter fine, but `$f2` will throw during
runtime:

```php
$p2->then(static function (int|string $a) {});
$p2->then(static function (bool $a) {});
```

Builds on top of reactphp#246 and
reactphp#188 and is a requirement for
reactphp/async#40
clue pushed a commit to WyriHaximus-secret-labs/promise that referenced this pull request Jul 11, 2023
Adds template annotations turning the `PromiseInterface` into a generic.

Variables `$p1` and `$p2` in the following code example both are
`PromiseInterface<int|string>`.

```php
$f = function (): int|string {
    return time() % 2 ? 'string' : time();
};

/**
 * @return PromiseInterface<int|string>
 */
$fp = function (): PromiseInterface {
    return resolve(time() % 2 ? 'string' : time());
};

$p1 = resolve($f());
$p2 = $fp();
```

When calling `then` on `$p1` or `$p2`, PHPStan understand that function
`$f1` is type hinting its parameter fine, but `$f2` will throw during
runtime:

```php
$p2->then(static function (int|string $a) {});
$p2->then(static function (bool $a) {});
```

Builds on top of reactphp#246 and
reactphp#188 and is a requirement for
reactphp/async#40
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

Successfully merging this pull request may close these issues.

6 participants