8029002: javac should take multiple upper bounds into account in incorporation
Reviewed-by: dlsmith, jjg
--- a/langtools/src/share/classes/com/sun/tools/javac/comp/Infer.java Fri Apr 18 11:53:34 2014 +0200
+++ b/langtools/src/share/classes/com/sun/tools/javac/comp/Infer.java Fri Apr 18 17:50:30 2014 +0100
@@ -515,6 +515,32 @@
/** max number of incorporation rounds */
static final int MAX_INCORPORATION_STEPS = 100;
+ /* If for two types t and s there is a least upper bound that is a
+ * parameterized type G, then there exists a supertype of 't' of the form
+ * G<T1, ..., Tn> and a supertype of 's' of the form G<S1, ..., Sn>
+ * which will be returned by this method. If no such supertypes exists then
+ * null is returned.
+ *
+ * As an example for the following input:
+ *
+ * t = java.util.ArrayList<java.lang.String>
+ * s = java.util.List<T>
+ *
+ * we get this ouput:
+ *
+ * Pair[java.util.List<java.lang.String>,java.util.List<T>]
+ */
+ private Pair<Type, Type> getParameterizedSupers(Type t, Type s) {
+ Type lubResult = types.lub(t, s);
+ if (lubResult == syms.errType || lubResult == syms.botType ||
+ !lubResult.isParameterized()) {
+ return null;
+ }
+ Type asSuperOfT = types.asSuper(t, lubResult.tsym);
+ Type asSuperOfS = types.asSuper(s, lubResult.tsym);
+ return new Pair<>(asSuperOfT, asSuperOfS);
+ }
+
/**
* This enumeration defines an entry point for doing inference variable
* bound incorporation - it can be used to inject custom incorporation
@@ -682,6 +708,53 @@
}
},
/**
+ * Given a bound set containing {@code alpha <: P<T>} and
+ * {@code alpha <: P<S>} where P is a parameterized type,
+ * perform {@code T = S} (which could lead to new bounds).
+ */
+ CROSS_UPPER_UPPER() {
+ @Override
+ public void apply(UndetVar uv, InferenceContext inferenceContext, Warner warn) {
+ Infer infer = inferenceContext.infer();
+ List<Type> boundList = uv.getBounds(InferenceBound.UPPER);
+ List<Type> boundListTail = boundList.tail;
+ while (boundList.nonEmpty()) {
+ List<Type> tmpTail = boundListTail;
+ while (tmpTail.nonEmpty()) {
+ Type b1 = boundList.head;
+ Type b2 = tmpTail.head;
+ if (b1 != b2) {
+ Pair<Type, Type> commonSupers = infer.getParameterizedSupers(b1, b2);
+ if (commonSupers != null) {
+ List<Type> allParamsSuperBound1 = commonSupers.fst.allparams();
+ List<Type> allParamsSuperBound2 = commonSupers.snd.allparams();
+ while (allParamsSuperBound1.nonEmpty() && allParamsSuperBound2.nonEmpty()) {
+ //traverse the list of all params comparing them
+ if (!allParamsSuperBound1.head.hasTag(WILDCARD) &&
+ !allParamsSuperBound2.head.hasTag(WILDCARD)) {
+ isSameType(inferenceContext.asUndetVar(allParamsSuperBound1.head),
+ inferenceContext.asUndetVar(allParamsSuperBound2.head), infer);
+ }
+ allParamsSuperBound1 = allParamsSuperBound1.tail;
+ allParamsSuperBound2 = allParamsSuperBound2.tail;
+ }
+ Assert.check(allParamsSuperBound1.isEmpty() && allParamsSuperBound2.isEmpty());
+ }
+ }
+ tmpTail = tmpTail.tail;
+ }
+ boundList = boundList.tail;
+ boundListTail = boundList.tail;
+ }
+ }
+
+ @Override
+ boolean accepts(UndetVar uv, InferenceContext inferenceContext) {
+ return !uv.isCaptured() &&
+ uv.getBounds(InferenceBound.UPPER).nonEmpty();
+ }
+ },
+ /**
* Given a bound set containing {@code alpha == S} and {@code alpha == T}
* perform {@code S == T} (which could lead to new bounds).
*/
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/langtools/test/tools/javac/T8029002/MultipleUpperBoundsIncorporationTest.java Fri Apr 18 17:50:30 2014 +0100
@@ -0,0 +1,72 @@
+/*
+ * Copyright (c) 2014, 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 8029002
+ * @summary javac should take multiple upper bounds into account in incorporation
+ * @compile MultipleUpperBoundsIncorporationTest.java
+ */
+
+import java.util.ArrayList;
+import java.util.List;
+
+public class MultipleUpperBoundsIncorporationTest {
+
+ static class TestCase1 {
+ interface Task<E extends Exception> {}
+
+ class Comparator<T> {}
+
+ class CustomException extends Exception {}
+
+ class TaskQueue<E extends Exception, T extends Task<E>> {}
+
+ abstract class Test {
+ abstract <E extends Exception, T extends Task<E>> TaskQueue<E, T> create(Comparator<? super T> comparator);
+
+ void f(Comparator<Task<CustomException>> comp) {
+ TaskQueue<CustomException, Task<CustomException>> queue = create(comp);
+ queue.getClass();
+ }
+ }
+ }
+
+ static class TestCase2 {
+ public <T, E extends List<T>> E typedNull() {
+ return null;
+ }
+
+ public void call() {
+ ArrayList<String> list = typedNull();
+ }
+ }
+
+ static class TestCase3 {
+ interface I extends Iterable<String> {}
+
+ <T, Exp extends Iterable<T>> Exp typedNull() { return null; }
+ I i = typedNull();
+ }
+
+}