Check separately auto casts for nullable types.

It's necessary for functions with generics: constraint system ignores nullability divergence,
the error checks are made afterwards, the auto cast check should be made similarly.
This commit is contained in:
Svetlana Isakova
2013-12-09 14:17:36 +04:00
parent f271cb3609
commit 4b89c22ba7
4 changed files with 54 additions and 3 deletions
@@ -892,9 +892,14 @@ public class CandidateResolver {
BindingContext bindingContext = trace.getBindingContext();
boolean safeAccess = isExplicitReceiver && !implicitInvokeCheck && candidateCall.isSafeCall();
if (!safeAccess && !receiverParameter.getType().isNullable() && receiverArgument.getType().isNullable()) {
if (!AutoCastUtils.isNotNull(receiverArgument, bindingContext, context.dataFlowInfo)) {
context.tracing.unsafeCall(trace, receiverArgumentType, implicitInvokeCheck);
return UNSAFE_CALL_ERROR;
context.tracing.unsafeCall(trace, receiverArgumentType, implicitInvokeCheck);
return UNSAFE_CALL_ERROR;
}
if (isExplicitReceiver) {
AutoCastUtils.recordAutoCastToNotNullableType(receiverArgument, context.trace);
}
}
DataFlowValue receiverValue = DataFlowValueFactory.createDataFlowValue(receiverArgument, bindingContext);
if (safeAccess && !context.dataFlowInfo.getNullability(receiverValue).canBeNull()) {
@@ -18,6 +18,7 @@ package org.jetbrains.jet.lang.resolve.calls.autocasts;
import com.google.common.collect.Lists;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.jet.lang.psi.JetExpression;
import org.jetbrains.jet.lang.resolve.BindingContext;
import org.jetbrains.jet.lang.resolve.BindingTrace;
import org.jetbrains.jet.lang.resolve.calls.context.ResolutionContext;
@@ -25,6 +26,7 @@ import org.jetbrains.jet.lang.resolve.scopes.receivers.ExpressionReceiver;
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 java.util.ArrayList;
import java.util.Collections;
@@ -117,4 +119,36 @@ public class AutoCastUtils {
}
}
}
public static void recordAutoCastToNotNullableType(@NotNull ReceiverValue receiver, @NotNull BindingTrace trace) {
if (!(receiver instanceof ExpressionReceiver)) return;
JetType receiverType = receiver.getType();
if (!receiverType.isNullable()) return;
JetType notNullableType = TypeUtils.makeNotNullable(receiverType);
DataFlowValue dataFlowValue = DataFlowValueFactory.createDataFlowValue(receiver, trace.getBindingContext());
JetExpression expression = ((ExpressionReceiver) receiver).getExpression();
if (dataFlowValue.isStableIdentifier()) {
trace.record(AUTOCAST, expression, notNullableType);
trace.record(EXPRESSION_TYPE, expression, notNullableType);
}
else {
trace.report(AUTOCAST_IMPOSSIBLE.on(expression, notNullableType, expression.getText()));
}
}
public static boolean isNotNull(
@NotNull ReceiverValue receiver,
@NotNull BindingContext bindingContext,
@NotNull DataFlowInfo dataFlowInfo
) {
if (!receiver.getType().isNullable()) return true;
List<ReceiverValue> autoCastVariants = getAutoCastVariants(receiver, bindingContext, dataFlowInfo);
for (ReceiverValue autoCastVariant : autoCastVariants) {
if (!autoCastVariant.getType().isNullable()) return true;
}
return false;
}
}
@@ -0,0 +1,7 @@
fun test(a: Any?) {
if (a != null) {
<!DEBUG_INFO_AUTOCAST!>a<!>.foo(11)
}
}
fun <T> Any.foo(t: T) = t
@@ -4702,6 +4702,11 @@ public class JetDiagnosticsTestGenerated extends AbstractDiagnosticsTestWithEage
doTest("compiler/testData/diagnostics/tests/nullabilityAndAutoCasts/senslessComparisonWithNullOnTypeParameters.kt");
}
@TestMetadata("smartCastedReceiverWithGenerics.kt")
public void testSmartCastedReceiverWithGenerics() throws Exception {
doTest("compiler/testData/diagnostics/tests/nullabilityAndAutoCasts/smartCastedReceiverWithGenerics.kt");
}
}
@TestMetadata("compiler/testData/diagnostics/tests/nullableTypes")
@@ -6182,7 +6187,7 @@ public class JetDiagnosticsTestGenerated extends AbstractDiagnosticsTestWithEage
public void testPublicVal() throws Exception {
doTest("compiler/testData/diagnostics/tests/smartCasts/publicVal.kt");
}
@TestMetadata("thisWithLabel.kt")
public void testThisWithLabel() throws Exception {
doTest("compiler/testData/diagnostics/tests/smartCasts/thisWithLabel.kt");