Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions src/Type/Accessory/AccessoryDecimalIntegerStringType.php
Original file line number Diff line number Diff line change
Expand Up @@ -133,6 +133,7 @@ public function isSubTypeOf(Type $otherType): IsSuperTypeOfResult
if (
(
$otherType instanceof AccessoryNumericStringType
|| $otherType instanceof AccessoryNonEmptyStringType
|| $otherType instanceof AccessoryLowercaseStringType
|| $otherType instanceof AccessoryUppercaseStringType
)
Expand Down
4 changes: 4 additions & 0 deletions src/Type/Accessory/AccessoryNumericStringType.php
Original file line number Diff line number Diff line change
Expand Up @@ -113,6 +113,10 @@ public function isSubTypeOf(Type $otherType): IsSuperTypeOfResult
return $otherType->isSuperTypeOf($this);
}

if ($otherType instanceof AccessoryNonEmptyStringType) {
return IsSuperTypeOfResult::createYes();
}

return IsSuperTypeOfResult::createFromTrinaryLogic(
$otherType->isNumericString()->and($otherType instanceof self ? TrinaryLogic::createYes() : TrinaryLogic::createMaybe()),
);
Expand Down
2 changes: 1 addition & 1 deletion tests/PHPStan/Analyser/nsrt/bcmath-number.php
Original file line number Diff line number Diff line change
Expand Up @@ -186,7 +186,7 @@ public function bcVsNull(Number $a): void
assertType('*ERROR*', $a * $b);
assertType('*ERROR*', $a / $b);
assertType('*ERROR*', $a % $b);
assertType('non-empty-string&numeric-string', $a . $b);
assertType('numeric-string', $a . $b);
assertType('*ERROR*', $a ** $b);
assertType('*ERROR*', $a << $b);
assertType('*ERROR*', $a >> $b);
Expand Down
12 changes: 6 additions & 6 deletions tests/PHPStan/Analyser/nsrt/bug-12312.php
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,7 @@ public function sayLowercase3(string $s): void
if ($s != '0') {
assertType('lowercase-string&non-falsy-string', $s);
}
assertType('(lowercase-string&non-empty-string&numeric-string)|(lowercase-string&non-falsy-string)', $s);
assertType('(lowercase-string&non-falsy-string)|(lowercase-string&numeric-string)', $s);
}

