From 03c39cbe7c7096ec89cfef7a9790b54e46a28bf2 Mon Sep 17 00:00:00 2001 From: Matthew Brown Date: Thu, 10 Oct 2019 20:16:43 -0400 Subject: [PATCH] Fix #2223 - make sure lists are handled in more places --- src/Psalm/Internal/Analyzer/FunctionAnalyzer.php | 10 ++++++++++ .../Assignment/ArrayAssignmentAnalyzer.php | 3 ++- .../Analyzer/Statements/Expression/CallAnalyzer.php | 10 +++++----- .../Expression/Fetch/ArrayFetchAnalyzer.php | 4 +++- src/Psalm/Internal/Codebase/CallMap.php | 10 ++++++---- src/Psalm/Internal/Scanner/PhpStormMetaScanner.php | 12 ++++++++++-- src/Psalm/Internal/Visitor/ReflectorVisitor.php | 4 +++- 7 files changed, 39 insertions(+), 14 deletions(-) diff --git a/src/Psalm/Internal/Analyzer/FunctionAnalyzer.php b/src/Psalm/Internal/Analyzer/FunctionAnalyzer.php index 1cbccf590..707910f80 100644 --- a/src/Psalm/Internal/Analyzer/FunctionAnalyzer.php +++ b/src/Psalm/Internal/Analyzer/FunctionAnalyzer.php @@ -120,6 +120,12 @@ class FunctionAnalyzer extends FunctionLikeAnalyzer ? new Type\Atomic\TLiteralInt($atomic_types['array']->count) : new Type\Atomic\TInt ]); + } elseif ($atomic_types['array'] instanceof Type\Atomic\TNonEmptyList) { + return new Type\Union([ + $atomic_types['array']->count !== null + ? new Type\Atomic\TLiteralInt($atomic_types['array']->count) + : new Type\Atomic\TInt + ]); } elseif ($atomic_types['array'] instanceof Type\Atomic\ObjectLike && $atomic_types['array']->sealed ) { @@ -307,6 +313,10 @@ class FunctionAnalyzer extends FunctionLikeAnalyzer if ($array_type instanceof Type\Atomic\TArray) { return clone $array_type->type_params[1]; } + + if ($array_type instanceof Type\Atomic\TList) { + return clone $array_type->type_param; + } } elseif ($first_arg->inferredType->hasScalarType() && isset($call_args[1]) && ($second_arg = $call_args[1]->value) && diff --git a/src/Psalm/Internal/Analyzer/Statements/Expression/Assignment/ArrayAssignmentAnalyzer.php b/src/Psalm/Internal/Analyzer/Statements/Expression/Assignment/ArrayAssignmentAnalyzer.php index a1b31ecdd..944d4284a 100644 --- a/src/Psalm/Internal/Analyzer/Statements/Expression/Assignment/ArrayAssignmentAnalyzer.php +++ b/src/Psalm/Internal/Analyzer/Statements/Expression/Assignment/ArrayAssignmentAnalyzer.php @@ -518,7 +518,8 @@ class ArrayAssignmentAnalyzer $atomic_root_types = $new_child_type->getTypes(); if (isset($atomic_root_types['array']) - && $atomic_root_types['array'] instanceof TNonEmptyArray + && ($atomic_root_types['array'] instanceof TNonEmptyArray + || $atomic_root_types['array'] instanceof TNonEmptyList) && $atomic_root_types['array']->count !== null ) { $atomic_root_types['array']->count++; diff --git a/src/Psalm/Internal/Analyzer/Statements/Expression/CallAnalyzer.php b/src/Psalm/Internal/Analyzer/Statements/Expression/CallAnalyzer.php index 36545d08b..a6652a2ab 100644 --- a/src/Psalm/Internal/Analyzer/Statements/Expression/CallAnalyzer.php +++ b/src/Psalm/Internal/Analyzer/Statements/Expression/CallAnalyzer.php @@ -816,7 +816,7 @@ class CallAnalyzer if (isset($array_arg->inferredType) && $array_arg->inferredType->hasArray()) { /** * @psalm-suppress PossiblyUndefinedArrayOffset - * @var TArray|ObjectLike + * @var TArray|ObjectLike|TList */ $array_type = $array_arg->inferredType->getTypes()['array']; @@ -961,7 +961,7 @@ class CallAnalyzer ) { /** * @psalm-suppress PossiblyUndefinedArrayOffset - * @var TArray|ObjectLike + * @var TArray|ObjectLike|TList */ $array_type = $array_arg->inferredType->getTypes()['array']; @@ -971,7 +971,7 @@ class CallAnalyzer /** * @psalm-suppress PossiblyUndefinedArrayOffset - * @var TArray|ObjectLike + * @var TArray|ObjectLike|TList */ $replacement_array_type = $replacement_arg->inferredType->getTypes()['array']; @@ -1435,11 +1435,11 @@ class CallAnalyzer ) { /** * @psalm-suppress PossiblyUndefinedArrayOffset - * @var TArray + * @var TList */ $array_type = $param_type->getTypes()['array']; - $param_type = $array_type->type_params[1]; + $param_type = $array_type->type_param; } if ($param_type && !$param_type->hasMixed()) { diff --git a/src/Psalm/Internal/Analyzer/Statements/Expression/Fetch/ArrayFetchAnalyzer.php b/src/Psalm/Internal/Analyzer/Statements/Expression/Fetch/ArrayFetchAnalyzer.php index 0c6c7f4ec..14f61abad 100644 --- a/src/Psalm/Internal/Analyzer/Statements/Expression/Fetch/ArrayFetchAnalyzer.php +++ b/src/Psalm/Internal/Analyzer/Statements/Expression/Fetch/ArrayFetchAnalyzer.php @@ -183,12 +183,14 @@ class ArrayFetchAnalyzer ) { /** * @psalm-suppress PossiblyUndefinedArrayOffset - * @var TArray|ObjectLike + * @var TArray|ObjectLike|TList */ $array_type = $stmt->var->inferredType->getTypes()['array']; if ($array_type instanceof TArray) { $const_array_key_type = $array_type->type_params[0]; + } elseif ($array_type instanceof TList) { + $const_array_key_type = $array_type->type_param; } else { $const_array_key_type = $array_type->getGenericKeyType(); } diff --git a/src/Psalm/Internal/Codebase/CallMap.php b/src/Psalm/Internal/Codebase/CallMap.php index ea35d3aeb..b85d34e87 100644 --- a/src/Psalm/Internal/Codebase/CallMap.php +++ b/src/Psalm/Internal/Codebase/CallMap.php @@ -135,15 +135,17 @@ class CallMap if ($arg_type->hasArray()) { /** * @psalm-suppress PossiblyUndefinedArrayOffset - * @var Type\Atomic\TArray|Type\Atomic\ObjectLike + * @var Type\Atomic\TArray|Type\Atomic\ObjectLike|Type\Atomic\TList */ $array_atomic_type = $arg_type->getTypes()['array']; if ($array_atomic_type instanceof Type\Atomic\ObjectLike) { - $array_atomic_type = $array_atomic_type->getGenericArrayType(); + $arg_type = $array_atomic_type->getGenericValueType(); + } elseif ($array_atomic_type instanceof Type\Atomic\TList) { + $arg_type = $array_atomic_type->type_param; + } else { + $arg_type = $array_atomic_type->type_params[1]; } - - $arg_type = $array_atomic_type->type_params[1]; } } diff --git a/src/Psalm/Internal/Scanner/PhpStormMetaScanner.php b/src/Psalm/Internal/Scanner/PhpStormMetaScanner.php index dc99add8e..357f4ed43 100644 --- a/src/Psalm/Internal/Scanner/PhpStormMetaScanner.php +++ b/src/Psalm/Internal/Scanner/PhpStormMetaScanner.php @@ -203,7 +203,7 @@ class PhpStormMetaScanner if ($call_arg_type->hasArray()) { /** * @psalm-suppress PossiblyUndefinedArrayOffset - * @var Type\Atomic\TArray|Type\Atomic\ObjectLike + * @var Type\Atomic\TArray|Type\Atomic\ObjectLike|Type\Atomic\TList */ $array_atomic_type = $call_arg_type->getTypes()['array']; @@ -211,6 +211,10 @@ class PhpStormMetaScanner return $array_atomic_type->getGenericValueType(); } + if ($array_atomic_type instanceof Type\Atomic\TList) { + return $array_atomic_type->type_param; + } + return clone $array_atomic_type->type_params[1]; } } @@ -334,7 +338,7 @@ class PhpStormMetaScanner if ($call_arg_type->hasArray()) { /** * @psalm-suppress PossiblyUndefinedArrayOffset - * @var Type\Atomic\TArray|Type\Atomic\ObjectLike + * @var Type\Atomic\TArray|Type\Atomic\ObjectLike|Type\Atomic\TList */ $array_atomic_type = $call_arg_type->getTypes()['array']; @@ -342,6 +346,10 @@ class PhpStormMetaScanner return $array_atomic_type->getGenericValueType(); } + if ($array_atomic_type instanceof Type\Atomic\TList) { + return $array_atomic_type->type_param; + } + return clone $array_atomic_type->type_params[1]; } } diff --git a/src/Psalm/Internal/Visitor/ReflectorVisitor.php b/src/Psalm/Internal/Visitor/ReflectorVisitor.php index 12bc78d62..1cdc9c874 100644 --- a/src/Psalm/Internal/Visitor/ReflectorVisitor.php +++ b/src/Psalm/Internal/Visitor/ReflectorVisitor.php @@ -2853,12 +2853,14 @@ class ReflectorVisitor extends PhpParser\NodeVisitorAbstract implements PhpParse if (!$docblock_param_variadic && $storage_param->is_variadic && $new_param_type->hasArray()) { /** * @psalm-suppress PossiblyUndefinedArrayOffset - * @var Type\Atomic\TArray|Type\Atomic\ObjectLike + * @var Type\Atomic\TArray|Type\Atomic\ObjectLike|Type\Atomic\TList */ $array_type = $new_param_type->getTypes()['array']; if ($array_type instanceof Type\Atomic\ObjectLike) { $new_param_type = $array_type->getGenericValueType(); + } elseif ($array_type instanceof Type\Atomic\TList) { + $new_param_type = $array_type->type_param; } else { $new_param_type = $array_type->type_params[1]; }