Skip to content

Conversation

@SplotyCode
Copy link
Contributor

@SplotyCode SplotyCode commented Nov 8, 2025

This pr is trying to fix a false positive.

/**
 * @param list<int> $array
 * @param positive-int $index
 */
public function guardNotSafeLowerBound(array $array, int $index) {
    if ($index < count($array)) { // index is within 0..count(array)-1
        return $array[$index]; // phpstan reports a potentially unsafe array access
    }
    return null;
}

Note that 1) $array is a list 2) $index is positive (or at least >= 0)

Comment on lines 294 to 314
if (
$context->true()
&& $expr instanceof Node\Expr\BinaryOp\Smaller
&& $argType->isList()->yes()
&& IntegerRangeType::fromInterval(0, null)->isSuperTypeOf($leftType)->yes()
) {
$dimFetch = new ArrayDimFetch(
$expr->right->getArgs()[0]->value,
$expr->left,
);
$result = $result->unionWith(
$this->create(
$dimFetch,
$argType->getIterableValueType(),
TypeSpecifierContext::createTrue(),
$scope,
)
);
}
Copy link
Contributor

@staabm staabm Nov 11, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

is this PR trying to fix phpstan/phpstan#13773 ?
(since the PR does not at all contain a description.. I can only guess)

if so, you should either adjust the logic added with #4403 or maybe even delete it in case you want to re-implement it in a different place

Copy link
Contributor Author

@SplotyCode SplotyCode Nov 11, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks for pointing this out! I updated the description of this pr.

I have not opened a issue for this pr. But i will also try and fix phpstan/phpstan#13773 later in a diffrent pr. Here i am trying to fix array access on lists if we explicitly guard the index.

@SplotyCode
Copy link
Contributor Author

SplotyCode commented Nov 11, 2025

There seems to be a regression

$var = null;
if ($index < count($array) {
    $var = 2;
}
if ($index < count($array) {
    /* phpstan does not recognize that $var is always 2 now */
}

This did work before this pr. I am wondering if this is also true for the other checks in the method i changed.

if (count($c) > 0) {
$c = array_map(fn() => new stdClass(), $c);
assertType('non-empty-list<stdClass>', $c);
assertType('non-empty-list<stdClass>&hasOffsetValue(0, stdClass)', $c);
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

this type does not make sense, because non-empty-list<stdClass> already implies that the list has a offset 0 with value stdClass

$context->true()
&& $expr instanceof Node\Expr\BinaryOp\Smaller
&& $argType->isList()->yes()
&& $argExpr instanceof Expr\Variable
Copy link
Contributor

@staabm staabm Nov 11, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

instanceof Expr\Variable is usually a bug as most logic works for other expressions (e.g. a pure function call can also be remembered).

most of the time this works just by dropping this line

$this->create(
$dimFetch,
$argType->getIterableValueType(),
TypeSpecifierContext::createTrue(),
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

usually we pass thru the $context, instead of creating a new one.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants