1
0
mirror of https://github.com/danog/psalm.git synced 2025-01-22 05:41:20 +01:00
This commit is contained in:
ging-dev 2023-12-20 17:16:21 +07:00
parent b38530ed0d
commit 5731f927fe
2 changed files with 39 additions and 55 deletions

View File

@ -641,13 +641,31 @@ final class TypeParser
throw new TypeParseTreeException('No generic params provided for type');
}
if ($generic_type_value === 'array' || $generic_type_value === 'associative-array') {
if ($generic_type_value === 'array'
|| $generic_type_value === 'associative-array'
|| $generic_type_value === 'non-empty-array'
) {
if ($generic_type_value !== 'non-empty-array') {
$generic_type_value = 'array';
}
if ($generic_params[0]->isMixed()) {
$generic_params[0] = Type::getArrayKey($from_docblock);
}
if (count($generic_params) !== 2) {
throw new TypeParseTreeException('Too many template parameters for array');
throw new TypeParseTreeException('Too many template parameters for '.$generic_type_value);
}
if ($type_aliases !== []) {
$intersection_types = self::resolveTypeAliases(
$codebase,
$generic_params[0]->getAtomicTypes(),
);
if ($intersection_types !== []) {
$generic_params[0] = $generic_params[0]->setTypes($intersection_types);
}
}
foreach ($generic_params[0]->getAtomicTypes() as $key => $atomic_type) {
@ -671,6 +689,7 @@ final class TypeParser
|| $atomic_type instanceof TNever
|| $atomic_type instanceof TTemplateParam
|| $atomic_type instanceof TValueOf
|| !$from_docblock
) {
continue;
}
@ -690,7 +709,10 @@ final class TypeParser
throw new TypeParseTreeException('Invalid array key type ' . $atomic_type->getKey());
}
return new TArray($generic_params, $from_docblock);
return $generic_type_value === 'array'
? new TArray($generic_params, $from_docblock)
: new TNonEmptyArray($generic_params, null, null, 'non-empty-array', $from_docblock)
;
}
if ($generic_type_value === 'arraylike-object') {
@ -709,58 +731,6 @@ final class TypeParser
);
}
if ($generic_type_value === 'non-empty-array') {
if ($generic_params[0]->isMixed()) {
$generic_params[0] = Type::getArrayKey($from_docblock);
}
if (count($generic_params) !== 2) {
throw new TypeParseTreeException('Too many template parameters for non-empty-array');
}
foreach ($generic_params[0]->getAtomicTypes() as $key => $atomic_type) {
// PHP 8 values with whitespace after number are counted as numeric
// and filter_var treats them as such too
if ($atomic_type instanceof TLiteralString
&& trim($atomic_type->value) === $atomic_type->value
&& ($string_to_int = filter_var($atomic_type->value, FILTER_VALIDATE_INT)) !== false
) {
$builder = $generic_params[0]->getBuilder();
$builder->removeType($key);
$generic_params[0] = $builder->addType(new TLiteralInt($string_to_int, $from_docblock))->freeze();
continue;
}
if ($atomic_type instanceof TInt
|| $atomic_type instanceof TString
|| $atomic_type instanceof TArrayKey
|| $atomic_type instanceof TClassConstant // @todo resolve and check types
|| $atomic_type instanceof TMixed
|| $atomic_type instanceof TNever
|| $atomic_type instanceof TTemplateParam
|| $atomic_type instanceof TValueOf
) {
continue;
}
if ($codebase->register_stub_files || $codebase->register_autoload_files) {
$builder = $generic_params[0]->getBuilder();
$builder->removeType($key);
if (count($generic_params[0]->getAtomicTypes()) <= 1) {
$builder = $builder->addType(new TArrayKey($from_docblock));
}
$generic_params[0] = $builder->freeze();
continue;
}
throw new TypeParseTreeException('Invalid array key type ' . $atomic_type->getKey());
}
return new TNonEmptyArray($generic_params, null, null, 'non-empty-array', $from_docblock);
}
if ($generic_type_value === 'iterable') {
if (count($generic_params) > 2) {
throw new TypeParseTreeException('Too many template parameters for iterable');

View File

@ -1348,6 +1348,20 @@ class AnnotationTest extends TestCase
}
EOT,
],
'validArrayKeyAlias' => [
'code' => '<?php
/**
* @psalm-type ArrayKeyType array-key
*/
class Bar {}
/**
* @psalm-import-type ArrayKeyType from Bar
* @psalm-type UsesArrayKeyType array<ArrayKeyType, bool>
*/
class Foo {}',
'assertions' => [],
],
];
}