Psalm: Template parameters are not resolved for implicit `getIterator()` call

Created on 10 Sep 2018  路  4Comments  路  Source: vimeo/psalm

https://getpsalm.org/r/6512bf307d

<?php
  namespace NS;
  /**
   * @template TKey
   * @template TValue
   */
  interface ICollection extends \IteratorAggregate {
     /** @return \Traversable<TKey,TValue> */
     public function getIterator();
  }

  class Collection implements ICollection {
     /** @var array */
     private $data;
     public function __construct(array $data) {
       $this->data = $data;
     }
     /** @psalm-suppress LessSpecificImplementedReturnType */
     public function getIterator(): \Traversable {
       return new \ArrayIterator($this->data);
     }
  }
  /** @var ICollection<string, int> */
  $c = new Collection(["a" => 1]);

  foreach ($c as $k => $v) { atan($k); strlen($v); } // $k and $v are reported as TKey, TValue, (and mixed if any methods are called on them)
  foreach ($c->getIterator() as $k => $v) { atan($k); strlen($v); } // $k and $v resolved to string/int property

Expected: both loops result in $k/$v types inferred as string/int.
Actual: only loop with explicit getIterator() resolve $k/$v as expected. Implicit call in first loop reports variables as TKey/TValue, and mixed if any method calls are performed on them.

bug

All 4 comments

Note: when I dropped the ICollection interface and moved template definitions to the Collection itself Psalm was able to infer both cases properly. So it might have something to do with inheritance.

It didn't, the output is the same with 80cd77832b0020f5acb0ede2653ff773c438dd79

Thanks for this!

Was this page helpful?
0 / 5 - 0 ratings