Skip to content

Commit

Permalink
More fixes
Browse files Browse the repository at this point in the history
  • Loading branch information
danog committed Mar 30, 2024
1 parent f9250d5 commit a1b24db
Show file tree
Hide file tree
Showing 4 changed files with 174 additions and 169 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -204,100 +204,101 @@ public static function handleAddition(
if (($array_arg_type = $statements_analyzer->node_data->getType($array_arg))
&& $array_arg_type->hasArray()
) {
$array_type = $array_arg_type->getArray();
$array_types = $array_arg_type->getArrays();
$by_ref_type = new Union([$array_types]);

$objectlike_list = null;
foreach ($array_types as $array_type) {
$objectlike_list = null;

if ($array_type instanceof TKeyedArray) {
if ($array_type->is_list) {
$objectlike_list = $array_type;
if ($array_type instanceof TKeyedArray) {
if ($array_type->is_list) {
$objectlike_list = $array_type;
}
}
}

$by_ref_type = new Union([$array_type]);

foreach ($args as $argument_offset => $arg) {
if ($argument_offset === 0) {
continue;
}
foreach ($args as $argument_offset => $arg) {
if ($argument_offset === 0) {
continue;
}

if (ExpressionAnalyzer::analyze(
$statements_analyzer,
$arg->value,
$context,
) === false) {
return false;
}
if (ExpressionAnalyzer::analyze(
$statements_analyzer,
$arg->value,
$context,
) === false) {
return false;
}

if ($method_id === 'array_unshift' && $nb_args === 2 && !$unpacked_args) {
$new_offset_type = Type::getInt(false, 0);
} else {
$new_offset_type = Type::getInt();
}
if ($method_id === 'array_unshift' && $nb_args === 2 && !$unpacked_args) {
$new_offset_type = Type::getInt(false, 0);
} else {
$new_offset_type = Type::getInt();
}

if (!($arg_value_type = $statements_analyzer->node_data->getType($arg->value))
if (!($arg_value_type = $statements_analyzer->node_data->getType($arg->value))
|| $arg_value_type->hasMixed()
) {
$by_ref_type = Type::combineUnionTypes(
$by_ref_type,
new Union([new TArray([$new_offset_type, Type::getMixed()])]),
);
} elseif ($arg->unpack) {
$arg_value_type = $arg_value_type->getBuilder();

foreach ($arg_value_type->getAtomicTypes() as $arg_value_atomic_type) {
if ($arg_value_atomic_type instanceof TKeyedArray) {
$was_list = $arg_value_atomic_type->is_list;

$arg_value_atomic_type = $arg_value_atomic_type->getGenericArrayType();

if ($was_list) {
if ($arg_value_atomic_type instanceof TNonEmptyArray) {
$arg_value_atomic_type = Type::getNonEmptyListAtomic(
$arg_value_atomic_type->type_params[1],
);
} else {
$arg_value_atomic_type = Type::getListAtomic(
$arg_value_atomic_type->type_params[1],
);
) {
$by_ref_type = Type::combineUnionTypes(
$by_ref_type,
new Union([new TArray([$new_offset_type, Type::getMixed()])]),
);
} elseif ($arg->unpack) {
$arg_value_type = $arg_value_type->getBuilder();

foreach ($arg_value_type->getAtomicTypes() as $arg_value_atomic_type) {
if ($arg_value_atomic_type instanceof TKeyedArray) {
$was_list = $arg_value_atomic_type->is_list;

$arg_value_atomic_type = $arg_value_atomic_type->getGenericArrayType();

if ($was_list) {
if ($arg_value_atomic_type instanceof TNonEmptyArray) {
$arg_value_atomic_type = Type::getNonEmptyListAtomic(
$arg_value_atomic_type->type_params[1],
);
} else {
$arg_value_atomic_type = Type::getListAtomic(
$arg_value_atomic_type->type_params[1],
);
}
}
}

$arg_value_type->addType($arg_value_atomic_type);
$arg_value_type->addType($arg_value_atomic_type);
}
}
}
$arg_value_type = $arg_value_type->freeze();
$arg_value_type = $arg_value_type->freeze();

$by_ref_type = Type::combineUnionTypes(
$by_ref_type,
$arg_value_type,
);
} else {
if ($objectlike_list) {
$properties = $objectlike_list->properties;
array_unshift($properties, $arg_value_type);

$by_ref_type = new Union([$objectlike_list->setProperties($properties)]);
} elseif ($array_type instanceof TArray && $array_type->isEmpty()) {
$by_ref_type = new Union([new TKeyedArray([
$arg_value_type,
], null, null, true)]);
} else {
$by_ref_type = Type::combineUnionTypes(
$by_ref_type,
new Union(
[
$arg_value_type,
);
} else {
if ($objectlike_list) {
$properties = $objectlike_list->properties;
array_unshift($properties, $arg_value_type);

$by_ref_type = new Union([$objectlike_list->setProperties($properties)]);
} elseif ($array_type instanceof TArray && $array_type->isEmpty()) {
$by_ref_type = new Union([new TKeyedArray([
$arg_value_type,
], null, null, true)]);
} else {
$by_ref_type = Type::combineUnionTypes(
$by_ref_type,
new Union(
[
new TNonEmptyArray(
[
$new_offset_type,
$arg_value_type,
],
),
],
),
null,
true,
);
],
),
null,
true,
);
}
}
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,6 @@
use Psalm\Storage\FunctionLikeStorage;
use Psalm\Type;
use Psalm\Type\Atomic\ArrayInterface;
use Psalm\Type\Atomic\TArray;
use Psalm\Type\Atomic\TCallable;
use Psalm\Type\Atomic\TCallableKeyedArray;
use Psalm\Type\Atomic\TClassString;
Expand Down Expand Up @@ -429,14 +428,7 @@ private static function getReturnTypeFromCallMapWithArgs(

if ($first_arg_type = $statements_analyzer->node_data->getType($first_arg)) {
if ($first_arg_type->hasArray()) {
$array_type = $first_arg_type->getArray();
if ($array_type instanceof TKeyedArray) {
return $array_type->getGenericValueType();
}

if ($array_type instanceof TArray) {
return $array_type->type_params[1];
}
return $first_arg_type->getArrayValueType($codebase);
} elseif ($first_arg_type->hasScalarType()
&& ($second_arg = ($call_args[1]->value ?? null))
&& ($second_arg_type = $statements_analyzer->node_data->getType($second_arg))
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -47,85 +47,99 @@ public static function getFunctionReturnType(FunctionReturnTypeProviderEvent $ev
return null;
}

$keys = $keys_type->getArray();
if ($keys instanceof TArray && $keys->isEmptyArray()) {
$keys = [];
} elseif (!$keys instanceof TKeyedArray || $keys->fallback_params) {
return null;
} else {
$keys = $keys->properties;
}

if (!$values_type = $statements_source->node_data->getType($call_args[1]->value)) {
return null;
}
if (!$values_type->isArray()) {
return null;
}

$values = $values_type->getArray();
if ($values instanceof TArray && $values->isEmptyArray()) {
$values = [];
} elseif (!$values instanceof TKeyedArray || $values->fallback_params) {
return null;
} else {
$values = $values->properties;
}


$keys_array = [];
$is_list = true;
$prev_key = -1;
foreach ($keys as $key) {
if ($key->possibly_undefined) {
return null;
}
if ($key->isSingleIntLiteral()) {
$key = $key->getSingleIntLiteral()->value;
$keys_array []= $key;
if ($is_list && $key-1 !== $prev_key) {
$is_list = false;
}
$prev_key = $key;
} elseif ($key->isSingleStringLiteral()) {
$keys_array []= $key->getSingleStringLiteral()->value;
$is_list = false;
$has_fallback = false;
$result = [];
foreach ($values_type->getArrays() as $values) {
if ($values instanceof TArray && $values->isEmptyArray()) {
$values = [];
} elseif (!$values instanceof TKeyedArray || $values->fallback_params) {
$has_fallback = true;
continue;
} else {
return null;
$values = $values->properties;
foreach ($values as $value) {
if ($value->possibly_undefined) {
$has_fallback = true;
continue;
}
}
}
}

foreach ($values as $value) {
if ($value->possibly_undefined) {
return null;
}
}
foreach ($keys_type->getArrays() as $keys) {
$keys_array = [];

if ($keys instanceof TArray && $keys->isEmptyArray()) {
$keys = [];
} elseif (!$keys instanceof TKeyedArray || $keys->fallback_params) {
$has_fallback = true;
continue;
} else {
$keys = $keys->properties;
$is_list = true;
$prev_key = -1;

foreach ($keys as $key) {
if ($key->possibly_undefined) {
$has_fallback = true;
continue;
}
if ($key->isSingleIntLiteral()) {
$key = $key->getSingleIntLiteral()->value;
$keys_array []= $key;
if ($is_list && $key-1 !== $prev_key) {
$is_list = false;
}
$prev_key = $key;
} elseif ($key->isSingleStringLiteral()) {
$keys_array []= $key->getSingleStringLiteral()->value;
$is_list = false;
} else {
$has_fallback = true;
continue;
}
}
}

if (count($keys_array) !== count($values)) {
IssueBuffer::maybeAdd(
new InvalidArgument(
'The keys array ' . $keys_type->getId() . ' must have exactly the same '
. 'number of elements as the values array '
if (count($keys_array) !== count($values)) {
IssueBuffer::maybeAdd(
new InvalidArgument(
'The keys array ' . $keys_type->getId() . ' must have exactly the same '
. 'number of elements as the values array '
. $values_type->getId(),
$event->getCodeLocation(),
'array_combine',
),
$statements_source->getSuppressedIssues(),
);
return $statements_source->getCodebase()->analysis_php_version_id >= 8_00_00
? Type::getNever()
: Type::getFalse();
}
$event->getCodeLocation(),
'array_combine',
),
$statements_source->getSuppressedIssues(),
);
return $statements_source->getCodebase()->analysis_php_version_id >= 8_00_00
? Type::getNever()
: Type::getFalse();
}

$temp = array_combine(
$keys_array,
$values,
);

$result = array_combine(
$keys_array,
$values,
);
if ($temp) {
$result []= Type::getEmptyArrayAtomic();
} else {
$result []= new TKeyedArray($result, null, null, $is_list);
}
}
}

if (!$result) {
return Type::getEmptyArray();
if ($has_fallback) {
$result []= new TArray([Type::getArrayKey(), Type::getMixed()]);
}

return new Union([new TKeyedArray($result, null, null, $is_list)]);
return new Union($result);
}
}

0 comments on commit a1b24db

Please sign in to comment.