在试验Hack中对泛型函数的约束时,我想到了以下内容:
<?hh // strict
class Base {}
class Derived extends Base {}
abstract class ImplBase {
abstract const type T as Base;
public function foo<Tf as this::T>(Tf $v): void {}
}
class ImplDerived extends ImplBase {
const type T = Derived;
}
function foo(ImplDerived $v): void {
bar($v);
}
function bar(ImplBase $v): void {
$v->foo(new Base());
$v->foo(new Derived());
}
这个原则很基本:从具体ImplDerived
向上转换,类型检查器将ImplBase::T
视为bar
中的抽象类型,可以通过Base
转换为T = Derived
约束,还是保留对bar
的引用?但奇怪的是,答案都不是。 $v->foo(new Base());
中的每一行都因其他原因而失败:
Tf
失败,因为<expr#1>::T
“被约束为依赖类型new Base()
[...]引用$v->foo(new Derived());
”。Tf
失败,因为噗! Base
突然变成[this::T]
! “Base
是ImplBase::T
[...]类型的对象,是因为扩展类型常量git checkout <old_branch_name>
”。我问不可能,或者这可能还没有完全实现?
答案 0 :(得分:2)
有趣的是,你今天是我第二个提到这个的人;第一个是Hack团队开发人员之一,他们正在研究改进类型常量和约束之间的交互。
是的,我们正在研究它。在任何时间表上都没有承诺将其整理出来。