mirror of
https://github.com/danog/psalm.git
synced 2024-12-03 10:07:52 +01:00
Process @psalm-this-out
on __construct()
as well
Fixes vimeo/psalm#9649
This commit is contained in:
parent
ceaea625f3
commit
def0489b98
@ -11,6 +11,7 @@ use Psalm\Internal\Analyzer\ClassAnalyzer;
|
|||||||
use Psalm\Internal\Analyzer\ClassLikeAnalyzer;
|
use Psalm\Internal\Analyzer\ClassLikeAnalyzer;
|
||||||
use Psalm\Internal\Analyzer\FunctionLikeAnalyzer;
|
use Psalm\Internal\Analyzer\FunctionLikeAnalyzer;
|
||||||
use Psalm\Internal\Analyzer\NamespaceAnalyzer;
|
use Psalm\Internal\Analyzer\NamespaceAnalyzer;
|
||||||
|
use Psalm\Internal\Analyzer\Statements\Expression\Call\Method\MethodCallReturnTypeFetcher;
|
||||||
use Psalm\Internal\Analyzer\Statements\Expression\Call\Method\MethodVisibilityAnalyzer;
|
use Psalm\Internal\Analyzer\Statements\Expression\Call\Method\MethodVisibilityAnalyzer;
|
||||||
use Psalm\Internal\Analyzer\Statements\Expression\CallAnalyzer;
|
use Psalm\Internal\Analyzer\Statements\Expression\CallAnalyzer;
|
||||||
use Psalm\Internal\Analyzer\Statements\ExpressionAnalyzer;
|
use Psalm\Internal\Analyzer\Statements\ExpressionAnalyzer;
|
||||||
@ -21,6 +22,7 @@ use Psalm\Internal\DataFlow\TaintSink;
|
|||||||
use Psalm\Internal\MethodIdentifier;
|
use Psalm\Internal\MethodIdentifier;
|
||||||
use Psalm\Internal\Type\TemplateResult;
|
use Psalm\Internal\Type\TemplateResult;
|
||||||
use Psalm\Internal\Type\TemplateStandinTypeReplacer;
|
use Psalm\Internal\Type\TemplateStandinTypeReplacer;
|
||||||
|
use Psalm\Internal\Type\TypeExpander;
|
||||||
use Psalm\Issue\AbstractInstantiation;
|
use Psalm\Issue\AbstractInstantiation;
|
||||||
use Psalm\Issue\DeprecatedClass;
|
use Psalm\Issue\DeprecatedClass;
|
||||||
use Psalm\Issue\ImpureMethodCall;
|
use Psalm\Issue\ImpureMethodCall;
|
||||||
@ -58,6 +60,7 @@ use Psalm\Type\Union;
|
|||||||
|
|
||||||
use function array_map;
|
use function array_map;
|
||||||
use function array_values;
|
use function array_values;
|
||||||
|
use function count;
|
||||||
use function in_array;
|
use function in_array;
|
||||||
use function md5;
|
use function md5;
|
||||||
use function preg_match;
|
use function preg_match;
|
||||||
@ -429,6 +432,8 @@ final class NewAnalyzer extends CallAnalyzer
|
|||||||
|
|
||||||
$declaring_method_id = $codebase->methods->getDeclaringMethodId($method_id);
|
$declaring_method_id = $codebase->methods->getDeclaringMethodId($method_id);
|
||||||
|
|
||||||
|
$method_storage = null;
|
||||||
|
|
||||||
if ($declaring_method_id) {
|
if ($declaring_method_id) {
|
||||||
$method_storage = $codebase->methods->getStorage($declaring_method_id);
|
$method_storage = $codebase->methods->getStorage($declaring_method_id);
|
||||||
|
|
||||||
@ -500,6 +505,7 @@ final class NewAnalyzer extends CallAnalyzer
|
|||||||
}
|
}
|
||||||
|
|
||||||
$generic_param_types = null;
|
$generic_param_types = null;
|
||||||
|
$self_out_candidate = null;
|
||||||
|
|
||||||
if ($storage->template_types) {
|
if ($storage->template_types) {
|
||||||
foreach ($storage->template_types as $template_name => $base_type) {
|
foreach ($storage->template_types as $template_name => $base_type) {
|
||||||
@ -537,9 +543,49 @@ final class NewAnalyzer extends CallAnalyzer
|
|||||||
'had_template' => true,
|
'had_template' => true,
|
||||||
]);
|
]);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if ($method_storage && $method_storage->self_out_type) {
|
||||||
|
$self_out_candidate = $method_storage->self_out_type;
|
||||||
|
|
||||||
|
if ($template_result->lower_bounds) {
|
||||||
|
$self_out_candidate = TypeExpander::expandUnion(
|
||||||
|
$codebase,
|
||||||
|
$self_out_candidate,
|
||||||
|
$fq_class_name,
|
||||||
|
null,
|
||||||
|
$storage->parent_class,
|
||||||
|
true,
|
||||||
|
false,
|
||||||
|
false,
|
||||||
|
true,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
$self_out_candidate = MethodCallReturnTypeFetcher::replaceTemplateTypes(
|
||||||
|
$self_out_candidate,
|
||||||
|
$template_result,
|
||||||
|
$method_id,
|
||||||
|
count($stmt->getArgs()),
|
||||||
|
$codebase,
|
||||||
|
);
|
||||||
|
|
||||||
|
$self_out_candidate = TypeExpander::expandUnion(
|
||||||
|
$codebase,
|
||||||
|
$self_out_candidate,
|
||||||
|
$fq_class_name,
|
||||||
|
$fq_class_name,
|
||||||
|
$storage->parent_class,
|
||||||
|
true,
|
||||||
|
false,
|
||||||
|
false,
|
||||||
|
true,
|
||||||
|
);
|
||||||
|
$statements_analyzer->node_data->setType($stmt, $self_out_candidate);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if ($generic_param_types) {
|
// XXX: what if we need both?
|
||||||
|
if ($generic_param_types && !$self_out_candidate) {
|
||||||
$result_atomic_type = new TGenericObject(
|
$result_atomic_type = new TGenericObject(
|
||||||
$fq_class_name,
|
$fq_class_name,
|
||||||
$generic_param_types,
|
$generic_param_types,
|
||||||
|
@ -84,6 +84,26 @@ class ThisOutTest extends TestCase
|
|||||||
'$data3===' => 'list<2|3>',
|
'$data3===' => 'list<2|3>',
|
||||||
],
|
],
|
||||||
],
|
],
|
||||||
|
'provideDefaultTypeToTypeArguments' => [
|
||||||
|
'code' => <<<'PHP'
|
||||||
|
<?php
|
||||||
|
/** @template T of 'idle'|'running' */
|
||||||
|
class App {
|
||||||
|
/** @psalm-this-out self<'idle'> */
|
||||||
|
public function __construct() {}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @psalm-if-this-is self<'idle'>
|
||||||
|
* @psalm-this-out self<'running'>
|
||||||
|
*/
|
||||||
|
public function start(): void {}
|
||||||
|
}
|
||||||
|
$app = new App();
|
||||||
|
PHP,
|
||||||
|
'assertions' => [
|
||||||
|
'$app===' => "App<'idle'>",
|
||||||
|
],
|
||||||
|
],
|
||||||
];
|
];
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user