8071241: Investigate alternate strategy for type-checking operators
Summary: Separat operator lookup logic from overload resolution.
Reviewed-by: jjg, jlahoda, sadayapalam
--- 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);
- }
-}