/**
Expand All @@ -47,7 +47,7 @@ public function sayLowercase4(string $s): void
if ('0' != $s) {
assertType('lowercase-string&non-falsy-string', $s);
}
assertType('(lowercase-string&non-empty-string&numeric-string)|(lowercase-string&non-falsy-string)', $s);
assertType('(lowercase-string&non-falsy-string)|(lowercase-string&numeric-string)', $s);
}

/**
Expand Down Expand Up @@ -80,7 +80,7 @@ public function sayUppercase3(string $s): void
if ($s != '0') {
assertType('non-falsy-string&uppercase-string', $s);
}
assertType('(non-empty-string&numeric-string&uppercase-string)|(non-falsy-string&uppercase-string)', $s);
assertType('(non-falsy-string&uppercase-string)|(numeric-string&uppercase-string)', $s);
}

/**
Expand All @@ -91,7 +91,7 @@ public function sayUppercase4(string $s): void
if ('0' != $s) {
assertType('non-falsy-string&uppercase-string', $s);
}
assertType('(non-empty-string&numeric-string&uppercase-string)|(non-falsy-string&uppercase-string)', $s);
assertType('(non-falsy-string&uppercase-string)|(numeric-string&uppercase-string)', $s);
}

/**
Expand Down Expand Up @@ -124,7 +124,7 @@ public function sayBoth3(string $s): void
if ($s != '0') {
assertType('lowercase-string&non-falsy-string&uppercase-string', $s);
}
assertType('(lowercase-string&non-empty-string&numeric-string&uppercase-string)|(lowercase-string&non-falsy-string&uppercase-string)', $s);
assertType('(lowercase-string&non-falsy-string&uppercase-string)|(lowercase-string&numeric-string&uppercase-string)', $s);
}

/**
Expand All @@ -135,6 +135,6 @@ public function sayBoth4(string $s): void
if ('0' != $s) {
assertType('lowercase-string&non-falsy-string&uppercase-string', $s);
}
assertType('(lowercase-string&non-empty-string&numeric-string&uppercase-string)|(lowercase-string&non-falsy-string&uppercase-string)', $s);
assertType('(lowercase-string&non-falsy-string&uppercase-string)|(lowercase-string&numeric-string&uppercase-string)', $s);
}
}
2 changes: 1 addition & 1 deletion tests/PHPStan/Analyser/nsrt/bug-12393b-php84.php
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ class StringableFoo {
// https://3v4l.org/nelJF#v8.4.6
public function doFoo3(\BcMath\Number $foo): void {
$this->foo = $foo;
assertType('non-empty-string&numeric-string', $this->foo);
assertType('numeric-string', $this->foo);
}

public function __toString(): string {
Expand Down
2 changes: 1 addition & 1 deletion tests/PHPStan/Analyser/nsrt/bug-12393b.php
Original file line number Diff line number Diff line change
Expand Up @@ -472,7 +472,7 @@ class FooNumericToString
public function doFoo(float|int $b): void
{
$this->foo = $b;
assertType('decimal-int-string|(non-empty-string&uppercase-string)', $this->foo);
assertType('non-empty-string&uppercase-string', $this->foo);
}

}
Expand Down
8 changes: 4 additions & 4 deletions tests/PHPStan/Analyser/nsrt/bug-14047.php
Original file line number Diff line number Diff line change
Expand Up @@ -46,20 +46,20 @@ function test_strings(string $a, string $b): void
}

if ($b !== '' && is_numeric($b)) {
assertType('non-empty-string&numeric-string', $b);
assertType('numeric-string', $b);
}

if (strtolower($b) === $b && $b !== '' && is_numeric($b)) {
assertType('lowercase-string&non-empty-string&numeric-string', $b);
assertType('lowercase-string&numeric-string', $b);
}

assertType('string', $b);
if (is_numeric($b)) {
assertType('numeric-string', $b);
if (strtolower($b) === $b) {
assertType('lowercase-string&non-empty-string&numeric-string', $b);
assertType('lowercase-string&numeric-string', $b);
if ($b !== '') {
assertType('lowercase-string&non-empty-string&numeric-string', $b);
assertType('lowercase-string&numeric-string', $b);
}
}
if ($b !== '') {
Expand Down
6 changes: 3 additions & 3 deletions tests/PHPStan/Analyser/nsrt/cast-to-numeric-string.php
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ function foo(int $a, float $b, $numeric, $numeric2, $number, $positive, $negativ
assertType('non-empty-string&uppercase-string', (string)$b);
assertType('(non-empty-string&uppercase-string)|numeric-string', (string)$numeric);
assertType('(non-empty-string&uppercase-string)|numeric-string', (string)$numeric2);
assertType('decimal-int-string|(non-empty-string&uppercase-string)', (string)$number);
assertType('non-empty-string&uppercase-string', (string)$number);
assertType('decimal-int-string&non-falsy-string', (string)$positive);
assertType('decimal-int-string&non-falsy-string', (string)$negative);
assertType("'1'", (string)$constantInt);
Expand All @@ -36,7 +36,7 @@ function concatEmptyString(int $a, float $b, $numeric, $numeric2, $number, $posi
assertType('non-empty-string&uppercase-string', '' . $b);
assertType('(non-empty-string&uppercase-string)|numeric-string', '' . $numeric);
assertType('(non-empty-string&uppercase-string)|numeric-string', '' . $numeric2);
assertType('decimal-int-string|(non-empty-string&uppercase-string)', '' . $number);
assertType('non-empty-string&uppercase-string', '' . $number);
assertType('decimal-int-string&non-falsy-string', '' . $positive);
assertType('decimal-int-string&non-falsy-string', '' . $negative);
assertType("'1'", '' . $constantInt);
Expand All @@ -45,7 +45,7 @@ function concatEmptyString(int $a, float $b, $numeric, $numeric2, $number, $posi
assertType('non-empty-string&uppercase-string', $b . '');
assertType('(non-empty-string&uppercase-string)|numeric-string', $numeric . '');
assertType('(non-empty-string&uppercase-string)|numeric-string', $numeric2 . '');
assertType('decimal-int-string|(non-empty-string&uppercase-string)', $number . '');
assertType('non-empty-string&uppercase-string', $number . '');
assertType('decimal-int-string&non-falsy-string', $positive . '');
assertType('decimal-int-string&non-falsy-string', $negative . '');
assertType("'1'", $constantInt . '');
Expand Down
2 changes: 1 addition & 1 deletion tests/PHPStan/Analyser/nsrt/float-to-string.php
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ function doFoo(float $float, $number): void
assertType('non-empty-string&uppercase-string', (string) $float);
assertType('non-empty-string&uppercase-string', '' . $float);
assertType('non-falsy-string&uppercase-string', $float . '1');
assertType('decimal-int-string|(non-empty-string&uppercase-string)', (string) $number);
assertType('non-empty-string&uppercase-string', (string) $number);

// constant floats stay exact
assertType("'1.5'", (string) 1.5);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@ public function strTypes($nonES, $nonFalsyString, $numericString) {
assertType('non-falsy-string', $nonFalsyString);

if (dir($numericString)) {
assertType('non-empty-string&numeric-string', $numericString);
assertType('numeric-string', $numericString);
}
assertType('numeric-string', $numericString);
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -54,14 +54,14 @@ public function strContains(string $s, string $s2, $nonES, $nonFalsy, $numS, $li
assertType('non-empty-string', $s);
}
if (str_contains($numS, $nonEAndNumericS)) {
assertType('non-empty-string&numeric-string', $numS);
assertType('numeric-string', $numS);
}

if (str_contains($nonES, $s)) {
assertType('non-empty-string', $nonES);
}
if (str_contains($nonEAndNumericS, $s)) {
assertType('non-empty-string&numeric-string', $nonEAndNumericS);
assertType('numeric-string', $nonEAndNumericS);
}

if (str_contains($i, $s2)) {
Expand Down
2 changes: 1 addition & 1 deletion tests/PHPStan/Analyser/nsrt/non-empty-string.php
Original file line number Diff line number Diff line change
Expand Up @@ -140,7 +140,7 @@ public function doWithNumeric(string $s): void
return;
}

assertType('non-empty-string&numeric-string', $s);
assertType('numeric-string', $s);
}

public function doEmpty(string $s): void
Expand Down
2 changes: 1 addition & 1 deletion tests/PHPStan/Type/MixedTypeTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -374,7 +374,7 @@ public static function dataSubstractedIsNumericString(): array
new StringType(),
new AccessoryNonEmptyStringType(),
),
TrinaryLogic::createMaybe(),
TrinaryLogic::createNo(),
],
[
new MixedType(),
Expand Down
49 changes: 49 additions & 0 deletions tests/PHPStan/Type/TypeCombinatorTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -3389,6 +3389,38 @@ public static function dataUnion(): iterable
FloatType::class,
'float',
];
yield [
[
'non-empty-string',
'numeric-string',
],
IntersectionType::class,
'non-empty-string',
];
yield [
[
'non-empty-string',
'decimal-int-string',
],
IntersectionType::class,
'non-empty-string',
];
yield [
[
'non-empty-uppercase-string',
'numeric-string&uppercase-string',
],
IntersectionType::class,
'non-empty-string&uppercase-string',
];
yield [
[
'non-empty-lowercase-string',
'decimal-int-string',
],
IntersectionType::class,
'lowercase-string&non-empty-string',
];
}

/**
Expand Down Expand Up @@ -5603,6 +5635,23 @@ public static function dataIntersect(): iterable
'lowercase-string&non-decimal-int-string',
];

yield [
[
'non-empty-string',
'numeric-string',
],
IntersectionType::class,
'numeric-string',
];
yield [
[
'non-empty-string',
'decimal-int-string',
],
IntersectionType::class,
'decimal-int-string',
];

yield [
[
new ConstantArrayType(
Expand Down
5 changes: 3 additions & 2 deletions turbo-ext/src/AccessoryDecimalIntegerStringType.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -100,8 +100,8 @@ class AccessoryDecimalIntegerStringType
return pt_type_is_super_type_of_result(pt_trinary_and(isString, inverse ? trinaryNegate(isDecimalIntegerString) : isDecimalIntegerString));
}

/* the union/intersection callback; yes for a numeric, lowercase or
* uppercase accessory when not inverted; else the other type's
/* the union/intersection callback; yes for a numeric, non-empty,
* lowercase or uppercase accessory when not inverted; else the other type's
* string-and-(negated-)decimal-int verdict, and'ed with maybe unless it
* equals $this; UNDEF = pending exception */
zv::Val isSubTypeOf(zval *otherType) const
Expand All @@ -115,6 +115,7 @@ class AccessoryDecimalIntegerStringType
}
zend_class_entry *otherCe = Z_OBJCE_P(otherType);
if (instanceof_function(otherCe, pt_ce_accessory_numeric_string_type)
|| instanceof_function(otherCe, pt_ce_accessory_non_empty_string_type)
|| instanceof_function(otherCe, pt_ce_accessory_lowercase_string_type)
|| instanceof_function(otherCe, pt_ce_accessory_uppercase_string_type)
) {
Expand Down
7 changes: 4 additions & 3 deletions turbo-ext/src/AccessoryNumericStringType.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -59,9 +59,9 @@ class AccessoryNumericStringType
return pt_type_is_super_type_of_result(isNumericString);
}

/* the union/intersection callback; else the other type's numeric-string
* verdict, and'ed with maybe unless it is an AccessoryNumericStringType;
* UNDEF = pending exception */
/* the union/intersection callback; yes for a non-empty-string accessory;
* else the other type's numeric-string verdict, and'ed with maybe unless it
* is an AccessoryNumericStringType; UNDEF = pending exception */
zv::Val isSubTypeOf(zval *otherType) const
{
bool unionOrIntersection;
Expand All @@ -71,6 +71,7 @@ class AccessoryNumericStringType
ZVAL_OBJ(&selfZv, self);
return pt_type_op(Z_OBJ_P(otherType), PT_OP_IS_SUPER_TYPE_OF, 1, &selfZv);
}
if (instanceof_function(Z_OBJCE_P(otherType), pt_ce_accessory_non_empty_string_type)) return pt_type_is_super_type_of_result(PT_TRI_YES);
zend_long value = pt_type_call_trinary(Z_OBJ_P(otherType), PT_LC("isnumericstring"), 0, NULL);
if (UNEXPECTED(value < 0)) return zv::Val();
if (!instanceof_function(Z_OBJCE_P(otherType), pt_ce_accessory_numeric_string_type)) {
Expand Down
Loading