LR: Detecting and disconnecting loops in type hierarchy

This commit is contained in:
Andrey Breslav
2012-07-19 14:33:44 +04:00
parent 542068d14a
commit 77353d4a56
@@ -19,6 +19,7 @@ package org.jetbrains.jet.lang.resolve.lazy;
import com.google.common.base.Predicate;
import com.google.common.base.Predicates;
import com.google.common.collect.Collections2;
import com.google.common.collect.Lists;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import org.jetbrains.jet.lang.descriptors.*;
@@ -39,10 +40,7 @@ import org.jetbrains.jet.lang.types.JetType;
import org.jetbrains.jet.lang.types.TypeConstructor;
import org.jetbrains.jet.lang.types.TypeUtils;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.List;
import java.util.*;
/**
* @author abreslav
@@ -326,13 +324,38 @@ public class LazyClassDescriptor extends ClassDescriptorBase implements ClassDes
.resolveSupertypes(getScopeForClassHeaderResolution(),
classOrObject,
resolveSession.getTrace());
this.supertypes = Collections2.filter(allSupertypes, VALID_SUPERTYPE);
List<JetType> validSupertypes = Lists.newArrayList(Collections2.filter(allSupertypes, VALID_SUPERTYPE));
this.supertypes = validSupertypes;
findAndDisconnectLoopsInTypeHierarchy(validSupertypes);
}
}
}
return supertypes;
}
private void findAndDisconnectLoopsInTypeHierarchy(List<JetType> supertypes) {
for (Iterator<JetType> iterator = supertypes.iterator(); iterator.hasNext(); ) {
JetType supertype = iterator.next();
if (isReachable(supertype.getConstructor(), this, new HashSet<TypeConstructor>())) {
iterator.remove();
}
}
}
private boolean isReachable(TypeConstructor from, TypeConstructor to, Set<TypeConstructor> visited) {
if (!visited.add(from)) return false;
for (JetType supertype : from.getSupertypes()) {
TypeConstructor supertypeConstructor = supertype.getConstructor();
if (supertypeConstructor == to) {
return true;
}
if (isReachable(supertypeConstructor, to, visited)) {
return true;
}
}
return false;
}
@Override
public boolean isSealed() {
return !getModality().isOverridable();