Change resolution priority level for SAM adapters
After this change SAM adapters are being resolved in the same group as members, thus their overload resolution happens simultaneously. But in the case of overload resolution ambiguity try to filter out all synthetic members and run the process again. See the issue and new test for clarification #KT-11128 In Progress
This commit is contained in:
@@ -20,6 +20,7 @@ import org.jetbrains.kotlin.descriptors.CallableDescriptor
|
||||
import org.jetbrains.kotlin.descriptors.MemberDescriptor
|
||||
import org.jetbrains.kotlin.descriptors.TypeParameterDescriptor
|
||||
import org.jetbrains.kotlin.descriptors.ValueParameterDescriptor
|
||||
import org.jetbrains.kotlin.descriptors.synthetic.SyntheticMemberDescriptor
|
||||
import org.jetbrains.kotlin.types.*
|
||||
import org.jetbrains.kotlin.types.checker.KotlinTypeChecker
|
||||
import org.jetbrains.kotlin.utils.singletonOrEmptyList
|
||||
@@ -43,7 +44,8 @@ class FlatSignature<out T> private constructor(
|
||||
val hasExtensionReceiver: Boolean,
|
||||
val hasVarargs: Boolean,
|
||||
val numDefaults: Int,
|
||||
val isPlatform: Boolean
|
||||
val isPlatform: Boolean,
|
||||
val isSyntheticMember: Boolean
|
||||
) {
|
||||
val isGeneric = typeParameters.isNotEmpty()
|
||||
|
||||
@@ -63,7 +65,8 @@ class FlatSignature<out T> private constructor(
|
||||
hasExtensionReceiver = extensionReceiverType != null,
|
||||
hasVarargs = descriptor.valueParameters.any { it.varargElementType != null },
|
||||
numDefaults = numDefaults,
|
||||
isPlatform = descriptor is MemberDescriptor && descriptor.isPlatform
|
||||
isPlatform = descriptor is MemberDescriptor && descriptor.isPlatform,
|
||||
isSyntheticMember = descriptor is SyntheticMemberDescriptor<*>
|
||||
)
|
||||
}
|
||||
|
||||
|
||||
+5
-1
@@ -133,6 +133,10 @@ class OverloadingConflictResolver<C : Any>(
|
||||
|
||||
CheckArgumentTypesMode.CHECK_VALUE_ARGUMENTS ->
|
||||
findMaximallySpecificCall(candidates, discriminateGenerics, isDebuggerContext)
|
||||
?: findMaximallySpecificCall(
|
||||
candidates.filterNotTo(mutableSetOf()) { createFlatSignature(it).isSyntheticMember },
|
||||
discriminateGenerics, isDebuggerContext
|
||||
)
|
||||
}
|
||||
|
||||
// null means ambiguity between variables
|
||||
@@ -219,7 +223,7 @@ class OverloadingConflictResolver<C : Any>(
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns `true` if [call1] is definitely not less specific than [call2],
|
||||
* Returns `true` if [call1] is definitely more or equally specific [call2],
|
||||
* `false` otherwise.
|
||||
*/
|
||||
private fun compareCallsByUsedArguments(
|
||||
|
||||
@@ -67,7 +67,6 @@ data class ResolutionCandidateStatus(val diagnostics: List<ResolutionDiagnostic>
|
||||
|
||||
enum class ResolutionCandidateApplicability {
|
||||
RESOLVED, // call success or has uncompleted inference or in other words possible successful candidate
|
||||
RESOLVED_SYNTHESIZED, // todo remove it (need for SAM adapters which created inside some MemberScope)
|
||||
RESOLVED_LOW_PRIORITY,
|
||||
CONVENTION_ERROR, // missing infix, operator etc
|
||||
MAY_THROW_RUNTIME_ERROR, // unsafe call or unstable smart cast
|
||||
@@ -89,7 +88,6 @@ class UsedSmartCastForDispatchReceiver(val smartCastType: KotlinType): Resolutio
|
||||
|
||||
object ErrorDescriptorDiagnostic : ResolutionDiagnostic(ResolutionCandidateApplicability.RESOLVED) // todo discuss and change to INAPPLICABLE
|
||||
object LowPriorityDescriptorDiagnostic : ResolutionDiagnostic(ResolutionCandidateApplicability.RESOLVED_LOW_PRIORITY)
|
||||
object SynthesizedDescriptorDiagnostic : ResolutionDiagnostic(ResolutionCandidateApplicability.RESOLVED_SYNTHESIZED)
|
||||
object DynamicDescriptorDiagnostic: ResolutionDiagnostic(ResolutionCandidateApplicability.RESOLVED_LOW_PRIORITY)
|
||||
object UnstableSmartCastDiagnostic: ResolutionDiagnostic(ResolutionCandidateApplicability.MAY_THROW_RUNTIME_ERROR)
|
||||
object ExtensionWithStaticTypeWithDynamicReceiver: ResolutionDiagnostic(ResolutionCandidateApplicability.HIDDEN)
|
||||
|
||||
+32
-2
@@ -67,8 +67,9 @@ internal class ExplicitReceiverScopeTowerProcessor<D : CallableDescriptor, C: Ca
|
||||
}
|
||||
|
||||
private fun resolveAsMember(): Collection<C> {
|
||||
val members = ReceiverScopeTowerLevel(scopeTower, explicitReceiver)
|
||||
.collectCandidates(null).filter { !it.requiresExtensionReceiver }
|
||||
val members =
|
||||
MemberScopeTowerLevel(scopeTower, explicitReceiver)
|
||||
.collectCandidates(null).filter { !it.requiresExtensionReceiver }
|
||||
return members.map { candidateFactory.createCandidate(it, ExplicitReceiverKind.DISPATCH_RECEIVER, extensionReceiver = null) }
|
||||
}
|
||||
|
||||
@@ -118,6 +119,35 @@ private class NoExplicitReceiverScopeTowerProcessor<D : CallableDescriptor, C: C
|
||||
}
|
||||
else -> emptyList()
|
||||
}
|
||||
|
||||
}
|
||||
private fun <D : CallableDescriptor, C : Candidate<D>> processCommonAndSyntheticMembers(
|
||||
receiverForMember: ReceiverValueWithSmartCastInfo,
|
||||
scopeTowerLevel: ScopeTowerLevel,
|
||||
collectCandidates: CandidatesCollector<D>,
|
||||
candidateFactory: CandidateFactory<D, C>,
|
||||
isExplicitReceiver: Boolean
|
||||
): List<C> {
|
||||
val (members, syntheticExtension) =
|
||||
scopeTowerLevel.collectCandidates(null)
|
||||
.filter {
|
||||
it.descriptor.dispatchReceiverParameter == null || it.descriptor.extensionReceiverParameter == null
|
||||
}.partition { !it.requiresExtensionReceiver }
|
||||
|
||||
return members.map {
|
||||
candidateFactory.createCandidate(
|
||||
it,
|
||||
if (isExplicitReceiver) ExplicitReceiverKind.DISPATCH_RECEIVER else ExplicitReceiverKind.NO_EXPLICIT_RECEIVER,
|
||||
extensionReceiver = null
|
||||
)
|
||||
} +
|
||||
syntheticExtension.map {
|
||||
candidateFactory.createCandidate(
|
||||
it,
|
||||
if (isExplicitReceiver) ExplicitReceiverKind.EXTENSION_RECEIVER else ExplicitReceiverKind.NO_EXPLICIT_RECEIVER,
|
||||
extensionReceiver = receiverForMember
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
private fun <D : CallableDescriptor, C: Candidate<D>> createSimpleProcessor(
|
||||
|
||||
@@ -40,6 +40,7 @@ import org.jetbrains.kotlin.types.*
|
||||
import org.jetbrains.kotlin.types.typeUtil.getImmediateSuperclassNotAny
|
||||
import org.jetbrains.kotlin.utils.SmartList
|
||||
import org.jetbrains.kotlin.utils.addIfNotNull
|
||||
import org.jetbrains.kotlin.utils.singletonOrEmptyList
|
||||
import org.jetbrains.kotlin.utils.toReadOnlyList
|
||||
import java.util.*
|
||||
|
||||
@@ -62,7 +63,6 @@ internal abstract class AbstractScopeTowerLevel(
|
||||
}
|
||||
else {
|
||||
if (descriptor.hasLowPriorityInOverloadResolution()) diagnostics.add(LowPriorityDescriptorDiagnostic)
|
||||
if (descriptor.isSynthesized) diagnostics.add(SynthesizedDescriptorDiagnostic)
|
||||
if (dispatchReceiverSmartCastType != null) diagnostics.add(UsedSmartCastForDispatchReceiver(dispatchReceiverSmartCastType))
|
||||
|
||||
val shouldSkipVisibilityCheck = scopeTower.isDebuggerContext
|
||||
@@ -81,11 +81,13 @@ internal abstract class AbstractScopeTowerLevel(
|
||||
|
||||
// todo KT-9538 Unresolved inner class via subclass reference
|
||||
// todo add static methods & fields with error
|
||||
internal class ReceiverScopeTowerLevel(
|
||||
internal class MemberScopeTowerLevel(
|
||||
scopeTower: ImplicitScopeTower,
|
||||
val dispatchReceiver: ReceiverValueWithSmartCastInfo
|
||||
): AbstractScopeTowerLevel(scopeTower) {
|
||||
|
||||
private val syntheticScopes = scopeTower.syntheticScopes
|
||||
|
||||
private fun <D : CallableDescriptor> collectMembers(
|
||||
getMembers: ResolutionScope.(KotlinType?) -> Collection<D>
|
||||
): Collection<CandidateWithBoundDispatchReceiver<D>> {
|
||||
@@ -100,7 +102,11 @@ internal class ReceiverScopeTowerLevel(
|
||||
|
||||
for (possibleType in dispatchReceiver.possibleTypes) {
|
||||
possibleType.memberScope.getMembers(possibleType).mapTo(unstableCandidates ?: result) {
|
||||
createCandidateDescriptor(it, dispatchReceiver.smartCastReceiver(possibleType), unstableError, dispatchReceiverSmartCastType = possibleType)
|
||||
createCandidateDescriptor(
|
||||
it,
|
||||
dispatchReceiver.smartCastReceiver(possibleType),
|
||||
unstableError, dispatchReceiverSmartCastType = possibleType
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -139,7 +145,8 @@ internal class ReceiverScopeTowerLevel(
|
||||
|
||||
override fun getFunctions(name: Name, extensionReceiver: ReceiverValueWithSmartCastInfo?): Collection<CandidateWithBoundDispatchReceiver<FunctionDescriptor>> {
|
||||
return collectMembers {
|
||||
getContributedFunctions(name, location) + it.getInnerConstructors(name, location)
|
||||
getContributedFunctions(name, location) + it.getInnerConstructors(name, location) +
|
||||
syntheticScopes.collectSyntheticExtensionFunctions(it.singletonOrEmptyList(), name, location)
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -204,16 +211,17 @@ internal class SyntheticScopeBasedTowerLevel(
|
||||
}
|
||||
}
|
||||
|
||||
override fun getObjects(name: Name, extensionReceiver: ReceiverValueWithSmartCastInfo?): Collection<CandidateWithBoundDispatchReceiver<VariableDescriptor>>
|
||||
= emptyList()
|
||||
override fun getObjects(
|
||||
name: Name, extensionReceiver: ReceiverValueWithSmartCastInfo?
|
||||
): Collection<CandidateWithBoundDispatchReceiver<VariableDescriptor>> =
|
||||
emptyList()
|
||||
|
||||
override fun getFunctions(name: Name, extensionReceiver: ReceiverValueWithSmartCastInfo?): Collection<CandidateWithBoundDispatchReceiver<FunctionDescriptor>> {
|
||||
if (extensionReceiver == null) return emptyList()
|
||||
override fun getFunctions(
|
||||
name: Name,
|
||||
extensionReceiver: ReceiverValueWithSmartCastInfo?
|
||||
): Collection<CandidateWithBoundDispatchReceiver<FunctionDescriptor>> =
|
||||
emptyList()
|
||||
|
||||
return syntheticScopes.collectSyntheticExtensionFunctions(extensionReceiver.allTypes, name, location).map {
|
||||
createCandidateDescriptor(it, dispatchReceiver = null)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
internal class HidesMembersTowerLevel(scopeTower: ImplicitScopeTower): AbstractScopeTowerLevel(scopeTower) {
|
||||
|
||||
@@ -89,7 +89,7 @@ class TowerResolver {
|
||||
if (scope is LexicalScope) {
|
||||
if (!scope.kind.withLocalDescriptors) result.add(ScopeBasedTowerLevel(this, scope))
|
||||
|
||||
getImplicitReceiver(scope)?.let { result.add(ReceiverScopeTowerLevel(this, it)) }
|
||||
getImplicitReceiver(scope)?.let { result.add(MemberScopeTowerLevel(this, it)) }
|
||||
}
|
||||
else {
|
||||
result.add(ImportingScopeBasedTowerLevel(this, scope as ImportingScope))
|
||||
@@ -119,7 +119,7 @@ class TowerResolver {
|
||||
TowerData.TowerLevel(hidesMembersLevel).process()?.let { return it }
|
||||
// possibly there is explicit member
|
||||
TowerData.Empty.process()?.let { return it }
|
||||
// synthetic member for explicit receiver
|
||||
// synthetic property for explicit receiver
|
||||
TowerData.TowerLevel(syntheticLevel).process()?.let { return it }
|
||||
|
||||
// local non-extensions or extension for explicit receiver
|
||||
@@ -140,9 +140,9 @@ class TowerResolver {
|
||||
TowerData.BothTowerLevelAndImplicitReceiver(hidesMembersLevel, implicitReceiver).process()?.let { return it }
|
||||
|
||||
// members of implicit receiver or member extension for explicit receiver
|
||||
TowerData.TowerLevel(ReceiverScopeTowerLevel(this, implicitReceiver)).process()?.let { return it }
|
||||
TowerData.TowerLevel(MemberScopeTowerLevel(this, implicitReceiver)).process()?.let { return it }
|
||||
|
||||
// synthetic members
|
||||
// synthetic properties
|
||||
TowerData.BothTowerLevelAndImplicitReceiver(syntheticLevel, implicitReceiver).process()?.let { return it }
|
||||
|
||||
// invokeExtension on local variable
|
||||
@@ -233,19 +233,17 @@ class TowerResolver {
|
||||
private var currentCandidates: Collection<C> = emptyList()
|
||||
private var currentLevel: ResolutionCandidateApplicability? = null
|
||||
|
||||
override fun getSuccessfulCandidates(): Collection<C>? = getResolved() ?: getResolvedSynthetic()
|
||||
override fun getSuccessfulCandidates(): Collection<C>? = getResolved()
|
||||
|
||||
fun getResolved() = currentCandidates.check { currentLevel == ResolutionCandidateApplicability.RESOLVED }
|
||||
|
||||
fun getResolvedSynthetic() = currentCandidates.check { currentLevel == ResolutionCandidateApplicability.RESOLVED_SYNTHESIZED }
|
||||
|
||||
fun getResolvedLowPriority() = currentCandidates.check { currentLevel == ResolutionCandidateApplicability.RESOLVED_LOW_PRIORITY }
|
||||
|
||||
fun getErrors() = currentCandidates.check {
|
||||
currentLevel == null || currentLevel!! > ResolutionCandidateApplicability.RESOLVED_LOW_PRIORITY
|
||||
}
|
||||
|
||||
override fun getFinalCandidates() = getResolved() ?: getResolvedSynthetic() ?: getResolvedLowPriority() ?: getErrors() ?: emptyList()
|
||||
override fun getFinalCandidates() = getResolved() ?: getResolvedLowPriority() ?: getErrors() ?: emptyList()
|
||||
|
||||
override fun addCandidates(candidates: Collection<C>) {
|
||||
val minimalLevel = candidates.map { getStatus(it).resultingApplicability }.min()!!
|
||||
|
||||
Reference in New Issue
Block a user