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:
+25
-18
@@ -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(
|
||||
|
||||
+2
@@ -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
|
||||
}
|
||||
|
||||
|
||||
+14
@@ -0,0 +1,14 @@
|
||||
package test
|
||||
|
||||
import test.Foo.a
|
||||
import test.Foo.foo
|
||||
|
||||
object Foo {
|
||||
val a: String = ""
|
||||
fun foo(): String = ""
|
||||
}
|
||||
|
||||
val test1 = ::a
|
||||
val test1a = Foo::a
|
||||
val test2 = ::foo
|
||||
val test2a = Foo::foo
|
||||
+65
@@ -0,0 +1,65 @@
|
||||
FILE /callableReferenceToImportedFromObject.kt
|
||||
CLASS OBJECT Foo
|
||||
$this: VALUE_PARAMETER this@Foo: Foo
|
||||
CONSTRUCTOR private constructor Foo()
|
||||
BLOCK_BODY
|
||||
DELEGATING_CONSTRUCTOR_CALL 'constructor Any()'
|
||||
INSTANCE_INITIALIZER_CALL classDescriptor='Foo'
|
||||
PROPERTY public final val a: kotlin.String = ""
|
||||
FIELD PROPERTY_BACKING_FIELD public final val a: kotlin.String = ""
|
||||
EXPRESSION_BODY
|
||||
CONST String type=kotlin.String value=''
|
||||
FUN DEFAULT_PROPERTY_ACCESSOR public final fun <get-a>(): kotlin.String
|
||||
$this: VALUE_PARAMETER this@Foo: Foo
|
||||
BLOCK_BODY
|
||||
RETURN type=kotlin.Nothing from='<get-a>(): String'
|
||||
GET_FIELD 'a: String' type=kotlin.String origin=null
|
||||
receiver: GET_VAR 'this@Foo: Foo' type=test.Foo origin=null
|
||||
FUN public final fun foo(): kotlin.String
|
||||
$this: VALUE_PARAMETER this@Foo: Foo
|
||||
BLOCK_BODY
|
||||
RETURN type=kotlin.Nothing from='foo(): String'
|
||||
CONST String type=kotlin.String value=''
|
||||
FUN FAKE_OVERRIDE public open override fun equals(other: kotlin.Any?): kotlin.Boolean
|
||||
$this: VALUE_PARAMETER this@Any: Any
|
||||
VALUE_PARAMETER value-parameter other: kotlin.Any?
|
||||
FUN FAKE_OVERRIDE public open override fun hashCode(): kotlin.Int
|
||||
$this: VALUE_PARAMETER this@Any: Any
|
||||
FUN FAKE_OVERRIDE public open override fun toString(): kotlin.String
|
||||
$this: VALUE_PARAMETER this@Any: Any
|
||||
PROPERTY public val test1: kotlin.reflect.KProperty0<kotlin.String>
|
||||
FIELD PROPERTY_BACKING_FIELD public val test1: kotlin.reflect.KProperty0<kotlin.String>
|
||||
EXPRESSION_BODY
|
||||
PROPERTY_REFERENCE 'a: String' field=null getter='<get-a>(): String' setter=null type=kotlin.reflect.KProperty0<kotlin.String> origin=null
|
||||
$this: GET_OBJECT 'Foo' type=test.Foo
|
||||
FUN DEFAULT_PROPERTY_ACCESSOR public fun <get-test1>(): kotlin.reflect.KProperty0<kotlin.String>
|
||||
BLOCK_BODY
|
||||
RETURN type=kotlin.Nothing from='<get-test1>(): KProperty0<String>'
|
||||
GET_FIELD 'test1: KProperty0<String>' type=kotlin.reflect.KProperty0<kotlin.String> origin=null
|
||||
PROPERTY public val test1a: kotlin.reflect.KProperty0<kotlin.String>
|
||||
FIELD PROPERTY_BACKING_FIELD public val test1a: kotlin.reflect.KProperty0<kotlin.String>
|
||||
EXPRESSION_BODY
|
||||
PROPERTY_REFERENCE 'a: String' field=null getter='<get-a>(): String' setter=null type=kotlin.reflect.KProperty0<kotlin.String> origin=null
|
||||
$this: GET_OBJECT 'Foo' type=test.Foo
|
||||
FUN DEFAULT_PROPERTY_ACCESSOR public fun <get-test1a>(): kotlin.reflect.KProperty0<kotlin.String>
|
||||
BLOCK_BODY
|
||||
RETURN type=kotlin.Nothing from='<get-test1a>(): KProperty0<String>'
|
||||
GET_FIELD 'test1a: KProperty0<String>' type=kotlin.reflect.KProperty0<kotlin.String> origin=null
|
||||
PROPERTY public val test2: kotlin.reflect.KFunction0<kotlin.String>
|
||||
FIELD PROPERTY_BACKING_FIELD public val test2: kotlin.reflect.KFunction0<kotlin.String>
|
||||
EXPRESSION_BODY
|
||||
FUNCTION_REFERENCE 'foo(): String' type=kotlin.reflect.KFunction0<kotlin.String> origin=null
|
||||
$this: GET_OBJECT 'Foo' type=test.Foo
|
||||
FUN DEFAULT_PROPERTY_ACCESSOR public fun <get-test2>(): kotlin.reflect.KFunction0<kotlin.String>
|
||||
BLOCK_BODY
|
||||
RETURN type=kotlin.Nothing from='<get-test2>(): KFunction0<String>'
|
||||
GET_FIELD 'test2: KFunction0<String>' type=kotlin.reflect.KFunction0<kotlin.String> origin=null
|
||||
PROPERTY public val test2a: kotlin.reflect.KFunction0<kotlin.String>
|
||||
FIELD PROPERTY_BACKING_FIELD public val test2a: kotlin.reflect.KFunction0<kotlin.String>
|
||||
EXPRESSION_BODY
|
||||
FUNCTION_REFERENCE 'foo(): String' type=kotlin.reflect.KFunction0<kotlin.String> origin=null
|
||||
$this: GET_OBJECT 'Foo' type=test.Foo
|
||||
FUN DEFAULT_PROPERTY_ACCESSOR public fun <get-test2a>(): kotlin.reflect.KFunction0<kotlin.String>
|
||||
BLOCK_BODY
|
||||
RETURN type=kotlin.Nothing from='<get-test2a>(): KFunction0<String>'
|
||||
GET_FIELD 'test2a: KFunction0<String>' type=kotlin.reflect.KFunction0<kotlin.String> origin=null
|
||||
@@ -563,6 +563,12 @@ public class IrTextTestCaseGenerated extends AbstractIrTextTestCase {
|
||||
doTest(fileName);
|
||||
}
|
||||
|
||||
@TestMetadata("callableReferenceToImportedFromObject.kt")
|
||||
public void testCallableReferenceToImportedFromObject() throws Exception {
|
||||
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/ir/irText/expressions/callableReferenceToImportedFromObject.kt");
|
||||
doTest(fileName);
|
||||
}
|
||||
|
||||
@TestMetadata("calls.kt")
|
||||
public void testCalls() throws Exception {
|
||||
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/ir/irText/expressions/calls.kt");
|
||||
|
||||
Reference in New Issue
Block a user