[NI] Reanalyze coroutine-block if there is inapplicable call
It's not clear how one should rollback _all_ resolution results if there is inapplicable call. Ideally, such calls should not be available in coroutine block but for now, to have backward compatibility, we'll just reanalyze coroutine block as a usual lambda if there is at least one such call. As a result, also remove diagnostic about non-applicable call as it become useless with current reanalysis #KT-37061 Fixed #KT-32097 Fixed #KT-32203 Fixed #KT-35306 Fixed #KT-36202 Fixed #KT-36220 Fixed #KT-32654 Fixed
This commit is contained in:
+20
-4
@@ -28,6 +28,7 @@ import org.jetbrains.kotlin.resolve.deprecation.DeprecationResolver
|
||||
import org.jetbrains.kotlin.types.*
|
||||
import org.jetbrains.kotlin.types.expressions.DoubleColonExpressionResolver
|
||||
import org.jetbrains.kotlin.types.expressions.ExpressionTypingServices
|
||||
import org.jetbrains.kotlin.types.typeUtil.contains
|
||||
import org.jetbrains.kotlin.utils.addToStdlib.cast
|
||||
|
||||
class CoroutineInferenceSession(
|
||||
@@ -52,6 +53,7 @@ class CoroutineInferenceSession(
|
||||
) {
|
||||
private val commonCalls = arrayListOf<PSICompletedCallInfo>()
|
||||
private val diagnostics = arrayListOf<KotlinCallDiagnostic>()
|
||||
private var hasInapplicableCall = false
|
||||
|
||||
override fun shouldRunCompletion(candidate: KotlinResolutionCandidate): Boolean {
|
||||
val system = candidate.getSystem() as NewConstraintSystemImpl
|
||||
@@ -78,26 +80,40 @@ class CoroutineInferenceSession(
|
||||
|
||||
commonCalls.add(callInfo)
|
||||
|
||||
val resultingDescriptor = callInfo.resolvedCall.resultingDescriptor
|
||||
|
||||
// This check is similar to one for old inference, see getCoroutineInferenceData() function
|
||||
val checkCall = resultingDescriptor is LocalVariableDescriptor || anyReceiverContainStubType(resultingDescriptor)
|
||||
|
||||
if (!checkCall) return
|
||||
|
||||
val isApplicableCall =
|
||||
callComponents.statelessCallbacks.isApplicableCallForBuilderInference(
|
||||
callInfo.resolvedCall.resultingDescriptor,
|
||||
resultingDescriptor,
|
||||
callComponents.languageVersionSettings
|
||||
)
|
||||
|
||||
if (!isApplicableCall) {
|
||||
diagnostics.add(NonApplicableCallForBuilderInferenceDiagnostic(callInfo.callResolutionResult.resultCallAtom.atom))
|
||||
hasInapplicableCall = true
|
||||
}
|
||||
}
|
||||
|
||||
private fun anyReceiverContainStubType(descriptor: CallableDescriptor): Boolean {
|
||||
return descriptor.dispatchReceiverParameter?.type?.contains { it is StubType } == true ||
|
||||
descriptor.extensionReceiverParameter?.type?.contains { it is StubType } == true
|
||||
}
|
||||
|
||||
fun hasInapplicableCall(): Boolean = hasInapplicableCall
|
||||
|
||||
override fun writeOnlyStubs(callInfo: SingleCallResolutionResult): Boolean {
|
||||
return !skipCall(callInfo)
|
||||
}
|
||||
|
||||
private fun skipCall(callInfo: SingleCallResolutionResult): Boolean {
|
||||
// FakeCallableDescriptorForObject and LocalVariableDescriptor can't introduce new information for inference,
|
||||
// FakeCallableDescriptorForObject can't introduce new information for inference,
|
||||
// so it's safe to complete it fully
|
||||
val descriptor = callInfo.resultCallAtom.candidateDescriptor
|
||||
return descriptor is FakeCallableDescriptorForObject || descriptor is LocalVariableDescriptor
|
||||
return descriptor is FakeCallableDescriptorForObject
|
||||
}
|
||||
|
||||
override fun currentConstraintSystem(): ConstraintStorage {
|
||||
|
||||
+16
-4
@@ -139,8 +139,6 @@ class KotlinResolutionCallbacksImpl(
|
||||
if (expectedReturnType == null) ContextDependency.DEPENDENT else ContextDependency.INDEPENDENT
|
||||
)
|
||||
|
||||
trace.record(BindingContext.NEW_INFERENCE_LAMBDA_INFO, psiCallArgument.ktFunction, lambdaInfo)
|
||||
|
||||
val builtIns = outerCallContext.scope.ownerDescriptor.builtIns
|
||||
|
||||
// We have to refine receiverType because resolve inside lambda needs proper scope from receiver,
|
||||
@@ -179,8 +177,16 @@ class KotlinResolutionCallbacksImpl(
|
||||
null
|
||||
}
|
||||
|
||||
|
||||
val temporaryTrace = if (coroutineSession != null)
|
||||
TemporaryBindingTrace.create(trace, "Trace to resolve coroutine $lambdaArgument")
|
||||
else
|
||||
null
|
||||
|
||||
(temporaryTrace ?: trace).record(BindingContext.NEW_INFERENCE_LAMBDA_INFO, psiCallArgument.ktFunction, lambdaInfo)
|
||||
|
||||
val actualContext = outerCallContext
|
||||
.replaceBindingTrace(trace)
|
||||
.replaceBindingTrace(temporaryTrace ?: trace)
|
||||
.replaceContextDependency(lambdaInfo.contextDependency)
|
||||
.replaceExpectedType(approximatesExpectedType)
|
||||
.replaceDataFlowInfo(psiCallArgument.dataFlowInfoBeforeThisArgument).let {
|
||||
@@ -188,7 +194,13 @@ class KotlinResolutionCallbacksImpl(
|
||||
}
|
||||
|
||||
val functionTypeInfo = expressionTypingServices.getTypeInfo(psiCallArgument.expression, actualContext)
|
||||
trace.record(BindingContext.NEW_INFERENCE_LAMBDA_INFO, psiCallArgument.ktFunction, LambdaInfo.STUB_EMPTY)
|
||||
(temporaryTrace ?: trace).record(BindingContext.NEW_INFERENCE_LAMBDA_INFO, psiCallArgument.ktFunction, LambdaInfo.STUB_EMPTY)
|
||||
|
||||
if (coroutineSession?.hasInapplicableCall() == true) {
|
||||
return ReturnArgumentsAnalysisResult(ReturnArgumentsInfo.empty, coroutineSession, hasInapplicableCallForBuilderInference = true)
|
||||
} else {
|
||||
temporaryTrace?.commit()
|
||||
}
|
||||
|
||||
var hasReturnWithoutExpression = false
|
||||
var returnArgumentFound = false
|
||||
|
||||
Reference in New Issue
Block a user