changeset 164:c711bcdb18ea

OPENJDK6-34: OpenJDK6-b31 backport of JDK-6638712 to openjdk6 Summary: Original bug synopsis-Inference of formal type parameter (unused in formal parameters) is not performed Reviewed-by: aph Contributed-by: nikgor <nikolay@azulsystems.com>
author ikrylov
date Fri, 20 Jun 2014 16:52:01 +0400
parents be4293ad2bbc
children e62c8af01197
files src/share/classes/com/sun/tools/javac/code/Type.java src/share/classes/com/sun/tools/javac/code/Types.java src/share/classes/com/sun/tools/javac/comp/Check.java src/share/classes/com/sun/tools/javac/comp/Infer.java src/share/classes/com/sun/tools/javac/comp/Resolve.java src/share/classes/com/sun/tools/javac/resources/compiler.properties test/tools/javac/generics/inference/6302954/T6476073.java test/tools/javac/generics/inference/6638712/T6638712a.java test/tools/javac/generics/inference/6638712/T6638712a.out test/tools/javac/generics/inference/6638712/T6638712b.java test/tools/javac/generics/inference/6638712/T6638712b.out test/tools/javac/generics/inference/6638712/T6638712c.java test/tools/javac/generics/inference/6638712/T6638712c.out test/tools/javac/generics/inference/6638712/T6638712d.java test/tools/javac/generics/inference/6638712/T6638712d.out test/tools/javac/generics/inference/6638712/T6638712e.java test/tools/javac/generics/inference/6638712/T6638712e.out
diffstat 17 files changed, 248 insertions(+), 65 deletions(-) [+]
line wrap: on
line diff
--- a/src/share/classes/com/sun/tools/javac/code/Type.java	Thu Apr 10 11:54:01 2014 -0400
+++ b/src/share/classes/com/sun/tools/javac/code/Type.java	Fri Jun 20 16:52:01 2014 +0400
@@ -1061,6 +1061,21 @@
             return qtype.isErroneous();
         }
 
+        /**
+         * Replaces this ForAll's typevars with a set of concrete Java types
+         * and returns the instantiated generic type. Subclasses might override
+         * in order to check that the list of types is a valid instantiation
+         * of the ForAll's typevars.
+         *
+         * @param actuals list of actual types
+         * @param types types instance
+         * @return qtype where all occurrences of tvars are replaced
+         * by types in actuals
+         */
+        public Type inst(List<Type> actuals, Types types) {
+            return types.subst(qtype, tvars, actuals);
+        }
+
         public Type map(Mapping f) {
             return f.apply(qtype);
         }
--- a/src/share/classes/com/sun/tools/javac/code/Types.java	Thu Apr 10 11:54:01 2014 -0400
+++ b/src/share/classes/com/sun/tools/javac/code/Types.java	Fri Jun 20 16:52:01 2014 +0400
@@ -335,6 +335,14 @@
         if (s.tag >= firstPartialTag)
             return isSuperType(s, t);
 
+        if (s.isCompound()) {
+            for (Type s2 : interfaces(s).prepend(supertype(s))) {
+                if (!isSubtype(t, s2, capture))
+                    return false;
+            }
+            return true;
+        }
+
         Type lower = lowerBound(s);
         if (s != lower)
             return isSubtype(capture ? capture(t) : t, lower, false);
@@ -2770,6 +2778,14 @@
     /**
      * Capture conversion as specified by JLS 3rd Ed.
      */
+
+    public List<Type> capture(List<Type> ts) {
+        List<Type> buf = List.nil();
+        for (Type t : ts) {
+            buf = buf.prepend(capture(t));
+        }
+        return buf.reverse();
+    }
     public Type capture(Type t) {
         if (t.tag != CLASS)
             return t;
--- a/src/share/classes/com/sun/tools/javac/comp/Check.java	Thu Apr 10 11:54:01 2014 -0400
+++ b/src/share/classes/com/sun/tools/javac/comp/Check.java	Fri Jun 20 16:52:01 2014 +0400
@@ -383,6 +383,10 @@
                                      JCDiagnostic.fragment("incompatible.types" + (d!=null ? ".1" : ""), d),
                                      t, pt);
                 }
