Refactoring. Remove ResolutionCandidateStatus.

Use diagnostics directly.
Also TowerCandidate since now know only about applicability
and not about diagnostics itself.
This commit is contained in:
Stanislav Erokhin
2017-08-15 11:55:48 +03:00
parent aca21c847d
commit 6b8293ae5b
11 changed files with 86 additions and 92 deletions
@@ -347,7 +347,7 @@ class KotlinToResolvedCallTransformer(
val newContext = context.replaceBindingTrace(trackingTrace) val newContext = context.replaceBindingTrace(trackingTrace)
val diagnosticReporter = DiagnosticReporterByTrackingStrategy(constantExpressionEvaluator, newContext, completedCall.kotlinCall.psiKotlinCall) val diagnosticReporter = DiagnosticReporterByTrackingStrategy(constantExpressionEvaluator, newContext, completedCall.kotlinCall.psiKotlinCall)
for (diagnostic in completedCall.resolutionStatus.diagnostics) { for (diagnostic in completedCall.diagnostics) {
trackingTrace.reported = false trackingTrace.reported = false
diagnostic.report(diagnosticReporter) diagnostic.report(diagnosticReporter)
@@ -464,7 +464,7 @@ class NewResolvedCallImpl<D : CallableDescriptor>(
): NewAbstractResolvedCall<D>() { ): NewAbstractResolvedCall<D>() {
override val kotlinCall: KotlinCall get() = completedCall.kotlinCall override val kotlinCall: KotlinCall get() = completedCall.kotlinCall
override fun getStatus(): ResolutionStatus = completedCall.resolutionStatus.resultingApplicability.toResolutionStatus() override fun getStatus(): ResolutionStatus = completedCall.resultingApplicability.toResolutionStatus()
override val argumentMappingByOriginal: Map<ValueParameterDescriptor, ResolvedCallArgument> override val argumentMappingByOriginal: Map<ValueParameterDescriptor, ResolvedCallArgument>
get() = completedCall.argumentMappingByOriginal get() = completedCall.argumentMappingByOriginal
@@ -496,7 +496,7 @@ class NewVariableAsFunctionResolvedCallImpl(
): VariableAsFunctionResolvedCall, ResolvedCall<FunctionDescriptor> by functionCall ): VariableAsFunctionResolvedCall, ResolvedCall<FunctionDescriptor> by functionCall
class StubOnlyResolvedCall<D : CallableDescriptor>(val candidate: SimpleKotlinResolutionCandidate): NewAbstractResolvedCall<D>() { class StubOnlyResolvedCall<D : CallableDescriptor>(val candidate: SimpleKotlinResolutionCandidate): NewAbstractResolvedCall<D>() {
override fun getStatus() = candidate.status.resultingApplicability.toResolutionStatus() override fun getStatus() = candidate.resultingApplicability.toResolutionStatus()
override fun getCandidateDescriptor(): D = candidate.candidateDescriptor as D override fun getCandidateDescriptor(): D = candidate.candidateDescriptor as D
override fun getResultingDescriptor(): D = candidate.descriptorWithFreshTypes as D override fun getResultingDescriptor(): D = candidate.descriptorWithFreshTypes as D
@@ -29,7 +29,6 @@ import org.jetbrains.kotlin.psi.Call
import org.jetbrains.kotlin.psi.KtReferenceExpression import org.jetbrains.kotlin.psi.KtReferenceExpression
import org.jetbrains.kotlin.resolve.BindingContext import org.jetbrains.kotlin.resolve.BindingContext
import org.jetbrains.kotlin.resolve.TemporaryBindingTrace import org.jetbrains.kotlin.resolve.TemporaryBindingTrace
import org.jetbrains.kotlin.resolve.calls.model.KotlinCallKind
import org.jetbrains.kotlin.resolve.calls.CallTransformer import org.jetbrains.kotlin.resolve.calls.CallTransformer
import org.jetbrains.kotlin.resolve.calls.CandidateResolver import org.jetbrains.kotlin.resolve.calls.CandidateResolver
import org.jetbrains.kotlin.resolve.calls.callResolverUtil.isBinaryRemOperator import org.jetbrains.kotlin.resolve.calls.callResolverUtil.isBinaryRemOperator
@@ -38,9 +37,7 @@ import org.jetbrains.kotlin.resolve.calls.callResolverUtil.isInfixCall
import org.jetbrains.kotlin.resolve.calls.callUtil.createLookupLocation import org.jetbrains.kotlin.resolve.calls.callUtil.createLookupLocation
import org.jetbrains.kotlin.resolve.calls.context.* import org.jetbrains.kotlin.resolve.calls.context.*
import org.jetbrains.kotlin.resolve.calls.inference.CoroutineInferenceSupport import org.jetbrains.kotlin.resolve.calls.inference.CoroutineInferenceSupport
import org.jetbrains.kotlin.resolve.calls.model.MutableResolvedCall import org.jetbrains.kotlin.resolve.calls.model.*
import org.jetbrains.kotlin.resolve.calls.model.ResolvedCallImpl
import org.jetbrains.kotlin.resolve.calls.model.VariableAsFunctionResolvedCallImpl
import org.jetbrains.kotlin.resolve.calls.results.OverloadResolutionResultsImpl import org.jetbrains.kotlin.resolve.calls.results.OverloadResolutionResultsImpl
import org.jetbrains.kotlin.resolve.calls.results.ResolutionResultsHandler import org.jetbrains.kotlin.resolve.calls.results.ResolutionResultsHandler
import org.jetbrains.kotlin.resolve.calls.results.ResolutionStatus import org.jetbrains.kotlin.resolve.calls.results.ResolutionStatus
@@ -176,7 +173,7 @@ class NewResolutionOldInference(
// Temporary hack to resolve 'rem' as 'mod' if the first is do not present // Temporary hack to resolve 'rem' as 'mod' if the first is do not present
val emptyOrInapplicableCandidates = candidates.isEmpty() || val emptyOrInapplicableCandidates = candidates.isEmpty() ||
candidates.all { it.candidateStatus.resultingApplicability.isInapplicable } candidates.all { it.resultingApplicability.isInapplicable }
if (isBinaryRemOperator && shouldUseOperatorRem && emptyOrInapplicableCandidates) { if (isBinaryRemOperator && shouldUseOperatorRem && emptyOrInapplicableCandidates) {
val deprecatedName = OperatorConventions.REM_TO_MOD_OPERATION_NAMES[name] val deprecatedName = OperatorConventions.REM_TO_MOD_OPERATION_NAMES[name]
val processorForDeprecatedName = kind.createTowerProcessor(this, deprecatedName!!, tracing, scopeTower, detailedReceiver, context) val processorForDeprecatedName = kind.createTowerProcessor(this, deprecatedName!!, tracing, scopeTower, detailedReceiver, context)
@@ -204,7 +201,7 @@ class NewResolutionOldInference(
val resolvedCall = ResolvedCallImpl.create(candidate, candidateTrace, tracing, basicCallContext.dataFlowInfoForArguments) val resolvedCall = ResolvedCallImpl.create(candidate, candidateTrace, tracing, basicCallContext.dataFlowInfoForArguments)
if (candidate.descriptor.isHiddenInResolution(languageVersionSettings, basicCallContext.isSuperCall)) { if (candidate.descriptor.isHiddenInResolution(languageVersionSettings, basicCallContext.isSuperCall)) {
return@map MyCandidate(ResolutionCandidateStatus(listOf(HiddenDescriptor)), resolvedCall) return@map MyCandidate(listOf(HiddenDescriptor), resolvedCall)
} }
val callCandidateResolutionContext = CallCandidateResolutionContext.create( val callCandidateResolutionContext = CallCandidateResolutionContext.create(
@@ -214,16 +211,16 @@ class NewResolutionOldInference(
candidateResolver.performResolutionForCandidateCall(callCandidateResolutionContext, basicCallContext.checkArguments) // todo candidateResolver.performResolutionForCandidateCall(callCandidateResolutionContext, basicCallContext.checkArguments) // todo
val diagnostics = listOfNotNull(createPreviousResolveError(resolvedCall.status)) val diagnostics = listOfNotNull(createPreviousResolveError(resolvedCall.status))
MyCandidate(ResolutionCandidateStatus(diagnostics), resolvedCall) MyCandidate(diagnostics, resolvedCall)
} }
if (basicCallContext.collectAllCandidates) { if (basicCallContext.collectAllCandidates) {
val allCandidates = towerResolver.runWithEmptyTowerData(KnownResultProcessor(resolvedCandidates), val allCandidates = towerResolver.runWithEmptyTowerData(KnownResultProcessor(resolvedCandidates),
TowerResolver.AllCandidatesCollector { it.candidateStatus }, useOrder = false) TowerResolver.AllCandidatesCollector(), useOrder = false)
return allCandidatesResult(allCandidates) return allCandidatesResult(allCandidates)
} }
val processedCandidates = towerResolver.runWithEmptyTowerData(KnownResultProcessor(resolvedCandidates), val processedCandidates = towerResolver.runWithEmptyTowerData(KnownResultProcessor(resolvedCandidates),
TowerResolver.SuccessfulResultCollector { it.candidateStatus }, useOrder = true) TowerResolver.SuccessfulResultCollector(), useOrder = true)
return convertToOverloadResults(processedCandidates, tracing, basicCallContext, languageVersionSettings) return convertToOverloadResults(processedCandidates, tracing, basicCallContext, languageVersionSettings)
} }
@@ -240,7 +237,7 @@ class NewResolutionOldInference(
languageVersionSettings: LanguageVersionSettings languageVersionSettings: LanguageVersionSettings
): OverloadResolutionResultsImpl<D> { ): OverloadResolutionResultsImpl<D> {
val resolvedCalls = candidates.map { val resolvedCalls = candidates.map {
val (status, resolvedCall) = it val (diagnostics, resolvedCall) = it
if (resolvedCall is VariableAsFunctionResolvedCallImpl) { if (resolvedCall is VariableAsFunctionResolvedCallImpl) {
// todo hacks // todo hacks
tracing.bindReference(resolvedCall.variableCall.trace, resolvedCall.variableCall) tracing.bindReference(resolvedCall.variableCall.trace, resolvedCall.variableCall)
@@ -256,7 +253,7 @@ class NewResolutionOldInference(
} }
if (resolvedCall.status.possibleTransformToSuccess()) { if (resolvedCall.status.possibleTransformToSuccess()) {
for (error in status.diagnostics) { for (error in diagnostics) {
when (error) { when (error) {
is UnsupportedInnerClassCall -> resolvedCall.trace.report(Errors.UNSUPPORTED.on(resolvedCall.call.callElement, error.message)) is UnsupportedInnerClassCall -> resolvedCall.trace.report(Errors.UNSUPPORTED.on(resolvedCall.call.callElement, error.message))
is NestedClassViaInstanceReference -> tracing.nestedClassAccessViaInstanceReference(resolvedCall.trace, error.classDescriptor, resolvedCall.explicitReceiverKind) is NestedClassViaInstanceReference -> tracing.nestedClassAccessViaInstanceReference(resolvedCall.trace, error.classDescriptor, resolvedCall.explicitReceiverKind)
@@ -317,13 +314,11 @@ class NewResolutionOldInference(
} }
internal data class MyCandidate( internal data class MyCandidate(
val candidateStatus: ResolutionCandidateStatus, val diagnostics: List<KotlinCallDiagnostic>,
val resolvedCall: MutableResolvedCall<*> val resolvedCall: MutableResolvedCall<*>
) : Candidate { ) : Candidate {
override val isSuccessful: Boolean override val resultingApplicability: ResolutionCandidateApplicability = getResultApplicability(diagnostics)
get() = candidateStatus.resultingApplicability.isSuccess override val isSuccessful get() = resultingApplicability.isSuccess
override val status: ResolutionCandidateStatus
get() = candidateStatus
} }
private inner class CandidateFactoryImpl( private inner class CandidateFactoryImpl(
@@ -358,12 +353,12 @@ class NewResolutionOldInference(
if (parameterIsDynamic != argumentIsDynamic || if (parameterIsDynamic != argumentIsDynamic ||
(parameterIsDynamic && !towerCandidate.descriptor.hasDynamicExtensionAnnotation()) (parameterIsDynamic && !towerCandidate.descriptor.hasDynamicExtensionAnnotation())
) { ) {
return MyCandidate(ResolutionCandidateStatus(listOf(HiddenExtensionRelatedToDynamicTypes)), candidateCall) return MyCandidate(listOf(HiddenExtensionRelatedToDynamicTypes), candidateCall)
} }
} }
if (towerCandidate.descriptor.isHiddenInResolution(languageVersionSettings, basicCallContext.isSuperCall)) { if (towerCandidate.descriptor.isHiddenInResolution(languageVersionSettings, basicCallContext.isSuperCall)) {
return MyCandidate(ResolutionCandidateStatus(listOf(HiddenDescriptor)), candidateCall) return MyCandidate(listOf(HiddenDescriptor), candidateCall)
} }
val callCandidateResolutionContext = CallCandidateResolutionContext.create( val callCandidateResolutionContext = CallCandidateResolutionContext.create(
@@ -375,7 +370,7 @@ class NewResolutionOldInference(
val diagnostics = (towerCandidate.diagnostics + val diagnostics = (towerCandidate.diagnostics +
checkInfixAndOperator(basicCallContext.call, towerCandidate.descriptor) + checkInfixAndOperator(basicCallContext.call, towerCandidate.descriptor) +
createPreviousResolveError(candidateCall.status)).filterNotNull() // todo createPreviousResolveError(candidateCall.status)).filterNotNull() // todo
return MyCandidate(ResolutionCandidateStatus(diagnostics), candidateCall) return MyCandidate(diagnostics, candidateCall)
} }
private fun checkInfixAndOperator(call: Call, descriptor: CallableDescriptor): List<ResolutionDiagnostic> { private fun checkInfixAndOperator(call: Call, descriptor: CallableDescriptor): List<ResolutionDiagnostic> {
@@ -403,11 +398,11 @@ class NewResolutionOldInference(
invoke.resolvedCall as MutableResolvedCall<FunctionDescriptor>, invoke.resolvedCall as MutableResolvedCall<FunctionDescriptor>,
variable.resolvedCall as MutableResolvedCall<VariableDescriptor> variable.resolvedCall as MutableResolvedCall<VariableDescriptor>
) )
assert(variable.candidateStatus.resultingApplicability.isSuccess) { assert(variable.resultingApplicability.isSuccess) {
"Variable call must be success: $variable" "Variable call must be success: $variable"
} }
return MyCandidate(ResolutionCandidateStatus(variable.candidateStatus.diagnostics + invoke.candidateStatus.diagnostics), resolvedCallImpl) return MyCandidate(variable.diagnostics + invoke.diagnostics, resolvedCallImpl)
} }
override fun factoryForVariable(stripExplicitReceiver: Boolean): CandidateFactory<MyCandidate> { override fun factoryForVariable(stripExplicitReceiver: Boolean): CandidateFactory<MyCandidate> {
@@ -179,7 +179,7 @@ class PSICallResolver(
1 -> { 1 -> {
val singleCandidate = result.single() val singleCandidate = result.single()
val isInapplicableReceiver = singleCandidate.currentStatus.resultingApplicability == ResolutionCandidateApplicability.INAPPLICABLE_WRONG_RECEIVER val isInapplicableReceiver = singleCandidate.resultingApplicability == ResolutionCandidateApplicability.INAPPLICABLE_WRONG_RECEIVER
val resolvedCall = kotlinToResolvedCallTransformer.transformAndReport<D>(singleCandidate, context, trace.takeUnless { isInapplicableReceiver }) val resolvedCall = kotlinToResolvedCallTransformer.transformAndReport<D>(singleCandidate, context, trace.takeUnless { isInapplicableReceiver })
@@ -211,12 +211,12 @@ class PSICallResolver(
private fun Collection<ResolvedKotlinCall>.areAllCompletedAndFailed() = private fun Collection<ResolvedKotlinCall>.areAllCompletedAndFailed() =
all { all {
it is ResolvedKotlinCall.CompletedResolvedKotlinCall && it is ResolvedKotlinCall.CompletedResolvedKotlinCall &&
!it.completedCall.resolutionStatus.resultingApplicability.isSuccess !it.completedCall.resultingApplicability.isSuccess
} }
private fun Collection<ResolvedKotlinCall>.areAllCompletedAndInapplicable() = private fun Collection<ResolvedKotlinCall>.areAllCompletedAndInapplicable() =
all { all {
val applicability = it.currentStatus.resultingApplicability val applicability = it.resultingApplicability
applicability == ResolutionCandidateApplicability.INAPPLICABLE || applicability == ResolutionCandidateApplicability.INAPPLICABLE ||
applicability == ResolutionCandidateApplicability.INAPPLICABLE_WRONG_RECEIVER || applicability == ResolutionCandidateApplicability.INAPPLICABLE_WRONG_RECEIVER ||
applicability == ResolutionCandidateApplicability.HIDDEN applicability == ResolutionCandidateApplicability.HIDDEN
@@ -82,7 +82,7 @@ class KotlinCallResolver(
) )
} }
val candidates = towerResolver.runWithEmptyTowerData(KnownResultProcessor(resolutionCandidates), val candidates = towerResolver.runWithEmptyTowerData(KnownResultProcessor(resolutionCandidates),
TowerResolver.SuccessfulResultCollector { it.status }, TowerResolver.SuccessfulResultCollector(),
useOrder = true) useOrder = true)
return choseMostSpecific(resolutionCallbacks, expectedType, candidates) return choseMostSpecific(resolutionCallbacks, expectedType, candidates)
} }
@@ -42,7 +42,7 @@ class AdditionalDiagnosticReporter {
} }
private fun reportSmartCastOnReceiver( private fun reportSmartCastOnReceiver(
candidate: KotlinResolutionCandidate, candidate: SimpleKotlinResolutionCandidate,
receiver: SimpleKotlinCallArgument?, receiver: SimpleKotlinCallArgument?,
parameter: ReceiverParameterDescriptor? parameter: ReceiverParameterDescriptor?
): SmartCastDiagnostic? { ): SmartCastDiagnostic? {
@@ -53,11 +53,11 @@ class AdditionalDiagnosticReporter {
// todo may be we have smart cast to Int? // todo may be we have smart cast to Int?
return smartCastDiagnostic.takeIf { return smartCastDiagnostic.takeIf {
candidate.status.diagnostics.filterIsInstance<UnsafeCallError>().none { candidate.getCandidateDiagnostics().filterIsInstance<UnsafeCallError>().none {
it.receiver == receiver it.receiver == receiver
} }
&& &&
candidate.status.diagnostics.filterIsInstance<UnstableSmartCast>().none { candidate.getCandidateDiagnostics().filterIsInstance<UnstableSmartCast>().none {
it.argument == receiver it.argument == receiver
} }
} }
@@ -72,7 +72,7 @@ class AdditionalDiagnosticReporter {
for (argument in candidate.argumentMappingByOriginal[parameter.original]?.arguments ?: continue) { for (argument in candidate.argumentMappingByOriginal[parameter.original]?.arguments ?: continue) {
val smartCastDiagnostic = createSmartCastDiagnostic(argument, argument.getExpectedType(parameter)) ?: continue val smartCastDiagnostic = createSmartCastDiagnostic(argument, argument.getExpectedType(parameter)) ?: continue
val thereIsUnstableSmartCastError = candidate.status.diagnostics.filterIsInstance<UnstableSmartCast>().any { val thereIsUnstableSmartCastError = candidate.getCandidateDiagnostics().filterIsInstance<UnstableSmartCast>().any {
it.argument == argument it.argument == argument
} }
@@ -68,9 +68,10 @@ class CallableReferenceCandidate(
val explicitReceiverKind: ExplicitReceiverKind, val explicitReceiverKind: ExplicitReceiverKind,
val reflectionCandidateType: UnwrappedType, val reflectionCandidateType: UnwrappedType,
val numDefaults: Int, val numDefaults: Int,
override val status: ResolutionCandidateStatus val diagnostics: List<KotlinCallDiagnostic>
) : Candidate { ) : Candidate {
override val isSuccessful get() = status.resultingApplicability.isSuccess override val resultingApplicability = getResultApplicability(diagnostics)
override val isSuccessful get() = resultingApplicability.isSuccess
} }
/** /**
@@ -184,9 +185,9 @@ class CallableReferencesCandidateFactory(
} }
if (candidateDescriptor !is CallableMemberDescriptor) { if (candidateDescriptor !is CallableMemberDescriptor) {
val status = ResolutionCandidateStatus(listOf(NotCallableMemberReference(argument, candidateDescriptor)))
return CallableReferenceCandidate(candidateDescriptor, dispatchCallableReceiver, extensionCallableReceiver, return CallableReferenceCandidate(candidateDescriptor, dispatchCallableReceiver, extensionCallableReceiver,
explicitReceiverKind, reflectionCandidateType, defaults, status) explicitReceiverKind, reflectionCandidateType, defaults,
listOf(NotCallableMemberReference(argument, candidateDescriptor)))
} }
diagnostics.addAll(towerCandidate.diagnostics) diagnostics.addAll(towerCandidate.diagnostics)
@@ -205,7 +206,7 @@ class CallableReferencesCandidateFactory(
} }
return CallableReferenceCandidate(candidateDescriptor, dispatchCallableReceiver, extensionCallableReceiver, return CallableReferenceCandidate(candidateDescriptor, dispatchCallableReceiver, extensionCallableReceiver,
explicitReceiverKind, reflectionCandidateType, defaults, ResolutionCandidateStatus(diagnostics)) explicitReceiverKind, reflectionCandidateType, defaults, diagnostics)
} }
private fun getArgumentAndReturnTypeUseMappingByExpectedType( private fun getArgumentAndReturnTypeUseMappingByExpectedType(
@@ -27,7 +27,6 @@ import org.jetbrains.kotlin.resolve.calls.inference.model.NewTypeVariable
import org.jetbrains.kotlin.resolve.calls.inference.returnTypeOrNothing import org.jetbrains.kotlin.resolve.calls.inference.returnTypeOrNothing
import org.jetbrains.kotlin.resolve.calls.inference.substituteAndApproximateCapturedTypes import org.jetbrains.kotlin.resolve.calls.inference.substituteAndApproximateCapturedTypes
import org.jetbrains.kotlin.resolve.calls.model.* import org.jetbrains.kotlin.resolve.calls.model.*
import org.jetbrains.kotlin.resolve.calls.tower.ResolutionCandidateStatus
import org.jetbrains.kotlin.types.TypeApproximator import org.jetbrains.kotlin.types.TypeApproximator
import org.jetbrains.kotlin.types.TypeApproximatorConfiguration import org.jetbrains.kotlin.types.TypeApproximatorConfiguration
import org.jetbrains.kotlin.types.TypeUtils import org.jetbrains.kotlin.types.TypeUtils
@@ -104,9 +103,9 @@ class KotlinCallCompleter(
resolutionCallbacks: KotlinResolutionCallbacks resolutionCallbacks: KotlinResolutionCallbacks
): ResolvedKotlinCall.CompletedResolvedKotlinCall { ): ResolvedKotlinCall.CompletedResolvedKotlinCall {
val currentSubstitutor = c.buildResultingSubstitutor() val currentSubstitutor = c.buildResultingSubstitutor()
val completedCall = candidate.toCompletedCall(currentSubstitutor) val completedCall = candidate.toCompletedCall(currentSubstitutor, isTopLevel = true)
val competedCalls = c.innerCalls.map { val competedCalls = c.innerCalls.map {
it.candidate.toCompletedCall(currentSubstitutor) it.candidate.toCompletedCall(currentSubstitutor, isTopLevel = false)
} }
for (postponedArgument in c.postponedArguments) { for (postponedArgument in c.postponedArguments) {
when (postponedArgument) { when (postponedArgument) {
@@ -125,17 +124,17 @@ class KotlinCallCompleter(
return ResolvedKotlinCall.CompletedResolvedKotlinCall(completedCall, competedCalls, c.lambdaArguments) return ResolvedKotlinCall.CompletedResolvedKotlinCall(completedCall, competedCalls, c.lambdaArguments)
} }
private fun KotlinResolutionCandidate.toCompletedCall(substitutor: NewTypeSubstitutor): CompletedKotlinCall { private fun KotlinResolutionCandidate.toCompletedCall(substitutor: NewTypeSubstitutor, isTopLevel: Boolean): CompletedKotlinCall {
if (this is VariableAsFunctionKotlinResolutionCandidate) { if (this is VariableAsFunctionKotlinResolutionCandidate) {
val variable = resolvedVariable.toCompletedCall(substitutor) val variable = resolvedVariable.toCompletedCall(substitutor, isTopLevel = false)
val invoke = invokeCandidate.toCompletedCall(substitutor) val invoke = invokeCandidate.toCompletedCall(substitutor, isTopLevel)
return CompletedKotlinCall.VariableAsFunction(kotlinCall, variable, invoke) return CompletedKotlinCall.VariableAsFunction(kotlinCall, variable, invoke)
} }
return (this as SimpleKotlinResolutionCandidate).toCompletedCall(substitutor) return (this as SimpleKotlinResolutionCandidate).toCompletedCall(substitutor, isTopLevel)
} }
private fun SimpleKotlinResolutionCandidate.toCompletedCall(substitutor: NewTypeSubstitutor): CompletedKotlinCall.Simple { private fun SimpleKotlinResolutionCandidate.toCompletedCall(substitutor: NewTypeSubstitutor, isTopLevel: Boolean): CompletedKotlinCall.Simple {
val containsCapturedTypes = descriptorWithFreshTypes.returnType?.contains { it is NewCapturedType } ?: false val containsCapturedTypes = descriptorWithFreshTypes.returnType?.contains { it is NewCapturedType } ?: false
val resultingDescriptor = when { val resultingDescriptor = when {
descriptorWithFreshTypes is FunctionDescriptor || descriptorWithFreshTypes is FunctionDescriptor ||
@@ -152,15 +151,22 @@ class KotlinCallCompleter(
TypeApproximator().approximateToSuperType(substituted, TypeApproximatorConfiguration.CapturedTypesApproximation) ?: substituted TypeApproximator().approximateToSuperType(substituted, TypeApproximatorConfiguration.CapturedTypesApproximation) ?: substituted
} }
val status = computeStatus(this, resultingDescriptor) val diagnostics = computeDiagnostics(this, resultingDescriptor, isTopLevel)
return CompletedKotlinCall.Simple(kotlinCall, candidateDescriptor, resultingDescriptor, status, explicitReceiverKind, return CompletedKotlinCall.Simple(kotlinCall, candidateDescriptor, resultingDescriptor, diagnostics, explicitReceiverKind,
dispatchReceiverArgument?.receiver, extensionReceiver?.receiver, typeArguments, argumentMappingByOriginal) dispatchReceiverArgument?.receiver, extensionReceiver?.receiver, typeArguments, argumentMappingByOriginal)
} }
private fun computeStatus(candidate: SimpleKotlinResolutionCandidate, resultingDescriptor: CallableDescriptor): ResolutionCandidateStatus { private fun computeDiagnostics(
val smartCasts = additionalDiagnosticReporter.createAdditionalDiagnostics(candidate, resultingDescriptor).takeIf { it.isNotEmpty() } ?: candidate: SimpleKotlinResolutionCandidate,
return candidate.status resultingDescriptor: CallableDescriptor,
return ResolutionCandidateStatus(candidate.status.diagnostics + smartCasts) isTopLevel: Boolean
): List<KotlinCallDiagnostic> {
var diagnostics = candidate.getCandidateDiagnostics()
if (isTopLevel) {
diagnostics += candidate.constraintSystem.diagnostics
}
diagnostics += additionalDiagnosticReporter.createAdditionalDiagnostics(candidate, resultingDescriptor)
return diagnostics
} }
// true if we should complete this call // true if we should complete this call
@@ -25,10 +25,7 @@ import org.jetbrains.kotlin.resolve.calls.inference.NewConstraintSystem
import org.jetbrains.kotlin.resolve.calls.inference.model.NewConstraintSystemImpl import org.jetbrains.kotlin.resolve.calls.inference.model.NewConstraintSystemImpl
import org.jetbrains.kotlin.resolve.calls.inference.model.NewTypeVariable import org.jetbrains.kotlin.resolve.calls.inference.model.NewTypeVariable
import org.jetbrains.kotlin.resolve.calls.tasks.ExplicitReceiverKind import org.jetbrains.kotlin.resolve.calls.tasks.ExplicitReceiverKind
import org.jetbrains.kotlin.resolve.calls.tower.Candidate import org.jetbrains.kotlin.resolve.calls.tower.*
import org.jetbrains.kotlin.resolve.calls.tower.ImplicitScopeTower
import org.jetbrains.kotlin.resolve.calls.tower.ResolutionCandidateStatus
import org.jetbrains.kotlin.resolve.calls.tower.isSuccess
import org.jetbrains.kotlin.types.TypeSubstitutor import org.jetbrains.kotlin.types.TypeSubstitutor
import java.util.* import java.util.*
@@ -49,8 +46,8 @@ class VariableAsFunctionKotlinResolutionCandidate(
val invokeCandidate: SimpleKotlinResolutionCandidate val invokeCandidate: SimpleKotlinResolutionCandidate
) : KotlinResolutionCandidate() { ) : KotlinResolutionCandidate() {
override val isSuccessful: Boolean get() = resolvedVariable.isSuccessful && invokeCandidate.isSuccessful override val isSuccessful: Boolean get() = resolvedVariable.isSuccessful && invokeCandidate.isSuccessful
override val status: ResolutionCandidateStatus override val resultingApplicability: ResolutionCandidateApplicability
get() = ResolutionCandidateStatus(resolvedVariable.status.diagnostics + invokeCandidate.status.diagnostics) get() = maxOf(resolvedVariable.resultingApplicability, invokeCandidate.resultingApplicability)
override val lastCall: SimpleKotlinResolutionCandidate get() = invokeCandidate override val lastCall: SimpleKotlinResolutionCandidate get() = invokeCandidate
} }
@@ -65,15 +62,10 @@ sealed class AbstractSimpleKotlinResolutionCandidate(
return !hasErrors return !hasErrors
} }
private var _status: ResolutionCandidateStatus? = null override val resultingApplicability: ResolutionCandidateApplicability
override val status: ResolutionCandidateStatus
get() { get() {
if (_status == null) { process(stopOnFirstError = false)
process(stopOnFirstError = false) return getResultApplicability(diagnostics + constraintSystem.diagnostics)
_status = ResolutionCandidateStatus(diagnostics + constraintSystem.diagnostics)
}
return _status!!
} }
private val diagnostics = ArrayList<KotlinCallDiagnostic>() private val diagnostics = ArrayList<KotlinCallDiagnostic>()
@@ -100,6 +92,7 @@ sealed class AbstractSimpleKotlinResolutionCandidate(
addDiagnostics(initialDiagnostics) addDiagnostics(initialDiagnostics)
} }
fun getCandidateDiagnostics(): List<KotlinCallDiagnostic> = diagnostics
abstract val resolutionSequence: List<ResolutionPart> abstract val resolutionSequence: List<ResolutionPart>
} }
@@ -19,49 +19,50 @@ package org.jetbrains.kotlin.resolve.calls.model
import org.jetbrains.kotlin.descriptors.CallableDescriptor import org.jetbrains.kotlin.descriptors.CallableDescriptor
import org.jetbrains.kotlin.descriptors.ValueParameterDescriptor import org.jetbrains.kotlin.descriptors.ValueParameterDescriptor
import org.jetbrains.kotlin.resolve.calls.tasks.ExplicitReceiverKind import org.jetbrains.kotlin.resolve.calls.tasks.ExplicitReceiverKind
import org.jetbrains.kotlin.resolve.calls.tower.ResolutionCandidateStatus import org.jetbrains.kotlin.resolve.calls.tower.ResolutionCandidateApplicability
import org.jetbrains.kotlin.resolve.calls.tower.getResultApplicability
import org.jetbrains.kotlin.resolve.scopes.receivers.ReceiverValueWithSmartCastInfo import org.jetbrains.kotlin.resolve.scopes.receivers.ReceiverValueWithSmartCastInfo
import org.jetbrains.kotlin.types.UnwrappedType import org.jetbrains.kotlin.types.UnwrappedType
sealed class ResolvedKotlinCall { sealed class ResolvedKotlinCall {
abstract val currentStatus: ResolutionCandidateStatus abstract val resultingApplicability: ResolutionCandidateApplicability
class CompletedResolvedKotlinCall( class CompletedResolvedKotlinCall(
val completedCall: CompletedKotlinCall, val completedCall: CompletedKotlinCall,
val allInnerCalls: Collection<CompletedKotlinCall>, val allInnerCalls: Collection<CompletedKotlinCall>,
val lambdaArguments: List<PostponedLambdaArgument> val lambdaArguments: List<PostponedLambdaArgument>
): ResolvedKotlinCall() { ): ResolvedKotlinCall() {
override val currentStatus get() = completedCall.resolutionStatus override val resultingApplicability get() = completedCall.resultingApplicability
} }
class OnlyResolvedKotlinCall(val candidate: KotlinResolutionCandidate) : ResolvedKotlinCall() { class OnlyResolvedKotlinCall(val candidate: KotlinResolutionCandidate) : ResolvedKotlinCall() {
override val currentStatus get() = candidate.status override val resultingApplicability get() = candidate.resultingApplicability
} }
} }
sealed class CompletedKotlinCall { sealed class CompletedKotlinCall {
abstract val resolutionStatus: ResolutionCandidateStatus abstract val resultingApplicability: ResolutionCandidateApplicability
class Simple( class Simple(
val kotlinCall: KotlinCall, val kotlinCall: KotlinCall,
val candidateDescriptor: CallableDescriptor, val candidateDescriptor: CallableDescriptor,
val resultingDescriptor: CallableDescriptor, val resultingDescriptor: CallableDescriptor,
override val resolutionStatus: ResolutionCandidateStatus, val diagnostics: List<KotlinCallDiagnostic>,
val explicitReceiverKind: ExplicitReceiverKind, val explicitReceiverKind: ExplicitReceiverKind,
val dispatchReceiver: ReceiverValueWithSmartCastInfo?, val dispatchReceiver: ReceiverValueWithSmartCastInfo?,
val extensionReceiver: ReceiverValueWithSmartCastInfo?, val extensionReceiver: ReceiverValueWithSmartCastInfo?,
val typeArguments: List<UnwrappedType>, val typeArguments: List<UnwrappedType>,
val argumentMappingByOriginal: Map<ValueParameterDescriptor, ResolvedCallArgument> val argumentMappingByOriginal: Map<ValueParameterDescriptor, ResolvedCallArgument>
): CompletedKotlinCall() ): CompletedKotlinCall() {
override val resultingApplicability = getResultApplicability(diagnostics)
}
class VariableAsFunction( class VariableAsFunction(
val kotlinCall: KotlinCall, val kotlinCall: KotlinCall,
val variableCall: Simple, val variableCall: Simple,
val invokeCall: Simple val invokeCall: Simple
): CompletedKotlinCall() { ): CompletedKotlinCall() {
override val resultingApplicability get() = maxOf(variableCall.resultingApplicability, invokeCall.resultingApplicability)
override val resolutionStatus: ResolutionCandidateStatus =
ResolutionCandidateStatus(variableCall.resolutionStatus.diagnostics + invokeCall.resolutionStatus.diagnostics)
} }
} }
@@ -21,8 +21,8 @@ import org.jetbrains.kotlin.descriptors.ClassDescriptor
import org.jetbrains.kotlin.descriptors.DeclarationDescriptorWithVisibility import org.jetbrains.kotlin.descriptors.DeclarationDescriptorWithVisibility
import org.jetbrains.kotlin.incremental.components.LookupLocation import org.jetbrains.kotlin.incremental.components.LookupLocation
import org.jetbrains.kotlin.name.Name import org.jetbrains.kotlin.name.Name
import org.jetbrains.kotlin.resolve.calls.model.KotlinCallDiagnostic
import org.jetbrains.kotlin.resolve.calls.model.DiagnosticReporter import org.jetbrains.kotlin.resolve.calls.model.DiagnosticReporter
import org.jetbrains.kotlin.resolve.calls.model.KotlinCallDiagnostic
import org.jetbrains.kotlin.resolve.calls.tower.ResolutionCandidateApplicability.* import org.jetbrains.kotlin.resolve.calls.tower.ResolutionCandidateApplicability.*
import org.jetbrains.kotlin.resolve.scopes.LexicalScope import org.jetbrains.kotlin.resolve.scopes.LexicalScope
import org.jetbrains.kotlin.resolve.scopes.MemberScope import org.jetbrains.kotlin.resolve.scopes.MemberScope
@@ -60,10 +60,8 @@ interface CandidateWithBoundDispatchReceiver {
val dispatchReceiver: ReceiverValueWithSmartCastInfo? val dispatchReceiver: ReceiverValueWithSmartCastInfo?
} }
data class ResolutionCandidateStatus(val diagnostics: List<KotlinCallDiagnostic>) { fun getResultApplicability(diagnostics: List<KotlinCallDiagnostic>) = diagnostics.maxBy { it.candidateApplicability }?.candidateApplicability
val resultingApplicability: ResolutionCandidateApplicability = diagnostics.asSequence().map { it.candidateApplicability }.max() ?: RESOLVED
?: RESOLVED
}
enum class ResolutionCandidateApplicability { enum class ResolutionCandidateApplicability {
RESOLVED, // call success or has uncompleted inference or in other words possible successful candidate RESOLVED, // call success or has uncompleted inference or in other words possible successful candidate
@@ -28,7 +28,7 @@ interface Candidate {
// this operation should be very fast // this operation should be very fast
val isSuccessful: Boolean val isSuccessful: Boolean
val status: ResolutionCandidateStatus val resultingApplicability: ResolutionCandidateApplicability
} }
interface CandidateFactory<out C: Candidate> { interface CandidateFactory<out C: Candidate> {
@@ -75,13 +75,13 @@ class TowerResolver {
scopeTower: ImplicitScopeTower, scopeTower: ImplicitScopeTower,
processor: ScopeTowerProcessor<C>, processor: ScopeTowerProcessor<C>,
useOrder: Boolean useOrder: Boolean
): Collection<C> = scopeTower.run(processor, SuccessfulResultCollector { it.status }, useOrder) ): Collection<C> = scopeTower.run(processor, SuccessfulResultCollector(), useOrder)
fun <C: Candidate> collectAllCandidates( fun <C: Candidate> collectAllCandidates(
scopeTower: ImplicitScopeTower, scopeTower: ImplicitScopeTower,
processor: ScopeTowerProcessor<C> processor: ScopeTowerProcessor<C>
): Collection<C> ): Collection<C>
= scopeTower.run(processor, AllCandidatesCollector { it.status }, false) = scopeTower.run(processor, AllCandidatesCollector(), false)
private fun ImplicitScopeTower.createNonLocalLevels(): List<ScopeTowerLevel> { private fun ImplicitScopeTower.createNonLocalLevels(): List<ScopeTowerLevel> {
val result = ArrayList<ScopeTowerLevel>() val result = ArrayList<ScopeTowerLevel>()
@@ -100,7 +100,7 @@ class TowerResolver {
return result return result
} }
private fun <C> ImplicitScopeTower.run( private fun <C : Candidate> ImplicitScopeTower.run(
processor: ScopeTowerProcessor<C>, processor: ScopeTowerProcessor<C>,
resultCollector: ResultCollector<C>, resultCollector: ResultCollector<C>,
useOrder: Boolean useOrder: Boolean
@@ -173,13 +173,13 @@ class TowerResolver {
return resultCollector.getFinalCandidates() return resultCollector.getFinalCandidates()
} }
fun <C> runWithEmptyTowerData( fun <C : Candidate> runWithEmptyTowerData(
processor: ScopeTowerProcessor<C>, processor: ScopeTowerProcessor<C>,
resultCollector: ResultCollector<C>, resultCollector: ResultCollector<C>,
useOrder: Boolean useOrder: Boolean
): Collection<C> = processTowerData(processor, resultCollector, useOrder, TowerData.Empty) ?: resultCollector.getFinalCandidates() ): Collection<C> = processTowerData(processor, resultCollector, useOrder, TowerData.Empty) ?: resultCollector.getFinalCandidates()
private fun <C> processTowerData( private fun <C : Candidate> processTowerData(
processor: ScopeTowerProcessor<C>, processor: ScopeTowerProcessor<C>,
resultCollector: ResultCollector<C>, resultCollector: ResultCollector<C>,
useOrder: Boolean, useOrder: Boolean,
@@ -203,14 +203,14 @@ class TowerResolver {
} }
abstract class ResultCollector<C>(protected val getStatus: (C) -> ResolutionCandidateStatus) { abstract class ResultCollector<C : Candidate> {
abstract fun getSuccessfulCandidates(): Collection<C>? abstract fun getSuccessfulCandidates(): Collection<C>?
abstract fun getFinalCandidates(): Collection<C> abstract fun getFinalCandidates(): Collection<C>
fun pushCandidates(candidates: Collection<C>) { fun pushCandidates(candidates: Collection<C>) {
val filteredCandidates = candidates.filter { val filteredCandidates = candidates.filter {
getStatus(it).resultingApplicability != ResolutionCandidateApplicability.HIDDEN it.resultingApplicability != ResolutionCandidateApplicability.HIDDEN
} }
if (filteredCandidates.isNotEmpty()) addCandidates(filteredCandidates) if (filteredCandidates.isNotEmpty()) addCandidates(filteredCandidates)
} }
@@ -218,7 +218,7 @@ class TowerResolver {
protected abstract fun addCandidates(candidates: Collection<C>) protected abstract fun addCandidates(candidates: Collection<C>)
} }
class AllCandidatesCollector<C>(getStatus: (C) -> ResolutionCandidateStatus): ResultCollector<C>(getStatus) { class AllCandidatesCollector<C : Candidate>: ResultCollector<C>() {
private val allCandidates = ArrayList<C>() private val allCandidates = ArrayList<C>()
override fun getSuccessfulCandidates(): Collection<C>? = null override fun getSuccessfulCandidates(): Collection<C>? = null
@@ -230,7 +230,7 @@ class TowerResolver {
} }
} }
class SuccessfulResultCollector<C>(getStatus: (C) -> ResolutionCandidateStatus): ResultCollector<C>(getStatus) { class SuccessfulResultCollector<C : Candidate>: ResultCollector<C>() {
private var currentCandidates: Collection<C> = emptyList() private var currentCandidates: Collection<C> = emptyList()
private var currentLevel: ResolutionCandidateApplicability? = null private var currentLevel: ResolutionCandidateApplicability? = null
@@ -247,10 +247,10 @@ class TowerResolver {
override fun getFinalCandidates() = getResolved() ?: getResolvedLowPriority() ?: getErrors() ?: emptyList() override fun getFinalCandidates() = getResolved() ?: getResolvedLowPriority() ?: getErrors() ?: emptyList()
override fun addCandidates(candidates: Collection<C>) { override fun addCandidates(candidates: Collection<C>) {
val minimalLevel = candidates.map { getStatus(it).resultingApplicability }.min()!! val minimalLevel = candidates.map { it.resultingApplicability }.min()!!
if (currentLevel == null || currentLevel!! > minimalLevel) { if (currentLevel == null || currentLevel!! > minimalLevel) {
currentLevel = minimalLevel currentLevel = minimalLevel
currentCandidates = candidates.filter { getStatus(it).resultingApplicability == minimalLevel } currentCandidates = candidates.filter { it.resultingApplicability == minimalLevel }
} }
} }
} }