Jump to page: 1 2
Thread overview
[Issue 18199] Error with lambda in struct initializer
Mar 17, 2018
John Belmonte
Mar 18, 2018
John Belmonte
Mar 18, 2018
John Belmonte
Mar 18, 2018
John Belmonte
Mar 18, 2018
John Belmonte
Mar 18, 2018
John Belmonte
Mar 19, 2018
John Belmonte
Mar 19, 2018
John Belmonte
January 06, 2018
https://issues.dlang.org/show_bug.cgi?id=18199

--- Comment #1 from elronnd@elronnd.net ---
Oh, one more thing.

Bla bla = {(int a, int b) => a + b};

works fine.

--
March 17, 2018
https://issues.dlang.org/show_bug.cgi?id=18199

John Belmonte <john@neggie.net> changed:

           What    |Removed                     |Added
----------------------------------------------------------------------------
                 CC|                            |john@neggie.net

--- Comment #2 from John Belmonte <john@neggie.net> ---
The memberName:expression variant of initialization is also affected:

struct Foo {
    int function(int) bar;
}

static Foo foo = {
    bar : function(x) { return 2 * x; },  // broken
    //bar : (x) => 2 * x,  // works
};

This seems to be a parsing issue where the struct initializer can't handle nested curly brackets.

--
March 18, 2018
https://issues.dlang.org/show_bug.cgi?id=18199

--- Comment #3 from John Belmonte <john@neggie.net> ---
I'm trying to locate relevant code in the dmd source code, any pointers would be appreciated.

The emitted "Deprecation: use { } for an empty statement, not ;" error is telling.  We can infer that the compiler is incorrectly interpreting the initializer expression as a statement.

--
March 18, 2018
https://issues.dlang.org/show_bug.cgi?id=18199

--- Comment #4 from John Belmonte <john@neggie.net> ---
The problem stems from the presence of the "return" token in the lambda expression, not the curly brackets.

parseInitializer() scans ahead to see if there is a struct initializer (in
curly brackets).  However the scan is aborted when the return token is hit.

https://github.com/dlang/dmd/blob/4244b8b1abea8ad26941c33464780a13f554b0bf/src/dmd/parse.d#L6043

--
March 18, 2018
https://issues.dlang.org/show_bug.cgi?id=18199

--- Comment #5 from John Belmonte <john@neggie.net> ---
To clarify, the struct initializer test aborts on any semicolon or return token, which can happen in any function literal with curly brackets.

I believe these are all the cases which need to additionally be tolerated:

  function (parameters) { statements... }
  delegate (parameters) { statements... }
  (parameters) { statements... }
  { statements... }

--
March 18, 2018
https://issues.dlang.org/show_bug.cgi?id=18199

--- Comment #6 from John Belmonte <john@neggie.net> ---
Here is my understanding of the current code's intention.  When presented with "MyType foo = { ... }", the parser must infer whether the RHS is a struct initializer or a 0-parameter function literal without knowing anything about MyType.  A contrived example of the two cases, respectively:


  // RHS is struct initializer (e.g. MyType is struct with a string field)
  static MyType foo = {
    "a" + "b",
  };

  // RHS is function literal (e.g. MyType is alias of void function())
  static MyType bar = {
    "a" + "b";
  };

So the implementation uses the presence of semicolon or return tokens to infer that the RHS is a function literal.  However that solution yields the wrong answer when a struct initializer happens to hold certain forms of function literals.

To fix this the parser may require an isFunctionLiteral() at least handling the "{ ... }" form.  A caveat with this approach is that a malformed function literal will be parsed as a struct initializer, yielding confusing error reports.

--
March 18, 2018
https://issues.dlang.org/show_bug.cgi?id=18199

John Belmonte <john@neggie.net> changed:

           What    |Removed                     |Added
----------------------------------------------------------------------------
           Assignee|nobody@puremagic.com        |john@neggie.net

--- Comment #7 from John Belmonte <john@neggie.net> ---
Besides the code's documented case of "{}" (could be empty struct initializer or empty parameterless function literal), there is another ambiguous case:

  static MyStruct foo = {
    { return 1 + 1; }
  };

where RHS could either be a struct initializer (with member type "int
function()") or function literal with a needless added scope.

In the "{}" case, the code sides with struct initializer.  This makes sense
since the function literal could be disambiguated in several ways (e.g. as
"function() {}").

Given that, I propose to resolve this bug as follows:

   1) document this other ambiguous case
   2) document why we side with struct literal in ambiguous cases (i.e. since
you can disambiguate function literal cases via extra syntax)
   3) change the parser to only abort struct literal look-ahead if semicolon or
return token appears at top level of curly brackets, so that struct initializer
may contain function literals

--
March 19, 2018
https://issues.dlang.org/show_bug.cgi?id=18199

--- Comment #8 from John Belmonte <john@neggie.net> ---
https://github.com/dlang/dmd/pull/8051

--
March 19, 2018
https://issues.dlang.org/show_bug.cgi?id=18199

--- Comment #9 from John Belmonte <john@neggie.net> ---
The attempted change to parser.d broke some code in a test application.  It's possible to have a function body with no colon or return tokens at the top level (e.g. a body with just a switch statement).

I also realized that the current dmd code can misinterpret a function literal as a struct initializer as well.  Contrived, but consider the following function body which has no colon or return at any scope:

  static MyFun foo = {
    final switch(5) {
    }
  };

So the "color or return" test is clearly not robust for discerning function literal from struct initializer.

New plan is to try to implement a simple lookahead to test for struct initializer.

--
April 10, 2018
https://issues.dlang.org/show_bug.cgi?id=18199

--- Comment #10 from github-bugzilla@puremagic.com ---
Commits pushed to master at https://github.com/dlang/dmd

https://github.com/dlang/dmd/commit/019f0016cf7a6e11584fe0188f9e692215cce212 fix Issue 18199 - Error with lambda in struct initializer

Allow struct initializers to include all function literal forms.

Previously, a function literal containing semicolon or return tokens would cause the containing struct initializer to be incorrectly treated as a parameterless funtion literal (i.e. {statements...}).

The issue is resolved by only aborting the struct initializer lookahead when statement tokens appear at the top curly bracket scope.

A bug in the converse case, where a function literal containing no semicolon or return tokens would be incorrectly parsed as a struct initializer, is also addressed.

Also, document another ambiguous case in function literal vs. struct initializer, as well as explain why these are resolved as struct initializer.

https://github.com/dlang/dmd/commit/1edd074334f9f65d75d318df347f377d69eb002e Merge pull request #8051 from belm0/fix-18199

fix Issue 18199 - Error with lambda in struct initializer merged-on-behalf-of: Mike Franklin <JinShil@users.noreply.github.com>

--
« First   ‹ Prev
1 2