+            } catch (Infer.InvalidInstanceException ex) {
+                JCDiagnostic d = ex.getDiagnostic();
+                log.error(pos, "invalid.inferred.types", t.tvars, d);
+                return syms.errType;
             }
         }
     }
--- a/src/share/classes/com/sun/tools/javac/comp/Infer.java	Thu Apr 10 11:54:01 2014 -0400
+++ b/src/share/classes/com/sun/tools/javac/comp/Infer.java	Fri Jun 20 16:52:01 2014 +0400
@@ -25,10 +25,10 @@
 
 package com.sun.tools.javac.comp;
 
+import com.sun.tools.javac.code.*;
+import com.sun.tools.javac.code.Symbol.*;
+import com.sun.tools.javac.code.Type.*;
 import com.sun.tools.javac.util.*;
-import com.sun.tools.javac.util.List;
-import com.sun.tools.javac.code.*;
-import com.sun.tools.javac.code.Type.*;
 
 import static com.sun.tools.javac.code.Flags.*;
 import static com.sun.tools.javac.code.Kinds.*;
@@ -50,6 +50,7 @@
 
     Symtab syms;
     Types types;
+    Resolve rs;
 
     public static Infer instance(Context context) {
         Infer instance = context.get(inferKey);
@@ -62,43 +63,48 @@
         context.put(inferKey, this);
         syms = Symtab.instance(context);
         types = Types.instance(context);
+        rs = Resolve.instance(context);
     }
 
