record smartcast to the most specific type

This commit is contained in:
Svetlana Isakova
2014-01-31 12:55:30 +04:00
parent 9832676701
commit 9063b3803e
2 changed files with 29 additions and 17 deletions
@@ -17,7 +17,9 @@
package org.jetbrains.jet.lang.resolve.calls.autocasts;
import com.google.common.collect.Lists;
import com.google.common.collect.Sets;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import org.jetbrains.jet.lang.psi.JetExpression;
import org.jetbrains.jet.lang.resolve.BindingContext;
import org.jetbrains.jet.lang.resolve.BindingTrace;
@@ -28,9 +30,11 @@ import org.jetbrains.jet.lang.resolve.scopes.receivers.ReceiverValue;
import org.jetbrains.jet.lang.resolve.scopes.receivers.ThisReceiver;
import org.jetbrains.jet.lang.types.JetType;
import org.jetbrains.jet.lang.types.TypeUtils;
import org.jetbrains.jet.lang.types.checker.JetTypeChecker;
import java.util.Collections;
import java.util.List;
import java.util.Set;
import static org.jetbrains.jet.lang.diagnostics.Errors.AUTOCAST_IMPOSSIBLE;
import static org.jetbrains.jet.lang.resolve.BindingContext.AUTOCAST;
@@ -96,20 +100,28 @@ public class AutoCastUtils {
@NotNull ResolutionContext context
) {
List<JetType> autoCastTypes = getAutoCastVariants(receiverArgument, context);
return isSubTypeByAutoCast(receiverParameterType, autoCastTypes);
return getAutoCastSubType(receiverParameterType, autoCastTypes) != null;
}
private static boolean isSubTypeByAutoCast(
@Nullable
private static JetType getAutoCastSubType(
@NotNull JetType receiverParameterType,
@NotNull List<JetType> autoCastTypes
) {
Set<JetType> subTypes = Sets.newHashSet();
for (JetType autoCastType : autoCastTypes) {
JetType effectiveAutoCastType = TypeUtils.makeNotNullable(autoCastType);
if (ArgumentTypeResolver.isSubtypeOfForArgumentType(effectiveAutoCastType, receiverParameterType)) {
return true;
subTypes.add(autoCastType);
}
}
return false;
if (subTypes.isEmpty()) return null;
JetType intersection = TypeUtils.intersect(JetTypeChecker.INSTANCE, subTypes);
if (intersection == null || !intersection.getConstructor().isDenotable()) {
return receiverParameterType;
}
return intersection;
}
public static boolean recordAutoCastIfNecessary(
@@ -125,14 +137,14 @@ public class AutoCastUtils {
List<JetType> autoCastTypesExcludingReceiver = getAutoCastVariantsExcludingReceiver(
context.trace.getBindingContext(), context.dataFlowInfo, receiver);
boolean autoCast = isSubTypeByAutoCast(receiverType, autoCastTypesExcludingReceiver);
if (autoCast) {
JetExpression expression = ((ExpressionReceiver) receiver).getExpression();
DataFlowValue dataFlowValue = DataFlowValueFactory.createDataFlowValue(receiver, context.trace.getBindingContext());
JetType autoCastSubType = getAutoCastSubType(receiverType, autoCastTypesExcludingReceiver);
if (autoCastSubType == null) return false;
recordCastOrError(expression, receiverType, context.trace, dataFlowValue.isStableIdentifier(), true);
}
return autoCast;
JetExpression expression = ((ExpressionReceiver) receiver).getExpression();
DataFlowValue dataFlowValue = DataFlowValueFactory.createDataFlowValue(receiver, context.trace.getBindingContext());
recordCastOrError(expression, autoCastSubType, context.trace, dataFlowValue.isStableIdentifier(), true);
return true;
}
public static void recordAutoCastToNotNullableType(@NotNull ReceiverValue receiver, @NotNull BindingTrace trace) {
+6 -6
View File
@@ -11,7 +11,7 @@ fun f9(a : A?) {
a<info>?.</info><error descr="[UNRESOLVED_REFERENCE] Unresolved reference: bar">bar</error>()
if (a is B) {
<info descr="Automatically cast to B">a</info>.bar()
<info descr="Automatically cast to A">a</info>.foo()
<info descr="Automatically cast to B">a</info>.foo()
}
a<info>?.</info>foo()
a<info>?.</info><error descr="[UNRESOLVED_REFERENCE] Unresolved reference: bar">bar</error>()
@@ -26,7 +26,7 @@ fun f9(a : A?) {
return;
}
<info descr="Automatically cast to B">a</info>.bar()
<info descr="Automatically cast to A">a</info>.foo()
<info descr="Automatically cast to B">a</info>.foo()
}
fun f10(a : A?) {
@@ -80,7 +80,7 @@ fun f12(a : A?) {
fun f13(a : A?) {
if (a is B) {
<info descr="Automatically cast to A">a</info>.foo()
<info descr="Automatically cast to B">a</info>.foo()
<info descr="Automatically cast to B">a</info>.bar()
}
else {
@@ -93,12 +93,12 @@ fun f13(a : A?) {
a<info>?.</info>foo()
}
else {
<info descr="Automatically cast to A">a</info>.foo()
<info descr="Automatically cast to B">a</info>.foo()
}
a<info>?.</info>foo()
if (a is B && <info descr="Automatically cast to A">a</info>.foo() == Unit.VALUE) {
<info descr="Automatically cast to A">a</info>.foo()
if (a is B && <info descr="Automatically cast to B">a</info>.foo() == Unit.VALUE) {
<info descr="Automatically cast to B">a</info>.foo()
<info descr="Automatically cast to B">a</info>.bar()
}
else {