1 /*
2  * Copyright (c) 2010, 2019, 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 7007432 7006109
27  * @summary Test generic types well-formedness
28  * @author mcimadamore
29  * @library /tools/lib/types
30  * @modules jdk.compiler/com.sun.tools.javac.code
31  *          jdk.compiler/com.sun.tools.javac.comp
32  *          jdk.compiler/com.sun.tools.javac.file
33  *          jdk.compiler/com.sun.tools.javac.util
34  *          jdk.compiler/com.sun.tools.javac.main
35  *          jdk.compiler/com.sun.tools.javac.tree
36  * @build TypeHarness
37  * @run main GenericTypeWellFormednessTest
38  */
39 
40 import com.sun.tools.javac.code.BoundKind;
41 import com.sun.tools.javac.code.Type;
42 import com.sun.tools.javac.code.Type.*;
43 import com.sun.tools.javac.code.Symbol;
44 import com.sun.tools.javac.code.Symbol.*;
45 import java.lang.reflect.Array;
46 
47 /**
48  * Check parameterized type well-formedness. This test executes a number of checks
49  * in order to establish as to whether an instantiation of a generic type conforms
50  * to the generic class' declared bounds.
51  */
52 public class GenericTypeWellFormednessTest extends TypeHarness {
53 
54     static int executedCount = 0;
55     static int ignoredCount = 0;
56 
57     InstantiableType[] rows;
58     Type[] columns;
59 
60     static class InstantiableType {
61         protected Type type;
62 
InstantiableType(Type type)63         public InstantiableType(Type type) {
64             this.type = type;
65         }
66 
inst(Type clazz)67         Type inst(Type clazz) {
68             return type;
69         }
70     }
71 
72     enum Result {
73         /* generic type is well-formed w.r.t. declared bounds */
74         OK(true),
75         /* generic type is not well-formed w.r.t. declared bounds */
76         FAIL(false),
77         /* generic type is not well-formed w.r.t. declared bounds according to the JLS 3rd,
78          * but javac allows it (spec for generic type well-formedness is overly restrictive)
79          * See regression test test/tools/generics/wildcards/T5097548.java
80          */
81         IGNORE(false);
82 
83         boolean value;
84 
Result(boolean value)85         Result(boolean value) {
86             this.value = value;
87         }
88     }
89 
90     static final Result T = Result.OK;
91     static final Result F = Result.FAIL;
92     static final Result I = Result.IGNORE;
93 
94     /*is a type in 'rows' a valid instantiation for the generic class in 'col' ? */
95     Result[][] isValidInstantiation = {
96                      //Foo<X>, Foo<X ext Object>, Foo<X ext Number>, Foo<X ext Foo<X>>, Foo<X ext Foo<+X>>, Foo<X ext Foo<-X>>, Foo<X ext Foo<?>>
97     /*Foo<Object>*/  { T     , T                , F                , F                , F                 , F                 , F },
98     /*Foo<Number>*/  { T     , T                , T                , F                , F                 , F                 , F },
99     /*Foo<Integer>*/ { T     , T                , T                , F                , F                 , F                 , F },
100     /*Foo<Double>*/  { T     , T                , T                , F                , F                 , F                 , F },
101     /*Foo<String>*/  { T     , T                , F                , F                , F                 , F                 , F },
102     /*Foo<X1>*/      { T     , T                , F                , F                , F                 , F                 , F },
103     /*Foo<X2>*/      { T     , T                , T                , F                , F                 , F                 , F },
104     /*Foo<X3>*/      { T     , T                , T                , F                , F                 , F                 , F },
105     /*Foo<X4>*/      { T     , T                , T                , F                , F                 , F                 , F },
106     /*Foo<X5>*/      { T     , T                , F                , F                , F                 , F                 , F },
107     /*Foo<X6>*/      { T     , T                , F                , T                , T                 , T                 , T },
108     /*Foo<+Object>*/ { T     , T                , I                , I                , I                 , I                 , I },
109     /*Foo<+Number>*/ { T     , T                , T                , F                , F                 , F                 , F },
110     /*Foo<+Integer>*/{ T     , T                , T                , F                , F                 , F                 , F },
111     /*Foo<+Double>*/ { T     , T                , T                , F                , F                 , F                 , F },
112     /*Foo<+String>*/ { T     , T                , F                , F                , F                 , F                 , F },
113     /*Foo<+X1>*/     { T     , T                , F                , F                , F                 , F                 , F },
114     /*Foo<+X2>*/     { T     , T                , T                , F                , F                 , F                 , F },
115     /*Foo<+X3>*/     { T     , T                , T                , F                , F                 , F                 , F },
116     /*Foo<+X4>*/     { T     , T                , T                , F                , F                 , F                 , F },
117     /*Foo<+X5>*/     { T     , T                , F                , F                , F                 , F                 , F },
118     /*Foo<+X6>*/     { T     , T                , F                , T                , T                 , I                 , T },
119     /*Foo<-Object>*/ { T     , T                , F                , F                , F                 , F                 , F },
120     /*Foo<-Number>*/ { T     , T                , T                , F                , F                 , F                 , F },
121     /*Foo<-Integer>*/{ T     , T                , T                , F                , F                 , F                 , F },
122     /*Foo<-Double>*/ { T     , T                , T                , F                , F                 , F                 , F },
123     /*Foo<-String>*/ { T     , T                , F                , F                , F                 , F                 , F },
124     /*Foo<-X1>*/     { T     , T                , I                , I                , I                 , I                 , I },
125     /*Foo<-X2>*/     { T     , T                , I                , F                , F                 , F                 , F },
126     /*Foo<-X3>*/     { T     , T                , I                , F                , F                 , F                 , F },
127     /*Foo<-X4>*/     { T     , T                , I                , F                , F                 , F                 , F },
128     /*Foo<-X5>*/     { T     , T                , I                , F                , F                 , F                 , F },
129     /*Foo<-X6>*/     { T     , T                , F                , T                , I                 , I                 , T },
130     /*Foo<?>*/       { T     , T                , T                , T                , T                 , T                 , T }};
131 
GenericTypeWellFormednessTest()132     GenericTypeWellFormednessTest() {
133         InstantiableType[] basicTypes = {
134             new InstantiableType(predef.objectType),
135             new InstantiableType(NumberType()),
136             new InstantiableType(box(predef.intType)),
137             new InstantiableType(box(predef.doubleType)),
138             new InstantiableType(predef.stringType) };
139 
140         InstantiableType[] typeVars = new InstantiableType[basicTypes.length + 1];
141         for (int i = 0 ; i < basicTypes.length ; i++) {
142            typeVars[i] = new InstantiableType(fac.TypeVariable(basicTypes[i].type));
143         }
144         typeVars[typeVars.length - 1] = new InstantiableType(null) {
145             Type inst(Type clazz) {
146                 TypeVar tvar = fac.TypeVariable();
147                 tvar.setUpperBound( subst(clazz, Mapping(clazz.getTypeArguments().head, tvar)) );
148                 return tvar;
149             }
150         };
151 
152         InstantiableType[] typeArgs = join(InstantiableType.class, basicTypes, typeVars);
153 
154         InstantiableType[] invariantTypes = new InstantiableType[typeArgs.length];
155         for (int i = 0 ; i < typeArgs.length ; i++) {
156            final InstantiableType type1 = typeArgs[i];
157            invariantTypes[i] = new InstantiableType(typeArgs[i].type) {
158                Type inst(Type clazz) {
159                    return subst(clazz, Mapping(clazz.getTypeArguments().head, type1.inst(clazz)));
160                }
161             };
162         }
163 
164         InstantiableType[] covariantTypes = new InstantiableType[typeArgs.length];
165         for (int i = 0 ; i < typeArgs.length ; i++) {
166            final InstantiableType type1 = typeArgs[i];
167            covariantTypes[i] = new InstantiableType(null) {
168                Type inst(Type clazz) {
169                    Type t = fac.Wildcard(BoundKind.EXTENDS, type1.inst(clazz));
170                    return subst(clazz, Mapping(clazz.getTypeArguments().head, t));
171                }
172             };
173         }
174 
175         InstantiableType[] contravariantTypes = new InstantiableType[typeArgs.length];
176         for (int i = 0 ; i < typeArgs.length ; i++) {
177            final InstantiableType type1 = typeArgs[i];
178            contravariantTypes[i] = new InstantiableType(null) {
179                Type inst(Type clazz) {
180                    Type t = fac.Wildcard(BoundKind.SUPER, type1.inst(clazz));
181                    return subst(clazz, Mapping(clazz.getTypeArguments().head, t));
182                }
183             };
184         }
185 
186         InstantiableType[] bivariantTypes = {
187             new InstantiableType(fac.Wildcard(BoundKind.UNBOUND, predef.objectType)) {
188                Type inst(Type clazz) {
189                    return subst(clazz, Mapping(clazz.getTypeArguments().head, type));
190                }
191             }
192         };
193 
194         rows = join(InstantiableType.class, invariantTypes, covariantTypes, contravariantTypes, bivariantTypes);
195 
196         Type tv1 = fac.TypeVariable();
197         Type decl1 = fac.Class(tv1);
198 
199         Type tv2 = fac.TypeVariable(predef.objectType);
200         Type decl2 = fac.Class(tv2);
201 
202         Type tv3 = fac.TypeVariable(NumberType());
203         Type decl3 = fac.Class(tv3);
204 
205         TypeVar tv4 = fac.TypeVariable();
206         Type decl4 = fac.Class(tv4);
207         tv4.setUpperBound(decl4);
208         tv4.tsym.name = predef.exceptionType.tsym.name;
209 
210         TypeVar tv5 = fac.TypeVariable();
211         Type decl5 = fac.Class(tv5);
212         tv5.setUpperBound( subst(decl5, Mapping(tv5, fac.Wildcard(BoundKind.EXTENDS, tv5))) );
213 
214         TypeVar tv6 = fac.TypeVariable();
215         Type decl6 = fac.Class(tv6);
216         tv6.setUpperBound( subst(decl6, Mapping(tv6, fac.Wildcard(BoundKind.SUPER, tv6))) );
217 
218         TypeVar tv7 = fac.TypeVariable();
219         Type decl7 = fac.Class(tv7);
220         tv7.setUpperBound( subst(decl7, Mapping(tv7, fac.Wildcard(BoundKind.UNBOUND, predef.objectType))) );
221 
222         columns = new Type[] {
223             decl1, decl2, decl3, decl4, decl5, decl6, decl7
224         };
225     }
226 
test()227     void test() {
228         for (int i = 0; i < rows.length ; i++) {
229             for (int j = 0; j < columns.length ; j++) {
230                 Type decl = columns[j];
231                 Type inst = rows[i].inst(decl);
232                 if (isValidInstantiation[i][j] != Result.IGNORE) {
233                     executedCount++;
234                     assertValidGenericType(inst, isValidInstantiation[i][j].value);
235                 } else {
236                     ignoredCount++;
237                 }
238             }
239         }
240     }
241 
NumberType()242     Type NumberType() {
243         Symbol s = box(predef.intType).tsym;
244         s.complete();
245         return ((ClassType)s.type).supertype_field;
246     }
247 
248     @SuppressWarnings("unchecked")
join(Class<T> type, T[]... args)249     <T> T[] join(Class<T> type, T[]... args) {
250         int totalLength = 0;
251         for (T[] arr : args) {
252             totalLength += arr.length;
253         }
254         T[] new_arr = (T[])Array.newInstance(type, totalLength);
255         int idx = 0;
256         for (T[] arr : args) {
257             System.arraycopy(arr, 0, new_arr, idx, arr.length);
258             idx += arr.length;
259         }
260         return new_arr;
261     }
262 
main(String[] args)263     public static void main(String[] args) {
264         new GenericTypeWellFormednessTest().test();
265         System.out.println("Executed checks : " + executedCount);
266         System.out.println("Ignored checks : " + ignoredCount);
267     }
268 }
269