diff --git a/compiler/ir/ir.psi2ir/ir.psi2ir.iml b/compiler/ir/ir.psi2ir/ir.psi2ir.iml
index 1152e9530d3..1932e72398c 100644
--- a/compiler/ir/ir.psi2ir/ir.psi2ir.iml
+++ b/compiler/ir/ir.psi2ir/ir.psi2ir.iml
@@ -10,5 +10,6 @@
+
\ No newline at end of file
diff --git a/compiler/ir/ir.psi2ir/src/org/jetbrains/kotlin/psi2ir/builders/ExpressionHelpers.kt b/compiler/ir/ir.psi2ir/src/org/jetbrains/kotlin/psi2ir/builders/ExpressionHelpers.kt
new file mode 100644
index 00000000000..97daeba85eb
--- /dev/null
+++ b/compiler/ir/ir.psi2ir/src/org/jetbrains/kotlin/psi2ir/builders/ExpressionHelpers.kt
@@ -0,0 +1,126 @@
+/*
+ * 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.builders
+
+import org.jetbrains.kotlin.descriptors.*
+import org.jetbrains.kotlin.ir.IrElement
+import org.jetbrains.kotlin.ir.IrStatement
+import org.jetbrains.kotlin.ir.expressions.*
+import org.jetbrains.kotlin.psi2ir.generators.Scope
+import org.jetbrains.kotlin.psi2ir.generators.eqeqeq
+import org.jetbrains.kotlin.psi2ir.generators.primitiveOp1
+import org.jetbrains.kotlin.psi2ir.generators.primitiveOp2
+import org.jetbrains.kotlin.types.KotlinType
+
+
+inline fun IrBuilderWithScope.irLet(
+ value: IrExpression,
+ operator: IrOperator? = null,
+ nameHint: String? = null,
+ body: (VariableDescriptor) -> IrExpression
+): IrExpression {
+ val irTemporary = scope.createTemporaryVariable(value, nameHint)
+ val irResult = body(irTemporary.descriptor)
+ val irBlock = IrBlockImpl(startOffset, endOffset, irResult.type, operator)
+ irBlock.addStatement(irTemporary)
+ irBlock.addStatement(irResult)
+ return irBlock
+}
+
+fun IrStatementsBuilder.defineTemporary(value: IrExpression, nameHint: String? = null): VariableDescriptor {
+ val temporary = scope.createTemporaryVariable(value, nameHint)
+ +temporary
+ return temporary.descriptor
+}
+
+fun IrBuilderWithScope.irReturn(value: IrExpression) =
+ IrReturnImpl(startOffset, endOffset, context.builtIns.nothingType, scope.assertCastOwner(), value)
+
+fun IrBuilderWithScope.irReturnTrue() =
+ irReturn(IrConstImpl(startOffset, endOffset, context.builtIns.booleanType, IrConstKind.Boolean, true))
+
+fun IrBuilderWithScope.irReturnFalse() =
+ irReturn(IrConstImpl(startOffset, endOffset, context.builtIns.booleanType, IrConstKind.Boolean, false))
+
+fun IrBuilderWithScope.irIfThenElse(type: KotlinType, condition: IrExpression, thenPart: IrExpression, elsePart: IrExpression) =
+ IrIfThenElseImpl(startOffset, endOffset, type, condition, thenPart, elsePart)
+
+fun IrBuilderWithScope.irIfNull(type: KotlinType, subject: IrExpression, thenPart: IrExpression, elsePart: IrExpression) =
+ irIfThenElse(type, irEqualsNull(subject), thenPart, elsePart)
+
+fun IrBuilderWithScope.irIfThenReturnTrue(condition: IrExpression) =
+ IrIfThenElseImpl(startOffset, endOffset, context.builtIns.unitType, condition, irReturnTrue())
+
+fun IrBuilderWithScope.irIfThenReturnFalse(condition: IrExpression) =
+ IrIfThenElseImpl(startOffset, endOffset, context.builtIns.unitType, condition, irReturnFalse())
+
+fun IrBuilderWithScope.irThis() =
+ scope.classOwner().let { classOwner ->
+ IrThisReferenceImpl(startOffset, endOffset, classOwner.defaultType, classOwner)
+ }
+
+
+fun IrBuilderWithScope.irGet(variable: VariableDescriptor) =
+ IrGetVariableImpl(startOffset, endOffset, variable)
+
+fun IrBuilderWithScope.irSetVar(variable: VariableDescriptor, value: IrExpression) =
+ IrSetVariableImpl(startOffset, endOffset, variable, value, IrOperator.EQ)
+
+fun IrBuilderWithScope.irOther() =
+ irGet(scope.functionOwner().valueParameters.single())
+
+fun IrBuilderWithScope.irEqeqeq(arg1: IrExpression, arg2: IrExpression) =
+ context.eqeqeq(startOffset, endOffset, arg1, arg2)
+
+fun IrBuilderWithScope.irNull() =
+ IrConstImpl.constNull(startOffset, endOffset, context.builtIns.nullableNothingType)
+
+fun IrBuilderWithScope.irEqualsNull(argument: IrExpression) =
+ primitiveOp2(startOffset, endOffset, context.irBuiltIns.eqeq, IrOperator.EQEQ,
+ argument, irNull())
+
+fun IrBuilderWithScope.irNotEquals(arg1: IrExpression, arg2: IrExpression) =
+ primitiveOp1(startOffset, endOffset, context.irBuiltIns.booleanNot, IrOperator.EXCLEQ,
+ primitiveOp2(startOffset, endOffset, context.irBuiltIns.eqeq, IrOperator.EXCLEQ,
+ arg1, arg2))
+
+fun IrBuilderWithScope.irGet(receiver: IrExpression, property: PropertyDescriptor): IrExpression =
+ IrGetterCallImpl(startOffset, endOffset, property.getter!!, receiver, null, IrOperator.GET_PROPERTY)
+
+fun IrBuilderWithScope.irCall(callee: CallableDescriptor) =
+ IrCallImpl(startOffset, endOffset, callee.returnType!!, callee)
+
+fun IrBuilderWithScope.irCallOp(callee: CallableDescriptor, dispatchReceiver: IrExpression, argument: IrExpression) =
+ IrCallImpl(startOffset, endOffset, callee.returnType!!, callee).apply {
+ this.dispatchReceiver = dispatchReceiver
+ putArgument(0, argument)
+ }
+
+fun IrBuilderWithScope.irNotIs(argument: IrExpression, type: KotlinType) =
+ IrTypeOperatorCallImpl(startOffset, endOffset, context.builtIns.booleanType, IrTypeOperator.NOT_INSTANCEOF, type, argument)
+
+fun IrBuilderWithScope.irAs(argument: IrExpression, type: KotlinType) =
+ IrTypeOperatorCallImpl(startOffset, endOffset, type, IrTypeOperator.CAST, type, argument)
+
+fun IrBuilderWithScope.irInt(value: Int) =
+ IrConstImpl.int(startOffset, endOffset, context.builtIns.intType, value)
+
+fun IrBuilderWithScope.irString(value: String) =
+ IrConstImpl.string(startOffset, endOffset, context.builtIns.stringType, value)
+
+fun IrBuilderWithScope.irConcat() =
+ IrStringConcatenationImpl(startOffset, endOffset, context.builtIns.stringType)
\ No newline at end of file
diff --git a/compiler/ir/ir.psi2ir/src/org/jetbrains/kotlin/psi2ir/builders/IrBuilder.kt b/compiler/ir/ir.psi2ir/src/org/jetbrains/kotlin/psi2ir/builders/IrBuilder.kt
new file mode 100644
index 00000000000..31b9b4fa517
--- /dev/null
+++ b/compiler/ir/ir.psi2ir/src/org/jetbrains/kotlin/psi2ir/builders/IrBuilder.kt
@@ -0,0 +1,102 @@
+/*
+ * 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.builders
+
+import org.jetbrains.kotlin.descriptors.FunctionDescriptor
+import org.jetbrains.kotlin.ir.IrElement
+import org.jetbrains.kotlin.ir.IrStatement
+import org.jetbrains.kotlin.ir.expressions.*
+import org.jetbrains.kotlin.psi2ir.generators.Generator
+import org.jetbrains.kotlin.psi2ir.generators.GeneratorContext
+import org.jetbrains.kotlin.psi2ir.generators.GeneratorWithScope
+import org.jetbrains.kotlin.psi2ir.generators.Scope
+import org.jetbrains.kotlin.types.KotlinType
+import java.util.*
+
+abstract class IrBuilder(
+ override val context: GeneratorContext,
+ var startOffset: Int,
+ var endOffset: Int
+) : Generator
+
+abstract class IrBuilderWithScope(
+ context: GeneratorContext,
+ override val scope: Scope,
+ startOffset: Int,
+ endOffset: Int
+) : IrBuilder(context, startOffset, endOffset), GeneratorWithScope
+
+abstract class IrStatementsBuilder(
+ context: GeneratorContext,
+ scope: Scope,
+ startOffset: Int,
+ endOffset: Int
+) : IrBuilderWithScope(context, scope, startOffset, endOffset), GeneratorWithScope {
+ operator fun IrStatement.unaryPlus() {
+ addStatement(this)
+ }
+
+ protected abstract fun addStatement(irStatement: IrStatement)
+ protected abstract fun doBuild(): T
+}
+
+open class IrBlockBodyBuilder(
+ context: GeneratorContext,
+ scope: Scope,
+ startOffset: Int,
+ endOffset: Int
+) : IrStatementsBuilder(context, scope, startOffset, endOffset) {
+ private val irBlockBody = IrBlockBodyImpl(startOffset, endOffset)
+
+ override fun addStatement(irStatement: IrStatement) {
+ irBlockBody.addStatement(irStatement)
+ }
+
+ override fun doBuild(): IrBlockBody {
+ return irBlockBody
+ }
+}
+
+class IrBlockBuilder(
+ context: GeneratorContext,
+ scope: Scope,
+ startOffset: Int,
+ endOffset: Int,
+ val operator: IrOperator? = null,
+ var resultType: KotlinType? = null
+) : IrStatementsBuilder(context, scope, startOffset, endOffset) {
+ private val statements = ArrayList()
+
+ override fun addStatement(irStatement: IrStatement) {
+ statements.add(irStatement)
+ }
+
+ override fun doBuild(): IrBlock {
+ val resultType = this.resultType ?:
+ (statements.lastOrNull() as? IrExpression)?.type ?:
+ context.builtIns.unitType
+ val irBlock = IrBlockImpl(startOffset, endOffset, resultType, operator)
+ irBlock.addAll(statements)
+ return irBlock
+ }
+}
+
+fun T.at(startOffset: Int, endOffset: Int): T {
+ this.startOffset = startOffset
+ this.endOffset = endOffset
+ return this
+}
diff --git a/compiler/ir/ir.psi2ir/src/org/jetbrains/kotlin/psi2ir/builders/ScopeHelpers.kt b/compiler/ir/ir.psi2ir/src/org/jetbrains/kotlin/psi2ir/builders/ScopeHelpers.kt
new file mode 100644
index 00000000000..d62955684b6
--- /dev/null
+++ b/compiler/ir/ir.psi2ir/src/org/jetbrains/kotlin/psi2ir/builders/ScopeHelpers.kt
@@ -0,0 +1,34 @@
+/*
+ * 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.builders
+
+import org.jetbrains.kotlin.descriptors.*
+import org.jetbrains.kotlin.psi2ir.generators.Scope
+
+inline fun Scope.assertCastOwner() =
+ scopeOwner as? T ?:
+ throw AssertionError("Unexpected scopeOwner: $scopeOwner")
+
+fun Scope.functionOwner(): FunctionDescriptor =
+ assertCastOwner()
+
+fun Scope.classOwner(): ClassDescriptor =
+ when (scopeOwner) {
+ is ClassDescriptor -> scopeOwner
+ is MemberDescriptor -> scopeOwner.containingDeclaration as ClassDescriptor
+ else -> throw AssertionError("Unexpected scopeOwner: $scopeOwner")
+ }
diff --git a/compiler/ir/ir.psi2ir/src/org/jetbrains/kotlin/psi2ir/generators/ClassGenerator.kt b/compiler/ir/ir.psi2ir/src/org/jetbrains/kotlin/psi2ir/generators/ClassGenerator.kt
index 662b95120e5..3fbfb027a56 100644
--- a/compiler/ir/ir.psi2ir/src/org/jetbrains/kotlin/psi2ir/generators/ClassGenerator.kt
+++ b/compiler/ir/ir.psi2ir/src/org/jetbrains/kotlin/psi2ir/generators/ClassGenerator.kt
@@ -46,9 +46,17 @@ class ClassGenerator(val declarationGenerator: DeclarationGenerator) : Generator
irClass.nestedInitializers = BodyGenerator(descriptor, context).generateNestedInitializersBody(ktClassOrObject)
}
+ if (descriptor.isData) {
+ generateAdditionalMembersForDataClass(irClass, ktClassOrObject)
+ }
+
return irClass
}
+ private fun generateAdditionalMembersForDataClass(irClass: IrClassImpl, ktClassOrObject: KtClassOrObject) {
+ DataClassMembersGenerator(ktClassOrObject, context, irClass).generate()
+ }
+
private fun shouldGenerateNestedInitializers(ktClassOrObject: KtClassOrObject): Boolean {
val ktClassBody = ktClassOrObject.getBody() ?: return false
diff --git a/compiler/ir/ir.psi2ir/src/org/jetbrains/kotlin/psi2ir/generators/DataClassMembersGenerator.kt b/compiler/ir/ir.psi2ir/src/org/jetbrains/kotlin/psi2ir/generators/DataClassMembersGenerator.kt
new file mode 100644
index 00000000000..c8595ae5b60
--- /dev/null
+++ b/compiler/ir/ir.psi2ir/src/org/jetbrains/kotlin/psi2ir/generators/DataClassMembersGenerator.kt
@@ -0,0 +1,161 @@
+/*
+ * 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 com.intellij.psi.PsiElement
+import org.jetbrains.kotlin.backend.common.DataClassMethodGenerator
+import org.jetbrains.kotlin.descriptors.*
+import org.jetbrains.kotlin.incremental.components.NoLookupLocation
+import org.jetbrains.kotlin.ir.UNDEFINED_OFFSET
+import org.jetbrains.kotlin.ir.declarations.IrClassImpl
+import org.jetbrains.kotlin.ir.declarations.IrDeclarationOrigin
+import org.jetbrains.kotlin.ir.declarations.IrFunctionImpl
+import org.jetbrains.kotlin.ir.expressions.IrExpression
+import org.jetbrains.kotlin.ir.expressions.mapValueParameters
+import org.jetbrains.kotlin.name.Name
+import org.jetbrains.kotlin.psi.KtClassOrObject
+import org.jetbrains.kotlin.psi.KtParameter
+import org.jetbrains.kotlin.psi.psiUtil.endOffset
+import org.jetbrains.kotlin.psi.psiUtil.startOffset
+import org.jetbrains.kotlin.psi2ir.builders.*
+import org.jetbrains.kotlin.psi2ir.containsNull
+import org.jetbrains.kotlin.resolve.BindingContext
+import org.jetbrains.kotlin.resolve.DescriptorToSourceUtils
+import org.jetbrains.kotlin.types.KotlinType
+import org.jetbrains.kotlin.types.checker.KotlinTypeChecker
+import java.lang.AssertionError
+
+class DataClassMembersGenerator(
+ ktClassOrObject: KtClassOrObject,
+ override val context: GeneratorContext,
+ val irClass: IrClassImpl
+) : Generator, DataClassMethodGenerator(ktClassOrObject, context.bindingContext) {
+ private class IrMemberFunctionBuilder(
+ context: GeneratorContext,
+ val irClass: IrClassImpl,
+ val function: FunctionDescriptor,
+ startOffset: Int = UNDEFINED_OFFSET,
+ endOffset: Int = UNDEFINED_OFFSET
+ ) : IrBlockBodyBuilder(context, Scope(function), startOffset, endOffset){
+ inline fun addToClass(body: IrMemberFunctionBuilder.() -> Unit) {
+ val irFunction = IrFunctionImpl(startOffset, endOffset, IrDeclarationOrigin.GENERATED_DATA_CLASS_MEMBER, function)
+ body()
+ irFunction.body = doBuild()
+ irClass.addMember(irFunction)
+ }
+ }
+
+ private inline fun buildMember(function: FunctionDescriptor, psiElement: PsiElement? = null, body: IrMemberFunctionBuilder.() -> Unit) {
+ IrMemberFunctionBuilder(context, irClass, function,
+ psiElement?.startOffset ?: UNDEFINED_OFFSET,
+ psiElement?.endOffset ?: UNDEFINED_OFFSET
+ ).addToClass(body)
+
+ }
+
+ override fun generateComponentFunction(function: FunctionDescriptor, parameter: ValueParameterDescriptor) {
+ val ktParameter = DescriptorToSourceUtils.descriptorToDeclaration(parameter) ?:
+ throw AssertionError("No definition for data class constructor parameter $parameter")
+
+ val property = getOrFail(BindingContext.VALUE_PARAMETER_AS_PROPERTY, parameter)
+
+ buildMember(function, ktParameter) {
+ +irReturn(irGet(irThis(), property))
+ }
+ }
+
+ override fun generateCopyFunction(function: FunctionDescriptor, constructorParameters: List) {
+ val dataClassConstructor = classDescriptor.unsubstitutedPrimaryConstructor ?:
+ throw AssertionError("Data class should have a primary constructor: $classDescriptor")
+
+ buildMember(function) {
+ +irReturn(irCall(dataClassConstructor).mapValueParameters { irGet(function.valueParameters[it.index]) })
+ }
+ }
+
+ override fun generateEqualsMethod(function: FunctionDescriptor, properties: List) {
+ buildMember(function) {
+ +irIfThenReturnTrue(irEqeqeq(irThis(), irOther()))
+ +irIfThenReturnFalse(irNotIs(irOther(), classDescriptor.defaultType))
+ val otherWithCast = defineTemporary(irAs(irOther(), classDescriptor.defaultType), "other_with_cast")
+ for (property in properties) {
+ +irIfThenReturnFalse(
+ irNotEquals(irGet(irThis(), property),
+ irGet(irGet(otherWithCast), property)))
+ }
+ +irReturnTrue()
+ }
+ }
+
+ private val INT = context.builtIns.int
+ private val INT_TYPE = context.builtIns.intType
+
+ private inline fun ClassDescriptor.findFirstFunction(name: String, predicate: (CallableMemberDescriptor) -> Boolean) =
+ unsubstitutedMemberScope.getContributedFunctions(Name.identifier(name), NoLookupLocation.FROM_BACKEND).first(predicate)
+
+ private val IMUL = INT.findFirstFunction("times") { KotlinTypeChecker.DEFAULT.equalTypes(it.valueParameters[0].type, INT_TYPE) }
+ private val IADD = INT.findFirstFunction("plus") { KotlinTypeChecker.DEFAULT.equalTypes(it.valueParameters[0].type, INT_TYPE) }
+
+ private fun getHashCodeFunction(type: KotlinType): CallableDescriptor =
+ (type.constructor.declarationDescriptor as? ClassDescriptor)?.findFirstFunction("hashCode") { it.valueParameters.isEmpty() } ?:
+ throw AssertionError("Unexpected type: $type")
+
+ override fun generateHashCodeMethod(function: FunctionDescriptor, properties: List) {
+ buildMember(function) {
+ val result = defineTemporary(irInt(0), "result")
+ var first = true
+ for (property in properties) {
+ val hashCodeOfProperty = getHashCodeOfProperty(irThis(), property)
+ val irNewValue =
+ if (first) hashCodeOfProperty
+ else irCallOp(IADD, irCallOp(IMUL, irGet(result), irInt(31)), hashCodeOfProperty)
+ +irSetVar(result, irNewValue)
+ first = false
+ }
+ +irReturn(irGet(result))
+ }
+ }
+
+ private fun IrMemberFunctionBuilder.getHashCodeOfProperty(receiver: IrExpression, property: PropertyDescriptor): IrExpression =
+ when {
+ property.type.containsNull() ->
+ irLet(irGet(receiver, property)) { variable ->
+ irIfNull(context.builtIns.intType, irGet(variable), irInt(0), getHashCodeOf(irGet(variable)))
+ }
+ else ->
+ getHashCodeOf(irGet(receiver, property))
+ }
+
+ private fun IrMemberFunctionBuilder.getHashCodeOf(irValue: IrExpression): IrExpression =
+ irCall(getHashCodeFunction(irValue.type)).apply { dispatchReceiver = irValue }
+
+ override fun generateToStringMethod(function: FunctionDescriptor, properties: List) {
+ buildMember(function) {
+ val irConcat = irConcat()
+ irConcat.addArgument(irString(classDescriptor.name.asString() + "("))
+ var first = true
+ for (property in properties) {
+ if (!first) irConcat.addArgument(irString(", "))
+ irConcat.addArgument(irString(property.name.asString() + "="))
+ irConcat.addArgument(irGet(irThis(), property))
+ first = false
+ }
+ irConcat.addArgument(irString(")"))
+ +irReturn(irConcat)
+ }
+ }
+}
diff --git a/compiler/ir/ir.psi2ir/src/org/jetbrains/kotlin/psi2ir/generators/Primitives.kt b/compiler/ir/ir.psi2ir/src/org/jetbrains/kotlin/psi2ir/generators/Primitives.kt
index e2140a387a6..c3be0f3e059 100644
--- a/compiler/ir/ir.psi2ir/src/org/jetbrains/kotlin/psi2ir/generators/Primitives.kt
+++ b/compiler/ir/ir.psi2ir/src/org/jetbrains/kotlin/psi2ir/generators/Primitives.kt
@@ -35,6 +35,9 @@ fun GeneratorContext.equalsNull(startOffset: Int, endOffset: Int, argument: IrEx
primitiveOp2(startOffset, endOffset, irBuiltIns.eqeq, IrOperator.EQEQ,
argument, constNull(startOffset, endOffset))
+fun GeneratorContext.eqeqeq(startOffset: Int, endOffset: Int, argument1: IrExpression, argument2: IrExpression): IrExpression =
+ primitiveOp2(startOffset, endOffset, irBuiltIns.eqeqeq, IrOperator.EQEQEQ, argument1, argument2)
+
fun GeneratorContext.throwNpe(startOffset: Int, endOffset: Int, operator: IrOperator): IrExpression =
IrNullaryPrimitiveImpl(startOffset, endOffset, operator, irBuiltIns.throwNpe)
diff --git a/compiler/ir/ir.psi2ir/src/org/jetbrains/kotlin/psi2ir/intermediate/VariableLValue.kt b/compiler/ir/ir.psi2ir/src/org/jetbrains/kotlin/psi2ir/intermediate/VariableLValue.kt
index 440dc2df7b1..ac9c0f48799 100644
--- a/compiler/ir/ir.psi2ir/src/org/jetbrains/kotlin/psi2ir/intermediate/VariableLValue.kt
+++ b/compiler/ir/ir.psi2ir/src/org/jetbrains/kotlin/psi2ir/intermediate/VariableLValue.kt
@@ -40,8 +40,8 @@ class VariableLValue(
IrGetVariableImpl(startOffset, endOffset, descriptor, irOperator)
override fun store(irExpression: IrExpression): IrExpression =
- IrSetVariableImpl(startOffset, endOffset, descriptor.type.builtIns.unitType,
- descriptor, irExpression, irOperator)
+ IrSetVariableImpl(startOffset, endOffset, descriptor,
+ irExpression, irOperator)
override fun assign(withLValue: (LValue) -> IrExpression): IrExpression =
withLValue(this)
diff --git a/compiler/ir/ir.tree/src/org/jetbrains/kotlin/ir/declarations/IrDeclaration.kt b/compiler/ir/ir.tree/src/org/jetbrains/kotlin/ir/declarations/IrDeclaration.kt
index 1e39c2b2b68..a87a13d0251 100644
--- a/compiler/ir/ir.tree/src/org/jetbrains/kotlin/ir/declarations/IrDeclaration.kt
+++ b/compiler/ir/ir.tree/src/org/jetbrains/kotlin/ir/declarations/IrDeclaration.kt
@@ -42,6 +42,7 @@ enum class IrDeclarationKind {
enum class IrDeclarationOrigin {
DEFINED,
+ GENERATED_DATA_CLASS_MEMBER,
LOCAL_FUNCTION_FOR_LAMBDA,
IR_TEMPORARY_VARIABLE,
}
diff --git a/compiler/ir/ir.tree/src/org/jetbrains/kotlin/ir/descriptors/IrBuiltIns.kt b/compiler/ir/ir.tree/src/org/jetbrains/kotlin/ir/descriptors/IrBuiltIns.kt
index 38ed8fe1112..e3f8d5cf44a 100644
--- a/compiler/ir/ir.tree/src/org/jetbrains/kotlin/ir/descriptors/IrBuiltIns.kt
+++ b/compiler/ir/ir.tree/src/org/jetbrains/kotlin/ir/descriptors/IrBuiltIns.kt
@@ -74,6 +74,4 @@ class IrBuiltIns(val builtIns: KotlinBuiltIns) {
private fun ClassDescriptor.findSingleFunction(name: String): FunctionDescriptor =
getMemberScope(TypeSubstitution.EMPTY).getContributedFunctions(Name.identifier(name), NoLookupLocation.FROM_BUILTINS).single()
-
-
}
diff --git a/compiler/ir/ir.tree/src/org/jetbrains/kotlin/ir/expressions/IrGeneralCall.kt b/compiler/ir/ir.tree/src/org/jetbrains/kotlin/ir/expressions/IrGeneralCall.kt
index c50f0d7cf04..bb2705d5b97 100644
--- a/compiler/ir/ir.tree/src/org/jetbrains/kotlin/ir/expressions/IrGeneralCall.kt
+++ b/compiler/ir/ir.tree/src/org/jetbrains/kotlin/ir/expressions/IrGeneralCall.kt
@@ -17,6 +17,7 @@
package org.jetbrains.kotlin.ir.expressions
import org.jetbrains.kotlin.descriptors.CallableDescriptor
+import org.jetbrains.kotlin.descriptors.ValueParameterDescriptor
import org.jetbrains.kotlin.ir.IrElement
import org.jetbrains.kotlin.ir.assertCast
import org.jetbrains.kotlin.ir.assertDetached
@@ -34,6 +35,20 @@ interface IrGeneralCall : IrMemberAccessExpression {
fun removeArgument(index: Int)
}
+fun T.putArguments(arguments: List): T {
+ arguments.forEachIndexed { i, irArgument ->
+ putArgument(i, irArgument)
+ }
+ return this
+}
+
+inline fun T.mapValueParameters(transform: (ValueParameterDescriptor) -> IrExpression): T {
+ descriptor.valueParameters.forEach {
+ putArgument(it.index, transform(it))
+ }
+ return this
+}
+
abstract class IrGeneralCallBase(
startOffset: Int,
endOffset: Int,
diff --git a/compiler/ir/ir.tree/src/org/jetbrains/kotlin/ir/expressions/IrThisReference.kt b/compiler/ir/ir.tree/src/org/jetbrains/kotlin/ir/expressions/IrThisReference.kt
index 3031e321e9e..bbaed5346f9 100644
--- a/compiler/ir/ir.tree/src/org/jetbrains/kotlin/ir/expressions/IrThisReference.kt
+++ b/compiler/ir/ir.tree/src/org/jetbrains/kotlin/ir/expressions/IrThisReference.kt
@@ -17,6 +17,7 @@
package org.jetbrains.kotlin.ir.expressions
import org.jetbrains.kotlin.descriptors.ClassDescriptor
+import org.jetbrains.kotlin.descriptors.ReceiverParameterDescriptor
import org.jetbrains.kotlin.ir.visitors.IrElementVisitor
import org.jetbrains.kotlin.types.KotlinType
@@ -25,6 +26,9 @@ interface IrThisReference : IrExpression, IrExpressionWithCopy {
override fun copy(): IrThisReference
}
+val IrThisReference.receiverParameter: ReceiverParameterDescriptor
+ get() = classDescriptor.thisAsReceiverParameter
+
class IrThisReferenceImpl(
startOffset: Int,
endOffset: Int,
@@ -36,5 +40,4 @@ class IrThisReferenceImpl(
override fun copy(): IrThisReference =
IrThisReferenceImpl(startOffset, endOffset, type, classDescriptor)
-
}
\ No newline at end of file
diff --git a/compiler/ir/ir.tree/src/org/jetbrains/kotlin/ir/expressions/IrVariableAccessExpression.kt b/compiler/ir/ir.tree/src/org/jetbrains/kotlin/ir/expressions/IrVariableAccessExpression.kt
index 7321893d77c..78f960347f6 100644
--- a/compiler/ir/ir.tree/src/org/jetbrains/kotlin/ir/expressions/IrVariableAccessExpression.kt
+++ b/compiler/ir/ir.tree/src/org/jetbrains/kotlin/ir/expressions/IrVariableAccessExpression.kt
@@ -19,7 +19,7 @@ package org.jetbrains.kotlin.ir.expressions
import org.jetbrains.kotlin.descriptors.VariableDescriptor
import org.jetbrains.kotlin.ir.*
import org.jetbrains.kotlin.ir.visitors.IrElementVisitor
-import org.jetbrains.kotlin.types.KotlinType
+import org.jetbrains.kotlin.resolve.descriptorUtil.builtIns
interface IrVariableAccessExpression : IrDeclarationReference {
override val descriptor: VariableDescriptor
@@ -50,18 +50,16 @@ class IrGetVariableImpl(
class IrSetVariableImpl(
startOffset: Int,
endOffset: Int,
- type: KotlinType,
override val descriptor: VariableDescriptor,
override val operator: IrOperator?
-) : IrExpressionBase(startOffset, endOffset, type), IrSetVariable {
+) : IrExpressionBase(startOffset, endOffset, descriptor.builtIns.unitType), IrSetVariable {
constructor(
startOffset: Int,
endOffset: Int,
- type: KotlinType,
descriptor: VariableDescriptor,
value: IrExpression,
operator: IrOperator?
- ) : this(startOffset, endOffset, type, descriptor, operator) {
+ ) : this(startOffset, endOffset, descriptor, operator) {
this.value = value
}
diff --git a/compiler/testData/ir/irText/classes/dataClasses.kt b/compiler/testData/ir/irText/classes/dataClasses.kt
new file mode 100644
index 00000000000..2bb29a731ea
--- /dev/null
+++ b/compiler/testData/ir/irText/classes/dataClasses.kt
@@ -0,0 +1 @@
+data class Test1(val x: Int, val y: String, val z: Any)
\ No newline at end of file
diff --git a/compiler/testData/ir/irText/classes/dataClasses.txt b/compiler/testData/ir/irText/classes/dataClasses.txt
new file mode 100644
index 00000000000..da991c905b3
--- /dev/null
+++ b/compiler/testData/ir/irText/classes/dataClasses.txt
@@ -0,0 +1,129 @@
+FILE /dataClasses.kt
+ CLASS CLASS Test1
+ FUN public constructor Test1(/*0*/ x: kotlin.Int, /*1*/ y: kotlin.String, /*2*/ z: kotlin.Any)
+ BLOCK_BODY
+ SET_BACKING_FIELD x type=kotlin.Unit operator=null
+ GET_VAR x type=kotlin.Int operator=INITIALIZE_PROPERTY_FROM_PARAMETER
+ SET_BACKING_FIELD y type=kotlin.Unit operator=null
+ GET_VAR y type=kotlin.String operator=INITIALIZE_PROPERTY_FROM_PARAMETER
+ SET_BACKING_FIELD z type=kotlin.Unit operator=null
+ GET_VAR z type=kotlin.Any operator=INITIALIZE_PROPERTY_FROM_PARAMETER
+ PROPERTY public final val x: kotlin.Int getter=null setter=null
+ EXPRESSION_BODY
+ GET_VAR x type=kotlin.Int operator=INITIALIZE_PROPERTY_FROM_PARAMETER
+ PROPERTY public final val y: kotlin.String getter=null setter=null
+ EXPRESSION_BODY
+ GET_VAR y type=kotlin.String operator=INITIALIZE_PROPERTY_FROM_PARAMETER
+ PROPERTY public final val z: kotlin.Any getter=null setter=null
+ EXPRESSION_BODY
+ GET_VAR z type=kotlin.Any operator=INITIALIZE_PROPERTY_FROM_PARAMETER
+ FUN public final operator /*synthesized*/ fun component1(): kotlin.Int
+ BLOCK_BODY
+ RETURN type=kotlin.Nothing from=component1
+ CALL . type=kotlin.Int operator=GET_PROPERTY
+ $this: THIS public final data class Test1 type=Test1
+ FUN public final operator /*synthesized*/ fun component2(): kotlin.String
+ BLOCK_BODY
+ RETURN type=kotlin.Nothing from=component2
+ CALL . type=kotlin.String operator=GET_PROPERTY
+ $this: THIS public final data class Test1 type=Test1
+ FUN public final operator /*synthesized*/ fun component3(): kotlin.Any
+ BLOCK_BODY
+ RETURN type=kotlin.Nothing from=component3
+ CALL . type=kotlin.Any operator=GET_PROPERTY
+ $this: THIS public final data class Test1 type=Test1
+ FUN public final /*synthesized*/ fun copy(/*0*/ x: kotlin.Int = ..., /*1*/ y: kotlin.String = ..., /*2*/ z: kotlin.Any = ...): Test1
+ BLOCK_BODY
+ RETURN type=kotlin.Nothing from=copy
+ CALL . type=Test1 operator=null
+ x: GET_VAR x type=kotlin.Int operator=null
+ y: GET_VAR y type=kotlin.String operator=null
+ z: GET_VAR z type=kotlin.Any operator=null
+ FUN public open override /*1*/ /*fake_override*/ fun toString(): kotlin.String
+ BLOCK_BODY
+ RETURN type=kotlin.Nothing from=toString
+ STRING_CONCATENATION type=kotlin.String
+ CONST String type=kotlin.String value='Test1('
+ CONST String type=kotlin.String value='x='
+ CALL . type=kotlin.Int operator=GET_PROPERTY
+ $this: THIS public final data class Test1 type=Test1
+ CONST String type=kotlin.String value=', '
+ CONST String type=kotlin.String value='y='
+ CALL . type=kotlin.String operator=GET_PROPERTY
+ $this: THIS public final data class Test1 type=Test1
+ CONST String type=kotlin.String value=', '
+ CONST String type=kotlin.String value='z='
+ CALL . type=kotlin.Any operator=GET_PROPERTY
+ $this: THIS public final data class Test1 type=Test1
+ CONST String type=kotlin.String value=')'
+ FUN public open override /*1*/ /*fake_override*/ fun hashCode(): kotlin.Int
+ BLOCK_BODY
+ VAR val tmp0_result: kotlin.Int
+ CONST Int type=kotlin.Int value='0'
+ SET_VAR tmp0_result type=kotlin.Unit operator=EQ
+ CALL .hashCode type=kotlin.Int operator=null
+ $this: CALL . type=kotlin.Int operator=GET_PROPERTY
+ $this: THIS public final data class Test1 type=Test1
+ SET_VAR tmp0_result type=kotlin.Unit operator=EQ
+ CALL .plus type=kotlin.Int operator=null
+ $this: CALL .times type=kotlin.Int operator=null
+ $this: GET_VAR tmp0_result type=kotlin.Int operator=null
+ other: CONST Int type=kotlin.Int value='31'
+ other: CALL .hashCode type=kotlin.Int operator=null
+ $this: CALL . type=kotlin.String operator=GET_PROPERTY
+ $this: THIS public final data class Test1 type=Test1
+ SET_VAR tmp0_result type=kotlin.Unit operator=EQ
+ CALL .plus type=kotlin.Int operator=null
+ $this: CALL .times type=kotlin.Int operator=null
+ $this: GET_VAR tmp0_result type=kotlin.Int operator=null
+ other: CONST Int type=kotlin.Int value='31'
+ other: CALL .hashCode type=kotlin.Int operator=null
+ $this: CALL . type=kotlin.Any operator=GET_PROPERTY
+ $this: THIS public final data class Test1 type=Test1
+ RETURN type=kotlin.Nothing from=hashCode
+ GET_VAR tmp0_result type=kotlin.Int operator=null
+ FUN public open override /*1*/ /*fake_override*/ fun equals(/*0*/ other: kotlin.Any?): kotlin.Boolean
+ BLOCK_BODY
+ WHEN type=kotlin.Unit operator=null
+ if: CALL .EQEQEQ type=kotlin.Boolean operator=EQEQEQ
+ arg0: THIS public final data class Test1 type=Test1
+ arg1: GET_VAR other type=kotlin.Any? operator=null
+ then: RETURN type=kotlin.Nothing from=equals
+ CONST Boolean type=kotlin.Boolean value='true'
+ WHEN type=kotlin.Unit operator=null
+ if: TYPE_OP operator=NOT_INSTANCEOF typeOperand=Test1
+ GET_VAR other type=kotlin.Any? operator=null
+ then: RETURN type=kotlin.Nothing from=equals
+ CONST Boolean type=kotlin.Boolean value='false'
+ VAR val tmp0_other_with_cast: Test1
+ TYPE_OP operator=CAST typeOperand=Test1
+ GET_VAR other type=kotlin.Any? operator=null
+ WHEN type=kotlin.Unit operator=null
+ if: CALL .NOT type=kotlin.Boolean operator=EXCLEQ
+ arg0: CALL .EQEQ type=kotlin.Boolean operator=EXCLEQ
+ arg0: CALL . type=kotlin.Int operator=GET_PROPERTY
+ $this: THIS public final data class Test1 type=Test1
+ arg1: CALL . type=kotlin.Int operator=GET_PROPERTY
+ $this: GET_VAR tmp0_other_with_cast type=Test1 operator=null
+ then: RETURN type=kotlin.Nothing from=equals
+ CONST Boolean type=kotlin.Boolean value='false'
+ WHEN type=kotlin.Unit operator=null
+ if: CALL .NOT type=kotlin.Boolean operator=EXCLEQ
+ arg0: CALL .EQEQ type=kotlin.Boolean operator=EXCLEQ
+ arg0: CALL . type=kotlin.String operator=GET_PROPERTY
+ $this: THIS public final data class Test1 type=Test1
+ arg1: CALL . type=kotlin.String operator=GET_PROPERTY
+ $this: GET_VAR tmp0_other_with_cast type=Test1 operator=null
+ then: RETURN type=kotlin.Nothing from=equals
+ CONST Boolean type=kotlin.Boolean value='false'
+ WHEN type=kotlin.Unit operator=null
+ if: CALL .NOT type=kotlin.Boolean operator=EXCLEQ
+ arg0: CALL .EQEQ type=kotlin.Boolean operator=EXCLEQ
+ arg0: CALL . type=kotlin.Any operator=GET_PROPERTY
+ $this: THIS public final data class Test1 type=Test1
+ arg1: CALL . type=kotlin.Any operator=GET_PROPERTY
+ $this: GET_VAR tmp0_other_with_cast type=Test1 operator=null
+ then: RETURN type=kotlin.Nothing from=equals
+ CONST Boolean type=kotlin.Boolean value='false'
+ RETURN type=kotlin.Nothing from=equals
+ CONST Boolean type=kotlin.Boolean value='true'
diff --git a/compiler/tests/org/jetbrains/kotlin/ir/IrTextTestCaseGenerated.java b/compiler/tests/org/jetbrains/kotlin/ir/IrTextTestCaseGenerated.java
index 75545fc8021..52541bf910b 100644
--- a/compiler/tests/org/jetbrains/kotlin/ir/IrTextTestCaseGenerated.java
+++ b/compiler/tests/org/jetbrains/kotlin/ir/IrTextTestCaseGenerated.java
@@ -67,6 +67,12 @@ public class IrTextTestCaseGenerated extends AbstractIrTextTestCase {
doTest(fileName);
}
+ @TestMetadata("dataClasses.kt")
+ public void testDataClasses() throws Exception {
+ String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/ir/irText/classes/dataClasses.kt");
+ doTest(fileName);
+ }
+
@TestMetadata("delegatingConstructorCallsInSecondaryConstructors.kt")
public void testDelegatingConstructorCallsInSecondaryConstructors() throws Exception {
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/ir/irText/classes/delegatingConstructorCallsInSecondaryConstructors.kt");