Uncorrect resolving Unknown<?> type returned from function
ze0nni opened this issue · comments
Look like haxe resolve type Unknown<?>
after first comparisons for all branches of code.
enum abstract GameType<TBody>(String) {
final Unit: GameType<{ hp: Float }>;
final Box: GameType<{ size: Float }>;
}
@: forward()
abstract GameObject < TBody = Void > ({
final type: GameType<TBody>;
final body: TBody;
}) {
inline public function new<T>(type: GameType<T>, body: T) {
this = cast { type: type, body: body };
}
inline public function resolve<TResolvedBody>(): GameObject<TResolvedBody> {
return cast this;
}
}
class Test {
static function main() {
final objects: Array<GameObject> = [
new GameObject(Unit, { hp: 10 }),
new GameObject(Box, { size: 5 })
];
for (i in objects) {
final o = i.resolve();
switch (o.type) {
case Unit:
//o.body.hp -= 1;
case Box: //<< 36
//o.body.size += 1;
}
}
}
}
[ERROR] Test.hx:36: characters 14-17
36 | case Box:
| ^^^
| error: { hp : Float } has no field size
| have: GameType<{ size }>
| want: GameType<{ hp }>
But it's work good here:
static function resolve<TBody>(type: GameType<TBody>, body: TBody) {
switch(type) {
case Unit:
body.hp -= 1;
case Box:
body.size -= 1;
}
Actually I would like to be able to use the Unknown
type in my code too. For cases when the type is really unknown is this possible?
I'm not sure what exactly you're reporting here. The first example doesn't look unexpected because TResolvedBody
is never unified with anything.
I expect behavior like this
enum abstract GameType<TBody>(String) {
final Unit: GameType<{ hp: Float }>;
final Box: GameType<{ size: Float }>;
}
typedef GameObject<TBody> = {
final type: GameType<TBody>;
final body: TBody;
}
final objects: object: Array<GameObject<Unknown>> = [];
for (o in objects) {
switch (o.type) {
case Unit: o.body.hp -= 1;
case Box: o.body.size -= 1;
}
}
You can achieve it with one more step:
class Test {
static function main() {
final objects:Array<GameObject<Any>> = [
{type: Unit, body: {hp: 42}},
{type: Box, body: {size: 4.2}}
];
inline function foo<T>(o:GameObject<T>) {
switch (o.type) {
case Unit:
$type(o); // GameObject<{ hp : Float }>
case Box:
$type(o); // GameObject<{ size : Float }>
}
}
for (o in objects)
foo(o);
}
}
enum abstract GameType<TBody>(String) {
final Unit:GameType<{hp:Float}>;
final Box:GameType<{size:Float}>;
}
typedef GameObject<TBody> = {
final type:GameType<TBody>;
final body:TBody;
}
Right. But why doesn't the same work for return-types?
I don't know if we want to support this kind of typing for monomorphs in general. Type inference is already tricky enough as it is, and changing it to support a corner case like here doesn't have a good risk/reward ratio in my opinion.
Sad to hear. I find it feature powerful when haxe-Enum cannot be used