You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@groovy.apache.org by em...@apache.org on 2022/04/07 16:40:14 UTC
[groovy] branch GROOVY_3_0_X updated: GROOVY-9033: STC: resolve "def list = []" to List
This is an automated email from the ASF dual-hosted git repository.
emilles pushed a commit to branch GROOVY_3_0_X
in repository https://gitbox.apache.org/repos/asf/groovy.git
The following commit(s) were added to refs/heads/GROOVY_3_0_X by this push:
new 0e976a58ad GROOVY-9033: STC: resolve "def list = []" to List<Object> not List<E>
0e976a58ad is described below
commit 0e976a58ad1780578697c8e32b82d305c147cbcf
Author: Eric Milles <er...@thomsonreuters.com>
AuthorDate: Fri Apr 16 16:01:20 2021 -0500
GROOVY-9033: STC: resolve "def list = []" to List<Object> not List<E>
GROOVY-10089, GROOVY-10324, GROOVY-10367
---
.../transform/stc/StaticTypeCheckingSupport.java | 49 ++++----
.../transform/stc/StaticTypeCheckingVisitor.java | 87 +++++++-------
.../groovy/transform/stc/GenericsSTCTest.groovy | 8 +-
.../transform/stc/TypeInferenceSTCTest.groovy | 129 ++++++++++++++++-----
.../classgen/asm/sc/BugsStaticCompileTest.groovy | 4 +-
.../asm/sc/TypeInferenceStaticCompileTest.groovy | 68 +----------
6 files changed, 179 insertions(+), 166 deletions(-)
diff --git a/src/main/java/org/codehaus/groovy/transform/stc/StaticTypeCheckingSupport.java b/src/main/java/org/codehaus/groovy/transform/stc/StaticTypeCheckingSupport.java
index 367b8cdb7d..873f228a85 100644
--- a/src/main/java/org/codehaus/groovy/transform/stc/StaticTypeCheckingSupport.java
+++ b/src/main/java/org/codehaus/groovy/transform/stc/StaticTypeCheckingSupport.java
@@ -1296,31 +1296,32 @@ public abstract class StaticTypeCheckingSupport {
}
protected static ClassNode fullyResolveType(final ClassNode type, final Map<GenericsTypeName, GenericsType> placeholders) {
- if (type.isUsingGenerics() && !type.isGenericsPlaceHolder()) {
- GenericsType[] gts = type.getGenericsTypes();
- if (gts != null) {
- GenericsType[] copy = new GenericsType[gts.length];
- for (int i = 0, n = gts.length; i < n; i += 1) {
- GenericsType genericsType = gts[i];
- if (genericsType.isPlaceholder() && placeholders.containsKey(new GenericsTypeName(genericsType.getName()))) {
- copy[i] = placeholders.get(new GenericsTypeName(genericsType.getName()));
- } else {
- copy[i] = fullyResolve(genericsType, placeholders);
- }
+ if (type.isArray()) {
+ return fullyResolveType(type.getComponentType(), placeholders).makeArray();
+ }
+ if (type.isUsingGenerics()) {
+ if (type.isGenericsPlaceHolder()) {
+ GenericsType gt = placeholders.get(new GenericsTypeName(type.getUnresolvedName()));
+ if (gt != null) {
+ return gt.getType();
}
- gts = copy;
- }
- ClassNode result = type.getPlainNodeReference();
- result.setGenericsTypes(gts);
- return result;
- } else if (type.isUsingGenerics() && OBJECT_TYPE.equals(type) && type.getGenericsTypes() != null) {
- // Object<T>
- GenericsType genericsType = placeholders.get(new GenericsTypeName(type.getGenericsTypes()[0].getName()));
- if (genericsType != null) {
- return genericsType.getType();
+ ClassNode cn = type.redirect();
+ return cn != type ? cn : OBJECT_TYPE;
+ } else {
+ GenericsType[] gts = type.getGenericsTypes();
+ if (gts != null) {
+ gts = Arrays.stream(gts).map(gt -> {
+ if (gt.isPlaceholder()) {
+ GenericsTypeName gtn = new GenericsTypeName(gt.getName());
+ return placeholders.getOrDefault(gtn, extractType(gt).asGenericsType());
+ }
+ return fullyResolve(gt, placeholders);
+ }).toArray(GenericsType[]::new);
+ }
+ ClassNode cn = type.getPlainNodeReference();
+ cn.setGenericsTypes(gts);
+ return cn;
}
- } else if (type.isArray()) {
- return fullyResolveType(type.getComponentType(), placeholders).makeArray();
}
return type;
}
@@ -1717,7 +1718,7 @@ public abstract class StaticTypeCheckingSupport {
}
public static ClassNode getCorrectedClassNode(final ClassNode type, final ClassNode superClass, final boolean handlingGenerics) {
- if (handlingGenerics && missesGenericsTypes(type)) return superClass.getPlainNodeReference();
+ if (handlingGenerics && GenericsUtils.hasUnresolvedGenerics(type)) return superClass.getPlainNodeReference();
return GenericsUtils.correctToGenericsSpecRecurse(GenericsUtils.createGenericsSpec(type), superClass);
}
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 fcfc80f29a..fe75e83e78 100644
--- a/src/main/java/org/codehaus/groovy/transform/stc/StaticTypeCheckingVisitor.java
+++ b/src/main/java/org/codehaus/groovy/transform/stc/StaticTypeCheckingVisitor.java
@@ -198,7 +198,6 @@ import static org.codehaus.groovy.ast.tools.GeneralUtils.localVarX;
import static org.codehaus.groovy.ast.tools.GeneralUtils.propX;
import static org.codehaus.groovy.ast.tools.GeneralUtils.thisPropX;
import static org.codehaus.groovy.ast.tools.GeneralUtils.varX;
-import static org.codehaus.groovy.ast.tools.GenericsUtils.toGenericTypesString;
import static org.codehaus.groovy.ast.tools.WideningCategories.isBigDecCategory;
import static org.codehaus.groovy.ast.tools.WideningCategories.isBigIntCategory;
import static org.codehaus.groovy.ast.tools.WideningCategories.isDouble;
@@ -804,24 +803,6 @@ public class StaticTypeCheckingVisitor extends ClassCodeVisitorSupport {
typeCheckingContext.secondPassExpressions.add(new SecondPassExpression(expression));
}
- boolean isAssignment = isAssignment(expression.getOperation().getType());
- if (isAssignment && rightExpression instanceof ConstructorCallExpression) {
- inferDiamondType((ConstructorCallExpression) rightExpression, lType);
- }
- if (isAssignment && lType.isUsingGenerics() && missesGenericsTypes(resultType)) {
- // unchecked assignment
- // examples:
- // List<A> list = []
- // List<A> list = new LinkedList()
- // Iterable<A> list = new LinkedList()
-
- // in that case, the inferred type of the binary expression is the type of the RHS
- // "completed" with generics type information available in the LHS
- ClassNode completedType = GenericsUtils.parameterizeType(lType, resultType.getPlainNodeReference());
-
- resultType = completedType;
- }
-
if (isArrayOp(op)
&& !lType.isArray()
&& enclosingBinaryExpression != null
@@ -842,16 +823,40 @@ public class StaticTypeCheckingVisitor extends ClassCodeVisitorSupport {
}
boolean isEmptyDeclaration = (expression instanceof DeclarationExpression && rightExpression instanceof EmptyExpression);
- if (isAssignment && !isEmptyDeclaration) {
+ if (!isEmptyDeclaration && isAssignment(op)) {
+ if (rightExpression instanceof ConstructorCallExpression)
+ inferDiamondType((ConstructorCallExpression) rightExpression, lType);
+
+ if (lType.isUsingGenerics() && missesGenericsTypes(resultType)) {
+ // unchecked assignment
+ // List<Type> list = new LinkedList()
+ // Iterable<Type> iter = new LinkedList()
+ // Collection<Type> coll = Collections.emptyList()
+ // Collection<Type> view = ConcurrentHashMap.newKeySet()
+
+ // the inferred type of the binary expression is the type of the RHS
+ // "completed" with generics type information available from the LHS
+ if (lType.equals(resultType)) {
+ if (!lType.isGenericsPlaceHolder()) resultType = lType;
+ } else if (!resultType.isGenericsPlaceHolder()) { // GROOVY-10235, GROOVY-10324, et al.
+ Map<GenericsTypeName, GenericsType> gt = new HashMap<>();
+ extractGenericsConnections(gt, resultType, resultType.redirect());
+ ClassNode sc = resultType;
+ do { sc = getNextSuperClass(sc, lType);
+ } while (sc != null && !sc.equals(lType));
+ extractGenericsConnections(gt, lType, sc);
+
+ resultType = applyGenericsContext(gt, resultType.redirect());
+ }
+ }
+
ClassNode originType = getOriginalDeclarationType(leftExpression);
typeCheckAssignment(expression, leftExpression, originType, rightExpression, resultType);
- // if assignment succeeds but result type is not a subtype of original type, then we are in a special cast handling
- // and we must update the result type
- if (!implementsInterfaceOrIsSubclassOf(getWrapper(resultType), getWrapper(originType))) {
+ // check for implicit conversion like "String a = 123", "int[] b = [1,2,3]", "List c = [].stream()", etc.
+ if (!implementsInterfaceOrIsSubclassOf(wrapTypeIfNecessary(resultType), wrapTypeIfNecessary(originType))) {
resultType = originType;
- } else if (lType.isUsingGenerics() && !lType.isEnum() && hasRHSIncompleteGenericTypeInfo(resultType)) {
- // for example, LHS is List<ConcreteClass> and RHS is List<T> where T is a placeholder
- resultType = lType;
+ } else if (isPrimitiveType(originType) && resultType.equals(getWrapper(originType))) {
+ resultType = originType; // retain primitive semantics
} else {
// GROOVY-7549: RHS type may not be accessible to enclosing class
int modifiers = resultType.getModifiers();
@@ -860,14 +865,12 @@ public class StaticTypeCheckingVisitor extends ClassCodeVisitorSupport {
&& !getOutermost(enclosingType).equals(getOutermost(resultType))
&& (Modifier.isPrivate(modifiers) || !Objects.equals(enclosingType.getPackageName(), resultType.getPackageName()))) {
resultType = originType; // TODO: Find accesible type in hierarchy of resultType?
+ } else if (GenericsUtils.hasUnresolvedGenerics(resultType)) { // GROOVY-9033, GROOVY-10089, et al.
+ Map<GenericsTypeName, GenericsType> enclosing = extractGenericsParameterMapOfThis(typeCheckingContext);
+ resultType = fullyResolveType(resultType, Optional.ofNullable(enclosing).orElseGet(Collections::emptyMap));
}
}
- // make sure we keep primitive types
- if (isPrimitiveType(originType) && resultType.equals(getWrapper(originType))) {
- resultType = originType;
- }
-
// track conditional assignment
if (!isNullConstant(rightExpression)
&& leftExpression instanceof VariableExpression
@@ -1261,9 +1264,9 @@ public class StaticTypeCheckingVisitor extends ClassCodeVisitorSupport {
private void checkTypeGenerics(final ClassNode leftExpressionType, final ClassNode wrappedRHS, final Expression rightExpression) {
// last, check generic type information to ensure that inferred types are compatible
if (!leftExpressionType.isUsingGenerics()) return;
- // List<Foo> l = new List() is an example for incomplete generics type info
- // we assume arity related errors are already handled here.
- if (hasRHSIncompleteGenericTypeInfo(wrappedRHS)) return;
+ // example of incomplete type info: "List<Type> list = new LinkedList()"
+ // we assume arity related errors are already handled here
+ if (missesGenericsTypes(wrappedRHS)) return;
GenericsType gt = GenericsUtils.buildWildcardType(leftExpressionType);
if (UNKNOWN_PARAMETER_TYPE.equals(wrappedRHS) ||
@@ -1342,6 +1345,7 @@ public class StaticTypeCheckingVisitor extends ClassCodeVisitorSupport {
typeCheckingContext.popEnclosingBinaryExpression();
}
+ @Deprecated
protected static boolean hasRHSIncompleteGenericTypeInfo(final ClassNode inferredRightExpressionType) {
boolean replaceType = false;
GenericsType[] genericsTypes = inferredRightExpressionType.getGenericsTypes();
@@ -5673,29 +5677,26 @@ public class StaticTypeCheckingVisitor extends ClassCodeVisitorSupport {
protected boolean typeCheckMethodsWithGenericsOrFail(final ClassNode receiver, final ClassNode[] arguments, final MethodNode candidateMethod, final Expression location) {
if (!typeCheckMethodsWithGenerics(receiver, arguments, candidateMethod)) {
- Map<GenericsTypeName, GenericsType> classGTs = GenericsUtils.extractPlaceholders(receiver);
+ Map<GenericsTypeName, GenericsType> generics = GenericsUtils.extractPlaceholders(receiver);
+ applyGenericsConnections(extractGenericsParameterMapOfThis(typeCheckingContext), generics);
+ addMethodLevelDeclaredGenerics(candidateMethod, generics);
Parameter[] parameters = candidateMethod.getParameters();
ClassNode[] paramTypes = new ClassNode[parameters.length];
for (int i = 0, n = parameters.length; i < n; i += 1) {
- paramTypes[i] = fullyResolveType(parameters[i].getType(), classGTs);
+ paramTypes[i] = fullyResolveType(parameters[i].getType(), generics);
// GROOVY-10010: check for List<String> parameter and ["foo","$bar"] argument
if (i < arguments.length && hasGStringStringError(paramTypes[i], arguments[i], location)) {
return false;
}
}
- addStaticTypeError("Cannot call " + toMethodGenericTypesString(candidateMethod) + receiver.toString(false) + "#" +
+ GenericsType[] mgt = candidateMethod.getGenericsTypes();
+ addStaticTypeError("Cannot call " + (mgt == null ? "" : GenericsUtils.toGenericTypesString(mgt)) + receiver.toString(false) + "#" +
toMethodParametersString(candidateMethod.getName(), paramTypes) + " with arguments " + formatArgumentList(arguments), location);
return false;
}
return true;
}
- private static String toMethodGenericTypesString(final MethodNode node) {
- GenericsType[] genericsTypes = node.getGenericsTypes();
- if (genericsTypes == null) return "";
- return toGenericTypesString(genericsTypes);
- }
-
protected static String formatArgumentList(final ClassNode[] nodes) {
if (nodes == null || nodes.length == 0) return "[]";
diff --git a/src/test/groovy/transform/stc/GenericsSTCTest.groovy b/src/test/groovy/transform/stc/GenericsSTCTest.groovy
index 0ad84dde39..7057a06c46 100644
--- a/src/test/groovy/transform/stc/GenericsSTCTest.groovy
+++ b/src/test/groovy/transform/stc/GenericsSTCTest.groovy
@@ -208,7 +208,7 @@ class GenericsSTCTest extends StaticTypeCheckingTestCase {
assertScript '''
@ASTTest(phase=INSTRUCTION_SELECTION, value={
def type = node.getNodeMetaData(INFERRED_TYPE)
- assert type.toString(false) == 'java.util.List <T extends java.lang.Object>'
+ assert type.toString(false) == 'java.util.List <java.lang.Object>'
})
def list = Arrays.asList()
assert list.size() == 0
@@ -268,7 +268,7 @@ class GenericsSTCTest extends StaticTypeCheckingTestCase {
'''
}
- @NotYetImplemented // GROOVY-9033
+ // GROOVY-9033
void testReturnTypeInferenceWithMethodGenerics8() {
shouldFailWithMessages '''
List<String> test() {
@@ -1123,7 +1123,7 @@ class GenericsSTCTest extends StaticTypeCheckingTestCase {
'''
}
- @NotYetImplemented // GROOVY-10324
+ // GROOVY-10324
void testDiamondInferrenceFromConstructor20() {
assertScript '''
class C<T> {
@@ -1214,7 +1214,7 @@ class GenericsSTCTest extends StaticTypeCheckingTestCase {
}
}
- @NotYetImplemented // GROOVY-10367
+ // GROOVY-10367
void testDiamondInferrenceFromConstructor26() {
assertScript '''
@groovy.transform.TupleConstructor(defaults=false)
diff --git a/src/test/groovy/transform/stc/TypeInferenceSTCTest.groovy b/src/test/groovy/transform/stc/TypeInferenceSTCTest.groovy
index ec9119ec41..97f09ecaf3 100644
--- a/src/test/groovy/transform/stc/TypeInferenceSTCTest.groovy
+++ b/src/test/groovy/transform/stc/TypeInferenceSTCTest.groovy
@@ -560,7 +560,7 @@ class TypeInferenceSTCTest extends StaticTypeCheckingTestCase {
'''
}
- void testShouldNotFailWithWithAndExplicitTypedIt() {
+ void testShouldFailWithWithAndWrongExplicitIt() {
shouldFailWithMessages '''
class A {
int x
@@ -569,7 +569,8 @@ class TypeInferenceSTCTest extends StaticTypeCheckingTestCase {
a.with { String it ->
it.x = 2 // should be recognized as a.x at compile time
}
- ''', 'Expected parameter of type A but got java.lang.String'
+ ''',
+ 'Expected parameter of type A but got java.lang.String'
}
void testShouldNotFailWithInheritanceAndWith() {
@@ -600,7 +601,7 @@ class TypeInferenceSTCTest extends StaticTypeCheckingTestCase {
'''
}
- void testCallMethodInWithContextAndShadowing() {
+ void testCallMethodInWithContextAndShadowing() {
// make sure that the method which is found in 'with' is actually the one from class A
// which returns a String
assertScript '''
@@ -727,11 +728,9 @@ class TypeInferenceSTCTest extends StaticTypeCheckingTestCase {
}
void testFlowTypingWithStringVariable() {
- // as anything can be assigned to a string, flow typing engine
- // could "erase" the type of the original variable although is must not
assertScript '''
- String str = new Object() // type checker will not complain, anything assignable to a String
- str.toUpperCase() // should not complain
+ String s = new Object() // anything assignable to String
+ s.toUpperCase()
'''
}
@@ -740,7 +739,7 @@ class TypeInferenceSTCTest extends StaticTypeCheckingTestCase {
def o
o = 1L
o = 2
- @ASTTest(phase=INSTRUCTION_SELECTION, value= {
+ @ASTTest(phase=INSTRUCTION_SELECTION, value={
assert node.rightExpression.accessedVariable.getNodeMetaData(DECLARATION_INFERRED_TYPE) == long_TYPE
})
def z = o
@@ -811,10 +810,10 @@ class TypeInferenceSTCTest extends StaticTypeCheckingTestCase {
returnValue = 1;
break;
}
- @ASTTest(phase=INSTRUCTION_SELECTION,value={
- def ift = node.getNodeMetaData(INFERRED_TYPE)
- assert ift instanceof LUB
- assert ift.name == 'java.io.Serializable'
+ @ASTTest(phase=INSTRUCTION_SELECTION, value={
+ def type = node.getNodeMetaData(INFERRED_TYPE)
+ assert type instanceof LUB
+ assert type.name == 'java.io.Serializable'
})
def val = returnValue
@@ -823,7 +822,8 @@ class TypeInferenceSTCTest extends StaticTypeCheckingTestCase {
'''
}
- void testGroovy6215() {
+ // GROOVY-6215
+ void testSwitchCaseAnalysis2() {
assertScript '''
def processNumber(int x) {
def value = getValueForNumber(x)
@@ -866,8 +866,8 @@ class TypeInferenceSTCTest extends StaticTypeCheckingTestCase {
assertScript """
$orig b = 65 as $orig
@ASTTest(phase=INSTRUCTION_SELECTION, value={
- def rit = node.rightExpression.getNodeMetaData(INFERRED_TYPE)
- assert rit == make($dest)
+ def type = node.rightExpression.getNodeMetaData(INFERRED_TYPE)
+ assert type == make($dest)
})
def pp = ++b
println '++${orig} -> ' + pp.class + ' ' + pp
@@ -890,8 +890,8 @@ class TypeInferenceSTCTest extends StaticTypeCheckingTestCase {
assertScript """
$orig b = 65 as $orig
@ASTTest(phase=INSTRUCTION_SELECTION, value={
- def rit = node.rightExpression.getNodeMetaData(INFERRED_TYPE)
- assert rit == make($dest)
+ def type = node.rightExpression.getNodeMetaData(INFERRED_TYPE)
+ assert type == make($dest)
})
def pp = b++
println '${orig}++ -> ' + pp.class + ' ' + pp
@@ -912,11 +912,11 @@ class TypeInferenceSTCTest extends StaticTypeCheckingTestCase {
callable.call()
}
- @ASTTest(phase=INSTRUCTION_SELECTION,value={
+ @ASTTest(phase=INSTRUCTION_SELECTION, value={
lookup('test').each {
def call = it.expression
- def irt = call.getNodeMetaData(INFERRED_TYPE)
- assert irt == LIST_TYPE
+ def type = call.getNodeMetaData(INFERRED_TYPE)
+ assert type == LIST_TYPE
}
})
static void run() {
@@ -935,7 +935,7 @@ class TypeInferenceSTCTest extends StaticTypeCheckingTestCase {
public <T> T[] intArray(ArrayFactory<T> f) {
f.array()
}
- @ASTTest(phase=INSTRUCTION_SELECTION,value={
+ @ASTTest(phase=INSTRUCTION_SELECTION, value={
assert node.getNodeMetaData(INFERRED_TYPE) == Integer_TYPE.makeArray()
})
def array = intArray { new Integer[8] }
@@ -951,10 +951,10 @@ class TypeInferenceSTCTest extends StaticTypeCheckingTestCase {
f.list()
}
- @ASTTest(phase=INSTRUCTION_SELECTION,value={
- def irt = node.getNodeMetaData(INFERRED_TYPE)
- assert irt == LIST_TYPE
- assert irt.genericsTypes[0].type == Integer_TYPE
+ @ASTTest(phase=INSTRUCTION_SELECTION, value={
+ def type = node.getNodeMetaData(INFERRED_TYPE)
+ assert type == LIST_TYPE
+ assert type.genericsTypes[0].type == Integer_TYPE
})
def res = list { new LinkedList<Integer>() }
assert res.size() == 0
@@ -995,7 +995,7 @@ class TypeInferenceSTCTest extends StaticTypeCheckingTestCase {
void testShouldInferPrimitiveBoolean() {
assertScript '''
def foo(Boolean o) {
- @ASTTest(phase=INSTRUCTION_SELECTION,value={
+ @ASTTest(phase=INSTRUCTION_SELECTION, value={
assert node.getNodeMetaData(INFERRED_TYPE) == boolean_TYPE
})
boolean b = o
@@ -1062,6 +1062,60 @@ class TypeInferenceSTCTest extends StaticTypeCheckingTestCase {
}
}
+ // GROOVY-5655
+ void testByteArrayInference() {
+ assertScript '''
+ @ASTTest(phase=INSTRUCTION_SELECTION, value={
+ assert node.getNodeMetaData(INFERRED_TYPE) == byte_TYPE.makeArray()
+ })
+ def b = "foo".bytes
+ new String(b)
+ '''
+ }
+
+ // GROOVY-
+ void testGetAnnotationFails() {
+ assertScript '''
+ import groovy.transform.*
+ import java.lang.annotation.*
+
+ @Retention(RetentionPolicy.RUNTIME)
+ @Target([ElementType.FIELD])
+ @interface Ann1 {}
+
+ @Retention(RetentionPolicy.RUNTIME)
+ @Target([ElementType.FIELD])
+ @interface Ann2 {}
+
+ class A {
+ @Ann2
+ String field
+ }
+
+ @ASTTest(phase=INSTRUCTION_SELECTION, value={
+ lookup('second').each {
+ assert it.expression.getNodeMetaData(INFERRED_TYPE).name == 'Ann2'
+ }
+ })
+ def doit(obj, String propName) {
+ def field = obj.getClass().getDeclaredField(propName)
+ if (field) {
+ @ASTTest(phase=INSTRUCTION_SELECTION, value={
+ assert node.getNodeMetaData(INFERRED_TYPE).name == 'Ann1'
+ })
+ def annotation = field.getAnnotation Ann1
+ if(true) {
+ second: annotation = field.getAnnotation Ann2
+ }
+ return annotation
+ }
+ return null
+ }
+
+ assert Ann2.isAssignableFrom(doit(new A(), "field").class)
+ '''
+ }
+
// GROOVY-9077
void testInferredTypeForPropertyThatResolvesToMethod() {
assertScript '''
@@ -1094,4 +1148,27 @@ class TypeInferenceSTCTest extends StaticTypeCheckingTestCase {
meth()
'''
}
+
+ // GROOVY-10089
+ void testInferredTypeForMapOfList() {
+ assertScript '''
+ void test(... attributes) {
+ List one = [
+ [id:'x', options:[count:1]]
+ ]
+ List two = attributes.collect {
+ def node = Collections.singletonMap('children', one)
+ if (node) {
+ node = node.get('children').find { child -> child['id'] == 'x' }
+ }
+ // inferred type of node must be something like Map<String,List<...>>
+
+ [id: it['id'], name: node['name'], count: node['options']['count']]
+ // ^^^^^^^^^^^^^^^ GroovyCastException (map ctor for Collection)
+ }
+ }
+
+ test( [id:'x'] )
+ '''
+ }
}
diff --git a/src/test/org/codehaus/groovy/classgen/asm/sc/BugsStaticCompileTest.groovy b/src/test/org/codehaus/groovy/classgen/asm/sc/BugsStaticCompileTest.groovy
index e5e3948c28..32a6202527 100644
--- a/src/test/org/codehaus/groovy/classgen/asm/sc/BugsStaticCompileTest.groovy
+++ b/src/test/org/codehaus/groovy/classgen/asm/sc/BugsStaticCompileTest.groovy
@@ -1159,7 +1159,7 @@ assert it.next() == 1G
def ift = node.getNodeMetaData(INFERRED_TYPE)
assert ift == make(Set)
assert ift.isUsingGenerics()
- assert ift.genericsTypes[0].type==STRING_TYPE
+ assert ift.genericsTypes[0].name == 'java.lang.String'
})
def set = map.keySet()
def key = set[0]
@@ -1171,7 +1171,7 @@ assert it.next() == 1G
def ift = node.getNodeMetaData(INFERRED_TYPE)
assert ift == make(Set)
assert ift.isUsingGenerics()
- assert ift.genericsTypes[0].name=='K'
+ assert ift.genericsTypes[0].name == 'java.lang.Object'
})
def set = map.keySet()
def key = set[0]
diff --git a/src/test/org/codehaus/groovy/classgen/asm/sc/TypeInferenceStaticCompileTest.groovy b/src/test/org/codehaus/groovy/classgen/asm/sc/TypeInferenceStaticCompileTest.groovy
index 40fc4e7184..afe168980f 100644
--- a/src/test/org/codehaus/groovy/classgen/asm/sc/TypeInferenceStaticCompileTest.groovy
+++ b/src/test/org/codehaus/groovy/classgen/asm/sc/TypeInferenceStaticCompileTest.groovy
@@ -21,73 +21,7 @@ package org.codehaus.groovy.classgen.asm.sc
import groovy.transform.stc.TypeInferenceSTCTest
/**
- * Unit tests for static type checking : type inference.
+ * Unit tests for static compilation : type inference.
*/
class TypeInferenceStaticCompileTest extends TypeInferenceSTCTest implements StaticCompilationTestSupport {
-
- // GROOVY-5655
- void testByteArrayInference() {
- assertScript '''
- @ASTTest(phase=INSTRUCTION_SELECTION, value={
- assert node.getNodeMetaData(INFERRED_TYPE) == byte_TYPE.makeArray()
- })
- def b = "foo".bytes
- new String(b)
- '''
- }
-
- @Override
- void testShouldNotThrowIncompatibleArgToFunVerifyError() {
- try {
- super.testShouldNotThrowIncompatibleArgToFunVerifyError()
- } finally {
-// println astTrees
- }
- }
-
- // GROOVY-
- void testGetAnnotationFail() {
- assertScript '''import groovy.transform.*
- import java.lang.annotation.ElementType;
- import java.lang.annotation.Retention;
- import java.lang.annotation.RetentionPolicy;
- import java.lang.annotation.Target;
-
- @Retention(RetentionPolicy.RUNTIME)
- @Target([ElementType.FIELD])
- @interface Ann1 {}
- @Retention(RetentionPolicy.RUNTIME)
- @Target([ElementType.FIELD])
- @interface Ann2 {}
-
- class A {
- @Ann2
- String field
- }
-
- @ASTTest(phase=INSTRUCTION_SELECTION,value={
- lookup('second').each {
- assert it.expression.getNodeMetaData(INFERRED_TYPE).name == 'Ann2'
- }
- })
- def doit(obj, String propName) {
- def field = obj.getClass().getDeclaredField propName
- println field
- if(field) {
- @ASTTest(phase=INSTRUCTION_SELECTION,value={
- assert node.getNodeMetaData(INFERRED_TYPE).name == 'Ann1'
- })
- def annotation = field.getAnnotation Ann1
- if(true) {
- second: annotation = field.getAnnotation Ann2
- }
- return annotation
- }
- return null
- }
-
- assert Ann2.isAssignableFrom (doit(new A(), "field").class)
- '''
- }
}
-