Skip to content

Commit

Permalink
A few more MutatingScope method parameters made required
Browse files Browse the repository at this point in the history
  • Loading branch information
ondrejmirtes committed Sep 14, 2024
1 parent a2854d1 commit 2c4c0cd
Show file tree
Hide file tree
Showing 9 changed files with 68 additions and 63 deletions.
38 changes: 18 additions & 20 deletions src/Analyser/MutatingScope.php
Original file line number Diff line number Diff line change
Expand Up @@ -3614,7 +3614,7 @@ private function enterArrowFunctionWithoutReflection(Expr\ArrowFunction $arrowFu
if (!$parameter->var instanceof Variable || !is_string($parameter->var->name)) {
throw new ShouldNotHappenException();
}
$arrowFunctionScope = $arrowFunctionScope->assignVariable($parameter->var->name, $parameterType, $parameterType);
$arrowFunctionScope = $arrowFunctionScope->assignVariable($parameter->var->name, $parameterType, $parameterType, TrinaryLogic::createYes());
}

if ($arrowFunction->static) {
Expand Down Expand Up @@ -3733,6 +3733,7 @@ public function enterForeach(self $originalScope, Expr $iteratee, string $valueN
$valueName,
$originalScope->getIterableValueType($iterateeType),
$originalScope->getIterableValueType($nativeIterateeType),
TrinaryLogic::createYes(),
);
if ($keyName !== null) {
$scope = $scope->enterForeachKey($originalScope, $iteratee, $keyName);
Expand All @@ -3749,6 +3750,7 @@ public function enterForeachKey(self $originalScope, Expr $iteratee, string $key
$keyName,
$originalScope->getIterableKeyType($iterateeType),
$originalScope->getIterableKeyType($nativeIterateeType),
TrinaryLogic::createYes(),
);

if ($iterateeType->isArray()->yes()) {
Expand Down Expand Up @@ -3783,6 +3785,7 @@ public function enterCatchType(Type $catchType, ?string $variableName): self
$variableName,
TypeCombinator::intersect($catchType, new ObjectType(Throwable::class)),
TypeCombinator::intersect($catchType, new ObjectType(Throwable::class)),
TrinaryLogic::createYes(),
);
}

Expand Down Expand Up @@ -3928,18 +3931,16 @@ public function isUndefinedExpressionAllowed(Expr $expr): bool
return array_key_exists($exprString, $this->currentlyAllowedUndefinedExpressions);
}

