diff --git a/langtools/src/share/classes/com/sun/tools/javac/code/Types.java b/langtools/src/share/classes/com/sun/tools/javac/code/Types.java index 80a8d002a15..f7d0352bc28 100644 --- a/langtools/src/share/classes/com/sun/tools/javac/code/Types.java +++ b/langtools/src/share/classes/com/sun/tools/javac/code/Types.java @@ -3213,6 +3213,7 @@ public class Types { containsType(t, s) && containsType(s, t); } + // /** * Adapt a type by computing a substitution which maps a source * type to a target type. @@ -3226,92 +3227,113 @@ public class Types { Type target, ListBuffer from, ListBuffer to) throws AdaptFailure { - Map mapping = new HashMap(); - adaptRecursive(source, target, from, to, mapping); - List fromList = from.toList(); - List toList = to.toList(); - while (!fromList.isEmpty()) { - Type val = mapping.get(fromList.head.tsym); - if (toList.head != val) - toList.head = val; - fromList = fromList.tail; - toList = toList.tail; - } + new Adapter(from, to).adapt(source, target); } - // where - private void adaptRecursive(Type source, - Type target, - ListBuffer from, - ListBuffer to, - Map mapping) throws AdaptFailure { - if (source.tag == TYPEVAR) { - // Check to see if there is - // already a mapping for $source$, in which case - // the old mapping will be merged with the new - Type val = mapping.get(source.tsym); - if (val != null) { - if (val.isSuperBound() && target.isSuperBound()) { - val = isSubtype(lowerBound(val), lowerBound(target)) - ? target : val; - } else if (val.isExtendsBound() && target.isExtendsBound()) { - val = isSubtype(upperBound(val), upperBound(target)) - ? val : target; - } else if (!isSameType(val, target)) { - throw new AdaptFailure(); - } - } else { - val = target; - from.append(source); - to.append(target); - } - mapping.put(source.tsym, val); - } else if (source.tag == target.tag) { - switch (source.tag) { - case CLASS: - adapt(source.allparams(), target.allparams(), - from, to, mapping); - break; - case ARRAY: - adaptRecursive(elemtype(source), elemtype(target), - from, to, mapping); - break; - case WILDCARD: - if (source.isExtendsBound()) { - adaptRecursive(upperBound(source), upperBound(target), - from, to, mapping); - } else if (source.isSuperBound()) { - adaptRecursive(lowerBound(source), lowerBound(target), - from, to, mapping); - } - break; - } - } - } - public static class AdaptFailure extends Exception { - static final long serialVersionUID = -7490231548272701566L; + + class Adapter extends SimpleVisitor { + + ListBuffer from; + ListBuffer to; + Map mapping; + + Adapter(ListBuffer from, ListBuffer to) { + this.from = from; + this.to = to; + mapping = new HashMap(); } - /** - * Adapt a type by computing a substitution which maps a list of - * source types to a list of target types. - * - * @param source the source type - * @param target the target type - * @param from the type variables of the computed substitution - * @param to the types of the computed substitution. - */ - private void adapt(List source, - List target, - ListBuffer from, - ListBuffer to, - Map mapping) throws AdaptFailure { - if (source.length() == target.length()) { - while (source.nonEmpty()) { - adaptRecursive(source.head, target.head, from, to, mapping); - source = source.tail; - target = target.tail; + public void adapt(Type source, Type target) throws AdaptFailure { + visit(source, target); + List fromList = from.toList(); + List toList = to.toList(); + while (!fromList.isEmpty()) { + Type val = mapping.get(fromList.head.tsym); + if (toList.head != val) + toList.head = val; + fromList = fromList.tail; + toList = toList.tail; } } + + @Override + public Void visitClassType(ClassType source, Type target) throws AdaptFailure { + if (target.tag == CLASS) + adaptRecursive(source.allparams(), target.allparams()); + return null; + } + + @Override + public Void visitArrayType(ArrayType source, Type target) throws AdaptFailure { + if (target.tag == ARRAY) + adaptRecursive(elemtype(source), elemtype(target)); + return null; + } + + @Override + public Void visitWildcardType(WildcardType source, Type target) throws AdaptFailure { + if (source.isExtendsBound()) + adaptRecursive(upperBound(source), upperBound(target)); + else if (source.isSuperBound()) + adaptRecursive(lowerBound(source), lowerBound(target)); + return null; + } + + @Override + public Void visitTypeVar(TypeVar source, Type target) throws AdaptFailure { + // Check to see if there is + // already a mapping for $source$, in which case + // the old mapping will be merged with the new + Type val = mapping.get(source.tsym); + if (val != null) { + if (val.isSuperBound() && target.isSuperBound()) { + val = isSubtype(lowerBound(val), lowerBound(target)) + ? target : val; + } else if (val.isExtendsBound() && target.isExtendsBound()) { + val = isSubtype(upperBound(val), upperBound(target)) + ? val : target; + } else if (!isSameType(val, target)) { + throw new AdaptFailure(); + } + } else { + val = target; + from.append(source); + to.append(target); + } + mapping.put(source.tsym, val); + return null; + } + + @Override + public Void visitType(Type source, Type target) { + return null; + } + + private Set cache = new HashSet(); + + private void adaptRecursive(Type source, Type target) { + TypePair pair = new TypePair(source, target); + if (cache.add(pair)) { + try { + visit(source, target); + } finally { + cache.remove(pair); + } + } + } + + private void adaptRecursive(List source, List target) { + if (source.length() == target.length()) { + while (source.nonEmpty()) { + adaptRecursive(source.head, target.head); + source = source.tail; + target = target.tail; + } + } + } + } + + public static class AdaptFailure extends RuntimeException { + static final long serialVersionUID = -7490231548272701566L; } private void adaptSelf(Type t, @@ -3326,6 +3348,7 @@ public class Types { throw new AssertionError(ex); } } + // /** * Rewrite all type variables (universal quantifiers) in the given diff --git a/langtools/test/tools/javac/cast/6586091/T6586091.java b/langtools/test/tools/javac/cast/6586091/T6586091.java new file mode 100644 index 00000000000..5cc9ae8aa75 --- /dev/null +++ b/langtools/test/tools/javac/cast/6586091/T6586091.java @@ -0,0 +1,38 @@ +/* + * Copyright 2008 Sun Microsystems, Inc. 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 Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, + * CA 95054 USA or visit www.sun.com if you need additional information or + * have any questions. + */ + +/* + * @test + * @author Maurizio Cimadamore + * @bug 6586091 + * @summary javac crashes with StackOverflowError + * @compile T6586091.java + */ + +class T6586091 { + static class A> {} + static class B extends A> {} + + A> t = null; + B c = (B)t; +} \ No newline at end of file