Bug 17871 – Delegate type inference doesn't work

Status
RESOLVED
Resolution
INVALID
Severity
enhancement
Priority
P1
Component
dmd
Product
D
Version
D2
Platform
All
OS
All
Creation time
2017-10-01T22:34:09Z
Last change time
2017-10-02T11:50:12Z
Assigned to
No Owner
Creator
Mathias Lang

Comments

Comment #0 by mathias.lang — 2017-10-01T22:34:09Z
I'm surprised that I couldn't find an issue about it, but this is probably a duplicate. In any case, the following code: ``` struct Symbol { public int opApply (scope int delegate (size_t, string) dg) { return 0; } public int opApply (scope int delegate (string) dg) { scope wrapper = (size_t, string v) { return dg(v); }; return this.opApply(wrapper); } } ``` Will trigger the following error: ``` bug.d(10): Error: variable bug.Symbol.opApply.wrapper type void is inferred from initializer (size_t, string v) { return dg(v); } , and variables cannot be of type void bug.d(10): Error: template lambda has no value ``` Using `auto` will provide the same result, same for the new delegate syntax. It looks quite weird that the frontend is not able to infer this type.
Comment #1 by ag0aep6g — 2017-10-02T10:42:02Z
This comes down to: ---- auto wrapper = (size_t) {}; ---- It doesn't compile because "size_t" is not the parameter type here. It's the parameter *name*. Since the parameter has no type, the function literal is a template. A template has no type, and you can't put it in a variable. Closing as invalid. Reopen if I'm missing the point.
Comment #2 by mathias.lang — 2017-10-02T10:54:55Z
Oh damn, of course. Thanks for pointing this out! It is rather inconsistent though: ``` auto wrapper = (foo) {}; ``` Doesn't compile, but: ``` auto wrapper = (int) {}; ``` Does. Likewise, naming the parameter make it compile: ``` auto wrapper = (size_t foo) {}; ``` The grammar mentions that a FunctionLiteral (https://dlang.org/spec/grammar.html#FunctionLiteral) is, in this case: ParameterMemberAttributes FunctionLiteralBody Skipping a couple of intermediate steps, we end up with a list of Parameter (https://dlang.org/spec/grammar.html#Parameter) which always starts with `Type` or `BasicType`, so it looks like the grammar is not up to date in that regard (unless I'm again missing something?).
Comment #3 by ag0aep6g — 2017-10-02T11:50:12Z
(In reply to Mathias Lang from comment #2) > It is rather inconsistent though: > ``` > auto wrapper = (foo) {}; > ``` > Doesn't compile, but: > ``` > auto wrapper = (int) {}; > ``` > Does. The key here is that `int` is a built-in type. I.e., "int" is a keyword and cannot be used as a parameter name. dmd is being smart and recognizes it as the type then. Similarly, stuff like `auto wrapper = (typeof(size_t.init)) {};` works, because `typeof(size_t.init)` isn't an identifier, so it can't be a parameter name. [...] > The grammar mentions that a FunctionLiteral > (https://dlang.org/spec/grammar.html#FunctionLiteral) is, in this case: > ParameterMemberAttributes FunctionLiteralBody > > Skipping a couple of intermediate steps, we end up with a list of Parameter > (https://dlang.org/spec/grammar.html#Parameter) which always starts with > `Type` or `BasicType`, so it looks like the grammar is not up to date in > that regard (unless I'm again missing something?). I think you're right. The compiler treats single identifiers differently in function literals than in function declarations (in `void f(size_t) {}`, "size_t" is the parameter *type*). But the grammar is the same for both. It should probably show the difference. Grammar-wise, the "size_t" in `(size_t) {}` is matched by the rule `Parameter: InOut_opt Type` ("size_t" -> Identifier -> ... -> Parameter). It could be argued that semantic analysis makes a parameter name out of the "Type". But then the grammar is clearly misleading.