1 /*
2  * Copyright (c) 2013, 2016, Oracle and/or its affiliates. All rights reserved.
3  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4  *
5  * This code is free software; you can redistribute it and/or modify it
6  * under the terms of the GNU General Public License version 2 only, as
7  * published by the Free Software Foundation.
8  *
9  * This code is distributed in the hope that it will be useful, but WITHOUT
10  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
11  * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
12  * version 2 for more details (a copy is included in the LICENSE file that
13  * accompanied this code).
14  *
15  * You should have received a copy of the GNU General Public License version
16  * 2 along with this work; if not, write to the Free Software Foundation,
17  * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
18  *
19  * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
20  * or visit www.oracle.com if you need additional information or have any
21  * questions.
22  */
23 
24 /*
25  * @test
26  * @bug 8013357
27  * @summary javac should correctly enforce binary comparison rules.
28  * @modules jdk.compiler
29  */
30 
31 import java.io.*;
32 
33 public class TestComparisons {
34 
35     private int errors = 0;
36     private int testnum = 0;
37 
38     static final File testdir = new File("8013357");
39 
40     private enum CompareType {
41         BYTE_PRIM("byte"),
42         SHORT_PRIM("short"),
43         CHAR_PRIM("char"),
44         INTEGER_PRIM("int"),
45         LONG_PRIM("long"),
46         FLOAT_PRIM("float"),
47         DOUBLE_PRIM("double"),
48         BOOLEAN_PRIM("boolean"),
49 
50         BYTE("Byte"),
51         SHORT("Short"),
52         CHAR("Character"),
53         INTEGER("Integer"),
54         LONG("Long"),
55         FLOAT("Float"),
56         DOUBLE("Double"),
57         BOOLEAN("Boolean"),
58 
59         BYTE_SUPER("List<? super Byte>", true),
60         SHORT_SUPER("List<? super Short>", true),
61         CHAR_SUPER("List<? super Character>", true),
62         INTEGER_SUPER("List<? super Integer>", true),
63         LONG_SUPER("List<? super Long>", true),
64         FLOAT_SUPER("List<? super Float>", true),
65         DOUBLE_SUPER("List<? super Double>", true),
66         BOOLEAN_SUPER("List<? super Boolean>", true),
67 
68         OBJECT("Object"),
69         NUMBER("Number"),
70         STRING("String");
71 
72         public final boolean isList;
73         public final String name;
74 
CompareType(final String name, final boolean isList)75         private CompareType(final String name, final boolean isList) {
76             this.isList = isList;
77             this.name = name;
78         }
79 
CompareType(final String name)80         private CompareType(final String name) {
81             this(name, false);
82         }
83     }
84 
85     // The integers here refer to which subsection of JLS 15.21 is in
86     // effect.  0 means no comparison is allowed.
87     private static final int truthtab[][] = {
88         // byte, comparable to itself, any numeric type, or any boxed
89         // numeric type.
90         { 1, 1, 1, 1, 1, 1, 1, 0, // Primitives
91           1, 1, 1, 1, 1, 1, 1, 0, // Boxed primitives
92           0, 0, 0, 0, 0, 0, 0, 0, // Captures
93           0, 0, 0                 // Reference types
94         },
95         // short, comparable to itself, any numeric type, or any boxed
96         // numeric type.
97         { 1, 1, 1, 1, 1, 1, 1, 0, // Primitives
98           1, 1, 1, 1, 1, 1, 1, 0, // Boxed primitives
99           0, 0, 0, 0, 0, 0, 0, 0, // Captures
100           0, 0, 0                 // Reference types
101         },
102         // char, comparable to itself, any numeric type, or any boxed
103         // numeric type.
104         { 1, 1, 1, 1, 1, 1, 1, 0, // Primitives
105           1, 1, 1, 1, 1, 1, 1, 0, // Boxed primitives
106           0, 0, 0, 0, 0, 0, 0, 0, // Captures
107           0, 0, 0                 // Reference types
108         },
109         // int, comparable to itself, any numeric type, or any boxed
110         // numeric type.
111         { 1, 1, 1, 1, 1, 1, 1, 0, // Primitives
112           1, 1, 1, 1, 1, 1, 1, 0, // Boxed primitives
113           0, 0, 0, 0, 0, 0, 0, 0, // Captures
114           0, 0, 0                 // Reference types
115         },
116         // long, comparable to itself, any numeric type, or any boxed
117         // numeric type.
118         { 1, 1, 1, 1, 1, 1, 1, 0, // Primitives
119           1, 1, 1, 1, 1, 1, 1, 0, // Boxed primitives
120           0, 0, 0, 0, 0, 0, 0, 0, // Captures
121           0, 0, 0                 // Reference types
122         },
123         // float, comparable to itself, any numeric type, or any boxed
124         // numeric type.
125         { 1, 1, 1, 1, 1, 1, 1, 0, // Primitives
126           1, 1, 1, 1, 1, 1, 1, 0, // Boxed primitives
127           0, 0, 0, 0, 0, 0, 0, 0, // Captures
128           0, 0, 0                 // Reference types
129         },
130         // double, comparable to itself, any numeric type, or any boxed
131         // numeric type.
132         { 1, 1, 1, 1, 1, 1, 1, 0, // Primitives
133           1, 1, 1, 1, 1, 1, 1, 0, // Boxed primitives
134           0, 0, 0, 0, 0, 0, 0, 0, // Captures
135           0, 0, 0                 // Reference types
136         },
137         // boolean, comparable only to itself and Boolean.
138         { 0, 0, 0, 0, 0, 0, 0, 2, // Primitives
139           0, 0, 0, 0, 0, 0, 0, 2, // Boxed primitives
140           0, 0, 0, 0, 0, 0, 0, 0, // Captures
141           0, 0, 0                 // Reference types
142         },
143         // Byte, comparable to itself, Number, Object, any numeric primitive,
144         // and any captures.
145         { 1, 1, 1, 1, 1, 1, 1, 0, // Primitives
146           3, 0, 0, 0, 0, 0, 0, 0, // Boxed primitives
147           3, 3, 3, 3, 3, 3, 3, 3, // Captures
148           3, 3, 0                 // Reference types
149         },
150         // Short, comparable to itself, Number, Object, any numeric primitive,
151         // and any captures.
152         { 1, 1, 1, 1, 1, 1, 1, 0, // Primitives
153           0, 3, 0, 0, 0, 0, 0, 0, // Boxed primitives
154           3, 3, 3, 3, 3, 3, 3, 3, // Captures
155           3, 3, 0                 // Reference types
156         },
157         // Character, comparable to itself, Object, any numeric primitive,
158         // and any captures.
159         { 1, 1, 1, 1, 1, 1, 1, 0, // Primitives
160           0, 0, 3, 0, 0, 0, 0, 0, // Boxed primitives
161           3, 3, 3, 3, 3, 3, 3, 3, // Captures
162           3, 0, 0                 // Reference types
163         },
164         // Int, comparable to itself, Number, Object, any numeric primitive,
165         // and any captures.
166         { 1, 1, 1, 1, 1, 1, 1, 0, // Primitives
167           0, 0, 0, 3, 0, 0, 0, 0, // Boxed primitives
168           3, 3, 3, 3, 3, 3, 3, 3, // Captures
169           3, 3, 0                 // Reference types
170         },
171         // Long, comparable to itself, Number, Object, any numeric primitive,
172         // and any captures.
173         { 1, 1, 1, 1, 1, 1, 1, 0, // Primitives
174           0, 0, 0, 0, 3, 0, 0, 0, // Boxed primitives
175           3, 3, 3, 3, 3, 3, 3, 3, // Captures
176           3, 3, 0                 // Reference types
177         },
178         // Float, comparable to itself, Number, Object, any numeric primitive,
179         // and any captures.
180         { 1, 1, 1, 1, 1, 1, 1, 0, // Primitives
181           0, 0, 0, 0, 0, 3, 0, 0, // Boxed primitives
182           3, 3, 3, 3, 3, 3, 3, 3, // Captures
183           3, 3, 0                 // Reference types
184         },
185         // Double, comparable to itself, Number, Object, any numeric primitive,
186         // and any captures.
187         { 1, 1, 1, 1, 1, 1, 1, 0, // Primitives
188           0, 0, 0, 0, 0, 0, 3, 0, // Boxed primitives
189           3, 3, 3, 3, 3, 3, 3, 3, // Captures
190           3, 3, 0                 // Reference types
191         },
192         // Boolean, to itself, any capture, Object, and boolean.
193         { 0, 0, 0, 0, 0, 0, 0, 2, // Primitives
194           0, 0, 0, 0, 0, 0, 0, 2, // Boxed primitives
195           3, 3, 3, 3, 3, 3, 3, 3, // Captures
196           3, 0, 0                 // Reference types
197         },
198         // Byte supertype wildcard, comparable to any reference type.
199         // and any captures.
200         { 0, 0, 0, 0, 0, 0, 0, 0, // Primitives
201           3, 3, 3, 3, 3, 3, 3, 3, // Boxed primitives
202           3, 3, 3, 3, 3, 3, 3, 3, // Captures
203           3, 3, 3                 // Reference types
204         },
205         // Short supertype wildcard, comparable to any reference type.
206         // and any captures.
207         { 0, 0, 0, 0, 0, 0, 0, 0, // Primitives
208           3, 3, 3, 3, 3, 3, 3, 3, // Boxed primitives
209           3, 3, 3, 3, 3, 3, 3, 3, // Captures
210           3, 3, 3                 // Reference types
211         },
212         // Character supertype wildcard, comparable to any reference type.
213         // and any captures.
214         { 0, 0, 0, 0, 0, 0, 0, 0, // Primitives
215           3, 3, 3, 3, 3, 3, 3, 3, // Boxed primitives
216           3, 3, 3, 3, 3, 3, 3, 3, // Captures
217           3, 3, 3                 // Reference types
218         },
219         // Integer supertype wildcard, comparable to any reference type.
220         // and any captures.
221         { 0, 0, 0, 0, 0, 0, 0, 0, // Primitives
222           3, 3, 3, 3, 3, 3, 3, 3, // Boxed primitives
223           3, 3, 3, 3, 3, 3, 3, 3, // Captures
224           3, 3, 3                 // Reference types
225         },
226         // Long supertype wildcard, comparable to any reference type.
227         // and any captures.
228         { 0, 0, 0, 0, 0, 0, 0, 0, // Primitives
229           3, 3, 3, 3, 3, 3, 3, 3, // Boxed primitives
230           3, 3, 3, 3, 3, 3, 3, 3, // Captures
231           3, 3, 3                 // Reference types
232         },
233         // Float supertype wildcard, comparable to any reference type.
234         // and any captures.
235         { 0, 0, 0, 0, 0, 0, 0, 0, // Primitives
236           3, 3, 3, 3, 3, 3, 3, 3, // Boxed primitives
237           3, 3, 3, 3, 3, 3, 3, 3, // Captures
238           3, 3, 3                 // Reference types
239         },
240         // Double supertype wildcard, comparable to any reference type.
241         // and any captures.
242         { 0, 0, 0, 0, 0, 0, 0, 0, // Primitives
243           3, 3, 3, 3, 3, 3, 3, 3, // Boxed primitives
244           3, 3, 3, 3, 3, 3, 3, 3, // Captures
245           3, 3, 3                 // Reference types
246         },
247         // Boolean supertype wildcard, comparable to any reference type.
248         // and any captures.
249         { 0, 0, 0, 0, 0, 0, 0, 0, // Primitives
250           3, 3, 3, 3, 3, 3, 3, 3, // Boxed primitives
251           3, 3, 3, 3, 3, 3, 3, 3, // Captures
252           3, 3, 3                 // Reference types
253         },
254         // Object, comparable to any reference type.
255         // and any captures.
256         { 0, 0, 0, 0, 0, 0, 0, 0, // Primitives
257           3, 3, 3, 3, 3, 3, 3, 3, // Boxed primitives
258           3, 3, 3, 3, 3, 3, 3, 3, // Captures
259           3, 3, 3                 // Reference types
260         },
261         // Number, comparable to Object, any of its subclasses.
262         // and any captures.
263         { 0, 0, 0, 0, 0, 0, 0, 0, // Primitives
264           3, 3, 0, 3, 3, 3, 3, 0, // Boxed primitives
265           3, 3, 3, 3, 3, 3, 3, 3, // Captures
266           3, 3, 0                 // Reference types
267         },
268         // String supertype wildcard, comparable to any reference type.
269         // and any captures.
270         { 0, 0, 0, 0, 0, 0, 0, 0, // Primitives
271           0, 0, 0, 0, 0, 0, 0, 0, // Boxed primitives
272           3, 3, 3, 3, 3, 3, 3, 3, // Captures
273           3, 0, 3                 // Reference types
274         }
275     };
276 
assert_compile_fail(final File file, final String body)277     private void assert_compile_fail(final File file, final String body) {
278         final String filename = file.getPath();
279         final String[] args = { filename };
280         final StringWriter sw = new StringWriter();
281         final PrintWriter pw = new PrintWriter(sw);
282         final int rc = com.sun.tools.javac.Main.compile(args, pw);
283         pw.close();
284         if (rc == 0) {
285             System.err.println("Compilation of " + file.getName() +
286                                " didn't fail as expected.\nFile:\n" +
287                                body + "\nOutput:\n" + sw.toString());
288             errors++;
289         }
290     }
291 
assert_compile_succeed(final File file, final String body)292     private void assert_compile_succeed(final File file, final String body) {
293         final String filename = file.getPath();
294         final String[] args = { filename };
295         final StringWriter sw = new StringWriter();
296         final PrintWriter pw = new PrintWriter(sw);
297         final int rc = com.sun.tools.javac.Main.compile(args, pw);
298         pw.close();
299         if (rc != 0) {
300             System.err.println("Compilation of " + file.getName() +
301                                " didn't succeed as expected.\nFile:\n" +
302                                body + "\nOutput:\n" +
303                                sw.toString());
304             errors++;
305         }
306     }
307 
makeBody(final int num, final CompareType left, final CompareType right)308     private String makeBody(final int num,
309                             final CompareType left,
310                             final CompareType right) {
311         return "import java.util.List;\n" +
312             "public class Test" + num + " {\n" +
313             "    public boolean test(" + left.name +
314             " left, " + right.name + " right) {\n" +
315             "        return left" + (left.isList ? ".get(0)" : "") +
316             " == right" + (right.isList ? ".get(0)" : "") + ";\n" +
317             "    }\n" +
318             "}\n";
319     }
320 
writeFile(final String filename, final String body)321     private File writeFile(final String filename,
322                            final String body)
323         throws IOException {
324         final File f = new File(testdir, filename);
325         f.getParentFile().mkdirs();
326         final FileWriter out = new FileWriter(f);
327         out.write(body);
328         out.close();
329         return f;
330     }
331 
test(final CompareType left, final CompareType right)332     private void test(final CompareType left, final CompareType right)
333         throws IOException {
334         final int num = testnum++;
335         final String filename = "Test" + num + ".java";
336         final String body = makeBody(num, left, right);
337         final File file = writeFile(filename, body);
338         if (truthtab[left.ordinal()][right.ordinal()] != 0)
339             assert_compile_succeed(file, body);
340         else
341             assert_compile_fail(file, body);
342     }
343 
run()344     void run() throws Exception {
345         testdir.mkdir();
346 
347         for(CompareType left : CompareType.values())
348             for(CompareType right : CompareType.values())
349                 test(left, right);
350 
351         if (errors != 0)
352             throw new Exception("ObjectZeroCompare test failed with " +
353                                 errors + " errors.");
354     }
355 
main(String... args)356     public static void main(String... args) throws Exception {
357         new TestComparisons().run();
358     }
359 }
360