Browse Source

Remove Painless Type from e-nodes in favor of Java Class (#28364)

Jack Conradson 7 years ago
parent
commit
f13da9f534
58 changed files with 592 additions and 676 deletions
  1. 63 62
      modules/lang-painless/src/main/java/org/elasticsearch/painless/Definition.java
  2. 3 5
      modules/lang-painless/src/main/java/org/elasticsearch/painless/node/AExpression.java
  3. 1 2
      modules/lang-painless/src/main/java/org/elasticsearch/painless/node/AStoreable.java
  4. 45 56
      modules/lang-painless/src/main/java/org/elasticsearch/painless/node/EAssignment.java
  5. 92 123
      modules/lang-painless/src/main/java/org/elasticsearch/painless/node/EBinary.java
  6. 6 8
      modules/lang-painless/src/main/java/org/elasticsearch/painless/node/EBool.java
  7. 2 3
      modules/lang-painless/src/main/java/org/elasticsearch/painless/node/EBoolean.java
  8. 3 2
      modules/lang-painless/src/main/java/org/elasticsearch/painless/node/ECallLocal.java
  9. 5 4
      modules/lang-painless/src/main/java/org/elasticsearch/painless/node/ECapturingFunctionRef.java
  10. 4 5
      modules/lang-painless/src/main/java/org/elasticsearch/painless/node/ECast.java
  11. 93 117
      modules/lang-painless/src/main/java/org/elasticsearch/painless/node/EComp.java
  12. 6 10
      modules/lang-painless/src/main/java/org/elasticsearch/painless/node/EConditional.java
  13. 21 23
      modules/lang-painless/src/main/java/org/elasticsearch/painless/node/EConstant.java
  14. 3 4
      modules/lang-painless/src/main/java/org/elasticsearch/painless/node/EDecimal.java
  15. 3 6
      modules/lang-painless/src/main/java/org/elasticsearch/painless/node/EElvis.java
  16. 3 2
      modules/lang-painless/src/main/java/org/elasticsearch/painless/node/EExplicit.java
  17. 6 6
      modules/lang-painless/src/main/java/org/elasticsearch/painless/node/EFunctionRef.java
  18. 8 8
      modules/lang-painless/src/main/java/org/elasticsearch/painless/node/EInstanceof.java
  19. 5 5
      modules/lang-painless/src/main/java/org/elasticsearch/painless/node/ELambda.java
  20. 7 6
      modules/lang-painless/src/main/java/org/elasticsearch/painless/node/EListInit.java
  21. 8 7
      modules/lang-painless/src/main/java/org/elasticsearch/painless/node/EMapInit.java
  22. 12 9
      modules/lang-painless/src/main/java/org/elasticsearch/painless/node/ENewArray.java
  23. 4 7
      modules/lang-painless/src/main/java/org/elasticsearch/painless/node/ENewObj.java
  24. 6 6
      modules/lang-painless/src/main/java/org/elasticsearch/painless/node/ENull.java
  25. 10 12
      modules/lang-painless/src/main/java/org/elasticsearch/painless/node/ENumeric.java
  26. 4 6
      modules/lang-painless/src/main/java/org/elasticsearch/painless/node/ERegex.java
  27. 2 1
      modules/lang-painless/src/main/java/org/elasticsearch/painless/node/EStatic.java
  28. 2 3
      modules/lang-painless/src/main/java/org/elasticsearch/painless/node/EString.java
  29. 42 46
      modules/lang-painless/src/main/java/org/elasticsearch/painless/node/EUnary.java
  30. 6 6
      modules/lang-painless/src/main/java/org/elasticsearch/painless/node/EVariable.java
  31. 11 9
      modules/lang-painless/src/main/java/org/elasticsearch/painless/node/PBrace.java
  32. 6 5
      modules/lang-painless/src/main/java/org/elasticsearch/painless/node/PCallInvoke.java
  33. 11 10
      modules/lang-painless/src/main/java/org/elasticsearch/painless/node/PField.java
  34. 2 4
      modules/lang-painless/src/main/java/org/elasticsearch/painless/node/PSubArrayLength.java
  35. 8 10
      modules/lang-painless/src/main/java/org/elasticsearch/painless/node/PSubBrace.java
  36. 7 7
      modules/lang-painless/src/main/java/org/elasticsearch/painless/node/PSubCallInvoke.java
  37. 11 11
      modules/lang-painless/src/main/java/org/elasticsearch/painless/node/PSubDefArray.java
  38. 6 4
      modules/lang-painless/src/main/java/org/elasticsearch/painless/node/PSubDefCall.java
  39. 6 6
      modules/lang-painless/src/main/java/org/elasticsearch/painless/node/PSubDefField.java
  40. 3 3
      modules/lang-painless/src/main/java/org/elasticsearch/painless/node/PSubField.java
  41. 3 4
      modules/lang-painless/src/main/java/org/elasticsearch/painless/node/PSubListShortcut.java
  42. 7 8
      modules/lang-painless/src/main/java/org/elasticsearch/painless/node/PSubMapShortcut.java
  43. 1 1
      modules/lang-painless/src/main/java/org/elasticsearch/painless/node/PSubNullSafeCallInvoke.java
  44. 2 3
      modules/lang-painless/src/main/java/org/elasticsearch/painless/node/PSubNullSafeField.java
  45. 3 3
      modules/lang-painless/src/main/java/org/elasticsearch/painless/node/PSubShortcut.java
  46. 2 1
      modules/lang-painless/src/main/java/org/elasticsearch/painless/node/SDeclaration.java
  47. 1 2
      modules/lang-painless/src/main/java/org/elasticsearch/painless/node/SDo.java
  48. 5 3
      modules/lang-painless/src/main/java/org/elasticsearch/painless/node/SEach.java
  49. 4 3
      modules/lang-painless/src/main/java/org/elasticsearch/painless/node/SExpression.java
  50. 2 3
      modules/lang-painless/src/main/java/org/elasticsearch/painless/node/SFor.java
  51. 1 2
      modules/lang-painless/src/main/java/org/elasticsearch/painless/node/SIf.java
  52. 1 2
      modules/lang-painless/src/main/java/org/elasticsearch/painless/node/SIfElse.java
  53. 3 2
      modules/lang-painless/src/main/java/org/elasticsearch/painless/node/SReturn.java
  54. 3 2
      modules/lang-painless/src/main/java/org/elasticsearch/painless/node/SSubEachArray.java
  55. 5 3
      modules/lang-painless/src/main/java/org/elasticsearch/painless/node/SSubEachIterable.java
  56. 1 2
      modules/lang-painless/src/main/java/org/elasticsearch/painless/node/SThrow.java
  57. 1 2
      modules/lang-painless/src/main/java/org/elasticsearch/painless/node/SWhile.java
  58. 1 1
      modules/lang-painless/src/test/java/org/elasticsearch/painless/node/NodeToStringTests.java

+ 63 - 62
modules/lang-painless/src/main/java/org/elasticsearch/painless/Definition.java

@@ -452,60 +452,60 @@ public final class Definition {
         return getTypeInternal(struct, dimensions);
     }
 
-    public Type getBoxedType(Type unboxed) {
-        if (unboxed.clazz == boolean.class) {
-            return BooleanType;
-        } else if (unboxed.clazz == byte.class) {
-            return ByteType;
-        } else if (unboxed.clazz == short.class) {
-            return ShortType;
-        } else if (unboxed.clazz == char.class) {
-            return CharacterType;
-        } else if (unboxed.clazz == int.class) {
-            return IntegerType;
-        } else if (unboxed.clazz == long.class) {
-            return LongType;
-        } else if (unboxed.clazz == float.class) {
-            return FloatType;
-        } else if (unboxed.clazz == double.class) {
-            return DoubleType;
-        }
-
-        return unboxed;
+    public static Class<?> getBoxedType(Class<?> clazz) {
+        if (clazz == boolean.class) {
+            return Boolean.class;
+        } else if (clazz == byte.class) {
+            return Byte.class;
+        } else if (clazz == short.class) {
+            return Short.class;
+        } else if (clazz == char.class) {
+            return Character.class;
+        } else if (clazz == int.class) {
+            return Integer.class;
+        } else if (clazz == long.class) {
+            return Long.class;
+        } else if (clazz == float.class) {
+            return Float.class;
+        } else if (clazz == double.class) {
+            return Double.class;
+        }
+
+        return clazz;
     }
 
-    public Type getUnboxedType(Type boxed) {
-        if (boxed.clazz == Boolean.class) {
-            return booleanType;
-        } else if (boxed.clazz == Byte.class) {
-            return byteType;
-        } else if (boxed.clazz == Short.class) {
-            return shortType;
-        } else if (boxed.clazz == Character.class) {
-            return charType;
-        } else if (boxed.clazz == Integer.class) {
-            return intType;
-        } else if (boxed.clazz == Long.class) {
-            return longType;
-        } else if (boxed.clazz == Float.class) {
-            return floatType;
-        } else if (boxed.clazz == Double.class) {
-            return doubleType;
-        }
-
-        return boxed;
+    public static Class<?> getUnboxedype(Class<?> clazz) {
+        if (clazz == Boolean.class) {
+            return boolean.class;
+        } else if (clazz == Byte.class) {
+            return byte.class;
+        } else if (clazz == Short.class) {
+            return short.class;
+        } else if (clazz == Character.class) {
+            return char.class;
+        } else if (clazz == Integer.class) {
+            return int.class;
+        } else if (clazz == Long.class) {
+            return long.class;
+        } else if (clazz == Float.class) {
+            return float.class;
+        } else if (clazz == Double.class) {
+            return double.class;
+        }
+
+        return clazz;
     }
 
-    public static boolean isConstantType(Type constant) {
-        return constant.clazz == boolean.class ||
-               constant.clazz == byte.class    ||
-               constant.clazz == short.class   ||
-               constant.clazz == char.class    ||
-               constant.clazz == int.class     ||
-               constant.clazz == long.class    ||
-               constant.clazz == float.class   ||
-               constant.clazz == double.class  ||
-               constant.clazz == String.class;
+    public static boolean isConstantType(Class<?> clazz) {
+        return clazz == boolean.class ||
+               clazz == byte.class    ||
+               clazz == short.class   ||
+               clazz == char.class    ||
+               clazz == int.class     ||
+               clazz == long.class    ||
+               clazz == float.class   ||
+               clazz == double.class  ||
+               clazz == String.class;
     }
 
     public static Class<?> ObjectClassTodefClass(Class<?> clazz) {
@@ -579,7 +579,7 @@ public final class Definition {
             }
 
             if (component == def.class) {
-                StringBuilder builder = new StringBuilder("def");
+                StringBuilder builder = new StringBuilder(def.class.getSimpleName());
 
                 for (int dimension = 0; dimension < dimensions; dimensions++) {
                     builder.append("[]");
@@ -588,7 +588,7 @@ public final class Definition {
                 return builder.toString();
             }
         } else if (clazz == def.class) {
-            return "def";
+            return def.class.getSimpleName();
         }
 
         return clazz.getCanonicalName().replace('$', '.');
@@ -606,20 +606,20 @@ public final class Definition {
                 ++dimensions;
             }
 
-            if (clazz == def.class) {
-                return getType(structsMap.get("def"), dimensions);
+            if (component == def.class) {
+                return getType(structsMap.get(def.class.getSimpleName()), dimensions);
             } else {
-                return getType(runtimeMap.get(clazz).struct, dimensions);
+                return getType(runtimeMap.get(component).struct, dimensions);
             }
         } else if (clazz == def.class) {
-            return getType(structsMap.get("def"), 0);
+            return getType(structsMap.get(def.class.getSimpleName()), 0);
         }
 
         return getType(structsMap.get(ClassToName(clazz)), 0);
     }
 
-    public static Class<?> TypeToClass (Type type) {
-        if (type.dynamic) {
+    public static Class<?> TypeToClass(Type type) {
+        if (def.class.getSimpleName().equals(type.struct.name)) {
             return ObjectClassTodefClass(type.clazz);
         }
 
@@ -672,7 +672,8 @@ public final class Definition {
         String origin = null;
 
         // add the universal def type
-        structsMap.put("def", new Struct("def", Object.class, org.objectweb.asm.Type.getType(Object.class)));
+        structsMap.put(def.class.getSimpleName(),
+                new Struct(def.class.getSimpleName(), Object.class, org.objectweb.asm.Type.getType(Object.class)));
 
         try {
             // first iteration collects all the Painless type names that
@@ -777,7 +778,7 @@ public final class Definition {
             copyStruct(painlessStruct.name, painlessSuperStructs);
 
             // copies methods and fields from Object into interface types
-            if (painlessStruct.clazz.isInterface() || ("def").equals(painlessStruct.name)) {
+            if (painlessStruct.clazz.isInterface() || (def.class.getSimpleName()).equals(painlessStruct.name)) {
                 Struct painlessObjectStruct = javaClassesToPainlessStructs.get(Object.class);
 
                 if (painlessObjectStruct != null) {
@@ -835,7 +836,7 @@ public final class Definition {
         charType = getType("char");
         CharacterType = getType("Character");
         ObjectType = getType("Object");
-        DefType = getType("def");
+        DefType = getType(def.class.getSimpleName());
         NumberType = getType("Number");
         StringType = getType("String");
         ExceptionType = getType("Exception");
@@ -1409,7 +1410,7 @@ public final class Definition {
             }
         }
 
-        return new Type(name, dimensions, "def".equals(name), struct, clazz, type);
+        return new Type(name, dimensions, def.class.getSimpleName().equals(name), struct, clazz, type);
     }
 
     private int getDimensions(String name) {

+ 3 - 5
modules/lang-painless/src/main/java/org/elasticsearch/painless/node/AExpression.java

@@ -22,7 +22,6 @@ package org.elasticsearch.painless.node;
 import org.elasticsearch.painless.AnalyzerCaster;
 import org.elasticsearch.painless.Definition;
 import org.elasticsearch.painless.Definition.Cast;
-import org.elasticsearch.painless.Definition.Type;
 import org.elasticsearch.painless.Locals;
 import org.elasticsearch.painless.Location;
 
@@ -60,7 +59,7 @@ public abstract class AExpression extends ANode {
      * Set to the expected type this node needs to be.  Note this variable
      * is always set by the parent as input and should never be read from.
      */
-    Type expected = null;
+    Class<?> expected = null;
 
     /**
      * Set to the actual type this node is.  Note this variable is always
@@ -68,7 +67,7 @@ public abstract class AExpression extends ANode {
      * node itself.  <b>Also, actual can always be read after a cast is
      * called on this node to get the type of the node after the cast.</b>
      */
-    Type actual = null;
+    Class<?> actual = null;
 
     /**
      * Set by {@link EExplicit} if a cast made on an expression node should be
@@ -119,8 +118,7 @@ public abstract class AExpression extends ANode {
      * @return The new child node for the parent node calling this method.
      */
     AExpression cast(Locals locals) {
-        Cast cast =
-            AnalyzerCaster.getLegalCast(location, Definition.TypeToClass(actual), Definition.TypeToClass(expected), explicit, internal);
+        Cast cast = AnalyzerCaster.getLegalCast(location, actual, expected, explicit, internal);
 
         if (cast == null) {
             if (constant == null || this instanceof EConstant) {

+ 1 - 2
modules/lang-painless/src/main/java/org/elasticsearch/painless/node/AStoreable.java

@@ -19,7 +19,6 @@
 
 package org.elasticsearch.painless.node;
 
-import org.elasticsearch.painless.Definition.Type;
 import org.elasticsearch.painless.Globals;
 import org.elasticsearch.painless.Location;
 import org.elasticsearch.painless.MethodWriter;
@@ -86,7 +85,7 @@ abstract class AStoreable extends AExpression {
      * actual will be set to this value. This is used for an optimization
      * during assignment to def type targets.
      */
-    abstract void updateActual(Type actual);
+    abstract void updateActual(Class<?> actual);
 
     /**
      * Called before a storeable node is loaded or stored.  Used to load prefixes and

+ 45 - 56
modules/lang-painless/src/main/java/org/elasticsearch/painless/node/EAssignment.java

@@ -22,9 +22,7 @@ package org.elasticsearch.painless.node;
 
 import org.elasticsearch.painless.AnalyzerCaster;
 import org.elasticsearch.painless.DefBootstrap;
-import org.elasticsearch.painless.Definition;
 import org.elasticsearch.painless.Definition.Cast;
-import org.elasticsearch.painless.Definition.Type;
 import org.elasticsearch.painless.Definition.def;
 import org.elasticsearch.painless.Globals;
 import org.elasticsearch.painless.Locals;
@@ -49,11 +47,10 @@ public final class EAssignment extends AExpression {
     private Operation operation;
 
     private boolean cat = false;
-    private Type promote = null;
-    private Type shiftDistance; // for shifts, the RHS is promoted independently
+    private Class<?> promote = null;
+    private Class<?> shiftDistance; // for shifts, the RHS is promoted independently
     private Cast there = null;
     private Cast back = null;
-    private Type DefType = null;
 
     public EAssignment(Location location, AExpression lhs, AExpression rhs, boolean pre, boolean post, Operation operation) {
         super(location);
@@ -83,8 +80,6 @@ public final class EAssignment extends AExpression {
         } else {
             throw new IllegalStateException("Illegal tree structure.");
         }
-
-        DefType = locals.getDefinition().DefType;
     }
 
     private void analyzeLHS(Locals locals) {
@@ -108,11 +103,11 @@ public final class EAssignment extends AExpression {
             }
 
             if (operation == Operation.INCR) {
-                if (lhs.actual.clazz == double.class) {
+                if (lhs.actual == double.class) {
                     rhs = new EConstant(location, 1D);
-                } else if (lhs.actual.clazz == float.class) {
+                } else if (lhs.actual == float.class) {
                     rhs = new EConstant(location, 1F);
-                } else if (lhs.actual.clazz == long.class) {
+                } else if (lhs.actual == long.class) {
                     rhs = new EConstant(location, 1L);
                 } else {
                     rhs = new EConstant(location, 1);
@@ -120,11 +115,11 @@ public final class EAssignment extends AExpression {
 
                 operation = Operation.ADD;
             } else if (operation == Operation.DECR) {
-                if (lhs.actual.clazz == double.class) {
+                if (lhs.actual == double.class) {
                     rhs = new EConstant(location, 1D);
-                } else if (lhs.actual.clazz == float.class) {
+                } else if (lhs.actual == float.class) {
                     rhs = new EConstant(location, 1F);
-                } else if (lhs.actual.clazz == long.class) {
+                } else if (lhs.actual == long.class) {
                     rhs = new EConstant(location, 1L);
                 } else {
                     rhs = new EConstant(location, 1);
@@ -143,41 +138,33 @@ public final class EAssignment extends AExpression {
         boolean shift = false;
 
         if (operation == Operation.MUL) {
-            promote = locals.getDefinition().ClassToType(
-                AnalyzerCaster.promoteNumeric(Definition.TypeToClass(lhs.actual), Definition.TypeToClass(rhs.actual), true));
+            promote = AnalyzerCaster.promoteNumeric(lhs.actual, rhs.actual, true);
         } else if (operation == Operation.DIV) {
-            promote = locals.getDefinition().ClassToType(
-                AnalyzerCaster.promoteNumeric(Definition.TypeToClass(lhs.actual), Definition.TypeToClass(rhs.actual), true));
+            promote = AnalyzerCaster.promoteNumeric(lhs.actual, rhs.actual, true);
         } else if (operation == Operation.REM) {
-            promote = locals.getDefinition().ClassToType(
-                AnalyzerCaster.promoteNumeric(Definition.TypeToClass(lhs.actual), Definition.TypeToClass(rhs.actual), true));
+            promote = AnalyzerCaster.promoteNumeric(lhs.actual, rhs.actual, true);
         } else if (operation == Operation.ADD) {
-            promote = locals.getDefinition().ClassToType(
-                AnalyzerCaster.promoteAdd(Definition.TypeToClass(lhs.actual), Definition.TypeToClass(rhs.actual)));
+            promote = AnalyzerCaster.promoteAdd(lhs.actual, rhs.actual);
         } else if (operation == Operation.SUB) {
-            promote = locals.getDefinition().ClassToType(
-                AnalyzerCaster.promoteNumeric(Definition.TypeToClass(lhs.actual), Definition.TypeToClass(rhs.actual), true));
+            promote = AnalyzerCaster.promoteNumeric(lhs.actual, rhs.actual, true);
         } else if (operation == Operation.LSH) {
-            promote = locals.getDefinition().ClassToType(AnalyzerCaster.promoteNumeric(Definition.TypeToClass(lhs.actual), false));
-            shiftDistance = locals.getDefinition().ClassToType(AnalyzerCaster.promoteNumeric(Definition.TypeToClass(rhs.actual), false));
+            promote = AnalyzerCaster.promoteNumeric(lhs.actual, false);
+            shiftDistance = AnalyzerCaster.promoteNumeric(rhs.actual, false);
             shift = true;
         } else if (operation == Operation.RSH) {
-            promote = locals.getDefinition().ClassToType(AnalyzerCaster.promoteNumeric(Definition.TypeToClass(lhs.actual), false));
-            shiftDistance = locals.getDefinition().ClassToType(AnalyzerCaster.promoteNumeric(Definition.TypeToClass(rhs.actual), false));
+            promote = AnalyzerCaster.promoteNumeric(lhs.actual, false);
+            shiftDistance = AnalyzerCaster.promoteNumeric(rhs.actual, false);
             shift = true;
         } else if (operation == Operation.USH) {
-            promote = locals.getDefinition().ClassToType(AnalyzerCaster.promoteNumeric(Definition.TypeToClass(lhs.actual), false));
-            shiftDistance = locals.getDefinition().ClassToType(AnalyzerCaster.promoteNumeric(Definition.TypeToClass(rhs.actual), false));
+            promote = AnalyzerCaster.promoteNumeric(lhs.actual, false);
+            shiftDistance = AnalyzerCaster.promoteNumeric(rhs.actual, false);
             shift = true;
         } else if (operation == Operation.BWAND) {
-            promote = locals.getDefinition().ClassToType(
-                AnalyzerCaster.promoteXor(Definition.TypeToClass(lhs.actual), Definition.TypeToClass(rhs.actual)));
+            promote = AnalyzerCaster.promoteXor(lhs.actual, rhs.actual);
         } else if (operation == Operation.XOR) {
-            promote = locals.getDefinition().ClassToType(
-                AnalyzerCaster.promoteXor(Definition.TypeToClass(lhs.actual), Definition.TypeToClass(rhs.actual)));
+            promote = AnalyzerCaster.promoteXor(lhs.actual, rhs.actual);
         } else if (operation == Operation.BWOR) {
-            promote = locals.getDefinition().ClassToType(
-                AnalyzerCaster.promoteXor(Definition.TypeToClass(lhs.actual), Definition.TypeToClass(rhs.actual)));
+            promote = AnalyzerCaster.promoteXor(lhs.actual, rhs.actual);
         } else {
             throw createError(new IllegalStateException("Illegal tree structure."));
         }
@@ -187,20 +174,20 @@ public final class EAssignment extends AExpression {
                 "[" + operation.symbol + "=] to types [" + lhs.actual + "] and [" + rhs.actual + "]."));
         }
 
-        cat = operation == Operation.ADD && promote.clazz == String.class;
+        cat = operation == Operation.ADD && promote == String.class;
 
         if (cat) {
-            if (rhs instanceof EBinary && ((EBinary)rhs).operation == Operation.ADD && rhs.actual.clazz == String.class) {
+            if (rhs instanceof EBinary && ((EBinary)rhs).operation == Operation.ADD && rhs.actual == String.class) {
                 ((EBinary)rhs).cat = true;
             }
 
             rhs.expected = rhs.actual;
         } else if (shift) {
-            if (promote.dynamic) {
+            if (promote == def.class) {
                 // shifts are promoted independently, but for the def type, we need object.
                 rhs.expected = promote;
-            } else if (shiftDistance.clazz == long.class) {
-                rhs.expected = locals.getDefinition().intType;
+            } else if (shiftDistance == long.class) {
+                rhs.expected = int.class;
                 rhs.explicit = true;
             } else {
                 rhs.expected = shiftDistance;
@@ -211,11 +198,11 @@ public final class EAssignment extends AExpression {
 
         rhs = rhs.cast(locals);
 
-        there = AnalyzerCaster.getLegalCast(location, Definition.TypeToClass(lhs.actual), Definition.TypeToClass(promote), false, false);
-        back = AnalyzerCaster.getLegalCast(location, Definition.TypeToClass(promote), Definition.TypeToClass(lhs.actual), true, false);
+        there = AnalyzerCaster.getLegalCast(location, lhs.actual, promote, false, false);
+        back = AnalyzerCaster.getLegalCast(location, promote, lhs.actual, true, false);
 
         this.statement = true;
-        this.actual = read ? lhs.actual : locals.getDefinition().voidType;
+        this.actual = read ? lhs.actual : void.class;
     }
 
     private void analyzeSimple(Locals locals) {
@@ -225,7 +212,7 @@ public final class EAssignment extends AExpression {
         if (lhs.isDefOptimized()) {
             rhs.analyze(locals);
 
-            if (rhs.actual.clazz == void.class) {
+            if (rhs.actual == void.class) {
                 throw createError(new IllegalArgumentException("Right-hand side cannot be a [void] type for assignment."));
             }
 
@@ -240,7 +227,7 @@ public final class EAssignment extends AExpression {
         rhs = rhs.cast(locals);
 
         this.statement = true;
-        this.actual = read ? lhs.actual : locals.getDefinition().voidType;
+        this.actual = read ? lhs.actual : void.class;
     }
 
     /**
@@ -275,20 +262,20 @@ public final class EAssignment extends AExpression {
             writer.writeDup(lhs.accessElementCount(), catElementStackSize); // dup the top element and insert it
                                                                             // before concat helper on stack
             lhs.load(writer, globals);                                      // read the current lhs's value
-            writer.writeAppendStrings(Definition.TypeToClass(lhs.actual));  // append the lhs's value using the StringBuilder
+            writer.writeAppendStrings(lhs.actual);  // append the lhs's value using the StringBuilder
 
             rhs.write(writer, globals); // write the bytecode for the rhs
 
             if (!(rhs instanceof EBinary) || !((EBinary)rhs).cat) {            // check to see if the rhs has already done a concatenation
-                writer.writeAppendStrings(Definition.TypeToClass(rhs.actual)); // append the rhs's value since it's hasn't already
+                writer.writeAppendStrings(rhs.actual); // append the rhs's value since it's hasn't already
             }
 
             writer.writeToStrings(); // put the value for string concat onto the stack
             writer.writeCast(back);  // if necessary, cast the String to the lhs actual type
 
             if (lhs.read) {
-                writer.writeDup(lhs.actual.type.getSize(), lhs.accessElementCount()); // if this lhs is also read
-                                                                          // from dup the value onto the stack
+                writer.writeDup(MethodWriter.getType(lhs.actual).getSize(), lhs.accessElementCount()); // if this lhs is also read
+                                                                                                       // from dup the value onto the stack
             }
 
             lhs.store(writer, globals); // store the lhs's value from the stack in its respective variable/field/array
@@ -301,7 +288,7 @@ public final class EAssignment extends AExpression {
             lhs.load(writer, globals);                    // load the current lhs's value
 
             if (lhs.read && post) {
-                writer.writeDup(lhs.actual.type.getSize(), lhs.accessElementCount()); // dup the value if the lhs is also
+                writer.writeDup(MethodWriter.getType(lhs.actual).getSize(), lhs.accessElementCount()); // dup the value if the lhs is also
                                                                                  // read from and is a post increment
             }
 
@@ -312,18 +299,19 @@ public final class EAssignment extends AExpression {
         // XXX: fix these types, but first we need def compound assignment tests.
         // its tricky here as there are possibly explicit casts, too.
         // write the operation instruction for compound assignment
-            if (promote.dynamic) {
+            if (promote == def.class) {
                 writer.writeDynamicBinaryInstruction(
-                    location, Definition.TypeToClass(promote), def.class, def.class, operation, DefBootstrap.OPERATOR_COMPOUND_ASSIGNMENT);
+                    location, promote, def.class, def.class, operation, DefBootstrap.OPERATOR_COMPOUND_ASSIGNMENT);
             } else {
-                writer.writeBinaryInstruction(location, Definition.TypeToClass(promote), operation);
+                writer.writeBinaryInstruction(location, promote, operation);
             }
 
             writer.writeCast(back); // if necessary cast the promotion type value back to the lhs's type
 
             if (lhs.read && !post) {
-                writer.writeDup(lhs.actual.type.getSize(), lhs.accessElementCount()); // dup the value if the lhs is also
-                                                                                 // read from and is not a post increment
+                writer.writeDup(MethodWriter.getType(lhs.actual).getSize(), lhs.accessElementCount()); // dup the value if the lhs is also
+                                                                                                       // read from and is not a post
+                                                                                                       // increment
             }
 
             lhs.store(writer, globals); // store the lhs's value from the stack in its respective variable/field/array
@@ -333,7 +321,8 @@ public final class EAssignment extends AExpression {
             rhs.write(writer, globals); // write the bytecode for the rhs rhs
 
             if (lhs.read) {
-                writer.writeDup(lhs.actual.type.getSize(), lhs.accessElementCount()); // dup the value if the lhs is also read from
+                writer.writeDup(MethodWriter.getType(lhs.actual).getSize(), lhs.accessElementCount()); // dup the value if the lhs
+                                                                                                       // is also read from
             }
 
             lhs.store(writer, globals); // store the lhs's value from the stack in its respective variable/field/array

+ 92 - 123
modules/lang-painless/src/main/java/org/elasticsearch/painless/node/EBinary.java

@@ -22,7 +22,7 @@ package org.elasticsearch.painless.node;
 import org.elasticsearch.painless.AnalyzerCaster;
 import org.elasticsearch.painless.DefBootstrap;
 import org.elasticsearch.painless.Definition;
-import org.elasticsearch.painless.Definition.Type;
+import org.elasticsearch.painless.Definition.def;
 import org.elasticsearch.painless.Globals;
 import org.elasticsearch.painless.Locals;
 import org.elasticsearch.painless.Location;
@@ -44,8 +44,8 @@ public final class EBinary extends AExpression {
     private AExpression left;
     private AExpression right;
 
-    private Type promote = null;                // promoted type
-    private Type shiftDistance = null;          // for shifts, the rhs is promoted independently
+    private Class<?> promote = null;            // promoted type
+    private Class<?> shiftDistance = null;      // for shifts, the rhs is promoted independently
     boolean cat = false;
     private boolean originallyExplicit = false; // record whether there was originally an explicit cast
 
@@ -102,17 +102,16 @@ public final class EBinary extends AExpression {
         left.analyze(variables);
         right.analyze(variables);
 
-        promote = variables.getDefinition().ClassToType(
-            AnalyzerCaster.promoteNumeric(Definition.TypeToClass(left.actual), Definition.TypeToClass(right.actual), true));
+        promote = AnalyzerCaster.promoteNumeric(left.actual, right.actual, true);
 
         if (promote == null) {
             throw createError(new ClassCastException("Cannot apply multiply [*] to types " +
-                "[" + left.actual.name + "] and [" + right.actual.name + "]."));
+                "[" + Definition.ClassToName(left.actual) + "] and [" + Definition.ClassToName(right.actual) + "]."));
         }
 
         actual = promote;
 
-        if (promote.dynamic) {
+        if (promote == def.class) {
             left.expected = left.actual;
             right.expected = right.actual;
             if (expected != null) {
@@ -127,15 +126,13 @@ public final class EBinary extends AExpression {
         right = right.cast(variables);
 
         if (left.constant != null && right.constant != null) {
-            Class<?> sort = promote.clazz;
-
-            if (sort == int.class) {
+            if (promote == int.class) {
                 constant = (int)left.constant * (int)right.constant;
-            } else if (sort == long.class) {
+            } else if (promote == long.class) {
                 constant = (long)left.constant * (long)right.constant;
-            } else if (sort == float.class) {
+            } else if (promote == float.class) {
                 constant = (float)left.constant * (float)right.constant;
-            } else if (sort == double.class) {
+            } else if (promote == double.class) {
                 constant = (double)left.constant * (double)right.constant;
             } else {
                 throw createError(new IllegalStateException("Illegal tree structure."));
@@ -147,17 +144,16 @@ public final class EBinary extends AExpression {
         left.analyze(variables);
         right.analyze(variables);
 
-        promote = variables.getDefinition().ClassToType(
-            AnalyzerCaster.promoteNumeric(Definition.TypeToClass(left.actual), Definition.TypeToClass(right.actual), true));
+        promote = AnalyzerCaster.promoteNumeric(left.actual, right.actual, true);
 
         if (promote == null) {
             throw createError(new ClassCastException("Cannot apply divide [/] to types " +
-                "[" + left.actual.name + "] and [" + right.actual.name + "]."));
+                "[" + Definition.ClassToName(left.actual) + "] and [" + Definition.ClassToName(right.actual) + "]."));
         }
 
         actual = promote;
 
-        if (promote.dynamic) {
+        if (promote == def.class) {
             left.expected = left.actual;
             right.expected = right.actual;
 
@@ -173,16 +169,14 @@ public final class EBinary extends AExpression {
         right = right.cast(variables);
 
         if (left.constant != null && right.constant != null) {
-            Class<?> sort = promote.clazz;
-
             try {
-                if (sort == int.class) {
+                if (promote == int.class) {
                     constant = (int)left.constant / (int)right.constant;
-                } else if (sort == long.class) {
+                } else if (promote == long.class) {
                     constant = (long)left.constant / (long)right.constant;
-                } else if (sort == float.class) {
+                } else if (promote == float.class) {
                     constant = (float)left.constant / (float)right.constant;
-                } else if (sort == double.class) {
+                } else if (promote == double.class) {
                     constant = (double)left.constant / (double)right.constant;
                 } else {
                     throw createError(new IllegalStateException("Illegal tree structure."));
@@ -197,17 +191,16 @@ public final class EBinary extends AExpression {
         left.analyze(variables);
         right.analyze(variables);
 
-        promote = variables.getDefinition().ClassToType(
-            AnalyzerCaster.promoteNumeric(Definition.TypeToClass(left.actual), Definition.TypeToClass(right.actual), true));
+        promote = AnalyzerCaster.promoteNumeric(left.actual, right.actual, true);
 
         if (promote == null) {
             throw createError(new ClassCastException("Cannot apply remainder [%] to types " +
-                "[" + left.actual.name + "] and [" + right.actual.name + "]."));
+                "[" + Definition.ClassToName(left.actual) + "] and [" + Definition.ClassToName(right.actual) + "]."));
         }
 
         actual = promote;
 
-        if (promote.dynamic) {
+        if (promote == def.class) {
             left.expected = left.actual;
             right.expected = right.actual;
 
@@ -223,16 +216,14 @@ public final class EBinary extends AExpression {
         right = right.cast(variables);
 
         if (left.constant != null && right.constant != null) {
-            Class<?> sort = promote.clazz;
-
             try {
-                if (sort == int.class) {
+                if (promote == int.class) {
                     constant = (int)left.constant % (int)right.constant;
-                } else if (sort == long.class) {
+                } else if (promote == long.class) {
                     constant = (long)left.constant % (long)right.constant;
-                } else if (sort == float.class) {
+                } else if (promote == float.class) {
                     constant = (float)left.constant % (float)right.constant;
-                } else if (sort == double.class) {
+                } else if (promote == double.class) {
                     constant = (double)left.constant % (double)right.constant;
                 } else {
                     throw createError(new IllegalStateException("Illegal tree structure."));
@@ -247,31 +238,28 @@ public final class EBinary extends AExpression {
         left.analyze(variables);
         right.analyze(variables);
 
-        promote = variables.getDefinition().ClassToType(
-            AnalyzerCaster.promoteAdd(Definition.TypeToClass(left.actual), Definition.TypeToClass(right.actual)));
+        promote = AnalyzerCaster.promoteAdd(left.actual, right.actual);
 
         if (promote == null) {
             throw createError(new ClassCastException("Cannot apply add [+] to types " +
-                "[" + left.actual.name + "] and [" + right.actual.name + "]."));
+                "[" + Definition.ClassToName(left.actual) + "] and [" + Definition.ClassToName(right.actual) + "]."));
         }
 
-        Class<?> sort = promote.clazz;
-
         actual = promote;
 
-        if (sort == String.class) {
+        if (promote == String.class) {
             left.expected = left.actual;
 
-            if (left instanceof EBinary && ((EBinary)left).operation == Operation.ADD && left.actual.clazz == String.class) {
+            if (left instanceof EBinary && ((EBinary)left).operation == Operation.ADD && left.actual == String.class) {
                 ((EBinary)left).cat = true;
             }
 
             right.expected = right.actual;
 
-            if (right instanceof EBinary && ((EBinary)right).operation == Operation.ADD && right.actual.clazz == String.class) {
+            if (right instanceof EBinary && ((EBinary)right).operation == Operation.ADD && right.actual == String.class) {
                 ((EBinary)right).cat = true;
             }
-        } else if (promote.dynamic) {
+        } else if (promote == def.class) {
             left.expected = left.actual;
             right.expected = right.actual;
 
@@ -287,15 +275,15 @@ public final class EBinary extends AExpression {
         right = right.cast(variables);
 
         if (left.constant != null && right.constant != null) {
-            if (sort == int.class) {
+            if (promote == int.class) {
                 constant = (int)left.constant + (int)right.constant;
-            } else if (sort == long.class) {
+            } else if (promote == long.class) {
                 constant = (long)left.constant + (long)right.constant;
-            } else if (sort == float.class) {
+            } else if (promote == float.class) {
                 constant = (float)left.constant + (float)right.constant;
-            } else if (sort == double.class) {
+            } else if (promote == double.class) {
                 constant = (double)left.constant + (double)right.constant;
-            } else if (sort == String.class) {
+            } else if (promote == String.class) {
                 constant = left.constant.toString() + right.constant.toString();
             } else {
                 throw createError(new IllegalStateException("Illegal tree structure."));
@@ -308,17 +296,16 @@ public final class EBinary extends AExpression {
         left.analyze(variables);
         right.analyze(variables);
 
-        promote = variables.getDefinition().ClassToType(
-            AnalyzerCaster.promoteNumeric(Definition.TypeToClass(left.actual), Definition.TypeToClass(right.actual), true));
+        promote = AnalyzerCaster.promoteNumeric(left.actual, right.actual, true);
 
         if (promote == null) {
             throw createError(new ClassCastException("Cannot apply subtract [-] to types " +
-                "[" + left.actual.name + "] and [" + right.actual.name + "]."));
+                "[" + Definition.ClassToName(left.actual) + "] and [" + Definition.ClassToName(right.actual) + "]."));
         }
 
         actual = promote;
 
-        if (promote.dynamic) {
+        if (promote == def.class) {
             left.expected = left.actual;
             right.expected = right.actual;
 
@@ -334,15 +321,13 @@ public final class EBinary extends AExpression {
         right = right.cast(variables);
 
         if (left.constant != null && right.constant != null) {
-            Class<?> sort = promote.clazz;
-
-            if (sort == int.class) {
+            if (promote == int.class) {
                 constant = (int)left.constant - (int)right.constant;
-            } else if (sort == long.class) {
+            } else if (promote == long.class) {
                 constant = (long)left.constant - (long)right.constant;
-            } else if (sort == float.class) {
+            } else if (promote == float.class) {
                 constant = (float)left.constant - (float)right.constant;
-            } else if (sort == double.class) {
+            } else if (promote == double.class) {
                 constant = (double)left.constant - (double)right.constant;
             } else {
                 throw createError(new IllegalStateException("Illegal tree structure."));
@@ -354,32 +339,32 @@ public final class EBinary extends AExpression {
         left.analyze(variables);
         right.analyze(variables);
 
-        left.expected = variables.getDefinition().StringType;
-        right.expected = variables.getDefinition().PatternType;
+        left.expected = String.class;
+        right.expected = Pattern.class;
 
         left = left.cast(variables);
         right = right.cast(variables);
 
-        promote = variables.getDefinition().booleanType;
-        actual = variables.getDefinition().booleanType;
+        promote = boolean.class;
+        actual = boolean.class;
     }
 
     private void analyzeLSH(Locals variables) {
         left.analyze(variables);
         right.analyze(variables);
 
-        Type lhspromote = variables.getDefinition().ClassToType(AnalyzerCaster.promoteNumeric(Definition.TypeToClass(left.actual), false));
-        Type rhspromote = variables.getDefinition().ClassToType(AnalyzerCaster.promoteNumeric(Definition.TypeToClass(right.actual), false));
+        Class<?> lhspromote = AnalyzerCaster.promoteNumeric(left.actual, false);
+        Class<?> rhspromote = AnalyzerCaster.promoteNumeric(right.actual, false);
 
         if (lhspromote == null || rhspromote == null) {
             throw createError(new ClassCastException("Cannot apply left shift [<<] to types " +
-                "[" + left.actual.name + "] and [" + right.actual.name + "]."));
+                "[" + Definition.ClassToName(left.actual) + "] and [" + Definition.ClassToName(right.actual) + "]."));
         }
 
         actual = promote = lhspromote;
         shiftDistance = rhspromote;
 
-        if (lhspromote.dynamic || rhspromote.dynamic) {
+        if (lhspromote == def.class || rhspromote == def.class) {
             left.expected = left.actual;
             right.expected = right.actual;
 
@@ -389,8 +374,8 @@ public final class EBinary extends AExpression {
         } else {
             left.expected = lhspromote;
 
-            if (rhspromote.clazz == long.class) {
-                right.expected = variables.getDefinition().intType;
+            if (rhspromote == long.class) {
+                right.expected = int.class;
                 right.explicit = true;
             } else {
                 right.expected = rhspromote;
@@ -401,11 +386,9 @@ public final class EBinary extends AExpression {
         right = right.cast(variables);
 
         if (left.constant != null && right.constant != null) {
-            Class<?> sort = lhspromote.clazz;
-
-            if (sort == int.class) {
+            if (promote == int.class) {
                 constant = (int)left.constant << (int)right.constant;
-            } else if (sort == long.class) {
+            } else if (promote == long.class) {
                 constant = (long)left.constant << (int)right.constant;
             } else {
                 throw createError(new IllegalStateException("Illegal tree structure."));
@@ -417,18 +400,18 @@ public final class EBinary extends AExpression {
         left.analyze(variables);
         right.analyze(variables);
 
-        Type lhspromote = variables.getDefinition().ClassToType(AnalyzerCaster.promoteNumeric(Definition.TypeToClass(left.actual), false));
-        Type rhspromote = variables.getDefinition().ClassToType(AnalyzerCaster.promoteNumeric(Definition.TypeToClass(right.actual), false));
+        Class<?> lhspromote = AnalyzerCaster.promoteNumeric(left.actual, false);
+        Class<?> rhspromote = AnalyzerCaster.promoteNumeric(right.actual, false);
 
         if (lhspromote == null || rhspromote == null) {
             throw createError(new ClassCastException("Cannot apply right shift [>>] to types " +
-                "[" + left.actual.name + "] and [" + right.actual.name + "]."));
+                "[" + Definition.ClassToName(left.actual) + "] and [" + Definition.ClassToName(right.actual) + "]."));
         }
 
         actual = promote = lhspromote;
         shiftDistance = rhspromote;
 
-        if (lhspromote.dynamic || rhspromote.dynamic) {
+        if (lhspromote == def.class || rhspromote == def.class) {
             left.expected = left.actual;
             right.expected = right.actual;
 
@@ -438,8 +421,8 @@ public final class EBinary extends AExpression {
         } else {
             left.expected = lhspromote;
 
-            if (rhspromote.clazz == long.class) {
-                right.expected = variables.getDefinition().intType;
+            if (rhspromote == long.class) {
+                right.expected = int.class;
                 right.explicit = true;
             } else {
                 right.expected = rhspromote;
@@ -450,11 +433,9 @@ public final class EBinary extends AExpression {
         right = right.cast(variables);
 
         if (left.constant != null && right.constant != null) {
-            Class<?> sort = lhspromote.clazz;
-
-            if (sort == int.class) {
+            if (promote == int.class) {
                 constant = (int)left.constant >> (int)right.constant;
-            } else if (sort == long.class) {
+            } else if (promote == long.class) {
                 constant = (long)left.constant >> (int)right.constant;
             } else {
                 throw createError(new IllegalStateException("Illegal tree structure."));
@@ -466,18 +447,18 @@ public final class EBinary extends AExpression {
         left.analyze(variables);
         right.analyze(variables);
 
-        Type lhspromote = variables.getDefinition().ClassToType(AnalyzerCaster.promoteNumeric(Definition.TypeToClass(left.actual), false));
-        Type rhspromote = variables.getDefinition().ClassToType(AnalyzerCaster.promoteNumeric(Definition.TypeToClass(right.actual), false));
+        Class<?> lhspromote = AnalyzerCaster.promoteNumeric(left.actual, false);
+        Class<?> rhspromote = AnalyzerCaster.promoteNumeric(right.actual, false);
 
         actual = promote = lhspromote;
         shiftDistance = rhspromote;
 
         if (lhspromote == null || rhspromote == null) {
             throw createError(new ClassCastException("Cannot apply unsigned shift [>>>] to types " +
-                "[" + left.actual.name + "] and [" + right.actual.name + "]."));
+                "[" + Definition.ClassToName(left.actual) + "] and [" + Definition.ClassToName(right.actual) + "]."));
         }
 
-        if (lhspromote.dynamic || rhspromote.dynamic) {
+        if (lhspromote == def.class || rhspromote == def.class) {
             left.expected = left.actual;
             right.expected = right.actual;
 
@@ -487,8 +468,8 @@ public final class EBinary extends AExpression {
         } else {
             left.expected = lhspromote;
 
-            if (rhspromote.clazz == long.class) {
-                right.expected = variables.getDefinition().intType;
+            if (rhspromote == long.class) {
+                right.expected = int.class;
                 right.explicit = true;
             } else {
                 right.expected = rhspromote;
@@ -499,11 +480,9 @@ public final class EBinary extends AExpression {
         right = right.cast(variables);
 
         if (left.constant != null && right.constant != null) {
-            Class<?> sort = lhspromote.clazz;
-
-            if (sort == int.class) {
+            if (promote == int.class) {
                 constant = (int)left.constant >>> (int)right.constant;
-            } else if (sort == long.class) {
+            } else if (promote == long.class) {
                 constant = (long)left.constant >>> (int)right.constant;
             } else {
                 throw createError(new IllegalStateException("Illegal tree structure."));
@@ -515,17 +494,16 @@ public final class EBinary extends AExpression {
         left.analyze(variables);
         right.analyze(variables);
 
-        promote = variables.getDefinition().ClassToType(
-            AnalyzerCaster.promoteNumeric(Definition.TypeToClass(left.actual), Definition.TypeToClass(right.actual), false));
+        promote = AnalyzerCaster.promoteNumeric(left.actual, right.actual, false);
 
         if (promote == null) {
             throw createError(new ClassCastException("Cannot apply and [&] to types " +
-                "[" + left.actual.name + "] and [" + right.actual.name + "]."));
+                "[" + Definition.ClassToName(left.actual) + "] and [" + Definition.ClassToName(right.actual) + "]."));
         }
 
         actual = promote;
 
-        if (promote.dynamic) {
+        if (promote == def.class) {
             left.expected = left.actual;
             right.expected = right.actual;
 
@@ -541,11 +519,9 @@ public final class EBinary extends AExpression {
         right = right.cast(variables);
 
         if (left.constant != null && right.constant != null) {
-            Class<?> sort = promote.clazz;
-
-            if (sort == int.class) {
+            if (promote == int.class) {
                 constant = (int)left.constant & (int)right.constant;
-            } else if (sort == long.class) {
+            } else if (promote == long.class) {
                 constant = (long)left.constant & (long)right.constant;
             } else {
                 throw createError(new IllegalStateException("Illegal tree structure."));
@@ -557,17 +533,16 @@ public final class EBinary extends AExpression {
         left.analyze(variables);
         right.analyze(variables);
 
-        promote = variables.getDefinition().ClassToType(
-            AnalyzerCaster.promoteXor(Definition.TypeToClass(left.actual), Definition.TypeToClass(right.actual)));
+        promote = AnalyzerCaster.promoteXor(left.actual, right.actual);
 
         if (promote == null) {
             throw createError(new ClassCastException("Cannot apply xor [^] to types " +
-                "[" + left.actual.name + "] and [" + right.actual.name + "]."));
+                "[" + Definition.ClassToName(left.actual) + "] and [" + Definition.ClassToName(right.actual) + "]."));
         }
 
         actual = promote;
 
-        if (promote.dynamic) {
+        if (promote == def.class) {
             left.expected = left.actual;
             right.expected = right.actual;
             if (expected != null) {
@@ -582,13 +557,11 @@ public final class EBinary extends AExpression {
         right = right.cast(variables);
 
         if (left.constant != null && right.constant != null) {
-            Class<?> sort = promote.clazz;
-
-            if (sort == boolean.class) {
+            if (promote == boolean.class) {
                 constant = (boolean)left.constant ^ (boolean)right.constant;
-            } else if (sort == int.class) {
+            } else if (promote == int.class) {
                 constant = (int)left.constant ^ (int)right.constant;
-            } else if (sort == long.class) {
+            } else if (promote == long.class) {
                 constant = (long)left.constant ^ (long)right.constant;
             } else {
                 throw createError(new IllegalStateException("Illegal tree structure."));
@@ -600,17 +573,16 @@ public final class EBinary extends AExpression {
         left.analyze(variables);
         right.analyze(variables);
 
-        promote = variables.getDefinition().ClassToType(
-            AnalyzerCaster.promoteNumeric(Definition.TypeToClass(left.actual), Definition.TypeToClass(right.actual), false));
+        promote = AnalyzerCaster.promoteNumeric(left.actual, right.actual, false);
 
         if (promote == null) {
             throw createError(new ClassCastException("Cannot apply or [|] to types " +
-                "[" + left.actual.name + "] and [" + right.actual.name + "]."));
+                "[" + Definition.ClassToName(left.actual) + "] and [" + Definition.ClassToName(right.actual) + "]."));
         }
 
         actual = promote;
 
-        if (promote.dynamic) {
+        if (promote == def.class) {
             left.expected = left.actual;
             right.expected = right.actual;
             if (expected != null) {
@@ -625,11 +597,9 @@ public final class EBinary extends AExpression {
         right = right.cast(variables);
 
         if (left.constant != null && right.constant != null) {
-            Class<?> sort = promote.clazz;
-
-            if (sort == int.class) {
+            if (promote == int.class) {
                 constant = (int)left.constant | (int)right.constant;
-            } else if (sort == long.class) {
+            } else if (promote == long.class) {
                 constant = (long)left.constant | (long)right.constant;
             } else {
                 throw createError(new IllegalStateException("Illegal tree structure."));
@@ -641,7 +611,7 @@ public final class EBinary extends AExpression {
     void write(MethodWriter writer, Globals globals) {
         writer.writeDebugInfo(location);
 
-        if (promote.clazz == String.class && operation == Operation.ADD) {
+        if (promote == String.class && operation == Operation.ADD) {
             if (!cat) {
                 writer.writeNewStrings();
             }
@@ -649,13 +619,13 @@ public final class EBinary extends AExpression {
             left.write(writer, globals);
 
             if (!(left instanceof EBinary) || !((EBinary)left).cat) {
-                writer.writeAppendStrings(Definition.TypeToClass(left.actual));
+                writer.writeAppendStrings(left.actual);
             }
 
             right.write(writer, globals);
 
             if (!(right instanceof EBinary) || !((EBinary)right).cat) {
-                writer.writeAppendStrings(Definition.TypeToClass(right.actual));
+                writer.writeAppendStrings(right.actual);
             }
 
             if (!cat) {
@@ -677,17 +647,16 @@ public final class EBinary extends AExpression {
             left.write(writer, globals);
             right.write(writer, globals);
 
-            if (promote.dynamic || (shiftDistance != null && shiftDistance.dynamic)) {
+            if (promote == def.class || (shiftDistance != null && shiftDistance == def.class)) {
                 // def calls adopt the wanted return value. if there was a narrowing cast,
                 // we need to flag that so that its done at runtime.
                 int flags = 0;
                 if (originallyExplicit) {
                     flags |= DefBootstrap.OPERATOR_EXPLICIT_CAST;
                 }
-                writer.writeDynamicBinaryInstruction(location, Definition.TypeToClass(actual),
-                    Definition.TypeToClass(left.actual), Definition.TypeToClass(right.actual), operation, flags);
+                writer.writeDynamicBinaryInstruction(location, actual, left.actual, right.actual, operation, flags);
             } else {
-                writer.writeBinaryInstruction(location, Definition.TypeToClass(actual), operation);
+                writer.writeBinaryInstruction(location, actual, operation);
             }
         }
     }

+ 6 - 8
modules/lang-painless/src/main/java/org/elasticsearch/painless/node/EBool.java

@@ -19,19 +19,17 @@
 
 package org.elasticsearch.painless.node;
 
-import org.elasticsearch.painless.Definition;
 import org.elasticsearch.painless.Globals;
+import org.elasticsearch.painless.Locals;
 import org.elasticsearch.painless.Location;
+import org.elasticsearch.painless.MethodWriter;
 import org.elasticsearch.painless.Operation;
-import org.elasticsearch.painless.Locals;
 import org.objectweb.asm.Label;
+import org.objectweb.asm.Opcodes;
 
 import java.util.Objects;
 import java.util.Set;
 
-import org.elasticsearch.painless.MethodWriter;
-import org.objectweb.asm.Opcodes;
-
 /**
  * Represents a boolean expression.
  */
@@ -57,11 +55,11 @@ public final class EBool extends AExpression {
 
     @Override
     void analyze(Locals locals) {
-        left.expected = locals.getDefinition().booleanType;
+        left.expected = boolean.class;
         left.analyze(locals);
         left = left.cast(locals);
 
-        right.expected = locals.getDefinition().booleanType;
+        right.expected = boolean.class;
         right.analyze(locals);
         right = right.cast(locals);
 
@@ -75,7 +73,7 @@ public final class EBool extends AExpression {
             }
         }
 
-        actual = locals.getDefinition().booleanType;
+        actual = boolean.class;
     }
 
     @Override

+ 2 - 3
modules/lang-painless/src/main/java/org/elasticsearch/painless/node/EBoolean.java

@@ -19,10 +19,9 @@
 
 package org.elasticsearch.painless.node;
 
-import org.elasticsearch.painless.Definition;
 import org.elasticsearch.painless.Globals;
-import org.elasticsearch.painless.Location;
 import org.elasticsearch.painless.Locals;
+import org.elasticsearch.painless.Location;
 import org.elasticsearch.painless.MethodWriter;
 
 import java.util.Set;
@@ -49,7 +48,7 @@ public final class EBoolean extends AExpression {
             throw createError(new IllegalArgumentException("Must read from constant [" + constant + "]."));
         }
 
-        actual = locals.getDefinition().booleanType;
+        actual = boolean.class;
     }
 
     @Override

+ 3 - 2
modules/lang-painless/src/main/java/org/elasticsearch/painless/node/ECallLocal.java

@@ -19,6 +19,7 @@
 
 package org.elasticsearch.painless.node;
 
+import org.elasticsearch.painless.Definition;
 import org.elasticsearch.painless.Definition.Method;
 import org.elasticsearch.painless.Definition.MethodKey;
 import org.elasticsearch.painless.Globals;
@@ -68,14 +69,14 @@ public final class ECallLocal extends AExpression {
         for (int argument = 0; argument < arguments.size(); ++argument) {
             AExpression expression = arguments.get(argument);
 
-            expression.expected = method.arguments.get(argument);
+            expression.expected = Definition.TypeToClass(method.arguments.get(argument));
             expression.internal = true;
             expression.analyze(locals);
             arguments.set(argument, expression.cast(locals));
         }
 
         statement = true;
-        actual = method.rtn;
+        actual = Definition.TypeToClass(method.rtn);
     }
 
     @Override

+ 5 - 4
modules/lang-painless/src/main/java/org/elasticsearch/painless/node/ECapturingFunctionRef.java

@@ -70,13 +70,14 @@ public final class ECapturingFunctionRef extends AExpression implements ILambda
                 // typed implementation
                 defPointer = "S" + captured.type.name + "." + call + ",1";
             }
-            actual = locals.getDefinition().getType("String");
+            actual = String.class;
         } else {
             defPointer = null;
             // static case
             if (captured.type.dynamic == false) {
                 try {
-                    ref = new FunctionRef(locals.getDefinition(), expected, captured.type.name, call, 1);
+                    ref = new FunctionRef(
+                        locals.getDefinition(), locals.getDefinition().ClassToType(expected), captured.type.name, call, 1);
 
                     // check casts between the interface method and the delegate method are legal
                     for (int i = 0; i < ref.interfaceMethod.arguments.size(); ++i) {
@@ -108,8 +109,8 @@ public final class ECapturingFunctionRef extends AExpression implements ILambda
         } else if (ref == null) {
             // typed interface, dynamic implementation
             writer.visitVarInsn(captured.type.type.getOpcode(Opcodes.ILOAD), captured.getSlot());
-            Type methodType = Type.getMethodType(expected.type, captured.type.type);
-            writer.invokeDefCall(call, methodType, DefBootstrap.REFERENCE, expected.name);
+            Type methodType = Type.getMethodType(MethodWriter.getType(expected), captured.type.type);
+            writer.invokeDefCall(call, methodType, DefBootstrap.REFERENCE, Definition.ClassToName(expected));
         } else {
             // typed interface, typed implementation
             writer.visitVarInsn(captured.type.type.getOpcode(Opcodes.ILOAD), captured.getSlot());

+ 4 - 5
modules/lang-painless/src/main/java/org/elasticsearch/painless/node/ECast.java

@@ -21,15 +21,14 @@ package org.elasticsearch.painless.node;
 
 import org.elasticsearch.painless.Definition;
 import org.elasticsearch.painless.Definition.Cast;
-
-import java.util.Objects;
-import java.util.Set;
-
-import org.elasticsearch.painless.Location;
 import org.elasticsearch.painless.Globals;
 import org.elasticsearch.painless.Locals;
+import org.elasticsearch.painless.Location;
 import org.elasticsearch.painless.MethodWriter;
 
+import java.util.Objects;
+import java.util.Set;
+
 /**
  * Represents a cast that is inserted into the tree replacing other casts.  (Internal only.)
  */

+ 93 - 117
modules/lang-painless/src/main/java/org/elasticsearch/painless/node/EComp.java

@@ -19,23 +19,23 @@
 
 package org.elasticsearch.painless.node;
 
+import org.elasticsearch.painless.AnalyzerCaster;
+import org.elasticsearch.painless.DefBootstrap;
 import org.elasticsearch.painless.Definition;
+import org.elasticsearch.painless.Definition.def;
 import org.elasticsearch.painless.Globals;
-import org.elasticsearch.painless.Definition.Type;
+import org.elasticsearch.painless.Locals;
 import org.elasticsearch.painless.Location;
-import org.elasticsearch.painless.AnalyzerCaster;
-import org.elasticsearch.painless.DefBootstrap;
+import org.elasticsearch.painless.MethodWriter;
 import org.elasticsearch.painless.Operation;
-import org.elasticsearch.painless.Locals;
 import org.objectweb.asm.Label;
+import org.objectweb.asm.Type;
 
 import java.util.Objects;
 import java.util.Set;
 
-import org.elasticsearch.painless.MethodWriter;
-
-import static org.elasticsearch.painless.WriterConstants.OBJECTS_TYPE;
 import static org.elasticsearch.painless.WriterConstants.EQUALS;
+import static org.elasticsearch.painless.WriterConstants.OBJECTS_TYPE;
 
 /**
  * Represents a comparison expression.
@@ -46,7 +46,7 @@ public final class EComp extends AExpression {
     private AExpression left;
     private AExpression right;
 
-    private Type promotedType;
+    private Class<?> promotedType;
 
     public EComp(Location location, Operation operation, AExpression left, AExpression right) {
         super(location);
@@ -89,15 +89,14 @@ public final class EComp extends AExpression {
         left.analyze(variables);
         right.analyze(variables);
 
-        promotedType = variables.getDefinition().ClassToType(
-            AnalyzerCaster.promoteEquality(Definition.TypeToClass(left.actual), Definition.TypeToClass(right.actual)));
+        promotedType = AnalyzerCaster.promoteEquality(left.actual, right.actual);
 
         if (promotedType == null) {
             throw createError(new ClassCastException("Cannot apply equals [==] to types " +
-                "[" + left.actual.name + "] and [" + right.actual.name + "]."));
+                "[" + Definition.ClassToName(left.actual) + "] and [" + Definition.ClassToName(right.actual) + "]."));
         }
 
-        if (promotedType.dynamic) {
+        if (promotedType == def.class) {
             left.expected = left.actual;
             right.expected = right.actual;
         } else {
@@ -113,17 +112,15 @@ public final class EComp extends AExpression {
         }
 
         if ((left.constant != null || left.isNull) && (right.constant != null || right.isNull)) {
-            Class<?> sort = promotedType.clazz;
-
-            if (sort == boolean.class) {
+            if (promotedType == boolean.class) {
                 constant = (boolean)left.constant == (boolean)right.constant;
-            } else if (sort == int.class) {
+            } else if (promotedType == int.class) {
                 constant = (int)left.constant == (int)right.constant;
-            } else if (sort == long.class) {
+            } else if (promotedType == long.class) {
                 constant = (long)left.constant == (long)right.constant;
-            } else if (sort == float.class) {
+            } else if (promotedType == float.class) {
                 constant = (float)left.constant == (float)right.constant;
-            } else if (sort == double.class) {
+            } else if (promotedType == double.class) {
                 constant = (double)left.constant == (double)right.constant;
             } else if (!left.isNull) {
                 constant = left.constant.equals(right.constant);
@@ -134,19 +131,18 @@ public final class EComp extends AExpression {
             }
         }
 
-        actual = variables.getDefinition().booleanType;
+        actual = boolean.class;
     }
 
     private void analyzeEqR(Locals variables) {
         left.analyze(variables);
         right.analyze(variables);
 
-        promotedType = variables.getDefinition().ClassToType(
-            AnalyzerCaster.promoteEquality(Definition.TypeToClass(left.actual), Definition.TypeToClass(right.actual)));
+        promotedType = AnalyzerCaster.promoteEquality(left.actual, right.actual);
 
         if (promotedType == null) {
             throw createError(new ClassCastException("Cannot apply reference equals [===] to types " +
-                "[" + left.actual.name + "] and [" + right.actual.name + "]."));
+                "[" + Definition.ClassToName(left.actual) + "] and [" + Definition.ClassToName(right.actual) + "]."));
         }
 
         left.expected = promotedType;
@@ -160,39 +156,36 @@ public final class EComp extends AExpression {
         }
 
         if ((left.constant != null || left.isNull) && (right.constant != null || right.isNull)) {
-            Class<?> sort = promotedType.clazz;
-
-            if (sort == boolean.class) {
+            if (promotedType == boolean.class) {
                 constant = (boolean)left.constant == (boolean)right.constant;
-            } else if (sort == int.class) {
+            } else if (promotedType == int.class) {
                 constant = (int)left.constant == (int)right.constant;
-            } else if (sort == long.class) {
+            } else if (promotedType == long.class) {
                 constant = (long)left.constant == (long)right.constant;
-            } else if (sort == float.class) {
+            } else if (promotedType == float.class) {
                 constant = (float)left.constant == (float)right.constant;
-            } else if (sort == double.class) {
+            } else if (promotedType == double.class) {
                 constant = (double)left.constant == (double)right.constant;
             } else {
                 constant = left.constant == right.constant;
             }
         }
 
-        actual = variables.getDefinition().booleanType;
+        actual = boolean.class;
     }
 
     private void analyzeNE(Locals variables) {
         left.analyze(variables);
         right.analyze(variables);
 
-        promotedType = variables.getDefinition().ClassToType(
-            AnalyzerCaster.promoteEquality(Definition.TypeToClass(left.actual), Definition.TypeToClass(right.actual)));
+        promotedType = AnalyzerCaster.promoteEquality(left.actual, right.actual);
 
         if (promotedType == null) {
             throw createError(new ClassCastException("Cannot apply not equals [!=] to types " +
-                "[" + left.actual.name + "] and [" + right.actual.name + "]."));
+                "[" + Definition.ClassToName(left.actual) + "] and [" + Definition.ClassToName(right.actual) + "]."));
         }
 
-        if (promotedType.dynamic) {
+        if (promotedType == def.class) {
             left.expected = left.actual;
             right.expected = right.actual;
         } else {
@@ -208,17 +201,15 @@ public final class EComp extends AExpression {
         }
 
         if ((left.constant != null || left.isNull) && (right.constant != null || right.isNull)) {
-            Class<?> sort = promotedType.clazz;
-
-            if (sort == boolean.class) {
+            if (promotedType == boolean.class) {
                 constant = (boolean)left.constant != (boolean)right.constant;
-            } else if (sort == int.class) {
+            } else if (promotedType == int.class) {
                 constant = (int)left.constant != (int)right.constant;
-            } else if (sort == long.class) {
+            } else if (promotedType == long.class) {
                 constant = (long)left.constant != (long)right.constant;
-            } else if (sort == float.class) {
+            } else if (promotedType == float.class) {
                 constant = (float)left.constant != (float)right.constant;
-            } else if (sort == double.class) {
+            } else if (promotedType == double.class) {
                 constant = (double)left.constant != (double)right.constant;
             } else if (!left.isNull) {
                 constant = !left.constant.equals(right.constant);
@@ -229,19 +220,18 @@ public final class EComp extends AExpression {
             }
         }
 
-        actual = variables.getDefinition().booleanType;
+        actual = boolean.class;
     }
 
     private void analyzeNER(Locals variables) {
         left.analyze(variables);
         right.analyze(variables);
 
-        promotedType = variables.getDefinition().ClassToType(
-            AnalyzerCaster.promoteEquality(Definition.TypeToClass(left.actual), Definition.TypeToClass(right.actual)));
+        promotedType = AnalyzerCaster.promoteEquality(left.actual, right.actual);
 
         if (promotedType == null) {
             throw createError(new ClassCastException("Cannot apply reference not equals [!==] to types " +
-                "[" + left.actual.name + "] and [" + right.actual.name + "]."));
+                "[" + Definition.ClassToName(left.actual) + "] and [" + Definition.ClassToName(right.actual) + "]."));
         }
 
         left.expected = promotedType;
@@ -255,39 +245,36 @@ public final class EComp extends AExpression {
         }
 
         if ((left.constant != null || left.isNull) && (right.constant != null || right.isNull)) {
-            Class<?> sort = promotedType.clazz;
-
-            if (sort == boolean.class) {
+            if (promotedType == boolean.class) {
                 constant = (boolean)left.constant != (boolean)right.constant;
-            } else if (sort == int.class) {
+            } else if (promotedType == int.class) {
                 constant = (int)left.constant != (int)right.constant;
-            } else if (sort == long.class) {
+            } else if (promotedType == long.class) {
                 constant = (long)left.constant != (long)right.constant;
-            } else if (sort == float.class) {
+            } else if (promotedType == float.class) {
                 constant = (float)left.constant != (float)right.constant;
-            } else if (sort == double.class) {
+            } else if (promotedType == double.class) {
                 constant = (double)left.constant != (double)right.constant;
             } else {
                 constant = left.constant != right.constant;
             }
         }
 
-        actual = variables.getDefinition().booleanType;
+        actual = boolean.class;
     }
 
     private void analyzeGTE(Locals variables) {
         left.analyze(variables);
         right.analyze(variables);
 
-        promotedType = variables.getDefinition().ClassToType(
-            AnalyzerCaster.promoteNumeric(Definition.TypeToClass(left.actual), Definition.TypeToClass(right.actual), true));
+        promotedType = AnalyzerCaster.promoteNumeric(left.actual, right.actual, true);
 
         if (promotedType == null) {
             throw createError(new ClassCastException("Cannot apply greater than or equals [>=] to types " +
-                "[" + left.actual.name + "] and [" + right.actual.name + "]."));
+                "[" + Definition.ClassToName(left.actual) + "] and [" + Definition.ClassToName(right.actual) + "]."));
         }
 
-        if (promotedType.dynamic) {
+        if (promotedType == def.class) {
             left.expected = left.actual;
             right.expected = right.actual;
         } else {
@@ -299,37 +286,34 @@ public final class EComp extends AExpression {
         right = right.cast(variables);
 
         if (left.constant != null && right.constant != null) {
-            Class<?> sort = promotedType.clazz;
-
-            if (sort == int.class) {
+            if (promotedType == int.class) {
                 constant = (int)left.constant >= (int)right.constant;
-            } else if (sort == long.class) {
+            } else if (promotedType == long.class) {
                 constant = (long)left.constant >= (long)right.constant;
-            } else if (sort == float.class) {
+            } else if (promotedType == float.class) {
                 constant = (float)left.constant >= (float)right.constant;
-            } else if (sort == double.class) {
+            } else if (promotedType == double.class) {
                 constant = (double)left.constant >= (double)right.constant;
             } else {
                 throw createError(new IllegalStateException("Illegal tree structure."));
             }
         }
 
-        actual = variables.getDefinition().booleanType;
+        actual = boolean.class;
     }
 
     private void analyzeGT(Locals variables) {
         left.analyze(variables);
         right.analyze(variables);
 
-        promotedType = variables.getDefinition().ClassToType(
-            AnalyzerCaster.promoteNumeric(Definition.TypeToClass(left.actual), Definition.TypeToClass(right.actual), true));
+        promotedType = AnalyzerCaster.promoteNumeric(left.actual, right.actual, true);
 
         if (promotedType == null) {
             throw createError(new ClassCastException("Cannot apply greater than [>] to types " +
-                "[" + left.actual.name + "] and [" + right.actual.name + "]."));
+                "[" + Definition.ClassToName(left.actual) + "] and [" + Definition.ClassToName(right.actual) + "]."));
         }
 
-        if (promotedType.dynamic) {
+        if (promotedType == def.class) {
             left.expected = left.actual;
             right.expected = right.actual;
         } else {
@@ -341,37 +325,34 @@ public final class EComp extends AExpression {
         right = right.cast(variables);
 
         if (left.constant != null && right.constant != null) {
-            Class<?> sort = promotedType.clazz;
-
-            if (sort == int.class) {
+            if (promotedType == int.class) {
                 constant = (int)left.constant > (int)right.constant;
-            } else if (sort == long.class) {
+            } else if (promotedType == long.class) {
                 constant = (long)left.constant > (long)right.constant;
-            } else if (sort == float.class) {
+            } else if (promotedType == float.class) {
                 constant = (float)left.constant > (float)right.constant;
-            } else if (sort == double.class) {
+            } else if (promotedType == double.class) {
                 constant = (double)left.constant > (double)right.constant;
             } else {
                 throw createError(new IllegalStateException("Illegal tree structure."));
             }
         }
 
-        actual = variables.getDefinition().booleanType;
+        actual = boolean.class;
     }
 
     private void analyzeLTE(Locals variables) {
         left.analyze(variables);
         right.analyze(variables);
 
-        promotedType = variables.getDefinition().ClassToType(
-            AnalyzerCaster.promoteNumeric(Definition.TypeToClass(left.actual), Definition.TypeToClass(right.actual), true));
+        promotedType = AnalyzerCaster.promoteNumeric(left.actual, right.actual, true);
 
         if (promotedType == null) {
             throw createError(new ClassCastException("Cannot apply less than or equals [<=] to types " +
-                "[" + left.actual.name + "] and [" + right.actual.name + "]."));
+                "[" + Definition.ClassToName(left.actual) + "] and [" + Definition.ClassToName(right.actual) + "]."));
         }
 
-        if (promotedType.dynamic) {
+        if (promotedType == def.class) {
             left.expected = left.actual;
             right.expected = right.actual;
         } else {
@@ -383,37 +364,34 @@ public final class EComp extends AExpression {
         right = right.cast(variables);
 
         if (left.constant != null && right.constant != null) {
-            Class<?> sort = promotedType.clazz;
-
-            if (sort == int.class) {
+            if (promotedType == int.class) {
                 constant = (int)left.constant <= (int)right.constant;
-            } else if (sort == long.class) {
+            } else if (promotedType == long.class) {
                 constant = (long)left.constant <= (long)right.constant;
-            } else if (sort == float.class) {
+            } else if (promotedType == float.class) {
                 constant = (float)left.constant <= (float)right.constant;
-            } else if (sort == double.class) {
+            } else if (promotedType == double.class) {
                 constant = (double)left.constant <= (double)right.constant;
             } else {
                 throw createError(new IllegalStateException("Illegal tree structure."));
             }
         }
 
-        actual = variables.getDefinition().booleanType;
+        actual = boolean.class;
     }
 
     private void analyzeLT(Locals variables) {
         left.analyze(variables);
         right.analyze(variables);
 
-        promotedType = variables.getDefinition().ClassToType(
-            AnalyzerCaster.promoteNumeric(Definition.TypeToClass(left.actual), Definition.TypeToClass(right.actual), true));
+        promotedType = AnalyzerCaster.promoteNumeric(left.actual, right.actual, true);
 
         if (promotedType == null) {
             throw createError(new ClassCastException("Cannot apply less than [>=] to types " +
-                "[" + left.actual.name + "] and [" + right.actual.name + "]."));
+                "[" + Definition.ClassToName(left.actual) + "] and [" + Definition.ClassToName(right.actual) + "]."));
         }
 
-        if (promotedType.dynamic) {
+        if (promotedType == def.class) {
             left.expected = left.actual;
             right.expected = right.actual;
         } else {
@@ -425,22 +403,20 @@ public final class EComp extends AExpression {
         right = right.cast(variables);
 
         if (left.constant != null && right.constant != null) {
-            Class<?> sort = promotedType.clazz;
-
-            if (sort == int.class) {
+            if (promotedType == int.class) {
                 constant = (int)left.constant < (int)right.constant;
-            } else if (sort == long.class) {
+            } else if (promotedType == long.class) {
                 constant = (long)left.constant < (long)right.constant;
-            } else if (sort == float.class) {
+            } else if (promotedType == float.class) {
                 constant = (float)left.constant < (float)right.constant;
-            } else if (sort == double.class) {
+            } else if (promotedType == double.class) {
                 constant = (double)left.constant < (double)right.constant;
             } else {
                 throw createError(new IllegalStateException("Illegal tree structure."));
             }
         }
 
-        actual = variables.getDefinition().booleanType;
+        actual = boolean.class;
     }
 
     @Override
@@ -465,30 +441,30 @@ public final class EComp extends AExpression {
 
         boolean writejump = true;
 
-        Class<?> sort = promotedType.clazz;
+        Type type = MethodWriter.getType(promotedType);
 
-        if (sort == void.class || sort == byte.class || sort == short.class || sort == char.class) {
+        if (promotedType == void.class || promotedType == byte.class || promotedType == short.class || promotedType == char.class) {
             throw createError(new IllegalStateException("Illegal tree structure."));
-        } else if (sort == boolean.class) {
-            if (eq) writer.ifCmp(promotedType.type, MethodWriter.EQ, jump);
-            else if (ne) writer.ifCmp(promotedType.type, MethodWriter.NE, jump);
+        } else if (promotedType == boolean.class) {
+            if (eq) writer.ifCmp(type, MethodWriter.EQ, jump);
+            else if (ne) writer.ifCmp(type, MethodWriter.NE, jump);
             else {
                 throw createError(new IllegalStateException("Illegal tree structure."));
             }
-        } else if (sort == int.class || sort == long.class || sort == float.class || sort == double.class) {
-            if (eq) writer.ifCmp(promotedType.type, MethodWriter.EQ, jump);
-            else if (ne) writer.ifCmp(promotedType.type, MethodWriter.NE, jump);
-            else if (lt) writer.ifCmp(promotedType.type, MethodWriter.LT, jump);
-            else if (lte) writer.ifCmp(promotedType.type, MethodWriter.LE, jump);
-            else if (gt) writer.ifCmp(promotedType.type, MethodWriter.GT, jump);
-            else if (gte) writer.ifCmp(promotedType.type, MethodWriter.GE, jump);
+        } else if (promotedType == int.class || promotedType == long.class || promotedType == float.class || promotedType == double.class) {
+            if (eq) writer.ifCmp(type, MethodWriter.EQ, jump);
+            else if (ne) writer.ifCmp(type, MethodWriter.NE, jump);
+            else if (lt) writer.ifCmp(type, MethodWriter.LT, jump);
+            else if (lte) writer.ifCmp(type, MethodWriter.LE, jump);
+            else if (gt) writer.ifCmp(type, MethodWriter.GT, jump);
+            else if (gte) writer.ifCmp(type, MethodWriter.GE, jump);
             else {
                 throw createError(new IllegalStateException("Illegal tree structure."));
             }
 
-        } else if (promotedType.dynamic) {
-            org.objectweb.asm.Type booleanType = org.objectweb.asm.Type.getType(boolean.class);
-            org.objectweb.asm.Type descriptor = org.objectweb.asm.Type.getMethodType(booleanType, left.actual.type, right.actual.type);
+        } else if (promotedType == def.class) {
+            Type booleanType = Type.getType(boolean.class);
+            Type descriptor = Type.getMethodType(booleanType, MethodWriter.getType(left.actual), MethodWriter.getType(right.actual));
 
             if (eq) {
                 if (right.isNull) {
@@ -497,7 +473,7 @@ public final class EComp extends AExpression {
                     writer.invokeDefCall("eq", descriptor, DefBootstrap.BINARY_OPERATOR, DefBootstrap.OPERATOR_ALLOWS_NULL);
                     writejump = false;
                 } else {
-                    writer.ifCmp(promotedType.type, MethodWriter.EQ, jump);
+                    writer.ifCmp(type, MethodWriter.EQ, jump);
                 }
             } else if (ne) {
                 if (right.isNull) {
@@ -506,7 +482,7 @@ public final class EComp extends AExpression {
                     writer.invokeDefCall("eq", descriptor, DefBootstrap.BINARY_OPERATOR, DefBootstrap.OPERATOR_ALLOWS_NULL);
                     writer.ifZCmp(MethodWriter.EQ, jump);
                 } else {
-                    writer.ifCmp(promotedType.type, MethodWriter.NE, jump);
+                    writer.ifCmp(type, MethodWriter.NE, jump);
                 }
             } else if (lt) {
                 writer.invokeDefCall("lt", descriptor, DefBootstrap.BINARY_OPERATOR, 0);
@@ -531,7 +507,7 @@ public final class EComp extends AExpression {
                     writer.invokeStatic(OBJECTS_TYPE, EQUALS);
                     writejump = false;
                 } else {
-                    writer.ifCmp(promotedType.type, MethodWriter.EQ, jump);
+                    writer.ifCmp(type, MethodWriter.EQ, jump);
                 }
             } else if (ne) {
                 if (right.isNull) {
@@ -540,7 +516,7 @@ public final class EComp extends AExpression {
                     writer.invokeStatic(OBJECTS_TYPE, EQUALS);
                     writer.ifZCmp(MethodWriter.EQ, jump);
                 } else {
-                    writer.ifCmp(promotedType.type, MethodWriter.NE, jump);
+                    writer.ifCmp(type, MethodWriter.NE, jump);
                 }
             } else {
                 throw createError(new IllegalStateException("Illegal tree structure."));

+ 6 - 10
modules/lang-painless/src/main/java/org/elasticsearch/painless/node/EConditional.java

@@ -19,20 +19,17 @@
 
 package org.elasticsearch.painless.node;
 
-import org.elasticsearch.painless.Definition;
-import org.elasticsearch.painless.Globals;
-import org.elasticsearch.painless.Definition.Type;
-import org.elasticsearch.painless.Location;
 import org.elasticsearch.painless.AnalyzerCaster;
+import org.elasticsearch.painless.Globals;
 import org.elasticsearch.painless.Locals;
+import org.elasticsearch.painless.Location;
+import org.elasticsearch.painless.MethodWriter;
 import org.objectweb.asm.Label;
+import org.objectweb.asm.Opcodes;
 
 import java.util.Objects;
 import java.util.Set;
 
-import org.elasticsearch.painless.MethodWriter;
-import org.objectweb.asm.Opcodes;
-
 /**
  * Represents a conditional expression.
  */
@@ -59,7 +56,7 @@ public final class EConditional extends AExpression {
 
     @Override
     void analyze(Locals locals) {
-        condition.expected = locals.getDefinition().booleanType;
+        condition.expected = boolean.class;
         condition.analyze(locals);
         condition = condition.cast(locals);
 
@@ -79,8 +76,7 @@ public final class EConditional extends AExpression {
         right.analyze(locals);
 
         if (expected == null) {
-            Type promote = locals.getDefinition().ClassToType(AnalyzerCaster.promoteConditional(
-                Definition.TypeToClass(left.actual), Definition.TypeToClass(right.actual), left.constant, right.constant));
+            Class<?> promote = AnalyzerCaster.promoteConditional(left.actual, right.actual, left.constant, right.constant);
 
             left.expected = promote;
             right.expected = promote;

+ 21 - 23
modules/lang-painless/src/main/java/org/elasticsearch/painless/node/EConstant.java

@@ -19,15 +19,13 @@
 
 package org.elasticsearch.painless.node;
 
-import org.elasticsearch.painless.Definition;
 import org.elasticsearch.painless.Globals;
-
-import java.util.Set;
-
-import org.elasticsearch.painless.Location;
 import org.elasticsearch.painless.Locals;
+import org.elasticsearch.painless.Location;
 import org.elasticsearch.painless.MethodWriter;
 
+import java.util.Set;
+
 /**
  * Represents a constant inserted into the tree replacing
  * other constants during constant folding.  (Internal only.)
@@ -48,23 +46,23 @@ final class EConstant extends AExpression {
     @Override
     void analyze(Locals locals) {
         if (constant instanceof String) {
-            actual = locals.getDefinition().StringType;
+            actual = String.class;
         } else if (constant instanceof Double) {
-            actual = locals.getDefinition().doubleType;
+            actual = double.class;
         } else if (constant instanceof Float) {
-            actual = locals.getDefinition().floatType;
+            actual = float.class;
         } else if (constant instanceof Long) {
-            actual = locals.getDefinition().longType;
+            actual = long.class;
         } else if (constant instanceof Integer) {
-            actual = locals.getDefinition().intType;
+            actual = int.class;
         } else if (constant instanceof Character) {
-            actual = locals.getDefinition().charType;
+            actual = char.class;
         } else if (constant instanceof Short) {
-            actual = locals.getDefinition().shortType;
+            actual = short.class;
         } else if (constant instanceof Byte) {
-            actual = locals.getDefinition().byteType;
+            actual = byte.class;
         } else if (constant instanceof Boolean) {
-            actual = locals.getDefinition().booleanType;
+            actual = boolean.class;
         } else {
             throw createError(new IllegalStateException("Illegal tree structure."));
         }
@@ -72,15 +70,15 @@ final class EConstant extends AExpression {
 
     @Override
     void write(MethodWriter writer, Globals globals) {
-        if      (actual.clazz == String.class) writer.push((String)constant);
-        else if (actual.clazz == double.class) writer.push((double)constant);
-        else if (actual.clazz == float.class) writer.push((float)constant);
-        else if (actual.clazz == long.class) writer.push((long)constant);
-        else if (actual.clazz == int.class) writer.push((int)constant);
-        else if (actual.clazz == char.class) writer.push((char)constant);
-        else if (actual.clazz == short.class) writer.push((short)constant);
-        else if (actual.clazz == byte.class) writer.push((byte)constant);
-        else if (actual.clazz == boolean.class) writer.push((boolean)constant);
+        if      (actual == String.class) writer.push((String)constant);
+        else if (actual == double.class) writer.push((double)constant);
+        else if (actual == float.class) writer.push((float)constant);
+        else if (actual == long.class) writer.push((long)constant);
+        else if (actual == int.class) writer.push((int)constant);
+        else if (actual == char.class) writer.push((char)constant);
+        else if (actual == short.class) writer.push((short)constant);
+        else if (actual == byte.class) writer.push((byte)constant);
+        else if (actual == boolean.class) writer.push((boolean)constant);
         else {
             throw createError(new IllegalStateException("Illegal tree structure."));
         }

+ 3 - 4
modules/lang-painless/src/main/java/org/elasticsearch/painless/node/EDecimal.java

@@ -19,10 +19,9 @@
 
 package org.elasticsearch.painless.node;
 
-import org.elasticsearch.painless.Definition;
 import org.elasticsearch.painless.Globals;
-import org.elasticsearch.painless.Location;
 import org.elasticsearch.painless.Locals;
+import org.elasticsearch.painless.Location;
 import org.elasticsearch.painless.MethodWriter;
 
 import java.util.Objects;
@@ -53,7 +52,7 @@ public final class EDecimal extends AExpression {
         if (value.endsWith("f") || value.endsWith("F")) {
             try {
                 constant = Float.parseFloat(value.substring(0, value.length() - 1));
-                actual = locals.getDefinition().floatType;
+                actual = float.class;
             } catch (NumberFormatException exception) {
                 throw createError(new IllegalArgumentException("Invalid float constant [" + value + "]."));
             }
@@ -64,7 +63,7 @@ public final class EDecimal extends AExpression {
             }
             try {
                 constant = Double.parseDouble(toParse);
-                actual = locals.getDefinition().doubleType;
+                actual = double.class;
             } catch (NumberFormatException exception) {
                 throw createError(new IllegalArgumentException("Invalid double constant [" + value + "]."));
             }

+ 3 - 6
modules/lang-painless/src/main/java/org/elasticsearch/painless/node/EElvis.java

@@ -20,8 +20,6 @@
 package org.elasticsearch.painless.node;
 
 import org.elasticsearch.painless.AnalyzerCaster;
-import org.elasticsearch.painless.Definition;
-import org.elasticsearch.painless.Definition.Type;
 import org.elasticsearch.painless.Globals;
 import org.elasticsearch.painless.Locals;
 import org.elasticsearch.painless.Location;
@@ -55,7 +53,7 @@ public class EElvis extends AExpression {
 
     @Override
     void analyze(Locals locals) {
-        if (expected != null && expected.clazz.isPrimitive()) {
+        if (expected != null && expected.isPrimitive()) {
             throw createError(new IllegalArgumentException("Elvis operator cannot return primitives"));
         }
         lhs.expected = expected;
@@ -74,7 +72,7 @@ public class EElvis extends AExpression {
         if (lhs.constant != null) {
             throw createError(new IllegalArgumentException("Extraneous elvis operator. LHS is a constant."));
         }
-        if (lhs.actual.clazz.isPrimitive()) {
+        if (lhs.actual.isPrimitive()) {
             throw createError(new IllegalArgumentException("Extraneous elvis operator. LHS is a primitive."));
         }
         if (rhs.isNull) {
@@ -82,8 +80,7 @@ public class EElvis extends AExpression {
         }
 
         if (expected == null) {
-            Type promote = locals.getDefinition().ClassToType(AnalyzerCaster.promoteConditional(
-                Definition.TypeToClass(lhs.actual), Definition.TypeToClass(rhs.actual), lhs.constant, rhs.constant));
+            Class<?> promote = AnalyzerCaster.promoteConditional(lhs.actual, rhs.actual, lhs.constant, rhs.constant);
 
             lhs.expected = promote;
             rhs.expected = promote;

+ 3 - 2
modules/lang-painless/src/main/java/org/elasticsearch/painless/node/EExplicit.java

@@ -19,6 +19,7 @@
 
 package org.elasticsearch.painless.node;
 
+import org.elasticsearch.painless.Definition;
 import org.elasticsearch.painless.Globals;
 import org.elasticsearch.painless.Locals;
 import org.elasticsearch.painless.Location;
@@ -50,9 +51,9 @@ public final class EExplicit extends AExpression {
     @Override
     void analyze(Locals locals) {
         try {
-            actual = locals.getDefinition().getType(type);
+            actual = Definition.TypeToClass(locals.getDefinition().getType(type));
         } catch (IllegalArgumentException exception) {
-            throw createError(new IllegalArgumentException("Not a type [" + this.type + "]."));
+            throw createError(new IllegalArgumentException("Not a type [" + type + "]."));
         }
 
         child.expected = actual;

+ 6 - 6
modules/lang-painless/src/main/java/org/elasticsearch/painless/node/EFunctionRef.java

@@ -59,24 +59,24 @@ public final class EFunctionRef extends AExpression implements ILambda {
     void analyze(Locals locals) {
         if (expected == null) {
             ref = null;
-            actual = locals.getDefinition().getType("String");
+            actual = String.class;
             defPointer = "S" + type + "." + call + ",0";
         } else {
             defPointer = null;
             try {
                 if ("this".equals(type)) {
                     // user's own function
-                    Method interfaceMethod = expected.struct.getFunctionalMethod();
+                    Method interfaceMethod = locals.getDefinition().ClassToType(expected).struct.getFunctionalMethod();
                     if (interfaceMethod == null) {
                         throw new IllegalArgumentException("Cannot convert function reference [" + type + "::" + call + "] " +
-                                                           "to [" + expected.name + "], not a functional interface");
+                                                           "to [" + Definition.ClassToName(expected) + "], not a functional interface");
                     }
                     Method delegateMethod = locals.getMethod(new MethodKey(call, interfaceMethod.arguments.size()));
                     if (delegateMethod == null) {
                         throw new IllegalArgumentException("Cannot convert function reference [" + type + "::" + call + "] " +
-                                                           "to [" + expected.name + "], function not found");
+                                                           "to [" + Definition.ClassToName(expected) + "], function not found");
                     }
-                    ref = new FunctionRef(expected, interfaceMethod, delegateMethod, 0);
+                    ref = new FunctionRef(locals.getDefinition().ClassToType(expected), interfaceMethod, delegateMethod, 0);
 
                     // check casts between the interface method and the delegate method are legal
                     for (int i = 0; i < interfaceMethod.arguments.size(); ++i) {
@@ -91,7 +91,7 @@ public final class EFunctionRef extends AExpression implements ILambda {
                     }
                 } else {
                     // whitelist lookup
-                    ref = new FunctionRef(locals.getDefinition(), expected, type, call, 0);
+                    ref = new FunctionRef(locals.getDefinition(), locals.getDefinition().ClassToType(expected), type, call, 0);
                 }
 
             } catch (IllegalArgumentException e) {

+ 8 - 8
modules/lang-painless/src/main/java/org/elasticsearch/painless/node/EInstanceof.java

@@ -20,7 +20,6 @@
 package org.elasticsearch.painless.node;
 
 import org.elasticsearch.painless.Definition;
-import org.elasticsearch.painless.Definition.Type;
 import org.elasticsearch.painless.Globals;
 import org.elasticsearch.painless.Locals;
 import org.elasticsearch.painless.Location;
@@ -55,17 +54,17 @@ public final class EInstanceof extends AExpression {
 
     @Override
     void analyze(Locals locals) {
-        final Type type;
+        Class<?> clazz;
 
         // ensure the specified type is part of the definition
         try {
-            type = locals.getDefinition().getType(this.type);
+            clazz = Definition.TypeToClass(locals.getDefinition().getType(this.type));
         } catch (IllegalArgumentException exception) {
             throw createError(new IllegalArgumentException("Not a type [" + this.type + "]."));
         }
 
         // map to wrapped type for primitive types
-        resolvedType = type.clazz.isPrimitive() ? locals.getDefinition().getBoxedType(type).clazz : type.clazz;
+        resolvedType = clazz.isPrimitive() ? Definition.getBoxedType(clazz) : Definition.defClassToObjectClass(clazz);
 
         // analyze and cast the expression
         expression.analyze(locals);
@@ -73,11 +72,12 @@ public final class EInstanceof extends AExpression {
         expression = expression.cast(locals);
 
         // record if the expression returns a primitive
-        primitiveExpression = expression.actual.clazz.isPrimitive();
+        primitiveExpression = expression.actual.isPrimitive();
         // map to wrapped type for primitive types
-        expressionType = expression.actual.clazz.isPrimitive() ? locals.getDefinition().getBoxedType(expression.actual).clazz : type.clazz;
+        expressionType = expression.actual.isPrimitive() ?
+            Definition.getBoxedType(expression.actual) : Definition.defClassToObjectClass(clazz);
 
-        actual = locals.getDefinition().booleanType;
+        actual = boolean.class;
     }
 
     @Override
@@ -87,7 +87,7 @@ public final class EInstanceof extends AExpression {
             // run the expression anyway (who knows what it does)
             expression.write(writer, globals);
             // discard its result
-            writer.writePop(expression.actual.type.getSize());
+            writer.writePop(MethodWriter.getType(expression.actual).getSize());
             // push our result: its a primitive so it cannot be null.
             writer.push(resolvedType.isAssignableFrom(expressionType));
         } else {

+ 5 - 5
modules/lang-painless/src/main/java/org/elasticsearch/painless/node/ELambda.java

@@ -120,15 +120,15 @@ public final class ELambda extends AExpression implements ILambda {
             }
         } else {
             // we know the method statically, infer return type and any unknown/def types
-            interfaceMethod = expected.struct.getFunctionalMethod();
+            interfaceMethod = locals.getDefinition().ClassToType(expected).struct.getFunctionalMethod();
             if (interfaceMethod == null) {
-                throw createError(new IllegalArgumentException("Cannot pass lambda to [" + expected.name +
+                throw createError(new IllegalArgumentException("Cannot pass lambda to [" + Definition.ClassToName(expected) +
                                                                "], not a functional interface"));
             }
             // check arity before we manipulate parameters
             if (interfaceMethod.arguments.size() != paramTypeStrs.size())
                 throw new IllegalArgumentException("Incorrect number of parameters for [" + interfaceMethod.name +
-                                                   "] in [" + expected.clazz + "]");
+                                                   "] in [" + Definition.ClassToName(expected) + "]");
             // for method invocation, its allowed to ignore the return value
             if (interfaceMethod.rtn.equals(locals.getDefinition().voidType)) {
                 returnType = locals.getDefinition().DefType;
@@ -178,12 +178,12 @@ public final class ELambda extends AExpression implements ILambda {
         // setup method reference to synthetic method
         if (expected == null) {
             ref = null;
-            actual = locals.getDefinition().getType("String");
+            actual = String.class;
             defPointer = "Sthis." + name + "," + captures.size();
         } else {
             defPointer = null;
             try {
-                ref = new FunctionRef(expected, interfaceMethod, desugared.method, captures.size());
+                ref = new FunctionRef(locals.getDefinition().ClassToType(expected), interfaceMethod, desugared.method, captures.size());
             } catch (IllegalArgumentException e) {
                 throw createError(e);
             }

+ 7 - 6
modules/lang-painless/src/main/java/org/elasticsearch/painless/node/EListInit.java

@@ -19,14 +19,15 @@
 
 package org.elasticsearch.painless.node;
 
-import org.elasticsearch.painless.Definition;
 import org.elasticsearch.painless.Definition.Method;
 import org.elasticsearch.painless.Definition.MethodKey;
+import org.elasticsearch.painless.Definition.def;
 import org.elasticsearch.painless.Globals;
 import org.elasticsearch.painless.Locals;
 import org.elasticsearch.painless.Location;
 import org.elasticsearch.painless.MethodWriter;
 
+import java.util.ArrayList;
 import java.util.List;
 import java.util.Set;
 
@@ -58,15 +59,15 @@ public final class EListInit extends AExpression {
             throw createError(new IllegalArgumentException("Must read from list initializer."));
         }
 
-        actual = locals.getDefinition().ArrayListType;
+        actual = ArrayList.class;
 
-        constructor = actual.struct.constructors.get(new MethodKey("<init>", 0));
+        constructor = locals.getDefinition().ClassToType(actual).struct.constructors.get(new MethodKey("<init>", 0));
 
         if (constructor == null) {
             throw createError(new IllegalStateException("Illegal tree structure."));
         }
 
-        method = actual.struct.methods.get(new MethodKey("add", 1));
+        method = locals.getDefinition().ClassToType(actual).struct.methods.get(new MethodKey("add", 1));
 
         if (method == null) {
             throw createError(new IllegalStateException("Illegal tree structure."));
@@ -75,7 +76,7 @@ public final class EListInit extends AExpression {
         for (int index = 0; index < values.size(); ++index) {
             AExpression expression = values.get(index);
 
-            expression.expected = locals.getDefinition().DefType;
+            expression.expected = def.class;
             expression.internal = true;
             expression.analyze(locals);
             values.set(index, expression.cast(locals));
@@ -86,7 +87,7 @@ public final class EListInit extends AExpression {
     void write(MethodWriter writer, Globals globals) {
         writer.writeDebugInfo(location);
 
-        writer.newInstance(actual.type);
+        writer.newInstance(MethodWriter.getType(actual));
         writer.dup();
         writer.invokeConstructor(constructor.owner.type, constructor.method);
 

+ 8 - 7
modules/lang-painless/src/main/java/org/elasticsearch/painless/node/EMapInit.java

@@ -19,14 +19,15 @@
 
 package org.elasticsearch.painless.node;
 
-import org.elasticsearch.painless.Definition;
 import org.elasticsearch.painless.Definition.Method;
 import org.elasticsearch.painless.Definition.MethodKey;
+import org.elasticsearch.painless.Definition.def;
 import org.elasticsearch.painless.Globals;
 import org.elasticsearch.painless.Locals;
 import org.elasticsearch.painless.Location;
 import org.elasticsearch.painless.MethodWriter;
 
+import java.util.HashMap;
 import java.util.List;
 import java.util.Set;
 
@@ -64,15 +65,15 @@ public final class EMapInit extends AExpression {
             throw createError(new IllegalArgumentException("Must read from map initializer."));
         }
 
-        actual = locals.getDefinition().HashMapType;
+        actual = HashMap.class;
 
-        constructor = actual.struct.constructors.get(new MethodKey("<init>", 0));
+        constructor = locals.getDefinition().ClassToType(actual).struct.constructors.get(new MethodKey("<init>", 0));
 
         if (constructor == null) {
             throw createError(new IllegalStateException("Illegal tree structure."));
         }
 
-        method = actual.struct.methods.get(new MethodKey("put", 2));
+        method = locals.getDefinition().ClassToType(actual).struct.methods.get(new MethodKey("put", 2));
 
         if (method == null) {
             throw createError(new IllegalStateException("Illegal tree structure."));
@@ -85,7 +86,7 @@ public final class EMapInit extends AExpression {
         for (int index = 0; index < keys.size(); ++index) {
             AExpression expression = keys.get(index);
 
-            expression.expected = locals.getDefinition().DefType;
+            expression.expected = def.class;
             expression.internal = true;
             expression.analyze(locals);
             keys.set(index, expression.cast(locals));
@@ -94,7 +95,7 @@ public final class EMapInit extends AExpression {
         for (int index = 0; index < values.size(); ++index) {
             AExpression expression = values.get(index);
 
-            expression.expected = locals.getDefinition().DefType;
+            expression.expected = def.class;
             expression.internal = true;
             expression.analyze(locals);
             values.set(index, expression.cast(locals));
@@ -105,7 +106,7 @@ public final class EMapInit extends AExpression {
     void write(MethodWriter writer, Globals globals) {
         writer.writeDebugInfo(location);
 
-        writer.newInstance(actual.type);
+        writer.newInstance(MethodWriter.getType(actual));
         writer.dup();
         writer.invokeConstructor(constructor.owner.type, constructor.method);
 

+ 12 - 9
modules/lang-painless/src/main/java/org/elasticsearch/painless/node/ENewArray.java

@@ -20,7 +20,6 @@
 package org.elasticsearch.painless.node;
 
 import org.elasticsearch.painless.Definition;
-import org.elasticsearch.painless.Definition.Type;
 import org.elasticsearch.painless.Globals;
 import org.elasticsearch.painless.Locals;
 import org.elasticsearch.painless.Location;
@@ -39,6 +38,8 @@ public final class ENewArray extends AExpression {
     private final List<AExpression> arguments;
     private final boolean initialize;
 
+    private Class<?> array;
+
     public ENewArray(Location location, String type, List<AExpression> arguments, boolean initialize) {
         super(location);
 
@@ -60,10 +61,10 @@ public final class ENewArray extends AExpression {
             throw createError(new IllegalArgumentException("A newly created array must be read from."));
         }
 
-        final Type type;
+        Class<?> clazz;
 
         try {
-            type = locals.getDefinition().getType(this.type);
+            clazz = Definition.TypeToClass(locals.getDefinition().getType(this.type));
         } catch (IllegalArgumentException exception) {
             throw createError(new IllegalArgumentException("Not a type [" + this.type + "]."));
         }
@@ -71,13 +72,15 @@ public final class ENewArray extends AExpression {
         for (int argument = 0; argument < arguments.size(); ++argument) {
             AExpression expression = arguments.get(argument);
 
-            expression.expected = initialize ? locals.getDefinition().getType(type.struct, 0) : locals.getDefinition().intType;
+            expression.expected = initialize ? clazz : int.class;
             expression.internal = true;
             expression.analyze(locals);
             arguments.set(argument, expression.cast(locals));
         }
 
-        actual = locals.getDefinition().getType(type.struct, initialize ? 1 : arguments.size());
+        actual = Definition.TypeToClass(locals.getDefinition().getType(
+            locals.getDefinition().ClassToType(clazz).struct, initialize ? 1 : arguments.size()));
+        array = Definition.defClassToObjectClass(actual);
     }
 
     @Override
@@ -86,7 +89,7 @@ public final class ENewArray extends AExpression {
 
         if (initialize) {
             writer.push(arguments.size());
-            writer.newArray(actual.struct.type);
+            writer.newArray(MethodWriter.getType(array.getComponentType()));
 
             for (int index = 0; index < arguments.size(); ++index) {
                 AExpression argument = arguments.get(index);
@@ -94,7 +97,7 @@ public final class ENewArray extends AExpression {
                 writer.dup();
                 writer.push(index);
                 argument.write(writer, globals);
-                writer.arrayStore(actual.struct.type);
+                writer.arrayStore(MethodWriter.getType(array.getComponentType()));
             }
         } else {
             for (AExpression argument : arguments) {
@@ -102,9 +105,9 @@ public final class ENewArray extends AExpression {
             }
 
             if (arguments.size() > 1) {
-                writer.visitMultiANewArrayInsn(actual.type.getDescriptor(), actual.type.getDimensions());
+                writer.visitMultiANewArrayInsn(MethodWriter.getType(array).getDescriptor(), arguments.size());
             } else {
-                writer.newArray(actual.struct.type);
+                writer.newArray(MethodWriter.getType(array.getComponentType()));
             }
         }
     }

+ 4 - 7
modules/lang-painless/src/main/java/org/elasticsearch/painless/node/ENewObj.java

@@ -58,15 +58,13 @@ public final class ENewObj extends AExpression {
 
     @Override
     void analyze(Locals locals) {
-        final Type type;
-
         try {
-            type = locals.getDefinition().getType(this.type);
+            actual = Definition.TypeToClass(locals.getDefinition().getType(this.type));
         } catch (IllegalArgumentException exception) {
             throw createError(new IllegalArgumentException("Not a type [" + this.type + "]."));
         }
 
-        Struct struct = type.struct;
+        Struct struct = locals.getDefinition().ClassToType(actual).struct;
         constructor = struct.constructors.get(new Definition.MethodKey("<init>", arguments.size()));
 
         if (constructor != null) {
@@ -81,14 +79,13 @@ public final class ENewObj extends AExpression {
             for (int argument = 0; argument < arguments.size(); ++argument) {
                 AExpression expression = arguments.get(argument);
 
-                expression.expected = types[argument];
+                expression.expected = Definition.TypeToClass(types[argument]);
                 expression.internal = true;
                 expression.analyze(locals);
                 arguments.set(argument, expression.cast(locals));
             }
 
             statement = true;
-            actual = type;
         } else {
             throw createError(new IllegalArgumentException("Unknown new call on type [" + struct.name + "]."));
         }
@@ -98,7 +95,7 @@ public final class ENewObj extends AExpression {
     void write(MethodWriter writer, Globals globals) {
         writer.writeDebugInfo(location);
 
-        writer.newInstance(actual.type);
+        writer.newInstance(MethodWriter.getType(actual));
 
         if (read) {
             writer.dup();

+ 6 - 6
modules/lang-painless/src/main/java/org/elasticsearch/painless/node/ENull.java

@@ -21,14 +21,13 @@ package org.elasticsearch.painless.node;
 
 import org.elasticsearch.painless.Definition;
 import org.elasticsearch.painless.Globals;
-import org.elasticsearch.painless.Location;
 import org.elasticsearch.painless.Locals;
+import org.elasticsearch.painless.Location;
+import org.elasticsearch.painless.MethodWriter;
 import org.objectweb.asm.Opcodes;
 
 import java.util.Set;
 
-import org.elasticsearch.painless.MethodWriter;
-
 /**
  * Represents a null constant.
  */
@@ -52,13 +51,14 @@ public final class ENull extends AExpression {
         isNull = true;
 
         if (expected != null) {
-            if (expected.clazz.isPrimitive()) {
-                throw createError(new IllegalArgumentException("Cannot cast null to a primitive type [" + expected.name + "]."));
+            if (expected.isPrimitive()) {
+                throw createError(new IllegalArgumentException(
+                    "Cannot cast null to a primitive type [" + Definition.ClassToName(expected) + "]."));
             }
 
             actual = expected;
         } else {
-            actual = locals.getDefinition().ObjectType;
+            actual = Object.class;
         }
     }
 

+ 10 - 12
modules/lang-painless/src/main/java/org/elasticsearch/painless/node/ENumeric.java

@@ -19,16 +19,14 @@
 
 package org.elasticsearch.painless.node;
 
-import org.elasticsearch.painless.Definition;
 import org.elasticsearch.painless.Globals;
+import org.elasticsearch.painless.Locals;
 import org.elasticsearch.painless.Location;
+import org.elasticsearch.painless.MethodWriter;
 
 import java.util.Objects;
 import java.util.Set;
 
-import org.elasticsearch.painless.Locals;
-import org.elasticsearch.painless.MethodWriter;
-
 /**
  * Represents a non-decimal numeric constant.
  */
@@ -62,7 +60,7 @@ public final class ENumeric extends AExpression {
 
             try {
                 constant = Double.parseDouble(value.substring(0, value.length() - 1));
-                actual = locals.getDefinition().doubleType;
+                actual = double.class;
             } catch (NumberFormatException exception) {
                 throw createError(new IllegalArgumentException("Invalid double constant [" + value + "]."));
             }
@@ -73,34 +71,34 @@ public final class ENumeric extends AExpression {
 
             try {
                 constant = Float.parseFloat(value.substring(0, value.length() - 1));
-                actual = locals.getDefinition().floatType;
+                actual = float.class;
             } catch (NumberFormatException exception) {
                 throw createError(new IllegalArgumentException("Invalid float constant [" + value + "]."));
             }
         } else if (value.endsWith("l") || value.endsWith("L")) {
             try {
                 constant = Long.parseLong(value.substring(0, value.length() - 1), radix);
-                actual = locals.getDefinition().longType;
+                actual = long.class;
             } catch (NumberFormatException exception) {
                 throw createError(new IllegalArgumentException("Invalid long constant [" + value + "]."));
             }
         } else {
             try {
-                Class<?> sort = expected == null ? int.class : expected.clazz;
+                Class<?> sort = expected == null ? int.class : expected;
                 int integer = Integer.parseInt(value, radix);
 
                 if (sort == byte.class && integer >= Byte.MIN_VALUE && integer <= Byte.MAX_VALUE) {
                     constant = (byte)integer;
-                    actual = locals.getDefinition().byteType;
+                    actual = byte.class;
                 } else if (sort == char.class && integer >= Character.MIN_VALUE && integer <= Character.MAX_VALUE) {
                     constant = (char)integer;
-                    actual = locals.getDefinition().charType;
+                    actual = char.class;
                 } else if (sort == short.class && integer >= Short.MIN_VALUE && integer <= Short.MAX_VALUE) {
                     constant = (short)integer;
-                    actual = locals.getDefinition().shortType;
+                    actual = short.class;
                 } else {
                     constant = integer;
-                    actual = locals.getDefinition().intType;
+                    actual = int.class;
                 }
             } catch (NumberFormatException exception) {
                 try {

+ 4 - 6
modules/lang-painless/src/main/java/org/elasticsearch/painless/node/ERegex.java

@@ -20,18 +20,16 @@
 package org.elasticsearch.painless.node;
 
 import org.elasticsearch.painless.Constant;
-import org.elasticsearch.painless.Definition;
 import org.elasticsearch.painless.Globals;
 import org.elasticsearch.painless.Locals;
+import org.elasticsearch.painless.Location;
+import org.elasticsearch.painless.MethodWriter;
+import org.elasticsearch.painless.WriterConstants;
 
 import java.util.Set;
 import java.util.regex.Pattern;
 import java.util.regex.PatternSyntaxException;
 
-import org.elasticsearch.painless.Location;
-import org.elasticsearch.painless.MethodWriter;
-import org.elasticsearch.painless.WriterConstants;
-
 /**
  * Represents a regex constant. All regexes are constants.
  */
@@ -75,7 +73,7 @@ public final class ERegex extends AExpression {
 
         constant = new Constant(
             location, locals.getDefinition().PatternType.type, "regexAt$" + location.getOffset(), this::initializeConstant);
-        actual = locals.getDefinition().PatternType;
+        actual = Pattern.class;
     }
 
     @Override

+ 2 - 1
modules/lang-painless/src/main/java/org/elasticsearch/painless/node/EStatic.java

@@ -19,6 +19,7 @@
 
 package org.elasticsearch.painless.node;
 
+import org.elasticsearch.painless.Definition;
 import org.elasticsearch.painless.Globals;
 import org.elasticsearch.painless.Locals;
 import org.elasticsearch.painless.Location;
@@ -48,7 +49,7 @@ public final class EStatic extends AExpression {
     @Override
     void analyze(Locals locals) {
         try {
-            actual = locals.getDefinition().getType(type);
+            actual = Definition.TypeToClass(locals.getDefinition().getType(type));
         } catch (IllegalArgumentException exception) {
             throw createError(new IllegalArgumentException("Not a type [" + type + "]."));
         }

+ 2 - 3
modules/lang-painless/src/main/java/org/elasticsearch/painless/node/EString.java

@@ -19,10 +19,9 @@
 
 package org.elasticsearch.painless.node;
 
-import org.elasticsearch.painless.Definition;
 import org.elasticsearch.painless.Globals;
-import org.elasticsearch.painless.Location;
 import org.elasticsearch.painless.Locals;
+import org.elasticsearch.painless.Location;
 import org.elasticsearch.painless.MethodWriter;
 
 import java.util.Objects;
@@ -50,7 +49,7 @@ public final class EString extends AExpression {
             throw createError(new IllegalArgumentException("Must read from constant [" + constant + "]."));
         }
 
-        actual = locals.getDefinition().StringType;
+        actual = String.class;
     }
 
     @Override

+ 42 - 46
modules/lang-painless/src/main/java/org/elasticsearch/painless/node/EUnary.java

@@ -19,22 +19,22 @@
 
 package org.elasticsearch.painless.node;
 
+import org.elasticsearch.painless.AnalyzerCaster;
+import org.elasticsearch.painless.DefBootstrap;
 import org.elasticsearch.painless.Definition;
+import org.elasticsearch.painless.Definition.def;
 import org.elasticsearch.painless.Globals;
+import org.elasticsearch.painless.Locals;
 import org.elasticsearch.painless.Location;
-import org.elasticsearch.painless.Definition.Type;
-import org.elasticsearch.painless.AnalyzerCaster;
-import org.elasticsearch.painless.DefBootstrap;
+import org.elasticsearch.painless.MethodWriter;
 import org.elasticsearch.painless.Operation;
-import org.elasticsearch.painless.Locals;
 import org.objectweb.asm.Label;
+import org.objectweb.asm.Opcodes;
+import org.objectweb.asm.Type;
 
 import java.util.Objects;
 import java.util.Set;
 
-import org.elasticsearch.painless.MethodWriter;
-import org.objectweb.asm.Opcodes;
-
 /**
  * Represents a unary math expression.
  */
@@ -43,7 +43,7 @@ public final class EUnary extends AExpression {
     private final Operation operation;
     private AExpression child;
 
-    private Type promote;
+    private Class<?> promote;
     private boolean originallyExplicit = false; // record whether there was originally an explicit cast
 
     public EUnary(Location location, Operation operation, AExpression child) {
@@ -76,7 +76,7 @@ public final class EUnary extends AExpression {
     }
 
     void analyzeNot(Locals variables) {
-        child.expected = variables.getDefinition().booleanType;
+        child.expected = boolean.class;
         child.analyze(variables);
         child = child.cast(variables);
 
@@ -84,34 +84,32 @@ public final class EUnary extends AExpression {
             constant = !(boolean)child.constant;
         }
 
-        actual = variables.getDefinition().booleanType;
+        actual = boolean.class;
     }
 
     void analyzeBWNot(Locals variables) {
         child.analyze(variables);
 
-        promote = variables.getDefinition().ClassToType(AnalyzerCaster.promoteNumeric(Definition.TypeToClass(child.actual), false));
+        promote = AnalyzerCaster.promoteNumeric(child.actual, false);
 
         if (promote == null) {
-            throw createError(new ClassCastException("Cannot apply not [~] to type [" + child.actual.name + "]."));
+            throw createError(new ClassCastException("Cannot apply not [~] to type [" + Definition.ClassToName(child.actual) + "]."));
         }
 
         child.expected = promote;
         child = child.cast(variables);
 
         if (child.constant != null) {
-            Class<?> sort = promote.clazz;
-
-            if (sort == int.class) {
+            if (promote == int.class) {
                 constant = ~(int)child.constant;
-            } else if (sort == long.class) {
+            } else if (promote == long.class) {
                 constant = ~(long)child.constant;
             } else {
                 throw createError(new IllegalStateException("Illegal tree structure."));
             }
         }
 
-        if (promote.dynamic && expected != null) {
+        if (promote == def.class && expected != null) {
             actual = expected;
         } else {
             actual = promote;
@@ -121,32 +119,30 @@ public final class EUnary extends AExpression {
     void analyzerAdd(Locals variables) {
         child.analyze(variables);
 
-        promote = variables.getDefinition().ClassToType(AnalyzerCaster.promoteNumeric(Definition.TypeToClass(child.actual), true));
+        promote = AnalyzerCaster.promoteNumeric(child.actual, true);
 
         if (promote == null) {
-            throw createError(new ClassCastException("Cannot apply positive [+] to type [" + child.actual.name + "]."));
+            throw createError(new ClassCastException("Cannot apply positive [+] to type [" + Definition.ClassToName(child.actual) + "]."));
         }
 
         child.expected = promote;
         child = child.cast(variables);
 
         if (child.constant != null) {
-            Class<?> sort = promote.clazz;
-
-            if (sort == int.class) {
+            if (promote == int.class) {
                 constant = +(int)child.constant;
-            } else if (sort == long.class) {
+            } else if (promote == long.class) {
                 constant = +(long)child.constant;
-            } else if (sort == float.class) {
+            } else if (promote == float.class) {
                 constant = +(float)child.constant;
-            } else if (sort == double.class) {
+            } else if (promote == double.class) {
                 constant = +(double)child.constant;
             } else {
                 throw createError(new IllegalStateException("Illegal tree structure."));
             }
         }
 
-        if (promote.dynamic && expected != null) {
+        if (promote == def.class && expected != null) {
             actual = expected;
         } else {
             actual = promote;
@@ -156,32 +152,30 @@ public final class EUnary extends AExpression {
     void analyzerSub(Locals variables) {
         child.analyze(variables);
 
-        promote = variables.getDefinition().ClassToType(AnalyzerCaster.promoteNumeric(Definition.TypeToClass(child.actual), true));
+        promote = AnalyzerCaster.promoteNumeric(child.actual, true);
 
         if (promote == null) {
-            throw createError(new ClassCastException("Cannot apply negative [-] to type [" + child.actual.name + "]."));
+            throw createError(new ClassCastException("Cannot apply negative [-] to type [" + Definition.ClassToName(child.actual) + "]."));
         }
 
         child.expected = promote;
         child = child.cast(variables);
 
         if (child.constant != null) {
-            Class<?> sort = promote.clazz;
-
-            if (sort == int.class) {
+            if (promote == int.class) {
                 constant = -(int)child.constant;
-            } else if (sort == long.class) {
+            } else if (promote == long.class) {
                 constant = -(long)child.constant;
-            } else if (sort == float.class) {
+            } else if (promote == float.class) {
                 constant = -(float)child.constant;
-            } else if (sort == double.class) {
+            } else if (promote == double.class) {
                 constant = -(double)child.constant;
             } else {
                 throw createError(new IllegalStateException("Illegal tree structure."));
             }
         }
 
-        if (promote.dynamic && expected != null) {
+        if (promote == def.class && expected != null) {
             actual = expected;
         } else {
             actual = promote;
@@ -205,7 +199,6 @@ public final class EUnary extends AExpression {
             writer.push(true);
             writer.mark(end);
         } else {
-            Class<?> sort = promote.clazz;
             child.write(writer, globals);
 
             // Def calls adopt the wanted return value. If there was a narrowing cast,
@@ -216,31 +209,34 @@ public final class EUnary extends AExpression {
                 defFlags |= DefBootstrap.OPERATOR_EXPLICIT_CAST;
             }
 
+            Type actualType = MethodWriter.getType(actual);
+            Type childType = MethodWriter.getType(child.actual);
+
             if (operation == Operation.BWNOT) {
-                if (promote.dynamic) {
-                    org.objectweb.asm.Type descriptor = org.objectweb.asm.Type.getMethodType(actual.type, child.actual.type);
+                if (promote == def.class) {
+                    org.objectweb.asm.Type descriptor = org.objectweb.asm.Type.getMethodType(actualType, childType);
                     writer.invokeDefCall("not", descriptor, DefBootstrap.UNARY_OPERATOR, defFlags);
                 } else {
-                    if (sort == int.class) {
+                    if (promote == int.class) {
                         writer.push(-1);
-                    } else if (sort == long.class) {
+                    } else if (promote == long.class) {
                         writer.push(-1L);
                     } else {
                         throw createError(new IllegalStateException("Illegal tree structure."));
                     }
 
-                    writer.math(MethodWriter.XOR, actual.type);
+                    writer.math(MethodWriter.XOR, actualType);
                 }
             } else if (operation == Operation.SUB) {
-                if (promote.dynamic) {
-                    org.objectweb.asm.Type descriptor = org.objectweb.asm.Type.getMethodType(actual.type, child.actual.type);
+                if (promote == def.class) {
+                    org.objectweb.asm.Type descriptor = org.objectweb.asm.Type.getMethodType(actualType, childType);
                     writer.invokeDefCall("neg", descriptor, DefBootstrap.UNARY_OPERATOR, defFlags);
                 } else {
-                    writer.math(MethodWriter.NEG, actual.type);
+                    writer.math(MethodWriter.NEG, actualType);
                 }
             } else if (operation == Operation.ADD) {
-                if (promote.dynamic) {
-                    org.objectweb.asm.Type descriptor = org.objectweb.asm.Type.getMethodType(actual.type, child.actual.type);
+                if (promote == def.class) {
+                    org.objectweb.asm.Type descriptor = org.objectweb.asm.Type.getMethodType(actualType, childType);
                     writer.invokeDefCall("plus", descriptor, DefBootstrap.UNARY_OPERATOR, defFlags);
                 }
             } else {

+ 6 - 6
modules/lang-painless/src/main/java/org/elasticsearch/painless/node/EVariable.java

@@ -19,7 +19,7 @@
 
 package org.elasticsearch.painless.node;
 
-import org.elasticsearch.painless.Definition.Type;
+import org.elasticsearch.painless.Definition;
 import org.elasticsearch.painless.Globals;
 import org.elasticsearch.painless.Locals;
 import org.elasticsearch.painless.Locals.Variable;
@@ -58,12 +58,12 @@ public final class EVariable extends AStoreable {
             throw createError(new IllegalArgumentException("Variable [" + variable.name + "] is read-only."));
         }
 
-        actual = variable.type;
+        actual = Definition.TypeToClass(variable.type);
     }
 
     @Override
     void write(MethodWriter writer, Globals globals) {
-        writer.visitVarInsn(actual.type.getOpcode(Opcodes.ILOAD), variable.getSlot());
+        writer.visitVarInsn(MethodWriter.getType(actual).getOpcode(Opcodes.ILOAD), variable.getSlot());
     }
 
     @Override
@@ -77,7 +77,7 @@ public final class EVariable extends AStoreable {
     }
 
     @Override
-    void updateActual(Type actual) {
+    void updateActual(Class<?> actual) {
         throw new IllegalArgumentException("Illegal tree structure.");
     }
 
@@ -88,12 +88,12 @@ public final class EVariable extends AStoreable {
 
     @Override
     void load(MethodWriter writer, Globals globals) {
-        writer.visitVarInsn(actual.type.getOpcode(Opcodes.ILOAD), variable.getSlot());
+        writer.visitVarInsn(MethodWriter.getType(actual).getOpcode(Opcodes.ILOAD), variable.getSlot());
     }
 
     @Override
     void store(MethodWriter writer, Globals globals) {
-        writer.visitVarInsn(actual.type.getOpcode(Opcodes.ISTORE), variable.getSlot());
+        writer.visitVarInsn(MethodWriter.getType(actual).getOpcode(Opcodes.ISTORE), variable.getSlot());
     }
 
     @Override

+ 11 - 9
modules/lang-painless/src/main/java/org/elasticsearch/painless/node/PBrace.java

@@ -19,7 +19,8 @@
 
 package org.elasticsearch.painless.node;
 
-import org.elasticsearch.painless.Definition.Type;
+import org.elasticsearch.painless.Definition;
+import org.elasticsearch.painless.Definition.def;
 import org.elasticsearch.painless.Globals;
 import org.elasticsearch.painless.Locals;
 import org.elasticsearch.painless.Location;
@@ -57,16 +58,17 @@ public final class PBrace extends AStoreable {
         prefix.expected = prefix.actual;
         prefix = prefix.cast(locals);
 
-        if (prefix.actual.dimensions > 0) {
+        if (prefix.actual.isArray()) {
             sub = new PSubBrace(location, prefix.actual, index);
-        } else if (prefix.actual.dynamic) {
+        } else if (prefix.actual == def.class) {
             sub = new PSubDefArray(location, index);
-        } else if (Map.class.isAssignableFrom(prefix.actual.clazz)) {
-            sub = new PSubMapShortcut(location, prefix.actual.struct, index);
-        } else if (List.class.isAssignableFrom(prefix.actual.clazz)) {
-            sub = new PSubListShortcut(location, prefix.actual.struct, index);
+        } else if (Map.class.isAssignableFrom(prefix.actual)) {
+            sub = new PSubMapShortcut(location, locals.getDefinition().ClassToType(prefix.actual).struct, index);
+        } else if (List.class.isAssignableFrom(prefix.actual)) {
+            sub = new PSubListShortcut(location, locals.getDefinition().ClassToType(prefix.actual).struct, index);
         } else {
-            throw createError(new IllegalArgumentException("Illegal array access on type [" + prefix.actual.name + "]."));
+            throw createError(
+                new IllegalArgumentException("Illegal array access on type [" + Definition.ClassToName(prefix.actual) + "]."));
         }
 
         sub.write = write;
@@ -89,7 +91,7 @@ public final class PBrace extends AStoreable {
     }
 
     @Override
-    void updateActual(Type actual) {
+    void updateActual(Class<?> actual) {
         sub.updateActual(actual);
         this.actual = actual;
     }

+ 6 - 5
modules/lang-painless/src/main/java/org/elasticsearch/painless/node/PCallInvoke.java

@@ -23,6 +23,7 @@ import org.elasticsearch.painless.Definition;
 import org.elasticsearch.painless.Definition.Method;
 import org.elasticsearch.painless.Definition.MethodKey;
 import org.elasticsearch.painless.Definition.Struct;
+import org.elasticsearch.painless.Definition.def;
 import org.elasticsearch.painless.Globals;
 import org.elasticsearch.painless.Locals;
 import org.elasticsearch.painless.Location;
@@ -66,14 +67,14 @@ public final class PCallInvoke extends AExpression {
         prefix.expected = prefix.actual;
         prefix = prefix.cast(locals);
 
-        if (prefix.actual.dimensions > 0) {
+        if (prefix.actual.isArray()) {
             throw createError(new IllegalArgumentException("Illegal call [" + name + "] on array type."));
         }
 
-        Struct struct = prefix.actual.struct;
+        Struct struct = locals.getDefinition().ClassToType(prefix.actual).struct;
 
-        if (prefix.actual.clazz.isPrimitive()) {
-            struct = locals.getDefinition().getBoxedType(prefix.actual).struct;
+        if (prefix.actual.isPrimitive()) {
+            struct = locals.getDefinition().ClassToType(Definition.getBoxedType(prefix.actual)).struct;
         }
 
         MethodKey methodKey = new MethodKey(name, arguments.size());
@@ -81,7 +82,7 @@ public final class PCallInvoke extends AExpression {
 
         if (method != null) {
             sub = new PSubCallInvoke(location, method, prefix.actual, arguments);
-        } else if (prefix.actual.dynamic) {
+        } else if (prefix.actual == def.class) {
             sub = new PSubDefCall(location, name, arguments);
         } else {
             throw createError(new IllegalArgumentException(

+ 11 - 10
modules/lang-painless/src/main/java/org/elasticsearch/painless/node/PField.java

@@ -23,7 +23,7 @@ import org.elasticsearch.painless.Definition;
 import org.elasticsearch.painless.Definition.Field;
 import org.elasticsearch.painless.Definition.Method;
 import org.elasticsearch.painless.Definition.Struct;
-import org.elasticsearch.painless.Definition.Type;
+import org.elasticsearch.painless.Definition.def;
 import org.elasticsearch.painless.Globals;
 import org.elasticsearch.painless.Locals;
 import org.elasticsearch.painless.Location;
@@ -62,12 +62,12 @@ public final class PField extends AStoreable {
         prefix.expected = prefix.actual;
         prefix = prefix.cast(locals);
 
-        if (prefix.actual.dimensions > 0) {
-            sub = new PSubArrayLength(location, prefix.actual.name, value);
-        } else if (prefix.actual.dynamic) {
+        if (prefix.actual.isArray()) {
+            sub = new PSubArrayLength(location, Definition.ClassToName(prefix.actual), value);
+        } else if (prefix.actual == def.class) {
             sub = new PSubDefField(location, value);
         } else {
-            Struct struct = prefix.actual.struct;
+            Struct struct = locals.getDefinition().ClassToType(prefix.actual).struct;
             Field field = prefix instanceof EStatic ? struct.staticMembers.get(value) : struct.members.get(value);
 
             if (field != null) {
@@ -85,16 +85,16 @@ public final class PField extends AStoreable {
                     new Definition.MethodKey("set" + Character.toUpperCase(value.charAt(0)) + value.substring(1), 1));
 
                 if (getter != null || setter != null) {
-                    sub = new PSubShortcut(location, value, prefix.actual.name, getter, setter);
+                    sub = new PSubShortcut(location, value, Definition.ClassToName(prefix.actual), getter, setter);
                 } else {
                     EConstant index = new EConstant(location, value);
                     index.analyze(locals);
 
-                    if (Map.class.isAssignableFrom(prefix.actual.clazz)) {
+                    if (Map.class.isAssignableFrom(prefix.actual)) {
                         sub = new PSubMapShortcut(location, struct, index);
                     }
 
-                    if (List.class.isAssignableFrom(prefix.actual.clazz)) {
+                    if (List.class.isAssignableFrom(prefix.actual)) {
                         sub = new PSubListShortcut(location, struct, index);
                     }
                 }
@@ -102,7 +102,8 @@ public final class PField extends AStoreable {
         }
 
         if (sub == null) {
-            throw createError(new IllegalArgumentException("Unknown field [" + value + "] for type [" + prefix.actual.name + "]."));
+            throw createError(new IllegalArgumentException(
+                "Unknown field [" + value + "] for type [" + Definition.ClassToName(prefix.actual) + "]."));
         }
 
         if (nullSafe) {
@@ -129,7 +130,7 @@ public final class PField extends AStoreable {
     }
 
     @Override
-    void updateActual(Type actual) {
+    void updateActual(Class<?> actual) {
         sub.updateActual(actual);
         this.actual = actual;
     }

+ 2 - 4
modules/lang-painless/src/main/java/org/elasticsearch/painless/node/PSubArrayLength.java

@@ -19,8 +19,6 @@
 
 package org.elasticsearch.painless.node;
 
-import org.elasticsearch.painless.Definition;
-import org.elasticsearch.painless.Definition.Type;
 import org.elasticsearch.painless.Globals;
 import org.elasticsearch.painless.Locals;
 import org.elasticsearch.painless.Location;
@@ -56,7 +54,7 @@ final class PSubArrayLength extends AStoreable {
                 throw createError(new IllegalArgumentException("Cannot write to read-only field [length] for an array."));
             }
 
-            actual = locals.getDefinition().intType;
+            actual = int.class;
         } else {
             throw createError(new IllegalArgumentException("Field [" + value + "] does not exist for type [" + type + "]."));
         }
@@ -79,7 +77,7 @@ final class PSubArrayLength extends AStoreable {
     }
 
     @Override
-    void updateActual(Type actual) {
+    void updateActual(Class<?> actual) {
         throw new IllegalStateException("Illegal tree structure.");
     }
 

+ 8 - 10
modules/lang-painless/src/main/java/org/elasticsearch/painless/node/PSubBrace.java

@@ -19,8 +19,6 @@
 
 package org.elasticsearch.painless.node;
 
-import org.elasticsearch.painless.Definition;
-import org.elasticsearch.painless.Definition.Type;
 import org.elasticsearch.painless.Globals;
 import org.elasticsearch.painless.Locals;
 import org.elasticsearch.painless.Location;
@@ -34,13 +32,13 @@ import java.util.Set;
  */
 final class PSubBrace extends AStoreable {
 
-    private final Type type;
+    private final Class<?> clazz;
     private AExpression index;
 
-    PSubBrace(Location location, Type type, AExpression index) {
+    PSubBrace(Location location, Class<?> clazz, AExpression index) {
         super(location);
 
-        this.type = Objects.requireNonNull(type);
+        this.clazz = Objects.requireNonNull(clazz);
         this.index = Objects.requireNonNull(index);
     }
 
@@ -51,11 +49,11 @@ final class PSubBrace extends AStoreable {
 
     @Override
     void analyze(Locals locals) {
-        index.expected = locals.getDefinition().intType;
+        index.expected = int.class;
         index.analyze(locals);
         index = index.cast(locals);
 
-        actual = locals.getDefinition().getType(type.struct, type.dimensions - 1);
+        actual = clazz.getComponentType();
     }
 
     @Override
@@ -75,7 +73,7 @@ final class PSubBrace extends AStoreable {
     }
 
     @Override
-    void updateActual(Type actual) {
+    void updateActual(Class<?> actual) {
         throw createError(new IllegalStateException("Illegal tree structure."));
     }
 
@@ -88,13 +86,13 @@ final class PSubBrace extends AStoreable {
     @Override
     void load(MethodWriter writer, Globals globals) {
         writer.writeDebugInfo(location);
-        writer.arrayLoad(actual.type);
+        writer.arrayLoad(MethodWriter.getType(actual));
     }
 
     @Override
     void store(MethodWriter writer, Globals globals) {
         writer.writeDebugInfo(location);
-        writer.arrayStore(actual.type);
+        writer.arrayStore(MethodWriter.getType(actual));
     }
 
     @Override

+ 7 - 7
modules/lang-painless/src/main/java/org/elasticsearch/painless/node/PSubCallInvoke.java

@@ -19,8 +19,8 @@
 
 package org.elasticsearch.painless.node;
 
+import org.elasticsearch.painless.Definition;
 import org.elasticsearch.painless.Definition.Method;
-import org.elasticsearch.painless.Definition.Type;
 import org.elasticsearch.painless.Globals;
 import org.elasticsearch.painless.Locals;
 import org.elasticsearch.painless.Location;
@@ -36,10 +36,10 @@ import java.util.Set;
 final class PSubCallInvoke extends AExpression {
 
     private final Method method;
-    private final Type box;
+    private final Class<?> box;
     private final List<AExpression> arguments;
 
-    PSubCallInvoke(Location location, Method method, Type box, List<AExpression> arguments) {
+    PSubCallInvoke(Location location, Method method, Class<?> box, List<AExpression> arguments) {
         super(location);
 
         this.method = Objects.requireNonNull(method);
@@ -57,22 +57,22 @@ final class PSubCallInvoke extends AExpression {
         for (int argument = 0; argument < arguments.size(); ++argument) {
             AExpression expression = arguments.get(argument);
 
-            expression.expected = method.arguments.get(argument);
+            expression.expected = Definition.TypeToClass(method.arguments.get(argument));
             expression.internal = true;
             expression.analyze(locals);
             arguments.set(argument, expression.cast(locals));
         }
 
         statement = true;
-        actual = method.rtn;
+        actual = Definition.TypeToClass(method.rtn);
     }
 
     @Override
     void write(MethodWriter writer, Globals globals) {
         writer.writeDebugInfo(location);
 
-        if (box.clazz.isPrimitive()) {
-            writer.box(box.type);
+        if (box.isPrimitive()) {
+            writer.box(MethodWriter.getType(box));
         }
 
         for (AExpression argument : arguments) {

+ 11 - 11
modules/lang-painless/src/main/java/org/elasticsearch/painless/node/PSubDefArray.java

@@ -20,12 +20,12 @@
 package org.elasticsearch.painless.node;
 
 import org.elasticsearch.painless.DefBootstrap;
-import org.elasticsearch.painless.Definition;
-import org.elasticsearch.painless.Definition.Type;
+import org.elasticsearch.painless.Definition.def;
 import org.elasticsearch.painless.Globals;
 import org.elasticsearch.painless.Locals;
 import org.elasticsearch.painless.Location;
 import org.elasticsearch.painless.MethodWriter;
+import org.objectweb.asm.Type;
 
 import java.util.Objects;
 import java.util.Set;
@@ -53,7 +53,7 @@ final class PSubDefArray extends AStoreable {
         index.expected = index.actual;
         index = index.cast(locals);
 
-        actual = expected == null || explicit ? locals.getDefinition().DefType : expected;
+        actual = expected == null || explicit ? def.class : expected;
     }
 
     @Override
@@ -73,7 +73,7 @@ final class PSubDefArray extends AStoreable {
     }
 
     @Override
-    void updateActual(Type actual) {
+    void updateActual(Class<?> actual) {
         this.actual = actual;
     }
 
@@ -82,8 +82,8 @@ final class PSubDefArray extends AStoreable {
         // Current stack:                                                                    def
         writer.dup();                                                                     // def, def
         index.write(writer, globals);                                                     // def, def, unnormalized_index
-        org.objectweb.asm.Type methodType = org.objectweb.asm.Type.getMethodType(
-                index.actual.type, org.objectweb.asm.Type.getType(Object.class), index.actual.type);
+        Type methodType = Type.getMethodType(
+                MethodWriter.getType(index.actual), Type.getType(Object.class), MethodWriter.getType(index.actual));
         writer.invokeDefCall("normalizeIndex", methodType, DefBootstrap.INDEX_NORMALIZE); // def, normalized_index
     }
 
@@ -91,8 +91,8 @@ final class PSubDefArray extends AStoreable {
     void load(MethodWriter writer, Globals globals) {
         writer.writeDebugInfo(location);
 
-        org.objectweb.asm.Type methodType =
-            org.objectweb.asm.Type.getMethodType(actual.type, org.objectweb.asm.Type.getType(Object.class), index.actual.type);
+        Type methodType =
+            Type.getMethodType(MethodWriter.getType(actual), Type.getType(Object.class), MethodWriter.getType(index.actual));
         writer.invokeDefCall("arrayLoad", methodType, DefBootstrap.ARRAY_LOAD);
     }
 
@@ -100,9 +100,9 @@ final class PSubDefArray extends AStoreable {
     void store(MethodWriter writer, Globals globals) {
         writer.writeDebugInfo(location);
 
-        org.objectweb.asm.Type methodType =
-            org.objectweb.asm.Type.getMethodType(
-                org.objectweb.asm.Type.getType(void.class), org.objectweb.asm.Type.getType(Object.class), index.actual.type, actual.type);
+        Type methodType =
+            Type.getMethodType(
+                Type.getType(void.class), Type.getType(Object.class), MethodWriter.getType(index.actual), MethodWriter.getType(actual));
         writer.invokeDefCall("arrayStore", methodType, DefBootstrap.ARRAY_STORE);
     }
 

+ 6 - 4
modules/lang-painless/src/main/java/org/elasticsearch/painless/node/PSubDefCall.java

@@ -20,6 +20,8 @@
 package org.elasticsearch.painless.node;
 
 import org.elasticsearch.painless.DefBootstrap;
+
+import org.elasticsearch.painless.Definition.def;
 import org.elasticsearch.painless.Globals;
 import org.elasticsearch.painless.Locals;
 import org.elasticsearch.painless.Location;
@@ -75,7 +77,7 @@ final class PSubDefCall extends AExpression {
                 totalCaptures += lambda.getCaptureCount();
             }
 
-            if (expression.actual.clazz == void.class) {
+            if (expression.actual == void.class) {
                 throw createError(new IllegalArgumentException("Argument(s) cannot be of [void] type when calling method [" + name + "]."));
             }
 
@@ -83,7 +85,7 @@ final class PSubDefCall extends AExpression {
             arguments.set(argument, expression.cast(locals));
         }
 
-        actual = expected == null || explicit ? locals.getDefinition().DefType : expected;
+        actual = expected == null || explicit ? def.class : expected;
     }
 
     @Override
@@ -97,7 +99,7 @@ final class PSubDefCall extends AExpression {
 
         // append each argument
         for (AExpression argument : arguments) {
-            parameterTypes.add(argument.actual.type);
+            parameterTypes.add(MethodWriter.getType(argument.actual));
 
             if (argument instanceof ILambda) {
                 ILambda lambda = (ILambda) argument;
@@ -108,7 +110,7 @@ final class PSubDefCall extends AExpression {
         }
 
         // create method type from return value and arguments
-        Type methodType = Type.getMethodType(actual.type, parameterTypes.toArray(new Type[0]));
+        Type methodType = Type.getMethodType(MethodWriter.getType(actual), parameterTypes.toArray(new Type[0]));
 
         List<Object> args = new ArrayList<>();
         args.add(recipe.toString());

+ 6 - 6
modules/lang-painless/src/main/java/org/elasticsearch/painless/node/PSubDefField.java

@@ -20,7 +20,7 @@
 package org.elasticsearch.painless.node;
 
 import org.elasticsearch.painless.DefBootstrap;
-import org.elasticsearch.painless.Definition.Type;
+import org.elasticsearch.painless.Definition.def;
 import org.elasticsearch.painless.Globals;
 import org.elasticsearch.painless.Locals;
 import org.elasticsearch.painless.Location;
@@ -49,7 +49,7 @@ final class PSubDefField extends AStoreable {
 
     @Override
     void analyze(Locals locals) {
-        actual = expected == null || explicit ? locals.getDefinition().DefType : expected;
+        actual = expected == null || explicit ? def.class : expected;
     }
 
     @Override
@@ -57,7 +57,7 @@ final class PSubDefField extends AStoreable {
         writer.writeDebugInfo(location);
 
         org.objectweb.asm.Type methodType =
-            org.objectweb.asm.Type.getMethodType(actual.type, org.objectweb.asm.Type.getType(Object.class));
+            org.objectweb.asm.Type.getMethodType(MethodWriter.getType(actual), org.objectweb.asm.Type.getType(Object.class));
         writer.invokeDefCall(value, methodType, DefBootstrap.LOAD);
     }
 
@@ -72,7 +72,7 @@ final class PSubDefField extends AStoreable {
     }
 
     @Override
-    void updateActual(Type actual) {
+    void updateActual(Class<?> actual) {
         this.actual = actual;
     }
 
@@ -86,7 +86,7 @@ final class PSubDefField extends AStoreable {
         writer.writeDebugInfo(location);
 
         org.objectweb.asm.Type methodType =
-            org.objectweb.asm.Type.getMethodType(actual.type, org.objectweb.asm.Type.getType(Object.class));
+            org.objectweb.asm.Type.getMethodType(MethodWriter.getType(actual), org.objectweb.asm.Type.getType(Object.class));
         writer.invokeDefCall(value, methodType, DefBootstrap.LOAD);
     }
 
@@ -95,7 +95,7 @@ final class PSubDefField extends AStoreable {
         writer.writeDebugInfo(location);
 
         org.objectweb.asm.Type methodType = org.objectweb.asm.Type.getMethodType(
-            org.objectweb.asm.Type.getType(void.class), org.objectweb.asm.Type.getType(Object.class), actual.type);
+            org.objectweb.asm.Type.getType(void.class), org.objectweb.asm.Type.getType(Object.class), MethodWriter.getType(actual));
         writer.invokeDefCall(value, methodType, DefBootstrap.STORE);
     }
 

+ 3 - 3
modules/lang-painless/src/main/java/org/elasticsearch/painless/node/PSubField.java

@@ -19,8 +19,8 @@
 
 package org.elasticsearch.painless.node;
 
+import org.elasticsearch.painless.Definition;
 import org.elasticsearch.painless.Definition.Field;
-import org.elasticsearch.painless.Definition.Type;
 import org.elasticsearch.painless.Globals;
 import org.elasticsearch.painless.Locals;
 import org.elasticsearch.painless.Location;
@@ -55,7 +55,7 @@ final class PSubField extends AStoreable {
                  "Cannot write to read-only field [" + field.name + "] for type [" + field.type.name + "]."));
          }
 
-        actual = field.type;
+        actual = Definition.TypeToClass(field.type);
     }
 
     @Override
@@ -80,7 +80,7 @@ final class PSubField extends AStoreable {
     }
 
     @Override
-    void updateActual(Type actual) {
+    void updateActual(Class<?> actual) {
         throw new IllegalArgumentException("Illegal tree structure.");
     }
 

+ 3 - 4
modules/lang-painless/src/main/java/org/elasticsearch/painless/node/PSubListShortcut.java

@@ -22,7 +22,6 @@ package org.elasticsearch.painless.node;
 import org.elasticsearch.painless.Definition;
 import org.elasticsearch.painless.Definition.Method;
 import org.elasticsearch.painless.Definition.Struct;
-import org.elasticsearch.painless.Definition.Type;
 import org.elasticsearch.painless.Globals;
 import org.elasticsearch.painless.Locals;
 import org.elasticsearch.painless.Location;
@@ -75,11 +74,11 @@ final class PSubListShortcut extends AStoreable {
         }
 
         if ((read || write) && (!read || getter != null) && (!write || setter != null)) {
-            index.expected = locals.getDefinition().intType;
+            index.expected = int.class;
             index.analyze(locals);
             index = index.cast(locals);
 
-            actual = setter != null ? setter.arguments.get(1) : getter.rtn;
+            actual = setter != null ? Definition.TypeToClass(setter.arguments.get(1)) : Definition.TypeToClass(getter.rtn);
         } else {
             throw createError(new IllegalArgumentException("Illegal list shortcut for type [" + struct.name + "]."));
         }
@@ -102,7 +101,7 @@ final class PSubListShortcut extends AStoreable {
     }
 
     @Override
-    void updateActual(Type actual) {
+    void updateActual(Class<?> actual) {
         throw new IllegalArgumentException("Illegal tree structure.");
     }
 

+ 7 - 8
modules/lang-painless/src/main/java/org/elasticsearch/painless/node/PSubMapShortcut.java

@@ -20,18 +20,16 @@
 package org.elasticsearch.painless.node;
 
 import org.elasticsearch.painless.Definition;
+import org.elasticsearch.painless.Definition.Method;
 import org.elasticsearch.painless.Definition.Struct;
-import org.elasticsearch.painless.Definition.Type;
 import org.elasticsearch.painless.Globals;
+import org.elasticsearch.painless.Locals;
 import org.elasticsearch.painless.Location;
-import org.elasticsearch.painless.Definition.Method;
+import org.elasticsearch.painless.MethodWriter;
 
 import java.util.Objects;
 import java.util.Set;
 
-import org.elasticsearch.painless.Locals;
-import org.elasticsearch.painless.MethodWriter;
-
 /**
  * Represents a map load/store shortcut. (Internal only.)
  */
@@ -74,11 +72,12 @@ final class PSubMapShortcut extends AStoreable {
         }
 
         if ((read || write) && (!read || getter != null) && (!write || setter != null)) {
-            index.expected = setter != null ? setter.arguments.get(0) : getter.arguments.get(0);
+            index.expected = setter != null ?
+                    Definition.TypeToClass(setter.arguments.get(0)) : Definition.TypeToClass(getter.arguments.get(0));
             index.analyze(locals);
             index = index.cast(locals);
 
-            actual = setter != null ? setter.arguments.get(1) : getter.rtn;
+            actual = setter != null ? Definition.TypeToClass(setter.arguments.get(1)) : Definition.TypeToClass(getter.rtn);
         } else {
             throw createError(new IllegalArgumentException("Illegal map shortcut for type [" + struct.name + "]."));
         }
@@ -108,7 +107,7 @@ final class PSubMapShortcut extends AStoreable {
     }
 
     @Override
-    void updateActual(Type actual) {
+    void updateActual(Class<?> actual) {
         throw new IllegalArgumentException("Illegal tree structure.");
     }
 

+ 1 - 1
modules/lang-painless/src/main/java/org/elasticsearch/painless/node/PSubNullSafeCallInvoke.java

@@ -52,7 +52,7 @@ public class PSubNullSafeCallInvoke extends AExpression {
     void analyze(Locals locals) {
         guarded.analyze(locals);
         actual = guarded.actual;
-        if (actual.clazz.isPrimitive()) {
+        if (actual.isPrimitive()) {
             throw new IllegalArgumentException("Result of null safe operator must be nullable");
         }
     }

+ 2 - 3
modules/lang-painless/src/main/java/org/elasticsearch/painless/node/PSubNullSafeField.java

@@ -19,7 +19,6 @@
 
 package org.elasticsearch.painless.node;
 
-import org.elasticsearch.painless.Definition.Type;
 import org.elasticsearch.painless.Globals;
 import org.elasticsearch.painless.Locals;
 import org.elasticsearch.painless.Location;
@@ -52,7 +51,7 @@ public class PSubNullSafeField extends AStoreable {
         guarded.read = read;
         guarded.analyze(locals);
         actual = guarded.actual;
-        if (actual.clazz.isPrimitive()) {
+        if (actual.isPrimitive()) {
             throw new IllegalArgumentException("Result of null safe operator must be nullable");
         }
     }
@@ -69,7 +68,7 @@ public class PSubNullSafeField extends AStoreable {
     }
 
     @Override
-    void updateActual(Type actual) {
+    void updateActual(Class<?> actual) {
         guarded.updateActual(actual);
     }
 

+ 3 - 3
modules/lang-painless/src/main/java/org/elasticsearch/painless/node/PSubShortcut.java

@@ -19,8 +19,8 @@
 
 package org.elasticsearch.painless.node;
 
+import org.elasticsearch.painless.Definition;
 import org.elasticsearch.painless.Definition.Method;
-import org.elasticsearch.painless.Definition.Type;
 import org.elasticsearch.painless.Globals;
 import org.elasticsearch.painless.Locals;
 import org.elasticsearch.painless.Location;
@@ -69,7 +69,7 @@ final class PSubShortcut extends AStoreable {
         }
 
         if ((getter != null || setter != null) && (!read || getter != null) && (!write || setter != null)) {
-            actual = setter != null ? setter.arguments.get(0) : getter.rtn;
+            actual = setter != null ? Definition.TypeToClass(setter.arguments.get(0)) : Definition.TypeToClass(getter.rtn);
         } else {
             throw createError(new IllegalArgumentException("Illegal shortcut on field [" + value + "] for type [" + type + "]."));
         }
@@ -97,7 +97,7 @@ final class PSubShortcut extends AStoreable {
     }
 
     @Override
-    void updateActual(Type actual) {
+    void updateActual(Class<?> actual) {
         throw new IllegalArgumentException("Illegal tree structure.");
     }
 

+ 2 - 1
modules/lang-painless/src/main/java/org/elasticsearch/painless/node/SDeclaration.java

@@ -19,6 +19,7 @@
 
 package org.elasticsearch.painless.node;
 
+import org.elasticsearch.painless.Definition;
 import org.elasticsearch.painless.Definition.Type;
 import org.elasticsearch.painless.Globals;
 import org.elasticsearch.painless.Locals;
@@ -69,7 +70,7 @@ public final class SDeclaration extends AStatement {
         }
 
         if (expression != null) {
-            expression.expected = type;
+            expression.expected = Definition.TypeToClass(type);
             expression.analyze(locals);
             expression = expression.cast(locals);
         }

+ 1 - 2
modules/lang-painless/src/main/java/org/elasticsearch/painless/node/SDo.java

@@ -19,7 +19,6 @@
 
 package org.elasticsearch.painless.node;
 
-import org.elasticsearch.painless.Definition;
 import org.elasticsearch.painless.Globals;
 import org.elasticsearch.painless.Locals;
 import org.elasticsearch.painless.Location;
@@ -73,7 +72,7 @@ public final class SDo extends AStatement {
             throw createError(new IllegalArgumentException("Extraneous do while loop."));
         }
 
-        condition.expected = locals.getDefinition().booleanType;
+        condition.expected = boolean.class;
         condition.analyze(locals);
         condition = condition.cast(locals);
 

+ 5 - 3
modules/lang-painless/src/main/java/org/elasticsearch/painless/node/SEach.java

@@ -19,7 +19,9 @@
 
 package org.elasticsearch.painless.node;
 
+import org.elasticsearch.painless.Definition;
 import org.elasticsearch.painless.Definition.Type;
+import org.elasticsearch.painless.Definition.def;
 import org.elasticsearch.painless.Globals;
 import org.elasticsearch.painless.Locals;
 import org.elasticsearch.painless.Locals.Variable;
@@ -78,12 +80,12 @@ public class SEach extends AStatement {
         locals = Locals.newLocalScope(locals);
         Variable variable = locals.addVariable(location, type, name, true);
 
-        if (expression.actual.dimensions > 0) {
+        if (expression.actual.isArray()) {
             sub = new SSubEachArray(location, variable, expression, block);
-        } else if (expression.actual.dynamic || Iterable.class.isAssignableFrom(expression.actual.clazz)) {
+        } else if (expression.actual == def.class || Iterable.class.isAssignableFrom(expression.actual)) {
             sub = new SSubEachIterable(location, variable, expression, block);
         } else {
-            throw createError(new IllegalArgumentException("Illegal for each type [" + expression.actual.name + "]."));
+            throw createError(new IllegalArgumentException("Illegal for each type [" + Definition.ClassToName(expression.actual) + "]."));
         }
 
         sub.analyze(locals);

+ 4 - 3
modules/lang-painless/src/main/java/org/elasticsearch/painless/node/SExpression.java

@@ -19,6 +19,7 @@
 
 package org.elasticsearch.painless.node;
 
+import org.elasticsearch.painless.Definition;
 import org.elasticsearch.painless.Definition.Type;
 import org.elasticsearch.painless.Globals;
 import org.elasticsearch.painless.Locals;
@@ -58,9 +59,9 @@ public final class SExpression extends AStatement {
             throw createError(new IllegalArgumentException("Not a statement."));
         }
 
-        boolean rtn = lastSource && !isVoid && expression.actual.clazz != void.class;
+        boolean rtn = lastSource && !isVoid && expression.actual != void.class;
 
-        expression.expected = rtn ? rtnType : expression.actual;
+        expression.expected = rtn ? Definition.TypeToClass(rtnType) : expression.actual;
         expression.internal = rtn;
         expression = expression.cast(locals);
 
@@ -78,7 +79,7 @@ public final class SExpression extends AStatement {
         if (methodEscape) {
             writer.returnValue();
         } else {
-            writer.writePop(expression.expected.type.getSize());
+            writer.writePop(MethodWriter.getType(expression.expected).getSize());
         }
     }
 

+ 2 - 3
modules/lang-painless/src/main/java/org/elasticsearch/painless/node/SFor.java

@@ -19,7 +19,6 @@
 
 package org.elasticsearch.painless.node;
 
-import org.elasticsearch.painless.Definition;
 import org.elasticsearch.painless.Globals;
 import org.elasticsearch.painless.Locals;
 import org.elasticsearch.painless.Location;
@@ -94,7 +93,7 @@ public final class SFor extends AStatement {
         }
 
         if (condition != null) {
-            condition.expected = locals.getDefinition().booleanType;
+            condition.expected = boolean.class;
             condition.analyze(locals);
             condition = condition.cast(locals);
 
@@ -161,7 +160,7 @@ public final class SFor extends AStatement {
             AExpression initializer = (AExpression)this.initializer;
 
             initializer.write(writer, globals);
-            writer.writePop(initializer.expected.type.getSize());
+            writer.writePop(MethodWriter.getType(initializer.expected).getSize());
         }
 
         writer.mark(start);

+ 1 - 2
modules/lang-painless/src/main/java/org/elasticsearch/painless/node/SIf.java

@@ -19,7 +19,6 @@
 
 package org.elasticsearch.painless.node;
 
-import org.elasticsearch.painless.Definition;
 import org.elasticsearch.painless.Globals;
 import org.elasticsearch.painless.Locals;
 import org.elasticsearch.painless.Location;
@@ -56,7 +55,7 @@ public final class SIf extends AStatement {
 
     @Override
     void analyze(Locals locals) {
-        condition.expected = locals.getDefinition().booleanType;
+        condition.expected = boolean.class;
         condition.analyze(locals);
         condition = condition.cast(locals);
 

+ 1 - 2
modules/lang-painless/src/main/java/org/elasticsearch/painless/node/SIfElse.java

@@ -19,7 +19,6 @@
 
 package org.elasticsearch.painless.node;
 
-import org.elasticsearch.painless.Definition;
 import org.elasticsearch.painless.Globals;
 import org.elasticsearch.painless.Locals;
 import org.elasticsearch.painless.Location;
@@ -65,7 +64,7 @@ public final class SIfElse extends AStatement {
 
     @Override
     void analyze(Locals locals) {
-        condition.expected = locals.getDefinition().booleanType;
+        condition.expected = boolean.class;
         condition.analyze(locals);
         condition = condition.cast(locals);
 

+ 3 - 2
modules/lang-painless/src/main/java/org/elasticsearch/painless/node/SReturn.java

@@ -19,6 +19,7 @@
 
 package org.elasticsearch.painless.node;
 
+import org.elasticsearch.painless.Definition;
 import org.elasticsearch.painless.Globals;
 import org.elasticsearch.painless.Locals;
 import org.elasticsearch.painless.Location;
@@ -47,7 +48,7 @@ public final class SReturn extends AStatement {
 
     @Override
     void analyze(Locals locals) {
-        expression.expected = locals.getReturnType();
+        expression.expected = Definition.TypeToClass(locals.getReturnType());
         expression.internal = true;
         expression.analyze(locals);
         expression = expression.cast(locals);
@@ -68,6 +69,6 @@ public final class SReturn extends AStatement {
 
     @Override
     public String toString() {
-        return singleLineToString(expression); 
+        return singleLineToString(expression);
     }
 }

+ 3 - 2
modules/lang-painless/src/main/java/org/elasticsearch/painless/node/SSubEachArray.java

@@ -64,9 +64,10 @@ final class SSubEachArray extends AStatement {
     void analyze(Locals locals) {
         // We must store the array and index as variables for securing slots on the stack, and
         // also add the location offset to make the names unique in case of nested for each loops.
-        array = locals.addVariable(location, expression.actual, "#array" + location.getOffset(), true);
+        Type actualType = locals.getDefinition().ClassToType(expression.actual);
+        array = locals.addVariable(location, actualType, "#array" + location.getOffset(), true);
         index = locals.addVariable(location, locals.getDefinition().intType, "#index" + location.getOffset(), true);
-        indexed = locals.getDefinition().getType(expression.actual.struct, expression.actual.dimensions - 1);
+        indexed = locals.getDefinition().getType(actualType.struct, actualType.dimensions - 1);
         cast = AnalyzerCaster.getLegalCast(location, Definition.TypeToClass(indexed), Definition.TypeToClass(variable.type), true, true);
     }
 

+ 5 - 3
modules/lang-painless/src/main/java/org/elasticsearch/painless/node/SSubEachIterable.java

@@ -25,6 +25,7 @@ import org.elasticsearch.painless.Definition;
 import org.elasticsearch.painless.Definition.Cast;
 import org.elasticsearch.painless.Definition.Method;
 import org.elasticsearch.painless.Definition.MethodKey;
+import org.elasticsearch.painless.Definition.Type;
 import org.elasticsearch.painless.Definition.def;
 import org.elasticsearch.painless.Globals;
 import org.elasticsearch.painless.Locals;
@@ -75,14 +76,15 @@ final class SSubEachIterable extends AStatement {
         iterator = locals.addVariable(location, locals.getDefinition().getType("Iterator"),
                 "#itr" + location.getOffset(), true);
 
-        if (expression.actual.dynamic) {
+        if (expression.actual == def.class) {
             method = null;
         } else {
-            method = expression.actual.struct.methods.get(new MethodKey("iterator", 0));
+            Type actualType = locals.getDefinition().ClassToType(expression.actual);
+            method = actualType.struct.methods.get(new MethodKey("iterator", 0));
 
             if (method == null) {
                 throw createError(new IllegalArgumentException(
-                    "Unable to create iterator for the type [" + expression.actual.name + "]."));
+                    "Unable to create iterator for the type [" + actualType.name + "]."));
             }
         }
 

+ 1 - 2
modules/lang-painless/src/main/java/org/elasticsearch/painless/node/SThrow.java

@@ -19,7 +19,6 @@
 
 package org.elasticsearch.painless.node;
 
-import org.elasticsearch.painless.Definition;
 import org.elasticsearch.painless.Globals;
 import org.elasticsearch.painless.Locals;
 import org.elasticsearch.painless.Location;
@@ -48,7 +47,7 @@ public final class SThrow extends AStatement {
 
     @Override
     void analyze(Locals locals) {
-        expression.expected = locals.getDefinition().ExceptionType;
+        expression.expected = Exception.class;
         expression.analyze(locals);
         expression = expression.cast(locals);
 

+ 1 - 2
modules/lang-painless/src/main/java/org/elasticsearch/painless/node/SWhile.java

@@ -19,7 +19,6 @@
 
 package org.elasticsearch.painless.node;
 
-import org.elasticsearch.painless.Definition;
 import org.elasticsearch.painless.Globals;
 import org.elasticsearch.painless.Locals;
 import org.elasticsearch.painless.Location;
@@ -59,7 +58,7 @@ public final class SWhile extends AStatement {
     void analyze(Locals locals) {
         locals = Locals.newLocalScope(locals);
 
-        condition.expected = locals.getDefinition().booleanType;
+        condition.expected = boolean.class;
         condition.analyze(locals);
         condition = condition.cast(locals);
 

+ 1 - 1
modules/lang-painless/src/test/java/org/elasticsearch/painless/node/NodeToStringTests.java

@@ -397,7 +397,7 @@ public class NodeToStringTests extends ESTestCase {
 
     public void testPSubBrace() {
         Location l = new Location(getTestName(), 0);
-        PSubBrace node = new PSubBrace(l, definition.intType, new ENumeric(l, "1", 10));
+        PSubBrace node = new PSubBrace(l, int.class, new ENumeric(l, "1", 10));
         node.prefix = new EVariable(l, "a");
         assertEquals("(PSubBrace (EVariable a) (ENumeric 1))", node.toString());
     }