Skip to content

Commit 7c835a1

Browse files
eric-millesdaniellansun
authored andcommitted
GROOVY-5106, GROOVY-11508: re-implement trait with new type args warning
(closes #2117)
1 parent 904347c commit 7c835a1

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
@@ -265,61 +265,74 @@ protected SourceUnit getSourceUnit() {
265265
return source;
266266
}
267267

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

276311
resolveGenericsHeader(node.getGenericsTypes());
277312

313+
resolveOrFail(node.getReturnType(), node);
278314
for (Parameter p : node.getParameters()) {
279315
p.setInitialExpression(transform(p.getInitialExpression()));
280-
resolveOrFail(p.getType(), p.getType());
316+
ClassNode t = p.getType();
317+
resolveOrFail(t, t);
281318
visitAnnotations(p);
282319
}
283-
resolveOrFail(node.getReturnType(), node);
284320
if (node.getExceptions() != null) {
285321
for (ClassNode t : node.getExceptions()) {
286-
resolveOrFail(t, node);
322+
resolveOrFail(t, t);
287323
}
288324
}
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
}
@@ -1108,14 +1121,14 @@ protected Expression transformBinaryExpression(final BinaryExpression be) {
11081121
protected Expression transformClosureExpression(final ClosureExpression ce) {
11091122
boolean oldInClosure = inClosure;
11101123
inClosure = true;
1111-
for (Parameter para : getParametersSafe(ce)) {
1112-
ClassNode t = para.getType();
1113-
resolveOrFail(t, ce);
1114-
visitAnnotations(para);
1115-
if (para.hasInitialExpression()) {
1116-
para.setInitialExpression(transform(para.getInitialExpression()));
1124+
for (Parameter p : getParametersSafe(ce)) {
1125+
ClassNode t = p.getType();
1126+
resolveOrFail(t, t);
1127+
visitAnnotations(p);
1128+
if (p.hasInitialExpression()) {
1129+
p.setInitialExpression(transform(p.getInitialExpression()));
11171130
}
1118-
visitAnnotations(para);
1131+
visitAnnotations(p);
11191132
}
11201133

11211134
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)