Repository: groovy
Updated Branches:
  refs/heads/GROOVY_2_5_X 9ce3e1aa9 -> dbb665df2


GenericType name should use custom type rather than `String`(prepare to fix 
GROOVY-8409)

e.g. The content of resolvedPlaceholders is:
{R=T, T=java.util.Date, U=java.net.URL}
the `T` of `R=T` is defined by user,
but the `T` of `T=java.util.Date` is defined in `BiFunction`.
As a result, R -> T -> Date

See the comment of GROOVY-8409, which is not resolved yet.

(cherry picked from commit f8d4f1bec1dc8cd079e3db97bb2297ae448950af)


Project: http://git-wip-us.apache.org/repos/asf/groovy/repo
Commit: http://git-wip-us.apache.org/repos/asf/groovy/commit/dbb665df
Tree: http://git-wip-us.apache.org/repos/asf/groovy/tree/dbb665df
Diff: http://git-wip-us.apache.org/repos/asf/groovy/diff/dbb665df

Branch: refs/heads/GROOVY_2_5_X
Commit: dbb665df29e7e6298925e04dad8383f1f9b6cbf1
Parents: 9ce3e1a
Author: Daniel Sun <[email protected]>
Authored: Sat Aug 18 23:15:49 2018 +0800
Committer: Daniel Sun <[email protected]>
Committed: Sun Aug 19 00:01:37 2018 +0800

----------------------------------------------------------------------
 .../org/codehaus/groovy/ast/GenericsType.java   |  55 +++++++--
 .../groovy/ast/tools/GenericsUtils.java         |   9 +-
 .../groovy/ast/tools/WideningCategories.java    |   8 +-
 .../codehaus/groovy/control/ResolveVisitor.java |  30 ++---
 .../stc/StaticTypeCheckingSupport.java          | 111 ++++++++++---------
 .../stc/StaticTypeCheckingVisitor.java          |  71 ++++++------
 .../codehaus/groovy/ast/GenericsTypeTest.groovy |  16 +--
 7 files changed, 170 insertions(+), 130 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/groovy/blob/dbb665df/src/main/java/org/codehaus/groovy/ast/GenericsType.java
----------------------------------------------------------------------
diff --git a/src/main/java/org/codehaus/groovy/ast/GenericsType.java 
b/src/main/java/org/codehaus/groovy/ast/GenericsType.java
index 57d4919..5041fb1 100644
--- a/src/main/java/org/codehaus/groovy/ast/GenericsType.java
+++ b/src/main/java/org/codehaus/groovy/ast/GenericsType.java
@@ -24,6 +24,7 @@ import org.codehaus.groovy.ast.tools.WideningCategories;
 import java.lang.reflect.Modifier;
 import java.util.HashSet;
 import java.util.Map;
+import java.util.Objects;
 import java.util.Set;
 
 import static org.codehaus.groovy.ast.ClassHelper.GROOVY_OBJECT_TYPE;
@@ -371,18 +372,18 @@ public class GenericsType extends ASTNode {
                 return true;
             }
             GenericsType[] redirectBoundGenericTypes = 
