Data class members generation.
Builder-style API for desugaring expressions.
This commit is contained in:
committed by
Dmitry Petrov
parent
dc169e98d5
commit
1022725fd1
@@ -10,5 +10,6 @@
|
||||
<orderEntry type="module" module-name="util" />
|
||||
<orderEntry type="module" module-name="frontend" />
|
||||
<orderEntry type="module" module-name="ir.tree" />
|
||||
<orderEntry type="module" module-name="backend-common" />
|
||||
</component>
|
||||
</module>
|
||||
@@ -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 <T : IrElement> IrStatementsBuilder<T>.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)
|
||||
@@ -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<out T : IrElement>(
|
||||
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<IrBlockBody>(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<IrBlock>(context, scope, startOffset, endOffset) {
|
||||
private val statements = ArrayList<IrStatement>()
|
||||
|
||||
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 : IrBuilder> T.at(startOffset: Int, endOffset: Int): T {
|
||||
this.startOffset = startOffset
|
||||
this.endOffset = endOffset
|
||||
return this
|
||||
}
|
||||
@@ -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 <reified T> 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")
|
||||
}
|
||||
@@ -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
|
||||
|
||||
|
||||
+161
@@ -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<KtParameter>) {
|
||||
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<PropertyDescriptor>) {
|
||||
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<PropertyDescriptor>) {
|
||||
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<PropertyDescriptor>) {
|
||||
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)
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -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)
|
||||
|
||||
|
||||
+2
-2
@@ -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)
|
||||
|
||||
@@ -42,6 +42,7 @@ enum class IrDeclarationKind {
|
||||
|
||||
enum class IrDeclarationOrigin {
|
||||
DEFINED,
|
||||
GENERATED_DATA_CLASS_MEMBER,
|
||||
LOCAL_FUNCTION_FOR_LAMBDA,
|
||||
IR_TEMPORARY_VARIABLE,
|
||||
}
|
||||
|
||||
@@ -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()
|
||||
|
||||
|
||||
}
|
||||
|
||||
@@ -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 : IrGeneralCall> T.putArguments(arguments: List<IrExpression>): T {
|
||||
arguments.forEachIndexed { i, irArgument ->
|
||||
putArgument(i, irArgument)
|
||||
}
|
||||
return this
|
||||
}
|
||||
|
||||
inline fun <T : IrGeneralCall> T.mapValueParameters(transform: (ValueParameterDescriptor) -> IrExpression): T {
|
||||
descriptor.valueParameters.forEach {
|
||||
putArgument(it.index, transform(it))
|
||||
}
|
||||
return this
|
||||
}
|
||||
|
||||
abstract class IrGeneralCallBase(
|
||||
startOffset: Int,
|
||||
endOffset: Int,
|
||||
|
||||
@@ -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)
|
||||
|
||||
}
|
||||
+3
-5
@@ -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
|
||||
}
|
||||
|
||||
|
||||
@@ -0,0 +1 @@
|
||||
data class Test1(val x: Int, val y: String, val z: Any)
|
||||
+129
@@ -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 .<get-x> 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 .<get-y> 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 .<get-z> 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 .<init> 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 .<get-x> 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 .<get-y> 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 .<get-z> 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 .<get-x> 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 .<get-y> 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 .<get-z> 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 .<get-x> type=kotlin.Int operator=GET_PROPERTY
|
||||
$this: THIS public final data class Test1 type=Test1
|
||||
arg1: CALL .<get-x> 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 .<get-y> type=kotlin.String operator=GET_PROPERTY
|
||||
$this: THIS public final data class Test1 type=Test1
|
||||
arg1: CALL .<get-y> 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 .<get-z> type=kotlin.Any operator=GET_PROPERTY
|
||||
$this: THIS public final data class Test1 type=Test1
|
||||
arg1: CALL .<get-z> 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'
|
||||
@@ -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");
|
||||
|
||||
Reference in New Issue
Block a user