Skip to content
Permalink
Browse files

Fix #2478 - process trait template inheritance sensibly

  • Loading branch information
muglug committed Dec 18, 2019
1 parent e551b24 commit 49a3f895260a666ab24b3e825c0d7700d5cf698a
Showing with 156 additions and 5 deletions.
  1. +106 −4 src/Psalm/Internal/Analyzer/MethodAnalyzer.php
  2. +50 −1 tests/Template/ClassTemplateExtendsTest.php
@@ -665,6 +665,57 @@ public static function compareMethods(
);

$guide_class_name = $guide_classlike_storage->name;
$implementer_class_name = $implementer_classlike_storage->name;

$implementer_called_class_storage = $implementer_classlike_storage;

if ($implementer_called_class_name !== $implementer_class_name) {
$implementer_called_class_storage = $codebase->classlike_storage_provider->get(
$implementer_called_class_name
);
}

if ($implementer_called_class_storage !== $implementer_classlike_storage
&& isset($implementer_called_class_storage->template_type_extends[$implementer_class_name])
) {
$map = $implementer_called_class_storage->template_type_extends[$implementer_class_name];

$template_types = [];

foreach ($map as $key => $type) {
if (is_string($key)) {
$template_types[$key][$implementer_class_name] = [$type];
}
}

$template_result = new \Psalm\Internal\Type\TemplateResult($template_types, []);

$implementer_method_storage_return_type->replaceTemplateTypesWithArgTypes(
$template_result->template_types,
$codebase
);
}

if ($implementer_called_class_storage !== $implementer_classlike_storage
&& isset($implementer_called_class_storage->template_type_extends[$guide_class_name])
) {
$map = $implementer_called_class_storage->template_type_extends[$guide_class_name];

$template_types = [];

foreach ($map as $key => $type) {
if (is_string($key)) {
$template_types[$key][$guide_class_name] = [$type];
}
}

$template_result = new \Psalm\Internal\Type\TemplateResult($template_types, []);

$guide_method_storage_return_type->replaceTemplateTypesWithArgTypes(
$template_result->template_types,
$codebase
);
}

if (isset($implementer_classlike_storage->template_type_extends[$guide_class_name])) {
$map = $implementer_classlike_storage->template_type_extends[$guide_class_name];
@@ -673,7 +724,7 @@ public static function compareMethods(

foreach ($map as $key => $type) {
if (is_string($key)) {
$template_types[$key][$guide_classlike_storage->name] = [$type];
$template_types[$key][$guide_class_name] = [$type];
}
}

@@ -747,7 +798,7 @@ public static function compareMethods(
if ($union_comparison_results->type_coerced) {
if (IssueBuffer::accepts(
new LessSpecificImplementedReturnType(
'The return type \'' . $guide_method_storage_return_type->getId()
'The inherited return type \'' . $guide_method_storage_return_type->getId()
. '\' for ' . $cased_guide_method_id . ' is more specific than the implemented '
. 'return type for ' . $implementer_declaring_method_id . ' \''
. $implementer_method_storage_return_type->getId() . '\'',
@@ -761,7 +812,7 @@ public static function compareMethods(
} else {
if (IssueBuffer::accepts(
new ImplementedReturnTypeMismatch(
'The return type \'' . $guide_method_storage_return_type->getId()
'The inherited return type \'' . $guide_method_storage_return_type->getId()
. '\' for ' . $cased_guide_method_id . ' is different to the implemented '
. 'return type for ' . $implementer_declaring_method_id . ' \''
. $implementer_method_storage_return_type->getId() . '\'',
@@ -937,6 +988,57 @@ public static function compareMethods(
);

$guide_class_name = $guide_classlike_storage->name;
$implementer_class_name = $implementer_classlike_storage->name;

$implementer_called_class_storage = $implementer_classlike_storage;

if ($implementer_called_class_name !== $implementer_class_name) {
$implementer_called_class_storage = $codebase->classlike_storage_provider->get(
$implementer_called_class_name
);
}

if ($implementer_called_class_storage !== $implementer_classlike_storage
&& isset($implementer_called_class_storage->template_type_extends[$implementer_class_name])
) {
$map = $implementer_called_class_storage->template_type_extends[$implementer_class_name];

$template_types = [];

foreach ($map as $key => $type) {
if (is_string($key)) {
$template_types[$key][$implementer_class_name] = [$type];
}
}

$template_result = new \Psalm\Internal\Type\TemplateResult($template_types, []);

$implementer_method_storage_param_type->replaceTemplateTypesWithArgTypes(
$template_result->template_types,
$codebase
);
}

if ($implementer_called_class_storage !== $implementer_classlike_storage
&& isset($implementer_called_class_storage->template_type_extends[$guide_class_name])
) {
$map = $implementer_called_class_storage->template_type_extends[$guide_class_name];

$template_types = [];

foreach ($map as $key => $type) {
if (is_string($key)) {
$template_types[$key][$guide_class_name] = [$type];
}
}

$template_result = new \Psalm\Internal\Type\TemplateResult($template_types, []);

$guide_method_storage_param_type->replaceTemplateTypesWithArgTypes(
$template_result->template_types,
$codebase
);
}

if (isset($implementer_classlike_storage->template_type_extends[$guide_class_name])) {
$map = $implementer_classlike_storage->template_type_extends[$guide_class_name];
@@ -945,7 +1047,7 @@ public static function compareMethods(

foreach ($map as $key => $type) {
if (is_string($key)) {
$template_types[$key][$guide_classlike_storage->name] = [$type, 0];
$template_types[$key][$guide_class_name] = [$type, 0];
}
}

@@ -2616,6 +2616,55 @@ public function __construct(string $c) {
}
}'
],
'useTraitReturnType' => [
'<?php
/**
* @template TValue
* @template TNormalizedValue
*/
interface Normalizer
{
/**
* @param TValue $v
* @return TNormalizedValue
*/
function normalize($v);
}
/**
* @template TTraitValue
* @template TTraitNormalizedValue
*/
trait NormalizerTrait
{
/**
* @param TTraitValue $v
* @return TTraitNormalizedValue
*/
function normalize($v)
{
return $this->doNormalize($v);
}
/**
* @param TTraitValue $v
* @return TTraitNormalizedValue
*/
abstract protected function doNormalize($v);
}
/** @implements Normalizer<string, string> */
class StringNormalizer implements Normalizer
{
/** @use NormalizerTrait<string, string> */
use NormalizerTrait;
protected function doNormalize($v): string
{
return trim($v);
}
}'
],
];
}

@@ -2661,7 +2710,7 @@ public function getItem()
return new Foo();
}
}',
'error_message' => 'ImplementedReturnTypeMismatch - src' . DIRECTORY_SEPARATOR . 'somefile.php:29:36 - The return type \'A\Bar\' for',
'error_message' => 'ImplementedReturnTypeMismatch - src' . DIRECTORY_SEPARATOR . 'somefile.php:29:36 - The inherited return type \'A\Bar\' for',
],
'extendTemplateAndDoesNotOverrideWithWrongArg' => [
'<?php

0 comments on commit 49a3f89

Please sign in to comment.
You can’t perform that action at this time.