From 823bc51c72ae74ca990226addbc50af046efa547 Mon Sep 17 00:00:00 2001 From: "ondrej@mirtes.cz" Date: Fri, 6 Nov 2026 19:56:59 +0000 Subject: [PATCH 1/2] Ask Scope::getPhpVersion() instead of the injected PhpVersion in rules and expression handlers With a phpVersion range (or a composer.json PHP constraint), the injected PhpVersion is only the range's minimum. Rules and expression handlers now ask the scope, which knows the whole range and PHP_VERSION_ID narrowing: - Rules that report a problem (deprecations, tentative return types, invalid array keys, missing magic serialization methods, ...) report it when any version in the range is affected. - Throw points (property hooks, __toString() on string casts) are added when any version in the range may throw. - Checks that only relax an error (readonly assignment from a subclass, readonly reinitialization in __clone) need every version in the range. - MutatingScope's readonly property tracking, canWriteProperty() and the clone reinitialization follow the scope's versions too, and array unpacking keeps string keys when any version supports it. The native turbo-ext mirrors follow the same changes. Amp-Thread-ID: https://ampcode.com/threads/T-01a1b1b9-0a7d-772a-a8bb-331fd76aa9cc --- .../OverrideAttributeThirdPartyMethodRule.php | 2 +- src/Analyser/ExprHandler/ArrayHandler.php | 8 +- src/Analyser/ExprHandler/AssignHandler.php | 6 +- .../Helper/ImplicitToStringCallHelper.php | 4 +- .../ExprHandler/PropertyFetchHandler.php | 6 +- src/Analyser/MutatingScope.php | 30 +- src/Php/PhpVersions.php | 80 ++ .../InitializerExprTypeResolver.php | 12 +- src/Rules/Arrays/AllowedArrayKeysTypes.php | 8 +- .../Arrays/InvalidKeyInArrayDimFetchRule.php | 4 +- .../Arrays/InvalidKeyInArrayItemRule.php | 4 +- src/Rules/FunctionDefinitionCheck.php | 21 +- src/Rules/Functions/DefineParametersRule.php | 7 +- src/Rules/Functions/FilterVarRule.php | 4 +- src/Rules/Methods/MethodPrototypeFinder.php | 7 +- .../MissingMagicSerializationMethodsRule.php | 7 +- src/Rules/Methods/OverridingMethodRule.php | 7 +- src/Rules/Operators/BacktickRule.php | 9 +- .../Operators/InvalidIncDecOperationRule.php | 10 +- .../Properties/PropertyAssignRefRule.php | 4 +- .../Properties/ReadOnlyPropertyAssignRule.php | 6 +- src/Rules/Variables/UnsetRule.php | 4 +- ...hpVersionRangeReturnTypeExtensionsTest.php | 2 + .../array-unpacking-php-version-range.php | 21 + .../readonly-property-php-version-range.php | 39 + ...lidKeyInArrayDimFetchRuleConfigPhpTest.php | 40 + .../InvalidKeyInArrayDimFetchRuleTest.php | 2 - ...InvalidKeyInArrayItemRuleConfigPhpTest.php | 40 + .../Arrays/InvalidKeyInArrayItemRuleTest.php | 2 - .../data/invalid-key-php-version-range.php | 13 + ...thUnthrownExceptionRuleConfigPhp73Test.php | 37 + .../CatchWithUnthrownExceptionRuleTest.php | 15 + .../unthrown-exception-php-version-range.php | 59 ++ ...exception-property-hooks-version-guard.php | 66 ++ .../Exceptions/php-version-range-73.neon | 4 + .../DefineParametersRuleConfigPhpTest.php | 36 + .../Functions/DefineParametersRuleTest.php | 3 +- ...lassesInArrowFunctionTypehintsRuleTest.php | 187 +--- ...stingClassesInClosureTypehintsRuleTest.php | 187 +--- ...ingClassesInTypehintsRuleConfigPhpTest.php | 44 + .../ExistingClassesInTypehintsRuleTest.php | 187 +--- .../Functions/FilterVarRuleConfigPhpTest.php | 35 + .../Rules/Functions/FilterVarRuleTest.php | 2 - .../function-definition-php-version-range.php | 15 + .../ExistingClassesInTypehintsRuleTest.php | 187 +--- ...thPossiblyRenamedNamedArgumentRuleTest.php | 2 +- .../Rules/Methods/MethodSignatureRuleTest.php | 2 +- ...cSerializationMethodsRuleConfigPhpTest.php | 44 + ...ssingMagicSerializationMethodsRuleTest.php | 4 +- .../OverridingMethodRuleConfigPhpTest.php | 69 ++ .../Methods/OverridingMethodRuleTest.php | 116 +-- .../Operators/BacktickRuleConfigPhpTest.php | 44 + .../Rules/Operators/BacktickRuleTest.php | 3 +- ...nvalidIncDecOperationRuleConfigPhpTest.php | 73 ++ .../PropertyAssignRefRuleConfigPhpTest.php | 50 + .../Properties/PropertyAssignRefRuleTest.php | 4 +- ...eadOnlyPropertyAssignRuleConfigPhpTest.php | 42 + .../ReadOnlyPropertyAssignRuleTest.php | 2 - .../Properties/data/php-version-range-81.neon | 4 + ...only-property-assign-php-version-range.php | 48 + .../Variables/UnsetRuleConfigPhpTest.php | 36 + .../PHPStan/Rules/Variables/UnsetRuleTest.php | 2 - .../data/unset-php-version-range.php | 15 + .../PHPStan/Rules/data/php-version-range.neon | 4 + turbo-ext/src/ArrayHandler.cpp | 16 +- turbo-ext/src/AssignHandler.cpp | 18 +- turbo-ext/src/ImplicitToStringCallHelper.cpp | 29 +- turbo-ext/src/InitializerExprTypeResolver.cpp | 42 +- turbo-ext/src/MutatingScope.cpp | 106 +- turbo-ext/src/PhpVersionAccess.cpp | 5 - turbo-ext/src/PropertyFetchHandler.cpp | 24 +- .../src/PropertyHookThrowPointsResolver.cpp | 15 - turbo-ext/src/generated/AssignHandler.h | 921 +++++++++--------- .../generated/ImplicitToStringCallHelper.h | 59 +- .../generated/InitializerExprTypeResolver.h | 197 ++-- .../src/generated/PropertyFetchHandler.h | 167 ++-- turbo-ext/src/support.h | 15 +- turbo-ext/tests/scope-family.php | 40 +- 78 files changed, 2150 insertions(+), 1541 deletions(-) create mode 100644 tests/PHPStan/Analyser/data/array-unpacking-php-version-range.php create mode 100644 tests/PHPStan/Analyser/data/readonly-property-php-version-range.php create mode 100644 tests/PHPStan/Rules/Arrays/InvalidKeyInArrayDimFetchRuleConfigPhpTest.php create mode 100644 tests/PHPStan/Rules/Arrays/InvalidKeyInArrayItemRuleConfigPhpTest.php create mode 100644 tests/PHPStan/Rules/Arrays/data/invalid-key-php-version-range.php create mode 100644 tests/PHPStan/Rules/Exceptions/CatchWithUnthrownExceptionRuleConfigPhp73Test.php create mode 100644 tests/PHPStan/Rules/Exceptions/data/unthrown-exception-php-version-range.php create mode 100644 tests/PHPStan/Rules/Exceptions/data/unthrown-exception-property-hooks-version-guard.php create mode 100644 tests/PHPStan/Rules/Exceptions/php-version-range-73.neon create mode 100644 tests/PHPStan/Rules/Functions/DefineParametersRuleConfigPhpTest.php create mode 100644 tests/PHPStan/Rules/Functions/ExistingClassesInTypehintsRuleConfigPhpTest.php create mode 100644 tests/PHPStan/Rules/Functions/FilterVarRuleConfigPhpTest.php create mode 100644 tests/PHPStan/Rules/Functions/data/function-definition-php-version-range.php create mode 100644 tests/PHPStan/Rules/Methods/MissingMagicSerializationMethodsRuleConfigPhpTest.php create mode 100644 tests/PHPStan/Rules/Methods/OverridingMethodRuleConfigPhpTest.php create mode 100644 tests/PHPStan/Rules/Operators/BacktickRuleConfigPhpTest.php create mode 100644 tests/PHPStan/Rules/Operators/InvalidIncDecOperationRuleConfigPhpTest.php create mode 100644 tests/PHPStan/Rules/Properties/PropertyAssignRefRuleConfigPhpTest.php create mode 100644 tests/PHPStan/Rules/Properties/ReadOnlyPropertyAssignRuleConfigPhpTest.php create mode 100644 tests/PHPStan/Rules/Properties/data/php-version-range-81.neon create mode 100644 tests/PHPStan/Rules/Properties/data/readonly-property-assign-php-version-range.php create mode 100644 tests/PHPStan/Rules/Variables/UnsetRuleConfigPhpTest.php create mode 100644 tests/PHPStan/Rules/Variables/data/unset-php-version-range.php create mode 100644 tests/PHPStan/Rules/data/php-version-range.neon diff --git a/build/PHPStan/Build/OverrideAttributeThirdPartyMethodRule.php b/build/PHPStan/Build/OverrideAttributeThirdPartyMethodRule.php index eb13c987e3b..fe9546a678f 100644 --- a/build/PHPStan/Build/OverrideAttributeThirdPartyMethodRule.php +++ b/build/PHPStan/Build/OverrideAttributeThirdPartyMethodRule.php @@ -34,7 +34,7 @@ public function getNodeType(): string public function processNode(Node $node, Scope $scope): array { $method = $node->getMethodReflection(); - $prototypeData = $this->methodPrototypeFinder->findPrototype($node->getClassReflection(), $method->getName()); + $prototypeData = $this->methodPrototypeFinder->findPrototype($node->getClassReflection(), $method->getName(), $scope->getPhpVersion()); if ($prototypeData === null) { return []; } diff --git a/src/Analyser/ExprHandler/ArrayHandler.php b/src/Analyser/ExprHandler/ArrayHandler.php index 186169a8830..3863286fd74 100644 --- a/src/Analyser/ExprHandler/ArrayHandler.php +++ b/src/Analyser/ExprHandler/ArrayHandler.php @@ -299,7 +299,7 @@ private function getWalkedArrayType(NodeScopeResolver $nodeScopeResolver, array } if ($inner instanceof Array_) { - return $this->initializerExprTypeResolver->getArrayType($inner, $getType); + return $this->initializerExprTypeResolver->getArrayType($inner, $getType, $scope->getPhpVersion()); } if ($inner instanceof Scalar\String_ || $inner instanceof Scalar\Int_ || $inner instanceof Scalar\Float_) { @@ -309,7 +309,7 @@ private function getWalkedArrayType(NodeScopeResolver $nodeScopeResolver, array return new MixedType(); }; - return $this->initializerExprTypeResolver->getArrayType($walk['expr'], $getType); + return $this->initializerExprTypeResolver->getArrayType($walk['expr'], $getType, $scope->getPhpVersion()); } /** @@ -394,7 +394,7 @@ private function createResult(NodeScopeResolver $nodeScopeResolver, array $walk, } throw new ShouldNotHappenException(); - }); + }, $beforeScope->getPhpVersion()); if ( count($expr->items) === 2 @@ -594,7 +594,7 @@ private function collectAbsorbedItems(Array_ $expr, array $itemResults, Mutating return $scope; } - $arrayType = $this->initializerExprTypeResolver->getArrayType($expr, static fn (Expr $inner): Type => $itemResults[spl_object_id($inner)]->getType()); + $arrayType = $this->initializerExprTypeResolver->getArrayType($expr, static fn (Expr $inner): Type => $itemResults[spl_object_id($inner)]->getType(), $scope->getPhpVersion()); return $scope->addTemplateArgumentConstraints(ClosureSignatureInference::collectAbsorbedInto($itemTypes, $arrayType)); } diff --git a/src/Analyser/ExprHandler/AssignHandler.php b/src/Analyser/ExprHandler/AssignHandler.php index 3416417c328..4f785fe6de2 100644 --- a/src/Analyser/ExprHandler/AssignHandler.php +++ b/src/Analyser/ExprHandler/AssignHandler.php @@ -68,7 +68,6 @@ use PHPStan\Node\Variable\VariableWrite; use PHPStan\Node\VariableAssignNode; use PHPStan\Node\VirtualNode; -use PHPStan\Php\PhpVersion; use PHPStan\Rules\Properties\PropertyReflectionFinder; use PHPStan\ShouldNotHappenException; use PHPStan\TrinaryLogic; @@ -142,7 +141,6 @@ final class AssignHandler implements ExprHandler public function __construct( private TemplateArgumentObserver $templateArgumentObserver, private VarAnnotationProcessor $varAnnotationProcessor, - private PhpVersion $phpVersion, private ExprPrinter $exprPrinter, private MatchHandler $matchHandler, private TernaryHandler $ternaryHandler, @@ -1584,7 +1582,7 @@ public function applyWrite( $isAlwaysTerminating = $isAlwaysTerminating || $result->isAlwaysTerminating(); $scope = $result->getScope(); - if ($var->name instanceof Expr && $this->phpVersion->supportsPropertyHooks()) { + if ($var->name instanceof Expr && !$scope->getPhpVersion()->supportsPropertyHooks()->no()) { $throwPoints[] = InternalThrowPoint::createImplicit($scope, $var); } @@ -1647,7 +1645,7 @@ public function applyWrite( ) { $throwPoints[] = InternalThrowPoint::createExplicit($scope, new ObjectType(TypeError::class), $assignedExpr, false); } - if ($this->phpVersion->supportsPropertyHooks()) { + if (!$scope->getPhpVersion()->supportsPropertyHooks()->no()) { $throwPoints = array_merge($throwPoints, $this->propertyHookThrowPointsResolver->getThrowPointsFromPropertyHook($scope, $var, $nativeProperty, 'set')); } if ($enterExpressionAssign) { diff --git a/src/Analyser/ExprHandler/Helper/ImplicitToStringCallHelper.php b/src/Analyser/ExprHandler/Helper/ImplicitToStringCallHelper.php index 8ac4b6aa92f..d7aa7d8629a 100644 --- a/src/Analyser/ExprHandler/Helper/ImplicitToStringCallHelper.php +++ b/src/Analyser/ExprHandler/Helper/ImplicitToStringCallHelper.php @@ -12,7 +12,6 @@ use PHPStan\Analyser\MutatingScope; use PHPStan\Analyser\SpecifiedTypes; use PHPStan\DependencyInjection\AutowiredService; -use PHPStan\Php\PhpVersion; use PHPStan\Reflection\ParametersAcceptorSelector; use PHPStan\Turbo\ShadowedByTurboExtension; use PHPStan\Type\ErrorType; @@ -25,7 +24,6 @@ final class ImplicitToStringCallHelper { public function __construct( - private PhpVersion $phpVersion, private MethodThrowPointHelper $methodThrowPointHelper, private MethodCallReturnTypeHelper $methodCallReturnTypeHelper, private ExpressionResultFactory $expressionResultFactory, @@ -73,7 +71,7 @@ public function processImplicitToStringCall(Expr $expr, MutatingScope $scope, Ex ); } - if ($this->phpVersion->throwsOnStringCast()) { + if (!$scope->getPhpVersion()->throwsOnStringCast()->no()) { // the __toString() call's return type resolves directly (the receiver // type is already in hand); the fabricated node is only the payload // dynamic extensions receive - nothing walks it diff --git a/src/Analyser/ExprHandler/PropertyFetchHandler.php b/src/Analyser/ExprHandler/PropertyFetchHandler.php index 2095791b11c..5a2e139913d 100644 --- a/src/Analyser/ExprHandler/PropertyFetchHandler.php +++ b/src/Analyser/ExprHandler/PropertyFetchHandler.php @@ -23,7 +23,6 @@ use PHPStan\Analyser\VariableFlowBuilder; use PHPStan\Dependency\Dependencies; use PHPStan\DependencyInjection\AutowiredService; -use PHPStan\Php\PhpVersion; use PHPStan\Rules\Properties\FoundPropertyReflection; use PHPStan\Rules\Properties\PropertyReflectionFinder; use PHPStan\ShouldNotHappenException; @@ -45,7 +44,6 @@ final class PropertyFetchHandler implements ExprHandler { public function __construct( - private PhpVersion $phpVersion, private PropertyReflectionFinder $propertyReflectionFinder, private ExpressionResultFactory $expressionResultFactory, private PropertyHookThrowPointsResolver $propertyHookThrowPointsResolver, @@ -87,7 +85,7 @@ public function composeResult(NodeScopeResolver $nodeScopeResolver, PropertyFetc $scope = $varResult->getScope(); $mayShortCircuit = false; if ($expr->name instanceof Identifier) { - if ($this->phpVersion->supportsPropertyHooks()) { + if (!$scopeBeforeVar->getPhpVersion()->supportsPropertyHooks()->no()) { $propertyName = $expr->name->toString(); $propertyHolderType = $varResult->getType(); $propertyReflection = $scopeBeforeVar->getInstancePropertyReflection($propertyHolderType, $propertyName); @@ -115,7 +113,7 @@ public function composeResult(NodeScopeResolver $nodeScopeResolver, PropertyFetc // short-circuited world $scope = $scope->mergeWith($varResult->getScope()); } - if ($this->phpVersion->supportsPropertyHooks()) { + if (!$scope->getPhpVersion()->supportsPropertyHooks()->no()) { $throwPoints[] = InternalThrowPoint::createImplicit($scope, $expr); } } diff --git a/src/Analyser/MutatingScope.php b/src/Analyser/MutatingScope.php index 2f7f4681837..9bba572ab07 100644 --- a/src/Analyser/MutatingScope.php +++ b/src/Analyser/MutatingScope.php @@ -403,10 +403,6 @@ public function rememberConstructorScope(): self /** @internal called by ScopeOps */ public function isReadonlyPropertyFetch(PropertyFetch $expr, bool $allowOnlyOnThis): bool { - if (!$this->services->phpVersion->supportsReadOnlyProperties()) { - return false; - } - while ($expr instanceof PropertyFetch) { if ($expr->var instanceof Variable) { if ( @@ -436,7 +432,7 @@ public function isReadonlyPropertyFetch(PropertyFetch $expr, bool $allowOnlyOnTh $expr = $expr->var; } - return true; + return !$this->getPhpVersion()->supportsReadOnlyProperties()->no(); } /** @api */ @@ -2576,20 +2572,18 @@ public function enterAnonymousFunctionWithoutReflection( $expressionTypes['$this'] = ExpressionTypeHolder::createYes($node, $this->getType($node)); $nativeTypes['$this'] = ExpressionTypeHolder::createYes($node, $this->getNativeType($node)); - if ($this->services->phpVersion->supportsReadOnlyProperties()) { - foreach ($nonStaticExpressions as $exprString => $typeHolder) { - $expr = $typeHolder->getExpr(); - - if (!$expr instanceof PropertyFetch) { - continue; - } + foreach ($nonStaticExpressions as $exprString => $typeHolder) { + $expr = $typeHolder->getExpr(); - if (!$this->isReadonlyPropertyFetch($expr, true)) { - continue; - } + if (!$expr instanceof PropertyFetch) { + continue; + } - $expressionTypes[$exprString] = $typeHolder; + if (!$this->isReadonlyPropertyFetch($expr, true)) { + continue; } + + $expressionTypes[$exprString] = $typeHolder; } } @@ -3734,7 +3728,7 @@ public function assignInitializedProperty(Type $fetchedOnType, string $propertyN if ( $function instanceof MethodReflection && strtolower($function->getName()) === '__clone' - && $scope->services->phpVersion->supportsReadonlyPropertyReinitializationOnClone() + && $scope->getPhpVersion()->supportsReadonlyPropertyReinitializationOnClone()->yes() ) { $scope = $scope->assignExpression(new CloneReinitializationExpr($propertyName), new MixedType(), new MixedType()); } @@ -5598,7 +5592,7 @@ public function canWriteProperty(ExtendedPropertyReflection $propertyReflection) return $this->canAccessClassMember($propertyReflection); } - if (!$this->services->phpVersion->supportsAsymmetricVisibility()) { + if ($this->getPhpVersion()->supportsAsymmetricVisibility()->no()) { return $this->canAccessClassMember($propertyReflection); } diff --git a/src/Php/PhpVersions.php b/src/Php/PhpVersions.php index 4c4251e21ec..5db06c5de52 100644 --- a/src/Php/PhpVersions.php +++ b/src/Php/PhpVersions.php @@ -119,6 +119,11 @@ public function supportsFinalProperties(): TrinaryLogic return IntegerRangeType::fromInterval(80400, null)->isSuperTypeOf($this->phpVersions)->result; } + public function supportsAsymmetricVisibility(): TrinaryLogic + { + return IntegerRangeType::fromInterval(80400, null)->isSuperTypeOf($this->phpVersions)->result; + } + public function supportsAsymmetricVisibilityForStaticProperties(): TrinaryLogic { return IntegerRangeType::fromInterval(80500, null)->isSuperTypeOf($this->phpVersions)->result; @@ -184,11 +189,21 @@ public function supportsFinalConstants(): TrinaryLogic return IntegerRangeType::fromInterval(80100, null)->isSuperTypeOf($this->phpVersions)->result; } + public function throwsOnStringCast(): TrinaryLogic + { + return IntegerRangeType::fromInterval(70400, null)->isSuperTypeOf($this->phpVersions)->result; + } + public function supportsReadOnlyProperties(): TrinaryLogic { return IntegerRangeType::fromInterval(80100, null)->isSuperTypeOf($this->phpVersions)->result; } + public function supportsReadonlyPropertyReinitializationOnClone(): TrinaryLogic + { + return IntegerRangeType::fromInterval(80300, null)->isSuperTypeOf($this->phpVersions)->result; + } + public function supportsFirstClassCallables(): TrinaryLogic { return IntegerRangeType::fromInterval(80100, null)->isSuperTypeOf($this->phpVersions)->result; @@ -224,6 +239,71 @@ public function deprecatesNonStandardCasts(): TrinaryLogic return IntegerRangeType::fromInterval(80500, null)->isSuperTypeOf($this->phpVersions)->result; } + public function deprecatesBacktickOperator(): TrinaryLogic + { + return IntegerRangeType::fromInterval(80500, null)->isSuperTypeOf($this->phpVersions)->result; + } + + public function deprecatesDecOnNonNumericString(): TrinaryLogic + { + return IntegerRangeType::fromInterval(80300, null)->isSuperTypeOf($this->phpVersions)->result; + } + + public function deprecatesIncOnNonNumericString(): TrinaryLogic + { + return IntegerRangeType::fromInterval(80500, null)->isSuperTypeOf($this->phpVersions)->result; + } + + public function deprecatesImplicitlyFloatConversionToInt(): TrinaryLogic + { + return IntegerRangeType::fromInterval(80100, null)->isSuperTypeOf($this->phpVersions)->result; + } + + public function deprecatesNullArrayOffset(): TrinaryLogic + { + return IntegerRangeType::fromInterval(80500, null)->isSuperTypeOf($this->phpVersions)->result; + } + + public function deprecatesRequiredParameterAfterOptional(): TrinaryLogic + { + return IntegerRangeType::fromInterval(80000, null)->isSuperTypeOf($this->phpVersions)->result; + } + + public function deprecatesRequiredParameterAfterOptionalNullableAndDefaultNull(): TrinaryLogic + { + return IntegerRangeType::fromInterval(80100, null)->isSuperTypeOf($this->phpVersions)->result; + } + + public function deprecatesRequiredParameterAfterOptionalUnionOrMixed(): TrinaryLogic + { + return IntegerRangeType::fromInterval(80300, null)->isSuperTypeOf($this->phpVersions)->result; + } + + public function deprecatesImplicitlyNullableParameterTypes(): TrinaryLogic + { + return IntegerRangeType::fromInterval(80400, null)->isSuperTypeOf($this->phpVersions)->result; + } + + public function hasTentativeReturnTypes(): TrinaryLogic + { + return IntegerRangeType::fromInterval(80100, null)->isSuperTypeOf($this->phpVersions)->result; + } + + public function serializableRequiresMagicMethods(): TrinaryLogic + { + return IntegerRangeType::fromInterval(80100, null)->isSuperTypeOf($this->phpVersions)->result; + } + + public function supportsAbstractTraitMethods(): TrinaryLogic + { + return IntegerRangeType::fromInterval(80000, null)->isSuperTypeOf($this->phpVersions)->result; + } + + public function supportsCaseInsensitiveConstantNames(): TrinaryLogic + { + return IntegerRangeType::fromInterval(null, 79999)->isSuperTypeOf($this->phpVersions)->result; + } + public function supportsDeprecatedTraits(): TrinaryLogic { return IntegerRangeType::fromInterval(80500, null)->isSuperTypeOf($this->phpVersions)->result; diff --git a/src/Reflection/InitializerExprTypeResolver.php b/src/Reflection/InitializerExprTypeResolver.php index 276af68bdf3..2939b1c1456 100644 --- a/src/Reflection/InitializerExprTypeResolver.php +++ b/src/Reflection/InitializerExprTypeResolver.php @@ -531,9 +531,16 @@ public function resolveConcatType(Type $left, Type $right): Type /** * @param callable(Expr): Type $getTypeCallback + * @param PhpVersions|null $phpVersions the analysed scope's versions, the configured version when null */ - public function getArrayType(Expr\Array_ $expr, callable $getTypeCallback): Type + public function getArrayType(Expr\Array_ $expr, callable $getTypeCallback, ?PhpVersions $phpVersions = null): Type { + // unpacking an array with string keys is an Error below PHP 8.1, so the + // string keys are kept whenever any analysed version supports it + $keepStringKeys = $phpVersions !== null + ? !$phpVersions->supportsArrayUnpackingWithStringKeys()->no() + : $this->phpVersion->supportsArrayUnpackingWithStringKeys(); + if (count($expr->items) > ConstantArrayTypeBuilder::ARRAY_COUNT_LIMIT) { return $this->oversizedArrayBuilder->build($expr, $getTypeCallback); } @@ -546,7 +553,6 @@ public function getArrayType(Expr\Array_ $expr, callable $getTypeCallback): Type if ($arrayItem->unpack) { $constantArrays = $valueType->getConstantArrays(); if (count($constantArrays) > 0) { - $keepStringKeys = $this->phpVersion->supportsArrayUnpackingWithStringKeys(); $totalArrays = count($constantArrays); // Unpacking merges string keys by name, while integer keys are always @@ -615,7 +621,7 @@ public function getArrayType(Expr\Array_ $expr, callable $getTypeCallback): Type } else { $arrayBuilder->degradeToGeneralArray(); - if ($this->phpVersion->supportsArrayUnpackingWithStringKeys() && !$valueType->getIterableKeyType()->isString()->no()) { + if ($keepStringKeys && !$valueType->getIterableKeyType()->isString()->no()) { $isList = false; $offsetType = $valueType->getIterableKeyType(); diff --git a/src/Rules/Arrays/AllowedArrayKeysTypes.php b/src/Rules/Arrays/AllowedArrayKeysTypes.php index ba9fa18845f..c247a54ce75 100644 --- a/src/Rules/Arrays/AllowedArrayKeysTypes.php +++ b/src/Rules/Arrays/AllowedArrayKeysTypes.php @@ -2,7 +2,7 @@ namespace PHPStan\Rules\Arrays; -use PHPStan\Php\PhpVersion; +use PHPStan\Php\PhpVersions; use PHPStan\Turbo\ReferencedByTurboExtension; use PHPStan\Type\ArrayType; use PHPStan\Type\BooleanType; @@ -24,7 +24,7 @@ final class AllowedArrayKeysTypes { - public static function getType(?PhpVersion $phpVersion = null, bool $reportNonIntStringArrayKey = false): Type + public static function getType(?PhpVersions $phpVersions = null, bool $reportNonIntStringArrayKey = false): Type { $types = [ new IntegerType(), @@ -34,10 +34,10 @@ public static function getType(?PhpVersion $phpVersion = null, bool $reportNonIn if (!$reportNonIntStringArrayKey) { $types[] = new BooleanType(); - if ($phpVersion === null || !$phpVersion->deprecatesImplicitlyFloatConversionToInt()) { + if ($phpVersions === null || $phpVersions->deprecatesImplicitlyFloatConversionToInt()->no()) { $types[] = new FloatType(); } - if ($phpVersion === null || !$phpVersion->deprecatesNullArrayOffset()) { + if ($phpVersions === null || $phpVersions->deprecatesNullArrayOffset()->no()) { $types[] = new NullType(); } } diff --git a/src/Rules/Arrays/InvalidKeyInArrayDimFetchRule.php b/src/Rules/Arrays/InvalidKeyInArrayDimFetchRule.php index 4fc2abd36f5..9524916e8f7 100644 --- a/src/Rules/Arrays/InvalidKeyInArrayDimFetchRule.php +++ b/src/Rules/Arrays/InvalidKeyInArrayDimFetchRule.php @@ -6,7 +6,6 @@ use PHPStan\Analyser\Scope; use PHPStan\DependencyInjection\AutowiredParameter; use PHPStan\DependencyInjection\RegisteredRule; -use PHPStan\Php\PhpVersion; use PHPStan\Rules\Rule; use PHPStan\Rules\RuleErrorBuilder; use PHPStan\Rules\RuleLevelHelper; @@ -24,7 +23,6 @@ final class InvalidKeyInArrayDimFetchRule implements Rule public function __construct( private RuleLevelHelper $ruleLevelHelper, - private PhpVersion $phpVersion, #[AutowiredParameter] private bool $reportMaybes, #[AutowiredParameter] @@ -60,7 +58,7 @@ public function processNode(Node $node, Scope $scope): array return []; } - $allowedArrayKeys = AllowedArrayKeysTypes::getType($this->phpVersion, $this->reportNonIntStringArrayKey); + $allowedArrayKeys = AllowedArrayKeysTypes::getType($scope->getPhpVersion(), $this->reportNonIntStringArrayKey); $dimensionType = $this->ruleLevelHelper->findTypeToCheck( $scope, $node->dim, diff --git a/src/Rules/Arrays/InvalidKeyInArrayItemRule.php b/src/Rules/Arrays/InvalidKeyInArrayItemRule.php index 84b63e67278..f0430ca32db 100644 --- a/src/Rules/Arrays/InvalidKeyInArrayItemRule.php +++ b/src/Rules/Arrays/InvalidKeyInArrayItemRule.php @@ -6,7 +6,6 @@ use PHPStan\Analyser\Scope; use PHPStan\DependencyInjection\AutowiredParameter; use PHPStan\DependencyInjection\RegisteredRule; -use PHPStan\Php\PhpVersion; use PHPStan\Rules\Rule; use PHPStan\Rules\RuleErrorBuilder; use PHPStan\Rules\RuleLevelHelper; @@ -24,7 +23,6 @@ final class InvalidKeyInArrayItemRule implements Rule public function __construct( private RuleLevelHelper $ruleLevelHelper, - private PhpVersion $phpVersion, #[AutowiredParameter] private bool $reportNonIntStringArrayKey, ) @@ -42,7 +40,7 @@ public function processNode(Node $node, Scope $scope): array return []; } - $allowedArrayKeys = AllowedArrayKeysTypes::getType($this->phpVersion, $this->reportNonIntStringArrayKey); + $allowedArrayKeys = AllowedArrayKeysTypes::getType($scope->getPhpVersion(), $this->reportNonIntStringArrayKey); $dimensionType = $this->ruleLevelHelper->findTypeToCheck( $scope, $node->key, diff --git a/src/Rules/FunctionDefinitionCheck.php b/src/Rules/FunctionDefinitionCheck.php index 161679ecd34..9935a2eaa70 100644 --- a/src/Rules/FunctionDefinitionCheck.php +++ b/src/Rules/FunctionDefinitionCheck.php @@ -20,6 +20,7 @@ use PHPStan\DependencyInjection\AutowiredService; use PHPStan\Node\Printer\NodeTypePrinter; use PHPStan\Php\PhpVersion; +use PHPStan\Php\PhpVersions; use PHPStan\Reflection\ExtendedParameterReflection; use PHPStan\Reflection\ExtendedParametersAcceptor; use PHPStan\Reflection\ParameterReflection; @@ -141,6 +142,7 @@ public function checkAnonymousFunction( } $implicitlyNullableTypeError = $this->checkImplicitlyNullableType( + $scope->getPhpVersion(), $param->type, $param->default, $i + 1, @@ -202,8 +204,8 @@ public function checkAnonymousFunction( ); } - if ($this->phpVersion->deprecatesRequiredParameterAfterOptional()) { - $errors = array_merge($errors, $this->checkRequiredParameterAfterOptional($parameters)); + if (!$scope->getPhpVersion()->deprecatesRequiredParameterAfterOptional()->no()) { + $errors = array_merge($errors, $this->checkRequiredParameterAfterOptional($scope->getPhpVersion(), $parameters)); } if ($returnTypeNode === null) { @@ -402,7 +404,7 @@ private function checkParametersAcceptor( if (!$parameterNode->var instanceof Variable || !is_string($parameterNode->var->name)) { throw new ShouldNotHappenException(); } - $implicitlyNullableTypeError = $this->checkImplicitlyNullableType($parameterNode->type, $parameterNode->default, $i + 1, $parameterNode->getStartLine(), $parameterNode->var->name); + $implicitlyNullableTypeError = $this->checkImplicitlyNullableType($scope->getPhpVersion(), $parameterNode->type, $parameterNode->default, $i + 1, $parameterNode->getStartLine(), $parameterNode->var->name); if ($implicitlyNullableTypeError === null) { continue; } @@ -410,8 +412,8 @@ private function checkParametersAcceptor( $errors[] = $implicitlyNullableTypeError; } - if ($this->phpVersion->deprecatesRequiredParameterAfterOptional()) { - $errors = array_merge($errors, $this->checkRequiredParameterAfterOptional($parameterNodes)); + if (!$scope->getPhpVersion()->deprecatesRequiredParameterAfterOptional()->no()) { + $errors = array_merge($errors, $this->checkRequiredParameterAfterOptional($scope->getPhpVersion(), $parameterNodes)); } $returnTypeNode = $functionNode->getReturnType() ?? $functionNode; @@ -628,7 +630,7 @@ private function checkParametersAcceptor( * @param Param[] $parameterNodes * @return list */ - private function checkRequiredParameterAfterOptional(array $parameterNodes): array + private function checkRequiredParameterAfterOptional(PhpVersions $phpVersions, array $parameterNodes): array { /** @var string|null $optionalParameter */ $optionalParameter = null; @@ -672,7 +674,7 @@ private function checkRequiredParameterAfterOptional(array $parameterNodes): arr $constantName = $defaultValue->name->toLowerString(); if ($constantName === 'null') { - if (!$this->phpVersion->deprecatesRequiredParameterAfterOptionalNullableAndDefaultNull()) { + if ($phpVersions->deprecatesRequiredParameterAfterOptionalNullableAndDefaultNull()->no()) { continue; } @@ -682,7 +684,7 @@ private function checkRequiredParameterAfterOptional(array $parameterNodes): arr $targetPhpVersion = '8.1'; } - if ($this->phpVersion->deprecatesRequiredParameterAfterOptionalUnionOrMixed()) { + if (!$phpVersions->deprecatesRequiredParameterAfterOptionalUnionOrMixed()->no()) { $types = []; if ($parameterNodeType instanceof UnionType) { @@ -782,6 +784,7 @@ private function getReturnTypeReferencedClasses(ParametersAcceptor $parametersAc } private function checkImplicitlyNullableType( + PhpVersions $phpVersions, Identifier|Name|ComplexType|null $type, ?Node\Expr $default, int $order, @@ -805,7 +808,7 @@ private function checkImplicitlyNullableType( return null; } - if (!$this->phpVersion->deprecatesImplicitlyNullableParameterTypes()) { + if ($phpVersions->deprecatesImplicitlyNullableParameterTypes()->no()) { return null; } diff --git a/src/Rules/Functions/DefineParametersRule.php b/src/Rules/Functions/DefineParametersRule.php index 3534ebc70b0..f4414cca998 100644 --- a/src/Rules/Functions/DefineParametersRule.php +++ b/src/Rules/Functions/DefineParametersRule.php @@ -6,7 +6,6 @@ use PhpParser\Node\Expr\FuncCall; use PHPStan\Analyser\Scope; use PHPStan\DependencyInjection\RegisteredRule; -use PHPStan\Php\PhpVersion; use PHPStan\Rules\Rule; use PHPStan\Rules\RuleErrorBuilder; use function count; @@ -19,10 +18,6 @@ final class DefineParametersRule implements Rule { - public function __construct(private PhpVersion $phpVersion) - { - } - public function getNodeType(): string { return FuncCall::class; @@ -33,7 +28,7 @@ public function processNode(Node $node, Scope $scope): array if (!($node->name instanceof Node\Name)) { return []; } - if ($this->phpVersion->supportsCaseInsensitiveConstantNames()) { + if ($scope->getPhpVersion()->supportsCaseInsensitiveConstantNames()->yes()) { return []; } $name = strtolower((string) $node->name); diff --git a/src/Rules/Functions/FilterVarRule.php b/src/Rules/Functions/FilterVarRule.php index 147dfd0cf86..db6edba91cc 100644 --- a/src/Rules/Functions/FilterVarRule.php +++ b/src/Rules/Functions/FilterVarRule.php @@ -7,7 +7,6 @@ use PhpParser\Node\Name; use PHPStan\Analyser\Scope; use PHPStan\DependencyInjection\RegisteredRule; -use PHPStan\Php\PhpVersion; use PHPStan\Reflection\ReflectionProvider; use PHPStan\Rules\Rule; use PHPStan\Rules\RuleErrorBuilder; @@ -25,7 +24,6 @@ public function __construct( private ReflectionProvider $reflectionProvider, private FilterFunctionReturnTypeHelper $filterFunctionReturnTypeHelper, private FilterFunctionFlagsHelper $filterFunctionFlagsHelper, - private PhpVersion $phpVersion, ) { } @@ -51,7 +49,7 @@ public function processNode(Node $node, Scope $scope): array } if ( - !$this->phpVersion->hasFilterThrowOnFailureConstant() + $scope->getPhpVersion()->hasFilterThrowOnFailureConstant()->no() || !$this->reflectionProvider->hasConstant(new Name\FullyQualified('FILTER_THROW_ON_FAILURE'), null) ) { return []; diff --git a/src/Rules/Methods/MethodPrototypeFinder.php b/src/Rules/Methods/MethodPrototypeFinder.php index e76d0b156ab..2f0c0ef56e3 100644 --- a/src/Rules/Methods/MethodPrototypeFinder.php +++ b/src/Rules/Methods/MethodPrototypeFinder.php @@ -3,7 +3,7 @@ namespace PHPStan\Rules\Methods; use PHPStan\DependencyInjection\AutowiredService; -use PHPStan\Php\PhpVersion; +use PHPStan\Php\PhpVersions; use PHPStan\Reflection\ClassReflection; use PHPStan\Reflection\ExtendedMethodReflection; use PHPStan\Reflection\MethodPrototypeReflection; @@ -18,7 +18,6 @@ final class MethodPrototypeFinder { public function __construct( - private PhpVersion $phpVersion, private PhpClassReflectionExtension $phpClassReflectionExtension, ) { @@ -33,7 +32,7 @@ public function __construct( * * @return array{ExtendedMethodReflection, ClassReflection, bool, ExtendedMethodReflection, ClassReflection}|null */ - public function findPrototype(ClassReflection $classReflection, string $methodName): ?array + public function findPrototype(ClassReflection $classReflection, string $methodName, PhpVersions $phpVersions): ?array { foreach ($classReflection->getImmediateInterfaces() as $immediateInterface) { if ($immediateInterface->hasNativeMethod($methodName)) { @@ -42,7 +41,7 @@ public function findPrototype(ClassReflection $classReflection, string $methodNa } } - if ($this->phpVersion->supportsAbstractTraitMethods()) { + if (!$phpVersions->supportsAbstractTraitMethods()->no()) { foreach ($classReflection->getTraits(true) as $trait) { $nativeTraitReflection = $trait->getNativeReflection(); if (!$nativeTraitReflection->hasMethod($methodName)) { diff --git a/src/Rules/Methods/MissingMagicSerializationMethodsRule.php b/src/Rules/Methods/MissingMagicSerializationMethodsRule.php index 604afa86661..9919ddab357 100644 --- a/src/Rules/Methods/MissingMagicSerializationMethodsRule.php +++ b/src/Rules/Methods/MissingMagicSerializationMethodsRule.php @@ -7,7 +7,6 @@ use PHPStan\BetterReflection\Reflector\Exception\IdentifierNotFound; use PHPStan\DependencyInjection\RegisteredRule; use PHPStan\Node\InClassNode; -use PHPStan\Php\PhpVersion; use PHPStan\Rules\Rule; use PHPStan\Rules\RuleErrorBuilder; use Serializable; @@ -21,10 +20,6 @@ final class MissingMagicSerializationMethodsRule implements Rule { - public function __construct(private PhpVersion $phpversion) - { - } - public function getNodeType(): string { return InClassNode::class; @@ -33,7 +28,7 @@ public function getNodeType(): string public function processNode(Node $node, Scope $scope): array { $classReflection = $node->getClassReflection(); - if (!$this->phpversion->serializableRequiresMagicMethods()) { + if ($scope->getPhpVersion()->serializableRequiresMagicMethods()->no()) { return []; } if (!$classReflection->implementsInterface(Serializable::class)) { diff --git a/src/Rules/Methods/OverridingMethodRule.php b/src/Rules/Methods/OverridingMethodRule.php index a0156ce844d..071cf204442 100644 --- a/src/Rules/Methods/OverridingMethodRule.php +++ b/src/Rules/Methods/OverridingMethodRule.php @@ -56,7 +56,7 @@ public function getNodeType(): string public function processNode(Node $node, Scope&NodeCallbackInvoker&CollectedDataEmitter&DependencyTracker $scope): array { $method = $node->getMethodReflection(); - $prototypeData = $this->methodPrototypeFinder->findPrototype($node->getClassReflection(), $method->getName()); + $prototypeData = $this->methodPrototypeFinder->findPrototype($node->getClassReflection(), $method->getName(), $scope->getPhpVersion()); if ($prototypeData === null) { if (strtolower($method->getName()) === '__construct') { $parent = $method->getDeclaringClass()->getParentClass(); @@ -237,10 +237,11 @@ public function processNode(Node $node, Scope&NodeCallbackInvoker&CollectedDataE $methodReturnType = $method->getNativeReturnType(); $realPrototype = $method->getPrototype(); + $hasTentativeReturnTypes = !$scope->getPhpVersion()->hasTentativeReturnTypes()->no(); if ( $realPrototype instanceof MethodPrototypeReflection - && $this->phpVersion->hasTentativeReturnTypes() + && $hasTentativeReturnTypes && $realPrototype->getTentativeReturnType() !== null && !$this->hasReturnTypeWillChangeAttribute($node->getOriginalNode()) && count($prototypeDeclaringClass->getNativeReflection()->getMethod($prototype->getName())->getAttributes('ReturnTypeWillChange')) === 0 @@ -270,7 +271,7 @@ public function processNode(Node $node, Scope&NodeCallbackInvoker&CollectedDataE $prototypeReturnType = $prototypeVariant->getNativeReturnType(); $reportReturnType = true; - if ($this->phpVersion->hasTentativeReturnTypes()) { + if ($hasTentativeReturnTypes) { $reportReturnType = !$realPrototype instanceof MethodPrototypeReflection || $realPrototype->getTentativeReturnType() === null || (is_bool($prototype->isBuiltin()) ? !$prototype->isBuiltin() : $prototype->isBuiltin()->no()); diff --git a/src/Rules/Operators/BacktickRule.php b/src/Rules/Operators/BacktickRule.php index 1722a5450d1..c261130106b 100644 --- a/src/Rules/Operators/BacktickRule.php +++ b/src/Rules/Operators/BacktickRule.php @@ -6,7 +6,6 @@ use PhpParser\Node\Expr\ShellExec; use PHPStan\Analyser\Scope; use PHPStan\DependencyInjection\RegisteredRule; -use PHPStan\Php\PhpVersion; use PHPStan\Rules\Rule; use PHPStan\Rules\RuleErrorBuilder; use PHPStan\ShouldNotHappenException; @@ -18,12 +17,6 @@ final class BacktickRule implements Rule { - public function __construct( - private PhpVersion $phpVersion, - ) - { - } - public function getNodeType(): string { return ShellExec::class; @@ -31,7 +24,7 @@ public function getNodeType(): string public function processNode(Node $node, Scope $scope): array { - if (!$this->phpVersion->deprecatesBacktickOperator()) { + if ($scope->getPhpVersion()->deprecatesBacktickOperator()->no()) { return []; } diff --git a/src/Rules/Operators/InvalidIncDecOperationRule.php b/src/Rules/Operators/InvalidIncDecOperationRule.php index f8c95fca14e..3d8ef0d0b9f 100644 --- a/src/Rules/Operators/InvalidIncDecOperationRule.php +++ b/src/Rules/Operators/InvalidIncDecOperationRule.php @@ -97,17 +97,19 @@ public function processNode(Node $node, Scope $scope): array ]; } + $phpVersions = $scope->getPhpVersion(); + $deprecatesDecOnNonNumericString = !$phpVersions->deprecatesDecOnNonNumericString()->no(); $string = new StringType(); $deprecatedString = false; if ( ( - $this->phpVersion->deprecatesDecOnNonNumericString() + $deprecatesDecOnNonNumericString && ( $node instanceof Node\Expr\PreDec || $node instanceof Node\Expr\PostDec ) ) || ( - $this->phpVersion->deprecatesIncOnNonNumericString() + !$phpVersions->deprecatesIncOnNonNumericString()->no() && ( $node instanceof Node\Expr\PreInc || $node instanceof Node\Expr\PostInc @@ -121,7 +123,7 @@ public function processNode(Node $node, Scope $scope): array $allowedTypes = [new FloatType(), new IntegerType(), $string, new ObjectType('SimpleXMLElement'), new ObjectType('GMP')]; $deprecatedNull = false; if ( - !$this->phpVersion->deprecatesDecOnNonNumericString() + !$deprecatesDecOnNonNumericString || $node instanceof Node\Expr\PreInc || $node instanceof Node\Expr\PostInc ) { @@ -131,7 +133,7 @@ public function processNode(Node $node, Scope $scope): array } $deprecatedBool = false; - if (!$this->phpVersion->deprecatesDecOnNonNumericString()) { + if (!$deprecatesDecOnNonNumericString) { $allowedTypes[] = new BooleanType(); } else { $deprecatedBool = true; diff --git a/src/Rules/Properties/PropertyAssignRefRule.php b/src/Rules/Properties/PropertyAssignRefRule.php index c61bceff276..16d58a1dd4c 100644 --- a/src/Rules/Properties/PropertyAssignRefRule.php +++ b/src/Rules/Properties/PropertyAssignRefRule.php @@ -5,7 +5,6 @@ use PhpParser\Node; use PHPStan\Analyser\Scope; use PHPStan\DependencyInjection\RegisteredRule; -use PHPStan\Php\PhpVersion; use PHPStan\Rules\Rule; use PHPStan\Rules\RuleErrorBuilder; use function sprintf; @@ -18,7 +17,6 @@ final class PropertyAssignRefRule implements Rule { public function __construct( - private PhpVersion $phpVersion, private PropertyReflectionFinder $propertyReflectionFinder, ) { @@ -31,7 +29,7 @@ public function getNodeType(): string public function processNode(Node $node, Scope $scope): array { - if (!$this->phpVersion->supportsAsymmetricVisibility()) { + if ($scope->getPhpVersion()->supportsAsymmetricVisibility()->no()) { return []; } diff --git a/src/Rules/Properties/ReadOnlyPropertyAssignRule.php b/src/Rules/Properties/ReadOnlyPropertyAssignRule.php index 396cbc0ae3a..2eafebcb38d 100644 --- a/src/Rules/Properties/ReadOnlyPropertyAssignRule.php +++ b/src/Rules/Properties/ReadOnlyPropertyAssignRule.php @@ -7,7 +7,6 @@ use PHPStan\DependencyInjection\RegisteredRule; use PHPStan\Node\Expr\CloneReinitializationExpr; use PHPStan\Node\PropertyAssignNode; -use PHPStan\Php\PhpVersion; use PHPStan\Reflection\ConstructorsHelper; use PHPStan\Reflection\MethodReflection; use PHPStan\Rules\Rule; @@ -28,7 +27,6 @@ final class ReadOnlyPropertyAssignRule implements Rule public function __construct( private PropertyReflectionFinder $propertyReflectionFinder, private ConstructorsHelper $constructorsHelper, - private PhpVersion $phpVersion, ) { } @@ -76,7 +74,7 @@ public function processNode(Node $node, Scope $scope): array $scopeClassReflection = $scope->getClassReflection(); if ($scopeClassReflection->getName() !== $declaringClass->getName()) { - $allowedInSubclass = $this->phpVersion->supportsAsymmetricVisibility() + $allowedInSubclass = $scope->getPhpVersion()->supportsAsymmetricVisibility()->yes() && !$propertyReflection->isPrivateSet() && $scopeClassReflection->isSubclassOfClass($propertyReflection->getDeclaringClass()); if (!$allowedInSubclass) { @@ -94,7 +92,7 @@ public function processNode(Node $node, Scope $scope): array } $methodName = $scopeMethod->getName(); - $inClone = $this->phpVersion->supportsReadonlyPropertyReinitializationOnClone() && strtolower($methodName) === '__clone'; + $inClone = $scope->getPhpVersion()->supportsReadonlyPropertyReinitializationOnClone()->yes() && strtolower($methodName) === '__clone'; if ( in_array($methodName, $this->constructorsHelper->getConstructors($scopeClassReflection), true) || strtolower($methodName) === '__unserialize' diff --git a/src/Rules/Variables/UnsetRule.php b/src/Rules/Variables/UnsetRule.php index d2893e17fe3..14383f8810a 100644 --- a/src/Rules/Variables/UnsetRule.php +++ b/src/Rules/Variables/UnsetRule.php @@ -5,7 +5,6 @@ use PhpParser\Node; use PHPStan\Analyser\Scope; use PHPStan\DependencyInjection\RegisteredRule; -use PHPStan\Php\PhpVersion; use PHPStan\Rules\IdentifierRuleError; use PHPStan\Rules\Properties\PropertyReflectionFinder; use PHPStan\Rules\Rule; @@ -23,7 +22,6 @@ final class UnsetRule implements Rule public function __construct( private PropertyReflectionFinder $propertyReflectionFinder, - private PhpVersion $phpVersion, ) { } @@ -80,7 +78,7 @@ public function processNode(Node $node, Scope $scope): array ->identifier('unset.hookedProperty') ->build(); continue; - } elseif ($this->phpVersion->supportsPropertyHooks()) { + } elseif (!$scope->getPhpVersion()->supportsPropertyHooks()->no()) { if ( !$propertyReflection->isPrivate() && !$propertyReflection->isFinal()->yes() diff --git a/tests/PHPStan/Analyser/ScopePhpVersionRangeReturnTypeExtensionsTest.php b/tests/PHPStan/Analyser/ScopePhpVersionRangeReturnTypeExtensionsTest.php index 9861e04fac4..83045e04698 100644 --- a/tests/PHPStan/Analyser/ScopePhpVersionRangeReturnTypeExtensionsTest.php +++ b/tests/PHPStan/Analyser/ScopePhpVersionRangeReturnTypeExtensionsTest.php @@ -12,6 +12,8 @@ public static function dataFileAsserts(): iterable { yield from self::gatherAssertTypes(__DIR__ . '/data/scope-php-version-range-return-type-extensions.php'); yield from self::gatherAssertTypes(__DIR__ . '/data/loose-equality-php-version-range.php'); + yield from self::gatherAssertTypes(__DIR__ . '/data/readonly-property-php-version-range.php'); + yield from self::gatherAssertTypes(__DIR__ . '/data/array-unpacking-php-version-range.php'); } /** diff --git a/tests/PHPStan/Analyser/data/array-unpacking-php-version-range.php b/tests/PHPStan/Analyser/data/array-unpacking-php-version-range.php new file mode 100644 index 00000000000..d9439a940d3 --- /dev/null +++ b/tests/PHPStan/Analyser/data/array-unpacking-php-version-range.php @@ -0,0 +1,21 @@ + $map + */ + public function doFoo(array $shape, array $map): void + { + // unpacking string keys is an Error below PHP 8.1, so the keys survive + assertType('array{a: int, b: string}', [...$shape]); + assertType('array', [...$map]); + } + +} diff --git a/tests/PHPStan/Analyser/data/readonly-property-php-version-range.php b/tests/PHPStan/Analyser/data/readonly-property-php-version-range.php new file mode 100644 index 00000000000..62d9bcbd1dc --- /dev/null +++ b/tests/PHPStan/Analyser/data/readonly-property-php-version-range.php @@ -0,0 +1,39 @@ += 8.1 + +declare(strict_types = 1); + +namespace ReadonlyPropertyPhpVersionRange; + +use function PHPStan\Testing\assertType; + +class Foo +{ + + public function __construct( + public readonly int|string $a, + public int|string $b, + ) + { + } + + public function doFoo(): void + { + if (!is_int($this->a) || !is_int($this->b)) { + return; + } + + function () { + assertType('int', $this->a); + assertType('int|string', $this->b); + }; + + $this->impure(); + assertType('int', $this->a); + assertType('int|string', $this->b); + } + + public function impure(): void + { + } + +} diff --git a/tests/PHPStan/Rules/Arrays/InvalidKeyInArrayDimFetchRuleConfigPhpTest.php b/tests/PHPStan/Rules/Arrays/InvalidKeyInArrayDimFetchRuleConfigPhpTest.php new file mode 100644 index 00000000000..24a646acfb9 --- /dev/null +++ b/tests/PHPStan/Rules/Arrays/InvalidKeyInArrayDimFetchRuleConfigPhpTest.php @@ -0,0 +1,40 @@ + + */ +class InvalidKeyInArrayDimFetchRuleConfigPhpTest extends RuleTestCase +{ + + protected function getRule(): Rule + { + return self::getContainer()->getByType(InvalidKeyInArrayDimFetchRule::class); + } + + public function testRuleInPhpVersionRange(): void + { + $this->analyse([__DIR__ . '/data/invalid-key-php-version-range.php'], [ + [ + 'Invalid array key type float.', + 11, + ], + [ + 'Invalid array key type null.', + 12, + ], + ]); + } + + public static function getAdditionalConfigFiles(): array + { + return [ + __DIR__ . '/../data/php-version-range.neon', + ]; + } + +} diff --git a/tests/PHPStan/Rules/Arrays/InvalidKeyInArrayDimFetchRuleTest.php b/tests/PHPStan/Rules/Arrays/InvalidKeyInArrayDimFetchRuleTest.php index 94a97036425..6e4e21fc938 100644 --- a/tests/PHPStan/Rules/Arrays/InvalidKeyInArrayDimFetchRuleTest.php +++ b/tests/PHPStan/Rules/Arrays/InvalidKeyInArrayDimFetchRuleTest.php @@ -2,7 +2,6 @@ namespace PHPStan\Rules\Arrays; -use PHPStan\Php\PhpVersion; use PHPStan\Rules\Rule; use PHPStan\Rules\RuleLevelHelper; use PHPStan\Testing\RuleTestCase; @@ -31,7 +30,6 @@ protected function getRule(): Rule ); return new InvalidKeyInArrayDimFetchRule( $ruleLevelHelper, - self::getContainer()->getByType(PhpVersion::class), true, $this->reportNonIntStringArrayKey, ); diff --git a/tests/PHPStan/Rules/Arrays/InvalidKeyInArrayItemRuleConfigPhpTest.php b/tests/PHPStan/Rules/Arrays/InvalidKeyInArrayItemRuleConfigPhpTest.php new file mode 100644 index 00000000000..a9784a89118 --- /dev/null +++ b/tests/PHPStan/Rules/Arrays/InvalidKeyInArrayItemRuleConfigPhpTest.php @@ -0,0 +1,40 @@ + + */ +class InvalidKeyInArrayItemRuleConfigPhpTest extends RuleTestCase +{ + + protected function getRule(): Rule + { + return self::getContainer()->getByType(InvalidKeyInArrayItemRule::class); + } + + public function testRuleInPhpVersionRange(): void + { + $this->analyse([__DIR__ . '/data/invalid-key-php-version-range.php'], [ + [ + 'Invalid array key type float.', + 7, + ], + [ + 'Invalid array key type null.', + 8, + ], + ]); + } + + public static function getAdditionalConfigFiles(): array + { + return [ + __DIR__ . '/../data/php-version-range.neon', + ]; + } + +} diff --git a/tests/PHPStan/Rules/Arrays/InvalidKeyInArrayItemRuleTest.php b/tests/PHPStan/Rules/Arrays/InvalidKeyInArrayItemRuleTest.php index cc35322c58a..50ec90c805b 100644 --- a/tests/PHPStan/Rules/Arrays/InvalidKeyInArrayItemRuleTest.php +++ b/tests/PHPStan/Rules/Arrays/InvalidKeyInArrayItemRuleTest.php @@ -2,7 +2,6 @@ namespace PHPStan\Rules\Arrays; -use PHPStan\Php\PhpVersion; use PHPStan\Rules\Rule; use PHPStan\Rules\RuleLevelHelper; use PHPStan\Testing\RuleTestCase; @@ -36,7 +35,6 @@ protected function getRule(): Rule return new InvalidKeyInArrayItemRule( $ruleLevelHelper, - self::getContainer()->getByType(PhpVersion::class), $this->reportNonIntStringArrayKey, ); } diff --git a/tests/PHPStan/Rules/Arrays/data/invalid-key-php-version-range.php b/tests/PHPStan/Rules/Arrays/data/invalid-key-php-version-range.php new file mode 100644 index 00000000000..a01fd877647 --- /dev/null +++ b/tests/PHPStan/Rules/Arrays/data/invalid-key-php-version-range.php @@ -0,0 +1,13 @@ + 1]; + $b = [null => 1]; + + $c = []; + $c[$f] = 1; + $c[null] = 1; +} diff --git a/tests/PHPStan/Rules/Exceptions/CatchWithUnthrownExceptionRuleConfigPhp73Test.php b/tests/PHPStan/Rules/Exceptions/CatchWithUnthrownExceptionRuleConfigPhp73Test.php new file mode 100644 index 00000000000..62a4081ceaf --- /dev/null +++ b/tests/PHPStan/Rules/Exceptions/CatchWithUnthrownExceptionRuleConfigPhp73Test.php @@ -0,0 +1,37 @@ + + */ +class CatchWithUnthrownExceptionRuleConfigPhp73Test extends RuleTestCase +{ + + protected function getRule(): Rule + { + return new CatchWithUnthrownExceptionRule(new DefaultExceptionTypeResolver( + self::createReflectionProvider(), + [], + [], + [], + [], + ), true); + } + + public function testRuleInPhpVersionRange(): void + { + $this->analyse([__DIR__ . '/data/unthrown-exception-php-version-range.php'], []); + } + + public static function getAdditionalConfigFiles(): array + { + return [ + __DIR__ . '/php-version-range-73.neon', + ]; + } + +} diff --git a/tests/PHPStan/Rules/Exceptions/CatchWithUnthrownExceptionRuleTest.php b/tests/PHPStan/Rules/Exceptions/CatchWithUnthrownExceptionRuleTest.php index 43633d859c5..d264aac9a30 100644 --- a/tests/PHPStan/Rules/Exceptions/CatchWithUnthrownExceptionRuleTest.php +++ b/tests/PHPStan/Rules/Exceptions/CatchWithUnthrownExceptionRuleTest.php @@ -720,6 +720,21 @@ public function testPropertyHooks(): void ]); } + #[RequiresPhp('>= 8.4.0')] + public function testPropertyHooksUnderPhpVersionGuard(): void + { + $this->analyse([__DIR__ . '/data/unthrown-exception-property-hooks-version-guard.php'], [ + [ + 'Dead catch - UnthrownExceptionPropertyHooksVersionGuard\\MyCustomException is never thrown in the try block.', + 54, + ], + [ + 'Dead catch - UnthrownExceptionPropertyHooksVersionGuard\\MyCustomException is never thrown in the try block.', + 60, + ], + ]); + } + public function testBug9146(): void { $this->analyse([__DIR__ . '/data/bug-9146.php'], [ diff --git a/tests/PHPStan/Rules/Exceptions/data/unthrown-exception-php-version-range.php b/tests/PHPStan/Rules/Exceptions/data/unthrown-exception-php-version-range.php new file mode 100644 index 00000000000..fc8496598b0 --- /dev/null +++ b/tests/PHPStan/Rules/Exceptions/data/unthrown-exception-php-version-range.php @@ -0,0 +1,59 @@ +$s; + } catch (MyException $e) { // implicit throw point - a property hook might run on PHP 8.4+ + + } + } + + public function dynamicAssign(Bar $o, string $s): void + { + try { + $o->$s = 1; + } catch (MyException $e) { // implicit throw point - a property hook might run on PHP 8.4+ + + } + } + + public function stringCast(ThrowsOnToString $o): string + { + try { + return (string) $o; + } catch (MyException $e) { // __toString() may throw on PHP 7.4+ + return ''; + } + } + +} diff --git a/tests/PHPStan/Rules/Exceptions/data/unthrown-exception-property-hooks-version-guard.php b/tests/PHPStan/Rules/Exceptions/data/unthrown-exception-property-hooks-version-guard.php new file mode 100644 index 00000000000..479d67374f5 --- /dev/null +++ b/tests/PHPStan/Rules/Exceptions/data/unthrown-exception-property-hooks-version-guard.php @@ -0,0 +1,66 @@ += 8.4 + +namespace UnthrownExceptionPropertyHooksVersionGuard; + +class MyCustomException extends \Exception +{ + +} + +class Foo +{ + + public int $i { + /** @throws MyCustomException */ + get { + if (rand(0, 1)) { + throw new MyCustomException(); + } + + return 1; + } + } + + public int $j { + /** @throws MyCustomException */ + set { + if (rand(0, 1)) { + throw new MyCustomException(); + } + + $this->j = $value; + } + } + + public function doFoo(int $v): void + { + if (PHP_VERSION_ID >= 80400) { + try { + $a = $this->i; + } catch (MyCustomException $e) { + + } + + try { + $this->j = $v; + } catch (MyCustomException $e) { + + } + } + + if (PHP_VERSION_ID < 80400) { + try { + $a = $this->i; + } catch (MyCustomException $e) { // no property hooks below PHP 8.4 + + } + + try { + $this->j = $v; + } catch (MyCustomException $e) { // no property hooks below PHP 8.4 + + } + } + } + +} diff --git a/tests/PHPStan/Rules/Exceptions/php-version-range-73.neon b/tests/PHPStan/Rules/Exceptions/php-version-range-73.neon new file mode 100644 index 00000000000..cbf9d40968b --- /dev/null +++ b/tests/PHPStan/Rules/Exceptions/php-version-range-73.neon @@ -0,0 +1,4 @@ +parameters: + phpVersion: + min: 70300 + max: 80599 diff --git a/tests/PHPStan/Rules/Functions/DefineParametersRuleConfigPhpTest.php b/tests/PHPStan/Rules/Functions/DefineParametersRuleConfigPhpTest.php new file mode 100644 index 00000000000..142b73485a4 --- /dev/null +++ b/tests/PHPStan/Rules/Functions/DefineParametersRuleConfigPhpTest.php @@ -0,0 +1,36 @@ + + */ +class DefineParametersRuleConfigPhpTest extends RuleTestCase +{ + + protected function getRule(): Rule + { + return self::getContainer()->getByType(DefineParametersRule::class); + } + + public function testRuleInPhpVersionRange(): void + { + $this->analyse([__DIR__ . '/data/call-to-define.php'], [ + [ + 'Argument #3 ($case_insensitive) is ignored since declaration of case-insensitive constants is no longer supported.', + 3, + ], + ]); + } + + public static function getAdditionalConfigFiles(): array + { + return [ + __DIR__ . '/../data/php-version-range.neon', + ]; + } + +} diff --git a/tests/PHPStan/Rules/Functions/DefineParametersRuleTest.php b/tests/PHPStan/Rules/Functions/DefineParametersRuleTest.php index d78909627d0..1b5b4a9cdca 100644 --- a/tests/PHPStan/Rules/Functions/DefineParametersRuleTest.php +++ b/tests/PHPStan/Rules/Functions/DefineParametersRuleTest.php @@ -2,7 +2,6 @@ namespace PHPStan\Rules\Functions; -use PHPStan\Php\PhpVersion; use PHPStan\Rules\Rule; use PHPStan\Testing\RuleTestCase; use const PHP_VERSION_ID; @@ -15,7 +14,7 @@ class DefineParametersRuleTest extends RuleTestCase protected function getRule(): Rule { - return new DefineParametersRule(new PhpVersion(PHP_VERSION_ID)); + return new DefineParametersRule(); } public function testFile(): void diff --git a/tests/PHPStan/Rules/Functions/ExistingClassesInArrowFunctionTypehintsRuleTest.php b/tests/PHPStan/Rules/Functions/ExistingClassesInArrowFunctionTypehintsRuleTest.php index ca7f16511e7..b7d26f609e2 100644 --- a/tests/PHPStan/Rules/Functions/ExistingClassesInArrowFunctionTypehintsRuleTest.php +++ b/tests/PHPStan/Rules/Functions/ExistingClassesInArrowFunctionTypehintsRuleTest.php @@ -79,151 +79,70 @@ public function testNativeUnionTypes(): void $this->analyse([__DIR__ . '/data/native-union-types.php'], $errors); } - public static function dataRequiredParameterAfterOptional(): array + #[RequiresPhp('>= 8.0.0')] + public function testRequiredParameterAfterOptional(): void { - return [ + $errors = [ [ - 70400, - [], + 'Deprecated in PHP 8.0: Required parameter $bar follows optional parameter $foo.', + 5, ], [ - 80000, - [ - [ - 'Deprecated in PHP 8.0: Required parameter $bar follows optional parameter $foo.', - 5, - ], - [ - 'Deprecated in PHP 8.0: Required parameter $bar follows optional parameter $foo.', - 9, - ], - [ - 'Deprecated in PHP 8.0: Required parameter $bar follows optional parameter $foo.', - 11, - ], - [ - 'Deprecated in PHP 8.0: Required parameter $bar follows optional parameter $foo.', - 13, - ], - [ - 'Deprecated in PHP 8.0: Required parameter $bar follows optional parameter $foo.', - 17, - ], - [ - 'Deprecated in PHP 8.0: Required parameter $bar follows optional parameter $foo.', - 21, - ], - [ - 'Deprecated in PHP 8.0: Required parameter $quuz follows optional parameter $quux.', - 25, - ], - ], + 'Deprecated in PHP 8.0: Required parameter $bar follows optional parameter $foo.', + 9, ], [ - 80100, - [ - [ - 'Deprecated in PHP 8.0: Required parameter $bar follows optional parameter $foo.', - 5, - ], - [ - 'Deprecated in PHP 8.0: Required parameter $bar follows optional parameter $foo.', - 9, - ], - [ - 'Deprecated in PHP 8.0: Required parameter $bar follows optional parameter $foo.', - 11, - ], - [ - 'Deprecated in PHP 8.0: Required parameter $bar follows optional parameter $foo.', - 13, - ], - [ - 'Deprecated in PHP 8.1: Required parameter $bar follows optional parameter $foo.', - 15, - ], - [ - 'Deprecated in PHP 8.0: Required parameter $bar follows optional parameter $foo.', - 17, - ], - [ - 'Deprecated in PHP 8.0: Required parameter $bar follows optional parameter $foo.', - 21, - ], - [ - 'Deprecated in PHP 8.1: Required parameter $qux follows optional parameter $baz.', - 25, - ], - [ - 'Deprecated in PHP 8.0: Required parameter $quuz follows optional parameter $quux.', - 25, - ], - ], + 'Deprecated in PHP 8.0: Required parameter $bar follows optional parameter $foo.', + 11, ], [ - 80300, - [ - [ - 'Deprecated in PHP 8.0: Required parameter $bar follows optional parameter $foo.', - 5, - ], - [ - 'Deprecated in PHP 8.0: Required parameter $bar follows optional parameter $foo.', - 9, - ], - [ - 'Deprecated in PHP 8.0: Required parameter $bar follows optional parameter $foo.', - 11, - ], - [ - 'Deprecated in PHP 8.0: Required parameter $bar follows optional parameter $foo.', - 13, - ], - [ - 'Deprecated in PHP 8.1: Required parameter $bar follows optional parameter $foo.', - 15, - ], - [ - 'Deprecated in PHP 8.0: Required parameter $bar follows optional parameter $foo.', - 17, - ], - [ - 'Deprecated in PHP 8.3: Required parameter $bar follows optional parameter $foo.', - 19, - ], - [ - 'Deprecated in PHP 8.0: Required parameter $bar follows optional parameter $foo.', - 21, - ], - [ - 'Deprecated in PHP 8.3: Required parameter $bar follows optional parameter $foo.', - 23, - ], - [ - 'Deprecated in PHP 8.3: Required parameter $bar follows optional parameter $foo.', - 25, - ], - [ - 'Deprecated in PHP 8.1: Required parameter $qux follows optional parameter $baz.', - 25, - ], - [ - 'Deprecated in PHP 8.0: Required parameter $quuz follows optional parameter $quux.', - 25, - ], - ], + 'Deprecated in PHP 8.0: Required parameter $bar follows optional parameter $foo.', + 13, + ], + [ + 'Deprecated in PHP 8.0: Required parameter $bar follows optional parameter $foo.', + 17, + ], + [ + 'Deprecated in PHP 8.0: Required parameter $bar follows optional parameter $foo.', + 21, + ], + [ + 'Deprecated in PHP 8.0: Required parameter $quuz follows optional parameter $quux.', + 25, ], ]; - } + if (PHP_VERSION_ID >= 80100) { + $errors[] = [ + 'Deprecated in PHP 8.1: Required parameter $bar follows optional parameter $foo.', + 15, + ]; + $errors[] = [ + 'Deprecated in PHP 8.1: Required parameter $qux follows optional parameter $baz.', + 25, + ]; + } + if (PHP_VERSION_ID >= 80300) { + $errors[] = [ + 'Deprecated in PHP 8.3: Required parameter $bar follows optional parameter $foo.', + 19, + ]; + $errors[] = [ + 'Deprecated in PHP 8.3: Required parameter $bar follows optional parameter $foo.', + 23, + ]; + $errors[] = [ + 'Deprecated in PHP 8.3: Required parameter $bar follows optional parameter $foo.', + 25, + ]; + } - /** - * @param list $errors - */ - #[RequiresPhp('>= 8.0.0')] - #[DataProvider('dataRequiredParameterAfterOptional')] - public function testRequiredParameterAfterOptional(int $phpVersionId, array $errors): void - { - $this->phpVersionId = $phpVersionId; + if (PHP_VERSION_ID >= 80400) { + $errors[] = [ + 'Deprecated in PHP 8.4: Parameter #1 $foo (int) is implicitly nullable via default value null.', + 7, + ]; + } $this->analyse([__DIR__ . '/data/required-parameter-after-optional-arrow.php'], $errors); } diff --git a/tests/PHPStan/Rules/Functions/ExistingClassesInClosureTypehintsRuleTest.php b/tests/PHPStan/Rules/Functions/ExistingClassesInClosureTypehintsRuleTest.php index 5fbefbb56d8..989e13b75b7 100644 --- a/tests/PHPStan/Rules/Functions/ExistingClassesInClosureTypehintsRuleTest.php +++ b/tests/PHPStan/Rules/Functions/ExistingClassesInClosureTypehintsRuleTest.php @@ -143,151 +143,70 @@ public function testNativeUnionTypes(): void $this->analyse([__DIR__ . '/data/native-union-types.php'], $errors); } - public static function dataRequiredParameterAfterOptional(): array + #[RequiresPhp('>= 8.0.0')] + public function testRequiredParameterAfterOptional(): void { - return [ + $errors = [ [ - 70400, - [], + 'Deprecated in PHP 8.0: Required parameter $bar follows optional parameter $foo.', + 5, ], [ - 80000, - [ - [ - 'Deprecated in PHP 8.0: Required parameter $bar follows optional parameter $foo.', - 5, - ], - [ - 'Deprecated in PHP 8.0: Required parameter $bar follows optional parameter $foo.', - 13, - ], - [ - 'Deprecated in PHP 8.0: Required parameter $bar follows optional parameter $foo.', - 17, - ], - [ - 'Deprecated in PHP 8.0: Required parameter $bar follows optional parameter $foo.', - 21, - ], - [ - 'Deprecated in PHP 8.0: Required parameter $bar follows optional parameter $foo.', - 29, - ], - [ - 'Deprecated in PHP 8.0: Required parameter $bar follows optional parameter $foo.', - 37, - ], - [ - 'Deprecated in PHP 8.0: Required parameter $quuz follows optional parameter $quux.', - 45, - ], - ], + 'Deprecated in PHP 8.0: Required parameter $bar follows optional parameter $foo.', + 13, ], [ - 80100, - [ - [ - 'Deprecated in PHP 8.0: Required parameter $bar follows optional parameter $foo.', - 5, - ], - [ - 'Deprecated in PHP 8.0: Required parameter $bar follows optional parameter $foo.', - 13, - ], - [ - 'Deprecated in PHP 8.0: Required parameter $bar follows optional parameter $foo.', - 17, - ], - [ - 'Deprecated in PHP 8.0: Required parameter $bar follows optional parameter $foo.', - 21, - ], - [ - 'Deprecated in PHP 8.1: Required parameter $bar follows optional parameter $foo.', - 25, - ], - [ - 'Deprecated in PHP 8.0: Required parameter $bar follows optional parameter $foo.', - 29, - ], - [ - 'Deprecated in PHP 8.0: Required parameter $bar follows optional parameter $foo.', - 37, - ], - [ - 'Deprecated in PHP 8.1: Required parameter $qux follows optional parameter $baz.', - 45, - ], - [ - 'Deprecated in PHP 8.0: Required parameter $quuz follows optional parameter $quux.', - 45, - ], - ], + 'Deprecated in PHP 8.0: Required parameter $bar follows optional parameter $foo.', + 17, ], [ - 80300, - [ - [ - 'Deprecated in PHP 8.0: Required parameter $bar follows optional parameter $foo.', - 5, - ], - [ - 'Deprecated in PHP 8.0: Required parameter $bar follows optional parameter $foo.', - 13, - ], - [ - 'Deprecated in PHP 8.0: Required parameter $bar follows optional parameter $foo.', - 17, - ], - [ - 'Deprecated in PHP 8.0: Required parameter $bar follows optional parameter $foo.', - 21, - ], - [ - 'Deprecated in PHP 8.1: Required parameter $bar follows optional parameter $foo.', - 25, - ], - [ - 'Deprecated in PHP 8.0: Required parameter $bar follows optional parameter $foo.', - 29, - ], - [ - 'Deprecated in PHP 8.3: Required parameter $bar follows optional parameter $foo.', - 33, - ], - [ - 'Deprecated in PHP 8.0: Required parameter $bar follows optional parameter $foo.', - 37, - ], - [ - 'Deprecated in PHP 8.3: Required parameter $bar follows optional parameter $foo.', - 41, - ], - [ - 'Deprecated in PHP 8.3: Required parameter $bar follows optional parameter $foo.', - 45, - ], - [ - 'Deprecated in PHP 8.1: Required parameter $qux follows optional parameter $baz.', - 45, - ], - [ - 'Deprecated in PHP 8.0: Required parameter $quuz follows optional parameter $quux.', - 45, - ], - ], + 'Deprecated in PHP 8.0: Required parameter $bar follows optional parameter $foo.', + 21, + ], + [ + 'Deprecated in PHP 8.0: Required parameter $bar follows optional parameter $foo.', + 29, + ], + [ + 'Deprecated in PHP 8.0: Required parameter $bar follows optional parameter $foo.', + 37, + ], + [ + 'Deprecated in PHP 8.0: Required parameter $quuz follows optional parameter $quux.', + 45, ], ]; - } + if (PHP_VERSION_ID >= 80100) { + $errors[] = [ + 'Deprecated in PHP 8.1: Required parameter $bar follows optional parameter $foo.', + 25, + ]; + $errors[] = [ + 'Deprecated in PHP 8.1: Required parameter $qux follows optional parameter $baz.', + 45, + ]; + } + if (PHP_VERSION_ID >= 80300) { + $errors[] = [ + 'Deprecated in PHP 8.3: Required parameter $bar follows optional parameter $foo.', + 33, + ]; + $errors[] = [ + 'Deprecated in PHP 8.3: Required parameter $bar follows optional parameter $foo.', + 41, + ]; + $errors[] = [ + 'Deprecated in PHP 8.3: Required parameter $bar follows optional parameter $foo.', + 45, + ]; + } - /** - * @param list $errors - */ - #[RequiresPhp('>= 8.0.0')] - #[DataProvider('dataRequiredParameterAfterOptional')] - public function testRequiredParameterAfterOptional(int $phpVersionId, array $errors): void - { - $this->phpVersionId = $phpVersionId; + if (PHP_VERSION_ID >= 80400) { + $errors[] = [ + 'Deprecated in PHP 8.4: Parameter #1 $foo (int) is implicitly nullable via default value null.', + 9, + ]; + } $this->analyse([__DIR__ . '/data/required-parameter-after-optional-closures.php'], $errors); } diff --git a/tests/PHPStan/Rules/Functions/ExistingClassesInTypehintsRuleConfigPhpTest.php b/tests/PHPStan/Rules/Functions/ExistingClassesInTypehintsRuleConfigPhpTest.php new file mode 100644 index 00000000000..dd019b1ad2d --- /dev/null +++ b/tests/PHPStan/Rules/Functions/ExistingClassesInTypehintsRuleConfigPhpTest.php @@ -0,0 +1,44 @@ + + */ +class ExistingClassesInTypehintsRuleConfigPhpTest extends RuleTestCase +{ + + protected function getRule(): Rule + { + return self::getContainer()->getByType(ExistingClassesInTypehintsRule::class); + } + + public function testRuleInPhpVersionRange(): void + { + $this->analyse([__DIR__ . '/data/function-definition-php-version-range.php'], [ + [ + 'Deprecated in PHP 8.0: Required parameter $b follows optional parameter $a.', + 5, + ], + [ + 'Deprecated in PHP 8.1: Required parameter $b follows optional parameter $a.', + 9, + ], + [ + 'Deprecated in PHP 8.4: Parameter #1 $a (int) is implicitly nullable via default value null.', + 13, + ], + ]); + } + + public static function getAdditionalConfigFiles(): array + { + return [ + __DIR__ . '/../data/php-version-range.neon', + ]; + } + +} diff --git a/tests/PHPStan/Rules/Functions/ExistingClassesInTypehintsRuleTest.php b/tests/PHPStan/Rules/Functions/ExistingClassesInTypehintsRuleTest.php index d003c6a1e50..fcc8dce1e5e 100644 --- a/tests/PHPStan/Rules/Functions/ExistingClassesInTypehintsRuleTest.php +++ b/tests/PHPStan/Rules/Functions/ExistingClassesInTypehintsRuleTest.php @@ -213,151 +213,70 @@ public function testNativeUnionTypes(): void $this->analyse([__DIR__ . '/data/native-union-types.php'], $errors); } - public static function dataRequiredParameterAfterOptional(): array + #[RequiresPhp('>= 8.0.0')] + public function testRequiredParameterAfterOptional(): void { - return [ + $errors = [ [ - 70400, - [], + 'Deprecated in PHP 8.0: Required parameter $bar follows optional parameter $foo.', + 5, ], [ - 80000, - [ - [ - 'Deprecated in PHP 8.0: Required parameter $bar follows optional parameter $foo.', - 5, - ], - [ - 'Deprecated in PHP 8.0: Required parameter $bar follows optional parameter $foo.', - 14, - ], - [ - 'Deprecated in PHP 8.0: Required parameter $bar follows optional parameter $foo.', - 18, - ], - [ - 'Deprecated in PHP 8.0: Required parameter $bar follows optional parameter $foo.', - 26, - ], - [ - 'Deprecated in PHP 8.0: Required parameter $bar follows optional parameter $foo.', - 34, - ], - [ - 'Deprecated in PHP 8.0: Required parameter $bar follows optional parameter $foo.', - 42, - ], - [ - 'Deprecated in PHP 8.0: Required parameter $quuz follows optional parameter $quux.', - 50, - ], - ], + 'Deprecated in PHP 8.0: Required parameter $bar follows optional parameter $foo.', + 14, ], [ - 80100, - [ - [ - 'Deprecated in PHP 8.0: Required parameter $bar follows optional parameter $foo.', - 5, - ], - [ - 'Deprecated in PHP 8.0: Required parameter $bar follows optional parameter $foo.', - 14, - ], - [ - 'Deprecated in PHP 8.0: Required parameter $bar follows optional parameter $foo.', - 18, - ], - [ - 'Deprecated in PHP 8.0: Required parameter $bar follows optional parameter $foo.', - 26, - ], - [ - 'Deprecated in PHP 8.1: Required parameter $bar follows optional parameter $foo.', - 30, - ], - [ - 'Deprecated in PHP 8.0: Required parameter $bar follows optional parameter $foo.', - 34, - ], - [ - 'Deprecated in PHP 8.0: Required parameter $bar follows optional parameter $foo.', - 42, - ], - [ - 'Deprecated in PHP 8.1: Required parameter $qux follows optional parameter $baz.', - 50, - ], - [ - 'Deprecated in PHP 8.0: Required parameter $quuz follows optional parameter $quux.', - 50, - ], - ], + 'Deprecated in PHP 8.0: Required parameter $bar follows optional parameter $foo.', + 18, ], [ - 80300, - [ - [ - 'Deprecated in PHP 8.0: Required parameter $bar follows optional parameter $foo.', - 5, - ], - [ - 'Deprecated in PHP 8.0: Required parameter $bar follows optional parameter $foo.', - 14, - ], - [ - 'Deprecated in PHP 8.0: Required parameter $bar follows optional parameter $foo.', - 18, - ], - [ - 'Deprecated in PHP 8.0: Required parameter $bar follows optional parameter $foo.', - 26, - ], - [ - 'Deprecated in PHP 8.1: Required parameter $bar follows optional parameter $foo.', - 30, - ], - [ - 'Deprecated in PHP 8.0: Required parameter $bar follows optional parameter $foo.', - 34, - ], - [ - 'Deprecated in PHP 8.3: Required parameter $bar follows optional parameter $foo.', - 38, - ], - [ - 'Deprecated in PHP 8.0: Required parameter $bar follows optional parameter $foo.', - 42, - ], - [ - 'Deprecated in PHP 8.3: Required parameter $bar follows optional parameter $foo.', - 46, - ], - [ - 'Deprecated in PHP 8.3: Required parameter $bar follows optional parameter $foo.', - 50, - ], - [ - 'Deprecated in PHP 8.1: Required parameter $qux follows optional parameter $baz.', - 50, - ], - [ - 'Deprecated in PHP 8.0: Required parameter $quuz follows optional parameter $quux.', - 50, - ], - ], + 'Deprecated in PHP 8.0: Required parameter $bar follows optional parameter $foo.', + 26, + ], + [ + 'Deprecated in PHP 8.0: Required parameter $bar follows optional parameter $foo.', + 34, + ], + [ + 'Deprecated in PHP 8.0: Required parameter $bar follows optional parameter $foo.', + 42, + ], + [ + 'Deprecated in PHP 8.0: Required parameter $quuz follows optional parameter $quux.', + 50, ], ]; - } + if (PHP_VERSION_ID >= 80100) { + $errors[] = [ + 'Deprecated in PHP 8.1: Required parameter $bar follows optional parameter $foo.', + 30, + ]; + $errors[] = [ + 'Deprecated in PHP 8.1: Required parameter $qux follows optional parameter $baz.', + 50, + ]; + } + if (PHP_VERSION_ID >= 80300) { + $errors[] = [ + 'Deprecated in PHP 8.3: Required parameter $bar follows optional parameter $foo.', + 38, + ]; + $errors[] = [ + 'Deprecated in PHP 8.3: Required parameter $bar follows optional parameter $foo.', + 46, + ]; + $errors[] = [ + 'Deprecated in PHP 8.3: Required parameter $bar follows optional parameter $foo.', + 50, + ]; + } - /** - * @param list $errors - */ - #[RequiresPhp('>= 8.0.0')] - #[DataProvider('dataRequiredParameterAfterOptional')] - public function testRequiredParameterAfterOptional(int $phpVersionId, array $errors): void - { - $this->phpVersionId = $phpVersionId; + if (PHP_VERSION_ID >= 80400) { + $errors[] = [ + 'Deprecated in PHP 8.4: Parameter #1 $foo (int) is implicitly nullable via default value null.', + 10, + ]; + } $this->analyse([__DIR__ . '/data/required-parameter-after-optional.php'], $errors); } diff --git a/tests/PHPStan/Rules/Functions/FilterVarRuleConfigPhpTest.php b/tests/PHPStan/Rules/Functions/FilterVarRuleConfigPhpTest.php new file mode 100644 index 00000000000..64a255047ba --- /dev/null +++ b/tests/PHPStan/Rules/Functions/FilterVarRuleConfigPhpTest.php @@ -0,0 +1,35 @@ + */ +class FilterVarRuleConfigPhpTest extends RuleTestCase +{ + + protected function getRule(): Rule + { + return self::getContainer()->getByType(FilterVarRule::class); + } + + #[RequiresPhp('>= 8.5.0')] + public function testRuleInPhpVersionRange(): void + { + $this->analyse([__DIR__ . '/data/filter_var_null_and_throw.php'], [ + ['Cannot use both FILTER_NULL_ON_FAILURE and FILTER_THROW_ON_FAILURE.', 5], + ['Cannot use both FILTER_NULL_ON_FAILURE and FILTER_THROW_ON_FAILURE.', 8], + ['Cannot use both FILTER_NULL_ON_FAILURE and FILTER_THROW_ON_FAILURE.', 10], + ]); + } + + public static function getAdditionalConfigFiles(): array + { + return [ + __DIR__ . '/../data/php-version-range.neon', + ]; + } + +} diff --git a/tests/PHPStan/Rules/Functions/FilterVarRuleTest.php b/tests/PHPStan/Rules/Functions/FilterVarRuleTest.php index 91edc0ed7f4..a84798b849f 100644 --- a/tests/PHPStan/Rules/Functions/FilterVarRuleTest.php +++ b/tests/PHPStan/Rules/Functions/FilterVarRuleTest.php @@ -2,7 +2,6 @@ namespace PHPStan\Rules\Functions; -use PHPStan\Php\PhpVersion; use PHPStan\Rules\Rule; use PHPStan\Testing\RuleTestCase; use PHPStan\Type\Php\FilterFunctionFlagsHelper; @@ -19,7 +18,6 @@ protected function getRule(): Rule self::createReflectionProvider(), self::getContainer()->getByType(FilterFunctionReturnTypeHelper::class), self::getContainer()->getByType(FilterFunctionFlagsHelper::class), - self::getContainer()->getByType(PhpVersion::class), ); } diff --git a/tests/PHPStan/Rules/Functions/data/function-definition-php-version-range.php b/tests/PHPStan/Rules/Functions/data/function-definition-php-version-range.php new file mode 100644 index 00000000000..f4465772f8e --- /dev/null +++ b/tests/PHPStan/Rules/Functions/data/function-definition-php-version-range.php @@ -0,0 +1,15 @@ +analyse([__DIR__ . '/data/native-union-types.php'], $errors); } - public static function dataRequiredParameterAfterOptional(): array + #[RequiresPhp('>= 8.0.0')] + public function testRequiredParameterAfterOptional(): void { - return [ + $errors = [ [ - 70400, - [], + 'Deprecated in PHP 8.0: Required parameter $bar follows optional parameter $foo.', + 8, ], [ - 80000, - [ - [ - 'Deprecated in PHP 8.0: Required parameter $bar follows optional parameter $foo.', - 8, - ], - [ - 'Deprecated in PHP 8.0: Required parameter $bar follows optional parameter $foo.', - 17, - ], - [ - 'Deprecated in PHP 8.0: Required parameter $bar follows optional parameter $foo.', - 21, - ], - [ - 'Deprecated in PHP 8.0: Required parameter $bar follows optional parameter $foo.', - 25, - ], - [ - 'Deprecated in PHP 8.0: Required parameter $bar follows optional parameter $foo.', - 33, - ], - [ - 'Deprecated in PHP 8.0: Required parameter $bar follows optional parameter $foo.', - 41, - ], - [ - 'Deprecated in PHP 8.0: Required parameter $quuz follows optional parameter $quux.', - 49, - ], - ], + 'Deprecated in PHP 8.0: Required parameter $bar follows optional parameter $foo.', + 17, ], [ - 80100, - [ - [ - 'Deprecated in PHP 8.0: Required parameter $bar follows optional parameter $foo.', - 8, - ], - [ - 'Deprecated in PHP 8.0: Required parameter $bar follows optional parameter $foo.', - 17, - ], - [ - 'Deprecated in PHP 8.0: Required parameter $bar follows optional parameter $foo.', - 21, - ], - [ - 'Deprecated in PHP 8.0: Required parameter $bar follows optional parameter $foo.', - 25, - ], - [ - 'Deprecated in PHP 8.1: Required parameter $bar follows optional parameter $foo.', - 29, - ], - [ - 'Deprecated in PHP 8.0: Required parameter $bar follows optional parameter $foo.', - 33, - ], - [ - 'Deprecated in PHP 8.0: Required parameter $bar follows optional parameter $foo.', - 41, - ], - [ - 'Deprecated in PHP 8.1: Required parameter $qux follows optional parameter $baz.', - 49, - ], - [ - 'Deprecated in PHP 8.0: Required parameter $quuz follows optional parameter $quux.', - 49, - ], - ], + 'Deprecated in PHP 8.0: Required parameter $bar follows optional parameter $foo.', + 21, ], [ - 80300, - [ - [ - 'Deprecated in PHP 8.0: Required parameter $bar follows optional parameter $foo.', - 8, - ], - [ - 'Deprecated in PHP 8.0: Required parameter $bar follows optional parameter $foo.', - 17, - ], - [ - 'Deprecated in PHP 8.0: Required parameter $bar follows optional parameter $foo.', - 21, - ], - [ - 'Deprecated in PHP 8.0: Required parameter $bar follows optional parameter $foo.', - 25, - ], - [ - 'Deprecated in PHP 8.1: Required parameter $bar follows optional parameter $foo.', - 29, - ], - [ - 'Deprecated in PHP 8.0: Required parameter $bar follows optional parameter $foo.', - 33, - ], - [ - 'Deprecated in PHP 8.3: Required parameter $bar follows optional parameter $foo.', - 37, - ], - [ - 'Deprecated in PHP 8.0: Required parameter $bar follows optional parameter $foo.', - 41, - ], - [ - 'Deprecated in PHP 8.3: Required parameter $bar follows optional parameter $foo.', - 45, - ], - [ - 'Deprecated in PHP 8.3: Required parameter $bar follows optional parameter $foo.', - 49, - ], - [ - 'Deprecated in PHP 8.1: Required parameter $qux follows optional parameter $baz.', - 49, - ], - [ - 'Deprecated in PHP 8.0: Required parameter $quuz follows optional parameter $quux.', - 49, - ], - ], + 'Deprecated in PHP 8.0: Required parameter $bar follows optional parameter $foo.', + 25, + ], + [ + 'Deprecated in PHP 8.0: Required parameter $bar follows optional parameter $foo.', + 33, + ], + [ + 'Deprecated in PHP 8.0: Required parameter $bar follows optional parameter $foo.', + 41, + ], + [ + 'Deprecated in PHP 8.0: Required parameter $quuz follows optional parameter $quux.', + 49, ], ]; - } + if (PHP_VERSION_ID >= 80100) { + $errors[] = [ + 'Deprecated in PHP 8.1: Required parameter $bar follows optional parameter $foo.', + 29, + ]; + $errors[] = [ + 'Deprecated in PHP 8.1: Required parameter $qux follows optional parameter $baz.', + 49, + ]; + } + if (PHP_VERSION_ID >= 80300) { + $errors[] = [ + 'Deprecated in PHP 8.3: Required parameter $bar follows optional parameter $foo.', + 37, + ]; + $errors[] = [ + 'Deprecated in PHP 8.3: Required parameter $bar follows optional parameter $foo.', + 45, + ]; + $errors[] = [ + 'Deprecated in PHP 8.3: Required parameter $bar follows optional parameter $foo.', + 49, + ]; + } - /** - * @param list $errors - */ - #[RequiresPhp('>= 8.0.0')] - #[DataProvider('dataRequiredParameterAfterOptional')] - public function testRequiredParameterAfterOptional(int $phpVersionId, array $errors): void - { - $this->phpVersionId = $phpVersionId; + if (PHP_VERSION_ID >= 80400) { + $errors[] = [ + 'Deprecated in PHP 8.4: Parameter #1 $foo (int) is implicitly nullable via default value null.', + 13, + ]; + } $this->analyse([__DIR__ . '/data/required-parameter-after-optional.php'], $errors); } diff --git a/tests/PHPStan/Rules/Methods/MethodCallWithPossiblyRenamedNamedArgumentRuleTest.php b/tests/PHPStan/Rules/Methods/MethodCallWithPossiblyRenamedNamedArgumentRuleTest.php index d69008e793c..97f58061df0 100644 --- a/tests/PHPStan/Rules/Methods/MethodCallWithPossiblyRenamedNamedArgumentRuleTest.php +++ b/tests/PHPStan/Rules/Methods/MethodCallWithPossiblyRenamedNamedArgumentRuleTest.php @@ -43,7 +43,7 @@ protected function getRule(): Rule false, new MethodParameterComparisonHelper($phpVersion), new MethodVisibilityComparisonHelper(), - new MethodPrototypeFinder($phpVersion, $phpClassReflectionExtension), + new MethodPrototypeFinder($phpClassReflectionExtension), false, ), new MethodCallWithPossiblyRenamedNamedArgumentRule(), diff --git a/tests/PHPStan/Rules/Methods/MethodSignatureRuleTest.php b/tests/PHPStan/Rules/Methods/MethodSignatureRuleTest.php index f24317d6b61..3ae0124f513 100644 --- a/tests/PHPStan/Rules/Methods/MethodSignatureRuleTest.php +++ b/tests/PHPStan/Rules/Methods/MethodSignatureRuleTest.php @@ -33,7 +33,7 @@ protected function getRule(): Rule true, new MethodParameterComparisonHelper($phpVersion), new MethodVisibilityComparisonHelper(), - new MethodPrototypeFinder($phpVersion, $phpClassReflectionExtension), + new MethodPrototypeFinder($phpClassReflectionExtension), false, ); } diff --git a/tests/PHPStan/Rules/Methods/MissingMagicSerializationMethodsRuleConfigPhpTest.php b/tests/PHPStan/Rules/Methods/MissingMagicSerializationMethodsRuleConfigPhpTest.php new file mode 100644 index 00000000000..2ea03992ce0 --- /dev/null +++ b/tests/PHPStan/Rules/Methods/MissingMagicSerializationMethodsRuleConfigPhpTest.php @@ -0,0 +1,44 @@ + + */ +class MissingMagicSerializationMethodsRuleConfigPhpTest extends RuleTestCase +{ + + protected function getRule(): Rule + { + return self::getContainer()->getByType(MissingMagicSerializationMethodsRule::class); + } + + #[RequiresPhp('>= 8.1.0')] + public function testRuleInPhpVersionRange(): void + { + $this->analyse([__DIR__ . '/data/missing-serialization.php'], [ + [ + 'Non-abstract class MissingMagicSerializationMethods\\myObj implements the Serializable interface, but does not implement __serialize().', + 14, + 'See https://wiki.php.net/rfc/phase_out_serializable', + ], + [ + 'Non-abstract class MissingMagicSerializationMethods\\myObj implements the Serializable interface, but does not implement __unserialize().', + 14, + 'See https://wiki.php.net/rfc/phase_out_serializable', + ], + ]); + } + + public static function getAdditionalConfigFiles(): array + { + return [ + __DIR__ . '/../data/php-version-range.neon', + ]; + } + +} diff --git a/tests/PHPStan/Rules/Methods/MissingMagicSerializationMethodsRuleTest.php b/tests/PHPStan/Rules/Methods/MissingMagicSerializationMethodsRuleTest.php index 45a07171df5..ceb09b45c30 100644 --- a/tests/PHPStan/Rules/Methods/MissingMagicSerializationMethodsRuleTest.php +++ b/tests/PHPStan/Rules/Methods/MissingMagicSerializationMethodsRuleTest.php @@ -2,11 +2,9 @@ namespace PHPStan\Rules\Methods; -use PHPStan\Php\PhpVersion; use PHPStan\Rules\Rule; use PHPStan\Testing\RuleTestCase; use PHPUnit\Framework\Attributes\RequiresPhp; -use const PHP_VERSION_ID; /** * @extends RuleTestCase @@ -16,7 +14,7 @@ class MissingMagicSerializationMethodsRuleTest extends RuleTestCase protected function getRule(): Rule { - return new MissingMagicSerializationMethodsRule(new PhpVersion(PHP_VERSION_ID)); + return new MissingMagicSerializationMethodsRule(); } #[RequiresPhp('>= 8.1.0')] diff --git a/tests/PHPStan/Rules/Methods/OverridingMethodRuleConfigPhpTest.php b/tests/PHPStan/Rules/Methods/OverridingMethodRuleConfigPhpTest.php new file mode 100644 index 00000000000..92f4c5666af --- /dev/null +++ b/tests/PHPStan/Rules/Methods/OverridingMethodRuleConfigPhpTest.php @@ -0,0 +1,69 @@ + + */ +class OverridingMethodRuleConfigPhpTest extends RuleTestCase +{ + + protected function getRule(): Rule + { + $phpVersion = self::getContainer()->getByType(PhpVersion::class); + $phpClassReflectionExtension = self::getContainer()->getByType(PhpClassReflectionExtension::class); + + return new OverridingMethodRule( + $phpVersion, + new MethodSignatureRule(new ParentMethodHelper($phpClassReflectionExtension), true, true, false), + false, + new MethodParameterComparisonHelper($phpVersion), + new MethodVisibilityComparisonHelper(), + new MethodPrototypeFinder($phpClassReflectionExtension), + false, + ); + } + + #[RequiresPhp('>= 8.1.0')] + public function testTentativeReturnTypesInPhpVersionRange(): void + { + $this->analyse([__DIR__ . '/data/tentative-return-types.php'], OverridingMethodRuleTest::getTentativeReturnTypesErrors()); + } + + #[RequiresPhp('>= 8.0.0')] + public function testAbstractTraitMethodsInPhpVersionRange(): void + { + $this->analyse([__DIR__ . '/data/overriding-trait-methods.php'], [ + [ + 'Parameter #1 $i (int) of method OverridingTraitMethods\Bar::doBar() is not contravariant with parameter #1 $i (string) of method OverridingTraitMethods\Foo::doBar().', + 27, + ], + [ + 'Parameter #1 $i (int) of method OverridingTraitMethods\Baz::doBar() is not contravariant with parameter #1 $i (string) of method OverridingTraitMethods\FooPrivate::doBar().', + 45, + ], + [ + 'Static method OverridingTraitMethods\Ipsum::doBar() overrides non-static method OverridingTraitMethods\Foo::doBar().', + 65, + ], + [ + 'Non-static method OverridingTraitMethods\Dolor::doBar() overrides static method OverridingTraitMethods\FooStatic::doBar().', + 80, + ], + ]); + } + + public static function getAdditionalConfigFiles(): array + { + return [ + __DIR__ . '/../data/php-version-range.neon', + ]; + } + +} diff --git a/tests/PHPStan/Rules/Methods/OverridingMethodRuleTest.php b/tests/PHPStan/Rules/Methods/OverridingMethodRuleTest.php index 9a441ef6b28..af2919b28d1 100644 --- a/tests/PHPStan/Rules/Methods/OverridingMethodRuleTest.php +++ b/tests/PHPStan/Rules/Methods/OverridingMethodRuleTest.php @@ -34,7 +34,7 @@ protected function getRule(): Rule false, new MethodParameterComparisonHelper($phpVersion), new MethodVisibilityComparisonHelper(), - new MethodPrototypeFinder($phpVersion, $phpClassReflectionExtension), + new MethodPrototypeFinder($phpClassReflectionExtension), $this->checkMissingOverrideMethodAttribute, ); } @@ -141,6 +141,25 @@ public function testOverridingFinalMethod(int $phpVersion, string $contravariant $errors = array_values(array_filter($errors, static fn (array $error): bool => $error[1] !== 125)); } + if (PHP_VERSION_ID >= 80100) { + $tip = 'Make it covariant, or use the #[\ReturnTypeWillChange] attribute to temporarily suppress the error.'; + $errors[] = [ + 'Return type bool of method OverridingFinalMethod\FixedArray::setSize() is not covariant with tentative return type true of method SplFixedArray::setSize().', + 125, + $tip, + ]; + $errors[] = [ + 'Return type mixed of method OverridingFinalMethod\SomeIterator::getIterator() is not covariant with tentative return type Traversable of method IteratorAggregate::getIterator().', + 250, + $tip, + ]; + $errors[] = [ + 'Return type mixed of method OverridingFinalMethod\FixedArrayOffsetExists::offsetExists() is not covariant with tentative return type bool of method ArrayAccess::offsetExists().', + 313, + $tip, + ]; + } + $this->phpVersionId = $phpVersion; $this->analyse([__DIR__ . '/data/overriding-method.php'], $errors); } @@ -473,69 +492,54 @@ public function testBug4516(): void $this->analyse([__DIR__ . '/data/bug-4516.php'], []); } - public static function dataTentativeReturnTypes(): array + /** + * @return list + */ + public static function getTentativeReturnTypesErrors(): array { return [ - [70400, []], - [80000, []], [ - 80100, - [ - [ - 'Return type mixed of method TentativeReturnTypes\Foo::getIterator() is not covariant with tentative return type Traversable of method IteratorAggregate::getIterator().', - 8, - 'Make it covariant, or use the #[\ReturnTypeWillChange] attribute to temporarily suppress the error.', - ], - [ - 'Return type string of method TentativeReturnTypes\Lorem::getIterator() is not covariant with tentative return type Traversable of method IteratorAggregate::getIterator().', - 40, - 'Make it covariant, or use the #[\ReturnTypeWillChange] attribute to temporarily suppress the error.', - ], - [ - 'Return type mixed of method TentativeReturnTypes\UntypedIterator::current() is not covariant with tentative return type mixed of method Iterator::current().', - 75, - 'Make it covariant, or use the #[\ReturnTypeWillChange] attribute to temporarily suppress the error.', - ], - [ - 'Return type mixed of method TentativeReturnTypes\UntypedIterator::next() is not covariant with tentative return type void of method Iterator::next().', - 79, - 'Make it covariant, or use the #[\ReturnTypeWillChange] attribute to temporarily suppress the error.', - ], - [ - 'Return type mixed of method TentativeReturnTypes\UntypedIterator::key() is not covariant with tentative return type mixed of method Iterator::key().', - 83, - 'Make it covariant, or use the #[\ReturnTypeWillChange] attribute to temporarily suppress the error.', - ], - [ - 'Return type mixed of method TentativeReturnTypes\UntypedIterator::valid() is not covariant with tentative return type bool of method Iterator::valid().', - 87, - 'Make it covariant, or use the #[\ReturnTypeWillChange] attribute to temporarily suppress the error.', - ], - [ - 'Return type mixed of method TentativeReturnTypes\UntypedIterator::rewind() is not covariant with tentative return type void of method Iterator::rewind().', - 91, - 'Make it covariant, or use the #[\ReturnTypeWillChange] attribute to temporarily suppress the error.', - ], - ], + 'Return type mixed of method TentativeReturnTypes\Foo::getIterator() is not covariant with tentative return type Traversable of method IteratorAggregate::getIterator().', + 8, + 'Make it covariant, or use the #[\ReturnTypeWillChange] attribute to temporarily suppress the error.', + ], + [ + 'Return type string of method TentativeReturnTypes\Lorem::getIterator() is not covariant with tentative return type Traversable of method IteratorAggregate::getIterator().', + 40, + 'Make it covariant, or use the #[\ReturnTypeWillChange] attribute to temporarily suppress the error.', + ], + [ + 'Return type mixed of method TentativeReturnTypes\UntypedIterator::current() is not covariant with tentative return type mixed of method Iterator::current().', + 75, + 'Make it covariant, or use the #[\ReturnTypeWillChange] attribute to temporarily suppress the error.', + ], + [ + 'Return type mixed of method TentativeReturnTypes\UntypedIterator::next() is not covariant with tentative return type void of method Iterator::next().', + 79, + 'Make it covariant, or use the #[\ReturnTypeWillChange] attribute to temporarily suppress the error.', + ], + [ + 'Return type mixed of method TentativeReturnTypes\UntypedIterator::key() is not covariant with tentative return type mixed of method Iterator::key().', + 83, + 'Make it covariant, or use the #[\ReturnTypeWillChange] attribute to temporarily suppress the error.', + ], + [ + 'Return type mixed of method TentativeReturnTypes\UntypedIterator::valid() is not covariant with tentative return type bool of method Iterator::valid().', + 87, + 'Make it covariant, or use the #[\ReturnTypeWillChange] attribute to temporarily suppress the error.', + ], + [ + 'Return type mixed of method TentativeReturnTypes\UntypedIterator::rewind() is not covariant with tentative return type void of method Iterator::rewind().', + 91, + 'Make it covariant, or use the #[\ReturnTypeWillChange] attribute to temporarily suppress the error.', ], ]; } - /** - * @param list $errors - */ - #[DataProvider('dataTentativeReturnTypes')] - public function testTentativeReturnTypes(int $phpVersionId, array $errors): void + public function testTentativeReturnTypes(): void { - if (PHP_VERSION_ID < 80100) { - $errors = []; - } - if ($phpVersionId > PHP_VERSION_ID) { - $this->markTestSkipped(); - } - - $this->phpVersionId = $phpVersionId; - $this->analyse([__DIR__ . '/data/tentative-return-types.php'], $errors); + $this->phpVersionId = PHP_VERSION_ID; + $this->analyse([__DIR__ . '/data/tentative-return-types.php'], PHP_VERSION_ID >= 80100 ? self::getTentativeReturnTypesErrors() : []); } public function testCountableBug(): void diff --git a/tests/PHPStan/Rules/Operators/BacktickRuleConfigPhpTest.php b/tests/PHPStan/Rules/Operators/BacktickRuleConfigPhpTest.php new file mode 100644 index 00000000000..6d33220ac6d --- /dev/null +++ b/tests/PHPStan/Rules/Operators/BacktickRuleConfigPhpTest.php @@ -0,0 +1,44 @@ + + */ +class BacktickRuleConfigPhpTest extends RuleTestCase +{ + + protected function getRule(): Rule + { + return self::getContainer()->getByType(BacktickRule::class); + } + + public function testRuleInPhpVersionRange(): void + { + $this->analyse([__DIR__ . '/data/backtick.php'], [ + [ + 'Backtick operator is deprecated in PHP 8.5. Use shell_exec() function call instead.', + 4, + ], + [ + 'Backtick operator is deprecated in PHP 8.5. Use shell_exec() function call instead.', + 5, + ], + [ + 'Backtick operator is deprecated in PHP 8.5. Use shell_exec() function call instead.', + 6, + ], + ]); + } + + public static function getAdditionalConfigFiles(): array + { + return [ + __DIR__ . '/../data/php-version-range.neon', + ]; + } + +} diff --git a/tests/PHPStan/Rules/Operators/BacktickRuleTest.php b/tests/PHPStan/Rules/Operators/BacktickRuleTest.php index 47341f402fe..fd104d2225a 100644 --- a/tests/PHPStan/Rules/Operators/BacktickRuleTest.php +++ b/tests/PHPStan/Rules/Operators/BacktickRuleTest.php @@ -2,7 +2,6 @@ namespace PHPStan\Rules\Operators; -use PHPStan\Php\PhpVersion; use PHPStan\Rules\Rule; use PHPStan\Testing\RuleTestCase; use PHPUnit\Framework\Attributes\RequiresPhp; @@ -16,7 +15,7 @@ class BacktickRuleTest extends RuleTestCase protected function getRule(): Rule { - return new BacktickRule(new PhpVersion(PHP_VERSION_ID)); + return new BacktickRule(); } public function testRule(): void diff --git a/tests/PHPStan/Rules/Operators/InvalidIncDecOperationRuleConfigPhpTest.php b/tests/PHPStan/Rules/Operators/InvalidIncDecOperationRuleConfigPhpTest.php new file mode 100644 index 00000000000..f0f11dc04f3 --- /dev/null +++ b/tests/PHPStan/Rules/Operators/InvalidIncDecOperationRuleConfigPhpTest.php @@ -0,0 +1,73 @@ + + */ +class InvalidIncDecOperationRuleConfigPhpTest extends RuleTestCase +{ + + protected function getRule(): Rule + { + return self::getContainer()->getByType(InvalidIncDecOperationRule::class); + } + + public function testDecNonNumericStringInPhpVersionRange(): void + { + $this->analyse([__DIR__ . '/data/dec-non-numeric-string.php'], [ + [ + 'Cannot use -- on \'a\'.', + 21, + 'Operator -- is deprecated for non-numeric-strings. Either narrow the type to numeric-string, or use str_decrement().', + ], + [ + 'Cannot use -- on string.', + 23, + 'Operator -- is deprecated for non-numeric-strings. Either narrow the type to numeric-string, or use str_decrement().', + ], + [ + 'Cannot use -- on null.', + 30, + 'Operator -- is deprecated for null.', + ], + [ + 'Cannot use ++ on bool.', + 32, + 'Operator ++ is deprecated for bool.', + ], + [ + 'Cannot use -- on bool.', + 40, + 'Operator -- is deprecated for bool.', + ], + ]); + } + + public function testIncNonNumericStringInPhpVersionRange(): void + { + $this->analyse([__DIR__ . '/data/inc-non-numeric-string.php'], [ + [ + 'Cannot use ++ on \'a\'.', + 21, + 'Operator ++ is deprecated for non-numeric-strings. Either narrow the type to numeric-string, or use str_increment().', + ], + [ + 'Cannot use ++ on string.', + 23, + 'Operator ++ is deprecated for non-numeric-strings. Either narrow the type to numeric-string, or use str_increment().', + ], + ]); + } + + public static function getAdditionalConfigFiles(): array + { + return [ + __DIR__ . '/../data/php-version-range.neon', + ]; + } + +} diff --git a/tests/PHPStan/Rules/Properties/PropertyAssignRefRuleConfigPhpTest.php b/tests/PHPStan/Rules/Properties/PropertyAssignRefRuleConfigPhpTest.php new file mode 100644 index 00000000000..c86d8d78f1e --- /dev/null +++ b/tests/PHPStan/Rules/Properties/PropertyAssignRefRuleConfigPhpTest.php @@ -0,0 +1,50 @@ + + */ +class PropertyAssignRefRuleConfigPhpTest extends RuleTestCase +{ + + protected function getRule(): Rule + { + return self::getContainer()->getByType(PropertyAssignRefRule::class); + } + + #[RequiresPhp('>= 8.4.0')] + public function testRuleInPhpVersionRange(): void + { + $this->analyse([__DIR__ . '/data/property-assign-ref.php'], [ + [ + 'Property PropertyAssignRef\\Foo::$foo with private visibility is assigned by reference.', + 25, + ], + [ + 'Property PropertyAssignRef\\Foo::$bar with protected(set) visibility is assigned by reference.', + 26, + ], + [ + 'Property PropertyAssignRef\\Baz::$a with protected visibility is assigned by reference.', + 41, + ], + [ + 'Property PropertyAssignRef\\Baz::$b with private visibility is assigned by reference.', + 42, + ], + ]); + } + + public static function getAdditionalConfigFiles(): array + { + return [ + __DIR__ . '/../data/php-version-range.neon', + ]; + } + +} diff --git a/tests/PHPStan/Rules/Properties/PropertyAssignRefRuleTest.php b/tests/PHPStan/Rules/Properties/PropertyAssignRefRuleTest.php index 10f791ab8f1..f7781f5faf4 100644 --- a/tests/PHPStan/Rules/Properties/PropertyAssignRefRuleTest.php +++ b/tests/PHPStan/Rules/Properties/PropertyAssignRefRuleTest.php @@ -2,11 +2,9 @@ namespace PHPStan\Rules\Properties; -use PHPStan\Php\PhpVersion; use PHPStan\Rules\Rule; use PHPStan\Testing\RuleTestCase; use PHPUnit\Framework\Attributes\RequiresPhp; -use const PHP_VERSION_ID; /** * @extends RuleTestCase @@ -16,7 +14,7 @@ class PropertyAssignRefRuleTest extends RuleTestCase protected function getRule(): Rule { - return new PropertyAssignRefRule(new PhpVersion(PHP_VERSION_ID), new PropertyReflectionFinder()); + return new PropertyAssignRefRule(new PropertyReflectionFinder()); } #[RequiresPhp('>= 8.4.0')] diff --git a/tests/PHPStan/Rules/Properties/ReadOnlyPropertyAssignRuleConfigPhpTest.php b/tests/PHPStan/Rules/Properties/ReadOnlyPropertyAssignRuleConfigPhpTest.php new file mode 100644 index 00000000000..0739fdaa2b1 --- /dev/null +++ b/tests/PHPStan/Rules/Properties/ReadOnlyPropertyAssignRuleConfigPhpTest.php @@ -0,0 +1,42 @@ + + */ +class ReadOnlyPropertyAssignRuleConfigPhpTest extends RuleTestCase +{ + + protected function getRule(): Rule + { + return self::getContainer()->getByType(ReadOnlyPropertyAssignRule::class); + } + + #[RequiresPhp('>= 8.4.0')] + public function testRuleInPhpVersionRange(): void + { + $this->analyse([__DIR__ . '/data/readonly-property-assign-php-version-range.php'], [ + [ + 'Readonly property ReadonlyPropertyAssignPhpVersionRange\ParentClass::$a is assigned outside of its declaring class.', + 25, + ], + [ + 'Readonly property ReadonlyPropertyAssignPhpVersionRange\Foo::$a is already assigned.', + 44, + ], + ]); + } + + public static function getAdditionalConfigFiles(): array + { + return [ + __DIR__ . '/data/php-version-range-81.neon', + ]; + } + +} diff --git a/tests/PHPStan/Rules/Properties/ReadOnlyPropertyAssignRuleTest.php b/tests/PHPStan/Rules/Properties/ReadOnlyPropertyAssignRuleTest.php index b351211ea98..98d73dc9e6a 100644 --- a/tests/PHPStan/Rules/Properties/ReadOnlyPropertyAssignRuleTest.php +++ b/tests/PHPStan/Rules/Properties/ReadOnlyPropertyAssignRuleTest.php @@ -2,7 +2,6 @@ namespace PHPStan\Rules\Properties; -use PHPStan\Php\PhpVersion; use PHPStan\Reflection\AdditionalConstructorsExtension; use PHPStan\Reflection\ConstructorsHelper; use PHPStan\Rules\Rule; @@ -27,7 +26,6 @@ protected function getRule(): Rule 'ReadonlyPropertyAssign\\TestCase::setUp', ], ), - new PhpVersion(PHP_VERSION_ID), ); } diff --git a/tests/PHPStan/Rules/Properties/data/php-version-range-81.neon b/tests/PHPStan/Rules/Properties/data/php-version-range-81.neon new file mode 100644 index 00000000000..3fa1d38f1d6 --- /dev/null +++ b/tests/PHPStan/Rules/Properties/data/php-version-range-81.neon @@ -0,0 +1,4 @@ +parameters: + phpVersion: + min: 80100 + max: 80599 diff --git a/tests/PHPStan/Rules/Properties/data/readonly-property-assign-php-version-range.php b/tests/PHPStan/Rules/Properties/data/readonly-property-assign-php-version-range.php new file mode 100644 index 00000000000..7beffad7881 --- /dev/null +++ b/tests/PHPStan/Rules/Properties/data/readonly-property-assign-php-version-range.php @@ -0,0 +1,48 @@ += 8.1 + +namespace ReadonlyPropertyAssignPhpVersionRange; + +class ParentClass +{ + + public readonly int $a; + +} + +class ChildClass extends ParentClass +{ + + public function __construct() + { + if (PHP_VERSION_ID >= 80400) { + $this->a = 1; + } + } + + public function doFoo(): void + { + if (PHP_VERSION_ID < 80400) { + $this->a = 1; + } + } + +} + +class Foo +{ + + public function __construct( + public readonly int $a, + ) + { + } + + public function __clone() + { + if (PHP_VERSION_ID >= 80300) { + $this->a = 1; + $this->a = 2; + } + } + +} diff --git a/tests/PHPStan/Rules/Variables/UnsetRuleConfigPhpTest.php b/tests/PHPStan/Rules/Variables/UnsetRuleConfigPhpTest.php new file mode 100644 index 00000000000..c7c67feeeba --- /dev/null +++ b/tests/PHPStan/Rules/Variables/UnsetRuleConfigPhpTest.php @@ -0,0 +1,36 @@ + + */ +class UnsetRuleConfigPhpTest extends RuleTestCase +{ + + protected function getRule(): Rule + { + return self::getContainer()->getByType(UnsetRule::class); + } + + public function testRuleInPhpVersionRange(): void + { + $this->analyse([__DIR__ . '/data/unset-php-version-range.php'], [ + [ + 'Cannot unset property UnsetPhpVersionRange\\Foo::$p because it might have hooks in a subclass.', + 14, + ], + ]); + } + + public static function getAdditionalConfigFiles(): array + { + return [ + __DIR__ . '/../data/php-version-range.neon', + ]; + } + +} diff --git a/tests/PHPStan/Rules/Variables/UnsetRuleTest.php b/tests/PHPStan/Rules/Variables/UnsetRuleTest.php index 73515e60d5f..f6fb29d501a 100644 --- a/tests/PHPStan/Rules/Variables/UnsetRuleTest.php +++ b/tests/PHPStan/Rules/Variables/UnsetRuleTest.php @@ -2,7 +2,6 @@ namespace PHPStan\Rules\Variables; -use PHPStan\Php\PhpVersion; use PHPStan\Rules\Properties\PropertyReflectionFinder; use PHPStan\Rules\Rule; use PHPStan\Testing\RuleTestCase; @@ -21,7 +20,6 @@ protected function getRule(): Rule $container = self::getContainer(); return new UnsetRule( $container->getByType(PropertyReflectionFinder::class), - $container->getByType(PhpVersion::class), ); } diff --git a/tests/PHPStan/Rules/Variables/data/unset-php-version-range.php b/tests/PHPStan/Rules/Variables/data/unset-php-version-range.php new file mode 100644 index 00000000000..bd5a6b8b5ed --- /dev/null +++ b/tests/PHPStan/Rules/Variables/data/unset-php-version-range.php @@ -0,0 +1,15 @@ +p); +} diff --git a/tests/PHPStan/Rules/data/php-version-range.neon b/tests/PHPStan/Rules/data/php-version-range.neon new file mode 100644 index 00000000000..771e4def950 --- /dev/null +++ b/tests/PHPStan/Rules/data/php-version-range.neon @@ -0,0 +1,4 @@ +parameters: + phpVersion: + min: 70400 + max: 80599 diff --git a/turbo-ext/src/ArrayHandler.cpp b/turbo-ext/src/ArrayHandler.cpp index 6174f999bda..0634e7e7e4e 100644 --- a/turbo-ext/src/ArrayHandler.cpp +++ b/turbo-ext/src/ArrayHandler.cpp @@ -57,10 +57,12 @@ constexpr zend_long PT_ARH_KIND_ARRAY_LITERAL_ITEM = 14; /* {{{ the PHP collaborators (one site each; switch to their direct entries * once they are ported) */ -/* $initializerExprTypeResolver->getArrayType($expr, $getTypeCallback) */ -zv::Val getArrayType(zval *initializerExprTypeResolver, zval *expr, const pt_ietr_get_type &getTypeCallback) +/* $initializerExprTypeResolver->getArrayType($expr, $getTypeCallback, $scope->getPhpVersion()) */ +zv::Val getArrayType(zval *initializerExprTypeResolver, zval *expr, const pt_ietr_get_type &getTypeCallback, zval *scope) { - return pt_initializer_expr_type_resolver_get_array_type(initializerExprTypeResolver, expr, getTypeCallback); + zv::Val phpVersions = pt_type_call(Z_OBJ_P(scope), PT_LC("getphpversion"), 0, NULL); + if (UNEXPECTED(phpVersions.isUndef())) return zv::Val(); + return pt_initializer_expr_type_resolver_get_array_type(initializerExprTypeResolver, expr, getTypeCallback, phpVersions.raw()); } /* }}} */ @@ -280,7 +282,7 @@ class ArrayHandler { ItemTypeFrame frame{itemResults, false}; pt_ietr_get_type getTypeCallback{&itemTypeCallback, &frame, &itemTypeCallable}; - arrayType = getArrayType(OBJ_PROP_NUM(self, slots::initializerExprTypeResolver), expr, getTypeCallback); + arrayType = getArrayType(OBJ_PROP_NUM(self, slots::initializerExprTypeResolver), expr, getTypeCallback, scope.raw()); if (UNEXPECTED(arrayType.isUndef())) return zv::Val(); } zv::Val itemTypesHold(std::move(itemTypes)); @@ -618,7 +620,7 @@ class ArrayHandler if (UNEXPECTED(isArray < 0)) return zv::Val(); if (isArray == 1) { pt_ietr_get_type getTypeCallback{&walkedType, frame, &walkedTypeCallable}; - return getArrayType(OBJ_PROP_NUM(handler.self, slots::initializerExprTypeResolver), inner, getTypeCallback); + return getArrayType(OBJ_PROP_NUM(handler.self, slots::initializerExprTypeResolver), inner, getTypeCallback, frame->scope); } for (int scalarClass : {PT_CLASS_SCALAR_STRING, PT_CLASS_SCALAR_INT, PT_CLASS_SCALAR_FLOAT}) { @@ -712,7 +714,7 @@ class ArrayHandler zv::Val typesValue(std::move(types)); WalkedTypeFrame frame{self, typesValue.raw(), nodeScopeResolver, view.walk->scope.raw()}; pt_ietr_get_type getTypeCallback{&walkedType, &frame, &walkedTypeCallable}; - return getArrayType(OBJ_PROP_NUM(self, slots::initializerExprTypeResolver), view.walk->expr, getTypeCallback); + return getArrayType(OBJ_PROP_NUM(self, slots::initializerExprTypeResolver), view.walk->expr, getTypeCallback, view.walk->scope.raw()); } /* Mirrors createResult() */ @@ -1204,7 +1206,7 @@ class ArrayHandler { ItemTypeFrame frame{itemResults, nativeTypesPromoted}; pt_ietr_get_type getTypeCallback{&itemTypeCallback, &frame, &itemTypeCallable}; - type = getArrayType(OBJ_PROP_NUM(self, slots::initializerExprTypeResolver), expr, getTypeCallback); + type = getArrayType(OBJ_PROP_NUM(self, slots::initializerExprTypeResolver), expr, getTypeCallback, beforeScope); if (UNEXPECTED(type.isUndef())) return zv::Val(); } diff --git a/turbo-ext/src/AssignHandler.cpp b/turbo-ext/src/AssignHandler.cpp index c171bf981b8..d1364a92627 100644 --- a/turbo-ext/src/AssignHandler.cpp +++ b/turbo-ext/src/AssignHandler.cpp @@ -688,10 +688,14 @@ zv::Val vehCreateTypeExprResult(zval *helper, zval *scope, zval *expr) return pt_virtual_expr_result_helper_create_type_expr_result(helper, scope, expr); } -/* $phpVersion->supportsPropertyHooks(); false = pending exception */ -[[nodiscard]] bool phpVersionSupportsPropertyHooks(zval *phpVersion, bool &out) +/* !$scope->getPhpVersion()->supportsPropertyHooks()->no(); false = pending + * exception */ +[[nodiscard]] bool scopeMaySupportPropertyHooks(zval *scope, bool &out) { - return pt_php_version_supports_property_hooks(phpVersion, out); + zend_long supports = pt_mutating_scope_php_versions_trinary(Z_OBJ_P(scope), PT_LC("supportspropertyhooks")); + if (UNEXPECTED(supports < 0)) return false; + out = supports != PT_TRI_NO; + return true; } /* VirtualAssignNodeCallback::create($nodeCallback) */ @@ -1082,7 +1086,7 @@ class AssignHandler void construct(zval *argv) { zv::ObjRef object(self); - for (uint32_t i = 0; i < 20; i++) { + for (uint32_t i = 0; i < 19; i++) { object.propAtWrite(i, zv::Val::copyOf(zv::Ref(&argv[i]))); } } @@ -3973,7 +3977,7 @@ class AssignHandler if (ahIs(AH_PROP(var, name), PT_CLASS_EXPR)) { bool supportsPropertyHooks; - AH_OKB(phpVersionSupportsPropertyHooks(prop(slots::phpVersion), supportsPropertyHooks)); + AH_OKB(scopeMaySupportPropertyHooks(scope.raw(), supportsPropertyHooks)); if (supportsPropertyHooks) { AH_VALB(throwPoint, itpCreateImplicit(scope.raw(), var)); ahPush(throwPoints, std::move(throwPoint)); @@ -4023,7 +4027,7 @@ class AssignHandler ahPush(throwPoints, std::move(throwPoint)); } bool supportsPropertyHooks; - AH_OKB(phpVersionSupportsPropertyHooks(prop(slots::phpVersion), supportsPropertyHooks)); + AH_OKB(scopeMaySupportPropertyHooks(scope.raw(), supportsPropertyHooks)); if (supportsPropertyHooks) { AH_VALB(points, phtprGetThrowPointsFromSetHook(prop(slots::propertyHookThrowPointsResolver), scope.raw(), var, nativeProperty.raw())); AH_OKB(ahMerge(throwPoints, points.raw())); @@ -4883,7 +4887,7 @@ PT_MINIT_REGISTRATION(pt_register_assign_handler) cls.method(sigs::__construct, [](INTERNAL_FUNCTION_PARAMETERS) { zval *argv; uint32_t argc; - ZEND_PARSE_PARAMETERS_START(20, 20) + ZEND_PARSE_PARAMETERS_START(19, 19) Z_PARAM_VARIADIC('+', argv, argc) ZEND_PARSE_PARAMETERS_END(); for (uint32_t i = 0; i < argc; i++) { diff --git a/turbo-ext/src/ImplicitToStringCallHelper.cpp b/turbo-ext/src/ImplicitToStringCallHelper.cpp index 26de31c0be3..1fa6b3532f6 100644 --- a/turbo-ext/src/ImplicitToStringCallHelper.cpp +++ b/turbo-ext/src/ImplicitToStringCallHelper.cpp @@ -12,9 +12,9 @@ * MutatingScope, ExpressionResult, ExpressionContext, ImpurePoint, the * method reflections, ClassReflection, ParametersAcceptorSelector, * MethodCallReturnTypeHelper, MethodThrowPointHelper, SpecifiedTypes and the - * Type kernel are called through their direct entries; PhpVersion's - * throwsOnStringCast() reads the final class's versionId slot (the method - * otherwise), and the combined acceptor's getNativeReturnType() goes through + * Type kernel are called through their direct entries; the scope's + * PhpVersions answers throwsOnStringCast() through its method, and the + * combined acceptor's getNativeReturnType() goes through * the cached site of CallHandlerSupport.h. */ @@ -35,13 +35,6 @@ zend_string *pt_itsch_method_call = nullptr; zend_string *pt_itsch_synthetic_site_attribute = nullptr; -/* $phpVersion->throwsOnStringCast(): `$this->versionId >= 70400` of exactly - * the final PhpVersion, the method otherwise; false = pending exception */ -[[nodiscard]] bool throwsOnStringCast(zval *phpVersion, bool &out) -{ - return pt_php_version_answer(phpVersion, PT_PHP_VERSION_THROWS_ON_STRING_CAST, out); -} - /* sprintf('call to method %s::%s()', $declaringClassDisplayName, $methodName) */ zend_string *callToMethodDescription(zval *displayName, zval *methodName) { @@ -70,9 +63,8 @@ class ImplicitToStringCallHelper explicit ImplicitToStringCallHelper(zend_object *self) : self(self) {} /* the constructor body: the promoted properties */ - void construct(zval *phpVersion, zval *methodThrowPointHelper, zval *methodCallReturnTypeHelper, zval *expressionResultFactory) const + void construct(zval *methodThrowPointHelper, zval *methodCallReturnTypeHelper, zval *expressionResultFactory) const { - pt_write_slot(self, slots::phpVersion, phpVersion); pt_write_slot(self, slots::methodThrowPointHelper, methodThrowPointHelper); pt_write_slot(self, slots::methodCallReturnTypeHelper, methodCallReturnTypeHelper); pt_write_slot(self, slots::expressionResultFactory, expressionResultFactory); @@ -134,9 +126,10 @@ class ImplicitToStringCallHelper impurePoints.push(std::move(impurePoint)); } - bool throws; - if (UNEXPECTED(!throwsOnStringCast(OBJ_PROP_NUM(self, slots::phpVersion), throws))) return zv::Val(); - if (throws) { + /* $scope->getPhpVersion()->throwsOnStringCast()->no() negated */ + zend_long throws = pt_mutating_scope_php_versions_trinary(Z_OBJ_P(scope), PT_LC("throwsonstringcast")); + if (UNEXPECTED(throws < 0)) return zv::Val(); + if (throws != PT_TRI_NO) { // the __toString() call's return type resolves directly (the receiver // type is already in hand); the fabricated node is only the payload // dynamic extensions receive - nothing walks it @@ -245,9 +238,9 @@ PT_MINIT_REGISTRATION(pt_register_implicit_to_string_call_helper) /* the real parameter class names: the DI container autowires the * service by reflecting the constructor */ cls.method(sigs::__construct, [](INTERNAL_FUNCTION_PARAMETERS) { - zval *phpVersion, *methodThrowPointHelper, *methodCallReturnTypeHelper, *expressionResultFactory; - if (!zp::parse(execute_data, phpVersion, methodThrowPointHelper, methodCallReturnTypeHelper, expressionResultFactory)) RETURN_THROWS(); - ImplicitToStringCallHelper(Z_OBJ_P(ZEND_THIS)).construct(phpVersion, methodThrowPointHelper, methodCallReturnTypeHelper, expressionResultFactory); + zval *methodThrowPointHelper, *methodCallReturnTypeHelper, *expressionResultFactory; + if (!zp::parse(execute_data, methodThrowPointHelper, methodCallReturnTypeHelper, expressionResultFactory)) RETURN_THROWS(); + ImplicitToStringCallHelper(Z_OBJ_P(ZEND_THIS)).construct(methodThrowPointHelper, methodCallReturnTypeHelper, expressionResultFactory); }); cls.method(sigs::processImplicitToStringCall, [](INTERNAL_FUNCTION_PARAMETERS) { diff --git a/turbo-ext/src/InitializerExprTypeResolver.cpp b/turbo-ext/src/InitializerExprTypeResolver.cpp index ae1215771fe..4544dddd9cc 100644 --- a/turbo-ext/src/InitializerExprTypeResolver.cpp +++ b/turbo-ext/src/InitializerExprTypeResolver.cpp @@ -1610,9 +1610,21 @@ class InitializerExprTypeResolver /* {{{ getArrayType() / getCastType() / getCastObjectType() */ - /* Mirrors getArrayType(). */ - zv::Val getArrayType(zval *expr, const pt_ietr_get_type &getTypeCallback) const + /* Mirrors getArrayType(); phpVersions NULL (or IS_NULL) stands for null. */ + zv::Val getArrayType(zval *expr, const pt_ietr_get_type &getTypeCallback, zval *phpVersions = NULL) const { + if (phpVersions != NULL && Z_TYPE_P(phpVersions) == IS_NULL) phpVersions = NULL; + // unpacking an array with string keys is an Error below PHP 8.1, so the + // string keys are kept whenever any analysed version supports it + int keepStringKeys; + if (phpVersions != NULL) { + zend_long supports = pt_type_call_trinary(Z_OBJ_P(phpVersions), PT_LC("supportsarrayunpackingwithstringkeys"), 0, NULL); + if (UNEXPECTED(supports < 0)) return zv::Val(); + keepStringKeys = supports != PT_TRI_NO; + } else { + keepStringKeys = phpVersionAtLeast(prop(slots::phpVersion), 80100, PT_LC("supportsarrayunpackingwithstringkeys")); + if (UNEXPECTED(keepStringKeys < 0)) return zv::Val(); + } zval *items = nodeProp(pt_ietr_array_items, expr); if (UNEXPECTED(items == NULL)) return zv::Val(); if (UNEXPECTED(!requireArray(items))) return zv::Val(); @@ -1652,12 +1664,10 @@ class InitializerExprTypeResolver if (UNEXPECTED(!requireArray(constantArrays.raw()))) return zv::Val(); uint32_t totalArrays = zend_hash_num_elements(Z_ARRVAL_P(constantArrays.raw())); if (totalArrays > 0) { - if (UNEXPECTED(!unpackConstantArrays(arrayBuilder.raw(), constantArrays.raw(), totalArrays, hasOffsetValueTypes))) return zv::Val(); + if (UNEXPECTED(!unpackConstantArrays(arrayBuilder.raw(), constantArrays.raw(), totalArrays, keepStringKeys, hasOffsetValueTypes))) return zv::Val(); } else { if (UNEXPECTED(!pt_constant_array_type_builder_degrade_to_general_array(arrayBuilder.raw()))) return zv::Val(); - int keepStringKeys = phpVersionAtLeast(prop(slots::phpVersion), 80100, PT_LC("supportsarrayunpackingwithstringkeys")); - if (UNEXPECTED(keepStringKeys < 0)) return zv::Val(); bool stringKeys = false; if (keepStringKeys) { IETR_VAL(iterableKeyType, callOn(valueType.raw(), mGetIterableKeyType)); @@ -1741,10 +1751,8 @@ class InitializerExprTypeResolver /* the unpack arm of getArrayType() over the item's constant arrays: * the slots merged by string key / integer position, set on the builder * and remembered as HasOffsetValueTypes; false = pending exception */ - bool unpackConstantArrays(zval *arrayBuilder, zval *constantArrays, uint32_t totalArrays, zv::Arr &hasOffsetValueTypes) const + bool unpackConstantArrays(zval *arrayBuilder, zval *constantArrays, uint32_t totalArrays, bool keepStringKeys, zv::Arr &hasOffsetValueTypes) const { - int keepStringKeys = phpVersionAtLeast(prop(slots::phpVersion), 80100, PT_LC("supportsarrayunpackingwithstringkeys")); - if (UNEXPECTED(keepStringKeys < 0)) return false; // Unpacking merges string keys by name, while integer keys are always // renumbered, so they're merged by their position among integer keys. @@ -3261,11 +3269,15 @@ zv::Val pt_initializer_expr_type_resolver_resolve_equal_type(zval *resolver, zva return callResolverMethod(site, resolver, PT_LC("resolveequaltype"), 3, argv); } -zv::Val pt_initializer_expr_type_resolver_get_array_type(zval *resolver, zval *expr, const pt_ietr_get_type &getTypeCallback) +zv::Val pt_initializer_expr_type_resolver_get_array_type(zval *resolver, zval *expr, const pt_ietr_get_type &getTypeCallback, zval *phpVersions) { - if (EXPECTED(isNativeResolver(resolver))) return InitializerExprTypeResolver(Z_OBJ_P(resolver)).getArrayType(expr, getTypeCallback); + if (EXPECTED(isNativeResolver(resolver))) return InitializerExprTypeResolver(Z_OBJ_P(resolver)).getArrayType(expr, getTypeCallback, phpVersions); static pt_method_site site; - return callResolverUnaryMethod(site, resolver, PT_LC("getarraytype"), expr, getTypeCallback); + IETR_VAL(callable, callbackCallable(getTypeCallback)); + zval nullVersions; + ZVAL_NULL(&nullVersions); + zv::Args argv{expr, callable.raw(), phpVersions != NULL ? phpVersions : &nullVersions}; + return callResolverMethod(site, resolver, PT_LC("getarraytype"), 3, argv); } zv::Val pt_initializer_expr_type_resolver_get_cast_type(zval *resolver, zval *expr, const pt_ietr_get_type &getTypeCallback) @@ -3475,7 +3487,13 @@ PT_MINIT_REGISTRATION(pt_register_initializer_expr_type_resolver) PT_RETURN_VAL(IETR_THIS.resolveConcatType(left, right)); }); - cls.method(sigs::getArrayType, IETR_UNARY_GLUE(PT_CLASS_ARRAY_EXPR, "PhpParser\\Node\\Expr\\Array_", self.getArrayType(expr, getTypeCallback))); + cls.method(sigs::getArrayType, [](INTERNAL_FUNCTION_PARAMETERS) { + zval *expr, *callable, *phpVersions = NULL; + if (!zp::parse>(execute_data, expr, callable, phpVersions)) RETURN_THROWS(); + if (UNEXPECTED(!ietrArgClass(expr, 1, PT_CLASS_ARRAY_EXPR, "PhpParser\\Node\\Expr\\Array_") || !ietrArgCallable(callable, 2))) RETURN_THROWS(); + pt_ietr_get_type getTypeCallback = callableCallback(callable); + PT_RETURN_VAL(IETR_THIS.getArrayType(expr, getTypeCallback, phpVersions)); + }); cls.method(sigs::getCastType, IETR_UNARY_GLUE(PT_CLASS_CAST_EXPR, "PhpParser\\Node\\Expr\\Cast", self.getCastType(expr, getTypeCallback))); cls.method(sigs::getCastObjectType, [](INTERNAL_FUNCTION_PARAMETERS) { diff --git a/turbo-ext/src/MutatingScope.cpp b/turbo-ext/src/MutatingScope.cpp index c1f2806aefd..ff7d5376cd3 100644 --- a/turbo-ext/src/MutatingScope.cpp +++ b/turbo-ext/src/MutatingScope.cpp @@ -1362,18 +1362,6 @@ class MutatingScope /** @internal called by ScopeOps; false = pending exception */ [[nodiscard]] bool isReadonlyPropertyFetch(zend_object *exprObject, bool allowOnlyOnThis, bool &out) { - zv::Ref phpVersion = service(PT_MSS_PHP_VERSION); - if (UNEXPECTED(!phpVersion.isObject())) { - (void) uninitializedProperty("phpVersion"); - return false; - } - bool supports; - if (UNEXPECTED(!pt_php_version_answer(phpVersion.raw(), PT_PHP_VERSION_SUPPORTS_READ_ONLY_PROPERTIES, supports))) return false; - if (!supports) { - out = false; - return true; - } - zend_class_entry *propertyFetchCe = pt_class(PT_CLASS_PROPERTY_FETCH); zend_class_entry *variableCe = pt_class(PT_CLASS_VARIABLE); zend_class_entry *identifierCe = pt_class(PT_CLASS_IDENTIFIER); @@ -1441,7 +1429,10 @@ class MutatingScope expr = zv::Val::copyOf(var); } - out = true; + /* return !$this->getPhpVersion()->supportsReadOnlyProperties()->no(); */ + zend_long supports = phpVersionsTrinary(PT_LC("supportsreadonlyproperties")); + if (UNEXPECTED(supports < 0)) return false; + out = supports != PT_TRI_NO; return true; } @@ -3806,6 +3797,18 @@ class MutatingScope return true; } + /* $this->getPhpVersion()->() as PT_TRI_*; negative = pending exception */ + [[nodiscard]] zend_long phpVersionsTrinary(const char *lcMethod, size_t lcMethodLength) + { + zv::Val phpVersions = thisGetPhpVersion(); + if (UNEXPECTED(phpVersions.isUndef())) return -1; + if (UNEXPECTED(Z_TYPE_P(phpVersions.raw()) != IS_OBJECT)) { + zend_throw_error(NULL, "Call to a member function %s() on %s", lcMethod, zend_zval_value_name(phpVersions.raw())); + return -1; + } + return pt_type_call_trinary(Z_OBJ_P(phpVersions.raw()), lcMethod, lcMethodLength, 0, NULL); + } + /* IntegerRangeType::createAllGreaterThanOrEqualTo(0) */ static zv::Val allGreaterThanOrEqualToZero() { @@ -4897,17 +4900,6 @@ class MutatingScope } } - /* $this->phpVersion->() (PhpVersionAccess.cpp); false = pending exception */ - [[nodiscard]] bool phpVersionQuery(pt_php_version_query query, bool &out) - { - zv::Ref phpVersion = service(PT_MSS_PHP_VERSION); - if (UNEXPECTED(!phpVersion.isObject())) { - (void) uninitializedProperty("phpVersion"); - return false; - } - return pt_php_version_answer(phpVersion.raw(), query, out); - } - zv::Val thisGetCurrentExpressionResultStorage() { return thisCall(PT_LC("getcurrentexpressionresultstorage"), msGetCurrentExpressionResultStorage, 0, NULL, [&]() { return getCurrentExpressionResultStorage(); }); @@ -5375,22 +5367,18 @@ class MutatingScope setHolder(expressionTypes, thisKey.get(), node.raw(), type.raw(), PT_TRI_YES); setHolder(nativeTypes, thisKey.get(), node.raw(), nativeType.raw(), PT_TRI_YES); - bool supportsReadOnlyProperties; - if (UNEXPECTED(!phpVersionQuery(PT_PHP_VERSION_SUPPORTS_READ_ONLY_PROPERTIES, supportsReadOnlyProperties))) return zv::Val(); - if (supportsReadOnlyProperties) { - for (auto entry : zv::ArrRef(nonStaticExpressions.raw())) { - zend_string *exprString = entry.stringKeyOrNull(); - if (exprString == NULL) continue; - zv::Val expr = holderExpr(entry.value()); - if (UNEXPECTED(expr.isUndef())) return zv::Val(); - bool isPropertyFetch; - if (UNEXPECTED(!isInstance(expr.ref(), PT_CLASS_PROPERTY_FETCH, isPropertyFetch))) return zv::Val(); - if (!isPropertyFetch) continue; - bool readonly; - if (UNEXPECTED(!thisIsReadonlyPropertyFetch(expr.raw(), true, readonly))) return zv::Val(); - if (!readonly) continue; - expressionTypes.set(exprString, zv::Val::copyOf(entry.value().deref())); - } + for (auto entry : zv::ArrRef(nonStaticExpressions.raw())) { + zend_string *exprString = entry.stringKeyOrNull(); + if (exprString == NULL) continue; + zv::Val expr = holderExpr(entry.value()); + if (UNEXPECTED(expr.isUndef())) return zv::Val(); + bool isPropertyFetch; + if (UNEXPECTED(!isInstance(expr.ref(), PT_CLASS_PROPERTY_FETCH, isPropertyFetch))) return zv::Val(); + if (!isPropertyFetch) continue; + bool readonly; + if (UNEXPECTED(!thisIsReadonlyPropertyFetch(expr.raw(), true, readonly))) return zv::Val(); + if (!readonly) continue; + expressionTypes.set(exprString, zv::Val::copyOf(entry.value().deref())); } } @@ -6976,16 +6964,10 @@ class MutatingScope bool isClone = zend_string_equals_literal(lowered, "__clone"); zend_string_release(lowered); if (!isClone) return scope; - zval *phpVersion = otherService(scopeObject, PT_MSS_PHP_VERSION); - if (UNEXPECTED(phpVersion == NULL)) return zv::Val(); - ZVAL_DEREF(phpVersion); - if (UNEXPECTED(Z_TYPE_P(phpVersion) != IS_OBJECT)) { - zend_throw_error(NULL, "Call to a member function supportsReadonlyPropertyReinitializationOnClone() on %s", zend_zval_value_name(phpVersion)); - return zv::Val(); - } - bool supports; - if (UNEXPECTED(!pt_php_version_answer(phpVersion, PT_PHP_VERSION_SUPPORTS_READONLY_PROPERTY_REINITIALIZATION_ON_CLONE, supports))) return zv::Val(); - if (!supports) return scope; + /* $scope->getPhpVersion()->supportsReadonlyPropertyReinitializationOnClone()->yes() */ + zend_long supports = pt_mutating_scope_php_versions_trinary(scopeObject, PT_LC("supportsreadonlypropertyreinitializationonclone")); + if (UNEXPECTED(supports < 0)) return zv::Val(); + if (supports != PT_TRI_YES) return scope; zv::Val reinitializationExpr = pt_type_new(PT_CLASS_CLONE_REINITIALIZATION_EXPR, 1, &propertyNameZv); if (UNEXPECTED(reinitializationExpr.isUndef())) return zv::Val(); zval cloneMixedZv, cloneNativeMixedZv; @@ -10066,14 +10048,10 @@ class MutatingScope if (!isProtectedSet) return canAccessClassMember(propertyReflection, out); } - zv::Ref phpVersion = service(PT_MSS_PHP_VERSION); - if (UNEXPECTED(!phpVersion.isObject())) { - (void) uninitializedProperty("phpVersion"); - return false; - } - bool supportsAsymmetricVisibility; - if (UNEXPECTED(!pt_php_version_answer(phpVersion.raw(), PT_PHP_VERSION_SUPPORTS_ASYMMETRIC_VISIBILITY, supportsAsymmetricVisibility))) return false; - if (!supportsAsymmetricVisibility) return canAccessClassMember(propertyReflection, out); + /* $this->getPhpVersion()->supportsAsymmetricVisibility()->no() */ + zend_long supportsAsymmetricVisibility = phpVersionsTrinary(PT_LC("supportsasymmetricvisibility")); + if (UNEXPECTED(supportsAsymmetricVisibility < 0)) return false; + if (supportsAsymmetricVisibility == PT_TRI_NO) return canAccessClassMember(propertyReflection, out); return memberAccessibleFromScope(propertyReflection, PT_LC("isprivateset"), out); } @@ -11823,6 +11801,18 @@ zv::Val pt_mutating_scope_get_current_template_argument_frame(zend_object *scope return pt_this_call(scope, scope->ce == pt_ce_mutating_scope, PT_LC("getcurrenttemplateargumentframe"), ®::detail::Bound<&MutatingScope::getCurrentTemplateArgumentFrame>::handle, 0, NULL, [&]() { return MutatingScope(scope).getCurrentTemplateArgumentFrame(); }); } +zend_long pt_mutating_scope_php_versions_trinary(zend_object *scope, const char *lcMethod, size_t lcMethodLength) +{ + if (EXPECTED(scope->ce == pt_ce_mutating_scope)) return MutatingScope(scope).phpVersionsTrinary(lcMethod, lcMethodLength); + zv::Val phpVersions = pt_type_call(scope, PT_LC("getphpversion"), 0, NULL); + if (UNEXPECTED(phpVersions.isUndef())) return -1; + if (UNEXPECTED(Z_TYPE_P(phpVersions.raw()) != IS_OBJECT)) { + zend_throw_error(NULL, "Call to a member function %s() on %s", lcMethod, zend_zval_value_name(phpVersions.raw())); + return -1; + } + return pt_type_call_trinary(Z_OBJ_P(phpVersions.raw()), lcMethod, lcMethodLength, 0, NULL); +} + bool pt_mutating_scope_native_types_promoted(zend_object *scope, bool &out) { return MutatingScope::scopeNativeTypesPromoted(scope, out); diff --git a/turbo-ext/src/PhpVersionAccess.cpp b/turbo-ext/src/PhpVersionAccess.cpp index 7a03644761b..e7d07edac59 100644 --- a/turbo-ext/src/PhpVersionAccess.cpp +++ b/turbo-ext/src/PhpVersionAccess.cpp @@ -32,13 +32,8 @@ const VersionQuery pt_pva_queries[PT_PHP_VERSION_QUERY_COUNT] = { /* PT_PHP_VERSION_SUPPORTS_LEGACY_CONSTRUCTOR */ {PT_LC("supportslegacyconstructor"), "supportsLegacyConstructor", 80000, true}, /* PT_PHP_VERSION_DEPRECATES_DYNAMIC_PROPERTIES */ {PT_LC("deprecatesdynamicproperties"), "deprecatesDynamicProperties", 80200, false}, /* PT_PHP_VERSION_SUPPORTS_CALLABLE_INSTANCE_METHODS */ {PT_LC("supportscallableinstancemethods"), "supportsCallableInstanceMethods", 80000, true}, - /* PT_PHP_VERSION_THROWS_ON_STRING_CAST */ {PT_LC("throwsonstringcast"), "throwsOnStringCast", 70400, false}, /* PT_PHP_VERSION_NON_NUMERIC_STRING_AND_INTEGER_IS_FALSE_ON_LOOSE_COMPARISON */ {PT_LC("nonnumericstringandintegerisfalseonloosecomparison"), "nonNumericStringAndIntegerIsFalseOnLooseComparison", 80000, false}, - /* PT_PHP_VERSION_SUPPORTS_READ_ONLY_PROPERTIES */ {PT_LC("supportsreadonlyproperties"), "supportsReadOnlyProperties", 80100, false}, - /* PT_PHP_VERSION_SUPPORTS_READONLY_PROPERTY_REINITIALIZATION_ON_CLONE */ {PT_LC("supportsreadonlypropertyreinitializationonclone"), "supportsReadonlyPropertyReinitializationOnClone", 80300, false}, - /* PT_PHP_VERSION_SUPPORTS_ASYMMETRIC_VISIBILITY */ {PT_LC("supportsasymmetricvisibility"), "supportsAsymmetricVisibility", 80400, false}, /* PT_PHP_VERSION_SUPPORTS_ENUMS */ {PT_LC("supportsenums"), "supportsEnums", 80100, false}, - /* PT_PHP_VERSION_SUPPORTS_PROPERTY_HOOKS */ {PT_LC("supportspropertyhooks"), "supportsPropertyHooks", 80400, false}, /* PT_PHP_VERSION_CASTS_NUMBERS_TO_STRINGS_ON_LOOSE_COMPARISON */ {PT_LC("castsnumberstostringsonloosecomparison"), "castsNumbersToStringsOnLooseComparison", 80000, false}, /* PT_PHP_VERSION_ALLOWS_TRAILING_WHITESPACE_IN_NUMERIC_STRINGS */ {PT_LC("allowstrailingwhitespaceinnumericstrings"), "allowsTrailingWhitespaceInNumericStrings", 80000, false}, /* PT_PHP_VERSION_THROWS_ON_DIVISION_BY_ZERO */ {PT_LC("throwsondivisionbyzero"), "throwsOnDivisionByZero", 80000, false}, diff --git a/turbo-ext/src/PropertyFetchHandler.cpp b/turbo-ext/src/PropertyFetchHandler.cpp index ea2ef96f8b2..031278c3866 100644 --- a/turbo-ext/src/PropertyFetchHandler.cpp +++ b/turbo-ext/src/PropertyFetchHandler.cpp @@ -80,9 +80,8 @@ class PropertyFetchHandler explicit PropertyFetchHandler(zend_object *self) : self(self) {} /* the constructor body: the promoted properties */ - void construct(zval *phpVersion, zval *propertyReflectionFinder, zval *expressionResultFactory, zval *propertyHookThrowPointsResolver, zval *defaultNarrowingHelper) const + void construct(zval *propertyReflectionFinder, zval *expressionResultFactory, zval *propertyHookThrowPointsResolver, zval *defaultNarrowingHelper) const { - pt_write_slot(self, slots::phpVersion, phpVersion); pt_write_slot(self, slots::propertyReflectionFinder, propertyReflectionFinder); pt_write_slot(self, slots::expressionResultFactory, expressionResultFactory); pt_write_slot(self, slots::propertyHookThrowPointsResolver, propertyHookThrowPointsResolver); @@ -153,9 +152,10 @@ class PropertyFetchHandler if (UNEXPECTED(nameIsIdentifier < 0)) return zv::Val(); bool mayShortCircuit = false; if (nameIsIdentifier) { - bool supportsPropertyHooks; - if (UNEXPECTED(!pt_php_version_supports_property_hooks(OBJ_PROP_NUM(self, slots::phpVersion), supportsPropertyHooks))) return zv::Val(); - if (supportsPropertyHooks && UNEXPECTED(!addGetHookPoints(nodeScopeResolver, expr, name, varResult, scopeBeforeVar, throwPoints, impurePoints))) return zv::Val(); + /* $scopeBeforeVar->getPhpVersion()->supportsPropertyHooks()->no() negated */ + zend_long supportsPropertyHooks = pt_mutating_scope_php_versions_trinary(Z_OBJ_P(scopeBeforeVar), PT_LC("supportspropertyhooks")); + if (UNEXPECTED(supportsPropertyHooks < 0)) return zv::Val(); + if (supportsPropertyHooks != PT_TRI_NO && UNEXPECTED(!addGetHookPoints(nodeScopeResolver, expr, name, varResult, scopeBeforeVar, throwPoints, impurePoints))) return zv::Val(); } else if (nameResult != NULL) { // a fetch that is a link in a nullsafe chain may never run - see // MethodCallHandler::processExpr(). Only the dynamic name is skipped @@ -180,9 +180,10 @@ class PropertyFetchHandler scope = pt_mutating_scope_merge_with(Z_OBJ_P(scope.raw()), borrowed); if (UNEXPECTED(scope.isUndef())) return zv::Val(); } - bool supportsPropertyHooks; - if (UNEXPECTED(!pt_php_version_supports_property_hooks(OBJ_PROP_NUM(self, slots::phpVersion), supportsPropertyHooks))) return zv::Val(); - if (supportsPropertyHooks) { + /* $scope->getPhpVersion()->supportsPropertyHooks()->no() negated */ + zend_long supportsPropertyHooks = pt_mutating_scope_php_versions_trinary(Z_OBJ_P(scope.raw()), PT_LC("supportspropertyhooks")); + if (UNEXPECTED(supportsPropertyHooks < 0)) return zv::Val(); + if (supportsPropertyHooks != PT_TRI_NO) { zv::Val throwPoint = pt_internal_throw_point_create_implicit(scope.raw(), expr); if (UNEXPECTED(throwPoint.isUndef())) return zv::Val(); appendTo(throwPoints, std::move(throwPoint)); @@ -511,15 +512,14 @@ PT_MINIT_REGISTRATION(pt_register_property_fetch_handler) /* the real parameter class names: the DI container autowires the * service by reflecting the constructor */ cls.method(sigs::__construct, [](INTERNAL_FUNCTION_PARAMETERS) { - zval *phpVersion, *propertyReflectionFinder, *expressionResultFactory, *propertyHookThrowPointsResolver, *defaultNarrowingHelper; - ZEND_PARSE_PARAMETERS_START(5, 5) - Z_PARAM_OBJECT(phpVersion) + zval *propertyReflectionFinder, *expressionResultFactory, *propertyHookThrowPointsResolver, *defaultNarrowingHelper; + ZEND_PARSE_PARAMETERS_START(4, 4) Z_PARAM_OBJECT(propertyReflectionFinder) Z_PARAM_OBJECT(expressionResultFactory) Z_PARAM_OBJECT(propertyHookThrowPointsResolver) Z_PARAM_OBJECT(defaultNarrowingHelper) ZEND_PARSE_PARAMETERS_END(); - PropertyFetchHandler(Z_OBJ_P(ZEND_THIS)).construct(phpVersion, propertyReflectionFinder, expressionResultFactory, propertyHookThrowPointsResolver, defaultNarrowingHelper); + PropertyFetchHandler(Z_OBJ_P(ZEND_THIS)).construct(propertyReflectionFinder, expressionResultFactory, propertyHookThrowPointsResolver, defaultNarrowingHelper); }); cls.method<&PropertyFetchHandler::supports, zp::Obj>(sigs::supports); diff --git a/turbo-ext/src/PropertyHookThrowPointsResolver.cpp b/turbo-ext/src/PropertyHookThrowPointsResolver.cpp index 5e619d453ad..94f6661c6b7 100644 --- a/turbo-ext/src/PropertyHookThrowPointsResolver.cpp +++ b/turbo-ext/src/PropertyHookThrowPointsResolver.cpp @@ -346,21 +346,6 @@ zv::Val pt_property_reflection_get_writable_type(zval *reflection) /* }}} */ -/* {{{ $phpVersion->supportsPropertyHooks(): `$this->versionId >= 80400` of - * exactly the final PhpVersion, the method otherwise */ - -namespace { - - -} // namespace - -bool pt_php_version_supports_property_hooks(zval *phpVersion, bool &out) -{ - return pt_php_version_answer(phpVersion, PT_PHP_VERSION_SUPPORTS_PROPERTY_HOOKS, out); -} - -/* }}} */ - /* {{{ engine ABI glue: parameter parsing + registration */ #include "reg.h" diff --git a/turbo-ext/src/generated/AssignHandler.h b/turbo-ext/src/generated/AssignHandler.h index 90adffcb2c7..bcb70d4a148 100644 --- a/turbo-ext/src/generated/AssignHandler.h +++ b/turbo-ext/src/generated/AssignHandler.h @@ -12,24 +12,23 @@ namespace ptdecl::AssignHandler { namespace slot { inline constexpr uint32_t templateArgumentObserver = 0; inline constexpr uint32_t varAnnotationProcessor = 1; -inline constexpr uint32_t phpVersion = 2; -inline constexpr uint32_t exprPrinter = 3; -inline constexpr uint32_t matchHandler = 4; -inline constexpr uint32_t ternaryHandler = 5; -inline constexpr uint32_t expressionResultFactory = 6; -inline constexpr uint32_t defaultNarrowingHelper = 7; -inline constexpr uint32_t identicalNarrowingHelper = 8; -inline constexpr uint32_t propertyReflectionFinder = 9; -inline constexpr uint32_t virtualExprResultHelper = 10; -inline constexpr uint32_t nonNullabilityHelper = 11; -inline constexpr uint32_t variableHandler = 12; -inline constexpr uint32_t arrayDimFetchHandler = 13; -inline constexpr uint32_t propertyFetchHandler = 14; -inline constexpr uint32_t staticPropertyFetchHandler = 15; -inline constexpr uint32_t methodThrowPointHelper = 16; -inline constexpr uint32_t propertyHookThrowPointsResolver = 17; -inline constexpr uint32_t statementsHandler = 18; -inline constexpr uint32_t arrayUnpackingHelper = 19; +inline constexpr uint32_t exprPrinter = 2; +inline constexpr uint32_t matchHandler = 3; +inline constexpr uint32_t ternaryHandler = 4; +inline constexpr uint32_t expressionResultFactory = 5; +inline constexpr uint32_t defaultNarrowingHelper = 6; +inline constexpr uint32_t identicalNarrowingHelper = 7; +inline constexpr uint32_t propertyReflectionFinder = 8; +inline constexpr uint32_t virtualExprResultHelper = 9; +inline constexpr uint32_t nonNullabilityHelper = 10; +inline constexpr uint32_t variableHandler = 11; +inline constexpr uint32_t arrayDimFetchHandler = 12; +inline constexpr uint32_t propertyFetchHandler = 13; +inline constexpr uint32_t staticPropertyFetchHandler = 14; +inline constexpr uint32_t methodThrowPointHelper = 15; +inline constexpr uint32_t propertyHookThrowPointsResolver = 16; +inline constexpr uint32_t statementsHandler = 17; +inline constexpr uint32_t arrayUnpackingHelper = 18; } // namespace slot inline void declareClass(reg::Class &cls) @@ -43,7 +42,6 @@ inline void declareProperties(reg::Class &cls) { cls.property("templateArgumentObserver", ZEND_ACC_PRIVATE, reg::PropertyKind::Typed, 0, "PHPStan\\Analyser\\Generics\\TemplateArgumentObserver"); cls.property("varAnnotationProcessor", ZEND_ACC_PRIVATE, reg::PropertyKind::Typed, 0, "PHPStan\\Analyser\\VarAnnotationProcessor"); - cls.property("phpVersion", ZEND_ACC_PRIVATE, reg::PropertyKind::Typed, 0, "PHPStan\\Php\\PhpVersion"); cls.property("exprPrinter", ZEND_ACC_PRIVATE, reg::PropertyKind::Typed, 0, "PHPStan\\Node\\Printer\\ExprPrinter"); cls.property("matchHandler", ZEND_ACC_PRIVATE, reg::PropertyKind::Typed, 0, "PHPStan\\Analyser\\ExprHandler\\MatchHandler"); cls.property("ternaryHandler", ZEND_ACC_PRIVATE, reg::PropertyKind::Typed, 0, "PHPStan\\Analyser\\ExprHandler\\TernaryHandler"); @@ -70,459 +68,456 @@ inline constexpr char strings[] = "PHPStan\\Analyser\\Generics\\TemplateArgumentObserver\0" /* 25 */ "varAnnotationProcessor\0" /* 76 */ "PHPStan\\Analyser\\VarAnnotationProcessor\0" /* 99 */ - "phpVersion\0" /* 139 */ - "PHPStan\\Php\\PhpVersion\0" /* 150 */ - "exprPrinter\0" /* 173 */ - "PHPStan\\Node\\Printer\\ExprPrinter\0" /* 185 */ - "matchHandler\0" /* 218 */ - "PHPStan\\Analyser\\ExprHandler\\MatchHandler\0" /* 231 */ - "ternaryHandler\0" /* 273 */ - "PHPStan\\Analyser\\ExprHandler\\TernaryHandler\0" /* 288 */ - "expressionResultFactory\0" /* 332 */ - "PHPStan\\Analyser\\ExpressionResultFactory\0" /* 356 */ - "defaultNarrowingHelper\0" /* 397 */ - "PHPStan\\Analyser\\ExprHandler\\Helper\\DefaultNarrowingHelper\0" /* 420 */ - "identicalNarrowingHelper\0" /* 479 */ - "PHPStan\\Analyser\\ExprHandler\\Helper\\IdenticalNarrowingHelper\0" /* 504 */ - "propertyReflectionFinder\0" /* 565 */ - "PHPStan\\Rules\\Properties\\PropertyReflectionFinder\0" /* 590 */ - "virtualExprResultHelper\0" /* 640 */ - "PHPStan\\Analyser\\ExprHandler\\Helper\\VirtualExprResultHelper\0" /* 664 */ - "nonNullabilityHelper\0" /* 724 */ - "PHPStan\\Analyser\\ExprHandler\\Helper\\NonNullabilityHelper\0" /* 745 */ - "variableHandler\0" /* 802 */ - "PHPStan\\Analyser\\ExprHandler\\VariableHandler\0" /* 818 */ - "arrayDimFetchHandler\0" /* 863 */ - "PHPStan\\Analyser\\ExprHandler\\ArrayDimFetchHandler\0" /* 884 */ - "propertyFetchHandler\0" /* 934 */ - "PHPStan\\Analyser\\ExprHandler\\PropertyFetchHandler\0" /* 955 */ - "staticPropertyFetchHandler\0" /* 1005 */ - "PHPStan\\Analyser\\ExprHandler\\StaticPropertyFetchHandler\0" /* 1032 */ - "methodThrowPointHelper\0" /* 1088 */ - "PHPStan\\Analyser\\ExprHandler\\Helper\\MethodThrowPointHelper\0" /* 1111 */ - "propertyHookThrowPointsResolver\0" /* 1170 */ - "PHPStan\\Analyser\\PropertyHookThrowPointsResolver\0" /* 1202 */ - "statementsHandler\0" /* 1251 */ - "PHPStan\\Analyser\\StatementsHandler\0" /* 1269 */ - "arrayUnpackingHelper\0" /* 1304 */ - "PHPStan\\Type\\ArrayUnpackingHelper\0" /* 1325 */ - "__construct\0" /* 1359 */ - "expr\0" /* 1371 */ - "PhpParser\\Node\\Expr\0" /* 1376 */ - "\0" /* 1396 */ - "supports\0" /* 1397 */ - "nodeScopeResolver\0" /* 1406 */ - "PHPStan\\Analyser\\NodeScopeResolver\0" /* 1424 */ - "stmt\0" /* 1459 */ - "PhpParser\\Node\\Stmt\0" /* 1464 */ - "scope\0" /* 1484 */ - "PHPStan\\Analyser\\MutatingScope\0" /* 1490 */ - "storage\0" /* 1521 */ - "PHPStan\\Analyser\\ExpressionResultStorage\0" /* 1529 */ - "nodeCallback\0" /* 1570 */ - "context\0" /* 1583 */ - "PHPStan\\Analyser\\ExpressionContext\0" /* 1591 */ - "PHPStan\\Analyser\\ExpressionResult\0" /* 1626 */ - "processExpr\0" /* 1660 */ - "assignedExpr\0" /* 1672 */ - "captureAssignedCallArgResults\0" /* 1685 */ - "PhpParser\\Node\\Expr\\Assign\0" /* 1715 */ - "assignedExprResult\0" /* 1742 */ - "beforeScope\0" /* 1761 */ - "Closure\0" /* 1773 */ - "createCreateTypesCallback\0" /* 1781 */ - "createSpecifyTypesCallback\0" /* 1807 */ - "var\0" /* 1834 */ - "null\0" /* 1838 */ - "processVirtualAssign\0" /* 1843 */ - "mode\0" /* 1864 */ - "PHPStan\\Analyser\\AssignTargetWalkMode\0" /* 1869 */ - "PHPStan\\Analyser\\PreparedAssignTarget\0" /* 1907 */ - "prepareTarget\0" /* 1945 */ - "doPrepareTarget\0" /* 1959 */ - "target\0" /* 1975 */ - "valueResult\0" /* 1982 */ - "assignedValueResult\0" /* 1994 */ - "applyWrite\0" /* 2014 */ - "receiverType\0" /* 2025 */ - "PHPStan\\Type\\Type\0" /* 2038 */ - "keyType\0" /* 2056 */ - "valueType\0" /* 2064 */ - "PHPStan\\Analyser\\Generics\\TemplateArgumentConstraints\0" /* 2074 */ - "collectOffsetSetUsage\0" /* 2128 */ - "keyVar\0" /* 2150 */ - "PhpParser\\Node\\Expr\\Variable\0" /* 2157 */ - "arrayArg\0" /* 2186 */ - "narrowedKeyType\0" /* 2195 */ - "dimFetchType\0" /* 2211 */ - "PHPStan\\Analyser\\SpecifiedTypes\0" /* 2224 */ - "createArrayDimFetchConditionalExpressionHolder\0" /* 2256 */ - "readAssignedValueType\0" /* 2303 */ - "varResult\0" /* 2325 */ - "postEvalScope\0" /* 2335 */ - "preEvalScope\0" /* 2349 */ - "resolveContainerTypesAfterAssignedExprEval\0" /* 2362 */ - "nameResult\0" /* 2405 */ - "nativeValueType\0" /* 2416 */ - "assignDynamicVariable\0" /* 2432 */ - "getWrittenExpr\0" /* 2454 */ - "unwrapAssign\0" /* 2469 */ - "variableName\0" /* 2482 */ - "conditionalExpressions\0" /* 2495 */ - "specifiedTypes\0" /* 2518 */ - "variableType\0" /* 2533 */ - "rhsImpurePoints\0" /* 2546 */ - "processSureTypesForConditionalExpressionsAfterAssign\0" /* 2562 */ - "processSureNotTypesForConditionalExpressionsAfterAssign\0" /* 2615 */ - "currentTypeForConditionalHolder\0" /* 2671 */ - "armScope\0" /* 2703 */ - "armExpr\0" /* 2712 */ - "remainderType\0" /* 2720 */ - "otherArmType\0" /* 2734 */ - "processTernaryArmValueImpliedTypesAfterAssign\0" /* 2747 */ - "holderExpr\0" /* 2793 */ - "holderExprString\0" /* 2804 */ - "holderType\0" /* 2821 */ - "holderCertainty\0" /* 2832 */ - "PHPStan\\TrinaryLogic\0" /* 2848 */ - "addConditionalExpressionHolder\0" /* 2869 */ - "newConditionalExpressions\0" /* 2900 */ - "mergeConditionalExpressions\0" /* 2926 */ - "PhpParser\\Node\\Expr\\Match_\0" /* 2954 */ - "processMatchForConditionalExpressionsAfterAssign\0" /* 2981 */ - "assignedType\0" /* 3030 */ - "processDerivedConditionalExpressionsAfterAssign\0" /* 3043 */ - "PhpParser\\Node\\Expr\\FuncCall\0" /* 3091 */ - "processInArrayForConditionalExpressionsAfterAssign\0" /* 3120 */ - "isExprSafeToProjectThroughVariable\0" /* 3171 */ - "dimFetchStack\0" /* 3206 */ - "PHPStan\\Analyser\\Scope\0" /* 3220 */ - "isImplicitArrayCreation\0" /* 3243 */ - "rootVarName\0" /* 3267 */ - "arrayExpr\0" /* 3279 */ - "PhpParser\\Node\\Expr\\Array_\0" /* 3289 */ - "parentExpr\0" /* 3316 */ - "processArrayByRefItems\0" /* 3327 */ - "implicitIndex\0" /* 3350 */ - "processArrayByRefItemsWithImplicitIndex\0" /* 3364 */ - "isFlattenableUnpackedArray\0" /* 3404 */ - "index\0" /* 3431 */ - "advanceImplicitIndex\0" /* 3437 */ - "offsetTypes\0" /* 3458 */ - "offsetValueType\0" /* 3470 */ - "valueToWrite\0" /* 3486 */ - "produceArrayDimFetchAssignValueToWrite\0" /* 3499 */ - "arrayDimFetch\0" /* 3538 */ - "PhpParser\\Node\\Expr\\ArrayDimFetch\0" /* 3552 */ - "shouldKeepList\0" /* 3586 */ - "offsetType\0" /* 3601 */ - "trackedLinkImpliesOffset\0" /* 3612 */ - "a\0" /* 3637 */ - "b\0" /* 3639 */ - "isSameVariable\0" /* 3641 */ - "isSameOffset\0" /* 3656 */ - "getLiteralArrayKeyType\0" /* 3669 */ - "propertyFetch\0" /* 3692 */ - "PhpParser\\Node\\Expr\\PropertyFetch|PhpParser\\Node\\Expr\\StaticPropertyFetch\0" /* 3706 */ - "getOriginalPropertyType\0" /* 3780 */ - "array\0" /* 3804 */ - "hasArrayReference\0" /* 3810 */ - "rhs\0" /* 3828 */ - "redundant"; /* 3832 */ + "exprPrinter\0" /* 139 */ + "PHPStan\\Node\\Printer\\ExprPrinter\0" /* 151 */ + "matchHandler\0" /* 184 */ + "PHPStan\\Analyser\\ExprHandler\\MatchHandler\0" /* 197 */ + "ternaryHandler\0" /* 239 */ + "PHPStan\\Analyser\\ExprHandler\\TernaryHandler\0" /* 254 */ + "expressionResultFactory\0" /* 298 */ + "PHPStan\\Analyser\\ExpressionResultFactory\0" /* 322 */ + "defaultNarrowingHelper\0" /* 363 */ + "PHPStan\\Analyser\\ExprHandler\\Helper\\DefaultNarrowingHelper\0" /* 386 */ + "identicalNarrowingHelper\0" /* 445 */ + "PHPStan\\Analyser\\ExprHandler\\Helper\\IdenticalNarrowingHelper\0" /* 470 */ + "propertyReflectionFinder\0" /* 531 */ + "PHPStan\\Rules\\Properties\\PropertyReflectionFinder\0" /* 556 */ + "virtualExprResultHelper\0" /* 606 */ + "PHPStan\\Analyser\\ExprHandler\\Helper\\VirtualExprResultHelper\0" /* 630 */ + "nonNullabilityHelper\0" /* 690 */ + "PHPStan\\Analyser\\ExprHandler\\Helper\\NonNullabilityHelper\0" /* 711 */ + "variableHandler\0" /* 768 */ + "PHPStan\\Analyser\\ExprHandler\\VariableHandler\0" /* 784 */ + "arrayDimFetchHandler\0" /* 829 */ + "PHPStan\\Analyser\\ExprHandler\\ArrayDimFetchHandler\0" /* 850 */ + "propertyFetchHandler\0" /* 900 */ + "PHPStan\\Analyser\\ExprHandler\\PropertyFetchHandler\0" /* 921 */ + "staticPropertyFetchHandler\0" /* 971 */ + "PHPStan\\Analyser\\ExprHandler\\StaticPropertyFetchHandler\0" /* 998 */ + "methodThrowPointHelper\0" /* 1054 */ + "PHPStan\\Analyser\\ExprHandler\\Helper\\MethodThrowPointHelper\0" /* 1077 */ + "propertyHookThrowPointsResolver\0" /* 1136 */ + "PHPStan\\Analyser\\PropertyHookThrowPointsResolver\0" /* 1168 */ + "statementsHandler\0" /* 1217 */ + "PHPStan\\Analyser\\StatementsHandler\0" /* 1235 */ + "arrayUnpackingHelper\0" /* 1270 */ + "PHPStan\\Type\\ArrayUnpackingHelper\0" /* 1291 */ + "__construct\0" /* 1325 */ + "expr\0" /* 1337 */ + "PhpParser\\Node\\Expr\0" /* 1342 */ + "\0" /* 1362 */ + "supports\0" /* 1363 */ + "nodeScopeResolver\0" /* 1372 */ + "PHPStan\\Analyser\\NodeScopeResolver\0" /* 1390 */ + "stmt\0" /* 1425 */ + "PhpParser\\Node\\Stmt\0" /* 1430 */ + "scope\0" /* 1450 */ + "PHPStan\\Analyser\\MutatingScope\0" /* 1456 */ + "storage\0" /* 1487 */ + "PHPStan\\Analyser\\ExpressionResultStorage\0" /* 1495 */ + "nodeCallback\0" /* 1536 */ + "context\0" /* 1549 */ + "PHPStan\\Analyser\\ExpressionContext\0" /* 1557 */ + "PHPStan\\Analyser\\ExpressionResult\0" /* 1592 */ + "processExpr\0" /* 1626 */ + "assignedExpr\0" /* 1638 */ + "captureAssignedCallArgResults\0" /* 1651 */ + "PhpParser\\Node\\Expr\\Assign\0" /* 1681 */ + "assignedExprResult\0" /* 1708 */ + "beforeScope\0" /* 1727 */ + "Closure\0" /* 1739 */ + "createCreateTypesCallback\0" /* 1747 */ + "createSpecifyTypesCallback\0" /* 1773 */ + "var\0" /* 1800 */ + "null\0" /* 1804 */ + "processVirtualAssign\0" /* 1809 */ + "mode\0" /* 1830 */ + "PHPStan\\Analyser\\AssignTargetWalkMode\0" /* 1835 */ + "PHPStan\\Analyser\\PreparedAssignTarget\0" /* 1873 */ + "prepareTarget\0" /* 1911 */ + "doPrepareTarget\0" /* 1925 */ + "target\0" /* 1941 */ + "valueResult\0" /* 1948 */ + "assignedValueResult\0" /* 1960 */ + "applyWrite\0" /* 1980 */ + "receiverType\0" /* 1991 */ + "PHPStan\\Type\\Type\0" /* 2004 */ + "keyType\0" /* 2022 */ + "valueType\0" /* 2030 */ + "PHPStan\\Analyser\\Generics\\TemplateArgumentConstraints\0" /* 2040 */ + "collectOffsetSetUsage\0" /* 2094 */ + "keyVar\0" /* 2116 */ + "PhpParser\\Node\\Expr\\Variable\0" /* 2123 */ + "arrayArg\0" /* 2152 */ + "narrowedKeyType\0" /* 2161 */ + "dimFetchType\0" /* 2177 */ + "PHPStan\\Analyser\\SpecifiedTypes\0" /* 2190 */ + "createArrayDimFetchConditionalExpressionHolder\0" /* 2222 */ + "readAssignedValueType\0" /* 2269 */ + "varResult\0" /* 2291 */ + "postEvalScope\0" /* 2301 */ + "preEvalScope\0" /* 2315 */ + "resolveContainerTypesAfterAssignedExprEval\0" /* 2328 */ + "nameResult\0" /* 2371 */ + "nativeValueType\0" /* 2382 */ + "assignDynamicVariable\0" /* 2398 */ + "getWrittenExpr\0" /* 2420 */ + "unwrapAssign\0" /* 2435 */ + "variableName\0" /* 2448 */ + "conditionalExpressions\0" /* 2461 */ + "specifiedTypes\0" /* 2484 */ + "variableType\0" /* 2499 */ + "rhsImpurePoints\0" /* 2512 */ + "processSureTypesForConditionalExpressionsAfterAssign\0" /* 2528 */ + "processSureNotTypesForConditionalExpressionsAfterAssign\0" /* 2581 */ + "currentTypeForConditionalHolder\0" /* 2637 */ + "armScope\0" /* 2669 */ + "armExpr\0" /* 2678 */ + "remainderType\0" /* 2686 */ + "otherArmType\0" /* 2700 */ + "processTernaryArmValueImpliedTypesAfterAssign\0" /* 2713 */ + "holderExpr\0" /* 2759 */ + "holderExprString\0" /* 2770 */ + "holderType\0" /* 2787 */ + "holderCertainty\0" /* 2798 */ + "PHPStan\\TrinaryLogic\0" /* 2814 */ + "addConditionalExpressionHolder\0" /* 2835 */ + "newConditionalExpressions\0" /* 2866 */ + "mergeConditionalExpressions\0" /* 2892 */ + "PhpParser\\Node\\Expr\\Match_\0" /* 2920 */ + "processMatchForConditionalExpressionsAfterAssign\0" /* 2947 */ + "assignedType\0" /* 2996 */ + "processDerivedConditionalExpressionsAfterAssign\0" /* 3009 */ + "PhpParser\\Node\\Expr\\FuncCall\0" /* 3057 */ + "processInArrayForConditionalExpressionsAfterAssign\0" /* 3086 */ + "isExprSafeToProjectThroughVariable\0" /* 3137 */ + "dimFetchStack\0" /* 3172 */ + "PHPStan\\Analyser\\Scope\0" /* 3186 */ + "isImplicitArrayCreation\0" /* 3209 */ + "rootVarName\0" /* 3233 */ + "arrayExpr\0" /* 3245 */ + "PhpParser\\Node\\Expr\\Array_\0" /* 3255 */ + "parentExpr\0" /* 3282 */ + "processArrayByRefItems\0" /* 3293 */ + "implicitIndex\0" /* 3316 */ + "processArrayByRefItemsWithImplicitIndex\0" /* 3330 */ + "isFlattenableUnpackedArray\0" /* 3370 */ + "index\0" /* 3397 */ + "advanceImplicitIndex\0" /* 3403 */ + "offsetTypes\0" /* 3424 */ + "offsetValueType\0" /* 3436 */ + "valueToWrite\0" /* 3452 */ + "produceArrayDimFetchAssignValueToWrite\0" /* 3465 */ + "arrayDimFetch\0" /* 3504 */ + "PhpParser\\Node\\Expr\\ArrayDimFetch\0" /* 3518 */ + "shouldKeepList\0" /* 3552 */ + "offsetType\0" /* 3567 */ + "trackedLinkImpliesOffset\0" /* 3578 */ + "a\0" /* 3603 */ + "b\0" /* 3605 */ + "isSameVariable\0" /* 3607 */ + "isSameOffset\0" /* 3622 */ + "getLiteralArrayKeyType\0" /* 3635 */ + "propertyFetch\0" /* 3658 */ + "PhpParser\\Node\\Expr\\PropertyFetch|PhpParser\\Node\\Expr\\StaticPropertyFetch\0" /* 3672 */ + "getOriginalPropertyType\0" /* 3746 */ + "array\0" /* 3770 */ + "hasArrayReference\0" /* 3776 */ + "rhs\0" /* 3794 */ + "redundant"; /* 3798 */ inline constexpr reg::PackedArg args[] = { reg::packed(0, 0, 25), /* __construct $templateArgumentObserver */ reg::packed(76, 0, 99), /* __construct $varAnnotationProcessor */ - reg::packed(139, 0, 150), /* __construct $phpVersion */ - reg::packed(173, 0, 185), /* __construct $exprPrinter */ - reg::packed(218, 0, 231), /* __construct $matchHandler */ - reg::packed(273, 0, 288), /* __construct $ternaryHandler */ - reg::packed(332, 0, 356), /* __construct $expressionResultFactory */ - reg::packed(397, 0, 420), /* __construct $defaultNarrowingHelper */ - reg::packed(479, 0, 504), /* __construct $identicalNarrowingHelper */ - reg::packed(565, 0, 590), /* __construct $propertyReflectionFinder */ - reg::packed(640, 0, 664), /* __construct $virtualExprResultHelper */ - reg::packed(724, 0, 745), /* __construct $nonNullabilityHelper */ - reg::packed(802, 0, 818), /* __construct $variableHandler */ - reg::packed(863, 0, 884), /* __construct $arrayDimFetchHandler */ - reg::packed(934, 0, 955), /* __construct $propertyFetchHandler */ - reg::packed(1005, 0, 1032), /* __construct $staticPropertyFetchHandler */ - reg::packed(1088, 0, 1111), /* __construct $methodThrowPointHelper */ - reg::packed(1170, 0, 1202), /* __construct $propertyHookThrowPointsResolver */ - reg::packed(1251, 0, 1269), /* __construct $statementsHandler */ - reg::packed(1304, 0, 1325), /* __construct $arrayUnpackingHelper */ - reg::packed(1371, 0, 1376), /* supports $expr */ - reg::packed(1396, MAY_BE_BOOL), /* supports return */ - reg::packed(1406, 0, 1424), /* processExpr $nodeScopeResolver */ - reg::packed(1459, 0, 1464), /* processExpr $stmt */ - reg::packed(1371, 0, 1376), /* processExpr $expr */ - reg::packed(1484, 0, 1490), /* processExpr $scope */ - reg::packed(1521, 0, 1529), /* processExpr $storage */ - reg::packed(1570, MAY_BE_CALLABLE), /* processExpr $nodeCallback */ - reg::packed(1583, 0, 1591), /* processExpr $context */ - reg::packed(1396, 0, 1626), /* processExpr return */ - reg::packed(1672, 0, 1376), /* captureAssignedCallArgResults $assignedExpr */ - reg::packed(1521, 0, 1529), /* captureAssignedCallArgResults $storage */ - reg::packed(1396, MAY_BE_ARRAY), /* captureAssignedCallArgResults return */ - reg::packed(1371, 0, 1715), /* createCreateTypesCallback $expr */ - reg::packed(1742, 0, 1626), /* createCreateTypesCallback $assignedExprResult */ - reg::packed(1761, 0, 1490), /* createCreateTypesCallback $beforeScope */ - reg::packed(1396, 0, 1773), /* createCreateTypesCallback return */ - reg::packed(1371, 0, 1715), /* createSpecifyTypesCallback $expr */ - reg::packed(1742, 0, 1626), /* createSpecifyTypesCallback $assignedExprResult */ - reg::packed(1761, 0, 1490), /* createSpecifyTypesCallback $beforeScope */ - reg::packed(1521, 0, 1529), /* createSpecifyTypesCallback $storage */ - reg::packed(1396, 0, 1773), /* createSpecifyTypesCallback return */ - reg::packed(1406, 0, 1424), /* processVirtualAssign $nodeScopeResolver */ - reg::packed(1484, 0, 1490), /* processVirtualAssign $scope */ - reg::packed(1521, 0, 1529), /* processVirtualAssign $storage */ - reg::packed(1459, 0, 1464), /* processVirtualAssign $stmt */ - reg::packed(1834, 0, 1376), /* processVirtualAssign $var */ - reg::packed(1672, 0, 1376), /* processVirtualAssign $assignedExpr */ - reg::packed(1570, MAY_BE_CALLABLE), /* processVirtualAssign $nodeCallback */ - reg::packed(1742, MAY_BE_NULL, 1626, false, false, 1838), /* processVirtualAssign $assignedExprResult */ - reg::packed(1396, 0, 1626), /* processVirtualAssign return */ - reg::packed(1406, 0, 1424), /* prepareTarget $nodeScopeResolver */ - reg::packed(1484, 0, 1490), /* prepareTarget $scope */ - reg::packed(1521, 0, 1529), /* prepareTarget $storage */ - reg::packed(1459, 0, 1464), /* prepareTarget $stmt */ - reg::packed(1834, 0, 1376), /* prepareTarget $var */ - reg::packed(1672, 0, 1376), /* prepareTarget $assignedExpr */ - reg::packed(1570, MAY_BE_CALLABLE), /* prepareTarget $nodeCallback */ - reg::packed(1583, 0, 1591), /* prepareTarget $context */ - reg::packed(1864, 0, 1869), /* prepareTarget $mode */ - reg::packed(1396, 0, 1907), /* prepareTarget return */ - reg::packed(1406, 0, 1424), /* doPrepareTarget $nodeScopeResolver */ - reg::packed(1484, 0, 1490), /* doPrepareTarget $scope */ - reg::packed(1521, 0, 1529), /* doPrepareTarget $storage */ - reg::packed(1459, 0, 1464), /* doPrepareTarget $stmt */ - reg::packed(1834, 0, 1376), /* doPrepareTarget $var */ - reg::packed(1672, 0, 1376), /* doPrepareTarget $assignedExpr */ - reg::packed(1570, MAY_BE_CALLABLE), /* doPrepareTarget $nodeCallback */ - reg::packed(1583, 0, 1591), /* doPrepareTarget $context */ - reg::packed(1864, 0, 1869), /* doPrepareTarget $mode */ - reg::packed(1396, 0, 1907), /* doPrepareTarget return */ - reg::packed(1406, 0, 1424), /* applyWrite $nodeScopeResolver */ - reg::packed(1975, 0, 1907), /* applyWrite $target */ - reg::packed(1982, 0, 1626), /* applyWrite $valueResult */ - reg::packed(1994, MAY_BE_NULL, 1626), /* applyWrite $assignedValueResult */ - reg::packed(1459, 0, 1464), /* applyWrite $stmt */ - reg::packed(1521, 0, 1529), /* applyWrite $storage */ - reg::packed(1570, MAY_BE_CALLABLE), /* applyWrite $nodeCallback */ - reg::packed(1583, 0, 1591), /* applyWrite $context */ - reg::packed(1396, 0, 1626), /* applyWrite return */ - reg::packed(1406, 0, 1424), /* collectOffsetSetUsage $nodeScopeResolver */ - reg::packed(1484, 0, 1490), /* collectOffsetSetUsage $scope */ - reg::packed(2025, 0, 2038), /* collectOffsetSetUsage $receiverType */ - reg::packed(2056, MAY_BE_NULL, 2038), /* collectOffsetSetUsage $keyType */ - reg::packed(2064, 0, 2038), /* collectOffsetSetUsage $valueType */ - reg::packed(1396, 0, 2074), /* collectOffsetSetUsage return */ - reg::packed(2150, 0, 2157), /* createArrayDimFetchConditionalExpressionHolder $keyVar */ - reg::packed(2186, 0, 1376), /* createArrayDimFetchConditionalExpressionHolder $arrayArg */ - reg::packed(2195, 0, 2038), /* createArrayDimFetchConditionalExpressionHolder $narrowedKeyType */ - reg::packed(2211, 0, 2038), /* createArrayDimFetchConditionalExpressionHolder $dimFetchType */ - reg::packed(1396, 0, 2224), /* createArrayDimFetchConditionalExpressionHolder return */ - reg::packed(1406, 0, 1424), /* readAssignedValueType $nodeScopeResolver */ - reg::packed(1994, MAY_BE_NULL, 1626), /* readAssignedValueType $assignedValueResult */ - reg::packed(1672, 0, 1376), /* readAssignedValueType $assignedExpr */ - reg::packed(1484, 0, 1490), /* readAssignedValueType $scope */ - reg::packed(1396, 0, 2038), /* readAssignedValueType return */ - reg::packed(1406, 0, 1424), /* resolveContainerTypesAfterAssignedExprEval $nodeScopeResolver */ - reg::packed(1834, 0, 1376), /* resolveContainerTypesAfterAssignedExprEval $var */ - reg::packed(2325, 0, 1626), /* resolveContainerTypesAfterAssignedExprEval $varResult */ - reg::packed(2335, 0, 1490), /* resolveContainerTypesAfterAssignedExprEval $postEvalScope */ - reg::packed(2349, MAY_BE_NULL, 1490), /* resolveContainerTypesAfterAssignedExprEval $preEvalScope */ - reg::packed(1521, 0, 1529), /* resolveContainerTypesAfterAssignedExprEval $storage */ - reg::packed(1396, MAY_BE_ARRAY), /* resolveContainerTypesAfterAssignedExprEval return */ - reg::packed(1484, 0, 1490), /* assignDynamicVariable $scope */ - reg::packed(2405, 0, 1626), /* assignDynamicVariable $nameResult */ - reg::packed(2064, 0, 2038), /* assignDynamicVariable $valueType */ - reg::packed(2416, 0, 2038), /* assignDynamicVariable $nativeValueType */ - reg::packed(1396, 0, 1490), /* assignDynamicVariable return */ - reg::packed(1672, 0, 1376), /* getWrittenExpr $assignedExpr */ - reg::packed(1396, 0, 1376), /* getWrittenExpr return */ - reg::packed(1371, 0, 1376), /* unwrapAssign $expr */ - reg::packed(1396, 0, 1376), /* unwrapAssign return */ - reg::packed(1406, 0, 1424), /* processSureTypesForConditionalExpressionsAfterAssign $nodeScopeResolver */ - reg::packed(1484, 0, 1490), /* processSureTypesForConditionalExpressionsAfterAssign $scope */ - reg::packed(1521, 0, 1529), /* processSureTypesForConditionalExpressionsAfterAssign $storage */ - reg::packed(2482, MAY_BE_STRING), /* processSureTypesForConditionalExpressionsAfterAssign $variableName */ - reg::packed(2495, MAY_BE_ARRAY), /* processSureTypesForConditionalExpressionsAfterAssign $conditionalExpressions */ - reg::packed(2518, 0, 2224), /* processSureTypesForConditionalExpressionsAfterAssign $specifiedTypes */ - reg::packed(2533, 0, 2038), /* processSureTypesForConditionalExpressionsAfterAssign $variableType */ - reg::packed(2546, MAY_BE_ARRAY), /* processSureTypesForConditionalExpressionsAfterAssign $rhsImpurePoints */ - reg::packed(1672, 0, 1376), /* processSureTypesForConditionalExpressionsAfterAssign $assignedExpr */ - reg::packed(1994, MAY_BE_NULL, 1626), /* processSureTypesForConditionalExpressionsAfterAssign $assignedValueResult */ - reg::packed(1396, MAY_BE_ARRAY), /* processSureTypesForConditionalExpressionsAfterAssign return */ - reg::packed(1406, 0, 1424), /* processSureNotTypesForConditionalExpressionsAfterAssign $nodeScopeResolver */ - reg::packed(1484, 0, 1490), /* processSureNotTypesForConditionalExpressionsAfterAssign $scope */ - reg::packed(1521, 0, 1529), /* processSureNotTypesForConditionalExpressionsAfterAssign $storage */ - reg::packed(2482, MAY_BE_STRING), /* processSureNotTypesForConditionalExpressionsAfterAssign $variableName */ - reg::packed(2495, MAY_BE_ARRAY), /* processSureNotTypesForConditionalExpressionsAfterAssign $conditionalExpressions */ - reg::packed(2518, 0, 2224), /* processSureNotTypesForConditionalExpressionsAfterAssign $specifiedTypes */ - reg::packed(2533, 0, 2038), /* processSureNotTypesForConditionalExpressionsAfterAssign $variableType */ - reg::packed(2546, MAY_BE_ARRAY), /* processSureNotTypesForConditionalExpressionsAfterAssign $rhsImpurePoints */ - reg::packed(1672, 0, 1376), /* processSureNotTypesForConditionalExpressionsAfterAssign $assignedExpr */ - reg::packed(1994, MAY_BE_NULL, 1626), /* processSureNotTypesForConditionalExpressionsAfterAssign $assignedValueResult */ - reg::packed(1396, MAY_BE_ARRAY), /* processSureNotTypesForConditionalExpressionsAfterAssign return */ - reg::packed(1406, 0, 1424), /* currentTypeForConditionalHolder $nodeScopeResolver */ - reg::packed(1484, 0, 1490), /* currentTypeForConditionalHolder $scope */ - reg::packed(1521, 0, 1529), /* currentTypeForConditionalHolder $storage */ - reg::packed(1371, 0, 1376), /* currentTypeForConditionalHolder $expr */ - reg::packed(1672, 0, 1376), /* currentTypeForConditionalHolder $assignedExpr */ - reg::packed(1994, MAY_BE_NULL, 1626), /* currentTypeForConditionalHolder $assignedValueResult */ - reg::packed(1396, 0, 2038), /* currentTypeForConditionalHolder return */ - reg::packed(1406, 0, 1424), /* processTernaryArmValueImpliedTypesAfterAssign $nodeScopeResolver */ - reg::packed(2703, 0, 1490), /* processTernaryArmValueImpliedTypesAfterAssign $armScope */ - reg::packed(1521, 0, 1529), /* processTernaryArmValueImpliedTypesAfterAssign $storage */ - reg::packed(2482, MAY_BE_STRING), /* processTernaryArmValueImpliedTypesAfterAssign $variableName */ - reg::packed(2495, MAY_BE_ARRAY), /* processTernaryArmValueImpliedTypesAfterAssign $conditionalExpressions */ - reg::packed(2712, 0, 1376), /* processTernaryArmValueImpliedTypesAfterAssign $armExpr */ - reg::packed(2720, 0, 2038), /* processTernaryArmValueImpliedTypesAfterAssign $remainderType */ - reg::packed(2734, 0, 2038), /* processTernaryArmValueImpliedTypesAfterAssign $otherArmType */ - reg::packed(2546, MAY_BE_ARRAY), /* processTernaryArmValueImpliedTypesAfterAssign $rhsImpurePoints */ - reg::packed(1672, 0, 1376), /* processTernaryArmValueImpliedTypesAfterAssign $assignedExpr */ - reg::packed(1994, MAY_BE_NULL, 1626), /* processTernaryArmValueImpliedTypesAfterAssign $assignedValueResult */ - reg::packed(1396, MAY_BE_ARRAY), /* processTernaryArmValueImpliedTypesAfterAssign return */ - reg::packed(2495, MAY_BE_ARRAY), /* addConditionalExpressionHolder $conditionalExpressions */ - reg::packed(2482, MAY_BE_STRING), /* addConditionalExpressionHolder $variableName */ - reg::packed(2533, 0, 2038), /* addConditionalExpressionHolder $variableType */ - reg::packed(2793, 0, 1376), /* addConditionalExpressionHolder $holderExpr */ - reg::packed(2804, MAY_BE_STRING), /* addConditionalExpressionHolder $holderExprString */ - reg::packed(2821, 0, 2038), /* addConditionalExpressionHolder $holderType */ - reg::packed(2832, 0, 2848), /* addConditionalExpressionHolder $holderCertainty */ - reg::packed(1396, MAY_BE_ARRAY), /* addConditionalExpressionHolder return */ - reg::packed(2495, MAY_BE_ARRAY), /* mergeConditionalExpressions $conditionalExpressions */ - reg::packed(2900, MAY_BE_ARRAY), /* mergeConditionalExpressions $newConditionalExpressions */ - reg::packed(1396, MAY_BE_ARRAY), /* mergeConditionalExpressions return */ - reg::packed(1484, 0, 1490), /* processMatchForConditionalExpressionsAfterAssign $scope */ - reg::packed(2482, MAY_BE_STRING), /* processMatchForConditionalExpressionsAfterAssign $variableName */ - reg::packed(1371, 0, 2954), /* processMatchForConditionalExpressionsAfterAssign $expr */ - reg::packed(1396, MAY_BE_ARRAY), /* processMatchForConditionalExpressionsAfterAssign return */ - reg::packed(1406, 0, 1424), /* processDerivedConditionalExpressionsAfterAssign $nodeScopeResolver */ - reg::packed(1484, 0, 1490), /* processDerivedConditionalExpressionsAfterAssign $scope */ - reg::packed(2482, MAY_BE_STRING), /* processDerivedConditionalExpressionsAfterAssign $variableName */ - reg::packed(2495, MAY_BE_ARRAY), /* processDerivedConditionalExpressionsAfterAssign $conditionalExpressions */ - reg::packed(1672, 0, 1376), /* processDerivedConditionalExpressionsAfterAssign $assignedExpr */ - reg::packed(3030, 0, 2038), /* processDerivedConditionalExpressionsAfterAssign $assignedType */ - reg::packed(2546, MAY_BE_ARRAY), /* processDerivedConditionalExpressionsAfterAssign $rhsImpurePoints */ - reg::packed(1396, MAY_BE_ARRAY), /* processDerivedConditionalExpressionsAfterAssign return */ - reg::packed(1406, 0, 1424), /* processInArrayForConditionalExpressionsAfterAssign $nodeScopeResolver */ - reg::packed(1484, 0, 1490), /* processInArrayForConditionalExpressionsAfterAssign $scope */ - reg::packed(2482, MAY_BE_STRING), /* processInArrayForConditionalExpressionsAfterAssign $variableName */ - reg::packed(2495, MAY_BE_ARRAY), /* processInArrayForConditionalExpressionsAfterAssign $conditionalExpressions */ - reg::packed(1672, 0, 3091), /* processInArrayForConditionalExpressionsAfterAssign $assignedExpr */ - reg::packed(3030, 0, 2038), /* processInArrayForConditionalExpressionsAfterAssign $assignedType */ - reg::packed(2546, MAY_BE_ARRAY), /* processInArrayForConditionalExpressionsAfterAssign $rhsImpurePoints */ - reg::packed(1396, MAY_BE_ARRAY), /* processInArrayForConditionalExpressionsAfterAssign return */ - reg::packed(1371, 0, 1376), /* isExprSafeToProjectThroughVariable $expr */ - reg::packed(2482, MAY_BE_STRING), /* isExprSafeToProjectThroughVariable $variableName */ - reg::packed(2546, MAY_BE_ARRAY), /* isExprSafeToProjectThroughVariable $rhsImpurePoints */ - reg::packed(1672, 0, 1376), /* isExprSafeToProjectThroughVariable $assignedExpr */ - reg::packed(1396, MAY_BE_BOOL), /* isExprSafeToProjectThroughVariable return */ - reg::packed(3206, MAY_BE_ARRAY), /* isImplicitArrayCreation $dimFetchStack */ - reg::packed(1484, 0, 3220), /* isImplicitArrayCreation $scope */ - reg::packed(1396, 0, 2848), /* isImplicitArrayCreation return */ - reg::packed(1406, 0, 1424), /* processArrayByRefItems $nodeScopeResolver */ - reg::packed(1484, 0, 1490), /* processArrayByRefItems $scope */ - reg::packed(1521, 0, 1529), /* processArrayByRefItems $storage */ - reg::packed(3267, MAY_BE_STRING), /* processArrayByRefItems $rootVarName */ - reg::packed(3279, 0, 3289), /* processArrayByRefItems $arrayExpr */ - reg::packed(3316, 0, 1376), /* processArrayByRefItems $parentExpr */ - reg::packed(1396, 0, 1490), /* processArrayByRefItems return */ - reg::packed(1406, 0, 1424), /* processArrayByRefItemsWithImplicitIndex $nodeScopeResolver */ - reg::packed(1484, 0, 1490), /* processArrayByRefItemsWithImplicitIndex $scope */ - reg::packed(1521, 0, 1529), /* processArrayByRefItemsWithImplicitIndex $storage */ - reg::packed(3267, MAY_BE_STRING), /* processArrayByRefItemsWithImplicitIndex $rootVarName */ - reg::packed(3279, 0, 3289), /* processArrayByRefItemsWithImplicitIndex $arrayExpr */ - reg::packed(3316, 0, 1376), /* processArrayByRefItemsWithImplicitIndex $parentExpr */ - reg::packed(3350, MAY_BE_NULL | MAY_BE_LONG), /* processArrayByRefItemsWithImplicitIndex $implicitIndex */ - reg::packed(1396, MAY_BE_ARRAY), /* processArrayByRefItemsWithImplicitIndex return */ - reg::packed(3279, 0, 3289), /* isFlattenableUnpackedArray $arrayExpr */ - reg::packed(1396, MAY_BE_BOOL), /* isFlattenableUnpackedArray return */ - reg::packed(3431, MAY_BE_LONG), /* advanceImplicitIndex $index */ - reg::packed(1396, MAY_BE_NULL | MAY_BE_LONG), /* advanceImplicitIndex return */ - reg::packed(1406, 0, 1424), /* produceArrayDimFetchAssignValueToWrite $nodeScopeResolver */ - reg::packed(3206, MAY_BE_ARRAY), /* produceArrayDimFetchAssignValueToWrite $dimFetchStack */ - reg::packed(3458, MAY_BE_ARRAY), /* produceArrayDimFetchAssignValueToWrite $offsetTypes */ - reg::packed(3470, 0, 2038), /* produceArrayDimFetchAssignValueToWrite $offsetValueType */ - reg::packed(3486, 0, 2038), /* produceArrayDimFetchAssignValueToWrite $valueToWrite */ - reg::packed(1484, 0, 1490), /* produceArrayDimFetchAssignValueToWrite $scope */ - reg::packed(1521, 0, 1529), /* produceArrayDimFetchAssignValueToWrite $storage */ - reg::packed(1396, MAY_BE_ARRAY), /* produceArrayDimFetchAssignValueToWrite return */ - reg::packed(1406, 0, 1424), /* shouldKeepList $nodeScopeResolver */ - reg::packed(3538, 0, 3552), /* shouldKeepList $arrayDimFetch */ - reg::packed(1484, 0, 1490), /* shouldKeepList $scope */ - reg::packed(1521, 0, 1529), /* shouldKeepList $storage */ - reg::packed(3470, 0, 2038), /* shouldKeepList $offsetValueType */ - reg::packed(1396, MAY_BE_BOOL), /* shouldKeepList return */ - reg::packed(3470, 0, 2038), /* trackedLinkImpliesOffset $offsetValueType */ - reg::packed(3601, 0, 2038), /* trackedLinkImpliesOffset $offsetType */ - reg::packed(1396, MAY_BE_BOOL), /* trackedLinkImpliesOffset return */ - reg::packed(3637, 0, 1376), /* isSameVariable $a */ - reg::packed(3639, 0, 1376), /* isSameVariable $b */ - reg::packed(1396, MAY_BE_BOOL), /* isSameVariable return */ - reg::packed(3637, 0, 1376), /* isSameOffset $a */ - reg::packed(3639, 0, 1376), /* isSameOffset $b */ - reg::packed(1396, MAY_BE_BOOL), /* isSameOffset return */ - reg::packed(1371, 0, 1376), /* getLiteralArrayKeyType $expr */ - reg::packed(1396, MAY_BE_NULL, 2038), /* getLiteralArrayKeyType return */ - reg::packed(1406, 0, 1424), /* getOriginalPropertyType $nodeScopeResolver */ - reg::packed(3692, 0, 3706), /* getOriginalPropertyType $propertyFetch */ - reg::packed(1484, 0, 1490), /* getOriginalPropertyType $scope */ - reg::packed(1396, 0, 2038), /* getOriginalPropertyType return */ - reg::packed(3804, 0, 3289), /* hasArrayReference $array */ - reg::packed(1396, MAY_BE_BOOL), /* hasArrayReference return */ - reg::packed(3828, 0, 1626), /* redundant $rhs */ - reg::packed(1975, 0, 1376), /* redundant $target */ - reg::packed(1521, 0, 1529), /* redundant $storage */ - reg::packed(1396, MAY_BE_NULL, 2038), /* redundant return */ + reg::packed(139, 0, 151), /* __construct $exprPrinter */ + reg::packed(184, 0, 197), /* __construct $matchHandler */ + reg::packed(239, 0, 254), /* __construct $ternaryHandler */ + reg::packed(298, 0, 322), /* __construct $expressionResultFactory */ + reg::packed(363, 0, 386), /* __construct $defaultNarrowingHelper */ + reg::packed(445, 0, 470), /* __construct $identicalNarrowingHelper */ + reg::packed(531, 0, 556), /* __construct $propertyReflectionFinder */ + reg::packed(606, 0, 630), /* __construct $virtualExprResultHelper */ + reg::packed(690, 0, 711), /* __construct $nonNullabilityHelper */ + reg::packed(768, 0, 784), /* __construct $variableHandler */ + reg::packed(829, 0, 850), /* __construct $arrayDimFetchHandler */ + reg::packed(900, 0, 921), /* __construct $propertyFetchHandler */ + reg::packed(971, 0, 998), /* __construct $staticPropertyFetchHandler */ + reg::packed(1054, 0, 1077), /* __construct $methodThrowPointHelper */ + reg::packed(1136, 0, 1168), /* __construct $propertyHookThrowPointsResolver */ + reg::packed(1217, 0, 1235), /* __construct $statementsHandler */ + reg::packed(1270, 0, 1291), /* __construct $arrayUnpackingHelper */ + reg::packed(1337, 0, 1342), /* supports $expr */ + reg::packed(1362, MAY_BE_BOOL), /* supports return */ + reg::packed(1372, 0, 1390), /* processExpr $nodeScopeResolver */ + reg::packed(1425, 0, 1430), /* processExpr $stmt */ + reg::packed(1337, 0, 1342), /* processExpr $expr */ + reg::packed(1450, 0, 1456), /* processExpr $scope */ + reg::packed(1487, 0, 1495), /* processExpr $storage */ + reg::packed(1536, MAY_BE_CALLABLE), /* processExpr $nodeCallback */ + reg::packed(1549, 0, 1557), /* processExpr $context */ + reg::packed(1362, 0, 1592), /* processExpr return */ + reg::packed(1638, 0, 1342), /* captureAssignedCallArgResults $assignedExpr */ + reg::packed(1487, 0, 1495), /* captureAssignedCallArgResults $storage */ + reg::packed(1362, MAY_BE_ARRAY), /* captureAssignedCallArgResults return */ + reg::packed(1337, 0, 1681), /* createCreateTypesCallback $expr */ + reg::packed(1708, 0, 1592), /* createCreateTypesCallback $assignedExprResult */ + reg::packed(1727, 0, 1456), /* createCreateTypesCallback $beforeScope */ + reg::packed(1362, 0, 1739), /* createCreateTypesCallback return */ + reg::packed(1337, 0, 1681), /* createSpecifyTypesCallback $expr */ + reg::packed(1708, 0, 1592), /* createSpecifyTypesCallback $assignedExprResult */ + reg::packed(1727, 0, 1456), /* createSpecifyTypesCallback $beforeScope */ + reg::packed(1487, 0, 1495), /* createSpecifyTypesCallback $storage */ + reg::packed(1362, 0, 1739), /* createSpecifyTypesCallback return */ + reg::packed(1372, 0, 1390), /* processVirtualAssign $nodeScopeResolver */ + reg::packed(1450, 0, 1456), /* processVirtualAssign $scope */ + reg::packed(1487, 0, 1495), /* processVirtualAssign $storage */ + reg::packed(1425, 0, 1430), /* processVirtualAssign $stmt */ + reg::packed(1800, 0, 1342), /* processVirtualAssign $var */ + reg::packed(1638, 0, 1342), /* processVirtualAssign $assignedExpr */ + reg::packed(1536, MAY_BE_CALLABLE), /* processVirtualAssign $nodeCallback */ + reg::packed(1708, MAY_BE_NULL, 1592, false, false, 1804), /* processVirtualAssign $assignedExprResult */ + reg::packed(1362, 0, 1592), /* processVirtualAssign return */ + reg::packed(1372, 0, 1390), /* prepareTarget $nodeScopeResolver */ + reg::packed(1450, 0, 1456), /* prepareTarget $scope */ + reg::packed(1487, 0, 1495), /* prepareTarget $storage */ + reg::packed(1425, 0, 1430), /* prepareTarget $stmt */ + reg::packed(1800, 0, 1342), /* prepareTarget $var */ + reg::packed(1638, 0, 1342), /* prepareTarget $assignedExpr */ + reg::packed(1536, MAY_BE_CALLABLE), /* prepareTarget $nodeCallback */ + reg::packed(1549, 0, 1557), /* prepareTarget $context */ + reg::packed(1830, 0, 1835), /* prepareTarget $mode */ + reg::packed(1362, 0, 1873), /* prepareTarget return */ + reg::packed(1372, 0, 1390), /* doPrepareTarget $nodeScopeResolver */ + reg::packed(1450, 0, 1456), /* doPrepareTarget $scope */ + reg::packed(1487, 0, 1495), /* doPrepareTarget $storage */ + reg::packed(1425, 0, 1430), /* doPrepareTarget $stmt */ + reg::packed(1800, 0, 1342), /* doPrepareTarget $var */ + reg::packed(1638, 0, 1342), /* doPrepareTarget $assignedExpr */ + reg::packed(1536, MAY_BE_CALLABLE), /* doPrepareTarget $nodeCallback */ + reg::packed(1549, 0, 1557), /* doPrepareTarget $context */ + reg::packed(1830, 0, 1835), /* doPrepareTarget $mode */ + reg::packed(1362, 0, 1873), /* doPrepareTarget return */ + reg::packed(1372, 0, 1390), /* applyWrite $nodeScopeResolver */ + reg::packed(1941, 0, 1873), /* applyWrite $target */ + reg::packed(1948, 0, 1592), /* applyWrite $valueResult */ + reg::packed(1960, MAY_BE_NULL, 1592), /* applyWrite $assignedValueResult */ + reg::packed(1425, 0, 1430), /* applyWrite $stmt */ + reg::packed(1487, 0, 1495), /* applyWrite $storage */ + reg::packed(1536, MAY_BE_CALLABLE), /* applyWrite $nodeCallback */ + reg::packed(1549, 0, 1557), /* applyWrite $context */ + reg::packed(1362, 0, 1592), /* applyWrite return */ + reg::packed(1372, 0, 1390), /* collectOffsetSetUsage $nodeScopeResolver */ + reg::packed(1450, 0, 1456), /* collectOffsetSetUsage $scope */ + reg::packed(1991, 0, 2004), /* collectOffsetSetUsage $receiverType */ + reg::packed(2022, MAY_BE_NULL, 2004), /* collectOffsetSetUsage $keyType */ + reg::packed(2030, 0, 2004), /* collectOffsetSetUsage $valueType */ + reg::packed(1362, 0, 2040), /* collectOffsetSetUsage return */ + reg::packed(2116, 0, 2123), /* createArrayDimFetchConditionalExpressionHolder $keyVar */ + reg::packed(2152, 0, 1342), /* createArrayDimFetchConditionalExpressionHolder $arrayArg */ + reg::packed(2161, 0, 2004), /* createArrayDimFetchConditionalExpressionHolder $narrowedKeyType */ + reg::packed(2177, 0, 2004), /* createArrayDimFetchConditionalExpressionHolder $dimFetchType */ + reg::packed(1362, 0, 2190), /* createArrayDimFetchConditionalExpressionHolder return */ + reg::packed(1372, 0, 1390), /* readAssignedValueType $nodeScopeResolver */ + reg::packed(1960, MAY_BE_NULL, 1592), /* readAssignedValueType $assignedValueResult */ + reg::packed(1638, 0, 1342), /* readAssignedValueType $assignedExpr */ + reg::packed(1450, 0, 1456), /* readAssignedValueType $scope */ + reg::packed(1362, 0, 2004), /* readAssignedValueType return */ + reg::packed(1372, 0, 1390), /* resolveContainerTypesAfterAssignedExprEval $nodeScopeResolver */ + reg::packed(1800, 0, 1342), /* resolveContainerTypesAfterAssignedExprEval $var */ + reg::packed(2291, 0, 1592), /* resolveContainerTypesAfterAssignedExprEval $varResult */ + reg::packed(2301, 0, 1456), /* resolveContainerTypesAfterAssignedExprEval $postEvalScope */ + reg::packed(2315, MAY_BE_NULL, 1456), /* resolveContainerTypesAfterAssignedExprEval $preEvalScope */ + reg::packed(1487, 0, 1495), /* resolveContainerTypesAfterAssignedExprEval $storage */ + reg::packed(1362, MAY_BE_ARRAY), /* resolveContainerTypesAfterAssignedExprEval return */ + reg::packed(1450, 0, 1456), /* assignDynamicVariable $scope */ + reg::packed(2371, 0, 1592), /* assignDynamicVariable $nameResult */ + reg::packed(2030, 0, 2004), /* assignDynamicVariable $valueType */ + reg::packed(2382, 0, 2004), /* assignDynamicVariable $nativeValueType */ + reg::packed(1362, 0, 1456), /* assignDynamicVariable return */ + reg::packed(1638, 0, 1342), /* getWrittenExpr $assignedExpr */ + reg::packed(1362, 0, 1342), /* getWrittenExpr return */ + reg::packed(1337, 0, 1342), /* unwrapAssign $expr */ + reg::packed(1362, 0, 1342), /* unwrapAssign return */ + reg::packed(1372, 0, 1390), /* processSureTypesForConditionalExpressionsAfterAssign $nodeScopeResolver */ + reg::packed(1450, 0, 1456), /* processSureTypesForConditionalExpressionsAfterAssign $scope */ + reg::packed(1487, 0, 1495), /* processSureTypesForConditionalExpressionsAfterAssign $storage */ + reg::packed(2448, MAY_BE_STRING), /* processSureTypesForConditionalExpressionsAfterAssign $variableName */ + reg::packed(2461, MAY_BE_ARRAY), /* processSureTypesForConditionalExpressionsAfterAssign $conditionalExpressions */ + reg::packed(2484, 0, 2190), /* processSureTypesForConditionalExpressionsAfterAssign $specifiedTypes */ + reg::packed(2499, 0, 2004), /* processSureTypesForConditionalExpressionsAfterAssign $variableType */ + reg::packed(2512, MAY_BE_ARRAY), /* processSureTypesForConditionalExpressionsAfterAssign $rhsImpurePoints */ + reg::packed(1638, 0, 1342), /* processSureTypesForConditionalExpressionsAfterAssign $assignedExpr */ + reg::packed(1960, MAY_BE_NULL, 1592), /* processSureTypesForConditionalExpressionsAfterAssign $assignedValueResult */ + reg::packed(1362, MAY_BE_ARRAY), /* processSureTypesForConditionalExpressionsAfterAssign return */ + reg::packed(1372, 0, 1390), /* processSureNotTypesForConditionalExpressionsAfterAssign $nodeScopeResolver */ + reg::packed(1450, 0, 1456), /* processSureNotTypesForConditionalExpressionsAfterAssign $scope */ + reg::packed(1487, 0, 1495), /* processSureNotTypesForConditionalExpressionsAfterAssign $storage */ + reg::packed(2448, MAY_BE_STRING), /* processSureNotTypesForConditionalExpressionsAfterAssign $variableName */ + reg::packed(2461, MAY_BE_ARRAY), /* processSureNotTypesForConditionalExpressionsAfterAssign $conditionalExpressions */ + reg::packed(2484, 0, 2190), /* processSureNotTypesForConditionalExpressionsAfterAssign $specifiedTypes */ + reg::packed(2499, 0, 2004), /* processSureNotTypesForConditionalExpressionsAfterAssign $variableType */ + reg::packed(2512, MAY_BE_ARRAY), /* processSureNotTypesForConditionalExpressionsAfterAssign $rhsImpurePoints */ + reg::packed(1638, 0, 1342), /* processSureNotTypesForConditionalExpressionsAfterAssign $assignedExpr */ + reg::packed(1960, MAY_BE_NULL, 1592), /* processSureNotTypesForConditionalExpressionsAfterAssign $assignedValueResult */ + reg::packed(1362, MAY_BE_ARRAY), /* processSureNotTypesForConditionalExpressionsAfterAssign return */ + reg::packed(1372, 0, 1390), /* currentTypeForConditionalHolder $nodeScopeResolver */ + reg::packed(1450, 0, 1456), /* currentTypeForConditionalHolder $scope */ + reg::packed(1487, 0, 1495), /* currentTypeForConditionalHolder $storage */ + reg::packed(1337, 0, 1342), /* currentTypeForConditionalHolder $expr */ + reg::packed(1638, 0, 1342), /* currentTypeForConditionalHolder $assignedExpr */ + reg::packed(1960, MAY_BE_NULL, 1592), /* currentTypeForConditionalHolder $assignedValueResult */ + reg::packed(1362, 0, 2004), /* currentTypeForConditionalHolder return */ + reg::packed(1372, 0, 1390), /* processTernaryArmValueImpliedTypesAfterAssign $nodeScopeResolver */ + reg::packed(2669, 0, 1456), /* processTernaryArmValueImpliedTypesAfterAssign $armScope */ + reg::packed(1487, 0, 1495), /* processTernaryArmValueImpliedTypesAfterAssign $storage */ + reg::packed(2448, MAY_BE_STRING), /* processTernaryArmValueImpliedTypesAfterAssign $variableName */ + reg::packed(2461, MAY_BE_ARRAY), /* processTernaryArmValueImpliedTypesAfterAssign $conditionalExpressions */ + reg::packed(2678, 0, 1342), /* processTernaryArmValueImpliedTypesAfterAssign $armExpr */ + reg::packed(2686, 0, 2004), /* processTernaryArmValueImpliedTypesAfterAssign $remainderType */ + reg::packed(2700, 0, 2004), /* processTernaryArmValueImpliedTypesAfterAssign $otherArmType */ + reg::packed(2512, MAY_BE_ARRAY), /* processTernaryArmValueImpliedTypesAfterAssign $rhsImpurePoints */ + reg::packed(1638, 0, 1342), /* processTernaryArmValueImpliedTypesAfterAssign $assignedExpr */ + reg::packed(1960, MAY_BE_NULL, 1592), /* processTernaryArmValueImpliedTypesAfterAssign $assignedValueResult */ + reg::packed(1362, MAY_BE_ARRAY), /* processTernaryArmValueImpliedTypesAfterAssign return */ + reg::packed(2461, MAY_BE_ARRAY), /* addConditionalExpressionHolder $conditionalExpressions */ + reg::packed(2448, MAY_BE_STRING), /* addConditionalExpressionHolder $variableName */ + reg::packed(2499, 0, 2004), /* addConditionalExpressionHolder $variableType */ + reg::packed(2759, 0, 1342), /* addConditionalExpressionHolder $holderExpr */ + reg::packed(2770, MAY_BE_STRING), /* addConditionalExpressionHolder $holderExprString */ + reg::packed(2787, 0, 2004), /* addConditionalExpressionHolder $holderType */ + reg::packed(2798, 0, 2814), /* addConditionalExpressionHolder $holderCertainty */ + reg::packed(1362, MAY_BE_ARRAY), /* addConditionalExpressionHolder return */ + reg::packed(2461, MAY_BE_ARRAY), /* mergeConditionalExpressions $conditionalExpressions */ + reg::packed(2866, MAY_BE_ARRAY), /* mergeConditionalExpressions $newConditionalExpressions */ + reg::packed(1362, MAY_BE_ARRAY), /* mergeConditionalExpressions return */ + reg::packed(1450, 0, 1456), /* processMatchForConditionalExpressionsAfterAssign $scope */ + reg::packed(2448, MAY_BE_STRING), /* processMatchForConditionalExpressionsAfterAssign $variableName */ + reg::packed(1337, 0, 2920), /* processMatchForConditionalExpressionsAfterAssign $expr */ + reg::packed(1362, MAY_BE_ARRAY), /* processMatchForConditionalExpressionsAfterAssign return */ + reg::packed(1372, 0, 1390), /* processDerivedConditionalExpressionsAfterAssign $nodeScopeResolver */ + reg::packed(1450, 0, 1456), /* processDerivedConditionalExpressionsAfterAssign $scope */ + reg::packed(2448, MAY_BE_STRING), /* processDerivedConditionalExpressionsAfterAssign $variableName */ + reg::packed(2461, MAY_BE_ARRAY), /* processDerivedConditionalExpressionsAfterAssign $conditionalExpressions */ + reg::packed(1638, 0, 1342), /* processDerivedConditionalExpressionsAfterAssign $assignedExpr */ + reg::packed(2996, 0, 2004), /* processDerivedConditionalExpressionsAfterAssign $assignedType */ + reg::packed(2512, MAY_BE_ARRAY), /* processDerivedConditionalExpressionsAfterAssign $rhsImpurePoints */ + reg::packed(1362, MAY_BE_ARRAY), /* processDerivedConditionalExpressionsAfterAssign return */ + reg::packed(1372, 0, 1390), /* processInArrayForConditionalExpressionsAfterAssign $nodeScopeResolver */ + reg::packed(1450, 0, 1456), /* processInArrayForConditionalExpressionsAfterAssign $scope */ + reg::packed(2448, MAY_BE_STRING), /* processInArrayForConditionalExpressionsAfterAssign $variableName */ + reg::packed(2461, MAY_BE_ARRAY), /* processInArrayForConditionalExpressionsAfterAssign $conditionalExpressions */ + reg::packed(1638, 0, 3057), /* processInArrayForConditionalExpressionsAfterAssign $assignedExpr */ + reg::packed(2996, 0, 2004), /* processInArrayForConditionalExpressionsAfterAssign $assignedType */ + reg::packed(2512, MAY_BE_ARRAY), /* processInArrayForConditionalExpressionsAfterAssign $rhsImpurePoints */ + reg::packed(1362, MAY_BE_ARRAY), /* processInArrayForConditionalExpressionsAfterAssign return */ + reg::packed(1337, 0, 1342), /* isExprSafeToProjectThroughVariable $expr */ + reg::packed(2448, MAY_BE_STRING), /* isExprSafeToProjectThroughVariable $variableName */ + reg::packed(2512, MAY_BE_ARRAY), /* isExprSafeToProjectThroughVariable $rhsImpurePoints */ + reg::packed(1638, 0, 1342), /* isExprSafeToProjectThroughVariable $assignedExpr */ + reg::packed(1362, MAY_BE_BOOL), /* isExprSafeToProjectThroughVariable return */ + reg::packed(3172, MAY_BE_ARRAY), /* isImplicitArrayCreation $dimFetchStack */ + reg::packed(1450, 0, 3186), /* isImplicitArrayCreation $scope */ + reg::packed(1362, 0, 2814), /* isImplicitArrayCreation return */ + reg::packed(1372, 0, 1390), /* processArrayByRefItems $nodeScopeResolver */ + reg::packed(1450, 0, 1456), /* processArrayByRefItems $scope */ + reg::packed(1487, 0, 1495), /* processArrayByRefItems $storage */ + reg::packed(3233, MAY_BE_STRING), /* processArrayByRefItems $rootVarName */ + reg::packed(3245, 0, 3255), /* processArrayByRefItems $arrayExpr */ + reg::packed(3282, 0, 1342), /* processArrayByRefItems $parentExpr */ + reg::packed(1362, 0, 1456), /* processArrayByRefItems return */ + reg::packed(1372, 0, 1390), /* processArrayByRefItemsWithImplicitIndex $nodeScopeResolver */ + reg::packed(1450, 0, 1456), /* processArrayByRefItemsWithImplicitIndex $scope */ + reg::packed(1487, 0, 1495), /* processArrayByRefItemsWithImplicitIndex $storage */ + reg::packed(3233, MAY_BE_STRING), /* processArrayByRefItemsWithImplicitIndex $rootVarName */ + reg::packed(3245, 0, 3255), /* processArrayByRefItemsWithImplicitIndex $arrayExpr */ + reg::packed(3282, 0, 1342), /* processArrayByRefItemsWithImplicitIndex $parentExpr */ + reg::packed(3316, MAY_BE_NULL | MAY_BE_LONG), /* processArrayByRefItemsWithImplicitIndex $implicitIndex */ + reg::packed(1362, MAY_BE_ARRAY), /* processArrayByRefItemsWithImplicitIndex return */ + reg::packed(3245, 0, 3255), /* isFlattenableUnpackedArray $arrayExpr */ + reg::packed(1362, MAY_BE_BOOL), /* isFlattenableUnpackedArray return */ + reg::packed(3397, MAY_BE_LONG), /* advanceImplicitIndex $index */ + reg::packed(1362, MAY_BE_NULL | MAY_BE_LONG), /* advanceImplicitIndex return */ + reg::packed(1372, 0, 1390), /* produceArrayDimFetchAssignValueToWrite $nodeScopeResolver */ + reg::packed(3172, MAY_BE_ARRAY), /* produceArrayDimFetchAssignValueToWrite $dimFetchStack */ + reg::packed(3424, MAY_BE_ARRAY), /* produceArrayDimFetchAssignValueToWrite $offsetTypes */ + reg::packed(3436, 0, 2004), /* produceArrayDimFetchAssignValueToWrite $offsetValueType */ + reg::packed(3452, 0, 2004), /* produceArrayDimFetchAssignValueToWrite $valueToWrite */ + reg::packed(1450, 0, 1456), /* produceArrayDimFetchAssignValueToWrite $scope */ + reg::packed(1487, 0, 1495), /* produceArrayDimFetchAssignValueToWrite $storage */ + reg::packed(1362, MAY_BE_ARRAY), /* produceArrayDimFetchAssignValueToWrite return */ + reg::packed(1372, 0, 1390), /* shouldKeepList $nodeScopeResolver */ + reg::packed(3504, 0, 3518), /* shouldKeepList $arrayDimFetch */ + reg::packed(1450, 0, 1456), /* shouldKeepList $scope */ + reg::packed(1487, 0, 1495), /* shouldKeepList $storage */ + reg::packed(3436, 0, 2004), /* shouldKeepList $offsetValueType */ + reg::packed(1362, MAY_BE_BOOL), /* shouldKeepList return */ + reg::packed(3436, 0, 2004), /* trackedLinkImpliesOffset $offsetValueType */ + reg::packed(3567, 0, 2004), /* trackedLinkImpliesOffset $offsetType */ + reg::packed(1362, MAY_BE_BOOL), /* trackedLinkImpliesOffset return */ + reg::packed(3603, 0, 1342), /* isSameVariable $a */ + reg::packed(3605, 0, 1342), /* isSameVariable $b */ + reg::packed(1362, MAY_BE_BOOL), /* isSameVariable return */ + reg::packed(3603, 0, 1342), /* isSameOffset $a */ + reg::packed(3605, 0, 1342), /* isSameOffset $b */ + reg::packed(1362, MAY_BE_BOOL), /* isSameOffset return */ + reg::packed(1337, 0, 1342), /* getLiteralArrayKeyType $expr */ + reg::packed(1362, MAY_BE_NULL, 2004), /* getLiteralArrayKeyType return */ + reg::packed(1372, 0, 1390), /* getOriginalPropertyType $nodeScopeResolver */ + reg::packed(3658, 0, 3672), /* getOriginalPropertyType $propertyFetch */ + reg::packed(1450, 0, 1456), /* getOriginalPropertyType $scope */ + reg::packed(1362, 0, 2004), /* getOriginalPropertyType return */ + reg::packed(3770, 0, 3255), /* hasArrayReference $array */ + reg::packed(1362, MAY_BE_BOOL), /* hasArrayReference return */ + reg::packed(3794, 0, 1592), /* redundant $rhs */ + reg::packed(1941, 0, 1342), /* redundant $target */ + reg::packed(1487, 0, 1495), /* redundant $storage */ + reg::packed(1362, MAY_BE_NULL, 2004), /* redundant return */ }; using Sig = reg::Sig; } // namespace sigtab /* the signatures of the methods the class declares itself (a used trait's are in the trait's header) */ namespace sig { -inline constexpr sigtab::Sig __construct = { { 1359 /* __construct */, 20, 0, 20, reg::NoArg, ZEND_ACC_PUBLIC } }; -inline constexpr sigtab::Sig supports = { { 1397 /* supports */, 1, 20, 1, 21, ZEND_ACC_PUBLIC } }; -inline constexpr sigtab::Sig processExpr = { { 1660 /* processExpr */, 7, 22, 7, 29, ZEND_ACC_PUBLIC } }; -inline constexpr sigtab::Sig captureAssignedCallArgResults = { { 1685 /* captureAssignedCallArgResults */, 2, 30, 2, 32, ZEND_ACC_PRIVATE } }; -inline constexpr sigtab::Sig createCreateTypesCallback = { { 1781 /* createCreateTypesCallback */, 3, 33, 3, 36, ZEND_ACC_PRIVATE } }; -inline constexpr sigtab::Sig createSpecifyTypesCallback = { { 1807 /* createSpecifyTypesCallback */, 4, 37, 4, 41, ZEND_ACC_PRIVATE } }; -inline constexpr sigtab::Sig processVirtualAssign = { { 1843 /* processVirtualAssign */, 7, 42, 8, 50, ZEND_ACC_PUBLIC } }; -inline constexpr sigtab::Sig prepareTarget = { { 1945 /* prepareTarget */, 9, 51, 9, 60, ZEND_ACC_PUBLIC } }; -inline constexpr sigtab::Sig doPrepareTarget = { { 1959 /* doPrepareTarget */, 9, 61, 9, 70, ZEND_ACC_PRIVATE } }; -inline constexpr sigtab::Sig applyWrite = { { 2014 /* applyWrite */, 8, 71, 8, 79, ZEND_ACC_PUBLIC } }; -inline constexpr sigtab::Sig collectOffsetSetUsage = { { 2128 /* collectOffsetSetUsage */, 5, 80, 5, 85, ZEND_ACC_PRIVATE } }; -inline constexpr sigtab::Sig createArrayDimFetchConditionalExpressionHolder = { { 2256 /* createArrayDimFetchConditionalExpressionHolder */, 4, 86, 4, 90, ZEND_ACC_PRIVATE } }; -inline constexpr sigtab::Sig readAssignedValueType = { { 2303 /* readAssignedValueType */, 4, 91, 4, 95, ZEND_ACC_PRIVATE } }; -inline constexpr sigtab::Sig resolveContainerTypesAfterAssignedExprEval = { { 2362 /* resolveContainerTypesAfterAssignedExprEval */, 6, 96, 6, 102, ZEND_ACC_PRIVATE } }; -inline constexpr sigtab::Sig assignDynamicVariable = { { 2432 /* assignDynamicVariable */, 4, 103, 4, 107, ZEND_ACC_PRIVATE } }; -inline constexpr sigtab::Sig getWrittenExpr = { { 2454 /* getWrittenExpr */, 1, 108, 1, 109, ZEND_ACC_PRIVATE } }; -inline constexpr sigtab::Sig unwrapAssign = { { 2469 /* unwrapAssign */, 1, 110, 1, 111, ZEND_ACC_PRIVATE } }; -inline constexpr sigtab::Sig processSureTypesForConditionalExpressionsAfterAssign = { { 2562 /* processSureTypesForConditionalExpressionsAfterAssign */, 10, 112, 10, 122, ZEND_ACC_PRIVATE } }; -inline constexpr sigtab::Sig processSureNotTypesForConditionalExpressionsAfterAssign = { { 2615 /* processSureNotTypesForConditionalExpressionsAfterAssign */, 10, 123, 10, 133, ZEND_ACC_PRIVATE } }; -inline constexpr sigtab::Sig currentTypeForConditionalHolder = { { 2671 /* currentTypeForConditionalHolder */, 6, 134, 6, 140, ZEND_ACC_PRIVATE } }; -inline constexpr sigtab::Sig processTernaryArmValueImpliedTypesAfterAssign = { { 2747 /* processTernaryArmValueImpliedTypesAfterAssign */, 11, 141, 11, 152, ZEND_ACC_PRIVATE } }; -inline constexpr sigtab::Sig addConditionalExpressionHolder = { { 2869 /* addConditionalExpressionHolder */, 7, 153, 7, 160, ZEND_ACC_PRIVATE } }; -inline constexpr sigtab::Sig mergeConditionalExpressions = { { 2926 /* mergeConditionalExpressions */, 2, 161, 2, 163, ZEND_ACC_PRIVATE } }; -inline constexpr sigtab::Sig processMatchForConditionalExpressionsAfterAssign = { { 2981 /* processMatchForConditionalExpressionsAfterAssign */, 3, 164, 3, 167, ZEND_ACC_PRIVATE } }; -inline constexpr sigtab::Sig processDerivedConditionalExpressionsAfterAssign = { { 3043 /* processDerivedConditionalExpressionsAfterAssign */, 7, 168, 7, 175, ZEND_ACC_PRIVATE } }; -inline constexpr sigtab::Sig processInArrayForConditionalExpressionsAfterAssign = { { 3120 /* processInArrayForConditionalExpressionsAfterAssign */, 7, 176, 7, 183, ZEND_ACC_PRIVATE } }; -inline constexpr sigtab::Sig isExprSafeToProjectThroughVariable = { { 3171 /* isExprSafeToProjectThroughVariable */, 4, 184, 4, 188, ZEND_ACC_PRIVATE } }; -inline constexpr sigtab::Sig isImplicitArrayCreation = { { 3243 /* isImplicitArrayCreation */, 2, 189, 2, 191, ZEND_ACC_PRIVATE } }; -inline constexpr sigtab::Sig processArrayByRefItems = { { 3327 /* processArrayByRefItems */, 6, 192, 6, 198, ZEND_ACC_PRIVATE } }; -inline constexpr sigtab::Sig processArrayByRefItemsWithImplicitIndex = { { 3364 /* processArrayByRefItemsWithImplicitIndex */, 7, 199, 7, 206, ZEND_ACC_PRIVATE } }; -inline constexpr sigtab::Sig isFlattenableUnpackedArray = { { 3404 /* isFlattenableUnpackedArray */, 1, 207, 1, 208, ZEND_ACC_PRIVATE } }; -inline constexpr sigtab::Sig advanceImplicitIndex = { { 3437 /* advanceImplicitIndex */, 1, 209, 1, 210, ZEND_ACC_PRIVATE } }; -inline constexpr sigtab::Sig produceArrayDimFetchAssignValueToWrite = { { 3499 /* produceArrayDimFetchAssignValueToWrite */, 7, 211, 7, 218, ZEND_ACC_PRIVATE } }; -inline constexpr sigtab::Sig shouldKeepList = { { 3586 /* shouldKeepList */, 5, 219, 5, 224, ZEND_ACC_PRIVATE } }; -inline constexpr sigtab::Sig trackedLinkImpliesOffset = { { 3612 /* trackedLinkImpliesOffset */, 2, 225, 2, 227, ZEND_ACC_PRIVATE } }; -inline constexpr sigtab::Sig isSameVariable = { { 3641 /* isSameVariable */, 2, 228, 2, 230, ZEND_ACC_PRIVATE } }; -inline constexpr sigtab::Sig isSameOffset = { { 3656 /* isSameOffset */, 2, 231, 2, 233, ZEND_ACC_PRIVATE } }; -inline constexpr sigtab::Sig getLiteralArrayKeyType = { { 3669 /* getLiteralArrayKeyType */, 1, 234, 1, 235, ZEND_ACC_PRIVATE } }; -inline constexpr sigtab::Sig getOriginalPropertyType = { { 3780 /* getOriginalPropertyType */, 3, 236, 3, 239, ZEND_ACC_PRIVATE } }; -inline constexpr sigtab::Sig hasArrayReference = { { 3810 /* hasArrayReference */, 1, 240, 1, 241, ZEND_ACC_PRIVATE | ZEND_ACC_STATIC } }; -inline constexpr sigtab::Sig redundant = { { 3832 /* redundant */, 3, 242, 3, 245, ZEND_ACC_PRIVATE | ZEND_ACC_STATIC } }; +inline constexpr sigtab::Sig __construct = { { 1325 /* __construct */, 19, 0, 19, reg::NoArg, ZEND_ACC_PUBLIC } }; +inline constexpr sigtab::Sig supports = { { 1363 /* supports */, 1, 19, 1, 20, ZEND_ACC_PUBLIC } }; +inline constexpr sigtab::Sig processExpr = { { 1626 /* processExpr */, 7, 21, 7, 28, ZEND_ACC_PUBLIC } }; +inline constexpr sigtab::Sig captureAssignedCallArgResults = { { 1651 /* captureAssignedCallArgResults */, 2, 29, 2, 31, ZEND_ACC_PRIVATE } }; +inline constexpr sigtab::Sig createCreateTypesCallback = { { 1747 /* createCreateTypesCallback */, 3, 32, 3, 35, ZEND_ACC_PRIVATE } }; +inline constexpr sigtab::Sig createSpecifyTypesCallback = { { 1773 /* createSpecifyTypesCallback */, 4, 36, 4, 40, ZEND_ACC_PRIVATE } }; +inline constexpr sigtab::Sig processVirtualAssign = { { 1809 /* processVirtualAssign */, 7, 41, 8, 49, ZEND_ACC_PUBLIC } }; +inline constexpr sigtab::Sig prepareTarget = { { 1911 /* prepareTarget */, 9, 50, 9, 59, ZEND_ACC_PUBLIC } }; +inline constexpr sigtab::Sig doPrepareTarget = { { 1925 /* doPrepareTarget */, 9, 60, 9, 69, ZEND_ACC_PRIVATE } }; +inline constexpr sigtab::Sig applyWrite = { { 1980 /* applyWrite */, 8, 70, 8, 78, ZEND_ACC_PUBLIC } }; +inline constexpr sigtab::Sig collectOffsetSetUsage = { { 2094 /* collectOffsetSetUsage */, 5, 79, 5, 84, ZEND_ACC_PRIVATE } }; +inline constexpr sigtab::Sig createArrayDimFetchConditionalExpressionHolder = { { 2222 /* createArrayDimFetchConditionalExpressionHolder */, 4, 85, 4, 89, ZEND_ACC_PRIVATE } }; +inline constexpr sigtab::Sig readAssignedValueType = { { 2269 /* readAssignedValueType */, 4, 90, 4, 94, ZEND_ACC_PRIVATE } }; +inline constexpr sigtab::Sig resolveContainerTypesAfterAssignedExprEval = { { 2328 /* resolveContainerTypesAfterAssignedExprEval */, 6, 95, 6, 101, ZEND_ACC_PRIVATE } }; +inline constexpr sigtab::Sig assignDynamicVariable = { { 2398 /* assignDynamicVariable */, 4, 102, 4, 106, ZEND_ACC_PRIVATE } }; +inline constexpr sigtab::Sig getWrittenExpr = { { 2420 /* getWrittenExpr */, 1, 107, 1, 108, ZEND_ACC_PRIVATE } }; +inline constexpr sigtab::Sig unwrapAssign = { { 2435 /* unwrapAssign */, 1, 109, 1, 110, ZEND_ACC_PRIVATE } }; +inline constexpr sigtab::Sig processSureTypesForConditionalExpressionsAfterAssign = { { 2528 /* processSureTypesForConditionalExpressionsAfterAssign */, 10, 111, 10, 121, ZEND_ACC_PRIVATE } }; +inline constexpr sigtab::Sig processSureNotTypesForConditionalExpressionsAfterAssign = { { 2581 /* processSureNotTypesForConditionalExpressionsAfterAssign */, 10, 122, 10, 132, ZEND_ACC_PRIVATE } }; +inline constexpr sigtab::Sig currentTypeForConditionalHolder = { { 2637 /* currentTypeForConditionalHolder */, 6, 133, 6, 139, ZEND_ACC_PRIVATE } }; +inline constexpr sigtab::Sig processTernaryArmValueImpliedTypesAfterAssign = { { 2713 /* processTernaryArmValueImpliedTypesAfterAssign */, 11, 140, 11, 151, ZEND_ACC_PRIVATE } }; +inline constexpr sigtab::Sig addConditionalExpressionHolder = { { 2835 /* addConditionalExpressionHolder */, 7, 152, 7, 159, ZEND_ACC_PRIVATE } }; +inline constexpr sigtab::Sig mergeConditionalExpressions = { { 2892 /* mergeConditionalExpressions */, 2, 160, 2, 162, ZEND_ACC_PRIVATE } }; +inline constexpr sigtab::Sig processMatchForConditionalExpressionsAfterAssign = { { 2947 /* processMatchForConditionalExpressionsAfterAssign */, 3, 163, 3, 166, ZEND_ACC_PRIVATE } }; +inline constexpr sigtab::Sig processDerivedConditionalExpressionsAfterAssign = { { 3009 /* processDerivedConditionalExpressionsAfterAssign */, 7, 167, 7, 174, ZEND_ACC_PRIVATE } }; +inline constexpr sigtab::Sig processInArrayForConditionalExpressionsAfterAssign = { { 3086 /* processInArrayForConditionalExpressionsAfterAssign */, 7, 175, 7, 182, ZEND_ACC_PRIVATE } }; +inline constexpr sigtab::Sig isExprSafeToProjectThroughVariable = { { 3137 /* isExprSafeToProjectThroughVariable */, 4, 183, 4, 187, ZEND_ACC_PRIVATE } }; +inline constexpr sigtab::Sig isImplicitArrayCreation = { { 3209 /* isImplicitArrayCreation */, 2, 188, 2, 190, ZEND_ACC_PRIVATE } }; +inline constexpr sigtab::Sig processArrayByRefItems = { { 3293 /* processArrayByRefItems */, 6, 191, 6, 197, ZEND_ACC_PRIVATE } }; +inline constexpr sigtab::Sig processArrayByRefItemsWithImplicitIndex = { { 3330 /* processArrayByRefItemsWithImplicitIndex */, 7, 198, 7, 205, ZEND_ACC_PRIVATE } }; +inline constexpr sigtab::Sig isFlattenableUnpackedArray = { { 3370 /* isFlattenableUnpackedArray */, 1, 206, 1, 207, ZEND_ACC_PRIVATE } }; +inline constexpr sigtab::Sig advanceImplicitIndex = { { 3403 /* advanceImplicitIndex */, 1, 208, 1, 209, ZEND_ACC_PRIVATE } }; +inline constexpr sigtab::Sig produceArrayDimFetchAssignValueToWrite = { { 3465 /* produceArrayDimFetchAssignValueToWrite */, 7, 210, 7, 217, ZEND_ACC_PRIVATE } }; +inline constexpr sigtab::Sig shouldKeepList = { { 3552 /* shouldKeepList */, 5, 218, 5, 223, ZEND_ACC_PRIVATE } }; +inline constexpr sigtab::Sig trackedLinkImpliesOffset = { { 3578 /* trackedLinkImpliesOffset */, 2, 224, 2, 226, ZEND_ACC_PRIVATE } }; +inline constexpr sigtab::Sig isSameVariable = { { 3607 /* isSameVariable */, 2, 227, 2, 229, ZEND_ACC_PRIVATE } }; +inline constexpr sigtab::Sig isSameOffset = { { 3622 /* isSameOffset */, 2, 230, 2, 232, ZEND_ACC_PRIVATE } }; +inline constexpr sigtab::Sig getLiteralArrayKeyType = { { 3635 /* getLiteralArrayKeyType */, 1, 233, 1, 234, ZEND_ACC_PRIVATE } }; +inline constexpr sigtab::Sig getOriginalPropertyType = { { 3746 /* getOriginalPropertyType */, 3, 235, 3, 238, ZEND_ACC_PRIVATE } }; +inline constexpr sigtab::Sig hasArrayReference = { { 3776 /* hasArrayReference */, 1, 239, 1, 240, ZEND_ACC_PRIVATE | ZEND_ACC_STATIC } }; +inline constexpr sigtab::Sig redundant = { { 3798 /* redundant */, 3, 241, 3, 244, ZEND_ACC_PRIVATE | ZEND_ACC_STATIC } }; } // namespace sig } // namespace ptdecl::AssignHandler diff --git a/turbo-ext/src/generated/ImplicitToStringCallHelper.h b/turbo-ext/src/generated/ImplicitToStringCallHelper.h index a0bb5df1a2d..15f87d3800d 100644 --- a/turbo-ext/src/generated/ImplicitToStringCallHelper.h +++ b/turbo-ext/src/generated/ImplicitToStringCallHelper.h @@ -10,10 +10,9 @@ namespace ptdecl::ImplicitToStringCallHelper { /* the OBJ_PROP_NUM slots of the instance properties the class declares (the inherited ones come first) */ namespace slot { -inline constexpr uint32_t phpVersion = 0; -inline constexpr uint32_t methodThrowPointHelper = 1; -inline constexpr uint32_t methodCallReturnTypeHelper = 2; -inline constexpr uint32_t expressionResultFactory = 3; +inline constexpr uint32_t methodThrowPointHelper = 0; +inline constexpr uint32_t methodCallReturnTypeHelper = 1; +inline constexpr uint32_t expressionResultFactory = 2; } // namespace slot inline void declareClass(reg::Class &cls) @@ -24,7 +23,6 @@ inline void declareClass(reg::Class &cls) /* the properties the class declares itself, in declaration order (a used trait's come from its registrar) */ inline void declareProperties(reg::Class &cls) { - cls.property("phpVersion", ZEND_ACC_PRIVATE, reg::PropertyKind::Typed, 0, "PHPStan\\Php\\PhpVersion"); cls.property("methodThrowPointHelper", ZEND_ACC_PRIVATE, reg::PropertyKind::Typed, 0, "PHPStan\\Analyser\\ExprHandler\\Helper\\MethodThrowPointHelper"); cls.property("methodCallReturnTypeHelper", ZEND_ACC_PRIVATE, reg::PropertyKind::Typed, 0, "PHPStan\\Analyser\\ExprHandler\\Helper\\MethodCallReturnTypeHelper"); cls.property("expressionResultFactory", ZEND_ACC_PRIVATE, reg::PropertyKind::Typed, 0, "PHPStan\\Analyser\\ExpressionResultFactory"); @@ -33,40 +31,37 @@ inline void declareProperties(reg::Class &cls) /* the string and parameter tables the signatures below index into (see reg::Sig) */ namespace sigtab { inline constexpr char strings[] = - "phpVersion\0" /* 0 */ - "PHPStan\\Php\\PhpVersion\0" /* 11 */ - "methodThrowPointHelper\0" /* 34 */ - "PHPStan\\Analyser\\ExprHandler\\Helper\\MethodThrowPointHelper\0" /* 57 */ - "methodCallReturnTypeHelper\0" /* 116 */ - "PHPStan\\Analyser\\ExprHandler\\Helper\\MethodCallReturnTypeHelper\0" /* 143 */ - "expressionResultFactory\0" /* 206 */ - "PHPStan\\Analyser\\ExpressionResultFactory\0" /* 230 */ - "__construct\0" /* 271 */ - "expr\0" /* 283 */ - "PhpParser\\Node\\Expr\0" /* 288 */ - "scope\0" /* 308 */ - "PHPStan\\Analyser\\MutatingScope\0" /* 314 */ - "exprResult\0" /* 345 */ - "PHPStan\\Analyser\\ExpressionResult\0" /* 356 */ - "\0" /* 390 */ - "processImplicitToStringCall"; /* 391 */ + "methodThrowPointHelper\0" /* 0 */ + "PHPStan\\Analyser\\ExprHandler\\Helper\\MethodThrowPointHelper\0" /* 23 */ + "methodCallReturnTypeHelper\0" /* 82 */ + "PHPStan\\Analyser\\ExprHandler\\Helper\\MethodCallReturnTypeHelper\0" /* 109 */ + "expressionResultFactory\0" /* 172 */ + "PHPStan\\Analyser\\ExpressionResultFactory\0" /* 196 */ + "__construct\0" /* 237 */ + "expr\0" /* 249 */ + "PhpParser\\Node\\Expr\0" /* 254 */ + "scope\0" /* 274 */ + "PHPStan\\Analyser\\MutatingScope\0" /* 280 */ + "exprResult\0" /* 311 */ + "PHPStan\\Analyser\\ExpressionResult\0" /* 322 */ + "\0" /* 356 */ + "processImplicitToStringCall"; /* 357 */ inline constexpr reg::PackedArg args[] = { - reg::packed(0, 0, 11), /* __construct $phpVersion */ - reg::packed(34, 0, 57), /* __construct $methodThrowPointHelper */ - reg::packed(116, 0, 143), /* __construct $methodCallReturnTypeHelper */ - reg::packed(206, 0, 230), /* __construct $expressionResultFactory */ - reg::packed(283, 0, 288), /* processImplicitToStringCall $expr */ - reg::packed(308, 0, 314), /* processImplicitToStringCall $scope */ - reg::packed(345, 0, 356), /* processImplicitToStringCall $exprResult */ - reg::packed(390, 0, 356), /* processImplicitToStringCall return */ + reg::packed(0, 0, 23), /* __construct $methodThrowPointHelper */ + reg::packed(82, 0, 109), /* __construct $methodCallReturnTypeHelper */ + reg::packed(172, 0, 196), /* __construct $expressionResultFactory */ + reg::packed(249, 0, 254), /* processImplicitToStringCall $expr */ + reg::packed(274, 0, 280), /* processImplicitToStringCall $scope */ + reg::packed(311, 0, 322), /* processImplicitToStringCall $exprResult */ + reg::packed(356, 0, 322), /* processImplicitToStringCall return */ }; using Sig = reg::Sig; } // namespace sigtab /* the signatures of the methods the class declares itself (a used trait's are in the trait's header) */ namespace sig { -inline constexpr sigtab::Sig __construct = { { 271 /* __construct */, 4, 0, 4, reg::NoArg, ZEND_ACC_PUBLIC } }; -inline constexpr sigtab::Sig processImplicitToStringCall = { { 391 /* processImplicitToStringCall */, 3, 4, 3, 7, ZEND_ACC_PUBLIC } }; +inline constexpr sigtab::Sig __construct = { { 237 /* __construct */, 3, 0, 3, reg::NoArg, ZEND_ACC_PUBLIC } }; +inline constexpr sigtab::Sig processImplicitToStringCall = { { 357 /* processImplicitToStringCall */, 3, 3, 3, 6, ZEND_ACC_PUBLIC } }; } // namespace sig } // namespace ptdecl::ImplicitToStringCallHelper diff --git a/turbo-ext/src/generated/InitializerExprTypeResolver.h b/turbo-ext/src/generated/InitializerExprTypeResolver.h index 14e68151c77..8826d1d74cf 100644 --- a/turbo-ext/src/generated/InitializerExprTypeResolver.h +++ b/turbo-ext/src/generated/InitializerExprTypeResolver.h @@ -74,44 +74,44 @@ inline constexpr char strings[] = "getConcatType\0" /* 663 */ "resolveConcatType\0" /* 677 */ "PhpParser\\Node\\Expr\\Array_\0" /* 695 */ - "getArrayType\0" /* 722 */ - "PhpParser\\Node\\Expr\\Cast\0" /* 735 */ - "getCastType\0" /* 760 */ - "exprType\0" /* 772 */ - "getCastObjectType\0" /* 781 */ - "type\0" /* 799 */ - "isNullable\0" /* 804 */ - "isVariadic\0" /* 815 */ - "getFunctionType\0" /* 826 */ - "parameter\0" /* 842 */ - "PhpParser\\Node\\Param\0" /* 852 */ - "isParameterValueNullable\0" /* 873 */ - "PhpParser\\Node\\Expr\\CallLike\0" /* 898 */ - "nativeTypesPromoted\0" /* 927 */ - "getFirstClassCallableType\0" /* 947 */ - "function\0" /* 973 */ - "PHPStan\\Reflection\\FunctionReflection|PHPStan\\Reflection\\ExtendedMethodReflection\0" /* 982 */ - "variants\0" /* 1064 */ - "createFirstClassCallable\0" /* 1073 */ - "getBitwiseAndType\0" /* 1098 */ - "getBitwiseOrType\0" /* 1116 */ - "getBitwiseXorType\0" /* 1133 */ - "getSpaceshipType\0" /* 1151 */ - "getDivType\0" /* 1168 */ - "getModType\0" /* 1179 */ - "getPlusType\0" /* 1190 */ - "getMinusType\0" /* 1202 */ - "getMulType\0" /* 1215 */ - "getPowType\0" /* 1226 */ - "getShiftLeftType\0" /* 1237 */ - "getShiftRightType\0" /* 1254 */ - "leftType\0" /* 1272 */ - "rightType\0" /* 1281 */ - "PHPStan\\Type\\TypeResult\0" /* 1291 */ - "resolveIdenticalType\0" /* 1315 */ - "phpVersions\0" /* 1336 */ - "PHPStan\\Php\\PhpVersions\0" /* 1348 */ - "null\0" /* 1372 */ + "phpVersions\0" /* 722 */ + "PHPStan\\Php\\PhpVersions\0" /* 734 */ + "null\0" /* 758 */ + "getArrayType\0" /* 763 */ + "PhpParser\\Node\\Expr\\Cast\0" /* 776 */ + "getCastType\0" /* 801 */ + "exprType\0" /* 813 */ + "getCastObjectType\0" /* 822 */ + "type\0" /* 840 */ + "isNullable\0" /* 845 */ + "isVariadic\0" /* 856 */ + "getFunctionType\0" /* 867 */ + "parameter\0" /* 883 */ + "PhpParser\\Node\\Param\0" /* 893 */ + "isParameterValueNullable\0" /* 914 */ + "PhpParser\\Node\\Expr\\CallLike\0" /* 939 */ + "nativeTypesPromoted\0" /* 968 */ + "getFirstClassCallableType\0" /* 988 */ + "function\0" /* 1014 */ + "PHPStan\\Reflection\\FunctionReflection|PHPStan\\Reflection\\ExtendedMethodReflection\0" /* 1023 */ + "variants\0" /* 1105 */ + "createFirstClassCallable\0" /* 1114 */ + "getBitwiseAndType\0" /* 1139 */ + "getBitwiseOrType\0" /* 1157 */ + "getBitwiseXorType\0" /* 1174 */ + "getSpaceshipType\0" /* 1192 */ + "getDivType\0" /* 1209 */ + "getModType\0" /* 1220 */ + "getPlusType\0" /* 1231 */ + "getMinusType\0" /* 1243 */ + "getMulType\0" /* 1256 */ + "getPowType\0" /* 1267 */ + "getShiftLeftType\0" /* 1278 */ + "getShiftRightType\0" /* 1295 */ + "leftType\0" /* 1313 */ + "rightType\0" /* 1322 */ + "PHPStan\\Type\\TypeResult\0" /* 1332 */ + "resolveIdenticalType\0" /* 1356 */ "resolveEqualType\0" /* 1377 */ "PHPStan\\Type\\Constant\\ConstantArrayType\0" /* 1394 */ "valueComparisonCallback\0" /* 1434 */ @@ -167,26 +167,27 @@ inline constexpr reg::PackedArg args[] = { reg::packed(559, 0, 560), /* resolveConcatType return */ reg::packed(484, 0, 695), /* getArrayType $expr */ reg::packed(647, MAY_BE_CALLABLE), /* getArrayType $getTypeCallback */ + reg::packed(722, MAY_BE_NULL, 734, false, false, 758), /* getArrayType $phpVersions */ reg::packed(559, 0, 560), /* getArrayType return */ - reg::packed(484, 0, 735), /* getCastType $expr */ + reg::packed(484, 0, 776), /* getCastType $expr */ reg::packed(647, MAY_BE_CALLABLE), /* getCastType $getTypeCallback */ reg::packed(559, 0, 560), /* getCastType return */ - reg::packed(772, 0, 560), /* getCastObjectType $exprType */ + reg::packed(813, 0, 560), /* getCastObjectType $exprType */ reg::packed(559, 0, 560), /* getCastObjectType return */ - reg::packed(799, 0), /* getFunctionType $type */ - reg::packed(804, MAY_BE_BOOL), /* getFunctionType $isNullable */ - reg::packed(815, MAY_BE_BOOL), /* getFunctionType $isVariadic */ + reg::packed(840, 0), /* getFunctionType $type */ + reg::packed(845, MAY_BE_BOOL), /* getFunctionType $isNullable */ + reg::packed(856, MAY_BE_BOOL), /* getFunctionType $isVariadic */ reg::packed(509, 0, 517), /* getFunctionType $context */ reg::packed(559, 0, 560), /* getFunctionType return */ - reg::packed(842, 0, 852), /* isParameterValueNullable $parameter */ + reg::packed(883, 0, 893), /* isParameterValueNullable $parameter */ reg::packed(559, MAY_BE_BOOL), /* isParameterValueNullable return */ - reg::packed(484, 0, 898), /* getFirstClassCallableType $expr */ + reg::packed(484, 0, 939), /* getFirstClassCallableType $expr */ reg::packed(509, 0, 517), /* getFirstClassCallableType $context */ - reg::packed(927, MAY_BE_BOOL), /* getFirstClassCallableType $nativeTypesPromoted */ + reg::packed(968, MAY_BE_BOOL), /* getFirstClassCallableType $nativeTypesPromoted */ reg::packed(559, 0, 560), /* getFirstClassCallableType return */ - reg::packed(973, MAY_BE_NULL, 982), /* createFirstClassCallable $function */ - reg::packed(1064, MAY_BE_ARRAY), /* createFirstClassCallable $variants */ - reg::packed(927, MAY_BE_BOOL), /* createFirstClassCallable $nativeTypesPromoted */ + reg::packed(1014, MAY_BE_NULL, 1023), /* createFirstClassCallable $function */ + reg::packed(1105, MAY_BE_ARRAY), /* createFirstClassCallable $variants */ + reg::packed(968, MAY_BE_BOOL), /* createFirstClassCallable $nativeTypesPromoted */ reg::packed(559, 0, 560), /* createFirstClassCallable return */ reg::packed(636, 0, 489), /* getBitwiseAndType $left */ reg::packed(641, 0, 489), /* getBitwiseAndType $right */ @@ -236,24 +237,24 @@ inline constexpr reg::PackedArg args[] = { reg::packed(641, 0, 489), /* getShiftRightType $right */ reg::packed(647, MAY_BE_CALLABLE), /* getShiftRightType $getTypeCallback */ reg::packed(559, 0, 560), /* getShiftRightType return */ - reg::packed(1272, 0, 560), /* resolveIdenticalType $leftType */ - reg::packed(1281, 0, 560), /* resolveIdenticalType $rightType */ - reg::packed(559, 0, 1291), /* resolveIdenticalType return */ - reg::packed(1272, 0, 560), /* resolveEqualType $leftType */ - reg::packed(1281, 0, 560), /* resolveEqualType $rightType */ - reg::packed(1336, MAY_BE_NULL, 1348, false, false, 1372), /* resolveEqualType $phpVersions */ - reg::packed(559, 0, 1291), /* resolveEqualType return */ - reg::packed(1272, 0, 1394), /* resolveConstantArrayTypeComparison $leftType */ - reg::packed(1281, 0, 1394), /* resolveConstantArrayTypeComparison $rightType */ + reg::packed(1313, 0, 560), /* resolveIdenticalType $leftType */ + reg::packed(1322, 0, 560), /* resolveIdenticalType $rightType */ + reg::packed(559, 0, 1332), /* resolveIdenticalType return */ + reg::packed(1313, 0, 560), /* resolveEqualType $leftType */ + reg::packed(1322, 0, 560), /* resolveEqualType $rightType */ + reg::packed(722, MAY_BE_NULL, 734, false, false, 758), /* resolveEqualType $phpVersions */ + reg::packed(559, 0, 1332), /* resolveEqualType return */ + reg::packed(1313, 0, 1394), /* resolveConstantArrayTypeComparison $leftType */ + reg::packed(1322, 0, 1394), /* resolveConstantArrayTypeComparison $rightType */ reg::packed(1434, MAY_BE_CALLABLE), /* resolveConstantArrayTypeComparison $valueComparisonCallback */ - reg::packed(559, 0, 1291), /* resolveConstantArrayTypeComparison return */ + reg::packed(559, 0, 1332), /* resolveConstantArrayTypeComparison return */ reg::packed(1493, 0, 1499), /* getClassConstFetchTypeByReflection $class */ reg::packed(1539, MAY_BE_STRING), /* getClassConstFetchTypeByReflection $constantName */ reg::packed(1552, MAY_BE_NULL, 1568), /* getClassConstFetchTypeByReflection $classReflection */ reg::packed(647, MAY_BE_CALLABLE), /* getClassConstFetchTypeByReflection $getTypeCallback */ - reg::packed(927, MAY_BE_BOOL, reg::NoString, false, false, 1603), /* getClassConstFetchTypeByReflection $nativeTypesPromoted */ + reg::packed(968, MAY_BE_BOOL, reg::NoString, false, false, 1603), /* getClassConstFetchTypeByReflection $nativeTypesPromoted */ reg::packed(559, 0, 560), /* getClassConstFetchTypeByReflection return */ - reg::packed(799, 0, 560), /* transformStaticType $type */ + reg::packed(840, 0, 560), /* transformStaticType $type */ reg::packed(1644, 0, 560), /* transformStaticType $fetchedOnType */ reg::packed(559, 0, 560), /* transformStaticType return */ reg::packed(1493, 0, 1499), /* getClassConstFetchType $class */ @@ -270,7 +271,7 @@ inline constexpr reg::PackedArg args[] = { reg::packed(484, 0, 489), /* getBitwiseNotType $expr */ reg::packed(647, MAY_BE_CALLABLE), /* getBitwiseNotType $getTypeCallback */ reg::packed(559, 0, 560), /* getBitwiseNotType return */ - reg::packed(772, 0, 560), /* getBitwiseNotTypeFromType $exprType */ + reg::packed(813, 0, 560), /* getBitwiseNotTypeFromType $exprType */ reg::packed(559, 0, 560), /* getBitwiseNotTypeFromType return */ reg::packed(1780, 0, 1785), /* resolveName $name */ reg::packed(1552, MAY_BE_NULL, 1568), /* resolveName $classReflection */ @@ -283,8 +284,8 @@ inline constexpr reg::PackedArg args[] = { reg::packed(1876, 0, 1902), /* resolveTypeByNameWithLateStaticBinding $methodReflectionCandidate */ reg::packed(559, 0, 560), /* resolveTypeByNameWithLateStaticBinding return */ reg::packed(559, 0, 1977), /* getReflectionProvider return */ - reg::packed(1272, 0, 560), /* getNeverType $leftType */ - reg::packed(1281, 0, 560), /* getNeverType $rightType */ + reg::packed(1313, 0, 560), /* getNeverType $leftType */ + reg::packed(1322, 0, 560), /* getNeverType $rightType */ reg::packed(559, 0, 560), /* getNeverType return */ }; using Sig = reg::Sig; @@ -297,40 +298,40 @@ inline constexpr sigtab::Sig getType = { { 578 /* getType */, 2, 7, 2, 9, ZEND_A inline constexpr sigtab::Sig getEnumCaseValueType = { { 615 /* getEnumCaseValueType */, 4, 10, 4, 14, ZEND_ACC_PUBLIC } }; inline constexpr sigtab::Sig getConcatType = { { 663 /* getConcatType */, 3, 15, 3, 18, ZEND_ACC_PUBLIC } }; inline constexpr sigtab::Sig resolveConcatType = { { 677 /* resolveConcatType */, 2, 19, 2, 21, ZEND_ACC_PUBLIC } }; -inline constexpr sigtab::Sig getArrayType = { { 722 /* getArrayType */, 2, 22, 2, 24, ZEND_ACC_PUBLIC } }; -inline constexpr sigtab::Sig getCastType = { { 760 /* getCastType */, 2, 25, 2, 27, ZEND_ACC_PUBLIC } }; -inline constexpr sigtab::Sig getCastObjectType = { { 781 /* getCastObjectType */, 1, 28, 1, 29, ZEND_ACC_PUBLIC } }; -inline constexpr sigtab::Sig getFunctionType = { { 826 /* getFunctionType */, 4, 30, 4, 34, ZEND_ACC_PUBLIC } }; -inline constexpr sigtab::Sig isParameterValueNullable = { { 873 /* isParameterValueNullable */, 1, 35, 1, 36, ZEND_ACC_PRIVATE } }; -inline constexpr sigtab::Sig getFirstClassCallableType = { { 947 /* getFirstClassCallableType */, 3, 37, 3, 40, ZEND_ACC_PUBLIC } }; -inline constexpr sigtab::Sig createFirstClassCallable = { { 1073 /* createFirstClassCallable */, 3, 41, 3, 44, ZEND_ACC_PUBLIC } }; -inline constexpr sigtab::Sig getBitwiseAndType = { { 1098 /* getBitwiseAndType */, 3, 45, 3, 48, ZEND_ACC_PUBLIC } }; -inline constexpr sigtab::Sig getBitwiseOrType = { { 1116 /* getBitwiseOrType */, 3, 49, 3, 52, ZEND_ACC_PUBLIC } }; -inline constexpr sigtab::Sig getBitwiseXorType = { { 1133 /* getBitwiseXorType */, 3, 53, 3, 56, ZEND_ACC_PUBLIC } }; -inline constexpr sigtab::Sig getSpaceshipType = { { 1151 /* getSpaceshipType */, 3, 57, 3, 60, ZEND_ACC_PUBLIC } }; -inline constexpr sigtab::Sig getDivType = { { 1168 /* getDivType */, 3, 61, 3, 64, ZEND_ACC_PUBLIC } }; -inline constexpr sigtab::Sig getModType = { { 1179 /* getModType */, 3, 65, 3, 68, ZEND_ACC_PUBLIC } }; -inline constexpr sigtab::Sig getPlusType = { { 1190 /* getPlusType */, 3, 69, 3, 72, ZEND_ACC_PUBLIC } }; -inline constexpr sigtab::Sig getMinusType = { { 1202 /* getMinusType */, 3, 73, 3, 76, ZEND_ACC_PUBLIC } }; -inline constexpr sigtab::Sig getMulType = { { 1215 /* getMulType */, 3, 77, 3, 80, ZEND_ACC_PUBLIC } }; -inline constexpr sigtab::Sig getPowType = { { 1226 /* getPowType */, 3, 81, 3, 84, ZEND_ACC_PUBLIC } }; -inline constexpr sigtab::Sig getShiftLeftType = { { 1237 /* getShiftLeftType */, 3, 85, 3, 88, ZEND_ACC_PUBLIC } }; -inline constexpr sigtab::Sig getShiftRightType = { { 1254 /* getShiftRightType */, 3, 89, 3, 92, ZEND_ACC_PUBLIC } }; -inline constexpr sigtab::Sig resolveIdenticalType = { { 1315 /* resolveIdenticalType */, 2, 93, 2, 95, ZEND_ACC_PUBLIC } }; -inline constexpr sigtab::Sig resolveEqualType = { { 1377 /* resolveEqualType */, 2, 96, 3, 99, ZEND_ACC_PUBLIC } }; -inline constexpr sigtab::Sig resolveConstantArrayTypeComparison = { { 1458 /* resolveConstantArrayTypeComparison */, 3, 100, 3, 103, ZEND_ACC_PRIVATE } }; -inline constexpr sigtab::Sig getClassConstFetchTypeByReflection = { { 1609 /* getClassConstFetchTypeByReflection */, 4, 104, 5, 109, ZEND_ACC_PUBLIC } }; -inline constexpr sigtab::Sig transformStaticType = { { 1658 /* transformStaticType */, 2, 110, 2, 112, ZEND_ACC_PRIVATE } }; -inline constexpr sigtab::Sig getClassConstFetchType = { { 1678 /* getClassConstFetchType */, 4, 113, 4, 117, ZEND_ACC_PUBLIC } }; -inline constexpr sigtab::Sig getUnaryPlusType = { { 1701 /* getUnaryPlusType */, 2, 118, 2, 120, ZEND_ACC_PUBLIC } }; -inline constexpr sigtab::Sig getUnaryMinusType = { { 1718 /* getUnaryMinusType */, 2, 121, 2, 123, ZEND_ACC_PUBLIC } }; -inline constexpr sigtab::Sig getBitwiseNotType = { { 1736 /* getBitwiseNotType */, 2, 124, 2, 126, ZEND_ACC_PUBLIC } }; -inline constexpr sigtab::Sig getBitwiseNotTypeFromType = { { 1754 /* getBitwiseNotTypeFromType */, 1, 127, 1, 128, ZEND_ACC_PUBLIC } }; -inline constexpr sigtab::Sig resolveName = { { 1805 /* resolveName */, 2, 129, 2, 131, ZEND_ACC_PRIVATE } }; -inline constexpr sigtab::Sig resolveTypeByName = { { 1848 /* resolveTypeByName */, 2, 132, 2, 134, ZEND_ACC_PRIVATE } }; -inline constexpr sigtab::Sig resolveTypeByNameWithLateStaticBinding = { { 1938 /* resolveTypeByNameWithLateStaticBinding */, 3, 135, 3, 138, ZEND_ACC_PRIVATE } }; -inline constexpr sigtab::Sig getReflectionProvider = { { 2015 /* getReflectionProvider */, 0, 139, 0, 139, ZEND_ACC_PRIVATE } }; -inline constexpr sigtab::Sig getNeverType = { { 2037 /* getNeverType */, 2, 140, 2, 142, ZEND_ACC_PRIVATE } }; +inline constexpr sigtab::Sig getArrayType = { { 763 /* getArrayType */, 2, 22, 3, 25, ZEND_ACC_PUBLIC } }; +inline constexpr sigtab::Sig getCastType = { { 801 /* getCastType */, 2, 26, 2, 28, ZEND_ACC_PUBLIC } }; +inline constexpr sigtab::Sig getCastObjectType = { { 822 /* getCastObjectType */, 1, 29, 1, 30, ZEND_ACC_PUBLIC } }; +inline constexpr sigtab::Sig getFunctionType = { { 867 /* getFunctionType */, 4, 31, 4, 35, ZEND_ACC_PUBLIC } }; +inline constexpr sigtab::Sig isParameterValueNullable = { { 914 /* isParameterValueNullable */, 1, 36, 1, 37, ZEND_ACC_PRIVATE } }; +inline constexpr sigtab::Sig getFirstClassCallableType = { { 988 /* getFirstClassCallableType */, 3, 38, 3, 41, ZEND_ACC_PUBLIC } }; +inline constexpr sigtab::Sig createFirstClassCallable = { { 1114 /* createFirstClassCallable */, 3, 42, 3, 45, ZEND_ACC_PUBLIC } }; +inline constexpr sigtab::Sig getBitwiseAndType = { { 1139 /* getBitwiseAndType */, 3, 46, 3, 49, ZEND_ACC_PUBLIC } }; +inline constexpr sigtab::Sig getBitwiseOrType = { { 1157 /* getBitwiseOrType */, 3, 50, 3, 53, ZEND_ACC_PUBLIC } }; +inline constexpr sigtab::Sig getBitwiseXorType = { { 1174 /* getBitwiseXorType */, 3, 54, 3, 57, ZEND_ACC_PUBLIC } }; +inline constexpr sigtab::Sig getSpaceshipType = { { 1192 /* getSpaceshipType */, 3, 58, 3, 61, ZEND_ACC_PUBLIC } }; +inline constexpr sigtab::Sig getDivType = { { 1209 /* getDivType */, 3, 62, 3, 65, ZEND_ACC_PUBLIC } }; +inline constexpr sigtab::Sig getModType = { { 1220 /* getModType */, 3, 66, 3, 69, ZEND_ACC_PUBLIC } }; +inline constexpr sigtab::Sig getPlusType = { { 1231 /* getPlusType */, 3, 70, 3, 73, ZEND_ACC_PUBLIC } }; +inline constexpr sigtab::Sig getMinusType = { { 1243 /* getMinusType */, 3, 74, 3, 77, ZEND_ACC_PUBLIC } }; +inline constexpr sigtab::Sig getMulType = { { 1256 /* getMulType */, 3, 78, 3, 81, ZEND_ACC_PUBLIC } }; +inline constexpr sigtab::Sig getPowType = { { 1267 /* getPowType */, 3, 82, 3, 85, ZEND_ACC_PUBLIC } }; +inline constexpr sigtab::Sig getShiftLeftType = { { 1278 /* getShiftLeftType */, 3, 86, 3, 89, ZEND_ACC_PUBLIC } }; +inline constexpr sigtab::Sig getShiftRightType = { { 1295 /* getShiftRightType */, 3, 90, 3, 93, ZEND_ACC_PUBLIC } }; +inline constexpr sigtab::Sig resolveIdenticalType = { { 1356 /* resolveIdenticalType */, 2, 94, 2, 96, ZEND_ACC_PUBLIC } }; +inline constexpr sigtab::Sig resolveEqualType = { { 1377 /* resolveEqualType */, 2, 97, 3, 100, ZEND_ACC_PUBLIC } }; +inline constexpr sigtab::Sig resolveConstantArrayTypeComparison = { { 1458 /* resolveConstantArrayTypeComparison */, 3, 101, 3, 104, ZEND_ACC_PRIVATE } }; +inline constexpr sigtab::Sig getClassConstFetchTypeByReflection = { { 1609 /* getClassConstFetchTypeByReflection */, 4, 105, 5, 110, ZEND_ACC_PUBLIC } }; +inline constexpr sigtab::Sig transformStaticType = { { 1658 /* transformStaticType */, 2, 111, 2, 113, ZEND_ACC_PRIVATE } }; +inline constexpr sigtab::Sig getClassConstFetchType = { { 1678 /* getClassConstFetchType */, 4, 114, 4, 118, ZEND_ACC_PUBLIC } }; +inline constexpr sigtab::Sig getUnaryPlusType = { { 1701 /* getUnaryPlusType */, 2, 119, 2, 121, ZEND_ACC_PUBLIC } }; +inline constexpr sigtab::Sig getUnaryMinusType = { { 1718 /* getUnaryMinusType */, 2, 122, 2, 124, ZEND_ACC_PUBLIC } }; +inline constexpr sigtab::Sig getBitwiseNotType = { { 1736 /* getBitwiseNotType */, 2, 125, 2, 127, ZEND_ACC_PUBLIC } }; +inline constexpr sigtab::Sig getBitwiseNotTypeFromType = { { 1754 /* getBitwiseNotTypeFromType */, 1, 128, 1, 129, ZEND_ACC_PUBLIC } }; +inline constexpr sigtab::Sig resolveName = { { 1805 /* resolveName */, 2, 130, 2, 132, ZEND_ACC_PRIVATE } }; +inline constexpr sigtab::Sig resolveTypeByName = { { 1848 /* resolveTypeByName */, 2, 133, 2, 135, ZEND_ACC_PRIVATE } }; +inline constexpr sigtab::Sig resolveTypeByNameWithLateStaticBinding = { { 1938 /* resolveTypeByNameWithLateStaticBinding */, 3, 136, 3, 139, ZEND_ACC_PRIVATE } }; +inline constexpr sigtab::Sig getReflectionProvider = { { 2015 /* getReflectionProvider */, 0, 140, 0, 140, ZEND_ACC_PRIVATE } }; +inline constexpr sigtab::Sig getNeverType = { { 2037 /* getNeverType */, 2, 141, 2, 143, ZEND_ACC_PRIVATE } }; } // namespace sig } // namespace ptdecl::InitializerExprTypeResolver diff --git a/turbo-ext/src/generated/PropertyFetchHandler.h b/turbo-ext/src/generated/PropertyFetchHandler.h index a2f39543f83..1058350b07b 100644 --- a/turbo-ext/src/generated/PropertyFetchHandler.h +++ b/turbo-ext/src/generated/PropertyFetchHandler.h @@ -10,11 +10,10 @@ namespace ptdecl::PropertyFetchHandler { /* the OBJ_PROP_NUM slots of the instance properties the class declares (the inherited ones come first) */ namespace slot { -inline constexpr uint32_t phpVersion = 0; -inline constexpr uint32_t propertyReflectionFinder = 1; -inline constexpr uint32_t expressionResultFactory = 2; -inline constexpr uint32_t propertyHookThrowPointsResolver = 3; -inline constexpr uint32_t defaultNarrowingHelper = 4; +inline constexpr uint32_t propertyReflectionFinder = 0; +inline constexpr uint32_t expressionResultFactory = 1; +inline constexpr uint32_t propertyHookThrowPointsResolver = 2; +inline constexpr uint32_t defaultNarrowingHelper = 3; } // namespace slot inline void declareClass(reg::Class &cls) @@ -26,7 +25,6 @@ inline void declareClass(reg::Class &cls) /* the properties the class declares itself, in declaration order (a used trait's come from its registrar) */ inline void declareProperties(reg::Class &cls) { - cls.property("phpVersion", ZEND_ACC_PRIVATE, reg::PropertyKind::Typed, 0, "PHPStan\\Php\\PhpVersion"); cls.property("propertyReflectionFinder", ZEND_ACC_PRIVATE, reg::PropertyKind::Typed, 0, "PHPStan\\Rules\\Properties\\PropertyReflectionFinder"); cls.property("expressionResultFactory", ZEND_ACC_PRIVATE, reg::PropertyKind::Typed, 0, "PHPStan\\Analyser\\ExpressionResultFactory"); cls.property("propertyHookThrowPointsResolver", ZEND_ACC_PRIVATE, reg::PropertyKind::Typed, 0, "PHPStan\\Analyser\\PropertyHookThrowPointsResolver"); @@ -36,93 +34,90 @@ inline void declareProperties(reg::Class &cls) /* the string and parameter tables the signatures below index into (see reg::Sig) */ namespace sigtab { inline constexpr char strings[] = - "phpVersion\0" /* 0 */ - "PHPStan\\Php\\PhpVersion\0" /* 11 */ - "propertyReflectionFinder\0" /* 34 */ - "PHPStan\\Rules\\Properties\\PropertyReflectionFinder\0" /* 59 */ - "expressionResultFactory\0" /* 109 */ - "PHPStan\\Analyser\\ExpressionResultFactory\0" /* 133 */ - "propertyHookThrowPointsResolver\0" /* 174 */ - "PHPStan\\Analyser\\PropertyHookThrowPointsResolver\0" /* 206 */ - "defaultNarrowingHelper\0" /* 255 */ - "PHPStan\\Analyser\\ExprHandler\\Helper\\DefaultNarrowingHelper\0" /* 278 */ - "__construct\0" /* 337 */ - "expr\0" /* 349 */ - "PhpParser\\Node\\Expr\0" /* 354 */ - "\0" /* 374 */ - "supports\0" /* 375 */ - "nodeScopeResolver\0" /* 384 */ - "PHPStan\\Analyser\\NodeScopeResolver\0" /* 402 */ - "stmt\0" /* 437 */ - "PhpParser\\Node\\Stmt\0" /* 442 */ - "scope\0" /* 462 */ - "PHPStan\\Analyser\\MutatingScope\0" /* 468 */ - "storage\0" /* 499 */ - "PHPStan\\Analyser\\ExpressionResultStorage\0" /* 507 */ - "nodeCallback\0" /* 548 */ - "context\0" /* 561 */ - "PHPStan\\Analyser\\ExpressionContext\0" /* 569 */ - "PHPStan\\Analyser\\ExpressionResult\0" /* 604 */ - "processExpr\0" /* 638 */ - "PhpParser\\Node\\Expr\\PropertyFetch\0" /* 650 */ - "varResult\0" /* 684 */ - "nameResult\0" /* 694 */ - "scopeBeforeVar\0" /* 705 */ - "beforeScope\0" /* 720 */ - "composeResult\0" /* 732 */ - "result\0" /* 746 */ - "PHPStan\\Dependency\\Dependencies\0" /* 753 */ - "getDependencies\0" /* 785 */ - "fetchedOnType\0" /* 801 */ - "PHPStan\\Type\\Type\0" /* 815 */ - "propertyName\0" /* 833 */ - "propertyFetch\0" /* 846 */ - "propertyFetchType"; /* 860 */ + "propertyReflectionFinder\0" /* 0 */ + "PHPStan\\Rules\\Properties\\PropertyReflectionFinder\0" /* 25 */ + "expressionResultFactory\0" /* 75 */ + "PHPStan\\Analyser\\ExpressionResultFactory\0" /* 99 */ + "propertyHookThrowPointsResolver\0" /* 140 */ + "PHPStan\\Analyser\\PropertyHookThrowPointsResolver\0" /* 172 */ + "defaultNarrowingHelper\0" /* 221 */ + "PHPStan\\Analyser\\ExprHandler\\Helper\\DefaultNarrowingHelper\0" /* 244 */ + "__construct\0" /* 303 */ + "expr\0" /* 315 */ + "PhpParser\\Node\\Expr\0" /* 320 */ + "\0" /* 340 */ + "supports\0" /* 341 */ + "nodeScopeResolver\0" /* 350 */ + "PHPStan\\Analyser\\NodeScopeResolver\0" /* 368 */ + "stmt\0" /* 403 */ + "PhpParser\\Node\\Stmt\0" /* 408 */ + "scope\0" /* 428 */ + "PHPStan\\Analyser\\MutatingScope\0" /* 434 */ + "storage\0" /* 465 */ + "PHPStan\\Analyser\\ExpressionResultStorage\0" /* 473 */ + "nodeCallback\0" /* 514 */ + "context\0" /* 527 */ + "PHPStan\\Analyser\\ExpressionContext\0" /* 535 */ + "PHPStan\\Analyser\\ExpressionResult\0" /* 570 */ + "processExpr\0" /* 604 */ + "PhpParser\\Node\\Expr\\PropertyFetch\0" /* 616 */ + "varResult\0" /* 650 */ + "nameResult\0" /* 660 */ + "scopeBeforeVar\0" /* 671 */ + "beforeScope\0" /* 686 */ + "composeResult\0" /* 698 */ + "result\0" /* 712 */ + "PHPStan\\Dependency\\Dependencies\0" /* 719 */ + "getDependencies\0" /* 751 */ + "fetchedOnType\0" /* 767 */ + "PHPStan\\Type\\Type\0" /* 781 */ + "propertyName\0" /* 799 */ + "propertyFetch\0" /* 812 */ + "propertyFetchType"; /* 826 */ inline constexpr reg::PackedArg args[] = { - reg::packed(0, 0, 11), /* __construct $phpVersion */ - reg::packed(34, 0, 59), /* __construct $propertyReflectionFinder */ - reg::packed(109, 0, 133), /* __construct $expressionResultFactory */ - reg::packed(174, 0, 206), /* __construct $propertyHookThrowPointsResolver */ - reg::packed(255, 0, 278), /* __construct $defaultNarrowingHelper */ - reg::packed(349, 0, 354), /* supports $expr */ - reg::packed(374, MAY_BE_BOOL), /* supports return */ - reg::packed(384, 0, 402), /* processExpr $nodeScopeResolver */ - reg::packed(437, 0, 442), /* processExpr $stmt */ - reg::packed(349, 0, 354), /* processExpr $expr */ - reg::packed(462, 0, 468), /* processExpr $scope */ - reg::packed(499, 0, 507), /* processExpr $storage */ - reg::packed(548, MAY_BE_CALLABLE), /* processExpr $nodeCallback */ - reg::packed(561, 0, 569), /* processExpr $context */ - reg::packed(374, 0, 604), /* processExpr return */ - reg::packed(384, 0, 402), /* composeResult $nodeScopeResolver */ - reg::packed(349, 0, 650), /* composeResult $expr */ - reg::packed(684, 0, 604), /* composeResult $varResult */ - reg::packed(694, MAY_BE_NULL, 604), /* composeResult $nameResult */ - reg::packed(705, 0, 468), /* composeResult $scopeBeforeVar */ - reg::packed(720, 0, 468), /* composeResult $beforeScope */ - reg::packed(374, 0, 604), /* composeResult return */ - reg::packed(462, 0, 468), /* getDependencies $scope */ - reg::packed(349, 0, 650), /* getDependencies $expr */ - reg::packed(684, 0, 604), /* getDependencies $varResult */ - reg::packed(746, 0, 604), /* getDependencies $result */ - reg::packed(374, MAY_BE_NULL, 753), /* getDependencies return */ - reg::packed(462, 0, 468), /* propertyFetchType $scope */ - reg::packed(801, 0, 815), /* propertyFetchType $fetchedOnType */ - reg::packed(833, MAY_BE_STRING), /* propertyFetchType $propertyName */ - reg::packed(846, 0, 650), /* propertyFetchType $propertyFetch */ - reg::packed(374, MAY_BE_NULL, 815), /* propertyFetchType return */ + reg::packed(0, 0, 25), /* __construct $propertyReflectionFinder */ + reg::packed(75, 0, 99), /* __construct $expressionResultFactory */ + reg::packed(140, 0, 172), /* __construct $propertyHookThrowPointsResolver */ + reg::packed(221, 0, 244), /* __construct $defaultNarrowingHelper */ + reg::packed(315, 0, 320), /* supports $expr */ + reg::packed(340, MAY_BE_BOOL), /* supports return */ + reg::packed(350, 0, 368), /* processExpr $nodeScopeResolver */ + reg::packed(403, 0, 408), /* processExpr $stmt */ + reg::packed(315, 0, 320), /* processExpr $expr */ + reg::packed(428, 0, 434), /* processExpr $scope */ + reg::packed(465, 0, 473), /* processExpr $storage */ + reg::packed(514, MAY_BE_CALLABLE), /* processExpr $nodeCallback */ + reg::packed(527, 0, 535), /* processExpr $context */ + reg::packed(340, 0, 570), /* processExpr return */ + reg::packed(350, 0, 368), /* composeResult $nodeScopeResolver */ + reg::packed(315, 0, 616), /* composeResult $expr */ + reg::packed(650, 0, 570), /* composeResult $varResult */ + reg::packed(660, MAY_BE_NULL, 570), /* composeResult $nameResult */ + reg::packed(671, 0, 434), /* composeResult $scopeBeforeVar */ + reg::packed(686, 0, 434), /* composeResult $beforeScope */ + reg::packed(340, 0, 570), /* composeResult return */ + reg::packed(428, 0, 434), /* getDependencies $scope */ + reg::packed(315, 0, 616), /* getDependencies $expr */ + reg::packed(650, 0, 570), /* getDependencies $varResult */ + reg::packed(712, 0, 570), /* getDependencies $result */ + reg::packed(340, MAY_BE_NULL, 719), /* getDependencies return */ + reg::packed(428, 0, 434), /* propertyFetchType $scope */ + reg::packed(767, 0, 781), /* propertyFetchType $fetchedOnType */ + reg::packed(799, MAY_BE_STRING), /* propertyFetchType $propertyName */ + reg::packed(812, 0, 616), /* propertyFetchType $propertyFetch */ + reg::packed(340, MAY_BE_NULL, 781), /* propertyFetchType return */ }; using Sig = reg::Sig; } // namespace sigtab /* the signatures of the methods the class declares itself (a used trait's are in the trait's header) */ namespace sig { -inline constexpr sigtab::Sig __construct = { { 337 /* __construct */, 5, 0, 5, reg::NoArg, ZEND_ACC_PUBLIC } }; -inline constexpr sigtab::Sig supports = { { 375 /* supports */, 1, 5, 1, 6, ZEND_ACC_PUBLIC } }; -inline constexpr sigtab::Sig processExpr = { { 638 /* processExpr */, 7, 7, 7, 14, ZEND_ACC_PUBLIC } }; -inline constexpr sigtab::Sig composeResult = { { 732 /* composeResult */, 6, 15, 6, 21, ZEND_ACC_PUBLIC } }; -inline constexpr sigtab::Sig getDependencies = { { 785 /* getDependencies */, 4, 22, 4, 26, ZEND_ACC_PRIVATE } }; -inline constexpr sigtab::Sig propertyFetchType = { { 860 /* propertyFetchType */, 4, 27, 4, 31, ZEND_ACC_PRIVATE } }; +inline constexpr sigtab::Sig __construct = { { 303 /* __construct */, 4, 0, 4, reg::NoArg, ZEND_ACC_PUBLIC } }; +inline constexpr sigtab::Sig supports = { { 341 /* supports */, 1, 4, 1, 5, ZEND_ACC_PUBLIC } }; +inline constexpr sigtab::Sig processExpr = { { 604 /* processExpr */, 7, 6, 7, 13, ZEND_ACC_PUBLIC } }; +inline constexpr sigtab::Sig composeResult = { { 698 /* composeResult */, 6, 14, 6, 20, ZEND_ACC_PUBLIC } }; +inline constexpr sigtab::Sig getDependencies = { { 751 /* getDependencies */, 4, 21, 4, 25, ZEND_ACC_PRIVATE } }; +inline constexpr sigtab::Sig propertyFetchType = { { 826 /* propertyFetchType */, 4, 26, 4, 30, ZEND_ACC_PRIVATE } }; } // namespace sig } // namespace ptdecl::PropertyFetchHandler diff --git a/turbo-ext/src/support.h b/turbo-ext/src/support.h index d105b6105e7..31ac298eb8f 100644 --- a/turbo-ext/src/support.h +++ b/turbo-ext/src/support.h @@ -2096,6 +2096,10 @@ zv::Val pt_mutating_scope_get_template_argument_constraints(zend_object *scope); zv::Val pt_mutating_scope_add_template_argument_constraints(zend_object *scope, zval *constraints); zv::Val pt_mutating_scope_merge_with(zend_object *scope, zval *otherScope, bool preserveVacuousConditionals = false); +/* MutatingScope.cpp — $scope->getPhpVersion()->() as PT_TRI_*; + * negative = pending exception */ +[[nodiscard]] zend_long pt_mutating_scope_php_versions_trinary(zend_object *scope, const char *lcMethod, size_t lcMethodLength); + /* }}} */ /* {{{ TemplateArgumentFrame.cpp, AssignTargetWalkMode.cpp, @@ -3121,14 +3125,12 @@ zv::Val pt_static_property_fetch_handler_compose_result(zval *handler, zval *exp * ResolvedPropertyReflection / ChangedTypePropertyReflection / * PhpPropertyReflection read in place where the getter only returns (or * forwards to) one, a filled memo included; the method through a cached site - * otherwise. $phpVersion->supportsPropertyHooks(): the versionId slot of - * PhpVersion, the method otherwise. UNDEF / false = pending exception */ + * otherwise. UNDEF / false = pending exception */ zv::Val pt_property_reflection_get_declaring_class(zval *reflection); [[nodiscard]] bool pt_property_reflection_has_native_type(zval *reflection, bool &out); zv::Val pt_property_reflection_get_native_type(zval *reflection); zv::Val pt_property_reflection_get_readable_type(zval *reflection); zv::Val pt_property_reflection_get_writable_type(zval *reflection); -[[nodiscard]] bool pt_php_version_supports_property_hooks(zval *phpVersion, bool &out); /* MutatingScope.cpp — $scope->getInstancePropertyReflection($type, $name) / * ->isInWriteExpressionAssign($expr): the native body for exactly a @@ -4075,7 +4077,7 @@ zv::Val pt_initializer_expr_type_resolver_get_binary_op_type(zval *resolver, pt_ zv::Val pt_initializer_expr_type_resolver_resolve_concat_type(zval *resolver, zval *left, zval *right); zv::Val pt_initializer_expr_type_resolver_resolve_identical_type(zval *resolver, zval *leftType, zval *rightType); zv::Val pt_initializer_expr_type_resolver_resolve_equal_type(zval *resolver, zval *leftType, zval *rightType, zval *phpVersions = NULL); -zv::Val pt_initializer_expr_type_resolver_get_array_type(zval *resolver, zval *expr, const pt_ietr_get_type &getTypeCallback); +zv::Val pt_initializer_expr_type_resolver_get_array_type(zval *resolver, zval *expr, const pt_ietr_get_type &getTypeCallback, zval *phpVersions = NULL); zv::Val pt_initializer_expr_type_resolver_get_cast_type(zval *resolver, zval *expr, const pt_ietr_get_type &getTypeCallback); zv::Val pt_initializer_expr_type_resolver_get_cast_object_type(zval *resolver, zval *exprType); zv::Val pt_initializer_expr_type_resolver_get_function_type(zval *resolver, zval *type, bool isNullable, bool isVariadic, zval *context); @@ -4467,13 +4469,8 @@ enum pt_php_version_query PT_PHP_VERSION_SUPPORTS_LEGACY_CONSTRUCTOR = 0, PT_PHP_VERSION_DEPRECATES_DYNAMIC_PROPERTIES, PT_PHP_VERSION_SUPPORTS_CALLABLE_INSTANCE_METHODS, - PT_PHP_VERSION_THROWS_ON_STRING_CAST, PT_PHP_VERSION_NON_NUMERIC_STRING_AND_INTEGER_IS_FALSE_ON_LOOSE_COMPARISON, - PT_PHP_VERSION_SUPPORTS_READ_ONLY_PROPERTIES, - PT_PHP_VERSION_SUPPORTS_READONLY_PROPERTY_REINITIALIZATION_ON_CLONE, - PT_PHP_VERSION_SUPPORTS_ASYMMETRIC_VISIBILITY, PT_PHP_VERSION_SUPPORTS_ENUMS, - PT_PHP_VERSION_SUPPORTS_PROPERTY_HOOKS, PT_PHP_VERSION_CASTS_NUMBERS_TO_STRINGS_ON_LOOSE_COMPARISON, PT_PHP_VERSION_ALLOWS_TRAILING_WHITESPACE_IN_NUMERIC_STRINGS, PT_PHP_VERSION_THROWS_ON_DIVISION_BY_ZERO, diff --git a/turbo-ext/tests/scope-family.php b/turbo-ext/tests/scope-family.php index b60fc4cf039..21fb6a02eeb 100644 --- a/turbo-ext/tests/scope-family.php +++ b/turbo-ext/tests/scope-family.php @@ -674,7 +674,9 @@ public function exprRef(Node\Expr $expr): mixed } foreach ([80500, 70400] as $sfVersionId) { $sfVersionScope = $sfScopeFactory->create(\PHPStan\Analyser\ScopeContext::create($sfFile)->enterClass($sfReflectionProvider->getClass(\ScopeFamilyFixture\Holder::class))) - ->assignExpression(new \PhpParser\Node\Expr\ConstFetch(new \PhpParser\Node\Name('PHP_VERSION_ID')), new \PHPStan\Type\Constant\ConstantIntegerType($sfVersionId), new \PHPStan\Type\IntegerType()); + ->assignExpression(new \PhpParser\Node\Expr\ConstFetch(new \PhpParser\Node\Name('PHP_VERSION_ID')), new \PHPStan\Type\Constant\ConstantIntegerType($sfVersionId), new \PHPStan\Type\IntegerType()) + // $this for isReadonlyPropertyFetch() over the readonly Holder::$name + ->assignVariable('this', new \PHPStan\Type\ObjectType(\ScopeFamilyFixture\Holder::class), new \PHPStan\Type\ObjectType(\ScopeFamilyFixture\Holder::class), \PHPStan\TrinaryLogic::createYes()); $sfScopes[spl_object_id($sfVersionScope)] = [$sfVersionScope, [new \PhpParser\Node\Expr\ConstFetch(new \PhpParser\Node\Name('PHP_VERSION_ID'))], null]; } // a scope whose tables carry types built on each side's own classes: under @@ -1402,10 +1404,6 @@ public function exprRef(Node\Expr $expr): mixed if ($scope->hasExpressionType($expr)->yes()) { $observe("getTrackedExpressionType#$i $key", static fn () => $scope->getTrackedExpressionType($expr)); } - if ($expr instanceof \PhpParser\Node\Expr\PropertyFetch) { - $observe("isReadonlyPropertyFetch(this)#$i $key", static fn () => $scope->isReadonlyPropertyFetch($expr, true)); - $observe("isReadonlyPropertyFetch(any)#$i $key", static fn () => $scope->isReadonlyPropertyFetch($expr, false)); - } $observe("getType#$i $key", static fn () => $scope->getType($expr)); $observe("getType again#$i $key", static fn () => $scope->getType($expr)); $observe("getScopeType#$i $key", static fn () => $scope->getScopeType($expr)); @@ -1491,6 +1489,18 @@ public function exprRef(Node\Expr $expr): mixed $sfPhpVersionIdFetch = new \PhpParser\Node\Expr\ConstFetch(new \PhpParser\Node\Name('PHP_VERSION_ID')); $sfTracksPhpVersionId = $scope->hasExpressionType($sfPhpVersionIdFetch)->yes() && $scope->getPhpVersion()->getType() === $scope->getType($sfPhpVersionIdFetch); + // isReadonlyPropertyFetch() answers with getPhpVersion() too: only where + // both sides' PhpVersions wrap the walk's own (PHP) type + if ($sfTracksPhpVersionId) { + foreach ($exprs as $i => $expr) { + if (!$expr instanceof \PhpParser\Node\Expr\PropertyFetch) { + continue; + } + $key = $sfHarness->key($expr); + $observe("isReadonlyPropertyFetch(this)#$i $key", static fn () => $scope->isReadonlyPropertyFetch($expr, true)); + $observe("isReadonlyPropertyFetch(any)#$i $key", static fn () => $scope->isReadonlyPropertyFetch($expr, false)); + } + } foreach ($sfProbeTypeNodes as $i => $typeNode) { foreach ([[false, false], [true, false], [false, true], [true, true]] as $j => [$nullable, $variadic]) { if ($variadic && !$sfTracksPhpVersionId) { @@ -1656,6 +1666,10 @@ public function exprRef(Node\Expr $expr): mixed // the variadic parameter shapes (see getFunctionType above) $producers['enterClassMethod(variadic)'] = static fn () => $scope->enterClassMethod($sfProbeVariadicClassMethod, $sfEmptyTemplateTypeMap, [], null, null, null, false, false, false); } + if (!$sfTracksPhpVersionId) { + // asks getPhpVersion() whether readonly properties are supported + unset($producers['rememberConstructorScope']); + } foreach ($producers as $label => $fn) { $before = count($factory->calls); $observe($label, static function () use ($fn, $scope, $dummy) { @@ -2210,6 +2224,18 @@ public function exprRef(Node\Expr $expr): mixed // exitFirstLevelStatements() memoizes on it $sfRestoredScopeProps = array_merge($sfMutableProps, ['scopeOutOfFirstLevelStatement']); try { + if (!$sfTracksPhpVersionId) { + // these ask getPhpVersion() about readonly properties or + // asymmetric visibility (see $sfTracksPhpVersionId) + foreach ($chainingRuns as $label => $fn) { + if ( + str_starts_with($label, 'enterAnonymousFunctionWithoutReflection') + || str_starts_with($label, 'invalidateExpression(') + ) { + unset($chainingRuns[$label]); + } + } + } foreach ($chainingRuns as $label => $fn) { $state = $sfSnapshot($dummy); $observe($label, static fn () => $sfScopeDigest($fn(), $scope, $dummy)); @@ -2222,6 +2248,10 @@ public function exprRef(Node\Expr $expr): mixed $sfRestore($dummy, $state); $sfRestore($scope, $scopeState); } + if (!$sfTracksPhpVersionId) { + // asks getPhpVersion() about asymmetric visibility + unset($closureLoopRuns['canWriteProperty(public)'], $closureLoopRuns['canWriteProperty(private set)']); + } foreach ($closureLoopRuns as $label => $fn) { $state = $sfSnapshot($dummy); $scopeState = $sfSnapshot($scope, $sfRestoredScopeProps); From b6cb1e700779ee5fb2c063192307b5d81d27bfb4 Mon Sep 17 00:00:00 2001 From: "ondrej@mirtes.cz" Date: Fri, 6 Nov 2026 20:08:11 +0000 Subject: [PATCH 2/2] Fix tests for PHP versions below 8.4 SplFixedArray::setSize() has the tentative return type true only since PHP 8.4. The SOAP E2E fixture is analysed in a PHP 8.2+ range from composer.json, so its implicitly nullable parameter is now reported as deprecated in PHP 8.4; declare it explicitly nullable instead. Amp-Thread-ID: https://ampcode.com/threads/T-01a1b1b9-0a7d-772a-a8bb-331fd76aa9cc --- .../Rules/Methods/OverridingMethodRuleTest.php | 13 ++++++++----- tests/e2e/data/soap.php | 2 +- 2 files changed, 9 insertions(+), 6 deletions(-) diff --git a/tests/PHPStan/Rules/Methods/OverridingMethodRuleTest.php b/tests/PHPStan/Rules/Methods/OverridingMethodRuleTest.php index af2919b28d1..a14b66cf3eb 100644 --- a/tests/PHPStan/Rules/Methods/OverridingMethodRuleTest.php +++ b/tests/PHPStan/Rules/Methods/OverridingMethodRuleTest.php @@ -143,11 +143,14 @@ public function testOverridingFinalMethod(int $phpVersion, string $contravariant if (PHP_VERSION_ID >= 80100) { $tip = 'Make it covariant, or use the #[\ReturnTypeWillChange] attribute to temporarily suppress the error.'; - $errors[] = [ - 'Return type bool of method OverridingFinalMethod\FixedArray::setSize() is not covariant with tentative return type true of method SplFixedArray::setSize().', - 125, - $tip, - ]; + if (PHP_VERSION_ID >= 80400) { + // SplFixedArray::setSize() has the tentative return type true since PHP 8.4, bool before + $errors[] = [ + 'Return type bool of method OverridingFinalMethod\FixedArray::setSize() is not covariant with tentative return type true of method SplFixedArray::setSize().', + 125, + $tip, + ]; + } $errors[] = [ 'Return type mixed of method OverridingFinalMethod\SomeIterator::getIterator() is not covariant with tentative return type Traversable of method IteratorAggregate::getIterator().', 250, diff --git a/tests/e2e/data/soap.php b/tests/e2e/data/soap.php index cf41d88ec14..5ec84a5d8d3 100644 --- a/tests/e2e/data/soap.php +++ b/tests/e2e/data/soap.php @@ -29,7 +29,7 @@ class MySoapClient3 extends \SoapClient * @param string|null $wsdl * @param mixed[]|null $options */ - public function __construct($wsdl, array $options = null) + public function __construct($wsdl, ?array $options = null) { parent::SoapClient($wsdl, $options); }