From 83d56213cde0147f6b6fc854ccc1c1c8c9946e8d Mon Sep 17 00:00:00 2001 From: Alexander Udalov Date: Wed, 14 Nov 2012 19:50:07 +0400 Subject: [PATCH] Separate DataFlowInfo into interface & implementation --- .../resolve/calls/autocasts/DataFlowInfo.java | 171 ++------------- .../calls/autocasts/DataFlowInfoImpl.java | 202 ++++++++++++++++++ 2 files changed, 222 insertions(+), 151 deletions(-) create mode 100644 compiler/frontend/src/org/jetbrains/jet/lang/resolve/calls/autocasts/DataFlowInfoImpl.java diff --git a/compiler/frontend/src/org/jetbrains/jet/lang/resolve/calls/autocasts/DataFlowInfo.java b/compiler/frontend/src/org/jetbrains/jet/lang/resolve/calls/autocasts/DataFlowInfo.java index d05e25904ae..888928f21b9 100644 --- a/compiler/frontend/src/org/jetbrains/jet/lang/resolve/calls/autocasts/DataFlowInfo.java +++ b/compiler/frontend/src/org/jetbrains/jet/lang/resolve/calls/autocasts/DataFlowInfo.java @@ -16,173 +16,42 @@ package org.jetbrains.jet.lang.resolve.calls.autocasts; -import com.google.common.collect.*; +import com.google.common.collect.ImmutableMap; +import com.google.common.collect.Multimaps; import org.jetbrains.annotations.NotNull; import org.jetbrains.jet.lang.types.JetType; -import org.jetbrains.jet.lang.types.TypeUtils; import org.jetbrains.jet.util.CommonSuppliers; -import java.util.*; +import java.util.Collection; +import java.util.Collections; +import java.util.List; -import static org.jetbrains.jet.lang.resolve.calls.autocasts.Nullability.NOT_NULL; - -public class DataFlowInfo { - public static DataFlowInfo EMPTY = new DataFlowInfo( +public interface DataFlowInfo { + public static final DataFlowInfo EMPTY = new DataFlowInfoImpl( ImmutableMap.of(), - Multimaps.newListMultimap(Collections.>emptyMap(), CommonSuppliers.getArrayListSupplier())); - - private final ImmutableMap nullabilityInfo; - /** Also immutable */ - private final ListMultimap typeInfo; - - private DataFlowInfo(ImmutableMap nullabilityInfo, ListMultimap typeInfo) { - this.nullabilityInfo = nullabilityInfo; - this.typeInfo = typeInfo; - } + Multimaps.newListMultimap(Collections.>emptyMap(), + CommonSuppliers.getArrayListSupplier())); @NotNull - public Nullability getNullability(@NotNull DataFlowValue a) { - if (!a.isStableIdentifier()) return a.getImmanentNullability(); - Nullability nullability = nullabilityInfo.get(a); - if (nullability == null) { - nullability = a.getImmanentNullability(); - } - return nullability; - } - - private boolean putNullability(@NotNull Map map, @NotNull DataFlowValue value, @NotNull Nullability nullability) { - if (!value.isStableIdentifier()) return false; - return map.put(value, nullability) != nullability; - } + Nullability getNullability(@NotNull DataFlowValue key); @NotNull - public List getPossibleTypes(DataFlowValue key) { - JetType originalType = key.getType(); - List types = typeInfo.get(key); - Nullability nullability = getNullability(key); - if (nullability.canBeNull()) { - return types; - } - List enrichedTypes = Lists.newArrayListWithCapacity(types.size()); - if (originalType.isNullable()) { - enrichedTypes.add(TypeUtils.makeNotNullable(originalType)); - } - for (JetType type: types) { - if (type.isNullable()) { - enrichedTypes.add(TypeUtils.makeNotNullable(type)); - } - else { - enrichedTypes.add(type); - } - } - return enrichedTypes; - } + List getPossibleTypes(@NotNull DataFlowValue key); @NotNull - public DataFlowInfo equate(@NotNull DataFlowValue a, @NotNull DataFlowValue b) { - Map builder = Maps.newHashMap(nullabilityInfo); - Nullability nullabilityOfA = getNullability(a); - Nullability nullabilityOfB = getNullability(b); - - boolean changed = false; - changed |= putNullability(builder, a, nullabilityOfA.refine(nullabilityOfB)); - changed |= putNullability(builder, b, nullabilityOfB.refine(nullabilityOfA)); - return changed ? new DataFlowInfo(ImmutableMap.copyOf(builder), typeInfo) : this; - } + DataFlowInfo equate(@NotNull DataFlowValue a, @NotNull DataFlowValue b); @NotNull - public DataFlowInfo disequate(@NotNull DataFlowValue a, @NotNull DataFlowValue b) { - Map builder = Maps.newHashMap(nullabilityInfo); - Nullability nullabilityOfA = getNullability(a); - Nullability nullabilityOfB = getNullability(b); - - boolean changed = false; - changed |= putNullability(builder, a, nullabilityOfA.refine(nullabilityOfB.invert())); - changed |= putNullability(builder, b, nullabilityOfB.refine(nullabilityOfA.invert())); - return changed ? new DataFlowInfo(ImmutableMap.copyOf(builder), typeInfo) : this; - } + DataFlowInfo disequate(@NotNull DataFlowValue a, @NotNull DataFlowValue b); @NotNull - public DataFlowInfo establishSubtyping(@NotNull DataFlowValue[] values, @NotNull JetType type) { - ListMultimap newTypeInfo = copyTypeInfo(); - Map newNullabilityInfo = Maps.newHashMap(nullabilityInfo); - boolean changed = false; - for (DataFlowValue value : values) { -// if (!value.isStableIdentifier()) continue; - changed = true; - newTypeInfo.put(value, type); - if (!type.isNullable()) { - putNullability(newNullabilityInfo, value, NOT_NULL); - } - } - if (!changed) return this; - return new DataFlowInfo(ImmutableMap.copyOf(newNullabilityInfo), newTypeInfo); - } + DataFlowInfo establishSubtyping(@NotNull DataFlowValue[] values, @NotNull JetType type); - private ListMultimap copyTypeInfo() { - ListMultimap newTypeInfo = Multimaps.newListMultimap(Maps.>newHashMap(), CommonSuppliers.getArrayListSupplier()); - newTypeInfo.putAll(typeInfo); - return newTypeInfo; - } + @NotNull + DataFlowInfo and(@NotNull DataFlowInfo other); - public DataFlowInfo and(DataFlowInfo other) { - Map nullabilityMapBuilder = Maps.newHashMap(); - nullabilityMapBuilder.putAll(nullabilityInfo); - for (Map.Entry entry : other.nullabilityInfo.entrySet()) { - DataFlowValue key = entry.getKey(); - Nullability otherFlags = entry.getValue(); - Nullability thisFlags = nullabilityInfo.get(key); - if (thisFlags != null) { - nullabilityMapBuilder.put(key, thisFlags.and(otherFlags)); - } - else { - nullabilityMapBuilder.put(key, otherFlags); - } - } + @NotNull + DataFlowInfo or(@NotNull DataFlowInfo other); - ListMultimap newTypeInfo = copyTypeInfo(); - newTypeInfo.putAll(other.typeInfo); - return new DataFlowInfo(ImmutableMap.copyOf(nullabilityMapBuilder), newTypeInfo); - } - - public DataFlowInfo or(DataFlowInfo other) { - Map builder = Maps.newHashMap(nullabilityInfo); - builder.keySet().retainAll(other.nullabilityInfo.keySet()); - for (Map.Entry entry : builder.entrySet()) { - DataFlowValue key = entry.getKey(); - Nullability thisFlags = entry.getValue(); - Nullability otherFlags = other.nullabilityInfo.get(key); - assert (otherFlags != null); - builder.put(key, thisFlags.or(otherFlags)); - } - - ListMultimap newTypeInfo = Multimaps.newListMultimap(Maps.>newHashMap(), CommonSuppliers.getArrayListSupplier()); - - Set keys = Sets.newHashSet(typeInfo.keySet()); - keys.retainAll(other.typeInfo.keySet()); - - for (DataFlowValue key : keys) { - Collection thisTypes = typeInfo.get(key); - Collection otherTypes = other.typeInfo.get(key); - - Collection newTypes = Sets.newHashSet(thisTypes); - newTypes.retainAll(otherTypes); - - newTypeInfo.putAll(key, newTypes); - } - - return new DataFlowInfo(ImmutableMap.copyOf(builder), newTypeInfo); - } - - public boolean hasTypeInfoConstraints() { - return !typeInfo.isEmpty(); - } - - @Override - public String toString() { - if (typeInfo.isEmpty() && nullabilityInfo.isEmpty()) { - return "EMPTY"; - } - return "Non-trivial DataFlowInfo"; - } -} \ No newline at end of file + boolean hasTypeInfoConstraints(); +} diff --git a/compiler/frontend/src/org/jetbrains/jet/lang/resolve/calls/autocasts/DataFlowInfoImpl.java b/compiler/frontend/src/org/jetbrains/jet/lang/resolve/calls/autocasts/DataFlowInfoImpl.java new file mode 100644 index 00000000000..392f7dad6ef --- /dev/null +++ b/compiler/frontend/src/org/jetbrains/jet/lang/resolve/calls/autocasts/DataFlowInfoImpl.java @@ -0,0 +1,202 @@ +/* + * 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.lang.resolve.calls.autocasts; + +import com.google.common.collect.*; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.jet.lang.types.JetType; +import org.jetbrains.jet.lang.types.TypeUtils; +import org.jetbrains.jet.util.CommonSuppliers; + +import java.util.Collection; +import java.util.List; +import java.util.Map; +import java.util.Set; + +import static org.jetbrains.jet.lang.resolve.calls.autocasts.Nullability.NOT_NULL; + +public class DataFlowInfoImpl implements DataFlowInfo { + private final ImmutableMap nullabilityInfo; + /** Also immutable */ + private final ListMultimap typeInfo; + + /* package */ DataFlowInfoImpl( + @NotNull ImmutableMap nullabilityInfo, + @NotNull ListMultimap typeInfo + ) { + this.nullabilityInfo = nullabilityInfo; + this.typeInfo = typeInfo; + } + + @Override + @NotNull + public Nullability getNullability(@NotNull DataFlowValue key) { + if (!key.isStableIdentifier()) return key.getImmanentNullability(); + Nullability nullability = nullabilityInfo.get(key); + if (nullability == null) { + nullability = key.getImmanentNullability(); + } + return nullability; + } + + private boolean putNullability(@NotNull Map map, @NotNull DataFlowValue value, @NotNull Nullability nullability) { + if (!value.isStableIdentifier()) return false; + return map.put(value, nullability) != nullability; + } + + @Override + @NotNull + public List getPossibleTypes(@NotNull DataFlowValue key) { + JetType originalType = key.getType(); + List types = typeInfo.get(key); + Nullability nullability = getNullability(key); + if (nullability.canBeNull()) { + return types; + } + List enrichedTypes = Lists.newArrayListWithCapacity(types.size()); + if (originalType.isNullable()) { + enrichedTypes.add(TypeUtils.makeNotNullable(originalType)); + } + for (JetType type: types) { + if (type.isNullable()) { + enrichedTypes.add(TypeUtils.makeNotNullable(type)); + } + else { + enrichedTypes.add(type); + } + } + return enrichedTypes; + } + + @Override + @NotNull + public DataFlowInfo equate(@NotNull DataFlowValue a, @NotNull DataFlowValue b) { + Map builder = Maps.newHashMap(nullabilityInfo); + Nullability nullabilityOfA = getNullability(a); + Nullability nullabilityOfB = getNullability(b); + + boolean changed = false; + changed |= putNullability(builder, a, nullabilityOfA.refine(nullabilityOfB)); + changed |= putNullability(builder, b, nullabilityOfB.refine(nullabilityOfA)); + return changed ? new DataFlowInfoImpl(ImmutableMap.copyOf(builder), typeInfo) : this; + } + + @Override + @NotNull + public DataFlowInfo disequate(@NotNull DataFlowValue a, @NotNull DataFlowValue b) { + Map builder = Maps.newHashMap(nullabilityInfo); + Nullability nullabilityOfA = getNullability(a); + Nullability nullabilityOfB = getNullability(b); + + boolean changed = false; + changed |= putNullability(builder, a, nullabilityOfA.refine(nullabilityOfB.invert())); + changed |= putNullability(builder, b, nullabilityOfB.refine(nullabilityOfA.invert())); + return changed ? new DataFlowInfoImpl(ImmutableMap.copyOf(builder), typeInfo) : this; + } + + @Override + @NotNull + public DataFlowInfo establishSubtyping(@NotNull DataFlowValue[] values, @NotNull JetType type) { + ListMultimap newTypeInfo = copyTypeInfo(); + Map newNullabilityInfo = Maps.newHashMap(nullabilityInfo); + boolean changed = false; + for (DataFlowValue value : values) { +// if (!value.isStableIdentifier()) continue; + changed = true; + newTypeInfo.put(value, type); + if (!type.isNullable()) { + putNullability(newNullabilityInfo, value, NOT_NULL); + } + } + if (!changed) return this; + return new DataFlowInfoImpl(ImmutableMap.copyOf(newNullabilityInfo), newTypeInfo); + } + + private ListMultimap copyTypeInfo() { + ListMultimap newTypeInfo = Multimaps.newListMultimap(Maps.>newHashMap(), CommonSuppliers.getArrayListSupplier()); + newTypeInfo.putAll(typeInfo); + return newTypeInfo; + } + + @NotNull + @Override + public DataFlowInfo and(@NotNull DataFlowInfo otherInfo) { + DataFlowInfoImpl other = (DataFlowInfoImpl) otherInfo; + Map nullabilityMapBuilder = Maps.newHashMap(); + nullabilityMapBuilder.putAll(nullabilityInfo); + for (Map.Entry entry : other.nullabilityInfo.entrySet()) { + DataFlowValue key = entry.getKey(); + Nullability otherFlags = entry.getValue(); + Nullability thisFlags = nullabilityInfo.get(key); + if (thisFlags != null) { + nullabilityMapBuilder.put(key, thisFlags.and(otherFlags)); + } + else { + nullabilityMapBuilder.put(key, otherFlags); + } + } + + ListMultimap newTypeInfo = copyTypeInfo(); + newTypeInfo.putAll(other.typeInfo); + return new DataFlowInfoImpl(ImmutableMap.copyOf(nullabilityMapBuilder), newTypeInfo); + } + + @NotNull + @Override + public DataFlowInfo or(@NotNull DataFlowInfo otherInfo) { + DataFlowInfoImpl other = (DataFlowInfoImpl) otherInfo; + Map builder = Maps.newHashMap(nullabilityInfo); + builder.keySet().retainAll(other.nullabilityInfo.keySet()); + for (Map.Entry entry : builder.entrySet()) { + DataFlowValue key = entry.getKey(); + Nullability thisFlags = entry.getValue(); + Nullability otherFlags = other.nullabilityInfo.get(key); + assert (otherFlags != null); + builder.put(key, thisFlags.or(otherFlags)); + } + + ListMultimap newTypeInfo = Multimaps.newListMultimap(Maps.>newHashMap(), CommonSuppliers.getArrayListSupplier()); + + Set keys = Sets.newHashSet(typeInfo.keySet()); + keys.retainAll(other.typeInfo.keySet()); + + for (DataFlowValue key : keys) { + Collection thisTypes = typeInfo.get(key); + Collection otherTypes = other.typeInfo.get(key); + + Collection newTypes = Sets.newHashSet(thisTypes); + newTypes.retainAll(otherTypes); + + newTypeInfo.putAll(key, newTypes); + } + + return new DataFlowInfoImpl(ImmutableMap.copyOf(builder), newTypeInfo); + } + + @Override + public boolean hasTypeInfoConstraints() { + return !typeInfo.isEmpty(); + } + + @Override + public String toString() { + if (typeInfo.isEmpty() && nullabilityInfo.isEmpty()) { + return "EMPTY"; + } + return "Non-trivial DataFlowInfo"; + } +} \ No newline at end of file