mirror of
https://github.com/danog/psalm.git
synced 2025-01-22 13:51:54 +01:00
Fix intersection of final classes
This commit is contained in:
parent
c2a8d1bb06
commit
c409675e3e
@ -795,15 +795,7 @@ class CallAnalyzer
|
|||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
foreach ($intersection->getAtomicTypes() as $atomic_type) {
|
foreach ($intersection->getAtomicTypes() as $atomic_type) {
|
||||||
if ($assertion_type_atomic instanceof TTemplateParam
|
$orred_rules[] = new IsIdentical($atomic_type);
|
||||||
&& $assertion_type_atomic->as->getId() === $atomic_type->getId()
|
|
||||||
) {
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
$assertion_rule = clone $assertion_rule;
|
|
||||||
$assertion_rule->setAtomicType($atomic_type);
|
|
||||||
$orred_rules[] = $assertion_rule;
|
|
||||||
}
|
}
|
||||||
} elseif ($assertion_rule instanceof IsType) {
|
} elseif ($assertion_rule instanceof IsType) {
|
||||||
if (!UnionTypeComparator::canExpressionTypesBeIdentical(
|
if (!UnionTypeComparator::canExpressionTypesBeIdentical(
|
||||||
|
@ -19,6 +19,7 @@ use Psalm\Type\Atomic\TClosure;
|
|||||||
use Psalm\Type\Atomic\TFalse;
|
use Psalm\Type\Atomic\TFalse;
|
||||||
use Psalm\Type\Atomic\TFloat;
|
use Psalm\Type\Atomic\TFloat;
|
||||||
use Psalm\Type\Atomic\TInt;
|
use Psalm\Type\Atomic\TInt;
|
||||||
|
use Psalm\Type\Atomic\TIntRange;
|
||||||
use Psalm\Type\Atomic\TIterable;
|
use Psalm\Type\Atomic\TIterable;
|
||||||
use Psalm\Type\Atomic\TList;
|
use Psalm\Type\Atomic\TList;
|
||||||
use Psalm\Type\Atomic\TLiteralClassString;
|
use Psalm\Type\Atomic\TLiteralClassString;
|
||||||
@ -691,6 +692,14 @@ abstract class Type
|
|||||||
$intersection_performed = true;
|
$intersection_performed = true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
if ($type_1_atomic instanceof TIntRange && $type_2_atomic instanceof TIntRange) {
|
||||||
|
$intersection_atomic = TIntRange::intersectIntRanges(
|
||||||
|
$type_1_atomic,
|
||||||
|
$type_2_atomic
|
||||||
|
);
|
||||||
|
$intersection_performed = true;
|
||||||
|
return $intersection_atomic;
|
||||||
|
}
|
||||||
|
|
||||||
if (null === $intersection_atomic) {
|
if (null === $intersection_atomic) {
|
||||||
if (AtomicTypeComparator::isContainedBy(
|
if (AtomicTypeComparator::isContainedBy(
|
||||||
@ -719,8 +728,8 @@ abstract class Type
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (static::mayHaveIntersection($type_1_atomic)
|
if (self::mayHaveIntersection($type_1_atomic, $codebase)
|
||||||
&& static::mayHaveIntersection($type_2_atomic)
|
&& self::mayHaveIntersection($type_2_atomic, $codebase)
|
||||||
) {
|
) {
|
||||||
if ($intersection_atomic === null && $wider_type === null) {
|
if ($intersection_atomic === null && $wider_type === null) {
|
||||||
$intersection_atomic = clone $type_1_atomic;
|
$intersection_atomic = clone $type_1_atomic;
|
||||||
@ -733,8 +742,8 @@ abstract class Type
|
|||||||
.' Did you forget to assign one of the variables?'
|
.' Did you forget to assign one of the variables?'
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
if (!static::mayHaveIntersection($intersection_atomic)
|
if (!self::mayHaveIntersection($intersection_atomic, $codebase)
|
||||||
|| !static::mayHaveIntersection($wider_type)
|
|| !self::mayHaveIntersection($wider_type, $codebase)
|
||||||
) {
|
) {
|
||||||
throw new LogicException(
|
throw new LogicException(
|
||||||
'$intersection_atomic and $wider_type should be both support intersection.'
|
'$intersection_atomic and $wider_type should be both support intersection.'
|
||||||
@ -769,12 +778,19 @@ abstract class Type
|
|||||||
/**
|
/**
|
||||||
* @psalm-assert-if-true TIterable|TNamedObject|TTemplateParam|TObjectWithProperties $type
|
* @psalm-assert-if-true TIterable|TNamedObject|TTemplateParam|TObjectWithProperties $type
|
||||||
*/
|
*/
|
||||||
private static function mayHaveIntersection(Atomic $type): bool
|
public static function mayHaveIntersection(Atomic $type, Codebase $codebase): bool
|
||||||
{
|
{
|
||||||
return $type instanceof TIterable
|
if ($type instanceof TIterable
|
||||||
|| $type instanceof TNamedObject
|
|
||||||
|| $type instanceof TTemplateParam
|
|| $type instanceof TTemplateParam
|
||||||
|| $type instanceof TObjectWithProperties;
|
|| $type instanceof TObjectWithProperties
|
||||||
|
) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
if (!$type instanceof TNamedObject) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
$storage = $codebase->classlike_storage_provider->get($type->value);
|
||||||
|
return !$storage->final;
|
||||||
}
|
}
|
||||||
|
|
||||||
private static function hasIntersection(Atomic $type): bool
|
private static function hasIntersection(Atomic $type): bool
|
||||||
|
@ -1123,7 +1123,7 @@ class FunctionTemplateAssertTest extends TestCase
|
|||||||
}',
|
}',
|
||||||
'error_message' => 'RedundantCondition',
|
'error_message' => 'RedundantCondition',
|
||||||
],
|
],
|
||||||
'SKIPPED-assertNotSameClasses' => [
|
'assertNotSameClasses' => [
|
||||||
'code' => '<?php
|
'code' => '<?php
|
||||||
/**
|
/**
|
||||||
* Asserts that two variables are the same.
|
* Asserts that two variables are the same.
|
||||||
@ -1137,7 +1137,7 @@ class FunctionTemplateAssertTest extends TestCase
|
|||||||
|
|
||||||
class a {}
|
class a {}
|
||||||
class b {}
|
class b {}
|
||||||
class c {}
|
final class c {}
|
||||||
|
|
||||||
$expected = rand(0, 1) ? new a : new b;
|
$expected = rand(0, 1) ? new a : new b;
|
||||||
$actual = new c;
|
$actual = new c;
|
||||||
|
Loading…
x
Reference in New Issue
Block a user