From 837f5d7096d08304f5d58d3bc220e34cd7dfafef Mon Sep 17 00:00:00 2001 From: Matthew Brown Date: Tue, 20 Mar 2018 20:56:33 -0400 Subject: [PATCH] Fix #594 - support intersection types (and catch errors) --- src/Psalm/Checker/TypeChecker.php | 76 +++++++++++++++++-------------- tests/TypeReconciliationTest.php | 2 +- 2 files changed, 43 insertions(+), 35 deletions(-) diff --git a/src/Psalm/Checker/TypeChecker.php b/src/Psalm/Checker/TypeChecker.php index 2a0181dab..eb544654c 100644 --- a/src/Psalm/Checker/TypeChecker.php +++ b/src/Psalm/Checker/TypeChecker.php @@ -216,45 +216,53 @@ class TypeChecker ) { $intersection_input_types = $input_type_part->extra_types ?: []; $intersection_input_types[] = $input_type_part; - $container_type_lower = strtolower($container_type_part->value); - foreach ($intersection_input_types as $intersection_input_type) { - if ($intersection_input_type->value === $container_type_part->value) { - return true; + $intersection_container_types = $container_type_part->extra_types ?: []; + $intersection_container_types[] = $container_type_part; + + foreach ($intersection_container_types as $intersection_container_type) { + $intersection_container_type_lower = strtolower($intersection_container_type->value); + + foreach ($intersection_input_types as $intersection_input_type) { + $intersection_input_type_lower = strtolower($intersection_input_type->value); + + if ($intersection_container_type_lower === $intersection_input_type_lower) { + continue 2; + } + + if ($intersection_input_type_lower === 'generator' + && in_array($intersection_container_type_lower, ['iterator', 'traversable', 'iterable'], true) + ) { + continue 2; + } + + if ($codebase->classExists($intersection_input_type->value) + && $codebase->classExtendsOrImplements( + $intersection_input_type->value, + $intersection_container_type->value + ) + ) { + continue 2; + } + + if ($codebase->interfaceExists($intersection_input_type->value) + && $codebase->interfaceExtends( + $intersection_input_type->value, + $intersection_container_type->value + ) + ) { + continue 2; + } + + if (ExpressionChecker::isMock($intersection_input_type->value)) { + return true; + } } - $intersection_input_type_lower = strtolower($intersection_input_type->value); - - if ($intersection_input_type_lower === 'generator' - && in_array($container_type_lower, ['iterator', 'traversable', 'iterable'], true) - ) { - return true; - } - - if ($codebase->classExists($intersection_input_type->value) - && $codebase->classExtendsOrImplements( - $intersection_input_type->value, - $container_type_part->value - ) - ) { - return true; - } - - if ($codebase->interfaceExists($intersection_input_type->value) - && $codebase->interfaceExtends( - $intersection_input_type->value, - $container_type_part->value - ) - ) { - return true; - } - - if (ExpressionChecker::isMock($intersection_input_type->value)) { - return true; - } + return false; } - return false; + return true; } /** diff --git a/tests/TypeReconciliationTest.php b/tests/TypeReconciliationTest.php index b29c73f40..65866078b 100644 --- a/tests/TypeReconciliationTest.php +++ b/tests/TypeReconciliationTest.php @@ -838,7 +838,7 @@ class TypeReconciliationTest extends TestCase }', 'error_message' => 'PossiblyInvalidArgument', ], - 'SKIPPED-intersection' => [ + 'intersectionIncorrect' => [ '