Skip to content

Commit

Permalink
Prevent re-resolution of static
Browse files Browse the repository at this point in the history
  • Loading branch information
danog committed Oct 14, 2022
1 parent cf2dcb3 commit 12996ea
Show file tree
Hide file tree
Showing 3 changed files with 120 additions and 7 deletions.
12 changes: 5 additions & 7 deletions src/Psalm/Internal/Type/TypeExpander.php
Expand Up @@ -638,14 +638,11 @@ private static function expandNamedObject(

if (!$final && $return_type instanceof TNamedObject) {
$return_type->is_static = true;
$return_type->is_static_resolved = true;
}
} elseif ($return_type->is_static
&& (($static_class_type instanceof TNamedObject
&& $codebase->classlikes->classExtends(
$static_class_type->value,
$return_type->value
)
) || $static_class_type instanceof TTemplateParam)
} elseif ($return_type->is_static && !$return_type->is_static_resolved
&& ($static_class_type instanceof TNamedObject
|| $static_class_type instanceof TTemplateParam)
) {
$return_type = clone $return_type;
$cloned_static = clone $static_class_type;
Expand All @@ -661,6 +658,7 @@ private static function expandNamedObject(
$return_type->extra_types[$extra_static_type->getKey()] = clone $extra_static_type;
}
}
$return_type->is_static_resolved = true;
} elseif ($return_type->is_static && is_string($static_class_type) && $final) {
$return_type->value = $static_class_type;
$return_type->is_static = false;
Expand Down
5 changes: 5 additions & 0 deletions src/Psalm/Type/Atomic/TNamedObject.php
Expand Up @@ -29,6 +29,11 @@ class TNamedObject extends Atomic
*/
public $is_static = false;

/**
* @var bool
*/
public $is_static_resolved = false;

/**
* Whether or not this type can represent a child of the class named in $value
* @var bool
Expand Down
110 changes: 110 additions & 0 deletions tests/ClassTest.php
Expand Up @@ -611,6 +611,116 @@ function intersect(A $a) {
return $b;
}'
],
'preventDoubleStaticResolution1' => [
'code' => '<?php
/**
* @template TTKey
* @template TTValue
*
* @extends ArrayObject<TTKey, TTValue>
*/
class iter extends ArrayObject {
/**
* @return self<TTKey, TTValue>
*/
public function stabilize(): self {
return $this;
}
}
class a {
/**
* @return iter<int, static>
*/
public function ret(): iter {
return new iter([$this]);
}
}
class b extends a {
}
$a = new b;
$a = $a->ret();
$a = $a->stabilize();',
'assertions' => [
'$a===' => 'iter<int, b&static>'
]
],
'preventDoubleStaticResolution2' => [
'code' => '<?php
/**
* @template TTKey
* @template TTValue
*
* @extends ArrayObject<TTKey, TTValue>
*/
class iter extends ArrayObject {
/**
* @return self<TTKey, TTValue>
*/
public function stabilize(): self {
return $this;
}
}
interface a {
/**
* @return iter<int, static>
*/
public function ret(): iter;
}
class b implements a {
public function ret(): iter {
return new iter([$this]);
}
}
/** @var a */
$a = new b;
$a = $a->ret();
$a = $a->stabilize();',
'assertions' => [
'$a===' => 'iter<int, a&static>'
]
],
'preventDoubleStaticResolution3' => [
'code' => '<?php
/**
* @template TTKey
* @template TTValue
*
* @extends ArrayObject<TTKey, TTValue>
*/
class iter extends ArrayObject {
/**
* @return self<TTKey, TTValue>
*/
public function stabilize(): self {
return $this;
}
}
interface a {
/**
* @return iter<int, a&static>
*/
public function ret(): iter;
}
class b implements a {
public function ret(): iter {
return new iter([$this]);
}
}
/** @var a */
$a = new b;
$a = $a->ret();
$a = $a->stabilize();',
'assertions' => [
'$a===' => 'iter<int, a&static>'
]
],
'allowTraversableImplementationAlongWithIteratorAggregate' => [
'code' => '<?php
/**
Expand Down

0 comments on commit 12996ea

Please sign in to comment.