Reputation: 982
I wanted to use macro to check if a function is returning a particular generic type, say Array
, so it is fine if the function is returning Array<Dynamic>
, Array<String>
, or even generic Array<T>
.
So I tried to Context.unify
it with Array<Dynamic>
. It is fine for Array<String>
or Array<Dynamic>
but it fails when the type parameter is "generic" because the ComplexType Array<T>
won't convert to a Type with Type not found: T
(See code below). Are there any possible ways to achieve what I am attempting to do?
package;
#if macro
import haxe.macro.Context;
using haxe.macro.ComplexTypeTools;
#end
#if !macro @:build(Macros.build()) #end
class Main
{
public function test<T>():Array<T>
{
return [];
}
}
class Macros
{
public static function build()
{
#if macro
var fields = Context.getBuildFields();
for(field in fields)
{
switch(field.kind)
{
case FFun(f):
// try to unify Array<String> with Array<Dynamic>
trace(Context.unify((macro:Array<String>).toType(), (macro:Array<Dynamic>).toType()));
// true
// try to unify Array<T> with Array<Dynamic>
trace(Context.unify(f.ret.toType(), (macro:Array<Dynamic>).toType()));
// Type not found: T
default:
}
}
return null;
#end
}
}
Upvotes: 1
Views: 374
Reputation: 853
So, checking TPath was not the best idea.
Based on the previous assumption about Dynamic being assignable to any type we can replace unconvertable type parameter with the Dynamic (eg Array<T>
= Array<Dynamic>
) and when try to unify it.
static function toTypeExt(c:ComplexType):Null<haxe.macro.Type>
{
try {
return c.toType();
} catch (error:Error)
{
switch (c)
{
case TPath(p):
//deep copy of the TPath with all type parameters as Dynamic
var paramsCopy = [for (i in 0...p.params.length) TPType(macro:Dynamic)];
var pCopy:TypePath = {
name: p.name,
pack: p.pack,
sub: p.sub,
params: paramsCopy
}
var cCopy = TPath(pCopy);
//convert after
return cCopy.toType();
default:
}
}
return null;
}
Use toTypeExt() in your build macro instead of toType.
trace(Context.unify(toTypeExt(f.ret), (macro:Array<Dynamic>).toType()));
Looks more like a workaround to me, but there is a strange thing about ComplexTypeTools.toType - it will succeed with a class type parameter while failing with method type parameter.
Unification won't work since there is no way of converting ComplexType with the type parameter to Type (in that context). But since you are unifying with Array it is safe to assume that any Array will unify with it (since any type is assignable to Dynamic http://haxe.org/manual/types-dynamic.html).
May be it is not the pritiest solution, but simple TPath check is the way to go here:
case FFun(f):
switch (f.ret) {
case TPath({ name: "Array", pack: [], params: _ }):
trace("Yay!");
default:
}
Upvotes: 2