From 0f7284f83a903c8260347fa8cc460d1f4484b506 Mon Sep 17 00:00:00 2001 From: Mikhail Glukhikh Date: Fri, 12 Feb 2016 13:21:10 +0300 Subject: [PATCH] More accurate safe call handling in GenericCandidateResolver / CallExpressionResolver (real receiver nullability is taken into account) --- .../kotlin/resolve/calls/CallExpressionResolver.java | 6 ++++-- .../kotlin/resolve/calls/GenericCandidateResolver.kt | 11 +++-------- .../testData/diagnostics/tests/generics/kt9985.kt | 4 ++++ 3 files changed, 11 insertions(+), 10 deletions(-) diff --git a/compiler/frontend/src/org/jetbrains/kotlin/resolve/calls/CallExpressionResolver.java b/compiler/frontend/src/org/jetbrains/kotlin/resolve/calls/CallExpressionResolver.java index 1ad9d177f59..fbf65d1d086 100644 --- a/compiler/frontend/src/org/jetbrains/kotlin/resolve/calls/CallExpressionResolver.java +++ b/compiler/frontend/src/org/jetbrains/kotlin/resolve/calls/CallExpressionResolver.java @@ -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); } diff --git a/compiler/frontend/src/org/jetbrains/kotlin/resolve/calls/GenericCandidateResolver.kt b/compiler/frontend/src/org/jetbrains/kotlin/resolve/calls/GenericCandidateResolver.kt index 1a89b9fe151..3c2a2ba48a9 100644 --- a/compiler/frontend/src/org/jetbrains/kotlin/resolve/calls/GenericCandidateResolver.kt +++ b/compiler/frontend/src/org/jetbrains/kotlin/resolve/calls/GenericCandidateResolver.kt @@ -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, diff --git a/compiler/testData/diagnostics/tests/generics/kt9985.kt b/compiler/testData/diagnostics/tests/generics/kt9985.kt index db1b604f0f3..f648b646555 100644 --- a/compiler/testData/diagnostics/tests/generics/kt9985.kt +++ b/compiler/testData/diagnostics/tests/generics/kt9985.kt @@ -26,6 +26,10 @@ fun foo(l: A?) { // No errors should be here foo(l?.bar()) checkType { _() } foo(l?.gav()) checkType { _() } + if (l != null) { + foo(l?.bar()) checkType { _() } + foo(l?.gav()) checkType { _() } + } } fun fooNotNull(l: A) {