From ce9d100908215f7042a84a746264f60ac98b28f6 Mon Sep 17 00:00:00 2001 From: Matt Brown Date: Sun, 6 Dec 2020 18:14:21 -0500 Subject: [PATCH] Fix #4794 - invvalidate dependent types when their variables change --- src/Psalm/Context.php | 10 ++++++++- src/Psalm/Type/Atomic/DependentType.php | 12 ++++++++++ src/Psalm/Type/Atomic/TDependentGetClass.php | 19 +++++++++++++++- .../Type/Atomic/TDependentGetDebugType.php | 17 +++++++++++++- tests/SwitchTypeTest.php | 22 +++++++++++++++++++ 5 files changed, 77 insertions(+), 3 deletions(-) create mode 100644 src/Psalm/Type/Atomic/DependentType.php diff --git a/src/Psalm/Context.php b/src/Psalm/Context.php index 25c802d96..f180f23ef 100644 --- a/src/Psalm/Context.php +++ b/src/Psalm/Context.php @@ -656,10 +656,18 @@ class Context $statements_analyzer ); - foreach ($this->vars_in_scope as $var_id => $_) { + foreach ($this->vars_in_scope as $var_id => $type) { if (preg_match('/' . preg_quote($remove_var_id, '/') . '[\]\[\-]/', $var_id)) { unset($this->vars_in_scope[$var_id]); } + + foreach ($type->getAtomicTypes() as $atomic_type) { + if ($atomic_type instanceof Type\Atomic\DependentType + && $atomic_type->getVarId() === $remove_var_id + ) { + $type->addType($atomic_type->getReplacement()); + } + } } } diff --git a/src/Psalm/Type/Atomic/DependentType.php b/src/Psalm/Type/Atomic/DependentType.php new file mode 100644 index 000000000..9ad9768fc --- /dev/null +++ b/src/Psalm/Type/Atomic/DependentType.php @@ -0,0 +1,12 @@ +as_type->getId() . '>'; } + public function getKey(bool $include_extra = true): string + { + return 'get-class-of<' . $this->typeof + . (!$this->as_type->isMixed() && !$this->as_type->hasObject() ? ', ' . $this->as_type->getId() : '') + . '>'; + } + + public function getVarId() : string + { + return $this->typeof; + } + + public function getReplacement() : \Psalm\Type\Atomic + { + return new TClassString(); + } + public function canBeFullyExpressedInPhp(int $php_major_version, int $php_minor_version): bool { return false; diff --git a/src/Psalm/Type/Atomic/TDependentGetDebugType.php b/src/Psalm/Type/Atomic/TDependentGetDebugType.php index 58de45af4..cdd7ed24b 100644 --- a/src/Psalm/Type/Atomic/TDependentGetDebugType.php +++ b/src/Psalm/Type/Atomic/TDependentGetDebugType.php @@ -4,7 +4,7 @@ namespace Psalm\Type\Atomic; /** * Represents a string whose value is that of a type found by get_debug_type($var) */ -class TDependentGetDebugType extends TString +class TDependentGetDebugType extends TString implements DependentType { /** * Used to hold information as to what this refers to @@ -21,6 +21,21 @@ class TDependentGetDebugType extends TString $this->typeof = $typeof; } + public function getKey(bool $include_extra = true): string + { + return 'get-debug-type-of<' . $this->typeof . '>'; + } + + public function getVarId() : string + { + return $this->typeof; + } + + public function getReplacement() : \Psalm\Type\Atomic + { + return new TString(); + } + public function canBeFullyExpressedInPhp(int $php_major_version, int $php_minor_version): bool { return false; diff --git a/tests/SwitchTypeTest.php b/tests/SwitchTypeTest.php index df6021154..b524342f8 100644 --- a/tests/SwitchTypeTest.php +++ b/tests/SwitchTypeTest.php @@ -1301,6 +1301,28 @@ class SwitchTypeTest extends TestCase }', 'error_message' => 'InvalidReturnType' ], + 'clearDependentTypeWhenAssigning' => [ + 'bar(); + } + }', + 'error_message' => 'UndefinedMethod' + ], ]; } }