HaxeFoundation / haxe

Haxe - The Cross-Platform Toolkit
https://haxe.org
6.14k stars 656 forks source link

Cannot access static functions on Java platform #3030

Closed Atry closed 9 years ago

Atry commented 10 years ago
package ;

class StaticFunction
{

  public static function main() 
  {
    var thisClass = StaticFunction;
    var thisFunction = thisClass.main;
  }

}
$ haxe -java output -main StaticFunction

haxelib run hxjava hxjava_build.txt --haxe-version 3103
D:\Program Files (x86)\Java\jdk1.7.0_55/bin/javac.exe "-sourcepath" "src" "-d" "obj" "-g:none" "@cmd"
src\haxe\root\StaticFunction.java:36: 错误: 找不到符号
                haxe.lang.Function thisFunctio = ((haxe.lang.Function) (haxe.root.StaticFunction.main) );
                                                                                                ^
  符号:   变量 main
  位置: 类 StaticFunction
src\haxe\root\StaticFunction.java:36: 错误: 非法的类型开始
                haxe.lang.Function thisFunction = ((haxe.lang.Function) (haxe.root.StaticFunction.main) );
                                                                        ^
2 个错误
Compilation error
Native compilation failed
Error: Build failed
waneck commented 9 years ago

It seems that the test code is breaking on php now

waneck commented 9 years ago

@Simn, can you have a look? I still haven't disabled the test, ok?

Simn commented 9 years ago

I don't know how to address this, someone with any notion of PHP knowledge will have to check it.

class Main {
    static function main() {
        var s = Something;
        var fn = s.somefunc;
        fn();
    }
}

@:keep private class Something {
    public static function somefunc() {
        trace("Hello World");
    }
}

Generated code:

class Main {
    public function __construct(){}
    static function main() {
        $s = _hx_qtype("_Main.Something");
        $fn = (isset($s->somefunc) ? $s->somefunc: array($s, "somefunc"));
        call_user_func($fn);
    }
    function __toString() { return 'Main'; }
}

This then fails with uncaught exception: call_user_func() expects parameter 1 to be a valid callback, class 'ReflectionClass' does not have a method 'somefunc' (errno: 2).

My uneducated guess is that the isset fails and the call is made on that array thing, which doesn't take into account some magical __call function.

Simn commented 9 years ago

I will probably not look into this for 3.2. unless some PHP expert wants to chime in (ping @mockey, @tml).

mockey commented 9 years ago

For a static function somefunc the call must be $s::$somefunc. $fn = (isset($s::$somefunc) ? $s::$somefunc: array($s, "somefunc")); works, but I don't know where this is generated and I don't know if this array-access is correct...

Simn commented 9 years ago

It's generated in this general area: https://github.com/HaxeFoundation/haxe/blob/development/genphp.ml#L956

mockey commented 9 years ago

Ah, I think I understand now. array($s, "somefunc") is apparently the fallback for a static function. Hm, that's pretty awful, actually. Anyway, it seems that _hx_qtype("_Main.Something"); is the problem then. It returns "_Main.Something" and it should be "_Main_Something".

mockey commented 9 years ago

Where does that hx_qtype come from? Is that used somewhere else? I thought it returns a string but it's actually some kind of class construct.

Simn commented 9 years ago

There's a bunch of PHP defines in php/Boot.hx: https://github.com/HaxeFoundation/haxe/blob/development/std/php/Boot.hx#L540

tml commented 9 years ago

Actually, iiuc the flow correctly, the _hx_qtype call is returning the wrapped class, whose __call method returns a ReflectionClass instance instead of a callable. I'm digging into Boot.hx to wrap my head around what the right thing is here.

mockey commented 9 years ago

Yeah, this is beyond me. isset($s->somefunc) is actually true for a static function (!), but that seems to be normal (I tried with haxe.Log.trace), then $s->somefunc is called and that __call -> __dynamics -> ReflectionClass magic goes loose (but fails).

mockey commented 9 years ago

I might have a fix for that now in php.Boot.hx. Not sure if this breaks something but unit-tests seem to run OK. PR?

Simn commented 9 years ago

Sure!

tml commented 9 years ago

isset($s->somefunc) is actually true for a static function (!)

Right, that's because of this block in _hx_type.

mockey commented 9 years ago

Done. BTW: This travis-condition for the SPOD tests is still there in Test.hx. I have changed it locally for now.

mockey commented 9 years ago

@tml: Yes, I think I understand now a bit better what's going on there. Lots of magic functions. A bit difficult to understand when you read the PHP-code. Did you see my fix? __get returned an array($r, $n), $r being the ReflectionClass, now it's array($r->name, $n), class name and function name. I guess this was meant to be passed to call_user_func. Makes sense?

tml commented 9 years ago

Yeah, I saw your fix and it does make sense here, I'm just worried about what else it might affect. The other option I thought of was to add 'is_callable' into the conditional in genphp.ml, but that level of ML is beyond me at the moment, and I'm not entirely convinced it's provably a better solution.

mockey commented 9 years ago

@tml: I thought maybe that returned array was meant to be like this. I can't really think of a situation where passing array(ReflectionClass, $function_name) makes sense. But you never know...

Simn commented 9 years ago

Fixed in #3904.