Skip to content

feat: make Promise and PromiseAdapter generic over the adopted promise type#1941

Merged
spawnia merged 1 commit into
webonyx:masterfrom
simPod:fix/amp-promise-fqn
Jul 5, 2026
Merged

feat: make Promise and PromiseAdapter generic over the adopted promise type#1941
spawnia merged 1 commit into
webonyx:masterfrom
simPod:fix/amp-promise-fqn

Conversation

@simPod

@simPod simPod commented Jul 4, 2026

Copy link
Copy Markdown
Collaborator

Problem

GraphQL\Executor\Promise\Promise documents $adoptedPromise with a @var union naming every supported platform type, which requires importing both Amp\Future and Amp\Promise:

/** @var SyncPromise|ReactPromise<mixed>|AmpFuture<mixed>|AmpPromise<mixed> */
public $adoptedPromise;

amphp/amp v2 ships Amp\Promise and v3 ships Amp\Future, so on any single installation one of those classes does not exist. Because the property is read by consumers, static analysis resolves the whole union and crashes on the missing class — e.g. PHPStan:

Internal error: Class Amp\Promise was not found while trying to analyse it

Change

Make Promise and PromiseAdapter generic over TAdopted, with each adapter binding the concrete platform type:

  • SyncPromiseAdapterPromiseAdapter<SyncPromise>
  • ReactPromiseAdapterPromiseAdapter<React\Promise\PromiseInterface<mixed>>
  • AmpFutureAdapterPromiseAdapter<Amp\Future<mixed>>
  • AmpPromiseAdapterPromiseAdapter<Amp\Promise<mixed>>

Promise no longer names any optional platform class, so it analyses cleanly regardless of which promise library is installed. The adapters gain @phpstan-return Promise<T> annotations and shed now-redundant assert()/instanceof guards; adapter tests drop assertInstanceOf assertions the generics make statically provable.

TAdopted defaults to mixed, so existing bare Promise/PromiseAdapter references are unchanged — not a BC break.

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Pull request overview

This PR adjusts the GraphQL\Executor\Promise\Promise PHPDoc to reference Amp types via fully-qualified names instead of use imports, preventing static analyzers from failing symbol discovery when only one of Amp\Promise (v2) or Amp\Future (v3) exists (or Amp isn’t installed).

Changes:

  • Removed use Amp\Future / use Amp\Promise imports that may reference non-installed symbols.
  • Updated the $adoptedPromise @var union to use \Amp\Future and \Amp\Promise as FQNs.

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

@simPod
simPod requested review from spawnia and removed request for spawnia July 4, 2026 09:54
@simPod
simPod marked this pull request as draft July 4, 2026 10:01
@simPod

This comment was marked as outdated.

@simPod
simPod force-pushed the fix/amp-promise-fqn branch from 91343b7 to d99661d Compare July 4, 2026 10:08
@simPod simPod changed the title fix: reference amphp types by FQN in Promise @var feat: make Promise generic over its adopted promise type Jul 4, 2026
@simPod
simPod force-pushed the fix/amp-promise-fqn branch 2 times, most recently from 8c5b9aa to 877608b Compare July 5, 2026 05:34
@simPod simPod changed the title feat: make Promise generic over its adopted promise type feat: make Promise and PromiseAdapter generic over the adopted promise type Jul 5, 2026
@simPod
simPod force-pushed the fix/amp-promise-fqn branch from 3a6c43b to 33111ce Compare July 5, 2026 06:04
Comment thread src/Executor/Promise/Promise.php

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Pull request overview

Copilot reviewed 10 out of 10 changed files in this pull request and generated 3 comments.

Comment thread src/Executor/Promise/PromiseAdapter.php
Comment thread src/Executor/Promise/PromiseAdapter.php
Comment thread src/Executor/Promise/Promise.php
@simPod
simPod force-pushed the fix/amp-promise-fqn branch 4 times, most recently from 40cce47 to b6ed59c Compare July 5, 2026 06:50
@simPod
simPod requested a review from Copilot July 5, 2026 07:02

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Pull request overview

Copilot reviewed 11 out of 11 changed files in this pull request and generated 6 comments.

Comments suppressed due to low confidence (1)

src/Executor/Promise/Adapter/AmpFutureAdapter.php:52

  • then() no longer validates that the wrapped value is an Amp\Future. If a Promise from a different adapter is passed in, $future->await() will fatal instead of producing a controlled InvariantViolation.
    public function then(Promise $promise, ?callable $onFulfilled = null, ?callable $onRejected = null): Promise
    {
        $future = $promise->adoptedPromise;

        $next = async(static function () use ($future, $onFulfilled, $onRejected) {
            try {
                $value = $future->await();
            } catch (\Throwable $reason) {

Comment thread src/Executor/Promise/PromiseAdapter.php
Comment thread src/Executor/Promise/Adapter/SyncPromiseAdapter.php
Comment thread src/Executor/Promise/Adapter/ReactPromiseAdapter.php
Comment thread src/Executor/Promise/Adapter/ReactPromiseAdapter.php
Comment thread src/Executor/Promise/Adapter/AmpPromiseAdapter.php
Comment thread tests/Executor/Promise/SyncPromiseAdapterTest.php

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Pull request overview

Copilot reviewed 11 out of 11 changed files in this pull request and generated 1 comment.

Comments suppressed due to low confidence (1)

src/Executor/Promise/Promise.php:34

  • Promise is generic over TAdopted, but the stored adapter is not typed as PromiseAdapter<TAdopted>. Without binding the adapter to the same template, static analysis can’t verify that $this->adapter->then($this, ...) actually returns Promise<TAdopted>, and it also permits constructing Promise<TAdopted> with a mismatched adapter type.
    private PromiseAdapter $adapter;

    /**
     * @phpstan-param TAdopted $adoptedPromise
     *
     * @throws InvariantViolation
     */
    public function __construct($adoptedPromise, PromiseAdapter $adapter)

Comment thread src/Executor/Promise/PromiseAdapter.php
@simPod
simPod force-pushed the fix/amp-promise-fqn branch from 644f403 to cfd879c Compare July 5, 2026 08:19
Comment thread src/Executor/Promise/Adapter/AmpFutureAdapter.php Outdated
Comment thread src/Executor/Promise/Adapter/ReactPromiseAdapter.php Outdated
Comment thread src/Executor/Promise/Promise.php
Comment thread src/Executor/Promise/PromiseAdapter.php Outdated
@simPod
simPod force-pushed the fix/amp-promise-fqn branch 3 times, most recently from 4543954 to e605d0c Compare July 5, 2026 12:30
@simPod
simPod marked this pull request as ready for review July 5, 2026 12:34
@simPod
simPod requested a review from Copilot July 5, 2026 12:35

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Pull request overview

Copilot reviewed 12 out of 12 changed files in this pull request and generated 2 comments.

Comment thread src/Executor/Promise/Adapter/AmpFutureAdapter.php
Comment thread composer.json Outdated
@simPod
simPod force-pushed the fix/amp-promise-fqn branch from e605d0c to f1f02d7 Compare July 5, 2026 12:56
@simPod
simPod requested a review from spawnia July 5, 2026 13:10
@simPod
simPod force-pushed the fix/amp-promise-fqn branch from f1f02d7 to 6078203 Compare July 5, 2026 16:38

@spawnia spawnia left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

Looks good overall, happy to do a final review and merge once CI passes.

@simPod
simPod force-pushed the fix/amp-promise-fqn branch from 6078203 to f1f02d7 Compare July 5, 2026 17:09
@simPod

simPod commented Jul 5, 2026

Copy link
Copy Markdown
Collaborator Author

I tried to fiddle with one more thing but I'll skip it for now. CI is green.

@spawnia
spawnia merged commit e7ee6ad into webonyx:master Jul 5, 2026
42 checks passed
@spawnia

spawnia commented Jul 5, 2026

Copy link
Copy Markdown
Collaborator

Thanks @simPod, released with https://github.com/webonyx/graphql-php/releases/tag/v15.34.0.

@simPod
simPod deleted the fix/amp-promise-fqn branch July 5, 2026 18:21
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants