diff --git a/compiler/ir/ir.psi2ir/src/org/jetbrains/kotlin/psi2ir/generators/LocalClassGenerator.kt b/compiler/ir/ir.psi2ir/src/org/jetbrains/kotlin/psi2ir/generators/LocalClassGenerator.kt new file mode 100644 index 00000000000..b2713ab6655 --- /dev/null +++ b/compiler/ir/ir.psi2ir/src/org/jetbrains/kotlin/psi2ir/generators/LocalClassGenerator.kt @@ -0,0 +1,53 @@ +/* + * Copyright 2010-2016 JetBrains s.r.o. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.jetbrains.kotlin.psi2ir.generators + +import org.jetbrains.kotlin.ir.IrStatement +import org.jetbrains.kotlin.ir.expressions.IrBlockImpl +import org.jetbrains.kotlin.ir.expressions.IrCallImpl +import org.jetbrains.kotlin.ir.expressions.IrOperator +import org.jetbrains.kotlin.psi.KtObjectLiteralExpression +import org.jetbrains.kotlin.psi.psiUtil.endOffset +import org.jetbrains.kotlin.psi.psiUtil.startOffset + +class LocalClassGenerator(statementGenerator: StatementGenerator): StatementGeneratorExtension(statementGenerator) { + fun generateObjectLiteral(expression: KtObjectLiteralExpression): IrStatement { + val objectLiteralType = getInferredTypeWithImplicitCastsOrFail(expression) + val irBlock = IrBlockImpl(expression.startOffset, expression.endOffset, objectLiteralType, IrOperator.OBJECT_LITERAL) + + val irClass = DeclarationGenerator(statementGenerator.context).generateClassOrObjectDeclaration(expression.objectDeclaration) + irBlock.addStatement(irClass) + + val objectConstructor = irClass.descriptor.unsubstitutedPrimaryConstructor ?: + throw AssertionError("Object literal should have a primary constructor: ${irClass.descriptor}") + assert(objectConstructor.dispatchReceiverParameter == null) { + "Object literal constructor should have no dispatch receiver parameter: $objectConstructor" + } + assert(objectConstructor.extensionReceiverParameter == null) { + "Object literal constructor should have no extension receiver parameter: $objectConstructor" + } + assert(objectConstructor.valueParameters.size == 0) { + "Object literal constructor should have no value parameters: $objectConstructor" + } + + irBlock.addStatement(IrCallImpl(expression.startOffset, expression.endOffset, objectLiteralType, + objectConstructor, IrOperator.OBJECT_LITERAL)) + + return irBlock + } + +} diff --git a/compiler/ir/ir.psi2ir/src/org/jetbrains/kotlin/psi2ir/generators/StatementGenerator.kt b/compiler/ir/ir.psi2ir/src/org/jetbrains/kotlin/psi2ir/generators/StatementGenerator.kt index 2b15573fa89..e2d019f6267 100644 --- a/compiler/ir/ir.psi2ir/src/org/jetbrains/kotlin/psi2ir/generators/StatementGenerator.kt +++ b/compiler/ir/ir.psi2ir/src/org/jetbrains/kotlin/psi2ir/generators/StatementGenerator.kt @@ -336,6 +336,9 @@ class StatementGenerator( override fun visitNamedFunction(function: KtNamedFunction, data: Nothing?): IrStatement = LocalFunctionGenerator(this).generateFunction(function) + + override fun visitObjectLiteralExpression(expression: KtObjectLiteralExpression, data: Nothing?): IrStatement = + LocalClassGenerator(this).generateObjectLiteral(expression) } abstract class StatementGeneratorExtension(val statementGenerator: StatementGenerator) : GeneratorWithScope { diff --git a/compiler/ir/ir.tree/src/org/jetbrains/kotlin/ir/expressions/IrOperator.kt b/compiler/ir/ir.tree/src/org/jetbrains/kotlin/ir/expressions/IrOperator.kt index 8975cf7e29d..1594231ba8c 100644 --- a/compiler/ir/ir.tree/src/org/jetbrains/kotlin/ir/expressions/IrOperator.kt +++ b/compiler/ir/ir.tree/src/org/jetbrains/kotlin/ir/expressions/IrOperator.kt @@ -86,9 +86,9 @@ interface IrOperator { object LAMBDA : IrOperatorImpl("LAMBDA") object ANONYMOUS_FUNCTION : IrOperatorImpl("ANONYMOUS_FUNCTION") + object OBJECT_LITERAL : IrOperatorImpl("OBJECT_LITERAL") object SUPER_CONSTRUCTOR_CALL : IrOperatorImpl("SUPER_CONSTRUCTOR_CALL") - object DELEGATING_CONSTRUCTOR_CALL : IrOperatorImpl("DELEGATING_CONSTRUCTOR_CALL") object INITIALIZE_PROPERTY_FROM_PARAMETER : IrOperatorImpl("INITIALIZE_PROPERTY_FROM_PARAMETER") object ANONYMOUS_INITIALIZER : IrOperatorImpl("ANONYMOUS_INITIALIZER") diff --git a/compiler/testData/ir/irText/classes/objectLiteralExpressions.kt b/compiler/testData/ir/irText/classes/objectLiteralExpressions.kt new file mode 100644 index 00000000000..82f1fdd0700 --- /dev/null +++ b/compiler/testData/ir/irText/classes/objectLiteralExpressions.kt @@ -0,0 +1,28 @@ +interface IFoo { + fun foo() +} + +val test1 = object {} + +val test2 = object : IFoo { + override fun foo() { + println("foo") + } +} + +class Outer { + abstract inner class Inner : IFoo + + fun test3() = object : Inner() { + override fun foo() { + println("foo") + } + } +} + +fun Outer.test4() = + object : Outer.Inner() { + override fun foo() { + println("foo") + } + } \ No newline at end of file diff --git a/compiler/testData/ir/irText/classes/objectLiteralExpressions.txt b/compiler/testData/ir/irText/classes/objectLiteralExpressions.txt new file mode 100644 index 00000000000..31495b65017 --- /dev/null +++ b/compiler/testData/ir/irText/classes/objectLiteralExpressions.txt @@ -0,0 +1,55 @@ +FILE /objectLiteralExpressions.kt + CLASS INTERFACE IFoo + FUN public abstract fun foo(): kotlin.Unit + PROPERTY public val test1: kotlin.Any getter=null setter=null + EXPRESSION_BODY + BLOCK type=test1. operator=OBJECT_LITERAL + CLASS CLASS + FUN public constructor () + BLOCK_BODY + CALL . type=test1. operator=OBJECT_LITERAL + PROPERTY public val test2: IFoo getter=null setter=null + EXPRESSION_BODY + BLOCK type=test2. operator=OBJECT_LITERAL + CLASS CLASS + FUN public constructor () + BLOCK_BODY + FUN public open override /*1*/ fun foo(): kotlin.Unit + BLOCK_BODY + CALL .println type=kotlin.Unit operator=null + message: CONST String type=kotlin.String value='foo' + CALL . type=test2. operator=OBJECT_LITERAL + CLASS CLASS Outer + FUN public constructor Outer() + BLOCK_BODY + CLASS CLASS Inner + FUN public constructor Inner() + BLOCK_BODY + FUN public final fun test3(): Outer.Inner + BLOCK_BODY + RETURN type=kotlin.Nothing from=test3 + BLOCK type=Outer.test3. operator=OBJECT_LITERAL + CLASS CLASS + FUN public constructor () + BLOCK_BODY + CALL . type=Outer.Inner operator=SUPER_CONSTRUCTOR_CALL + $this: THIS public final class Outer type=Outer + FUN public open override /*1*/ fun foo(): kotlin.Unit + BLOCK_BODY + CALL .println type=kotlin.Unit operator=null + message: CONST String type=kotlin.String value='foo' + CALL . type=Outer.test3. operator=OBJECT_LITERAL + FUN public fun Outer.test4(): Outer.Inner + BLOCK_BODY + RETURN type=kotlin.Nothing from=test4 + BLOCK type=test4. operator=OBJECT_LITERAL + CLASS CLASS + FUN public constructor () + BLOCK_BODY + CALL . type=Outer.Inner operator=SUPER_CONSTRUCTOR_CALL + $this: $RECEIVER of: test4 type=Outer + FUN public open override /*1*/ fun foo(): kotlin.Unit + BLOCK_BODY + CALL .println type=kotlin.Unit operator=null + message: CONST String type=kotlin.String value='foo' + CALL . type=test4. operator=OBJECT_LITERAL diff --git a/compiler/tests/org/jetbrains/kotlin/ir/IrTextTestCaseGenerated.java b/compiler/tests/org/jetbrains/kotlin/ir/IrTextTestCaseGenerated.java index ca36396a494..a45e0aa3754 100644 --- a/compiler/tests/org/jetbrains/kotlin/ir/IrTextTestCaseGenerated.java +++ b/compiler/tests/org/jetbrains/kotlin/ir/IrTextTestCaseGenerated.java @@ -85,6 +85,12 @@ public class IrTextTestCaseGenerated extends AbstractIrTextTestCase { doTest(fileName); } + @TestMetadata("objectLiteralExpressions.kt") + public void testObjectLiteralExpressions() throws Exception { + String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/ir/irText/classes/objectLiteralExpressions.kt"); + doTest(fileName); + } + @TestMetadata("primaryConstructor.kt") public void testPrimaryConstructor() throws Exception { String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/ir/irText/classes/primaryConstructor.kt");