Skip to content

[6.x] Resolve method templates for polymorphic array callables - #11815

Merged
danog merged 4 commits into
vimeo:6.xfrom
alies-dev:fix/6549-polymorphic-array-callable
Sep 28, 2026
Merged

danog merged 4 commits into
vimeo:6.xfrom
alies-dev:fix/6549-polymorphic-array-callable

Conversation

@alies-dev

@alies-dev alies-dev commented Apr 18, 2026 •

Copy link
Copy Markdown
Contributor

Fixes #6549.

Passing [Id::class, 'id'] to a callable(int): int parameter used to fail with InvalidArgument when Id::id has its own @template B (@param B $b, @return B), because the method's templates were carried into the callable unresolved and nothing later matched int against B.

When the expected callable is known, CallableTypeComparator::getCallableFromAtomic now infers the method's templates from it: each parameter is bound to the argument type the expected callable passes at that position (a variadic parameter to every remaining argument), and the return type to the expected return type unless that is void. Arguments the expected callable may omit bind to the parameter's default value, with unresolved constant defaults or otherwise uninferred defaults treated as mixed.

Inference only ever makes the callable more specific when that is safe. If a template would land outside its declared bound (for example through class-string), or if any argument, including a default, is not accepted by the resolved parameter type, the templates stay unresolved and the comparison reports the mismatch as before. Tests cover the accepted cases (static, instance, multiple templates, array_map, nested callables, variadics, defaults, void returns) and the rejected ones. The invokable-object branch now uses the same replaceTemplateTypesWithArgTypes helper, which keeps the result typed as TCallable and removes two baseline entries.

When a `[Class::class, 'method']` array is passed where a specialised
callable signature is expected, infer the method's `@template` params
from the container signature instead of leaving them as raw template
standins. The previous behaviour produced spurious `InvalidArgument`
errors because the container types could not match the template atoms.

Fixes vimeo#6549
@alies-dev
alies-dev force-pushed the fix/6549-polymorphic-array-callable branch from 1e5e74d to a99132c Compare April 18, 2026 16:14
@alies-dev alies-dev changed the title Resolve method templates for polymorphic array callables [6.x] Resolve method templates for polymorphic array callables Apr 18, 2026
@danog

danog commented Sep 27, 2026

Copy link
Copy Markdown
Collaborator

fix failing CI pls

@danog danog added the release:fix The PR will be included in 'Fixes' section of the release notes label Sep 28, 2026
@danog
danog merged commit 234bc92 into vimeo:6.x Sep 28, 2026
59 of 62 checks passed
@alies-dev

Copy link
Copy Markdown
Contributor Author

Fixed: the self-analysis failure came from getSingleAtomic() widening the callable to Atomic, it now stays a TCallable. I also tightened the inference so it falls back to the old behaviour whenever resolving the templates could hide a real mismatch (defaults, variadics, template bounds), with tests for each.

@alies-dev

Copy link
Copy Markdown
Contributor Author

The version merged here predates the self-analysis fix and the soundness guards for defaults, variadics and template bounds; those are in #12012, which also removes the @psalm-suppress and baseline entries that cover it on 6.x.

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

Labels

release:fix The PR will be included in 'Fixes' section of the release notes

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Polymorphic callables specified as arrays are not recognised

2 participants