Skip to content

Add Type::spliceArray(), improve splice_array() array type narrowing #3952

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 2 commits into
base: 2.1.x
Choose a base branch
from

Conversation

herndlm
Copy link
Contributor

@herndlm herndlm commented Apr 19, 2025

Needs #3959 first

Closes phpstan/phpstan#11917

This is very similar to Type:: sliceArray() and it is used in NodeScopeResolver in a similar fashion as Type::popArray() is. Moving logic to Type deals obviously with all accessory types which were not working properly before too like e.g. list or non-empty-array.

First commit is a tiny refactor I didn't want to cause more noise and dependencies with another PR..

@herndlm herndlm force-pushed the array-splice branch 5 times, most recently from c7df375 to 4ebff11 Compare April 20, 2025 06:43
Comment on lines 1047 to 1049
$offset *= -1;
$reversedLength = min($length, $offset);
$reversedOffset = $offset - $reversedLength;
Copy link
Contributor

Choose a reason for hiding this comment

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

these operations look like they could be expressed on the type-level directly.

but as you said, maybe this would be too much and we leave it less abstract for now and see whether people report new issues

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Can we do such calculations too, can you show me an example maybe? I'm not too confident that I can make it work, but might be also a good follow-up.

Copy link
Contributor

Choose a reason for hiding this comment

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

maybe

if (count($argType->getConstantArrays()) > 0) {
foreach ($argType->getConstantArrays() as $constantArray) {
$node = new Int_(0);
foreach ($constantArray->getValueTypes() as $i => $type) {
if ($constantArray->isOptionalKey($i)) {
$node = new Plus($node, new TypeExpr(TypeCombinator::union($type, new ConstantIntegerType(0))));
} else {
$node = new Plus($node, new TypeExpr($type));
}
}
$resultTypes[] = $scope->getType($node);
}
} else {
$itemType = $argType->getIterableValueType();
$mulNode = new Mul(new TypeExpr($itemType), new TypeExpr(IntegerRangeType::fromInterval(0, null)));
$resultTypes[] = $scope->getType(new Plus(new TypeExpr($itemType), $mulNode));
}

or InitializerExprTypeResolver::get(Minus|Plus|...)Type

Copy link
Contributor Author

Choose a reason for hiding this comment

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

can't figure out how to do this now unfortunately, there's also no access to scope in the type. but it's way simpler because non-optional keys don't have to be considered and there's a chance it might work somehow I suppose. maybe still a good follow-up :)

@herndlm herndlm marked this pull request as draft April 20, 2025 07:23
@herndlm herndlm force-pushed the array-splice branch 2 times, most recently from 116c71e to e7afdd9 Compare April 20, 2025 19:38
@herndlm herndlm marked this pull request as ready for review April 20, 2025 19:46
@phpstan-bot
Copy link
Collaborator

This pull request has been marked as ready for review.

@herndlm herndlm force-pushed the array-splice branch 4 times, most recently from 7721222 to a76dc4a Compare April 20, 2025 21:00
@herndlm herndlm marked this pull request as draft April 21, 2025 06:24
@herndlm herndlm marked this pull request as ready for review April 21, 2025 06:33
@phpstan-bot
Copy link
Collaborator

This pull request has been marked as ready for review.

Comment on lines 15 to 18
assertType('non-empty-array<0|1|2|3|4, 0|1|2|3|4>', $items);
assertType('non-empty-list<int<min, 4>>', $items);
$batch = array_splice($items, 0, 2);
assertType('array<0|1|2|3|4, 0|1|2|3|4>', $items);
assertType('non-empty-list<0|1|2|3|4>', $batch);
assertType('list<int<min, 4>>', $items);
assertType('non-empty-list<int<min, 4>>', $batch);
Copy link
Contributor Author

Choose a reason for hiding this comment

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

the changes here confused me briefly, but it seems to be coming from loop generalization and there's not much I can do about it

@herndlm
Copy link
Contributor Author

herndlm commented Apr 21, 2025

Meh, I'll do one more improvement and also add tests for the return types into the same file. Surely can't hurt and hopefully does not discover slice issues...

@herndlm herndlm marked this pull request as draft April 21, 2025 08:21
@herndlm
Copy link
Contributor Author

herndlm commented Apr 28, 2025

Ok, so I figured out a way to get correct types for array_splice() without using getAllArrays(). But I had to use sliceArray() internally once to deal with the optional offsets.

@herndlm herndlm marked this pull request as ready for review April 28, 2025 13:32
@phpstan-bot
Copy link
Collaborator

This pull request has been marked as ready for review.

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.

Types are wrong for array_splice
3 participants