public function assignVariable(string $variableName, Type $type, Type $nativeType, ?TrinaryLogic $certainty = null): self
public function assignVariable(string $variableName, Type $type, Type $nativeType, TrinaryLogic $certainty): self
{
$node = new Variable($variableName);
$scope = $this->assignExpression($node, $type, $nativeType);
if ($certainty !== null) {
if ($certainty->no()) {
throw new ShouldNotHappenException();
} elseif (!$certainty->yes()) {
$exprString = '$' . $variableName;
$scope->expressionTypes[$exprString] = new ExpressionTypeHolder($node, $type, $certainty);
$scope->nativeExpressionTypes[$exprString] = new ExpressionTypeHolder($node, $nativeType, $certainty);
}
if ($certainty->no()) {
throw new ShouldNotHappenException();
} elseif (!$certainty->yes()) {
$exprString = '$' . $variableName;
$scope->expressionTypes[$exprString] = new ExpressionTypeHolder($node, $type, $certainty);
$scope->nativeExpressionTypes[$exprString] = new ExpressionTypeHolder($node, $nativeType, $certainty);
}

$parameterOriginalValueExprString = $this->getNodeKey(new ParameterVariableOriginalValueExpr($variableName));
Expand Down Expand Up @@ -3987,7 +3988,7 @@ public function unsetExpression(Expr $expr): self
return $scope->invalidateExpression($expr);
}

public function specifyExpressionType(Expr $expr, Type $type, Type $nativeType, ?TrinaryLogic $certainty = null): self
public function specifyExpressionType(Expr $expr, Type $type, Type $nativeType, TrinaryLogic $certainty): self
{
if ($expr instanceof ConstFetch) {
$loweredConstName = strtolower($expr->name->toString());
Expand Down Expand Up @@ -4035,9 +4036,7 @@ public function specifyExpressionType(Expr $expr, Type $type, Type $nativeType,
}
}

if ($certainty === null) {
$certainty = TrinaryLogic::createYes();
} elseif ($certainty->no()) {
if ($certainty->no()) {
throw new ShouldNotHappenException();
}

Expand Down Expand Up @@ -4073,11 +4072,8 @@ public function specifyExpressionType(Expr $expr, Type $type, Type $nativeType,
return $scope;
}

public function assignExpression(Expr $expr, Type $type, ?Type $nativeType = null): self
public function assignExpression(Expr $expr, Type $type, Type $nativeType): self
{
if ($nativeType === null) {
$nativeType = new MixedType();
}
$scope = $this;
if ($expr instanceof PropertyFetch) {
$scope = $this->invalidateExpression($expr)
Expand All @@ -4088,7 +4084,7 @@ public function assignExpression(Expr $expr, Type $type, ?Type $nativeType = nul
$scope = $this->invalidateExpression($expr);
}

return $scope->specifyExpressionType($expr, $type, $nativeType);
return $scope->specifyExpressionType($expr, $type, $nativeType, TrinaryLogic::createYes());
}

public function assignInitializedProperty(Type $fetchedOnType, string $propertyName): self
Expand Down Expand Up @@ -4292,13 +4288,14 @@ public function addTypeToExpression(Expr $expr, Type $type): self

if ($originalExprType->equals($nativeType)) {
$newType = TypeCombinator::intersect($type, $originalExprType);
return $this->specifyExpressionType($expr, $newType, $newType);
return $this->specifyExpressionType($expr, $newType, $newType, TrinaryLogic::createYes());
}

return $this->specifyExpressionType(
$expr,
TypeCombinator::intersect($type, $originalExprType),
TypeCombinator::intersect($type, $nativeType),
TrinaryLogic::createYes(),
);
}

Expand All @@ -4315,6 +4312,7 @@ public function removeTypeFromExpression(Expr $expr, Type $typeToRemove): self
$expr,
TypeCombinator::remove($exprType, $typeToRemove),
TypeCombinator::remove($this->getNativeType($expr), $typeToRemove),
TrinaryLogic::createYes(),
);
}

Expand Down
23 changes: 12 additions & 11 deletions src/Analyser/NodeScopeResolver.php
Original file line number Diff line number Diff line change
Expand Up @@ -1809,7 +1809,7 @@ static function (Node $node, Scope $scope) use ($nodeCallback): void {
continue;
}

$scope = $scope->assignVariable($var->name, new MixedType(), new MixedType());
$scope = $scope->assignVariable($var->name, new MixedType(), new MixedType(), TrinaryLogic::createYes());
$vars[] = $var->name;
}
$scope = $this->processVarAnnotation($scope, $vars, $stmt);
Expand Down Expand Up @@ -1842,7 +1842,7 @@ static function (Node $node, Scope $scope) use ($nodeCallback): void {
$impurePoints = array_merge($impurePoints, $varResult->getImpurePoints());
$scope = $scope->exitExpressionAssign($var->var);

$scope = $scope->assignVariable($var->var->name, new MixedType(), new MixedType());
$scope = $scope->assignVariable($var->var->name, new MixedType(), new MixedType(), TrinaryLogic::createYes());
$vars[] = $var->var->name;
}

Expand Down Expand Up @@ -2091,6 +2091,7 @@ private function ensureShallowNonNullability(MutatingScope $scope, Scope $origin
$exprToSpecify,
$exprTypeWithoutNull,
TypeCombinator::removeNull($nativeType),
TrinaryLogic::createYes(),
);

