DFS utility class factored out of CommonSupertypes
This commit is contained in:
@@ -10,6 +10,7 @@
|
|||||||
<orderEntry type="sourceFolder" forTests="false" />
|
<orderEntry type="sourceFolder" forTests="false" />
|
||||||
<orderEntry type="library" scope="PROVIDED" name="intellij-core" level="project" />
|
<orderEntry type="library" scope="PROVIDED" name="intellij-core" level="project" />
|
||||||
<orderEntry type="library" name="javax.inject" level="project" />
|
<orderEntry type="library" name="javax.inject" level="project" />
|
||||||
|
<orderEntry type="module" module-name="util" />
|
||||||
</component>
|
</component>
|
||||||
</module>
|
</module>
|
||||||
|
|
||||||
|
|||||||
@@ -16,6 +16,8 @@
|
|||||||
|
|
||||||
package org.jetbrains.jet.lang.types;
|
package org.jetbrains.jet.lang.types;
|
||||||
|
|
||||||
|
import com.google.common.collect.Lists;
|
||||||
|
import com.google.common.collect.Sets;
|
||||||
import org.jetbrains.annotations.NotNull;
|
import org.jetbrains.annotations.NotNull;
|
||||||
import org.jetbrains.jet.lang.descriptors.ClassDescriptor;
|
import org.jetbrains.jet.lang.descriptors.ClassDescriptor;
|
||||||
import org.jetbrains.jet.lang.descriptors.DeclarationDescriptor;
|
import org.jetbrains.jet.lang.descriptors.DeclarationDescriptor;
|
||||||
@@ -24,11 +26,11 @@ import org.jetbrains.jet.lang.descriptors.annotations.AnnotationDescriptor;
|
|||||||
import org.jetbrains.jet.lang.resolve.scopes.JetScope;
|
import org.jetbrains.jet.lang.resolve.scopes.JetScope;
|
||||||
import org.jetbrains.jet.lang.types.checker.JetTypeChecker;
|
import org.jetbrains.jet.lang.types.checker.JetTypeChecker;
|
||||||
import org.jetbrains.jet.lang.types.lang.JetStandardClasses;
|
import org.jetbrains.jet.lang.types.lang.JetStandardClasses;
|
||||||
|
import org.jetbrains.jet.utils.DFS;
|
||||||
|
|
||||||
import java.util.*;
|
import java.util.*;
|
||||||
|
|
||||||
import static org.jetbrains.jet.lang.types.Variance.IN_VARIANCE;
|
import static org.jetbrains.jet.lang.types.Variance.*;
|
||||||
import static org.jetbrains.jet.lang.types.Variance.OUT_VARIANCE;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @author abreslav
|
* @author abreslav
|
||||||
@@ -91,33 +93,8 @@ public class CommonSupertypes {
|
|||||||
|
|
||||||
List<TypeConstructor> order = null;
|
List<TypeConstructor> order = null;
|
||||||
for (JetType type : types) {
|
for (JetType type : types) {
|
||||||
Set<TypeConstructor> visited = new HashSet<TypeConstructor>();
|
Set<TypeConstructor> visited = Sets.newHashSet();
|
||||||
|
order = topologicallySortSuperclassesAndRecordAllInstances(type, constructorToAllInstances, visited);
|
||||||
order = dfs(type, visited, new DfsNodeHandler<List<TypeConstructor>>() {
|
|
||||||
public LinkedList<TypeConstructor> list = new LinkedList<TypeConstructor>();
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void beforeChildren(JetType current) {
|
|
||||||
TypeConstructor constructor = current.getConstructor();
|
|
||||||
|
|
||||||
Set<JetType> instances = constructorToAllInstances.get(constructor);
|
|
||||||
if (instances == null) {
|
|
||||||
instances = new HashSet<JetType>();
|
|
||||||
constructorToAllInstances.put(constructor, instances);
|
|
||||||
}
|
|
||||||
instances.add(current);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void afterChildren(JetType current) {
|
|
||||||
list.addFirst(current.getConstructor());
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public List<TypeConstructor> result() {
|
|
||||||
return list;
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
if (commonSuperclasses == null) {
|
if (commonSuperclasses == null) {
|
||||||
commonSuperclasses = visited;
|
commonSuperclasses = visited;
|
||||||
@@ -144,6 +121,55 @@ public class CommonSupertypes {
|
|||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private static List<TypeConstructor> topologicallySortSuperclassesAndRecordAllInstances(
|
||||||
|
@NotNull JetType type,
|
||||||
|
@NotNull final Map<TypeConstructor, Set<JetType>> constructorToAllInstances,
|
||||||
|
@NotNull final Set<TypeConstructor> visited
|
||||||
|
) {
|
||||||
|
return DFS.dfs(
|
||||||
|
Collections.singletonList(type),
|
||||||
|
new DFS.Neighbors<JetType>() {
|
||||||
|
@NotNull
|
||||||
|
@Override
|
||||||
|
public Iterable<JetType> getNeighbors(JetType current) {
|
||||||
|
TypeSubstitutor substitutor = TypeSubstitutor.create(current);
|
||||||
|
List<JetType> result = Lists.newArrayList();
|
||||||
|
for (JetType supertype : current.getConstructor().getSupertypes()) {
|
||||||
|
if (visited.contains(supertype.getConstructor())) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
result.add(substitutor.safeSubstitute(supertype, INVARIANT));
|
||||||
|
}
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
},
|
||||||
|
new DFS.Visited<JetType>() {
|
||||||
|
@Override
|
||||||
|
public boolean checkAndMarkVisited(JetType current) {
|
||||||
|
return visited.add(current.getConstructor());
|
||||||
|
}
|
||||||
|
},
|
||||||
|
new DFS.NodeHandlerWithListResult<JetType, TypeConstructor>() {
|
||||||
|
@Override
|
||||||
|
public void beforeChildren(JetType current) {
|
||||||
|
TypeConstructor constructor = current.getConstructor();
|
||||||
|
|
||||||
|
Set<JetType> instances = constructorToAllInstances.get(constructor);
|
||||||
|
if (instances == null) {
|
||||||
|
instances = new HashSet<JetType>();
|
||||||
|
constructorToAllInstances.put(constructor, instances);
|
||||||
|
}
|
||||||
|
instances.add(current);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void afterChildren(JetType current) {
|
||||||
|
result.addFirst(current.getConstructor());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
// constructor - type constructor of a supertype to be instantiated
|
// constructor - type constructor of a supertype to be instantiated
|
||||||
// types - instantiations of constructor occurring as supertypes of classes we are trying to intersect
|
// types - instantiations of constructor occurring as supertypes of classes we are trying to intersect
|
||||||
@NotNull
|
@NotNull
|
||||||
@@ -251,42 +277,4 @@ public class CommonSupertypes {
|
|||||||
markAll(type.getConstructor(), markerSet);
|
markAll(type.getConstructor(), markerSet);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private static <R> R dfs(@NotNull JetType current, @NotNull Set<TypeConstructor> visited, @NotNull DfsNodeHandler<R> handler) {
|
|
||||||
doDfs(current, visited, handler);
|
|
||||||
return handler.result();
|
|
||||||
}
|
|
||||||
|
|
||||||
private static void doDfs(@NotNull JetType current, @NotNull Set<TypeConstructor> visited, @NotNull DfsNodeHandler<?> handler) {
|
|
||||||
if (!visited.add(current.getConstructor())) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
handler.beforeChildren(current);
|
|
||||||
// Map<TypeConstructor, TypeProjection> substitutionContext = TypeUtils.buildSubstitutionContext(current);
|
|
||||||
TypeSubstitutor substitutor = TypeSubstitutor.create(current);
|
|
||||||
for (JetType supertype : current.getConstructor().getSupertypes()) {
|
|
||||||
TypeConstructor supertypeConstructor = supertype.getConstructor();
|
|
||||||
if (visited.contains(supertypeConstructor)) {
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
JetType substitutedSupertype = substitutor.safeSubstitute(supertype, Variance.INVARIANT);
|
|
||||||
dfs(substitutedSupertype, visited, handler);
|
|
||||||
}
|
|
||||||
handler.afterChildren(current);
|
|
||||||
}
|
|
||||||
|
|
||||||
private static class DfsNodeHandler<R> {
|
|
||||||
|
|
||||||
public void beforeChildren(JetType current) {
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
public void afterChildren(JetType current) {
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
public R result() {
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -0,0 +1,148 @@
|
|||||||
|
/*
|
||||||
|
* Copyright 2010-2012 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.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package org.jetbrains.jet.utils;
|
||||||
|
|
||||||
|
import com.google.common.collect.Lists;
|
||||||
|
import com.google.common.collect.Sets;
|
||||||
|
import org.jetbrains.annotations.NotNull;
|
||||||
|
|
||||||
|
import java.util.Collection;
|
||||||
|
import java.util.LinkedList;
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.Set;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @author abreslav
|
||||||
|
*/
|
||||||
|
public class DFS {
|
||||||
|
public static <N, R> R dfs(@NotNull Collection<N> nodes, @NotNull Neighbors<N> neighbors, @NotNull Visited<N> visited, @NotNull NodeHandler<N, R> handler) {
|
||||||
|
for (N node : nodes) {
|
||||||
|
doDfs(node, neighbors, visited, handler);
|
||||||
|
}
|
||||||
|
return handler.result();
|
||||||
|
}
|
||||||
|
|
||||||
|
public static <N, R> R dfs(
|
||||||
|
@NotNull Collection<N> nodes,
|
||||||
|
@NotNull Neighbors<N> neighbors,
|
||||||
|
@NotNull NodeHandler<N, R> handler
|
||||||
|
) {
|
||||||
|
return dfs(nodes, neighbors, new VisitedWithSet<N>(), handler);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static <N, R> R dfsFromNode(@NotNull N node, @NotNull Neighbors<N> neighbors, @NotNull Visited<N> visited, @NotNull NodeHandler<N, R> handler) {
|
||||||
|
doDfs(node, neighbors, visited, handler);
|
||||||
|
return handler.result();
|
||||||
|
}
|
||||||
|
|
||||||
|
public static <N> void dfsFromNode(
|
||||||
|
@NotNull N node,
|
||||||
|
@NotNull Neighbors<N> neighbors,
|
||||||
|
@NotNull Visited<N> visited
|
||||||
|
) {
|
||||||
|
dfsFromNode(node, neighbors, visited, new AbstractNodeHandler<N, Void>() {
|
||||||
|
@Override
|
||||||
|
public Void result() {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
public static <N> List<N> topologicalOrder(@NotNull Iterable<N> nodes, @NotNull Neighbors<N> neighbors, @NotNull Visited<N> visited) {
|
||||||
|
TopologicalOrder<N> handler = new TopologicalOrder<N>();
|
||||||
|
for (N node : nodes) {
|
||||||
|
doDfs(node, neighbors, visited, handler);
|
||||||
|
}
|
||||||
|
return handler.result();
|
||||||
|
}
|
||||||
|
|
||||||
|
public static <N> List<N> topologicalOrder(@NotNull Iterable<N> nodes, @NotNull Neighbors<N> neighbors) {
|
||||||
|
return topologicalOrder(nodes, neighbors, new VisitedWithSet<N>());
|
||||||
|
}
|
||||||
|
|
||||||
|
private static <N> void doDfs(@NotNull N current, @NotNull Neighbors<N> neighbors, @NotNull Visited<N> visited, @NotNull NodeHandler<N, ?> handler) {
|
||||||
|
if (!visited.checkAndMarkVisited(current)) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
handler.beforeChildren(current);
|
||||||
|
for (N neighbor : neighbors.getNeighbors(current)) {
|
||||||
|
doDfs(neighbor, neighbors, visited, handler);
|
||||||
|
}
|
||||||
|
handler.afterChildren(current);
|
||||||
|
}
|
||||||
|
|
||||||
|
public interface NodeHandler<N, R> {
|
||||||
|
|
||||||
|
void beforeChildren(N current);
|
||||||
|
|
||||||
|
void afterChildren(N current);
|
||||||
|
|
||||||
|
R result();
|
||||||
|
}
|
||||||
|
|
||||||
|
public interface Neighbors<N> {
|
||||||
|
@NotNull
|
||||||
|
Iterable<N> getNeighbors(N current);
|
||||||
|
}
|
||||||
|
|
||||||
|
public interface Visited<N> {
|
||||||
|
boolean checkAndMarkVisited(N current);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static abstract class AbstractNodeHandler<N, R> implements NodeHandler<N, R> {
|
||||||
|
@Override
|
||||||
|
public void beforeChildren(N current) {
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void afterChildren(N current) {
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public static class VisitedWithSet<N> implements Visited<N> {
|
||||||
|
private final Set<N> visited;
|
||||||
|
|
||||||
|
public VisitedWithSet() {
|
||||||
|
this(Sets.<N>newHashSet());
|
||||||
|
}
|
||||||
|
|
||||||
|
public VisitedWithSet(@NotNull Set<N> visited) {
|
||||||
|
this.visited = visited;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean checkAndMarkVisited(N current) {
|
||||||
|
return visited.add(current);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public static abstract class NodeHandlerWithListResult<N, R> extends AbstractNodeHandler<N, List<R>> {
|
||||||
|
protected final LinkedList<R> result = Lists.newLinkedList();
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public List<R> result() {
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public static class TopologicalOrder<N> extends NodeHandlerWithListResult<N, N> {
|
||||||
|
@Override
|
||||||
|
public void afterChildren(N current) {
|
||||||
|
result.addFirst(current);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user