https://issues.dlang.org/show_bug.cgi?id=15624
--- Comment #5 from Dlang Bot <dlang-bot@dlang.rocks> --- dlang/dmd pull request #13226 "Rework fix for attribute based opApply overloads (issue 15624)" was merged into master: - a28680a845a06d0cac476442c25e7c7fe8e0d16d by MoonlightSentinel: Rework fix for attribute based opApply overloads (issue 15624) The old implementation uses `Type.covariant` to suppress overzealous ambiguity errors for `opApply` specialisations. Deferring the ambiguity checks after the attribute inference on the loop body allows for `opApply` overloads with different attributes, e.g. `@safe / @system` for `@safe / @system` delegates. Example: ```d 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) {} // Resolves to A. } ``` The previous code achieved this by checking whether the previously selected `opApply` and the current overload are covariant in any direction (i.e. `A.covariant(B)` or `B.covariant(A)`). This implementation builds on the flawed assumption that the `opApply` functions in this example are covariant - which they are not (falsely reported due to a bug in `Type.covariant`). Consider the types of the `opApply` overloads: ```d A: int function(int delegate(int) @safe dg) @safe; B: int function(int delegate(int) @system dg) @system; ``` Neither of those is an appropriate substitute for the other: - A <= B is invalid due to the `opApply`'s attributes. A `@system` function may not appear in place of a `@safe` function - A => B is invalid due to the parameter types (`dg` attributes). A function expecting a `@safe` delegate may not be treated as a function accepting `@system` callbacks. Otherwise it could silently execute a `@system` callback which is disallowed in `@safe` functions. Note that `Type.covariant` already rejects covariance when using `function` instead of `delegate` for the callbacks in the example. --- The new implementation does not rely on the buggy behaviour of `Type.covariant`. It checks two different aspects to defer the `opApply` resolution: 1. different attributes on the `opApply` function 2. different attributes on the `opApply` function 3. covariance of the callbacks receiving the foreach body (2) should handle different qualifiers on the foreach body because missmatched parameter types are usually rejected by `matchParamsToOpApply`. --- This patch enables us to fix the aforementioned bug without breaking existing code. It also enables the code added the test case wich is valid despite being utterly useless. https://github.com/dlang/dmd/pull/13226 --