在宏中统一泛型类型
Unify generic types in macro
我想使用宏来检查函数是否返回特定的泛型类型,比如 Array
,所以如果函数返回 Array<Dynamic>
、Array<String>
也没问题甚至是通用的 Array<T>
.
所以我尝试 Context.unify
它与 Array<Dynamic>
。对于 Array<String>
或 Array<Dynamic>
没问题,但当类型参数为 "generic" 时它会失败,因为 ComplexType Array<T>
不会转换为具有 Type not found: T
的类型(请参见下面的代码)。是否有任何可能的方法来实现我正在尝试做的事情?
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
}
}
更新
因此,检查 TPath 并不是最好的主意。
基于先前关于 Dynamic 可分配给任何类型的假设,我们可以用 Dynamic 替换不可转换的类型参数(例如 Array<T>
= Array<Dynamic>
)并尝试统一它。
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;
}
在构建宏中使用 toTypeExt() 而不是 toType。
trace(Context.unify(toTypeExt(f.ret), (macro:Array<Dynamic>).toType()));
在我看来更像是一种解决方法,但是 ComplexTypeTools.toType 有一个奇怪的地方 - 它会在 class 类型参数下成功,而在方法类型参数上失败。
旧答案
统一将不起作用,因为无法将具有类型参数的 ComplexType 转换为 Type(在该上下文中)。但是由于您正在与 Array 统一,因此可以安全地假设任何 Array 都将与它统一(因为任何类型都可以分配给 Dynamic http://haxe.org/manual/types-dynamic.html)。
可能不是 pritiest 解决方案,但简单的 TPath 检查是解决方法:
case FFun(f):
switch (f.ret) {
case TPath({ name: "Array", pack: [], params: _ }):
trace("Yay!");
default:
}
我想使用宏来检查函数是否返回特定的泛型类型,比如 Array
,所以如果函数返回 Array<Dynamic>
、Array<String>
也没问题甚至是通用的 Array<T>
.
所以我尝试 Context.unify
它与 Array<Dynamic>
。对于 Array<String>
或 Array<Dynamic>
没问题,但当类型参数为 "generic" 时它会失败,因为 ComplexType Array<T>
不会转换为具有 Type not found: T
的类型(请参见下面的代码)。是否有任何可能的方法来实现我正在尝试做的事情?
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
}
}
更新
因此,检查 TPath 并不是最好的主意。
基于先前关于 Dynamic 可分配给任何类型的假设,我们可以用 Dynamic 替换不可转换的类型参数(例如 Array<T>
= Array<Dynamic>
)并尝试统一它。
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;
}
在构建宏中使用 toTypeExt() 而不是 toType。
trace(Context.unify(toTypeExt(f.ret), (macro:Array<Dynamic>).toType()));
在我看来更像是一种解决方法,但是 ComplexTypeTools.toType 有一个奇怪的地方 - 它会在 class 类型参数下成功,而在方法类型参数上失败。
旧答案
统一将不起作用,因为无法将具有类型参数的 ComplexType 转换为 Type(在该上下文中)。但是由于您正在与 Array 统一,因此可以安全地假设任何 Array 都将与它统一(因为任何类型都可以分配给 Dynamic http://haxe.org/manual/types-dynamic.html)。
可能不是 pritiest 解决方案,但简单的 TPath 检查是解决方法:
case FFun(f):
switch (f.ret) {
case TPath({ name: "Array", pack: [], params: _ }):
trace("Yay!");
default:
}