mcimadamore@821: /* ohair@962: * Copyright (c) 2010, 2011, Oracle and/or its affiliates. All rights reserved. mcimadamore@821: * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. mcimadamore@821: * mcimadamore@821: * This code is free software; you can redistribute it and/or modify it mcimadamore@821: * under the terms of the GNU General Public License version 2 only, as mcimadamore@821: * published by the Free Software Foundation. mcimadamore@821: * mcimadamore@821: * This code is distributed in the hope that it will be useful, but WITHOUT mcimadamore@821: * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or mcimadamore@821: * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License mcimadamore@821: * version 2 for more details (a copy is included in the LICENSE file that mcimadamore@821: * accompanied this code). mcimadamore@821: * mcimadamore@821: * You should have received a copy of the GNU General Public License version mcimadamore@821: * 2 along with this work; if not, write to the Free Software Foundation, mcimadamore@821: * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. mcimadamore@821: * mcimadamore@821: * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA mcimadamore@821: * or visit www.oracle.com if you need additional information or have any mcimadamore@821: * questions. mcimadamore@821: */ mcimadamore@821: mcimadamore@821: /* mcimadamore@821: * @test mcimadamore@821: * @bug 7007432 7006109 mcimadamore@821: * @summary Test generic types well-formedness mcimadamore@821: * @author mcimadamore mcimadamore@821: * @library . mcimadamore@821: * @run main GenericTypeWellFormednessTest mcimadamore@821: */ mcimadamore@821: mcimadamore@821: import com.sun.tools.javac.code.BoundKind; mcimadamore@821: import com.sun.tools.javac.code.Type; mcimadamore@821: import com.sun.tools.javac.code.Type.*; mcimadamore@821: import com.sun.tools.javac.code.Symbol; mcimadamore@821: import com.sun.tools.javac.code.Symbol.*; mcimadamore@821: import java.lang.reflect.Array; mcimadamore@821: mcimadamore@821: /** mcimadamore@821: * Check parameterized type well-formedness. This test executes a number of checks mcimadamore@821: * in order to establish as to whether an instantiation of a generic type conforms mcimadamore@821: * to the generic class' declared bounds. mcimadamore@821: */ mcimadamore@821: public class GenericTypeWellFormednessTest extends TypeHarness { mcimadamore@821: mcimadamore@821: static int executedCount = 0; mcimadamore@821: static int ignoredCount = 0; mcimadamore@821: mcimadamore@821: InstantiableType[] rows; mcimadamore@821: Type[] columns; mcimadamore@821: mcimadamore@821: static class InstantiableType { mcimadamore@821: protected Type type; mcimadamore@821: mcimadamore@821: public InstantiableType(Type type) { mcimadamore@821: this.type = type; mcimadamore@821: } mcimadamore@821: mcimadamore@821: Type inst(Type clazz) { mcimadamore@821: return type; mcimadamore@821: } mcimadamore@821: } mcimadamore@821: mcimadamore@821: enum Result { mcimadamore@821: /* generic type is well-formed w.r.t. declared bounds */ mcimadamore@821: OK(true), mcimadamore@821: /* generic type is not well-formed w.r.t. declared bounds */ mcimadamore@821: FAIL(false), mcimadamore@821: /* generic type is not well-formed w.r.t. declared bounds according to the JLS 3rd, mcimadamore@821: * but javac allows it (spec for generic type well-formedness is overly restrictive) mcimadamore@821: * See regression test test/tools/generics/wildcards/T5097548.java mcimadamore@821: */ mcimadamore@821: IGNORE(false); mcimadamore@821: mcimadamore@821: boolean value; mcimadamore@821: mcimadamore@821: Result(boolean value) { mcimadamore@821: this.value = value; mcimadamore@821: } mcimadamore@821: } mcimadamore@821: mcimadamore@821: static final Result T = Result.OK; mcimadamore@821: static final Result F = Result.FAIL; mcimadamore@821: static final Result I = Result.IGNORE; mcimadamore@821: mcimadamore@821: /*is a type in 'rows' a valid instantiation for the generic class in 'col' ? */ mcimadamore@821: Result[][] isValidInstantiation = { mcimadamore@821: //Foo, Foo, Foo, Foo>, Foo>, Foo>, Foo> mcimadamore@821: /*Foo*/ { T , T , F , F , F , F , F }, mcimadamore@821: /*Foo*/ { T , T , T , F , F , F , F }, mcimadamore@821: /*Foo*/ { T , T , T , F , F , F , F }, mcimadamore@821: /*Foo*/ { T , T , T , F , F , F , F }, mcimadamore@821: /*Foo*/ { T , T , F , F , F , F , F }, mcimadamore@821: /*Foo*/ { T , T , F , F , F , F , F }, mcimadamore@821: /*Foo*/ { T , T , T , F , F , F , F }, mcimadamore@821: /*Foo*/ { T , T , T , F , F , F , F }, mcimadamore@821: /*Foo*/ { T , T , T , F , F , F , F }, mcimadamore@821: /*Foo*/ { T , T , F , F , F , F , F }, mcimadamore@821: /*Foo*/ { T , T , F , T , T , T , T }, mcimadamore@821: /*Foo<+Object>*/ { T , T , I , I , I , I , I }, mcimadamore@821: /*Foo<+Number>*/ { T , T , T , F , F , F , F }, mcimadamore@821: /*Foo<+Integer>*/{ T , T , T , F , F , F , F }, mcimadamore@821: /*Foo<+Double>*/ { T , T , T , F , F , F , F }, mcimadamore@821: /*Foo<+String>*/ { T , T , F , F , F , F , F }, mcimadamore@821: /*Foo<+X1>*/ { T , T , F , F , F , F , F }, mcimadamore@821: /*Foo<+X2>*/ { T , T , T , F , F , F , F }, mcimadamore@821: /*Foo<+X3>*/ { T , T , T , F , F , F , F }, mcimadamore@821: /*Foo<+X4>*/ { T , T , T , F , F , F , F }, mcimadamore@821: /*Foo<+X5>*/ { T , T , F , F , F , F , F }, mcimadamore@821: /*Foo<+X6>*/ { T , T , F , T , T , I , T }, mcimadamore@821: /*Foo<-Object>*/ { T , T , F , F , F , F , F }, mcimadamore@821: /*Foo<-Number>*/ { T , T , T , F , F , F , F }, mcimadamore@821: /*Foo<-Integer>*/{ T , T , T , F , F , F , F }, mcimadamore@821: /*Foo<-Double>*/ { T , T , T , F , F , F , F }, mcimadamore@821: /*Foo<-String>*/ { T , T , F , F , F , F , F }, mcimadamore@821: /*Foo<-X1>*/ { T , T , I , I , I , I , I }, mcimadamore@821: /*Foo<-X2>*/ { T , T , I , F , F , F , F }, mcimadamore@821: /*Foo<-X3>*/ { T , T , I , F , F , F , F }, mcimadamore@821: /*Foo<-X4>*/ { T , T , I , F , F , F , F }, mcimadamore@821: /*Foo<-X5>*/ { T , T , I , F , F , F , F }, mcimadamore@821: /*Foo<-X6>*/ { T , T , F , T , I , I , T }, mcimadamore@821: /*Foo*/ { T , T , T , T , T , T , T }}; mcimadamore@821: mcimadamore@821: GenericTypeWellFormednessTest() { mcimadamore@821: InstantiableType[] basicTypes = { mcimadamore@821: new InstantiableType(predef.objectType), mcimadamore@821: new InstantiableType(NumberType()), mcimadamore@821: new InstantiableType(box(predef.intType)), mcimadamore@821: new InstantiableType(box(predef.doubleType)), mcimadamore@821: new InstantiableType(predef.stringType) }; mcimadamore@821: mcimadamore@821: InstantiableType[] typeVars = new InstantiableType[basicTypes.length + 1]; mcimadamore@821: for (int i = 0 ; i < basicTypes.length ; i++) { mcimadamore@821: typeVars[i] = new InstantiableType(fac.TypeVariable(basicTypes[i].type)); mcimadamore@821: } mcimadamore@821: typeVars[typeVars.length - 1] = new InstantiableType(null) { mcimadamore@821: Type inst(Type clazz) { mcimadamore@821: TypeVar tvar = fac.TypeVariable(); mcimadamore@821: tvar.bound = subst(clazz, Mapping(clazz.getTypeArguments().head, tvar)); mcimadamore@821: return tvar; mcimadamore@821: } mcimadamore@821: }; mcimadamore@821: mcimadamore@821: InstantiableType[] typeArgs = join(InstantiableType.class, basicTypes, typeVars); mcimadamore@821: mcimadamore@821: InstantiableType[] invariantTypes = new InstantiableType[typeArgs.length]; mcimadamore@821: for (int i = 0 ; i < typeArgs.length ; i++) { mcimadamore@821: final InstantiableType type1 = typeArgs[i]; mcimadamore@821: invariantTypes[i] = new InstantiableType(typeArgs[i].type) { mcimadamore@821: Type inst(Type clazz) { mcimadamore@821: return subst(clazz, Mapping(clazz.getTypeArguments().head, type1.inst(clazz))); mcimadamore@821: } mcimadamore@821: }; mcimadamore@821: } mcimadamore@821: mcimadamore@821: InstantiableType[] covariantTypes = new InstantiableType[typeArgs.length]; mcimadamore@821: for (int i = 0 ; i < typeArgs.length ; i++) { mcimadamore@821: final InstantiableType type1 = typeArgs[i]; mcimadamore@821: covariantTypes[i] = new InstantiableType(null) { mcimadamore@821: Type inst(Type clazz) { mcimadamore@821: Type t = fac.Wildcard(BoundKind.EXTENDS, type1.inst(clazz)); mcimadamore@821: return subst(clazz, Mapping(clazz.getTypeArguments().head, t)); mcimadamore@821: } mcimadamore@821: }; mcimadamore@821: } mcimadamore@821: mcimadamore@821: InstantiableType[] contravariantTypes = new InstantiableType[typeArgs.length]; mcimadamore@821: for (int i = 0 ; i < typeArgs.length ; i++) { mcimadamore@821: final InstantiableType type1 = typeArgs[i]; mcimadamore@821: contravariantTypes[i] = new InstantiableType(null) { mcimadamore@821: Type inst(Type clazz) { mcimadamore@821: Type t = fac.Wildcard(BoundKind.SUPER, type1.inst(clazz)); mcimadamore@821: return subst(clazz, Mapping(clazz.getTypeArguments().head, t)); mcimadamore@821: } mcimadamore@821: }; mcimadamore@821: } mcimadamore@821: mcimadamore@821: InstantiableType[] bivariantTypes = { mcimadamore@821: new InstantiableType(fac.Wildcard(BoundKind.UNBOUND, predef.objectType)) { mcimadamore@821: Type inst(Type clazz) { mcimadamore@821: return subst(clazz, Mapping(clazz.getTypeArguments().head, type)); mcimadamore@821: } mcimadamore@821: } mcimadamore@821: }; mcimadamore@821: mcimadamore@821: rows = join(InstantiableType.class, invariantTypes, covariantTypes, contravariantTypes, bivariantTypes); mcimadamore@821: mcimadamore@821: Type tv1 = fac.TypeVariable(); mcimadamore@821: Type decl1 = fac.Class(tv1); mcimadamore@821: mcimadamore@821: Type tv2 = fac.TypeVariable(predef.objectType); mcimadamore@821: Type decl2 = fac.Class(tv2); mcimadamore@821: mcimadamore@821: Type tv3 = fac.TypeVariable(NumberType()); mcimadamore@821: Type decl3 = fac.Class(tv3); mcimadamore@821: mcimadamore@821: TypeVar tv4 = fac.TypeVariable(); mcimadamore@821: Type decl4 = fac.Class(tv4); mcimadamore@821: tv4.bound = decl4; mcimadamore@821: tv4.tsym.name = predef.exceptionType.tsym.name; mcimadamore@821: mcimadamore@821: TypeVar tv5 = fac.TypeVariable(); mcimadamore@821: Type decl5 = fac.Class(tv5); mcimadamore@821: tv5.bound = subst(decl5, Mapping(tv5, fac.Wildcard(BoundKind.EXTENDS, tv5))); mcimadamore@821: mcimadamore@821: TypeVar tv6 = fac.TypeVariable(); mcimadamore@821: Type decl6 = fac.Class(tv6); mcimadamore@821: tv6.bound = subst(decl6, Mapping(tv6, fac.Wildcard(BoundKind.SUPER, tv6))); mcimadamore@821: mcimadamore@821: TypeVar tv7 = fac.TypeVariable(); mcimadamore@821: Type decl7 = fac.Class(tv7); mcimadamore@821: tv7.bound = subst(decl7, Mapping(tv7, fac.Wildcard(BoundKind.UNBOUND, predef.objectType))); mcimadamore@821: mcimadamore@821: columns = new Type[] { mcimadamore@821: decl1, decl2, decl3, decl4, decl5, decl6, decl7 mcimadamore@821: }; mcimadamore@821: } mcimadamore@821: mcimadamore@821: void test() { mcimadamore@821: for (int i = 0; i < rows.length ; i++) { mcimadamore@821: for (int j = 0; j < columns.length ; j++) { mcimadamore@821: Type decl = columns[j]; mcimadamore@821: Type inst = rows[i].inst(decl); mcimadamore@821: if (isValidInstantiation[i][j] != Result.IGNORE) { mcimadamore@821: executedCount++; mcimadamore@821: assertValidGenericType(inst, isValidInstantiation[i][j].value); mcimadamore@821: } else { mcimadamore@821: ignoredCount++; mcimadamore@821: } mcimadamore@821: } mcimadamore@821: } mcimadamore@821: } mcimadamore@821: mcimadamore@821: Type NumberType() { mcimadamore@821: Symbol s = box(predef.intType).tsym; mcimadamore@821: s.complete(); mcimadamore@821: return ((ClassType)s.type).supertype_field; mcimadamore@821: } mcimadamore@821: mcimadamore@821: @SuppressWarnings("unchecked") mcimadamore@821: T[] join(Class type, T[]... args) { mcimadamore@821: int totalLength = 0; mcimadamore@821: for (T[] arr : args) { mcimadamore@821: totalLength += arr.length; mcimadamore@821: } mcimadamore@821: T[] new_arr = (T[])Array.newInstance(type, totalLength); mcimadamore@821: int idx = 0; mcimadamore@821: for (T[] arr : args) { mcimadamore@821: System.arraycopy(arr, 0, new_arr, idx, arr.length); mcimadamore@821: idx += arr.length; mcimadamore@821: } mcimadamore@821: return new_arr; mcimadamore@821: } mcimadamore@821: mcimadamore@821: public static void main(String[] args) { mcimadamore@821: new GenericTypeWellFormednessTest().test(); mcimadamore@821: System.out.println("Executed checks : " + executedCount); mcimadamore@821: System.out.println("Ignored checks : " + ignoredCount); mcimadamore@821: } mcimadamore@821: }