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