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

Fix #3535 - match template param class constants properly

This commit is contained in:
Matthew Brown 2020-06-06 20:02:14 -04:00
parent 74a34f066c
commit ce445636e7
4 changed files with 102 additions and 3 deletions

View File

@ -412,7 +412,7 @@ class ReturnAnalyzer
} else {
if (IssueBuffer::accepts(
new InvalidReturnStatement(
'The inferred type \'' . $stmt_type->getId()
'The inferred type \'' . $inferred_type->getId()
. '\' does not match the declared return '
. 'type \'' . $local_return_type->getId() . '\' for ' . $cased_method_id,
new CodeLocation($source, $stmt->expr)

View File

@ -187,6 +187,19 @@ class TypeExpander
$return_type->as_type = $new_as_type;
$return_type->as = $return_type->as_type->value;
}
} elseif ($return_type instanceof Type\Atomic\TTemplateParam) {
$new_as_type = self::expandUnion(
$codebase,
clone $return_type->as,
$self_class,
$static_class_type,
$parent_class,
$evaluate_class_constants,
$evaluate_conditional_types,
$final
);
$return_type->as = $new_as_type;
}
if ($return_type instanceof Type\Atomic\TScalarClassConstant) {
@ -327,8 +340,9 @@ class TypeExpander
|| $return_type instanceof Type\Atomic\TGenericObject
|| $return_type instanceof Type\Atomic\TIterable
) {
foreach ($return_type->type_params as &$type_param) {
$type_param = self::expandUnion(
foreach ($return_type->type_params as $k => $type_param) {
/** @psalm-suppress PropertyTypeCoercion */
$return_type->type_params[$k] = self::expandUnion(
$codebase,
$type_param,
$self_class,

View File

@ -461,6 +461,16 @@ class UnionTemplateHandler
$atomic_types[] = clone $as_atomic_type;
}
} else {
if ($codebase) {
$replacement_type = TypeExpander::expandUnion(
$codebase,
$replacement_type,
$calling_class,
$calling_class,
null
);
}
if ($depth < 10) {
$replacement_type = self::replaceTemplateTypesWithStandins(
$replacement_type,
@ -534,6 +544,16 @@ class UnionTemplateHandler
$matching_input_keys = [];
if ($codebase) {
$atomic_type->as = TypeExpander::expandUnion(
$codebase,
$atomic_type->as,
$calling_class,
$calling_class,
null
);
}
$atomic_type->as = self::replaceTemplateTypesWithStandins(
$atomic_type->as,
$template_result,

View File

@ -855,6 +855,71 @@ class ConstantTest extends TestCase
*/
function param(int $type): void {}'
],
'templatedConstantInType' => [
'<?php
/**
* @template T of (self::READ_UNCOMMITTED|self::READ_COMMITTED|self::REPEATABLE_READ|self::SERIALIZABLE)
*/
final class TransactionIsolationLevel {
private const READ_UNCOMMITTED = \'read uncommitted\';
private const READ_COMMITTED = \'read committed\';
private const REPEATABLE_READ = \'repeatable read\';
private const SERIALIZABLE = \'serializable\';
/**
* @psalm-var T
*/
private string $level;
/**
* @psalm-param T $level
*/
private function __construct(string $level)
{
$this->level = $level;
}
/**
* @psalm-return self<self::READ_UNCOMMITTED>
*/
public static function readUncommitted(): self
{
return new self(self::READ_UNCOMMITTED);
}
/**
* @psalm-return self<self::READ_COMMITTED>
*/
public static function readCommitted(): self
{
return new self(self::READ_COMMITTED);
}
/**
* @psalm-return self<self::REPEATABLE_READ>
*/
public static function repeatableRead(): self
{
return new self(self::REPEATABLE_READ);
}
/**
* @psalm-return self<self::SERIALIZABLE>
*/
public static function serializable(): self
{
return new self(self::SERIALIZABLE);
}
/**
* @psalm-return T
*/
public function toString(): string
{
return $this->level;
}
}'
],
];
}