www.digitalmars.com         C & C++   DMDScript  

digitalmars.D.bugs - [Issue 23955] New: Can't access non-eponymous members in IFTI template

https://issues.dlang.org/show_bug.cgi?id=23955

          Issue ID: 23955
           Summary: Can't access non-eponymous members in IFTI template
           Product: D
           Version: D2
          Hardware: All
                OS: All
            Status: NEW
          Keywords: rejects-valid
          Severity: normal
          Priority: P3
         Component: dmd
          Assignee: nobody puremagic.com
          Reporter: dlang-bugzilla thecybershadow.net

////// test.d //////
template foo()
{
    alias T = int;

    void foo(T v)
    {
    }
}

void main()
{
    foo!()(1); // OK
    foo   (1); // NG
}
////////////////////

Compiler says:

test.d(5): Error: undefined identifier `T`
test.d(13): Error: template `test.foo` is not callable using argument types
`!()(int)`
test.d(1):        Candidate is: `foo()(T v)`

I think this is an effect of how IFTI resolution is done
(https://dlang.org/spec/template.html#ifti). However,

- This limitation is not explicitly documented.
- The error message is misleading.
- This particular case should work. The argument does not have any provenance
from the template parameters (of which there are none).

In practice, this limitation makes "This Parameters"
(https://dlang.org/spec/template.html#template_this_parameter) a lot less
useful, as it's not possible to use the constness of "this" or something like
typeof(This.field) in the function signature.

Consider for example:

struct S
{
    int[] arr;
    void getArr(scope void delegate(int[]) fn) { fn(arr); }
}


overload:

    void getArr(scope void delegate(int[]) fn) { fn(arr); }
    void getArr(scope void delegate(const(int)[]) fn) const { fn(arr); }

Oops, now calling getArr on a mutable object with a lambda causes "matches
both" errors.



    void getArr(scope void delegate(inout(int)[]) fn) inout { fn(arr); }

Oops, that doesn't actually work, inout is not smart enough to propagate to
delegates. The inout on the delegate parameter always resolves to const.



    template getArr(this This) {
        void getArr(scope void delegate(typeof(This.arr)) fn) { fn(arr); }
    }


typeof(this.arr) instead:

    template getArr(this This) {
        void getArr(scope void delegate(typeof(this.arr)) fn) { fn(arr); }
    }

Oops, "this" in the parameter list does not yet have the qualifiers applied to
it, so it's always mutable. SOL!

--
Jun 02 2023