Use the new type inference for top-level callable reference resolution
^KT-47797 Fixed ^KT-47987 Fixed ^KT-45034 Fixed ^KT-48446 Fixed ^KT-13934 Fixed
This commit is contained in:
@@ -7,12 +7,12 @@ package org.jetbrains.kotlin.resolve.calls
|
||||
|
||||
import org.jetbrains.kotlin.config.LanguageFeature
|
||||
import org.jetbrains.kotlin.progress.ProgressIndicatorAndCompilationCanceledStatus
|
||||
import org.jetbrains.kotlin.resolve.calls.components.CallableReferenceResolver
|
||||
import org.jetbrains.kotlin.resolve.calls.components.KotlinCallCompleter
|
||||
import org.jetbrains.kotlin.resolve.calls.components.KotlinResolutionCallbacks
|
||||
import org.jetbrains.kotlin.resolve.calls.components.NewOverloadingConflictResolver
|
||||
import org.jetbrains.kotlin.resolve.calls.components.*
|
||||
import org.jetbrains.kotlin.resolve.calls.components.candidate.ResolutionCandidate
|
||||
import org.jetbrains.kotlin.resolve.calls.components.candidate.CallableReferenceResolutionCandidate
|
||||
import org.jetbrains.kotlin.resolve.calls.components.candidate.SimpleResolutionCandidate
|
||||
import org.jetbrains.kotlin.resolve.calls.context.CheckArgumentTypesMode
|
||||
import org.jetbrains.kotlin.resolve.calls.inference.model.ConstraintStorage
|
||||
import org.jetbrains.kotlin.resolve.calls.model.*
|
||||
import org.jetbrains.kotlin.resolve.calls.tower.*
|
||||
import org.jetbrains.kotlin.resolve.descriptorUtil.OVERLOAD_RESOLUTION_BY_LAMBDA_ANNOTATION_FQ_NAME
|
||||
@@ -24,24 +24,116 @@ class KotlinCallResolver(
|
||||
private val towerResolver: TowerResolver,
|
||||
private val kotlinCallCompleter: KotlinCallCompleter,
|
||||
private val overloadingConflictResolver: NewOverloadingConflictResolver,
|
||||
private val callableReferenceResolver: CallableReferenceResolver,
|
||||
private val callableReferenceArgumentResolver: CallableReferenceArgumentResolver,
|
||||
private val callComponents: KotlinCallComponents
|
||||
) {
|
||||
fun resolveCall(
|
||||
fun resolveAndCompleteCall(
|
||||
scopeTower: ImplicitScopeTower,
|
||||
resolutionCallbacks: KotlinResolutionCallbacks,
|
||||
kotlinCall: KotlinCall,
|
||||
expectedType: UnwrappedType?,
|
||||
collectAllCandidates: Boolean,
|
||||
createFactoryProviderForInvoke: () -> CandidateFactoryProviderForInvoke<ResolutionCandidate>
|
||||
): CallResolutionResult {
|
||||
val candidateFactory = createFactory(scopeTower, kotlinCall, resolutionCallbacks, expectedType)
|
||||
val candidates = resolveCall(scopeTower, resolutionCallbacks, kotlinCall, collectAllCandidates, candidateFactory)
|
||||
|
||||
if (collectAllCandidates) {
|
||||
return kotlinCallCompleter.createAllCandidatesResult(candidates, expectedType, resolutionCallbacks)
|
||||
}
|
||||
|
||||
return kotlinCallCompleter.runCompletion(candidateFactory, candidates, expectedType, resolutionCallbacks)
|
||||
}
|
||||
|
||||
fun resolveAndCompleteGivenCandidates(
|
||||
scopeTower: ImplicitScopeTower,
|
||||
resolutionCallbacks: KotlinResolutionCallbacks,
|
||||
kotlinCall: KotlinCall,
|
||||
expectedType: UnwrappedType?,
|
||||
givenCandidates: Collection<GivenCandidate>,
|
||||
collectAllCandidates: Boolean
|
||||
): CallResolutionResult {
|
||||
ProgressIndicatorAndCompilationCanceledStatus.checkCanceled()
|
||||
|
||||
kotlinCall.checkCallInvariants()
|
||||
|
||||
val candidateFactory = SimpleCandidateFactory(
|
||||
callComponents, scopeTower, kotlinCall, resolutionCallbacks, callableReferenceResolver
|
||||
val candidateFactory = SimpleCandidateFactory(callComponents, scopeTower, kotlinCall, resolutionCallbacks)
|
||||
val resolutionCandidates = givenCandidates.map { candidateFactory.createCandidate(it).forceResolution() }
|
||||
|
||||
if (collectAllCandidates) {
|
||||
val allCandidates = towerResolver.runWithEmptyTowerData(
|
||||
KnownResultProcessor(resolutionCandidates),
|
||||
TowerResolver.AllCandidatesCollector(),
|
||||
useOrder = false
|
||||
)
|
||||
return kotlinCallCompleter.createAllCandidatesResult(allCandidates, expectedType, resolutionCallbacks)
|
||||
|
||||
}
|
||||
|
||||
val candidates = towerResolver.runWithEmptyTowerData(
|
||||
KnownResultProcessor(resolutionCandidates),
|
||||
TowerResolver.SuccessfulResultCollector(),
|
||||
useOrder = true
|
||||
)
|
||||
val mostSpecificCandidates = choseMostSpecific(kotlinCall, resolutionCallbacks, candidates)
|
||||
|
||||
return kotlinCallCompleter.runCompletion(candidateFactory, mostSpecificCandidates, expectedType, resolutionCallbacks)
|
||||
}
|
||||
|
||||
fun resolveCallableReferenceArgument(
|
||||
argument: CallableReferenceKotlinCallArgument,
|
||||
expectedType: UnwrappedType?,
|
||||
baseSystem: ConstraintStorage,
|
||||
resolutionCallbacks: KotlinResolutionCallbacks
|
||||
): Collection<CallableReferenceResolutionCandidate> {
|
||||
val scopeTower = callComponents.statelessCallbacks.getScopeTowerForCallableReferenceArgument(argument)
|
||||
val factory = createCallableReferenceCallFactory(scopeTower, argument.call, resolutionCallbacks, expectedType, argument, baseSystem)
|
||||
|
||||
return resolveCall(scopeTower, resolutionCallbacks, argument.call, collectAllCandidates = false, factory)
|
||||
}
|
||||
|
||||
private fun createCallableReferenceCallFactory(
|
||||
scopeTower: ImplicitScopeTower,
|
||||
kotlinCall: KotlinCall,
|
||||
resolutionCallbacks: KotlinResolutionCallbacks,
|
||||
expectedType: UnwrappedType?,
|
||||
argument: CallableReferenceKotlinCallArgument? = null,
|
||||
baseSystem: ConstraintStorage? = null
|
||||
): CandidateFactory<CallableReferenceResolutionCandidate> {
|
||||
val resolutionAtom = argument
|
||||
?: CallableReferenceKotlinCall(kotlinCall, resolutionCallbacks.getLhsResult(kotlinCall), kotlinCall.name)
|
||||
|
||||
return CallableReferencesCandidateFactory(resolutionAtom, callComponents, scopeTower, expectedType, baseSystem, resolutionCallbacks)
|
||||
}
|
||||
|
||||
private fun createSimpleCallFactory(
|
||||
scopeTower: ImplicitScopeTower,
|
||||
kotlinCall: KotlinCall,
|
||||
resolutionCallbacks: KotlinResolutionCallbacks,
|
||||
): CandidateFactory<ResolutionCandidate> = SimpleCandidateFactory(callComponents, scopeTower, kotlinCall, resolutionCallbacks)
|
||||
|
||||
private fun createFactory(
|
||||
scopeTower: ImplicitScopeTower,
|
||||
kotlinCall: KotlinCall,
|
||||
resolutionCallbacks: KotlinResolutionCallbacks,
|
||||
expectedType: UnwrappedType?
|
||||
): CandidateFactory<ResolutionCandidate> =
|
||||
when (kotlinCall.callKind) {
|
||||
KotlinCallKind.CALLABLE_REFERENCE -> createCallableReferenceCallFactory(scopeTower, kotlinCall, resolutionCallbacks, expectedType)
|
||||
else -> createSimpleCallFactory(scopeTower, kotlinCall, resolutionCallbacks)
|
||||
}
|
||||
|
||||
private fun <C : ResolutionCandidate> resolveCall(
|
||||
scopeTower: ImplicitScopeTower,
|
||||
resolutionCallbacks: KotlinResolutionCallbacks,
|
||||
kotlinCall: KotlinCall,
|
||||
collectAllCandidates: Boolean,
|
||||
candidateFactory: CandidateFactory<C>,
|
||||
): Collection<C> {
|
||||
ProgressIndicatorAndCompilationCanceledStatus.checkCanceled()
|
||||
|
||||
kotlinCall.checkCallInvariants()
|
||||
|
||||
@Suppress("UNCHECKED_CAST")
|
||||
val processor = when (kotlinCall.callKind) {
|
||||
KotlinCallKind.VARIABLE -> {
|
||||
createVariableAndObjectProcessor(scopeTower, kotlinCall.name, candidateFactory, kotlinCall.explicitReceiver?.receiver)
|
||||
@@ -51,9 +143,12 @@ class KotlinCallResolver(
|
||||
scopeTower,
|
||||
kotlinCall.name,
|
||||
candidateFactory,
|
||||
createFactoryProviderForInvoke(),
|
||||
resolutionCallbacks.getCandidateFactoryForInvoke(scopeTower, kotlinCall),
|
||||
kotlinCall.explicitReceiver?.receiver
|
||||
)
|
||||
) as ScopeTowerProcessor<C>
|
||||
}
|
||||
KotlinCallKind.CALLABLE_REFERENCE -> {
|
||||
createCallableReferenceProcessor(candidateFactory as CallableReferencesCandidateFactory) as ScopeTowerProcessor<C>
|
||||
}
|
||||
KotlinCallKind.INVOKE -> {
|
||||
createProcessorWithReceiverValueOrEmpty(kotlinCall.explicitReceiver?.receiver) {
|
||||
@@ -69,8 +164,7 @@ class KotlinCallResolver(
|
||||
}
|
||||
|
||||
if (collectAllCandidates) {
|
||||
val allCandidates = towerResolver.collectAllCandidates(scopeTower, processor, kotlinCall.name)
|
||||
return kotlinCallCompleter.createAllCandidatesResult(allCandidates, expectedType, resolutionCallbacks)
|
||||
return towerResolver.collectAllCandidates(scopeTower, processor, kotlinCall.name)
|
||||
}
|
||||
|
||||
val candidates = towerResolver.runResolve(
|
||||
@@ -80,73 +174,55 @@ class KotlinCallResolver(
|
||||
name = kotlinCall.name
|
||||
)
|
||||
|
||||
return choseMostSpecific(candidateFactory, resolutionCallbacks, expectedType, candidates)
|
||||
}
|
||||
|
||||
fun resolveGivenCandidates(
|
||||
scopeTower: ImplicitScopeTower,
|
||||
resolutionCallbacks: KotlinResolutionCallbacks,
|
||||
kotlinCall: KotlinCall,
|
||||
expectedType: UnwrappedType?,
|
||||
givenCandidates: Collection<GivenCandidate>,
|
||||
collectAllCandidates: Boolean
|
||||
): CallResolutionResult {
|
||||
ProgressIndicatorAndCompilationCanceledStatus.checkCanceled()
|
||||
|
||||
kotlinCall.checkCallInvariants()
|
||||
val candidateFactory = SimpleCandidateFactory(
|
||||
callComponents, scopeTower, kotlinCall, resolutionCallbacks, callableReferenceResolver
|
||||
)
|
||||
|
||||
val resolutionCandidates = givenCandidates.map { candidateFactory.createCandidate(it).forceResolution() }
|
||||
|
||||
if (collectAllCandidates) {
|
||||
val allCandidates = towerResolver.runWithEmptyTowerData(
|
||||
KnownResultProcessor(resolutionCandidates),
|
||||
TowerResolver.AllCandidatesCollector(),
|
||||
useOrder = false
|
||||
)
|
||||
return kotlinCallCompleter.createAllCandidatesResult(allCandidates, expectedType, resolutionCallbacks)
|
||||
|
||||
}
|
||||
val candidates = towerResolver.runWithEmptyTowerData(
|
||||
KnownResultProcessor(resolutionCandidates),
|
||||
TowerResolver.SuccessfulResultCollector(),
|
||||
useOrder = true
|
||||
)
|
||||
return choseMostSpecific(candidateFactory, resolutionCallbacks, expectedType, candidates)
|
||||
@Suppress("UNCHECKED_CAST")
|
||||
return choseMostSpecific(kotlinCall, resolutionCallbacks, candidates) as Set<C>
|
||||
}
|
||||
|
||||
private fun choseMostSpecific(
|
||||
candidateFactory: SimpleCandidateFactory,
|
||||
kotlinCall: KotlinCall,
|
||||
resolutionCallbacks: KotlinResolutionCallbacks,
|
||||
expectedType: UnwrappedType?,
|
||||
candidates: Collection<ResolutionCandidate>
|
||||
): CallResolutionResult {
|
||||
): Set<ResolutionCandidate> {
|
||||
var refinedCandidates = candidates
|
||||
if (!callComponents.languageVersionSettings.supportsFeature(LanguageFeature.RefinedSamAdaptersPriority)) {
|
||||
|
||||
if (!callComponents.languageVersionSettings.supportsFeature(LanguageFeature.RefinedSamAdaptersPriority) && kotlinCall.callKind != KotlinCallKind.CALLABLE_REFERENCE) {
|
||||
val nonSynthesized = candidates.filter { !it.resolvedCall.candidateDescriptor.isSynthesized }
|
||||
if (!nonSynthesized.isEmpty()) {
|
||||
if (nonSynthesized.isNotEmpty()) {
|
||||
refinedCandidates = nonSynthesized
|
||||
}
|
||||
}
|
||||
|
||||
var maximallySpecificCandidates = overloadingConflictResolver.chooseMaximallySpecificCandidates(
|
||||
refinedCandidates,
|
||||
CheckArgumentTypesMode.CHECK_VALUE_ARGUMENTS,
|
||||
discriminateGenerics = true // todo
|
||||
)
|
||||
var maximallySpecificCandidates = if (kotlinCall.callKind == KotlinCallKind.CALLABLE_REFERENCE) {
|
||||
@Suppress("UNCHECKED_CAST")
|
||||
callableReferenceArgumentResolver.callableReferenceOverloadConflictResolver.chooseMaximallySpecificCandidates(
|
||||
refinedCandidates as Collection<CallableReferenceResolutionCandidate>,
|
||||
CheckArgumentTypesMode.CHECK_VALUE_ARGUMENTS,
|
||||
discriminateGenerics = true
|
||||
)
|
||||
} else {
|
||||
overloadingConflictResolver.chooseMaximallySpecificCandidates(
|
||||
refinedCandidates,
|
||||
CheckArgumentTypesMode.CHECK_VALUE_ARGUMENTS,
|
||||
discriminateGenerics = true // todo
|
||||
)
|
||||
}
|
||||
|
||||
if (
|
||||
maximallySpecificCandidates.size > 1 &&
|
||||
callComponents.languageVersionSettings.supportsFeature(LanguageFeature.OverloadResolutionByLambdaReturnType) &&
|
||||
candidates.all { resolutionCallbacks.inferenceSession.shouldRunCompletion(it) }
|
||||
candidates.all { resolutionCallbacks.inferenceSession.shouldRunCompletion(it) } &&
|
||||
kotlinCall.callKind != KotlinCallKind.CALLABLE_REFERENCE
|
||||
) {
|
||||
val candidatesWithAnnotation =
|
||||
candidates.filter { it.resolvedCall.candidateDescriptor.annotations.hasAnnotation(OVERLOAD_RESOLUTION_BY_LAMBDA_ANNOTATION_FQ_NAME) }
|
||||
val candidatesWithAnnotation = candidates.filter {
|
||||
it.resolvedCall.candidateDescriptor.annotations.hasAnnotation(OVERLOAD_RESOLUTION_BY_LAMBDA_ANNOTATION_FQ_NAME)
|
||||
}.toSet()
|
||||
val candidatesWithoutAnnotation = candidates - candidatesWithAnnotation
|
||||
if (candidatesWithAnnotation.isNotEmpty()) {
|
||||
val newCandidates = kotlinCallCompleter.chooseCandidateRegardingOverloadResolutionByLambdaReturnType(maximallySpecificCandidates, resolutionCallbacks)
|
||||
@Suppress("UNCHECKED_CAST")
|
||||
val newCandidates = kotlinCallCompleter.chooseCandidateRegardingOverloadResolutionByLambdaReturnType(
|
||||
maximallySpecificCandidates as Set<SimpleResolutionCandidate>,
|
||||
resolutionCallbacks
|
||||
)
|
||||
maximallySpecificCandidates = overloadingConflictResolver.chooseMaximallySpecificCandidates(
|
||||
newCandidates,
|
||||
CheckArgumentTypesMode.CHECK_VALUE_ARGUMENTS,
|
||||
@@ -160,7 +236,6 @@ class KotlinCallResolver(
|
||||
}
|
||||
}
|
||||
|
||||
return kotlinCallCompleter.runCompletion(candidateFactory, maximallySpecificCandidates, expectedType, resolutionCallbacks)
|
||||
return maximallySpecificCandidates
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
+74
@@ -0,0 +1,74 @@
|
||||
/*
|
||||
* Copyright 2010-2021 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.calls.components
|
||||
|
||||
import org.jetbrains.kotlin.resolve.calls.inference.ConstraintSystemBuilder
|
||||
import org.jetbrains.kotlin.resolve.calls.inference.components.NewTypeSubstitutor
|
||||
import org.jetbrains.kotlin.resolve.calls.model.*
|
||||
import org.jetbrains.kotlin.resolve.calls.tower.isInapplicable
|
||||
|
||||
class CallableReferenceArgumentResolver(val callableReferenceOverloadConflictResolver: CallableReferenceOverloadConflictResolver) {
|
||||
fun processCallableReferenceArgument(
|
||||
csBuilder: ConstraintSystemBuilder,
|
||||
resolvedAtom: ResolvedCallableReferenceArgumentAtom,
|
||||
diagnosticsHolder: KotlinDiagnosticsHolder,
|
||||
resolutionCallbacks: KotlinResolutionCallbacks
|
||||
) {
|
||||
val argument = resolvedAtom.atom
|
||||
val expectedType = resolvedAtom.expectedType?.let { (csBuilder.buildCurrentSubstitutor() as NewTypeSubstitutor).safeSubstitute(it) }
|
||||
val candidates = resolutionCallbacks.resolveCallableReferenceArgument(resolvedAtom.atom, expectedType, csBuilder.currentStorage())
|
||||
|
||||
if (candidates.size > 1 && resolvedAtom is EagerCallableReferenceAtom) {
|
||||
if (candidates.all { it.resultingApplicability.isInapplicable }) {
|
||||
diagnosticsHolder.addDiagnostic(CallableReferenceCallCandidatesAmbiguity(argument, candidates))
|
||||
}
|
||||
|
||||
resolvedAtom.setAnalyzedResults(
|
||||
candidate = null,
|
||||
subResolvedAtoms = listOf(resolvedAtom.transformToPostponed())
|
||||
)
|
||||
return
|
||||
}
|
||||
|
||||
val chosenCandidate = candidates.singleOrNull()
|
||||
if (chosenCandidate != null) {
|
||||
val toFreshSubstitutor = CreateFreshVariablesSubstitutor.createToFreshVariableSubstitutorAndAddInitialConstraints(
|
||||
chosenCandidate.candidate,
|
||||
csBuilder
|
||||
)
|
||||
chosenCandidate.addConstraints(csBuilder, toFreshSubstitutor, callableReference = argument)
|
||||
chosenCandidate.diagnostics.forEach {
|
||||
val transformedDiagnostic = when (it) {
|
||||
is CompatibilityWarning -> CompatibilityWarningOnArgument(argument, it.candidate)
|
||||
else -> it
|
||||
}
|
||||
diagnosticsHolder.addDiagnostic(transformedDiagnostic)
|
||||
}
|
||||
chosenCandidate.freshVariablesSubstitutor = toFreshSubstitutor
|
||||
} else {
|
||||
if (candidates.isEmpty()) {
|
||||
diagnosticsHolder.addDiagnostic(NoneCallableReferenceCallCandidates(argument))
|
||||
} else {
|
||||
diagnosticsHolder.addDiagnostic(CallableReferenceCallCandidatesAmbiguity(argument, candidates))
|
||||
}
|
||||
}
|
||||
|
||||
// todo -- create this inside CallableReferencesCandidateFactory
|
||||
val subKtArguments = listOfNotNull(buildResolvedKtArgument(argument.lhsResult))
|
||||
|
||||
resolvedAtom.setAnalyzedResults(chosenCandidate, subKtArguments)
|
||||
}
|
||||
|
||||
private fun buildResolvedKtArgument(lhsResult: LHSResult): ResolvedAtom? {
|
||||
if (lhsResult !is LHSResult.Expression) return null
|
||||
return when (val lshCallArgument = lhsResult.lshCallArgument) {
|
||||
is SubKotlinCallArgument -> lshCallArgument.callResult
|
||||
is ExpressionKotlinCallArgument -> ResolvedExpressionAtom(lshCallArgument)
|
||||
else -> unexpectedArgument(lshCallArgument)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
+46
@@ -0,0 +1,46 @@
|
||||
/*
|
||||
* Copyright 2010-2021 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.calls.components
|
||||
|
||||
import org.jetbrains.kotlin.builtins.KotlinBuiltIns
|
||||
import org.jetbrains.kotlin.descriptors.ModuleDescriptor
|
||||
import org.jetbrains.kotlin.resolve.calls.components.candidate.CallableReferenceResolutionCandidate
|
||||
import org.jetbrains.kotlin.resolve.calls.inference.components.ConstraintInjector
|
||||
import org.jetbrains.kotlin.resolve.calls.results.*
|
||||
import org.jetbrains.kotlin.types.checker.KotlinTypeRefiner
|
||||
import org.jetbrains.kotlin.util.CancellationChecker
|
||||
|
||||
class CallableReferenceOverloadConflictResolver(
|
||||
builtIns: KotlinBuiltIns,
|
||||
module: ModuleDescriptor,
|
||||
specificityComparator: TypeSpecificityComparator,
|
||||
platformOverloadsSpecificityComparator: PlatformOverloadsSpecificityComparator,
|
||||
cancellationChecker: CancellationChecker,
|
||||
statelessCallbacks: KotlinResolutionStatelessCallbacks,
|
||||
constraintInjector: ConstraintInjector,
|
||||
kotlinTypeRefiner: KotlinTypeRefiner,
|
||||
) : OverloadingConflictResolver<CallableReferenceResolutionCandidate>(
|
||||
builtIns,
|
||||
module,
|
||||
specificityComparator,
|
||||
platformOverloadsSpecificityComparator,
|
||||
cancellationChecker,
|
||||
{ it.candidate },
|
||||
{ statelessCallbacks.createConstraintSystemForOverloadResolution(constraintInjector, builtIns) },
|
||||
Companion::createFlatSignature,
|
||||
{ null },
|
||||
{ statelessCallbacks.isDescriptorFromSource(it) },
|
||||
null,
|
||||
kotlinTypeRefiner,
|
||||
) {
|
||||
companion object {
|
||||
private fun createFlatSignature(candidate: CallableReferenceResolutionCandidate) =
|
||||
FlatSignature.createFromReflectionType(
|
||||
candidate, candidate.candidate, candidate.numDefaults, hasBoundExtensionReceiver = candidate.extensionReceiver != null,
|
||||
candidate.reflectionCandidateType
|
||||
)
|
||||
}
|
||||
}
|
||||
+17
-44
@@ -6,32 +6,19 @@
|
||||
package org.jetbrains.kotlin.resolve.calls.components
|
||||
|
||||
import org.jetbrains.kotlin.builtins.*
|
||||
import org.jetbrains.kotlin.config.ApiVersion
|
||||
import org.jetbrains.kotlin.config.LanguageFeature
|
||||
import org.jetbrains.kotlin.descriptors.*
|
||||
import org.jetbrains.kotlin.descriptors.annotations.Annotations
|
||||
import org.jetbrains.kotlin.resolve.calls.components.CreateFreshVariablesSubstitutor.createToFreshVariableSubstitutorAndAddInitialConstraints
|
||||
import org.jetbrains.kotlin.resolve.calls.components.candidate.CallableReferenceResolutionCandidate
|
||||
import org.jetbrains.kotlin.resolve.calls.inference.ConstraintSystemOperation
|
||||
import org.jetbrains.kotlin.resolve.calls.inference.components.FreshVariableNewTypeSubstitutor
|
||||
import org.jetbrains.kotlin.resolve.calls.inference.model.ArgumentConstraintPositionImpl
|
||||
import org.jetbrains.kotlin.resolve.calls.inference.model.*
|
||||
import org.jetbrains.kotlin.resolve.calls.model.*
|
||||
import org.jetbrains.kotlin.resolve.calls.tasks.ExplicitReceiverKind
|
||||
import org.jetbrains.kotlin.resolve.calls.tasks.ExplicitReceiverKind.DISPATCH_RECEIVER
|
||||
import org.jetbrains.kotlin.resolve.calls.tasks.ExplicitReceiverKind.EXTENSION_RECEIVER
|
||||
import org.jetbrains.kotlin.resolve.calls.tower.*
|
||||
import org.jetbrains.kotlin.resolve.descriptorUtil.builtIns
|
||||
import org.jetbrains.kotlin.resolve.descriptorUtil.isCompanionObject
|
||||
import org.jetbrains.kotlin.resolve.scopes.receivers.DetailedReceiver
|
||||
import org.jetbrains.kotlin.resolve.scopes.receivers.ReceiverValue
|
||||
import org.jetbrains.kotlin.resolve.scopes.receivers.ReceiverValueWithSmartCastInfo
|
||||
import org.jetbrains.kotlin.types.*
|
||||
import org.jetbrains.kotlin.types.checker.captureFromExpression
|
||||
import org.jetbrains.kotlin.types.expressions.CoercionStrategy
|
||||
import org.jetbrains.kotlin.types.typeUtil.immediateSupertypes
|
||||
import org.jetbrains.kotlin.types.typeUtil.isUnit
|
||||
import org.jetbrains.kotlin.types.typeUtil.supertypes
|
||||
import org.jetbrains.kotlin.utils.SmartList
|
||||
import org.jetbrains.kotlin.utils.addIfNotNull
|
||||
|
||||
sealed class CallableReceiver(val receiver: ReceiverValueWithSmartCastInfo) {
|
||||
class UnboundReference(receiver: ReceiverValueWithSmartCastInfo) : CallableReceiver(receiver)
|
||||
@@ -40,10 +27,6 @@ sealed class CallableReceiver(val receiver: ReceiverValueWithSmartCastInfo) {
|
||||
class ExplicitValueReceiver(receiver: ReceiverValueWithSmartCastInfo) : CallableReceiver(receiver)
|
||||
}
|
||||
|
||||
// todo investigate similar code in CheckVisibility
|
||||
private val CallableReceiver.asReceiverValueForVisibilityChecks: ReceiverValue
|
||||
get() = receiver.receiverValue
|
||||
|
||||
class CallableReferenceAdaptation(
|
||||
val argumentTypes: Array<KotlinType>,
|
||||
val coercionStrategy: CoercionStrategy,
|
||||
@@ -90,41 +73,31 @@ fun createCallableReferenceProcessor(factory: CallableReferencesCandidateFactory
|
||||
}
|
||||
}
|
||||
|
||||
fun ConstraintSystemOperation.checkCallableReference(
|
||||
argument: CallableReferenceKotlinCallArgument,
|
||||
dispatchReceiver: CallableReceiver?,
|
||||
extensionReceiver: CallableReceiver?,
|
||||
candidateDescriptor: CallableDescriptor,
|
||||
reflectionCandidateType: UnwrappedType,
|
||||
expectedType: UnwrappedType?,
|
||||
ownerDescriptor: DeclarationDescriptor
|
||||
): Pair<FreshVariableNewTypeSubstitutor, KotlinCallDiagnostic?> {
|
||||
val position = ArgumentConstraintPositionImpl(argument)
|
||||
|
||||
val toFreshSubstitutor = createToFreshVariableSubstitutorAndAddInitialConstraints(candidateDescriptor, this)
|
||||
|
||||
if (!ErrorUtils.isError(candidateDescriptor)) {
|
||||
addReceiverConstraint(toFreshSubstitutor, dispatchReceiver, candidateDescriptor.dispatchReceiverParameter, position)
|
||||
addReceiverConstraint(toFreshSubstitutor, extensionReceiver, candidateDescriptor.extensionReceiverParameter, position)
|
||||
fun CallableReferenceResolutionCandidate.addConstraints(
|
||||
constraintSystem: ConstraintSystemOperation,
|
||||
substitutor: FreshVariableNewTypeSubstitutor,
|
||||
callableReference: CallableReferenceResolutionAtom
|
||||
) {
|
||||
val position = when (callableReference) {
|
||||
is CallableReferenceKotlinCallArgument -> ArgumentConstraintPositionImpl(callableReference)
|
||||
is CallableReferenceKotlinCall -> CallableReferenceConstraintPositionImpl(callableReference)
|
||||
}
|
||||
|
||||
if (expectedType != null && !hasContradiction) {
|
||||
addSubtypeConstraint(toFreshSubstitutor.safeSubstitute(reflectionCandidateType), expectedType, position)
|
||||
if (!ErrorUtils.isError(candidate)) {
|
||||
constraintSystem.addReceiverConstraint(substitutor, dispatchReceiver, candidate.dispatchReceiverParameter, position)
|
||||
constraintSystem.addReceiverConstraint(substitutor, extensionReceiver, candidate.extensionReceiverParameter, position)
|
||||
}
|
||||
|
||||
val invisibleMember = DescriptorVisibilities.findInvisibleMember(
|
||||
dispatchReceiver?.asReceiverValueForVisibilityChecks,
|
||||
candidateDescriptor, ownerDescriptor
|
||||
)
|
||||
return toFreshSubstitutor to invisibleMember?.let(::VisibilityError)
|
||||
if (expectedType != null && !TypeUtils.noExpectedType(expectedType) && !constraintSystem.hasContradiction) {
|
||||
constraintSystem.addSubtypeConstraint(substitutor.safeSubstitute(reflectionCandidateType), expectedType, position)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
private fun ConstraintSystemOperation.addReceiverConstraint(
|
||||
toFreshSubstitutor: FreshVariableNewTypeSubstitutor,
|
||||
receiverArgument: CallableReceiver?,
|
||||
receiverParameter: ReceiverParameterDescriptor?,
|
||||
position: ArgumentConstraintPositionImpl
|
||||
position: ConstraintPosition
|
||||
) {
|
||||
if (receiverArgument == null || receiverParameter == null) {
|
||||
assert(receiverArgument == null) { "Receiver argument should be null if parameter is: $receiverArgument" }
|
||||
|
||||
-162
@@ -1,162 +0,0 @@
|
||||
/*
|
||||
* Copyright 2010-2017 JetBrains s.r.o.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.jetbrains.kotlin.resolve.calls.components
|
||||
|
||||
import org.jetbrains.kotlin.builtins.KotlinBuiltIns
|
||||
import org.jetbrains.kotlin.descriptors.ModuleDescriptor
|
||||
import org.jetbrains.kotlin.resolve.calls.context.CheckArgumentTypesMode
|
||||
import org.jetbrains.kotlin.resolve.calls.inference.ConstraintSystemBuilder
|
||||
import org.jetbrains.kotlin.resolve.calls.inference.ConstraintSystemOperation
|
||||
import org.jetbrains.kotlin.resolve.calls.inference.components.ConstraintInjector
|
||||
import org.jetbrains.kotlin.resolve.calls.inference.components.NewTypeSubstitutor
|
||||
import org.jetbrains.kotlin.resolve.calls.model.*
|
||||
import org.jetbrains.kotlin.resolve.calls.results.*
|
||||
import org.jetbrains.kotlin.resolve.calls.tower.ImplicitScopeTower
|
||||
import org.jetbrains.kotlin.resolve.calls.tower.TowerResolver
|
||||
import org.jetbrains.kotlin.resolve.calls.tower.isInapplicable
|
||||
import org.jetbrains.kotlin.types.UnwrappedType
|
||||
import org.jetbrains.kotlin.types.checker.KotlinTypeRefiner
|
||||
import org.jetbrains.kotlin.util.CancellationChecker
|
||||
|
||||
|
||||
class CallableReferenceOverloadConflictResolver(
|
||||
builtIns: KotlinBuiltIns,
|
||||
module: ModuleDescriptor,
|
||||
specificityComparator: TypeSpecificityComparator,
|
||||
platformOverloadsSpecificityComparator: PlatformOverloadsSpecificityComparator,
|
||||
cancellationChecker: CancellationChecker,
|
||||
statelessCallbacks: KotlinResolutionStatelessCallbacks,
|
||||
constraintInjector: ConstraintInjector,
|
||||
kotlinTypeRefiner: KotlinTypeRefiner,
|
||||
) : OverloadingConflictResolver<CallableReferenceCandidate>(
|
||||
builtIns,
|
||||
module,
|
||||
specificityComparator,
|
||||
platformOverloadsSpecificityComparator,
|
||||
cancellationChecker,
|
||||
{ it.candidate },
|
||||
{ statelessCallbacks.createConstraintSystemForOverloadResolution(constraintInjector, builtIns) },
|
||||
Companion::createFlatSignature,
|
||||
{ null },
|
||||
{ statelessCallbacks.isDescriptorFromSource(it) },
|
||||
null,
|
||||
kotlinTypeRefiner,
|
||||
) {
|
||||
companion object {
|
||||
private fun createFlatSignature(candidate: CallableReferenceCandidate) =
|
||||
FlatSignature.createFromReflectionType(
|
||||
candidate, candidate.candidate, candidate.numDefaults, hasBoundExtensionReceiver = candidate.extensionReceiver != null,
|
||||
candidate.reflectionCandidateType
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
class CallableReferenceResolver(
|
||||
private val towerResolver: TowerResolver,
|
||||
private val callableReferenceOverloadConflictResolver: CallableReferenceOverloadConflictResolver,
|
||||
private val callComponents: KotlinCallComponents
|
||||
) {
|
||||
|
||||
fun processCallableReferenceArgument(
|
||||
csBuilder: ConstraintSystemBuilder,
|
||||
resolvedAtom: ResolvedCallableReferenceAtom,
|
||||
diagnosticsHolder: KotlinDiagnosticsHolder,
|
||||
resolutionCallbacks: KotlinResolutionCallbacks
|
||||
) {
|
||||
val argument = resolvedAtom.atom
|
||||
val expectedType = resolvedAtom.expectedType?.let { (csBuilder.buildCurrentSubstitutor() as NewTypeSubstitutor).safeSubstitute(it) }
|
||||
|
||||
val scopeTower = callComponents.statelessCallbacks.getScopeTowerForCallableReferenceArgument(argument)
|
||||
val candidates = runRHSResolution(scopeTower, argument, expectedType, csBuilder, resolutionCallbacks) { checkCallableReference ->
|
||||
csBuilder.runTransaction { checkCallableReference(this); false }
|
||||
}
|
||||
|
||||
if (candidates.size > 1 && resolvedAtom is EagerCallableReferenceAtom) {
|
||||
if (candidates.all { it.resultingApplicability.isInapplicable }) {
|
||||
diagnosticsHolder.addDiagnostic(CallableReferenceCandidatesAmbiguity(argument, candidates))
|
||||
}
|
||||
|
||||
resolvedAtom.setAnalyzedResults(
|
||||
candidate = null,
|
||||
subResolvedAtoms = listOf(resolvedAtom.transformToPostponed())
|
||||
)
|
||||
return
|
||||
}
|
||||
|
||||
val chosenCandidate = candidates.singleOrNull()
|
||||
if (chosenCandidate != null) {
|
||||
val (toFreshSubstitutor, diagnostic) = with(chosenCandidate) {
|
||||
csBuilder.checkCallableReference(
|
||||
argument, dispatchReceiver, extensionReceiver, candidate,
|
||||
reflectionCandidateType, expectedType, scopeTower.lexicalScope.ownerDescriptor
|
||||
)
|
||||
}
|
||||
diagnosticsHolder.addDiagnosticIfNotNull(diagnostic)
|
||||
chosenCandidate.diagnostics.forEach {
|
||||
val transformedDiagnostic = when (it) {
|
||||
is CompatibilityWarning -> CompatibilityWarningOnArgument(argument, it.candidate)
|
||||
else -> it
|
||||
}
|
||||
diagnosticsHolder.addDiagnostic(transformedDiagnostic)
|
||||
}
|
||||
chosenCandidate.freshSubstitutor = toFreshSubstitutor
|
||||
} else {
|
||||
if (candidates.isEmpty()) {
|
||||
diagnosticsHolder.addDiagnostic(NoneCallableReferenceCandidates(argument))
|
||||
} else {
|
||||
diagnosticsHolder.addDiagnostic(CallableReferenceCandidatesAmbiguity(argument, candidates))
|
||||
}
|
||||
}
|
||||
|
||||
// todo -- create this inside CallableReferencesCandidateFactory
|
||||
val subKtArguments = listOfNotNull(buildResolvedKtArgument(argument.lhsResult))
|
||||
|
||||
resolvedAtom.setAnalyzedResults(chosenCandidate, subKtArguments)
|
||||
}
|
||||
|
||||
private fun buildResolvedKtArgument(lhsResult: LHSResult): ResolvedAtom? {
|
||||
if (lhsResult !is LHSResult.Expression) return null
|
||||
val lshCallArgument = lhsResult.lshCallArgument
|
||||
return when (lshCallArgument) {
|
||||
is SubKotlinCallArgument -> lshCallArgument.callResult
|
||||
is ExpressionKotlinCallArgument -> ResolvedExpressionAtom(lshCallArgument)
|
||||
else -> unexpectedArgument(lshCallArgument)
|
||||
}
|
||||
}
|
||||
|
||||
private fun runRHSResolution(
|
||||
scopeTower: ImplicitScopeTower,
|
||||
callableReference: CallableReferenceKotlinCallArgument,
|
||||
expectedType: UnwrappedType?, // this type can have not fixed type variable inside
|
||||
csBuilder: ConstraintSystemBuilder,
|
||||
resolutionCallbacks: KotlinResolutionCallbacks,
|
||||
compatibilityChecker: ((ConstraintSystemOperation) -> Unit) -> Unit // you can run anything throw this operation and all this operation will be rolled back
|
||||
): Set<CallableReferenceCandidate> {
|
||||
val factory = CallableReferencesCandidateFactory(
|
||||
callableReference, callComponents, scopeTower, compatibilityChecker, expectedType, csBuilder, resolutionCallbacks
|
||||
)
|
||||
val processor = createCallableReferenceProcessor(factory)
|
||||
val candidates = towerResolver.runResolve(scopeTower, processor, useOrder = true, name = callableReference.rhsName)
|
||||
return callableReferenceOverloadConflictResolver.chooseMaximallySpecificCandidates(
|
||||
candidates,
|
||||
CheckArgumentTypesMode.CHECK_VALUE_ARGUMENTS,
|
||||
discriminateGenerics = false // we can't specify generics explicitly for callable references
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
+2
-1
@@ -5,6 +5,7 @@
|
||||
|
||||
package org.jetbrains.kotlin.resolve.calls.components
|
||||
|
||||
import org.jetbrains.kotlin.resolve.calls.components.candidate.ResolutionCandidate
|
||||
import org.jetbrains.kotlin.resolve.calls.inference.components.ConstraintSystemCompletionContext
|
||||
import org.jetbrains.kotlin.resolve.calls.inference.components.KotlinConstraintSystemCompleter
|
||||
import org.jetbrains.kotlin.resolve.calls.inference.components.ConstraintSystemCompletionMode
|
||||
@@ -42,7 +43,7 @@ class CompletionModeCalculator {
|
||||
if (returnType == null) return ConstraintSystemCompletionMode.PARTIAL
|
||||
|
||||
// Full if return type for call has no type variables
|
||||
if (csBuilder.isProperType(returnType)) return ConstraintSystemCompletionMode.FULL
|
||||
if (getSystem().getBuilder().isProperType(returnType)) return ConstraintSystemCompletionMode.FULL
|
||||
|
||||
// For nested call with variables in return type check possibility of full completion
|
||||
return CalculatorForNestedCall(
|
||||
|
||||
+17
-1
@@ -11,10 +11,15 @@ import org.jetbrains.kotlin.descriptors.CallableDescriptor
|
||||
import org.jetbrains.kotlin.descriptors.DeclarationDescriptor
|
||||
import org.jetbrains.kotlin.descriptors.ValueParameterDescriptor
|
||||
import org.jetbrains.kotlin.descriptors.annotations.Annotations
|
||||
import org.jetbrains.kotlin.resolve.calls.components.candidate.ResolutionCandidate
|
||||
import org.jetbrains.kotlin.resolve.calls.components.candidate.CallableReferenceResolutionCandidate
|
||||
import org.jetbrains.kotlin.resolve.calls.components.candidate.SimpleResolutionCandidate
|
||||
import org.jetbrains.kotlin.resolve.calls.inference.components.ConstraintInjector
|
||||
import org.jetbrains.kotlin.resolve.calls.inference.model.ConstraintStorage
|
||||
import org.jetbrains.kotlin.resolve.calls.inference.model.NewTypeVariable
|
||||
import org.jetbrains.kotlin.resolve.calls.model.*
|
||||
import org.jetbrains.kotlin.resolve.calls.results.SimpleConstraintSystem
|
||||
import org.jetbrains.kotlin.resolve.calls.tower.CandidateFactoryProviderForInvoke
|
||||
import org.jetbrains.kotlin.resolve.calls.tower.ImplicitScopeTower
|
||||
import org.jetbrains.kotlin.resolve.constants.IntegerValueTypeConstant
|
||||
import org.jetbrains.kotlin.types.KotlinType
|
||||
@@ -37,7 +42,7 @@ interface KotlinResolutionStatelessCallbacks {
|
||||
|
||||
fun isSuperExpression(receiver: SimpleKotlinCallArgument?): Boolean
|
||||
fun getScopeTowerForCallableReferenceArgument(argument: CallableReferenceKotlinCallArgument): ImplicitScopeTower
|
||||
fun getVariableCandidateIfInvoke(functionCall: KotlinCall): KotlinResolutionCandidate?
|
||||
fun getVariableCandidateIfInvoke(functionCall: KotlinCall): ResolutionCandidate?
|
||||
fun isBuilderInferenceCall(argument: KotlinCallArgument, parameter: ValueParameterDescriptor): Boolean
|
||||
fun isApplicableCallForBuilderInference(descriptor: CallableDescriptor, languageVersionSettings: LanguageVersionSettings): Boolean
|
||||
|
||||
@@ -77,6 +82,17 @@ interface KotlinResolutionCallbacks {
|
||||
stubsForPostponedVariables: Map<NewTypeVariable, StubTypeForBuilderInference>,
|
||||
): ReturnArgumentsAnalysisResult
|
||||
|
||||
fun getCandidateFactoryForInvoke(
|
||||
scopeTower: ImplicitScopeTower,
|
||||
kotlinCall: KotlinCall,
|
||||
): CandidateFactoryProviderForInvoke<ResolutionCandidate>
|
||||
|
||||
fun resolveCallableReferenceArgument(
|
||||
argument: CallableReferenceKotlinCallArgument,
|
||||
expectedType: UnwrappedType?,
|
||||
baseSystem: ConstraintStorage,
|
||||
): Collection<CallableReferenceResolutionCandidate>
|
||||
|
||||
fun bindStubResolvedCallForCandidate(candidate: ResolvedCallAtom)
|
||||
|
||||
fun isCompileTimeConstant(resolvedAtom: ResolvedCallAtom, expectedType: UnwrappedType): Boolean
|
||||
|
||||
+29
-14
@@ -20,6 +20,7 @@ import org.jetbrains.kotlin.resolve.calls.inference.components.TrivialConstraint
|
||||
import org.jetbrains.kotlin.resolve.calls.inference.model.ConstraintStorage.Empty.hasContradiction
|
||||
import org.jetbrains.kotlin.resolve.calls.inference.model.ExpectedTypeConstraintPositionImpl
|
||||
import org.jetbrains.kotlin.resolve.calls.model.*
|
||||
import org.jetbrains.kotlin.resolve.calls.tower.CandidateFactory
|
||||
import org.jetbrains.kotlin.resolve.calls.tower.forceResolution
|
||||
import org.jetbrains.kotlin.types.ErrorUtils
|
||||
import org.jetbrains.kotlin.types.TypeUtils
|
||||
@@ -40,22 +41,27 @@ class KotlinCallCompleter(
|
||||
resolutionCallbacks: KotlinResolutionCallbacks
|
||||
): CallResolutionResult {
|
||||
val diagnosticHolder = KotlinDiagnosticsHolder.SimpleHolder()
|
||||
|
||||
when {
|
||||
candidates.isEmpty() -> diagnosticHolder.addDiagnostic(NoneCandidatesCallDiagnostic(factory.kotlinCall))
|
||||
candidates.size > 1 -> diagnosticHolder.addDiagnostic(ManyCandidatesCallDiagnostic(factory.kotlinCall, candidates))
|
||||
candidates.isEmpty() -> diagnosticHolder.addDiagnostic(NoneCandidatesCallDiagnostic())
|
||||
candidates.size > 1 -> diagnosticHolder.addDiagnostic(ManyCandidatesCallDiagnostic(candidates))
|
||||
}
|
||||
|
||||
val candidate = prepareCandidateForCompletion(factory, candidates, resolutionCallbacks)
|
||||
val returnType = candidate.substitutedReturnType()
|
||||
val resultType = when (candidate) {
|
||||
is SimpleResolutionCandidate -> {
|
||||
candidate.checkSamWithVararg(diagnosticHolder)
|
||||
candidate.substitutedReturnType().also {
|
||||
candidate.addExpectedTypeConstraint(it, expectedType)
|
||||
candidate.addExpectedTypeFromCastConstraint(it, resolutionCallbacks)
|
||||
}
|
||||
}
|
||||
is CallableReferenceResolutionCandidate -> candidate.substitutedReflectionType()
|
||||
}
|
||||
|
||||
candidate.addExpectedTypeConstraint(returnType, expectedType)
|
||||
candidate.addExpectedTypeFromCastConstraint(returnType, resolutionCallbacks)
|
||||
candidate.checkSamWithVararg(diagnosticHolder)
|
||||
|
||||
val completionMode =
|
||||
CompletionModeCalculator.computeCompletionMode(
|
||||
candidate, expectedType, returnType, trivialConstraintTypeInferenceOracle, resolutionCallbacks.inferenceSession
|
||||
)
|
||||
val completionMode = CompletionModeCalculator.computeCompletionMode(
|
||||
candidate, expectedType, resultType, trivialConstraintTypeInferenceOracle, resolutionCallbacks.inferenceSession
|
||||
)
|
||||
|
||||
return when (completionMode) {
|
||||
ConstraintSystemCompletionMode.FULL -> {
|
||||
@@ -151,7 +157,7 @@ class KotlinCallCompleter(
|
||||
|
||||
private fun SimpleResolutionCandidate.getInputTypesOfLambdaAtom(atom: ResolvedLambdaAtom): List<UnwrappedType> {
|
||||
val result = mutableListOf<UnwrappedType>()
|
||||
val substitutor = csBuilder.buildCurrentSubstitutor()
|
||||
val substitutor = getSystem().getBuilder().buildCurrentSubstitutor()
|
||||
val ctx = getSystem().asConstraintSystemCompleterContext()
|
||||
for (inputType in atom.inputTypes) {
|
||||
result += substitutor.safeSubstitute(ctx, inputType) as UnwrappedType
|
||||
@@ -198,7 +204,7 @@ class KotlinCallCompleter(
|
||||
collectAllCandidatesMode = true
|
||||
)
|
||||
|
||||
CandidateWithDiagnostics(candidate, diagnosticsHolder.getDiagnostics() + candidate.diagnosticsFromResolutionParts)
|
||||
CandidateWithDiagnostics(candidate, diagnosticsHolder.getDiagnostics() + candidate.diagnostics)
|
||||
}
|
||||
return AllCandidatesResolutionResult(completedCandidates)
|
||||
}
|
||||
@@ -264,6 +270,10 @@ class KotlinCallCompleter(
|
||||
return candidate ?: factory.createErrorCandidate().forceResolution()
|
||||
}
|
||||
|
||||
private fun CallableReferenceResolutionCandidate.substitutedReflectionType(): UnwrappedType {
|
||||
return resolvedCall.freshVariablesSubstitutor.safeSubstitute(this.reflectionCandidateType)
|
||||
}
|
||||
|
||||
private fun ResolutionCandidate.substitutedReturnType(): UnwrappedType? {
|
||||
val returnType = resolvedCall.candidateDescriptor.returnType?.unwrap() ?: return null
|
||||
return resolvedCall.freshVariablesSubstitutor.safeSubstitute(returnType)
|
||||
@@ -276,6 +286,8 @@ class KotlinCallCompleter(
|
||||
if (returnType == null) return
|
||||
if (expectedType == null || (TypeUtils.noExpectedType(expectedType) && expectedType !== TypeUtils.UNIT_EXPECTED_TYPE)) return
|
||||
|
||||
val csBuilder = getSystem().getBuilder()
|
||||
|
||||
when {
|
||||
csBuilder.currentStorage().notFixedTypeVariables.isEmpty() -> {
|
||||
// This is needed to avoid multiple mismatch errors as we type check resulting type against expected one later
|
||||
@@ -304,7 +316,10 @@ class KotlinCallCompleter(
|
||||
) {
|
||||
if (!callComponents.languageVersionSettings.supportsFeature(LanguageFeature.ExpectedTypeFromCast)) return
|
||||
if (returnType == null) return
|
||||
|
||||
val expectedType = resolutionCallbacks.getExpectedTypeFromAsExpressionAndRecordItInTrace(resolvedCall) ?: return
|
||||
val csBuilder = getSystem().getBuilder()
|
||||
|
||||
csBuilder.addSubtypeConstraint(returnType, expectedType, ExpectedTypeConstraintPositionImpl(resolvedCall.atom))
|
||||
}
|
||||
|
||||
@@ -314,7 +329,7 @@ class KotlinCallCompleter(
|
||||
forwardToInferenceSession: Boolean = false
|
||||
): CallResolutionResult {
|
||||
val systemStorage = getSystem().asReadOnlyStorage()
|
||||
val allDiagnostics = diagnosticsHolder.getDiagnostics() + diagnosticsFromResolutionParts
|
||||
val allDiagnostics = diagnosticsHolder.getDiagnostics() + diagnostics
|
||||
|
||||
if (isErrorCandidate()) {
|
||||
return ErrorCallResolutionResult(resolvedCall, allDiagnostics, systemStorage)
|
||||
|
||||
+5
-3
@@ -25,7 +25,7 @@ import org.jetbrains.kotlin.types.typeUtil.builtIns
|
||||
import org.jetbrains.kotlin.utils.addToStdlib.cast
|
||||
|
||||
class PostponedArgumentsAnalyzer(
|
||||
private val callableReferenceResolver: CallableReferenceResolver,
|
||||
private val callableReferenceArgumentResolver: CallableReferenceArgumentResolver,
|
||||
private val languageVersionSettings: LanguageVersionSettings
|
||||
) {
|
||||
|
||||
@@ -49,8 +49,10 @@ class PostponedArgumentsAnalyzer(
|
||||
diagnosticsHolder
|
||||
)
|
||||
|
||||
is ResolvedCallableReferenceAtom ->
|
||||
callableReferenceResolver.processCallableReferenceArgument(c.getBuilder(), argument, diagnosticsHolder, resolutionCallbacks)
|
||||
is ResolvedCallableReferenceArgumentAtom ->
|
||||
callableReferenceArgumentResolver.processCallableReferenceArgument(
|
||||
c.getBuilder(), argument, diagnosticsHolder, resolutionCallbacks
|
||||
)
|
||||
|
||||
is ResolvedCollectionLiteralAtom -> TODO("Not supported")
|
||||
|
||||
|
||||
+26
-6
@@ -119,6 +119,7 @@ internal object NoArguments : ResolutionPart() {
|
||||
|
||||
internal object CreateFreshVariablesSubstitutor : ResolutionPart() {
|
||||
override fun ResolutionCandidate.process(workIndex: Int) {
|
||||
val csBuilder = getSystem().getBuilder()
|
||||
val toFreshVariables =
|
||||
if (candidateDescriptor.typeParameters.isEmpty())
|
||||
FreshVariableNewTypeSubstitutor.Empty
|
||||
@@ -126,7 +127,7 @@ internal object CreateFreshVariablesSubstitutor : ResolutionPart() {
|
||||
createToFreshVariableSubstitutorAndAddInitialConstraints(candidateDescriptor, csBuilder)
|
||||
|
||||
val knownTypeParametersSubstitutor = knownTypeParametersResultingSubstitutor?.let {
|
||||
createKnownParametersFromFreshVariablesSubstitutor(toFreshVariables, knownTypeParametersResultingSubstitutor)
|
||||
createKnownParametersFromFreshVariablesSubstitutor(toFreshVariables, it)
|
||||
} ?: EmptySubstitutor
|
||||
|
||||
resolvedCall.freshVariablesSubstitutor = toFreshVariables
|
||||
@@ -275,6 +276,7 @@ internal object CreateFreshVariablesSubstitutor : ResolutionPart() {
|
||||
|
||||
internal object PostponedVariablesInitializerResolutionPart : ResolutionPart() {
|
||||
override fun ResolutionCandidate.process(workIndex: Int) {
|
||||
val csBuilder = getSystem().getBuilder()
|
||||
for ((argument, parameter) in resolvedCall.argumentToCandidateParameter) {
|
||||
if (!callComponents.statelessCallbacks.isBuilderInferenceCall(argument, parameter)) continue
|
||||
val receiverType = parameter.type.getReceiverTypeFromFunctionType() ?: continue
|
||||
@@ -302,6 +304,7 @@ internal object PostponedVariablesInitializerResolutionPart : ResolutionPart() {
|
||||
|
||||
internal object CompatibilityOfTypeVariableAsIntersectionTypePart : ResolutionPart() {
|
||||
override fun ResolutionCandidate.process(workIndex: Int) {
|
||||
val csBuilder = getSystem().getBuilder()
|
||||
for ((_, variableWithConstraints) in csBuilder.currentStorage().notFixedTypeVariables) {
|
||||
val constraints = variableWithConstraints.constraints.filter { csBuilder.isProperType(it.type) }
|
||||
|
||||
@@ -487,13 +490,14 @@ internal object CollectionTypeVariableUsagesInfo : ResolutionPart() {
|
||||
|
||||
override fun ResolutionCandidate.process(workIndex: Int) {
|
||||
for (variable in resolvedCall.freshVariablesSubstitutor.freshVariables) {
|
||||
if (resolvedCall.candidateDescriptor is ClassConstructorDescriptor) {
|
||||
val typeParameters = resolvedCall.candidateDescriptor.containingDeclaration.declaredTypeParameters
|
||||
val candidateDescriptor = resolvedCall.candidateDescriptor
|
||||
if (candidateDescriptor is ClassConstructorDescriptor) {
|
||||
val typeParameters = candidateDescriptor.containingDeclaration.declaredTypeParameters
|
||||
|
||||
if (isContainedInInvariantOrContravariantPositionsAmongTypeParameters(variable, typeParameters)) {
|
||||
variable.recordInfoAboutTypeVariableUsagesAsInvariantOrContravariantParameter()
|
||||
}
|
||||
} else if (getSystem().isContainedInInvariantOrContravariantPositionsWithDependencies(variable, candidateDescriptor)) {
|
||||
} else if (getSystem().isContainedInInvariantOrContravariantPositionsWithDependencies(variable, this.candidateDescriptor)) {
|
||||
variable.recordInfoAboutTypeVariableUsagesAsInvariantOrContravariantParameter()
|
||||
}
|
||||
}
|
||||
@@ -505,6 +509,7 @@ private fun ResolutionCandidate.resolveKotlinArgument(
|
||||
candidateParameter: ParameterDescriptor?,
|
||||
receiverInfo: ReceiverInfo
|
||||
) {
|
||||
val csBuilder = getSystem().getBuilder()
|
||||
val candidateExpectedType = candidateParameter?.let { argument.getExpectedType(it, callComponents.languageVersionSettings) }
|
||||
|
||||
val isReceiver = receiverInfo.isReceiver
|
||||
@@ -602,6 +607,7 @@ private fun ResolutionCandidate.resolveKotlinArgument(
|
||||
|
||||
private fun ResolutionCandidate.shouldRunConversionForConstants(expectedType: UnwrappedType): Boolean {
|
||||
if (UnsignedTypes.isUnsignedType(expectedType)) return true
|
||||
val csBuilder = getSystem().getBuilder()
|
||||
if (csBuilder.isTypeVariable(expectedType)) {
|
||||
val variableWithConstraints = csBuilder.currentStorage().notFixedTypeVariables[expectedType.constructor] ?: return false
|
||||
return variableWithConstraints.constraints.any {
|
||||
@@ -650,7 +656,7 @@ internal object CheckReceivers : ResolutionPart() {
|
||||
receiverParameter: ReceiverParameterDescriptor?,
|
||||
shouldCheckImplicitInvoke: Boolean,
|
||||
) {
|
||||
if ((receiverArgument == null) != (receiverParameter == null)) {
|
||||
if (this !is CallableReferenceResolutionCandidate && (receiverArgument == null) != (receiverParameter == null)) {
|
||||
error("Inconsistency receiver state for call $kotlinCall and candidate descriptor: $candidateDescriptor")
|
||||
}
|
||||
if (receiverArgument == null || receiverParameter == null) return
|
||||
@@ -709,11 +715,25 @@ internal object EagerResolveOfCallableReferences : ResolutionPart() {
|
||||
getSubResolvedAtoms()
|
||||
.filterIsInstance<EagerCallableReferenceAtom>()
|
||||
.forEach {
|
||||
callableReferenceResolver.processCallableReferenceArgument(csBuilder, it, this, resolutionCallbacks)
|
||||
callComponents.callableReferenceArgumentResolver.processCallableReferenceArgument(
|
||||
getSystem().getBuilder(), it, this, resolutionCallbacks
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
internal object CheckCallableReference : ResolutionPart() {
|
||||
override fun ResolutionCandidate.process(workIndex: Int) {
|
||||
if (this !is CallableReferenceResolutionCandidate) {
|
||||
error("`CheckCallableReferences` resolution part is applicable only to callable reference calls")
|
||||
}
|
||||
|
||||
val constraintSystem = getSystem().takeIf { !it.hasContradiction } ?: return
|
||||
|
||||
addConstraints(constraintSystem.getBuilder(), resolvedCall.freshVariablesSubstitutor, kotlinCall)
|
||||
}
|
||||
}
|
||||
|
||||
internal object CheckInfixResolutionPart : ResolutionPart() {
|
||||
override fun ResolutionCandidate.process(workIndex: Int) {
|
||||
val candidateDescriptor = resolvedCall.candidateDescriptor
|
||||
|
||||
+4
-2
@@ -28,8 +28,10 @@ object UnitTypeConversions : ParameterTypeConversion {
|
||||
if (argument !is SimpleKotlinCallArgument) return true
|
||||
|
||||
val receiver = argument.receiver
|
||||
if (receiver.receiverValue.type.hasUnitOrSubtypeReturnType(candidate.csBuilder)) return true
|
||||
if (receiver.typesFromSmartCasts.any { it.hasUnitOrSubtypeReturnType(candidate.csBuilder) }) return true
|
||||
val csBuilder = candidate.getSystem().getBuilder()
|
||||
|
||||
if (receiver.receiverValue.type.hasUnitOrSubtypeReturnType(csBuilder)) return true
|
||||
if (receiver.typesFromSmartCasts.any { it.hasUnitOrSubtypeReturnType(csBuilder) }) return true
|
||||
|
||||
if (
|
||||
!expectedParameterType.isBuiltinFunctionalType ||
|
||||
|
||||
+1
-1
@@ -33,10 +33,10 @@ class CallableReferenceResolutionCandidate(
|
||||
val reflectionCandidateType: UnwrappedType,
|
||||
val callableReferenceAdaptation: CallableReferenceAdaptation?,
|
||||
val kotlinCall: CallableReferenceResolutionAtom,
|
||||
val expectedType: UnwrappedType?,
|
||||
override val callComponents: KotlinCallComponents,
|
||||
override val scopeTower: ImplicitScopeTower,
|
||||
override val resolutionCallbacks: KotlinResolutionCallbacks,
|
||||
val expectedType: UnwrappedType?,
|
||||
override val baseSystem: ConstraintStorage?
|
||||
) : ResolutionCandidate() {
|
||||
override val variableCandidateIfInvoke: ResolutionCandidate? = null
|
||||
|
||||
+44
-46
@@ -20,30 +20,61 @@ import java.util.ArrayList
|
||||
sealed class ResolutionCandidate : Candidate, KotlinDiagnosticsHolder {
|
||||
abstract val resolvedCall: MutableResolvedCallAtom
|
||||
abstract val callComponents: KotlinCallComponents
|
||||
abstract fun getSubResolvedAtoms(): List<ResolvedAtom>
|
||||
abstract fun addResolvedKtPrimitive(resolvedAtom: ResolvedAtom)
|
||||
abstract val variableCandidateIfInvoke: ResolutionCandidate?
|
||||
abstract val scopeTower: ImplicitScopeTower
|
||||
abstract val knownTypeParametersResultingSubstitutor: TypeSubstitutor?
|
||||
abstract val resolutionCallbacks: KotlinResolutionCallbacks
|
||||
|
||||
override val isSuccessful: Boolean
|
||||
get() {
|
||||
processParts(stopOnFirstError = true)
|
||||
return resultingApplicabilities.minOrNull()!!.isSuccess && !getSystem().hasContradiction
|
||||
}
|
||||
|
||||
override val resultingApplicability: CandidateApplicability
|
||||
get() {
|
||||
processParts(stopOnFirstError = false)
|
||||
return resultingApplicabilities.minOrNull() ?: CandidateApplicability.RESOLVED
|
||||
}
|
||||
|
||||
open val resolutionSequence: List<ResolutionPart> get() = resolvedCall.atom.callKind.resolutionSequence
|
||||
|
||||
protected abstract val baseSystem: ConstraintStorage?
|
||||
protected val mutableDiagnostics: ArrayList<KotlinCallDiagnostic> = arrayListOf()
|
||||
|
||||
val descriptor: CallableDescriptor get() = resolvedCall.candidateDescriptor
|
||||
val diagnostics: List<KotlinCallDiagnostic> = mutableDiagnostics
|
||||
val resultingApplicabilities: Array<CandidateApplicability>
|
||||
get() = arrayOf(currentApplicability, getResultApplicability(getSystem().errors), variableApplicability)
|
||||
|
||||
private val variableApplicability
|
||||
get() = variableCandidateIfInvoke?.resultingApplicability ?: CandidateApplicability.RESOLVED
|
||||
private val stepCount get() = resolutionSequence.sumOf { it.run { workCount() } }
|
||||
|
||||
private var step = 0
|
||||
private var newSystem: NewConstraintSystemImpl? = null
|
||||
private var currentApplicability: CandidateApplicability = CandidateApplicability.RESOLVED
|
||||
|
||||
abstract fun getSubResolvedAtoms(): List<ResolvedAtom>
|
||||
abstract fun addResolvedKtPrimitive(resolvedAtom: ResolvedAtom)
|
||||
|
||||
override fun addDiagnostic(diagnostic: KotlinCallDiagnostic) {
|
||||
mutableDiagnostics.add(diagnostic)
|
||||
currentApplicability = minOf(diagnostic.candidateApplicability, currentApplicability)
|
||||
}
|
||||
|
||||
private val variableApplicability
|
||||
get() = variableCandidateIfInvoke?.resultingApplicability ?: CandidateApplicability.RESOLVED
|
||||
override fun addCompatibilityWarning(other: Candidate) {
|
||||
if (other is ResolutionCandidate && this !== other && this::class == other::class) {
|
||||
addDiagnostic(CompatibilityWarning(other.descriptor))
|
||||
}
|
||||
}
|
||||
|
||||
val descriptor: CallableDescriptor get() = resolvedCall.candidateDescriptor
|
||||
|
||||
protected val mutableDiagnostics: ArrayList<KotlinCallDiagnostic> = arrayListOf()
|
||||
|
||||
open val resolutionSequence: List<ResolutionPart> get() = resolvedCall.atom.callKind.resolutionSequence
|
||||
private var newSystem: NewConstraintSystemImpl? = null
|
||||
|
||||
val diagnostics: List<KotlinCallDiagnostic> = mutableDiagnostics
|
||||
override fun toString(): String {
|
||||
val descriptor = DescriptorRenderer.COMPACT.render(resolvedCall.candidateDescriptor)
|
||||
val okOrFail = if (resultingApplicabilities.minOrNull()?.isSuccess != false) "OK" else "FAIL"
|
||||
val step = "$step/$stepCount"
|
||||
return "$okOrFail($step): $descriptor"
|
||||
}
|
||||
|
||||
fun getSystem(): NewConstraintSystem {
|
||||
if (newSystem == null) {
|
||||
@@ -57,9 +88,6 @@ sealed class ResolutionCandidate : Candidate, KotlinDiagnosticsHolder {
|
||||
return newSystem!!
|
||||
}
|
||||
|
||||
private val stepCount get() = resolutionSequence.sumOf { it.run { workCount() } }
|
||||
private var step = 0
|
||||
|
||||
private fun processParts(stopOnFirstError: Boolean) {
|
||||
if (stopOnFirstError && step > 0) return // error already happened
|
||||
if (step == stepCount) return
|
||||
@@ -99,34 +127,4 @@ sealed class ResolutionCandidate : Candidate, KotlinDiagnosticsHolder {
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
protected var currentApplicability: CandidateApplicability = CandidateApplicability.RESOLVED
|
||||
|
||||
override val isSuccessful: Boolean
|
||||
get() {
|
||||
processParts(stopOnFirstError = true)
|
||||
return resultingApplicabilities.minOrNull()!!.isSuccess && !getSystem().hasContradiction
|
||||
}
|
||||
|
||||
val resultingApplicabilities: Array<CandidateApplicability>
|
||||
get() = arrayOf(currentApplicability, getResultApplicability(getSystem().errors), variableApplicability)
|
||||
|
||||
override val resultingApplicability: CandidateApplicability
|
||||
get() {
|
||||
processParts(stopOnFirstError = false)
|
||||
return resultingApplicabilities.minOrNull()!!
|
||||
}
|
||||
|
||||
override fun addCompatibilityWarning(other: Candidate) {
|
||||
if (other is ResolutionCandidate && this !== other && this::class == other::class) {
|
||||
addDiagnostic(CompatibilityWarning(other.descriptor))
|
||||
}
|
||||
}
|
||||
|
||||
override fun toString(): String {
|
||||
val descriptor = DescriptorRenderer.COMPACT.render(resolvedCall.candidateDescriptor)
|
||||
val okOrFail = if (resultingApplicabilities.minOrNull()!!.isSuccess) "OK" else "FAIL"
|
||||
val step = "$step/$stepCount"
|
||||
return "$okOrFail($step): $descriptor"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
+2
-2
@@ -25,8 +25,6 @@ open class SimpleResolutionCandidate(
|
||||
override val resolvedCall: MutableResolvedCallAtom,
|
||||
override val knownTypeParametersResultingSubstitutor: TypeSubstitutor? = null,
|
||||
) : ResolutionCandidate() {
|
||||
private var subResolvedAtoms: MutableList<ResolvedAtom> = arrayListOf()
|
||||
|
||||
override val variableCandidateIfInvoke: ResolutionCandidate?
|
||||
get() = callComponents.statelessCallbacks.getVariableCandidateIfInvoke(resolvedCall.atom)
|
||||
|
||||
@@ -35,4 +33,6 @@ open class SimpleResolutionCandidate(
|
||||
override fun addResolvedKtPrimitive(resolvedAtom: ResolvedAtom) {
|
||||
subResolvedAtoms.add(resolvedAtom)
|
||||
}
|
||||
|
||||
private var subResolvedAtoms: MutableList<ResolvedAtom> = arrayListOf()
|
||||
}
|
||||
|
||||
+9
-3
@@ -35,6 +35,8 @@ val CallableDescriptor.returnTypeOrNothing: UnwrappedType
|
||||
fun TypeSubstitutor.substitute(type: UnwrappedType): UnwrappedType = safeSubstitute(type, Variance.INVARIANT).unwrap()
|
||||
|
||||
fun CallableDescriptor.substitute(substitutor: NewTypeSubstitutor): CallableDescriptor {
|
||||
if (substitutor.isEmpty) return this
|
||||
|
||||
val wrappedSubstitution = object : TypeSubstitution() {
|
||||
override fun get(key: KotlinType): TypeProjection? = null
|
||||
override fun prepareTopLevelType(topLevelType: KotlinType, position: Variance) = substitutor.safeSubstitute(topLevelType.unwrap())
|
||||
@@ -44,16 +46,20 @@ fun CallableDescriptor.substitute(substitutor: NewTypeSubstitutor): CallableDesc
|
||||
|
||||
fun CallableDescriptor.substituteAndApproximateTypes(
|
||||
substitutor: NewTypeSubstitutor,
|
||||
typeApproximator: TypeApproximator?
|
||||
typeApproximator: TypeApproximator?,
|
||||
positionDependentApproximation: Boolean = false
|
||||
): CallableDescriptor {
|
||||
if (substitutor.isEmpty) return this
|
||||
|
||||
val wrappedSubstitution = object : TypeSubstitution() {
|
||||
override fun get(key: KotlinType): TypeProjection? = null
|
||||
|
||||
override fun prepareTopLevelType(topLevelType: KotlinType, position: Variance) =
|
||||
substitutor.safeSubstitute(topLevelType.unwrap()).let { substitutedType ->
|
||||
typeApproximator?.approximateToSuperType(
|
||||
typeApproximator?.approximateTo(
|
||||
substitutedType,
|
||||
TypeApproximatorConfiguration.FinalApproximationAfterResolutionAndInference
|
||||
TypeApproximatorConfiguration.FinalApproximationAfterResolutionAndInference,
|
||||
position != Variance.IN_VARIANCE || !positionDependentApproximation
|
||||
) ?: substitutedType
|
||||
}
|
||||
}
|
||||
|
||||
+2
-1
@@ -7,6 +7,7 @@ package org.jetbrains.kotlin.resolve.calls.inference.components
|
||||
|
||||
import org.jetbrains.kotlin.config.LanguageFeature
|
||||
import org.jetbrains.kotlin.config.LanguageVersionSettings
|
||||
import org.jetbrains.kotlin.resolve.calls.components.candidate.SimpleResolutionCandidate
|
||||
import org.jetbrains.kotlin.resolve.calls.components.transformToResolvedLambda
|
||||
import org.jetbrains.kotlin.resolve.calls.inference.model.*
|
||||
import org.jetbrains.kotlin.resolve.calls.model.*
|
||||
@@ -286,7 +287,7 @@ class KotlinConstraintSystemCompleter(
|
||||
diagnosticsHolder: KotlinDiagnosticsHolder,
|
||||
): ResolvedLambdaAtom {
|
||||
val returnVariable = TypeVariableForLambdaReturnType(candidate.callComponents.builtIns, "_R")
|
||||
val csBuilder = candidate.csBuilder
|
||||
val csBuilder = candidate.getSystem().getBuilder()
|
||||
csBuilder.registerVariable(returnVariable)
|
||||
val functionalType: KotlinType = csBuilder.buildCurrentSubstitutor().safeSubstitute(candidate.getSystem().asConstraintSystemCompleterContext(), atom.expectedType!!) as KotlinType
|
||||
val expectedType = KotlinTypeFactory.simpleType(
|
||||
|
||||
+3
@@ -34,6 +34,9 @@ class DeclaredUpperBoundConstraintPositionImpl(
|
||||
|
||||
class ArgumentConstraintPositionImpl(argument: KotlinCallArgument) : ArgumentConstraintPosition<KotlinCallArgument>(argument)
|
||||
|
||||
class CallableReferenceConstraintPositionImpl(val callableReferenceCall: CallableReferenceKotlinCall) :
|
||||
CallableReferenceConstraintPosition<CallableReferenceResolutionAtom>(callableReferenceCall)
|
||||
|
||||
class ReceiverConstraintPositionImpl(argument: KotlinCallArgument) : ReceiverConstraintPosition<KotlinCallArgument>(argument)
|
||||
|
||||
class FixVariableConstraintPositionImpl(
|
||||
|
||||
+62
-63
@@ -3,7 +3,7 @@
|
||||
* 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.calls.components
|
||||
package org.jetbrains.kotlin.resolve.calls.model
|
||||
|
||||
import org.jetbrains.kotlin.builtins.KotlinBuiltIns
|
||||
import org.jetbrains.kotlin.builtins.ReflectionTypes
|
||||
@@ -13,35 +13,53 @@ import org.jetbrains.kotlin.config.ApiVersion
|
||||
import org.jetbrains.kotlin.config.LanguageFeature
|
||||
import org.jetbrains.kotlin.descriptors.*
|
||||
import org.jetbrains.kotlin.descriptors.annotations.Annotations
|
||||
import org.jetbrains.kotlin.resolve.calls.inference.ConstraintSystemOperation
|
||||
import org.jetbrains.kotlin.resolve.calls.model.*
|
||||
import org.jetbrains.kotlin.resolve.calls.components.*
|
||||
import org.jetbrains.kotlin.resolve.calls.components.candidate.CallableReferenceResolutionCandidate
|
||||
import org.jetbrains.kotlin.resolve.calls.inference.model.ConstraintStorage
|
||||
import org.jetbrains.kotlin.resolve.calls.inference.model.TypeVariableTypeConstructor
|
||||
import org.jetbrains.kotlin.resolve.calls.tasks.ExplicitReceiverKind
|
||||
import org.jetbrains.kotlin.resolve.calls.tower.*
|
||||
import org.jetbrains.kotlin.resolve.descriptorUtil.builtIns
|
||||
import org.jetbrains.kotlin.resolve.descriptorUtil.isCompanionObject
|
||||
import org.jetbrains.kotlin.resolve.scopes.receivers.DetailedReceiver
|
||||
import org.jetbrains.kotlin.resolve.scopes.receivers.ReceiverValue
|
||||
import org.jetbrains.kotlin.resolve.scopes.receivers.ReceiverValueWithSmartCastInfo
|
||||
import org.jetbrains.kotlin.types.ErrorUtils
|
||||
import org.jetbrains.kotlin.types.KotlinType
|
||||
import org.jetbrains.kotlin.types.UnwrappedType
|
||||
import org.jetbrains.kotlin.types.Variance
|
||||
import org.jetbrains.kotlin.types.*
|
||||
import org.jetbrains.kotlin.types.expressions.CoercionStrategy
|
||||
import org.jetbrains.kotlin.types.typeUtil.isUnit
|
||||
import org.jetbrains.kotlin.utils.SmartList
|
||||
import org.jetbrains.kotlin.utils.addIfNotNull
|
||||
|
||||
class CallableReferencesCandidateFactory(
|
||||
val argument: CallableReferenceKotlinCallArgument,
|
||||
val kotlinCall: CallableReferenceResolutionAtom,
|
||||
val callComponents: KotlinCallComponents,
|
||||
val scopeTower: ImplicitScopeTower,
|
||||
val compatibilityChecker: ((ConstraintSystemOperation) -> Unit) -> Unit,
|
||||
val expectedType: UnwrappedType?,
|
||||
private val csBuilder: ConstraintSystemOperation,
|
||||
private val baseSystem: ConstraintStorage?,
|
||||
private val resolutionCallbacks: KotlinResolutionCallbacks
|
||||
) : CandidateFactory<CallableReferenceResolutionCandidate> {
|
||||
// todo investigate similar code in CheckVisibility
|
||||
private val CallableReceiver.asReceiverValueForVisibilityChecks: ReceiverValue
|
||||
get() = receiver.receiverValue
|
||||
|
||||
fun createCallableProcessor(explicitReceiver: DetailedReceiver?) =
|
||||
createCallableReferenceProcessor(scopeTower, argument.rhsName, this, explicitReceiver)
|
||||
override fun createErrorCandidate(): CallableReferenceResolutionCandidate {
|
||||
val errorScope = ErrorUtils.createErrorScope("Error resolution candidate for call $kotlinCall")
|
||||
val errorDescriptor = errorScope.getContributedFunctions(kotlinCall.rhsName, scopeTower.location).first()
|
||||
|
||||
val (reflectionCandidateType, callableReferenceAdaptation) = buildReflectionType(
|
||||
errorDescriptor,
|
||||
dispatchReceiver = null,
|
||||
extensionReceiver = null,
|
||||
expectedType,
|
||||
callComponents.builtIns,
|
||||
buildTypeWithConversions = kotlinCall is CallableReferenceKotlinCallArgument
|
||||
)
|
||||
|
||||
return CallableReferenceResolutionCandidate(
|
||||
errorDescriptor, dispatchReceiver = null, extensionReceiver = null,
|
||||
ExplicitReceiverKind.NO_EXPLICIT_RECEIVER, reflectionCandidateType, callableReferenceAdaptation,
|
||||
kotlinCall, expectedType, callComponents, scopeTower, resolutionCallbacks, baseSystem
|
||||
)
|
||||
}
|
||||
|
||||
override fun createCandidate(
|
||||
towerCandidate: CandidateWithBoundDispatchReceiver,
|
||||
@@ -59,18 +77,20 @@ class CallableReferencesCandidateFactory(
|
||||
dispatchCallableReceiver,
|
||||
extensionCallableReceiver,
|
||||
expectedType,
|
||||
callComponents.builtIns
|
||||
callComponents.builtIns,
|
||||
// conversions aren't needed for top-level callable references
|
||||
buildTypeWithConversions = kotlinCall is CallableReferenceKotlinCallArgument
|
||||
)
|
||||
|
||||
fun createReferenceCandidate(): CallableReferenceResolutionCandidate =
|
||||
CallableReferenceResolutionCandidate(
|
||||
candidateDescriptor, dispatchCallableReceiver, extensionCallableReceiver,
|
||||
explicitReceiverKind, reflectionCandidateType, callableReferenceAdaptation, diagnostics
|
||||
)
|
||||
fun createCallableReferenceCallCandidate(diagnostics: List<KotlinCallDiagnostic>) = CallableReferenceResolutionCandidate(
|
||||
candidateDescriptor, dispatchCallableReceiver, extensionCallableReceiver,
|
||||
explicitReceiverKind, reflectionCandidateType, callableReferenceAdaptation,
|
||||
kotlinCall, expectedType, callComponents, scopeTower, resolutionCallbacks, baseSystem
|
||||
).also { diagnostics.forEach(it::addDiagnostic) }
|
||||
|
||||
if (callComponents.statelessCallbacks.isHiddenInResolution(candidateDescriptor, argument, resolutionCallbacks)) {
|
||||
if (callComponents.statelessCallbacks.isHiddenInResolution(candidateDescriptor, kotlinCall.call, resolutionCallbacks)) {
|
||||
diagnostics.add(HiddenDescriptor)
|
||||
return createReferenceCandidate()
|
||||
return createCallableReferenceCallCandidate(diagnostics)
|
||||
}
|
||||
|
||||
if (needCompatibilityResolveForCallableReference(callableReferenceAdaptation, candidateDescriptor)) {
|
||||
@@ -79,7 +99,7 @@ class CallableReferencesCandidateFactory(
|
||||
|
||||
if (callableReferenceAdaptation != null && expectedType != null && hasNonTrivialAdaptation(callableReferenceAdaptation)) {
|
||||
if (!expectedType.isFunctionType && !expectedType.isSuspendFunctionType) { // expectedType has some reflection type
|
||||
diagnostics.add(AdaptedCallableReferenceIsUsedWithReflection(argument))
|
||||
diagnostics.add(AdaptedCallableReferenceIsUsedWithReflection(kotlinCall))
|
||||
}
|
||||
}
|
||||
|
||||
@@ -87,49 +107,28 @@ class CallableReferencesCandidateFactory(
|
||||
callableReferenceAdaptation.defaults != 0 &&
|
||||
!callComponents.languageVersionSettings.supportsFeature(LanguageFeature.FunctionReferenceWithDefaultValueAsOtherType)
|
||||
) {
|
||||
diagnostics.add(CallableReferencesDefaultArgumentUsed(argument, candidateDescriptor, callableReferenceAdaptation.defaults))
|
||||
diagnostics.add(CallableReferencesDefaultArgumentUsed(kotlinCall, candidateDescriptor, callableReferenceAdaptation.defaults))
|
||||
}
|
||||
|
||||
if (candidateDescriptor !is CallableMemberDescriptor) {
|
||||
return CallableReferenceResolutionCandidate(
|
||||
candidateDescriptor, dispatchCallableReceiver, extensionCallableReceiver,
|
||||
explicitReceiverKind, reflectionCandidateType, callableReferenceAdaptation,
|
||||
listOf(NotCallableMemberReference(argument, candidateDescriptor))
|
||||
)
|
||||
return createCallableReferenceCallCandidate(listOf(NotCallableMemberReference(kotlinCall, candidateDescriptor)))
|
||||
}
|
||||
|
||||
diagnostics.addAll(towerCandidate.diagnostics)
|
||||
// todo smartcast on receiver diagnostic and CheckInstantiationOfAbstractClass
|
||||
|
||||
compatibilityChecker {
|
||||
if (it.hasContradiction) return@compatibilityChecker
|
||||
|
||||
val (_, visibilityError) = it.checkCallableReference(
|
||||
argument, dispatchCallableReceiver, extensionCallableReceiver, candidateDescriptor,
|
||||
reflectionCandidateType, expectedType, scopeTower.lexicalScope.ownerDescriptor
|
||||
)
|
||||
|
||||
diagnostics.addIfNotNull(visibilityError)
|
||||
|
||||
if (it.hasContradiction) diagnostics.add(
|
||||
CallableReferenceNotCompatible(
|
||||
argument,
|
||||
candidateDescriptor,
|
||||
expectedType,
|
||||
reflectionCandidateType
|
||||
)
|
||||
)
|
||||
}
|
||||
|
||||
return createReferenceCandidate()
|
||||
return createCallableReferenceCallCandidate(diagnostics)
|
||||
}
|
||||
|
||||
fun createCallableProcessor(explicitReceiver: DetailedReceiver?) =
|
||||
createCallableReferenceProcessor(scopeTower, kotlinCall.rhsName, this, explicitReceiver)
|
||||
|
||||
private fun needCompatibilityResolveForCallableReference(
|
||||
callableReferenceAdaptation: CallableReferenceAdaptation?,
|
||||
candidate: CallableDescriptor
|
||||
): Boolean {
|
||||
// KT-13934: reference to companion object member via class name
|
||||
if (candidate.containingDeclaration.isCompanionObject() && argument.lhsResult is LHSResult.Type) return true
|
||||
if (candidate.containingDeclaration.isCompanionObject() && kotlinCall.lhsResult is LHSResult.Type) return true
|
||||
|
||||
if (callableReferenceAdaptation == null) return false
|
||||
|
||||
@@ -142,19 +141,13 @@ class CallableReferencesCandidateFactory(
|
||||
callableReferenceAdaptation.coercionStrategy != CoercionStrategy.NO_COERCION ||
|
||||
callableReferenceAdaptation.mappedArguments.values.any { it is ResolvedCallArgument.VarargArgument }
|
||||
|
||||
private enum class VarargMappingState {
|
||||
UNMAPPED, MAPPED_WITH_PLAIN_ARGS, MAPPED_WITH_ARRAY
|
||||
}
|
||||
|
||||
private fun getCallableReferenceAdaptation(
|
||||
descriptor: FunctionDescriptor,
|
||||
expectedType: UnwrappedType?,
|
||||
unboundReceiverCount: Int,
|
||||
builtins: KotlinBuiltIns
|
||||
): CallableReferenceAdaptation? {
|
||||
if (callComponents.languageVersionSettings.apiVersion < ApiVersion.KOTLIN_1_4) return null
|
||||
|
||||
if (expectedType == null) return null
|
||||
if (expectedType == null || TypeUtils.noExpectedType(expectedType)) return null
|
||||
|
||||
// Do not adapt references against KCallable type as it's impossible to map defaults/vararg to absent parameters of KCallable
|
||||
if (ReflectionTypes.hasKCallableTypeFqName(expectedType)) return null
|
||||
@@ -302,7 +295,7 @@ class CallableReferencesCandidateFactory(
|
||||
return when (varargMappingState) {
|
||||
VarargMappingState.UNMAPPED -> {
|
||||
if (KotlinBuiltIns.isArrayOrPrimitiveArray(expectedParameterType) ||
|
||||
csBuilder.isTypeVariable(expectedParameterType)
|
||||
expectedParameterType.constructor is TypeVariableTypeConstructor
|
||||
) {
|
||||
val arrayType = builtins.getPrimitiveArrayKotlinTypeByPrimitiveKotlinType(elementType)
|
||||
?: builtins.getArrayType(Variance.OUT_VARIANCE, elementType)
|
||||
@@ -327,7 +320,8 @@ class CallableReferencesCandidateFactory(
|
||||
dispatchReceiver: CallableReceiver?,
|
||||
extensionReceiver: CallableReceiver?,
|
||||
expectedType: UnwrappedType?,
|
||||
builtins: KotlinBuiltIns
|
||||
builtins: KotlinBuiltIns,
|
||||
buildTypeWithConversions: Boolean = true
|
||||
): Pair<UnwrappedType, CallableReferenceAdaptation?> {
|
||||
val argumentsAndReceivers = ArrayList<KotlinType>(descriptor.valueParameters.size + 2)
|
||||
|
||||
@@ -365,7 +359,7 @@ class CallableReferencesCandidateFactory(
|
||||
builtins = builtins
|
||||
)
|
||||
|
||||
val returnType = if (callableReferenceAdaptation == null) {
|
||||
val returnType = if (callableReferenceAdaptation == null || !buildTypeWithConversions) {
|
||||
descriptor.valueParameters.mapTo(argumentsAndReceivers) { it.type }
|
||||
descriptorReturnType
|
||||
} else {
|
||||
@@ -380,7 +374,8 @@ class CallableReferencesCandidateFactory(
|
||||
}
|
||||
|
||||
val suspendConversionStrategy = callableReferenceAdaptation?.suspendConversionStrategy
|
||||
val isSuspend = descriptor.isSuspend || suspendConversionStrategy == SuspendConversionStrategy.SUSPEND_CONVERSION
|
||||
val isSuspend = descriptor.isSuspend ||
|
||||
(suspendConversionStrategy == SuspendConversionStrategy.SUSPEND_CONVERSION && buildTypeWithConversions)
|
||||
|
||||
callComponents.reflectionTypes.getKFunctionType(
|
||||
Annotations.EMPTY, null, argumentsAndReceivers, null,
|
||||
@@ -397,7 +392,7 @@ class CallableReferencesCandidateFactory(
|
||||
private fun toCallableReceiver(receiver: ReceiverValueWithSmartCastInfo, isExplicit: Boolean): CallableReceiver {
|
||||
if (!isExplicit) return CallableReceiver.ScopeReceiver(receiver)
|
||||
|
||||
return when (val lhsResult = argument.lhsResult) {
|
||||
return when (val lhsResult = kotlinCall.lhsResult) {
|
||||
is LHSResult.Expression -> CallableReceiver.ExplicitValueReceiver(receiver)
|
||||
is LHSResult.Type -> {
|
||||
if (lhsResult.qualifier?.classValueReceiver?.type == receiver.receiverValue.type) {
|
||||
@@ -410,4 +405,8 @@ class CallableReferencesCandidateFactory(
|
||||
else -> throw IllegalStateException("Unsupported kind of lhsResult: $lhsResult")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private enum class VarargMappingState {
|
||||
UNMAPPED, MAPPED_WITH_PLAIN_ARGS, MAPPED_WITH_ARRAY
|
||||
}
|
||||
}
|
||||
|
||||
@@ -71,6 +71,18 @@ fun KotlinCall.checkCallInvariants() {
|
||||
|
||||
}
|
||||
|
||||
KotlinCallKind.CALLABLE_REFERENCE -> {
|
||||
assert(argumentsInParenthesis.isEmpty()) {
|
||||
"Callable references can't have value arguments"
|
||||
}
|
||||
assert(typeArguments.isEmpty()) {
|
||||
"Callable references can't have explicit type arguments"
|
||||
}
|
||||
assert(externalArgument == null) {
|
||||
"External argument is not allowed not for function call: $externalArgument."
|
||||
}
|
||||
}
|
||||
|
||||
KotlinCallKind.UNSUPPORTED -> error("Call with UNSUPPORTED kind")
|
||||
}
|
||||
}
|
||||
|
||||
+29
-24
@@ -34,6 +34,18 @@ abstract class InapplicableArgumentDiagnostic : KotlinCallDiagnostic(INAPPLICABL
|
||||
override fun report(reporter: DiagnosticReporter) = reporter.onCallArgument(argument, this)
|
||||
}
|
||||
|
||||
abstract class CallableReferenceInapplicableDiagnostic(
|
||||
private val argument: CallableReferenceResolutionAtom,
|
||||
applicability: CandidateApplicability = INAPPLICABLE
|
||||
) : KotlinCallDiagnostic(applicability) {
|
||||
override fun report(reporter: DiagnosticReporter) {
|
||||
when (argument) {
|
||||
is CallableReferenceKotlinCall -> reporter.onCall(this)
|
||||
is CallableReferenceKotlinCallArgument -> reporter.onCallArgument(argument, this)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// ArgumentsToParameterMapper
|
||||
class TooManyArguments(val argument: KotlinCallArgument, val descriptor: CallableDescriptor) :
|
||||
KotlinCallDiagnostic(INAPPLICABLE_ARGUMENTS_MAPPING_ERROR) {
|
||||
@@ -99,38 +111,40 @@ class WrongCountOfTypeArguments(
|
||||
|
||||
// Callable reference resolution
|
||||
class CallableReferenceNotCompatible(
|
||||
override val argument: CallableReferenceKotlinCallArgument,
|
||||
argument: CallableReferenceResolutionAtom,
|
||||
val candidate: CallableMemberDescriptor,
|
||||
val expectedType: UnwrappedType?,
|
||||
val callableReverenceType: UnwrappedType
|
||||
) : InapplicableArgumentDiagnostic()
|
||||
) : CallableReferenceInapplicableDiagnostic(argument)
|
||||
|
||||
// supported by FE but not supported by BE now
|
||||
class CallableReferencesDefaultArgumentUsed(
|
||||
val argument: CallableReferenceKotlinCallArgument,
|
||||
val argument: CallableReferenceResolutionAtom,
|
||||
val candidate: CallableDescriptor,
|
||||
val defaultsCount: Int
|
||||
) : KotlinCallDiagnostic(IMPOSSIBLE_TO_GENERATE) {
|
||||
override fun report(reporter: DiagnosticReporter) = reporter.onCallArgument(argument, this)
|
||||
}
|
||||
) : CallableReferenceInapplicableDiagnostic(argument)
|
||||
|
||||
class NotCallableMemberReference(
|
||||
override val argument: CallableReferenceKotlinCallArgument,
|
||||
val argument: CallableReferenceResolutionAtom,
|
||||
val candidate: CallableDescriptor
|
||||
) : InapplicableArgumentDiagnostic()
|
||||
) : CallableReferenceInapplicableDiagnostic(argument)
|
||||
|
||||
class NoneCallableReferenceCandidates(override val argument: CallableReferenceKotlinCallArgument) : InapplicableArgumentDiagnostic()
|
||||
class NoneCallableReferenceCallCandidates(val argument: CallableReferenceKotlinCallArgument) :
|
||||
CallableReferenceInapplicableDiagnostic(argument)
|
||||
|
||||
class CallableReferenceCandidatesAmbiguity(
|
||||
override val argument: CallableReferenceKotlinCallArgument,
|
||||
val candidates: Collection<CallableReferenceCandidate>
|
||||
) : InapplicableArgumentDiagnostic()
|
||||
class CallableReferenceCallCandidatesAmbiguity(
|
||||
val argument: CallableReferenceKotlinCallArgument,
|
||||
val candidates: Collection<CallableReferenceResolutionCandidate>
|
||||
) : CallableReferenceInapplicableDiagnostic(argument)
|
||||
|
||||
class NotCallableExpectedType(
|
||||
override val argument: CallableReferenceKotlinCallArgument,
|
||||
val argument: CallableReferenceKotlinCallArgument,
|
||||
val expectedType: UnwrappedType,
|
||||
val notCallableTypeConstructor: TypeConstructor
|
||||
) : InapplicableArgumentDiagnostic()
|
||||
) : CallableReferenceInapplicableDiagnostic(argument)
|
||||
|
||||
class AdaptedCallableReferenceIsUsedWithReflection(val argument: CallableReferenceResolutionAtom) :
|
||||
CallableReferenceInapplicableDiagnostic(argument, RESOLVED_WITH_ERROR)
|
||||
|
||||
// SmartCasts
|
||||
class SmartCastDiagnostic(
|
||||
@@ -258,15 +272,6 @@ class CompatibilityWarningOnArgument(
|
||||
}
|
||||
}
|
||||
|
||||
class AdaptedCallableReferenceIsUsedWithReflection(
|
||||
val argument: CallableReferenceKotlinCallArgument,
|
||||
) : KotlinCallDiagnostic(RESOLVED_WITH_ERROR) {
|
||||
override fun report(reporter: DiagnosticReporter) {
|
||||
reporter.onCallArgument(argument, this)
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
class KotlinConstraintSystemDiagnostic(
|
||||
val error: ConstraintSystemError
|
||||
) : KotlinCallDiagnostic(error.applicability) {
|
||||
|
||||
@@ -58,6 +58,16 @@ enum class KotlinCallKind(vararg resolutionPart: ResolutionPart) {
|
||||
PostponedVariablesInitializerResolutionPart
|
||||
),
|
||||
INVOKE(*FUNCTION.resolutionSequence.toTypedArray()),
|
||||
CALLABLE_REFERENCE(
|
||||
CheckVisibility,
|
||||
NoTypeArguments,
|
||||
NoArguments,
|
||||
CreateFreshVariablesSubstitutor,
|
||||
CollectionTypeVariableUsagesInfo,
|
||||
CheckReceivers,
|
||||
CheckCallableReference,
|
||||
CompatibilityOfTypeVariableAsIntersectionTypePart
|
||||
),
|
||||
UNSUPPORTED();
|
||||
|
||||
val resolutionSequence = resolutionPart.asList()
|
||||
|
||||
+3
-1
@@ -81,7 +81,9 @@ open class MutableResolvedCallAtom(
|
||||
override val candidateDescriptor: CallableDescriptor, // original candidate descriptor
|
||||
override val explicitReceiverKind: ExplicitReceiverKind,
|
||||
override val dispatchReceiverArgument: SimpleKotlinCallArgument?,
|
||||
override val extensionReceiverArgument: SimpleKotlinCallArgument?
|
||||
override val extensionReceiverArgument: SimpleKotlinCallArgument?,
|
||||
open val reflectionCandidateType: UnwrappedType? = null,
|
||||
open val candidate: CallableReferenceResolutionCandidate? = null
|
||||
) : ResolvedCallAtom() {
|
||||
override lateinit var typeArgumentMappingByOriginal: TypeArgumentsToParametersMapper.TypeArgumentsMapping
|
||||
override lateinit var argumentMappingByOriginal: Map<ValueParameterDescriptor, ResolvedCallArgument>
|
||||
|
||||
@@ -45,4 +45,7 @@ class TypeApproximator(
|
||||
// resultType <: type
|
||||
fun approximateToSubType(type: UnwrappedType, conf: TypeApproximatorConfiguration): UnwrappedType? =
|
||||
super.approximateToSubType(type, conf) as UnwrappedType?
|
||||
|
||||
fun approximateTo(type: UnwrappedType, conf: TypeApproximatorConfiguration, toSuperType: Boolean): UnwrappedType? =
|
||||
if (toSuperType) approximateToSuperType(type, conf) else approximateToSubType(type, conf)
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user