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/03/11 18:19:33 UTC
[groovy] 02/02: GROOVY-6919: STC: check bound types for fields, methods, properties, ...
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
commit a38ccfc546db231843680e29751783562f7efccd
Author: Eric Milles <er...@thomsonreuters.com>
AuthorDate: Wed Oct 6 14:26:25 2021 -0500
GROOVY-6919: STC: check bound types for fields, methods, properties, ...
---
.../transform/stc/StaticTypeCheckingVisitor.java | 85 ++++---------
.../groovy/transform/stc/GenericsSTCTest.groovy | 132 +++++++++++++++++----
.../console/ui/AstNodeToScriptAdapter.groovy | 12 +-
3 files changed, 138 insertions(+), 91 deletions(-)
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 4e294c6..aeef6ca 100644
--- a/src/main/java/org/codehaus/groovy/transform/stc/StaticTypeCheckingVisitor.java
+++ b/src/main/java/org/codehaus/groovy/transform/stc/StaticTypeCheckingVisitor.java
@@ -3806,10 +3806,10 @@ public class StaticTypeCheckingVisitor extends ClassCodeVisitorSupport {
addTraitType(staticType, owners); // T in Class<T$Trait$Helper>
owners.add(Receiver.make(receiver)); // Class<Type>
} else {
- owners.add(Receiver.make(receiver));
+ addBoundType(receiver, owners);
addSelfTypes(receiver, owners);
addTraitType(receiver, owners);
- if (receiver.isInterface()) {
+ if (receiver.redirect().isInterface()) {
owners.add(Receiver.make(OBJECT_TYPE));
}
}
@@ -3817,6 +3817,23 @@ public class StaticTypeCheckingVisitor extends ClassCodeVisitorSupport {
return owners;
}
+ private static void addBoundType(final ClassNode receiver, final List<Receiver<String>> owners) {
+ if (!receiver.isGenericsPlaceHolder() || receiver.getGenericsTypes() == null) {
+ owners.add(Receiver.make(receiver));
+ return;
+ }
+
+ GenericsType gt = receiver.getGenericsTypes()[0];
+ if (gt.getLowerBound() == null && gt.getUpperBounds() != null) {
+ for (ClassNode cn : gt.getUpperBounds()) { // T extends C & I
+ addBoundType(cn, owners);
+ addSelfTypes(cn, owners);
+ }
+ } else {
+ owners.add(Receiver.make(OBJECT_TYPE)); // T or T super Type
+ }
+ }
+
private static void addSelfTypes(final ClassNode receiver, final List<Receiver<String>> owners) {
for (ClassNode selfType : Traits.collectSelfTypes(receiver, new LinkedHashSet<>())) {
owners.add(Receiver.make(selfType));
@@ -5845,71 +5862,17 @@ public class StaticTypeCheckingVisitor extends ClassCodeVisitorSupport {
ParameterVariableExpression(final Parameter parameter) {
super(parameter);
this.parameter = parameter;
- ClassNode inferred = parameter.getNodeMetaData(INFERRED_TYPE);
- if (inferred == null) {
- inferred = infer(parameter);
-
- parameter.setNodeMetaData(INFERRED_TYPE, inferred);
- }
- }
-
- private static ClassNode infer(final Variable variable) {
- ClassNode originType = variable.getOriginType();
-
- if (originType.isGenericsPlaceHolder()) {
- GenericsType[] genericsTypes = originType.getGenericsTypes();
-
- if (genericsTypes != null && genericsTypes.length > 0) {
- GenericsType gt = genericsTypes[0];
- ClassNode[] upperBounds = gt.getUpperBounds();
-
- if (upperBounds != null && upperBounds.length > 0) {
- return upperBounds[0];
- }
- }
- }
-
- return originType;
- }
-
- @Override
- public void copyNodeMetaData(final ASTNode other) {
- parameter.copyNodeMetaData(other);
- }
-
- @Override
- public Object putNodeMetaData(final Object key, final Object value) {
- return parameter.putNodeMetaData(key, value);
- }
-
- @Override
- public void removeNodeMetaData(final Object key) {
- parameter.removeNodeMetaData(key);
- }
-
- @Override
- public Map<?, ?> getNodeMetaData() {
- return parameter.getNodeMetaData();
- }
-
- @Override
- public <T> T getNodeMetaData(final Object key) {
- return parameter.getNodeMetaData(key);
- }
-
- @Override
- public void setNodeMetaData(final Object key, final Object value) {
- parameter.setNodeMetaData(key, value);
+ this.parameter.getNodeMetaData(INFERRED_TYPE, x -> parameter.getOriginType());
}
@Override
- public int hashCode() {
- return parameter.hashCode();
+ public Map<?, ?> getMetaDataMap() {
+ return parameter.getMetaDataMap();
}
@Override
- public boolean equals(final Object other) {
- return parameter.equals(other);
+ public void setMetaDataMap(final Map<?, ?> metaDataMap) {
+ parameter.setMetaDataMap(metaDataMap);
}
}
diff --git a/src/test/groovy/transform/stc/GenericsSTCTest.groovy b/src/test/groovy/transform/stc/GenericsSTCTest.groovy
index ae365ab..c16b875 100644
--- a/src/test/groovy/transform/stc/GenericsSTCTest.groovy
+++ b/src/test/groovy/transform/stc/GenericsSTCTest.groovy
@@ -1726,29 +1726,23 @@ class GenericsSTCTest extends StaticTypeCheckingTestCase {
void testOutOfBoundsByExtendsPlaceholderParameterType() {
shouldFailWithMessages '''
class Foo {
- static <T extends List<? extends CharSequence>> void bar(T a) {}
+ static <T extends List<? extends CharSequence>> void bar(T list) {}
}
- class Baz {
- static <T extends List<Object>> void qux(T a) {
- Foo.bar(a)
- }
+ def <U extends List<Object>> void baz(U list) {
+ Foo.bar(list)
}
- Baz.qux([new Object()])
- ''', 'Cannot call <T extends java.util.List<? extends java.lang.CharSequence>> Foo#bar(T) with arguments [java.util.List <Object>]'
+ ''', 'Cannot call <T extends java.util.List<? extends java.lang.CharSequence>> Foo#bar(T) with arguments [U]'
}
void testOutOfBoundsBySuperPlaceholderParameterType() {
shouldFailWithMessages '''
class Foo {
- static <T extends List<? super CharSequence>> void bar(T a) {}
+ static <T extends List<? super CharSequence>> void bar(T list) {}
}
- class Baz {
- static <T extends List<String>> void qux(T a) {
- Foo.bar(a)
- }
+ def <U extends List<String>> void baz(U list) {
+ Foo.bar(list)
}
- Baz.qux(['abc'])
- ''', 'Cannot call <T extends java.util.List<? super java.lang.CharSequence>> Foo#bar(T) with arguments [java.util.List <String>]'
+ ''', 'Cannot call <T extends java.util.List<? super java.lang.CharSequence>> Foo#bar(T) with arguments [U]'
}
// GROOVY-5721
@@ -2172,8 +2166,8 @@ class GenericsSTCTest extends StaticTypeCheckingTestCase {
'#foo(java.util.List <? extends A>) with arguments [java.util.ArrayList <java.lang.Object>]'
}
+ // GROOVY-5891
void testMethodLevelGenericsForMethodCall() {
- // Groovy-5891
assertScript '''
public <T extends List<Integer>> T foo(Class<T> type, def x) {
return type.cast(x)
@@ -2187,24 +2181,116 @@ class GenericsSTCTest extends StaticTypeCheckingTestCase {
}
def cl = {1}
assert foo(cl.class, cl) == cl
- '''
- assertScript '''
+ '''
+ assertScript '''
public <T extends Runnable> T foo(Class<T> type, def x) {
return type.cast(x) as T
}
def cl = {1}
assert foo(cl.class, cl) == cl
- '''
- // GROOVY-5885
- assertScript '''
+ '''
+ }
+
+ // GROOVY-5885
+ void testMethodLevelGenericsForMethodCall2() {
+ assertScript '''
class Test {
- public <X extends Test> X castToMe(Class<X> type, Object o) {
+ public <T extends Test> T castToMe(Class<T> type, Object o) {
return type.cast(o);
}
}
def t = new Test()
- assert t.castToMe(Test, t) == t
- '''
+ assert t == t.castToMe(Test, t)
+ '''
+ }
+
+ // GROOVY-6919
+ void testMethodLevelGenericsForMethodCall3() {
+ assertScript '''
+ interface I1 {
+ String getFoo()
+ }
+ interface I2 {
+ String getBar()
+ }
+ def <T extends I1 & I2> void test(T obj) {
+ obj?.getFoo()
+ obj?.getBar()
+ }
+ test(null)
+ '''
+ }
+
+ // GROOVY-6919
+ void testMethodLevelGenericsForPropertyRead() {
+ assertScript '''
+ interface I1 {
+ String getFoo()
+ }
+ interface I2 {
+ String getBar()
+ }
+ def <T extends I1 & I2> void test(T obj) {
+ obj?.foo
+ obj?.bar
+ }
+ test(null)
+ '''
+ }
+
+ @NotYetImplemented
+ void testMethodLevelGenericsForPropertyRead2() {
+ assertScript '''
+ interface I1 {
+ static String getFoo() { 'foo' }
+ }
+ interface I2 {
+ String bar = 'bar'
+ }
+ def <T extends I1 & I2> void test(Class<T> cls) {
+ cls?.foo
+ cls?.bar
+ }
+ test(null)
+ '''
+ }
+
+ void testMethodLevelGenericsForPropertyRead3() {
+ assertScript '''
+ interface I1 {
+ String getFoo()
+ }
+ interface I2 {
+ String getBar()
+ }
+ class C<T extends I1 & I2> {
+ def <U extends T> void test(U obj) {
+ obj?.foo
+ obj?.bar
+ }
+ }
+ new C().test(null)
+ '''
+ }
+
+ void testMethodLevelGenericsForPropertyRead4() {
+ assertScript '''
+ interface I1 {
+ String getFoo()
+ }
+ interface I2 {
+ String getBar()
+ }
+ @groovy.transform.SelfType(I2) trait T2 {
+ abstract String getBaz()
+ }
+ def <T extends I1 & T2> void test(T obj) {
+ obj?.foo
+ obj?.bar
+ obj?.baz
+ }
+ test(null)
+ '''
}
// GROOVY-5839
diff --git a/subprojects/groovy-console/src/main/groovy/groovy/console/ui/AstNodeToScriptAdapter.groovy b/subprojects/groovy-console/src/main/groovy/groovy/console/ui/AstNodeToScriptAdapter.groovy
index fa78b38..dcd2ccd 100644
--- a/subprojects/groovy-console/src/main/groovy/groovy/console/ui/AstNodeToScriptAdapter.groovy
+++ b/subprojects/groovy-console/src/main/groovy/groovy/console/ui/AstNodeToScriptAdapter.groovy
@@ -710,14 +710,12 @@ class AstNodeToScriptVisitor implements CompilationUnit.IPrimaryClassNodeOperati
@Override
void visitStaticMethodCallExpression(StaticMethodCallExpression expression) {
+ boolean parens = expression?.arguments instanceof MethodCallExpression
+ || expression?.arguments instanceof VariableExpression
print expression?.ownerType?.name + '.' + expression?.method
- if (expression?.arguments instanceof VariableExpression || expression?.arguments instanceof MethodCallExpression) {
- print '('
- expression?.arguments?.visit this
- print ')'
- } else {
- expression?.arguments?.visit this
- }
+ if (parens) print '('
+ expression?.arguments?.visit(this)
+ if (parens) print ')'
}
@Override