Typing a handrolled collection when it's empty? #6731
-
|
Hi! I'm currently experimenting with how PHPStan treats In particular, if i write this, PHPStan 1.4.7 approves and it passes type checking: /** @var iterable<int, Friend> **/
private iterable $friends;
public function __construct() {
$friends = new \ArrayObject();
\PHPStan\dumpType($friends);
$this->friends = $friends;
}The dumped type is But if I write this, then I get a type error: /** @var iterable<int, Friend> **/
private iterable $friends;
public function __construct() {
$friends = new \Doctrine\Common\Collections\ArrayCollection();
\PHPStan\dumpType($friends);
$this->friends = $friends;
}The dumped type is now Both classes are So, why does PHPStan know that an brand-new empty Ideally, I'd like my own sequence type to behave the way |
Beta Was this translation helpful? Give feedback.
Replies: 2 comments 6 replies
-
|
Coincidentally, I made a change last night and you won't get an error on dev-master, feel free to try it out :) The change is that |
Beta Was this translation helpful? Give feedback.
-
|
This is an interesting problem. One workaround I've been using is to make the empty constructor aware of the types I want: Example: https://phpstan.org/r/49321c40-21e6-47c6-99b3-ad5de947f4a7 This allows to fully resolve the type parameters immediately, even on an empty container. Typescript appears to infer the type parameters from the destination that receives the instantiation, but will refuse to narrow the types after that: https://www.typescriptlang.org/play?#code/FDDGBsEMGdoAgMIB4AqA+OBvYddwKbj4C20AXHCgNoC6OeoA9gHbQAuATgK6huMcAKAJRZ6ePGwAWAS2gA6QiXgBeOLTFwAvhoAOXaJIH4KKEdnHipshUVJy9Bo0I3btYKLDgARUeOZdiACN8DnJEJH8gkLQNdg5pZgBzMOQ4hMSY8SZWTh4+QTMNLJZ2OFA4VWZ8AHdEYQBuIokZeUjg0IqyptwreTSklS7xVxAIGHgAUV88BLYwtpD1cX7kihWlhhLc3n5haYsyrbLOjYPeuVnB0G64c5Wrl2A3Mc8AMX24BdCKZC-MvHuPyQK3+uGycTyu0KBzBR1AQL+nSqtQQwhu5y+DxhtxacnuSJqdREAHpieF7qCtE8QAAzLjMXjSFhwGkCeHkzjpNBCCgAN0Y0gAJqJqcBWciiSSyalOUkYkA As a result, this works only when passing the instantiation result to something with a known type. This seems fine, because the syntax allows to express the type of a variable: In PHPStan, one solution could be to delay type inference until we are confronted to actual types:
This would work for assignments to properties: For arguments: Maybe for method calls as well, although in this case the type inference may be partial: For variables, although in this case the type parameters should be inferred to mixed: Same when passing the object to a generic method: References to Otherwise this seems safe, since the instant the variable is referenced, type parameters get resolved. So there is no way that it gets aliased with a different type. It's possible that I'm missing some case that will not work, though. WDYT ? Are you aware of type systems that resolved this problem ? Would be interesting to see other approaches. |
Beta Was this translation helpful? Give feedback.
Coincidentally, I made a change last night and you won't get an error on dev-master, feel free to try it out :)
composer require --dev phpstan/phpstan:dev-masterThe change is that
new \Doctrine\Common\Collections\ArrayCollection();leads toArrayCollection<*NEVER*, *NEVER*>which then gets accepted into the property.