Skip to content

Commit

Permalink
Merge pull request #9865 from klimick/intersection-with-template
Browse files Browse the repository at this point in the history
Intersect template types during inheritance check
  • Loading branch information
orklah committed Jun 4, 2023
2 parents c158605 + 38bd4d8 commit 43df1dc
Show file tree
Hide file tree
Showing 4 changed files with 62 additions and 4 deletions.
6 changes: 2 additions & 4 deletions src/Psalm/Internal/Codebase/Methods.php
Expand Up @@ -768,10 +768,8 @@ public function getMethodReturnType(
$candidate_type,
);

if (((!$old_contained_by_new && !$new_contained_by_old)
|| ($old_contained_by_new && $new_contained_by_old))
&& !$candidate_type->hasTemplate()
&& !$overridden_storage_return_type->hasTemplate()
if ((!$old_contained_by_new && !$new_contained_by_old)
|| ($old_contained_by_new && $new_contained_by_old)
) {
$attempted_intersection = null;
if ($old_contained_by_new) { //implicitly $new_contained_by_old as well
Expand Down
14 changes: 14 additions & 0 deletions src/Psalm/Type.php
Expand Up @@ -739,6 +739,20 @@ public static function intersectUnionTypes(
$combined_type = null;
foreach ($type_1->getAtomicTypes() as $type_1_atomic) {
foreach ($type_2->getAtomicTypes() as $type_2_atomic) {
if ($type_1_atomic instanceof TTemplateParam
&& $type_2_atomic instanceof TNamedObject
) {
$intersected_with_template = self::intersectUnionTypes(
$type_1_atomic->as,
new Union([$type_2_atomic]),
$codebase,
);

if ($intersected_with_template && $intersected_with_template->isSingle()) {
$type_1_atomic = $intersected_with_template->getSingleAtomic();
}
}

$intersection_atomic = self::intersectAtomicTypes(
$type_1_atomic,
$type_2_atomic,
Expand Down
24 changes: 24 additions & 0 deletions tests/MethodCallTest.php
Expand Up @@ -1023,6 +1023,30 @@ public function create($input): BlahModel
'$n' => 'BlahModel',
],
],
'methodLevelGenericsWillBeInherited' => [
'code' => '<?php
interface I
{
/**
* @template TResult
* @param TResult $value
* @return TResult
*/
public function method(mixed $value): mixed;
}
final class A implements I
{
public function method(mixed $value): mixed
{
return $value;
}
}
$_v = (new A)->method("a");
/** @psalm-check-type-exact $_v = "a" */',
'assertions' => [],
'ignored_issues' => [],
'php_version' => '8.0',
],
];
}

Expand Down
22 changes: 22 additions & 0 deletions tests/ReturnTypeTest.php
Expand Up @@ -1785,6 +1785,28 @@ function f(): array
PHP,
'error_message' => 'InvalidReturnStatement',
],
'invalidReturnStatementDetectedInOverriddenMethod' => [
'code' => <<<'PHP'
<?php
/** @template T */
interface I
{
/** @return T */
public function process(): mixed;
}
/** @implements I<int> */
final class B implements I
{
public function process(): mixed
{
return '';
}
}
PHP,
'error_message' => 'InvalidReturnStatement',
'ignored_issues' => [],
'php_version' => '8.0',
],
];
}
}

0 comments on commit 43df1dc

Please sign in to comment.