Skip to content
Permalink
Browse files

Improve reconciliation of arrays with constant offsets

  • Loading branch information
muglug committed Dec 13, 2019
1 parent 6d02aa8 commit 2469f04715bf640bb8e90b9b30fe61c187fe813d
@@ -503,35 +503,6 @@ public function remove($remove_var_id)
}
}

/**
* This removes all clauses that are invalidated because
* all possibilities are overwritten by changed var ids
*
* @param Clause[] $clauses
* @param array<string, bool> $changed_var_ids
*
* @return list<Clause>
*/
public static function removeOverwrittenClauses(array $clauses, array $changed_var_ids)
{
$included_clauses = [];

foreach ($clauses as $c) {
if ($c->wedge) {
$included_clauses[] = $c;
continue;
}

if (!\array_diff_key($c->possibilities, $changed_var_ids)) {
continue;
}

$included_clauses[] = $c;
}

return $included_clauses;
}

/**
* @param Clause[] $clauses
* @param array<string, bool> $changed_var_ids
@@ -142,13 +142,6 @@ function (Clause $c) use ($mixed_var_ids) {

$entry_clauses = $context->clauses;

if ($if_scope->if_cond_changed_var_ids) {
$entry_clauses = Context::removeOverwrittenClauses(
$entry_clauses,
$if_scope->if_cond_changed_var_ids
);
}

// this will see whether any of the clauses in set A conflict with the clauses in set B
AlgebraAnalyzer::checkForParadox(
$context->clauses,
@@ -1085,13 +1078,6 @@ function (Clause $c) use ($cond_assigned_var_ids) {
$cond_assigned_var_ids
);

if ($if_scope->if_cond_changed_var_ids) {
$entry_clauses = Context::removeOverwrittenClauses(
$entry_clauses,
$if_scope->if_cond_changed_var_ids
);
}

$elseif_context_clauses = array_merge($entry_clauses, $elseif_clauses);

if ($elseif_context->reconciled_expression_clauses) {
@@ -2,6 +2,7 @@
namespace Psalm\Internal\Analyzer\Statements\Expression\Assignment;

use PhpParser;
use Psalm\Internal\Analyzer\ClassLikeAnalyzer;
use Psalm\Internal\Analyzer\Statements\Expression\Fetch\ArrayFetchAnalyzer;
use Psalm\Internal\Analyzer\Statements\ExpressionAnalyzer;
use Psalm\Internal\Analyzer\StatementsAnalyzer;
@@ -223,6 +224,15 @@ public static function updateArrayType(
if ($object_id) {
$var_id_additions[] = '[' . $object_id . '->' . $child_stmt->dim->name->name . ']';
}
} elseif ($child_stmt->dim instanceof PhpParser\Node\Expr\ClassConstFetch
&& $child_stmt->dim->name instanceof PhpParser\Node\Identifier
&& $child_stmt->dim->class instanceof PhpParser\Node\Name
) {
$object_name = ClassLikeAnalyzer::getFQCLNFromNameObject(
$child_stmt->dim->class,
$statements_analyzer->getAliases()
);
$var_id_additions[] = '[' . $object_name . '::' . $child_stmt->dim->name->name . ']';
} else {
$var_id_additions[] = '[' . $child_stmt_dim_type . ']';
$full_var_id = false;
@@ -105,6 +105,11 @@ public static function reconcileKeyedTypes(

$base_key = array_shift($key_parts);

if ($base_key[0] !== '$' && count($key_parts) > 2 && $key_parts[0] === '::$') {
$base_key .= array_shift($key_parts);
$base_key .= array_shift($key_parts);
}

if (!isset($existing_types[$base_key]) || $existing_types[$base_key]->isNullable()) {
if (!isset($new_types[$base_key])) {
$new_types[$base_key] = [['=isset']];
@@ -465,6 +470,11 @@ private static function getValueForKey(

$base_key = array_shift($key_parts);

if ($base_key[0] !== '$' && count($key_parts) > 2 && $key_parts[0] === '::$') {
$base_key .= array_shift($key_parts);
$base_key .= array_shift($key_parts);
}

if (!isset($existing_keys[$base_key])) {
if (strpos($base_key, '::')) {
list($fq_class_name, $const_name) = explode('::', $base_key);
@@ -2238,19 +2238,52 @@ function foo() : void {
echo isset($a);
}'
],
'assertOnStaticClassKey' => [
'assertOnVarStaticClassKey' => [
'<?php
abstract class Obj {
/**
* @param array<class-string, array<string, int>> $arr
* @return array<string, int>
*/
public static function getArr(array $arr) : array {
if (!isset($arr[static::class])) {
$arr[static::class] = ["hello" => 5];
}
return $arr[static::class];
}
}'
],
'assertOnVarVar' => [
'<?php
abstract class Obj {
/**
* @param array<class-string, array<string, int>> $arr
* @return array<string, int>
*/
function getArr(array $arr, string $s) : array {
if (!isset($arr[$s])) {
$arr[$s] = ["hello" => 5];
}
return $arr[$s];
}
}'
],
'assertOnPropertyStaticClassKey' => [
'<?php
abstract class Obj {
/** @var array<class-string, array<string, int>> */
private static $arr = [];
/** @return array<string, int> */
public static function getArr() : array {
if (!isset(self::$arr[static::class])) {
self::$arr[static::class] = ["hello" => 5];
$arr = self::$arr;
if (!isset($arr[static::class])) {
$arr[static::class] = ["hello" => 5];
}
return self::$arr[static::class];
return $arr[static::class];
}
}'
],
@@ -2287,6 +2320,38 @@ function foo(array $p, int $id) : void {
}
}'
],
'reconcileEmptinessBetter' => [
'<?php
/**
* @param string|array $valuePath
*/
function combine($valuePath) : void {
if (!empty($valuePath) && is_array($valuePath)) {
} elseif (!empty($valuePath)) {
echo $valuePath;
}
}',
],
'issetAssertionOnStaticProperty' => [
'<?php
class C {
protected static array $cache = [];
/**
* @psalm-suppress MixedArrayAccess
* @psalm-suppress MixedReturnStatement
* @psalm-suppress MixedInferredReturnType
*/
public static function get(string $k1, string $k2) : ?string {
if (!isset(static::$cache[$k1][$k2])) {
return null;
}
return static::$cache[$k1][$k2];
}
}'
],
];
}

0 comments on commit 2469f04

Please sign in to comment.
You can’t perform that action at this time.