From d72b74f0a0d47a5d554dc153a780e16263ce00c3 Mon Sep 17 00:00:00 2001 From: Daniel Leech Date: Mon, 11 Mar 2024 22:23:49 +0000 Subject: [PATCH] gh-2576: Basic array_reduce stub --- CHANGELOG.md | 7 ++++ .../FunctionStub/ArrayReduceStub.php | 12 +++---- .../Resolver/AssignmentExpressionResolver.php | 12 ++++--- lib/WorseReflection/Core/Type/ArrayType.php | 11 +++++++ .../Inference/function/array_reduce.test | 33 ++++++++++++++++--- 5 files changed, 57 insertions(+), 18 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 7fa8c4633a..9e2bd84a79 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,6 +1,13 @@ Changelog ========= +## master + +Improvements: + + - Basic support for `array_reduce` stub #2576 + + ## 2024-03-09 Features: diff --git a/lib/WorseReflection/Core/Inference/FunctionStub/ArrayReduceStub.php b/lib/WorseReflection/Core/Inference/FunctionStub/ArrayReduceStub.php index 107fc2b36d..639bb4e86d 100644 --- a/lib/WorseReflection/Core/Inference/FunctionStub/ArrayReduceStub.php +++ b/lib/WorseReflection/Core/Inference/FunctionStub/ArrayReduceStub.php @@ -7,7 +7,6 @@ use Phpactor\WorseReflection\Core\Inference\FunctionStub; use Phpactor\WorseReflection\Core\Inference\NodeContext; use Phpactor\WorseReflection\Core\TypeFactory; -use Phpactor\WorseReflection\Core\Type\ClosureType; class ArrayReduceStub implements FunctionStub { @@ -16,15 +15,12 @@ public function resolve( NodeContext $context, FunctionArguments $args ): NodeContext { - if (!$args->at(0)->type()->isDefined()) { - return $context; + $initialType = $args->at(2)->type(); + if ($initialType->isDefined()) { + return $context->withType($initialType->generalize()); } - $closureType = $args->at(1); - if (!$closureType instanceof ClosureType) { - return $context; - } + return $context->withType(TypeFactory::array()); - return $context->withType(TypeFactory::array($closureType->returnType())); } } diff --git a/lib/WorseReflection/Core/Inference/Resolver/AssignmentExpressionResolver.php b/lib/WorseReflection/Core/Inference/Resolver/AssignmentExpressionResolver.php index c6e99efd2a..b2cd2eb108 100644 --- a/lib/WorseReflection/Core/Inference/Resolver/AssignmentExpressionResolver.php +++ b/lib/WorseReflection/Core/Inference/Resolver/AssignmentExpressionResolver.php @@ -179,11 +179,13 @@ private function walkSubscriptExpression(NodeContextResolver $resolver, Frame $f return; } - $frame->locals()->set( - $variable->withType( - $type->set($accessType->value(), $rightContext->type()) - )->withOffset($leftOperand->getStartPosition()) - ); + if ($type instanceof ArrayLiteral) { + $frame->locals()->set( + $variable->withType( + $type->set($accessType->value(), $rightContext->type()) + )->withOffset($leftOperand->getStartPosition()) + ); + } continue; } diff --git a/lib/WorseReflection/Core/Type/ArrayType.php b/lib/WorseReflection/Core/Type/ArrayType.php index 65bd871ef7..4b909cfcbb 100644 --- a/lib/WorseReflection/Core/Type/ArrayType.php +++ b/lib/WorseReflection/Core/Type/ArrayType.php @@ -54,4 +54,15 @@ public function allTypes(): Types { return (new Types([TypeFactory::array()]))->merge(parent::allTypes()); } + + public function add(Type $type): self + { + if (null === $this->valueType) { + return new self($this->keyType, $type); + } + if (!$this->valueType->isDefined()) { + return new self($this->keyType, $type); + } + return new self($this->keyType, $this->valueType->addType($type)); + } } diff --git a/lib/WorseReflection/Tests/Inference/function/array_reduce.test b/lib/WorseReflection/Tests/Inference/function/array_reduce.test index 285cdc721b..8e93d82f65 100644 --- a/lib/WorseReflection/Tests/Inference/function/array_reduce.test +++ b/lib/WorseReflection/Tests/Inference/function/array_reduce.test @@ -1,7 +1,30 @@ ', $carry); - return $carry; - }, []), +$reduced = array_reduce(['foobar'], function (int $carry, string $foo): int { +}, 0); + +wrAssertType('int', $reduced); + +$reduced = array_reduce(['foobar'], function (int $carry, string $foo): int { +}, ['string']); + +wrAssertType('array', $reduced); + + +// we cannot currently analyze the closure to determine the +$reduced = array_reduce(['foobar'], function (array $carry, string $foo): int { + $carry[] = 'foo'; + return $carry; +}, []); + +// should be string[] but we can't currently analyze the closure frames return type +wrAssertType('array', $reduced); + +$reduced = array_reduce(['foobar'], function (int $carry, string $foo): int { +}, ''); + +wrAssertType('string', $reduced); + +$reduced = array_reduce(['foobar'], function (int $carry, string $foo): int { +}); +wrAssertType('array', $reduced);