diff --git a/src/Analyser/ExprHandler/MethodCallHandler.php b/src/Analyser/ExprHandler/MethodCallHandler.php index 826d757a20..edc0676c94 100644 --- a/src/Analyser/ExprHandler/MethodCallHandler.php +++ b/src/Analyser/ExprHandler/MethodCallHandler.php @@ -288,12 +288,16 @@ public function resolveType(MutatingScope $scope, Expr $expr): Type { if ($expr->name instanceof Identifier) { if ($scope->nativeTypesPromoted) { + $nativeType = $scope->getNativeType($expr->var); $methodReflection = $scope->getMethodReflection( - $scope->getNativeType($expr->var), + $nativeType, $expr->name->name, ); if ($methodReflection === null) { - $returnType = new ErrorType(); + $nativeObjectType = $nativeType->getObjectTypeOrClassStringObjectType(); + $returnType = $nativeObjectType->isObject()->yes() && $nativeObjectType->getObjectClassNames() === [] + ? new MixedType() + : new ErrorType(); } else { $returnType = ParametersAcceptorSelector::combineAcceptors($methodReflection->getVariants())->getNativeReturnType(); } @@ -301,14 +305,18 @@ public function resolveType(MutatingScope $scope, Expr $expr): Type return NullsafeShortCircuitingHelper::getType($scope, $expr->var, $returnType); } + $calledOnType = $scope->getType($expr->var); $returnType = $this->methodCallReturnTypeHelper->methodCallReturnType( $scope, - $scope->getType($expr->var), + $calledOnType, $expr->name->name, $expr, ); if ($returnType === null) { - $returnType = new ErrorType(); + $objectType = $calledOnType->getObjectTypeOrClassStringObjectType(); + $returnType = $objectType->isObject()->yes() && $objectType->getObjectClassNames() === [] + ? new MixedType() + : new ErrorType(); } return NullsafeShortCircuitingHelper::getType($scope, $expr->var, $returnType); } diff --git a/src/Analyser/ExprHandler/StaticCallHandler.php b/src/Analyser/ExprHandler/StaticCallHandler.php index 2c06152b2c..cc798af209 100644 --- a/src/Analyser/ExprHandler/StaticCallHandler.php +++ b/src/Analyser/ExprHandler/StaticCallHandler.php @@ -335,14 +335,17 @@ public function resolveType(MutatingScope $scope, Expr $expr): Type $staticMethodCalledOnType = TypeCombinator::removeNull($scope->getType($expr->class))->getObjectTypeOrClassStringObjectType(); } + $methodName = $expr->name->toString(); $callType = $this->methodCallReturnTypeHelper->methodCallReturnType( $scope, $staticMethodCalledOnType, - $expr->name->toString(), + $methodName, $expr, ); if ($callType === null) { - $callType = new ErrorType(); + $callType = $staticMethodCalledOnType->isObject()->yes() && $staticMethodCalledOnType->getObjectClassNames() === [] + ? new MixedType() + : new ErrorType(); } if ($expr->class instanceof Expr) { diff --git a/tests/PHPStan/Analyser/nsrt/bug-9844.php b/tests/PHPStan/Analyser/nsrt/bug-9844.php new file mode 100644 index 0000000000..df488a9ad4 --- /dev/null +++ b/tests/PHPStan/Analyser/nsrt/bug-9844.php @@ -0,0 +1,22 @@ +foo()); + assertType('mixed', $class?->foo()); + assertType('mixed', $class::$method()); + assertType('mixed', $class->$property); + assertType('mixed', $class?->$property); + } +}