[FE] Relax the "no subtyping between context receivers" limitation
This commit is contained in:
committed by
TeamCityServer
parent
bfd20e1890
commit
1f6746dc74
+22
-44
@@ -10,6 +10,7 @@ import org.jetbrains.kotlin.builtins.getReceiverTypeFromFunctionType
|
||||
import org.jetbrains.kotlin.config.LanguageFeature
|
||||
import org.jetbrains.kotlin.descriptors.*
|
||||
import org.jetbrains.kotlin.descriptors.impl.TypeAliasConstructorDescriptor
|
||||
import org.jetbrains.kotlin.resolve.calls.components.CheckContextReceiversResolutionPart.candidateDescriptor
|
||||
import org.jetbrains.kotlin.resolve.calls.components.CheckReceivers.candidateDescriptor
|
||||
import org.jetbrains.kotlin.resolve.calls.components.CheckReceivers.checkReceiver
|
||||
import org.jetbrains.kotlin.resolve.calls.components.TypeArgumentsToParametersMapper.TypeArgumentsMapping.NoExplicitArguments
|
||||
@@ -17,6 +18,7 @@ import org.jetbrains.kotlin.resolve.calls.components.candidate.CallableReference
|
||||
import org.jetbrains.kotlin.resolve.calls.components.candidate.ResolutionCandidate
|
||||
import org.jetbrains.kotlin.resolve.calls.inference.ConstraintSystemOperation
|
||||
import org.jetbrains.kotlin.resolve.calls.inference.NewConstraintSystem
|
||||
import org.jetbrains.kotlin.resolve.calls.inference.addSubtypeConstraintIfCompatible
|
||||
import org.jetbrains.kotlin.resolve.calls.inference.components.*
|
||||
import org.jetbrains.kotlin.resolve.calls.inference.model.*
|
||||
import org.jetbrains.kotlin.resolve.calls.inference.substitute
|
||||
@@ -30,7 +32,6 @@ import org.jetbrains.kotlin.resolve.scopes.LexicalScope
|
||||
import org.jetbrains.kotlin.resolve.scopes.receivers.ReceiverValueWithSmartCastInfo
|
||||
import org.jetbrains.kotlin.resolve.scopes.utils.parentsWithSelf
|
||||
import org.jetbrains.kotlin.types.*
|
||||
import org.jetbrains.kotlin.types.checker.NewKotlinTypeChecker
|
||||
import org.jetbrains.kotlin.types.model.KotlinTypeMarker
|
||||
import org.jetbrains.kotlin.types.model.TypeConstructorMarker
|
||||
import org.jetbrains.kotlin.types.model.typeConstructor
|
||||
@@ -807,53 +808,30 @@ internal object ErrorDescriptorResolutionPart : ResolutionPart() {
|
||||
|
||||
internal object CheckContextReceiversResolutionPart : ResolutionPart() {
|
||||
private fun ResolutionCandidate.checkReceiver(
|
||||
receiverArgument: SimpleKotlinCallArgument?,
|
||||
receiverParameter: ReceiverParameterDescriptor?
|
||||
) {
|
||||
if ((receiverArgument == null) != (receiverParameter == null)) {
|
||||
error("Inconsistency receiver state for call $kotlinCall and candidate descriptor: $candidateDescriptor")
|
||||
implicitReceivers: Collection<ReceiverValueWithSmartCastInfo>,
|
||||
candidateContextReceiverParameter: ReceiverParameterDescriptor
|
||||
): SimpleKotlinCallArgument? {
|
||||
val csBuilder = getSystem().getBuilder()
|
||||
for (implicitReceiver in implicitReceivers) {
|
||||
val argument = ReceiverExpressionKotlinCallArgument(implicitReceiver)
|
||||
val expectedTypeUnprepared = argument.getExpectedType(candidateContextReceiverParameter, callComponents.languageVersionSettings)
|
||||
|
||||
val expectedType = prepareExpectedType(expectedTypeUnprepared)
|
||||
val argumentType = captureFromTypeParameterUpperBoundIfNeeded(argument.receiver.stableType, expectedType)
|
||||
val position = ReceiverConstraintPositionImpl(argument)
|
||||
if (csBuilder.addSubtypeConstraintIfCompatible(argumentType, expectedType, position)) return argument
|
||||
}
|
||||
if (receiverArgument == null || receiverParameter == null) return
|
||||
val receiverInfo = ReceiverInfo(
|
||||
isReceiver = true,
|
||||
shouldReportUnsafeCall = true,
|
||||
reportUnsafeCallAsUnsafeImplicitInvoke = false
|
||||
)
|
||||
|
||||
resolveKotlinArgument(receiverArgument, receiverParameter, receiverInfo)
|
||||
}
|
||||
|
||||
private fun ResolutionCandidate.searchForAdditionalReceivers(): List<SimpleKotlinCallArgument>? {
|
||||
val result = mutableListOf<ReceiverValueWithSmartCastInfo>()
|
||||
val candidateReceivers = scopeTower.lexicalScope.parentsWithSelf
|
||||
.flatMap { if (it is LexicalScope) scopeTower.getImplicitReceivers(it) else emptyList() }
|
||||
|
||||
fun KotlinType.prepared(): KotlinType = if (containsTypeParameter()) replaceArgumentsWithStarProjections() else this
|
||||
|
||||
for (receiver in candidateDescriptor.contextReceiverParameters) {
|
||||
val expectedReceiverType = receiver.type
|
||||
val expectedReceiverTypeClosestBound =
|
||||
if (expectedReceiverType.isTypeParameter()) expectedReceiverType.supertypes().first()
|
||||
else expectedReceiverType
|
||||
val selectedCandidate = candidateReceivers.firstOrNull { candidateReceiver ->
|
||||
val candidateReceiverType = candidateReceiver.receiverValue.type
|
||||
NewKotlinTypeChecker.Default.isSubtypeOf(candidateReceiverType.prepared(), expectedReceiverTypeClosestBound.prepared())
|
||||
} ?: run {
|
||||
this.diagnosticsFromResolutionParts.add(NoContextReceiver(receiver))
|
||||
return null
|
||||
}
|
||||
result.add(selectedCandidate)
|
||||
}
|
||||
return result.map { ReceiverExpressionKotlinCallArgument(it) }
|
||||
diagnosticsFromResolutionParts.add(NoContextReceiver(candidateContextReceiverParameter))
|
||||
return null
|
||||
}
|
||||
|
||||
override fun ResolutionCandidate.process(workIndex: Int) {
|
||||
resolvedCall.contextReceiversArguments = searchForAdditionalReceivers() ?: return
|
||||
for (i in resolvedCall.contextReceiversArguments.indices) {
|
||||
checkReceiver(
|
||||
resolvedCall.contextReceiversArguments[i],
|
||||
candidateDescriptor.contextReceiverParameters[i]
|
||||
)
|
||||
val implicitReceivers = scopeTower.lexicalScope.parentsWithSelf
|
||||
.flatMap { if (it is LexicalScope) scopeTower.getImplicitReceivers(it) else emptyList() }.toList()
|
||||
val contextReceiversArguments = mutableListOf<SimpleKotlinCallArgument>()
|
||||
for (candidateContextReceiverParameter in candidateDescriptor.contextReceiverParameters) {
|
||||
contextReceiversArguments.add(findContextReceiver(implicitReceivers, candidateContextReceiverParameter) ?: return)
|
||||
}
|
||||
resolvedCall.contextReceiversArguments = contextReceiversArguments
|
||||
}
|
||||
}
|
||||
+1
-1
@@ -153,7 +153,7 @@ private fun checkExpressionArgument(
|
||||
* }
|
||||
*
|
||||
*/
|
||||
private fun captureFromTypeParameterUpperBoundIfNeeded(argumentType: UnwrappedType, expectedType: UnwrappedType): UnwrappedType {
|
||||
fun captureFromTypeParameterUpperBoundIfNeeded(argumentType: UnwrappedType, expectedType: UnwrappedType): UnwrappedType {
|
||||
val expectedTypeConstructor = expectedType.upperIfFlexible().constructor
|
||||
|
||||
if (argumentType.lowerIfFlexible().constructor.declarationDescriptor is TypeParameterDescriptor) {
|
||||
|
||||
+2
-2
@@ -4,10 +4,10 @@ context(Collection<P>) class B<P>
|
||||
|
||||
fun Int.foo() {
|
||||
A<Int>()
|
||||
<!UNRESOLVED_REFERENCE_WRONG_RECEIVER!>A<!><String>()
|
||||
<!NO_CONTEXT_RECEIVER!>A<String>()<!>
|
||||
}
|
||||
|
||||
fun Collection<Int>.bar() {
|
||||
B<Int>()
|
||||
<!UNRESOLVED_REFERENCE_WRONG_RECEIVER!>B<!><String>()
|
||||
<!NO_CONTEXT_RECEIVER!>B<String>()<!>
|
||||
}
|
||||
@@ -14,28 +14,28 @@ fun <T> f(lazy1: Lazy<Int>, lazy2: Lazy<CharSequence>, lazyT: Lazy<T>, lazyLazyT
|
||||
with(lazy2) {
|
||||
test1()
|
||||
test2()
|
||||
<!UNRESOLVED_REFERENCE_WRONG_RECEIVER!>test3<!>()
|
||||
<!NO_CONTEXT_RECEIVER!><!NEW_INFERENCE_NO_INFORMATION_FOR_PARAMETER!>test3<!>()<!>
|
||||
}
|
||||
}
|
||||
with(lazy2) {
|
||||
with(lazy1) {
|
||||
test1()
|
||||
test2()
|
||||
<!UNRESOLVED_REFERENCE_WRONG_RECEIVER!>test3<!>()
|
||||
<!NO_CONTEXT_RECEIVER!><!NEW_INFERENCE_NO_INFORMATION_FOR_PARAMETER!>test3<!>()<!>
|
||||
}
|
||||
}
|
||||
with(lazyT) {
|
||||
with(lazy1) {
|
||||
<!NO_CONTEXT_RECEIVER!>test1()<!>
|
||||
test2()
|
||||
<!UNRESOLVED_REFERENCE_WRONG_RECEIVER!>test3<!>()
|
||||
<!NO_CONTEXT_RECEIVER!><!NEW_INFERENCE_NO_INFORMATION_FOR_PARAMETER!>test3<!>()<!>
|
||||
}
|
||||
}
|
||||
with(lazyLazyT) {
|
||||
with(lazy1) {
|
||||
<!NO_CONTEXT_RECEIVER!>test1()<!>
|
||||
test2()
|
||||
<!UNRESOLVED_REFERENCE_WRONG_RECEIVER!>test3<!>()
|
||||
test3()
|
||||
}
|
||||
}
|
||||
with(lazy1) {
|
||||
|
||||
+1
-1
@@ -7,5 +7,5 @@ context(T)
|
||||
fun <T> T.f(t: B<T>) {}
|
||||
|
||||
fun Int.main(a: A, b: B<String>) {
|
||||
a.<!UNRESOLVED_REFERENCE_WRONG_RECEIVER!>f<!>(b)
|
||||
a.<!NO_CONTEXT_RECEIVER!>f(<!TYPE_MISMATCH!>b<!>)<!>
|
||||
}
|
||||
+1
-1
@@ -12,6 +12,6 @@ fun main() {
|
||||
A<Int>().f()
|
||||
}
|
||||
with(listOf("1", "2", "3")) {
|
||||
A<Int>().<!UNRESOLVED_REFERENCE_WRONG_RECEIVER!>f<!>()
|
||||
A<Int>().<!NO_CONTEXT_RECEIVER!>f()<!>
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user