# HG changeset patch # User ikrylov # Date 1403268721 -14400 # Node ID c711bcdb18ea9dcf96873c3439cfa79a0cdcb094 # Parent be4293ad2bbce82089b00a40be0e77a4126a8e6f 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 diff -r be4293ad2bbc -r c711bcdb18ea src/share/classes/com/sun/tools/javac/code/Type.java --- 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 actuals, Types types) { + return types.subst(qtype, tvars, actuals); + } + public Type map(Mapping f) { return f.apply(qtype); } diff -r be4293ad2bbc -r c711bcdb18ea src/share/classes/com/sun/tools/javac/code/Types.java --- 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 capture(List ts) { + List 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; diff -r be4293ad2bbc -r c711bcdb18ea src/share/classes/com/sun/tools/javac/comp/Check.java --- 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; } } } diff -r be4293ad2bbc -r c711bcdb18ea src/share/classes/com/sun/tools/javac/comp/Infer.java --- 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 undetvars = Type.map(that.tvars, fromTypeVarFun); for (List l = undetvars; l.nonEmpty(); l = l.tail) { UndetVar v = (UndetVar) l.head; @@ -273,8 +279,7 @@ List 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 tvars, MethodType mt, - List argtypes, - boolean allowBoxing, - boolean useVarargs, - Warner warn) throws NoInstanceException { + final List argtypes, + final boolean allowBoxing, + final boolean useVarargs, + final Warner warn) throws InferenceException { //-System.err.println("instantiateMethod(" + tvars + ", " + mt + ", " + argtypes + ")"); //DEBUG List undetvars = Type.map(tvars, fromTypeVarFun); List formals = mt.argtypes; - + //need to capture exactly once - otherwise subsequent + //applicability checks might fail + final List capturedArgs = types.capture(argtypes); + List actuals = capturedArgs; + List 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 inferredTypes = insttypes.toList(); + final List 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 inferred, Types types) throws NoInstanceException { + List 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 tvars, - Warner warn) throws NoInstanceException { + Warner warn) throws InferenceException { List targs; try { return instantiateExpr(that, to, warn); @@ -401,16 +435,16 @@ private void checkWithinBounds(List tvars, List arguments, Warner warn) - throws NoInstanceException { + throws InvalidInstanceException { for (List tvs = tvars, args = arguments; tvs.nonEmpty(); tvs = tvs.tail, args = args.tail) { if (args.head instanceof UndetVar) continue; List 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); } } } diff -r be4293ad2bbc -r c711bcdb18ea src/share/classes/com/sun/tools/javac/comp/Resolve.java --- 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()); diff -r be4293ad2bbc -r c711bcdb18ea src/share/classes/com/sun/tools/javac/resources/compiler.properties --- 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} ##### diff -r be4293ad2bbc -r c711bcdb18ea test/tools/javac/generics/inference/6302954/T6476073.java --- 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 */ diff -r be4293ad2bbc -r c711bcdb18ea test/tools/javac/generics/inference/6638712/T6638712a.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 { + Comparator compound(Iterable> it) { + return null; + } + + public void test(List> x) { + Comparator c3 = compound(x); + } +} diff -r be4293ad2bbc -r c711bcdb18ea test/tools/javac/generics/inference/6638712/T6638712a.out --- /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>, java.util.List>) +1 error diff -r be4293ad2bbc -r c711bcdb18ea test/tools/javac/generics/inference/6638712/T6638712b.java --- /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 { + , T> T m(I test) { + return null; + } + + void test(T6638712b x) { + String i = m(x); + } +} diff -r be4293ad2bbc -r c711bcdb18ea test/tools/javac/generics/inference/6638712/T6638712b.out --- /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, T6638712b) +1 error diff -r be4293ad2bbc -r c711bcdb18ea test/tools/javac/generics/inference/6638712/T6638712c.java --- /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 sort(T[] a, Comparator c) { + return null; + } + + void test(Enum[] e, Comparator> comp) { + sort(e, comp); + } +} diff -r be4293ad2bbc -r c711bcdb18ea test/tools/javac/generics/inference/6638712/T6638712c.out --- /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: sort(T[],java.util.Comparator), T6638712c, , java.lang.Enum[],java.util.Comparator>, null +1 error diff -r be4293ad2bbc -r c711bcdb18ea test/tools/javac/generics/inference/6638712/T6638712d.java --- /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 m(U u, List> list) { + return null; + } + + void test(List> lls) { + m(1, lls); + } +} diff -r be4293ad2bbc -r c711bcdb18ea test/tools/javac/generics/inference/6638712/T6638712d.out --- /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: m(U,java.util.List>), T6638712d, , int,java.util.List>, null +1 error diff -r be4293ad2bbc -r c711bcdb18ea test/tools/javac/generics/inference/6638712/T6638712e.java --- /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 { + Foo m(Foo foo) { + return null; + } + } + + static class Test { + Foo test(Foo foo1, Foo foo2) { + return foo1.m(foo2); + } + } +} diff -r be4293ad2bbc -r c711bcdb18ea test/tools/javac/generics/inference/6638712/T6638712e.out --- /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, T6638712e.Foo) +1 error