6586091: javac crashes with StackOverflowError
Types.adapt should avoid infinite loops by exploiting a local cache Reviewed-by: jjg
This commit is contained in:
parent
68c9df4110
commit
c09e705e04
@ -3213,6 +3213,7 @@ public class Types {
|
||||
containsType(t, s) && containsType(s, t);
|
||||
}
|
||||
|
||||
// <editor-fold defaultstate="collapsed" desc="adapt">
|
||||
/**
|
||||
* Adapt a type by computing a substitution which maps a source
|
||||
* type to a target type.
|
||||
@ -3226,8 +3227,23 @@ public class Types {
|
||||
Type target,
|
||||
ListBuffer<Type> from,
|
||||
ListBuffer<Type> to) throws AdaptFailure {
|
||||
Map<Symbol,Type> mapping = new HashMap<Symbol,Type>();
|
||||
adaptRecursive(source, target, from, to, mapping);
|
||||
new Adapter(from, to).adapt(source, target);
|
||||
}
|
||||
|
||||
class Adapter extends SimpleVisitor<Void, Type> {
|
||||
|
||||
ListBuffer<Type> from;
|
||||
ListBuffer<Type> to;
|
||||
Map<Symbol,Type> mapping;
|
||||
|
||||
Adapter(ListBuffer<Type> from, ListBuffer<Type> to) {
|
||||
this.from = from;
|
||||
this.to = to;
|
||||
mapping = new HashMap<Symbol,Type>();
|
||||
}
|
||||
|
||||
public void adapt(Type source, Type target) throws AdaptFailure {
|
||||
visit(source, target);
|
||||
List<Type> fromList = from.toList();
|
||||
List<Type> toList = to.toList();
|
||||
while (!fromList.isEmpty()) {
|
||||
@ -3238,13 +3254,32 @@ public class Types {
|
||||
toList = toList.tail;
|
||||
}
|
||||
}
|
||||
// where
|
||||
private void adaptRecursive(Type source,
|
||||
Type target,
|
||||
ListBuffer<Type> from,
|
||||
ListBuffer<Type> to,
|
||||
Map<Symbol,Type> mapping) throws AdaptFailure {
|
||||
if (source.tag == TYPEVAR) {
|
||||
|
||||
@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
|
||||
@ -3265,54 +3300,41 @@ public class Types {
|
||||
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;
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* 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<Type> source,
|
||||
List<Type> target,
|
||||
ListBuffer<Type> from,
|
||||
ListBuffer<Type> to,
|
||||
Map<Symbol,Type> mapping) throws AdaptFailure {
|
||||
@Override
|
||||
public Void visitType(Type source, Type target) {
|
||||
return null;
|
||||
}
|
||||
|
||||
private Set<TypePair> cache = new HashSet<TypePair>();
|
||||
|
||||
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<Type> source, List<Type> target) {
|
||||
if (source.length() == target.length()) {
|
||||
while (source.nonEmpty()) {
|
||||
adaptRecursive(source.head, target.head, from, to, mapping);
|
||||
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,
|
||||
ListBuffer<Type> from,
|
||||
@ -3326,6 +3348,7 @@ public class Types {
|
||||
throw new AssertionError(ex);
|
||||
}
|
||||
}
|
||||
// </editor-fold>
|
||||
|
||||
/**
|
||||
* Rewrite all type variables (universal quantifiers) in the given
|
||||
|
38
langtools/test/tools/javac/cast/6586091/T6586091.java
Normal file
38
langtools/test/tools/javac/cast/6586091/T6586091.java
Normal file
@ -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<T extends A<?>> {}
|
||||
static class B extends A<A<?>> {}
|
||||
|
||||
A<A<?>> t = null;
|
||||
B c = (B)t;
|
||||
}
|
Loading…
x
Reference in New Issue
Block a user