8071241: Investigate alternate strategy for type-checking operators
authormcimadamore
Mon, 16 Feb 2015 12:24:25 +0000
changeset 29051 7244db2ab176
parent 29050 76df9080086c
child 29052 d1bc1685d7ce
8071241: Investigate alternate strategy for type-checking operators Summary: Separat operator lookup logic from overload resolution. Reviewed-by: jjg, jlahoda, sadayapalam
langtools/src/jdk.compiler/share/classes/com/sun/tools/javac/code/Symtab.java
langtools/src/jdk.compiler/share/classes/com/sun/tools/javac/code/Types.java
langtools/src/jdk.compiler/share/classes/com/sun/tools/javac/comp/Attr.java
langtools/src/jdk.compiler/share/classes/com/sun/tools/javac/comp/Check.java
langtools/src/jdk.compiler/share/classes/com/sun/tools/javac/comp/DeferredAttr.java
langtools/src/jdk.compiler/share/classes/com/sun/tools/javac/comp/LambdaToMethod.java
langtools/src/jdk.compiler/share/classes/com/sun/tools/javac/comp/Lower.java
langtools/src/jdk.compiler/share/classes/com/sun/tools/javac/comp/Operators.java
langtools/src/jdk.compiler/share/classes/com/sun/tools/javac/comp/Resolve.java
langtools/src/jdk.compiler/share/classes/com/sun/tools/javac/resources/compiler.properties
langtools/src/jdk.compiler/share/classes/com/sun/tools/javac/tree/TreeInfo.java
langtools/test/tools/javac/7102515/T7102515.out
langtools/test/tools/javac/diags/examples/IncomparableTypes.java
langtools/test/tools/javac/expression/NullAppend.out
langtools/test/tools/javac/expression/NullAppend2.out
langtools/test/tools/javac/resolve/tests/PrimitiveBinopOverload.java
--- a/langtools/src/jdk.compiler/share/classes/com/sun/tools/javac/code/Symtab.java	Fri Feb 13 17:00:45 2015 -0500
+++ b/langtools/src/jdk.compiler/share/classes/com/sun/tools/javac/code/Symtab.java	Mon Feb 16 12:24:25 2015 +0000
@@ -200,9 +200,6 @@
      */
     public final VarSymbol lengthVar;
 
-    /** The null check operator. */
-    public final OperatorSymbol nullcheck;
-
     /** The symbol representing the final finalize method on enums */
     public final MethodSymbol enumFinalFinalize;
 
@@ -217,10 +214,6 @@
      */
     public final Name[] boxedName = new Name[TypeTag.getTypeTagCount()];
 
-    /** A set containing all operator names.
-     */
-    public final Set<Name> operatorNames = new HashSet<>();
-
     /** A hashtable containing the encountered top-level and member classes,
      *  indexed by flat names. The table does not contain local classes.
      *  It should be updated from the outside to reflect classes defined
@@ -255,85 +248,6 @@
      */
     public final ClassSymbol predefClass;
 
-    /** Enter a constant into symbol table.
-     *  @param name   The constant's name.
-     *  @param type   The constant's type.
-     */
-    private VarSymbol enterConstant(String name, Type type) {
-        VarSymbol c = new VarSymbol(
-            PUBLIC | STATIC | FINAL,
-            names.fromString(name),
-            type,
-            predefClass);
-        c.setData(type.constValue());
-        predefClass.members().enter(c);
-        return c;
-    }
-
-    /** Enter a binary operation into symbol table.
-     *  @param name     The name of the operator.
-     *  @param left     The type of the left operand.
-     *  @param right    The type of the left operand.
-     *  @param res      The operation's result type.
-     *  @param opcode   The operation's bytecode instruction.
-     */
-    private void enterBinop(String name,
-                            Type left, Type right, Type res,
-                            int opcode) {
-        predefClass.members().enter(
-            new OperatorSymbol(
-                makeOperatorName(name),
-                new MethodType(List.of(left, right), res,
-                               List.<Type>nil(), methodClass),
-                opcode,
-                predefClass));
-    }
-
-    /** Enter a binary operation, as above but with two opcodes,
-     *  which get encoded as
-     *  {@code (opcode1 << ByteCodeTags.preShift) + opcode2 }.
-     *  @param opcode1     First opcode.
-     *  @param opcode2     Second opcode.
-     */
-    private void enterBinop(String name,
-                            Type left, Type right, Type res,
-                            int opcode1, int opcode2) {
-        enterBinop(
-            name, left, right, res, (opcode1 << ByteCodes.preShift) | opcode2);
-    }
-
-    /** Enter a unary operation into symbol table.
-     *  @param name     The name of the operator.
-     *  @param arg      The type of the operand.
-     *  @param res      The operation's result type.
-     *  @param opcode   The operation's bytecode instruction.
-     */
-    private OperatorSymbol enterUnop(String name,
-                                     Type arg,
-                                     Type res,
-                                     int opcode) {
-        OperatorSymbol sym =
-            new OperatorSymbol(makeOperatorName(name),
-                               new MethodType(List.of(arg),
-                                              res,
-                                              List.<Type>nil(),
-                                              methodClass),
-                               opcode,
-                               predefClass);
-        predefClass.members().enter(sym);
-        return sym;
-    }
-
-    /**
-     * Create a new operator name from corresponding String representation
-     * and add the name to the set of known operator names.
-     */
-    private Name makeOperatorName(String name) {
-        Name opName = names.fromString(name);
-        operatorNames.add(opName);
-        return opName;
-    }
-
     /** Enter a class into symbol table.
      *  @param s The name of the class.
      */
@@ -591,163 +505,6 @@
                            List.<Type>nil(), methodClass),
             arrayClass);
         arrayClass.members().enter(arrayCloneMethod);
