1 /*
  2  * Copyright (c) 2020, 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 8237072
 27  * @summary Test various relationships between a value type and its reference projection.
 28  * @library /tools/lib
 29  * @modules jdk.compiler/com.sun.tools.javac.api
 30  *          jdk.compiler/com.sun.tools.javac.code
 31  *          jdk.compiler/com.sun.tools.javac.util
 32  */
 33 
 34 import java.io.StringWriter;
 35 import javax.tools.JavaFileObject;
 36 import javax.tools.ToolProvider;
 37 import javax.lang.model.element.Element;
 38 import com.sun.source.util.JavacTask;
 39 import com.sun.tools.javac.api.JavacTool;
 40 import com.sun.tools.javac.code.Type;
 41 import com.sun.tools.javac.code.Types;
 42 import com.sun.tools.javac.code.Symtab;
 43 import com.sun.tools.javac.code.Symbol;
 44 import com.sun.tools.javac.code.Symbol.ClassSymbol;
 45 import com.sun.tools.javac.util.Context;
 46 import com.sun.tools.javac.util.Assert;
 47 import com.sun.tools.javac.util.List;
 48 import com.sun.tools.javac.util.Names;
 49 
 50 import toolbox.ToolBox;
 51 
 52 public class ProjectionRelationsTest {
 53 
 54     private static final ToolBox tb = new ToolBox();
 55 
 56     enum Relation {
 57         SUBTYPING,
 58         CASTING,
 59         ASSIGNING,
 60     }
 61 
 62     public static void main(String... args) throws Exception {
 63         String code = "primitive class C.val {\n" +
 64                 "         C cref     = new C();\n" +
 65                 "         C.val []  ca       = null;\n" +
 66                 "         C [] cra   = null;\n" +
 67                 "         Object[]  oa   = null;\n" +
 68                       "}\n";
 69         List<JavaFileObject> files = List.of(new ToolBox.JavaSource(code));
 70 
 71         JavacTool compiler = (JavacTool) ToolProvider.getSystemJavaCompiler();
 72         StringWriter out = new StringWriter();
 73 
 74         Context context = new Context();
 75 
 76         JavacTask task = (JavacTask) compiler.getTask(out, null, null, List.of("-XDinlinesAreIslands"), null, files, context);
 77         Iterable<? extends Element> elements = task.analyze();
 78         if (elements == null || !elements.iterator().hasNext()) {
 79             throw new RuntimeException("Didn't compile alright!");
 80         }
 81 
 82         Names names =  Names.instance(context);
 83 
 84         ClassSymbol valueCls = (ClassSymbol) elements.iterator().next();
 85         Type vType = valueCls.type.asValueType();
 86         Type vDotRefType = valueCls.members().findFirst(names.fromString("cref")).type;
 87         Type vArrayType = valueCls.members().findFirst(names.fromString("ca")).type;
 88         Type vRefArrayType = valueCls.members().findFirst(names.fromString("cra")).type;
 89         Type jlOArrayType = valueCls.members().findFirst(names.fromString("oa")).type;
 90 
 91         for (Relation relation : Relation.values()) {
 92             testRelation(context, relation, vType, vDotRefType);
 93             testRelation(context, relation, vArrayType, vRefArrayType, jlOArrayType);
 94         }
 95     }
 96 
 97     static void testRelation(Context context, Relation relation, Type vType, Type vDotRefType) {
 98         Types types =  Types.instance(context);
 99         Symtab syms =  Symtab.instance(context);
100         Type intType = syms.intType;
101         Type objectType = syms.objectType;
102         Type integerType = types.boxedTypeOrType(syms.intType);
103         Type stringType = syms.stringType;
104 
105         System.out.println("Testing relation " + relation + " between " +
106                                        vType.tsym.name + " and " + vDotRefType.tsym.name);
107             switch (relation) {
108                 case SUBTYPING:
109 
110                     // self check
111                     Assert.check(types.isSubtype(vType, vType));
112                     Assert.check(types.isSubtype(vDotRefType, vDotRefType));
113 
114                     Assert.check(types.isSubtype(vType, vDotRefType) ==
115                                  types.isSubtype(intType, integerType));
116                     Assert.check(types.isSubtype(vDotRefType, vType) ==
117                                  types.isSubtype(integerType, intType));
118 
119                     Assert.check(types.isSubtype(vType, objectType) ==
120                                  types.isSubtype(intType, objectType));
121                     Assert.check(types.isSubtype(objectType, vType) ==
122                                  types.isSubtype(objectType, intType));
123 
124                     Assert.check(types.isSubtype(vDotRefType, objectType) ==
125                                  types.isSubtype(integerType, objectType));
126                     Assert.check(types.isSubtype(objectType, vDotRefType) ==
127                                  types.isSubtype(objectType, integerType));
128 
129                     // check against a totally unrelated class.
130                     Assert.check(types.isSubtype(vType, stringType) ==
131                                  types.isSubtype(intType, stringType));
132                     Assert.check(types.isSubtype(stringType, vType) ==
133                                  types.isSubtype(stringType, intType));
134 
135                     Assert.check(types.isSubtype(vDotRefType, stringType) ==
136                                  types.isSubtype(integerType, stringType));
137                     Assert.check(types.isSubtype(stringType, vDotRefType) ==
138                                  types.isSubtype(stringType, integerType));
139                     break;
140 
141                 case CASTING:
142 
143                     // self check
144                     Assert.check(types.isCastable(vType, vType));
145                     Assert.check(types.isCastable(vDotRefType, vDotRefType));
146 
147                     Assert.check(types.isCastable(vType, vDotRefType) ==
148                                  types.isCastable(intType, integerType));
149                     Assert.check(types.isCastable(vDotRefType, vType) ==
150                                  types.isCastable(integerType, intType));
151                     Assert.check(types.isCastable(vType, objectType) ==
152                                  types.isCastable(intType, objectType));
153                     Assert.check(types.isCastable(objectType, vType) ==
154                                  types.isCastable(objectType, intType));
155                     Assert.check(types.isCastable(vDotRefType, objectType) ==
156                                  types.isCastable(integerType, objectType));
157                     Assert.check(types.isCastable(objectType, vDotRefType) ==
158                                  types.isCastable(objectType, integerType));
159                     // check against a totally unrelated class.
160                     Assert.check(types.isCastable(vType, stringType) ==
161                                  types.isCastable(intType, stringType));
162                     Assert.check(types.isCastable(stringType, vType) ==
163                                  types.isCastable(stringType, intType));
164 
165                     Assert.check(types.isCastable(vDotRefType, stringType) ==
166                                  types.isCastable(integerType, stringType));
167                     Assert.check(types.isCastable(stringType, vDotRefType) ==
168                                  types.isCastable(stringType, integerType));
169                     break;
170 
171                 case ASSIGNING:
172 
173                     // self check
174                     Assert.check(types.isAssignable(vType, vType));
175                     Assert.check(types.isAssignable(vDotRefType, vDotRefType));
176 
177                     Assert.check(types.isAssignable(vType, vDotRefType) ==
178                                  types.isAssignable(intType, integerType));
179                     Assert.check(types.isAssignable(vDotRefType, vType) ==
180                                  types.isAssignable(integerType, intType));
181                     Assert.check(types.isAssignable(vType, objectType) ==
182                                  types.isAssignable(intType, objectType));
183                     Assert.check(types.isAssignable(objectType, vType) ==
184                                  types.isAssignable(objectType, intType));
185                     Assert.check(types.isAssignable(vDotRefType, objectType) ==
186                                  types.isAssignable(integerType, objectType));
187                     Assert.check(types.isAssignable(objectType, vDotRefType) ==
188                                  types.isAssignable(objectType, integerType));
189                     // check against a totally unrelated class.
190                     Assert.check(types.isAssignable(vType, stringType) ==
191                                  types.isAssignable(intType, stringType));
192                     Assert.check(types.isAssignable(stringType, vType) ==
193                                  types.isAssignable(stringType, intType));
194 
195                     Assert.check(types.isAssignable(vDotRefType, stringType) ==
196                                  types.isAssignable(integerType, stringType));
197                     Assert.check(types.isAssignable(stringType, vDotRefType) ==
198                                  types.isAssignable(stringType, integerType));
199                     break;
200             }
201     }
202 
203     static void testRelation(Context context, Relation relation, Type vArrayType, Type vDotRefArrayType, Type objectArrayType) {
204         Types types =  Types.instance(context);
205         Symtab syms =  Symtab.instance(context);
206 
207         System.out.println("Testing relation " + relation + " between " +
208                                        vArrayType.tsym.name + " and " + vDotRefArrayType.tsym.name);
209             switch (relation) {
210                 case SUBTYPING:
211 
212                     /* check against self */
213                     Assert.check(types.isSubtype(vArrayType, vArrayType));
214                     Assert.check(types.isSubtype(vDotRefArrayType, vDotRefArrayType));
215 
216                     /* check against valid supers */
217                     Assert.check(types.isSubtype(vArrayType, vDotRefArrayType));
218                     Assert.check(types.isSubtype(vArrayType, objectArrayType));
219                     Assert.check(types.isSubtype(vArrayType, syms.objectType));
220                     Assert.check(types.isSubtype(vDotRefArrayType, objectArrayType));
221                     Assert.check(types.isSubtype(vDotRefArrayType, syms.objectType));
222 
223                     /* check negative cases */
224                     Assert.check(!types.isSubtype(vDotRefArrayType, vArrayType));
225                     Assert.check(!types.isSubtype(objectArrayType, vArrayType));
226                     Assert.check(!types.isSubtype(objectArrayType, vDotRefArrayType));
227 
228                     break;
229 
230                 case CASTING:
231 
232                     /* check self cast */
233                     Assert.check(types.isCastable(vArrayType, vArrayType));
234                     Assert.check(types.isCastable(vDotRefArrayType, vDotRefArrayType));
235 
236                     /* check widening cast of V */
237                     Assert.check(types.isCastable(vArrayType, vDotRefArrayType));
238                     Assert.check(types.isCastable(vArrayType, objectArrayType));
239                     Assert.check(types.isCastable(vArrayType, syms.objectType));
240 
241                     /* check cast of V.ref to supers */
242                     Assert.check(types.isCastable(vDotRefArrayType, objectArrayType));
243                     Assert.check(types.isCastable(vDotRefArrayType, syms.objectType));
244 
245                     /* check downcasts */
246                     Assert.check(types.isCastable(vDotRefArrayType, vArrayType));
247                     Assert.check(types.isCastable(objectArrayType, vArrayType));
248                     Assert.check(types.isCastable(objectArrayType, vDotRefArrayType));
249                     Assert.check(types.isCastable(syms.objectType, vArrayType));
250                     Assert.check(types.isCastable(syms.objectType, vDotRefArrayType));
251 
252                     break;
253 
254                 case ASSIGNING:
255 
256                     /* check self  */
257                     Assert.check(types.isAssignable(vArrayType, vArrayType));
258                     Assert.check(types.isAssignable(vDotRefArrayType, vDotRefArrayType));
259 
260                     /* check widening */
261                     Assert.check(types.isAssignable(vArrayType, vDotRefArrayType));
262                     Assert.check(types.isAssignable(vArrayType, objectArrayType));
263                     Assert.check(types.isAssignable(vArrayType, syms.objectType));
264 
265                     /* check more widening */
266                     Assert.check(types.isAssignable(vDotRefArrayType, objectArrayType));
267                     Assert.check(types.isAssignable(vDotRefArrayType, syms.objectType));
268 
269                     /* misc */
270                     Assert.check(!types.isAssignable(vDotRefArrayType, vArrayType));
271                     Assert.check(!types.isAssignable(objectArrayType, vArrayType));
272                     Assert.check(!types.isAssignable(objectArrayType, vDotRefArrayType));
273                     Assert.check(!types.isAssignable(syms.objectType, vArrayType));
274                     Assert.check(!types.isAssignable(syms.objectType, vDotRefArrayType));
275 
276                     break;
277             }
278     }
279 }