Bug 11886 – "cannot access frame" error on lambda in lambda

Status
RESOLVED
Resolution
FIXED
Severity
enhancement
Priority
P2
Component
dmd
Product
D
Version
D2
Platform
All
OS
All
Creation time
2014-01-09T12:38:44Z
Last change time
2017-09-19T22:04:18Z
Keywords
pull
Assigned to
No Owner
Creator
Denis Shelomovskii

Comments

Comment #0 by verylonglogin.reg — 2014-01-09T12:38:44Z
This code should compile: --- struct S(alias fun) { void sf() { fun(1); } } void f(alias fun)() { fun(); } void g(alias fun)() { auto s = S!fun(); } // line 8 void main() { int n; f!(() => g!(b => n)())(); // line 13 } --- main.d(13): Error: delegate main.main.__lambda1.__lambda1 cannot access frame of function D main main.d(13): Error: pure nested function '__lambda1' cannot access mutable data 'n' main.d(8): instantiated from here: S!(__lambda1) main.d(13): instantiated from here: g!((b) => n) --- It worked with previous dmd. As a result dmd rejects now such previously working code: --- import std.algorithm, std.array; auto makeInoutArray(alias func, T)(inout T[] src) { return cast(inout) func(cast(T[]) src).array(); } void f(inout(int)[] iarr) { int n; iarr.makeInoutArray!(arr => arr.map!(a => n)())(); } --- Also dmd ICEs once while reducing this code to minimal testcase.
Comment #1 by k.hara.pg — 2014-01-09T18:08:11Z
The change is introduced by fixing bug 9050 (5fb19ce). But it's not a regression. With old versions, the OP code had been *wrongly* accepted. So it was accepts-invalid bug. The error message is intended and reject invalid code expectedly. === To be things more clear, I'd explain a current limitation. Currently, D/dmd does not support nested context inference for indirectly instantiated template lambdas. It is known limitation (at least to me). For example following case does not work: struct Lambda(alias fun) { auto opCall(A...)(A args) { return fun(args); } // Line 3 } void main() { int n = 10; Lambda!(x => x + n) f; assert(f(1) == 11); // Line 9 } Output: test.d(3): Error: function test.main.Lambda!((x) => x + n).Lambda.opCall!(int).opCall cannot access frame of function D main test.d(9): Error: template instance test.main.Lambda!((x) => x + n).Lambda.opCall!(int) error instantiating The template lambda x => x + n has context access (reading local variable n declared in main). But, until Lambda.opCall is instantiated, the 'nestedness' is unknown. Therefore compiler won't supply hidden member for Lambda!(x => x + n) struct object. Finally, f(1) will call `fun` from instantiated opCall method, but it does not know the context pointer of main function, so fun(args) makes the error "cannot access frame of function D main". Because of the limitation, currently it is impossible to create polymorpthic lambda by using existing language primitives. === The OP code hits the limitation. By the dmd bug, it had been wrongly accepted. But currently it is fixed and expectedly rejected. So, I'll change this issue to 'enhancement'.
Comment #2 by verylonglogin.reg — 2014-01-13T06:38:28Z
(In reply to comment #1) > The change is introduced by fixing bug 9050 (5fb19ce). But it's not a > regression. > > With old versions, the OP code had been *wrongly* accepted. So it was > accepts-invalid bug. The error message is intended and reject invalid code > expectedly. So does it mean there was a feature in dmd that worked and now is silently removed breaking some code? Or had it produced a wrong code? I'd like to know whether I can use the old dmd with this feature.
Comment #3 by k.hara.pg — 2014-01-13T08:27:36Z
(In reply to comment #2) > (In reply to comment #1) > > The change is introduced by fixing bug 9050 (5fb19ce). But it's not a > > regression. > > > > With old versions, the OP code had been *wrongly* accepted. So it was > > accepts-invalid bug. The error message is intended and reject invalid code > > expectedly. > > So does it mean there was a feature in dmd that worked and now is silently > removed breaking some code? Or had it produced a wrong code? I'd like to know > whether I can use the old dmd with this feature. No. There was no such feature and not yet implemented. So I think that it had not generate correct code and accidentally worked.
Comment #4 by john.loughran.colvin — 2015-10-13T17:29:54Z
If th(In reply to Kenji Hara from comment #1) > The change is introduced by fixing bug 9050 (5fb19ce). But it's not a > regression. > > With old versions, the OP code had been *wrongly* accepted. So it was > accepts-invalid bug. The error message is intended and reject invalid code > expectedly. > > === > > To be things more clear, I'd explain a current limitation. > > Currently, D/dmd does not support nested context inference for indirectly > instantiated template lambdas. It is known limitation (at least to me). > For example following case does not work: > > struct Lambda(alias fun) > { > auto opCall(A...)(A args) { return fun(args); } // Line 3 > } > void main() > { > int n = 10; > Lambda!(x => x + n) f; > assert(f(1) == 11); // Line 9 > } > > Output: > test.d(3): Error: function test.main.Lambda!((x) => x + > n).Lambda.opCall!(int).opCall cannot access frame of function D main > test.d(9): Error: template instance test.main.Lambda!((x) => x + > n).Lambda.opCall!(int) error instantiating > > The template lambda x => x + n has context access (reading local variable n > declared in main). > But, until Lambda.opCall is instantiated, the 'nestedness' is unknown. > Therefore compiler won't supply hidden member for Lambda!(x => x + n) struct > object. > Finally, f(1) will call `fun` from instantiated opCall method, but it does > not know the context pointer of main function, so fun(args) makes the error > "cannot access frame of function D main". > > Because of the limitation, currently it is impossible to create polymorpthic > lambda by using existing language primitives. > > === > > The OP code hits the limitation. By the dmd bug, it had been wrongly > accepted. But currently it is fixed and expectedly rejected. > > So, I'll change this issue to 'enhancement'. Is this limitation likely to be ever lifted? I come across it quite frequently and it's often pretty hard/ugly to work around.
Comment #5 by k.hara.pg — 2016-03-12T11:26:53Z
Comment #6 by k.hara.pg — 2016-03-24T16:33:59Z
*** Issue 12318 has been marked as a duplicate of this issue. ***
Comment #7 by github-bugzilla — 2016-03-26T10:54:20Z
Commits pushed to master at https://github.com/D-Programming-Language/dmd https://github.com/D-Programming-Language/dmd/commit/703ebeb748134cbdcc65c1032f79a93692173789 fix Issue 11886 - "cannot access frame" error on lambda in lambda A function local struct (including instantiated ones) will be nested when it contains one or more template declarations. https://github.com/D-Programming-Language/dmd/commit/0624da5eb7568cfded19b1935e33af7c9d29844a Merge pull request #5518 from 9rnsr/fix11886 Issue 11886 - "cannot access frame" error on lambda in lambda
Comment #8 by dlang-bugzilla — 2017-07-03T18:16:06Z
*** Issue 12204 has been marked as a duplicate of this issue. ***
Comment #9 by sascha.orlov — 2017-09-19T22:04:18Z
Is #17841 a related issue?