1
0
mirror of https://github.com/danog/psalm.git synced 2024-11-26 12:24:49 +01:00

Fix int-mask-of expansion

This commit is contained in:
Matt Brown 2020-11-02 00:40:36 -05:00 committed by Daniil Gentili
parent b58782ae29
commit e3a352d287
Signed by: danog
GPG Key ID: 8C1BE3B34B230CA7
5 changed files with 88 additions and 5 deletions

View File

@ -290,8 +290,12 @@ class NonDivArithmeticOpAnalyzer
): ?Type\Union { ): ?Type\Union {
if ($left_type_part instanceof TLiteralInt if ($left_type_part instanceof TLiteralInt
&& $right_type_part instanceof TLiteralInt && $right_type_part instanceof TLiteralInt
&& ($left instanceof PhpParser\Node\Scalar || $left instanceof PhpParser\Node\Expr\ConstFetch) && ($left instanceof PhpParser\Node\Scalar
&& ($right instanceof PhpParser\Node\Scalar || $right instanceof PhpParser\Node\Expr\ConstFetch) || $left instanceof PhpParser\Node\Expr\ConstFetch
|| $left instanceof PhpParser\Node\Expr\ClassConstFetch)
&& ($right instanceof PhpParser\Node\Scalar
|| $right instanceof PhpParser\Node\Expr\ConstFetch
|| $right instanceof PhpParser\Node\Expr\ClassConstFetch)
) { ) {
// time for some arithmetic! // time for some arithmetic!

View File

@ -272,6 +272,12 @@ class ScalarTypeComparator
return true; return true;
} }
if (get_class($container_type_part) === TInt::class
&& $input_type_part instanceof TInt
) {
return true;
}
if ((get_class($input_type_part) === TInt::class && $container_type_part instanceof TLiteralInt) if ((get_class($input_type_part) === TInt::class && $container_type_part instanceof TLiteralInt)
|| (get_class($input_type_part) === TPositiveInt::class || (get_class($input_type_part) === TPositiveInt::class
&& $container_type_part instanceof TLiteralInt && $container_type_part instanceof TLiteralInt

View File

@ -379,7 +379,46 @@ class TypeExpander
$final $final
); );
if (\is_array($new_value_type) || !$new_value_type instanceof Type\Atomic\TLiteralInt) { if (\is_array($new_value_type)) {
$new_value_type = reset($new_value_type);
}
if (!$new_value_type instanceof Type\Atomic\TLiteralInt) {
return new Type\Atomic\TInt();
}
$potential_ints[] = $new_value_type->value;
}
return \Psalm\Internal\Type\TypeParser::getComputedIntsFromMask($potential_ints);
}
if ($return_type instanceof Type\Atomic\TIntMaskOf) {
if (!$evaluate_class_constants) {
return new Type\Atomic\TInt();
}
$value_type = $return_type->value;
$new_value_types = self::expandAtomic(
$codebase,
$value_type,
$self_class,
$static_class_type,
$parent_class,
$evaluate_class_constants,
$evaluate_conditional_types,
$final
);
if (!is_array($new_value_types)) {
return new Type\Atomic\TInt();
}
$potential_ints = [];
foreach ($new_value_types as $new_value_type) {
if (!$new_value_type instanceof Type\Atomic\TLiteralInt) {
return new Type\Atomic\TInt(); return new Type\Atomic\TInt();
} }

View File

@ -1143,6 +1143,40 @@ class AnnotationTest extends TestCase
/** @var DateTime $obj */ /** @var DateTime $obj */
echo $obj->format("Y");' echo $obj->format("Y");'
], ],
'intMaskWithClassConstants' => [
'<?php
class FileFlag {
public const OPEN = 1;
public const MODIFIED = 2;
public const NEW = 4;
}
/**
* @param int-mask<FileFlag::OPEN, FileFlag::MODIFIED, FileFlag::NEW> $flags
*/
function takesFlags(int $flags) : void {
echo $flags;
}
takesFlags(FileFlag::MODIFIED | FileFlag::NEW);'
],
'intMaskOfWithClassWildcard' => [
'<?php
class FileFlag {
public const OPEN = 1;
public const MODIFIED = 2;
public const NEW = 4;
}
/**
* @param int-mask-of<FileFlag::*> $flags
*/
function takesFlags(int $flags) : void {
echo $flags;
}
takesFlags(FileFlag::MODIFIED | FileFlag::NEW);'
],
]; ];
} }

View File

@ -49,8 +49,8 @@ class Php56Test extends TestCase
$c4 = (new C)->four;', $c4 = (new C)->four;',
'assertions' => [ 'assertions' => [
'$c1' => 'int', '$c1' => 'int',
'$c2' => 'positive-int', '$c2===' => 'int(2)',
'$c3' => 'positive-int', '$c3===' => 'int(3)',
'$c1_3rd' => 'float|int', '$c1_3rd' => 'float|int',
'$c_sentence' => 'string', '$c_sentence' => 'string',
'$cf' => 'int', '$cf' => 'int',