1
0
mirror of https://github.com/danog/psalm.git synced 2025-01-21 21:31:13 +01:00

Support intersections with __toString

Fixes #3149
This commit is contained in:
Brown 2020-04-26 20:04:34 -04:00
parent 5331a3e8b8
commit e65bffc94f
2 changed files with 62 additions and 27 deletions

View File

@ -2229,39 +2229,51 @@ class ExpressionAnalyzer
}
if ($atomic_type instanceof TNamedObject
&& $codebase->methods->methodExists(
new \Psalm\Internal\MethodIdentifier(
$atomic_type->value,
'__tostring'
)
)
|| $atomic_type instanceof TObject
) {
$return_type = $codebase->methods->getMethodReturnType(
new \Psalm\Internal\MethodIdentifier(
$atomic_type->value,
'__tostring'
),
$self_class
);
$intersection_types = [$atomic_type];
if ($return_type) {
$castable_types = array_merge(
$castable_types,
array_values($return_type->getAtomicTypes())
);
} else {
$castable_types[] = new TString();
if ($atomic_type->extra_types) {
$intersection_types = array_merge($intersection_types, $atomic_type->extra_types);
}
continue;
}
foreach ($intersection_types as $intersection_type) {
if ($intersection_type instanceof TNamedObject
&& $codebase->methods->methodExists(
new \Psalm\Internal\MethodIdentifier(
$intersection_type->value,
'__tostring'
)
)
) {
$return_type = $codebase->methods->getMethodReturnType(
new \Psalm\Internal\MethodIdentifier(
$intersection_type->value,
'__tostring'
),
$self_class
);
if ($atomic_type instanceof Type\Atomic\TObjectWithProperties
&& isset($atomic_type->methods['__toString'])
) {
$castable_types[] = new TString();
if ($return_type) {
$castable_types = array_merge(
$castable_types,
array_values($return_type->getAtomicTypes())
);
} else {
$castable_types[] = new TString();
}
continue;
continue 2;
}
if ($intersection_type instanceof Type\Atomic\TObjectWithProperties
&& isset($intersection_type->methods['__toString'])
) {
$castable_types[] = new TString();
continue 2;
}
}
}
if ($atomic_type instanceof Type\Atomic\TTemplateParam) {

View File

@ -119,6 +119,29 @@ class ToStringTest extends TestCase
}
}'
],
'intersectionCanBeString' => [
'<?php
interface EmptyInterface {}
class StringCastable implements EmptyInterface
{
public function __toString()
{
return \'I am castable\';
}
}
function factory(): EmptyInterface
{
return new StringCastable();
}
$object = factory();
if (method_exists($object, \'__toString\')) {
$a = (string) $object;
echo $a;
}'
],
];
}