mirror of
https://github.com/danog/psalm.git
synced 2025-01-21 21:31:13 +01:00
Fixup
This commit is contained in:
parent
147129345e
commit
17bf9a45a6
@ -46,6 +46,8 @@ use Psalm\Type\Atomic\TFalse;
|
||||
use Psalm\Type\Atomic\TInt;
|
||||
use Psalm\Type\Atomic\TKeyedArray;
|
||||
use Psalm\Type\Atomic\TList;
|
||||
use Psalm\Type\Atomic\TLiteralInt;
|
||||
use Psalm\Type\Atomic\TLiteralString;
|
||||
use Psalm\Type\Atomic\TMixed;
|
||||
use Psalm\Type\Atomic\TNamedObject;
|
||||
use Psalm\Type\Atomic\TNever;
|
||||
@ -1108,88 +1110,103 @@ class Reconciler
|
||||
throw new UnexpectedValueException('Not expecting null array key');
|
||||
}
|
||||
|
||||
$array_key_offsets = [];
|
||||
if ($array_key[0] === '$') {
|
||||
return;
|
||||
if (!isset($existing_types[$array_key])) {
|
||||
return;
|
||||
}
|
||||
$t = $existing_types[$array_key];
|
||||
foreach ($t->getAtomicTypes() as $lit) {
|
||||
if ($lit instanceof TLiteralInt || $lit instanceof TLiteralString) {
|
||||
$array_key_offsets []= $lit->value;
|
||||
continue;
|
||||
}
|
||||
return;
|
||||
}
|
||||
} else {
|
||||
$array_key_offsets []= $array_key[0] === '\'' || $array_key[0] === '"' ? substr($array_key, 1, -1) : $array_key;
|
||||
}
|
||||
|
||||
$array_key_offset = $array_key[0] === '\'' || $array_key[0] === '"' ? substr($array_key, 1, -1) : $array_key;
|
||||
|
||||
$base_key = implode($key_parts);
|
||||
|
||||
if (isset($existing_types[$base_key]) && $array_key_offset !== false) {
|
||||
foreach ($existing_types[$base_key]->getAtomicTypes() as $base_atomic_type) {
|
||||
if ($base_atomic_type instanceof TList) {
|
||||
$base_atomic_type = $base_atomic_type->getKeyedArray();
|
||||
}
|
||||
if ($base_atomic_type instanceof TKeyedArray
|
||||
$result_type = $result_type->setPossiblyUndefined(count($array_key_offsets) > 1);
|
||||
|
||||
foreach ($array_key_offsets as $array_key_offset) {
|
||||
if (isset($existing_types[$base_key]) && $array_key_offset !== false) {
|
||||
foreach ($existing_types[$base_key]->getAtomicTypes() as $base_atomic_type) {
|
||||
if ($base_atomic_type instanceof TList) {
|
||||
$base_atomic_type = $base_atomic_type->getKeyedArray();
|
||||
}
|
||||
if ($base_atomic_type instanceof TKeyedArray
|
||||
|| ($base_atomic_type instanceof TArray
|
||||
&& !$base_atomic_type->isEmptyArray())
|
||||
|| $base_atomic_type instanceof TClassStringMap
|
||||
) {
|
||||
$new_base_type = $existing_types[$base_key];
|
||||
) {
|
||||
$new_base_type = $existing_types[$base_key];
|
||||
|
||||
if ($base_atomic_type instanceof TArray) {
|
||||
$fallback_key_type = $base_atomic_type->type_params[0];
|
||||
$fallback_value_type = $base_atomic_type->type_params[1];
|
||||
if ($base_atomic_type instanceof TArray) {
|
||||
$fallback_key_type = $base_atomic_type->type_params[0];
|
||||
$fallback_value_type = $base_atomic_type->type_params[1];
|
||||
|
||||
$base_atomic_type = new TKeyedArray(
|
||||
[
|
||||
$base_atomic_type = new TKeyedArray(
|
||||
[
|
||||
$array_key_offset => $result_type,
|
||||
],
|
||||
null,
|
||||
$fallback_key_type->isNever() ? null : [$fallback_key_type, $fallback_value_type],
|
||||
);
|
||||
} elseif ($base_atomic_type instanceof TClassStringMap) {
|
||||
// do nothing
|
||||
} else {
|
||||
$properties = $base_atomic_type->properties;
|
||||
$properties[$array_key_offset] = $result_type;
|
||||
if ($base_atomic_type->is_list
|
||||
],
|
||||
null,
|
||||
$fallback_key_type->isNever() ? null : [$fallback_key_type, $fallback_value_type],
|
||||
);
|
||||
} elseif ($base_atomic_type instanceof TClassStringMap) {
|
||||
// do nothing
|
||||
} else {
|
||||
$properties = $base_atomic_type->properties;
|
||||
$properties[$array_key_offset] = $result_type;
|
||||
if ($base_atomic_type->is_list
|
||||
&& (!is_numeric($array_key_offset)
|
||||
|| ($array_key_offset
|
||||
&& !isset($properties[$array_key_offset-1])
|
||||
)
|
||||
)
|
||||
) {
|
||||
if ($base_atomic_type->fallback_params && is_numeric($array_key_offset)) {
|
||||
$fallback = $base_atomic_type->fallback_params[1]->setPossiblyUndefined(
|
||||
$result_type->isNever(),
|
||||
);
|
||||
for ($x = 0; $x < $array_key_offset; $x++) {
|
||||
$properties[$x] ??= $fallback;
|
||||
) {
|
||||
if ($base_atomic_type->fallback_params && is_numeric($array_key_offset)) {
|
||||
$fallback = $base_atomic_type->fallback_params[1]->setPossiblyUndefined(
|
||||
$result_type->isNever(),
|
||||
);
|
||||
for ($x = 0; $x < $array_key_offset; $x++) {
|
||||
$properties[$x] ??= $fallback;
|
||||
}
|
||||
ksort($properties);
|
||||
$base_atomic_type = $base_atomic_type->setProperties($properties);
|
||||
} else {
|
||||
// This should actually be a paradox
|
||||
$base_atomic_type = new TKeyedArray(
|
||||
$properties,
|
||||
null,
|
||||
$base_atomic_type->fallback_params,
|
||||
false,
|
||||
$base_atomic_type->from_docblock,
|
||||
);
|
||||
}
|
||||
ksort($properties);
|
||||
$base_atomic_type = $base_atomic_type->setProperties($properties);
|
||||
} else {
|
||||
// This should actually be a paradox
|
||||
$base_atomic_type = new TKeyedArray(
|
||||
$properties,
|
||||
null,
|
||||
$base_atomic_type->fallback_params,
|
||||
false,
|
||||
$base_atomic_type->from_docblock,
|
||||
);
|
||||
$base_atomic_type = $base_atomic_type->setProperties($properties);
|
||||
}
|
||||
} else {
|
||||
$base_atomic_type = $base_atomic_type->setProperties($properties);
|
||||
}
|
||||
|
||||
$new_base_type = $new_base_type->getBuilder()->addType($base_atomic_type)->freeze();
|
||||
|
||||
$changed_var_ids[$base_key . '[' . $array_key . ']'] = true;
|
||||
|
||||
if ($key_parts[count($key_parts) - 1] === ']') {
|
||||
self::adjustTKeyedArrayType(
|
||||
$key_parts,
|
||||
$existing_types,
|
||||
$changed_var_ids,
|
||||
$new_base_type,
|
||||
);
|
||||
}
|
||||
|
||||
$existing_types[$base_key] = $new_base_type;
|
||||
break;
|
||||
}
|
||||
|
||||
$new_base_type = $new_base_type->getBuilder()->addType($base_atomic_type)->freeze();
|
||||
|
||||
$changed_var_ids[$base_key . '[' . $array_key . ']'] = true;
|
||||
|
||||
if ($key_parts[count($key_parts) - 1] === ']') {
|
||||
self::adjustTKeyedArrayType(
|
||||
$key_parts,
|
||||
$existing_types,
|
||||
$changed_var_ids,
|
||||
$new_base_type,
|
||||
);
|
||||
}
|
||||
|
||||
$existing_types[$base_key] = $new_base_type;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -1027,7 +1027,9 @@ class ForeachTest extends TestCase
|
||||
$arr = [];
|
||||
|
||||
foreach ([1, 2, 3] as $i) {
|
||||
$arr[$i]["a"] ??= 0;
|
||||
if (!isset($arr[$i]["a"])) {
|
||||
$arr[$i]["a"] = 0;
|
||||
}
|
||||
|
||||
$arr[$i]["a"] += 5;
|
||||
}
|
||||
|
@ -54,7 +54,36 @@ class IssetTest extends TestCase
|
||||
$arr[$i] = 1;
|
||||
}
|
||||
return $arr;
|
||||
}'
|
||||
}',
|
||||
],
|
||||
'issetWithArrayAssignment2' => [
|
||||
'code'=> '<?php
|
||||
|
||||
/**
|
||||
* @param array{0?: 0, 1?: 0} $arr
|
||||
* @param 0|1 $i
|
||||
* @return array{0?: 0|1, 1?: 0|1}
|
||||
*/
|
||||
function t2(array $arr, int $i): array {
|
||||
if (!isset($arr[$i])) {
|
||||
$arr[$i] = 1;
|
||||
}
|
||||
return $arr;
|
||||
}',
|
||||
],
|
||||
'issetWithArrayAssignmentSubVar' => [
|
||||
'code'=> '<?php
|
||||
|
||||
/**
|
||||
* @param array{0?: 0, v: 0} $arr
|
||||
* @return array{0: 0|1, v: 0}
|
||||
*/
|
||||
function t2(array $arr): array {
|
||||
if (!isset($arr[$arr["v"]])) {
|
||||
$arr[$arr["v"]] = 1;
|
||||
}
|
||||
return $arr;
|
||||
}',
|
||||
],
|
||||
'isset' => [
|
||||
'code' => '<?php
|
||||
|
Loading…
x
Reference in New Issue
Block a user