aoqi@0: /* aoqi@0: * Copyright (c) 2013, Oracle and/or its affiliates. All rights reserved. aoqi@0: * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. aoqi@0: * aoqi@0: * This code is free software; you can redistribute it and/or modify it aoqi@0: * under the terms of the GNU General Public License version 2 only, as aoqi@0: * published by the Free Software Foundation. aoqi@0: * aoqi@0: * This code is distributed in the hope that it will be useful, but WITHOUT aoqi@0: * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or aoqi@0: * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License aoqi@0: * version 2 for more details (a copy is included in the LICENSE file that aoqi@0: * accompanied this code). aoqi@0: * aoqi@0: * You should have received a copy of the GNU General Public License version aoqi@0: * 2 along with this work; if not, write to the Free Software Foundation, aoqi@0: * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. aoqi@0: * aoqi@0: * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA aoqi@0: * or visit www.oracle.com if you need additional information or have any aoqi@0: * questions. aoqi@0: */ aoqi@0: aoqi@0: /* aoqi@0: * @test aoqi@0: * @bug 8013357 aoqi@0: * @summary javac should correctly enforce binary comparison rules. aoqi@0: */ aoqi@0: import com.sun.tools.javac.code.Type; aoqi@0: import com.sun.tools.javac.code.Type.*; aoqi@0: import com.sun.tools.javac.code.Symbol.*; aoqi@0: import java.io.*; aoqi@0: import java.lang.reflect.Array; aoqi@0: import java.util.EnumSet; aoqi@0: aoqi@0: public class TestComparisons { aoqi@0: aoqi@0: private int errors = 0; aoqi@0: private int testnum = 0; aoqi@0: aoqi@0: static final File testdir = new File("8013357"); aoqi@0: aoqi@0: private enum CompareType { aoqi@0: BYTE_PRIM("byte"), aoqi@0: SHORT_PRIM("short"), aoqi@0: CHAR_PRIM("char"), aoqi@0: INTEGER_PRIM("int"), aoqi@0: LONG_PRIM("long"), aoqi@0: FLOAT_PRIM("float"), aoqi@0: DOUBLE_PRIM("double"), aoqi@0: BOOLEAN_PRIM("boolean"), aoqi@0: aoqi@0: BYTE("Byte"), aoqi@0: SHORT("Short"), aoqi@0: CHAR("Character"), aoqi@0: INTEGER("Integer"), aoqi@0: LONG("Long"), aoqi@0: FLOAT("Float"), aoqi@0: DOUBLE("Double"), aoqi@0: BOOLEAN("Boolean"), aoqi@0: aoqi@0: BYTE_SUPER("List", true), aoqi@0: SHORT_SUPER("List", true), aoqi@0: CHAR_SUPER("List", true), aoqi@0: INTEGER_SUPER("List", true), aoqi@0: LONG_SUPER("List", true), aoqi@0: FLOAT_SUPER("List", true), aoqi@0: DOUBLE_SUPER("List", true), aoqi@0: BOOLEAN_SUPER("List", true), aoqi@0: aoqi@0: OBJECT("Object"), aoqi@0: NUMBER("Number"), aoqi@0: STRING("String"); aoqi@0: aoqi@0: public final boolean isList; aoqi@0: public final String name; aoqi@0: aoqi@0: private CompareType(final String name, final boolean isList) { aoqi@0: this.isList = isList; aoqi@0: this.name = name; aoqi@0: } aoqi@0: aoqi@0: private CompareType(final String name) { aoqi@0: this(name, false); aoqi@0: } aoqi@0: } aoqi@0: aoqi@0: // The integers here refer to which subsection of JLS 15.21 is in aoqi@0: // effect. 0 means no comparison is allowed. aoqi@0: private static final int truthtab[][] = { aoqi@0: // byte, comparable to itself, any numeric type, or any boxed aoqi@0: // numeric type. aoqi@0: { 1, 1, 1, 1, 1, 1, 1, 0, // Primitives aoqi@0: 1, 1, 1, 1, 1, 1, 1, 0, // Boxed primitives aoqi@0: 0, 0, 0, 0, 0, 0, 0, 0, // Captures aoqi@0: 0, 0, 0 // Reference types aoqi@0: }, aoqi@0: // short, comparable to itself, any numeric type, or any boxed aoqi@0: // numeric type. aoqi@0: { 1, 1, 1, 1, 1, 1, 1, 0, // Primitives aoqi@0: 1, 1, 1, 1, 1, 1, 1, 0, // Boxed primitives aoqi@0: 0, 0, 0, 0, 0, 0, 0, 0, // Captures aoqi@0: 0, 0, 0 // Reference types aoqi@0: }, aoqi@0: // char, comparable to itself, any numeric type, or any boxed aoqi@0: // numeric type. aoqi@0: { 1, 1, 1, 1, 1, 1, 1, 0, // Primitives aoqi@0: 1, 1, 1, 1, 1, 1, 1, 0, // Boxed primitives aoqi@0: 0, 0, 0, 0, 0, 0, 0, 0, // Captures aoqi@0: 0, 0, 0 // Reference types aoqi@0: }, aoqi@0: // int, comparable to itself, any numeric type, or any boxed aoqi@0: // numeric type. aoqi@0: { 1, 1, 1, 1, 1, 1, 1, 0, // Primitives aoqi@0: 1, 1, 1, 1, 1, 1, 1, 0, // Boxed primitives aoqi@0: 0, 0, 0, 0, 0, 0, 0, 0, // Captures aoqi@0: 0, 0, 0 // Reference types aoqi@0: }, aoqi@0: // long, comparable to itself, any numeric type, or any boxed aoqi@0: // numeric type. aoqi@0: { 1, 1, 1, 1, 1, 1, 1, 0, // Primitives aoqi@0: 1, 1, 1, 1, 1, 1, 1, 0, // Boxed primitives aoqi@0: 0, 0, 0, 0, 0, 0, 0, 0, // Captures aoqi@0: 0, 0, 0 // Reference types aoqi@0: }, aoqi@0: // float, comparable to itself, any numeric type, or any boxed aoqi@0: // numeric type. aoqi@0: { 1, 1, 1, 1, 1, 1, 1, 0, // Primitives aoqi@0: 1, 1, 1, 1, 1, 1, 1, 0, // Boxed primitives aoqi@0: 0, 0, 0, 0, 0, 0, 0, 0, // Captures aoqi@0: 0, 0, 0 // Reference types aoqi@0: }, aoqi@0: // double, comparable to itself, any numeric type, or any boxed aoqi@0: // numeric type. aoqi@0: { 1, 1, 1, 1, 1, 1, 1, 0, // Primitives aoqi@0: 1, 1, 1, 1, 1, 1, 1, 0, // Boxed primitives aoqi@0: 0, 0, 0, 0, 0, 0, 0, 0, // Captures aoqi@0: 0, 0, 0 // Reference types aoqi@0: }, aoqi@0: // boolean, comparable only to itself and Boolean. aoqi@0: { 0, 0, 0, 0, 0, 0, 0, 2, // Primitives aoqi@0: 0, 0, 0, 0, 0, 0, 0, 2, // Boxed primitives aoqi@0: 0, 0, 0, 0, 0, 0, 0, 0, // Captures aoqi@0: 0, 0, 0 // Reference types aoqi@0: }, aoqi@0: // Byte, comparable to itself, Number, Object, any numeric primitive, aoqi@0: // and any captures. aoqi@0: { 1, 1, 1, 1, 1, 1, 1, 0, // Primitives aoqi@0: 3, 0, 0, 0, 0, 0, 0, 0, // Boxed primitives aoqi@0: 3, 3, 3, 3, 3, 3, 3, 3, // Captures aoqi@0: 3, 3, 0 // Reference types aoqi@0: }, aoqi@0: // Short, comparable to itself, Number, Object, any numeric primitive, aoqi@0: // and any captures. aoqi@0: { 1, 1, 1, 1, 1, 1, 1, 0, // Primitives aoqi@0: 0, 3, 0, 0, 0, 0, 0, 0, // Boxed primitives aoqi@0: 3, 3, 3, 3, 3, 3, 3, 3, // Captures aoqi@0: 3, 3, 0 // Reference types aoqi@0: }, aoqi@0: // Character, comparable to itself, Object, any numeric primitive, aoqi@0: // and any captures. aoqi@0: { 1, 1, 1, 1, 1, 1, 1, 0, // Primitives aoqi@0: 0, 0, 3, 0, 0, 0, 0, 0, // Boxed primitives aoqi@0: 3, 3, 3, 3, 3, 3, 3, 3, // Captures aoqi@0: 3, 0, 0 // Reference types aoqi@0: }, aoqi@0: // Int, comparable to itself, Number, Object, any numeric primitive, aoqi@0: // and any captures. aoqi@0: { 1, 1, 1, 1, 1, 1, 1, 0, // Primitives aoqi@0: 0, 0, 0, 3, 0, 0, 0, 0, // Boxed primitives aoqi@0: 3, 3, 3, 3, 3, 3, 3, 3, // Captures aoqi@0: 3, 3, 0 // Reference types aoqi@0: }, aoqi@0: // Long, comparable to itself, Number, Object, any numeric primitive, aoqi@0: // and any captures. aoqi@0: { 1, 1, 1, 1, 1, 1, 1, 0, // Primitives aoqi@0: 0, 0, 0, 0, 3, 0, 0, 0, // Boxed primitives aoqi@0: 3, 3, 3, 3, 3, 3, 3, 3, // Captures aoqi@0: 3, 3, 0 // Reference types aoqi@0: }, aoqi@0: // Float, comparable to itself, Number, Object, any numeric primitive, aoqi@0: // and any captures. aoqi@0: { 1, 1, 1, 1, 1, 1, 1, 0, // Primitives aoqi@0: 0, 0, 0, 0, 0, 3, 0, 0, // Boxed primitives aoqi@0: 3, 3, 3, 3, 3, 3, 3, 3, // Captures aoqi@0: 3, 3, 0 // Reference types aoqi@0: }, aoqi@0: // Double, comparable to itself, Number, Object, any numeric primitive, aoqi@0: // and any captures. aoqi@0: { 1, 1, 1, 1, 1, 1, 1, 0, // Primitives aoqi@0: 0, 0, 0, 0, 0, 0, 3, 0, // Boxed primitives aoqi@0: 3, 3, 3, 3, 3, 3, 3, 3, // Captures aoqi@0: 3, 3, 0 // Reference types aoqi@0: }, aoqi@0: // Boolean, to itself, any capture, Object, and boolean. aoqi@0: { 0, 0, 0, 0, 0, 0, 0, 2, // Primitives aoqi@0: 0, 0, 0, 0, 0, 0, 0, 2, // Boxed primitives aoqi@0: 3, 3, 3, 3, 3, 3, 3, 3, // Captures aoqi@0: 3, 0, 0 // Reference types aoqi@0: }, aoqi@0: // Byte supertype wildcard, comparable to any reference type. aoqi@0: // and any captures. aoqi@0: { 0, 0, 0, 0, 0, 0, 0, 0, // Primitives aoqi@0: 3, 3, 3, 3, 3, 3, 3, 3, // Boxed primitives aoqi@0: 3, 3, 3, 3, 3, 3, 3, 3, // Captures aoqi@0: 3, 3, 3 // Reference types aoqi@0: }, aoqi@0: // Short supertype wildcard, comparable to any reference type. aoqi@0: // and any captures. aoqi@0: { 0, 0, 0, 0, 0, 0, 0, 0, // Primitives aoqi@0: 3, 3, 3, 3, 3, 3, 3, 3, // Boxed primitives aoqi@0: 3, 3, 3, 3, 3, 3, 3, 3, // Captures aoqi@0: 3, 3, 3 // Reference types aoqi@0: }, aoqi@0: // Character supertype wildcard, comparable to any reference type. aoqi@0: // and any captures. aoqi@0: { 0, 0, 0, 0, 0, 0, 0, 0, // Primitives aoqi@0: 3, 3, 3, 3, 3, 3, 3, 3, // Boxed primitives aoqi@0: 3, 3, 3, 3, 3, 3, 3, 3, // Captures aoqi@0: 3, 3, 3 // Reference types aoqi@0: }, aoqi@0: // Integer supertype wildcard, comparable to any reference type. aoqi@0: // and any captures. aoqi@0: { 0, 0, 0, 0, 0, 0, 0, 0, // Primitives aoqi@0: 3, 3, 3, 3, 3, 3, 3, 3, // Boxed primitives aoqi@0: 3, 3, 3, 3, 3, 3, 3, 3, // Captures aoqi@0: 3, 3, 3 // Reference types aoqi@0: }, aoqi@0: // Long supertype wildcard, comparable to any reference type. aoqi@0: // and any captures. aoqi@0: { 0, 0, 0, 0, 0, 0, 0, 0, // Primitives aoqi@0: 3, 3, 3, 3, 3, 3, 3, 3, // Boxed primitives aoqi@0: 3, 3, 3, 3, 3, 3, 3, 3, // Captures aoqi@0: 3, 3, 3 // Reference types aoqi@0: }, aoqi@0: // Float supertype wildcard, comparable to any reference type. aoqi@0: // and any captures. aoqi@0: { 0, 0, 0, 0, 0, 0, 0, 0, // Primitives aoqi@0: 3, 3, 3, 3, 3, 3, 3, 3, // Boxed primitives aoqi@0: 3, 3, 3, 3, 3, 3, 3, 3, // Captures aoqi@0: 3, 3, 3 // Reference types aoqi@0: }, aoqi@0: // Double supertype wildcard, comparable to any reference type. aoqi@0: // and any captures. aoqi@0: { 0, 0, 0, 0, 0, 0, 0, 0, // Primitives aoqi@0: 3, 3, 3, 3, 3, 3, 3, 3, // Boxed primitives aoqi@0: 3, 3, 3, 3, 3, 3, 3, 3, // Captures aoqi@0: 3, 3, 3 // Reference types aoqi@0: }, aoqi@0: // Boolean supertype wildcard, comparable to any reference type. aoqi@0: // and any captures. aoqi@0: { 0, 0, 0, 0, 0, 0, 0, 0, // Primitives aoqi@0: 3, 3, 3, 3, 3, 3, 3, 3, // Boxed primitives aoqi@0: 3, 3, 3, 3, 3, 3, 3, 3, // Captures aoqi@0: 3, 3, 3 // Reference types aoqi@0: }, aoqi@0: // Object, comparable to any reference type. aoqi@0: // and any captures. aoqi@0: { 0, 0, 0, 0, 0, 0, 0, 0, // Primitives aoqi@0: 3, 3, 3, 3, 3, 3, 3, 3, // Boxed primitives aoqi@0: 3, 3, 3, 3, 3, 3, 3, 3, // Captures aoqi@0: 3, 3, 3 // Reference types aoqi@0: }, aoqi@0: // Number, comparable to Object, any of its subclasses. aoqi@0: // and any captures. aoqi@0: { 0, 0, 0, 0, 0, 0, 0, 0, // Primitives aoqi@0: 3, 3, 0, 3, 3, 3, 3, 0, // Boxed primitives aoqi@0: 3, 3, 3, 3, 3, 3, 3, 3, // Captures aoqi@0: 3, 3, 0 // Reference types aoqi@0: }, aoqi@0: // String supertype wildcard, comparable to any reference type. aoqi@0: // and any captures. aoqi@0: { 0, 0, 0, 0, 0, 0, 0, 0, // Primitives aoqi@0: 0, 0, 0, 0, 0, 0, 0, 0, // Boxed primitives aoqi@0: 3, 3, 3, 3, 3, 3, 3, 3, // Captures aoqi@0: 3, 0, 3 // Reference types aoqi@0: } aoqi@0: }; aoqi@0: aoqi@0: private void assert_compile_fail(final File file, final String body) { aoqi@0: final String filename = file.getPath(); aoqi@0: final String[] args = { filename }; aoqi@0: final StringWriter sw = new StringWriter(); aoqi@0: final PrintWriter pw = new PrintWriter(sw); aoqi@0: final int rc = com.sun.tools.javac.Main.compile(args, pw); aoqi@0: pw.close(); aoqi@0: if (rc == 0) { aoqi@0: System.err.println("Compilation of " + file.getName() + aoqi@0: " didn't fail as expected.\nFile:\n" + aoqi@0: body + "\nOutput:\n" + sw.toString()); aoqi@0: errors++; aoqi@0: } aoqi@0: } aoqi@0: aoqi@0: private void assert_compile_succeed(final File file, final String body) { aoqi@0: final String filename = file.getPath(); aoqi@0: final String[] args = { filename }; aoqi@0: final StringWriter sw = new StringWriter(); aoqi@0: final PrintWriter pw = new PrintWriter(sw); aoqi@0: final int rc = com.sun.tools.javac.Main.compile(args, pw); aoqi@0: pw.close(); aoqi@0: if (rc != 0) { aoqi@0: System.err.println("Compilation of " + file.getName() + aoqi@0: " didn't succeed as expected.\nFile:\n" + aoqi@0: body + "\nOutput:\n" + aoqi@0: sw.toString()); aoqi@0: errors++; aoqi@0: } aoqi@0: } aoqi@0: aoqi@0: private String makeBody(final int num, aoqi@0: final CompareType left, aoqi@0: final CompareType right) { aoqi@0: return "import java.util.List;\n" + aoqi@0: "public class Test" + num + " {\n" + aoqi@0: " public boolean test(" + left.name + aoqi@0: " left, " + right.name + " right) {\n" + aoqi@0: " return left" + (left.isList ? ".get(0)" : "") + aoqi@0: " == right" + (right.isList ? ".get(0)" : "") + ";\n" + aoqi@0: " }\n" + aoqi@0: "}\n"; aoqi@0: } aoqi@0: aoqi@0: private File writeFile(final String filename, aoqi@0: final String body) aoqi@0: throws IOException { aoqi@0: final File f = new File(testdir, filename); aoqi@0: f.getParentFile().mkdirs(); aoqi@0: final FileWriter out = new FileWriter(f); aoqi@0: out.write(body); aoqi@0: out.close(); aoqi@0: return f; aoqi@0: } aoqi@0: aoqi@0: private void test(final CompareType left, final CompareType right) aoqi@0: throws IOException { aoqi@0: final int num = testnum++; aoqi@0: final String filename = "Test" + num + ".java"; aoqi@0: final String body = makeBody(num, left, right); aoqi@0: final File file = writeFile(filename, body); aoqi@0: if (truthtab[left.ordinal()][right.ordinal()] != 0) aoqi@0: assert_compile_succeed(file, body); aoqi@0: else aoqi@0: assert_compile_fail(file, body); aoqi@0: } aoqi@0: aoqi@0: void run() throws Exception { aoqi@0: testdir.mkdir(); aoqi@0: aoqi@0: for(CompareType left : CompareType.values()) aoqi@0: for(CompareType right : CompareType.values()) aoqi@0: test(left, right); aoqi@0: aoqi@0: if (errors != 0) aoqi@0: throw new Exception("ObjectZeroCompare test failed with " + aoqi@0: errors + " errors."); aoqi@0: } aoqi@0: aoqi@0: public static void main(String... args) throws Exception { aoqi@0: new TestComparisons().run(); aoqi@0: } aoqi@0: }