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");