Skip to content

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

Open
alies-dev wants to merge 2 commits intovimeo:6.xfrom
alies-dev:fix/6549-polymorphic-array-callable
Open

[6.x] Resolve method templates for polymorphic array callables#11815
alies-dev wants to merge 2 commits intovimeo:6.xfrom
alies-dev:fix/6549-polymorphic-array-callable

Conversation

@alies-dev
Copy link
Copy Markdown
Contributor

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

Fixes #6549.

Passing [Class::class, 'method'] to a specialised callable parameter used to trip InvalidArgument when the method was templated, because the method's @template atoms were carried into the callable unchanged and nothing would later match int against B.

Before / after

class Id {
    /** @template B @param B $b @return B */
    public static function id($b) { return $b; }
}

/** @param callable(int): int $f */
function bar(callable $f): int { return $f(1); }

bar([Id::class, 'id']);

Before: InvalidArgumentcallable(int): int vs callable(B as mixed): B as mixed.
After: accepted, B is inferred as int from the container.

What changed

In CallableTypeComparator::getCallableFromAtomic, the TKeyedArray branch now wraps the built callable in a Union and runs fillTemplateResult + TemplateInferredTypeReplacer::replace against the container callable — the same idiom the invokable-class branch below already uses. The template walker handles param/return variance and falls unmatched templates back to their declared bounds, so nothing leaks.

Guarded on template_types !== null && container_type_part !== null, so callers that don't supply a container (e.g. ClosureFromCallableReturnTypeProvider, ScalarTypeComparator) are untouched.


Note

Medium Risk
Changes callable type construction for array-callables to resolve method-level templates using the expected callable signature, which can affect type-checking outcomes across projects using templated methods as callables.

Overview
Fixes handling of templated methods used as array callables (e.g. [Class::class, "method"]) by resolving method-level templates against the expected callable type when building a TCallable in CallableTypeComparator::getCallableFromAtomic.

Adds coverage for polymorphic static/instance/multi-template array callables (including array_map) and a negative test ensuring mismatched expected return types still raise InvalidArgument.

Reviewed by Cursor Bugbot for commit 90abfd0. Bugbot is set up for automated code reviews on this repo. Configure here.

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
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.

Polymorphic callables specified as arrays are not recognised

1 participant