mirror of
https://github.com/openjdk/jdk.git
synced 2025-09-20 19:14:38 +02:00
7007432: Test generic types well-formedness
Add a new kind of check (well-formedness of generic type w.r.t. declared bounds) in the type-harness Reviewed-by: jjg
This commit is contained in:
parent
7d90979693
commit
ede9924b4e
3 changed files with 362 additions and 70 deletions
|
@ -506,43 +506,18 @@ public class Check {
|
||||||
* @param a The type that should be bounded by bs.
|
* @param a The type that should be bounded by bs.
|
||||||
* @param bs The bound.
|
* @param bs The bound.
|
||||||
*/
|
*/
|
||||||
private void checkExtends(DiagnosticPosition pos, Type a, TypeVar bs) {
|
private boolean checkExtends(Type a, TypeVar bs) {
|
||||||
if (a.isUnbound()) {
|
if (a.isUnbound()) {
|
||||||
return;
|
return true;
|
||||||
} else if (a.tag != WILDCARD) {
|
} else if (a.tag != WILDCARD) {
|
||||||
a = types.upperBound(a);
|
a = types.upperBound(a);
|
||||||
for (List<Type> l = types.getBounds(bs); l.nonEmpty(); l = l.tail) {
|
return types.isSubtype(a, bs.bound);
|
||||||
if (!types.isSubtype(a, l.head)) {
|
|
||||||
log.error(pos, "not.within.bounds", a);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
} else if (a.isExtendsBound()) {
|
} else if (a.isExtendsBound()) {
|
||||||
if (!types.isCastable(bs.getUpperBound(), types.upperBound(a), Warner.noWarnings))
|
return types.isCastable(bs.getUpperBound(), types.upperBound(a), Warner.noWarnings);
|
||||||
log.error(pos, "not.within.bounds", a);
|
|
||||||
} else if (a.isSuperBound()) {
|
} else if (a.isSuperBound()) {
|
||||||
if (types.notSoftSubtype(types.lowerBound(a), bs.getUpperBound()))
|
return !types.notSoftSubtype(types.lowerBound(a), bs.getUpperBound());
|
||||||
log.error(pos, "not.within.bounds", a);
|
|
||||||
}
|
}
|
||||||
}
|
return true;
|
||||||
|
|
||||||
/** Check that a type is within some bounds.
|
|
||||||
*
|
|
||||||
* Used in TypeApply to verify that, e.g., X in V<X> is a valid
|
|
||||||
* type argument.
|
|
||||||
* @param pos Position to be used for error reporting.
|
|
||||||
* @param a The type that should be bounded by bs.
|
|
||||||
* @param bs The bound.
|
|
||||||
*/
|
|
||||||
private void checkCapture(JCTypeApply tree) {
|
|
||||||
List<JCExpression> args = tree.getTypeArguments();
|
|
||||||
for (Type arg : types.capture(tree.type).getTypeArguments()) {
|
|
||||||
if (arg.tag == TYPEVAR && arg.getUpperBound().isErroneous()) {
|
|
||||||
log.error(args.head.pos, "not.within.bounds", args.head.type);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
args = args.tail;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/** Check that type is different from 'void'.
|
/** Check that type is different from 'void'.
|
||||||
|
@ -775,6 +750,74 @@ public class Check {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Check that type 't' is a valid instantiation of a generic class
|
||||||
|
* (see JLS 4.5)
|
||||||
|
*
|
||||||
|
* @param t class type to be checked
|
||||||
|
* @return true if 't' is well-formed
|
||||||
|
*/
|
||||||
|
public boolean checkValidGenericType(Type t) {
|
||||||
|
return firstIncompatibleTypeArg(t) == null;
|
||||||
|
}
|
||||||
|
//WHERE
|
||||||
|
private Type firstIncompatibleTypeArg(Type type) {
|
||||||
|
List<Type> formals = type.tsym.type.allparams();
|
||||||
|
List<Type> actuals = type.allparams();
|
||||||
|
List<Type> args = type.getTypeArguments();
|
||||||
|
List<Type> forms = type.tsym.type.getTypeArguments();
|
||||||
|
ListBuffer<Type> tvars_buf = new ListBuffer<Type>();
|
||||||
|
|
||||||
|
// For matching pairs of actual argument types `a' and
|
||||||
|
// formal type parameters with declared bound `b' ...
|
||||||
|
while (args.nonEmpty() && forms.nonEmpty()) {
|
||||||
|
// exact type arguments needs to know their
|
||||||
|
// bounds (for upper and lower bound
|
||||||
|
// calculations). So we create new TypeVars with
|
||||||
|
// bounds substed with actuals.
|
||||||
|
tvars_buf.append(types.substBound(((TypeVar)forms.head),
|
||||||
|
formals,
|
||||||
|
actuals));
|
||||||
|
args = args.tail;
|
||||||
|
forms = forms.tail;
|
||||||
|
}
|
||||||
|
|
||||||
|
args = type.getTypeArguments();
|
||||||
|
List<Type> tvars_cap = types.substBounds(formals,
|
||||||
|
formals,
|
||||||
|
types.capture(type).allparams());
|
||||||
|
while (args.nonEmpty() && tvars_cap.nonEmpty()) {
|
||||||
|
// Let the actual arguments know their bound
|
||||||
|
args.head.withTypeVar((TypeVar)tvars_cap.head);
|
||||||
|
args = args.tail;
|
||||||
|
tvars_cap = tvars_cap.tail;
|
||||||
|
}
|
||||||
|
|
||||||
|
args = type.getTypeArguments();
|
||||||
|
List<Type> tvars = tvars_buf.toList();
|
||||||
|
|
||||||
|
while (args.nonEmpty() && tvars.nonEmpty()) {
|
||||||
|
Type actual = types.subst(args.head,
|
||||||
|
type.tsym.type.getTypeArguments(),
|
||||||
|
tvars_buf.toList());
|
||||||
|
if (!checkExtends(actual, (TypeVar)tvars.head)) {
|
||||||
|
return args.head;
|
||||||
|
}
|
||||||
|
args = args.tail;
|
||||||
|
tvars = tvars.tail;
|
||||||
|
}
|
||||||
|
|
||||||
|
args = type.getTypeArguments();
|
||||||
|
|
||||||
|
for (Type arg : types.capture(type).getTypeArguments()) {
|
||||||
|
if (arg.tag == TYPEVAR && arg.getUpperBound().isErroneous()) {
|
||||||
|
return args.head;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
/** Check that given modifiers are legal for given symbol and
|
/** Check that given modifiers are legal for given symbol and
|
||||||
* return modifiers together with any implicit modififiers for that symbol.
|
* return modifiers together with any implicit modififiers for that symbol.
|
||||||
* Warning: we can't use flags() here since this method
|
* Warning: we can't use flags() here since this method
|
||||||
|
@ -987,11 +1030,17 @@ public class Check {
|
||||||
@Override
|
@Override
|
||||||
public void visitTypeApply(JCTypeApply tree) {
|
public void visitTypeApply(JCTypeApply tree) {
|
||||||
if (tree.type.tag == CLASS) {
|
if (tree.type.tag == CLASS) {
|
||||||
List<Type> formals = tree.type.tsym.type.allparams();
|
|
||||||
List<Type> actuals = tree.type.allparams();
|
|
||||||
List<JCExpression> args = tree.arguments;
|
List<JCExpression> args = tree.arguments;
|
||||||
List<Type> forms = tree.type.tsym.type.getTypeArguments();
|
List<Type> forms = tree.type.tsym.type.getTypeArguments();
|
||||||
ListBuffer<Type> tvars_buf = new ListBuffer<Type>();
|
|
||||||
|
Type incompatibleArg = firstIncompatibleTypeArg(tree.type);
|
||||||
|
if (incompatibleArg != null) {
|
||||||
|
for (JCTree arg : tree.arguments) {
|
||||||
|
if (arg.type == incompatibleArg) {
|
||||||
|
log.error(arg, "not.within.bounds", incompatibleArg);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
boolean is_java_lang_Class = tree.type.tsym.flatName() == names.java_lang_Class;
|
boolean is_java_lang_Class = tree.type.tsym.flatName() == names.java_lang_Class;
|
||||||
|
|
||||||
|
@ -1001,46 +1050,10 @@ public class Check {
|
||||||
validateTree(args.head,
|
validateTree(args.head,
|
||||||
!(isOuter && is_java_lang_Class),
|
!(isOuter && is_java_lang_Class),
|
||||||
false);
|
false);
|
||||||
|
|
||||||
// exact type arguments needs to know their
|
|
||||||
// bounds (for upper and lower bound
|
|
||||||
// calculations). So we create new TypeVars with
|
|
||||||
// bounds substed with actuals.
|
|
||||||
tvars_buf.append(types.substBound(((TypeVar)forms.head),
|
|
||||||
formals,
|
|
||||||
actuals));
|
|
||||||
|
|
||||||
args = args.tail;
|
args = args.tail;
|
||||||
forms = forms.tail;
|
forms = forms.tail;
|
||||||
}
|
}
|
||||||
|
|
||||||
args = tree.arguments;
|
|
||||||
List<Type> tvars_cap = types.substBounds(formals,
|
|
||||||
formals,
|
|
||||||
types.capture(tree.type).allparams());
|
|
||||||
while (args.nonEmpty() && tvars_cap.nonEmpty()) {
|
|
||||||
// Let the actual arguments know their bound
|
|
||||||
args.head.type.withTypeVar((TypeVar)tvars_cap.head);
|
|
||||||
args = args.tail;
|
|
||||||
tvars_cap = tvars_cap.tail;
|
|
||||||
}
|
|
||||||
|
|
||||||
args = tree.arguments;
|
|
||||||
List<Type> tvars = tvars_buf.toList();
|
|
||||||
|
|
||||||
while (args.nonEmpty() && tvars.nonEmpty()) {
|
|
||||||
Type actual = types.subst(args.head.type,
|
|
||||||
tree.type.tsym.type.getTypeArguments(),
|
|
||||||
tvars_buf.toList());
|
|
||||||
checkExtends(args.head.pos(),
|
|
||||||
actual,
|
|
||||||
(TypeVar)tvars.head);
|
|
||||||
args = args.tail;
|
|
||||||
tvars = tvars.tail;
|
|
||||||
}
|
|
||||||
|
|
||||||
checkCapture(tree);
|
|
||||||
|
|
||||||
// Check that this type is either fully parameterized, or
|
// Check that this type is either fully parameterized, or
|
||||||
// not parameterized at all.
|
// not parameterized at all.
|
||||||
if (tree.type.getEnclosingType().isRaw())
|
if (tree.type.getEnclosingType().isRaw())
|
||||||
|
|
|
@ -0,0 +1,261 @@
|
||||||
|
/*
|
||||||
|
* Copyright (c) 2010, Oracle and/or its affiliates. All rights reserved.
|
||||||
|
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||||
|
*
|
||||||
|
* This code is free software; you can redistribute it and/or modify it
|
||||||
|
* under the terms of the GNU General Public License version 2 only, as
|
||||||
|
* published by the Free Software Foundation.
|
||||||
|
*
|
||||||
|
* This code is distributed in the hope that it will be useful, but WITHOUT
|
||||||
|
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||||
|
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||||
|
* version 2 for more details (a copy is included in the LICENSE file that
|
||||||
|
* accompanied this code).
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License version
|
||||||
|
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||||
|
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||||
|
*
|
||||||
|
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||||
|
* or visit www.oracle.com if you need additional information or have any
|
||||||
|
* questions.
|
||||||
|
*/
|
||||||
|
|
||||||
|
/*
|
||||||
|
* @test
|
||||||
|
* @bug 7007432 7006109
|
||||||
|
* @summary Test generic types well-formedness
|
||||||
|
* @author mcimadamore
|
||||||
|
* @library .
|
||||||
|
* @run main GenericTypeWellFormednessTest
|
||||||
|
*/
|
||||||
|
|
||||||
|
import com.sun.tools.javac.code.BoundKind;
|
||||||
|
import com.sun.tools.javac.code.Type;
|
||||||
|
import com.sun.tools.javac.code.Type.*;
|
||||||
|
import com.sun.tools.javac.code.Symbol;
|
||||||
|
import com.sun.tools.javac.code.Symbol.*;
|
||||||
|
import java.lang.reflect.Array;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Check parameterized type well-formedness. This test executes a number of checks
|
||||||
|
* in order to establish as to whether an instantiation of a generic type conforms
|
||||||
|
* to the generic class' declared bounds.
|
||||||
|
*/
|
||||||
|
public class GenericTypeWellFormednessTest extends TypeHarness {
|
||||||
|
|
||||||
|
static int executedCount = 0;
|
||||||
|
static int ignoredCount = 0;
|
||||||
|
|
||||||
|
InstantiableType[] rows;
|
||||||
|
Type[] columns;
|
||||||
|
|
||||||
|
static class InstantiableType {
|
||||||
|
protected Type type;
|
||||||
|
|
||||||
|
public InstantiableType(Type type) {
|
||||||
|
this.type = type;
|
||||||
|
}
|
||||||
|
|
||||||
|
Type inst(Type clazz) {
|
||||||
|
return type;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
enum Result {
|
||||||
|
/* generic type is well-formed w.r.t. declared bounds */
|
||||||
|
OK(true),
|
||||||
|
/* generic type is not well-formed w.r.t. declared bounds */
|
||||||
|
FAIL(false),
|
||||||
|
/* generic type is not well-formed w.r.t. declared bounds according to the JLS 3rd,
|
||||||
|
* but javac allows it (spec for generic type well-formedness is overly restrictive)
|
||||||
|
* See regression test test/tools/generics/wildcards/T5097548.java
|
||||||
|
*/
|
||||||
|
IGNORE(false);
|
||||||
|
|
||||||
|
boolean value;
|
||||||
|
|
||||||
|
Result(boolean value) {
|
||||||
|
this.value = value;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static final Result T = Result.OK;
|
||||||
|
static final Result F = Result.FAIL;
|
||||||
|
static final Result I = Result.IGNORE;
|
||||||
|
|
||||||
|
/*is a type in 'rows' a valid instantiation for the generic class in 'col' ? */
|
||||||
|
Result[][] isValidInstantiation = {
|
||||||
|
//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<?>>
|
||||||
|
/*Foo<Object>*/ { T , T , F , F , F , F , F },
|
||||||
|
/*Foo<Number>*/ { T , T , T , F , F , F , F },
|
||||||
|
/*Foo<Integer>*/ { T , T , T , F , F , F , F },
|
||||||
|
/*Foo<Double>*/ { T , T , T , F , F , F , F },
|
||||||
|
/*Foo<String>*/ { T , T , F , F , F , F , F },
|
||||||
|
/*Foo<X1>*/ { T , T , F , F , F , F , F },
|
||||||
|
/*Foo<X2>*/ { T , T , T , F , F , F , F },
|
||||||
|
/*Foo<X3>*/ { T , T , T , F , F , F , F },
|
||||||
|
/*Foo<X4>*/ { T , T , T , F , F , F , F },
|
||||||
|
/*Foo<X5>*/ { T , T , F , F , F , F , F },
|
||||||
|
/*Foo<X6>*/ { T , T , F , T , T , T , T },
|
||||||
|
/*Foo<+Object>*/ { T , T , I , I , I , I , I },
|
||||||
|
/*Foo<+Number>*/ { T , T , T , F , F , F , F },
|
||||||
|
/*Foo<+Integer>*/{ T , T , T , F , F , F , F },
|
||||||
|
/*Foo<+Double>*/ { T , T , T , F , F , F , F },
|
||||||
|
/*Foo<+String>*/ { T , T , F , F , F , F , F },
|
||||||
|
/*Foo<+X1>*/ { T , T , F , F , F , F , F },
|
||||||
|
/*Foo<+X2>*/ { T , T , T , F , F , F , F },
|
||||||
|
/*Foo<+X3>*/ { T , T , T , F , F , F , F },
|
||||||
|
/*Foo<+X4>*/ { T , T , T , F , F , F , F },
|
||||||
|
/*Foo<+X5>*/ { T , T , F , F , F , F , F },
|
||||||
|
/*Foo<+X6>*/ { T , T , F , T , T , I , T },
|
||||||
|
/*Foo<-Object>*/ { T , T , F , F , F , F , F },
|
||||||
|
/*Foo<-Number>*/ { T , T , T , F , F , F , F },
|
||||||
|
/*Foo<-Integer>*/{ T , T , T , F , F , F , F },
|
||||||
|
/*Foo<-Double>*/ { T , T , T , F , F , F , F },
|
||||||
|
/*Foo<-String>*/ { T , T , F , F , F , F , F },
|
||||||
|
/*Foo<-X1>*/ { T , T , I , I , I , I , I },
|
||||||
|
/*Foo<-X2>*/ { T , T , I , F , F , F , F },
|
||||||
|
/*Foo<-X3>*/ { T , T , I , F , F , F , F },
|
||||||
|
/*Foo<-X4>*/ { T , T , I , F , F , F , F },
|
||||||
|
/*Foo<-X5>*/ { T , T , I , F , F , F , F },
|
||||||
|
/*Foo<-X6>*/ { T , T , F , T , I , I , T },
|
||||||
|
/*Foo<?>*/ { T , T , T , T , T , T , T }};
|
||||||
|
|
||||||
|
GenericTypeWellFormednessTest() {
|
||||||
|
InstantiableType[] basicTypes = {
|
||||||
|
new InstantiableType(predef.objectType),
|
||||||
|
new InstantiableType(NumberType()),
|
||||||
|
new InstantiableType(box(predef.intType)),
|
||||||
|
new InstantiableType(box(predef.doubleType)),
|
||||||
|
new InstantiableType(predef.stringType) };
|
||||||
|
|
||||||
|
InstantiableType[] typeVars = new InstantiableType[basicTypes.length + 1];
|
||||||
|
for (int i = 0 ; i < basicTypes.length ; i++) {
|
||||||
|
typeVars[i] = new InstantiableType(fac.TypeVariable(basicTypes[i].type));
|
||||||
|
}
|
||||||
|
typeVars[typeVars.length - 1] = new InstantiableType(null) {
|
||||||
|
Type inst(Type clazz) {
|
||||||
|
TypeVar tvar = fac.TypeVariable();
|
||||||
|
tvar.bound = subst(clazz, Mapping(clazz.getTypeArguments().head, tvar));
|
||||||
|
return tvar;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
InstantiableType[] typeArgs = join(InstantiableType.class, basicTypes, typeVars);
|
||||||
|
|
||||||
|
InstantiableType[] invariantTypes = new InstantiableType[typeArgs.length];
|
||||||
|
for (int i = 0 ; i < typeArgs.length ; i++) {
|
||||||
|
final InstantiableType type1 = typeArgs[i];
|
||||||
|
invariantTypes[i] = new InstantiableType(typeArgs[i].type) {
|
||||||
|
Type inst(Type clazz) {
|
||||||
|
return subst(clazz, Mapping(clazz.getTypeArguments().head, type1.inst(clazz)));
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
InstantiableType[] covariantTypes = new InstantiableType[typeArgs.length];
|
||||||
|
for (int i = 0 ; i < typeArgs.length ; i++) {
|
||||||
|
final InstantiableType type1 = typeArgs[i];
|
||||||
|
covariantTypes[i] = new InstantiableType(null) {
|
||||||
|
Type inst(Type clazz) {
|
||||||
|
Type t = fac.Wildcard(BoundKind.EXTENDS, type1.inst(clazz));
|
||||||
|
return subst(clazz, Mapping(clazz.getTypeArguments().head, t));
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
InstantiableType[] contravariantTypes = new InstantiableType[typeArgs.length];
|
||||||
|
for (int i = 0 ; i < typeArgs.length ; i++) {
|
||||||
|
final InstantiableType type1 = typeArgs[i];
|
||||||
|
contravariantTypes[i] = new InstantiableType(null) {
|
||||||
|
Type inst(Type clazz) {
|
||||||
|
Type t = fac.Wildcard(BoundKind.SUPER, type1.inst(clazz));
|
||||||
|
return subst(clazz, Mapping(clazz.getTypeArguments().head, t));
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
InstantiableType[] bivariantTypes = {
|
||||||
|
new InstantiableType(fac.Wildcard(BoundKind.UNBOUND, predef.objectType)) {
|
||||||
|
Type inst(Type clazz) {
|
||||||
|
return subst(clazz, Mapping(clazz.getTypeArguments().head, type));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
rows = join(InstantiableType.class, invariantTypes, covariantTypes, contravariantTypes, bivariantTypes);
|
||||||
|
|
||||||
|
Type tv1 = fac.TypeVariable();
|
||||||
|
Type decl1 = fac.Class(tv1);
|
||||||
|
|
||||||
|
Type tv2 = fac.TypeVariable(predef.objectType);
|
||||||
|
Type decl2 = fac.Class(tv2);
|
||||||
|
|
||||||
|
Type tv3 = fac.TypeVariable(NumberType());
|
||||||
|
Type decl3 = fac.Class(tv3);
|
||||||
|
|
||||||
|
TypeVar tv4 = fac.TypeVariable();
|
||||||
|
Type decl4 = fac.Class(tv4);
|
||||||
|
tv4.bound = decl4;
|
||||||
|
tv4.tsym.name = predef.exceptionType.tsym.name;
|
||||||
|
|
||||||
|
TypeVar tv5 = fac.TypeVariable();
|
||||||
|
Type decl5 = fac.Class(tv5);
|
||||||
|
tv5.bound = subst(decl5, Mapping(tv5, fac.Wildcard(BoundKind.EXTENDS, tv5)));
|
||||||
|
|
||||||
|
TypeVar tv6 = fac.TypeVariable();
|
||||||
|
Type decl6 = fac.Class(tv6);
|
||||||
|
tv6.bound = subst(decl6, Mapping(tv6, fac.Wildcard(BoundKind.SUPER, tv6)));
|
||||||
|
|
||||||
|
TypeVar tv7 = fac.TypeVariable();
|
||||||
|
Type decl7 = fac.Class(tv7);
|
||||||
|
tv7.bound = subst(decl7, Mapping(tv7, fac.Wildcard(BoundKind.UNBOUND, predef.objectType)));
|
||||||
|
|
||||||
|
columns = new Type[] {
|
||||||
|
decl1, decl2, decl3, decl4, decl5, decl6, decl7
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
void test() {
|
||||||
|
for (int i = 0; i < rows.length ; i++) {
|
||||||
|
for (int j = 0; j < columns.length ; j++) {
|
||||||
|
Type decl = columns[j];
|
||||||
|
Type inst = rows[i].inst(decl);
|
||||||
|
if (isValidInstantiation[i][j] != Result.IGNORE) {
|
||||||
|
executedCount++;
|
||||||
|
assertValidGenericType(inst, isValidInstantiation[i][j].value);
|
||||||
|
} else {
|
||||||
|
ignoredCount++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Type NumberType() {
|
||||||
|
Symbol s = box(predef.intType).tsym;
|
||||||
|
s.complete();
|
||||||
|
return ((ClassType)s.type).supertype_field;
|
||||||
|
}
|
||||||
|
|
||||||
|
@SuppressWarnings("unchecked")
|
||||||
|
<T> T[] join(Class<T> type, T[]... args) {
|
||||||
|
int totalLength = 0;
|
||||||
|
for (T[] arr : args) {
|
||||||
|
totalLength += arr.length;
|
||||||
|
}
|
||||||
|
T[] new_arr = (T[])Array.newInstance(type, totalLength);
|
||||||
|
int idx = 0;
|
||||||
|
for (T[] arr : args) {
|
||||||
|
System.arraycopy(arr, 0, new_arr, idx, arr.length);
|
||||||
|
idx += arr.length;
|
||||||
|
}
|
||||||
|
return new_arr;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void main(String[] args) {
|
||||||
|
new GenericTypeWellFormednessTest().test();
|
||||||
|
System.out.println("Executed checks : " + executedCount);
|
||||||
|
System.out.println("Ignored checks : " + ignoredCount);
|
||||||
|
}
|
||||||
|
}
|
|
@ -29,6 +29,7 @@ import com.sun.tools.javac.code.Symtab;
|
||||||
import com.sun.tools.javac.code.Type;
|
import com.sun.tools.javac.code.Type;
|
||||||
import com.sun.tools.javac.code.Type.*;
|
import com.sun.tools.javac.code.Type.*;
|
||||||
import com.sun.tools.javac.code.Symbol.*;
|
import com.sun.tools.javac.code.Symbol.*;
|
||||||
|
import com.sun.tools.javac.comp.Check;
|
||||||
import com.sun.tools.javac.util.List;
|
import com.sun.tools.javac.util.List;
|
||||||
import com.sun.tools.javac.util.ListBuffer;
|
import com.sun.tools.javac.util.ListBuffer;
|
||||||
import com.sun.tools.javac.util.Name;
|
import com.sun.tools.javac.util.Name;
|
||||||
|
@ -68,6 +69,7 @@ import com.sun.tools.javac.file.JavacFileManager;
|
||||||
public class TypeHarness {
|
public class TypeHarness {
|
||||||
|
|
||||||
protected Types types;
|
protected Types types;
|
||||||
|
protected Check chk;
|
||||||
protected Symtab predef;
|
protected Symtab predef;
|
||||||
protected Names names;
|
protected Names names;
|
||||||
protected Factory fac;
|
protected Factory fac;
|
||||||
|
@ -76,6 +78,7 @@ public class TypeHarness {
|
||||||
Context ctx = new Context();
|
Context ctx = new Context();
|
||||||
JavacFileManager.preRegister(ctx);
|
JavacFileManager.preRegister(ctx);
|
||||||
types = Types.instance(ctx);
|
types = Types.instance(ctx);
|
||||||
|
chk = Check.instance(ctx);
|
||||||
predef = Symtab.instance(ctx);
|
predef = Symtab.instance(ctx);
|
||||||
names = Names.instance(ctx);
|
names = Names.instance(ctx);
|
||||||
fac = new Factory();
|
fac = new Factory();
|
||||||
|
@ -157,6 +160,21 @@ public class TypeHarness {
|
||||||
error(s + msg + t);
|
error(s + msg + t);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/** assert that generic type 't' is well-formed */
|
||||||
|
public void assertValidGenericType(Type t) {
|
||||||
|
assertValidGenericType(t, true);
|
||||||
|
}
|
||||||
|
|
||||||
|
/** assert that 's' is/is not assignable to 't' */
|
||||||
|
public void assertValidGenericType(Type t, boolean expected) {
|
||||||
|
if (chk.checkValidGenericType(t) != expected) {
|
||||||
|
String msg = expected ?
|
||||||
|
" is not a valid generic type" :
|
||||||
|
" is a valid generic type";
|
||||||
|
error(t + msg + " " + t.tsym.type);
|
||||||
|
}
|
||||||
|
}
|
||||||
// </editor-fold>
|
// </editor-fold>
|
||||||
|
|
||||||
private void error(String msg) {
|
private void error(String msg) {
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue