Generate receivers for callable references in the same way as for calls

Properly handle callable members imported from objects
and other related corner cases.

 #KT-18084 Fixed
This commit is contained in:
Dmitry Petrov
2017-05-25 15:53:26 +03:00
parent 7220183912
commit 1420926a9b
6 changed files with 113 additions and 18 deletions
@@ -25,8 +25,9 @@ import org.jetbrains.kotlin.psi.KtCallableReferenceExpression
import org.jetbrains.kotlin.psi.KtClassLiteralExpression
import org.jetbrains.kotlin.psi.psiUtil.endOffset
import org.jetbrains.kotlin.psi.psiUtil.startOffset
import org.jetbrains.kotlin.psi2ir.intermediate.TransientReceiverValue
import org.jetbrains.kotlin.resolve.BindingContext
import org.jetbrains.kotlin.resolve.scopes.receivers.TransientReceiver
import org.jetbrains.kotlin.resolve.ImportedFromObjectCallableDescriptor
import org.jetbrains.kotlin.types.KotlinType
import org.jetbrains.kotlin.types.expressions.DoubleColonLHS
@@ -51,24 +52,30 @@ class ReflectionReferencesGenerator(statementGenerator: StatementGenerator) : St
fun generateCallableReference(ktCallableReference: KtCallableReferenceExpression): IrExpression {
val resolvedCall = getResolvedCall(ktCallableReference.callableReference)!!
val irCallableRef = generateCallableReference(
ktCallableReference.startOffset, ktCallableReference.endOffset,
getInferredTypeWithImplicitCastsOrFail(ktCallableReference),
resolvedCall.resultingDescriptor,
typeArguments = null
)
resolvedCall.dispatchReceiver?.let { dispatchReceiver ->
if (dispatchReceiver !is TransientReceiver) {
irCallableRef.dispatchReceiver = statementGenerator.generateReceiver(ktCallableReference, dispatchReceiver).load()
}
}
resolvedCall.extensionReceiver?.let { extensionReceiver ->
if (extensionReceiver !is TransientReceiver) {
irCallableRef.extensionReceiver = statementGenerator.generateReceiver(ktCallableReference, extensionReceiver).load()
}
}
return irCallableRef
val resultingDescriptor = resolvedCall.resultingDescriptor
val descriptorImportedFromObject = resultingDescriptor as? ImportedFromObjectCallableDescriptor<*>
val referencedDescriptor = descriptorImportedFromObject?.callableFromObject ?: resultingDescriptor
val startOffset = ktCallableReference.startOffset
val endOffset = ktCallableReference.endOffset
return statementGenerator.generateCallReceiver(
ktCallableReference,
resultingDescriptor,
resolvedCall.dispatchReceiver, resolvedCall.extensionReceiver,
isSafe = false
).call { dispatchReceiverValue, extensionReceiverValue ->
generateCallableReference(
startOffset, endOffset,
getInferredTypeWithImplicitCastsOrFail(ktCallableReference),
referencedDescriptor,
typeArguments = null
).also { irCallableReference ->
irCallableReference.dispatchReceiver = dispatchReceiverValue?.loadIfExists()
irCallableReference.extensionReceiver = extensionReceiverValue?.loadIfExists()
}
}
}
fun generateCallableReference(
@@ -23,4 +23,6 @@ class TransientReceiverValue(override val type: KotlinType): IntermediateValue {
override fun load(): IrExpression {
throw AssertionError("Transient receiver should not be instantiated")
}
override fun loadIfExists(): IrExpression? = null
}
@@ -21,6 +21,7 @@ import org.jetbrains.kotlin.types.KotlinType
interface IntermediateValue {
fun load(): IrExpression
fun loadIfExists(): IrExpression? = load()
val type: KotlinType
}