7015430: Incorrect thrown type determined for unchecked invocations
authormcimadamore
Mon, 28 Feb 2011 11:48:53 +0000
changeset 8616 5a47f5535883
parent 8615 11d80b55b0ed
child 8617 6a05d1669247
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
langtools/src/share/classes/com/sun/tools/javac/comp/Attr.java
langtools/src/share/classes/com/sun/tools/javac/comp/Infer.java
langtools/test/tools/javac/generics/7015430/T7015430.java
langtools/test/tools/javac/generics/7015430/T7015430.out
--- 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