Bug 23955 – Can't access non-eponymous members in IFTI template

Status
NEW
Severity
normal
Priority
P3
Component
dmd
Product
D
Version
D2
Platform
All
OS
All
Creation time
2023-06-02T15:41:34Z
Last change time
2024-12-13T19:29:23Z
Keywords
rejects-valid
Assigned to
No Owner
Creator
Vladimir Panteleev
Moved to GitHub: dmd#20291 →

Comments

Comment #0 by dlang-bugzilla — 2023-06-02T15:41:34Z
////// 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); } } Now, we want to make getArr callable with a const S. Attempt #1, add a const 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. OK, no overloads. Attempt #2, let's try inout: 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. OK, no inout. Attempt #3, let's try This parameters: template getArr(this This) { void getArr(scope void delegate(typeof(This.arr)) fn) { fn(arr); } } Oops, that doesn't work because of the bug described here. Attempt #4, just use 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!
Comment #1 by dlang-bugzilla — 2023-06-02T16:00:02Z
(In reply to Vladimir Panteleev from comment #0) > Now, we want to make getArr callable with a const S. Attempt #1, add a const > 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. Oh, actually this is a regression. https://issues.dlang.org/show_bug.cgi?id=23956
Comment #2 by dlang-bugzilla — 2023-06-03T22:45:28Z
For the above puzzle, the workaround/solution is to declare both a template overload and non-template overloads for the method. The lambdas (function templates) will resolve onto the overload set, and everything else can use the template.
Comment #3 by dlang-bugzilla — 2023-06-03T22:46:07Z
Err, however that does not help with const due to the regression linked above.
Comment #4 by snarwin+bugzilla — 2023-11-22T19:21:35Z
Seems like this might be related to issue 23292.
Comment #5 by robert.schadek — 2024-12-13T19:29:23Z
THIS ISSUE HAS BEEN MOVED TO GITHUB https://github.com/dlang/dmd/issues/20291 DO NOT COMMENT HERE ANYMORE, NOBODY WILL SEE IT, THIS ISSUE HAS BEEN MOVED TO GITHUB