Extract and convert 'findLoopsInSupertypesAndDisconnect'

This commit is contained in:
Denis Zharkov
2015-10-28 19:12:30 +03:00
parent 8ba2dc5530
commit 0bc5043c75
2 changed files with 80 additions and 24 deletions
@@ -0,0 +1,61 @@
/*
* Copyright 2010-2015 JetBrains s.r.o.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
@file:JvmName("FindLoopsInSupertypes")
package org.jetbrains.kotlin.resolve
import org.jetbrains.kotlin.types.KotlinType
import org.jetbrains.kotlin.types.TypeConstructor
import org.jetbrains.kotlin.utils.DFS
fun findLoopsInSupertypesAndDisconnect(
currentTypeConstructor: TypeConstructor,
superTypes: MutableCollection<KotlinType>,
neighbors: (TypeConstructor) -> Iterable<KotlinType>,
reportLoopAt: (KotlinType) -> Unit
) {
val graph = DFS.Neighbors<TypeConstructor> { node -> neighbors(node).map { it.constructor } }
val iterator = superTypes.iterator()
while (iterator.hasNext()) {
val item = iterator.next()
if (isReachable(item.constructor, currentTypeConstructor, graph)) {
iterator.remove()
reportLoopAt(item)
}
}
}
private fun isReachable(
from: TypeConstructor, to: TypeConstructor,
neighbors: DFS.Neighbors<TypeConstructor>
): Boolean {
var result = false
DFS.dfs(listOf(from), neighbors, DFS.VisitedWithSet(), object : DFS.AbstractNodeHandler<TypeConstructor, Unit>() {
override fun beforeChildren(current: TypeConstructor): Boolean {
if (current == to) {
result = true
return false
}
return true
}
override fun result() = Unit
})
return result
}
@@ -582,18 +582,27 @@ public class LazyClassDescriptor extends ClassDescriptorBase implements ClassDes
}
private void findAndDisconnectLoopsInTypeHierarchy(@Mutable Collection<KotlinType> supertypes) {
for (Iterator<KotlinType> iterator = supertypes.iterator(); iterator.hasNext(); ) {
KotlinType supertype = iterator.next();
if (isReachable(supertype.getConstructor(), this, new HashSet<TypeConstructor>())) {
iterator.remove();
FindLoopsInSupertypes.findLoopsInSupertypesAndDisconnect(
typeConstructor, supertypes,
new Function1<TypeConstructor, Iterable<? extends KotlinType>>() {
@Override
public Iterable<? extends KotlinType> invoke(TypeConstructor typeConstructor) {
return getNeighbors(typeConstructor);
}
},
new Function1<KotlinType, Unit>() {
@Override
public Unit invoke(KotlinType type) {
ClassifierDescriptor supertypeDescriptor = type.getConstructor().getDeclarationDescriptor();
if (supertypeDescriptor instanceof ClassDescriptor) {
ClassDescriptor superclass = (ClassDescriptor) supertypeDescriptor;
reportCyclicInheritanceHierarchyError(c.getTrace(), LazyClassDescriptor.this, superclass);
}
ClassifierDescriptor supertypeDescriptor = supertype.getConstructor().getDeclarationDescriptor();
if (supertypeDescriptor instanceof ClassDescriptor) {
ClassDescriptor superclass = (ClassDescriptor) supertypeDescriptor;
reportCyclicInheritanceHierarchyError(c.getTrace(), LazyClassDescriptor.this, superclass);
return Unit.INSTANCE;
}
}
}
}
);
}
private void reportCyclicInheritanceHierarchyError(
@@ -627,20 +636,6 @@ public class LazyClassDescriptor extends ClassDescriptorBase implements ClassDes
}
}
private boolean isReachable(TypeConstructor from, TypeConstructor to, Set<TypeConstructor> visited) {
if (!visited.add(from)) return false;
for (KotlinType supertype : getNeighbors(from)) {
TypeConstructor supertypeConstructor = supertype.getConstructor();
if (supertypeConstructor == to) {
return true;
}
if (isReachable(supertypeConstructor, to, visited)) {
return true;
}
}
return false;
}
private Collection<KotlinType> getNeighbors(TypeConstructor from) {
// Supertypes + type for container
Collection<KotlinType> neighbours = new ArrayList<KotlinType>(