DataFlowInfo.getPossibleTypes() now returns Set

This solves some performance problems related to DataFlowInfo (lots of nested
conditions etc.)
This commit is contained in:
Alexander Udalov
2012-11-16 16:21:00 +04:00
parent 6c7b32dc03
commit 712fafddb6
3 changed files with 60 additions and 65 deletions
@@ -20,7 +20,7 @@ import com.google.common.collect.ImmutableMap;
import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.NotNull;
import org.jetbrains.jet.lang.types.JetType; import org.jetbrains.jet.lang.types.JetType;
import java.util.List; import java.util.Set;
public interface DataFlowInfo { public interface DataFlowInfo {
DataFlowInfo EMPTY = new DelegatingDataFlowInfo(null, ImmutableMap.<DataFlowValue, Nullability>of(), DataFlowInfo EMPTY = new DelegatingDataFlowInfo(null, ImmutableMap.<DataFlowValue, Nullability>of(),
@@ -30,7 +30,7 @@ public interface DataFlowInfo {
Nullability getNullability(@NotNull DataFlowValue key); Nullability getNullability(@NotNull DataFlowValue key);
@NotNull @NotNull
List<JetType> getPossibleTypes(@NotNull DataFlowValue key); Set<JetType> getPossibleTypes(@NotNull DataFlowValue key);
@NotNull @NotNull
DataFlowInfo equate(@NotNull DataFlowValue a, @NotNull DataFlowValue b); DataFlowInfo equate(@NotNull DataFlowValue a, @NotNull DataFlowValue b);
@@ -36,16 +36,16 @@ import static org.jetbrains.jet.lang.resolve.calls.autocasts.Nullability.NOT_NUL
/** Also immutable */ /** Also immutable */
@NotNull @NotNull
private final ListMultimap<DataFlowValue, JetType> typeInfo; private final SetMultimap<DataFlowValue, JetType> typeInfo;
private static final ImmutableMap<DataFlowValue,Nullability> EMPTY_NULLABILITY_INFO = private static final ImmutableMap<DataFlowValue,Nullability> EMPTY_NULLABILITY_INFO =
ImmutableMap.copyOf(Collections.<DataFlowValue, Nullability>emptyMap()); ImmutableMap.copyOf(Collections.<DataFlowValue, Nullability>emptyMap());
private static final ListMultimap<DataFlowValue, JetType> EMPTY_TYPE_INFO = newTypeInfo(); private static final SetMultimap<DataFlowValue, JetType> EMPTY_TYPE_INFO = newTypeInfo();
/* package */ DelegatingDataFlowInfo( /* package */ DelegatingDataFlowInfo(
@Nullable DataFlowInfo parent, @Nullable DataFlowInfo parent,
@NotNull ImmutableMap<DataFlowValue, Nullability> nullabilityInfo, @NotNull ImmutableMap<DataFlowValue, Nullability> nullabilityInfo,
@NotNull ListMultimap<DataFlowValue, JetType> typeInfo @NotNull SetMultimap<DataFlowValue, JetType> typeInfo
) { ) {
this.parent = parent; this.parent = parent;
this.nullabilityInfo = nullabilityInfo; this.nullabilityInfo = nullabilityInfo;
@@ -70,8 +70,8 @@ import static org.jetbrains.jet.lang.resolve.calls.autocasts.Nullability.NOT_NUL
} }
@NotNull @NotNull
private ListMultimap<DataFlowValue, JetType> getCompleteTypeInfo() { private SetMultimap<DataFlowValue, JetType> getCompleteTypeInfo() {
ListMultimap<DataFlowValue, JetType> result = newTypeInfo(); SetMultimap<DataFlowValue, JetType> result = newTypeInfo();
DelegatingDataFlowInfo info = this; DelegatingDataFlowInfo info = this;
while (info != null) { while (info != null) {
for (DataFlowValue key : info.typeInfo.keySet()) { for (DataFlowValue key : info.typeInfo.keySet()) {
@@ -100,17 +100,13 @@ import static org.jetbrains.jet.lang.resolve.calls.autocasts.Nullability.NOT_NUL
@Override @Override
@NotNull @NotNull
public List<JetType> getPossibleTypes(@NotNull DataFlowValue key) { public Set<JetType> getPossibleTypes(@NotNull DataFlowValue key) {
List<JetType> types = typeInfo.get(key); Set<JetType> types = typeInfo.get(key);
if (getNullability(key).canBeNull()) { if (getNullability(key).canBeNull()) {
if (parent != null) { return parent == null ? types : Sets.union(types, parent.getPossibleTypes(key));
types = Lists.newArrayList(types);
addAllUnique(types, parent.getPossibleTypes(key));
}
return types;
} }
List<JetType> enrichedTypes = Lists.newArrayListWithCapacity(types.size() + 1); Set<JetType> enrichedTypes = Sets.newHashSetWithExpectedSize(types.size() + 1);
JetType originalType = key.getType(); JetType originalType = key.getType();
if (originalType.isNullable()) { if (originalType.isNullable()) {
enrichedTypes.add(TypeUtils.makeNotNullable(originalType)); enrichedTypes.add(TypeUtils.makeNotNullable(originalType));
@@ -119,19 +115,7 @@ import static org.jetbrains.jet.lang.resolve.calls.autocasts.Nullability.NOT_NUL
enrichedTypes.add(TypeUtils.makeNotNullable(type)); enrichedTypes.add(TypeUtils.makeNotNullable(type));
} }
if (parent != null) { return parent == null ? enrichedTypes : Sets.union(enrichedTypes, parent.getPossibleTypes(key));
addAllUnique(enrichedTypes, parent.getPossibleTypes(key));
}
return enrichedTypes;
}
private static void addAllUnique(@NotNull List<JetType> toList, @NotNull List<JetType> fromList) {
for (JetType type : fromList) {
if (!toList.contains(type)) {
toList.add(type);
}
}
} }
@Override @Override
@@ -167,7 +151,7 @@ import static org.jetbrains.jet.lang.resolve.calls.autocasts.Nullability.NOT_NUL
if (getPossibleTypes(value).contains(type)) return this; if (getPossibleTypes(value).contains(type)) return this;
ImmutableMap<DataFlowValue, Nullability> newNullabilityInfo = ImmutableMap<DataFlowValue, Nullability> newNullabilityInfo =
type.isNullable() ? EMPTY_NULLABILITY_INFO : ImmutableMap.of(value, NOT_NULL); type.isNullable() ? EMPTY_NULLABILITY_INFO : ImmutableMap.of(value, NOT_NULL);
ListMultimap<DataFlowValue, JetType> newTypeInfo = ImmutableListMultimap.of(value, type); SetMultimap<DataFlowValue, JetType> newTypeInfo = ImmutableSetMultimap.of(value, type);
return new DelegatingDataFlowInfo(this, newNullabilityInfo, newTypeInfo); return new DelegatingDataFlowInfo(this, newNullabilityInfo, newTypeInfo);
} }
@@ -192,12 +176,17 @@ import static org.jetbrains.jet.lang.resolve.calls.autocasts.Nullability.NOT_NUL
} }
} }
ListMultimap<DataFlowValue, JetType> newTypeInfo = other.getCompleteTypeInfo(); SetMultimap<DataFlowValue, JetType> myTypeInfo = getCompleteTypeInfo();
if (nullabilityMapBuilder.isEmpty() && newTypeInfo.isEmpty()) { SetMultimap<DataFlowValue, JetType> otherTypeInfo = other.getCompleteTypeInfo();
if (nullabilityMapBuilder.isEmpty() && containsAll(myTypeInfo, otherTypeInfo)) {
return this; return this;
} }
return new DelegatingDataFlowInfo(this, ImmutableMap.copyOf(nullabilityMapBuilder), newTypeInfo); return new DelegatingDataFlowInfo(this, ImmutableMap.copyOf(nullabilityMapBuilder), otherTypeInfo);
}
private static boolean containsAll(SetMultimap<DataFlowValue, JetType> first, SetMultimap<DataFlowValue, JetType> second) {
return first.entries().containsAll(second.entries());
} }
@NotNull @NotNull
@@ -218,21 +207,14 @@ import static org.jetbrains.jet.lang.resolve.calls.autocasts.Nullability.NOT_NUL
nullabilityMapBuilder.put(key, thisFlags.or(otherFlags)); nullabilityMapBuilder.put(key, thisFlags.or(otherFlags));
} }
ListMultimap<DataFlowValue, JetType> myTypeInfo = getCompleteTypeInfo(); SetMultimap<DataFlowValue, JetType> myTypeInfo = getCompleteTypeInfo();
ListMultimap<DataFlowValue, JetType> otherTypeInfo = other.getCompleteTypeInfo(); SetMultimap<DataFlowValue, JetType> otherTypeInfo = other.getCompleteTypeInfo();
ListMultimap<DataFlowValue, JetType> newTypeInfo = newTypeInfo(); SetMultimap<DataFlowValue, JetType> newTypeInfo = newTypeInfo();
Set<DataFlowValue> keys = Sets.newHashSet(myTypeInfo.keySet()); for (DataFlowValue key : Sets.intersection(myTypeInfo.keySet(), otherTypeInfo.keySet())) {
keys.retainAll(otherTypeInfo.keySet()); Set<JetType> thisTypes = myTypeInfo.get(key);
Set<JetType> otherTypes = otherTypeInfo.get(key);
for (DataFlowValue key : keys) { newTypeInfo.putAll(key, Sets.intersection(thisTypes, otherTypes));
Collection<JetType> thisTypes = myTypeInfo.get(key);
Collection<JetType> otherTypes = otherTypeInfo.get(key);
Collection<JetType> newTypes = Sets.newHashSet(thisTypes);
newTypes.retainAll(otherTypes);
newTypeInfo.putAll(key, newTypes);
} }
if (nullabilityMapBuilder.isEmpty() && newTypeInfo.isEmpty()) { if (nullabilityMapBuilder.isEmpty() && newTypeInfo.isEmpty()) {
@@ -243,8 +225,9 @@ import static org.jetbrains.jet.lang.resolve.calls.autocasts.Nullability.NOT_NUL
} }
@NotNull @NotNull
/* package */ static ListMultimap<DataFlowValue, JetType> newTypeInfo() { /* package */ static SetMultimap<DataFlowValue, JetType> newTypeInfo() {
return Multimaps.newListMultimap(Maps.<DataFlowValue, Collection<JetType>>newHashMap(), CommonSuppliers.<JetType>getArrayListSupplier()); return Multimaps.newSetMultimap(Maps.<DataFlowValue, Collection<JetType>>newHashMap(),
CommonSuppliers.<JetType>getLinkedHashSetSupplier());
} }
@Override @Override
@@ -1,18 +1,30 @@
fun foo(x: Number) { fun noUselessDataFlowInfoCreation(x: Number) {
if (x is Int) { if (x is Int) { if (x is Int) { if (x is Int) { if (x is Int) { if (x is Int) {
if (x is Int) { if (x is Int) { if (x is Int) { if (x is Int) { if (x is Int) { if (x is Int) {
if (x is Int) { if (x is Int) { if (x is Int) { if (x is Int) { if (x is Int) { if (x is Int) {
if (x is Int) { if (x is Int) { if (x is Int) { if (x is Int) { if (x is Int) { if (x is Int) {
if (x is Int) { if (x is Int) { if (x is Int) { if (x is Int) { if (x is Int) { if (x is Int) {
if (x is Int) { } } } } } } } } } } } } } } } } } } } } } } } } }
if (x is Int) { }
if (x is Int) {
if (x is Int) { fun dataFlowInfoAnd(a: Array<Number>) {
if (x is Int) { if (a[0] is Int) { if (a[1] is Int) { if (a[2] is Int) { if (a[3] is Int) { if (a[4] is Int) {
if (x is Int) { if (a[5] is Int) { if (a[6] is Int) { if (a[7] is Int) { if (a[8] is Int) { if (a[9] is Int) {
if (x is Int) { if (a[10] is Int) { if (a[11] is Int) { if (a[12] is Int) { if (a[13] is Int) { if (a[14] is Int) {
if (x is Int) { if (a[15] is Int) { if (a[16] is Int) { if (a[17] is Int) { if (a[18] is Int) { if (a[19] is Int) {
if (x is Int) { if (a[20] is Int) { if (a[21] is Int) { if (a[22] is Int) { if (a[23] is Int) { if (a[24] is Int) {
if (x is Int) { if (a[25] is Int) { if (a[26] is Int) { if (a[27] is Int) { if (a[28] is Int) { if (a[29] is Int) {
} } } } } } } } } } } } } } } <!TYPE_MISMATCH!>a[0]<!> : Int
} } } } } } } } } } } } } } } } } } } } } } } } } } } } } }
}
fun dataFlowInfoOr(a: Array<Number>) {
if (a[0] is Int || a[1] is Int || a[2] is Int || a[3] is Int || a[4] is Int || a[5] is Int || a[6] is Int || a[7] is Int || a[8] is Int || a[9] is Int ||
a[10] is Int || a[11] is Int || a[12] is Int || a[13] is Int || a[14] is Int || a[15] is Int || a[16] is Int || a[17] is Int || a[18] is Int || a[19] is Int ||
a[20] is Int || a[21] is Int || a[22] is Int || a[23] is Int || a[24] is Int || a[25] is Int || a[26] is Int || a[27] is Int || a[28] is Int || a[29] is Int ||
a[30] is Int || a[31] is Int || a[32] is Int || a[33] is Int || a[34] is Int || a[35] is Int || a[36] is Int || a[37] is Int || a[38] is Int || a[39] is Int ||
a[40] is Int || a[41] is Int || a[42] is Int || a[43] is Int || a[44] is Int || a[45] is Int || a[46] is Int || a[47] is Int || a[48] is Int || a[49] is Int ||
a[50] is Int || a[51] is Int || a[52] is Int || a[53] is Int || a[54] is Int || a[55] is Int || a[56] is Int || a[57] is Int || a[58] is Int || a[59] is Int) {
<!TYPE_MISMATCH!>a[0]<!> : Int
}
} }