Comment #0 by snarwin+bugzilla — 2020-09-30T19:44:02Z
---
struct A {}
alias canMatch(alias handler) = (A arg) => handler(arg);
struct StructuralSumType
{
void opDispatch()
{
void fun(Value)(Value _) {}
alias lambda = (_) {};
alias ok = canMatch!lambda;
alias err = canMatch!fun;
}
}
---
Compiler output as of DMD 2.093.1:
---
sumtype.d(3): Error: delegate sumtype.canMatch(alias handler) cannot access frame of function sumtype.StructuralSumType.opDispatch
sumtype.d(13): Error: template instance `sumtype.canMatch!(fun)` error instantiating
---
Possibly a duplicate of issue 15298, though the error messages are different.
Comment #1 by ibuclaw — 2021-08-23T12:10:48Z
1. Lambdas that don't have any non-local access are implicitly typed as function pointers. So the equivalent nested function would be:
static void fun(Value)(Value _) {}
2. Template function literals are special in that they are implicitly enclosed in their lexical context. Nested function templates are not enclosed, and so cannot access the surrounding frame when instantiated non-locally.
Comment #2 by ibuclaw — 2021-08-23T12:54:19Z
(In reply to Iain Buclaw from comment #1)
> 2. Template function literals are special in that they are implicitly
> enclosed in their lexical context. Nested function templates are not
> enclosed, and so cannot access the surrounding frame when instantiated
> non-locally.
Saying that, the documentation on this disparity is somewhat lacking.
10.23.10-7 seems to be the only place that vaguely mentions the existence of template function literals:
---
If the function literal is assigned to an alias, the inference of the parameter types is done when the types are needed, as the function literal becomes a template.
---
10.23.10-13 seems says that function literals should be equivalent to their nested function equivalent. It doesn't say what kind, so the assumption is that this applies to both function literals and template-function literals.
---
Note: When comparing function literals with nested functions, the function form is analogous to static or non-nested functions, and the delegate form is analogous to non-static nested functions. I.e. a delegate literal can access non-static local variables in an enclosing function, a function literal cannot.
---
However, in your example, `fun` is not a nested function, it's a function-template. Is there really a distinction? Will have to have a think about it.
https://dlang.org/spec/expression.html#function_literalshttps://dlang.org/spec/template.html#function-templates
The location in the compiler where the deviation occurs is in `TemplateInstance.hasNestedArgs`.
https://github.com/dlang/dmd/blob/45a07c0a7d24485ef78d3196a029b8d1d8a0cdf7/src/dmd/dtemplate.d#L7290
During the inspection of all instantiation arguments, only only kind of template considered to be a local symbol are template function literals.
Global and static templates are `TemplateDeclaration.isstatic`, so nested templates could be added to this condition with:
if ((td && (td.literal || !td.issstatic)) || ...)
The consequences of opening this particular floodgate is unknown. It is only anticipated to affect `alias` template-parameters, of which currently nested templates just result in an error.
Comment #3 by ibuclaw — 2021-08-23T13:07:55Z
(In reply to Iain Buclaw from comment #2)
> if ((td && (td.literal || !td.issstatic)) || ...)
This change also allows issue 15298 to compile.
Comment #4 by dlang-bot — 2021-08-23T14:39:11Z
@ibuclaw created dlang/dmd pull request #13006 "fix Issue 15298 - Can't call nested template function unless it's anonymous" fixing this issue:
- fix Issue 21287 - Delegate in global template can't call non-anonymous nested function passed as alias
https://github.com/dlang/dmd/pull/13006
Comment #5 by robert.schadek — 2024-12-13T19:11:54Z