Skip to content
Permalink
Browse files

Fix #2409 - use more robust assertion parsing

  • Loading branch information
muglug committed Dec 31, 2019
1 parent 5bd9b98 commit 16b8edd583c2bc1fd5e50ae0a2e399a1090c7a93
@@ -2659,37 +2659,42 @@ private function getAssertionParts(
return null;
}

$assertion_type_parts = explode('|', $assertion_type);

$class_template_types = !$stmt instanceof PhpParser\Node\Stmt\ClassMethod || !$stmt->isStatic()
? $this->class_template_types
: [];

foreach ($assertion_type_parts as $i => $assertion_type_part) {
if ($assertion_type_part !== 'falsy'
&& $assertion_type_part !== 'array'
&& $assertion_type_part !== 'list'
&& $assertion_type_part !== 'iterable'
) {
$namespaced_type = Type::parseTokens(
Type::fixUpLocalType(
$assertion_type_part,
$this->aliases,
$this->function_template_types + $class_template_types,
$this->type_aliases,
null
)
);
$namespaced_type = Type::parseTokens(
Type::fixUpLocalType(
$assertion_type,
$this->aliases,
$this->function_template_types + $class_template_types,
$this->type_aliases,
null,
null,
true
)
);

$namespaced_type->queueClassLikesForScanning(
$this->codebase,
$this->file_storage,
$this->function_template_types + $class_template_types
);
$namespaced_type->queueClassLikesForScanning(
$this->codebase,
$this->file_storage,
$this->function_template_types + $class_template_types
);

$assertion_type_parts[$i] = $prefix . $namespaced_type->getId();
foreach ($namespaced_type->getTypes() as $namespaced_type_part) {
if ($namespaced_type_part instanceof Type\Atomic\TAssertionFalsy
|| ($namespaced_type_part instanceof Type\Atomic\TList
&& $namespaced_type_part->type_param->isMixed())
|| ($namespaced_type_part instanceof Type\Atomic\TArray
&& $namespaced_type_part->type_params[0]->isArrayKey()
&& $namespaced_type_part->type_params[1]->isMixed())
|| ($namespaced_type_part instanceof Type\Atomic\TIterable
&& $namespaced_type_part->type_params[0]->isMixed()
&& $namespaced_type_part->type_params[1]->isMixed())
) {
$assertion_type_parts[] = $prefix . $namespaced_type_part->getAssertionString();
} else {
$assertion_type_parts[$i] = $prefix . $assertion_type_part;
$assertion_type_parts[] = $prefix . $namespaced_type_part->getId();
}
}

@@ -1030,7 +1030,8 @@ public static function fixUpLocalType(
array $template_type_map = null,
array $type_aliases = null,
?string $self_fqcln = null,
?string $parent_fqcln = null
?string $parent_fqcln = null,
bool $allow_assertions = false
) {
$type_tokens = self::tokenize($string_type);

@@ -1122,6 +1123,11 @@ public static function fixUpLocalType(
continue;
}

if ($allow_assertions && $string_type_token[0] === 'falsy') {
$type_tokens[$i][0] = 'false-y';
continue;
}

if (isset($type_aliases[$string_type_token[0]])) {
$replacement_tokens = $type_aliases[$string_type_token[0]];

@@ -26,6 +26,7 @@
use Psalm\Type\Atomic\ObjectLike;
use Psalm\Type\Atomic\TArray;
use Psalm\Type\Atomic\TArrayKey;
use Psalm\Type\Atomic\TAssertionFalsy;
use Psalm\Type\Atomic\TBool;
use Psalm\Type\Atomic\TCallable;
use Psalm\Type\Atomic\TCallableArray;
@@ -217,6 +218,9 @@ public static function create(
case 'html-escaped-string':
return new THtmlEscapedString();

case 'false-y':
return new TAssertionFalsy();

case '$this':
return new TNamedObject('static');
}
@@ -0,0 +1,50 @@
<?php
namespace Psalm\Type\Atomic;

class TAssertionFalsy extends \Psalm\Type\Atomic
{
public function __toString()
{
return 'falsy';
}

/**
* @return string
*/
public function getKey()
{
return 'falsy';
}

/**
* @return string
*/
public function getAssertionString()
{
return 'falsy';
}

/**
* @param string|null $namespace
* @param array<string> $aliased_classes
* @param string|null $this_class
* @param int $php_major_version
* @param int $php_minor_version
*
* @return null|string
*/
public function toPhpString(
$namespace,
array $aliased_classes,
$this_class,
$php_major_version,
$php_minor_version
) {
return null;
}

public function canBeFullyExpressedInPhp()
{
return false;
}
}
@@ -44,6 +44,14 @@ public function getKey()
return 'iterable';
}

/**
* @return string
*/
public function getAssertionString()
{
return 'iterable';
}

public function getId()
{
$s = '';
@@ -209,7 +209,7 @@ public function equals(Atomic $other_type)
*/
public function getAssertionString()
{
return $this->getKey();
return 'list';
}

/**
@@ -822,6 +822,13 @@ function foo(A $a) : void {
echo count($a->getArray());
}'
],
'preventErrorWhenAssertingOnArrayUnion' => [
'<?php
/**
* @psalm-assert array<string,string|object> $data
*/
function validate(array $data): void {}'
],
];
}

0 comments on commit 16b8edd

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