Skip to content

Commit 9d0d671

Browse files
committed
GROOVY-5106, GROOVY-11508: re-implement trait with new type args warning
(closes #2117)
1 parent b13ce1c commit 9d0d671

File tree

4 files changed

+114
-47
lines changed

4 files changed

+114
-47
lines changed

src/main/java/org/codehaus/groovy/classgen/Verifier.java

Lines changed: 9 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -363,9 +363,15 @@ private static void checkForDuplicateInterfaces(final ClassNode cn) {
363363
for (ClassNode t : set) { // find match and check generics
364364
if (t.equals(in)) {
365365
String one = in.toString(false), two = t.toString(false);
366-
if (!one.equals(two))
367-
throw new RuntimeParserException("The interface " + in.getNameWithoutPackage() +
368-
" cannot be implemented more than once with different arguments: " + one + " and " + two, cn);
366+
if (!one.equals(two)) {
367+
if (Traits.isTrait(in)) { // GROOVY-11508
368+
cn.getModule().getContext().addWarning("The trait " + in.getNameWithoutPackage() +
369+
" is implemented more than once with different arguments: " + one + " and " + two, cn);
370+
} else {
371+
throw new RuntimeParserException("The interface " + in.getNameWithoutPackage() +
372+
" cannot be implemented more than once with different arguments: " + one + " and " + two, cn);
373+
}
374+
}
369375
break;
370376
}
371377
}

src/main/java/org/codehaus/groovy/control/ResolveVisitor.java

Lines changed: 49 additions & 36 deletions
Original file line numberDiff line numberDiff line change
@@ -263,63 +263,76 @@ protected SourceUnit getSourceUnit() {
263263
return source;
264264
}
265265

266+
@Override
267+
public void visitField(final FieldNode node) {
268+
Map<GenericsTypeName, GenericsType> oldNames = genericParameterNames;
269+
if (!canSeeTypeVars(node.getModifiers(), node.getDeclaringClass())) {
270+
genericParameterNames = Collections.emptyMap();
271+
}
272+
273+
if (!fieldTypesChecked.contains(node)) {
274+
resolveOrFail(node.getType(), node);
275+
}
276+
super.visitField(node);
277+
278+
genericParameterNames = oldNames;
279+
}
280+
281+
@Override
282+
public void visitProperty(final PropertyNode node) {
283+
Map<GenericsTypeName, GenericsType> oldNames = genericParameterNames;
284+
if (!canSeeTypeVars(node.getModifiers(), node.getDeclaringClass())) {
285+
genericParameterNames = Collections.emptyMap();
286+
}
287+
288+
resolveOrFail(node.getType(), node);
289+
fieldTypesChecked.add(node.getField());
290+
291+
super.visitProperty(node);
292+
293+
genericParameterNames = oldNames;
294+
}
295+
296+
private static boolean canSeeTypeVars(final int mods, final ClassNode node) {
297+
return !Modifier.isStatic(mods) || Traits.isTrait(node); // GROOVY-8864, GROOVY-11508
298+
}
299+
266300
@Override
267301
protected void visitConstructorOrMethod(final MethodNode node, final boolean isConstructor) {
268302
VariableScope oldScope = currentScope;
269303
currentScope = node.getVariableScope();
270304
Map<GenericsTypeName, GenericsType> oldNames = genericParameterNames;
271-
genericParameterNames = node.isStatic() && !Traits.isTrait(node.getDeclaringClass())
272-
? new HashMap<>() : new HashMap<>(genericParameterNames);
305+
genericParameterNames =
306+
canSeeTypeVars(node.getModifiers(), node.getDeclaringClass())
307+
? new HashMap<>(genericParameterNames) : new HashMap<>();
273308

274309
resolveGenericsHeader(node.getGenericsTypes());
275310

311+
resolveOrFail(node.getReturnType(), node);
276312
for (Parameter p : node.getParameters()) {
277313
p.setInitialExpression(transform(p.getInitialExpression()));
278-
resolveOrFail(p.getType(), p.getType());
314+
ClassNode t = p.getType();
315+
resolveOrFail(t, t);
279316
visitAnnotations(p);
280317
}
281-
resolveOrFail(node.getReturnType(), node);
282318
if (node.getExceptions() != null) {
283319
for (ClassNode t : node.getExceptions()) {
284-
resolveOrFail(t, node);
320+
resolveOrFail(t, t);
285321
}
286322
}
287323

288324
checkGenericsCyclicInheritance(node.getGenericsTypes());
289325

290326
MethodNode oldCurrentMethod = currentMethod;
291327
currentMethod = node;
328+
292329
super.visitConstructorOrMethod(node, isConstructor);
293330

294331
currentMethod = oldCurrentMethod;
295332
genericParameterNames = oldNames;
296333
currentScope = oldScope;
297334
}
298335

299-
@Override
300-
public void visitField(final FieldNode node) {
301-
ClassNode t = node.getType();
302-
if (!fieldTypesChecked.contains(node)) {
303-
resolveOrFail(t, node);
304-
}
305-
super.visitField(node);
306-
}
307-
308-
@Override
309-
public void visitProperty(final PropertyNode node) {
310-
Map<GenericsTypeName, GenericsType> oldPNames = genericParameterNames;
311-
if (node.isStatic() && !Traits.isTrait(node.getDeclaringClass())) {
312-
genericParameterNames = new HashMap<>();
313-
}
314-
315-
ClassNode t = node.getType();
316-
resolveOrFail(t, node);
317-
super.visitProperty(node);
318-
fieldTypesChecked.add(node.getField());
319-
320-
genericParameterNames = oldPNames;
321-
}
322-
323336
private void resolveOrFail(final ClassNode type, final ASTNode node) {
324337
resolveOrFail(type, "", node);
325338
}
@@ -1098,14 +1111,14 @@ protected Expression transformBinaryExpression(final BinaryExpression be) {
10981111
protected Expression transformClosureExpression(final ClosureExpression ce) {
10991112
boolean oldInClosure = inClosure;
11001113
inClosure = true;
1101-
for (Parameter para : getParametersSafe(ce)) {
1102-
ClassNode t = para.getType();
1103-
resolveOrFail(t, ce);
1104-
visitAnnotations(para);
1105-
if (para.hasInitialExpression()) {
1106-
para.setInitialExpression(transform(para.getInitialExpression()));
1114+
for (Parameter p : getParametersSafe(ce)) {
1115+
ClassNode t = p.getType();
1116+
resolveOrFail(t, t);
1117+
visitAnnotations(p);
1118+
if (p.hasInitialExpression()) {
1119+
p.setInitialExpression(transform(p.getInitialExpression()));
11071120
}
1108-
visitAnnotations(para);
1121+
visitAnnotations(p);
11091122
}
11101123

11111124
Statement code = ce.getCode();
Lines changed: 45 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,45 @@
1+
/*
2+
* Licensed to the Apache Software Foundation (ASF) under one
3+
* or more contributor license agreements. See the NOTICE file
4+
* distributed with this work for additional information
5+
* regarding copyright ownership. The ASF licenses this file
6+
* to you under the Apache License, Version 2.0 (the
7+
* "License"); you may not use this file except in compliance
8+
* with the License. You may obtain a copy of the License at
9+
*
10+
* http://www.apache.org/licenses/LICENSE-2.0
11+
*
12+
* Unless required by applicable law or agreed to in writing,
13+
* software distributed under the License is distributed on an
14+
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
15+
* KIND, either express or implied. See the License for the
16+
* specific language governing permissions and limitations
17+
* under the License.
18+
*/
19+
package org.codehaus.groovy.transform.traitx
20+
21+
import org.junit.Test
22+
23+
import static groovy.test.GroovyAssert.assertScript
24+
25+
final class Groovy11508 {
26+
@Test
27+
void testGenericsAppliedToStaticMethodsForTraits() {
28+
assertScript '''
29+
trait T<U> {
30+
static U getYou() {
31+
}
32+
}
33+
class C implements T<C> {
34+
}
35+
class D extends C implements T<D> {
36+
}
37+
38+
C c = C.you
39+
D d = D.you
40+
41+
assert C.getMethod('getYou').returnType == C
42+
assert D.getMethod('getYou').returnType == D
43+
'''
44+
}
45+
}

src/test/groovy/bugs/Groovy8864Bug.groovy renamed to src/test/org/codehaus/groovy/transform/traitx/Groovy8864.groovy

Lines changed: 11 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -16,24 +16,27 @@
1616
* specific language governing permissions and limitations
1717
* under the License.
1818
*/
19-
package groovy.bugs
19+
package org.codehaus.groovy.transform.traitx
2020

21-
import groovy.test.GroovyTestCase
21+
import org.junit.Test
2222

23-
class Groovy8864Bug extends GroovyTestCase {
23+
import static groovy.test.GroovyAssert.assertScript
24+
25+
final class Groovy8864 {
26+
@Test
2427
void testGenericsAppliedToStaticMethodsForTraits() {
2528
assertScript '''
2629
trait Foo<T> {
2730
static T INSTANCE
28-
static T get(T arg) {
29-
null
30-
}
31+
static T get(T t) {
32+
}
33+
}
34+
class Bar implements Foo<Bar> {
3135
}
3236
33-
class Bar implements Foo<Bar> {}
3437
assert Bar.getMethod("get", [Bar] as Class[]).returnType == Bar
3538
assert Bar.getDeclaredField("Foo__INSTANCE").type == Bar
36-
assert Bar.getMethod("setINSTANCE", [Bar] as Class[])
39+
assert Bar.getMethod("setINSTANCE", new Class[]{Bar})
3740
assert Bar.getMethod("getINSTANCE").returnType == Bar
3841
'''
3942
}

0 commit comments

Comments
 (0)