Open
Description
Bolpat reported this on 2024-06-26T16:29:41Z
Transferred from https://issues.dlang.org/show_bug.cgi?id=24633
CC List
- Bolpat
Description
When `opApply` is an alias to an explicit function template instance, the explicit instantiation is used for overload resolution against potentially many `opApply` overloads and it is used to infer the types of `foreach` variables, however, the delegate created by the compiler in the `foreach` body lowering is passed to the function template uninstantiated. By this mechanism, when overloading `opApply`s based on the number of intended `foreach` variables, type inference is possible **and** function attributes (e.g. `@safe`) will be inferred.
Example:
```d
struct A
{
int opApply(scope int delegate(long) body) => body(42);
}
struct B
{
int opApply(Body)(scope Body body) => body(42);
}
struct C
{
int opApplyImpl(Body)(scope Body body) => body(42);
alias opApply = opApplyImpl!(int delegate(long));
}
void main() @nogc nothrow pure @safe
{
// Error: `@nogc` function cannot call non-@nogc function `A.opApply`
// Error: `pure` function cannot call impure function `A.opApply`
// Error: `@safe` function cannot call `@system` function `A.opApply`
// Error: function `A.opApply` is not `nothrow`
foreach (x; A()) { }
// Error: cannot infer type for `foreach` variable `x`
foreach (x; B()) { }
// Good:
foreach (x; C())
{
static assert(is(typeof(x) == long));
assert(x == 42);
}
}
```
This behavior is great and should be specified as intended.