[Issue 24785] New: Add explicit template arguments for lambdas
d-bugmail at puremagic.com
d-bugmail at puremagic.com
Wed Sep 25 16:38:03 UTC 2024
https://issues.dlang.org/show_bug.cgi?id=24785
Issue ID: 24785
Summary: Add explicit template arguments for lambdas
Product: D
Version: D2
Hardware: x86
OS: Windows
Status: NEW
Severity: enhancement
Priority: P1
Component: dmd
Assignee: nobody at puremagic.com
Reporter: qs.il.paperinik at gmail.com
Add explicit template arguments for lambdas
After the `function` and `delegate` keyword, optionally allow for a template
argument list, introduced by the `template` keyword and a following template
parameter list. The parameters of such a lambda would be parsed exactly like a
regular function’s parameter list, i.e. `function template() (x) {}` (unless
`x` is a type in scope) will not work. The explicit write-out of
`function(x){}` is `function template(T)(T x) {}`.
The advantages:
- A lambda can be a template, even if it would otherwise not be: `function
template() int (int x) => x`
- A programmer can use the template type parameters in the lambda body
- Constraints are possible
- The ordering of type parameters is up to the programmer: `function
template(T1, T2) (T2 x, T1 y) { }`
- Variadic lambdas are possible: `function template(Ts...) (Ts args) { }`
- Template parameters can be any kind of template parameter, not just type.
- Template parameters can have a specialization.
- Template parameters can have a default.
Not really an argument: C++20 is ahead of D in this regard.
Required grammar changes:
```diff
FunctionLiteral:
function RefOrAutoRef? BasicTypeWithSuffixes? ParameterWithAttributes?
FunctionLiteralBody
delegate RefOrAutoRef? BasicTypeWithSuffixes?
ParameterWithMemberAttributes? FunctionLiteralBody
+ function template TemplateParameters RefOrAutoRef?
BasicTypeWithSuffixes? ParameterWithAttributes? Constraint? FunctionLiteralBody
+ delegate template TemplateParameters RefOrAutoRef?
BasicTypeWithSuffixes? ParameterWithMemberAttributes? Constraint?
FunctionLiteralBody
```
A fully formed function literal can look like this:
```d
delegate template(T : Object = Object, Ts...)
auto ref T (auto ref Ts args) const @safe
if (allSatisfy!(function template(T) => is(T : Object), Ts))
in (Ts.length == 0 || args[$-1] !is null)
{ ... }
```
-------------------------------
I tried implementing this, and the parsing is doable, but it seems the
semantics doesn’t see the template parameters. A simple `function template(T)
=> is(T)` sets `is(T)` always `false`.
For a quick start for anyone who wants to tackle this, this is the diff of
parse.d I used: It works perfectly when using `alias fp = function template(T)
=> is(T);`, however, that’s due to `alias` lowering stuff to immediate
declarations.
diff --git a/compiler/src/dmd/parse.d b/compiler/src/dmd/parse.d
index bb2411825f..e4092f6040 100644
--- a/compiler/src/dmd/parse.d
+++ b/compiler/src/dmd/parse.d
@@ -5078,7 +5078,9 @@ class Parser(AST, Lexer = dmd.lexer.Lexer) : Lexer
private AST.Dsymbol parseFunctionLiteral()
{
const loc = token.loc;
+ bool isExplicitTemplate = false;
AST.TemplateParameters* tpl = null;
+ AST.Expression constraint = null;
AST.ParameterList parameterList;
AST.Type tret = null;
StorageClass stc = 0;
@@ -5090,6 +5092,14 @@ class Parser(AST, Lexer = dmd.lexer.Lexer) : Lexer
case TOK.delegate_:
save = token.value;
nextToken();
+
+ if (token.value == TOK.template_)
+ {
+ nextToken();
+ isExplicitTemplate = true;
+ tpl = parseTemplateParameterList();
+ }
+
if (token.value == TOK.auto_)
{
nextToken();
@@ -5158,7 +5168,7 @@ class Parser(AST, Lexer = dmd.lexer.Lexer) : Lexer
{
// (parameters) => expression
// (parameters) { statements... }
- parameterList = parseParameterList(&tpl);
+ parameterList = parseParameterList(isExplicitTemplate ? null :
&tpl);
stc = parsePostfix(stc, null);
if (StorageClass modStc = stc & STC.TYPECTOR)
{
@@ -5196,6 +5206,11 @@ class Parser(AST, Lexer = dmd.lexer.Lexer) : Lexer
assert(0);
}
+ if (isExplicitTemplate)
+ {
+ constraint = parseConstraint();
+ }
+
auto tf = new AST.TypeFunction(parameterList, tret, linkage, stc);
tf = cast(AST.TypeFunction)tf.addSTC(stc);
auto fd = new AST.FuncLiteralDeclaration(loc, Loc.initial, tf, save,
null, null, stc & STC.auto_);
@@ -5215,7 +5230,7 @@ class Parser(AST, Lexer = dmd.lexer.Lexer) : Lexer
}
else
{
- parseContracts(fd);
+ parseContracts(fd, isExplicitTemplate);
}
if (tpl)
--
More information about the Digitalmars-d-bugs
mailing list