1
0
mirror of https://github.com/danog/psalm.git synced 2025-01-21 21:31:13 +01:00

narrowed reset and end return type (#3950)

* narrowed `reset` return type
BUT psalm seems to ignore the stub

* narrowed `reset` and `end` return type, this time for real

* fixed UnusedVariable Issue

* fixed RedundantCondition Issue
caused by `end`s return type being more precise

* Improve solution slightly

Co-authored-by: Matthew Brown <github@muglug.com>
This commit is contained in:
ygottschalk 2020-08-07 18:23:20 +02:00 committed by GitHub
parent 84130770f4
commit f831ebdbcf
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
3 changed files with 166 additions and 7 deletions

View File

@ -1164,7 +1164,7 @@ class ClassLikes
unset($uses_flipped[$old_fq_class_name]);
$old_class_name_parts = explode('\\', $old_fq_class_name);
$old_class_name = end($old_class_name_parts);
if (strtolower($old_class_name) === strtolower($alias)) {
if ($old_class_name === strtolower($alias)) {
$new_class_name_parts = explode('\\', $new_fq_class_name);
$new_class_name = end($new_class_name_parts);
$uses_flipped[strtolower($new_fq_class_name)] = $new_class_name;
@ -1321,7 +1321,7 @@ class ClassLikes
unset($uses_flipped[$old_fq_class_name]);
$old_class_name_parts = explode('\\', $old_fq_class_name);
$old_class_name = end($old_class_name_parts);
if (strtolower($old_class_name) === strtolower($alias)) {
if ($old_class_name === strtolower($alias)) {
$new_class_name_parts = explode('\\', $new_fq_class_name);
$new_class_name = end($new_class_name_parts);
$uses_flipped[strtolower($new_fq_class_name)] = $new_class_name;

View File

@ -46,18 +46,25 @@ class ArrayPointerAdjustmentReturnTypeProvider implements \Psalm\Plugin\Hook\Fun
if ($first_arg_array instanceof Type\Atomic\TArray) {
$value_type = clone $first_arg_array->type_params[1];
$definitely_has_items = $first_arg_array instanceof Type\Atomic\TNonEmptyArray;
} elseif ($first_arg_array instanceof Type\Atomic\TList) {
$value_type = clone $first_arg_array->type_param;
$definitely_has_items = $first_arg_array instanceof Type\Atomic\TNonEmptyList;
} else {
$value_type = $first_arg_array->getGenericValueType();
$definitely_has_items = $value_type instanceof Type\Atomic\TNonEmptyArray;
}
$value_type->addType(new Type\Atomic\TFalse);
if ($value_type->isEmpty()) {
$value_type = Type::getFalse();
} elseif (($function_id !== 'reset' && $function_id !== 'end') || !$definitely_has_items) {
$value_type->addType(new Type\Atomic\TFalse);
$codebase = $statements_source->getCodebase();
$codebase = $statements_source->getCodebase();
if ($codebase->config->ignore_internal_falsable_issues) {
$value_type->ignore_falsable_issues = true;
if ($codebase->config->ignore_internal_falsable_issues) {
$value_type->ignore_falsable_issues = true;
}
}
return $value_type;

View File

@ -885,6 +885,158 @@ class ArrayFunctionCallTest extends TestCase
'$b' => 'null'
],
],
'arrayResetNonEmptyArray' => [
'<?php
/** @return non-empty-array<string, int> */
function makeArray(): array { return ["one" => 1, "two" => 3]; }
$a = makeArray();
$b = reset($a);',
'assertions' => [
'$b' => 'int'
],
],
'arrayResetNonEmptyList' => [
'<?php
/** @return non-empty-list<int> */
function makeArray(): array { return [1, 3]; }
$a = makeArray();
$b = reset($a);',
'assertions' => [
'$b' => 'int'
],
],
'arrayResetNonEmptyObjectLike' => [
'<?php
$a = ["one" => 1, "two" => 3];
$b = reset($a);',
'assertions' => [
'$b' => 'int'
],
],
'arrayResetEmptyArray' => [
'<?php
$a = [];
$b = reset($a);',
'assertions' => [
'$b' => 'false'
],
],
'arrayResetEmptyList' => [
'<?php
/** @return list<empty> */
function makeArray(): array { return []; }
$a = makeArray();
$b = reset($a);',
'assertions' => [
'$b' => 'false'
],
],
'arrayResetMaybeEmptyArray' => [
'<?php
/** @return array<string, int> */
function makeArray(): array { return ["one" => 1, "two" => 3]; }
$a = makeArray();
$b = reset($a);',
'assertions' => [
'$b' => 'false|int'
],
],
'arrayResetMaybeEmptyList' => [
'<?php
/** @return list<int> */
function makeArray(): array { return []; }
$a = makeArray();
$b = reset($a);',
'assertions' => [
'$b' => 'false|int'
],
],
'arrayResetMaybeEmptyObjectLike' => [
'<?php
/** @return array{foo?: int} */
function makeArray(): array { return []; }
$a = makeArray();
$b = reset($a);',
'assertions' => [
'$b' => 'false|int'
],
],
'arrayEndNonEmptyArray' => [
'<?php
/** @return non-empty-array<string, int> */
function makeArray(): array { return ["one" => 1, "two" => 3]; }
$a = makeArray();
$b = end($a);',
'assertions' => [
'$b' => 'int'
],
],
'arrayEndNonEmptyList' => [
'<?php
/** @return non-empty-list<int> */
function makeArray(): array { return [1, 3]; }
$a = makeArray();
$b = end($a);',
'assertions' => [
'$b' => 'int'
],
],
'arrayEndNonEmptyObjectLike' => [
'<?php
$a = ["one" => 1, "two" => 3];
$b = end($a);',
'assertions' => [
'$b' => 'int'
],
],
'arrayEndEmptyArray' => [
'<?php
$a = [];
$b = end($a);',
'assertions' => [
'$b' => 'false'
],
],
'arrayEndEmptyList' => [
'<?php
/** @return list<empty> */
function makeArray(): array { return []; }
$a = makeArray();
$b = end($a);',
'assertions' => [
'$b' => 'false'
],
],
'arrayEndMaybeEmptyArray' => [
'<?php
/** @return array<string, int> */
function makeArray(): array { return ["one" => 1, "two" => 3]; }
$a = makeArray();
$b = end($a);',
'assertions' => [
'$b' => 'false|int'
],
],
'arrayEndMaybeEmptyList' => [
'<?php
/** @return list<int> */
function makeArray(): array { return []; }
$a = makeArray();
$b = end($a);',
'assertions' => [
'$b' => 'false|int'
],
],
'arrayEndMaybeEmptyObjectLike' => [
'<?php
/** @return array{foo?: int} */
function makeArray(): array { return []; }
$a = makeArray();
$b = end($a);',
'assertions' => [
'$b' => 'false|int'
],
],
'arrayColumnInference' => [
'<?php
function makeMixedArray(): array { return []; }