Skip to content

Commit

Permalink
Add support for literal-int annotations as well
Browse files Browse the repository at this point in the history
  • Loading branch information
muglug committed Jun 15, 2021
1 parent c3fdfc5 commit 9dde8ee
Show file tree
Hide file tree
Showing 13 changed files with 465 additions and 292 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -146,10 +146,8 @@ public static function analyze(
// type is all string or int literals, combine them into new literal(s).
$literal_concat = false;

if ((($left_type->isSingleStringLiteral() || $left_type->isSingleIntLiteral())
&& ($right_type->allStringLiterals() || $right_type->allIntLiterals()))
|| (($right_type->isSingleStringLiteral() || $right_type->isSingleIntLiteral())
&& ($left_type->allStringLiterals() || $left_type->allIntLiterals()))
if (($left_type->allStringLiterals() || $left_type->allIntLiterals())
&& ($right_type->allStringLiterals() || $right_type->allIntLiterals())
) {
$literal_concat = true;
$result_type_parts = [];
Expand All @@ -170,7 +168,7 @@ public static function analyze(
}

if (!empty($result_type_parts)) {
if ($literal_concat) {
if ($literal_concat && count($result_type_parts) < 64) {
$result_type = new Type\Union($result_type_parts);
} else {
$result_type = new Type\Union([new Type\Atomic\TNonEmptyNonspecificLiteralString]);
Expand All @@ -189,62 +187,62 @@ public static function analyze(
$left_type,
$numeric_type
);
$right_uint = Type::getPositiveInt();
$right_uint->addType(new Type\Atomic\TLiteralInt(0));
$right_is_uint = UnionTypeComparator::isContainedBy(
$codebase,
$right_type,
$right_uint
);

if ($left_is_numeric && $right_is_uint) {
$result_type = Type::getNumericString();
return;
if ($left_is_numeric) {
$right_uint = Type::getPositiveInt();
$right_uint->addType(new Type\Atomic\TLiteralInt(0));
$right_is_uint = UnionTypeComparator::isContainedBy(
$codebase,
$right_type,
$right_uint
);

if ($right_is_uint) {
$result_type = Type::getNumericString();
return;
}
}

$lowercase_type = clone $numeric_type;
$lowercase_type->addType(new Type\Atomic\TLowercaseString());
$left_is_lowercase = UnionTypeComparator::isContainedBy(

$all_lowercase = UnionTypeComparator::isContainedBy(
$codebase,
$left_type,
$lowercase_type
);
$right_is_lowercase = UnionTypeComparator::isContainedBy(
) && UnionTypeComparator::isContainedBy(
$codebase,
$right_type,
$lowercase_type
);

$non_empty_string = Type::getNonEmptyString();

$left_is_non_empty = UnionTypeComparator::isContainedBy(
$has_non_empty = UnionTypeComparator::isContainedBy(
$codebase,
$left_type,
$non_empty_string
);
$right_is_non_empty = UnionTypeComparator::isContainedBy(
) || UnionTypeComparator::isContainedBy(
$codebase,
$right_type,
$non_empty_string
);

if ($left_is_lowercase && $right_is_lowercase) {
$result_type = $left_is_non_empty || $right_is_non_empty
? Type::getNonEmptyLowercaseString()
: Type::getLowercaseString();

return;
}
$all_literals = $left_type->allLiterals() && $right_type->allLiterals();

if ($left_is_non_empty || $right_is_non_empty) {
if ($left_type->allLiterals() && $right_type->allLiterals()) {
if ($has_non_empty) {
if ($all_literals) {
$result_type = new Type\Union([new Type\Atomic\TNonEmptyNonspecificLiteralString]);
} elseif ($all_lowercase) {
$result_type = Type::getNonEmptyLowercaseString();
} else {
$result_type = Type::getNonEmptyString();
}
} else {
if ($left_type->allLiterals() && $right_type->allLiterals()) {
if ($all_literals) {
$result_type = new Type\Union([new Type\Atomic\TNonspecificLiteralString]);
} elseif ($all_lowercase) {
$result_type = Type::getLowercaseString();
} else {
$result_type = Type::getString();
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -372,6 +372,8 @@ public static function castStringAttempt(
) {
if ($atomic_type instanceof Type\Atomic\TLiteralInt) {
$castable_types[] = new Type\Atomic\TLiteralString((string) $atomic_type->value);
} elseif ($atomic_type instanceof Type\Atomic\TNonspecificLiteralInt) {
$castable_types[] = new Type\Atomic\TNonspecificLiteralString();
} else {
$castable_types[] = new Type\Atomic\TNumericString();
}
Expand Down
24 changes: 22 additions & 2 deletions src/Psalm/Internal/Type/Comparator/ScalarTypeComparator.php
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@
use Psalm\Type\Atomic\TNonEmptyNonspecificLiteralString;
use Psalm\Type\Atomic\TNonEmptyString;
use Psalm\Type\Atomic\TNonFalsyString;
use Psalm\Type\Atomic\TNonspecificLiteralInt;
use Psalm\Type\Atomic\TNonspecificLiteralString;
use Psalm\Type\Atomic\TNumeric;
use Psalm\Type\Atomic\TNumericString;
Expand Down Expand Up @@ -94,8 +95,27 @@ public static function isContainedBy(
}

if ($container_type_part instanceof TNonspecificLiteralString) {
if ($atomic_comparison_result) {
$atomic_comparison_result->type_coerced = true;
if ($input_type_part instanceof TString) {
if ($atomic_comparison_result) {
$atomic_comparison_result->type_coerced = true;
}
}

return false;
}

if ($container_type_part instanceof TNonspecificLiteralInt
&& ($input_type_part instanceof TLiteralInt
|| $input_type_part instanceof TNonspecificLiteralInt)
) {
return true;
}

if ($container_type_part instanceof TNonspecificLiteralInt) {
if ($input_type_part instanceof TInt) {
if ($atomic_comparison_result) {
$atomic_comparison_result->type_coerced = true;
}
}

return false;
Expand Down
Loading

0 comments on commit 9dde8ee

Please sign in to comment.