Skip to content

Commit

Permalink
Fix int and float compatibility in union types
Browse files Browse the repository at this point in the history
This was broken in commit
0479532
as withType may be called in union type context.
First calling withValue() to set an int value and then updating the type
with withType() does not trigger the float cast, in turn causing a
mapping error.

Developed by: Social Deal (@socialdeal)
  • Loading branch information
NanoSector committed Sep 9, 2024
1 parent 4e0bc8b commit db1d88d
Show file tree
Hide file tree
Showing 2 changed files with 24 additions and 9 deletions.
24 changes: 15 additions & 9 deletions src/Mapper/Tree/Shell.php
Original file line number Diff line number Diff line change
Expand Up @@ -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;
}
Expand All @@ -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;
}
Expand Down Expand Up @@ -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;
}
}
9 changes: 9 additions & 0 deletions tests/Integration/Mapping/UnionMappingTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -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<string>',
'source' => 'foo',
Expand Down

0 comments on commit db1d88d

Please sign in to comment.