return new EnsuredNonNullabilityResult(
Expand Down Expand Up @@ -2457,7 +2458,7 @@ static function (): void {
$functionReflection !== null
&& in_array($functionReflection->getName(), ['fopen', 'file_get_contents'], true)
) {
$scope = $scope->assignVariable('http_response_header', AccessoryArrayListType::intersectWith(new ArrayType(new IntegerType(), new StringType())), new ArrayType(new IntegerType(), new StringType()));
$scope = $scope->assignVariable('http_response_header', AccessoryArrayListType::intersectWith(new ArrayType(new IntegerType(), new StringType())), new ArrayType(new IntegerType(), new StringType()), TrinaryLogic::createYes());
}

if (
Expand Down Expand Up @@ -4217,7 +4218,7 @@ private function processClosureNode(
$variableNativeType = TypeCombinator::union($scope->getVariableType($inAssignRightSideVariableName), $inAssignRightSideNativeType);
}
}
$scope = $scope->assignVariable($inAssignRightSideVariableName, $variableType, $variableNativeType);
$scope = $scope->assignVariable($inAssignRightSideVariableName, $variableType, $variableNativeType, TrinaryLogic::createYes());
}
}
$this->processExprNode($stmt, $use->var, $useScope, $nodeCallback, $context);
Expand Down Expand Up @@ -4625,7 +4626,7 @@ private function processArgs(
&& !$arg->value->static
) {
$restoreThisScope = $scopeToPass;
$scopeToPass = $scopeToPass->assignVariable('this', $parameter->getClosureThisType(), new ObjectWithoutClassType());
$scopeToPass = $scopeToPass->assignVariable('this', $parameter->getClosureThisType(), new ObjectWithoutClassType(), TrinaryLogic::createYes());
}

