Skip to content

Commit

Permalink
Merge branch refs/heads/1.12.x into 2.1.x
Browse files Browse the repository at this point in the history
  • Loading branch information
phpstan-bot authored Jan 16, 2025
2 parents f3ac9ea + c99b242 commit 0520107
Show file tree
Hide file tree
Showing 2 changed files with 172 additions and 6 deletions.
38 changes: 32 additions & 6 deletions src/Type/TypeCombinator.php
Original file line number Diff line number Diff line change
Expand Up @@ -3,8 +3,10 @@
namespace PHPStan\Type;

use PHPStan\Type\Accessory\AccessoryArrayListType;
use PHPStan\Type\Accessory\AccessoryLowercaseStringType;
use PHPStan\Type\Accessory\AccessoryNonEmptyStringType;
use PHPStan\Type\Accessory\AccessoryType;
use PHPStan\Type\Accessory\AccessoryUppercaseStringType;
use PHPStan\Type\Accessory\HasOffsetType;
use PHPStan\Type\Accessory\HasOffsetValueType;
use PHPStan\Type\Accessory\HasPropertyType;
Expand Down Expand Up @@ -451,7 +453,10 @@ private static function compareTypesInUnion(Type $a, Type $b): ?array
&& ($b->describe(VerbosityLevel::value()) === 'non-empty-string'
|| $b->describe(VerbosityLevel::value()) === 'non-falsy-string')
) {
return [null, new StringType()];
return [null, self::intersect(
new StringType(),
...self::getAccessoryCaseStringTypes($b),
)];
}

if (
Expand All @@ -460,34 +465,55 @@ private static function compareTypesInUnion(Type $a, Type $b): ?array
&& ($a->describe(VerbosityLevel::value()) === 'non-empty-string'
|| $a->describe(VerbosityLevel::value()) === 'non-falsy-string')
) {
return [new StringType(), null];
return [self::intersect(
new StringType(),
...self::getAccessoryCaseStringTypes($a),
), null];
}

if (
$a instanceof ConstantStringType
&& $a->getValue() === '0'
&& $b->describe(VerbosityLevel::value()) === 'non-falsy-string'
) {
return [null, new IntersectionType([
return [null, self::intersect(
new StringType(),
new AccessoryNonEmptyStringType(),
])];
...self::getAccessoryCaseStringTypes($b),
)];
}

if (
$b instanceof ConstantStringType
&& $b->getValue() === '0'
&& $a->describe(VerbosityLevel::value()) === 'non-falsy-string'
) {
return [new IntersectionType([
return [self::intersect(
new StringType(),
new AccessoryNonEmptyStringType(),
]), null];
...self::getAccessoryCaseStringTypes($a),
), null];
}

return null;
}

/**
* @return array<Type>
*/
private static function getAccessoryCaseStringTypes(Type $type): array
{
$accessory = [];
if ($type->isLowercaseString()->yes()) {
$accessory[] = new AccessoryLowercaseStringType();
}
if ($type->isUppercaseString()->yes()) {
$accessory[] = new AccessoryUppercaseStringType();
}

return $accessory;
}

private static function unionWithSubtractedType(
Type $type,
?Type $subtractedType,
Expand Down
140 changes: 140 additions & 0 deletions tests/PHPStan/Analyser/nsrt/bug-12312.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,140 @@
<?php declare(strict_types = 1);

namespace Bug12312;

use function PHPStan\Testing\assertType;

class HelloWorld
{
/**
* @param lowercase-string $s
*/
public function sayLowercase(string $s): void
{
if ($s != '') {
assertType('lowercase-string&non-empty-string', $s);
}
assertType('lowercase-string', $s);
}

/**
* @param lowercase-string $s
*/
public function sayLowercase2(string $s): void
{
if ('' != $s) {
assertType('lowercase-string&non-empty-string', $s);
}
assertType('lowercase-string', $s);
}

/**
* @param lowercase-string&non-empty-string $s
*/
public function sayLowercase3(string $s): void
{
if ($s != '0') {
assertType('lowercase-string&non-falsy-string', $s);
}
assertType('lowercase-string&non-empty-string', $s);
}

/**
* @param lowercase-string&non-empty-string $s
*/
public function sayLowercase4(string $s): void
{
if ('0' != $s) {
assertType('lowercase-string&non-falsy-string', $s);
}
assertType('lowercase-string&non-empty-string', $s);
}

/**
* @param uppercase-string $s
*/
public function sayUppercase(string $s): void
{
if ($s != '') {
assertType('non-empty-string&uppercase-string', $s);
}
assertType('uppercase-string', $s);
}

/**
* @param uppercase-string $s
*/
public function sayUppercase2(string $s): void
{
if ('' != $s) {
assertType('non-empty-string&uppercase-string', $s);
}
assertType('uppercase-string', $s);
}

/**
* @param uppercase-string&non-empty-string $s
*/
public function sayUppercase3(string $s): void
{
if ($s != '0') {
assertType('non-falsy-string&uppercase-string', $s);
}
assertType('non-empty-string&uppercase-string', $s);
}

/**
* @param uppercase-string&non-empty-string $s
*/
public function sayUppercase4(string $s): void
{
if ('0' != $s) {
assertType('non-falsy-string&uppercase-string', $s);
}
assertType('non-empty-string&uppercase-string', $s);
}

/**
* @param lowercase-string&uppercase-string $s
*/
public function sayBoth(string $s): void
{
if ($s != '') {
assertType('lowercase-string&non-empty-string&uppercase-string', $s);
}
assertType('lowercase-string&uppercase-string', $s);
}

/**
* @param lowercase-string&uppercase-string $s
*/
public function sayBoth2(string $s): void
{
if ('' != $s) {
assertType('lowercase-string&non-empty-string&uppercase-string', $s);
}
assertType('lowercase-string&uppercase-string', $s);
}

/**
* @param lowercase-string&uppercase-string&non-empty-string $s
*/
public function sayBoth3(string $s): void
{
if ($s != '0') {
assertType('lowercase-string&non-falsy-string&uppercase-string', $s);
}
assertType('lowercase-string&non-empty-string&uppercase-string', $s);
}

/**
* @param lowercase-string&uppercase-string&non-empty-string $s
*/
public function sayBoth4(string $s): void
{
if ('0' != $s) {
assertType('lowercase-string&non-falsy-string&uppercase-string', $s);
}
assertType('lowercase-string&non-empty-string&uppercase-string', $s);
}
}

0 comments on commit 0520107

Please sign in to comment.