Skip to content

Commit b40a1f6

Browse files
authored
More precise MixedType::toString() with subtracted type
1 parent 80fdfab commit b40a1f6

File tree

2 files changed

+65
-1
lines changed

2 files changed

+65
-1
lines changed

src/Type/MixedType.php

Lines changed: 29 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -27,7 +27,9 @@
2727
use PHPStan\Type\Accessory\OversizedArrayType;
2828
use PHPStan\Type\Constant\ConstantArrayType;
2929
use PHPStan\Type\Constant\ConstantBooleanType;
30+
use PHPStan\Type\Constant\ConstantFloatType;
3031
use PHPStan\Type\Constant\ConstantIntegerType;
32+
use PHPStan\Type\Constant\ConstantStringType;
3133
use PHPStan\Type\Generic\TemplateMixedType;
3234
use PHPStan\Type\Generic\TemplateType;
3335
use PHPStan\Type\Traits\NonGeneralizableTypeTrait;
@@ -504,7 +506,7 @@ public function toInteger(): Type
504506
new ConstantIntegerType(0),
505507
new ConstantArrayType([], []),
506508
new StringType(),
507-
new FloatType(),
509+
new FloatType(), // every 0.x float casts to int(0)
508510
]);
509511
if (
510512
$this->subtractedType !== null
@@ -526,6 +528,32 @@ public function toFloat(): Type
526528

527529
public function toString(): Type
528530
{
531+
if ($this->subtractedType !== null) {
532+
$castsToEmptyString = new UnionType([
533+
new NullType(),
534+
new ConstantBooleanType(false),
535+
new ConstantStringType(''),
536+
]);
537+
if ($this->subtractedType->isSuperTypeOf($castsToEmptyString)->yes()) {
538+
$accessories = [
539+
new StringType(),
540+
new AccessoryNonEmptyStringType(),
541+
];
542+
543+
$castsToZeroString = new UnionType([
544+
new ConstantFloatType(0.0),
545+
new ConstantStringType('0'),
546+
new ConstantIntegerType(0),
547+
]);
548+
if ($this->subtractedType->isSuperTypeOf($castsToZeroString)->yes()) {
549+
$accessories[] = new AccessoryNonFalsyStringType();
550+
}
551+
return new IntersectionType(
552+
$accessories,
553+
);
554+
}
555+
}
556+
529557
return new StringType();
530558
}
531559

tests/PHPStan/Analyser/nsrt/non-empty-string.php

Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -408,4 +408,40 @@ function multiplesPrintfFormats(string $s) {
408408
assertType('non-empty-string', sprintf($nonEmpty, $s));
409409
assertType('non-falsy-string', sprintf($nonFalsy, $s));
410410
}
411+
412+
function subtract($m) {
413+
if ($m) {
414+
assertType("mixed~(0|0.0|''|'0'|array{}|false|null)", $m);
415+
assertType('non-falsy-string', (string) $m);
416+
}
417+
if ($m != '') {
418+
assertType("mixed", $m);
419+
assertType('string', (string) $m);
420+
}
421+
if ($m !== '') {
422+
assertType("mixed~''", $m);
423+
assertType('string', (string) $m);
424+
}
425+
if (!is_string($m)) {
426+
assertType("mixed~string", $m);
427+
assertType('string', (string) $m);
428+
}
429+
430+
if ($m !== true) {
431+
assertType("mixed~true", $m);
432+
assertType('string', (string) $m);
433+
}
434+
if ($m !== false) {
435+
assertType("mixed~false", $m);
436+
assertType('string', (string) $m);
437+
}
438+
if ($m !== false && $m !== '' && $m !== null) {
439+
assertType("mixed~(''|false|null)", $m);
440+
assertType('non-empty-string', (string) $m);
441+
}
442+
if (!is_bool($m) && $m !== '' && $m !== null) {
443+
assertType("mixed~(''|bool|null)", $m);
444+
assertType('non-empty-string', (string) $m);
445+
}
446+
}
411447
}

0 commit comments

Comments
 (0)