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
Fix constant-string handling in union-types #2134
Merged
Merged
Changes from all commits
Commits
Show all changes
11 commits
Select commit
Hold shift + click to select a range
e7ef43d
Fix constant-string handling in union-types
staabm 4c8ddf9
fix php <=7.3
staabm fa19cac
added regression test
staabm fdfde48
remove UnionTypeHelper usages
staabm d1d9b44
simplify
staabm 3948597
Delete test.php
staabm c392ef8
fix getArrays
staabm c07a033
nope
ondrejmirtes 7d59e37
Another nope
ondrejmirtes 7d779e9
fix
ondrejmirtes 58d0472
recurse into union-inner Intersections
staabm File filter
Filter by extension
Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -4078,7 +4078,7 @@ public function processClosureScope( | |
$prevVariableType = $prevScope->getVariableType($variableName); | ||
if (!$variableType->equals($prevVariableType)) { | ||
$variableType = TypeCombinator::union($variableType, $prevVariableType); | ||
$variableType = self::generalizeType($variableType, $prevVariableType); | ||
$variableType = self::generalizeType($variableType, $prevVariableType, 0); | ||
} | ||
} | ||
|
||
|
@@ -4200,15 +4200,15 @@ private function generalizeVariableTypeHolders( | |
|
||
$variableTypeHolders[$variableExprString] = new ExpressionTypeHolder( | ||
$variableTypeHolder->getExpr(), | ||
self::generalizeType($variableTypeHolder->getType(), $otherVariableTypeHolders[$variableExprString]->getType()), | ||
self::generalizeType($variableTypeHolder->getType(), $otherVariableTypeHolders[$variableExprString]->getType(), 0), | ||
$variableTypeHolder->getCertainty(), | ||
); | ||
} | ||
|
||
return $variableTypeHolders; | ||
} | ||
|
||
private static function generalizeType(Type $a, Type $b): Type | ||
private static function generalizeType(Type $a, Type $b, int $depth): Type | ||
{ | ||
if ($a->equals($b)) { | ||
return $a; | ||
|
@@ -4301,6 +4301,7 @@ private static function generalizeType(Type $a, Type $b): Type | |
self::generalizeType( | ||
$constantArraysA->getOffsetValueType($keyType), | ||
$constantArraysB->getOffsetValueType($keyType), | ||
$depth + 1, | ||
), | ||
!$constantArraysA->hasOffsetValueType($keyType)->and($constantArraysB->hasOffsetValueType($keyType))->negate()->no(), | ||
); | ||
|
@@ -4309,8 +4310,8 @@ private static function generalizeType(Type $a, Type $b): Type | |
$resultTypes[] = $resultArrayBuilder->getArray(); | ||
} else { | ||
$resultType = new ArrayType( | ||
TypeCombinator::union(self::generalizeType($constantArraysA->getIterableKeyType(), $constantArraysB->getIterableKeyType())), | ||
TypeCombinator::union(self::generalizeType($constantArraysA->getIterableValueType(), $constantArraysB->getIterableValueType())), | ||
TypeCombinator::union(self::generalizeType($constantArraysA->getIterableKeyType(), $constantArraysB->getIterableKeyType(), $depth + 1)), | ||
TypeCombinator::union(self::generalizeType($constantArraysA->getIterableValueType(), $constantArraysB->getIterableValueType(), $depth + 1)), | ||
); | ||
if ($constantArraysA->isIterableAtLeastOnce()->yes() && $constantArraysB->isIterableAtLeastOnce()->yes()) { | ||
$resultType = TypeCombinator::intersect($resultType, new NonEmptyArrayType()); | ||
|
@@ -4334,16 +4335,14 @@ private static function generalizeType(Type $a, Type $b): Type | |
|
||
$aValueType = $generalArraysA->getIterableValueType(); | ||
$bValueType = $generalArraysB->getIterableValueType(); | ||
$aArrays = $aValueType->getArrays(); | ||
$bArrays = $bValueType->getArrays(); | ||
if ( | ||
count($aArrays) === 1 | ||
&& $aArrays[0]->isConstantArray()->no() | ||
&& count($bArrays) === 1 | ||
&& $bArrays[0]->isConstantArray()->no() | ||
$aValueType->isArray()->yes() | ||
&& $aValueType->isConstantArray()->no() | ||
&& $bValueType->isArray()->yes() | ||
&& $bValueType->isConstantArray()->no() | ||
) { | ||
$aDepth = self::getArrayDepth($aArrays[0]); | ||
$bDepth = self::getArrayDepth($bArrays[0]); | ||
$aDepth = self::getArrayDepth($aValueType) + $depth; | ||
$bDepth = self::getArrayDepth($bValueType) + $depth; | ||
if ( | ||
($aDepth > 2 || $bDepth > 2) | ||
&& abs($aDepth - $bDepth) > 0 | ||
|
@@ -4354,8 +4353,8 @@ private static function generalizeType(Type $a, Type $b): Type | |
} | ||
|
||
$resultType = new ArrayType( | ||
TypeCombinator::union(self::generalizeType($generalArraysA->getIterableKeyType(), $generalArraysB->getIterableKeyType())), | ||
TypeCombinator::union(self::generalizeType($aValueType, $bValueType)), | ||
TypeCombinator::union(self::generalizeType($generalArraysA->getIterableKeyType(), $generalArraysB->getIterableKeyType(), $depth + 1)), | ||
TypeCombinator::union(self::generalizeType($aValueType, $bValueType, $depth + 1)), | ||
); | ||
if ($generalArraysA->isIterableAtLeastOnce()->yes() && $generalArraysB->isIterableAtLeastOnce()->yes()) { | ||
$resultType = TypeCombinator::intersect($resultType, new NonEmptyArrayType()); | ||
|
@@ -4514,17 +4513,14 @@ private static function generalizeType(Type $a, Type $b): Type | |
); | ||
} | ||
|
||
private static function getArrayDepth(ArrayType $type): int | ||
private static function getArrayDepth(Type $type): int | ||
{ | ||
$depth = 0; | ||
while ($type instanceof ArrayType) { | ||
$arrays = TypeUtils::getAnyArrays($type); | ||
while (count($arrays) > 0) { | ||
$temp = $type->getIterableValueType(); | ||
$arrays = $temp->getArrays(); | ||
if (count($arrays) === 1) { | ||
$type = $arrays[0]; | ||
} else { | ||
$type = $temp; | ||
} | ||
$type = $temp; | ||
$arrays = TypeUtils::getAnyArrays($type); | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I think our problem is that and |
||
$depth++; | ||
} | ||
|
||
|
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,26 @@ | ||
<?php declare(strict_types = 1); | ||
|
||
namespace Bug8568; | ||
|
||
use function PHPStan\Testing\assertType; | ||
|
||
class HelloWorld | ||
{ | ||
public function sayHello(): void | ||
{ | ||
assertType('non-falsy-string', 'a' . $this->get()); | ||
} | ||
|
||
public function get(): ?int | ||
{ | ||
return rand() ? 5 : null; | ||
} | ||
|
||
/** | ||
* @param numeric-string $numericS | ||
*/ | ||
public function intersections($numericS): void { | ||
assertType('non-falsy-string', 'a'. $numericS); | ||
assertType('numeric-string', (string) $numericS); | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I printed the types after generalization at this line in this PR vs. 1.9.x-dev at 9128321
most types are identical. the only different are:
so after this PR we no longer get MixedType and therefore we get the errors