KT-16439 Generated methods of data classes have no expression for default arguments

Provide default argument expressions for generated 'copy' declaration.
This commit is contained in:
Dmitry Petrov
2017-02-27 16:08:33 +03:00
parent 0f1f354ba6
commit e2e57e5b6d
5 changed files with 36 additions and 6 deletions
@@ -21,8 +21,9 @@ import org.jetbrains.kotlin.backend.common.DataClassMethodGenerator
import org.jetbrains.kotlin.descriptors.* import org.jetbrains.kotlin.descriptors.*
import org.jetbrains.kotlin.ir.UNDEFINED_OFFSET import org.jetbrains.kotlin.ir.UNDEFINED_OFFSET
import org.jetbrains.kotlin.ir.builders.* import org.jetbrains.kotlin.ir.builders.*
import org.jetbrains.kotlin.ir.declarations.impl.IrClassImpl
import org.jetbrains.kotlin.ir.declarations.IrDeclarationOrigin import org.jetbrains.kotlin.ir.declarations.IrDeclarationOrigin
import org.jetbrains.kotlin.ir.declarations.IrFunction
import org.jetbrains.kotlin.ir.declarations.impl.IrClassImpl
import org.jetbrains.kotlin.ir.expressions.IrExpression import org.jetbrains.kotlin.ir.expressions.IrExpression
import org.jetbrains.kotlin.ir.expressions.mapValueParameters import org.jetbrains.kotlin.ir.expressions.mapValueParameters
import org.jetbrains.kotlin.psi.KtClassOrObject import org.jetbrains.kotlin.psi.KtClassOrObject
@@ -42,7 +43,11 @@ class DataClassMembersGenerator(
override val context: GeneratorContext, override val context: GeneratorContext,
val irClass: IrClassImpl val irClass: IrClassImpl
) : Generator, DataClassMethodGenerator(ktClassOrObject, context.bindingContext) { ) : Generator, DataClassMethodGenerator(ktClassOrObject, context.bindingContext) {
private inline fun buildMember(function: FunctionDescriptor, psiElement: PsiElement? = null, body: IrMemberFunctionBuilder.() -> Unit) { private inline fun buildMember(
function: FunctionDescriptor,
psiElement: PsiElement? = null,
body: IrMemberFunctionBuilder.(IrFunction) -> Unit
) {
IrMemberFunctionBuilder( IrMemberFunctionBuilder(
context, irClass, function, IrDeclarationOrigin.GENERATED_DATA_CLASS_MEMBER, context, irClass, function, IrDeclarationOrigin.GENERATED_DATA_CLASS_MEMBER,
psiElement?.startOffset ?: UNDEFINED_OFFSET, psiElement?.endOffset ?: UNDEFINED_OFFSET psiElement?.startOffset ?: UNDEFINED_OFFSET, psiElement?.endOffset ?: UNDEFINED_OFFSET
@@ -65,6 +70,10 @@ class DataClassMembersGenerator(
throw AssertionError("Data class should have a primary constructor: $classDescriptor") throw AssertionError("Data class should have a primary constructor: $classDescriptor")
buildMember(function) { buildMember(function) {
function.valueParameters.forEach { parameter ->
val property = getOrFail(BindingContext.VALUE_PARAMETER_AS_PROPERTY, parameter)
putDefault(parameter, irGet(irThis(), property))
}
+irReturn(irCall(dataClassConstructor).mapValueParameters { irGet(function.valueParameters[it.index]) }) +irReturn(irCall(dataClassConstructor).mapValueParameters { irGet(function.valueParameters[it.index]) })
} }
} }
@@ -51,6 +51,9 @@ fun <T : IrElement> IrStatementsBuilder<T>.defineTemporaryVar(value: IrExpressio
return temporary.descriptor return temporary.descriptor
} }
fun IrBuilderWithScope.irExprBody(value: IrExpression) =
IrExpressionBodyImpl(startOffset, endOffset, value)
fun IrBuilderWithScope.irReturn(value: IrExpression) = fun IrBuilderWithScope.irReturn(value: IrExpression) =
IrReturnImpl(startOffset, endOffset, context.builtIns.nothingType, scope.assertCastOwner(), value) IrReturnImpl(startOffset, endOffset, context.builtIns.nothingType, scope.assertCastOwner(), value)
@@ -49,7 +49,7 @@ abstract class IrStatementsBuilder<out T : IrElement>(
} }
protected abstract fun addStatement(irStatement: IrStatement) protected abstract fun addStatement(irStatement: IrStatement)
protected abstract fun doBuild(): T abstract fun doBuild(): T
} }
open class IrBlockBodyBuilder( open class IrBlockBodyBuilder(
@@ -17,10 +17,13 @@
package org.jetbrains.kotlin.ir.builders package org.jetbrains.kotlin.ir.builders
import org.jetbrains.kotlin.descriptors.FunctionDescriptor import org.jetbrains.kotlin.descriptors.FunctionDescriptor
import org.jetbrains.kotlin.descriptors.ValueParameterDescriptor
import org.jetbrains.kotlin.ir.UNDEFINED_OFFSET import org.jetbrains.kotlin.ir.UNDEFINED_OFFSET
import org.jetbrains.kotlin.ir.declarations.impl.IrClassImpl import org.jetbrains.kotlin.ir.declarations.impl.IrClassImpl
import org.jetbrains.kotlin.ir.declarations.IrDeclarationOrigin import org.jetbrains.kotlin.ir.declarations.IrDeclarationOrigin
import org.jetbrains.kotlin.ir.declarations.IrFunction
import org.jetbrains.kotlin.ir.declarations.impl.IrFunctionImpl import org.jetbrains.kotlin.ir.declarations.impl.IrFunctionImpl
import org.jetbrains.kotlin.ir.expressions.IrExpression
class IrMemberFunctionBuilder( class IrMemberFunctionBuilder(
context: IrGeneratorContext, context: IrGeneratorContext,
@@ -30,10 +33,16 @@ class IrMemberFunctionBuilder(
startOffset: Int = UNDEFINED_OFFSET, startOffset: Int = UNDEFINED_OFFSET,
endOffset: Int = UNDEFINED_OFFSET endOffset: Int = UNDEFINED_OFFSET
) : IrBlockBodyBuilder(context, Scope(function), startOffset, endOffset) { ) : IrBlockBodyBuilder(context, Scope(function), startOffset, endOffset) {
inline fun addToClass(body: IrMemberFunctionBuilder.() -> Unit) { lateinit var irFunction: IrFunction
val irFunction = IrFunctionImpl(startOffset, endOffset, origin, function)
body() inline fun addToClass(body: IrMemberFunctionBuilder.(IrFunction) -> Unit) {
irFunction = IrFunctionImpl(startOffset, endOffset, origin, function)
body(irFunction)
irFunction.body = doBuild() irFunction.body = doBuild()
irClass.addMember(irFunction) irClass.addMember(irFunction)
} }
fun putDefault(parameter: ValueParameterDescriptor, value: IrExpression) {
irFunction.putDefault(parameter, irExprBody(value))
}
} }
+9
View File
@@ -47,6 +47,15 @@ FILE /dataClasses.kt
CALL '<get-z>(): Any' type=kotlin.Any origin=GET_PROPERTY CALL '<get-z>(): Any' type=kotlin.Any origin=GET_PROPERTY
$this: GET_VAR '<receiver: Test1>' type=Test1 origin=null $this: GET_VAR '<receiver: Test1>' type=Test1 origin=null
FUN GENERATED_DATA_CLASS_MEMBER public final fun copy(x: kotlin.Int = ..., y: kotlin.String = ..., z: kotlin.Any = ...): Test1 FUN GENERATED_DATA_CLASS_MEMBER public final fun copy(x: kotlin.Int = ..., y: kotlin.String = ..., z: kotlin.Any = ...): Test1
x: EXPRESSION_BODY
CALL '<get-x>(): Int' type=kotlin.Int origin=GET_PROPERTY
$this: GET_VAR '<receiver: Test1>' type=Test1 origin=null
y: EXPRESSION_BODY
CALL '<get-y>(): String' type=kotlin.String origin=GET_PROPERTY
$this: GET_VAR '<receiver: Test1>' type=Test1 origin=null
z: EXPRESSION_BODY
CALL '<get-z>(): Any' type=kotlin.Any origin=GET_PROPERTY
$this: GET_VAR '<receiver: Test1>' type=Test1 origin=null
BLOCK_BODY BLOCK_BODY
RETURN type=kotlin.Nothing from='copy(Int = ..., String = ..., Any = ...): Test1' RETURN type=kotlin.Nothing from='copy(Int = ..., String = ..., Any = ...): Test1'
CALL 'constructor Test1(Int, String, Any)' type=Test1 origin=null CALL 'constructor Test1(Int, String, Any)' type=Test1 origin=null