[NI] Support callable references on qualified types with generics

#KT-32154 Fixed
This commit is contained in:
Mikhail Zarechenskiy
2019-06-25 15:55:33 +03:00
parent b8ccd98a17
commit c77f18fbe6
10 changed files with 106 additions and 25 deletions
@@ -19,10 +19,11 @@ import org.jetbrains.kotlin.resolve.calls.tasks.ExplicitReceiverKind.EXTENSION_R
import org.jetbrains.kotlin.resolve.calls.tower.*
import org.jetbrains.kotlin.resolve.descriptorUtil.builtIns
import org.jetbrains.kotlin.resolve.scopes.receivers.DetailedReceiver
import org.jetbrains.kotlin.resolve.scopes.receivers.QualifierReceiver
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.ErrorUtils
import org.jetbrains.kotlin.types.KotlinType
import org.jetbrains.kotlin.types.UnwrappedType
import org.jetbrains.kotlin.types.checker.captureFromExpression
import org.jetbrains.kotlin.types.expressions.CoercionStrategy
import org.jetbrains.kotlin.types.typeUtil.immediateSupertypes
@@ -32,11 +33,10 @@ import org.jetbrains.kotlin.utils.SmartList
import org.jetbrains.kotlin.utils.addIfNotNull
sealed class CallableReceiver(val receiver: ReceiverValueWithSmartCastInfo) {
class UnboundReference(val qualifier: QualifierReceiver, receiver: ReceiverValueWithSmartCastInfo) : CallableReceiver(receiver)
class BoundValueReference(val qualifier: QualifierReceiver, receiver: ReceiverValueWithSmartCastInfo) : CallableReceiver(receiver)
class UnboundReference(receiver: ReceiverValueWithSmartCastInfo) : CallableReceiver(receiver)
class BoundValueReference(receiver: ReceiverValueWithSmartCastInfo) : CallableReceiver(receiver)
class ScopeReceiver(receiver: ReceiverValueWithSmartCastInfo) : CallableReceiver(receiver)
class ExplicitValueReceiver(val lhsArgument: SimpleKotlinCallArgument, receiver: ReceiverValueWithSmartCastInfo) :
CallableReceiver(receiver)
class ExplicitValueReceiver(receiver: ReceiverValueWithSmartCastInfo) : CallableReceiver(receiver)
}
// todo investigate similar code in CheckVisibility
@@ -89,7 +89,7 @@ fun createCallableReferenceProcessor(factory: CallableReferencesCandidateFactory
// note that if we use PrioritizedCompositeScopeTowerProcessor then static will win over unbound members
val staticOrUnbound = SamePriorityCompositeScopeTowerProcessor(static, unbound)
val asValue = lhsResult.qualifier.classValueReceiverWithSmartCastInfo ?: return staticOrUnbound
val asValue = lhsResult.qualifier?.classValueReceiverWithSmartCastInfo ?: return staticOrUnbound
return PrioritizedCompositeScopeTowerProcessor(staticOrUnbound, factory.createCallableProcessor(asValue))
}
is LHSResult.Object -> {
@@ -329,17 +329,16 @@ class CallableReferencesCandidateFactory(
private fun toCallableReceiver(receiver: ReceiverValueWithSmartCastInfo, isExplicit: Boolean): CallableReceiver {
if (!isExplicit) return CallableReceiver.ScopeReceiver(receiver)
val lhsResult = argument.lhsResult
return when (lhsResult) {
is LHSResult.Expression -> CallableReceiver.ExplicitValueReceiver(lhsResult.lshCallArgument, receiver)
return when (val lhsResult = argument.lhsResult) {
is LHSResult.Expression -> CallableReceiver.ExplicitValueReceiver(receiver)
is LHSResult.Type -> {
if (lhsResult.qualifier.classValueReceiver?.type == receiver.receiverValue.type) {
CallableReceiver.BoundValueReference(lhsResult.qualifier, receiver)
if (lhsResult.qualifier?.classValueReceiver?.type == receiver.receiverValue.type) {
CallableReceiver.BoundValueReference(receiver)
} else {
CallableReceiver.UnboundReference(lhsResult.qualifier, receiver)
CallableReceiver.UnboundReference(receiver)
}
}
is LHSResult.Object -> CallableReceiver.BoundValueReference(lhsResult.qualifier, receiver)
is LHSResult.Object -> CallableReceiver.BoundValueReference(receiver)
else -> throw IllegalStateException("Unsupported kind of lhsResult: $lhsResult")
}
}
@@ -167,7 +167,11 @@ private fun preprocessCallableReference(
val lhsType = it.unboundDetailedReceiver.stableType
if (ReflectionTypes.isNumberedTypeWithOneOrMoreNumber(expectedType)) {
val lhsTypeVariable = expectedType.arguments.first().type.unwrap()
csBuilder.addSubtypeConstraint(lhsType, lhsTypeVariable, LHSArgumentConstraintPosition(it.qualifier))
csBuilder.addSubtypeConstraint(
lhsType,
lhsTypeVariable,
LHSArgumentConstraintPosition(it.qualifier ?: it.unboundDetailedReceiver)
)
}
}
if (notCallableTypeConstructor != null) {
@@ -21,9 +21,8 @@ import org.jetbrains.kotlin.resolve.calls.model.*
import org.jetbrains.kotlin.resolve.calls.tower.ResolutionCandidateApplicability
import org.jetbrains.kotlin.resolve.calls.tower.ResolutionCandidateApplicability.INAPPLICABLE
import org.jetbrains.kotlin.resolve.calls.tower.ResolutionCandidateApplicability.INAPPLICABLE_WRONG_RECEIVER
import org.jetbrains.kotlin.resolve.scopes.receivers.QualifierReceiver
import org.jetbrains.kotlin.resolve.scopes.receivers.DetailedReceiver
import org.jetbrains.kotlin.types.KotlinType
import org.jetbrains.kotlin.types.UnwrappedType
import org.jetbrains.kotlin.types.model.KotlinTypeMarker
import org.jetbrains.kotlin.types.model.TypeVariableMarker
@@ -58,7 +57,7 @@ class KnownTypeParameterConstraintPosition(val typeArgument: KotlinType) : Const
override fun toString() = "TypeArgument $typeArgument"
}
class LHSArgumentConstraintPosition(val receiver: QualifierReceiver) : ConstraintPosition() {
class LHSArgumentConstraintPosition(val receiver: DetailedReceiver) : ConstraintPosition() {
override fun toString(): String {
return "LHS receiver $receiver"
}
@@ -78,12 +78,14 @@ interface FunctionExpression : LambdaKotlinCallArgument {
* D.E::foo <-> Expression
*/
sealed class LHSResult {
class Type(val qualifier: QualifierReceiver, resolvedType: UnwrappedType) : LHSResult() {
class Type(val qualifier: QualifierReceiver?, resolvedType: UnwrappedType) : LHSResult() {
val unboundDetailedReceiver: ReceiverValueWithSmartCastInfo
init {
assert(qualifier.descriptor is ClassDescriptor || qualifier.descriptor is TypeAliasDescriptor) {
"Should be ClassDescriptor: ${qualifier.descriptor}"
if (qualifier != null) {
assert(qualifier.descriptor is ClassDescriptor || qualifier.descriptor is TypeAliasDescriptor) {
"Should be ClassDescriptor: ${qualifier.descriptor}"
}
}
val unboundReceiver = TransientReceiver(resolvedType)