Inferring during transpilation
Opened this issue · 0 comments
henrywood commented
If I do someting like:
EmulatedEnumInt.php
:
<?php
class EmulatedEnumInt {
protected int $value;
protected function __construct(int $value) {
$this->value = $value;
}
public function __toString() : string {
return (string) $this->value;
}
}
CfgType.php
:
<?php
#ifndef KPHP
enum CfgType : int {
case STRING = 1;
case INT = 2;
case BOOL = 3;
case ARRAY = 4;
}
if (false) {
#endif
final class CfgType extends EmulatedEnumInt
{
const STRING = 1;
const INT = 2;
const BOOL = 3;
const ARRAY = 4;
// GENERATED
public static function STRING() : static {
return new static(1);
}
public static function INT() : static {
return new static(2);
}
public static function BOOL() : static {
return new static(3);
}
public static function ARRAY() : static {
return new static(4);
}
private static $fromMap = [
1 => 'STRING',
2 => 'INT',
3 => 'BOOL',
4 => 'ARRAY',
];
public static function tryFrom(string|int $value) : static {
if (isset(self::$fromMap[$value])) return new static(self::$fromMap[$value]);
throw new \Exception("No such enum value:".$value);
}
}
#ifndef KPHP
}
#endif
code.php
:
<?php
include_once('CfgType.php');
#ifndef KPHP
/**
* Get a configuration value (PHP VERSION)
*
* (Assumes Config object is already stored in Memcache (in KEY: '___PROJECT_SHORT____CONFIG') )
*
* @param string $settingName
* @param CfgType $type
* @param int $ttl
*
* @return ?int|?string|boolean|array
*/
function cfg(string $settingName, CfgType $type = CfgType::STRING, int $ttl = 86400) {
switch($type) {
case CfgType::STRING:
$value = (time() % 2 === 0) ? NULL : (string)$settingName;
return $value;
case CfgType::INT:
$value = (time() % 2 === 0) ? NULL : (int)80;
return $value;
case CfgType::BOOL:
$value = (time() % 2 === 0) ? NULL : (bool) $settingName;
return $value;
case CfgType::ARRAY:
$value = (time() % 2 === 0) ? NULL : ['foo', 'bar'];
return $value;
}
}
if (false) {
#endif
/**
* Get a configuration value (KPHP VERSION)
*
* (Assumes Config object is already stored in Memcache (in KEY: '___PROJECT_SHORT____CONFIG') )
*
* @param string $settingName
* @param CfgType $type
* @param int $ttl
*
* @return ?int|?string|boolean|array
*/
function cfg(string $settingName, CfgType $type, int $ttl = 86400) {
$value = (string) $type;
switch($value) {
case (string)CfgType::STRING():
$value = (time() % 2 === 0) ? NULL : (string)$settingName;
return $value;
case (string)CfgType::INT():
$value = (time() % 2 === 0) ? NULL : (int)80;
return $value;
case (string)CfgType::BOOL():
$value = (time() % 2 === 0) ? NULL : (bool)$settingName;
return (bool) $settingName;
case (string)CfgType::ARRAY():
$value = (time() % 2 === 0) ? NULL : (array) ['foo', 'bar'];
return $value;
default:
return (string) $settingName.'_default';
}
}
#ifndef KPHP
}
#endif
main.php:
<?php
#ifndef KPHP // PHP
define('KPHP_VERSION', 0);
if (false)
#endif // KPHP
define('KPHP_VERSION', 1);
include('EmulatedEnumInt.php');
include('CfgType.php');
include('code.php');
$user = (KPHP_VERSION) ? cfg('USER', CfgType::STRING()) : cfg('USER', CfgType::STRING);
echo "User=".$user.PHP_EOL;
to cater for the fact that enums are not supported in KPHP (the code base I am trying to convert uses many enums), I would expect the transpiler to be able to deduce that the above statement can be re-written as:
$user = cfg('USER', CfgType::STRING());
since KPHP_VERSION is defined to be 1 when compiling with KPHP (and the else part of the ternary will only be taken when running in a PHP context)
However, if I compile like this:
# kphp main.php --mode server --include-dir $(pwd) -o ./server
I get this error:
Compilation error at stage: Calc actual calls, gen by type-inferer.cpp:53
main.php:14 in global scope
$user = (KPHP_VERSION) ? cfg('USER', CfgType::STRING()) : cfg('USER', CfgType::STRING);
pass int to argument $type of cfg
but it's declared as @param CfgType
main.php:14 in global scope
$user = (KPHP_VERSION) ? cfg('USER', CfgType::STRING()) : cfg('USER', CfgType::STRING);
1 is int
apparently because it takes the else part into account ?
I would like to be able to do assignments like ($user = ) on a single line.
However, I am aware that the $user = ...
line can be replaced by:
#ifndef KPHP // PHP
$user = cfg('USER', CfgType::STRING);
if (FALSE) { // KPHP
#endif
$user = cfg('USER', CfgType::STRING());
#ifndef KPHP // PHP
}
#endif
but that syntax is rather cumbersome ...
So can't the transpiler be improved in this regard ?