Fri, 18 Apr 2014 23:58:05 +0100
8029002: javac should take multiple upper bounds into account in incorporation
Reviewed-by: dlsmith, jjg
1.1 --- a/src/share/classes/com/sun/tools/javac/comp/Infer.java Fri Apr 18 23:50:41 2014 +0100 1.2 +++ b/src/share/classes/com/sun/tools/javac/comp/Infer.java Fri Apr 18 23:58:05 2014 +0100 1.3 @@ -516,6 +516,32 @@ 1.4 /** max number of incorporation rounds */ 1.5 static final int MAX_INCORPORATION_STEPS = 100; 1.6 1.7 + /* If for two types t and s there is a least upper bound that is a 1.8 + * parameterized type G, then there exists a supertype of 't' of the form 1.9 + * G<T1, ..., Tn> and a supertype of 's' of the form G<S1, ..., Sn> 1.10 + * which will be returned by this method. If no such supertypes exists then 1.11 + * null is returned. 1.12 + * 1.13 + * As an example for the following input: 1.14 + * 1.15 + * t = java.util.ArrayList<java.lang.String> 1.16 + * s = java.util.List<T> 1.17 + * 1.18 + * we get this ouput: 1.19 + * 1.20 + * Pair[java.util.List<java.lang.String>,java.util.List<T>] 1.21 + */ 1.22 + private Pair<Type, Type> getParameterizedSupers(Type t, Type s) { 1.23 + Type lubResult = types.lub(t, s); 1.24 + if (lubResult == syms.errType || lubResult == syms.botType || 1.25 + !lubResult.isParameterized()) { 1.26 + return null; 1.27 + } 1.28 + Type asSuperOfT = types.asSuper(t, lubResult.tsym); 1.29 + Type asSuperOfS = types.asSuper(s, lubResult.tsym); 1.30 + return new Pair<>(asSuperOfT, asSuperOfS); 1.31 + } 1.32 + 1.33 /** 1.34 * This enumeration defines an entry point for doing inference variable 1.35 * bound incorporation - it can be used to inject custom incorporation 1.36 @@ -651,6 +677,53 @@ 1.37 } 1.38 }, 1.39 /** 1.40 + * Given a bound set containing {@code alpha <: P<T>} and 1.41 + * {@code alpha <: P<S>} where P is a parameterized type, 1.42 + * perform {@code T = S} (which could lead to new bounds). 1.43 + */ 1.44 + CROSS_UPPER_UPPER() { 1.45 + @Override 1.46 + public void apply(UndetVar uv, InferenceContext inferenceContext, Warner warn) { 1.47 + Infer infer = inferenceContext.infer(); 1.48 + List<Type> boundList = uv.getBounds(InferenceBound.UPPER); 1.49 + List<Type> boundListTail = boundList.tail; 1.50 + while (boundList.nonEmpty()) { 1.51 + List<Type> tmpTail = boundListTail; 1.52 + while (tmpTail.nonEmpty()) { 1.53 + Type b1 = boundList.head; 1.54 + Type b2 = tmpTail.head; 1.55 + if (b1 != b2) { 1.56 + Pair<Type, Type> commonSupers = infer.getParameterizedSupers(b1, b2); 1.57 + if (commonSupers != null) { 1.58 + List<Type> allParamsSuperBound1 = commonSupers.fst.allparams(); 1.59 + List<Type> allParamsSuperBound2 = commonSupers.snd.allparams(); 1.60 + while (allParamsSuperBound1.nonEmpty() && allParamsSuperBound2.nonEmpty()) { 1.61 + //traverse the list of all params comparing them 1.62 + if (!allParamsSuperBound1.head.hasTag(WILDCARD) && 1.63 + !allParamsSuperBound2.head.hasTag(WILDCARD)) { 1.64 + isSameType(inferenceContext.asUndetVar(allParamsSuperBound1.head), 1.65 + inferenceContext.asUndetVar(allParamsSuperBound2.head), infer); 1.66 + } 1.67 + allParamsSuperBound1 = allParamsSuperBound1.tail; 1.68 + allParamsSuperBound2 = allParamsSuperBound2.tail; 1.69 + } 1.70 + Assert.check(allParamsSuperBound1.isEmpty() && allParamsSuperBound2.isEmpty()); 1.71 + } 1.72 + } 1.73 + tmpTail = tmpTail.tail; 1.74 + } 1.75 + boundList = boundList.tail; 1.76 + boundListTail = boundList.tail; 1.77 + } 1.78 + } 1.79 + 1.80 + @Override 1.81 + boolean accepts(UndetVar uv, InferenceContext inferenceContext) { 1.82 + return !uv.isCaptured() && 1.83 + uv.getBounds(InferenceBound.UPPER).nonEmpty(); 1.84 + } 1.85 + }, 1.86 + /** 1.87 * Given a bound set containing {@code alpha == S} and {@code alpha == T} 1.88 * perform {@code S == T} (which could lead to new bounds). 1.89 */
2.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 2.2 +++ b/test/tools/javac/T8029002/MultipleUpperBoundsIncorporationTest.java Fri Apr 18 23:58:05 2014 +0100 2.3 @@ -0,0 +1,72 @@ 2.4 +/* 2.5 + * Copyright (c) 2014, Oracle and/or its affiliates. All rights reserved. 2.6 + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. 2.7 + * 2.8 + * This code is free software; you can redistribute it and/or modify it 2.9 + * under the terms of the GNU General Public License version 2 only, as 2.10 + * published by the Free Software Foundation. 2.11 + * 2.12 + * This code is distributed in the hope that it will be useful, but WITHOUT 2.13 + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 2.14 + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License 2.15 + * version 2 for more details (a copy is included in the LICENSE file that 2.16 + * accompanied this code). 2.17 + * 2.18 + * You should have received a copy of the GNU General Public License version 2.19 + * 2 along with this work; if not, write to the Free Software Foundation, 2.20 + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. 2.21 + * 2.22 + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA 2.23 + * or visit www.oracle.com if you need additional information or have any 2.24 + * questions. 2.25 + */ 2.26 + 2.27 +/* 2.28 + * @test 2.29 + * @bug 8029002 2.30 + * @summary javac should take multiple upper bounds into account in incorporation 2.31 + * @compile MultipleUpperBoundsIncorporationTest.java 2.32 + */ 2.33 + 2.34 +import java.util.ArrayList; 2.35 +import java.util.List; 2.36 + 2.37 +public class MultipleUpperBoundsIncorporationTest { 2.38 + 2.39 + static class TestCase1 { 2.40 + interface Task<E extends Exception> {} 2.41 + 2.42 + class Comparator<T> {} 2.43 + 2.44 + class CustomException extends Exception {} 2.45 + 2.46 + class TaskQueue<E extends Exception, T extends Task<E>> {} 2.47 + 2.48 + abstract class Test { 2.49 + abstract <E extends Exception, T extends Task<E>> TaskQueue<E, T> create(Comparator<? super T> comparator); 2.50 + 2.51 + void f(Comparator<Task<CustomException>> comp) { 2.52 + TaskQueue<CustomException, Task<CustomException>> queue = create(comp); 2.53 + queue.getClass(); 2.54 + } 2.55 + } 2.56 + } 2.57 + 2.58 + static class TestCase2 { 2.59 + public <T, E extends List<T>> E typedNull() { 2.60 + return null; 2.61 + } 2.62 + 2.63 + public void call() { 2.64 + ArrayList<String> list = typedNull(); 2.65 + } 2.66 + } 2.67 + 2.68 + static class TestCase3 { 2.69 + interface I extends Iterable<String> {} 2.70 + 2.71 + <T, Exp extends Iterable<T>> Exp typedNull() { return null; } 2.72 + I i = typedNull(); 2.73 + } 2.74 + 2.75 +}