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.jet.lang.types.JetType;
import java.util.List;
import java.util.Set;
public interface DataFlowInfo {
DataFlowInfo EMPTY = new DelegatingDataFlowInfo(null, ImmutableMap.<DataFlowValue, Nullability>of(),
@@ -30,7 +30,7 @@ public interface DataFlowInfo {
Nullability getNullability(@NotNull DataFlowValue key);
@NotNull
List<JetType> getPossibleTypes(@NotNull DataFlowValue key);
Set<JetType> getPossibleTypes(@NotNull DataFlowValue key);
@NotNull
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 */
@NotNull
private final ListMultimap<DataFlowValue, JetType> typeInfo;
private final SetMultimap<DataFlowValue, JetType> typeInfo;
private static final ImmutableMap<DataFlowValue,Nullability> EMPTY_NULLABILITY_INFO =
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(
@Nullable DataFlowInfo parent,
@NotNull ImmutableMap<DataFlowValue, Nullability> nullabilityInfo,
@NotNull ListMultimap<DataFlowValue, JetType> typeInfo
@NotNull SetMultimap<DataFlowValue, JetType> typeInfo
) {
this.parent = parent;
this.nullabilityInfo = nullabilityInfo;
@@ -70,8 +70,8 @@ import static org.jetbrains.jet.lang.resolve.calls.autocasts.Nullability.NOT_NUL
}
@NotNull
private ListMultimap<DataFlowValue, JetType> getCompleteTypeInfo() {
ListMultimap<DataFlowValue, JetType> result = newTypeInfo();
private SetMultimap<DataFlowValue, JetType> getCompleteTypeInfo() {
SetMultimap<DataFlowValue, JetType> result = newTypeInfo();
DelegatingDataFlowInfo info = this;
while (info != null) {
for (DataFlowValue key : info.typeInfo.keySet()) {
@@ -100,17 +100,13 @@ import static org.jetbrains.jet.lang.resolve.calls.autocasts.Nullability.NOT_NUL
@Override
@NotNull
public List<JetType> getPossibleTypes(@NotNull DataFlowValue key) {
List<JetType> types = typeInfo.get(key);
public Set<JetType> getPossibleTypes(@NotNull DataFlowValue key) {
Set<JetType> types = typeInfo.get(key);
if (getNullability(key).canBeNull()) {
if (parent != null) {
types = Lists.newArrayList(types);
addAllUnique(types, parent.getPossibleTypes(key));
}
return types;
return parent == null ? types : Sets.union(types, parent.getPossibleTypes(key));
}
List<JetType> enrichedTypes = Lists.newArrayListWithCapacity(types.size() + 1);
Set<JetType> enrichedTypes = Sets.newHashSetWithExpectedSize(types.size() + 1);
JetType originalType = key.getType();
if (originalType.isNullable()) {
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));
}
if (parent != null) {
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);
}
}
return parent == null ? enrichedTypes : Sets.union(enrichedTypes, parent.getPossibleTypes(key));
}
@Override
@@ -167,7 +151,7 @@ import static org.jetbrains.jet.lang.resolve.calls.autocasts.Nullability.NOT_NUL
if (getPossibleTypes(value).contains(type)) return this;
ImmutableMap<DataFlowValue, Nullability> newNullabilityInfo =
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);
}
@@ -192,12 +176,17 @@ import static org.jetbrains.jet.lang.resolve.calls.autocasts.Nullability.NOT_NUL
}
}
ListMultimap<DataFlowValue, JetType> newTypeInfo = other.getCompleteTypeInfo();
if (nullabilityMapBuilder.isEmpty() && newTypeInfo.isEmpty()) {
SetMultimap<DataFlowValue, JetType> myTypeInfo = getCompleteTypeInfo();
SetMultimap<DataFlowValue, JetType> otherTypeInfo = other.getCompleteTypeInfo();
if (nullabilityMapBuilder.isEmpty() && containsAll(myTypeInfo, otherTypeInfo)) {
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
@@ -218,21 +207,14 @@ import static org.jetbrains.jet.lang.resolve.calls.autocasts.Nullability.NOT_NUL
nullabilityMapBuilder.put(key, thisFlags.or(otherFlags));
}
ListMultimap<DataFlowValue, JetType> myTypeInfo = getCompleteTypeInfo();
ListMultimap<DataFlowValue, JetType> otherTypeInfo = other.getCompleteTypeInfo();
ListMultimap<DataFlowValue, JetType> newTypeInfo = newTypeInfo();
SetMultimap<DataFlowValue, JetType> myTypeInfo = getCompleteTypeInfo();
SetMultimap<DataFlowValue, JetType> otherTypeInfo = other.getCompleteTypeInfo();
SetMultimap<DataFlowValue, JetType> newTypeInfo = newTypeInfo();
Set<DataFlowValue> keys = Sets.newHashSet(myTypeInfo.keySet());
keys.retainAll(otherTypeInfo.keySet());
for (DataFlowValue key : keys) {
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);
for (DataFlowValue key : Sets.intersection(myTypeInfo.keySet(), otherTypeInfo.keySet())) {
Set<JetType> thisTypes = myTypeInfo.get(key);
Set<JetType> otherTypes = otherTypeInfo.get(key);
newTypeInfo.putAll(key, Sets.intersection(thisTypes, otherTypes));
}
if (nullabilityMapBuilder.isEmpty() && newTypeInfo.isEmpty()) {
@@ -243,8 +225,9 @@ import static org.jetbrains.jet.lang.resolve.calls.autocasts.Nullability.NOT_NUL
}
@NotNull
/* package */ static ListMultimap<DataFlowValue, JetType> newTypeInfo() {
return Multimaps.newListMultimap(Maps.<DataFlowValue, Collection<JetType>>newHashMap(), CommonSuppliers.<JetType>getArrayListSupplier());
/* package */ static SetMultimap<DataFlowValue, JetType> newTypeInfo() {
return Multimaps.newSetMultimap(Maps.<DataFlowValue, Collection<JetType>>newHashMap(),
CommonSuppliers.<JetType>getLinkedHashSetSupplier());
}
@Override
@@ -1,18 +1,30 @@
fun foo(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) {
} } } } } } } } } } } } } } }
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) {
} } } } } } } } } } } } } } } } } } } } } } } } }
}
fun dataFlowInfoAnd(a: Array<Number>) {
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 (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 (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 (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 (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 (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
}
}