Problems with type inference of generic function's result

86 views
Skip to first unread message

basyg

unread,
Jan 13, 2016, 3:03:28 PM1/13/16
to Haxe
Runtime errors on flash target

@:generic
class Ref<T> {
        public var item:T;
        public function new(item:T) {
                this.item = item;
        }
}

class GetRef {
        @:generic
        static public function from<T>(item:T):Ref<T> {
                return new Ref(item);
        }
}

class Main {
static function main() {
                var ref = GetRef.from(0);
                // Runtime error: Type Coercion failed: cannot convert Ref_Int to Ref.
                
                var ref:Ref<Int> = GetRef.from(0);
                // Compile error: Ref<Int> should be Ref_Int
                
                function foo(ref) { }
                foo(GetRef.from(0));
                // Runtime error: Type Coercion failed: cannot convert Ref_Int to Ref.
                
                genericFoo(GetRef.from(0));
                // Compile error: Type Coercion failed: cannot convert Ref_Int to Ref.
}
        @:generic
        static inline function genericFoo<T>(ref:Ref<T>):Void { }
}

basyg

unread,
Jan 13, 2016, 3:12:23 PM1/13/16
to Haxe
More complex example

class Main {
        static inline function main():Void {
                var arr = new Arr<Int>();
                for (i in 0...10) {
                       arr.push(i); 
                }
                
                var iterator = Iterators.map(arr.iterator(), function(x) return x );
                // ok
                
                var iterator:MapIterator<Int, Int, ArrIterator<Int>> = Iterators.map(arr.iterator(), function(x) return x );
                // Compile error: MapIterator<Int, Int, ArrIterator_Int> should be MapIterator_Int_Int_ArrIterator_Int
                
                var iterator = Iterators.map(arr.iterator(), function(x) return x );
                while (iterator.hasNext()) {
                        trace(iterator.next());
                }
                // ok
                
                var iterator = Iterators.map(arr.iterator(), function(x) return x );
                for (x in iterator) {
                        trace(x);
                }
                // Runtime error: Type Coercion failed: cannot convert MapIterator_Int_Int_ArrIterator_Int to MapIterator.
                
                var iterator = Iterators.map(arr.iterator(), function(x) return x );
                function foo(iterator) { }
                foo(iterator);
                // Runtime error: Type Coercion failed: cannot convert MapIterator_Int_Int_ArrIterator_Int to MapIterator.
                
                var iterator = Iterators.map(arr.iterator(), function(x) return x);
                function bar(iterator:MapIterator<Int, Int, ArrIterator<Int>>) { }
                bar(iterator);
                // Compile error: MapIterator<Int, Int, ArrIterator_Int> should be MapIterator_Int_Int_ArrIterator_Int
                
                genericTakeIterator(Iterators.map(arr.iterator(), function(x) return x));
                // Ok
                
                var iterator = Iterators.map(arr.iterator(), function(x) return x);
                genericTakeIterator(iterator);
                // Runtime error: Type Coercion failed: cannot convert MapIterator_Int_Int_ArrIterator_Int to MapIterator.
        }
        @:generic
        static inline function genericTakeIterator<T, I:Iterator<T>>(iterator:I):Void {
                while (iterator.hasNext()) {
                        trace(iterator.next());
                }
        }
}

class Iterators<T> {
        @:generic
        static public inline function map<T, R, I:Iterator<T>>(iterator:I, func:T->R):MapIterator<T, R, I> {
                return new MapIterator(iterator, func);
        }
}

@:generic
class MapIterator<T, R, I:Iterator<T>> {
        public inline function new(iterator:I, func:T->R) {
                _iterator = iterator;
                _func = func;
        }
        public inline function hasNext():Bool {
                return _iterator.hasNext();
        }
        public inline function next():R {
                return _func(_iterator.next());
        }
        private var _iterator:I;
        private var _func:T->R;
}

@:generic
class Arr<T> {
        public inline function new() {
                _array = [];
        }
        public inline function push(item:T):Void {
                _array.push(item);
        }
        public inline function iterator():ArrIterator<T> {
                return new ArrIterator(_array);
        }
        var _array:Array<T>;
}

@:generic
class ArrIterator<T> {
        public inline function new(array:Array<T>) {
                _array = array;
                _i = 0;
        }
        public inline function hasNext():Bool {
                return _i < _array.length;
        }
        public inline function next():T {
                return _array[_i++];
        }
        var _array:Array<T>;
        var _i:Int;
}


basyg

unread,
Feb 1, 2016, 3:57:40 AM2/1/16
to Haxe
Is anyone know this is normal behavior or mistaken?
Reply all
Reply to author
Forward
0 new messages