mirror of
https://github.com/danog/psalm.git
synced 2025-01-22 05:41:20 +01:00
Fix #3603 - better typed value comparisons for loose equality
This commit is contained in:
parent
21e567832f
commit
137647a1a0
@ -970,8 +970,8 @@ class AssertionFinder
|
||||
if ($var_name && $var_type) {
|
||||
$identical = $conditional instanceof PhpParser\Node\Expr\BinaryOp\Identical
|
||||
|| ($other_type
|
||||
&& (($var_type->isString() && $other_type->isString())
|
||||
|| ($var_type->isInt() && $other_type->isInt())
|
||||
&& (($var_type->isString(true) && $other_type->isString(true))
|
||||
|| ($var_type->isInt(true) && $other_type->isInt(true))
|
||||
|| ($var_type->isFloat() && $other_type->isFloat())
|
||||
)
|
||||
);
|
||||
|
@ -1535,13 +1535,20 @@ class Union implements TypeNode
|
||||
/**
|
||||
* @return bool true if this is an int
|
||||
*/
|
||||
public function isInt()
|
||||
public function isInt(bool $check_templates = false)
|
||||
{
|
||||
if (!$this->isSingle()) {
|
||||
return false;
|
||||
return count(
|
||||
array_filter(
|
||||
$this->types,
|
||||
function ($type) use ($check_templates) {
|
||||
return $type instanceof TInt
|
||||
|| ($check_templates
|
||||
&& $type instanceof TTemplateParam
|
||||
&& $type->as->isInt()
|
||||
);
|
||||
}
|
||||
|
||||
return isset($this->types['int']) || $this->literal_int_types;
|
||||
)
|
||||
) === count($this->types);
|
||||
}
|
||||
|
||||
/**
|
||||
@ -1559,17 +1566,20 @@ class Union implements TypeNode
|
||||
/**
|
||||
* @return bool true if this is a string
|
||||
*/
|
||||
public function isString()
|
||||
public function isString(bool $check_templates = false)
|
||||
{
|
||||
if (!$this->isSingle()) {
|
||||
return false;
|
||||
return count(
|
||||
array_filter(
|
||||
$this->types,
|
||||
function ($type) use ($check_templates) {
|
||||
return $type instanceof TString
|
||||
|| ($check_templates
|
||||
&& $type instanceof TTemplateParam
|
||||
&& $type->as->isString()
|
||||
);
|
||||
}
|
||||
|
||||
return isset($this->types['string'])
|
||||
|| isset($this->types['class-string'])
|
||||
|| isset($this->types['trait-string'])
|
||||
|| isset($this->types['numeric-string'])
|
||||
|| $this->literal_string_types;
|
||||
)
|
||||
) === count($this->types);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -2781,6 +2781,63 @@ class ClassTemplateTest extends TestCase
|
||||
abstract protected function createMap(): Map;
|
||||
}'
|
||||
],
|
||||
'looseEquality' => [
|
||||
'<?php
|
||||
|
||||
/**
|
||||
* @psalm-immutable
|
||||
* @template T of self::READ_UNCOMMITTED|self::READ_COMMITTED|self::REPEATABLE_READ|self::SERIALIZABLE
|
||||
*/
|
||||
final class TransactionIsolationLevel
|
||||
{
|
||||
private const READ_UNCOMMITTED = "read uncommitted";
|
||||
private const READ_COMMITTED = "read committed";
|
||||
private const REPEATABLE_READ = "repeatable read";
|
||||
private const SERIALIZABLE = "serializable";
|
||||
|
||||
/**
|
||||
* @psalm-var T $level
|
||||
*/
|
||||
private string $level;
|
||||
|
||||
/**
|
||||
* @psalm-param T $level
|
||||
*/
|
||||
private function __construct(string $level)
|
||||
{
|
||||
$this->level = $level;
|
||||
}
|
||||
|
||||
/**
|
||||
* @psalm-return self<self::READ_UNCOMMITTED>
|
||||
*/
|
||||
public static function readUncommitted(): self
|
||||
{
|
||||
return new self(self::READ_UNCOMMITTED);
|
||||
}
|
||||
|
||||
/**
|
||||
* @psalm-return T
|
||||
*/
|
||||
public function toString(): string
|
||||
{
|
||||
return $this->level;
|
||||
}
|
||||
|
||||
/**
|
||||
* @psalm-template TResult
|
||||
* @psalm-param callable(self::READ_UNCOMMITTED): TResult $readUncommitted
|
||||
* @psalm-return TResult
|
||||
*/
|
||||
public function resolve(callable $readUncommitted) {
|
||||
if ($this->level == self::READ_UNCOMMITTED) {
|
||||
return $readUncommitted($this->level);
|
||||
}
|
||||
|
||||
throw new \LogicException("bad");
|
||||
}
|
||||
}'
|
||||
],
|
||||
];
|
||||
}
|
||||
|
||||
|
Loading…
x
Reference in New Issue
Block a user