--- old/src/share/classes/com/sun/tools/javac/code/Types.java 2013-06-07 11:19:07.811508404 -0400 +++ new/src/share/classes/com/sun/tools/javac/code/Types.java 2013-06-07 11:19:07.469505574 -0400 @@ -1317,6 +1317,23 @@ } // + /** + * 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) { + boolean tPrimitive = t.isPrimitive(); + boolean sPrimitive = s.isPrimitive(); + if (!tPrimitive && !sPrimitive) { + return isCastable(s, t, warn) || isCastable(t, s, warn); + } else { + return false; + } + } + // public boolean isCastable(Type t, Type s) { return isCastable(t, s, noWarnings); --- old/src/share/classes/com/sun/tools/javac/comp/Attr.java 2013-06-07 11:19:09.147519454 -0400 +++ new/src/share/classes/com/sun/tools/javac/comp/Attr.java 2013-06-07 11:19:08.804516617 -0400 @@ -2991,6 +2991,8 @@ !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(), @@ -3018,9 +3020,11 @@ } // Check that argument types of a reference ==, != are - // castable to each other, (JLS???). + // 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.isCastable(left, right, new Warner(tree.pos()))) { + if (!types.isEqualityComparable(left, right, + new Warner(tree.pos()))) { log.error(tree.pos(), "incomparable.types", left, right); } } --- old/test/tools/javac/lambda/LambdaConv01.java 2013-06-07 11:19:10.538530960 -0400 +++ new/test/tools/javac/lambda/LambdaConv01.java 2013-06-07 11:19:10.141527676 -0400 @@ -67,7 +67,7 @@ assertTrue(3 == f1.foo()); //Covariant returns: TU f2 = (Integer x) -> x; - assertTrue(3 == f2.foo(3)); + assertTrue(3 == f2.foo(3).intValue()); //Method resolution with boxing: int res = LambdaConv01.exec((Integer x) -> x, 3); assertTrue(3 == res); @@ -86,7 +86,7 @@ assertTrue(3 == f1.foo()); //Covariant returns: TU f2 = (Integer x) -> x; - assertTrue(3 == f2.foo(3)); + assertTrue(3 == f2.foo(3).intValue()); //Method resolution with boxing: int res = LambdaConv01.exec((Integer x) -> x, 3); assertTrue(3 == res); @@ -105,7 +105,7 @@ assertTrue(3 == f1.foo()); //Covariant returns: TU f2 = (Integer x) -> x; - assertTrue(3 == f2.foo(3)); + assertTrue(3 == f2.foo(3).intValue()); //Method resolution with boxing: int res = LambdaConv01.exec((Integer x) -> x, 3); assertTrue(3 == res); @@ -124,7 +124,7 @@ assertTrue(3 == f1.foo()); //Covariant returns: TU f2 = (Integer x) -> x; - assertTrue(3 == f2.foo(3)); + assertTrue(3 == f2.foo(3).intValue()); //Method resolution with boxing: int res = LambdaConv01.exec((Integer x) -> x, 3); assertTrue(3 == res); --- old/test/tools/javac/lambda/LambdaExpr15.java 2013-06-07 11:19:11.815541524 -0400 +++ new/test/tools/javac/lambda/LambdaExpr15.java 2013-06-07 11:19:11.447538480 -0400 @@ -48,7 +48,7 @@ new Object() { String get() { return ""; } }; - assertTrue(t == 1); + assertTrue((Integer)t == 1); }; ba1.apply(1); @@ -58,7 +58,7 @@ String get() { return ""; } }; new A(); - assertTrue(t == 2); + assertTrue((Integer)t == 2); }; ba2.apply(2); assertTrue(assertionCount == 2); --- old/test/tools/javac/lambda/typeInference/InferenceTest2b.java 2013-06-07 11:19:13.046551706 -0400 +++ new/test/tools/javac/lambda/typeInference/InferenceTest2b.java 2013-06-07 11:19:12.696548810 -0400 @@ -64,7 +64,7 @@ void m2(SAM6 s) { System.out.println("m2()"); - assertTrue(s.m6(1, 2) == 1); + assertTrue(s.m6(1, 2).equals(Integer.valueOf(1))); } void m3(SAM6 s) { --- /dev/null 2013-06-06 16:05:09.449150020 -0400 +++ new/test/tools/javac/8013357/ObjectZeroCompare.java 2013-06-07 11:19:13.802557960 -0400 @@ -0,0 +1,400 @@ +/* + * 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. + */ + +/* + * @test + * @bug 8013357 + * @summary javac should correctly enforce binary comparison rules. + */ +import java.io.File; +import java.io.FileWriter; +import java.io.IOException; +import java.io.PrintWriter; +import java.io.StringWriter; + +public class ObjectZeroCompare { + static final String LeftObject_name = "LeftObject"; + static final String LeftObject_contents = + "public class LeftObject {\n" + + " LeftObject() {}\n" + + " boolean foo0(Object o) {\n" + + " return o == 0;\n" + + " }\n" + + "}\n"; + static final String RightObject_name = "RightObject"; + static final String RightObject_contents = + "public class RightObject {\n" + + " RightObject() {}\n" + + " boolean foo0(Object o) {\n" + + " return 0 == o;\n" + + " }\n" + + "}\n"; + static final String LeftUncastable_name = "LeftUncastable"; + static final String LeftUncastable_contents = + "public class LeftUncastable {\n" + + " LeftUncastable() {}\n" + + " boolean foo0(String o, Integer i) {\n" + + " return o == i;\n" + + " }\n" + + "}\n"; + static final String RightUncastable_name = "RightUncastable"; + static final String RightUncastable_contents = + "public class RightUncastable {\n" + + " RightUncastable() {}\n" + + " boolean foo0(String o, Integer i) {\n" + + " return i == o;\n" + + " }\n" + + "}\n"; + static final String LeftNumber_name = "LeftNumber"; + static final String LeftNumber_contents = + "public class LeftNumber {\n" + + " LeftNumber() {}\n" + + " boolean bar0(Number o) {\n" + + " return o == 0;\n" + + " }\n" + + "}\n"; + static final String RightNumber_name = "RightNumber"; + static final String RightNumber_contents = + "public class RightNumber {\n" + + " RightNumber() {}\n" + + " boolean bar0(Number o) {\n" + + " return 0 == o;\n" + + " }\n" + + "}\n"; + static final String LeftIntegerSuper_name = "LeftIntegerSuper"; + static final String LeftIntegerSuper_contents = + "import java.util.List;\n" + + "public class LeftIntegerSuper {\n" + + " LeftIntegerSuper() {}\n" + + " boolean bar0(List o) {\n" + + " return o.get(0) == 0;\n" + + " }\n" + + "}\n"; + static final String RightIntegerSuper_name = "RightIntegerSuper"; + static final String RightIntegerSuper_contents = + "import java.util.List;\n" + + "public class RightIntegerSuper {\n" + + " RightIntegerSuper() {}\n" + + " boolean bar0(List o) {\n" + + " return 0 == o.get(0);\n" + + " }\n" + + "}\n"; + static final String LeftIntBool_name = "LeftIntBool"; + static final String LeftIntBool_contents = + "public class LeftIntBool {\n" + + " LeftIntBool() {}\n" + + " boolean quux0() {\n" + + " int a = 0;\n" + + " boolean b = false;\n" + + " return a == b;\n" + + " }\n" + + "}\n"; + static final String RightIntBool_name = "RightIntBool"; + static final String RightIntBool_contents = + "public class RightIntBool {\n" + + " RightIntBool() {}\n" + + " boolean quux0() {\n" + + " int a = 0;\n" + + " boolean b = false;\n" + + " return b == a;\n" + + " }\n" + + "}\n"; + static final String LeftCastable_name = "LeftCastable"; + static final String LeftCastable_contents = + "public class LeftCastable {\n" + + " LeftCastable() {}\n" + + " boolean foo0(Number n, Integer i) {\n" + + " return n == i;\n" + + " }\n" + + "}\n"; + static final String RightCastable_name = "RightCastable"; + static final String RightCastable_contents = + "public class RightCastable {\n" + + " RightCastable() {}\n" + + " boolean foo0(Number n, Integer i) {\n" + + " return i == n;\n" + + " }\n" + + "}\n"; + static final String LeftInteger_name = "LeftInteger"; + static final String LeftInteger_contents = + "public class LeftInteger {\n" + + " LeftInteger() {}\n" + + " boolean baz0(Integer o) {\n" + + " return 0 == o;\n" + + " }\n" + + "}\n"; + static final String RightInteger_name = "RightInteger"; + static final String RightInteger_contents = + "public class RightInteger {\n" + + " RightInteger() {}\n" + + " boolean baz0(Integer o) {\n" + + " return 0 == o;\n" + + " }\n" + + "}\n"; + static final String LeftDouble_name = "LeftDouble"; + static final String LeftDouble_contents = + "public class LeftDouble {\n" + + " LeftDouble() {}\n" + + " boolean qux0(Double o) {\n" + + " return o == 0.0;\n" + + " }\n" + + "}\n"; + static final String RightDouble_name = "RightDouble"; + static final String RightDouble_contents = + "public class RightDouble {\n" + + " RightDouble() {}\n" + + " boolean qux0(Double o) {\n" + + " return o == 0.0;\n" + + " }\n" + + "}\n"; + static final String LeftBoolean_name = "LeftBoolean"; + static final String LeftBoolean_contents = + "public class LeftBoolean {\n" + + " LeftBoolean() {}\n" + + " boolean quux0(Boolean b) {\n" + + " return true == b;\n" + + " }\n" + + "}\n"; + static final String RightBoolean_name = "RightBoolean"; + static final String RightBoolean_contents = + "public class RightBoolean {\n" + + " RightBoolean() {}\n" + + " boolean quux0(Boolean b) {\n" + + " return true == b;\n" + + " }\n" + + "}\n"; + static final String LeftInt_name = "LeftInt"; + static final String LeftInt_contents = + "public class LeftInt {\n" + + " LeftInt() {}\n" + + " boolean quux0() {\n" + + " int a = 0;\n" + + " int b = 0;\n" + + " return a == b;\n" + + " }\n" + + "}\n"; + static final String RightInt_name = "RightInt"; + static final String RightInt_contents = + "public class RightInt {\n" + + " RightInt() {}\n" + + " boolean quux0() {\n" + + " int a = 0;\n" + + " int b = 0;\n" + + " return b == a;\n" + + " }\n" + + "}\n"; + static final String LeftIntLong_name = "LeftIntLong"; + static final String LeftIntLong_contents = + "public class LeftIntLong {\n" + + " LeftIntLong() {}\n" + + " boolean quux0() {\n" + + " int a = 0;\n" + + " long b = 0;\n" + + " return a == b;\n" + + " }\n" + + "}\n"; + static final String RightIntLong_name = "RightIntLong"; + static final String RightIntLong_contents = + "public class RightIntLong {\n" + + " RightIntLong() {}\n" + + " boolean quux0() {\n" + + " int a = 0;\n" + + " long b = 0;\n" + + " return b == a;\n" + + " }\n" + + "}\n"; + static final String LeftSubtype_name = "LeftSubtype"; + static final String LeftSubtype_contents = + "import java.util.*;\n" + + "public class LeftSubtype {\n" + + " LeftSubtype() {}\n" + + " boolean quux0() {\n" + + " Collection a = null;\n" + + " List b = null;\n" + + " return a == b;\n" + + " }\n" + + "}\n"; + static final String RightSubtype_name = "RightSubtype"; + static final String RightSubtype_contents = + "import java.util.*;\n" + + "public class RightSubtype {\n" + + " RightSubtype() {}\n" + + " boolean quux0() {\n" + + " Collection a = null;\n" + + " List b = null;\n" + + " return b == a;\n" + + " }\n" + + "}\n"; + static final File classesdir = new File("8013357"); + + private int errors = 0; + + public static void main(String... args) throws Exception { + new ObjectZeroCompare().run(); + } + + void run() throws Exception { + classesdir.mkdir(); + final File LeftObject_java = + writeFile(classesdir, LeftObject_name + ".java", + LeftObject_contents); + final File RightObject_java = + writeFile(classesdir, RightObject_name + ".java", + RightObject_contents); + final File LeftUncastable_java = + writeFile(classesdir, LeftUncastable_name + ".java", + LeftUncastable_contents); + final File RightUncastable_java = + writeFile(classesdir, RightUncastable_name + ".java", + RightUncastable_contents); + final File LeftNumber_java = + writeFile(classesdir, LeftNumber_name + ".java", + LeftNumber_contents); + final File RightNumber_java = + writeFile(classesdir, RightNumber_name + ".java", + RightNumber_contents); + final File LeftIntegerSuper_java = + writeFile(classesdir, LeftIntegerSuper_name + ".java", + LeftIntegerSuper_contents); + final File RightIntegerSuper_java = + writeFile(classesdir, RightIntegerSuper_name + ".java", + RightIntegerSuper_contents); + final File LeftIntBool_java = + writeFile(classesdir, LeftIntBool_name + ".java", + LeftIntBool_contents); + final File RightIntBool_java = + writeFile(classesdir, RightIntBool_name + ".java", + RightIntBool_contents); + final File LeftCastable_java = + writeFile(classesdir, LeftCastable_name + ".java", + LeftCastable_contents); + final File RightCastable_java = + writeFile(classesdir, RightCastable_name + ".java", + RightCastable_contents); + final File LeftInteger_java = + writeFile(classesdir, LeftInteger_name + ".java", + LeftInteger_contents); + final File RightInteger_java = + writeFile(classesdir, RightInteger_name + ".java", + RightInteger_contents); + final File LeftDouble_java = + writeFile(classesdir, LeftDouble_name + ".java", + LeftDouble_contents); + final File RightDouble_java = + writeFile(classesdir, RightDouble_name + ".java", + RightDouble_contents); + final File LeftBoolean_java = + writeFile(classesdir, LeftBoolean_name + ".java", + LeftBoolean_contents); + final File RightBoolean_java = + writeFile(classesdir, RightBoolean_name + ".java", + RightBoolean_contents); + final File LeftInt_java = + writeFile(classesdir, LeftInt_name + ".java", + LeftInt_contents); + final File RightInt_java = + writeFile(classesdir, RightInt_name + ".java", + RightInt_contents); + final File LeftIntLong_java = + writeFile(classesdir, LeftIntLong_name + ".java", + LeftIntLong_contents); + final File RightIntLong_java = + writeFile(classesdir, RightIntLong_name + ".java", + RightIntLong_contents); + final File LeftSubtype_java = + writeFile(classesdir, LeftSubtype_name + ".java", + LeftSubtype_contents); + final File RightSubtype_java = + writeFile(classesdir, RightSubtype_name + ".java", + RightSubtype_contents); + assert_compile_fail(LeftObject_java); + assert_compile_fail(RightObject_java); + assert_compile_fail(LeftUncastable_java); + assert_compile_fail(RightUncastable_java); + assert_compile_fail(LeftNumber_java); + assert_compile_fail(RightNumber_java); + assert_compile_fail(LeftIntegerSuper_java); + assert_compile_fail(RightIntegerSuper_java); + assert_compile_fail(LeftIntBool_java); + assert_compile_fail(RightIntBool_java); + assert_compile_succeed(LeftCastable_java); + assert_compile_succeed(RightCastable_java); + assert_compile_succeed(LeftInteger_java); + assert_compile_succeed(RightInteger_java); + assert_compile_succeed(LeftDouble_java); + assert_compile_succeed(RightDouble_java); + assert_compile_succeed(LeftBoolean_java); + assert_compile_succeed(RightBoolean_java); + assert_compile_succeed(LeftInt_java); + assert_compile_succeed(RightInt_java); + assert_compile_succeed(LeftIntLong_java); + assert_compile_succeed(RightIntLong_java); + assert_compile_succeed(LeftSubtype_java); + assert_compile_succeed(RightSubtype_java); + if (errors != 0) + throw new Exception("ObjectZeroCompare test failed with " + + errors + " errors."); + } + + int compile(final File file) { + final String filename = file.getPath(); + final String[] args = { filename }; + final StringWriter sw = new StringWriter(); + final PrintWriter pw = new PrintWriter(sw); + final int rc = com.sun.tools.javac.Main.compile(args, pw); + pw.close(); + System.err.println("Compiled " + filename + ", output:\n" + + sw.toString()); + return rc; + } + + void assert_compile_fail(final File file) { + final int rc = compile(file); + if (rc == 0) { + System.err.println("Compilation of " + file.getName() + + " didn't fail as expected."); + errors++; + } + } + + void assert_compile_succeed(final File file) { + final int rc = compile(file); + if (rc != 0) { + System.err.println("Compilation of " + file.getName() + + " didn't succeed as expected."); + errors++; + } + } + + File writeFile(final File dir, + final String path, + final String body) throws IOException { + final File f = new File(dir, path); + f.getParentFile().mkdirs(); + final FileWriter out = new FileWriter(f); + out.write(body); + out.close(); + return f; + } + +}