修复opApply重载

对​​opApply​​特化,旧实现用​​Type.covariant​​来抑制​​过度歧义​​错误.延迟检查歧义至循环体上推断属性后,允许如对​​@safe/@system​​闭包用​​@safe/@system​​不同属性的​​opApply​​重载.

示例:

struct Collection {
/* A. */ int opApply(int delegate(int) @safe dg) @safe;
/* B. */ int opApply(int delegate(int) @system dg) @system;
}
void main() @safe {
Collection col;
foreach (entry; col) {} // 解析为A.
}

前面代码检查之前选择的​​opApply​​和当前重载是否在​​某​​方向上是​​协变​​的(即​​A.covariant(B)​​或​​B.协变(A)​​).

​本实现​​建立在即示例中的​​opApply​​函数是协变的​​有缺陷​​的假设上,但它们不是(由于​​Type.covariant​​中的错误而​​错误​​报告).

考虑​​opApply​​重载类型

A: int function(int delegate(int) @safe dg) @safe;
B: int function(int delegate(int) @system dg) @system;

​A/B​​都不是另一个合适的替代品:

由于​​opApply​​的属性,​​A<=B​​是无效的.​​A​​的​​@system​​函数可能不会在​​@safe​​函数中出现.

由于参数类型(​​dg属性​​),​​A=>B​​无效.

可能不会按接受​​@system​​回调函数对待期待​​@safe​​闭包的​​函数​​.否则可默默地执行​​@safe​​函数中禁止的​​@system​​回调.

注意,示例中回调用​​函数​​而不是​​闭包​​时,​​Type.covariant​​已拒绝协变.

新实现不依赖于​​Type.covariant​​的易错行为.它检查两个不同方面来延迟解析​​opApply​​:

​opApply​​函数上的不同属性

接收​​foreach​​主体回调的协变

因为​​matchParamsToOpApply​​拒绝不匹配参数类型,​​(2)​​应处理​​foreach​​主体上不同的​​限定符​​.

​此补丁​​使我们可不破坏​​现有代码​​修复上述错误.它还允许尽管有效但也没啥用的在​​测试用例​​中加代码.