GenericTypeWellFormednessTest.java revision 3504:30bfbfa94fad
1/*
2 * Copyright (c) 2010, 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 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
40import com.sun.tools.javac.code.BoundKind;
41import com.sun.tools.javac.code.Type;
42import com.sun.tools.javac.code.Type.*;
43import com.sun.tools.javac.code.Symbol;
44import com.sun.tools.javac.code.Symbol.*;
45import 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 */
52public 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
63        public InstantiableType(Type type) {
64            this.type = type;
65        }
66
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
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
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.bound = 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.bound = decl4;
208        tv4.tsym.name = predef.exceptionType.tsym.name;
209
210        TypeVar tv5 = fac.TypeVariable();
211        Type decl5 = fac.Class(tv5);
212        tv5.bound = subst(decl5, Mapping(tv5, fac.Wildcard(BoundKind.EXTENDS, tv5)));
213
214        TypeVar tv6 = fac.TypeVariable();
215        Type decl6 = fac.Class(tv6);
216        tv6.bound = subst(decl6, Mapping(tv6, fac.Wildcard(BoundKind.SUPER, tv6)));
217
218        TypeVar tv7 = fac.TypeVariable();
219        Type decl7 = fac.Class(tv7);
220        tv7.bound = 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
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
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")
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
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