[NI] Fix recursion in contract declaration analysis.
#KT-30410 Fixed
This commit is contained in:
@@ -0,0 +1,37 @@
|
|||||||
|
/*
|
||||||
|
* Copyright 2010-2019 JetBrains s.r.o. and Kotlin Programming Language contributors.
|
||||||
|
* Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package org.jetbrains.kotlin.resolve
|
||||||
|
|
||||||
|
import org.jetbrains.kotlin.contracts.description.ContractProviderKey
|
||||||
|
import org.jetbrains.kotlin.contracts.description.LazyContractProvider
|
||||||
|
import org.jetbrains.kotlin.contracts.parsing.isContractCallDescriptor
|
||||||
|
import org.jetbrains.kotlin.descriptors.CallableDescriptor
|
||||||
|
import org.jetbrains.kotlin.descriptors.FunctionDescriptor
|
||||||
|
import org.jetbrains.kotlin.psi.Call
|
||||||
|
import org.jetbrains.kotlin.psi.KtExpression
|
||||||
|
import org.jetbrains.kotlin.psi.psiUtil.isContractDescriptionCallPsiCheck
|
||||||
|
import org.jetbrains.kotlin.psi.psiUtil.isFirstStatement
|
||||||
|
import org.jetbrains.kotlin.resolve.scopes.LexicalScope
|
||||||
|
import org.jetbrains.kotlin.utils.addToStdlib.safeAs
|
||||||
|
|
||||||
|
/*
|
||||||
|
* See KT-26386 and KT-30410
|
||||||
|
*/
|
||||||
|
fun disableContractsInsideContractsBlock(call: Call, descriptor: CallableDescriptor?, scope: LexicalScope, trace: BindingTrace) {
|
||||||
|
call.callElement.safeAs<KtExpression>()?.let { callExpression ->
|
||||||
|
if (callExpression.isFirstStatement() && callExpression.isContractDescriptionCallPsiCheck()) {
|
||||||
|
if (descriptor?.isContractCallDescriptor() != true) {
|
||||||
|
scope.ownerDescriptor
|
||||||
|
.safeAs<FunctionDescriptor>()
|
||||||
|
?.getUserData(ContractProviderKey)
|
||||||
|
?.safeAs<LazyContractProvider>()
|
||||||
|
?.setContractDescription(null)
|
||||||
|
} else {
|
||||||
|
trace.record(BindingContext.IS_CONTRACT_DECLARATION_BLOCK, callExpression, true)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -135,19 +135,7 @@ class CallCompleter(
|
|||||||
context: BasicCallResolutionContext,
|
context: BasicCallResolutionContext,
|
||||||
tracing: TracingStrategy
|
tracing: TracingStrategy
|
||||||
) {
|
) {
|
||||||
context.call.callElement.safeAs<KtExpression>()?.let { callExpression ->
|
disableContractsInsideContractsBlock(context.call, resolvedCall?.resultingDescriptor, context.scope, context.trace)
|
||||||
if (callExpression.isFirstStatement() && callExpression.isContractDescriptionCallPsiCheck()) {
|
|
||||||
if (resolvedCall?.resultingDescriptor?.isContractCallDescriptor() != true) {
|
|
||||||
context.scope.ownerDescriptor
|
|
||||||
.safeAs<FunctionDescriptor>()
|
|
||||||
?.getUserData(ContractProviderKey)
|
|
||||||
?.safeAs<LazyContractProvider>()
|
|
||||||
?.setContractDescription(null)
|
|
||||||
} else {
|
|
||||||
context.trace.record(BindingContext.IS_CONTRACT_DECLARATION_BLOCK, callExpression, true)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (resolvedCall == null || resolvedCall.isCompleted || resolvedCall.constraintSystem == null) {
|
if (resolvedCall == null || resolvedCall.isCompleted || resolvedCall.constraintSystem == null) {
|
||||||
completeArguments(context, results)
|
completeArguments(context, results)
|
||||||
|
|||||||
+6
@@ -265,4 +265,10 @@ class KotlinResolutionCallbacksImpl(
|
|||||||
trace.record(BindingContext.CAST_TYPE_USED_AS_EXPECTED_TYPE, binaryParent)
|
trace.record(BindingContext.CAST_TYPE_USED_AS_EXPECTED_TYPE, binaryParent)
|
||||||
return resultType
|
return resultType
|
||||||
}
|
}
|
||||||
|
|
||||||
|
override fun disableContractsIfNecessary(resolvedAtom: ResolvedCallAtom) {
|
||||||
|
val atom = resolvedAtom.atom as? PSIKotlinCall ?: return
|
||||||
|
val context = topLevelCallContext ?: return
|
||||||
|
disableContractsInsideContractsBlock(atom.psiCall, resolvedAtom.candidateDescriptor, context.scope, trace)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
+2
@@ -55,6 +55,8 @@ interface KotlinResolutionCallbacks {
|
|||||||
val inferenceSession: InferenceSession
|
val inferenceSession: InferenceSession
|
||||||
|
|
||||||
fun getExpectedTypeFromAsExpressionAndRecordItInTrace(resolvedAtom: ResolvedCallAtom): UnwrappedType?
|
fun getExpectedTypeFromAsExpressionAndRecordItInTrace(resolvedAtom: ResolvedCallAtom): UnwrappedType?
|
||||||
|
|
||||||
|
fun disableContractsIfNecessary(resolvedAtom: ResolvedCallAtom)
|
||||||
}
|
}
|
||||||
|
|
||||||
interface SamConversionTransformer {
|
interface SamConversionTransformer {
|
||||||
|
|||||||
+4
-1
@@ -133,7 +133,10 @@ class KotlinCallCompleter(
|
|||||||
val candidate = candidates.singleOrNull()
|
val candidate = candidates.singleOrNull()
|
||||||
|
|
||||||
// this is needed at least for non-local return checker, because when we analyze lambda we should already bind descriptor for outer call
|
// this is needed at least for non-local return checker, because when we analyze lambda we should already bind descriptor for outer call
|
||||||
candidate?.resolvedCall?.let { resolutionCallbacks.bindStubResolvedCallForCandidate(it) }
|
candidate?.resolvedCall?.let {
|
||||||
|
resolutionCallbacks.bindStubResolvedCallForCandidate(it)
|
||||||
|
resolutionCallbacks.disableContractsIfNecessary(it)
|
||||||
|
}
|
||||||
|
|
||||||
return candidate ?: factory.createErrorCandidate().forceResolution()
|
return candidate ?: factory.createErrorCandidate().forceResolution()
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user