[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,
|
||||
tracing: TracingStrategy
|
||||
) {
|
||||
context.call.callElement.safeAs<KtExpression>()?.let { callExpression ->
|
||||
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)
|
||||
}
|
||||
}
|
||||
}
|
||||
disableContractsInsideContractsBlock(context.call, resolvedCall?.resultingDescriptor, context.scope, context.trace)
|
||||
|
||||
if (resolvedCall == null || resolvedCall.isCompleted || resolvedCall.constraintSystem == null) {
|
||||
completeArguments(context, results)
|
||||
|
||||
+6
@@ -265,4 +265,10 @@ class KotlinResolutionCallbacksImpl(
|
||||
trace.record(BindingContext.CAST_TYPE_USED_AS_EXPECTED_TYPE, binaryParent)
|
||||
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
|
||||
|
||||
fun getExpectedTypeFromAsExpressionAndRecordItInTrace(resolvedAtom: ResolvedCallAtom): UnwrappedType?
|
||||
|
||||
fun disableContractsIfNecessary(resolvedAtom: ResolvedCallAtom)
|
||||
}
|
||||
|
||||
interface SamConversionTransformer {
|
||||
|
||||
+4
-1
@@ -133,7 +133,10 @@ class KotlinCallCompleter(
|
||||
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
|
||||
candidate?.resolvedCall?.let { resolutionCallbacks.bindStubResolvedCallForCandidate(it) }
|
||||
candidate?.resolvedCall?.let {
|
||||
resolutionCallbacks.bindStubResolvedCallForCandidate(it)
|
||||
resolutionCallbacks.disableContractsIfNecessary(it)
|
||||
}
|
||||
|
||||
return candidate ?: factory.createErrorCandidate().forceResolution()
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user