diff --git a/src/Analyser/NodeScopeResolver.php b/src/Analyser/NodeScopeResolver.php index f6235d4bae..b29fb0745e 100644 --- a/src/Analyser/NodeScopeResolver.php +++ b/src/Analyser/NodeScopeResolver.php @@ -150,7 +150,6 @@ use PHPStan\Type\TypeUtils; use PHPStan\Type\TypeWithClassName; use PHPStan\Type\UnionType; -use PHPStan\Type\VoidType; use Throwable; use Traversable; use TypeError; @@ -1498,7 +1497,7 @@ private function getOverridingThrowPoints(Node\Stmt $statement, MutatingScope $s $throwsTag = $resolvedPhpDoc->getThrowsTag(); if ($throwsTag !== null) { $throwsType = $throwsTag->getType(); - if ($throwsType instanceof VoidType) { + if ($throwsType->isVoid()->yes()) { return []; } @@ -2820,7 +2819,7 @@ private function getFunctionThrowPoint( } if ($throwType !== null) { - if (!$throwType instanceof VoidType) { + if (!$throwType->isVoid()->yes()) { return ThrowPoint::createExplicit($scope, $throwType, $funcCall, true); } } elseif ($this->implicitThrows) { @@ -2878,7 +2877,7 @@ private function getMethodThrowPoint(MethodReflection $methodReflection, Paramet } if ($throwType !== null) { - if (!$throwType instanceof VoidType) { + if (!$throwType->isVoid()->yes()) { return ThrowPoint::createExplicit($scope, $throwType, $methodCall, true); } } elseif ($this->implicitThrows) { @@ -2915,7 +2914,7 @@ private function getConstructorThrowPoint(MethodReflection $constructorReflectio if ($constructorReflection->getThrowType() !== null) { $throwType = $constructorReflection->getThrowType(); - if (!$throwType instanceof VoidType) { + if (!$throwType->isVoid()->yes()) { return ThrowPoint::createExplicit($scope, $throwType, $new, true); } } elseif ($this->implicitThrows) { @@ -2947,7 +2946,7 @@ private function getStaticMethodThrowPoint(MethodReflection $methodReflection, P if ($methodReflection->getThrowType() !== null) { $throwType = $methodReflection->getThrowType(); - if (!$throwType instanceof VoidType) { + if (!$throwType->isVoid()->yes()) { return ThrowPoint::createExplicit($scope, $throwType, $methodCall, true); } } elseif ($this->implicitThrows) { diff --git a/src/Reflection/Native/NativeFunctionReflection.php b/src/Reflection/Native/NativeFunctionReflection.php index 106b9717a8..b2481b7411 100644 --- a/src/Reflection/Native/NativeFunctionReflection.php +++ b/src/Reflection/Native/NativeFunctionReflection.php @@ -7,7 +7,6 @@ use PHPStan\Reflection\ParametersAcceptorWithPhpDocs; use PHPStan\TrinaryLogic; use PHPStan\Type\Type; -use PHPStan\Type\VoidType; class NativeFunctionReflection implements FunctionReflection { @@ -89,7 +88,7 @@ public function hasSideEffects(): TrinaryLogic private function isVoid(): bool { foreach ($this->variants as $variant) { - if (!$variant->getReturnType() instanceof VoidType) { + if (!$variant->getReturnType()->isVoid()->yes()) { return false; } } diff --git a/src/Reflection/Native/NativeMethodReflection.php b/src/Reflection/Native/NativeMethodReflection.php index cfe14ff771..f61c89c41a 100644 --- a/src/Reflection/Native/NativeMethodReflection.php +++ b/src/Reflection/Native/NativeMethodReflection.php @@ -13,7 +13,6 @@ use PHPStan\TrinaryLogic; use PHPStan\Type\Type; use PHPStan\Type\TypehintHelper; -use PHPStan\Type\VoidType; use ReflectionException; use function strtolower; @@ -144,7 +143,7 @@ public function hasSideEffects(): TrinaryLogic private function isVoid(): bool { foreach ($this->variants as $variant) { - if (!$variant->getReturnType() instanceof VoidType) { + if (!$variant->getReturnType()->isVoid()->yes()) { return false; } } diff --git a/src/Reflection/Php/PhpFunctionFromParserNodeReflection.php b/src/Reflection/Php/PhpFunctionFromParserNodeReflection.php index f360036264..3b5f8d770d 100644 --- a/src/Reflection/Php/PhpFunctionFromParserNodeReflection.php +++ b/src/Reflection/Php/PhpFunctionFromParserNodeReflection.php @@ -19,7 +19,6 @@ use PHPStan\Type\MixedType; use PHPStan\Type\Type; use PHPStan\Type\TypehintHelper; -use PHPStan\Type\VoidType; use function array_reverse; use function is_array; use function is_string; @@ -194,7 +193,7 @@ public function getThrowType(): ?Type public function hasSideEffects(): TrinaryLogic { - if ($this->getReturnType() instanceof VoidType) { + if ($this->getReturnType()->isVoid()->yes()) { return TrinaryLogic::createYes(); } if ($this->isPure !== null) { diff --git a/src/Reflection/Php/PhpFunctionReflection.php b/src/Reflection/Php/PhpFunctionReflection.php index 4b5428d4fd..2627fdd927 100644 --- a/src/Reflection/Php/PhpFunctionReflection.php +++ b/src/Reflection/Php/PhpFunctionReflection.php @@ -24,7 +24,6 @@ use PHPStan\Type\MixedType; use PHPStan\Type\Type; use PHPStan\Type\TypehintHelper; -use PHPStan\Type\VoidType; use function array_map; use function filemtime; use function is_file; @@ -240,7 +239,7 @@ public function getThrowType(): ?Type public function hasSideEffects(): TrinaryLogic { - if ($this->getReturnType() instanceof VoidType) { + if ($this->getReturnType()->isVoid()->yes()) { return TrinaryLogic::createYes(); } if ($this->isPure !== null) { diff --git a/src/Reflection/Php/PhpMethodReflection.php b/src/Reflection/Php/PhpMethodReflection.php index e4f26e5dea..b6c46e5753 100644 --- a/src/Reflection/Php/PhpMethodReflection.php +++ b/src/Reflection/Php/PhpMethodReflection.php @@ -405,12 +405,9 @@ public function getThrowType(): ?Type public function hasSideEffects(): TrinaryLogic { - $name = strtolower($this->getName()); - $isVoid = $this->getReturnType() instanceof VoidType; - if ( - $name !== '__construct' - && $isVoid + strtolower($this->getName()) !== '__construct' + && $this->getReturnType()->isVoid()->yes() ) { return TrinaryLogic::createYes(); } diff --git a/src/Rules/Comparison/ImpossibleCheckTypeHelper.php b/src/Rules/Comparison/ImpossibleCheckTypeHelper.php index b03f41d101..6606d0554f 100644 --- a/src/Rules/Comparison/ImpossibleCheckTypeHelper.php +++ b/src/Rules/Comparison/ImpossibleCheckTypeHelper.php @@ -24,7 +24,6 @@ use PHPStan\Type\TypeUtils; use PHPStan\Type\TypeWithClassName; use PHPStan\Type\VerbosityLevel; -use PHPStan\Type\VoidType; use function array_map; use function array_pop; use function count; @@ -331,7 +330,7 @@ private function determineContext(Scope $scope, Expr $node): TypeSpecifierContex $parametersAcceptor = ParametersAcceptorSelector::selectFromArgs($scope, $node->getArgs(), $functionReflection->getVariants()); $returnType = TypeUtils::resolveLateResolvableTypes($parametersAcceptor->getReturnType()); - return $returnType instanceof VoidType ? TypeSpecifierContext::createNull() : TypeSpecifierContext::createTruthy(); + return $returnType->isVoid()->yes() ? TypeSpecifierContext::createNull() : TypeSpecifierContext::createTruthy(); } } elseif ($node instanceof MethodCall && $node->name instanceof Node\Identifier) { $methodCalledOnType = $scope->getType($node->var); @@ -340,7 +339,7 @@ private function determineContext(Scope $scope, Expr $node): TypeSpecifierContex $parametersAcceptor = ParametersAcceptorSelector::selectFromArgs($scope, $node->getArgs(), $methodReflection->getVariants()); $returnType = TypeUtils::resolveLateResolvableTypes($parametersAcceptor->getReturnType()); - return $returnType instanceof VoidType ? TypeSpecifierContext::createNull() : TypeSpecifierContext::createTruthy(); + return $returnType->isVoid()->yes() ? TypeSpecifierContext::createNull() : TypeSpecifierContext::createTruthy(); } } elseif ($node instanceof StaticCall && $node->name instanceof Node\Identifier) { if ($node->class instanceof Node\Name) { @@ -354,7 +353,7 @@ private function determineContext(Scope $scope, Expr $node): TypeSpecifierContex $parametersAcceptor = ParametersAcceptorSelector::selectFromArgs($scope, $node->getArgs(), $staticMethodReflection->getVariants()); $returnType = TypeUtils::resolveLateResolvableTypes($parametersAcceptor->getReturnType()); - return $returnType instanceof VoidType ? TypeSpecifierContext::createNull() : TypeSpecifierContext::createTruthy(); + return $returnType->isVoid()->yes() ? TypeSpecifierContext::createNull() : TypeSpecifierContext::createTruthy(); } } diff --git a/src/Rules/Comparison/UsageOfVoidMatchExpressionRule.php b/src/Rules/Comparison/UsageOfVoidMatchExpressionRule.php index 8494d0c2b2..bd7f18c99f 100644 --- a/src/Rules/Comparison/UsageOfVoidMatchExpressionRule.php +++ b/src/Rules/Comparison/UsageOfVoidMatchExpressionRule.php @@ -6,7 +6,6 @@ use PHPStan\Analyser\Scope; use PHPStan\Rules\Rule; use PHPStan\Rules\RuleErrorBuilder; -use PHPStan\Type\VoidType; /** * @implements Rule @@ -23,7 +22,7 @@ public function processNode(Node $node, Scope $scope): array { $matchResultType = $scope->getType($node); if ( - $matchResultType instanceof VoidType + $matchResultType->isVoid()->yes() && !$scope->isInFirstLevelStatement() ) { return [RuleErrorBuilder::message('Result of match expression (void) is used.')->build()]; diff --git a/src/Rules/Exceptions/ThrowsVoidFunctionWithExplicitThrowPointRule.php b/src/Rules/Exceptions/ThrowsVoidFunctionWithExplicitThrowPointRule.php index d0eed19fb9..e282df95f2 100644 --- a/src/Rules/Exceptions/ThrowsVoidFunctionWithExplicitThrowPointRule.php +++ b/src/Rules/Exceptions/ThrowsVoidFunctionWithExplicitThrowPointRule.php @@ -12,7 +12,6 @@ use PHPStan\Type\TypeUtils; use PHPStan\Type\TypeWithClassName; use PHPStan\Type\VerbosityLevel; -use PHPStan\Type\VoidType; use function sprintf; /** @@ -41,7 +40,7 @@ public function processNode(Node $node, Scope $scope): array throw new ShouldNotHappenException(); } - if (!$functionReflection->getThrowType() instanceof VoidType) { + if ($functionReflection->getThrowType() === null || !$functionReflection->getThrowType()->isVoid()->yes()) { return []; } diff --git a/src/Rules/Exceptions/ThrowsVoidMethodWithExplicitThrowPointRule.php b/src/Rules/Exceptions/ThrowsVoidMethodWithExplicitThrowPointRule.php index 91c97d157b..f515629cc6 100644 --- a/src/Rules/Exceptions/ThrowsVoidMethodWithExplicitThrowPointRule.php +++ b/src/Rules/Exceptions/ThrowsVoidMethodWithExplicitThrowPointRule.php @@ -12,7 +12,6 @@ use PHPStan\Type\TypeUtils; use PHPStan\Type\TypeWithClassName; use PHPStan\Type\VerbosityLevel; -use PHPStan\Type\VoidType; use function sprintf; /** @@ -41,7 +40,7 @@ public function processNode(Node $node, Scope $scope): array throw new ShouldNotHappenException(); } - if (!$methodReflection->getThrowType() instanceof VoidType) { + if ($methodReflection->getThrowType() === null || !$methodReflection->getThrowType()->isVoid()->yes()) { return []; } diff --git a/src/Rules/Exceptions/TooWideThrowTypeCheck.php b/src/Rules/Exceptions/TooWideThrowTypeCheck.php index 59a9ae1d88..2a15d3139f 100644 --- a/src/Rules/Exceptions/TooWideThrowTypeCheck.php +++ b/src/Rules/Exceptions/TooWideThrowTypeCheck.php @@ -8,7 +8,6 @@ use PHPStan\Type\TypeCombinator; use PHPStan\Type\TypeUtils; use PHPStan\Type\VerbosityLevel; -use PHPStan\Type\VoidType; use function array_map; class TooWideThrowTypeCheck @@ -20,7 +19,7 @@ class TooWideThrowTypeCheck */ public function check(Type $throwType, array $throwPoints): array { - if ($throwType instanceof VoidType) { + if ($throwType->isVoid()->yes()) { return []; } diff --git a/src/Rules/FunctionCallParametersCheck.php b/src/Rules/FunctionCallParametersCheck.php index a92a3376b2..3616068a47 100644 --- a/src/Rules/FunctionCallParametersCheck.php +++ b/src/Rules/FunctionCallParametersCheck.php @@ -23,7 +23,6 @@ use PHPStan\Type\TypeTraverser; use PHPStan\Type\TypeUtils; use PHPStan\Type\VerbosityLevel; -use PHPStan\Type\VoidType; use function array_fill; use function array_key_exists; use function count; @@ -209,7 +208,7 @@ public function check( } if ( - $scope->getType($funcCall) instanceof VoidType + $scope->getType($funcCall)->isVoid()->yes() && !$scope->isInFirstLevelStatement() && !$funcCall instanceof Node\Expr\New_ ) { diff --git a/src/Rules/FunctionDefinitionCheck.php b/src/Rules/FunctionDefinitionCheck.php index 7ab48062c9..9df74196e0 100644 --- a/src/Rules/FunctionDefinitionCheck.php +++ b/src/Rules/FunctionDefinitionCheck.php @@ -29,7 +29,6 @@ use PHPStan\Type\Type; use PHPStan\Type\TypeTraverser; use PHPStan\Type\VerbosityLevel; -use PHPStan\Type\VoidType; use function array_keys; use function array_map; use function array_merge; @@ -114,7 +113,7 @@ public function checkAnonymousFunction( throw new ShouldNotHappenException(); } $type = $scope->getFunctionType($param->type, false, false); - if ($type instanceof VoidType) { + if ($type->isVoid()->yes()) { $errors[] = RuleErrorBuilder::message(sprintf($parameterMessage, $param->var->name, 'void'))->line($param->type->getLine())->nonIgnorable()->build(); } if ( @@ -260,7 +259,7 @@ private function checkParametersAcceptor( if (!$parameterVar instanceof Variable || !is_string($parameterVar->name)) { throw new ShouldNotHappenException(); } - if ($parameter->getNativeType() instanceof VoidType) { + if ($parameter->getNativeType()->isVoid()->yes()) { $errors[] = RuleErrorBuilder::message(sprintf($parameterMessage, $parameterVar->name, 'void'))->line($parameterNodeCallback()->getLine())->nonIgnorable()->build(); } if ( diff --git a/src/Rules/Functions/CallToFunctionStatementWithoutSideEffectsRule.php b/src/Rules/Functions/CallToFunctionStatementWithoutSideEffectsRule.php index b675563d4c..78a3c55f14 100644 --- a/src/Rules/Functions/CallToFunctionStatementWithoutSideEffectsRule.php +++ b/src/Rules/Functions/CallToFunctionStatementWithoutSideEffectsRule.php @@ -8,7 +8,6 @@ use PHPStan\Rules\Rule; use PHPStan\Rules\RuleErrorBuilder; use PHPStan\Type\NeverType; -use PHPStan\Type\VoidType; use function in_array; use function sprintf; @@ -46,7 +45,7 @@ public function processNode(Node $node, Scope $scope): array if ($function->hasSideEffects()->no() || $node->expr->isFirstClassCallable()) { if (!$node->expr->isFirstClassCallable()) { $throwsType = $function->getThrowType(); - if ($throwsType !== null && !$throwsType instanceof VoidType) { + if ($throwsType !== null && !$throwsType->isVoid()->yes()) { return []; } } diff --git a/src/Rules/Generators/YieldFromTypeRule.php b/src/Rules/Generators/YieldFromTypeRule.php index 8926b3f270..60ab02e189 100644 --- a/src/Rules/Generators/YieldFromTypeRule.php +++ b/src/Rules/Generators/YieldFromTypeRule.php @@ -14,7 +14,6 @@ use PHPStan\Type\MixedType; use PHPStan\Type\TypeWithClassName; use PHPStan\Type\VerbosityLevel; -use PHPStan\Type\VoidType; use function sprintf; /** @@ -127,7 +126,7 @@ public function processNode(Node $node, Scope $scope): array ))->build(); } - if ($scope->getType($node) instanceof VoidType && !$scope->isInFirstLevelStatement()) { + if ($scope->getType($node)->isVoid()->yes() && !$scope->isInFirstLevelStatement()) { $messages[] = RuleErrorBuilder::message('Result of yield from (void) is used.')->build(); } diff --git a/src/Rules/Generators/YieldTypeRule.php b/src/Rules/Generators/YieldTypeRule.php index c5678f8a66..c71b242191 100644 --- a/src/Rules/Generators/YieldTypeRule.php +++ b/src/Rules/Generators/YieldTypeRule.php @@ -12,7 +12,6 @@ use PHPStan\Type\MixedType; use PHPStan\Type\NullType; use PHPStan\Type\VerbosityLevel; -use PHPStan\Type\VoidType; use function sprintf; /** @@ -77,7 +76,7 @@ public function processNode(Node $node, Scope $scope): array $valueType->describe($verbosityLevel), ))->build(); } - if ($scope->getType($node) instanceof VoidType && !$scope->isInFirstLevelStatement()) { + if ($scope->getType($node)->isVoid()->yes() && !$scope->isInFirstLevelStatement()) { $messages[] = RuleErrorBuilder::message('Result of yield (void) is used.')->build(); } diff --git a/src/Rules/Methods/CallToConstructorStatementWithoutSideEffectsRule.php b/src/Rules/Methods/CallToConstructorStatementWithoutSideEffectsRule.php index 713f3996af..4c4448ae4b 100644 --- a/src/Rules/Methods/CallToConstructorStatementWithoutSideEffectsRule.php +++ b/src/Rules/Methods/CallToConstructorStatementWithoutSideEffectsRule.php @@ -8,7 +8,6 @@ use PHPStan\Rules\Rule; use PHPStan\Rules\RuleErrorBuilder; use PHPStan\Type\NeverType; -use PHPStan\Type\VoidType; use function sprintf; /** @@ -50,7 +49,7 @@ public function processNode(Node $node, Scope $scope): array $constructor = $classReflection->getConstructor(); if ($constructor->hasSideEffects()->no()) { $throwsType = $constructor->getThrowType(); - if ($throwsType !== null && !$throwsType instanceof VoidType) { + if ($throwsType !== null && !$throwsType->isVoid()->yes()) { return []; } diff --git a/src/Rules/Methods/CallToMethodStatementWithoutSideEffectsRule.php b/src/Rules/Methods/CallToMethodStatementWithoutSideEffectsRule.php index 93b9202984..6d738cfc58 100644 --- a/src/Rules/Methods/CallToMethodStatementWithoutSideEffectsRule.php +++ b/src/Rules/Methods/CallToMethodStatementWithoutSideEffectsRule.php @@ -11,7 +11,6 @@ use PHPStan\Type\ErrorType; use PHPStan\Type\NeverType; use PHPStan\Type\Type; -use PHPStan\Type\VoidType; use function sprintf; /** @@ -65,7 +64,7 @@ public function processNode(Node $node, Scope $scope): array if ($method->hasSideEffects()->no() || $node->expr->isFirstClassCallable()) { if (!$node->expr->isFirstClassCallable()) { $throwsType = $method->getThrowType(); - if ($throwsType !== null && !$throwsType instanceof VoidType) { + if ($throwsType !== null && !$throwsType->isVoid()->yes()) { return []; } } diff --git a/src/Rules/Methods/CallToStaticMethodStatementWithoutSideEffectsRule.php b/src/Rules/Methods/CallToStaticMethodStatementWithoutSideEffectsRule.php index 593846a1d2..d96047140b 100644 --- a/src/Rules/Methods/CallToStaticMethodStatementWithoutSideEffectsRule.php +++ b/src/Rules/Methods/CallToStaticMethodStatementWithoutSideEffectsRule.php @@ -13,7 +13,6 @@ use PHPStan\Type\NeverType; use PHPStan\Type\ObjectType; use PHPStan\Type\Type; -use PHPStan\Type\VoidType; use function sprintf; use function strtolower; @@ -88,7 +87,7 @@ public function processNode(Node $node, Scope $scope): array if ($method->hasSideEffects()->no() || $node->expr->isFirstClassCallable()) { if (!$node->expr->isFirstClassCallable()) { $throwsType = $method->getThrowType(); - if ($throwsType !== null && !$throwsType instanceof VoidType) { + if ($throwsType !== null && !$throwsType->isVoid()->yes()) { return []; } } diff --git a/src/Rules/Methods/MethodSignatureRule.php b/src/Rules/Methods/MethodSignatureRule.php index 3065030aba..3da0ecb9d7 100644 --- a/src/Rules/Methods/MethodSignatureRule.php +++ b/src/Rules/Methods/MethodSignatureRule.php @@ -22,7 +22,6 @@ use PHPStan\Type\TypehintHelper; use PHPStan\Type\TypeTraverser; use PHPStan\Type\VerbosityLevel; -use PHPStan\Type\VoidType; use function count; use function min; use function sprintf; @@ -164,12 +163,12 @@ private function checkReturnTypeCompatibility( ); $parentReturnType = $this->transformStaticType($declaringClass, $originalParentReturnType); // Allow adding `void` return type hints when the parent defines no return type - if ($returnType instanceof VoidType && $parentReturnType instanceof MixedType) { + if ($returnType->isVoid()->yes() && $parentReturnType instanceof MixedType) { return [TrinaryLogic::createYes(), $returnType, $parentReturnType]; } // We can return anything - if ($parentReturnType instanceof VoidType) { + if ($parentReturnType->isVoid()->yes()) { return [TrinaryLogic::createYes(), $returnType, $parentReturnType]; } diff --git a/src/Rules/Missing/MissingReturnRule.php b/src/Rules/Missing/MissingReturnRule.php index 54ea24405e..77b500176e 100644 --- a/src/Rules/Missing/MissingReturnRule.php +++ b/src/Rules/Missing/MissingReturnRule.php @@ -82,7 +82,7 @@ public function processNode(Node $node, Scope $scope): array ); if ($generatorReturnType !== null) { $returnType = $generatorReturnType; - if ($returnType instanceof VoidType) { + if ($returnType->isVoid()->yes()) { return []; } if (!$returnType instanceof MixedType) { diff --git a/src/Type/Accessory/AccessoryArrayListType.php b/src/Type/Accessory/AccessoryArrayListType.php index c132d9329a..43e0d8e340 100644 --- a/src/Type/Accessory/AccessoryArrayListType.php +++ b/src/Type/Accessory/AccessoryArrayListType.php @@ -312,6 +312,11 @@ public function isClassStringType(): TrinaryLogic return TrinaryLogic::createNo(); } + public function isVoid(): TrinaryLogic + { + return TrinaryLogic::createNo(); + } + public function toNumber(): Type { return new ErrorType(); diff --git a/src/Type/Accessory/AccessoryLiteralStringType.php b/src/Type/Accessory/AccessoryLiteralStringType.php index 07369b9893..cad181ad26 100644 --- a/src/Type/Accessory/AccessoryLiteralStringType.php +++ b/src/Type/Accessory/AccessoryLiteralStringType.php @@ -226,6 +226,11 @@ public function isClassStringType(): TrinaryLogic return TrinaryLogic::createMaybe(); } + public function isVoid(): TrinaryLogic + { + return TrinaryLogic::createNo(); + } + public function traverse(callable $cb): Type { return $this; diff --git a/src/Type/Accessory/AccessoryNonEmptyStringType.php b/src/Type/Accessory/AccessoryNonEmptyStringType.php index 1a1ce0f17e..34deafe39e 100644 --- a/src/Type/Accessory/AccessoryNonEmptyStringType.php +++ b/src/Type/Accessory/AccessoryNonEmptyStringType.php @@ -226,6 +226,11 @@ public function isClassStringType(): TrinaryLogic return TrinaryLogic::createMaybe(); } + public function isVoid(): TrinaryLogic + { + return TrinaryLogic::createNo(); + } + public function traverse(callable $cb): Type { return $this; diff --git a/src/Type/Accessory/AccessoryNonFalsyStringType.php b/src/Type/Accessory/AccessoryNonFalsyStringType.php index 97276352e1..9325a9936b 100644 --- a/src/Type/Accessory/AccessoryNonFalsyStringType.php +++ b/src/Type/Accessory/AccessoryNonFalsyStringType.php @@ -226,6 +226,11 @@ public function isClassStringType(): TrinaryLogic return TrinaryLogic::createMaybe(); } + public function isVoid(): TrinaryLogic + { + return TrinaryLogic::createNo(); + } + public function traverse(callable $cb): Type { return $this; diff --git a/src/Type/Accessory/AccessoryNumericStringType.php b/src/Type/Accessory/AccessoryNumericStringType.php index 8a4ad974a9..9e26ab5f08 100644 --- a/src/Type/Accessory/AccessoryNumericStringType.php +++ b/src/Type/Accessory/AccessoryNumericStringType.php @@ -229,6 +229,11 @@ public function isClassStringType(): TrinaryLogic return TrinaryLogic::createNo(); } + public function isVoid(): TrinaryLogic + { + return TrinaryLogic::createNo(); + } + public function traverse(callable $cb): Type { return $this; diff --git a/src/Type/Accessory/HasOffsetType.php b/src/Type/Accessory/HasOffsetType.php index 2bf723e0e4..b4f1011064 100644 --- a/src/Type/Accessory/HasOffsetType.php +++ b/src/Type/Accessory/HasOffsetType.php @@ -229,6 +229,11 @@ public function isClassStringType(): TrinaryLogic return TrinaryLogic::createMaybe(); } + public function isVoid(): TrinaryLogic + { + return TrinaryLogic::createNo(); + } + public function getKeysArray(): Type { return new NonEmptyArrayType(); diff --git a/src/Type/Accessory/HasOffsetValueType.php b/src/Type/Accessory/HasOffsetValueType.php index 05b3e29324..c86748c9ec 100644 --- a/src/Type/Accessory/HasOffsetValueType.php +++ b/src/Type/Accessory/HasOffsetValueType.php @@ -280,6 +280,11 @@ public function isClassStringType(): TrinaryLogic return TrinaryLogic::createMaybe(); } + public function isVoid(): TrinaryLogic + { + return TrinaryLogic::createNo(); + } + public function toNumber(): Type { return new ErrorType(); diff --git a/src/Type/Accessory/NonEmptyArrayType.php b/src/Type/Accessory/NonEmptyArrayType.php index c4df2cbbbd..cff1a7f954 100644 --- a/src/Type/Accessory/NonEmptyArrayType.php +++ b/src/Type/Accessory/NonEmptyArrayType.php @@ -297,6 +297,11 @@ public function isClassStringType(): TrinaryLogic return TrinaryLogic::createNo(); } + public function isVoid(): TrinaryLogic + { + return TrinaryLogic::createNo(); + } + public function toNumber(): Type { return new ErrorType(); diff --git a/src/Type/Accessory/OversizedArrayType.php b/src/Type/Accessory/OversizedArrayType.php index 88bfcdd276..37c155675b 100644 --- a/src/Type/Accessory/OversizedArrayType.php +++ b/src/Type/Accessory/OversizedArrayType.php @@ -296,6 +296,11 @@ public function isClassStringType(): TrinaryLogic return TrinaryLogic::createNo(); } + public function isVoid(): TrinaryLogic + { + return TrinaryLogic::createNo(); + } + public function toNumber(): Type { return new ErrorType(); diff --git a/src/Type/ArrayType.php b/src/Type/ArrayType.php index 142e54e232..948270488c 100644 --- a/src/Type/ArrayType.php +++ b/src/Type/ArrayType.php @@ -320,6 +320,11 @@ public function isClassStringType(): TrinaryLogic return TrinaryLogic::createNo(); } + public function isVoid(): TrinaryLogic + { + return TrinaryLogic::createNo(); + } + public function isOffsetAccessible(): TrinaryLogic { return TrinaryLogic::createYes(); diff --git a/src/Type/CallableType.php b/src/Type/CallableType.php index a1f54edf26..036cc96f4d 100644 --- a/src/Type/CallableType.php +++ b/src/Type/CallableType.php @@ -382,6 +382,11 @@ public function isClassStringType(): TrinaryLogic return TrinaryLogic::createMaybe(); } + public function isVoid(): TrinaryLogic + { + return TrinaryLogic::createNo(); + } + public function isCommonCallable(): bool { return $this->isCommonCallable; diff --git a/src/Type/ClosureType.php b/src/Type/ClosureType.php index 9ae57b480f..7946da4885 100644 --- a/src/Type/ClosureType.php +++ b/src/Type/ClosureType.php @@ -451,6 +451,11 @@ public function isClassStringType(): TrinaryLogic return TrinaryLogic::createNo(); } + public function isVoid(): TrinaryLogic + { + return TrinaryLogic::createNo(); + } + /** * @param mixed[] $properties */ diff --git a/src/Type/FloatType.php b/src/Type/FloatType.php index fd53b13a6f..34f2f4c47a 100644 --- a/src/Type/FloatType.php +++ b/src/Type/FloatType.php @@ -181,6 +181,11 @@ public function isClassStringType(): TrinaryLogic return TrinaryLogic::createNo(); } + public function isVoid(): TrinaryLogic + { + return TrinaryLogic::createNo(); + } + public function traverse(callable $cb): Type { return $this; diff --git a/src/Type/IntersectionType.php b/src/Type/IntersectionType.php index 9a0c7299a8..706cc43ddf 100644 --- a/src/Type/IntersectionType.php +++ b/src/Type/IntersectionType.php @@ -511,6 +511,11 @@ public function isClassStringType(): TrinaryLogic return $this->intersectResults(static fn (Type $type): TrinaryLogic => $type->isClassStringType()); } + public function isVoid(): TrinaryLogic + { + return $this->intersectResults(static fn (Type $type): TrinaryLogic => $type->isVoid()); + } + public function isOffsetAccessible(): TrinaryLogic { return $this->intersectResults(static fn (Type $type): TrinaryLogic => $type->isOffsetAccessible()); diff --git a/src/Type/IterableType.php b/src/Type/IterableType.php index 57701731f8..cb5d8c8804 100644 --- a/src/Type/IterableType.php +++ b/src/Type/IterableType.php @@ -320,6 +320,11 @@ public function isClassStringType(): TrinaryLogic return TrinaryLogic::createNo(); } + public function isVoid(): TrinaryLogic + { + return TrinaryLogic::createNo(); + } + public function inferTemplateTypes(Type $receivedType): TemplateTypeMap { if ($receivedType instanceof UnionType || $receivedType instanceof IntersectionType) { diff --git a/src/Type/JustNullableTypeTrait.php b/src/Type/JustNullableTypeTrait.php index 8f659a5e41..c13fadae2b 100644 --- a/src/Type/JustNullableTypeTrait.php +++ b/src/Type/JustNullableTypeTrait.php @@ -112,4 +112,9 @@ public function isClassStringType(): TrinaryLogic return TrinaryLogic::createNo(); } + public function isVoid(): TrinaryLogic + { + return TrinaryLogic::createNo(); + } + } diff --git a/src/Type/MixedType.php b/src/Type/MixedType.php index 0274f36cc3..63f27ad888 100644 --- a/src/Type/MixedType.php +++ b/src/Type/MixedType.php @@ -756,6 +756,17 @@ public function isClassStringType(): TrinaryLogic return TrinaryLogic::createMaybe(); } + public function isVoid(): TrinaryLogic + { + if ($this->subtractedType !== null) { + if ($this->subtractedType->isSuperTypeOf(new VoidType())->yes()) { + return TrinaryLogic::createNo(); + } + } + + return TrinaryLogic::createMaybe(); + } + public function tryRemove(Type $typeToRemove): ?Type { if ($this->isSuperTypeOf($typeToRemove)->yes()) { diff --git a/src/Type/NeverType.php b/src/Type/NeverType.php index 38b824168c..788e8c03a1 100644 --- a/src/Type/NeverType.php +++ b/src/Type/NeverType.php @@ -393,6 +393,11 @@ public function isClassStringType(): TrinaryLogic return TrinaryLogic::createNo(); } + public function isVoid(): TrinaryLogic + { + return TrinaryLogic::createNo(); + } + /** * @param mixed[] $properties */ diff --git a/src/Type/NullType.php b/src/Type/NullType.php index c803e9bc4c..e79592a5af 100644 --- a/src/Type/NullType.php +++ b/src/Type/NullType.php @@ -237,6 +237,11 @@ public function isClassStringType(): TrinaryLogic return TrinaryLogic::createNo(); } + public function isVoid(): TrinaryLogic + { + return TrinaryLogic::createNo(); + } + public function getSmallerType(): Type { return new NeverType(); diff --git a/src/Type/ObjectType.php b/src/Type/ObjectType.php index 1319d2448b..bc10ad9224 100644 --- a/src/Type/ObjectType.php +++ b/src/Type/ObjectType.php @@ -893,6 +893,11 @@ public function isClassStringType(): TrinaryLogic return TrinaryLogic::createNo(); } + public function isVoid(): TrinaryLogic + { + return TrinaryLogic::createNo(); + } + private function isExtraOffsetAccessibleClass(): TrinaryLogic { $classReflection = $this->getClassReflection(); diff --git a/src/Type/StaticType.php b/src/Type/StaticType.php index db9803bc48..9867ce8c3b 100644 --- a/src/Type/StaticType.php +++ b/src/Type/StaticType.php @@ -486,6 +486,11 @@ public function isClassStringType(): TrinaryLogic return $this->getStaticObjectType()->isClassStringType(); } + public function isVoid(): TrinaryLogic + { + return $this->getStaticObjectType()->isVoid(); + } + /** * @return ParametersAcceptor[] */ diff --git a/src/Type/StrictMixedType.php b/src/Type/StrictMixedType.php index 01db3d74da..dcb09babfb 100644 --- a/src/Type/StrictMixedType.php +++ b/src/Type/StrictMixedType.php @@ -212,6 +212,11 @@ public function isClassStringType(): TrinaryLogic return TrinaryLogic::createNo(); } + public function isVoid(): TrinaryLogic + { + return TrinaryLogic::createNo(); + } + public function isOffsetAccessible(): TrinaryLogic { return TrinaryLogic::createNo(); diff --git a/src/Type/Traits/LateResolvableTypeTrait.php b/src/Type/Traits/LateResolvableTypeTrait.php index fb1a74d93e..bd6b3a67a3 100644 --- a/src/Type/Traits/LateResolvableTypeTrait.php +++ b/src/Type/Traits/LateResolvableTypeTrait.php @@ -370,6 +370,11 @@ public function isClassStringType(): TrinaryLogic return $this->resolve()->isClassStringType(); } + public function isVoid(): TrinaryLogic + { + return $this->resolve()->isVoid(); + } + public function getSmallerType(): Type { return $this->resolve()->getSmallerType(); diff --git a/src/Type/Traits/ObjectTypeTrait.php b/src/Type/Traits/ObjectTypeTrait.php index a764609a5f..ccdf3386b8 100644 --- a/src/Type/Traits/ObjectTypeTrait.php +++ b/src/Type/Traits/ObjectTypeTrait.php @@ -161,6 +161,11 @@ public function isClassStringType(): TrinaryLogic return TrinaryLogic::createNo(); } + public function isVoid(): TrinaryLogic + { + return TrinaryLogic::createNo(); + } + public function toNumber(): Type { return new ErrorType(); diff --git a/src/Type/Type.php b/src/Type/Type.php index 169eacdf9e..45078efea9 100644 --- a/src/Type/Type.php +++ b/src/Type/Type.php @@ -165,6 +165,8 @@ public function isLiteralString(): TrinaryLogic; public function isClassStringType(): TrinaryLogic; + public function isVoid(): TrinaryLogic; + public function getSmallerType(): Type; public function getSmallerOrEqualType(): Type; diff --git a/src/Type/TypehintHelper.php b/src/Type/TypehintHelper.php index a194e82657..1b2229eb90 100644 --- a/src/Type/TypehintHelper.php +++ b/src/Type/TypehintHelper.php @@ -155,7 +155,7 @@ public static function decideType( if ( $type instanceof MixedType && !$type->isExplicitMixed() - && $phpDocType instanceof VoidType + && $phpDocType->isVoid()->yes() ) { return $phpDocType; } diff --git a/src/Type/UnionType.php b/src/Type/UnionType.php index e55912aff4..c977f7e2cf 100644 --- a/src/Type/UnionType.php +++ b/src/Type/UnionType.php @@ -505,6 +505,11 @@ public function isClassStringType(): TrinaryLogic return $this->notBenevolentUnionResults(static fn (Type $type): TrinaryLogic => $type->isClassStringType()); } + public function isVoid(): TrinaryLogic + { + return $this->unionResults(static fn (Type $type): TrinaryLogic => $type->isVoid()); + } + public function isOffsetAccessible(): TrinaryLogic { return $this->unionResults(static fn (Type $type): TrinaryLogic => $type->isOffsetAccessible()); diff --git a/src/Type/VoidType.php b/src/Type/VoidType.php index f317ed421a..0dcb9b03e7 100644 --- a/src/Type/VoidType.php +++ b/src/Type/VoidType.php @@ -164,6 +164,11 @@ public function isClassStringType(): TrinaryLogic return TrinaryLogic::createNo(); } + public function isVoid(): TrinaryLogic + { + return TrinaryLogic::createYes(); + } + public function traverse(callable $cb): Type { return $this; diff --git a/tests/PHPStan/Type/MixedTypeTest.php b/tests/PHPStan/Type/MixedTypeTest.php index 286554241a..dfbd148dd3 100644 --- a/tests/PHPStan/Type/MixedTypeTest.php +++ b/tests/PHPStan/Type/MixedTypeTest.php @@ -636,6 +636,35 @@ public function dataSubstractedIsClassString(): array ]; } + /** @dataProvider dataSubtractedIsVoid */ + public function testSubtractedIsVoid(MixedType $mixedType, Type $typeToSubtract, TrinaryLogic $expectedResult): void + { + $subtracted = $mixedType->subtract($typeToSubtract); + $actualResult = $subtracted->isVoid(); + + $this->assertSame( + $expectedResult->describe(), + $actualResult->describe(), + sprintf('%s -> isVoid()', $subtracted->describe(VerbosityLevel::precise())), + ); + } + + public function dataSubtractedIsVoid(): array + { + return [ + [ + new MixedType(), + new VoidType(), + TrinaryLogic::createNo(), + ], + [ + new MixedType(), + new StringType(), + TrinaryLogic::createMaybe(), + ], + ]; + } + /** * @dataProvider dataSubstractedIsLiteralString */