if ($parameter !== null) {
Expand Down Expand Up @@ -4677,7 +4678,7 @@ private function processArgs(
&& $parameter->getClosureThisType() !== null
&& !$arg->value->static
) {
$scopeToPass = $scopeToPass->assignVariable('this', $parameter->getClosureThisType(), new ObjectWithoutClassType());
$scopeToPass = $scopeToPass->assignVariable('this', $parameter->getClosureThisType(), new ObjectWithoutClassType(), TrinaryLogic::createYes());
}

if ($parameter !== null) {
Expand Down Expand Up @@ -4983,7 +4984,7 @@ private function processAssignVar(
$conditionalExpressions = $this->processSureNotTypesForConditionalExpressionsAfterAssign($scope, $var->name, $conditionalExpressions, $falseySpecifiedTypes, $falseyType);

$nodeCallback(new VariableAssignNode($var, $assignedExpr, $isAssignOp), $result->getScope());
$scope = $scope->assignVariable($var->name, $type, $scope->getNativeType($assignedExpr));
$scope = $scope->assignVariable($var->name, $type, $scope->getNativeType($assignedExpr), TrinaryLogic::createYes());
foreach ($conditionalExpressions as $exprString => $holders) {
$scope = $scope->addConditionalExpressions($exprString, $holders);
}
Expand Down Expand Up @@ -5142,7 +5143,7 @@ private function processAssignVar(
if ($varType->isArray()->yes() || !(new ObjectType(ArrayAccess::class))->isSuperTypeOf($varType)->yes()) {
if ($var instanceof Variable && is_string($var->name)) {
$nodeCallback(new VariableAssignNode($var, $assignedPropertyExpr, $isAssignOp), $scope);
$scope = $scope->assignVariable($var->name, $valueToWrite, $nativeValueToWrite);
$scope = $scope->assignVariable($var->name, $valueToWrite, $nativeValueToWrite, TrinaryLogic::createYes());
} else {
if ($var instanceof PropertyFetch || $var instanceof StaticPropertyFetch) {
$nodeCallback(new PropertyAssignNode($var, $assignedPropertyExpr, $isAssignOp), $scope);
Expand Down Expand Up @@ -5394,7 +5395,7 @@ static function (): void {

if ($var instanceof Variable && is_string($var->name)) {
$nodeCallback(new VariableAssignNode($var, $assignedPropertyExpr, $isAssignOp), $scope);
$scope = $scope->assignVariable($var->name, $valueToWrite, $nativeValueToWrite);
$scope = $scope->assignVariable($var->name, $valueToWrite, $nativeValueToWrite, TrinaryLogic::createYes());
} else {
if ($var instanceof PropertyFetch || $var instanceof StaticPropertyFetch) {
$nodeCallback(new PropertyAssignNode($var, $assignedPropertyExpr, $isAssignOp), $scope);
Expand Down Expand Up @@ -5603,13 +5604,13 @@ private function processVarAnnotation(MutatingScope $scope, array $variableNames

$variableType = $varTags[$variableName]->getType();
$changed = true;
$scope = $scope->assignVariable($variableName, $variableType, new MixedType());
$scope = $scope->assignVariable($variableName, $variableType, new MixedType(), TrinaryLogic::createYes());
}

if (count($variableNames) === 1 && count($varTags) === 1 && isset($varTags[0])) {
$variableType = $varTags[0]->getType();
$changed = true;
$scope = $scope->assignVariable($variableNames[0], $variableType, new MixedType());
$scope = $scope->assignVariable($variableNames[0], $variableType, new MixedType(), TrinaryLogic::createYes());
}

return $scope;
Expand Down
5 changes: 3 additions & 2 deletions src/Rules/Operators/InvalidBinaryOperationRule.php
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@
use PHPStan\Rules\RuleErrorBuilder;
use PHPStan\Rules\RuleLevelHelper;
use PHPStan\ShouldNotHappenException;
use PHPStan\TrinaryLogic;
use PHPStan\Type\ErrorType;
use PHPStan\Type\Type;
use PHPStan\Type\VerbosityLevel;
Expand Down Expand Up @@ -104,8 +105,8 @@ public function processNode(Node $node, Scope $scope): array
}

$scope = $scope
->assignVariable($leftName, $leftType, $leftType)
->assignVariable($rightName, $rightType, $rightType);
->assignVariable($leftName, $leftType, $leftType, TrinaryLogic::createYes())
->assignVariable($rightName, $rightType, $rightType, TrinaryLogic::createYes());

if (!$scope->getType($newNode) instanceof ErrorType) {
return [];
Expand Down
3 changes: 2 additions & 1 deletion src/Rules/Operators/InvalidUnaryOperationRule.php
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@
use PHPStan\Rules\RuleErrorBuilder;
use PHPStan\Rules\RuleLevelHelper;
use PHPStan\ShouldNotHappenException;
use PHPStan\TrinaryLogic;
use PHPStan\Type\ErrorType;
use PHPStan\Type\Type;
use PHPStan\Type\VerbosityLevel;
Expand Down Expand Up @@ -69,7 +70,7 @@ public function processNode(Node $node, Scope $scope): array
throw new ShouldNotHappenException();
}

$scope = $scope->assignVariable($varName, $exprType, $exprType);
$scope = $scope->assignVariable($varName, $exprType, $exprType, TrinaryLogic::createYes());
if (!$scope->getType($newNode) instanceof ErrorType) {
return [];
}
Expand Down
5 changes: 3 additions & 2 deletions src/Type/Php/ArrayFilterFunctionReturnTypeExtension.php
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@
use PHPStan\Reflection\FunctionReflection;
use PHPStan\Reflection\ReflectionProvider;
use PHPStan\ShouldNotHappenException;
use PHPStan\TrinaryLogic;
use PHPStan\Type\ArrayType;
use PHPStan\Type\BenevolentUnionType;
use PHPStan\Type\Constant\ConstantArrayType;
Expand Down Expand Up @@ -244,7 +245,7 @@ private function processKeyAndItemType(MutatingScope $scope, Type $keyType, Type
throw new ShouldNotHappenException();
}
$itemVarName = $itemVar->name;
$scope = $scope->assignVariable($itemVarName, $itemType, new MixedType());
$scope = $scope->assignVariable($itemVarName, $itemType, new MixedType(), TrinaryLogic::createYes());
}

$keyVarName = null;
Expand All @@ -253,7 +254,7 @@ private function processKeyAndItemType(MutatingScope $scope, Type $keyType, Type
throw new ShouldNotHappenException();
}
$keyVarName = $keyVar->name;
$scope = $scope->assignVariable($keyVarName, $keyType, new MixedType());
$scope = $scope->assignVariable($keyVarName, $keyType, new MixedType(), TrinaryLogic::createYes());
}

$booleanResult = $scope->getType($expr)->toBoolean();
Expand Down
5 changes: 3 additions & 2 deletions tests/PHPStan/Analyser/ScopeTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
use PhpParser\Node\Expr\ConstFetch;
use PhpParser\Node\Name\FullyQualified;
use PHPStan\Testing\PHPStanTestCase;
use PHPStan\TrinaryLogic;
use PHPStan\Type\Constant\ConstantArrayType;
use PHPStan\Type\Constant\ConstantBooleanType;
use PHPStan\Type\Constant\ConstantIntegerType;
Expand Down Expand Up @@ -232,8 +233,8 @@ public function testGeneralize(Type $a, Type $b, string $expectedTypeDescription
{
/** @var ScopeFactory $scopeFactory */
$scopeFactory = self::getContainer()->getByType(ScopeFactory::class);
$scopeA = $scopeFactory->create(ScopeContext::create('file.php'))->assignVariable('a', $a, $a);
$scopeB = $scopeFactory->create(ScopeContext::create('file.php'))->assignVariable('a', $b, $b);
$scopeA = $scopeFactory->create(ScopeContext::create('file.php'))->assignVariable('a', $a, $a, TrinaryLogic::createYes());
$scopeB = $scopeFactory->create(ScopeContext::create('file.php'))->assignVariable('a', $b, $b, TrinaryLogic::createYes());
$resultScope = $scopeA->generalizeWith($scopeB);
$this->assertSame($expectedTypeDescription, $resultScope->getVariableType('a')->describe(VerbosityLevel::precise()));
}
Expand Down
9 changes: 5 additions & 4 deletions tests/PHPStan/Analyser/StatementResultTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
use PhpParser\Node\Stmt;
use PHPStan\Parser\Parser;
use PHPStan\Testing\PHPStanTestCase;
use PHPStan\TrinaryLogic;
use PHPStan\Type\ArrayType;
use PHPStan\Type\IntegerType;
use PHPStan\Type\MixedType;
Expand Down Expand Up @@ -395,10 +396,10 @@ public function testIsAlwaysTerminating(
/** @var ScopeFactory $scopeFactory */
$scopeFactory = self::getContainer()->getByType(ScopeFactory::class);
$scope = $scopeFactory->create(ScopeContext::create('test.php'))
->assignVariable('string', new StringType(), new StringType())
->assignVariable('x', new IntegerType(), new IntegerType())
->assignVariable('cond', new MixedType(), new MixedType())
->assignVariable('arr', new ArrayType(new MixedType(), new MixedType()), new ArrayType(new MixedType(), new MixedType()));
->assignVariable('string', new StringType(), new StringType(), TrinaryLogic::createYes())
->assignVariable('x', new IntegerType(), new IntegerType(), TrinaryLogic::createYes())
->assignVariable('cond', new MixedType(), new MixedType(), TrinaryLogic::createYes())
->assignVariable('arr', new ArrayType(new MixedType(), new MixedType()), new ArrayType(new MixedType(), new MixedType()), TrinaryLogic::createYes());
$result = $nodeScopeResolver->processStmtNodes(
new Stmt\Namespace_(null, $stmts),
$stmts,
Expand Down
Loading

0 comments on commit 2c4c0cd

Please sign in to comment.