Skip to content

Commit 0484437

Browse files
committed
GROOVY-10082: STC: allow simple covariace of closure return
1 parent ce2d680 commit 0484437

File tree

2 files changed

+27
-14
lines changed

2 files changed

+27
-14
lines changed

src/main/java/org/codehaus/groovy/transform/stc/StaticTypeCheckingVisitor.java

Lines changed: 12 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -850,7 +850,7 @@ && isAssignment(enclosingBinaryExpression.getOperation().getType())) {
850850
&& !getOutermost(enclosingType).equals(getOutermost(resultType))
851851
&& (Modifier.isPrivate(modifiers) || !Objects.equals(enclosingType.getPackageName(), resultType.getPackageName()))) {
852852
resultType = originType; // TODO: Find accesible type in hierarchy of resultType?
853-
} else if (GenericsUtils.hasUnresolvedGenerics(resultType)) {// GROOVY-9033, GROOVY-10089, et al.
853+
} else if (GenericsUtils.hasUnresolvedGenerics(resultType)) { // GROOVY-9033, GROOVY-10089, et al.
854854
Map<GenericsTypeName, GenericsType> enclosing = extractGenericsParameterMapOfThis(typeCheckingContext);
855855
resultType = fullyResolveType(resultType, Optional.ofNullable(enclosing).orElseGet(Collections::emptyMap));
856856
}
@@ -2174,11 +2174,17 @@ protected ClassNode checkReturnType(final ReturnStatement statement) {
21742174
type = getType(expression);
21752175
}
21762176
if (typeCheckingContext.getEnclosingClosure() != null) {
2177+
ClassNode inferredReturnType = getInferredReturnType(typeCheckingContext.getEnclosingClosure().getClosureExpression());
21772178
// GROOVY-9995: return ctor call with diamond operator
21782179
if (expression instanceof ConstructorCallExpression) {
2179-
ClassNode inferredClosureReturnType = getInferredReturnType(typeCheckingContext.getEnclosingClosure().getClosureExpression());
2180-
if (inferredClosureReturnType == null) inferredClosureReturnType = DYNAMIC_TYPE; // GROOVY-10080
2181-
inferDiamondType((ConstructorCallExpression) expression, inferredClosureReturnType);
2180+
inferDiamondType((ConstructorCallExpression) expression, inferredReturnType != null ? inferredReturnType : /*GROOVY-10080:*/DYNAMIC_TYPE);
2181+
}
2182+
if (STRING_TYPE.equals(inferredReturnType) && isGStringOrGStringStringLUB(type)) {
2183+
type = STRING_TYPE; // GROOVY-9971: convert GString to String at point of return
2184+
} else if (inferredReturnType != null && !inferredReturnType.isGenericsPlaceHolder()
2185+
&& !type.isUsingGenerics() && !type.equals(inferredReturnType) && (inferredReturnType.isInterface()
2186+
? type.implementsInterface(inferredReturnType) : type.isDerivedFrom(inferredReturnType))) {
2187+
type = inferredReturnType; // GROOVY-10082: allow simple covariance
21822188
}
21832189
return type;
21842190
}
@@ -2212,14 +2218,8 @@ protected ClassNode checkReturnType(final ReturnStatement statement) {
22122218
}
22132219

22142220
protected void addClosureReturnType(final ClassNode returnType) {
2215-
TypeCheckingContext.EnclosingClosure enclosingClosure = typeCheckingContext.getEnclosingClosure();
2216-
if (isGStringOrGStringStringLUB(returnType)
2217-
&& STRING_TYPE.equals(getInferredReturnType(enclosingClosure.getClosureExpression()))) {
2218-
// GROOVY-9971: convert GString to String at the point of return
2219-
enclosingClosure.addReturnType(STRING_TYPE);
2220-
} else if (!VOID_TYPE.equals(returnType)) {
2221-
enclosingClosure.addReturnType(returnType);
2222-
}
2221+
if (returnType != null && !returnType.equals(VOID_TYPE)) // GROOVY-8202
2222+
typeCheckingContext.getEnclosingClosure().addReturnType(returnType);
22232223
}
22242224

22252225
@Override

src/test/groovy/transform/stc/ClosuresSTCTest.groovy

Lines changed: 15 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -160,8 +160,21 @@ class ClosuresSTCTest extends StaticTypeCheckingTestCase {
160160
'''
161161
}
162162

163-
// GROOVY-8427
163+
// GROOVY-10082
164164
void testClosureReturnTypeInference6() {
165+
assertScript '''
166+
class A {}
167+
class B extends A {}
168+
Closure<A> c = { -> new B() } // Cannot assign Closure<B> to Closure<A>
169+
170+
def result = c()
171+
assert result instanceof A
172+
assert result instanceof B
173+
'''
174+
}
175+
176+
// GROOVY-8427
177+
void testClosureReturnTypeInference7() {
165178
assertScript '''
166179
import java.util.function.Consumer
167180
@@ -183,7 +196,7 @@ class ClosuresSTCTest extends StaticTypeCheckingTestCase {
183196
}
184197

185198
// GROOVY-8202
186-
void testClosureReturnTypeInference7() {
199+
void testClosureReturnTypeInference8() {
187200
assertScript '''
188201
void proc() {
189202
}

0 commit comments

Comments
 (0)