Skip to content

Commit

Permalink
Fix #4752 - add property base assertions too
Browse files Browse the repository at this point in the history
  • Loading branch information
muglug committed Dec 2, 2020
1 parent 496ce46 commit a2b20f0
Show file tree
Hide file tree
Showing 3 changed files with 47 additions and 7 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -230,7 +230,7 @@ function (Type\Union $_) use ($mapping_return_type): Type\Union {
}

/**
* @param-out array<string, array<array<string>>>|null $assertions
* @param-out array<string, array<array<int, string>>>|null $assertions
*/
private static function executeFakeCall(
\Psalm\Internal\Analyzer\StatementsAnalyzer $statements_analyzer,
Expand Down Expand Up @@ -309,9 +309,9 @@ private static function executeFakeCall(
}

/**
* @param non-empty-array<string> $mapping_function_ids
* @param non-empty-array<int, string> $mapping_function_ids
* @param list<PhpParser\Node\Arg> $array_args
* @param-out array<string, array<array<string>>>|null $assertions
* @param-out array<string, array<array<int, string>>>|null $assertions
*/
public static function getReturnTypeFromMappingIds(
\Psalm\Internal\Analyzer\StatementsAnalyzer $statements_source,
Expand Down
25 changes: 21 additions & 4 deletions src/Psalm/Type/Reconciler.php
Original file line number Diff line number Diff line change
Expand Up @@ -46,8 +46,8 @@ class Reconciler
/**
* Takes two arrays and consolidates them, removing null values from existing types where applicable
*
* @param array<string, array<int, array<int, string>>> $new_types
* @param array<string, array<int, array<int, string>>> $active_new_types - types we can complain about
* @param array<string, array<array<int, string>>> $new_types
* @param array<string, array<array<int, string>>> $active_new_types - types we can complain about
* @param array<string, Type\Union> $existing_types
* @param array<string, bool> $changed_var_ids
* @param array<string, bool> $referenced_var_ids
Expand Down Expand Up @@ -282,10 +282,23 @@ public static function reconcileKeyedTypes(
}

/**
* @param array<string, array<int, array<int, string>>> $new_types
* This generates a list of extra assertions for an assertion on a nested key.
*
* For example ['$a[0]->foo->bar' => 'isset']
*
* generates the assertions
*
* [
* '$a' => '=int-or-string-array-access',
* '$a[0]' => '=isset',
* '$a[0]->foo' => '=isset',
* '$a[0]->foo->bar' => 'isset' // original assertion
* ]
*
* @param array<string, array<array<int, string>>> $new_types
* @param array<string, Type\Union> $existing_types
*
* @return array<string, array<int, array<int, string>>>
* @return array<string, array<array<int, string>>>
*/
private static function addNestedAssertions(array $new_types, array $existing_types) : array
{
Expand Down Expand Up @@ -341,6 +354,10 @@ private static function addNestedAssertions(array $new_types, array $existing_ty
$property_name = array_shift($key_parts);
$new_base_key = $base_key . '->' . $property_name;

if (!isset($new_types[$base_key])) {
$new_types[$base_key] = [['=isset']];
}

$base_key = $new_base_key;
} else {
break;
Expand Down
23 changes: 23 additions & 0 deletions tests/ArrayAccessTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -216,6 +216,29 @@ public function testEnsureOffsetExistsAfterArrayPush() : void
$this->analyzeFile('somefile.php', new \Psalm\Context());
}

public function testEnsureOffsetExistsAfterNestedIsset(): void
{
\Psalm\Config::getInstance()->ensure_array_string_offsets_exist = true;

$this->addFile(
'somefile.php',
'<?php
class A {
public int $foo = 0;
}
/**
* @param array<string, A> $value
*/
function test(array $value): int
{
return isset($value["a"]->foo) ? $value["a"]->foo : 0;
}'
);

$this->analyzeFile('somefile.php', new \Psalm\Context());
}

public function testEnsureListOffsetExistsAfterCountValueInRange(): void
{
\Psalm\Config::getInstance()->ensure_array_int_offsets_exist = true;
Expand Down

0 comments on commit a2b20f0

Please sign in to comment.