6586091: javac crashes with StackOverflowError

Types.adapt should avoid infinite loops by exploiting a local cache

Reviewed-by: jjg
This commit is contained in:
Maurizio Cimadamore 2008-10-09 16:21:04 +01:00
parent 68c9df4110
commit c09e705e04
2 changed files with 142 additions and 81 deletions

View File

@ -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

View 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;
}