1
0
mirror of https://github.com/danog/psalm.git synced 2024-12-02 09:37:59 +01:00

Merge pull request #10357 from robchett/inherit_conditional_function_templates

Inherit conditional returns
This commit is contained in:
orklah 2023-11-30 19:25:45 +01:00 committed by GitHub
commit 0e43c441d0
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
4 changed files with 67 additions and 10 deletions

View File

@ -577,7 +577,7 @@ final class MethodCallReturnTypeFetcher
) { ) {
if ($template_type->param_name === 'TFunctionArgCount') { if ($template_type->param_name === 'TFunctionArgCount') {
$template_result->lower_bounds[$template_type->param_name] = [ $template_result->lower_bounds[$template_type->param_name] = [
'fn-' . strtolower((string) $method_id) => [ 'fn-' . $method_id->method_name => [
new TemplateBound( new TemplateBound(
Type::getInt(false, $arg_count), Type::getInt(false, $arg_count),
), ),
@ -585,7 +585,7 @@ final class MethodCallReturnTypeFetcher
]; ];
} elseif ($template_type->param_name === 'TPhpMajorVersion') { } elseif ($template_type->param_name === 'TPhpMajorVersion') {
$template_result->lower_bounds[$template_type->param_name] = [ $template_result->lower_bounds[$template_type->param_name] = [
'fn-' . strtolower((string) $method_id) => [ 'fn-' . $method_id->method_name => [
new TemplateBound( new TemplateBound(
Type::getInt(false, $codebase->getMajorAnalysisPhpVersion()), Type::getInt(false, $codebase->getMajorAnalysisPhpVersion()),
), ),
@ -593,7 +593,7 @@ final class MethodCallReturnTypeFetcher
]; ];
} elseif ($template_type->param_name === 'TPhpVersionId') { } elseif ($template_type->param_name === 'TPhpVersionId') {
$template_result->lower_bounds[$template_type->param_name] = [ $template_result->lower_bounds[$template_type->param_name] = [
'fn-' . strtolower((string) $method_id) => [ 'fn-' . $method_id->method_name => [
new TemplateBound( new TemplateBound(
Type::getInt( Type::getInt(
false, false,

View File

@ -629,7 +629,7 @@ final class ExistingAtomicStaticCallAnalyzer
): array { ): array {
if ($template_type->param_name === 'TFunctionArgCount') { if ($template_type->param_name === 'TFunctionArgCount') {
return [ return [
'fn-' . strtolower((string)$method_id) => [ 'fn-' . $method_id->method_name => [
new TemplateBound( new TemplateBound(
Type::getInt(false, count($stmt->getArgs())), Type::getInt(false, count($stmt->getArgs())),
), ),
@ -639,7 +639,7 @@ final class ExistingAtomicStaticCallAnalyzer
if ($template_type->param_name === 'TPhpMajorVersion') { if ($template_type->param_name === 'TPhpMajorVersion') {
return [ return [
'fn-' . strtolower((string)$method_id) => [ 'fn-' . $method_id->method_name => [
new TemplateBound( new TemplateBound(
Type::getInt(false, $codebase->getMajorAnalysisPhpVersion()), Type::getInt(false, $codebase->getMajorAnalysisPhpVersion()),
), ),
@ -649,7 +649,7 @@ final class ExistingAtomicStaticCallAnalyzer
if ($template_type->param_name === 'TPhpVersionId') { if ($template_type->param_name === 'TPhpVersionId') {
return [ return [
'fn-' . strtolower((string) $method_id) => [ 'fn-' . $method_id->method_name => [
new TemplateBound( new TemplateBound(
Type::getInt( Type::getInt(
false, false,

View File

@ -512,9 +512,8 @@ final class FunctionLikeDocblockScanner
if ($token_body === 'func_num_args()') { if ($token_body === 'func_num_args()') {
$template_name = 'TFunctionArgCount'; $template_name = 'TFunctionArgCount';
$storage->template_types[$template_name] = [ $storage->template_types[$template_name] = [
$template_function_id => Type::getInt(), 'fn-' . strtolower($storage->cased_name ?? '') => Type::getInt(),
]; ];
$function_template_types[$template_name] $function_template_types[$template_name]
@ -527,7 +526,7 @@ final class FunctionLikeDocblockScanner
$template_name = 'TPhpMajorVersion'; $template_name = 'TPhpMajorVersion';
$storage->template_types[$template_name] = [ $storage->template_types[$template_name] = [
$template_function_id => Type::getInt(), 'fn-' . strtolower($storage->cased_name ?? '') => Type::getInt(),
]; ];
$function_template_types[$template_name] $function_template_types[$template_name]
@ -540,7 +539,7 @@ final class FunctionLikeDocblockScanner
$template_name = 'TPhpVersionId'; $template_name = 'TPhpVersionId';
$storage->template_types[$template_name] = [ $storage->template_types[$template_name] = [
$template_function_id => Type::getInt(), 'fn-' . strtolower($storage->cased_name ?? '') => Type::getInt(),
]; ];
$function_template_types[$template_name] $function_template_types[$template_name]

View File

@ -463,6 +463,31 @@ class ConditionalReturnTypeTest extends TestCase
'$c' => 'string', '$c' => 'string',
], ],
], ],
'InheritFuncNumArgs' => [
'code' => '<?php
abstract class A
{
/**
* @psalm-return (func_num_args() is 1 ? string : int)
*/
public static function get(bool $a, ?bool $b = null)
{
if ($b) {
return 1;
}
return "";
}
}
class B extends A
{
public static function getB(bool $a): int
{
return self::get($a, true);
}
}',
],
'namespaceFuncNumArgs' => [ 'namespaceFuncNumArgs' => [
'code' => '<?php 'code' => '<?php
namespace Foo; namespace Foo;
@ -887,6 +912,39 @@ class ConditionalReturnTypeTest extends TestCase
'ignored_issues' => [], 'ignored_issues' => [],
'php_version' => '7.2', 'php_version' => '7.2',
], ],
'ineritedreturnTypeBasedOnPhpVersionId' => [
'code' => '<?php
class A {
/**
* @psalm-return (PHP_VERSION_ID is int<70300, max> ? string : int)
*/
function getSomething()
{
return mt_rand(1, 10) > 5 ? "a value" : 42;
}
/**
* @psalm-return (PHP_VERSION_ID is int<70100, max> ? string : int)
*/
function getSomethingElse()
{
return mt_rand(1, 10) > 5 ? "a value" : 42;
}
}
class B extends A {}
$class = new B();
$something = $class->getSomething();
$somethingElse = $class->getSomethingElse();
',
'assertions' => [
'$something' => 'int',
'$somethingElse' => 'string',
],
'ignored_issues' => [],
'php_version' => '7.2',
],
'ineritedConditionalTemplatedReturnType' => [ 'ineritedConditionalTemplatedReturnType' => [
'code' => '<?php 'code' => '<?php
/** @template InstanceType */ /** @template InstanceType */