7015430: Incorrect thrown type determined for unchecked invocations
Summary: Thrown types do not get updated after 15.12.2.8, and do not get erased as per 15.12.2.6
Reviewed-by: jjg, dlsmith
--- a/langtools/src/share/classes/com/sun/tools/javac/comp/Attr.java Fri Feb 25 12:19:00 2011 -0800
+++ b/langtools/src/share/classes/com/sun/tools/javac/comp/Attr.java Mon Feb 28 11:48:53 2011 +0000
@@ -2806,7 +2806,7 @@
sym.location());
owntype = new MethodType(owntype.getParameterTypes(),
types.erasure(owntype.getReturnType()),
- owntype.getThrownTypes(),
+ types.erasure(owntype.getThrownTypes()),
syms.methodClass);
}
if (useVarargs) {
--- a/langtools/src/share/classes/com/sun/tools/javac/comp/Infer.java Fri Feb 25 12:19:00 2011 -0800
+++ b/langtools/src/share/classes/com/sun/tools/javac/comp/Infer.java Mon Feb 28 11:48:53 2011 +0000
@@ -465,10 +465,9 @@
// quantify result type with them
final List<Type> inferredTypes = insttypes.toList();
final List<Type> all_tvars = tvars; //this is the wrong tvars
- final MethodType mt2 = new MethodType(mt.argtypes, null, mt.thrown, syms.methodClass);
- mt2.restype = new ForAll(restvars.toList(), mt.restype) {
+ return new UninferredMethodType(mt, restvars.toList()) {
@Override
- public List<Type> getConstraints(TypeVar tv, ConstraintKind ck) {
+ List<Type> getConstraints(TypeVar tv, ConstraintKind ck) {
for (Type t : restundet.toList()) {
UndetVar uv = (UndetVar)t;
if (uv.qtype == tv) {
@@ -481,21 +480,17 @@
}
return List.nil();
}
-
@Override
- public Type inst(List<Type> inferred, Types types) throws NoInstanceException {
- List<Type> formals = types.subst(mt2.argtypes, tvars, inferred);
+ void check(List<Type> inferred, Types types) throws NoInstanceException {
// check that actuals conform to inferred formals
- checkArgumentsAcceptable(env, capturedArgs, formals, allowBoxing, useVarargs, warn);
+ checkArgumentsAcceptable(env, capturedArgs, getParameterTypes(), allowBoxing, useVarargs, warn);
// check that inferred bounds conform to their bounds
checkWithinBounds(all_tvars,
types.subst(inferredTypes, tvars, inferred), warn);
if (useVarargs) {
- chk.checkVararg(env.tree.pos(), formals, msym);
+ chk.checkVararg(env.tree.pos(), getParameterTypes(), msym);
}
- return super.inst(inferred, types);
}};
- return mt2;
}
else {
// check that actuals conform to inferred formals
@@ -506,6 +501,62 @@
}
//where
+ /**
+ * A delegated type representing a partially uninferred method type.
+ * The return type of a partially uninferred method type is a ForAll
+ * type - when the return type is instantiated (see Infer.instantiateExpr)
+ * the underlying method type is also updated.
+ */
+ static abstract class UninferredMethodType extends DelegatedType {
+
+ final List<Type> tvars;
+
+ public UninferredMethodType(MethodType mtype, List<Type> tvars) {
+ super(METHOD, new MethodType(mtype.argtypes, null, mtype.thrown, mtype.tsym));
+ this.tvars = tvars;
+ asMethodType().restype = new UninferredReturnType(tvars, mtype.restype);
+ }
+
+ @Override
+ public MethodType asMethodType() {
+ return qtype.asMethodType();
+ }
+
+ @Override
+ public Type map(Mapping f) {
+ return qtype.map(f);
+ }
+
+ void instantiateReturnType(Type restype, List<Type> inferred, Types types) throws NoInstanceException {
+ //update method type with newly inferred type-arguments
+ qtype = new MethodType(types.subst(getParameterTypes(), tvars, inferred),
+ restype,
+ types.subst(UninferredMethodType.this.getThrownTypes(), tvars, inferred),
+ UninferredMethodType.this.qtype.tsym);
+ check(inferred, types);
+ }
+
+ abstract void check(List<Type> inferred, Types types) throws NoInstanceException;
+
+ abstract List<Type> getConstraints(TypeVar tv, ConstraintKind ck);
+
+ class UninferredReturnType extends ForAll {
+ public UninferredReturnType(List<Type> tvars, Type restype) {
+ super(tvars, restype);
+ }
+ @Override
+ public Type inst(List<Type> actuals, Types types) {
+ Type newRestype = super.inst(actuals, types);
+ instantiateReturnType(newRestype, actuals, types);
+ return newRestype;
+ }
+ @Override
+ public List<Type> getConstraints(TypeVar tv, ConstraintKind ck) {
+ return UninferredMethodType.this.getConstraints(tv, ck);
+ }
+ }
+ }
+
private void checkArgumentsAcceptable(Env<AttrContext> env, List<Type> actuals, List<Type> formals,
boolean allowBoxing, boolean useVarargs, Warner warn) {
try {
@@ -518,25 +569,25 @@
}
}
- /** Try to instantiate argument type `that' to given type `to'.
- * If this fails, try to insantiate `that' to `to' where
- * every occurrence of a type variable in `tvars' is replaced
- * by an unknown type.
- */
- private Type instantiateArg(ForAll that,
- Type to,
- List<Type> tvars,
- Warner warn) throws InferenceException {
- List<Type> targs;
- try {
- return instantiateExpr(that, to, warn);
- } catch (NoInstanceException ex) {
- Type to1 = to;
- for (List<Type> l = tvars; l.nonEmpty(); l = l.tail)
- to1 = types.subst(to1, List.of(l.head), List.of(syms.unknownType));
- return instantiateExpr(that, to1, warn);
- }
+ /** Try to instantiate argument type `that' to given type `to'.
+ * If this fails, try to insantiate `that' to `to' where
+ * every occurrence of a type variable in `tvars' is replaced
+ * by an unknown type.
+ */
+ private Type instantiateArg(ForAll that,
+ Type to,
+ List<Type> tvars,
+ Warner warn) throws InferenceException {
+ List<Type> targs;
+ try {
+ return instantiateExpr(that, to, warn);
+ } catch (NoInstanceException ex) {
+ Type to1 = to;
+ for (List<Type> l = tvars; l.nonEmpty(); l = l.tail)
+ to1 = types.subst(to1, List.of(l.head), List.of(syms.unknownType));
+ return instantiateExpr(that, to1, warn);
}
+ }
/** check that type parameters are within their bounds.
*/
@@ -616,4 +667,4 @@
return t;
}
};
-}
+ }
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/langtools/test/tools/javac/generics/7015430/T7015430.java Mon Feb 28 11:48:53 2011 +0000
@@ -0,0 +1,131 @@
+/*
+ * @test /nodynamiccopyright/
+ * @bug 7015430
+ *
+ * @summary Incorrect thrown type determined for unchecked invocations
+ * @author Daniel Smith
+ * @compile/fail/ref=T7015430.out -Xlint:unchecked -XDrawDiagnostics T7015430.java
+ *
+ */
+
+class T7015430 {
+ static <E extends Exception> Iterable<E> empty(Iterable<E> arg) throws E {
+ return null;
+ }
+
+ <E extends Exception> T7015430(Iterable<E> arg) throws E { }
+
+ static <E extends Exception> Iterable<E> empty2(Iterable x) throws E {
+ return null;
+ }
+
+ static class Foo<X extends Exception> {
+ Foo() throws X {}
+ }
+
+ /**
+ * Method invocation, no unchecked
+ * inferred: RuntimeException - should pass
+ */
+ void m1() {
+ Iterable<RuntimeException> i = java.util.Collections.emptyList();
+ empty(i);
+ }
+
+ /**
+ * Method invocation, unchecked, inferred arguments
+ * inferred: Exception - should fail
+ */
+ void m2() {
+ Iterable i = java.util.Collections.EMPTY_LIST;
+ empty(i);
+ }
+
+ /**
+ * Method invocation, unchecked, explicit arguments
+ * inferred: RuntimeException - should pass
+ */
+ void m3() {
+ Iterable i = java.util.Collections.EMPTY_LIST;
+ T7015430.<RuntimeException>empty(i);
+ }
+
+ /**
+ * Constructor invocation, no unchecked
+ * inferred: RuntimeException - should pass
+ */
+ void m4() {
+ Iterable<RuntimeException> i = java.util.Collections.emptyList();
+ new T7015430(i);
+ }
+
+ /**
+ * Constructor invocation, unchecked, inferred arguments
+ * inferred: Exception - should fail
+ */
+ void m5() {
+ Iterable i = java.util.Collections.EMPTY_LIST;
+ new T7015430(i);
+ }
+
+ /**
+ * Constructor invocation, unchecked, explicit arguments
+ * inferred: RuntimeException - should pass
+ */
+ void m6() {
+ Iterable i = java.util.Collections.EMPTY_LIST;
+ new <RuntimeException>T7015430(i);
+ }
+
+ /**
+ * Method invocation, no unchecked, inferred arguments
+ * inferred: RuntimeException - should pass
+ */
+ void m7() {
+ Iterable i = java.util.Collections.EMPTY_LIST;
+ Iterable<RuntimeException> e = empty2(i);
+ }
+
+ /**
+ * Method invocation, no unchecked, inferred arguments
+ * inferred: Exception - should fail
+ */
+ void m8() {
+ Iterable i = java.util.Collections.EMPTY_LIST;
+ empty2(i);
+ }
+
+ /**
+ * Constructor invocation, unchecked, explicit arguments
+ * inferred: RuntimeException - should pass
+ */
+ void m9() {
+ Iterable i = java.util.Collections.EMPTY_LIST;
+ new <RuntimeException> T7015430(i);
+ }
+
+ /**
+ * Constructor invocation, unchecked, inferred arguments
+ * inferred: Exception - should fail
+ */
+ void m10() {
+ Iterable i = java.util.Collections.EMPTY_LIST;
+ new T7015430(i);
+ }
+
+ /**
+ * Constructor invocation, no unchecked, inferred arguments (diamond)
+ * inferred: RuntimeException - should pass
+ */
+ void m11() {
+ Foo<RuntimeException> o = new Foo<>();
+ }
+
+ /**
+ * Constructor invocation, no unchecked, inferred arguments (diamond)
+ * inferred: Exception - should fail
+ */
+ void m12() {
+ new Foo<>();
+ }
+}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/langtools/test/tools/javac/generics/7015430/T7015430.out Mon Feb 28 11:48:53 2011 +0000
@@ -0,0 +1,19 @@
+T7015430.java:41:15: compiler.warn.prob.found.req: (compiler.misc.unchecked.assign), java.lang.Iterable, java.lang.Iterable<E>
+T7015430.java:41:14: compiler.warn.unchecked.meth.invocation.applied: kindname.method, empty, java.lang.Iterable<E>, java.lang.Iterable, kindname.class, T7015430
+T7015430.java:50:42: compiler.warn.prob.found.req: (compiler.misc.unchecked.assign), java.lang.Iterable, java.lang.Iterable<java.lang.RuntimeException>
+T7015430.java:50:41: compiler.warn.unchecked.meth.invocation.applied: kindname.method, empty, java.lang.Iterable<E>, java.lang.Iterable, kindname.class, T7015430
+T7015430.java:68:22: compiler.warn.prob.found.req: (compiler.misc.unchecked.assign), java.lang.Iterable, java.lang.Iterable<E>
+T7015430.java:68:9: compiler.warn.unchecked.meth.invocation.applied: kindname.constructor, <init>, java.lang.Iterable<E>, java.lang.Iterable, kindname.class, T7015430
+T7015430.java:77:40: compiler.warn.prob.found.req: (compiler.misc.unchecked.assign), java.lang.Iterable, java.lang.Iterable<java.lang.RuntimeException>
+T7015430.java:77:9: compiler.warn.unchecked.meth.invocation.applied: kindname.constructor, <init>, java.lang.Iterable<E>, java.lang.Iterable, kindname.class, T7015430
+T7015430.java:104:41: compiler.warn.prob.found.req: (compiler.misc.unchecked.assign), java.lang.Iterable, java.lang.Iterable<java.lang.RuntimeException>
+T7015430.java:104:9: compiler.warn.unchecked.meth.invocation.applied: kindname.constructor, <init>, java.lang.Iterable<E>, java.lang.Iterable, kindname.class, T7015430
+T7015430.java:113:22: compiler.warn.prob.found.req: (compiler.misc.unchecked.assign), java.lang.Iterable, java.lang.Iterable<E>
+T7015430.java:113:9: compiler.warn.unchecked.meth.invocation.applied: kindname.constructor, <init>, java.lang.Iterable<E>, java.lang.Iterable, kindname.class, T7015430
+T7015430.java:41:14: compiler.err.unreported.exception.need.to.catch.or.throw: java.lang.Exception
+T7015430.java:68:9: compiler.err.unreported.exception.need.to.catch.or.throw: java.lang.Exception
+T7015430.java:95:15: compiler.err.unreported.exception.need.to.catch.or.throw: java.lang.Exception
+T7015430.java:113:9: compiler.err.unreported.exception.need.to.catch.or.throw: java.lang.Exception
+T7015430.java:129:9: compiler.err.unreported.exception.need.to.catch.or.throw: java.lang.Exception
+5 errors
+12 warnings