Skip to content

Ignore a lower bound that refers to the inferred template argument itself - #6745

Open
HawkForge wants to merge 1 commit into
phpstan:2.3.xfrom
HawkForge:fix/self-referencing-template-lower-bound
Open

HawkForge wants to merge 1 commit into
phpstan:2.3.xfrom
HawkForge:fix/self-referencing-template-lower-bound

Conversation

@HawkForge

Copy link
Copy Markdown

Closes phpstan/phpstan#15434

Since 2.3.0, passing an object whose template argument is still being inferred to its own method makes the argument refer to itself:

/** @template TOwner of object */
class WeakAnalysingMap
{
	/** @param TOwner $owner */
	public function set(object $owner): void {}
}

$map = new WeakAnalysingMap(); // WeakAnalysingMap<WeakAnalysingMap<object>>, 2.2.17: WeakAnalysingMap<object>
$map->set($map); // Parameter #1 $owner of method WeakAnalysingMap<WeakAnalysingMap<object>>::set() expects WeakAnalysingMap<object>, WeakAnalysingMap<WeakAnalysingMap<object>> given.

$map->set($map) records WeakAnalysingMap<TOwner> as a lower bound on the new site's own TOwner. When TemplateArgumentSolver resolves that bound, the inner TOwner is the site that is being resolved, so resolveKey() returns its delegate (object). The site then resolves to WeakAnalysingMap<object>, and $map no longer matches the parameter it was inferred from.

A lower bound that contains the argument it bounds carries no information about it. resolveObservation() now skips such bounds, so the argument falls back to its bound (object), as on 2.2.17. Bounds from other calls still count: $map->set(new stdClass()) still infers WeakAnalysingMap<stdClass>.

  • tests/PHPStan/Rules/Methods/data/bug-15434.php is the issue's code. The test fails without the change in TemplateArgumentSolver.php (it reports the argument.type error from the issue) and passes with it.
  • TemplateArgumentSolver has no turbo mirror, so turbo-ext/ is unchanged.
  • make tests passes, and phpcs is clean on the changed files.

…self

`$map = new WeakAnalysingMap(); $map->set($map);` with
`@param TOwner $owner` puts `WeakAnalysingMap<TOwner>` as a lower bound
on the `new` site's own `TOwner`. Resolving it substituted the site's
default for the inner `TOwner`, so `$map` became
`WeakAnalysingMap<WeakAnalysingMap<object>>` - and then no longer
matched the parameter it was inferred from.

A bound that contains the argument it bounds says nothing about it.
Skip it, so the argument falls back to what 2.2 inferred.

Closes phpstan/phpstan#15434
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.

object template does not accept exact object type since v2.3.0

1 participant