@@ -2227,34 +2227,10 @@ public void visitDeclarationExpression(DeclarationExpression expression) {
22272227 VariableExpression firstVar = (VariableExpression ) tupleExpressions .get (0 );
22282228 TypeTree typeExpr = visitVariableExpressionType (firstVar );
22292229
2230- Space beforeOpenParen = sourceBefore ("(" );
2231-
2232- List <JRightPadded <J .VariableDeclarations >> tupleVars = new ArrayList <>(tupleExpressions .size ());
2233- for (int i = 0 ; i < tupleExpressions .size (); i ++) {
2234- VariableExpression varExpr = (VariableExpression ) tupleExpressions .get (i );
2235- TypeTree innerType = visitVariableExpressionType (varExpr );
2236- J .Identifier name = doVisit (varExpr );
2237- J .VariableDeclarations .NamedVariable nv = new J .VariableDeclarations .NamedVariable (
2238- randomId (),
2239- name .getPrefix (),
2240- Markers .EMPTY ,
2241- name .withPrefix (EMPTY ),
2242- emptyList (),
2243- null ,
2244- typeMapping .variableType (name .getSimpleName (), innerType .getType ()));
2245- J .VariableDeclarations innerDecl = new J .VariableDeclarations (
2246- randomId (), EMPTY , Markers .EMPTY ,
2247- emptyList (), emptyList (),
2248- innerType , null ,
2249- singletonList (JRightPadded .build (nv )));
2250- Space after = i < tupleExpressions .size () - 1 ? sourceBefore ("," ) : sourceBefore (")" );
2251- tupleVars .add (JRightPadded .<J .VariableDeclarations >build (innerDecl ).withAfter (after ));
2252- }
2253-
2254- G .TupleExpression tupleDeclarator = new G .TupleExpression (
2255- randomId (), EMPTY , Markers .EMPTY ,
2256- JContainer .build (beforeOpenParen , tupleVars , Markers .EMPTY ),
2257- null );
2230+ List <VariableExpression > tupleVarExprs = tupleExpressions .stream ()
2231+ .map (e -> (VariableExpression ) e )
2232+ .collect (toList ());
2233+ G .TupleExpression tupleDeclarator = parseTupleExpression (tupleVarExprs );
22582234
22592235 J .VariableDeclarations .NamedVariable namedVariable = new J .VariableDeclarations .NamedVariable (
22602236 randomId (), EMPTY , Markers .EMPTY ,
@@ -3022,11 +2998,28 @@ public void visitThrowStatement(ThrowStatement statement) {
30222998 queue .add (new J .Throw (randomId (), fmt , Markers .EMPTY , doVisit (statement .getExpression ())));
30232999 }
30243000
3025- // the current understanding is that TupleExpression only exist as method invocation arguments.
3026- // this is the reason behind the simplifying assumption that there is one expression, and it is
3027- // a NamedArgumentListExpression.
30283001 @ Override
30293002 public void visitTupleExpression (TupleExpression tuple ) {
3003+ List <org .codehaus .groovy .ast .expr .Expression > expressions = tuple .getExpressions ();
3004+
3005+ // A TupleExpression whose visible elements are all VariableExpression is the LHS of a
3006+ // destructuring assignment without `def`: (a, b) = expr.
3007+ // (Synthetic elements like the implicit outer-`this` are VariableExpression too but
3008+ // don't appear in source and must not influence this check.)
3009+ List <org .codehaus .groovy .ast .expr .Expression > visibleExpressions = expressions .stream ()
3010+ .filter (GroovyParserVisitor .this ::appearsInSource )
3011+ .collect (toList ());
3012+ boolean isDestructuringLhs = !visibleExpressions .isEmpty () &&
3013+ visibleExpressions .stream ().allMatch (e -> e instanceof VariableExpression );
3014+ if (isDestructuringLhs ) {
3015+ List <VariableExpression > varExprs = visibleExpressions .stream ()
3016+ .map (e -> (VariableExpression ) e )
3017+ .collect (toList ());
3018+ queue .add (parseTupleExpression (varExprs ));
3019+ return ;
3020+ }
3021+
3022+ // TupleExpression as method invocation arguments: each element is a NamedArgumentListExpression
30303023 int saveCursor = cursor ;
30313024 Space beforeOpenParen = whitespace ();
30323025
@@ -3039,8 +3032,8 @@ public void visitTupleExpression(TupleExpression tuple) {
30393032 cursor = saveCursor ;
30403033 }
30413034
3042- List <JRightPadded <Expression >> args = new ArrayList <>(tuple . getExpressions () .size ());
3043- for (org .codehaus .groovy .ast .expr .Expression expression : tuple . getExpressions () ) {
3035+ List <JRightPadded <Expression >> args = new ArrayList <>(expressions .size ());
3036+ for (org .codehaus .groovy .ast .expr .Expression expression : expressions ) {
30443037 // Skip synthetic args (e.g. the implicit outer-`this` Groovy adds when
30453038 // constructing a non-static inner class from within the enclosing class)
30463039 if (!appearsInSource (expression )) {
@@ -3084,6 +3077,27 @@ public void visitTupleExpression(TupleExpression tuple) {
30843077 queue .add (JContainer .build (beforeOpenParen , args , Markers .EMPTY ));
30853078 }
30863079
3080+ private G .TupleExpression parseTupleExpression (List <VariableExpression > varExprs ) {
3081+ Space beforeOpenParen = sourceBefore ("(" );
3082+ List <JRightPadded <J .VariableDeclarations >> tupleVars = new ArrayList <>(varExprs .size ());
3083+ for (int i = 0 ; i < varExprs .size (); i ++) {
3084+ VariableExpression varExpr = varExprs .get (i );
3085+ TypeTree innerType = visitVariableExpressionType (varExpr );
3086+ J .Identifier name = doVisit (varExpr );
3087+ J .VariableDeclarations .NamedVariable nv = new J .VariableDeclarations .NamedVariable (
3088+ randomId (), name .getPrefix (), Markers .EMPTY ,
3089+ name .withPrefix (EMPTY ), emptyList (), null ,
3090+ typeMapping .variableType (name .getSimpleName (), innerType .getType ()));
3091+ J .VariableDeclarations innerDecl = new J .VariableDeclarations (
3092+ randomId (), EMPTY , Markers .EMPTY , emptyList (), emptyList (),
3093+ innerType , null , singletonList (JRightPadded .build (nv )));
3094+ Space after = i < varExprs .size () - 1 ? sourceBefore ("," ) : sourceBefore (")" );
3095+ tupleVars .add (JRightPadded .<J .VariableDeclarations >build (innerDecl ).withAfter (after ));
3096+ }
3097+ return new G .TupleExpression (randomId (), EMPTY , Markers .EMPTY ,
3098+ JContainer .build (beforeOpenParen , tupleVars , Markers .EMPTY ), null );
3099+ }
3100+
30873101 @ Override
30883102 public void visitTryCatchFinally (TryCatchStatement node ) {
30893103 Space prefix = sourceBefore ("try" );
0 commit comments