diff --git a/compiler/ir/ir.psi2ir/src/org/jetbrains/kotlin/psi2ir/generators/ArgumentsGenerationUtils.kt b/compiler/ir/ir.psi2ir/src/org/jetbrains/kotlin/psi2ir/generators/ArgumentsGenerationUtils.kt index aa04315a3ce..eeb066305c2 100644 --- a/compiler/ir/ir.psi2ir/src/org/jetbrains/kotlin/psi2ir/generators/ArgumentsGenerationUtils.kt +++ b/compiler/ir/ir.psi2ir/src/org/jetbrains/kotlin/psi2ir/generators/ArgumentsGenerationUtils.kt @@ -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 -} \ No newline at end of file +} + +fun unwrapCallableDescriptor(resultingDescriptor: CallableDescriptor): CallableDescriptor = + when (resultingDescriptor) { + is ImportedFromObjectCallableDescriptor<*> -> + resultingDescriptor.callableFromObject + is TypeAliasConstructorDescriptor -> + resultingDescriptor.underlyingConstructorDescriptor + else -> + resultingDescriptor + } diff --git a/compiler/ir/ir.psi2ir/src/org/jetbrains/kotlin/psi2ir/generators/AssignmentGenerator.kt b/compiler/ir/ir.psi2ir/src/org/jetbrains/kotlin/psi2ir/generators/AssignmentGenerator.kt index b1e73ccc326..6b741a67337 100644 --- a/compiler/ir/ir.psi2ir/src/org/jetbrains/kotlin/psi2ir/generators/AssignmentGenerator.kt +++ b/compiler/ir/ir.psi2ir/src/org/jetbrains/kotlin/psi2ir/generators/AssignmentGenerator.kt @@ -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) diff --git a/compiler/ir/ir.psi2ir/src/org/jetbrains/kotlin/psi2ir/generators/CallGenerator.kt b/compiler/ir/ir.psi2ir/src/org/jetbrains/kotlin/psi2ir/generators/CallGenerator.kt index 05aaa8cb8d6..31cd798ee0b 100644 --- a/compiler/ir/ir.psi2ir/src/org/jetbrains/kotlin/psi2ir/generators/CallGenerator.kt +++ b/compiler/ir/ir.psi2ir/src/org/jetbrains/kotlin/psi2ir/generators/CallGenerator.kt @@ -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()) } diff --git a/compiler/ir/ir.psi2ir/src/org/jetbrains/kotlin/psi2ir/intermediate/CallBuilder.kt b/compiler/ir/ir.psi2ir/src/org/jetbrains/kotlin/psi2ir/intermediate/CallBuilder.kt index f85eff239a1..cba7e7e3548 100644 --- a/compiler/ir/ir.psi2ir/src/org/jetbrains/kotlin/psi2ir/intermediate/CallBuilder.kt +++ b/compiler/ir/ir.psi2ir/src/org/jetbrains/kotlin/psi2ir/intermediate/CallBuilder.kt @@ -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 diff --git a/compiler/ir/ir.psi2ir/src/org/jetbrains/kotlin/psi2ir/intermediate/OnceExpressionValue.kt b/compiler/ir/ir.psi2ir/src/org/jetbrains/kotlin/psi2ir/intermediate/OnceExpressionValue.kt index cb0667a4017..b0e77bb2679 100644 --- a/compiler/ir/ir.psi2ir/src/org/jetbrains/kotlin/psi2ir/intermediate/OnceExpressionValue.kt +++ b/compiler/ir/ir.psi2ir/src/org/jetbrains/kotlin/psi2ir/intermediate/OnceExpressionValue.kt @@ -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 diff --git a/compiler/testData/ir/irText/expressions/membersImportedFromObject.kt b/compiler/testData/ir/irText/expressions/membersImportedFromObject.kt new file mode 100644 index 00000000000..8b1ba910953 --- /dev/null +++ b/compiler/testData/ir/irText/expressions/membersImportedFromObject.kt @@ -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 \ No newline at end of file diff --git a/compiler/testData/ir/irText/expressions/membersImportedFromObject.txt b/compiler/testData/ir/irText/expressions/membersImportedFromObject.txt new file mode 100644 index 00000000000..2b5108d989c --- /dev/null +++ b/compiler/testData/ir/irText/expressions/membersImportedFromObject.txt @@ -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 (): kotlin.Int + BLOCK_BODY + RETURN type=kotlin.Nothing from='(): Int' + GET_FIELD 'bar: Int' type=kotlin.Int origin=null + receiver: GET_VAR '' type=A origin=null + PROPERTY public final val kotlin.Int.barExt: kotlin.Int + FUN public final fun kotlin.Int.(): kotlin.Int + BLOCK_BODY + RETURN type=kotlin.Nothing from='() 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 (): kotlin.Int + BLOCK_BODY + RETURN type=kotlin.Nothing from='(): 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 '(): Int' type=kotlin.Int origin=GET_PROPERTY + $this: GET_OBJECT 'A' type=A + FUN DEFAULT_PROPERTY_ACCESSOR public fun (): kotlin.Int + BLOCK_BODY + RETURN type=kotlin.Nothing from='(): 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 (): kotlin.Int + BLOCK_BODY + RETURN type=kotlin.Nothing from='(): 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 '() 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 (): kotlin.Int + BLOCK_BODY + RETURN type=kotlin.Nothing from='(): Int' + GET_FIELD 'test4: Int' type=kotlin.Int origin=null diff --git a/compiler/tests/org/jetbrains/kotlin/ir/IrTextTestCaseGenerated.java b/compiler/tests/org/jetbrains/kotlin/ir/IrTextTestCaseGenerated.java index eae7454e619..ec8df60af32 100644 --- a/compiler/tests/org/jetbrains/kotlin/ir/IrTextTestCaseGenerated.java +++ b/compiler/tests/org/jetbrains/kotlin/ir/IrTextTestCaseGenerated.java @@ -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");