Fix issue 21243 - Allow lambdas to return auto ref

This commit is contained in:
Paul Backus 2022-09-18 22:38:39 -04:00 committed by The Dlang Bot
parent 462affc6e6
commit dda09ee7b3
4 changed files with 94 additions and 5 deletions

View file

@ -3759,9 +3759,9 @@ extern (C++) final class FuncLiteralDeclaration : FuncDeclaration
// backend // backend
bool deferToObj; bool deferToObj;
extern (D) this(const ref Loc loc, const ref Loc endloc, Type type, TOK tok, ForeachStatement fes, Identifier id = null) extern (D) this(const ref Loc loc, const ref Loc endloc, Type type, TOK tok, ForeachStatement fes, Identifier id = null, StorageClass storage_class = STC.undefined_)
{ {
super(loc, endloc, null, STC.undefined_, type); super(loc, endloc, null, storage_class, type);
this.ident = id ? id : Id.empty; this.ident = id ? id : Id.empty;
this.tok = tok; this.tok = tok;
this.fes = fes; this.fes = fes;
@ -3775,7 +3775,7 @@ extern (C++) final class FuncLiteralDeclaration : FuncDeclaration
{ {
//printf("FuncLiteralDeclaration::syntaxCopy('%s')\n", toChars()); //printf("FuncLiteralDeclaration::syntaxCopy('%s')\n", toChars());
assert(!s); assert(!s);
auto f = new FuncLiteralDeclaration(loc, endloc, type.syntaxCopy(), tok, fes, ident); auto f = new FuncLiteralDeclaration(loc, endloc, type.syntaxCopy(), tok, fes, ident, storage_class & STC.auto_);
f.treq = treq; // don't need to copy f.treq = treq; // don't need to copy
FuncDeclaration.syntaxCopy(f); FuncDeclaration.syntaxCopy(f);
return f; return f;

View file

@ -4856,6 +4856,10 @@ class Parser(AST, Lexer = dmd.lexer.Lexer) : Lexer
token.value == TOK.identifier && peekNext() == TOK.goesTo || token.value == TOK.identifier && peekNext() == TOK.goesTo ||
token.value == TOK.ref_ && peekNext() == TOK.leftParenthesis && token.value == TOK.ref_ && peekNext() == TOK.leftParenthesis &&
skipAttributes(peekPastParen(peek(&token)), &tk) && skipAttributes(peekPastParen(peek(&token)), &tk) &&
(tk.value == TOK.goesTo || tk.value == TOK.leftCurly) ||
token.value == TOK.auto_ && peekNext() == TOK.ref_ &&
peekNext2() == TOK.leftParenthesis &&
skipAttributes(peekPastParen(peek(peek(&token))), &tk) &&
(tk.value == TOK.goesTo || tk.value == TOK.leftCurly) (tk.value == TOK.goesTo || tk.value == TOK.leftCurly)
) )
{ {
@ -4867,6 +4871,8 @@ class Parser(AST, Lexer = dmd.lexer.Lexer) : Lexer
// identifier => expression // identifier => expression
// ref (parameters) { statements... } // ref (parameters) { statements... }
// ref (parameters) => expression // ref (parameters) => expression
// auto ref (parameters) { statements... }
// auto ref (parameters) => expression
s = parseFunctionLiteral(); s = parseFunctionLiteral();
@ -4994,7 +5000,20 @@ class Parser(AST, Lexer = dmd.lexer.Lexer) : Lexer
case TOK.delegate_: case TOK.delegate_:
save = token.value; save = token.value;
nextToken(); nextToken();
if (token.value == TOK.ref_) if (token.value == TOK.auto_)
{
nextToken();
if (token.value == TOK.ref_)
{
// function auto ref (parameters) { statements... }
// delegate auto ref (parameters) { statements... }
stc = STC.auto_ | STC.ref_;
nextToken();
}
else
error("`auto` can only be used as part of `auto ref` for function literal return values");
}
else if (token.value == TOK.ref_)
{ {
// function ref (parameters) { statements... } // function ref (parameters) { statements... }
// delegate ref (parameters) { statements... } // delegate ref (parameters) { statements... }
@ -5022,6 +5041,20 @@ class Parser(AST, Lexer = dmd.lexer.Lexer) : Lexer
} }
goto case TOK.leftParenthesis; goto case TOK.leftParenthesis;
case TOK.auto_:
{
nextToken();
if (token.value == TOK.ref_)
{
// auto ref (parameters) => expression
// auto ref (parameters) { statements... }
stc = STC.auto_ | STC.ref_;
nextToken();
}
else
error("`auto` can only be used as part of `auto ref` for function literal return values");
goto case TOK.leftParenthesis;
}
case TOK.ref_: case TOK.ref_:
{ {
// ref (parameters) => expression // ref (parameters) => expression
@ -5074,7 +5107,7 @@ class Parser(AST, Lexer = dmd.lexer.Lexer) : Lexer
auto tf = new AST.TypeFunction(parameterList, tret, linkage, stc); auto tf = new AST.TypeFunction(parameterList, tret, linkage, stc);
tf = cast(AST.TypeFunction)tf.addSTC(stc); tf = cast(AST.TypeFunction)tf.addSTC(stc);
auto fd = new AST.FuncLiteralDeclaration(loc, Loc.initial, tf, save, null); auto fd = new AST.FuncLiteralDeclaration(loc, Loc.initial, tf, save, null, null, stc & STC.auto_);
if (token.value == TOK.goesTo) if (token.value == TOK.goesTo)
{ {
@ -8384,6 +8417,22 @@ LagainStc:
e = parseNewExp(null); e = parseNewExp(null);
break; break;
case TOK.auto_:
{
if (peekNext() == TOK.ref_ && peekNext2() == TOK.leftParenthesis)
{
Token* tk = peekPastParen(peek(peek(&token)));
if (skipAttributes(tk, &tk) && (tk.value == TOK.goesTo || tk.value == TOK.leftCurly))
{
// auto ref (arguments) => expression
// auto ref (arguments) { statements... }
goto case_delegate;
}
}
nextToken();
error("found `%s` when expecting `ref` and function literal following `auto`", token.toChars());
goto Lerr;
}
case TOK.ref_: case TOK.ref_:
{ {
if (peekNext() == TOK.leftParenthesis) if (peekNext() == TOK.leftParenthesis)

View file

@ -0,0 +1,21 @@
// Parsing - expressions
auto a = auto ref (int x) => x;
auto b = auto ref (int x) { return x; };
auto c = function auto ref (int x) { return x; };
auto d = delegate auto ref (int x) { return x; };
// Parsing - aliases
alias e = auto ref (int x) => x;
alias f = auto ref (int x) { return x; };
alias g = function auto ref (int x) { return x; };
alias h = delegate auto ref (int x) { return x; };
// Semantic
void test()
{
alias fun(alias x) = auto ref () => x;
int n = 123;
auto _ = fun!123();
static assert(!__traits(compiles, &fun!123())); // rvalue
fun!n() = 456; // lvalue
}

View file

@ -0,0 +1,19 @@
/+ TEST_OUTPUT:
---
fail_compilation/fail21243.d(16): Error: found `(` when expecting `ref` and function literal following `auto`
fail_compilation/fail21243.d(16): Error: semicolon expected following auto declaration, not `int`
fail_compilation/fail21243.d(16): Error: semicolon needed to end declaration of `x` instead of `)`
fail_compilation/fail21243.d(16): Error: declaration expected, not `)`
fail_compilation/fail21243.d(17): Error: `auto` can only be used as part of `auto ref` for function literal return values
fail_compilation/fail21243.d(18): Error: basic type expected, not `(`
fail_compilation/fail21243.d(18): Error: function declaration without return type. (Note that constructors are always named `this`)
fail_compilation/fail21243.d(18): Deprecation: storage class `auto` has no effect in type aliases
fail_compilation/fail21243.d(18): Error: semicolon expected to close `alias` declaration
fail_compilation/fail21243.d(18): Error: declaration expected, not `=>`
fail_compilation/fail21243.d(19): Error: `auto` can only be used as part of `auto ref` for function literal return values
---
+/
auto a = auto (int x) => x;
auto b = function auto (int x) { return x; };
alias c = auto (int x) => x;
alias d = function auto (int x) { return x; };