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;
|
||||
DataFlowValue receiverDataFlowValue = null;
|
||||
if (receiver instanceof ReceiverValue) {
|
||||
DataFlowValue receiverDataFlowValue = DataFlowValueFactory.createDataFlowValue((ReceiverValue) receiver, context);
|
||||
receiverDataFlowValue = DataFlowValueFactory.createDataFlowValue((ReceiverValue) receiver, context);
|
||||
// Additional "receiver != null" information
|
||||
// Should be applied if we consider a safe call
|
||||
if (element.getSafe()) {
|
||||
@@ -467,7 +468,8 @@ public class CallExpressionResolver {
|
||||
checkNestedClassAccess(element.getQualified(), contextForSelector);
|
||||
|
||||
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);
|
||||
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.ConstraintPositionKind.RECEIVER_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.INCOMPLETE_TYPE_INFERENCE
|
||||
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] }
|
||||
builder.registerTypeVariables(nestedCall.call.toHandle(), freshVariables, external = true)
|
||||
// Looks not too nice, but safe call result must be nullable if receiver is nullable
|
||||
val argumentExpressionType = candidateWithFreshVariables.returnType?.let {
|
||||
if (nestedCall.isSafeCall && nestedCall.getExplicitReceiverValue()?.type?.let {TypeUtils.isNullableType(it) } ?: true ) {
|
||||
TypeUtils.makeNullable(it)
|
||||
}
|
||||
else it
|
||||
}
|
||||
// Safe call result must be nullable if receiver is nullable
|
||||
val argumentExpressionType = nestedCall.makeNullableTypeIfSafeReceiver(candidateWithFreshVariables.returnType, context)
|
||||
|
||||
builder.addSubtypeConstraint(
|
||||
argumentExpressionType,
|
||||
|
||||
@@ -26,6 +26,10 @@ fun foo(l: A<String>?) {
|
||||
// No errors should be here
|
||||
foo(l?.bar()) 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>) {
|
||||
|
||||
Reference in New Issue
Block a user