Skip to content

Commit

Permalink
Inherit conditional returns
Browse files Browse the repository at this point in the history
Fixes #3593
  • Loading branch information
robchett committed Nov 9, 2023
1 parent b775d29 commit 9a32afd
Show file tree
Hide file tree
Showing 4 changed files with 67 additions and 10 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -577,23 +577,23 @@ public static function replaceTemplateTypes(
) {
if ($template_type->param_name === 'TFunctionArgCount') {
$template_result->lower_bounds[$template_type->param_name] = [
'fn-' . strtolower((string) $method_id) => [
'fn-' . strtolower($method_id->method_name) => [

Check failure on line 580 in src/Psalm/Internal/Analyzer/Statements/Expression/Call/Method/MethodCallReturnTypeFetcher.php

View workflow job for this annotation

GitHub Actions / build

RedundantFunctionCall

src/Psalm/Internal/Analyzer/Statements/Expression/Call/Method/MethodCallReturnTypeFetcher.php:580:37: RedundantFunctionCall: The call to strtolower is unnecessary (see https://psalm.dev/280)
new TemplateBound(
Type::getInt(false, $arg_count),
),
],
];
} elseif ($template_type->param_name === 'TPhpMajorVersion') {
$template_result->lower_bounds[$template_type->param_name] = [
'fn-' . strtolower((string) $method_id) => [
'fn-' . strtolower($method_id->method_name) => [

Check failure on line 588 in src/Psalm/Internal/Analyzer/Statements/Expression/Call/Method/MethodCallReturnTypeFetcher.php

View workflow job for this annotation

GitHub Actions / build

RedundantFunctionCall

src/Psalm/Internal/Analyzer/Statements/Expression/Call/Method/MethodCallReturnTypeFetcher.php:588:37: RedundantFunctionCall: The call to strtolower is unnecessary (see https://psalm.dev/280)
new TemplateBound(
Type::getInt(false, $codebase->getMajorAnalysisPhpVersion()),
),
],
];
} elseif ($template_type->param_name === 'TPhpVersionId') {
$template_result->lower_bounds[$template_type->param_name] = [
'fn-' . strtolower((string) $method_id) => [
'fn-' . strtolower($method_id->method_name) => [

Check failure on line 596 in src/Psalm/Internal/Analyzer/Statements/Expression/Call/Method/MethodCallReturnTypeFetcher.php

View workflow job for this annotation

GitHub Actions / build

RedundantFunctionCall

src/Psalm/Internal/Analyzer/Statements/Expression/Call/Method/MethodCallReturnTypeFetcher.php:596:37: RedundantFunctionCall: The call to strtolower is unnecessary (see https://psalm.dev/280)
new TemplateBound(
Type::getInt(
false,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -629,7 +629,7 @@ private static function resolveTemplateResultLowerBound(
): array {
if ($template_type->param_name === 'TFunctionArgCount') {
return [
'fn-' . strtolower((string)$method_id) => [
'fn-' . strtolower($method_id->method_name) => [

Check failure on line 632 in src/Psalm/Internal/Analyzer/Statements/Expression/Call/StaticMethod/ExistingAtomicStaticCallAnalyzer.php

View workflow job for this annotation

GitHub Actions / build

RedundantFunctionCall

src/Psalm/Internal/Analyzer/Statements/Expression/Call/StaticMethod/ExistingAtomicStaticCallAnalyzer.php:632:25: RedundantFunctionCall: The call to strtolower is unnecessary (see https://psalm.dev/280)
new TemplateBound(
Type::getInt(false, count($stmt->getArgs())),
),
Expand All @@ -639,7 +639,7 @@ private static function resolveTemplateResultLowerBound(

if ($template_type->param_name === 'TPhpMajorVersion') {
return [
'fn-' . strtolower((string)$method_id) => [
'fn-' . strtolower($method_id->method_name) => [

Check failure on line 642 in src/Psalm/Internal/Analyzer/Statements/Expression/Call/StaticMethod/ExistingAtomicStaticCallAnalyzer.php

View workflow job for this annotation

GitHub Actions / build

RedundantFunctionCall

src/Psalm/Internal/Analyzer/Statements/Expression/Call/StaticMethod/ExistingAtomicStaticCallAnalyzer.php:642:25: RedundantFunctionCall: The call to strtolower is unnecessary (see https://psalm.dev/280)
new TemplateBound(
Type::getInt(false, $codebase->getMajorAnalysisPhpVersion()),
),
Expand All @@ -649,7 +649,7 @@ private static function resolveTemplateResultLowerBound(

if ($template_type->param_name === 'TPhpVersionId') {
return [
'fn-' . strtolower((string) $method_id) => [
'fn-' . strtolower($method_id->method_name) => [

Check failure on line 652 in src/Psalm/Internal/Analyzer/Statements/Expression/Call/StaticMethod/ExistingAtomicStaticCallAnalyzer.php

View workflow job for this annotation

GitHub Actions / build

RedundantFunctionCall

src/Psalm/Internal/Analyzer/Statements/Expression/Call/StaticMethod/ExistingAtomicStaticCallAnalyzer.php:652:25: RedundantFunctionCall: The call to strtolower is unnecessary (see https://psalm.dev/280)
new TemplateBound(
Type::getInt(
false,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -512,9 +512,8 @@ private static function getConditionalSanitizedTypeTokens(

if ($token_body === 'func_num_args()') {
$template_name = 'TFunctionArgCount';

$storage->template_types[$template_name] = [
$template_function_id => Type::getInt(),
'fn-' . strtolower($storage->cased_name) => Type::getInt(),

Check failure on line 516 in src/Psalm/Internal/PhpVisitor/Reflector/FunctionLikeDocblockScanner.php

View workflow job for this annotation

GitHub Actions / build

PossiblyNullArgument

src/Psalm/Internal/PhpVisitor/Reflector/FunctionLikeDocblockScanner.php:516:40: PossiblyNullArgument: Argument 1 of strtolower cannot be null, possibly null value provided (see https://psalm.dev/078)
];

$function_template_types[$template_name]
Expand All @@ -527,7 +526,7 @@ private static function getConditionalSanitizedTypeTokens(
$template_name = 'TPhpMajorVersion';

$storage->template_types[$template_name] = [
$template_function_id => Type::getInt(),
'fn-' . strtolower($storage->cased_name) => Type::getInt(),

Check failure on line 529 in src/Psalm/Internal/PhpVisitor/Reflector/FunctionLikeDocblockScanner.php

View workflow job for this annotation

GitHub Actions / build

PossiblyNullArgument

src/Psalm/Internal/PhpVisitor/Reflector/FunctionLikeDocblockScanner.php:529:40: PossiblyNullArgument: Argument 1 of strtolower cannot be null, possibly null value provided (see https://psalm.dev/078)
];

$function_template_types[$template_name]
Expand All @@ -540,7 +539,7 @@ private static function getConditionalSanitizedTypeTokens(
$template_name = 'TPhpVersionId';

$storage->template_types[$template_name] = [
$template_function_id => Type::getInt(),
'fn-' . strtolower($storage->cased_name) => Type::getInt(),

Check failure on line 542 in src/Psalm/Internal/PhpVisitor/Reflector/FunctionLikeDocblockScanner.php

View workflow job for this annotation

GitHub Actions / build

PossiblyNullArgument

src/Psalm/Internal/PhpVisitor/Reflector/FunctionLikeDocblockScanner.php:542:40: PossiblyNullArgument: Argument 1 of strtolower cannot be null, possibly null value provided (see https://psalm.dev/078)
];

$function_template_types[$template_name]
Expand Down
58 changes: 58 additions & 0 deletions tests/Template/ConditionalReturnTypeTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -463,6 +463,31 @@ function zeroArgsFalseOneArgString(string $s = "") {
'$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): int|string
{
if ($b) {
return 1;
}
return "";
}
}
class B extends A
{
public static function getB(bool $a): int
{
return self::get($a, true);
}
}',
],
'namespaceFuncNumArgs' => [
'code' => '<?php
namespace Foo;
Expand Down Expand Up @@ -887,6 +912,39 @@ function getSomethingElse()
'ignored_issues' => [],
'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' => [
'code' => '<?php
/** @template InstanceType */
Expand Down

0 comments on commit 9a32afd

Please sign in to comment.