From 61099c4c9e36091441935409ade6d9d146939440 Mon Sep 17 00:00:00 2001 From: Yurun Date: Tue, 7 Jul 2026 11:40:01 +0800 Subject: [PATCH] =?UTF-8?q?fix(php):=20=E4=BF=AE=E5=A4=8D=E5=8F=82?= =?UTF-8?q?=E6=95=B0=E7=B1=BB=E5=9E=8B=E9=87=8D=E5=86=99=E5=85=BC=E5=AE=B9?= =?UTF-8?q?=E6=80=A7=E6=A3=80=E6=9F=A5=E4=BB=A5=E9=81=B5=E5=BE=AA=E9=80=86?= =?UTF-8?q?=E5=8F=98=E8=A7=84=E5=88=99?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/Php/Translator.php | 8 +- .../classes/class_implements_param_type.phpt | 104 ++++++++++++++++++ 2 files changed, 109 insertions(+), 3 deletions(-) create mode 100644 tests/core/classes/class_implements_param_type.phpt diff --git a/src/Php/Translator.php b/src/Php/Translator.php index 23386942..c736f0a6 100644 --- a/src/Php/Translator.php +++ b/src/Php/Translator.php @@ -3356,15 +3356,17 @@ CODE; private function isParameterTypeOverrideCompatible(ArgInfo $childArg, ArgInfo $parentArg): bool { - if ($parentArg->typeCheck || $childArg->typeCheck) { - return $parentArg->typeStr === $childArg->typeStr; - } + // Child methods may omit parameter types (contravariance — accepting a + // wider set of inputs is always compatible with the parent contract). if ($childArg->undeclared || $childArg->type === self::TYPE_VAR) { return true; } if ($parentArg->undeclared || $parentArg->type === self::TYPE_VAR) { return false; } + if ($parentArg->typeCheck || $childArg->typeCheck) { + return $parentArg->typeStr === $childArg->typeStr; + } if ($childArg->type !== $parentArg->type) { return false; } diff --git a/tests/core/classes/class_implements_param_type.phpt b/tests/core/classes/class_implements_param_type.phpt new file mode 100644 index 00000000..55e76b17 --- /dev/null +++ b/tests/core/classes/class_implements_param_type.phpt @@ -0,0 +1,104 @@ +--TEST-- +Class implements interface: union type / composite type parameter compatibility +Tests parameter type contravariance for interface implementation with union types: + - Child method omitting the type should accept a wider set of inputs. + - Child method declaring the identical union type should also compile. + - nullable union (T1|T2|null) and three-way union (T1|T2|T3) are covered. +--FILE-- +single('hello'); + $a->union2('world'); + $a->union2(42); + $a->union3(1); + $a->union3('two'); + $a->union3(3.14); + $a->nullableUnion(100); + $a->nullableUnion(null); + + // ImplMirror — explicit matching union type + $b = new ImplMirror; + $b->mirror('ok'); + $b->mirror(99); + + // ImplMulti — multiple interfaces + $c = new ImplMulti; + $c->a('yes'); + $c->a(true); + $c->b(123); + $c->b(4.56); +} +?> +--EXPECT-- +string(5) "hello" +string(5) "world" +int(42) +int(1) +string(3) "two" +float(3.14) +int(100) +NULL +string(2) "ok" +int(99) +string(3) "yes" +bool(true) +int(123) +float(4.56)