diff --git a/src/Mapper/Tree/Shell.php b/src/Mapper/Tree/Shell.php index 150083cd..10831820 100644 --- a/src/Mapper/Tree/Shell.php +++ b/src/Mapper/Tree/Shell.php @@ -80,6 +80,7 @@ public function withType(Type $newType): self { $clone = clone $this; $clone->type = $newType; + $clone->value = self::castCompatibleValue($newType, $this->value); return $clone; } @@ -91,17 +92,9 @@ public function type(): Type public function withValue(mixed $value): self { - // When the value is an integer and the type is a float, the value is - // cast to float, to follow the rule of PHP regarding acceptance of an - // integer value in a float type. Note that PHPStan/Psalm analysis - // applies the same rule. - if ($this->type instanceof FloatType && is_int($value)) { - $value = (float)$value; - } - $clone = clone $this; $clone->hasValue = true; - $clone->value = $value; + $clone->value = self::castCompatibleValue($clone->type, $value); return $clone; } @@ -173,4 +166,17 @@ public function path(): string return implode('.', $path); } + + private static function castCompatibleValue(Type $type, mixed $value): mixed + { + // When the value is an integer and the type is a float, the value is + // cast to float, to follow the rule of PHP regarding acceptance of an + // integer value in a float type. Note that PHPStan/Psalm analysis + // applies the same rule. + if ($type instanceof FloatType && is_int($value)) { + return (float)$value; + } + + return $value; + } } diff --git a/tests/Integration/Mapping/UnionMappingTest.php b/tests/Integration/Mapping/UnionMappingTest.php index 8612d507..e840a98c 100644 --- a/tests/Integration/Mapping/UnionMappingTest.php +++ b/tests/Integration/Mapping/UnionMappingTest.php @@ -64,6 +64,15 @@ public static function union_mapping_works_properly_data_provider(): iterable 'assertion' => fn (mixed $result) => self::assertNull($result), ]; + yield 'nullable float with integer value' => [ + 'type' => 'float|null', + 'source' => 42, + 'assertion' => function (mixed $result) { + self::assertIsFloat($result); + self::assertEquals(42.0, $result); + }, + ]; + yield 'string or list of string, with string' => [ 'type' => 'string|list', 'source' => 'foo',