bound.redirect().getGenericsTypes();
-            Map<String, GenericsType> classNodePlaceholders = 
GenericsUtils.extractPlaceholders(classNode);
-            Map<String, GenericsType> boundPlaceHolders = 
GenericsUtils.extractPlaceholders(bound);
+            Map<GenericsType.GenericsTypeName, GenericsType> 
classNodePlaceholders = GenericsUtils.extractPlaceholders(classNode);
+            Map<GenericsType.GenericsTypeName, GenericsType> boundPlaceHolders 
= GenericsUtils.extractPlaceholders(bound);
             boolean match = true;
             for (int i = 0; redirectBoundGenericTypes!=null && i < 
redirectBoundGenericTypes.length && match; i++) {
                 GenericsType redirectBoundType = redirectBoundGenericTypes[i];
                 GenericsType classNodeType = cnTypes[i];
                 if (classNodeType.isPlaceholder()) {
-                    String name = classNodeType.getName();
+                    GenericsTypeName name = new 
GenericsTypeName(classNodeType.getName());
                     if (redirectBoundType.isPlaceholder()) {
-                        match = name.equals(redirectBoundType.getName());
+                        match = name.equals(new 
GenericsTypeName(redirectBoundType.getName()));
                         if (!match) {
-                            GenericsType genericsType = 
boundPlaceHolders.get(redirectBoundType.getName());
+                            GenericsType genericsType = 
boundPlaceHolders.get(new GenericsTypeName(redirectBoundType.getName()));
                             match = false;
                             if (genericsType!=null) {
                                 if (genericsType.isPlaceholder()) {
@@ -408,7 +409,7 @@ public class GenericsType extends ASTNode {
                         if (classNodeType.isPlaceholder()) {
                             match = 
classNodeType.getName().equals(redirectBoundType.getName());
                         } else {
-                            String name = redirectBoundType.getName();
+                            GenericsTypeName name = new 
GenericsTypeName(redirectBoundType.getName());
                             if (boundPlaceHolders.containsKey(name)) {
                                 redirectBoundType = 
boundPlaceHolders.get(name);
                                 boolean wildcard = 
redirectBoundType.isWildcard();
@@ -423,8 +424,8 @@ public class GenericsType extends ASTNode {
                                             if (gt.isPlaceholder()) {
                                                 // check for recursive generic 
typedef, like in
                                                 // <T extends Comparable<? 
super T>>
-                                                if 
(classNodePlaceholders.containsKey(gt.getName())) {
-                                                    gt = 
classNodePlaceholders.get(gt.getName());
+                                                if 
(classNodePlaceholders.containsKey(new GenericsTypeName(gt.getName()))) {
+                                                    gt = 
classNodePlaceholders.get(new GenericsTypeName(gt.getName()));
                                                 }
                                             }
                                             match = 
implementsInterfaceOrIsSubclassOf(gt.getType(), classNodeType.getType());
@@ -435,8 +436,8 @@ public class GenericsType extends ASTNode {
                                                 if (gt.isPlaceholder()) {
                                                     // check for recursive 
generic typedef, like in
                                                     // <T extends Comparable<? 
super T>>
-                                                    if 
(classNodePlaceholders.containsKey(gt.getName())) {
-                                                        gt = 
classNodePlaceholders.get(gt.getName());
+                                                    if 
(classNodePlaceholders.containsKey(new GenericsTypeName(gt.getName()))) {
+                                                        gt = 
classNodePlaceholders.get(new GenericsTypeName(gt.getName()));
                                                     }
                                                 }
                                                 match = 
implementsInterfaceOrIsSubclassOf(classNodeType.getType(), gt.getType())
@@ -497,4 +498,38 @@ public class GenericsType extends ASTNode {
         }
         return superClass;
     }
+
+    /**
+     * Represents GenericsType name
+     * TODO In order to distinguish GenericsType with same name(See 
GROOVY-8409), we should add a property to keep the declaring class full name.
+     */
+    public static class GenericsTypeName {
+        private String name;
+
+        public GenericsTypeName(String name) {
+            this.name = name;
+        }
+
+        public String getName() {
+            return name;
+        }
+
+        @Override
+        public boolean equals(Object o) {
+            if (this == o) return true;
+            if (o == null || getClass() != o.getClass()) return false;
+            GenericsTypeName that = (GenericsTypeName) o;
+            return Objects.equals(name, that.name);
+        }
+
+        @Override
+        public int hashCode() {
+            return Objects.hash(name);
+        }
+
+        @Override
+        public String toString() {
+            return name;
+        }
+    }
 }

http://git-wip-us.apache.org/repos/asf/groovy/blob/dbb665df/src/main/java/org/codehaus/groovy/ast/tools/GenericsUtils.java
----------------------------------------------------------------------
diff --git a/src/main/java/org/codehaus/groovy/ast/tools/GenericsUtils.java 
b/src/main/java/org/codehaus/groovy/ast/tools/GenericsUtils.java
index 879d217..375d1ef 100644
--- a/src/main/java/org/codehaus/groovy/ast/tools/GenericsUtils.java
+++ b/src/main/java/org/codehaus/groovy/ast/tools/GenericsUtils.java
@@ -54,6 +54,7 @@ import java.util.Map;
 import java.util.Objects;
 import java.util.concurrent.atomic.AtomicReference;
 
+import static org.codehaus.groovy.ast.GenericsType.GenericsTypeName;
 import static 
org.codehaus.groovy.transform.stc.StaticTypeCheckingSupport.getCorrectedClassNode;
 import static 
org.codehaus.groovy.transform.stc.StaticTypeCheckingSupport.implementsInterfaceOrIsSubclassOf;
 
@@ -140,8 +141,8 @@ public class GenericsUtils {
         return gt;
     }
 
-    public static Map<String, GenericsType> extractPlaceholders(ClassNode cn) {
-        Map<String, GenericsType> ret = new HashMap<String, GenericsType>();
+    public static Map<GenericsTypeName, GenericsType> 
extractPlaceholders(ClassNode cn) {
+        Map<GenericsTypeName, GenericsType> ret = new 
HashMap<GenericsTypeName, GenericsType>();
         extractPlaceholders(cn, ret);
         return ret;
     }
@@ -153,7 +154,7 @@ public class GenericsUtils {
      * @param node the class node to check
      * @param map the generics type information collector
      */
-    public static void extractPlaceholders(ClassNode node, Map<String, 
GenericsType> map) {
+    public static void extractPlaceholders(ClassNode node, 
Map<GenericsTypeName, GenericsType> map) {
         if (node == null) return;
 
         if (node.isArray()) {
@@ -179,7 +180,7 @@ public class GenericsUtils {
         for (int i = 0; i < redirectGenericsTypes.length; i++) {
             GenericsType redirectType = redirectGenericsTypes[i];
             if (redirectType.isPlaceholder()) {
-                String name = redirectType.getName();
+                GenericsTypeName name = new 
GenericsTypeName(redirectType.getName());
                 if (!map.containsKey(name)) {
                     GenericsType value = parameterized[i];
                     map.put(name, value);

http://git-wip-us.apache.org/repos/asf/groovy/blob/dbb665df/src/main/java/org/codehaus/groovy/ast/tools/WideningCategories.java
----------------------------------------------------------------------
diff --git 
a/src/main/java/org/codehaus/groovy/ast/tools/WideningCategories.java 
b/src/main/java/org/codehaus/groovy/ast/tools/WideningCategories.java
index 3f6efbb..68b67b3 100644
--- a/src/main/java/org/codehaus/groovy/ast/tools/WideningCategories.java
+++ b/src/main/java/org/codehaus/groovy/ast/tools/WideningCategories.java
@@ -52,7 +52,7 @@ import static 
org.codehaus.groovy.ast.ClassHelper.isNumberType;
 import static org.codehaus.groovy.ast.ClassHelper.isPrimitiveType;
 import static org.codehaus.groovy.ast.ClassHelper.long_TYPE;
 import static org.codehaus.groovy.ast.ClassHelper.short_TYPE;
-
+import static org.codehaus.groovy.ast.GenericsType.GenericsTypeName;
 /**
  * This class provides helper methods to determine the type from a widening
  * operation for example for a plus operation.
@@ -303,14 +303,14 @@ public class WideningCategories {
         ClassNode superClass = source.getUnresolvedSuperClass();
         // copy generic type information if available
         if (superClass!=null && superClass.isUsingGenerics()) {
-            Map<String, GenericsType> genericsTypeMap = 
GenericsUtils.extractPlaceholders(source);
+            Map<GenericsTypeName, GenericsType> genericsTypeMap = 
GenericsUtils.extractPlaceholders(source);
             GenericsType[] genericsTypes = superClass.getGenericsTypes();
             if (genericsTypes!=null) {
                 GenericsType[] copyTypes = new 
GenericsType[genericsTypes.length];
                 for (int i = 0; i < genericsTypes.length; i++) {
                     GenericsType genericsType = genericsTypes[i];
-                    if (genericsType.isPlaceholder() && 
genericsTypeMap.containsKey(genericsType.getName())) {
-                        copyTypes[i] = 
genericsTypeMap.get(genericsType.getName());
+                    if (genericsType.isPlaceholder() && 
genericsTypeMap.containsKey(new GenericsTypeName(genericsType.getName()))) {
+                        copyTypes[i] = genericsTypeMap.get(new 
GenericsTypeName(genericsType.getName()));
                     } else {
                         copyTypes[i] = genericsType;
                     }

http://git-wip-us.apache.org/repos/asf/groovy/blob/dbb665df/src/main/java/org/codehaus/groovy/control/ResolveVisitor.java
----------------------------------------------------------------------
diff --git a/src/main/java/org/codehaus/groovy/control/ResolveVisitor.java 
b/src/main/java/org/codehaus/groovy/control/ResolveVisitor.java
index 20adb0f..5b02b57 100644
--- a/src/main/java/org/codehaus/groovy/control/ResolveVisitor.java
+++ b/src/main/java/org/codehaus/groovy/control/ResolveVisitor.java
@@ -77,9 +77,9 @@ import java.util.List;
 import java.util.Map;
 import java.util.Set;
 
+import static org.codehaus.groovy.ast.GenericsType.GenericsTypeName;
 import static org.codehaus.groovy.ast.tools.GeneralUtils.inSamePackage;
 import static org.codehaus.groovy.ast.tools.GeneralUtils.isDefaultVisibility;
-
 /**
  * Visitor to resolve Types and convert VariableExpression to
  * ClassExpressions if needed. The ResolveVisitor will try to
@@ -106,7 +106,7 @@ public class ResolveVisitor extends 
ClassCodeExpressionTransformer {
     private boolean inPropertyExpression = false;
     private boolean inClosure = false;
 
-    private Map<String, GenericsType> genericParameterNames = new 
HashMap<String, GenericsType>();
+    private Map<GenericsTypeName, GenericsType> genericParameterNames = new 
HashMap<GenericsTypeName, GenericsType>();
     private final Set<FieldNode> fieldTypesChecked = new HashSet<FieldNode>();
     private boolean checkingVariableTypeInDeclaration = false;
     private ImportNode currImportNode = null;
@@ -228,10 +228,10 @@ public class ResolveVisitor extends 
ClassCodeExpressionTransformer {
     protected void visitConstructorOrMethod(MethodNode node, boolean 
isConstructor) {
         VariableScope oldScope = currentScope;
         currentScope = node.getVariableScope();
-        Map<String, GenericsType> oldPNames = genericParameterNames;
+        Map<GenericsTypeName, GenericsType> oldPNames = genericParameterNames;
         genericParameterNames = node.isStatic()
-                ? new HashMap<String, GenericsType>()
-                : new HashMap<String, GenericsType>(genericParameterNames);
+                ? new HashMap<GenericsTypeName, GenericsType>()
+                : new HashMap<GenericsTypeName, 
GenericsType>(genericParameterNames);
 
         resolveGenericsHeader(node.getGenericsTypes());
 
@@ -265,9 +265,9 @@ public class ResolveVisitor extends 
ClassCodeExpressionTransformer {
     }
 
     public void visitProperty(PropertyNode node) {
-        Map<String, GenericsType> oldPNames = genericParameterNames;
+        Map<GenericsTypeName, GenericsType> oldPNames = genericParameterNames;
         if (node.isStatic()) {
-            genericParameterNames = new HashMap<String, GenericsType>();
+            genericParameterNames = new HashMap<GenericsTypeName, 
GenericsType>();
         }
 
         ClassNode t = node.getType();
@@ -372,7 +372,7 @@ public class ResolveVisitor extends 
ClassCodeExpressionTransformer {
 
         String typeName = type.getName();
 
-        GenericsType genericsType = genericParameterNames.get(typeName);
+        GenericsType genericsType = genericParameterNames.get(new 
GenericsTypeName(typeName));
         if (genericsType != null) {
             type.setRedirect(genericsType.getType());
             type.setGenericsTypes(new GenericsType[]{ genericsType });
@@ -1337,7 +1337,7 @@ public class ResolveVisitor extends 
ClassCodeExpressionTransformer {
 
         if (node instanceof InnerClassNode) {
             if (Modifier.isStatic(node.getModifiers())) {
-                genericParameterNames = new HashMap<String, GenericsType>();
+                genericParameterNames = new HashMap<GenericsTypeName, 
GenericsType>();
             }
 
             InnerClassNode innerClassNode = (InnerClassNode) node;
@@ -1348,7 +1348,7 @@ public class ResolveVisitor extends 
ClassCodeExpressionTransformer {
                 }
             }
         } else {
-            genericParameterNames = new HashMap<String, GenericsType>();
+            genericParameterNames = new HashMap<GenericsTypeName, 
GenericsType>();
         }
 
         resolveGenericsHeader(node.getGenericsTypes());
@@ -1493,7 +1493,7 @@ public class ResolveVisitor extends 
ClassCodeExpressionTransformer {
             String name = type.getName();
             ClassNode[] bounds = type.getUpperBounds();
             boolean isWild = QUESTION_MARK.equals(name);
-            boolean toDealWithGenerics = 0 == level || (level > 0 && null != 
genericParameterNames.get(name));
+            boolean toDealWithGenerics = 0 == level || (level > 0 && null != 
genericParameterNames.get(new GenericsTypeName(name)));
 
             if (bounds != null) {
                 boolean nameAdded = false;
@@ -1501,7 +1501,7 @@ public class ResolveVisitor extends 
ClassCodeExpressionTransformer {
                     if (!isWild) {
                         if (!nameAdded && upperBound != null || 
!resolve(classNode)) {
                             if (toDealWithGenerics) {
-                                genericParameterNames.put(name, type);
+                                genericParameterNames.put(new 
GenericsTypeName(name), type);
                                 type.setPlaceholder(true);
                                 classNode.setRedirect(upperBound);
                                 nameAdded = true;
@@ -1518,8 +1518,8 @@ public class ResolveVisitor extends 
ClassCodeExpressionTransformer {
             } else {
                 if (!isWild) {
                     if (toDealWithGenerics) {
-                        GenericsType originalGt = 
genericParameterNames.get(name);
-                        genericParameterNames.put(name, type);
+                        GenericsType originalGt = 
genericParameterNames.get(new GenericsTypeName(name));
+                        genericParameterNames.put(new GenericsTypeName(name), 
type);
                         type.setPlaceholder(true);
 
                         if (null == originalGt) {
@@ -1550,7 +1550,7 @@ public class ResolveVisitor extends 
ClassCodeExpressionTransformer {
         currentClass.setUsingGenerics(true);
         ClassNode type = genericsType.getType();
         // save name before redirect
-        String name = type.getName();
+        GenericsTypeName name = new GenericsTypeName(type.getName());
         ClassNode[] bounds = genericsType.getUpperBounds();
         if (!genericParameterNames.containsKey(name)) {
             if (bounds != null) {

http://git-wip-us.apache.org/repos/asf/groovy/blob/dbb665df/src/main/java/org/codehaus/groovy/transform/stc/StaticTypeCheckingSupport.java
----------------------------------------------------------------------
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 dac508b..5a6cfa8 100644
--- 
a/src/main/java/org/codehaus/groovy/transform/stc/StaticTypeCheckingSupport.java
+++ 
b/src/main/java/org/codehaus/groovy/transform/stc/StaticTypeCheckingSupport.java
@@ -16,6 +16,7 @@
  *  specific language governing permissions and limitations
  *  under the License.
  */
+
 package org.codehaus.groovy.transform.stc;
 
 import org.codehaus.groovy.GroovyBugError;
@@ -107,6 +108,7 @@ import static org.codehaus.groovy.ast.ClassHelper.make;
 import static org.codehaus.groovy.ast.ClassHelper.makeWithoutCaching;
 import static org.codehaus.groovy.ast.ClassHelper.short_TYPE;
 import static org.codehaus.groovy.ast.ClassHelper.void_WRAPPER_TYPE;
+import static org.codehaus.groovy.ast.GenericsType.GenericsTypeName;
 import static org.codehaus.groovy.ast.tools.GenericsUtils.getSuperClass;
 import static org.codehaus.groovy.syntax.Types.ASSIGN;
 import static org.codehaus.groovy.syntax.Types.BITWISE_AND;
@@ -152,7 +154,6 @@ import static org.codehaus.groovy.syntax.Types.RIGHT_SHIFT;
 import static org.codehaus.groovy.syntax.Types.RIGHT_SHIFT_EQUAL;
 import static org.codehaus.groovy.syntax.Types.RIGHT_SHIFT_UNSIGNED;
 import static org.codehaus.groovy.syntax.Types.RIGHT_SHIFT_UNSIGNED_EQUAL;
-
 /**
  * Static support methods for {@link StaticTypeCheckingVisitor}.
  */
@@ -1295,8 +1296,8 @@ public abstract class StaticTypeCheckingSupport {
      * @return the parameterized arguments
      */
     public static Parameter[] parameterizeArguments(final ClassNode receiver, 
final MethodNode m) {
-        Map<String, GenericsType> genericFromReceiver = 
GenericsUtils.extractPlaceholders(receiver);
-        Map<String, GenericsType> contextPlaceholders = 
extractGenericsParameterMapOfThis(m);
+        Map<GenericsTypeName, GenericsType> genericFromReceiver = 
GenericsUtils.extractPlaceholders(receiver);
+        Map<GenericsTypeName, GenericsType> contextPlaceholders = 
extractGenericsParameterMapOfThis(m);
         Parameter[] methodParameters = m.getParameters();
         Parameter[] params = new Parameter[methodParameters.length];
         for (int i = 0; i < methodParameters.length; i++) {
@@ -1316,7 +1317,7 @@ public abstract class StaticTypeCheckingSupport {
      * @param paramType                the (unresolved) type of the method 
parameter
      * @return a new parameter with the same name and type as the original 
one, but with resolved generic types
      */
-    private static Parameter buildParameter(final Map<String, GenericsType> 
genericFromReceiver, final Map<String, GenericsType> placeholdersFromContext, 
final Parameter methodParameter, final ClassNode paramType) {
+    private static Parameter buildParameter(final Map<GenericsTypeName, 
GenericsType> genericFromReceiver, final Map<GenericsTypeName, GenericsType> 
placeholdersFromContext, final Parameter methodParameter, final ClassNode 
paramType) {
         if (genericFromReceiver.isEmpty() && (placeholdersFromContext == null 
|| placeholdersFromContext.isEmpty())) {
             return methodParameter;
         }
@@ -1349,8 +1350,8 @@ public abstract class StaticTypeCheckingSupport {
      * Given a generics type representing SomeClass&lt;T,V&gt; and a resolved 
placeholder map, returns a new generics type
      * for which placeholders are resolved recursively.
      */
-    protected static GenericsType fullyResolve(GenericsType gt, Map<String, 
GenericsType> placeholders) {
-        GenericsType fromMap = placeholders.get(gt.getName());
+    protected static GenericsType fullyResolve(GenericsType gt, 
Map<GenericsTypeName, GenericsType> placeholders) {
+        GenericsType fromMap = placeholders.get(new 
GenericsTypeName(gt.getName()));
         if (gt.isPlaceholder() && fromMap != null) {
             gt = fromMap;
         }
@@ -1372,15 +1373,15 @@ public abstract class StaticTypeCheckingSupport {
         return genericsType;
     }
 
-    protected static ClassNode fullyResolveType(final ClassNode type, final 
Map<String, GenericsType> placeholders) {
+    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; i < gts.length; i++) {
                     GenericsType genericsType = gts[i];
-                    if (genericsType.isPlaceholder() && 
placeholders.containsKey(genericsType.getName())) {
-                        copy[i] = placeholders.get(genericsType.getName());
+                    if (genericsType.isPlaceholder() && 
placeholders.containsKey(new GenericsTypeName(genericsType.getName()))) {
+                        copy[i] = placeholders.get(new 
GenericsTypeName(genericsType.getName()));
                     } else {
                         copy[i] = fullyResolve(genericsType, placeholders);
                     }
@@ -1392,7 +1393,7 @@ public abstract class StaticTypeCheckingSupport {
             return result;
         } else if (type.isUsingGenerics() && OBJECT_TYPE.equals(type) && 
type.getGenericsTypes() != null) {
             // Object<T>
-            GenericsType genericsType = 
placeholders.get(type.getGenericsTypes()[0].getName());
+            GenericsType genericsType = placeholders.get(new 
GenericsTypeName(type.getGenericsTypes()[0].getName()));
             if (genericsType != null) {
                 return genericsType.getType();
             }
@@ -1444,7 +1445,7 @@ public abstract class StaticTypeCheckingSupport {
         return true;
     }
 
-    static void addMethodLevelDeclaredGenerics(MethodNode method, Map<String, 
GenericsType> resolvedPlaceholders) {
+    static void addMethodLevelDeclaredGenerics(MethodNode method, 
Map<GenericsTypeName, GenericsType> resolvedPlaceholders) {
         ClassNode dummy = OBJECT_TYPE.getPlainNodeReference();
         dummy.setGenericsTypes(method.getGenericsTypes());
         GenericsUtils.extractPlaceholders(dummy, resolvedPlaceholders);
@@ -1486,7 +1487,7 @@ public abstract class StaticTypeCheckingSupport {
         boolean skipBecauseOfInnerClassNotReceiver = isOuterClassOf(receiver, 
candidateMethod.getDeclaringClass());
 
         Parameter[] parameters = candidateMethod.getParameters();
-        Map<String, GenericsType> classGTs;
+        Map<GenericsTypeName, GenericsType> classGTs;
         if (skipBecauseOfInnerClassNotReceiver) {
             classGTs = Collections.EMPTY_MAP;
         } else {
@@ -1502,12 +1503,12 @@ public abstract class StaticTypeCheckingSupport {
         // There is firstly the context given through the class, and the 
method.
         // The method context may hide generics given through the class, but 
use 
         // the non-hidden ones.
-        Map<String, GenericsType> resolvedMethodGenerics = new HashMap<String, 
GenericsType>();
+        Map<GenericsTypeName, GenericsType> resolvedMethodGenerics = new 
HashMap<GenericsTypeName, GenericsType>();
         if (!skipBecauseOfInnerClassNotReceiver) {
             addMethodLevelDeclaredGenerics(candidateMethod, 
resolvedMethodGenerics);
         }
         // so first we remove hidden generics
-        for (String key : resolvedMethodGenerics.keySet()) 
classGTs.remove(key);
+        for (GenericsTypeName key : resolvedMethodGenerics.keySet()) 
classGTs.remove(key);
         // then we use the remaining information to refine the given generics
         applyGenericsConnections(classGTs, resolvedMethodGenerics);
         // and then start our checks with the receiver
@@ -1519,7 +1520,7 @@ public abstract class StaticTypeCheckingSupport {
         // extension methods are special, since they set the receiver as 
         // first parameter. While we normally allow generalization for the 
first
         // parameter, in case of an extension method we must not. 
-        Set<String> fixedGenericsPlaceHolders = 
extractResolvedPlaceHolders(resolvedMethodGenerics);
+        Set<GenericsTypeName> fixedGenericsPlaceHolders = 
extractResolvedPlaceHolders(resolvedMethodGenerics);
 
         for (int i = 0; i < arguments.length; i++) {
             int pindex = min(i, parameters.length - 1);
@@ -1540,10 +1541,10 @@ public abstract class StaticTypeCheckingSupport {
         return true;
     }
 
-    private static Set<String> extractResolvedPlaceHolders(Map<String, 
GenericsType> resolvedMethodGenerics) {
+    private static Set<GenericsTypeName> 
extractResolvedPlaceHolders(Map<GenericsTypeName, GenericsType> 
resolvedMethodGenerics) {
         if (resolvedMethodGenerics.isEmpty()) return Collections.EMPTY_SET;
-        Set<String> result = new HashSet<String>();
-        for (Map.Entry<String, GenericsType> entry : 
resolvedMethodGenerics.entrySet()) {
+        Set<GenericsTypeName> result = new HashSet<GenericsTypeName>();
+        for (Entry<GenericsTypeName, GenericsType> entry : 
resolvedMethodGenerics.entrySet()) {
             GenericsType value = entry.getValue();
             if (value.isPlaceholder()) continue;
             result.add(entry.getKey());
@@ -1551,8 +1552,8 @@ public abstract class StaticTypeCheckingSupport {
         return result;
     }
 
-    private static boolean inferenceCheck(Set<String> 
fixedGenericsPlaceHolders, Map<String, GenericsType> resolvedMethodGenerics, 
ClassNode type, ClassNode wrappedArgument, boolean lastArg) {
-        Map<String, GenericsType> connections = new HashMap<String, 
GenericsType>();
+    private static boolean inferenceCheck(Set<GenericsTypeName> 
fixedGenericsPlaceHolders, Map<GenericsTypeName, GenericsType> 
resolvedMethodGenerics, ClassNode type, ClassNode wrappedArgument, boolean 
lastArg) {
+        Map<GenericsTypeName, GenericsType> connections = new 
HashMap<GenericsTypeName, GenericsType>();
         if (isPrimitiveType(wrappedArgument)) wrappedArgument = 
getWrapper(wrappedArgument);
         // the context we compare with in the end is the one of the callsite
         // so far we specified the context of the method declaration only
@@ -1587,8 +1588,8 @@ public abstract class StaticTypeCheckingSupport {
         return gt;
     }
 
-    private static boolean compatibleConnections(Map<String, GenericsType> 
connections, Map<String, GenericsType> resolvedMethodGenerics, Set<String> 
fixedGenericsPlaceHolders) {
-        for (Map.Entry<String, GenericsType> entry : connections.entrySet()) {
+    private static boolean compatibleConnections(Map<GenericsTypeName, 
GenericsType> connections, Map<GenericsTypeName, GenericsType> 
resolvedMethodGenerics, Set<GenericsTypeName> fixedGenericsPlaceHolders) {
+        for (Entry<GenericsTypeName, GenericsType> entry : 
connections.entrySet()) {
             GenericsType resolved = resolvedMethodGenerics.get(entry.getKey());
             if (resolved == null) continue;
             GenericsType connection = entry.getValue();
@@ -1634,8 +1635,8 @@ public abstract class StaticTypeCheckingSupport {
         return gt.isCompatibleWith(compareNode);
     }
 
-    private static void addMissingEntries(Map<String, GenericsType> 
connections, Map<String, GenericsType> resolved) {
-        for (Entry<String, GenericsType> entry : connections.entrySet()) {
+    private static void addMissingEntries(Map<GenericsTypeName, GenericsType> 
connections, Map<GenericsTypeName, GenericsType> resolved) {
+        for (Entry<GenericsTypeName, GenericsType> entry : 
connections.entrySet()) {
             if (resolved.containsKey(entry.getKey())) continue;
             GenericsType gt = entry.getValue();
             ClassNode cn = gt.getType();
@@ -1644,12 +1645,12 @@ public abstract class StaticTypeCheckingSupport {
         }
     }
 
-    public static ClassNode resolveClassNodeGenerics(Map<String, GenericsType> 
resolvedPlaceholders, final Map<String, GenericsType> placeholdersFromContext, 
ClassNode currentType) {
+    public static ClassNode resolveClassNodeGenerics(Map<GenericsTypeName, 
GenericsType> resolvedPlaceholders, final Map<GenericsTypeName, GenericsType> 
placeholdersFromContext, ClassNode currentType) {
         ClassNode target = currentType.redirect();
-        resolvedPlaceholders = new HashMap<String, 
GenericsType>(resolvedPlaceholders);
+        resolvedPlaceholders = new HashMap<GenericsTypeName, 
GenericsType>(resolvedPlaceholders);
         applyContextGenerics(resolvedPlaceholders, placeholdersFromContext);
 
-        Map<String, GenericsType> connections = new HashMap<String, 
GenericsType>();
+        Map<GenericsTypeName, GenericsType> connections = new 
HashMap<GenericsTypeName, GenericsType>();
         extractGenericsConnections(connections, currentType, target);
         applyGenericsConnections(connections, resolvedPlaceholders);
         currentType = applyGenericsContext(resolvedPlaceholders, currentType);
@@ -1657,16 +1658,16 @@ public abstract class StaticTypeCheckingSupport {
     }
 
     static void applyGenericsConnections(
-            Map<String, GenericsType> connections,
-            Map<String, GenericsType> resolvedPlaceholders
+            Map<GenericsTypeName, GenericsType> connections,
+            Map<GenericsTypeName, GenericsType> resolvedPlaceholders
     ) {
         if (connections == null) return;
         int count = 0;
         while (count < 10000) {
             count++;
             boolean checkForMorePlaceHolders = false;
-            for (Map.Entry<String, GenericsType> entry : 
resolvedPlaceholders.entrySet()) {
-                String name = entry.getKey();
+            for (Entry<GenericsTypeName, GenericsType> entry : 
resolvedPlaceholders.entrySet()) {
+                GenericsTypeName name = entry.getKey();
                 GenericsType replacement = connections.get(name);
                 if (replacement == null) {
                     GenericsType value = entry.getValue();
@@ -1681,7 +1682,7 @@ public abstract class StaticTypeCheckingSupport {
                 }
                 boolean placeholderReplacement = replacement.isPlaceholder();
                 if (placeholderReplacement) {
-                    GenericsType connectedType = 
resolvedPlaceholders.get(replacement.getName());
+                    GenericsType connectedType = resolvedPlaceholders.get(new 
GenericsTypeName(replacement.getName()));
                     if (replacement == connectedType) continue;
                 }
                 // GROOVY-6787: Don't override the original if the replacement 
placeholder doesn't respect the bounds,
@@ -1771,7 +1772,7 @@ public abstract class StaticTypeCheckingSupport {
      * to get E=Integer, since IntRange is an AbstractList&lt;Integer&gt;)
      * Should the target not have any generics this method does nothing.
      */
-    static void extractGenericsConnections(Map<String, GenericsType> 
connections, ClassNode type, ClassNode target) {
+    static void extractGenericsConnections(Map<GenericsTypeName, GenericsType> 
connections, ClassNode type, ClassNode target) {
         if (target == null || type == target || 
!isUsingGenericsOrIsArrayUsingGenerics(target)) return;
         if (type == null || type == UNKNOWN_PARAMETER_TYPE) return;
         if (type.isArray() && target.isArray()) {
@@ -1779,7 +1780,7 @@ public abstract class StaticTypeCheckingSupport {
         } else if (target.isGenericsPlaceHolder() || type.equals(target) || 
!implementsInterfaceOrIsSubclassOf(type, target)) {
             // structural match route
             if (target.isGenericsPlaceHolder()) {
-                connections.put(target.getGenericsTypes()[0].getName(), new 
GenericsType(type));
+                connections.put(new 
GenericsTypeName(target.getGenericsTypes()[0].getName()), new 
GenericsType(type));
             } else {
                 extractGenericsConnections(connections, 
type.getGenericsTypes(), target.getGenericsTypes());
             }
@@ -1807,7 +1808,7 @@ public abstract class StaticTypeCheckingSupport {
         return corrected;
     }
 
-    private static void extractGenericsConnections(Map<String, GenericsType> 
connections, GenericsType[] usage, GenericsType[] declaration) {
+    private static void extractGenericsConnections(Map<GenericsTypeName, 
GenericsType> connections, GenericsType[] usage, GenericsType[] declaration) {
         // if declaration does not provide generics, there is no connection to 
make 
         if (usage == null || declaration == null || declaration.length == 0) 
return;
         if (usage.length != declaration.length) return;
@@ -1817,7 +1818,7 @@ public abstract class StaticTypeCheckingSupport {
             GenericsType ui = usage[i];
             GenericsType di = declaration[i];
             if (di.isPlaceholder()) {
-                connections.put(di.getName(), ui);
+                connections.put(new GenericsTypeName(di.getName()), ui);
             } else if (di.isWildcard()) {
                 if (ui.isWildcard()) {
                     extractGenericsConnections(connections, 
ui.getLowerBound(), di.getLowerBound());
@@ -1838,7 +1839,7 @@ public abstract class StaticTypeCheckingSupport {
         }
     }
 
-    private static void extractGenericsConnections(Map<String, GenericsType> 
connections, ClassNode[] usage, ClassNode[] declaration) {
+    private static void extractGenericsConnections(Map<GenericsTypeName, 
GenericsType> connections, ClassNode[] usage, ClassNode[] declaration) {
         if (usage == null || declaration == null || declaration.length == 0) 
return;
         // both have generics
         for (int i = 0; i < usage.length; i++) {
@@ -1847,7 +1848,7 @@ public abstract class StaticTypeCheckingSupport {
             if (di.isGenericsPlaceHolder()) {
                 GenericsType gt = new GenericsType(di);
                 gt.setPlaceholder(di.isGenericsPlaceHolder());
-                connections.put(di.getGenericsTypes()[0].getName(), gt);
+                connections.put(new 
GenericsTypeName(di.getGenericsTypes()[0].getName()), gt);
             } else if (di.isUsingGenerics()) {
                 extractGenericsConnections(connections, ui.getGenericsTypes(), 
di.getGenericsTypes());
             }
@@ -1859,8 +1860,8 @@ public abstract class StaticTypeCheckingSupport {
         return type.getGenericsTypes();
     }
 
-    static Map<String, GenericsType> applyGenericsContextToParameterClass(
-            Map<String, GenericsType> spec, ClassNode parameterUsage
+    static Map<GenericsTypeName, GenericsType> 
applyGenericsContextToParameterClass(
+            Map<GenericsTypeName, GenericsType> spec, ClassNode parameterUsage
     ) {
         GenericsType[] gts = parameterUsage.getGenericsTypes();
         if (gts == null) return Collections.EMPTY_MAP;
@@ -1872,7 +1873,7 @@ public abstract class StaticTypeCheckingSupport {
     }
 
     private static GenericsType[] applyGenericsContext(
-            Map<String, GenericsType> spec, GenericsType[] gts
+            Map<GenericsTypeName, GenericsType> spec, GenericsType[] gts
     ) {
         if (gts == null) return null;
         GenericsType[] newGTs = new GenericsType[gts.length];
@@ -1883,9 +1884,9 @@ public abstract class StaticTypeCheckingSupport {
         return newGTs;
     }
 
-    private static GenericsType applyGenericsContext(Map<String, GenericsType> 
spec, GenericsType gt) {
+    private static GenericsType applyGenericsContext(Map<GenericsTypeName, 
GenericsType> spec, GenericsType gt) {
         if (gt.isPlaceholder()) {
-            String name = gt.getName();
+            GenericsTypeName name = new GenericsTypeName(gt.getName());
             GenericsType specType = spec.get(name);
             if (specType != null) return specType;
             if (hasNonTrivialBounds(gt)) {
@@ -1918,7 +1919,7 @@ public abstract class StaticTypeCheckingSupport {
     }
 
     private static ClassNode[] applyGenericsContext(
-            Map<String, GenericsType> spec, ClassNode[] bounds
+            Map<GenericsTypeName, GenericsType> spec, ClassNode[] bounds
     ) {
         if (bounds == null) return null;
         ClassNode[] newBounds = new ClassNode[bounds.length];
@@ -1929,7 +1930,7 @@ public abstract class StaticTypeCheckingSupport {
     }
 
     static ClassNode applyGenericsContext(
-            Map<String, GenericsType> spec, ClassNode bound
+            Map<GenericsTypeName, GenericsType> spec, ClassNode bound
     ) {
         if (bound == null) return null;
         if (bound.isArray()) {
@@ -1966,12 +1967,12 @@ public abstract class StaticTypeCheckingSupport {
         return genericsType.getType();
     }
 
-    private static void applyContextGenerics(Map<String, GenericsType> 
resolvedPlaceholders, Map<String, GenericsType> placeholdersFromContext) {
+    private static void applyContextGenerics(Map<GenericsTypeName, 
GenericsType> resolvedPlaceholders, Map<GenericsTypeName, GenericsType> 
placeholdersFromContext) {
         if (placeholdersFromContext == null) return;
-        for (Map.Entry<String, GenericsType> entry : 
resolvedPlaceholders.entrySet()) {
+        for (Entry<GenericsTypeName, GenericsType> entry : 
resolvedPlaceholders.entrySet()) {
             GenericsType gt = entry.getValue();
             if (gt.isPlaceholder()) {
-                String name = gt.getName();
+                GenericsTypeName name = new GenericsTypeName(gt.getName());
                 GenericsType outer = placeholdersFromContext.get(name);
                 if (outer == null) continue;
                 entry.setValue(outer);
@@ -1979,9 +1980,9 @@ public abstract class StaticTypeCheckingSupport {
         }
     }
 
-    private static Map<String, GenericsType> 
getGenericsParameterMapOfThis(ClassNode cn) {
+    private static Map<GenericsTypeName, GenericsType> 
getGenericsParameterMapOfThis(ClassNode cn) {
         if (cn == null) return null;
-        Map<String, GenericsType> map = null;
+        Map<GenericsTypeName, GenericsType> map = null;
         if (cn.getEnclosingMethod() != null) {
             map = extractGenericsParameterMapOfThis(cn.getEnclosingMethod());
         } else if (cn.getOuterClass() != null) {
@@ -2039,10 +2040,10 @@ public abstract class StaticTypeCheckingSupport {
         return false;
     }
 
-    static Map<String, GenericsType> 
extractGenericsParameterMapOfThis(MethodNode mn) {
+    static Map<GenericsTypeName, GenericsType> 
extractGenericsParameterMapOfThis(MethodNode mn) {
         if (mn == null) return null;
 
-        Map<String, GenericsType> map;
+        Map<GenericsTypeName, GenericsType> map;
         if (mn.isStatic()) {
             map = new HashMap<>();
         } else {
@@ -2052,12 +2053,12 @@ public abstract class StaticTypeCheckingSupport {
         return mergeGenerics(map, mn.getGenericsTypes());
     }
 
-    private static Map<String, GenericsType> mergeGenerics(Map<String, 
GenericsType> current, GenericsType[] newGenerics) {
+    private static Map<GenericsTypeName, GenericsType> 
mergeGenerics(Map<GenericsTypeName, GenericsType> current, GenericsType[] 
newGenerics) {
         if (newGenerics == null || newGenerics.length == 0) return current;
-        if (current == null) current = new HashMap<String, GenericsType>();
+        if (current == null) current = new HashMap<GenericsTypeName, 
GenericsType>();
         for (GenericsType gt : newGenerics) {
             if (!gt.isPlaceholder()) continue;
-            String name = gt.getName();
+            GenericsTypeName name = new GenericsTypeName(gt.getName());
             if (!current.containsKey(name)) current.put(name, gt);
         }
         return current;

http://git-wip-us.apache.org/repos/asf/groovy/blob/dbb665df/src/main/java/org/codehaus/groovy/transform/stc/StaticTypeCheckingVisitor.java
----------------------------------------------------------------------
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 98ab3e5..56dc529 100644
--- 
a/src/main/java/org/codehaus/groovy/transform/stc/StaticTypeCheckingVisitor.java
+++ 
b/src/main/java/org/codehaus/groovy/transform/stc/StaticTypeCheckingVisitor.java
@@ -62,6 +62,7 @@ import org.codehaus.groovy.ast.expr.MapEntryExpression;
 import org.codehaus.groovy.ast.expr.MapExpression;
 import org.codehaus.groovy.ast.expr.MethodCall;
 import org.codehaus.groovy.ast.expr.MethodCallExpression;
+import org.codehaus.groovy.ast.expr.NotExpression;
 import org.codehaus.groovy.ast.expr.PostfixExpression;
 import org.codehaus.groovy.ast.expr.PrefixExpression;
 import org.codehaus.groovy.ast.expr.PropertyExpression;
@@ -73,7 +74,6 @@ import org.codehaus.groovy.ast.expr.TupleExpression;
 import org.codehaus.groovy.ast.expr.UnaryMinusExpression;
 import org.codehaus.groovy.ast.expr.UnaryPlusExpression;
 import org.codehaus.groovy.ast.expr.VariableExpression;
-import org.codehaus.groovy.ast.expr.NotExpression;
 import org.codehaus.groovy.ast.stmt.BlockStatement;
 import org.codehaus.groovy.ast.stmt.CaseStatement;
 import org.codehaus.groovy.ast.stmt.CatchStatement;
@@ -166,6 +166,7 @@ import static org.codehaus.groovy.ast.ClassHelper.long_TYPE;
 import static org.codehaus.groovy.ast.ClassHelper.make;
 import static org.codehaus.groovy.ast.ClassHelper.short_TYPE;
 import static org.codehaus.groovy.ast.ClassHelper.void_WRAPPER_TYPE;
+import static org.codehaus.groovy.ast.GenericsType.GenericsTypeName;
 import static org.codehaus.groovy.ast.tools.GeneralUtils.args;
 import static org.codehaus.groovy.ast.tools.GeneralUtils.binX;
 import static org.codehaus.groovy.ast.tools.GeneralUtils.callX;
@@ -1697,7 +1698,7 @@ public class StaticTypeCheckingVisitor extends 
ClassCodeVisitorSupport {
     private void storeWithResolve(ClassNode typeToResolve, ClassNode receiver, 
ClassNode declaringClass, boolean isStatic, PropertyExpression 
expressionToStoreOn) {
         ClassNode type = typeToResolve;
         if (getGenericsWithoutArray(type) != null) {
-            Map<String, GenericsType> resolvedPlaceholders = 
resolvePlaceHoldersFromDeclaration(receiver, declaringClass, null, isStatic);
+            Map<GenericsTypeName, GenericsType> resolvedPlaceholders = 
resolvePlaceHoldersFromDeclaration(receiver, declaringClass, null, isStatic);
             type = resolveGenericsWithContext(resolvedPlaceholders, type);
         }
         storeInferredTypeForPropertyExpression(expressionToStoreOn, type);
@@ -2635,18 +2636,18 @@ public class StaticTypeCheckingVisitor extends 
ClassCodeVisitorSupport {
     private void inferSAMType(Parameter param, ClassNode receiver, MethodNode 
methodWithSAMParameter, ArgumentListExpression originalMethodCallArguments, 
ClosureExpression openBlock) {
         // In a method call with SAM coercion the inference is to be
         // understood as a two phase process. We have the normal method call
-        // to the target method with the closure argument and we have the 
-        // SAM method that will be called inside the normal target method. 
+        // to the target method with the closure argument and we have the
+        // SAM method that will be called inside the normal target method.
         // To infer correctly we have to "simulate" this process. We know the
         // call to the closure will be done through the SAM type, so the SAM
         // type generics deliver information about the Closure. At the same
-        // time the SAM class is used in the target method parameter, 
+        // time the SAM class is used in the target method parameter,
         // providing a connection from the SAM type and the target method
         // declaration class.
 
         // First we try to get as much information about the declaration
         // class through the receiver
-        Map<String, GenericsType> targetMethodDeclarationClassConnections = 
new HashMap<String, GenericsType>();
+        Map<GenericsTypeName, GenericsType> 
targetMethodDeclarationClassConnections = new HashMap<GenericsTypeName, 
GenericsType>();
         extractGenericsConnections(targetMethodDeclarationClassConnections, 
receiver, receiver.redirect());
         // then we use the method with the SAM parameter to get more 
information about the declaration
         Parameter[] parametersOfMethodContainingSAM = 
methodWithSAMParameter.getParameters();
@@ -2667,7 +2668,7 @@ public class StaticTypeCheckingVisitor extends 
ClassCodeVisitorSupport {
         // to replace the generics in the SAM type parameter of the target
         // method and than that to make the connections to the SAM type 
generics
         ClassNode paramTypeWithReceiverInformation = 
applyGenericsContext(targetMethodDeclarationClassConnections, 
param.getOriginType());
-        Map<String, GenericsType> SAMTypeConnections = new HashMap<String, 
GenericsType>();
+        Map<GenericsTypeName, GenericsType> SAMTypeConnections = new 
HashMap<GenericsTypeName, GenericsType>();
         ClassNode classForSAM = paramTypeWithReceiverInformation.redirect();
         extractGenericsConnections(SAMTypeConnections, 
paramTypeWithReceiverInformation, classForSAM);
 
@@ -2699,7 +2700,7 @@ public class StaticTypeCheckingVisitor extends 
ClassCodeVisitorSupport {
             extractGenericsConnections(SAMTypeConnections, 
blockParameterTypes[i], typeOrNull(parameterTypesForSAM, i));
         }
 
-        // and finally we apply the generics information to the parameters and 
+        // and finally we apply the generics information to the parameters and
         // store the type of parameter and block type as meta information
         for (int i = 0; i < blockParameterTypes.length; i++) {
             ClassNode resolvedParameter =
@@ -4099,17 +4100,17 @@ public class StaticTypeCheckingVisitor extends 
ClassCodeVisitorSupport {
     }
 
     private ClassNode inferSAMTypeGenericsInAssignment(ClassNode samUsage, 
MethodNode sam, ClassNode closureType, ClosureExpression closureExpression) {
-        // if the sam type or closure type do not provide generics 
information, 
+        // if the sam type or closure type do not provide generics information,
         // we cannot infer anything, thus we simply return the provided 
samUsage
         GenericsType[] samGt = samUsage.getGenericsTypes();
         GenericsType[] closureGt = closureType.getGenericsTypes();
         if (samGt == null || closureGt == null) return samUsage;
 
         // extract the generics from the return type
-        Map<String, GenericsType> connections = new HashMap<String, 
GenericsType>();
+        Map<GenericsTypeName, GenericsType> connections = new 
HashMap<GenericsTypeName, GenericsType>();
         extractGenericsConnections(connections, 
getInferredReturnType(closureExpression), sam.getReturnType());
 
-        // next we get the block parameter types and set the generics 
+        // next we get the block parameter types and set the generics
         // information just like before
         // TODO: add vargs handling
         Parameter[] closureParams = closureExpression.getParameters();
@@ -4690,7 +4691,7 @@ public class StaticTypeCheckingVisitor extends 
ClassCodeVisitorSupport {
      */
     private ClassNode getGenericsResolvedTypeOfFieldOrProperty(AnnotatedNode 
an, ClassNode type) {
         if (!type.isUsingGenerics()) return type;
-        Map<String, GenericsType> connections = new HashMap<String, 
GenericsType>();
+        Map<GenericsTypeName, GenericsType> connections = new 
HashMap<GenericsTypeName, GenericsType>();
         //TODO: inner classes mean a different this-type. This is ignored here!
         extractGenericsConnections(connections, 
typeCheckingContext.getEnclosingClassNode(), an.getDeclaringClass());
         type = applyGenericsContext(connections, type);
@@ -4875,7 +4876,7 @@ public class StaticTypeCheckingVisitor extends 
ClassCodeVisitorSupport {
         }
         if (!isUsingGenericsOrIsArrayUsingGenerics(returnType)) return 
returnType;
         if (getGenericsWithoutArray(returnType) == null) return returnType;
-        Map<String, GenericsType> resolvedPlaceholders = 
resolvePlaceHoldersFromDeclaration(receiver, getDeclaringClass(method, 
arguments), method, method.isStatic());
+        Map<GenericsTypeName, GenericsType> resolvedPlaceholders = 
resolvePlaceHoldersFromDeclaration(receiver, getDeclaringClass(method, 
arguments), method, method.isStatic());
         if (!receiver.isGenericsPlaceHolder()) {
             GenericsUtils.extractPlaceholders(receiver, resolvedPlaceholders);
         }
@@ -4883,7 +4884,7 @@ public class StaticTypeCheckingVisitor extends 
ClassCodeVisitorSupport {
         if (resolvedPlaceholders.isEmpty()) {
             return boundUnboundedWildcards(returnType);
         }
-        Map<String, GenericsType> placeholdersFromContext = 
extractGenericsParameterMapOfThis(typeCheckingContext.getEnclosingMethod());
+        Map<GenericsTypeName, GenericsType> placeholdersFromContext = 
extractGenericsParameterMapOfThis(typeCheckingContext.getEnclosingMethod());
         applyGenericsConnections(placeholdersFromContext, 
resolvedPlaceholders);
 
         // then resolve receivers from method arguments
@@ -4905,7 +4906,7 @@ public class StaticTypeCheckingVisitor extends 
ClassCodeVisitorSupport {
                     if (implementsInterfaceOrIsSubclassOf(actualType, 
CLOSURE_TYPE) &&
                             isSAMType(type)) {
                         // implicit closure coercion in action!
-                        Map<String, GenericsType> pholders = 
applyGenericsContextToParameterClass(resolvedPlaceholders, type);
+                        Map<GenericsTypeName, GenericsType> pholders = 
applyGenericsContextToParameterClass(resolvedPlaceholders, type);
                         actualType = 
convertClosureTypeToSAMType(expressions.get(i), actualType, type, pholders);
                     }
                     if (isVargs && lastArg && actualType.isArray()) {
@@ -4916,7 +4917,7 @@ public class StaticTypeCheckingVisitor extends 
ClassCodeVisitorSupport {
                     }
                     actualType = wrapTypeIfNecessary(actualType);
 
-                    Map<String, GenericsType> connections = new 
HashMap<String, GenericsType>();
+                    Map<GenericsTypeName, GenericsType> connections = new 
HashMap<GenericsTypeName, GenericsType>();
                     extractGenericsConnections(connections, actualType, type);
                     
extractGenericsConnectionsForSuperClassAndInterfaces(resolvedPlaceholders, 
connections);
                     applyGenericsConnections(connections, 
resolvedPlaceholders);
@@ -4927,20 +4928,20 @@ public class StaticTypeCheckingVisitor extends 
ClassCodeVisitorSupport {
         return applyGenericsContext(resolvedPlaceholders, returnType);
     }
 
-    private static void resolvePlaceholdersFromExplicitTypeHints(final 
MethodNode method, final GenericsType[] explicitTypeHints, final Map<String, 
GenericsType> resolvedPlaceholders) {
+    private static void resolvePlaceholdersFromExplicitTypeHints(final 
MethodNode method, final GenericsType[] explicitTypeHints, final 
Map<GenericsTypeName, GenericsType> resolvedPlaceholders) {
         if (explicitTypeHints != null) {
             GenericsType[] methodGenericTypes = method.getGenericsTypes();
             if (methodGenericTypes != null && methodGenericTypes.length == 
explicitTypeHints.length) {
                 for (int i = 0; i < explicitTypeHints.length; i++) {
                     GenericsType methodGenericType = methodGenericTypes[i];
                     GenericsType explicitTypeHint = explicitTypeHints[i];
-                    resolvedPlaceholders.put(methodGenericType.getName(), 
explicitTypeHint);
+                    resolvedPlaceholders.put(new 
GenericsTypeName(methodGenericType.getName()), explicitTypeHint);
                 }
             }
         }
     }
 
-    private static void 
extractGenericsConnectionsForSuperClassAndInterfaces(final Map<String, 
GenericsType> resolvedPlaceholders, final Map<String, GenericsType> 
connections) {
+    private static void 
extractGenericsConnectionsForSuperClassAndInterfaces(final 
Map<GenericsTypeName, GenericsType> resolvedPlaceholders, final 
Map<GenericsTypeName, GenericsType> connections) {
         for (GenericsType value : new 
HashSet<GenericsType>(connections.values())) {
             if (!value.isPlaceholder() && !value.isWildcard()) {
                 ClassNode valueType = value.getType();
@@ -4988,7 +4989,7 @@ public class StaticTypeCheckingVisitor extends 
ClassCodeVisitorSupport {
      * @param samType     the type into which the closure is coerced into
      * @return same SAM type, but completed with information from the closure 
node
      */
-    private static ClassNode convertClosureTypeToSAMType(final Expression 
expression, final ClassNode closureType, final ClassNode samType, final 
Map<String, GenericsType> placeholders) {
+    private static ClassNode convertClosureTypeToSAMType(final Expression 
expression, final ClassNode closureType, final ClassNode samType, final 
Map<GenericsTypeName, GenericsType> placeholders) {
         if (!samType.isUsingGenerics()) return samType;
 
         // use the generics information from the Closure to further specify 
the type
@@ -5004,7 +5005,7 @@ public class StaticTypeCheckingVisitor extends 
ClassCodeVisitorSupport {
                 ClassNode unwrapped = 
closureReturnType.getGenericsTypes()[0].getType();
                 extractGenericsConnections(placeholders, unwrapped, 
samReturnType);
             } else if (samReturnType.isGenericsPlaceHolder()) {
-                
placeholders.put(samReturnType.getGenericsTypes()[0].getName(), 
closureType.getGenericsTypes()[0]);
+                placeholders.put(new 
GenericsTypeName(samReturnType.getGenericsTypes()[0].getName()), 
closureType.getGenericsTypes()[0]);
             }
 
             // now repeat the same for each parameter given in the 
ClosureExpression
@@ -5035,7 +5036,7 @@ public class StaticTypeCheckingVisitor extends 
ClassCodeVisitorSupport {
                         generifiedType = generifiedType.getComponentType();
                     }
                     if (expected.isGenericsPlaceHolder()) {
-                        
placeholders.put(expected.getGenericsTypes()[0].getName(), new 
GenericsType(generifiedType));
+                        placeholders.put(new 
GenericsTypeName(expected.getGenericsTypes()[0].getName()), new 
GenericsType(generifiedType));
                     } else {
                         GenericsType[] expectedGenericsTypes = 
expected.getGenericsTypes();
                         GenericsType[] foundGenericsTypes = 
generifiedType.getGenericsTypes();
@@ -5044,7 +5045,7 @@ public class StaticTypeCheckingVisitor extends 
ClassCodeVisitorSupport {
                             final GenericsType type = expectedGenericsTypes[i];
                             if (type.isPlaceholder()) {
                                 String name = type.getName();
-                                placeholders.put(name, foundGenericsTypes[i]);
+                                placeholders.put(new GenericsTypeName(name), 
foundGenericsTypes[i]);
                             }
                         }
                     }
@@ -5055,8 +5056,8 @@ public class StaticTypeCheckingVisitor extends 
ClassCodeVisitorSupport {
         return result;
     }
 
-    private ClassNode resolveGenericsWithContext(Map<String, GenericsType> 
resolvedPlaceholders, ClassNode currentType) {
-        Map<String, GenericsType> placeholdersFromContext = 
extractGenericsParameterMapOfThis(typeCheckingContext.getEnclosingMethod());
+    private ClassNode resolveGenericsWithContext(Map<GenericsTypeName, 
GenericsType> resolvedPlaceholders, ClassNode currentType) {
+        Map<GenericsTypeName, GenericsType> placeholdersFromContext = 
extractGenericsParameterMapOfThis(typeCheckingContext.getEnclosingMethod());
         return resolveClassNodeGenerics(resolvedPlaceholders, 
placeholdersFromContext, currentType);
     }
 
@@ -5075,8 +5076,8 @@ public class StaticTypeCheckingVisitor extends 
ClassCodeVisitorSupport {
         return declaringClass;
     }
 
-    private Map<String, GenericsType> 
resolvePlaceHoldersFromDeclaration(ClassNode receiver, ClassNode declaration, 
MethodNode method, boolean isStaticTarget) {
-        Map<String, GenericsType> resolvedPlaceholders;
+    private Map<GenericsTypeName, GenericsType> 
resolvePlaceHoldersFromDeclaration(ClassNode receiver, ClassNode declaration, 
MethodNode method, boolean isStaticTarget) {
+        Map<GenericsTypeName, GenericsType> resolvedPlaceholders;
         if (isStaticTarget && CLASS_Type.equals(receiver) &&
                 receiver.isUsingGenerics() &&
                 receiver.getGenericsTypes().length > 0 &&
@@ -5094,14 +5095,14 @@ public class StaticTypeCheckingVisitor extends 
ClassCodeVisitorSupport {
     }
 
 
-    private static Map<String, GenericsType> extractPlaceHolders(MethodNode 
method, ClassNode receiver, ClassNode declaringClass) {
+    private static Map<GenericsTypeName, GenericsType> 
extractPlaceHolders(MethodNode method, ClassNode receiver, ClassNode 
declaringClass) {
         if (declaringClass.equals(OBJECT_TYPE)) {
-            Map<String, GenericsType> resolvedPlaceholders = new 
HashMap<String, GenericsType>();
+            Map<GenericsTypeName, GenericsType> resolvedPlaceholders = new 
HashMap<GenericsTypeName, GenericsType>();
             if (method != null) addMethodLevelDeclaredGenerics(method, 
resolvedPlaceholders);
             return resolvedPlaceholders;
         }
 
-        Map<String, GenericsType> resolvedPlaceholders = null;
+        Map<GenericsTypeName, GenericsType> resolvedPlaceholders = null;
         if (isPrimitiveType(receiver) && !isPrimitiveType(declaringClass)) {
             receiver = getWrapper(receiver);
         }
@@ -5116,7 +5117,7 @@ public class StaticTypeCheckingVisitor extends 
ClassCodeVisitorSupport {
             while (current != null) {
                 boolean continueLoop = true;
                 //extract the place holders
-                Map<String, GenericsType> currentPlaceHolders = new 
HashMap<String, GenericsType>();
+                Map<GenericsTypeName, GenericsType> currentPlaceHolders = new 
HashMap<GenericsTypeName, GenericsType>();
                 if (isGenericsPlaceHolderOrArrayOf(declaringClass) || 
declaringClass.equals(current)) {
                     extractGenericsConnections(currentPlaceHolders, current, 
declaringClass);
                     if (method != null) addMethodLevelDeclaredGenerics(method, 
currentPlaceHolders);
@@ -5127,11 +5128,11 @@ public class StaticTypeCheckingVisitor extends 
ClassCodeVisitorSupport {
 
                 if (resolvedPlaceholders != null) {
                     // merge maps
-                    Set<Map.Entry<String, GenericsType>> entries = 
currentPlaceHolders.entrySet();
-                    for (Map.Entry<String, GenericsType> entry : entries) {
+                    Set<Map.Entry<GenericsTypeName, GenericsType>> entries = 
currentPlaceHolders.entrySet();
+                    for (Map.Entry<GenericsTypeName, GenericsType> entry : 
entries) {
                         GenericsType gt = entry.getValue();
                         if (!gt.isPlaceholder()) continue;
-                        GenericsType referenced = 
resolvedPlaceholders.get(gt.getName());
+                        GenericsType referenced = resolvedPlaceholders.get(new 
GenericsTypeName(gt.getName()));
                         if (referenced == null) continue;
                         entry.setValue(referenced);
                     }
@@ -5163,7 +5164,7 @@ public class StaticTypeCheckingVisitor extends 
ClassCodeVisitorSupport {
 
     protected boolean typeCheckMethodsWithGenericsOrFail(ClassNode receiver, 
ClassNode[] arguments, MethodNode candidateMethod, Expression location) {
         if (!typeCheckMethodsWithGenerics(receiver, arguments, 
candidateMethod)) {
-            Map<String, GenericsType> classGTs = 
GenericsUtils.extractPlaceholders(receiver);
+            Map<GenericsTypeName, GenericsType> classGTs = 
GenericsUtils.extractPlaceholders(receiver);
             ClassNode[] ptypes = new 
ClassNode[candidateMethod.getParameters().length];
             final Parameter[] parameters = candidateMethod.getParameters();
             for (int i = 0; i < parameters.length; i++) {

http://git-wip-us.apache.org/repos/asf/groovy/blob/dbb665df/src/test/org/codehaus/groovy/ast/GenericsTypeTest.groovy
----------------------------------------------------------------------
diff --git a/src/test/org/codehaus/groovy/ast/GenericsTypeTest.groovy 
b/src/test/org/codehaus/groovy/ast/GenericsTypeTest.groovy
index 7a72d66..858cdff 100644
--- a/src/test/org/codehaus/groovy/ast/GenericsTypeTest.groovy
+++ b/src/test/org/codehaus/groovy/ast/GenericsTypeTest.groovy
@@ -20,6 +20,8 @@ package org.codehaus.groovy.ast
 
 import org.codehaus.groovy.ast.tools.GenericsUtils
 
+import static org.codehaus.groovy.ast.GenericsType.GenericsTypeName
+
 /**
  * Various tests aimed at testing the {@link GenericsType} class.
  */
@@ -135,23 +137,23 @@ public class GenericsTypeTest extends GenericsTestCase {
     void testPlaceholderExtract() {
         def type = extractTypesFromCode("List<String> type").type
         def placeholders = GenericsUtils.extractPlaceholders(type)
-        assert placeholders.E?.type == ClassHelper.STRING_TYPE
+        assert placeholders[new GenericsTypeName('E')]?.type == 
ClassHelper.STRING_TYPE
     }
 
     void testPlaceholderExtract2() {
         def type = extractTypesFromCode("Map<String,Integer> type").type
         def placeholders = GenericsUtils.extractPlaceholders(type)
-        assert placeholders.K?.type == ClassHelper.STRING_TYPE
-        assert placeholders.V?.type == ClassHelper.Integer_TYPE
+        assert placeholders[new GenericsTypeName('K')]?.type == 
ClassHelper.STRING_TYPE
+        assert placeholders[new GenericsTypeName('V')]?.type == 
ClassHelper.Integer_TYPE
     }
 
     void testPlaceholderExtract3() {
         def type = extractTypesFromCode("List<Map<String,Integer>> type").type
         def placeholders = GenericsUtils.extractPlaceholders(type)
-        assert placeholders.E?.type == ClassHelper.MAP_TYPE
-        placeholders = GenericsUtils.extractPlaceholders(placeholders.E.type)
-        assert placeholders.K?.type == ClassHelper.STRING_TYPE
-        assert placeholders.V?.type == ClassHelper.Integer_TYPE
+        assert placeholders[new GenericsTypeName('E')]?.type == 
ClassHelper.MAP_TYPE
+        placeholders = GenericsUtils.extractPlaceholders(placeholders[new 
GenericsTypeName('E')].type)
+        assert placeholders[new GenericsTypeName('K')]?.type == 
ClassHelper.STRING_TYPE
+        assert placeholders[new GenericsTypeName('V')]?.type == 
ClassHelper.Integer_TYPE
     }
 
     // ------------------ Support methods -------------------------

Reply via email to