-
-        // Enter operators.
-        /*  Internally we use +++, --- for unary +, - to reduce +, - operators
-         *  overloading
-         */
-        enterUnop("+++", doubleType, doubleType, nop);
-        enterUnop("+++", floatType, floatType, nop);
-        enterUnop("+++", longType, longType, nop);
-        enterUnop("+++", intType, intType, nop);
-
-        enterUnop("---", doubleType, doubleType, dneg);
-        enterUnop("---", floatType, floatType, fneg);
-        enterUnop("---", longType, longType, lneg);
-        enterUnop("---", intType, intType, ineg);
-
-        enterUnop("~", longType, longType, lxor);
-        enterUnop("~", intType, intType, ixor);
-
-        enterUnop("++", doubleType, doubleType, dadd);
-        enterUnop("++", floatType, floatType, fadd);
-        enterUnop("++", longType, longType, ladd);
-        enterUnop("++", intType, intType, iadd);
-        enterUnop("++", charType, charType, iadd);
-        enterUnop("++", shortType, shortType, iadd);
-        enterUnop("++", byteType, byteType, iadd);
-
-        enterUnop("--", doubleType, doubleType, dsub);
-        enterUnop("--", floatType, floatType, fsub);
-        enterUnop("--", longType, longType, lsub);
-        enterUnop("--", intType, intType, isub);
-        enterUnop("--", charType, charType, isub);
-        enterUnop("--", shortType, shortType, isub);
-        enterUnop("--", byteType, byteType, isub);
-
-        enterUnop("!", booleanType, booleanType, bool_not);
-        nullcheck = enterUnop("<*nullchk*>", objectType, objectType, nullchk);
-
-        // string concatenation
-        enterBinop("+", stringType, objectType, stringType, string_add);
-        enterBinop("+", objectType, stringType, stringType, string_add);
-        enterBinop("+", stringType, stringType, stringType, string_add);
-        enterBinop("+", stringType, intType, stringType, string_add);
-        enterBinop("+", stringType, longType, stringType, string_add);
-        enterBinop("+", stringType, floatType, stringType, string_add);
-        enterBinop("+", stringType, doubleType, stringType, string_add);
-        enterBinop("+", stringType, booleanType, stringType, string_add);
-        enterBinop("+", stringType, botType, stringType, string_add);
-        enterBinop("+", intType, stringType, stringType, string_add);
-        enterBinop("+", longType, stringType, stringType, string_add);
-        enterBinop("+", floatType, stringType, stringType, string_add);
-        enterBinop("+", doubleType, stringType, stringType, string_add);
-        enterBinop("+", booleanType, stringType, stringType, string_add);
-        enterBinop("+", botType, stringType, stringType, string_add);
-
-        // these errors would otherwise be matched as string concatenation
-        enterBinop("+", botType, botType, botType, error);
-        enterBinop("+", botType, intType, botType, error);
-        enterBinop("+", botType, longType, botType, error);
-        enterBinop("+", botType, floatType, botType, error);
-        enterBinop("+", botType, doubleType, botType, error);
-        enterBinop("+", botType, booleanType, botType, error);
-        enterBinop("+", botType, objectType, botType, error);
-        enterBinop("+", intType, botType, botType, error);
-        enterBinop("+", longType, botType, botType, error);
-        enterBinop("+", floatType, botType, botType, error);
-        enterBinop("+", doubleType, botType, botType, error);
-        enterBinop("+", booleanType, botType, botType, error);
-        enterBinop("+", objectType, botType, botType, error);
-
-        enterBinop("+", doubleType, doubleType, doubleType, dadd);
-        enterBinop("+", floatType, floatType, floatType, fadd);
-        enterBinop("+", longType, longType, longType, ladd);
-        enterBinop("+", intType, intType, intType, iadd);
-
-        enterBinop("-", doubleType, doubleType, doubleType, dsub);
-        enterBinop("-", floatType, floatType, floatType, fsub);
-        enterBinop("-", longType, longType, longType, lsub);
-        enterBinop("-", intType, intType, intType, isub);
-
-        enterBinop("*", doubleType, doubleType, doubleType, dmul);
-        enterBinop("*", floatType, floatType, floatType, fmul);
-        enterBinop("*", longType, longType, longType, lmul);
-        enterBinop("*", intType, intType, intType, imul);
-
-        enterBinop("/", doubleType, doubleType, doubleType, ddiv);
-        enterBinop("/", floatType, floatType, floatType, fdiv);
-        enterBinop("/", longType, longType, longType, ldiv);
-        enterBinop("/", intType, intType, intType, idiv);
-
-        enterBinop("%", doubleType, doubleType, doubleType, dmod);
-        enterBinop("%", floatType, floatType, floatType, fmod);
-        enterBinop("%", longType, longType, longType, lmod);
-        enterBinop("%", intType, intType, intType, imod);
-
-        enterBinop("&", booleanType, booleanType, booleanType, iand);
-        enterBinop("&", longType, longType, longType, land);
-        enterBinop("&", intType, intType, intType, iand);
-
-        enterBinop("|", booleanType, booleanType, booleanType, ior);
-        enterBinop("|", longType, longType, longType, lor);
-        enterBinop("|", intType, intType, intType, ior);
-
-        enterBinop("^", booleanType, booleanType, booleanType, ixor);
-        enterBinop("^", longType, longType, longType, lxor);
-        enterBinop("^", intType, intType, intType, ixor);
-
-        enterBinop("<<", longType, longType, longType, lshll);
-        enterBinop("<<", intType, longType, intType, ishll);
-        enterBinop("<<", longType, intType, longType, lshl);
-        enterBinop("<<", intType, intType, intType, ishl);
-
-        enterBinop(">>", longType, longType, longType, lshrl);
-        enterBinop(">>", intType, longType, intType, ishrl);
-        enterBinop(">>", longType, intType, longType, lshr);
-        enterBinop(">>", intType, intType, intType, ishr);
-
-        enterBinop(">>>", longType, longType, longType, lushrl);
-        enterBinop(">>>", intType, longType, intType, iushrl);
-        enterBinop(">>>", longType, intType, longType, lushr);
-        enterBinop(">>>", intType, intType, intType, iushr);
-
-        enterBinop("<", doubleType, doubleType, booleanType, dcmpg, iflt);
-        enterBinop("<", floatType, floatType, booleanType, fcmpg, iflt);
-        enterBinop("<", longType, longType, booleanType, lcmp, iflt);
-        enterBinop("<", intType, intType, booleanType, if_icmplt);
-
-        enterBinop(">", doubleType, doubleType, booleanType, dcmpl, ifgt);
-        enterBinop(">", floatType, floatType, booleanType, fcmpl, ifgt);
-        enterBinop(">", longType, longType, booleanType, lcmp, ifgt);
-        enterBinop(">", intType, intType, booleanType, if_icmpgt);
-
-        enterBinop("<=", doubleType, doubleType, booleanType, dcmpg, ifle);
-        enterBinop("<=", floatType, floatType, booleanType, fcmpg, ifle);
-        enterBinop("<=", longType, longType, booleanType, lcmp, ifle);
-        enterBinop("<=", intType, intType, booleanType, if_icmple);
-
-        enterBinop(">=", doubleType, doubleType, booleanType, dcmpl, ifge);
-        enterBinop(">=", floatType, floatType, booleanType, fcmpl, ifge);
-        enterBinop(">=", longType, longType, booleanType, lcmp, ifge);
-        enterBinop(">=", intType, intType, booleanType, if_icmpge);
-
-        enterBinop("==", objectType, objectType, booleanType, if_acmpeq);
-        enterBinop("==", booleanType, booleanType, booleanType, if_icmpeq);
-        enterBinop("==", doubleType, doubleType, booleanType, dcmpl, ifeq);
-        enterBinop("==", floatType, floatType, booleanType, fcmpl, ifeq);
-        enterBinop("==", longType, longType, booleanType, lcmp, ifeq);
-        enterBinop("==", intType, intType, booleanType, if_icmpeq);
-
-        enterBinop("!=", objectType, objectType, booleanType, if_acmpne);
-        enterBinop("!=", booleanType, booleanType, booleanType, if_icmpne);
-        enterBinop("!=", doubleType, doubleType, booleanType, dcmpl, ifne);
-        enterBinop("!=", floatType, floatType, booleanType, fcmpl, ifne);
-        enterBinop("!=", longType, longType, booleanType, lcmp, ifne);
-        enterBinop("!=", intType, intType, booleanType, if_icmpne);
-
-        enterBinop("&&", booleanType, booleanType, booleanType, bool_and);
-        enterBinop("||", booleanType, booleanType, booleanType, bool_or);
     }
 
     /** Define a new class given its name and owner.
--- a/langtools/src/jdk.compiler/share/classes/com/sun/tools/javac/code/Types.java	Fri Feb 13 17:00:45 2015 -0500
+++ b/langtools/src/jdk.compiler/share/classes/com/sun/tools/javac/code/Types.java	Mon Feb 16 12:24:25 2015 +0000
@@ -1445,26 +1445,6 @@
     }
     // </editor-fold>
 
-    /**
-     * Can t and s be compared for equality?  Any primitive ==
-     * primitive or primitive == object comparisons here are an error.
-     * Unboxing and correct primitive == primitive comparisons are
-     * already dealt with in Attr.visitBinary.
-     *
-     */
-    public boolean isEqualityComparable(Type s, Type t, Warner warn) {
-        if (t.isNumeric() && s.isNumeric())
-            return true;
-
-        boolean tPrimitive = t.isPrimitive();
-        boolean sPrimitive = s.isPrimitive();
-        if (!tPrimitive && !sPrimitive) {
-            return isCastable(s, t, warn) || isCastable(t, s, warn);
-        } else {
-            return false;
-        }
-    }
-
     // <editor-fold defaultstate="collapsed" desc="isCastable">
     public boolean isCastable(Type t, Type s) {
         return isCastable(t, s, noWarnings);
--- a/langtools/src/jdk.compiler/share/classes/com/sun/tools/javac/comp/Attr.java	Fri Feb 13 17:00:45 2015 -0500
+++ b/langtools/src/jdk.compiler/share/classes/com/sun/tools/javac/comp/Attr.java	Mon Feb 16 12:24:25 2015 +0000
@@ -82,6 +82,7 @@
     final Log log;
     final Symtab syms;
     final Resolve rs;
+    final Operators operators;
     final Infer infer;
     final Analyzer analyzer;
     final DeferredAttr deferredAttr;
@@ -115,6 +116,7 @@
         log = Log.instance(context);
         syms = Symtab.instance(context);
         rs = Resolve.instance(context);
+        operators = Operators.instance(context);
         chk = Check.instance(context);
         flow = Flow.instance(context);
         memberEnter = MemberEnter.instance(context);
@@ -1467,7 +1469,7 @@
          *  @param thentype The type of the expression's then-part.
          *  @param elsetype The type of the expression's else-part.
          */
-        private Type condType(DiagnosticPosition pos,
+        Type condType(DiagnosticPosition pos,
                                Type thentype, Type elsetype) {
             // If same type, that is the result
             if (types.isSameType(thentype, elsetype))
@@ -2142,7 +2144,7 @@
 
         JCTree.Tag optag = NULLCHK;
         JCUnary tree = make.at(arg.pos).Unary(optag, arg);
-        tree.operator = syms.nullcheck;
+        tree.operator = operators.resolveUnary(arg, optag, arg.type);
         tree.type = arg.type;
         return tree;
     }
@@ -2903,18 +2905,10 @@
         Type owntype = attribTree(tree.lhs, env, varAssignmentInfo);
         Type operand = attribExpr(tree.rhs, env);
         // Find operator.
-        Symbol operator = tree.operator = rs.resolveBinaryOperator(
-            tree.pos(), tree.getTag().noAssignOp(), env,
-            owntype, operand);
-
+        Symbol operator = tree.operator = operators.resolveBinary(tree, tree.getTag().noAssignOp(), owntype, operand);
         if (operator.kind == MTH &&
                 !owntype.isErroneous() &&
                 !operand.isErroneous()) {
-            chk.checkOperator(tree.pos(),
-                              (OperatorSymbol)operator,
-                              tree.getTag().noAssignOp(),
-                              owntype,
-                              operand);
             chk.checkDivZero(tree.rhs.pos(), operator, operand);
             chk.checkCastable(tree.rhs.pos(),
                               operator.type.getReturnType(),
@@ -2930,9 +2924,7 @@
             : chk.checkNonVoid(tree.arg.pos(), attribExpr(tree.arg, env));
 
         // Find operator.
-        Symbol operator = tree.operator =
-            rs.resolveUnaryOperator(tree.pos(), tree.getTag(), env, argtype);
-
+        Symbol operator = tree.operator = operators.resolveUnary(tree, tree.getTag(), argtype);
         Type owntype = types.createErrorType(tree.type);
         if (operator.kind == MTH &&
                 !argtype.isErroneous()) {
@@ -2957,22 +2949,13 @@
         Type left = chk.checkNonVoid(tree.lhs.pos(), attribExpr(tree.lhs, env));
         Type right = chk.checkNonVoid(tree.lhs.pos(), attribExpr(tree.rhs, env));
         // Find operator.
-        Symbol operator = tree.operator =
-            rs.resolveBinaryOperator(tree.pos(), tree.getTag(), env, left, right);
-
+        Symbol operator = tree.operator = operators.resolveBinary(tree, tree.getTag(), left, right);
         Type owntype = types.createErrorType(tree.type);
         if (operator.kind == MTH &&
                 !left.isErroneous() &&
                 !right.isErroneous()) {
             owntype = operator.type.getReturnType();
-            // This will figure out when unboxing can happen and
-            // choose the right comparison operator.
-            int opc = chk.checkOperator(tree.lhs.pos(),
-                                        (OperatorSymbol)operator,
-                                        tree.getTag(),
-                                        left,
-                                        right);
-
+            int opc = ((OperatorSymbol)operator).opcode;
             // If both arguments are constants, fold them.
             if (left.constValue() != null && right.constValue() != null) {
                 Type ctype = cfolder.fold2(opc, left, right);
@@ -2985,8 +2968,7 @@
             // castable to each other, (JLS 15.21).  Note: unboxing
             // comparisons will not have an acmp* opc at this point.
             if ((opc == ByteCodes.if_acmpeq || opc == ByteCodes.if_acmpne)) {
-                if (!types.isEqualityComparable(left, right,
-                                                new Warner(tree.pos()))) {
+                if (!types.isCastable(left, right, new Warner(tree.pos()))) {
                     log.error(tree.pos(), "incomparable.types", left, right);
                 }
             }
--- a/langtools/src/jdk.compiler/share/classes/com/sun/tools/javac/comp/Check.java	Fri Feb 13 17:00:45 2015 -0500
+++ b/langtools/src/jdk.compiler/share/classes/com/sun/tools/javac/comp/Check.java	Mon Feb 16 12:24:25 2015 +0000
@@ -83,7 +83,6 @@
     private boolean warnOnSyntheticConflicts;
     private boolean suppressAbortOnBadClassFile;
     private boolean enableSunApiLintControl;
-    private final TreeInfo treeinfo;
     private final JavaFileManager fileManager;
     private final Profile profile;
     private final boolean warnOnAccessToSensitiveMembers;
@@ -121,7 +120,6 @@
         diags = JCDiagnostic.Factory.instance(context);
         Options options = Options.instance(context);
         lint = Lint.instance(context);
-        treeinfo = TreeInfo.instance(context);
         fileManager = context.get(JavaFileManager.class);
 
         Source source = Source.instance(context);
@@ -3265,30 +3263,6 @@
  **************************************************************************/
 
     /**
-     * Return the opcode of the operator but emit an error if it is an
-     * error.
-     * @param pos        position for error reporting.
-     * @param operator   an operator
-     * @param tag        a tree tag
-     * @param left       type of left hand side
-     * @param right      type of right hand side
-     */
-    int checkOperator(DiagnosticPosition pos,
-                       OperatorSymbol operator,
-                       JCTree.Tag tag,
-                       Type left,
-                       Type right) {
-        if (operator.opcode == ByteCodes.error) {
-            log.error(pos,
-                      "operator.cant.be.applied.1",
-                      treeinfo.operatorName(tag),
-                      left, right);
-        }
-        return operator.opcode;
-    }
-
-
-    /**
      *  Check for division by integer constant zero
      *  @param pos           Position for error reporting.
      *  @param operator      The operator for the expression
--- a/langtools/src/jdk.compiler/share/classes/com/sun/tools/javac/comp/DeferredAttr.java	Fri Feb 13 17:00:45 2015 -0500
+++ b/langtools/src/jdk.compiler/share/classes/com/sun/tools/javac/comp/DeferredAttr.java	Mon Feb 16 12:24:25 2015 +0000
@@ -1386,7 +1386,7 @@
                 Symbol lookup(Env<AttrContext> env, MethodResolutionPhase phase) {
                     return rec == null ?
                         rs.findFun(env, name, argtypes, typeargtypes, phase.isBoxingRequired(), phase.isVarargsRequired()) :
-                        rs.findMethod(env, site, name, argtypes, typeargtypes, phase.isBoxingRequired(), phase.isVarargsRequired(), false);
+                        rs.findMethod(env, site, name, argtypes, typeargtypes, phase.isBoxingRequired(), phase.isVarargsRequired());
                 }
                 @Override
                 Symbol access(Env<AttrContext> env, DiagnosticPosition pos, Symbol location, Symbol sym) {
--- a/langtools/src/jdk.compiler/share/classes/com/sun/tools/javac/comp/LambdaToMethod.java	Fri Feb 13 17:00:45 2015 -0500
+++ b/langtools/src/jdk.compiler/share/classes/com/sun/tools/javac/comp/LambdaToMethod.java	Mon Feb 16 12:24:25 2015 +0000
@@ -80,6 +80,7 @@
     private Names names;
     private Symtab syms;
     private Resolve rs;
+    private Operators operators;
     private TreeMaker make;
     private Types types;
     private TransTypes transTypes;
@@ -130,6 +131,7 @@
         names = Names.instance(context);
         syms = Symtab.instance(context);
         rs = Resolve.instance(context);
+        operators = Operators.instance(context);
         make = TreeMaker.instance(context);
         types = Types.instance(context);
         transTypes = TransTypes.instance(context);
@@ -654,7 +656,7 @@
 
     private JCExpression eqTest(Type argType, JCExpression arg1, JCExpression arg2) {
         JCBinary testExpr = make.Binary(JCTree.Tag.EQ, arg1, arg2);
-        testExpr.operator = rs.resolveBinaryOperator(null, JCTree.Tag.EQ, attrEnv, argType, argType);
+        testExpr.operator = operators.resolveBinary(testExpr, JCTree.Tag.EQ, argType, argType);
         testExpr.setType(syms.booleanType);
         return testExpr;
     }
@@ -668,7 +670,7 @@
                 List.<JCExpression>of(make.Literal(lit)));
         eqtest.setType(syms.booleanType);
         JCBinary compound = make.Binary(JCTree.Tag.AND, prev, eqtest);
-        compound.operator = rs.resolveBinaryOperator(null, JCTree.Tag.AND, attrEnv, syms.booleanType, syms.booleanType);
+        compound.operator = operators.resolveBinary(compound, JCTree.Tag.AND, syms.booleanType, syms.booleanType);
         compound.setType(syms.booleanType);
         return compound;
     }
--- a/langtools/src/jdk.compiler/share/classes/com/sun/tools/javac/comp/Lower.java	Fri Feb 13 17:00:45 2015 -0500
+++ b/langtools/src/jdk.compiler/share/classes/com/sun/tools/javac/comp/Lower.java	Mon Feb 16 12:24:25 2015 +0000
@@ -74,6 +74,7 @@
     private final Log log;
     private final Symtab syms;
     private final Resolve rs;
+    private final Operators operators;
     private final Check chk;
     private final Attr attr;
     private TreeMaker make;
@@ -95,6 +96,7 @@
         log = Log.instance(context);
         syms = Symtab.instance(context);
         rs = Resolve.instance(context);
+        operators = Operators.instance(context);
         chk = Check.instance(context);
         attr = Attr.instance(context);
         make = TreeMaker.instance(context);
@@ -575,8 +577,7 @@
      */
     JCUnary makeUnary(JCTree.Tag optag, JCExpression arg) {
         JCUnary tree = make.Unary(optag, arg);
-        tree.operator = rs.resolveUnaryOperator(
-            make_pos, optag, attrEnv, arg.type);
+        tree.operator = operators.resolveUnary(tree, optag, arg.type);
         tree.type = tree.operator.type.getReturnType();
         return tree;
     }
@@ -588,8 +589,7 @@
      */
     JCBinary makeBinary(JCTree.Tag optag, JCExpression lhs, JCExpression rhs) {
         JCBinary tree = make.Binary(optag, lhs, rhs);
-        tree.operator = rs.resolveBinaryOperator(
-            make_pos, optag, attrEnv, lhs.type, rhs.type);
+        tree.operator = operators.resolveBinary(tree, optag, lhs.type, rhs.type);
         tree.type = tree.operator.type.getReturnType();
         return tree;
     }
@@ -601,8 +601,7 @@
      */
     JCAssignOp makeAssignop(JCTree.Tag optag, JCTree lhs, JCTree rhs) {
         JCAssignOp tree = make.Assignop(optag, lhs, rhs);
-        tree.operator = rs.resolveBinaryOperator(
-            make_pos, tree.getTag().noAssignOp(), attrEnv, lhs.type, rhs.type);
+        tree.operator = operators.resolveBinary(tree, tree.getTag().noAssignOp(), lhs.type, rhs.type);
         tree.type = lhs.type;
         return tree;
     }
@@ -3193,9 +3192,8 @@
                         // tree.lhs.  However, we can still get the
                         // unerased type of tree.lhs as it is stored
                         // in tree.type in Attr.
-                        Symbol newOperator = rs.resolveBinaryOperator(tree.pos(),
+                        Symbol newOperator = operators.resolveBinary(tree,
                                                                       newTag,
-                                                                      attrEnv,
                                                                       tree.type,
                                                                       tree.rhs.type);
                         JCExpression expr = (JCExpression)lhs;
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/langtools/src/jdk.compiler/share/classes/com/sun/tools/javac/comp/Operators.java	Mon Feb 16 12:24:25 2015 +0000
@@ -0,0 +1,850 @@
+/*
+ * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package com.sun.tools.javac.comp;
+
+import com.sun.tools.javac.code.Symbol;
+import com.sun.tools.javac.code.Symbol.OperatorSymbol;
+import com.sun.tools.javac.code.Symtab;
+import com.sun.tools.javac.code.Type;
+import com.sun.tools.javac.code.Type.MethodType;
+import com.sun.tools.javac.code.TypeTag;
+import com.sun.tools.javac.code.Types;
+import com.sun.tools.javac.jvm.ByteCodes;
+import com.sun.tools.javac.resources.CompilerProperties.Errors;
+import com.sun.tools.javac.tree.JCTree;
+import com.sun.tools.javac.tree.JCTree.Tag;
+import com.sun.tools.javac.util.Assert;
+import com.sun.tools.javac.util.Context;
+import com.sun.tools.javac.util.JCDiagnostic;
+import com.sun.tools.javac.util.JCDiagnostic.DiagnosticPosition;
+import com.sun.tools.javac.util.List;
+import com.sun.tools.javac.util.Log;
+import com.sun.tools.javac.util.Name;
+import com.sun.tools.javac.util.Names;
+
+import java.util.HashMap;
+import java.util.Map;
+import java.util.Optional;
+import java.util.function.BiPredicate;
+import java.util.function.Function;
+import java.util.function.Predicate;
+import java.util.function.Supplier;
+import java.util.stream.Stream;
+
+import static com.sun.tools.javac.jvm.ByteCodes.*;
+import static com.sun.tools.javac.comp.Operators.OperatorType.*;
+
+/**
+ * This class contains the logic for unary and binary operator resolution/lookup.
+ *
+ * <p><b>This is NOT part of any supported API.
+ * If you write code that depends on this, you do so at your own risk.
+ * This code and its internal interfaces are subject to change or
+ * deletion without notice.</b>
+ */
+public class Operators {
+    protected static final Context.Key<Operators> operatorsKey = new Context.Key<>();
+
+    private final Names names;
+    private final Log log;
+    private final Symtab syms;
+    private final Types types;
+
+    /** Unary operators map. */
+    private Map<Name, List<UnaryOperatorHelper>> unaryOperators = new HashMap<>(Tag.getNumberOfOperators());
+
+    /** Binary operators map. */
+    private Map<Name, List<BinaryOperatorHelper>> binaryOperators = new HashMap<>(Tag.getNumberOfOperators());
+
+    /** The names of all operators. */
+    private Name[] opname = new Name[Tag.getNumberOfOperators()];
+
+    public static Operators instance(Context context) {
+        Operators instance = context.get(operatorsKey);
+        if (instance == null)
+            instance = new Operators(context);
+        return instance;
+    }
+
+    protected Operators(Context context) {
+        context.put(operatorsKey, this);
+        syms = Symtab.instance(context);
+        names = Names.instance(context);
+        log = Log.instance(context);
+        types = Types.instance(context);
+        initOperatorNames();
+        initUnaryOperators();
+        initBinaryOperators();
+    }
+
+    /**
+     * Perform unary promotion of a type; this routine implements JLS 5.6.1.
+     * If the input type is not supported by unary promotion, it is returned unaltered.
+     */
+    Type unaryPromotion(Type t) {
+        Type unboxed = types.unboxedTypeOrType(t);
+        switch (unboxed.getTag()) {
+            case BYTE:
+            case SHORT:
+            case CHAR:
+                return syms.intType;
+            default:
+                return unboxed;
+        }
+    }
+
+    /**
+     * Perform binary promotion of a pair of types; this routine implements JLS 5.6.2.
+     * If the input types are not supported by unary promotion, if such types are identical to
+     * a type C, then C is returned, otherwise Object is returned.
+     */
+    Type binaryPromotion(Type t1, Type t2) {
+        Type unboxedT1 = types.unboxedTypeOrType(t1);
+        Type unboxedT2 = types.unboxedTypeOrType(t2);
+
+        if (unboxedT1.isNumeric() && unboxedT2.isNumeric()) {
+            if (unboxedT1.hasTag(TypeTag.DOUBLE) || unboxedT2.hasTag(TypeTag.DOUBLE)) {
+                return syms.doubleType;
+            } else if (unboxedT1.hasTag(TypeTag.FLOAT) || unboxedT2.hasTag(TypeTag.FLOAT)) {
+                return syms.floatType;
+            } else if (unboxedT1.hasTag(TypeTag.LONG) || unboxedT2.hasTag(TypeTag.LONG)) {
+                return syms.longType;
+            } else {
+                return syms.intType;
+            }
+        } else if (types.isSameType(unboxedT1, unboxedT2)) {
+            return unboxedT1;
+        } else {
+            return syms.objectType;
+        }
+    }
+
+    /**
+     * Entry point for resolving a unary operator given an operator tag and an argument type.
+     */
+    Symbol resolveUnary(DiagnosticPosition pos, JCTree.Tag tag, Type op) {
+        return resolve(tag,
+                unaryOperators,
+                unop -> unop.test(op),
+                unop -> unop.resolve(op),
+                () -> reportErrorIfNeeded(pos, tag, op));
+    }
+
+    /**
+     * Entry point for resolving a binary operator given an operator tag and a pair of argument types.
+     */
+    Symbol resolveBinary(DiagnosticPosition pos, JCTree.Tag tag, Type op1, Type op2) {
+        return resolve(tag,
+                binaryOperators,
+                binop -> binop.test(op1, op2),
+                binop -> binop.resolve(op1, op2),
+                () -> reportErrorIfNeeded(pos, tag, op1, op2));
+    }
+
+    /**
+     * Main operator lookup routine; lookup an operator (either unary or binary) in its corresponding
+     * map. If there's a matching operator, its resolve routine is called and the result is returned;
+     * otherwise the result of a fallback function is returned.
+     */
+    private <O> Symbol resolve(Tag tag, Map<Name, List<O>> opMap, Predicate<O> opTestFunc,
+                       Function<O, Symbol> resolveFunc, Supplier<Symbol> noResultFunc) {
+        return opMap.get(operatorName(tag)).stream()
+                .filter(opTestFunc)
+                .map(resolveFunc)
+                .findFirst()
+                .orElseGet(noResultFunc);
+    }
+
+    /**
+     * Creates an operator symbol.
+     */
+    private Symbol makeOperator(Name name, List<OperatorType> formals, OperatorType res, int... opcodes) {
+        MethodType opType = new MethodType(
+                formals.stream()
+                        .map(o -> o.asType(syms))
+                        .collect(List.collector()),
+                res.asType(syms), List.nil(), syms.methodClass);
+        return new OperatorSymbol(name, opType, mergeOpcodes(opcodes), syms.noSymbol);
+    }
+
+    /**
+     * Fold two opcodes in a single int value (if required).
+     */
+    private int mergeOpcodes(int... opcodes) {
+        int opcodesLen = opcodes.length;
+        Assert.check(opcodesLen == 1 || opcodesLen == 2);
+        return (opcodesLen == 1) ?
+                opcodes[0] :
+                ((opcodes[0] << ByteCodes.preShift) | opcodes[1]);
+    }
+
+    /**
+     * Report an operator lookup error.
+     */
+    private Symbol reportErrorIfNeeded(DiagnosticPosition pos, Tag tag, Type... args) {
+        if (Stream.of(args).noneMatch(Type::isErroneous)) {
+            Name opName = operatorName(tag);
+            JCDiagnostic.Error opError = (args.length) == 1 ?
+                    Errors.OperatorCantBeApplied(opName, args[0]) :
+                    Errors.OperatorCantBeApplied1(opName, args[0], args[1]);
+            log.error(pos, opError);
+        }
+        return syms.noSymbol;
+    }
+
+    /**
+     * Return name of operator with given tree tag.
+     */
+    public Name operatorName(JCTree.Tag tag) {
+        return opname[tag.operatorIndex()];
+    }
+
+    /**
+     * The constants in this enum represent the types upon which all the operator helpers
+     * operate upon. This allows lazy and consise mapping between a type name and a type instance.
+     */
+    enum OperatorType {
+        BYTE(syms -> syms.byteType),
+        SHORT(syms -> syms.shortType),
+        INT(syms -> syms.intType),
+        LONG(syms -> syms.longType),
+        FLOAT(syms -> syms.floatType),
+        DOUBLE(syms -> syms.doubleType),
+        CHAR(syms -> syms.charType),
+        BOOLEAN(syms -> syms.booleanType),
+        OBJECT(syms -> syms.objectType),
+        STRING(syms -> syms.stringType),
+        BOT(syms -> syms.botType);
+
+        final Function<Symtab, Type> asTypeFunc;
+
+        OperatorType(Function<Symtab, Type> asTypeFunc) {
+            this.asTypeFunc = asTypeFunc;
+        }
+
+        Type asType(Symtab syms) {
+            return asTypeFunc.apply(syms);
+        }
+    }
+
+    /**
+     * Common root for all operator helpers. An operator helper instance is associated with a
+     * given operator (i.e. '+'); it contains routines to perform operator lookup, i.e. find
+     * which version of the '+' operator is the best given an argument type list. Supported
+     * operator symbols are initialized lazily upon first lookup request - this is in order to avoid
+     * initialization circularities between this class and {@code Symtab}.
+     */
+    abstract class OperatorHelper {
+
+        /** The operator name. */
+        final Name name;
+
+        /** The list of symbols associated with this operator (lazily populated). */
+        Optional<Symbol[]> alternatives = Optional.empty();
+
+        /** An array of operator symbol suppliers (used to lazily populate the symbol list). */
+        List<Supplier<Symbol>> operatorSuppliers = List.nil();
+
+        @SuppressWarnings("varargs")
+        OperatorHelper(Tag tag) {
+            this.name = operatorName(tag);
+        }
+
+        /**
+         * This routine implements the main operator lookup process. Each operator is tested
+         * using an applicability predicate; if the test suceeds that same operator is returned,
+         * otherwise a dummy symbol is returned.
+         */
+        final Symbol doLookup(Predicate<Symbol> applicabilityTest) {
+            return Stream.of(alternatives.orElseGet(this::initOperators))
+                    .filter(applicabilityTest)
+                    .findFirst()
+                    .orElse(syms.noSymbol);
+        }
+
+        /**
+         * This routine performs lazy instantiation of the operator symbols supported by this helper.
+         * After initialization is done, the suppliers are cleared, to free up memory.
+         */
+        private Symbol[] initOperators() {
+            Symbol[] operators = operatorSuppliers.stream()
+                    .map(op -> op.get())
+                    .toArray(Symbol[]::new);
+            alternatives = Optional.of(operators);
+            operatorSuppliers = null; //let GC do its work
+            return operators;
+        }
+    }
+
+    /**
+     * Common superclass for all unary operator helpers.
+     */
+    abstract class UnaryOperatorHelper extends OperatorHelper implements Predicate<Type> {
+
+        UnaryOperatorHelper(Tag tag) {
+            super(tag);
+        }
+
+        /**
+         * This routine implements the unary operator lookup process. It customizes the behavior
+         * of the shared lookup routine in {@link OperatorHelper}, by using an unary applicability test
+         * (see {@link UnaryOperatorHelper#isUnaryOperatorApplicable(OperatorSymbol, Type)}
+         */
+        final Symbol doLookup(Type t) {
+            return doLookup(op -> isUnaryOperatorApplicable((OperatorSymbol)op, t));
+        }
+
+        /**
+         * Unary operator applicability test - is the input type the same as the expected operand type?
+         */
+        boolean isUnaryOperatorApplicable(OperatorSymbol op, Type t) {
+            return types.isSameType(op.type.getParameterTypes().head, t);
+        }
+
+        /**
+         * Adds a unary operator symbol.
+         */
+        final UnaryOperatorHelper addUnaryOperator(OperatorType arg, OperatorType res, int... opcode) {
+            operatorSuppliers = operatorSuppliers.prepend(() -> makeOperator(name, List.of(arg), res, opcode));
+            return this;
+        }
+
+        /**
+         * This method will be overridden by unary operator helpers to provide custom resolution
+         * logic.
+         */
+        abstract Symbol resolve(Type t);
+    }
+
+    abstract class BinaryOperatorHelper extends OperatorHelper implements BiPredicate<Type, Type> {
+
+        BinaryOperatorHelper(Tag tag) {
+            super(tag);
+        }
+
+        /**
+         * This routine implements the binary operator lookup process. It customizes the behavior
+         * of the shared lookup routine in {@link OperatorHelper}, by using an unary applicability test
+         * (see {@link BinaryOperatorHelper#isBinaryOperatorApplicable(OperatorSymbol, Type, Type)}
+         */
+        final Symbol doLookup(Type t1, Type t2) {
+            return doLookup(op -> isBinaryOperatorApplicable((OperatorSymbol)op, t1, t2));
+        }
+
+        /**
+         * Binary operator applicability test - are the input types the same as the expected operand types?
+         */
+        boolean isBinaryOperatorApplicable(OperatorSymbol op, Type t1, Type t2) {
+            List<Type> formals = op.type.getParameterTypes();
+            return types.isSameType(formals.head, t1) &&
+                    types.isSameType(formals.tail.head, t2);
+        }
+
+        /**
+         * Adds a binary operator symbol.
+         */
+        final BinaryOperatorHelper addBinaryOperator(OperatorType arg1, OperatorType arg2, OperatorType res, int... opcode) {
+            operatorSuppliers = operatorSuppliers.prepend(() -> makeOperator(name, List.of(arg1, arg2), res, opcode));
+            return this;
+        }
+
+        /**
+         * This method will be overridden by binary operator helpers to provide custom resolution
+         * logic.
+         */
+        abstract Symbol resolve(Type t1, Type t2);
+    }
+
+    /**
+     * Class representing unary operator helpers that operate on reference types.
+     */
+    class UnaryReferenceOperator extends UnaryOperatorHelper {
+
+        UnaryReferenceOperator(Tag tag) {
+            super(tag);
+        }
+
+        @Override
+        public boolean test(Type type) {
+            return type.isNullOrReference();
+        }
+
+        @Override
+        public Symbol resolve(Type arg) {
+            return doLookup(syms.objectType);
+        }
+    }
+
+    /**
+     * Class representing unary operator helpers that operate on numeric types (either boxed or unboxed).
+     * Operator lookup is performed after applying numeric promotion of the input type.
+     */
+    class UnaryNumericOperator extends UnaryOperatorHelper {
+
+        UnaryNumericOperator(Tag tag) {
+            super(tag);
+        }
+
+        @Override
+        public boolean test(Type type) {
+            return unaryPromotion(type).isNumeric();
+        }
+
+        @Override
+        public Symbol resolve(Type arg) {
+            return doLookup(unaryPromotion(arg));
+        }
+    }
+
+    /**
+     * Class representing unary operator helpers that operate on boolean types  (either boxed or unboxed).
+     * Operator lookup is performed assuming the input type is a boolean type.
+     */
+    class UnaryBooleanOperator extends UnaryOperatorHelper {
+
+        UnaryBooleanOperator(Tag tag) {
+            super(tag);
+        }
+
+        @Override
+        public boolean test(Type type) {
+            return types.unboxedTypeOrType(type).hasTag(TypeTag.BOOLEAN);
+        }
+
+        @Override
+        public Symbol resolve(Type arg) {
+            return doLookup(syms.booleanType);
+        }
+    }
+
+    /**
+     * Class representing prefix/postfix unary operator helpers. Operates on numeric types (either
+     * boxed or unboxed). Operator lookup is performed on the unboxed version of the input type.
+     */
+    class UnaryPrefixPostfixOperator extends UnaryNumericOperator {
+
+        UnaryPrefixPostfixOperator(Tag tag) {
+            super(tag);
+        }
+
+        @Override
+        public Symbol resolve(Type arg) {
+            return doLookup(types.unboxedTypeOrType(arg));
+        }
+    }
+
+    /**
+     * Class representing binary operator helpers that operate on numeric types (either boxed or unboxed).
+     * Operator lookup is performed after applying binary numeric promotion of the input types.
+     */
+    class BinaryNumericOperator extends BinaryOperatorHelper {
+
+        BinaryNumericOperator(Tag tag) {
+            super(tag);
+        }
+
+        @Override
+        public Symbol resolve(Type arg1, Type arg2) {
+            Type t = binaryPromotion(arg1, arg2);
+            return doLookup(t, t);
+        }
+
+        @Override
+        public boolean test(Type arg1, Type arg2) {
+            return unaryPromotion(arg1).isNumeric() && unaryPromotion(arg2).isNumeric();
+        }
+    }
+
+    /**
+     * Class representing bitwise operator helpers that operate on all primitive types (either boxed or unboxed).
+     * Operator lookup is performed after applying binary numeric promotion of the input types.
+     */
+    class BinaryBitwiseOperator extends BinaryNumericOperator {
+
+        BinaryBitwiseOperator(Tag tag) {
+            super(tag);
+        }
+
+        @Override
+        public boolean test(Type arg1, Type arg2) {
+            return unaryPromotion(arg1).isPrimitive() && unaryPromotion(arg2).isPrimitive();
+        }
+    }
+
+    /**
+     * Class representing bitwise operator helpers that operate on boolean types (either boxed or unboxed).
+     * Operator lookup is performed assuming both input types are boolean types.
+     */
+    class BinaryBooleanOperator extends BinaryOperatorHelper {
+
+        BinaryBooleanOperator(Tag tag) {
+            super(tag);
+        }
+
+        @Override
+        public Symbol resolve(Type arg1, Type arg2) {
+            return doLookup(syms.booleanType, syms.booleanType);
+        }
+
+        @Override
+        public boolean test(Type arg1, Type arg2) {
+            return types.unboxedTypeOrType(arg1).hasTag(TypeTag.BOOLEAN) &&
+                    types.unboxedTypeOrType(arg2).hasTag(TypeTag.BOOLEAN);
+        }
+    }
+
+    /**
+     * Class representing string concatenation operator helper that operates on at least an
+     * string operand. Input types subject to an operator lookup undergoes a special string promotion
+     * (see {@link BinaryStringOperator#stringPromotion(Type)}.
+     */
+    class BinaryStringOperator extends BinaryOperatorHelper {
+
+        BinaryStringOperator(Tag tag) {
+            super(tag);
+        }
+
+        @Override
+        public Symbol resolve(Type arg1, Type arg2) {
+            return doLookup(stringPromotion(arg1), stringPromotion(arg2));
+        }
+
+        @Override
+        public boolean test(Type arg1, Type arg2) {
+            return types.isSameType(arg1, syms.stringType) ||
+                    types.isSameType(arg2, syms.stringType);
+        }
+
+        /**
+         * This routine applies following mappings:
+         * - if input type is primitive, apply numeric promotion
+         * - if input type is either 'null' or 'String' leave it untouched
+         * - otherwise return 'Object'
+         */
+        private Type stringPromotion(Type t) {
+            if (t.isPrimitive()) {
+                return unaryPromotion(t);
+            } else if (t.hasTag(TypeTag.BOT) ||
+                    types.isSameType(t, syms.stringType)) {
+                return t;
+            } else if (t.hasTag(TypeTag.TYPEVAR)) {
+                return stringPromotion(t.getUpperBound());
+            } else {
+                return syms.objectType;
+            }
+        }
+    }
+
+    /**
+     * Class representing shift operator helper that operates on integral operand types (either boxed
+     * or unboxed). Operator lookup is performed after applying unary numeric promotion to each input type.
+     */
+    class BinaryShiftOperator extends BinaryOperatorHelper {
+
+        BinaryShiftOperator(Tag tag) {
+            super(tag);
+        }
+
+        @Override
+        public Symbol resolve(Type arg1, Type arg2) {
+            return doLookup(unaryPromotion(arg1), unaryPromotion(arg2));
+        }
+
+        @Override
+        public boolean test(Type arg1, Type arg2) {
+            TypeTag op1 = unaryPromotion(arg1).getTag();
+            TypeTag op2 = unaryPromotion(arg2).getTag();
+            return (op1 == TypeTag.LONG || op1 == TypeTag.INT) &&
+                    (op2 == TypeTag.LONG || op2 == TypeTag.INT);
+        }
+    }
+
+    /**
+     * This enum represent the possible kinds of an comparison test ('==' and '!=').
+     */
+    enum ComparisonKind {
+        /** equality between numeric or boolean operands. */
+        NUMERIC_OR_BOOLEAN,
+        /** equality between reference operands. */
+        REFERENCE,
+        /** erroneous equality */
+        INVALID
+    }
+
+    /**
+     * Class representing equality operator helper that operates on either numeric, boolean or reference
+     * types. Operator lookup for numeric/boolean equality test is performed after binary numeric
+     * promotion to the input types. Operator lookup for reference equality test is performed assuming
+     * the input type is 'Object'.
+     */
+    class BinaryEqualityOperator extends BinaryOperatorHelper {
+
+        BinaryEqualityOperator(Tag tag) {
+            super(tag);
+        }
+
+        @Override
+        public boolean test(Type arg1, Type arg2) {
+            return getKind(arg1, arg2) != ComparisonKind.INVALID;
+        }
+
+        @Override
+        public Symbol resolve(Type t1, Type t2) {
+            ComparisonKind kind = getKind(t1, t2);
+            Type t = (kind == ComparisonKind.NUMERIC_OR_BOOLEAN) ?
+                    binaryPromotion(t1, t2) :
+                    syms.objectType;
+            return doLookup(t, t);
+        }
+
+        /**
+         * Retrieve the comparison kind associated with the given argument type pair.
+         */
+        private ComparisonKind getKind(Type arg1, Type arg2) {
+            boolean arg1Primitive = arg1.isPrimitive();
+            boolean arg2Primitive = arg2.isPrimitive();
+            if (arg1Primitive && arg2Primitive) {
+                return ComparisonKind.NUMERIC_OR_BOOLEAN;
+            } else if (arg1Primitive) {
+                return unaryPromotion(arg2).isPrimitive() ?
+                        ComparisonKind.NUMERIC_OR_BOOLEAN : ComparisonKind.INVALID;
+            } else if (arg2Primitive) {
+                return unaryPromotion(arg1).isPrimitive() ?
+                        ComparisonKind.NUMERIC_OR_BOOLEAN : ComparisonKind.INVALID;
+            } else {
+                return arg1.isNullOrReference() && arg2.isNullOrReference() ?
+                        ComparisonKind.REFERENCE : ComparisonKind.INVALID;
+            }
+        }
+    }
+
+    /**
+     * Initialize all unary operators.
+     */
+    private void initUnaryOperators() {
+        initOperators(unaryOperators,
+                new UnaryNumericOperator(Tag.POS)
+                        .addUnaryOperator(DOUBLE, DOUBLE, nop)
+                        .addUnaryOperator(FLOAT, FLOAT, nop)
+                        .addUnaryOperator(LONG, LONG, nop)
+                        .addUnaryOperator(INT, INT, nop),
+                new UnaryNumericOperator(Tag.NEG)
+                        .addUnaryOperator(DOUBLE, DOUBLE, dneg)
+                        .addUnaryOperator(FLOAT, FLOAT, fneg)
+                        .addUnaryOperator(LONG, LONG, lneg)
+                        .addUnaryOperator(INT, INT, ineg),
+                new UnaryNumericOperator(Tag.COMPL)
+                        .addUnaryOperator(LONG, LONG, lxor)
+                        .addUnaryOperator(INT, INT, ixor),
+                new UnaryPrefixPostfixOperator(Tag.POSTINC)
+                        .addUnaryOperator(DOUBLE, DOUBLE, dadd)
+                        .addUnaryOperator(FLOAT, FLOAT, fadd)
+                        .addUnaryOperator(LONG, LONG, ladd)
+                        .addUnaryOperator(INT, INT, iadd)
+                        .addUnaryOperator(CHAR, CHAR, iadd)
+                        .addUnaryOperator(SHORT, SHORT, iadd)
+                        .addUnaryOperator(BYTE, BYTE, iadd),
+                new UnaryPrefixPostfixOperator(Tag.POSTDEC)
+                        .addUnaryOperator(DOUBLE, DOUBLE, dsub)
+                        .addUnaryOperator(FLOAT, FLOAT, fsub)
+                        .addUnaryOperator(LONG, LONG, lsub)
+                        .addUnaryOperator(INT, INT, isub)
+                        .addUnaryOperator(CHAR, CHAR, isub)
+                        .addUnaryOperator(SHORT, SHORT, isub)
+                        .addUnaryOperator(BYTE, BYTE, isub),
+                new UnaryBooleanOperator(Tag.NOT)
+                        .addUnaryOperator(BOOLEAN, BOOLEAN, bool_not),
+                new UnaryReferenceOperator(Tag.NULLCHK)
+                        .addUnaryOperator(OBJECT, OBJECT, nullchk));
+    }
+
+    /**
+     * Initialize all binary operators.
+     */
+    private void initBinaryOperators() {
+        initOperators(binaryOperators,
+            new BinaryStringOperator(Tag.PLUS)
+                    .addBinaryOperator(STRING, OBJECT, STRING, string_add)
+                    .addBinaryOperator(OBJECT, STRING, STRING, string_add)
+                    .addBinaryOperator(STRING, STRING, STRING, string_add)
+                    .addBinaryOperator(STRING, INT, STRING, string_add)
+                    .addBinaryOperator(STRING, LONG, STRING, string_add)
+                    .addBinaryOperator(STRING, FLOAT, STRING, string_add)
+                    .addBinaryOperator(STRING, DOUBLE, STRING, string_add)
+                    .addBinaryOperator(STRING, BOOLEAN, STRING, string_add)
+                    .addBinaryOperator(STRING, BOT, STRING, string_add)
+                    .addBinaryOperator(INT, STRING, STRING, string_add)
+                    .addBinaryOperator(LONG, STRING, STRING, string_add)
+                    .addBinaryOperator(FLOAT, STRING, STRING, string_add)
+                    .addBinaryOperator(DOUBLE, STRING, STRING, string_add)
+                    .addBinaryOperator(BOOLEAN, STRING, STRING, string_add)
+                    .addBinaryOperator(BOT, STRING, STRING, string_add),
+            new BinaryNumericOperator(Tag.PLUS)
+                    .addBinaryOperator(DOUBLE, DOUBLE, DOUBLE, dadd)
+                    .addBinaryOperator(FLOAT, FLOAT, FLOAT, fadd)
+                    .addBinaryOperator(LONG, LONG, LONG, ladd)
+                    .addBinaryOperator(INT, INT, INT, iadd),
+            new BinaryNumericOperator(Tag.MINUS)
+                    .addBinaryOperator(DOUBLE, DOUBLE, DOUBLE, dsub)
+                    .addBinaryOperator(FLOAT, FLOAT, FLOAT, fsub)
+                    .addBinaryOperator(LONG, LONG, LONG, lsub)
+                    .addBinaryOperator(INT, INT, INT, isub),
+            new BinaryNumericOperator(Tag.MUL)
+                    .addBinaryOperator(DOUBLE, DOUBLE, DOUBLE, dmul)
+                    .addBinaryOperator(FLOAT, FLOAT, FLOAT, fmul)
+                    .addBinaryOperator(LONG, LONG, LONG, lmul)
+                    .addBinaryOperator(INT, INT, INT, imul),
+            new BinaryNumericOperator(Tag.DIV)
+                    .addBinaryOperator(DOUBLE, DOUBLE, DOUBLE, ddiv)
+                    .addBinaryOperator(FLOAT, FLOAT, FLOAT, fdiv)
+                    .addBinaryOperator(LONG, LONG, LONG, ldiv)
+                    .addBinaryOperator(INT, INT, INT, idiv),
+            new BinaryNumericOperator(Tag.MOD)
+                    .addBinaryOperator(DOUBLE, DOUBLE, DOUBLE, dmod)
+                    .addBinaryOperator(FLOAT, FLOAT, FLOAT, fmod)
+                    .addBinaryOperator(LONG, LONG, LONG, lmod)
+                    .addBinaryOperator(INT, INT, INT, imod),
+            new BinaryBitwiseOperator(Tag.BITAND)
+                    .addBinaryOperator(BOOLEAN, BOOLEAN, BOOLEAN, iand)
+                    .addBinaryOperator(LONG, LONG, LONG, land)
+                    .addBinaryOperator(INT, INT, INT, iand),
+            new BinaryBitwiseOperator(Tag.BITOR)
+                    .addBinaryOperator(BOOLEAN, BOOLEAN, BOOLEAN, ior)
+                    .addBinaryOperator(LONG, LONG, LONG, lor)
+                    .addBinaryOperator(INT, INT, INT, ior),
+            new BinaryBitwiseOperator(Tag.BITXOR)
+                    .addBinaryOperator(BOOLEAN, BOOLEAN, BOOLEAN, ixor)
+                    .addBinaryOperator(LONG, LONG, LONG, lxor)
+                    .addBinaryOperator(INT, INT, INT, ixor),
+            new BinaryShiftOperator(Tag.SL)
+                    .addBinaryOperator(INT, INT, INT, ishl)
+                    .addBinaryOperator(INT, LONG, INT, ishll)
+                    .addBinaryOperator(LONG, INT, LONG, lshl)
+                    .addBinaryOperator(LONG, LONG, LONG, lshll),
+            new BinaryShiftOperator(Tag.SR)
+                    .addBinaryOperator(INT, INT, INT, ishr)
+                    .addBinaryOperator(INT, LONG, INT, ishrl)
+                    .addBinaryOperator(LONG, INT, LONG, lshr)
+                    .addBinaryOperator(LONG, LONG, LONG, lshrl),
+            new BinaryShiftOperator(Tag.USR)
+                    .addBinaryOperator(INT, INT, INT, iushr)
+                    .addBinaryOperator(INT, LONG, INT, iushrl)
+                    .addBinaryOperator(LONG, INT, LONG, lushr)
+                    .addBinaryOperator(LONG, LONG, LONG, lushrl),
+            new BinaryNumericOperator(Tag.LT)
+                    .addBinaryOperator(DOUBLE, DOUBLE, BOOLEAN, dcmpg, iflt)
+                    .addBinaryOperator(FLOAT, FLOAT, BOOLEAN, fcmpg, iflt)
+                    .addBinaryOperator(LONG, LONG, BOOLEAN, lcmp, iflt)
+                    .addBinaryOperator(INT, INT, BOOLEAN, if_icmplt),
+            new BinaryNumericOperator(Tag.GT)
+                    .addBinaryOperator(DOUBLE, DOUBLE, BOOLEAN, dcmpl, ifgt)
+                    .addBinaryOperator(FLOAT, FLOAT, BOOLEAN, fcmpl, ifgt)
+                    .addBinaryOperator(LONG, LONG, BOOLEAN, lcmp, ifgt)
+                    .addBinaryOperator(INT, INT, BOOLEAN, if_icmpgt),
+            new BinaryNumericOperator(Tag.LE)
+                    .addBinaryOperator(DOUBLE, DOUBLE, BOOLEAN, dcmpg, ifle)
+                    .addBinaryOperator(FLOAT, FLOAT, BOOLEAN, fcmpg, ifle)
+                    .addBinaryOperator(LONG, LONG, BOOLEAN, lcmp, ifle)
+                    .addBinaryOperator(INT, INT, BOOLEAN, if_icmple),
+            new BinaryNumericOperator(Tag.GE)
+                    .addBinaryOperator(DOUBLE, DOUBLE, BOOLEAN, dcmpl, ifge)
+                    .addBinaryOperator(FLOAT, FLOAT, BOOLEAN, fcmpl, ifge)
+                    .addBinaryOperator(LONG, LONG, BOOLEAN, lcmp, ifge)
+                    .addBinaryOperator(INT, INT, BOOLEAN, if_icmpge),
+            new BinaryEqualityOperator(Tag.EQ)
+                    .addBinaryOperator(OBJECT, OBJECT, BOOLEAN, if_acmpeq)
+                    .addBinaryOperator(BOOLEAN, BOOLEAN, BOOLEAN, if_icmpeq)
+                    .addBinaryOperator(DOUBLE, DOUBLE, BOOLEAN, dcmpl, ifeq)
+                    .addBinaryOperator(FLOAT, FLOAT, BOOLEAN, fcmpl, ifeq)
+                    .addBinaryOperator(LONG, LONG, BOOLEAN, lcmp, ifeq)
+                    .addBinaryOperator(INT, INT, BOOLEAN, if_icmpeq),
+            new BinaryEqualityOperator(Tag.NE)
+                    .addBinaryOperator(OBJECT, OBJECT, BOOLEAN, if_acmpne)
+                    .addBinaryOperator(BOOLEAN, BOOLEAN, BOOLEAN, if_icmpne)
+                    .addBinaryOperator(DOUBLE, DOUBLE, BOOLEAN, dcmpl, ifne)
+                    .addBinaryOperator(FLOAT, FLOAT, BOOLEAN, fcmpl, ifne)
+                    .addBinaryOperator(LONG, LONG, BOOLEAN, lcmp, ifne)
+                    .addBinaryOperator(INT, INT, BOOLEAN, if_icmpne),
+            new BinaryBooleanOperator(Tag.AND)
+                    .addBinaryOperator(BOOLEAN, BOOLEAN, BOOLEAN, bool_and),
+            new BinaryBooleanOperator(Tag.OR)
+                    .addBinaryOperator(BOOLEAN, BOOLEAN, BOOLEAN, bool_or));
+    }
+
+    /**
+     * Complete the initialization of an operator helper by storing it into the corresponding operator map.
+     */
+    @SafeVarargs
+    private final <O extends OperatorHelper> void initOperators(Map<Name, List<O>> opsMap, O... ops) {
+        for (O o : ops) {
+            Name opName = o.name;
+            List<O> helpers = opsMap.getOrDefault(opName, List.nil());
+            opsMap.put(opName, helpers.prepend(o));
+        }
+    }
+
+    /**
+     * Initialize operator name array.
+     */
+    private void initOperatorNames() {
+        setOperatorName(Tag.POS, "+");
+        setOperatorName(Tag.NEG, "-");
+        setOperatorName(Tag.NOT, "!");
+        setOperatorName(Tag.COMPL, "~");
+        setOperatorName(Tag.PREINC, "++");
+        setOperatorName(Tag.PREDEC, "--");
+        setOperatorName(Tag.POSTINC, "++");
+        setOperatorName(Tag.POSTDEC, "--");
+        setOperatorName(Tag.NULLCHK, "<*nullchk*>");
+        setOperatorName(Tag.OR, "||");
+        setOperatorName(Tag.AND, "&&");
+        setOperatorName(Tag.EQ, "==");
+        setOperatorName(Tag.NE, "!=");
+        setOperatorName(Tag.LT, "<");
+        setOperatorName(Tag.GT, ">");
+        setOperatorName(Tag.LE, "<=");
+        setOperatorName(Tag.GE, ">=");
+        setOperatorName(Tag.BITOR, "|");
+        setOperatorName(Tag.BITXOR, "^");
+        setOperatorName(Tag.BITAND, "&");
+        setOperatorName(Tag.SL, "<<");
+        setOperatorName(Tag.SR, ">>");
+        setOperatorName(Tag.USR, ">>>");
+        setOperatorName(Tag.PLUS, "+");
+        setOperatorName(Tag.MINUS, names.hyphen);
+        setOperatorName(Tag.MUL, names.asterisk);
+        setOperatorName(Tag.DIV, names.slash);
+        setOperatorName(Tag.MOD, "%");
+    }
+    //where
+        private void setOperatorName(Tag tag, String name) {
+            setOperatorName(tag, names.fromString(name));
+        }
+
+        private void setOperatorName(Tag tag, Name name) {
+            opname[tag.operatorIndex()] = name;
+        }
+}
--- a/langtools/src/jdk.compiler/share/classes/com/sun/tools/javac/comp/Resolve.java	Fri Feb 13 17:00:45 2015 -0500
+++ b/langtools/src/jdk.compiler/share/classes/com/sun/tools/javac/comp/Resolve.java	Mon Feb 16 12:24:25 2015 +0000
@@ -90,7 +90,6 @@
     Check chk;
     Infer infer;
     ClassFinder finder;
-    TreeInfo treeinfo;
     Types types;
     JCDiagnostic.Factory diags;
     public final boolean allowMethodHandles;
@@ -118,7 +117,6 @@
         chk = Check.instance(context);
         infer = Infer.instance(context);
         finder = ClassFinder.instance(context);
-        treeinfo = TreeInfo.instance(context);
         types = Types.instance(context);
         diags = JCDiagnostic.Factory.instance(context);
         Source source = Source.instance(context);
@@ -652,7 +650,7 @@
          * Retrieve the method check object that will be used during a
          * most specific check.
          */
-        MethodCheck mostSpecificCheck(List<Type> actuals, boolean strict);
+        MethodCheck mostSpecificCheck(List<Type> actuals);
     }
 
     /**
@@ -698,7 +696,7 @@
             //do nothing - method always applicable regardless of actuals
         }
 
-        public MethodCheck mostSpecificCheck(List<Type> actuals, boolean strict) {
+        public MethodCheck mostSpecificCheck(List<Type> actuals) {
             return this;
         }
     };
@@ -773,7 +771,7 @@
             throw ex.setMessage(diags.create(DiagnosticType.FRAGMENT, log.currentSource(), pos, key, args));
         }
 
-        public MethodCheck mostSpecificCheck(List<Type> actuals, boolean strict) {
+        public MethodCheck mostSpecificCheck(List<Type> actuals) {
             return nilMethodCheck;
         }
 
@@ -881,8 +879,8 @@
         }
 
         @Override
-        public MethodCheck mostSpecificCheck(List<Type> actuals, boolean strict) {
-            return new MostSpecificCheck(strict, actuals);
+        public MethodCheck mostSpecificCheck(List<Type> actuals) {
+            return new MostSpecificCheck(actuals);
         }
 
         @Override
@@ -935,8 +933,8 @@
         }
 
         @Override
-        public MethodCheck mostSpecificCheck(List<Type> actuals, boolean strict) {
-            return new MostSpecificCheck(strict, actuals);
+        public MethodCheck mostSpecificCheck(List<Type> actuals) {
+            return new MostSpecificCheck(actuals);
         }
 
         @Override
@@ -1047,11 +1045,9 @@
      */
     class MostSpecificCheck implements MethodCheck {
 
-        boolean strict;
         List<Type> actuals;
 
-        MostSpecificCheck(boolean strict, List<Type> actuals) {
-            this.strict = strict;
+        MostSpecificCheck(List<Type> actuals) {
             this.actuals = actuals;
         }
 
@@ -1077,7 +1073,7 @@
         ResultInfo methodCheckResult(Type to, DeferredAttr.DeferredAttrContext deferredAttrContext,
                Warner rsWarner, Type actual) {
             return attr.new ResultInfo(KindSelector.VAL, to,
-                   new MostSpecificCheckContext(strict, deferredAttrContext, rsWarner, actual));
+                   new MostSpecificCheckContext(deferredAttrContext, rsWarner, actual));
         }
 
         /**
@@ -1089,8 +1085,8 @@
 
             Type actual;
 
-            public MostSpecificCheckContext(boolean strict, DeferredAttrContext deferredAttrContext, Warner rsWarner, Type actual) {
-                super(strict, deferredAttrContext, rsWarner);
+            public MostSpecificCheckContext(DeferredAttrContext deferredAttrContext, Warner rsWarner, Type actual) {
+                super(true, deferredAttrContext, rsWarner);
                 this.actual = actual;
             }
 
@@ -1236,7 +1232,7 @@
 
         }
 
-        public MethodCheck mostSpecificCheck(List<Type> actuals, boolean strict) {
+        public MethodCheck mostSpecificCheck(List<Type> actuals) {
             Assert.error("Cannot get here!");
             return null;
         }
@@ -1427,8 +1423,7 @@
                       Symbol sym,
                       Symbol bestSoFar,
                       boolean allowBoxing,
-                      boolean useVarargs,
-                      boolean operator) {
+                      boolean useVarargs) {
         if (sym.kind == ERR ||
                 !sym.isInheritedIn(site.tsym, types)) {
             return bestSoFar;
@@ -1441,16 +1436,13 @@
         try {
             Type mt = rawInstantiate(env, site, sym, null, argtypes, typeargtypes,
                                allowBoxing, useVarargs, types.noWarnings);
-            if (!operator || verboseResolutionMode.contains(VerboseResolutionMode.PREDEF))
-                currentResolutionContext.addApplicableCandidate(sym, mt);
+            currentResolutionContext.addApplicableCandidate(sym, mt);
         } catch (InapplicableMethodException ex) {
-            if (!operator)
-                currentResolutionContext.addInapplicableCandidate(sym, ex.getDiagnostic());
+            currentResolutionContext.addInapplicableCandidate(sym, ex.getDiagnostic());
             switch (bestSoFar.kind) {
                 case ABSENT_MTH:
                     return new InapplicableSymbolError(currentResolutionContext);
                 case WRONG_MTH:
-                    if (operator) return bestSoFar;
                     bestSoFar = new InapplicableSymbolsError(currentResolutionContext);
                 default:
                     return bestSoFar;
@@ -1463,8 +1455,7 @@
         }
         return (bestSoFar.kind.isOverloadError() && bestSoFar.kind != AMBIGUOUS)
             ? sym
-            : mostSpecific(argtypes, sym, bestSoFar, env, site,
-                           allowBoxing && operator, useVarargs);
+            : mostSpecific(argtypes, sym, bestSoFar, env, site, useVarargs);
     }
 
     /* Return the most specific of the two methods for a call,
@@ -1481,15 +1472,14 @@
                         Symbol m2,
                         Env<AttrContext> env,
                         final Type site,
-                        boolean allowBoxing,
                         boolean useVarargs) {
         switch (m2.kind) {
         case MTH:
             if (m1 == m2) return m1;
             boolean m1SignatureMoreSpecific =
-                    signatureMoreSpecific(argtypes, env, site, m1, m2, allowBoxing, useVarargs);
+                    signatureMoreSpecific(argtypes, env, site, m1, m2, useVarargs);
             boolean m2SignatureMoreSpecific =
-                    signatureMoreSpecific(argtypes, env, site, m2, m1, allowBoxing, useVarargs);
+                    signatureMoreSpecific(argtypes, env, site, m2, m1, useVarargs);
             if (m1SignatureMoreSpecific && m2SignatureMoreSpecific) {
                 Type mt1 = types.memberType(site, m1);
                 Type mt2 = types.memberType(site, m2);
@@ -1531,7 +1521,7 @@
             boolean m1MoreSpecificThanAnyAmbiguous = true;
             boolean allAmbiguousMoreSpecificThanM1 = true;
             for (Symbol s : e.ambiguousSyms) {
-                Symbol moreSpecific = mostSpecific(argtypes, m1, s, env, site, allowBoxing, useVarargs);
+                Symbol moreSpecific = mostSpecific(argtypes, m1, s, env, site, useVarargs);
                 m1MoreSpecificThanAnyAmbiguous &= moreSpecific == m1;
                 allAmbiguousMoreSpecificThanM1 &= moreSpecific == s;
             }
@@ -1547,7 +1537,7 @@
         }
     }
     //where
-    private boolean signatureMoreSpecific(List<Type> actuals, Env<AttrContext> env, Type site, Symbol m1, Symbol m2, boolean allowBoxing, boolean useVarargs) {
+    private boolean signatureMoreSpecific(List<Type> actuals, Env<AttrContext> env, Type site, Symbol m1, Symbol m2, boolean useVarargs) {
         noteWarner.clear();
         int maxLength = Math.max(
                             Math.max(m1.type.getParameterTypes().length(), actuals.length()),
@@ -1557,10 +1547,10 @@
             currentResolutionContext = new MethodResolutionContext();
             currentResolutionContext.step = prevResolutionContext.step;
             currentResolutionContext.methodCheck =
-                    prevResolutionContext.methodCheck.mostSpecificCheck(actuals, !allowBoxing);
+                    prevResolutionContext.methodCheck.mostSpecificCheck(actuals);
             Type mst = instantiate(env, site, m2, null,
                     adjustArgs(types.cvarLowerBounds(types.memberType(site, m1).getParameterTypes()), m1, maxLength, useVarargs), null,
-                    allowBoxing, useVarargs, noteWarner);
+                    false, useVarargs, noteWarner);
             return mst != null &&
                     !noteWarner.hasLint(Lint.LintCategory.UNCHECKED);
         } finally {
@@ -1623,11 +1613,10 @@
             Symbol bestSoFar,
             boolean allowBoxing,
             boolean useVarargs,
-            boolean operator,
             boolean abstractok) {
         for (Symbol s : sc.getSymbolsByName(name, new LookupFilter(abstractok))) {
             bestSoFar = selectBest(env, site, argtypes, typeargtypes, s,
-                    bestSoFar, allowBoxing, useVarargs, operator);
+                    bestSoFar, allowBoxing, useVarargs);
         }
         return bestSoFar;
     }
@@ -1667,8 +1656,7 @@
                       List<Type> argtypes,
                       List<Type> typeargtypes,
                       boolean allowBoxing,
-                      boolean useVarargs,
-                      boolean operator) {
+                      boolean useVarargs) {
         Symbol bestSoFar = methodNotFound;
         bestSoFar = findMethod(env,
                           site,
@@ -1678,8 +1666,7 @@
                           site.tsym.type,
                           bestSoFar,
                           allowBoxing,
-                          useVarargs,
-                          operator);
+                          useVarargs);
         return bestSoFar;
     }
     // where
@@ -1691,15 +1678,14 @@
                               Type intype,
                               Symbol bestSoFar,
                               boolean allowBoxing,
-                              boolean useVarargs,
-                              boolean operator) {
+                              boolean useVarargs) {
         @SuppressWarnings({"unchecked","rawtypes"})
         List<Type>[] itypes = (List<Type>[])new List[] { List.<Type>nil(), List.<Type>nil() };
 
         InterfaceLookupPhase iphase = InterfaceLookupPhase.ABSTRACT_OK;
         for (TypeSymbol s : superclasses(intype)) {
             bestSoFar = findMethodInScope(env, site, name, argtypes, typeargtypes,
-                    s.members(), bestSoFar, allowBoxing, useVarargs, operator, true);
+                    s.members(), bestSoFar, allowBoxing, useVarargs, true);
             if (name == names.init) return bestSoFar;
             iphase = (iphase == null) ? null : iphase.update(s, this);
             if (iphase != null) {
@@ -1720,7 +1706,7 @@
                 if (iphase2 == InterfaceLookupPhase.DEFAULT_OK &&
                         (itype.tsym.flags() & DEFAULT) == 0) continue;
                 bestSoFar = findMethodInScope(env, site, name, argtypes, typeargtypes,
-                        itype.tsym.members(), bestSoFar, allowBoxing, useVarargs, operator, true);
+                        itype.tsym.members(), bestSoFar, allowBoxing, useVarargs, true);
                 if (concrete != bestSoFar &&
                     concrete.kind.isValid() &&
                     bestSoFar.kind.isValid() &&
@@ -1833,7 +1819,7 @@
             if (isStatic(env1)) staticOnly = true;
             Symbol sym = findMethod(
                 env1, env1.enclClass.sym.type, name, argtypes, typeargtypes,
-                allowBoxing, useVarargs, false);
+                allowBoxing, useVarargs);
             if (sym.exists()) {
                 if (staticOnly &&
                     sym.kind == MTH &&
@@ -1848,7 +1834,7 @@
         }
 
         Symbol sym = findMethod(env, syms.predefClass.type, name, argtypes,
-                                typeargtypes, allowBoxing, useVarargs, false);
+                                typeargtypes, allowBoxing, useVarargs);
         if (sym.exists())
             return sym;
 
@@ -1862,7 +1848,7 @@
                 bestSoFar = selectBest(env, origin.type,
                                        argtypes, typeargtypes,
                                        currentSym, bestSoFar,
-                                       allowBoxing, useVarargs, false);
+                                       allowBoxing, useVarargs);
             }
         }
         if (bestSoFar.exists())
@@ -1878,7 +1864,7 @@
                 bestSoFar = selectBest(env, origin.type,
                                        argtypes, typeargtypes,
                                        currentSym, bestSoFar,
-                                       allowBoxing, useVarargs, false);
+                                       allowBoxing, useVarargs);
             }
         }
         return bestSoFar;
@@ -2269,9 +2255,7 @@
                         (typeargtypes == null || !Type.isErroneous(typeargtypes));
         }
         public List<Type> getArgumentTypes(ResolveError errSym, Symbol accessedSym, Name name, List<Type> argtypes) {
-            return (syms.operatorNames.contains(name)) ?
-                    argtypes :
-                    Type.map(argtypes, new ResolveDeferredRecoveryMap(AttrMode.SPECULATIVE, accessedSym, currentResolutionContext.step));
+            return Type.map(argtypes, new ResolveDeferredRecoveryMap(AttrMode.SPECULATIVE, accessedSym, currentResolutionContext.step));
         }
     };
 
@@ -2375,7 +2359,7 @@
             Symbol doLookup(Env<AttrContext> env, MethodResolutionPhase phase) {
                 return findMethod(env, site, name, argtypes, typeargtypes,
                         phase.isBoxingRequired(),
-                        phase.isVarargsRequired(), false);
+                        phase.isVarargsRequired());
             }
             @Override
             Symbol access(Env<AttrContext> env, DiagnosticPosition pos, Symbol location, Symbol sym) {
@@ -2506,7 +2490,7 @@
         Symbol sym = findMethod(env, site,
                                     names.init, argtypes,
                                     typeargtypes, allowBoxing,
-                                    useVarargs, false);
+                                    useVarargs);
         chk.checkDeprecated(pos, env.info.scope.owner, sym);
         return sym;
     }
@@ -2587,71 +2571,12 @@
                             newConstr,
                             bestSoFar,
                             allowBoxing,
-                            useVarargs,
-                            false);
+                            useVarargs);
             }
         }
         return bestSoFar;
     }
 
-
-
-    /** Resolve operator.
-     *  @param pos       The position to use for error reporting.
-     *  @param optag     The tag of the operation tree.
-     *  @param env       The environment current at the operation.
-     *  @param argtypes  The types of the operands.
-     */
-    Symbol resolveOperator(DiagnosticPosition pos, JCTree.Tag optag,
-                           Env<AttrContext> env, List<Type> argtypes) {
-        MethodResolutionContext prevResolutionContext = currentResolutionContext;
-        try {
-            currentResolutionContext = new MethodResolutionContext();
-            Name name = treeinfo.operatorName(optag);
-            return lookupMethod(env, pos, syms.predefClass, currentResolutionContext,
-                    new BasicLookupHelper(name, syms.predefClass.type, argtypes, null, BOX) {
-                @Override
-                Symbol doLookup(Env<AttrContext> env, MethodResolutionPhase phase) {
-                    return findMethod(env, site, name, argtypes, typeargtypes,
-                            phase.isBoxingRequired(),
-                            phase.isVarargsRequired(), true);
-                }
-                @Override
-                Symbol access(Env<AttrContext> env, DiagnosticPosition pos, Symbol location, Symbol sym) {
-                    return accessMethod(sym, pos, env.enclClass.sym.type, name,
-                          false, argtypes, null);
-                }
-            });
-        } finally {
-            currentResolutionContext = prevResolutionContext;
-        }
-    }
-
-    /** Resolve operator.
-     *  @param pos       The position to use for error reporting.
-     *  @param optag     The tag of the operation tree.
-     *  @param env       The environment current at the operation.
-     *  @param arg       The type of the operand.
-     */
-    Symbol resolveUnaryOperator(DiagnosticPosition pos, JCTree.Tag optag, Env<AttrContext> env, Type arg) {
-        return resolveOperator(pos, optag, env, List.of(arg));
-    }
-
-    /** Resolve binary operator.
-     *  @param pos       The position to use for error reporting.
-     *  @param optag     The tag of the operation tree.
-     *  @param env       The environment current at the operation.
-     *  @param left      The types of the left operand.
-     *  @param right     The types of the right operand.
-     */
-    Symbol resolveBinaryOperator(DiagnosticPosition pos,
-                                 JCTree.Tag optag,
-                                 Env<AttrContext> env,
-                                 Type left,
-                                 Type right) {
-        return resolveOperator(pos, optag, env, List.of(left, right));
-    }
-
     Symbol getMemberReference(DiagnosticPosition pos,
             Env<AttrContext> env,
             JCMemberReference referenceTree,
@@ -3122,7 +3047,7 @@
         @Override
         final Symbol lookup(Env<AttrContext> env, MethodResolutionPhase phase) {
             return findMethod(env, site, name, argtypes, typeargtypes,
-                    phase.isBoxingRequired(), phase.isVarargsRequired(), syms.operatorNames.contains(name));
+                    phase.isBoxingRequired(), phase.isVarargsRequired());
         }
 
         @Override
@@ -3217,7 +3142,7 @@
             MethodSymbol arrayConstr = new MethodSymbol(PUBLIC, name, null, site.tsym);
             arrayConstr.type = new MethodType(List.<Type>of(syms.intType), site, List.<Type>nil(), syms.methodClass);
             sc.enter(arrayConstr);
-            return findMethodInScope(env, site, name, argtypes, typeargtypes, sc, methodNotFound, phase.isBoxingRequired(), phase.isVarargsRequired(), false, false);
+            return findMethodInScope(env, site, name, argtypes, typeargtypes, sc, methodNotFound, phase.isBoxingRequired(), phase.isVarargsRequired(), false);
         }
 
         @Override
@@ -3252,7 +3177,7 @@
             Symbol sym = needsInference ?
                 findDiamond(env, site, argtypes, typeargtypes, phase.isBoxingRequired(), phase.isVarargsRequired()) :
                 findMethod(env, site, name, argtypes, typeargtypes,
-                        phase.isBoxingRequired(), phase.isVarargsRequired(), syms.operatorNames.contains(name));
+                        phase.isBoxingRequired(), phase.isVarargsRequired());
             return (sym.kind != MTH ||
                     site.getEnclosingType().hasTag(NONE) ||
                     hasEnclosingInstance(env, site)) ?
@@ -3607,16 +3532,6 @@
             if (name == names.error)
                 return null;
 
-            if (syms.operatorNames.contains(name)) {
-                boolean isUnaryOp = argtypes.size() == 1;
-                String key = argtypes.size() == 1 ?
-                    "operator.cant.be.applied" :
-                    "operator.cant.be.applied.1";
-                Type first = argtypes.head;
-                Type second = !isUnaryOp ? argtypes.tail.head : null;
-                return diags.create(dkind, log.currentSource(), pos,
-                        key, name, first, second);
-            }
             boolean hasLocation = false;
             if (location == null) {
                 location = site.tsym;
@@ -3716,36 +3631,24 @@
             if (name == names.error)
                 return null;
 
-            if (syms.operatorNames.contains(name)) {
-                boolean isUnaryOp = argtypes.size() == 1;
-                String key = argtypes.size() == 1 ?
-                    "operator.cant.be.applied" :
-                    "operator.cant.be.applied.1";
-                Type first = argtypes.head;
-                Type second = !isUnaryOp ? argtypes.tail.head : null;
-                return diags.create(dkind, log.currentSource(), pos,
-                        key, name, first, second);
+            Pair<Symbol, JCDiagnostic> c = errCandidate();
+            if (compactMethodDiags) {
+                JCDiagnostic simpleDiag =
+                    MethodResolutionDiagHelper.rewrite(diags, pos, log.currentSource(), dkind, c.snd);
+                if (simpleDiag != null) {
+                    return simpleDiag;
+                }
             }
-            else {
-                Pair<Symbol, JCDiagnostic> c = errCandidate();
-                if (compactMethodDiags) {
-                    JCDiagnostic simpleDiag =
-                        MethodResolutionDiagHelper.rewrite(diags, pos, log.currentSource(), dkind, c.snd);
-                    if (simpleDiag != null) {
-                        return simpleDiag;
-                    }
-                }
-                Symbol ws = c.fst.asMemberOf(site, types);
-                return diags.create(dkind, log.currentSource(), pos,
-                          "cant.apply.symbol",
-                          kindName(ws),
-                          ws.name == names.init ? ws.owner.name : ws.name,
-                          methodArguments(ws.type.getParameterTypes()),
-                          methodArguments(argtypes),
-                          kindName(ws.owner),
-                          ws.owner.type,
-                          c.snd);
-            }
+            Symbol ws = c.fst.asMemberOf(site, types);
+            return diags.create(dkind, log.currentSource(), pos,
+                      "cant.apply.symbol",
+                      kindName(ws),
+                      ws.name == names.init ? ws.owner.name : ws.name,
+                      methodArguments(ws.type.getParameterTypes()),
+                      methodArguments(argtypes),
+                      kindName(ws.owner),
+                      ws.owner.type,
+                      c.snd);
         }
 
         @Override
--- a/langtools/src/jdk.compiler/share/classes/com/sun/tools/javac/resources/compiler.properties	Fri Feb 13 17:00:45 2015 -0500
+++ b/langtools/src/jdk.compiler/share/classes/com/sun/tools/javac/resources/compiler.properties	Mon Feb 16 12:24:25 2015 +0000
@@ -828,7 +828,7 @@
 compiler.err.not.encl.class=\
     not an enclosing class: {0}
 
-# 0: name, 1: type, 2: unused
+# 0: name, 1: type
 compiler.err.operator.cant.be.applied=\
     bad operand type {1} for unary operator ''{0}''
 
--- a/langtools/src/jdk.compiler/share/classes/com/sun/tools/javac/tree/TreeInfo.java	Fri Feb 13 17:00:45 2015 -0500
+++ b/langtools/src/jdk.compiler/share/classes/com/sun/tools/javac/tree/TreeInfo.java	Mon Feb 16 12:24:25 2015 +0000
@@ -51,62 +51,6 @@
  *  deletion without notice.</b>
  */
 public class TreeInfo {
-    protected static final Context.Key<TreeInfo> treeInfoKey = new Context.Key<>();
-
-    public static TreeInfo instance(Context context) {
-        TreeInfo instance = context.get(treeInfoKey);
-        if (instance == null)
-            instance = new TreeInfo(context);
-        return instance;
-    }
-
-    /** The names of all operators.
-     */
-    private Name[] opname = new Name[Tag.getNumberOfOperators()];
-
-    private void setOpname(Tag tag, String name, Names names) {
-         setOpname(tag, names.fromString(name));
-     }
-     private void setOpname(Tag tag, Name name) {
-         opname[tag.operatorIndex()] = name;
-     }
-
-    private TreeInfo(Context context) {
-        context.put(treeInfoKey, this);
-
-        Names names = Names.instance(context);
-        /*  Internally we use +++, --- for unary +, - to reduce +, - operators
-         *  overloading
-         */
-        setOpname(POS, "+++", names);
-        setOpname(NEG, "---", names);
-        setOpname(NOT, "!", names);
-        setOpname(COMPL, "~", names);
-        setOpname(PREINC, "++", names);
-        setOpname(PREDEC, "--", names);
-        setOpname(POSTINC, "++", names);
-        setOpname(POSTDEC, "--", names);
-        setOpname(NULLCHK, "<*nullchk*>", names);
-        setOpname(OR, "||", names);
-        setOpname(AND, "&&", names);
-        setOpname(EQ, "==", names);
-        setOpname(NE, "!=", names);
-        setOpname(LT, "<", names);
-        setOpname(GT, ">", names);
-        setOpname(LE, "<=", names);
-        setOpname(GE, ">=", names);
-        setOpname(BITOR, "|", names);
-        setOpname(BITXOR, "^", names);
-        setOpname(BITAND, "&", names);
-        setOpname(SL, "<<", names);
-        setOpname(SR, ">>", names);
-        setOpname(USR, ">>>", names);
-        setOpname(PLUS, "+", names);
-        setOpname(MINUS, names.hyphen);
-        setOpname(MUL, names.asterisk);
-        setOpname(DIV, names.slash);
-        setOpname(MOD, "%", names);
-    }
 
     public static List<JCExpression> args(JCTree t) {
         switch (t.getTag()) {
@@ -119,12 +63,6 @@
         }
     }
 
-    /** Return name of operator with given tree tag.
-     */
-    public Name operatorName(JCTree.Tag tag) {
-        return opname[tag.operatorIndex()];
-    }
-
     /** Is tree a constructor declaration?
      */
     public static boolean isConstructor(JCTree tree) {
--- a/langtools/test/tools/javac/7102515/T7102515.out	Fri Feb 13 17:00:45 2015 -0500
+++ b/langtools/test/tools/javac/7102515/T7102515.out	Mon Feb 16 12:24:25 2015 +0000
@@ -1,3 +1,3 @@
 T7102515.java:9:41: compiler.err.operator.cant.be.applied.1: +, T7102515, T7102515
-T7102515.java:10:32: compiler.err.operator.cant.be.applied: ++, T7102515, null
+T7102515.java:10:32: compiler.err.operator.cant.be.applied: ++, T7102515
 2 errors
--- a/langtools/test/tools/javac/diags/examples/IncomparableTypes.java	Fri Feb 13 17:00:45 2015 -0500
+++ b/langtools/test/tools/javac/diags/examples/IncomparableTypes.java	Mon Feb 16 12:24:25 2015 +0000
@@ -24,5 +24,5 @@
 // key: compiler.err.incomparable.types
 
 class X {
-    boolean b = (this == 1);
+    boolean b = (this == "");
 }
--- a/langtools/test/tools/javac/expression/NullAppend.out	Fri Feb 13 17:00:45 2015 -0500
+++ b/langtools/test/tools/javac/expression/NullAppend.out	Mon Feb 16 12:24:25 2015 +0000
@@ -1,2 +1,2 @@
-NullAppend.java:11:16: compiler.err.operator.cant.be.applied.1: +, compiler.misc.type.null, compiler.misc.type.null
+NullAppend.java:11:21: compiler.err.operator.cant.be.applied.1: +, compiler.misc.type.null, compiler.misc.type.null
 1 error
--- a/langtools/test/tools/javac/expression/NullAppend2.out	Fri Feb 13 17:00:45 2015 -0500
+++ b/langtools/test/tools/javac/expression/NullAppend2.out	Mon Feb 16 12:24:25 2015 +0000
@@ -1,2 +1,2 @@
-NullAppend2.java:10:16: compiler.err.operator.cant.be.applied.1: +, compiler.misc.type.null, int
+NullAppend2.java:10:21: compiler.err.operator.cant.be.applied.1: +, compiler.misc.type.null, int
 1 error
--- a/langtools/test/tools/javac/resolve/tests/PrimitiveBinopOverload.java	Fri Feb 13 17:00:45 2015 -0500
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,71 +0,0 @@
-/*
- * Copyright (c) 2013, Oracle and/or its affiliates. All rights reserved.
- * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
- *
- * This code is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License version 2 only, as
- * published by the Free Software Foundation.
- *
- * This code is distributed in the hope that it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
- * version 2 for more details (a copy is included in the LICENSE file that
- * accompanied this code).
- *
- * You should have received a copy of the GNU General Public License version
- * 2 along with this work; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
- *
- * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
- * or visit www.oracle.com if you need additional information or have any
- * questions.
- */
-
-@TraceResolve
-class PrimitiveBinopOverload {
-
-    @Candidate(applicable=Phase.BASIC, mostSpecific=true)
-    int _plus(int x, int y) { return -1; }
-    @Candidate(applicable=Phase.BASIC)
-    long _plus(long x, long y) { return -1; }
-    @Candidate(applicable=Phase.BASIC)
-    float _plus(float x, float y) { return -1; }
-    @Candidate(applicable=Phase.BASIC)
-    double _plus(double x, double y) { return -1; }
-    //not a candidate
-    Object _plus(Object x, Object y) { return -1; }
-
-    @Candidate(applicable= { Phase.BASIC, Phase.BOX }, mostSpecific=true)
-    int _minus(int x, int y) { return -1; }
-    @Candidate(applicable= { Phase.BASIC, Phase.BOX })
-    long _minus(long x, long y) { return -1; }
-    @Candidate(applicable= { Phase.BASIC, Phase.BOX })
-    float _minus(float x, float y) { return -1; }
-    @Candidate(applicable= { Phase.BASIC, Phase.BOX })
-    double _minus(double x, double y) { return -1; }
-
-    @Candidate(applicable= { Phase.BASIC, Phase.BOX }, mostSpecific=true)
-    int _mul(int x, int y) { return -1; }
-    @Candidate(applicable= { Phase.BASIC, Phase.BOX })
-    long _mul(long x, long y) { return -1; }
-    @Candidate(applicable= { Phase.BASIC, Phase.BOX })
-    float _mul(float x, float y) { return -1; }
-    @Candidate(applicable= { Phase.BASIC, Phase.BOX })
-    double _mul(double x, double y) { return -1; }
-
-    @Candidate(applicable= { Phase.BASIC, Phase.BOX }, mostSpecific=true)
-    int _div(int x, int y) { return -1; }
-    @Candidate(applicable= { Phase.BASIC, Phase.BOX })
-    long _div(long x, long y) { return -1; }
-    @Candidate(applicable= { Phase.BASIC, Phase.BOX })
-    float _div(float x, float y) { return -1; }
-    @Candidate(applicable= { Phase.BASIC, Phase.BOX })
-    double _div(double x, double y) { return -1; }
-
-    {
-        int i1 = 1 + 1;
-        int i2 = 5 - new Integer(3);
-        int i3 = new Integer(5) * 3;
-        int i4 = new Integer(6) / new Integer(2);
-    }
-}