mirror of
https://github.com/danog/psalm.git
synced 2025-01-22 05:41:20 +01:00
Allow reconciling between object and iterable (#4706)
* Allow reconciling between object and iterable * add tests
This commit is contained in:
parent
4bbb72329e
commit
f7cfdaabd7
@ -1207,6 +1207,15 @@ class SimpleAssertionReconciler extends \Psalm\Type\Reconciler
|
|||||||
$object_types[] = $type;
|
$object_types[] = $type;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
$did_remove_type = true;
|
||||||
|
} elseif ($type instanceof Atomic\TIterable) {
|
||||||
|
$clone_type = clone $type;
|
||||||
|
|
||||||
|
self::refineArrayKey($clone_type->type_params[0]);
|
||||||
|
|
||||||
|
$object_types[] = new TArray($clone_type->type_params);
|
||||||
|
$object_types[] = new TNamedObject('ArrayAccess');
|
||||||
|
|
||||||
$did_remove_type = true;
|
$did_remove_type = true;
|
||||||
} else {
|
} else {
|
||||||
$did_remove_type = true;
|
$did_remove_type = true;
|
||||||
@ -1649,27 +1658,6 @@ class SimpleAssertionReconciler extends \Psalm\Type\Reconciler
|
|||||||
: Type::getEmpty();
|
: Type::getEmpty();
|
||||||
}
|
}
|
||||||
|
|
||||||
private static function refineArrayKey(Union $key_type) : void
|
|
||||||
{
|
|
||||||
foreach ($key_type->getAtomicTypes() as $key => $cat) {
|
|
||||||
if ($cat instanceof TTemplateParam) {
|
|
||||||
self::refineArrayKey($cat->as);
|
|
||||||
$key_type->bustCache();
|
|
||||||
} elseif ($cat instanceof TScalar || $cat instanceof TMixed) {
|
|
||||||
$key_type->removeType($key);
|
|
||||||
$key_type->addType(new Type\Atomic\TArrayKey());
|
|
||||||
} elseif (!$cat instanceof TString && !$cat instanceof TInt) {
|
|
||||||
$key_type->removeType($key);
|
|
||||||
$key_type->addType(new Type\Atomic\TArrayKey());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!$key_type->getAtomicTypes()) {
|
|
||||||
// this should ideally prompt some sort of error
|
|
||||||
$key_type->addType(new Type\Atomic\TArrayKey());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @param string[] $suppressed_issues
|
* @param string[] $suppressed_issues
|
||||||
* @param 0|1|2 $failed_reconciliation
|
* @param 0|1|2 $failed_reconciliation
|
||||||
|
@ -940,6 +940,14 @@ class SimpleNegatedAssertionReconciler extends Reconciler
|
|||||||
Type::getMixed()
|
Type::getMixed()
|
||||||
]);
|
]);
|
||||||
$non_object_types[] = new Atomic\TCallableString();
|
$non_object_types[] = new Atomic\TCallableString();
|
||||||
|
$did_remove_type = true;
|
||||||
|
} elseif ($type instanceof Atomic\TIterable) {
|
||||||
|
$clone_type = clone $type;
|
||||||
|
|
||||||
|
self::refineArrayKey($clone_type->type_params[0]);
|
||||||
|
|
||||||
|
$non_object_types[] = new TArray($clone_type->type_params);
|
||||||
|
|
||||||
$did_remove_type = true;
|
$did_remove_type = true;
|
||||||
} elseif (!$type->isObjectType()) {
|
} elseif (!$type->isObjectType()) {
|
||||||
$non_object_types[] = $type;
|
$non_object_types[] = $type;
|
||||||
|
@ -1,6 +1,8 @@
|
|||||||
<?php
|
<?php
|
||||||
namespace Psalm\Type;
|
namespace Psalm\Type;
|
||||||
|
|
||||||
|
use Psalm\Type\Atomic\TInt;
|
||||||
|
use Psalm\Type\Atomic\TScalar;
|
||||||
use function array_pop;
|
use function array_pop;
|
||||||
use function array_shift;
|
use function array_shift;
|
||||||
use function count;
|
use function count;
|
||||||
@ -1015,4 +1017,25 @@ class Reconciler
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
protected static function refineArrayKey(Union $key_type) : void
|
||||||
|
{
|
||||||
|
foreach ($key_type->getAtomicTypes() as $key => $cat) {
|
||||||
|
if ($cat instanceof TTemplateParam) {
|
||||||
|
self::refineArrayKey($cat->as);
|
||||||
|
$key_type->bustCache();
|
||||||
|
} elseif ($cat instanceof TScalar || $cat instanceof TMixed) {
|
||||||
|
$key_type->removeType($key);
|
||||||
|
$key_type->addType(new Type\Atomic\TArrayKey());
|
||||||
|
} elseif (!$cat instanceof TString && !$cat instanceof TInt) {
|
||||||
|
$key_type->removeType($key);
|
||||||
|
$key_type->addType(new Type\Atomic\TArrayKey());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!$key_type->getAtomicTypes()) {
|
||||||
|
// this should ideally prompt some sort of error
|
||||||
|
$key_type->addType(new Type\Atomic\TArrayKey());
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -134,6 +134,8 @@ class ReconcilerTest extends \Psalm\Tests\TestCase
|
|||||||
'traversableToIntersection' => ['Countable&Traversable', 'Traversable', 'Countable'],
|
'traversableToIntersection' => ['Countable&Traversable', 'Traversable', 'Countable'],
|
||||||
'iterableWithoutParamsToTraversableWithoutParams' => ['Traversable', '!array', 'iterable'],
|
'iterableWithoutParamsToTraversableWithoutParams' => ['Traversable', '!array', 'iterable'],
|
||||||
'iterableWithParamsToTraversableWithParams' => ['Traversable<int, string>', '!array', 'iterable<int, string>'],
|
'iterableWithParamsToTraversableWithParams' => ['Traversable<int, string>', '!array', 'iterable<int, string>'],
|
||||||
|
'iterableAndObject' => ['ArrayAccess|array<int, string>', 'object', 'iterable<int, string>'],
|
||||||
|
'iterableAndNotObject' => ['array<int, string>', '!object', 'iterable<int, string>'],
|
||||||
];
|
];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Loading…
x
Reference in New Issue
Block a user