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:
Denis Zharkov
2016-12-07 17:16:00 +03:00
parent a4adfb43d4
commit 891a036b59
22 changed files with 223 additions and 68 deletions
@@ -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<*>
)
}
@@ -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)
@@ -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()!!