[FE] Relax the "no subtyping between context receivers" limitation

This commit is contained in:
Anastasiya Shadrina
2021-06-10 15:21:32 +07:00
committed by TeamCityServer
parent bfd20e1890
commit 1f6746dc74
6 changed files with 31 additions and 53 deletions
@@ -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
}
}
@@ -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) {
@@ -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) {
@@ -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<!>)<!>
}
@@ -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()<!>
}
}