-    public static class NoInstanceException extends RuntimeException {
+    public static class InferenceException extends RuntimeException {
         private static final long serialVersionUID = 0;
 
-        boolean isAmbiguous; // exist several incomparable best instances?
-
         JCDiagnostic diagnostic;
 
-        NoInstanceException(boolean isAmbiguous) {
+        InferenceException() {
             this.diagnostic = null;
-            this.isAmbiguous = isAmbiguous;
         }
-        NoInstanceException setMessage(String key) {
-            this.diagnostic = JCDiagnostic.fragment(key);
+
+        InferenceException setMessage(String key, Object... args) {
+            this.diagnostic = JCDiagnostic.fragment(key, args);
             return this;
         }
-        NoInstanceException setMessage(String key, Object arg1) {
-            this.diagnostic = JCDiagnostic.fragment(key, arg1);
-            return this;
-        }
-        NoInstanceException setMessage(String key, Object arg1, Object arg2) {
-            this.diagnostic = JCDiagnostic.fragment(key, arg1, arg2);
-            return this;
-        }
-        NoInstanceException setMessage(String key, Object arg1, Object arg2, Object arg3) {
-            this.diagnostic = JCDiagnostic.fragment(key, arg1, arg2, arg3);
-            return this;
-        }
+
         public JCDiagnostic getDiagnostic() {
             return diagnostic;
         }
     }
+
+    public static class NoInstanceException extends InferenceException {
+        private static final long serialVersionUID = 1;
+
+        boolean isAmbiguous; // do several incomparable best instances exist?
+
+        NoInstanceException(boolean isAmbiguous) {
+            this.isAmbiguous = isAmbiguous;
+        }
+    }
+
+    public static class InvalidInstanceException extends InferenceException {
+        private static final long serialVersionUID = 2;
+    }
+
     private final NoInstanceException ambiguousNoInstanceException =
         new NoInstanceException(true);
     private final NoInstanceException unambiguousNoInstanceException =
         new NoInstanceException(false);
+    private final InvalidInstanceException invalidInstanceException =
+        new InvalidInstanceException();
 
 /***************************************************************************
  * Auxiliary type values and classes
@@ -247,7 +253,7 @@
      */
     public Type instantiateExpr(ForAll that,
                                 Type to,
-                                Warner warn) throws NoInstanceException {
+                                Warner warn) throws InferenceException {
         List<Type> undetvars = Type.map(that.tvars, fromTypeVarFun);
         for (List<Type> l = undetvars; l.nonEmpty(); l = l.tail) {
             UndetVar v = (UndetVar) l.head;
@@ -273,8 +279,7 @@
         List<Type> targs = Type.map(undetvars, getInstFun);
         targs = types.subst(targs, that.tvars, targs);
         checkWithinBounds(that.tvars, targs, warn);
-
-        return getInstFun.apply(qtype1);
+        return that.inst(targs, types);
     }
 
     /** Instantiate method type `mt' by finding instantiations of
@@ -282,36 +287,42 @@
      */
     public Type instantiateMethod(List<Type> tvars,
                                   MethodType mt,
-                                  List<Type> argtypes,
-                                  boolean allowBoxing,
-                                  boolean useVarargs,
-                                  Warner warn) throws NoInstanceException {
+                                  final List<Type> argtypes,
+                                  final boolean allowBoxing,
+                                  final boolean useVarargs,
+                                  final Warner warn) throws InferenceException {
         //-System.err.println("instantiateMethod(" + tvars + ", " + mt + ", " + argtypes + ")"); //DEBUG
         List<Type> undetvars = Type.map(tvars, fromTypeVarFun);
         List<Type> formals = mt.argtypes;
-
+        //need to capture exactly once - otherwise subsequent
+        //applicability checks might fail
+        final List<Type> capturedArgs = types.capture(argtypes);
+        List<Type> actuals = capturedArgs;
+        List<Type> actualsNoCapture = argtypes;
         // instantiate all polymorphic argument types and
         // set up lower bounds constraints for undetvars
         Type varargsFormal = useVarargs ? formals.last() : null;
-        while (argtypes.nonEmpty() && formals.head != varargsFormal) {
-            Type ft = formals.head;
-            Type at = argtypes.head.baseType();
-            if (at.tag == FORALL)
-                at = instantiateArg((ForAll) at, ft, tvars, warn);
-            Type sft = types.subst(ft, tvars, undetvars);
+        while (actuals.nonEmpty() && formals.head != varargsFormal) {
+            Type formal = formals.head;
+            Type actual = actuals.head.baseType();
+            Type actualNoCapture = actualsNoCapture.head.baseType();
+            if (actual.tag == FORALL)
+                actual = instantiateArg((ForAll)actual, formal, tvars, warn);
+            Type undetFormal = types.subst(formal, tvars, undetvars);
             boolean works = allowBoxing
-                ? types.isConvertible(at, sft, warn)
-                : types.isSubtypeUnchecked(at, sft, warn);
+                ? types.isConvertible(actual, undetFormal, warn)
+                : types.isSubtypeUnchecked(actual, undetFormal, warn);
             if (!works) {
                 throw unambiguousNoInstanceException
                     .setMessage("no.conforming.assignment.exists",
-                                tvars, at, ft);
+                                tvars, actualNoCapture, formal);
             }
             formals = formals.tail;
-            argtypes = argtypes.tail;
+            actuals = actuals.tail;
+            actualsNoCapture = actualsNoCapture.tail;
         }
         if (formals.head != varargsFormal || // not enough args
-            !useVarargs && argtypes.nonEmpty()) { // too many args
+            !useVarargs && actuals.nonEmpty()) { // too many args
             // argument lists differ in length
             throw unambiguousNoInstanceException
                 .setMessage("arg.length.mismatch");
@@ -319,20 +330,21 @@
 
         // for varargs arguments as well
         if (useVarargs) {
-            Type elt = types.elemtype(varargsFormal);
-            Type sft = types.subst(elt, tvars, undetvars);
-            while (argtypes.nonEmpty()) {
-                Type ft = sft;
-                Type at = argtypes.head.baseType();
-                if (at.tag == FORALL)
-                    at = instantiateArg((ForAll) at, ft, tvars, warn);
-                boolean works = types.isConvertible(at, sft, warn);
+            Type elemType = types.elemtype(varargsFormal);
+            Type elemUndet = types.subst(elemType, tvars, undetvars);
+            while (actuals.nonEmpty()) {
+                Type actual = actuals.head.baseType();
+                Type actualNoCapture = actualsNoCapture.head.baseType();
+                if (actual.tag == FORALL)
+                    actual = instantiateArg((ForAll)actual, elemType, tvars, warn);
+                boolean works = types.isConvertible(actual, elemUndet, warn);
                 if (!works) {
                     throw unambiguousNoInstanceException
                         .setMessage("no.conforming.assignment.exists",
-                                    tvars, at, ft);
+                                    tvars, actualNoCapture, elemType);
                 }
-                argtypes = argtypes.tail;
+                actuals = actuals.tail;
+                actualsNoCapture = actualsNoCapture.tail;
             }
         }
 
@@ -363,16 +375,38 @@
         }
         checkWithinBounds(tvars, undettypes.toList(), warn);
 
+        mt = (MethodType)types.subst(mt, tvars, insttypes.toList());
+
         if (!restvars.isEmpty()) {
             // if there are uninstantiated variables,
             // quantify result type with them
-            mt = new MethodType(mt.argtypes,
-                                new ForAll(restvars.toList(), mt.restype),
-                                mt.thrown, syms.methodClass);
+            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) {
+                @Override
+                public Type inst(List<Type> inferred, Types types) throws NoInstanceException {
+                    List<Type> formals = types.subst(mt2.argtypes, tvars, inferred);
+                   if (!rs.argumentsAcceptable(capturedArgs, formals,
+                           allowBoxing, useVarargs, warn)) {
+                      // inferred method is not applicable
+                      throw invalidInstanceException.setMessage("inferred.do.not.conform.to.params", formals, argtypes);
+                   }
+                   // check that inferred bounds conform to their bounds
+                   checkWithinBounds(all_tvars,
+                           types.subst(inferredTypes, tvars, inferred), warn);
+                   return super.inst(inferred, types);
+            }};
+            return mt2;
         }
-
-        // return instantiated version of method type
-        return types.subst(mt, tvars, insttypes.toList());
+        else if (!rs.argumentsAcceptable(capturedArgs, mt.getParameterTypes(), allowBoxing, useVarargs, warn)) {
+            // inferred method is not applicable
+            throw invalidInstanceException.setMessage("inferred.do.not.conform.to.params", mt.getParameterTypes(), argtypes);
+        }
+        else {
+            // return instantiated version of method type
+            return mt;
+        }
     }
     //where
 
@@ -384,7 +418,7 @@
         private Type instantiateArg(ForAll that,
                                     Type to,
                                     List<Type> tvars,
-                                    Warner warn) throws NoInstanceException {
+                                    Warner warn) throws InferenceException {
             List<Type> targs;
             try {
                 return instantiateExpr(that, to, warn);
@@ -401,16 +435,16 @@
     private void checkWithinBounds(List<Type> tvars,
                                    List<Type> arguments,
                                    Warner warn)
-        throws NoInstanceException {
+        throws InvalidInstanceException {
         for (List<Type> tvs = tvars, args = arguments;
              tvs.nonEmpty();
              tvs = tvs.tail, args = args.tail) {
             if (args.head instanceof UndetVar) continue;
             List<Type> bounds = types.subst(types.getBounds((TypeVar)tvs.head), tvars, arguments);
             if (!types.isSubtypeUnchecked(args.head, bounds, warn))
-                throw unambiguousNoInstanceException
+                throw invalidInstanceException
                     .setMessage("inferred.do.not.conform.to.bounds",
-                                arguments, tvars);
+                                args.head, bounds);
         }
     }
 }
--- a/src/share/classes/com/sun/tools/javac/comp/Resolve.java	Thu Apr 10 11:54:01 2014 -0400
+++ b/src/share/classes/com/sun/tools/javac/comp/Resolve.java	Fri Jun 20 16:52:01 2014 +0400
@@ -279,7 +279,7 @@
                         boolean allowBoxing,
                         boolean useVarargs,
                         Warner warn)
-        throws Infer.NoInstanceException {
+        throws Infer.InferenceException {
         if (useVarargs && (m.flags() & VARARGS) == 0) return null;
         Type mt = types.memberType(site, m);
 
@@ -350,7 +350,7 @@
         try {
             return rawInstantiate(env, site, m, argtypes, typeargtypes,
                                   allowBoxing, useVarargs, warn);
-        } catch (Infer.NoInstanceException ex) {
+        } catch (Infer.InferenceException ex) {
             return null;
         }
     }
@@ -562,7 +562,7 @@
                 default: return bestSoFar;
                 }
             }
-        } catch (Infer.NoInstanceException ex) {
+        } catch (Infer.InferenceException ex) {
             switch (bestSoFar.kind) {
             case ABSENT_MTH:
                 return wrongMethod.setWrongSym(sym, ex.getDiagnostic());
--- a/src/share/classes/com/sun/tools/javac/resources/compiler.properties	Thu Apr 10 11:54:01 2014 -0400
+++ b/src/share/classes/com/sun/tools/javac/resources/compiler.properties	Fri Jun 20 16:52:01 2014 +0400
@@ -454,6 +454,8 @@
     type parameters of {0} cannot be determined
 compiler.err.undetermined.type.1=\
     type parameters of {0} cannot be determined; {1}
+compiler.err.invalid.inferred.types=\
+    invalid inferred types for {0}; {1}
 compiler.err.unreachable.stmt=\
     unreachable statement
 compiler.err.initializer.must.be.able.to.complete.normally=\
@@ -960,7 +962,13 @@
 compiler.misc.arg.length.mismatch=\
     cannot instantiate from arguments because actual and formal argument lists differ in length
 compiler.misc.inferred.do.not.conform.to.bounds=\
-    inferred type argument(s) {0} do not conform to bounds of type variable(s) {1}
+    inferred type does not conform to declared bound(s)\n\
+    inferred: {0}\n\
+    bound(s): {1}
+compiler.misc.inferred.do.not.conform.to.params=\
+    actual arguments do not conforms to inferred formal arguments\n\
+    required: {0}\n\
+    found: {1}
 
 #####
 
--- a/test/tools/javac/generics/inference/6302954/T6476073.java	Thu Apr 10 11:54:01 2014 -0400
+++ b/test/tools/javac/generics/inference/6302954/T6476073.java	Fri Jun 20 16:52:01 2014 +0400
@@ -25,6 +25,7 @@
  * @test
  * @bug     6476073
  * @summary Capture using super wildcard of type variables doesn't work
+ * @ignore awaiting for 6650759 (see bug report for a detailed evaluation)
  * @compile T6476073.java
  */
 
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/tools/javac/generics/inference/6638712/T6638712a.java	Fri Jun 20 16:52:01 2014 +0400
@@ -0,0 +1,19 @@
+/*
+ * @test /nodynamiccopyright/
+ * @bug     6638712
+ * @author  mcimadamore
+ * @summary Inference with wildcard types causes selection of inapplicable method
+ * @compile/fail/ref=T6638712a.out -XDrawDiagnostics T6638712a.java
+ */
+
+import java.util.*;
+
+class T6638712a {
+    <T> Comparator<T> compound(Iterable<? extends Comparator<? super T>> it) {
+        return null;
+    }
+
+    public void test(List<Comparator<?>> x) {
+        Comparator<String> c3 = compound(x);
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/tools/javac/generics/inference/6638712/T6638712a.out	Fri Jun 20 16:52:01 2014 +0400
@@ -0,0 +1,2 @@
+T6638712a.java:17:41: compiler.err.invalid.inferred.types: T, (- compiler.misc.inferred.do.not.conform.to.params: java.lang.Iterable<? extends java.util.Comparator<? super java.lang.String>>, java.util.List<java.util.Comparator<?>>)
+1 error
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/tools/javac/generics/inference/6638712/T6638712b.java	Fri Jun 20 16:52:01 2014 +0400
@@ -0,0 +1,17 @@
+/*
+ * @test /nodynamiccopyright/
+ * @bug     6638712
+ * @author  mcimadamore
+ * @summary Inference with wildcard types causes selection of inapplicable method
+ * @compile/fail/ref=T6638712b.out -XDrawDiagnostics T6638712b.java
+ */
+
+class T6638712b<X> {
+    <I extends T6638712b<T>, T> T m(I test) {
+        return null;
+    }
+
+    void test(T6638712b<Integer> x) {
+        String i = m(x);
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/tools/javac/generics/inference/6638712/T6638712b.out	Fri Jun 20 16:52:01 2014 +0400
@@ -0,0 +1,2 @@
+T6638712b.java:15:21: compiler.err.invalid.inferred.types: T, (- compiler.misc.inferred.do.not.conform.to.bounds: T6638712b<java.lang.Integer>, T6638712b<java.lang.String>)
+1 error
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/tools/javac/generics/inference/6638712/T6638712c.java	Fri Jun 20 16:52:01 2014 +0400
@@ -0,0 +1,19 @@
+/*
+ * @test /nodynamiccopyright/
+ * @bug     6638712 6707034
+ * @author  mcimadamore
+ * @summary Inference with wildcard types causes selection of inapplicable method
+ * @compile/fail/ref=T6638712c.out -XDrawDiagnostics T6638712c.java
+ */
+
+import java.util.*;
+
+class T6638712c {
+    <T> T sort(T[] a, Comparator<? super T> c) {
+        return null;
+    }
+
+    void test(Enum[] e, Comparator<Enum<?>> comp) {
+        sort(e, comp);
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/tools/javac/generics/inference/6638712/T6638712c.out	Fri Jun 20 16:52:01 2014 +0400
@@ -0,0 +1,2 @@
+T6638712c.java:17:9: compiler.err.cant.apply.symbol: <T>sort(T[],java.util.Comparator<? super T>), T6638712c, , java.lang.Enum[],java.util.Comparator<java.lang.Enum<?>>, null
+1 error
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/tools/javac/generics/inference/6638712/T6638712d.java	Fri Jun 20 16:52:01 2014 +0400
@@ -0,0 +1,19 @@
+/*
+ * @test /nodynamiccopyright/
+ * @bug     6638712 6730468
+ * @author  mcimadamore
+ * @summary Inference with wildcard types causes selection of inapplicable method
+ * @compile/fail/ref=T6638712d.out -XDrawDiagnostics T6638712d.java
+ */
+
+import java.util.*;
+
+public class T6638712d {
+    <U> U m(U u, List<List<U>> list) {
+        return null;
+    }
+
+    void test(List<List<String>> lls) {
+        m(1, lls);
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/tools/javac/generics/inference/6638712/T6638712d.out	Fri Jun 20 16:52:01 2014 +0400
@@ -0,0 +1,2 @@
+T6638712d.java:17:9: compiler.err.cant.apply.symbol: <U>m(U,java.util.List<java.util.List<U>>), T6638712d, , int,java.util.List<java.util.List<java.lang.String>>, null
+1 error
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/tools/javac/generics/inference/6638712/T6638712e.java	Fri Jun 20 16:52:01 2014 +0400
@@ -0,0 +1,21 @@
+/*
+ * @test /nodynamiccopyright/
+ * @bug     6638712 6795689
+ * @author  mcimadamore
+ * @summary Inference with wildcard types causes selection of inapplicable method
+ * @compile/fail/ref=T6638712e.out -XDrawDiagnostics T6638712e.java
+ */
+
+class T6638712e {
+    static class Foo<A, B> {
+        <X> Foo<X, B> m(Foo<? super X, ? extends A> foo) {
+            return null;
+        }
+    }
+
+    static class Test {
+        Foo<Object, String> test(Foo<Boolean, String> foo1, Foo<Boolean, Boolean> foo2) {
+            return foo1.m(foo2);
+        }
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/tools/javac/generics/inference/6638712/T6638712e.out	Fri Jun 20 16:52:01 2014 +0400
@@ -0,0 +1,2 @@
+T6638712e.java:18:26: compiler.err.invalid.inferred.types: X, (- compiler.misc.inferred.do.not.conform.to.params: T6638712e.Foo<? super java.lang.Object,? extends java.lang.Boolean>, T6638712e.Foo<java.lang.Boolean,java.lang.Boolean>)
+1 error