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:
@@ -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()) {
|
||||
|
||||
+34
@@ -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;
|
||||
}
|
||||
}
|
||||
|
||||
+7
@@ -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");
|
||||
|
||||
Reference in New Issue
Block a user