HaxeFoundation / haxe

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

[cpp] Abstract multitype as function parameter incorrect with dynamic @:to #6476

Open MSGhero opened 7 years ago

MSGhero commented 7 years ago

Summary: When an abstract multitype is used as a function parameter on cpp, the generated function definition is incorrect if there's a @:to for T or Dynamic, regardless of the order of @:tos.

Let's say AMT is an abstract multitype. If it realllly matters, Concrete is an interface, and you can repro this using openfl.Vector, which is "AMT" in my case.

@:multiType(T)
abstract AMT<T>(Concrete<T>) {
    public function new();
    @:to static inline function toInt<T:Int>(t:Concrete<T>) { return new IntAMT(); }
    @:to static inline function toT<T>(t:Concrete<T>) { return new GenericAMT<T>(); }
}

In the below example, within the function definition of traceOut in Main.cpp, traceOut is expecting a GenericAMT, causing the parameter to be null when I pass in the IntAMT. It should be expecting a Concrete.

class Main {
    static function main() {
        var amt = new AMT<Int>();
        trace(amt); // works fine
        traceOut(amt); // null on cpp
    }

    static function traceOut<T>(amt:AMT<T>):Void {
        trace(amt);
    }
}

Flipping the order of @:tos doesn't affect the function definition.

When I remove the generic @:to, the function parameter becomes Concrete, as it should be.

Latest dev. Works in flash, doesn't on Windows or barebones cpp without OpenFL. I tried (@:followWithAbstracts T), but that didn't do anything if it's supposed to.

hughsando commented 6 years ago
interface Concrete<T>
{
   public function getT():T;
}

class IntAMT {
   public function new() { }
}

class GenericAMT<T> {
   public function new() { }
}

@:multiType(T)
abstract AMT<T>(Concrete<T>) {
    public function new();
    @:to static inline function toInt<T:Int>(t:Concrete<T>) { return new IntAMT(); }
    @:to static inline function toT<T>(t:Concrete<T>) { return new GenericAMT<T>(); }
}

class Test {
    static function main() {
        var amt = new AMT<Int>();
        trace(amt); // works fine
        traceOut(amt); // null on cpp
    }

    static function traceOut<T>(amt:AMT<T>):Void {
        trace(amt);
    }
}

For some reason cpp it typing traceout as

void Test_obj::traceOut( ::GenericAMT amt){
Simn commented 6 years ago

If it requires @:multiType, it's probably my bug...

hughsando commented 6 years ago

The -D dump looks ok, so I'm not ready to blame you yet. Maybe something in a 'follow' somewhere.