KT-16671 Calls to members imported from objects should be desugared in PSI2IR

This commit is contained in:
Dmitry Petrov
2017-03-06 17:41:56 +03:00
parent 4ba8268a29
commit 6bc6c1b6cc
8 changed files with 143 additions and 17 deletions
@@ -16,10 +16,12 @@
package org.jetbrains.kotlin.psi2ir.generators
import org.jetbrains.kotlin.descriptors.CallableDescriptor
import org.jetbrains.kotlin.descriptors.ClassDescriptor
import org.jetbrains.kotlin.descriptors.TypeParameterDescriptor
import org.jetbrains.kotlin.descriptors.ValueParameterDescriptor
import org.jetbrains.kotlin.descriptors.impl.SyntheticFieldDescriptor
import org.jetbrains.kotlin.descriptors.impl.TypeAliasConstructorDescriptor
import org.jetbrains.kotlin.ir.expressions.IrExpression
import org.jetbrains.kotlin.ir.expressions.IrExpressionWithCopy
import org.jetbrains.kotlin.ir.expressions.impl.IrGetObjectValueImpl
@@ -31,6 +33,7 @@ import org.jetbrains.kotlin.psi.psiUtil.endOffset
import org.jetbrains.kotlin.psi.psiUtil.startOffset
import org.jetbrains.kotlin.psi2ir.intermediate.*
import org.jetbrains.kotlin.resolve.BindingContext
import org.jetbrains.kotlin.resolve.ImportedFromObjectCallableDescriptor
import org.jetbrains.kotlin.resolve.calls.callResolverUtil.getSuperCallExpression
import org.jetbrains.kotlin.resolve.calls.callUtil.isSafeCall
import org.jetbrains.kotlin.resolve.calls.model.*
@@ -100,12 +103,22 @@ fun StatementGenerator.generateBackingFieldReceiver(
fun StatementGenerator.generateCallReceiver(
ktDefaultElement: KtElement,
calleeDescriptor: CallableDescriptor,
dispatchReceiver: ReceiverValue?,
extensionReceiver: ReceiverValue?,
isSafe: Boolean,
isAssignmentReceiver: Boolean = false
) : CallReceiver {
val dispatchReceiverValue = generateReceiverOrNull(ktDefaultElement, dispatchReceiver)
val dispatchReceiverValue: IntermediateValue? =
if (calleeDescriptor is ImportedFromObjectCallableDescriptor<*>) {
assert(dispatchReceiver == null) {
"Call for member imported from object $calleeDescriptor has non-null dispatch receiver $dispatchReceiver"
}
generateReceiverForCalleeImportedFromObject(ktDefaultElement.startOffset, ktDefaultElement.endOffset, calleeDescriptor)
}
else
generateReceiverOrNull(ktDefaultElement, dispatchReceiver)
val extensionReceiverValue = generateReceiverOrNull(ktDefaultElement, extensionReceiver)
return when {
@@ -119,6 +132,18 @@ fun StatementGenerator.generateCallReceiver(
}
}
private fun generateReceiverForCalleeImportedFromObject(
startOffset: Int,
endOffset: Int,
calleeDescriptor: ImportedFromObjectCallableDescriptor<*>
): ExpressionValue {
val objectDescriptor = calleeDescriptor.containingObject
val objectType = objectDescriptor.defaultType
return generateExpressionValue(objectType) {
IrGetObjectValueImpl(startOffset, endOffset, objectType, objectDescriptor)
}
}
fun StatementGenerator.generateVarargExpression(varargArgument: VarargValueArgument, valueParameter: ValueParameterDescriptor) : IrExpression? {
if (varargArgument.arguments.isEmpty()) {
return null
@@ -192,14 +217,25 @@ private fun StatementGenerator.pregenerateValueArguments(call: CallBuilder, reso
}
fun StatementGenerator.pregenerateCallWithReceivers(resolvedCall: ResolvedCall<*>): CallBuilder {
val call = CallBuilder(resolvedCall)
val call = CallBuilder(resolvedCall, unwrapCallableDescriptor(resolvedCall.resultingDescriptor))
call.callReceiver = generateCallReceiver(resolvedCall.call.callElement,
resolvedCall.resultingDescriptor,
resolvedCall.dispatchReceiver,
resolvedCall.extensionReceiver,
resolvedCall.call.isSafeCall())
isSafe = resolvedCall.call.isSafeCall())
call.superQualifier = getSuperQualifier(resolvedCall)
return call
}
}
fun unwrapCallableDescriptor(resultingDescriptor: CallableDescriptor): CallableDescriptor =
when (resultingDescriptor) {
is ImportedFromObjectCallableDescriptor<*> ->
resultingDescriptor.callableFromObject
is TypeAliasConstructorDescriptor ->
resultingDescriptor.underlyingConstructorDescriptor
else ->
resultingDescriptor
}
@@ -140,7 +140,7 @@ class AssignmentGenerator(statementGenerator: StatementGenerator) : StatementGen
}
val propertyReceiver = statementGenerator.generateCallReceiver(
ktLeft, resolvedCall.dispatchReceiver, resolvedCall.extensionReceiver,
ktLeft, descriptor, resolvedCall.dispatchReceiver, resolvedCall.extensionReceiver,
isSafe = resolvedCall.call.isSafeCall(),
isAssignmentReceiver = true)
@@ -19,7 +19,6 @@ package org.jetbrains.kotlin.psi2ir.generators
import org.jetbrains.kotlin.descriptors.*
import org.jetbrains.kotlin.descriptors.impl.LocalVariableDescriptor
import org.jetbrains.kotlin.descriptors.impl.SyntheticFieldDescriptor
import org.jetbrains.kotlin.descriptors.impl.TypeAliasConstructorDescriptor
import org.jetbrains.kotlin.ir.expressions.IrExpression
import org.jetbrains.kotlin.ir.expressions.IrMemberAccessExpression
import org.jetbrains.kotlin.ir.expressions.IrStatementOrigin
@@ -106,13 +105,8 @@ class CallGenerator(statementGenerator: StatementGenerator): StatementGeneratorE
IrGetValueImpl(startOffset, endOffset, descriptor, origin)
fun generateDelegatingConstructorCall(startOffset: Int, endOffset: Int, call: CallBuilder) : IrExpression {
val descriptor = call.descriptor.let { callDescriptor ->
when (callDescriptor) {
is ClassConstructorDescriptor -> callDescriptor
is TypeAliasConstructorDescriptor -> callDescriptor.underlyingConstructorDescriptor
else -> throw AssertionError("Unexpected constructor descriptor: $callDescriptor")
}
}
val descriptor = call.descriptor as? ClassConstructorDescriptor
?: throw AssertionError("Class constructor expected: ${call.descriptor}")
return call.callReceiver.call { dispatchReceiver, extensionReceiver ->
val irCall = IrDelegatingConstructorCallImpl(startOffset, endOffset, descriptor, getTypeArguments(call.original))
@@ -215,7 +209,7 @@ class CallGenerator(statementGenerator: StatementGenerator): StatementGeneratorE
irArgumentValues[valueParameter] = irArgumentValue
}
resolvedCall.valueArgumentsByIndex!!.forEachIndexed { index, valueArgument ->
resolvedCall.valueArgumentsByIndex!!.forEachIndexed { index, _ ->
val valueParameter = valueParameters[index]
irCall.putValueArgument(index, irArgumentValues[valueParameter]?.load())
}
@@ -25,9 +25,10 @@ import org.jetbrains.kotlin.psi2ir.isValueArgumentReorderingRequired
import org.jetbrains.kotlin.resolve.calls.model.ResolvedCall
import org.jetbrains.kotlin.types.KotlinType
class CallBuilder(val original: ResolvedCall<*>) {
val descriptor: CallableDescriptor = original.resultingDescriptor
class CallBuilder(
val original: ResolvedCall<*>,
val descriptor: CallableDescriptor
) {
var superQualifier: ClassDescriptor? = null
lateinit var callReceiver: CallReceiver
@@ -21,6 +21,13 @@ import org.jetbrains.kotlin.ir.util.render
import org.jetbrains.kotlin.psi2ir.generators.CallGenerator
import org.jetbrains.kotlin.types.KotlinType
abstract class ExpressionValue(override val type: KotlinType) : IntermediateValue
inline fun generateExpressionValue(type: KotlinType, crossinline generate: () -> IrExpression) =
object : ExpressionValue(type) {
override fun load(): IrExpression = generate()
}
class OnceExpressionValue(val irExpression: IrExpression) : LValue, AssignmentReceiver {
private var instantiated = false
@@ -0,0 +1,16 @@
import A.foo
import A.bar
import A.fooExt
import A.barExt
object A {
fun foo() = 1
fun Int.fooExt() = 2
val bar = 42
val Int.barExt get() = 43
}
val test1 = foo()
val test2 = bar
val test3 = 1.fooExt()
val test4 = 1.barExt
@@ -0,0 +1,66 @@
FILE /membersImportedFromObject.kt
CLASS OBJECT A
CONSTRUCTOR private constructor A()
BLOCK_BODY
DELEGATING_CONSTRUCTOR_CALL 'constructor Any()'
INSTANCE_INITIALIZER_CALL classDescriptor='A'
FUN public final fun foo(): kotlin.Int
BLOCK_BODY
RETURN type=kotlin.Nothing from='foo(): Int'
CONST Int type=kotlin.Int value='1'
FUN public final fun kotlin.Int.fooExt(): kotlin.Int
BLOCK_BODY
RETURN type=kotlin.Nothing from='fooExt() on Int: Int'
CONST Int type=kotlin.Int value='2'
PROPERTY public final val bar: kotlin.Int = 42
FIELD PROPERTY_BACKING_FIELD public final val bar: kotlin.Int = 42
EXPRESSION_BODY
CONST Int type=kotlin.Int value='42'
FUN DEFAULT_PROPERTY_ACCESSOR public final fun <get-bar>(): kotlin.Int
BLOCK_BODY
RETURN type=kotlin.Nothing from='<get-bar>(): Int'
GET_FIELD 'bar: Int' type=kotlin.Int origin=null
receiver: GET_VAR '<receiver: A>' type=A origin=null
PROPERTY public final val kotlin.Int.barExt: kotlin.Int
FUN public final fun kotlin.Int.<get-barExt>(): kotlin.Int
BLOCK_BODY
RETURN type=kotlin.Nothing from='<get-barExt>() on Int: Int'
CONST Int type=kotlin.Int value='43'
PROPERTY public val test1: kotlin.Int
FIELD PROPERTY_BACKING_FIELD public val test1: kotlin.Int
EXPRESSION_BODY
CALL 'foo(): Int' type=kotlin.Int origin=null
$this: GET_OBJECT 'A' type=A
FUN DEFAULT_PROPERTY_ACCESSOR public fun <get-test1>(): kotlin.Int
BLOCK_BODY
RETURN type=kotlin.Nothing from='<get-test1>(): Int'
GET_FIELD 'test1: Int' type=kotlin.Int origin=null
PROPERTY public val test2: kotlin.Int = 42
FIELD PROPERTY_BACKING_FIELD public val test2: kotlin.Int = 42
EXPRESSION_BODY
CALL '<get-bar>(): Int' type=kotlin.Int origin=GET_PROPERTY
$this: GET_OBJECT 'A' type=A
FUN DEFAULT_PROPERTY_ACCESSOR public fun <get-test2>(): kotlin.Int
BLOCK_BODY
RETURN type=kotlin.Nothing from='<get-test2>(): Int'
GET_FIELD 'test2: Int' type=kotlin.Int origin=null
PROPERTY public val test3: kotlin.Int
FIELD PROPERTY_BACKING_FIELD public val test3: kotlin.Int
EXPRESSION_BODY
CALL 'fooExt() on Int: Int' type=kotlin.Int origin=null
$this: GET_OBJECT 'A' type=A
$receiver: CONST Int type=kotlin.Int value='1'
FUN DEFAULT_PROPERTY_ACCESSOR public fun <get-test3>(): kotlin.Int
BLOCK_BODY
RETURN type=kotlin.Nothing from='<get-test3>(): Int'
GET_FIELD 'test3: Int' type=kotlin.Int origin=null
PROPERTY public val test4: kotlin.Int
FIELD PROPERTY_BACKING_FIELD public val test4: kotlin.Int
EXPRESSION_BODY
CALL '<get-barExt>() on Int: Int' type=kotlin.Int origin=GET_PROPERTY
$this: GET_OBJECT 'A' type=A
$receiver: CONST Int type=kotlin.Int value='1'
FUN DEFAULT_PROPERTY_ACCESSOR public fun <get-test4>(): kotlin.Int
BLOCK_BODY
RETURN type=kotlin.Nothing from='<get-test4>(): Int'
GET_FIELD 'test4: Int' type=kotlin.Int origin=null
@@ -596,6 +596,12 @@ public class IrTextTestCaseGenerated extends AbstractIrTextTestCase {
doTest(fileName);
}
@TestMetadata("membersImportedFromObject.kt")
public void testMembersImportedFromObject() throws Exception {
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/ir/irText/expressions/membersImportedFromObject.kt");
doTest(fileName);
}
@TestMetadata("objectAsCallable.kt")
public void testObjectAsCallable() throws Exception {
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/ir/irText/expressions/objectAsCallable.kt");