DFS utility class factored out of CommonSupertypes
This commit is contained in:
@@ -10,6 +10,7 @@
|
||||
<orderEntry type="sourceFolder" forTests="false" />
|
||||
<orderEntry type="library" scope="PROVIDED" name="intellij-core" level="project" />
|
||||
<orderEntry type="library" name="javax.inject" level="project" />
|
||||
<orderEntry type="module" module-name="util" />
|
||||
</component>
|
||||
</module>
|
||||
|
||||
|
||||
@@ -16,6 +16,8 @@
|
||||
|
||||
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.jet.lang.descriptors.ClassDescriptor;
|
||||
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.types.checker.JetTypeChecker;
|
||||
import org.jetbrains.jet.lang.types.lang.JetStandardClasses;
|
||||
import org.jetbrains.jet.utils.DFS;
|
||||
|
||||
import java.util.*;
|
||||
|
||||
import static org.jetbrains.jet.lang.types.Variance.IN_VARIANCE;
|
||||
import static org.jetbrains.jet.lang.types.Variance.OUT_VARIANCE;
|
||||
import static org.jetbrains.jet.lang.types.Variance.*;
|
||||
|
||||
/**
|
||||
* @author abreslav
|
||||
@@ -91,33 +93,8 @@ public class CommonSupertypes {
|
||||
|
||||
List<TypeConstructor> order = null;
|
||||
for (JetType type : types) {
|
||||
Set<TypeConstructor> visited = new HashSet<TypeConstructor>();
|
||||
|
||||
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;
|
||||
}
|
||||
});
|
||||
Set<TypeConstructor> visited = Sets.newHashSet();
|
||||
order = topologicallySortSuperclassesAndRecordAllInstances(type, constructorToAllInstances, visited);
|
||||
|
||||
if (commonSuperclasses == null) {
|
||||
commonSuperclasses = visited;
|
||||
@@ -144,6 +121,55 @@ public class CommonSupertypes {
|
||||
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
|
||||
// types - instantiations of constructor occurring as supertypes of classes we are trying to intersect
|
||||
@NotNull
|
||||
@@ -251,42 +277,4 @@ public class CommonSupertypes {
|
||||
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