Skip to content

Commit f1099db

Browse files
canvuralondrejmirtes
authored andcommitted
Fix inferring template types in ClosureType
1 parent ea7408d commit f1099db

File tree

3 files changed

+74
-2
lines changed

3 files changed

+74
-2
lines changed

Diff for: src/Type/CallableType.php

+1-1
Original file line numberDiff line numberDiff line change
@@ -218,7 +218,7 @@ public function inferTemplateTypes(Type $receivedType): TemplateTypeMap
218218
return $receivedType->inferTemplateTypesOn($this);
219219
}
220220

221-
if ($receivedType->isCallable()->no()) {
221+
if (! $receivedType->isCallable()->yes()) {
222222
return TemplateTypeMap::createEmpty();
223223
}
224224

Diff for: src/Type/ClosureType.php

+1-1
Original file line numberDiff line numberDiff line change
@@ -334,7 +334,7 @@ public function inferTemplateTypes(Type $receivedType): TemplateTypeMap
334334
return $receivedType->inferTemplateTypesOn($this);
335335
}
336336

337-
if ($receivedType->isCallable()->no()) {
337+
if ($receivedType->isCallable()->no() || ! $receivedType instanceof self) {
338338
return TemplateTypeMap::createEmpty();
339339
}
340340

Diff for: tests/PHPStan/Analyser/data/generic-unions.php

+72
Original file line numberDiff line numberDiff line change
@@ -61,3 +61,75 @@ public function foo(
6161
}
6262

6363
}
64+
65+
class InvokableClass
66+
{
67+
public function __invoke(): string
68+
{
69+
return 'foo';
70+
}
71+
}
72+
73+
/**
74+
*
75+
* @template TGetDefault
76+
* @template TKey
77+
*
78+
* @param TKey $key
79+
* @param TGetDefault|(\Closure(): TGetDefault) $default
80+
* @return TKey|TGetDefault
81+
*/
82+
function getWithDefault($key, $default = null)
83+
{
84+
if(rand(0,10) > 5) {
85+
return $key;
86+
}
87+
88+
if (is_callable($default)) {
89+
return $default();
90+
}
91+
92+
return $default;
93+
}
94+
95+
/**
96+
*
97+
* @template TGetDefault
98+
* @template TKey
99+
*
100+
* @param TKey $key
101+
* @param TGetDefault|(callable(): TGetDefault) $default
102+
* @return TKey|TGetDefault
103+
*/
104+
function getWithDefaultCallable($key, $default = null)
105+
{
106+
if(rand(0,10) > 5) {
107+
return $key;
108+
}
109+
110+
if (is_callable($default)) {
111+
return $default();
112+
}
113+
114+
return $default;
115+
}
116+
117+
assertType('int|null', getWithDefault(3));
118+
assertType('int|null', getWithDefaultCallable(3));
119+
assertType('int|string', getWithDefault(3, 'foo'));
120+
assertType('int|string', getWithDefaultCallable(3, 'foo'));
121+
assertType('int|string', getWithDefault(3, function () {
122+
return 'foo';
123+
}));
124+
assertType('int|string', getWithDefaultCallable(3, function () {
125+
return 'foo';
126+
}));
127+
assertType('GenericUnions\Foo|int', getWithDefault(3, function () {
128+
return new Foo;
129+
}));
130+
assertType('GenericUnions\Foo|int', getWithDefaultCallable(3, function () {
131+
return new Foo;
132+
}));
133+
assertType('GenericUnions\Foo|int', getWithDefault(3, new Foo));
134+
assertType('GenericUnions\Foo|int', getWithDefaultCallable(3, new Foo));
135+
assertType('int|string', getWithDefaultCallable(3, new InvokableClass));

0 commit comments

Comments
 (0)