Skip to content

Commit

Permalink
Keep NeverType isExplicit-flag in InitializerExprTypeResolver
Browse files Browse the repository at this point in the history
  • Loading branch information
staabm committed Dec 15, 2022
1 parent 9417e86 commit 332f6b4
Show file tree
Hide file tree
Showing 2 changed files with 137 additions and 9 deletions.
30 changes: 21 additions & 9 deletions src/Reflection/InitializerExprTypeResolver.php
Expand Up @@ -498,7 +498,7 @@ public function getBitwiseAndType(Expr $left, Expr $right, callable $getTypeCall
$rightType = $getTypeCallback($right);

if ($leftType instanceof NeverType || $rightType instanceof NeverType) {
return new NeverType();
return $this->getNeverType($leftType, $rightType);
}

$leftTypes = TypeUtils::getConstantScalars($leftType);
Expand Down Expand Up @@ -565,7 +565,7 @@ public function getBitwiseOrType(Expr $left, Expr $right, callable $getTypeCallb
$rightType = $getTypeCallback($right);

if ($leftType instanceof NeverType || $rightType instanceof NeverType) {
return new NeverType();
return $this->getNeverType($leftType, $rightType);
}

$leftTypes = TypeUtils::getConstantScalars($leftType);
Expand Down Expand Up @@ -622,7 +622,7 @@ public function getBitwiseXorType(Expr $left, Expr $right, callable $getTypeCall
$rightType = $getTypeCallback($right);

if ($leftType instanceof NeverType || $rightType instanceof NeverType) {
return new NeverType();
return $this->getNeverType($leftType, $rightType);
}

$leftTypes = TypeUtils::getConstantScalars($leftType);
Expand Down Expand Up @@ -679,7 +679,7 @@ public function getSpaceshipType(Expr $left, Expr $right, callable $getTypeCallb
$callbackRightType = $getTypeCallback($right);

if ($callbackLeftType instanceof NeverType || $callbackRightType instanceof NeverType) {
return new NeverType();
return $this->getNeverType($callbackLeftType, $callbackRightType);
}

$leftTypes = TypeUtils::getConstantScalars($callbackLeftType);
Expand Down Expand Up @@ -772,7 +772,7 @@ public function getModType(Expr $left, Expr $right, callable $getTypeCallback):
$rightType = $getTypeCallback($right);

if ($leftType instanceof NeverType || $rightType instanceof NeverType) {
return new NeverType();
return $this->getNeverType($leftType, $rightType);
}

$leftTypes = TypeUtils::getConstantScalars($leftType);
Expand Down Expand Up @@ -873,7 +873,7 @@ public function getPlusType(Expr $left, Expr $right, callable $getTypeCallback):
$rightType = $getTypeCallback($right);

if ($leftType instanceof NeverType || $rightType instanceof NeverType) {
return new NeverType();
return $this->getNeverType($leftType, $rightType);
}

$leftTypes = TypeUtils::getConstantScalars($leftType);
Expand Down Expand Up @@ -1192,7 +1192,7 @@ public function getShiftLeftType(Expr $left, Expr $right, callable $getTypeCallb
$rightType = $getTypeCallback($right);

if ($leftType instanceof NeverType || $rightType instanceof NeverType) {
return new NeverType();
return $this->getNeverType($leftType, $rightType);
}

$leftTypes = TypeUtils::getConstantScalars($leftType);
Expand Down Expand Up @@ -1249,7 +1249,7 @@ public function getShiftRightType(Expr $left, Expr $right, callable $getTypeCall
$rightType = $getTypeCallback($right);

if ($leftType instanceof NeverType || $rightType instanceof NeverType) {
return new NeverType();
return $this->getNeverType($leftType, $rightType);
}

$leftTypes = TypeUtils::getConstantScalars($leftType);
Expand Down Expand Up @@ -1488,7 +1488,7 @@ private function resolveCommonMath(Expr\BinaryOp $expr, Type $leftType, Type $ri
return new ErrorType();
}
if ($leftNumberType instanceof NeverType || $rightNumberType instanceof NeverType) {
return new NeverType();
return $this->getNeverType($leftNumberType, $rightNumberType);
}

if (
Expand Down Expand Up @@ -1982,4 +1982,16 @@ private function getReflectionProvider(): ReflectionProvider
return $this->reflectionProviderProvider->getReflectionProvider();
}

private function getNeverType(Type $leftType, Type $rightType): Type
{
// make sure we don't lose the explicit flag in the process
if ($leftType instanceof NeverType && $leftType->isExplicit()) {
return $leftType;
}
if ($rightType instanceof NeverType && $rightType->isExplicit()) {
return $rightType;
}
return new NeverType();
}

}
116 changes: 116 additions & 0 deletions tests/PHPStan/Analyser/AnalyserIntegrationTest.php
Expand Up @@ -5,14 +5,20 @@
use Bug4288\MyClass;
use Bug4713\Service;
use ExtendingKnownClassWithCheck\Foo;
use PhpParser\Node\Expr;
use PhpParser\Node\Scalar\LNumber;
use PhpParser\Node\Scalar\String_;
use PHPStan\File\FileHelper;
use PHPStan\Reflection\InitializerExprContext;
use PHPStan\Reflection\InitializerExprTypeResolver;
use PHPStan\Reflection\ParametersAcceptorSelector;
use PHPStan\Reflection\SignatureMap\SignatureMapProvider;
use PHPStan\ShouldNotHappenException;
use PHPStan\Testing\PHPStanTestCase;
use PHPStan\Type\Constant\ConstantIntegerType;
use PHPStan\Type\Constant\ConstantStringType;
use PHPStan\Type\NeverType;
use PHPStan\Type\Type;
use function extension_loaded;
use function restore_error_handler;
use function sprintf;
Expand Down Expand Up @@ -1075,6 +1081,116 @@ public function testBug8503(): void
$this->assertNoErrors($errors);
}

/**
* @dataProvider dataExplicitNever
*
* @param class-string $resultClass
* @param callable(Expr): Type $callback
*/
public function testExplicitNever(Expr $left, Expr $right, callable $callback, string $resultClass, ?bool $resultIsExplicit = null): void
{
$initializerExprTypeResolver = self::getContainer()->getByType(InitializerExprTypeResolver::class);

$result = $initializerExprTypeResolver->getPlusType(
$left,
$right,
$callback,
);
$this->assertInstanceOf($resultClass, $result);

if ($result instanceof NeverType) {
if ($resultIsExplicit === null) {
throw new ShouldNotHappenException();
}
$this->assertSame($resultIsExplicit, $result->isExplicit());
}
}

public function dataExplicitNever(): iterable
{
yield [
new LNumber(1),
new String_('foo'),
static function (Expr $expr): Type {
if ($expr instanceof LNumber) {
return new ConstantIntegerType(1);
}
return new NeverType(true);
},
NeverType::class,
true,
];
yield [
new String_('foo'),
new LNumber(1),
static function (Expr $expr): Type {
if ($expr instanceof LNumber) {
return new ConstantIntegerType(1);
}
return new NeverType(true);
},
NeverType::class,
true,
];

yield [
new LNumber(1),
new String_('foo'),
static function (Expr $expr): Type {
if ($expr instanceof LNumber) {
return new ConstantIntegerType(1);
}
return new NeverType(false);
},
NeverType::class,
false,
];
yield [
new String_('foo'),
new LNumber(1),
static function (Expr $expr): Type {
if ($expr instanceof LNumber) {
return new ConstantIntegerType(1);
}
return new NeverType(false);
},
NeverType::class,
false,
];

yield [
new String_('foo'),
new LNumber(1),
static function (Expr $expr): Type {
if ($expr instanceof LNumber) {
return new NeverType(true);
}
return new NeverType(false);
},
NeverType::class,
true,
];
yield [
new LNumber(1),
new String_('foo'),
static function (Expr $expr): Type {
if ($expr instanceof LNumber) {
return new NeverType(true);
}
return new NeverType(false);
},
NeverType::class,
true,
];

yield [
new LNumber(1),
new LNumber(1),
static fn (Expr $expr): Type => new ConstantIntegerType(1),
ConstantIntegerType::class,
];
}

/**
* @param string[]|null $allAnalysedFiles
* @return Error[]
Expand Down

0 comments on commit 332f6b4

Please sign in to comment.