Issue 19597 - distinguish opApply overload on ref
Summary: distinguish opApply overload on ref
Status: NEW
Alias: None
Product: D
Classification: Unclassified
Component: dmd (show other issues)
Version: D2
Hardware: All All
: P4 enhancement
Assignee: No Owner
URL:
Keywords:
Depends on:
Blocks:
 
Reported: 2019-01-19 21:01 UTC by Bolpat
Modified: 2022-12-17 10:31 UTC (History)
0 users

See Also:


Attachments

Note You need to log in before you can comment on or make changes to this issue.
Description Bolpat 2019-01-19 21:01:11 UTC
When opApply overloads are considered for foreach resolution, that have different ref-ness, the better match should be taken.
Currently, the compiler issues an ambiguity error.

There are two cases: When inferring the iteration variable type, and with explicit types on the iteration variable.

The case for inference:

struct Test
{
    const(int*) ptr;
    
    int opApply(scope int delegate(const(int)*) callback)
    {
        return callback(ptr);
    }
    int opApply(scope int delegate(ref const(int*)) callback)
    {
        return callback(ptr);
    }
}

void main()
{
    Test t = Test(new const int(1));
    foreach (p; t)
    {
        pragma(msg, typeof(p)); // should be const(int)*
        pragma(msg, __traits(isRef, p)); // should be false
    }
    
    foreach (ref p; t)
    {
        pragma(msg, typeof(p)); // should be const(int*)
        pragma(msg, __traits(isRef, p)); // should be true
    }
}

Making the types explicit solves this because the types aren't exactly the same.

For explicit types on the iteration variable, change the first opApply overload to take const(int*). The compiler issues an ambiguity error while there is clearly a better overload for each of them. Calling opApply directly works:

struct Test
{
    const(int*) ptr;
    int opApply(scope int delegate(const(int*)) callback)
    {
        return callback(ptr);
    }
    int opApply(scope int delegate(ref const(int*)) callback)
    {
        return callback(ptr);
    }
}

void main()
{
    t.opApply((const(int*) p)
    {
        pragma(msg, typeof(p)); // should be const(int*)
        pragma(msg, __traits(isRef, p)); // should be false
        return 0;
    });
    
    t.opApply((ref const(int*) p)
    {
        pragma(msg, typeof(p)); // should be const(int*)
        pragma(msg, __traits(isRef, p)); // should be true
        return 0;
    });
}