September 25 [Issue 24785] New: Add explicit template arguments for lambdas | ||||
---|---|---|---|---|
| ||||
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@puremagic.com Reporter: qs.il.paperinik@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) -- |
Copyright © 1999-2021 by the D Language Foundation