diff --git a/phpunit/code/float-constant-precision.php b/phpunit/code/float-constant-precision.php new file mode 100644 index 00000000..d5b8abf6 --- /dev/null +++ b/phpunit/code/float-constant-precision.php @@ -0,0 +1,13 @@ +assertSame((string) M_E, $this->invokeMethod('genCValue', M_E)); + // A string cast here would follow the precision ini, so the assertion + // is that the emitted literal reads back as the same double. + $this->assertSame(M_E, (float) $this->invokeMethod('genCValue', M_E)); $this->assertSame('1', $this->invokeMethod('genCValue', true)); $this->assertSame('0', $this->invokeMethod('genCValue', false)); @@ -370,7 +372,7 @@ public function testGeneratedCValuesAreAlwaysSourceCodeStrings(): void new \PhpParser\Node\Expr\ConstFetch(new \PhpParser\Node\Name('M_E')) ); $this->assertIsString($code); - $this->assertSame((string) M_E, $code); + $this->assertSame(M_E, (float) $code); } public function testNumericStringIdentifiersGenerateSourceCodeStrings(): void diff --git a/phpunit/src/FloatLiteralPrecisionTest.php b/phpunit/src/FloatLiteralPrecisionTest.php new file mode 100644 index 00000000..df961a32 --- /dev/null +++ b/phpunit/src/FloatLiteralPrecisionTest.php @@ -0,0 +1,50 @@ +compileToCpp('float-constant-precision.php'); + } finally { + if ($previous !== false) { + ini_set('precision', $previous); + } + } + + self::assertStringContainsString('2.7182818284590451', $cpp); + self::assertStringNotContainsString('2.718281828459)', $cpp); + } + + private function compileToCpp(string $file): string + { + global $translator; + + $compiler = CompilerTest::create(TYPEPHP_ROOT_PATH); + $translator = $compiler; + $source = TYPEPHP_ROOT_PATH . '/phpunit/code/' . $file; + $compiler->addFiles([$source]); + $compiler->prepareFile($source); + + return file_get_contents($compiler->convertFile($source)); + } +} diff --git a/phpunit/src/Generator/UtilsTest.php b/phpunit/src/Generator/UtilsTest.php index cc2264ea..56870e62 100644 --- a/phpunit/src/Generator/UtilsTest.php +++ b/phpunit/src/Generator/UtilsTest.php @@ -49,7 +49,12 @@ public function testGenCValueInt(): void public function testGenCValueFloat(): void { $result = $this->invokeMethod('genCValue', 3.14); - $this->assertSame((string) 3.14, $result); + + // The literal has to read back as the same double. Its exact spelling + // is not part of the contract, but a string cast would depend on the + // precision ini and lose digits. + $this->assertSame(3.14, (float) $result); + $this->assertMatchesRegularExpression('/[.E]/i', $result); } public function testGenCValueBool(): void diff --git a/src/Generator/Utils.php b/src/Generator/Utils.php index c243d81a..937c9809 100644 --- a/src/Generator/Utils.php +++ b/src/Generator/Utils.php @@ -31,7 +31,9 @@ protected function genCValue(mixed $value): string return $this->genIntegerLiteral($value); } if (is_float($value)) { - return (string) $value; + // A string cast formats with the precision ini, which defaults to + // 14 and would bake a truncated constant into the binary. + return $this->genFloatLiteral($value); } if (is_bool($value)) { return $value ? '1' : '0';