Bug 21697 – Absurd limitations when passing lambda as alias parameter and bad error message

Status
RESOLVED
Resolution
DUPLICATE
Severity
major
Priority
P2
Component
dmd
Product
D
Version
D2
Platform
x86
OS
All
Creation time
2021-03-10T01:23:30Z
Last change time
2024-03-19T10:05:37Z
Assigned to
No Owner
Creator
deadalnix

Comments

Comment #0 by deadalnix — 2021-03-10T01:23:30Z
See sample code: module test; struct S { void foo() {} void run(alias f)() { f(); } void bar() { // OK run!foo(); // OK void bar() { foo(); } run!bar(); // Error run!(() { foo(); })(); } } The limitation of the 3rd syntax seems rather arbitrary. The error message is also rather inscrutable for someone who's not very familiar with D: test.d(5): Error: function test.S.bar.run!(delegate () @system { this.foo(); } ).run cannot get frame pointer to test.S.bar.__lambda2 My interpretation of what is happening is that the lambda gets instantiated at the call site, and dmd assumes it needs a context when it doesn't. Note that the error message doesn't refers to the line at which the error occurs at all!
Comment #1 by john.loughran.colvin — 2021-03-10T13:37:22Z
The problem is triggered by the lambda being a template, yes I expanded this to cover a bunch of cases to make sure I understood what was happening, maybe it will be useful to someone trying to solve it and/or as a comprehensive test. module test; import std.stdio; //@safe: struct S { //@safe: void foo() { writeln(&this); } void foo2()() { writeln(&this); } void runInsideDirect(alias f)() { write("runInsideDirect!" ~ __traits(identifier, f) ~ ": "); f(); } void runInsideIndirect(alias f)() { write("runInsideIndirect!" ~ __traits(identifier, f) ~ ": "); auto b = &f; b(); } void runInsideTemplateDirect(alias f)() { write("runInsideTemplateDirect!" ~ __traits(identifier, f) ~ ": "); f!()(); } void runInsideTemplateIndirect(alias f)() { write("runInsideTemplateIndirect!" ~ __traits(identifier, f) ~ ": "); auto b = &f!(); b(); } void bar() { runInsideDirect!foo(); runInsideIndirect!foo(); //runOutsideDirect!foo(); // Error: need this runOutsideIndirect!foo(); // wrong this, caught by @safe runInsideTemplateDirect!foo2(); runInsideTemplateIndirect!foo2(); //runOutsideTemplateDirect!foo2(); // Error: need this runOutsideTemplateIndirect!foo2(); // wrong this, caught by @safe runInsideDirect!(foo2!())(); runInsideIndirect!(foo2!())(); //runOutsideDirect!(foo2!())(); // Error: need this runOutsideIndirect!(foo2!())(); // wrong this, caught by @safe void bar() //@safe { foo(); } void bar2()() //@safe { foo(); } runInsideDirect!bar(); runInsideIndirect!bar(); runOutsideDirect!bar(); runOutsideIndirect!bar(); //runInsideTemplateDirect!bar2(); // Error: need this, but no "Error instantiating" message?? //runInsideTemplateIndirect!bar2(); // Error: need this, but no "Error instantiating" message?? //runOutsideTemplateDirect!bar2(); // Error: need this //runOutsideTemplateIndirect!bar2(); // Error: need this runInsideDirect!(bar2!())(); runInsideIndirect!(bar2!())(); runOutsideDirect!(bar2!())(); runOutsideIndirect!(bar2!())(); } } void runOutsideDirect(alias f)() { write("runOutsideDirect!" ~ __traits(identifier, f) ~ ": "); f(); } void runOutsideIndirect(alias f)() { write("runOutsideIndirect!" ~ __traits(identifier, f) ~ ": "); auto b = &f; b(); } void runOutsideTemplateDirect(alias f)() { write("runOutsideTemplateDirect!" ~ __traits(identifier, f) ~ ": "); f!()(); } void runOutsideTemplateIndirect(alias f)() { write("runOutsideTemplateIndirect!" ~ __traits(identifier, f) ~ ": "); auto b = &f!(); b(); } void main() { S s; s.bar(); }
Comment #2 by snarwin+bugzilla — 2021-03-10T14:33:10Z
Probably related to issue 21287, although in that case it's the lambda that works and the nested function that fails.
Comment #3 by dfj1esp02 — 2024-03-19T10:05:37Z
*** This issue has been marked as a duplicate of issue 20922 ***