[FE] Move context receivers checks to the separate resolution part

This commit is contained in:
Anastasiya Shadrina
2021-06-10 02:26:48 +07:00
committed by TeamCityServer
parent 37a981cc29
commit bfd20e1890
2 changed files with 55 additions and 39 deletions
@@ -697,47 +697,10 @@ internal object CheckReceivers : ResolutionPart() {
shouldCheckImplicitInvoke = false, // reproduce old inference behaviour
)
}
else -> {
resolvedCall.contextReceiversArguments = searchForAdditionalReceivers() ?: return
for (i in resolvedCall.contextReceiversArguments.indices) {
checkReceiver(
resolvedCall.contextReceiversArguments[i],
candidateDescriptor.contextReceiverParameters[i],
shouldCheckImplicitInvoke = false
)
}
}
}
}
override fun ResolutionCandidate.workCount() = 3
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
org.jetbrains.kotlin.types.checker.NewKotlinTypeChecker.Default.isSubtypeOf(
candidateReceiverType.prepared(),
expectedReceiverTypeClosestBound.prepared()
)
} ?: run {
this.diagnosticsFromResolutionParts.add(NoContextReceiver(receiver))
return null
}
result.add(selectedCandidate)
}
return result.map { ReceiverExpressionKotlinCallArgument(it) }
}
override fun ResolutionCandidate.workCount() = 2
}
internal object CheckArgumentsInParenthesis : ResolutionPart() {
@@ -841,3 +804,56 @@ 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")
}
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) }
}
override fun ResolutionCandidate.process(workIndex: Int) {
resolvedCall.contextReceiversArguments = searchForAdditionalReceivers() ?: return
for (i in resolvedCall.contextReceiversArguments.indices) {
checkReceiver(
resolvedCall.contextReceiversArguments[i],
candidateDescriptor.contextReceiverParameters[i]
)
}
}
}
@@ -7,5 +7,5 @@ context(T)
fun <T> T.f(t: B<T>) {}
fun Int.main(a: A, b: B<String>) {
a.f(<!TYPE_MISMATCH, TYPE_MISMATCH!>b<!>)
a.<!UNRESOLVED_REFERENCE_WRONG_RECEIVER!>f<!>(b)
}