More accurate safe call handling in GenericCandidateResolver / CallExpressionResolver
(real receiver nullability is taken into account)
This commit is contained in:
committed by
Mikhail Glukhikh
parent
17593e4ef6
commit
0f7284f83a
+4
-2
@@ -441,8 +441,9 @@ public class CallExpressionResolver {
|
|||||||
}
|
}
|
||||||
|
|
||||||
DataFlowInfo initialDataFlowInfoForArguments = contextForSelector.dataFlowInfo;
|
DataFlowInfo initialDataFlowInfoForArguments = contextForSelector.dataFlowInfo;
|
||||||
|
DataFlowValue receiverDataFlowValue = null;
|
||||||
if (receiver instanceof ReceiverValue) {
|
if (receiver instanceof ReceiverValue) {
|
||||||
DataFlowValue receiverDataFlowValue = DataFlowValueFactory.createDataFlowValue((ReceiverValue) receiver, context);
|
receiverDataFlowValue = DataFlowValueFactory.createDataFlowValue((ReceiverValue) receiver, context);
|
||||||
// Additional "receiver != null" information
|
// Additional "receiver != null" information
|
||||||
// Should be applied if we consider a safe call
|
// Should be applied if we consider a safe call
|
||||||
if (element.getSafe()) {
|
if (element.getSafe()) {
|
||||||
@@ -467,7 +468,8 @@ public class CallExpressionResolver {
|
|||||||
checkNestedClassAccess(element.getQualified(), contextForSelector);
|
checkNestedClassAccess(element.getQualified(), contextForSelector);
|
||||||
|
|
||||||
boolean safeCall = element.getSafe();
|
boolean safeCall = element.getSafe();
|
||||||
if (safeCall && selectorReturnType != null && TypeUtils.isNullableType(receiverType)) {
|
if (safeCall && selectorReturnType != null && receiverDataFlowValue != null &&
|
||||||
|
contextForSelector.dataFlowInfo.getPredictableNullability(receiverDataFlowValue).canBeNull()) {
|
||||||
selectorReturnType = TypeUtils.makeNullable(selectorReturnType);
|
selectorReturnType = TypeUtils.makeNullable(selectorReturnType);
|
||||||
selectorReturnTypeInfo = selectorReturnTypeInfo.replaceType(selectorReturnType);
|
selectorReturnTypeInfo = selectorReturnTypeInfo.replaceType(selectorReturnType);
|
||||||
}
|
}
|
||||||
|
|||||||
+3
-8
@@ -36,7 +36,7 @@ import org.jetbrains.kotlin.resolve.calls.inference.*
|
|||||||
import org.jetbrains.kotlin.resolve.calls.inference.constraintPosition.ConstraintPosition
|
import org.jetbrains.kotlin.resolve.calls.inference.constraintPosition.ConstraintPosition
|
||||||
import org.jetbrains.kotlin.resolve.calls.inference.constraintPosition.ConstraintPositionKind.RECEIVER_POSITION
|
import org.jetbrains.kotlin.resolve.calls.inference.constraintPosition.ConstraintPositionKind.RECEIVER_POSITION
|
||||||
import org.jetbrains.kotlin.resolve.calls.inference.constraintPosition.ConstraintPositionKind.VALUE_PARAMETER_POSITION
|
import org.jetbrains.kotlin.resolve.calls.inference.constraintPosition.ConstraintPositionKind.VALUE_PARAMETER_POSITION
|
||||||
import org.jetbrains.kotlin.resolve.calls.resolvedCallUtil.getExplicitReceiverValue
|
import org.jetbrains.kotlin.resolve.calls.resolvedCallUtil.makeNullableTypeIfSafeReceiver
|
||||||
import org.jetbrains.kotlin.resolve.calls.results.ResolutionStatus
|
import org.jetbrains.kotlin.resolve.calls.results.ResolutionStatus
|
||||||
import org.jetbrains.kotlin.resolve.calls.results.ResolutionStatus.INCOMPLETE_TYPE_INFERENCE
|
import org.jetbrains.kotlin.resolve.calls.results.ResolutionStatus.INCOMPLETE_TYPE_INFERENCE
|
||||||
import org.jetbrains.kotlin.resolve.calls.results.ResolutionStatus.OTHER_ERROR
|
import org.jetbrains.kotlin.resolve.calls.results.ResolutionStatus.OTHER_ERROR
|
||||||
@@ -174,13 +174,8 @@ class GenericCandidateResolver(private val argumentTypeResolver: ArgumentTypeRes
|
|||||||
|
|
||||||
val freshVariables = returnType.getNestedTypeParameters().mapNotNull { conversion[it] }
|
val freshVariables = returnType.getNestedTypeParameters().mapNotNull { conversion[it] }
|
||||||
builder.registerTypeVariables(nestedCall.call.toHandle(), freshVariables, external = true)
|
builder.registerTypeVariables(nestedCall.call.toHandle(), freshVariables, external = true)
|
||||||
// Looks not too nice, but safe call result must be nullable if receiver is nullable
|
// Safe call result must be nullable if receiver is nullable
|
||||||
val argumentExpressionType = candidateWithFreshVariables.returnType?.let {
|
val argumentExpressionType = nestedCall.makeNullableTypeIfSafeReceiver(candidateWithFreshVariables.returnType, context)
|
||||||
if (nestedCall.isSafeCall && nestedCall.getExplicitReceiverValue()?.type?.let {TypeUtils.isNullableType(it) } ?: true ) {
|
|
||||||
TypeUtils.makeNullable(it)
|
|
||||||
}
|
|
||||||
else it
|
|
||||||
}
|
|
||||||
|
|
||||||
builder.addSubtypeConstraint(
|
builder.addSubtypeConstraint(
|
||||||
argumentExpressionType,
|
argumentExpressionType,
|
||||||
|
|||||||
@@ -26,6 +26,10 @@ fun foo(l: A<String>?) {
|
|||||||
// No errors should be here
|
// No errors should be here
|
||||||
foo(l?.bar()) checkType { _<String?>() }
|
foo(l?.bar()) checkType { _<String?>() }
|
||||||
foo(l?.gav()) checkType { _<String?>() }
|
foo(l?.gav()) checkType { _<String?>() }
|
||||||
|
if (l != null) {
|
||||||
|
foo(l<!UNNECESSARY_SAFE_CALL!>?.<!>bar()) checkType { _<String>() }
|
||||||
|
foo(l<!UNNECESSARY_SAFE_CALL!>?.<!>gav()) checkType { _<String>() }
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fun fooNotNull(l: A<String>) {
|
fun fooNotNull(l: A<String>) {
|
||||||
|
|||||||
Reference in New Issue
Block a user