Skip to content

Commit

Permalink
Fix #3535 - match template param class constants properly
Browse files Browse the repository at this point in the history
  • Loading branch information
muglug committed Jun 7, 2020
1 parent 74a34f0 commit ce44563
Show file tree
Hide file tree
Showing 4 changed files with 102 additions and 3 deletions.
2 changes: 1 addition & 1 deletion src/Psalm/Internal/Analyzer/Statements/ReturnAnalyzer.php
Original file line number Diff line number Diff line change
Expand Up @@ -412,7 +412,7 @@ public static function analyze(
} 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)
Expand Down
18 changes: 16 additions & 2 deletions src/Psalm/Internal/Type/TypeExpander.php
Original file line number Diff line number Diff line change
Expand Up @@ -187,6 +187,19 @@ public static function expandAtomic(
$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) {
Expand Down Expand Up @@ -327,8 +340,9 @@ function ($constant_name) use ($const_name_part) {
|| $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,
Expand Down
20 changes: 20 additions & 0 deletions src/Psalm/Internal/Type/UnionTemplateHandler.php
Original file line number Diff line number Diff line change
Expand Up @@ -461,6 +461,16 @@ private static function handleTemplateParamStandin(
$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,
Expand Down Expand Up @@ -534,6 +544,16 @@ private static function handleTemplateParamStandin(

$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,
Expand Down
65 changes: 65 additions & 0 deletions tests/ConstantTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -855,6 +855,71 @@ function one(array $a): void {
*/
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;
}
}'
],
];
}

Expand Down

0 comments on commit ce44563

Please sign in to comment.