Skip to content
Merged
16 changes: 11 additions & 5 deletions src/Analyser/ExpressionContext.php
Original file line number Diff line number Diff line change
Expand Up @@ -11,18 +11,19 @@ private function __construct(
private bool $isDeep,
private ?string $inAssignRightSideVariableName,
private ?Type $inAssignRightSideType,
private ?Type $inAssignRightSideNativeType,
)
{
}

public static function createTopLevel(): self
{
return new self(false, null, null);
return new self(false, null, null, null);
}

public static function createDeep(): self
{
return new self(true, null, null);
return new self(true, null, null, null);
}

public function enterDeep(): self
Expand All @@ -31,17 +32,17 @@ public function enterDeep(): self
return $this;
}

return new self(true, $this->inAssignRightSideVariableName, $this->inAssignRightSideType);
return new self(true, $this->inAssignRightSideVariableName, $this->inAssignRightSideType, $this->inAssignRightSideNativeType);
}

public function isDeep(): bool
{
return $this->isDeep;
}

public function enterRightSideAssign(string $variableName, Type $type): self
public function enterRightSideAssign(string $variableName, Type $type, Type $nativeType): self
{
return new self($this->isDeep, $variableName, $type);
return new self($this->isDeep, $variableName, $type, $nativeType);
}

public function getInAssignRightSideVariableName(): ?string
Expand All @@ -54,4 +55,9 @@ public function getInAssignRightSideType(): ?Type
return $this->inAssignRightSideType;
}

public function getInAssignRightSideNativeType(): ?Type
{
return $this->inAssignRightSideNativeType;
}

}
34 changes: 20 additions & 14 deletions src/Analyser/MutatingScope.php
Original file line number Diff line number Diff line change
Expand Up @@ -2848,6 +2848,7 @@ private function enterAnonymousFunctionWithoutReflection(
): self
{
$variableTypes = [];
$nativeTypes = [];
foreach ($closure->params as $i => $parameter) {
$isNullable = $this->isParameterValueNullable($parameter);
$parameterType = $this->getFunctionType($parameter->type, $isNullable, $parameter->variadic);
Expand All @@ -2872,9 +2873,9 @@ private function enterAnonymousFunctionWithoutReflection(
$variableTypes[$parameter->var->name] = VariableTypeHolder::createYes(
$parameterType,
);
$nativeTypes[sprintf('$%s', $parameter->var->name)] = $parameterType;
}

$nativeTypes = [];
$moreSpecificTypes = [];
foreach ($closure->uses as $use) {
if (!is_string($use->var->name)) {
Expand Down Expand Up @@ -3147,9 +3148,7 @@ public function enterForeach(Expr $iteratee, string $valueName, ?string $keyName
{
$iterateeType = $this->getType($iteratee);
$nativeIterateeType = $this->getNativeType($iteratee);
$scope = $this->assignVariable($valueName, $iterateeType->getIterableValueType());
$scope->nativeExpressionTypes[sprintf('$%s', $valueName)] = $nativeIterateeType->getIterableValueType();

$scope = $this->assignVariable($valueName, $iterateeType->getIterableValueType(), $nativeIterateeType->getIterableValueType());
if ($keyName !== null) {
$scope = $scope->enterForeachKey($iteratee, $keyName);
}
Expand All @@ -3161,13 +3160,13 @@ public function enterForeachKey(Expr $iteratee, string $keyName): self
{
$iterateeType = $this->getType($iteratee);
$nativeIterateeType = $this->getNativeType($iteratee);
$scope = $this->assignVariable($keyName, $iterateeType->getIterableKeyType());
$scope->nativeExpressionTypes[sprintf('$%s', $keyName)] = $nativeIterateeType->getIterableKeyType();
$scope = $this->assignVariable($keyName, $iterateeType->getIterableKeyType(), $nativeIterateeType->getIterableKeyType());

if ($iterateeType->isArray()->yes()) {
$scope = $scope->specifyExpressionType(
new Expr\ArrayDimFetch($iteratee, new Variable($keyName)),
$iterateeType->getIterableValueType(),
$nativeIterateeType->getIterableKeyType(),
);
}

Expand All @@ -3194,6 +3193,7 @@ public function enterCatchType(Type $catchType, ?string $variableName): self
return $this->assignVariable(
$variableName,
TypeCombinator::intersect($catchType, new ObjectType(Throwable::class)),
TypeCombinator::intersect($catchType, new ObjectType(Throwable::class)),
);
}

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

public function assignVariable(string $variableName, Type $type, ?TrinaryLogic $certainty = null): self
public function assignVariable(string $variableName, Type $type, Type $nativeType, ?TrinaryLogic $certainty = null): self
{
if ($certainty === null) {
$certainty = TrinaryLogic::createYes();
Expand All @@ -3354,7 +3354,7 @@ public function assignVariable(string $variableName, Type $type, ?TrinaryLogic $
$variableTypes[$variableName] = new VariableTypeHolder($type, $certainty);

$nativeTypes = $this->nativeExpressionTypes;
$nativeTypes[sprintf('$%s', $variableName)] = $type;
$nativeTypes[sprintf('$%s', $variableName)] = $nativeType;

$variableString = $this->exprPrinter->printExpr(new Variable($variableName));
$moreSpecificTypeHolders = $this->moreSpecificTypes;
Expand Down Expand Up @@ -3452,7 +3452,10 @@ public function unsetExpression(Expr $expr): self
$exprVarType = $this->getType($expr->var);
$dimType = $this->getType($expr->dim);
$unsetType = $exprVarType->unsetOffset($dimType);
$scope = $this->specifyExpressionType($expr->var, $unsetType)->invalidateExpression(
$exprVarNativeType = $this->getType($expr->var);
$dimNativeType = $this->getType($expr->dim);
$unsetNativeType = $exprVarNativeType->unsetOffset($dimNativeType);
$scope = $this->specifyExpressionType($expr->var, $unsetType, $unsetNativeType)->invalidateExpression(
new FuncCall(new FullyQualified('count'), [new Arg($expr->var)]),
)->invalidateExpression(
new FuncCall(new FullyQualified('sizeof'), [new Arg($expr->var)]),
Expand All @@ -3465,6 +3468,10 @@ public function unsetExpression(Expr $expr): self
$scope->getType($expr->var->dim),
$scope->getType($expr->var),
),
$scope->getNativeType($expr->var->var)->setOffsetValueType(
$scope->getNativeType($expr->var->dim),
$scope->getNativeType($expr->var),
),
);
}

Expand All @@ -3474,7 +3481,7 @@ public function unsetExpression(Expr $expr): self
return $this;
}

private function specifyExpressionType(Expr $expr, Type $type, ?Type $nativeType = null): self
private function specifyExpressionType(Expr $expr, Type $type, Type $nativeType): self
{
if ($expr instanceof Node\Scalar || $expr instanceof Array_) {
return $this;
Expand Down Expand Up @@ -3523,9 +3530,7 @@ private function specifyExpressionType(Expr $expr, Type $type, ?Type $nativeType

$nativeTypes = $this->nativeExpressionTypes;
$exprString = sprintf('$%s', $variableName);
if ($nativeType !== null) {
$nativeTypes[$exprString] = $nativeType;
}
$nativeTypes[$exprString] = $nativeType;

$conditionalExpressions = [];
foreach ($this->conditionalExpressions as $conditionalExprString => $holders) {
Expand Down Expand Up @@ -3613,6 +3618,7 @@ private function specifyExpressionType(Expr $expr, Type $type, ?Type $nativeType
TypeCombinator::intersect($exprVarType, TypeCombinator::union(...$types)),
new HasOffsetValueType($dimType, $type),
),
$this->getNativeType($expr->var),
);
}
}
Expand All @@ -3634,7 +3640,7 @@ private function specifyExpressionType(Expr $expr, Type $type, ?Type $nativeType
]);
}

public function assignExpression(Expr $expr, Type $type, ?Type $nativeType = null): self
public function assignExpression(Expr $expr, Type $type, Type $nativeType): self
{
$scope = $this;
if ($expr instanceof PropertyFetch) {
Expand Down
Loading