You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@groovy.apache.org by su...@apache.org on 2018/11/17 16:36:43 UTC
groovy git commit: GROOVY-8887: Support multi-assignment of tuples in
STC(closes #824)
Repository: groovy
Updated Branches:
refs/heads/master 55fd0ddaa -> f364a0c4b
GROOVY-8887: Support multi-assignment of tuples in STC(closes #824)
Project: http://git-wip-us.apache.org/repos/asf/groovy/repo
Commit: http://git-wip-us.apache.org/repos/asf/groovy/commit/f364a0c4
Tree: http://git-wip-us.apache.org/repos/asf/groovy/tree/f364a0c4
Diff: http://git-wip-us.apache.org/repos/asf/groovy/diff/f364a0c4
Branch: refs/heads/master
Commit: f364a0c4bff71a3f9eb688285ef58c314a61ae8e
Parents: 55fd0dd
Author: Daniel Sun <su...@apache.org>
Authored: Sun Nov 18 00:36:19 2018 +0800
Committer: Daniel Sun <su...@apache.org>
Committed: Sun Nov 18 00:36:34 2018 +0800
----------------------------------------------------------------------
.../org/codehaus/groovy/ast/ClassHelper.java | 25 +++++++++
.../stc/StaticTypeCheckingVisitor.java | 51 ++++++++++++++++++-
src/test/groovy/bugs/Groovy8887.groovy | 53 ++++++++++++++++++++
3 files changed, 128 insertions(+), 1 deletion(-)
----------------------------------------------------------------------
http://git-wip-us.apache.org/repos/asf/groovy/blob/f364a0c4/src/main/java/org/codehaus/groovy/ast/ClassHelper.java
----------------------------------------------------------------------
diff --git a/src/main/java/org/codehaus/groovy/ast/ClassHelper.java b/src/main/java/org/codehaus/groovy/ast/ClassHelper.java
index 2e034fb..0bdf585 100644
--- a/src/main/java/org/codehaus/groovy/ast/ClassHelper.java
+++ b/src/main/java/org/codehaus/groovy/ast/ClassHelper.java
@@ -28,6 +28,24 @@ import groovy.lang.MetaClass;
import groovy.lang.Range;
import groovy.lang.Reference;
import groovy.lang.Script;
+import groovy.lang.Tuple;
+import groovy.lang.Tuple0;
+import groovy.lang.Tuple1;
+import groovy.lang.Tuple10;
+import groovy.lang.Tuple11;
+import groovy.lang.Tuple12;
+import groovy.lang.Tuple13;
+import groovy.lang.Tuple14;
+import groovy.lang.Tuple15;
+import groovy.lang.Tuple16;
+import groovy.lang.Tuple2;
+import groovy.lang.Tuple3;
+import groovy.lang.Tuple4;
+import groovy.lang.Tuple5;
+import groovy.lang.Tuple6;
+import groovy.lang.Tuple7;
+import groovy.lang.Tuple8;
+import groovy.lang.Tuple9;
import org.apache.groovy.util.Maps;
import org.codehaus.groovy.classgen.asm.util.TypeUtil;
import org.codehaus.groovy.runtime.GeneratedClosure;
@@ -69,6 +87,12 @@ public class ClassHelper {
Iterator.class, GeneratedClosure.class, GeneratedLambda.class, GroovyObjectSupport.class
};
+ public static final Class[] TUPLE_CLASSES = new Class[] {
+ Tuple0.class, Tuple1.class, Tuple2.class, Tuple3.class, Tuple4.class, Tuple5.class, Tuple6.class,
+ Tuple7.class, Tuple8.class, Tuple9.class, Tuple10.class, Tuple11.class, Tuple12.class, Tuple13.class,
+ Tuple14.class, Tuple15.class, Tuple16.class
+ };
+
private static final String[] primitiveClassNames = new String[]{
"", "boolean", "char", "byte", "short",
"int", "long", "double", "float", "void"
@@ -79,6 +103,7 @@ public class ClassHelper {
VOID_TYPE = makeCached(Void.TYPE),
CLOSURE_TYPE = makeCached(Closure.class),
GSTRING_TYPE = makeCached(GString.class), LIST_TYPE = makeWithoutCaching(List.class),
+ TUPLE_TYPE = makeWithoutCaching(Tuple.class),
MAP_TYPE = makeWithoutCaching(Map.class), RANGE_TYPE = makeCached(Range.class),
PATTERN_TYPE = makeCached(Pattern.class), STRING_TYPE = makeCached(String.class),
SCRIPT_TYPE = makeCached(Script.class), REFERENCE_TYPE = makeWithoutCaching(Reference.class),
http://git-wip-us.apache.org/repos/asf/groovy/blob/f364a0c4/src/main/java/org/codehaus/groovy/transform/stc/StaticTypeCheckingVisitor.java
----------------------------------------------------------------------
diff --git a/src/main/java/org/codehaus/groovy/transform/stc/StaticTypeCheckingVisitor.java b/src/main/java/org/codehaus/groovy/transform/stc/StaticTypeCheckingVisitor.java
index 72ea3bc..f9b0a2a 100644
--- a/src/main/java/org/codehaus/groovy/transform/stc/StaticTypeCheckingVisitor.java
+++ b/src/main/java/org/codehaus/groovy/transform/stc/StaticTypeCheckingVisitor.java
@@ -153,6 +153,7 @@ import static org.codehaus.groovy.ast.ClassHelper.PATTERN_TYPE;
import static org.codehaus.groovy.ast.ClassHelper.RANGE_TYPE;
import static org.codehaus.groovy.ast.ClassHelper.STRING_TYPE;
import static org.codehaus.groovy.ast.ClassHelper.Short_TYPE;
+import static org.codehaus.groovy.ast.ClassHelper.TUPLE_CLASSES;
import static org.codehaus.groovy.ast.ClassHelper.VOID_TYPE;
import static org.codehaus.groovy.ast.ClassHelper.boolean_TYPE;
import static org.codehaus.groovy.ast.ClassHelper.byte_TYPE;
@@ -1085,11 +1086,14 @@ public class StaticTypeCheckingVisitor extends ClassCodeVisitorSupport {
// multiple assignment check
if (!(leftExpression instanceof TupleExpression)) return true;
- if (!(rightExpression instanceof ListExpression)) {
+ Expression transformedRightExpression = transformRightExpressionToSupportMultipleAssignment(rightExpression);
+ if (null == transformedRightExpression) {
addStaticTypeError("Multiple assignments without list expressions on the right hand side are unsupported in static type checking mode", rightExpression);
return false;
}
+ rightExpression = transformedRightExpression;
+
TupleExpression tuple = (TupleExpression) leftExpression;
ListExpression list = (ListExpression) rightExpression;
List<Expression> listExpressions = list.getExpressions();
@@ -1114,6 +1118,51 @@ public class StaticTypeCheckingVisitor extends ClassCodeVisitorSupport {
return true;
}
+ private Expression transformRightExpressionToSupportMultipleAssignment(Expression rightExpression) {
+ if (rightExpression instanceof ListExpression) {
+ return rightExpression;
+ }
+
+ ClassNode cn = null;
+ if (rightExpression instanceof MethodCallExpression || rightExpression instanceof VariableExpression) {
+ cn = rightExpression.getType();
+ }
+
+ if (null == cn) {
+ return null;
+ }
+
+ Expression listExpression = transformToListExpression(rightExpression, cn);
+ if (listExpression != null) return listExpression;
+
+ return null;
+ }
+
+ private Expression transformToListExpression(Expression expression, ClassNode cn) {
+ if (null != cn && cn.isDerivedFrom(ClassHelper.TUPLE_TYPE)) { // just for performance to check
+ for (int i = 0, n = TUPLE_CLASSES.length; i < n; i++) {
+ Class tcn = TUPLE_CLASSES[i];
+ if (tcn.equals(cn.getTypeClass())) {
+ ListExpression listExpression = new ListExpression();
+ GenericsType[] genericsTypes = cn.getGenericsTypes();
+ for (int j = 0; j < i; j++) {
+ // the index of element in tuple starts with 1
+ MethodCallExpression mce = new MethodCallExpression(expression, "v" + (j + 1), ArgumentListExpression.EMPTY_ARGUMENTS);
+ ClassNode elementType = null != genericsTypes ? genericsTypes[j].getType() : ClassHelper.OBJECT_TYPE;
+ mce.setType(elementType);
+ storeType(mce, elementType);
+ listExpression.addExpression(mce);
+ }
+
+ listExpression.setSourcePosition(expression);
+
+ return listExpression;
+ }
+ }
+ }
+ return null;
+ }
+
private static ClassNode adjustTypeForSpreading(ClassNode inferredRightExpressionType, Expression leftExpression) {
// imagine we have: list*.foo = 100
// then the assignment must be checked against [100], not 100
http://git-wip-us.apache.org/repos/asf/groovy/blob/f364a0c4/src/test/groovy/bugs/Groovy8887.groovy
----------------------------------------------------------------------
diff --git a/src/test/groovy/bugs/Groovy8887.groovy b/src/test/groovy/bugs/Groovy8887.groovy
new file mode 100644
index 0000000..2c4e80c
--- /dev/null
+++ b/src/test/groovy/bugs/Groovy8887.groovy
@@ -0,0 +1,53 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package groovy.bugs
+
+class Groovy8887 extends GroovyTestCase {
+ void testMultiAssignment() {
+ assertScript '''
+ @groovy.transform.CompileStatic
+ class TtcTuple {
+ void multiAssignedByMethodCall() {
+ def (String name, Integer age) = findPersonInfo()
+
+ assert 'Daniel' == name
+ assert 35 == age
+ }
+
+ void multiAssignedByVariableAccess() {
+ Tuple2<String, Integer> personInfo = findPersonInfo()
+ def (String name, Integer age) = personInfo
+
+ assert 'Daniel' == name
+ assert 35 == age
+ }
+
+ Tuple2<String, Integer> findPersonInfo() {
+ Tuple2<String, Integer> t = new Tuple2<>('Daniel', 35)
+
+ return t
+ }
+ }
+
+ def tt = new TtcTuple()
+ tt.multiAssignedByMethodCall()
+ tt.multiAssignedByVariableAccess()
+ '''
+ }
+}