Merge branch 'property_delegation'

This commit is contained in:
Igor Chevdar
2017-03-01 15:39:27 +03:00
30 changed files with 1136 additions and 125 deletions
@@ -4,7 +4,6 @@ import org.jetbrains.kotlin.backend.common.runOnFilePostfix
import org.jetbrains.kotlin.backend.common.lower.*
import org.jetbrains.kotlin.backend.konan.lower.*
import org.jetbrains.kotlin.ir.declarations.IrFile
import org.jetbrains.kotlin.ir.declarations.IrModuleFragment
internal class KonanLower(val context: Context) {
@@ -39,6 +38,10 @@ internal class KonanLower(val context: Context) {
phaser.phase(KonanPhase.LOWER_INITIALIZERS) {
InitializersLowering(context).runOnFilePostfix(irFile)
}
phaser.phase(KonanPhase.LOWER_DELEGATION) {
ClassDelegationLowering(context).runOnFilePostfix(irFile)
PropertyDelegationLowering(context).lower(irFile)
}
phaser.phase(KonanPhase.LOWER_TYPE_OPERATORS) {
TypeOperatorLowering(context).runOnFilePostfix(irFile)
}
@@ -58,7 +61,6 @@ internal class KonanLower(val context: Context) {
VarargInjectionLowering(context).runOnFilePostfix(irFile)
}
phaser.phase(KonanPhase.BRIDGES_BUILDING) {
DelegationLowering(context).runOnFilePostfix(irFile)
BridgesBuilding(context).runOnFilePostfix(irFile)
DirectBridgesCallsLowering(context).runOnFilePostfix(irFile)
}
@@ -25,6 +25,7 @@ enum class KonanPhase(val description: String,
/* ... ... */ LOWER_STRING_CONCAT("String concatenation lowering"),
/* ... ... */ LOWER_INITIALIZERS("Initializers lowering"),
/* ... ... */ BRIDGES_BUILDING("Bridges building"),
/* ... ... */ LOWER_DELEGATION("Delegation lowering"),
/* ... */ BITCODE("LLVM BitCode Generation"),
/* ... ... */ RTTI("RTTI Generation"),
/* ... ... */ CODEGEN("Code Generation"),
@@ -1,10 +1,21 @@
package org.jetbrains.kotlin.backend.konan.ir
import org.jetbrains.kotlin.backend.konan.Context
import org.jetbrains.kotlin.descriptors.*
import org.jetbrains.kotlin.descriptors.annotations.Annotations
import org.jetbrains.kotlin.descriptors.impl.ClassConstructorDescriptorImpl
import org.jetbrains.kotlin.incremental.components.NoLookupLocation
import org.jetbrains.kotlin.ir.*
import org.jetbrains.kotlin.ir.util.DumpIrTreeVisitor
import org.jetbrains.kotlin.ir.declarations.*
import org.jetbrains.kotlin.ir.declarations.impl.IrConstructorImpl
import org.jetbrains.kotlin.ir.expressions.*
import org.jetbrains.kotlin.ir.expressions.impl.*
import org.jetbrains.kotlin.name.FqName
import org.jetbrains.kotlin.name.Name
import org.jetbrains.kotlin.types.KotlinType
import org.jetbrains.kotlin.types.TypeProjectionImpl
import org.jetbrains.kotlin.types.TypeSubstitutor
import java.io.StringWriter
@@ -76,3 +87,50 @@ fun ir2stringWhole(ir: IrElement?): String {
return strWriter.toString()
}
internal fun ClassDescriptor.createSimpleDelegatingConstructor(superConstructorDescriptor: ClassConstructorDescriptor)
: Pair<ClassConstructorDescriptor, IrConstructor> {
val constructorDescriptor = ClassConstructorDescriptorImpl.createSynthesized(
this,
Annotations.EMPTY,
superConstructorDescriptor.isPrimary,
SourceElement.NO_SOURCE)
val valueParameters = superConstructorDescriptor.valueParameters.map {
it.copy(constructorDescriptor, it.name, it.index)
}
constructorDescriptor.initialize(valueParameters, superConstructorDescriptor.visibility)
constructorDescriptor.returnType = superConstructorDescriptor.returnType
val body = IrBlockBodyImpl(UNDEFINED_OFFSET, UNDEFINED_OFFSET,
listOf(
IrDelegatingConstructorCallImpl(UNDEFINED_OFFSET, UNDEFINED_OFFSET, superConstructorDescriptor).apply {
valueParameters.forEachIndexed { idx, parameter ->
putValueArgument(idx, IrGetValueImpl(UNDEFINED_OFFSET, UNDEFINED_OFFSET, parameter))
}
},
IrInstanceInitializerCallImpl(UNDEFINED_OFFSET, UNDEFINED_OFFSET, this)
)
)
val constructor = IrConstructorImpl(UNDEFINED_OFFSET, UNDEFINED_OFFSET, IrDeclarationOrigin.DEFINED, constructorDescriptor, body)
return Pair(constructorDescriptor, constructor)
}
internal fun Context.createArrayOfExpression(arrayElementType: KotlinType,
arrayElements: List<IrExpression>): IrExpression {
val kotlinPackage = irModule!!.descriptor.getPackage(FqName("kotlin"))
val genericArrayOfFun = kotlinPackage.memberScope.getContributedFunctions(Name.identifier("arrayOf"), NoLookupLocation.FROM_BACKEND).first()
val typeParameter0 = genericArrayOfFun.typeParameters[0]
val typeSubstitutor = TypeSubstitutor.create(mapOf(typeParameter0.typeConstructor to TypeProjectionImpl(arrayElementType)))
val substitutedArrayOfFun = genericArrayOfFun.substitute(typeSubstitutor)!!
val typeArguments = mapOf(typeParameter0 to arrayElementType)
val valueParameter0 = substitutedArrayOfFun.valueParameters[0]
val arg0VarargType = valueParameter0.type
val arg0VarargElementType = valueParameter0.varargElementType!!
val arg0 = IrVarargImpl(UNDEFINED_OFFSET, UNDEFINED_OFFSET, arg0VarargType, arg0VarargElementType, arrayElements)
return IrCallImpl(UNDEFINED_OFFSET, UNDEFINED_OFFSET, substitutedArrayOfFun, typeArguments).apply {
putValueArgument(0, arg0)
}
}
@@ -17,6 +17,7 @@ import org.jetbrains.kotlin.ir.IrStatement
import org.jetbrains.kotlin.ir.declarations.*
import org.jetbrains.kotlin.ir.descriptors.IrBuiltinOperatorDescriptorBase
import org.jetbrains.kotlin.ir.descriptors.IrImplementingDelegateDescriptorImpl
import org.jetbrains.kotlin.ir.descriptors.IrPropertyDelegateDescriptorImpl
import org.jetbrains.kotlin.ir.expressions.*
import org.jetbrains.kotlin.ir.visitors.IrElementVisitorVoid
import org.jetbrains.kotlin.ir.visitors.acceptChildrenVoid
@@ -1226,7 +1227,8 @@ internal class CodeGeneratorVisitor(val context: Context) : IrElementVisitorVoid
context.log("evaluateGetField : ${ir2string(value)}")
if (value.descriptor.dispatchReceiverParameter != null
// TODO: hack because of IR bug: https://github.com/JetBrains/kotlin/tree/rr/dispatch_receiver_for_delegate_descriptor.
|| value.descriptor is IrImplementingDelegateDescriptorImpl) {
|| value.descriptor is IrImplementingDelegateDescriptorImpl
|| (value.descriptor is IrPropertyDelegateDescriptorImpl && value.descriptor.containingDeclaration is ClassDescriptor)) {
val thisPtr = evaluateExpression(value.receiver!!)
return codegen.loadSlot(
fieldPtrOfClass(thisPtr, value.descriptor), value.descriptor.isVar())
@@ -1258,7 +1260,8 @@ internal class CodeGeneratorVisitor(val context: Context) : IrElementVisitorVoid
if (value.descriptor.dispatchReceiverParameter != null
// TODO: hack because of IR bug: https://github.com/JetBrains/kotlin/tree/rr/dispatch_receiver_for_delegate_descriptor.
|| value.descriptor is IrImplementingDelegateDescriptorImpl) {
|| value.descriptor is IrImplementingDelegateDescriptorImpl
|| (value.descriptor is IrPropertyDelegateDescriptorImpl && value.descriptor.containingDeclaration is ClassDescriptor)) {
val thisPtr = evaluateExpression(value.receiver!!)
codegen.storeAnyGlobal(valueToAssign, fieldPtrOfClass(thisPtr, value.descriptor))
}
@@ -125,7 +125,7 @@ private fun ContextUtils.getDeclaredFields(classDescriptor: ClassDescriptor): Li
}
private fun ContextUtils.createClassBodyType(name: String, fields: List<PropertyDescriptor>): LLVMTypeRef {
val fieldTypes = fields.map { getLLVMType(it.type) }.toTypedArray()
val fieldTypes = fields.map { getLLVMType(if (it.isDelegated) context.builtIns.nullableAnyType else it.type) }.toTypedArray()
val classType = LLVMStructCreateNamed(LLVMGetModuleContext(context.llvmModule), name)!!
@@ -300,7 +300,8 @@ private class DeclarationsGeneratorVisitor(override val context: Context) :
val dispatchReceiverParameter = descriptor.dispatchReceiverParameter
if (dispatchReceiverParameter != null
// TODO: hack because of IR bug: https://github.com/JetBrains/kotlin/tree/rr/dispatch_receiver_for_delegate_descriptor.
|| descriptor is IrImplementingDelegateDescriptorImpl) {
|| descriptor is IrImplementingDelegateDescriptorImpl
|| (descriptor is IrPropertyDelegateDescriptorImpl && descriptor.containingDeclaration is ClassDescriptor)) {
val containingClass = dispatchReceiverParameter?.containingDeclaration
// TODO: hack because of IR bug: https://github.com/JetBrains/kotlin/tree/rr/dispatch_receiver_for_delegate_descriptor.
?: descriptor.containingDeclaration
@@ -131,7 +131,7 @@ internal class MetadataGenerator(override val context: Context): ContextUtils {
internal fun property(declaration: IrProperty) {
if (declaration.backingField == null) return
assert(declaration.backingField!!.descriptor == declaration.descriptor)
assert(declaration.backingField!!.descriptor == declaration.descriptor || declaration.isDelegated)
context.ir.propertiesWithBackingFields.add(declaration.descriptor)
}
@@ -13,8 +13,10 @@ import org.jetbrains.kotlin.ir.declarations.IrFunction
import org.jetbrains.kotlin.ir.declarations.IrProperty
import org.jetbrains.kotlin.ir.declarations.impl.IrFunctionImpl
import org.jetbrains.kotlin.ir.expressions.*
import org.jetbrains.kotlin.ir.expressions.impl.*
import org.jetbrains.kotlin.ir.util.transformFlat
import org.jetbrains.kotlin.ir.expressions.impl.IrBlockBodyImpl
import org.jetbrains.kotlin.ir.expressions.impl.IrCallImpl
import org.jetbrains.kotlin.ir.expressions.impl.IrGetValueImpl
import org.jetbrains.kotlin.ir.expressions.impl.IrReturnImpl
import org.jetbrains.kotlin.ir.visitors.IrElementTransformerVoid
import org.jetbrains.kotlin.ir.visitors.transformChildrenVoid
import org.jetbrains.kotlin.types.KotlinType
@@ -66,71 +68,6 @@ internal class DirectBridgesCallsLowering(val context: Context) : BodyLoweringPa
}
}
private object DECLARATION_ORIGIN_BRIDGE_METHOD :
IrDeclarationOriginImpl("BRIDGE_METHOD")
internal class DelegationLowering(val context: Context) : ClassLoweringPass {
override fun lower(irClass: IrClass) {
irClass.declarations.transformFlat {
when (it) {
is IrFunction -> {
val transformedFun = transformBridgeToDelegatedMethod(irClass, it)
if (transformedFun == null) null
else listOf(transformedFun)
}
is IrProperty -> {
val getter = transformBridgeToDelegatedMethod(irClass, it.getter)
val setter = transformBridgeToDelegatedMethod(irClass, it.setter)
if (getter != null) it.getter = getter
if (setter != null) it.setter = setter
null
}
else -> null
}
}
}
// TODO: hack because of broken IR for synthesized delegated members: https://youtrack.jetbrains.com/issue/KT-16486.
private fun transformBridgeToDelegatedMethod(irClass: IrClass, irFunction: IrFunction?): IrFunction? {
if (irFunction == null || irFunction.descriptor.kind != CallableMemberDescriptor.Kind.DELEGATION) return null
val body = irFunction.body as? IrBlockBody
?: throw AssertionError("Unexpected method body: ${irFunction.body}")
val statement = body.statements.single()
val delegatedCall = ((statement as? IrReturn)?.value ?: statement) as? IrCall
?: throw AssertionError("Unexpected method body: $statement")
val propertyGetter = delegatedCall.dispatchReceiver as? IrGetValue
?: throw AssertionError("Unexpected dispatch receiver: ${delegatedCall.dispatchReceiver}")
val propertyDescriptor = propertyGetter.descriptor as? PropertyDescriptor
?: throw AssertionError("Unexpected dispatch receiver descriptor: ${propertyGetter.descriptor}")
val delegated = context.specialDescriptorsFactory.getBridgeDescriptor(
OverriddenFunctionDescriptor(irFunction.descriptor, delegatedCall.descriptor as FunctionDescriptor))
val newFunction = IrFunctionImpl(irFunction.startOffset, irFunction.endOffset, DECLARATION_ORIGIN_BRIDGE_METHOD, delegated)
val irBlockBody = IrBlockBodyImpl(irFunction.startOffset, irFunction.endOffset)
val returnType = delegatedCall.descriptor.returnType!!
val irCall = IrCallImpl(irFunction.startOffset, irFunction.endOffset, returnType, delegatedCall.descriptor, null)
val receiver = IrGetValueImpl(irFunction.startOffset, irFunction.endOffset, irClass.descriptor.thisAsReceiverParameter)
irCall.dispatchReceiver = IrGetFieldImpl(irFunction.startOffset, irFunction.endOffset, propertyDescriptor, receiver)
irCall.extensionReceiver = delegated.extensionReceiverParameter?.let { extensionReceiver ->
IrGetValueImpl(irFunction.startOffset, irFunction.endOffset, extensionReceiver)
}
irCall.mapValueParameters { overriddenValueParameter ->
val delegatedValueParameter = delegated.valueParameters[overriddenValueParameter.index]
IrGetValueImpl(irFunction.startOffset, irFunction.endOffset, delegatedValueParameter)
}
if (KotlinBuiltIns.isUnit(returnType) || KotlinBuiltIns.isNothing(returnType)) {
irBlockBody.statements.add(irCall)
} else {
val irReturn = IrReturnImpl(irFunction.startOffset, irFunction.endOffset, context.builtIns.nothingType, delegated, irCall)
irBlockBody.statements.add(irReturn)
}
newFunction.body = irBlockBody
return newFunction
}
}
internal class BridgesBuilding(val context: Context) : ClassLoweringPass {
override fun lower(irClass: IrClass) {
val functions = mutableSetOf<FunctionDescriptor?>()
@@ -160,6 +97,9 @@ internal class BridgesBuilding(val context: Context) : ClassLoweringPass {
}
}
private object DECLARATION_ORIGIN_BRIDGE_METHOD :
IrDeclarationOriginImpl("BRIDGE_METHOD")
private fun buildBridge(descriptor: OverriddenFunctionDescriptor, irClass: IrClass) {
val bridgeDescriptor = context.specialDescriptorsFactory.getBridgeDescriptor(descriptor)
val target = descriptor.descriptor.target
@@ -0,0 +1,200 @@
package org.jetbrains.kotlin.backend.konan.lower
import org.jetbrains.kotlin.backend.common.DeclarationContainerLoweringPass
import org.jetbrains.kotlin.backend.common.FileLoweringPass
import org.jetbrains.kotlin.backend.jvm.descriptors.initialize
import org.jetbrains.kotlin.backend.konan.Context
import org.jetbrains.kotlin.backend.konan.descriptors.OverriddenFunctionDescriptor
import org.jetbrains.kotlin.backend.konan.descriptors.synthesizedName
import org.jetbrains.kotlin.backend.konan.ir.createArrayOfExpression
import org.jetbrains.kotlin.builtins.KotlinBuiltIns
import org.jetbrains.kotlin.descriptors.*
import org.jetbrains.kotlin.descriptors.annotations.Annotations
import org.jetbrains.kotlin.descriptors.impl.PropertyDescriptorImpl
import org.jetbrains.kotlin.incremental.components.NoLookupLocation
import org.jetbrains.kotlin.ir.IrStatement
import org.jetbrains.kotlin.ir.UNDEFINED_OFFSET
import org.jetbrains.kotlin.ir.declarations.*
import org.jetbrains.kotlin.ir.declarations.impl.IrFieldImpl
import org.jetbrains.kotlin.ir.declarations.impl.IrFunctionImpl
import org.jetbrains.kotlin.ir.declarations.impl.IrVariableImpl
import org.jetbrains.kotlin.ir.expressions.*
import org.jetbrains.kotlin.ir.expressions.impl.*
import org.jetbrains.kotlin.ir.util.transformFlat
import org.jetbrains.kotlin.ir.visitors.IrElementTransformerVoid
import org.jetbrains.kotlin.ir.visitors.transformChildrenVoid
import org.jetbrains.kotlin.name.FqName
import org.jetbrains.kotlin.name.Name
import org.jetbrains.kotlin.types.*
internal class ClassDelegationLowering(val context: Context) : DeclarationContainerLoweringPass {
override fun lower(irDeclarationContainer: IrDeclarationContainer) {
irDeclarationContainer.declarations.transformFlat {
when (it) {
is IrFunction -> {
val transformedFun = transformBridgeToDelegatedMethod(irDeclarationContainer, it)
if (transformedFun == null) null
else listOf(transformedFun)
}
is IrProperty -> {
val getter = transformBridgeToDelegatedMethod(irDeclarationContainer, it.getter)
val setter = transformBridgeToDelegatedMethod(irDeclarationContainer, it.setter)
if (getter != null) it.getter = getter
if (setter != null) it.setter = setter
null
}
else -> null
}
}
}
private fun transformBridgeToDelegatedMethod(irDeclarationContainer: IrDeclarationContainer, irFunction: IrFunction?): IrFunction? {
if (irFunction == null) return null
val descriptor = irFunction.descriptor
if (descriptor.kind != CallableMemberDescriptor.Kind.DELEGATION) return null
// TODO: hack because of broken IR for synthesized delegated members: https://youtrack.jetbrains.com/issue/KT-16486.
val body = irFunction.body as? IrBlockBody
?: throw AssertionError("Unexpected method body: ${irFunction.body}")
val statement = body.statements.single()
val delegatedCall = ((statement as? IrReturn)?.value ?: statement) as? IrCall
?: throw AssertionError("Unexpected method body: $statement")
val propertyGetter = delegatedCall.dispatchReceiver as? IrGetValue
?: throw AssertionError("Unexpected dispatch receiver: ${delegatedCall.dispatchReceiver}")
val propertyDescriptor = propertyGetter.descriptor as? PropertyDescriptor
?: throw AssertionError("Unexpected dispatch receiver descriptor: ${propertyGetter.descriptor}")
val delegated = context.specialDescriptorsFactory.getBridgeDescriptor(
OverriddenFunctionDescriptor(descriptor, delegatedCall.descriptor as FunctionDescriptor))
val newFunction = IrFunctionImpl(irFunction.startOffset, irFunction.endOffset, irFunction.origin, delegated)
val irBlockBody = IrBlockBodyImpl(irFunction.startOffset, irFunction.endOffset)
val returnType = delegatedCall.descriptor.returnType!!
val irCall = IrCallImpl(irFunction.startOffset, irFunction.endOffset, returnType, delegatedCall.descriptor, null)
val receiver = IrGetValueImpl(irFunction.startOffset, irFunction.endOffset,
(irDeclarationContainer as IrClass).descriptor.thisAsReceiverParameter)
irCall.dispatchReceiver = IrGetFieldImpl(irFunction.startOffset, irFunction.endOffset, propertyDescriptor, receiver)
irCall.extensionReceiver = delegated.extensionReceiverParameter?.let { extensionReceiver ->
IrGetValueImpl(irFunction.startOffset, irFunction.endOffset, extensionReceiver)
}
irCall.mapValueParameters { overriddenValueParameter ->
val delegatedValueParameter = delegated.valueParameters[overriddenValueParameter.index]
IrGetValueImpl(irFunction.startOffset, irFunction.endOffset, delegatedValueParameter)
}
if (KotlinBuiltIns.isUnit(returnType) || KotlinBuiltIns.isNothing(returnType)) {
irBlockBody.statements.add(irCall)
} else {
val irReturn = IrReturnImpl(irFunction.startOffset, irFunction.endOffset, context.builtIns.nothingType, delegated, irCall)
irBlockBody.statements.add(irReturn)
}
newFunction.body = irBlockBody
return newFunction
}
}
internal class PropertyDelegationLowering(val context: Context) : FileLoweringPass {
private val kotlinReflectPackage = context.irModule!!.descriptor.getPackage(FqName.fromSegments(listOf("kotlin", "reflect")))
private val genericKPropertyImplType = kotlinReflectPackage.memberScope.getContributedClassifier(Name.identifier("KPropertyImpl"),
NoLookupLocation.FROM_BACKEND) as ClassDescriptor
private val kotlinPackage = context.irModule!!.descriptor.getPackage(FqName("kotlin"))
private val genericArrayType = kotlinPackage.memberScope.getContributedClassifier(Name.identifier("Array"), NoLookupLocation.FROM_BACKEND) as ClassDescriptor
fun getKPropertyImplConstructorDescriptorWithProjection(type: KotlinType): ClassConstructorDescriptor {
val typeParameterT = genericKPropertyImplType.declaredTypeParameters[0]
val typeSubstitutor = TypeSubstitutor.create(mapOf(typeParameterT.typeConstructor to TypeProjectionImpl(type)))
return genericKPropertyImplType.unsubstitutedPrimaryConstructor!!.substitute(typeSubstitutor)!!
}
fun ClassDescriptor.replace(vararg type: KotlinType): SimpleType {
return this.defaultType.replace(type.map(::TypeProjectionImpl))
}
override fun lower(irFile: IrFile) {
val kProperties = mutableListOf<IrExpression>()
val getter = genericArrayType.unsubstitutedMemberScope.getContributedFunctions(Name.identifier("get"), NoLookupLocation.FROM_BACKEND).single()
val typeParameterT = genericArrayType.declaredTypeParameters[0]
val kPropertyImplType = genericKPropertyImplType.replace(context.builtIns.anyType)
val typeSubstitutor = TypeSubstitutor.create(mapOf(typeParameterT.typeConstructor to TypeProjectionImpl(kPropertyImplType)))
val substitutedGetter = getter.substitute(typeSubstitutor)!!
val kPropertiesField = createKPropertiesFieldDescriptor(irFile.packageFragmentDescriptor, genericArrayType.replace(kPropertyImplType))
irFile.transformChildrenVoid(object : IrElementTransformerVoid() {
override fun visitFunction(declaration: IrFunction): IrStatement {
return super.visitFunction(declaration)
}
override fun visitLocalDelegatedProperty(declaration: IrLocalDelegatedProperty): IrStatement {
declaration.transformChildrenVoid(this)
val name = declaration.descriptor.name.asString()
val type = declaration.descriptor.type
val initializer = declaration.delegate.initializer!!
return IrVariableImpl(declaration.startOffset, declaration.endOffset,
declaration.origin, declaration.delegate.descriptor,
IrBlockImpl(initializer.startOffset, initializer.endOffset, initializer.type, null,
listOf(
transformBridgeToDelegate(name, type, declaration.getter),
transformBridgeToDelegate(name, type, declaration.setter),
initializer
).filterNotNull())
)
}
override fun visitProperty(declaration: IrProperty): IrStatement {
declaration.transformChildrenVoid(this)
if (declaration.isDelegated) {
val name = declaration.descriptor.name.asString()
val type = declaration.descriptor.returnType!!
declaration.getter = transformBridgeToDelegate(name, type, declaration.getter)
declaration.setter = transformBridgeToDelegate(name, type, declaration.setter)
}
return declaration
}
private fun transformBridgeToDelegate(name: String, type: KotlinType, irFunction: IrFunction?): IrFunction? {
irFunction?.transformChildrenVoid(object : IrElementTransformerVoid() {
override fun visitCallableReference(expression: IrCallableReference): IrExpression {
val fieldInitializer = IrCallImpl(UNDEFINED_OFFSET, UNDEFINED_OFFSET,
getKPropertyImplConstructorDescriptorWithProjection(type)).apply {
putValueArgument(0, IrConstImpl<String>(UNDEFINED_OFFSET, UNDEFINED_OFFSET,
context.builtIns.stringType, IrConstKind.String, name))
}
val index = kProperties.size
kProperties.add(fieldInitializer)
return IrCallImpl(expression.startOffset, expression.endOffset, substitutedGetter).apply {
dispatchReceiver = IrGetFieldImpl(expression.startOffset, expression.endOffset, kPropertiesField)
putValueArgument(0, IrConstImpl.int(startOffset, endOffset, context.builtIns.intType, index))
}
}
})
return irFunction
}
})
if (kProperties.size > 0) {
irFile.declarations.add(0, IrFieldImpl(UNDEFINED_OFFSET, UNDEFINED_OFFSET,
DECLARATION_ORIGIN_KPROPERTIES_FOR_DELEGATION,
kPropertiesField,
IrExpressionBodyImpl(UNDEFINED_OFFSET, UNDEFINED_OFFSET,
context.createArrayOfExpression(kPropertyImplType, kProperties))))
}
}
private object DECLARATION_ORIGIN_KPROPERTIES_FOR_DELEGATION :
IrDeclarationOriginImpl("KPROPERTIES_FOR_DELEGATION")
private fun createKPropertiesFieldDescriptor(containingDeclaration: DeclarationDescriptor, fieldType: SimpleType): PropertyDescriptorImpl {
return PropertyDescriptorImpl.create(containingDeclaration, Annotations.EMPTY, Modality.FINAL, Visibilities.PRIVATE,
false, "KPROPERTIES".synthesizedName, CallableMemberDescriptor.Kind.SYNTHESIZED, SourceElement.NO_SOURCE,
false, false, false, false, false, false).initialize(fieldType)
}
}
@@ -10,6 +10,8 @@ import org.jetbrains.kotlin.backend.konan.Context
import org.jetbrains.kotlin.backend.konan.KonanPlatform
import org.jetbrains.kotlin.backend.konan.descriptors.getKonanInternalFunctions
import org.jetbrains.kotlin.backend.konan.descriptors.synthesizedName
import org.jetbrains.kotlin.backend.konan.ir.createArrayOfExpression
import org.jetbrains.kotlin.backend.konan.ir.createSimpleDelegatingConstructor
import org.jetbrains.kotlin.descriptors.*
import org.jetbrains.kotlin.descriptors.annotations.Annotations
import org.jetbrains.kotlin.descriptors.impl.ClassConstructorDescriptorImpl
@@ -171,7 +173,7 @@ internal class EnumClassLowering(val context: Context) : ClassLoweringPass {
descriptor.constructors.forEach {
val loweredEnumConstructor = loweredEnumConstructors[it]!!
val (constructorDescriptor, constructor) = createSimpleDelegatingConstructor(defaultClassDescriptor, loweredEnumConstructor)
val (constructorDescriptor, constructor) = defaultClassDescriptor.createSimpleDelegatingConstructor(loweredEnumConstructor)
constructors.add(constructorDescriptor)
defaultClass.declarations.add(constructor)
defaultEnumEntryConstructors.put(loweredEnumConstructor, constructorDescriptor)
@@ -233,7 +235,7 @@ internal class EnumClassLowering(val context: Context) : ClassLoweringPass {
val memberScope = MemberScope.Empty
val constructorOfAny = irClass.descriptor.module.builtIns.any.constructors.first()
val (constructorDescriptor, constructor) = createSimpleDelegatingConstructor(implObjectDescriptor, constructorOfAny)
val (constructorDescriptor, constructor) = implObjectDescriptor.createSimpleDelegatingConstructor(constructorOfAny)
implObjectDescriptor.initialize(memberScope, setOf(constructorDescriptor), constructorDescriptor)
@@ -260,34 +262,6 @@ internal class EnumClassLowering(val context: Context) : ClassLoweringPass {
return newDescriptor
}
private fun createSimpleDelegatingConstructor(classDescriptor: ClassDescriptor,
superConstructorDescriptor: ClassConstructorDescriptor)
: Pair<ClassConstructorDescriptor, IrConstructor> {
val constructorDescriptor = ClassConstructorDescriptorImpl.createSynthesized(
classDescriptor,
Annotations.EMPTY,
superConstructorDescriptor.isPrimary,
SourceElement.NO_SOURCE)
val valueParameters = superConstructorDescriptor.valueParameters.map {
it.copy(constructorDescriptor, it.name, it.index)
}
constructorDescriptor.initialize(valueParameters, superConstructorDescriptor.visibility)
constructorDescriptor.returnType = superConstructorDescriptor.returnType
val body = IrBlockBodyImpl(UNDEFINED_OFFSET, UNDEFINED_OFFSET,
listOf(
IrDelegatingConstructorCallImpl(UNDEFINED_OFFSET, UNDEFINED_OFFSET, superConstructorDescriptor).apply {
valueParameters.forEachIndexed { idx, parameter ->
putValueArgument(idx, IrGetValueImpl(UNDEFINED_OFFSET, UNDEFINED_OFFSET, parameter))
}
},
IrInstanceInitializerCallImpl(UNDEFINED_OFFSET, UNDEFINED_OFFSET, classDescriptor)
)
)
val constructor = IrConstructorImpl(UNDEFINED_OFFSET, UNDEFINED_OFFSET, IrDeclarationOrigin.DEFINED, constructorDescriptor, body)
return Pair(constructorDescriptor, constructor)
}
private fun createSyntheticValuesFieldDeclaration(implObjectDescriptor: ClassDescriptor,
enumEntries: List<IrEnumEntry>): IrFieldImpl {
val valuesArrayType = context.builtIns.getArrayType(Variance.INVARIANT, irClass.descriptor.defaultType)
@@ -304,7 +278,7 @@ internal class EnumClassLowering(val context: Context) : ClassLoweringPass {
val loweredEnumEntry = LoweredEnumEntry(implObjectDescriptor, valuesFieldDescriptor, substitutedValueOf, entriesMap)
loweredEnumEntries.put(irClass.descriptor, loweredEnumEntry)
val irValuesInitializer = createArrayOfExpression(irClass.descriptor.defaultType, enumEntries.map { it.initializerExpression })
val irValuesInitializer = context.createArrayOfExpression(irClass.descriptor.defaultType, enumEntries.map { it.initializerExpression })
val irField = IrFieldImpl(UNDEFINED_OFFSET, UNDEFINED_OFFSET, IrDeclarationOrigin.DEFINED,
valuesFieldDescriptor,
@@ -321,31 +295,12 @@ internal class EnumClassLowering(val context: Context) : ClassLoweringPass {
private val kotlinPackage = context.irModule!!.descriptor.getPackage(FqName("kotlin"))
private val genericArrayOfFun = kotlinPackage.memberScope.getContributedFunctions(Name.identifier("arrayOf"), NoLookupLocation.FROM_BACKEND).first()
private val genericValueOfFun = context.builtIns.getKonanInternalFunctions("valueOfForEnum").single()
private val genericValuesFun = context.builtIns.getKonanInternalFunctions("valuesForEnum").single()
private val genericArrayType = kotlinPackage.memberScope.getContributedClassifier(Name.identifier("Array"), NoLookupLocation.FROM_BACKEND) as ClassDescriptor
private fun createArrayOfExpression(arrayElementType: KotlinType, arrayElements: List<IrExpression>): IrExpression {
val typeParameter0 = genericArrayOfFun.typeParameters[0]
val typeSubstitutor = TypeSubstitutor.create(mapOf(typeParameter0.typeConstructor to TypeProjectionImpl(arrayElementType)))
val substitutedArrayOfFun = genericArrayOfFun.substitute(typeSubstitutor)!!
val typeArguments = mapOf(typeParameter0 to arrayElementType)
val valueParameter0 = substitutedArrayOfFun.valueParameters[0]
val arg0VarargType = valueParameter0.type
val arg0VarargElementType = valueParameter0.varargElementType!!
val arg0 = IrVarargImpl(UNDEFINED_OFFSET, UNDEFINED_OFFSET, arg0VarargType, arg0VarargElementType, arrayElements)
return IrCallImpl(UNDEFINED_OFFSET, UNDEFINED_OFFSET, substitutedArrayOfFun, typeArguments).apply {
putValueArgument(0, arg0)
}
}
private fun createSyntheticValuesMethodDeclaration(companionObjectDescriptor: ClassDescriptor): IrFunction {
val typeParameterT = genericValuesFun.typeParameters[0]
val enumClassType = irClass.descriptor.defaultType
+41
View File
@@ -593,6 +593,47 @@ task classDelegation_withBridge(type: RunKonanTest) {
source = "codegen/classDelegation/withBridge.kt"
}
task delegatedProperty_simpleVal(type: RunKonanTest) {
goldValue = "x\n42\n"
source = "codegen/delegatedProperty/simpleVal.kt"
}
task delegatedProperty_simpleVar(type: RunKonanTest) {
goldValue = "get x\n42\nset x\nget x\n117\n"
source = "codegen/delegatedProperty/simpleVar.kt"
}
task delegatedProperty_packageLevel(type: RunKonanTest) {
goldValue = "x\n42\n"
source = "codegen/delegatedProperty/packageLevel.kt"
}
task delegatedProperty_local(type: RunKonanTest) {
goldValue = "x\n42\n"
source = "codegen/delegatedProperty/local.kt"
}
task delegatedProperty_delegatedOverride(type: LinkKonanTest) {
goldValue = "156\nx\n117\n42\n"
source = "codegen/delegatedProperty/delegatedOverride_main.kt"
lib = "codegen/delegatedProperty/delegatedOverride_lib.kt"
}
task delegatedProperty_lazy(type: RunKonanTest) {
goldValue = "computed!\nHello\nHello\n"
source = "codegen/delegatedProperty/lazy.kt"
}
task delegatedProperty_observable(type: RunKonanTest) {
goldValue = "<no name> -> first\nfirst -> second\n"
source = "codegen/delegatedProperty/observable.kt"
}
task delegatedProperty_map(type: RunKonanTest) {
goldValue = "John Doe\n25\n"
source = "codegen/delegatedProperty/map.kt"
}
task array0(type: RunKonanTest) {
goldValue = "5\n6\n7\n8\n9\n10\n11\n12\n13\n"
source = "runtime/collections/array0.kt"
@@ -0,0 +1,23 @@
package a
import kotlin.reflect.KProperty
open class A {
open val x = 42
}
class Delegate {
val f = 117
operator fun getValue(receiver: Any?, p: KProperty<*>): Int {
println(p.name)
return f
}
}
open class B: A() {
override val x: Int by Delegate()
fun bar() {
println(super<A>.x)
}
}
@@ -0,0 +1,17 @@
import a.*
open class C: B() {
override val x: Int = 156
fun foo() {
println(x)
println(super<B>.x)
bar()
}
}
fun main(args: Array<String>) {
val c = C()
c.foo()
}
@@ -0,0 +1,9 @@
val lazyValue: String by lazy {
println("computed!")
"Hello"
}
fun main(args: Array<String>) {
println(lazyValue)
println(lazyValue)
}
@@ -0,0 +1,18 @@
import kotlin.reflect.KProperty
fun foo(): Int {
class Delegate {
operator fun getValue(receiver: Any?, p: KProperty<*>): Int {
println(p.name)
return 42
}
}
val x: Int by Delegate()
return x
}
fun main(args: Array<String>) {
println(foo())
}
@@ -0,0 +1,13 @@
class User(val map: Map<String, Any?>) {
val name: String by map
val age: Int by map
}
fun main(args: Array<String>) {
val user = User(mapOf(
"name" to "John Doe",
"age" to 25
))
println(user.name) // Prints "John Doe"
println(user.age) // Prints 25
}
@@ -0,0 +1,14 @@
import kotlin.properties.Delegates
class User {
var name: String by Delegates.observable("<no name>") {
prop, old, new ->
println("$old -> $new")
}
}
fun main(args: Array<String>) {
val user = User()
user.name = "first"
user.name = "second"
}
@@ -0,0 +1,14 @@
import kotlin.reflect.KProperty
class Delegate {
operator fun getValue(receiver: Any?, p: KProperty<*>): Int {
println(p.name)
return 42
}
}
val x: Int by Delegate()
fun main(args: Array<String>) {
println(x)
}
@@ -0,0 +1,16 @@
import kotlin.reflect.KProperty
class Delegate {
operator fun getValue(receiver: Any?, p: KProperty<*>): Int {
println(p.name)
return 42
}
}
class C {
val x: Int by Delegate()
}
fun main(args: Array<String>) {
println(C().x)
}
@@ -0,0 +1,26 @@
import kotlin.reflect.KProperty
class Delegate {
var f: Int = 42
operator fun getValue(receiver: Any?, p: KProperty<*>): Int {
println("get ${p.name}")
return f
}
operator fun setValue(receiver: Any?, p: KProperty<*>, value: Int) {
println("set ${p.name}")
f = value
}
}
class C {
var x: Int by Delegate()
}
fun main(args: Array<String>) {
val c = C()
println(c.x)
c.x = 117
println(c.x)
}
@@ -186,7 +186,7 @@ class RunInteropKonanTest extends KonanTest {
}
@ParallelizableTask
class LinkKonanTest extends KonanTest {
class LinkKonanTestNoStdlib extends KonanTest {
protected String lib
void compileTest(List<String> filesToCompile, String exe) {
@@ -198,6 +198,19 @@ class LinkKonanTest extends KonanTest {
}
}
@ParallelizableTask
class LinkKonanTest extends KonanTest {
protected String lib
void compileTest(List<String> filesToCompile, String exe) {
def libDir = project.file(lib).absolutePath
def libBc = "${libDir}.bc"
runCompiler(lib, libBc, ['-nolink'])
runCompiler(filesToCompile, exe, ['-library', libBc])
}
}
@ParallelizableTask
class RunExternalTestGroup extends RunKonanTest {
@@ -54,6 +54,16 @@ public annotation class FixmeVariance
*/
public annotation class FixmeRegex
/**
* Need to be fixed because of reflection.
*/
public annotation class FixmeReflection
/**
* Need to be fixed because of concurrency.
*/
public annotation class FixmeConcurrency
/**
* Need to be fixed.
*/
+206
View File
@@ -0,0 +1,206 @@
package kotlin
import kotlin.reflect.KProperty
/**
* Represents a value with lazy initialization.
*
* To create an instance of [Lazy] use the [lazy] function.
*/
public interface Lazy<out T> {
/**
* Gets the lazily initialized value of the current Lazy instance.
* Once the value was initialized it must not change during the rest of lifetime of this Lazy instance.
*/
public val value: T
/**
* Returns `true` if a value for this Lazy instance has been already initialized, and `false` otherwise.
* Once this function has returned `true` it stays `true` for the rest of lifetime of this Lazy instance.
*/
public fun isInitialized(): Boolean
}
/**
* Creates a new instance of the [Lazy] that is already initialized with the specified [value].
*/
public fun <T> lazyOf(value: T): Lazy<T> = InitializedLazyImpl(value)
/**
* Creates a new instance of the [Lazy] that uses the specified initialization function [initializer]
* and the default thread-safety mode [LazyThreadSafetyMode.SYNCHRONIZED].
*
* If the initialization of a value throws an exception, it will attempt to reinitialize the value at next access.
*
* Note that the returned instance uses itself to synchronize on. Do not synchronize from external code on
* the returned instance as it may cause accidental deadlock. Also this behavior can be changed in the future.
*/
@FixmeConcurrency
public fun <T> lazy(initializer: () -> T): Lazy<T> = UnsafeLazyImpl(initializer)//SynchronizedLazyImpl(initializer)
/**
* Creates a new instance of the [Lazy] that uses the specified initialization function [initializer]
* and thread-safety [mode].
*
* If the initialization of a value throws an exception, it will attempt to reinitialize the value at next access.
*
* Note that when the [LazyThreadSafetyMode.SYNCHRONIZED] mode is specified the returned instance uses itself
* to synchronize on. Do not synchronize from external code on the returned instance as it may cause accidental deadlock.
* Also this behavior can be changed in the future.
*/
@FixmeConcurrency
public fun <T> lazy(mode: LazyThreadSafetyMode, initializer: () -> T): Lazy<T> =
when (mode) {
LazyThreadSafetyMode.SYNCHRONIZED -> TODO()//SynchronizedLazyImpl(initializer)
LazyThreadSafetyMode.PUBLICATION -> TODO()//SafePublicationLazyImpl(initializer)
LazyThreadSafetyMode.NONE -> UnsafeLazyImpl(initializer)
}
/**
* Creates a new instance of the [Lazy] that uses the specified initialization function [initializer]
* and the default thread-safety mode [LazyThreadSafetyMode.SYNCHRONIZED].
*
* If the initialization of a value throws an exception, it will attempt to reinitialize the value at next access.
*
* The returned instance uses the specified [lock] object to synchronize on.
* When the [lock] is not specified the instance uses itself to synchronize on,
* in this case do not synchronize from external code on the returned instance as it may cause accidental deadlock.
* Also this behavior can be changed in the future.
*/
@FixmeConcurrency
public fun <T> lazy(lock: Any?, initializer: () -> T): Lazy<T> = TODO()//SynchronizedLazyImpl(initializer, lock)
/**
* An extension to delegate a read-only property of type [T] to an instance of [Lazy].
*
* This extension allows to use instances of Lazy for property delegation:
* `val property: String by lazy { initializer }`
*/
@kotlin.internal.InlineOnly
public inline operator fun <T> Lazy<T>.getValue(thisRef: Any?, property: KProperty<*>): T = value
/**
* Specifies how a [Lazy] instance synchronizes access among multiple threads.
*/
public enum class LazyThreadSafetyMode {
/**
* Locks are used to ensure that only a single thread can initialize the [Lazy] instance.
*/
SYNCHRONIZED,
/**
* Initializer function can be called several times on concurrent access to uninitialized [Lazy] instance value,
* but only first returned value will be used as the value of [Lazy] instance.
*/
PUBLICATION,
/**
* No locks are used to synchronize the access to the [Lazy] instance value; if the instance is accessed from multiple threads, its behavior is undefined.
*
* This mode should be used only when high performance is crucial and the [Lazy] instance is guaranteed never to be initialized from more than one thread.
*/
NONE,
}
private object UNINITIALIZED_VALUE
//private class SynchronizedLazyImpl<out T>(initializer: () -> T, lock: Any? = null) : Lazy<T>, Serializable {
// private var initializer: (() -> T)? = initializer
// @Volatile private var _value: Any? = UNINITIALIZED_VALUE
// // final field is required to enable safe publication of constructed instance
// private val lock = lock ?: this
//
// override val value: T
// get() {
// val _v1 = _value
// if (_v1 !== UNINITIALIZED_VALUE) {
// @Suppress("UNCHECKED_CAST")
// return _v1 as T
// }
//
// return synchronized(lock) {
// val _v2 = _value
// if (_v2 !== UNINITIALIZED_VALUE) {
// @Suppress("UNCHECKED_CAST") (_v2 as T)
// }
// else {
// val typedValue = initializer!!()
// _value = typedValue
// initializer = null
// typedValue
// }
// }
// }
//
// override fun isInitialized(): Boolean = _value !== UNINITIALIZED_VALUE
//
// override fun toString(): String = if (isInitialized()) value.toString() else "Lazy value not initialized yet."
//
// private fun writeReplace(): Any = InitializedLazyImpl(value)
//}
internal class UnsafeLazyImpl<out T>(initializer: () -> T) : Lazy<T>/*, Serializable*/ {
private var initializer: (() -> T)? = initializer
private var _value: Any? = UNINITIALIZED_VALUE
override val value: T
get() {
if (_value === UNINITIALIZED_VALUE) {
_value = initializer!!()
initializer = null
}
@Suppress("UNCHECKED_CAST")
return _value as T
}
override fun isInitialized(): Boolean = _value !== UNINITIALIZED_VALUE
override fun toString(): String = if (isInitialized()) value.toString() else "Lazy value not initialized yet."
private fun writeReplace(): Any = InitializedLazyImpl(value)
}
private class InitializedLazyImpl<out T>(override val value: T) : Lazy<T>/*, Serializable*/ {
override fun isInitialized(): Boolean = true
override fun toString(): String = value.toString()
}
//private class SafePublicationLazyImpl<out T>(initializer: () -> T) : Lazy<T>, Serializable {
// private var initializer: (() -> T)? = initializer
// @Volatile private var _value: Any? = UNINITIALIZED_VALUE
// // this final field is required to enable safe publication of constructed instance
// private val final: Any = UNINITIALIZED_VALUE
//
// override val value: T
// get() {
// if (_value === UNINITIALIZED_VALUE) {
// val initializerValue = initializer
// // if we see null in initializer here, it means that the value is already set by another thread
// if (initializerValue != null) {
// val newValue = initializerValue()
// if (valueUpdater.compareAndSet(this, UNINITIALIZED_VALUE, newValue)) {
// initializer = null
// }
// }
// }
// @Suppress("UNCHECKED_CAST")
// return _value as T
// }
//
// override fun isInitialized(): Boolean = _value !== UNINITIALIZED_VALUE
//
// override fun toString(): String = if (isInitialized()) value.toString() else "Lazy value not initialized yet."
//
// private fun writeReplace(): Any = InitializedLazyImpl(value)
//
// companion object {
// private val valueUpdater = java.util.concurrent.atomic.AtomicReferenceFieldUpdater.newUpdater(
// SafePublicationLazyImpl::class.java,
// Any::class.java,
// "_value")
// }
//}
@@ -0,0 +1,39 @@
package kotlin.collections
import kotlin.reflect.KProperty
import kotlin.internal.Exact
/**
* Returns the value of the property for the given object from this read-only map.
* @param thisRef the object for which the value is requested (not used).
* @param property the metadata for the property, used to get the name of property and lookup the value corresponding to this name in the map.
* @return the property value.
*
* @throws NoSuchElementException when the map doesn't contain value for the property name and doesn't provide an implicit default (see [withDefault]).
*/
@kotlin.internal.InlineOnly
public inline operator fun <V, V1: V> Map<in String, @Exact V>.getValue(thisRef: Any?, property: KProperty<*>): V1
= @Suppress("UNCHECKED_CAST", "NON_PUBLIC_CALL_FROM_PUBLIC_INLINE") (getOrImplicitDefault(property.name) as V1)
/**
* Returns the value of the property for the given object from this mutable map.
* @param thisRef the object for which the value is requested (not used).
* @param property the metadata for the property, used to get the name of property and lookup the value corresponding to this name in the map.
* @return the property value.
*
* @throws NoSuchElementException when the map doesn't contain value for the property name and doesn't provide an implicit default (see [withDefault]).
*/
@kotlin.internal.InlineOnly
public inline operator fun <V> MutableMap<in String, in V>.getValue(thisRef: Any?, property: KProperty<*>): V
= @Suppress("UNCHECKED_CAST", "NON_PUBLIC_CALL_FROM_PUBLIC_INLINE") (getOrImplicitDefault(property.name) as V)
/**
* Stores the value of the property for the given object in this mutable map.
* @param thisRef the object for which the value is requested (not used).
* @param property the metadata for the property, used to get the name of property and store the value associated with that name in the map.
* @param value the value to set.
*/
@kotlin.internal.InlineOnly
public inline operator fun <V> MutableMap<in String, in V>.setValue(thisRef: Any?, property: KProperty<*>, value: V) {
this.put(property.name, value)
}
@@ -0,0 +1,94 @@
package kotlin.collections
/**
* Returns the value for the given key, or the implicit default value for this map.
* By default no implicit value is provided for maps and a [NoSuchElementException] is thrown.
* To create a map with implicit default value use [withDefault] method.
*
* @throws NoSuchElementException when the map doesn't contain a value for the specified key and no implicit default was provided for that map.
*/
@PublishedApi
internal fun <K, V> Map<K, V>.getOrImplicitDefault(key: K): V {
if (this is MapWithDefault)
return this.getOrImplicitDefault(key)
return getOrElseNullable(key, { throw NoSuchElementException("Key $key is missing in the map.") })
}
/**
* Returns a wrapper of this read-only map, having the implicit default value provided with the specified function [defaultValue].
* This implicit default value is used when properties are delegated to the returned map,
* and that map doesn't contain a value for the key specified.
*
* When this map already has an implicit default value provided with a former call to [withDefault], it is being replaced by this call.
*/
public fun <K, V> Map<K, V>.withDefault(defaultValue: (key: K) -> V): Map<K, V> =
when (this) {
is MapWithDefault -> this.map.withDefault(defaultValue)
else -> MapWithDefaultImpl(this, defaultValue)
}
/**
* Returns a wrapper of this mutable map, having the implicit default value provided with the specified function [defaultValue].
* This implicit default value is used when properties are delegated to the returned map,
* and that map doesn't contain a value for the key specified.
*
* When this map already has an implicit default value provided with a former call to [withDefault], it is being replaced by this call.
*/
public fun <K, V> MutableMap<K, V>.withDefault(defaultValue: (key: K) -> V): MutableMap<K, V> =
when (this) {
is MutableMapWithDefault -> this.map.withDefault(defaultValue)
else -> MutableMapWithDefaultImpl(this, defaultValue)
}
private interface MapWithDefault<K, out V>: Map<K, V> {
public val map: Map<K, V>
public fun getOrImplicitDefault(key: K): V
}
private interface MutableMapWithDefault<K, V>: MutableMap<K, V>, MapWithDefault<K, V> {
public override val map: MutableMap<K, V>
}
private class MapWithDefaultImpl<K, out V>(public override val map: Map<K,V>, private val default: (key: K) -> V) : MapWithDefault<K, V> {
override fun equals(other: Any?): Boolean = map.equals(other)
override fun hashCode(): Int = map.hashCode()
override fun toString(): String = map.toString()
override val size: Int get() = map.size
override fun isEmpty(): Boolean = map.isEmpty()
override fun containsKey(key: K): Boolean = map.containsKey(key)
override fun containsValue(value: @UnsafeVariance V): Boolean = map.containsValue(value)
override fun get(key: K): V? = map.get(key)
override val keys: Set<K> get() = map.keys
override val values: Collection<V> get() = map.values
override val entries: Set<Map.Entry<K, V>> get() = map.entries
override fun getOrImplicitDefault(key: K): V = map.getOrElseNullable(key, { default(key) })
}
private class MutableMapWithDefaultImpl<K, V>(public override val map: MutableMap<K, V>, private val default: (key: K) -> V): MutableMapWithDefault<K, V> {
override fun equals(other: Any?): Boolean = map.equals(other)
override fun hashCode(): Int = map.hashCode()
override fun toString(): String = map.toString()
override val size: Int get() = map.size
override fun isEmpty(): Boolean = map.isEmpty()
override fun containsKey(key: K): Boolean = map.containsKey(key)
override fun containsValue(value: @UnsafeVariance V): Boolean = map.containsValue(value)
override fun get(key: K): V? = map.get(key)
override val keys: MutableSet<K> get() = map.keys
override val values: MutableCollection<V> get() = map.values
override val entries: MutableSet<MutableMap.MutableEntry<K, V>> get() = map.entries
override fun put(key: K, value: V): V? = map.put(key, value)
override fun remove(key: K): V? = map.remove(key)
override fun putAll(from: Map<out K, V>) = map.putAll(from)
override fun clear() = map.clear()
override fun getOrImplicitDefault(key: K): V = map.getOrElseNullable(key, { default(key) })
}
@@ -0,0 +1,55 @@
package kotlin.properties
import kotlin.reflect.KProperty
/**
* Standard property delegates.
*/
public object Delegates {
/**
* Returns a property delegate for a read/write property with a non-`null` value that is initialized not during
* object construction time but at a later time. Trying to read the property before the initial value has been
* assigned results in an exception.
*/
public fun <T: Any> notNull(): ReadWriteProperty<Any?, T> = NotNullVar()
/**
* Returns a property delegate for a read/write property that calls a specified callback function when changed.
* @param initialValue the initial value of the property.
* @param onChange the callback which is called after the change of the property is made. The value of the property
* has already been changed when this callback is invoked.
*/
public inline fun <T> observable(initialValue: T, crossinline onChange: (property: KProperty<*>, oldValue: T, newValue: T) -> Unit):
ReadWriteProperty<Any?, T> = object : ObservableProperty<T>(initialValue) {
override fun afterChange(property: KProperty<*>, oldValue: T, newValue: T) = onChange(property, oldValue, newValue)
}
/**
* Returns a property delegate for a read/write property that calls a specified callback function when changed,
* allowing the callback to veto the modification.
* @param initialValue the initial value of the property.
* @param onChange the callback which is called before a change to the property value is attempted.
* The value of the property hasn't been changed yet, when this callback is invoked.
* If the callback returns `true` the value of the property is being set to the new value,
* and if the callback returns `false` the new value is discarded and the property remains its old value.
*/
public inline fun <T> vetoable(initialValue: T, crossinline onChange: (property: KProperty<*>, oldValue: T, newValue: T) -> Boolean):
ReadWriteProperty<Any?, T> = object : ObservableProperty<T>(initialValue) {
override fun beforeChange(property: KProperty<*>, oldValue: T, newValue: T): Boolean = onChange(property, oldValue, newValue)
}
}
private class NotNullVar<T: Any>() : ReadWriteProperty<Any?, T> {
private var value: T? = null
public override fun getValue(thisRef: Any?, property: KProperty<*>): T {
return value ?: throw IllegalStateException("Property ${property.name} should be initialized before get.")
}
public override fun setValue(thisRef: Any?, property: KProperty<*>, value: T) {
this.value = value
}
}
@@ -0,0 +1,49 @@
package kotlin.properties
import kotlin.reflect.KProperty
/**
* Base interface that can be used for implementing property delegates of read-only properties.
*
* This is provided only for convenience; you don't have to extend this interface
* as long as your property delegate has methods with the same signatures.
*
* @param R the type of object which owns the delegated property.
* @param T the type of the property value.
*/
public interface ReadOnlyProperty<in R, out T> {
/**
* Returns the value of the property for the given object.
* @param thisRef the object for which the value is requested.
* @param property the metadata for the property.
* @return the property value.
*/
public operator fun getValue(thisRef: R, property: KProperty<*>): T
}
/**
* Base interface that can be used for implementing property delegates of read-write properties.
*
* This is provided only for convenience; you don't have to extend this interface
* as long as your property delegate has methods with the same signatures.
*
* @param R the type of object which owns the delegated property.
* @param T the type of the property value.
*/
public interface ReadWriteProperty<in R, T> {
/**
* Returns the value of the property for the given object.
* @param thisRef the object for which the value is requested.
* @param property the metadata for the property.
* @return the property value.
*/
public operator fun getValue(thisRef: R, property: KProperty<*>): T
/**
* Sets the value of the property for the given object.
* @param thisRef the object for which the value is requested.
* @param property the metadata for the property.
* @param value the value to set.
*/
public operator fun setValue(thisRef: R, property: KProperty<*>, value: T)
}
@@ -0,0 +1,38 @@
package kotlin.properties
import kotlin.reflect.KProperty
/**
* Implements the core logic of a property delegate for a read/write property that calls callback functions when changed.
* @param initialValue the initial value of the property.
*/
public abstract class ObservableProperty<T>(initialValue: T) : ReadWriteProperty<Any?, T> {
private var value = initialValue
/**
* The callback which is called before a change to the property value is attempted.
* The value of the property hasn't been changed yet, when this callback is invoked.
* If the callback returns `true` the value of the property is being set to the new value,
* and if the callback returns `false` the new value is discarded and the property remains its old value.
*/
protected open fun beforeChange(property: KProperty<*>, oldValue: T, newValue: T): Boolean = true
/**
* The callback which is called after the change of the property is made. The value of the property
* has already been changed when this callback is invoked.
*/
protected open fun afterChange (property: KProperty<*>, oldValue: T, newValue: T): Unit {}
public override fun getValue(thisRef: Any?, property: KProperty<*>): T {
return value
}
public override fun setValue(thisRef: Any?, property: KProperty<*>, value: T) {
val oldValue = this.value
if (!beforeChange(property, oldValue, value)) {
return
}
this.value = value
afterChange(property, oldValue, value)
}
}
@@ -0,0 +1,14 @@
package kotlin.reflect
/**
* Represents an annotated element and allows to obtain its annotations.
* See the [Kotlin language documentation](http://kotlinlang.org/docs/reference/annotations.html)
* for more information.
*/
@FixmeReflection
public interface KAnnotatedElement {
// /**
// * Annotations which are present on this element.
// */
// public val annotations: List<Annotation>
}
@@ -0,0 +1,75 @@
package kotlin.reflect
/**
* Represents a callable entity, such as a function or a property.
*
* @param R return type of the callable.
*/
@FixmeReflection
public interface KCallable<out R> : KAnnotatedElement {
/**
* The name of this callable as it was declared in the source code.
* If the callable has no name, a special invented name is created.
* Nameless callables include:
* - constructors have the name "<init>",
* - property accessors: the getter for a property named "foo" will have the name "<get-foo>",
* the setter, similarly, will have the name "<set-foo>".
*/
public val name: String
// /**
// * Parameters required to make a call to this callable.
// * If this callable requires a `this` instance or an extension receiver parameter,
// * they come first in the list in that order.
// */
// public val parameters: List<KParameter>
//
// /**
// * The type of values returned by this callable.
// */
// public val returnType: KType
//
// /**
// * The list of type parameters of this callable.
// */
// @SinceKotlin("1.1")
// public val typeParameters: List<KTypeParameter>
//
// /**
// * Calls this callable with the specified list of arguments and returns the result.
// * Throws an exception if the number of specified arguments is not equal to the size of [parameters],
// * or if their types do not match the types of the parameters.
// */
// public fun call(vararg args: Any?): R
//
// /**
// * Calls this callable with the specified mapping of parameters to arguments and returns the result.
// * If a parameter is not found in the mapping and is not optional (as per [KParameter.isOptional]),
// * or its type does not match the type of the provided value, an exception is thrown.
// */
// public fun callBy(args: Map<KParameter, Any?>): R
//
// /**
// * Visibility of this callable, or `null` if its visibility cannot be represented in Kotlin.
// */
// @SinceKotlin("1.1")
// public val visibility: KVisibility?
//
// /**
// * `true` if this callable is `final`.
// */
// @SinceKotlin("1.1")
// public val isFinal: Boolean
//
// /**
// * `true` if this callable is `open`.
// */
// @SinceKotlin("1.1")
// public val isOpen: Boolean
//
// /**
// * `true` if this callable is `abstract`.
// */
// @SinceKotlin("1.1")
// public val isAbstract: Boolean
}
@@ -0,0 +1,67 @@
package kotlin.reflect
/**
* Represents a property, such as a named `val` or `var` declaration.
* Instances of this class are obtainable by the `::` operator.
* See the [Kotlin language documentation](http://kotlinlang.org/docs/reference/reflection.html)
* for more information.
*
* @param R the type of the property.
*/
@FixmeReflection
public interface KProperty<out R> : KCallable<R> {
// /**
// * `true` if this property is `lateinit`.
// * See the [Kotlin language documentation](https://kotlinlang.org/docs/reference/properties.html#late-initialized-properties)
// * for more information.
// */
// @SinceKotlin("1.1")
// public val isLateinit: Boolean
//
// /**
// * `true` if this property is `const`.
// * See the [Kotlin language documentation](https://kotlinlang.org/docs/reference/properties.html#compile-time-constants)
// * for more information.
// */
// @SinceKotlin("1.1")
// public val isConst: Boolean
//
// /** The getter of this property, used to obtain the value of the property. */
// public val getter: Getter<R>
//
// /**
// * Represents a property accessor, which is a `get` or `set` method declared alongside the property.
// * See the [Kotlin language documentation](http://kotlinlang.org/docs/reference/properties.html#getters-and-setters)
// * for more information.
// *
// * @param R the type of the property, which it is an accessor of.
// */
// public interface Accessor<out R> {
// /** The property which this accessor is originated from. */
// public val property: KProperty<R>
// }
//
// /**
// * Getter of the property is a `get` method declared alongside the property.
// */
// public interface Getter<out R> : Accessor<R>, KFunction<R>
}
/**
* Represents a property declared as a `var`.
*/
@FixmeReflection
public interface KMutableProperty<R> : KProperty<R> {
// /** The setter of this mutable property, used to change the value of the property. */
// public val setter: Setter<R>
//
// /**
// * Setter of the property is a `set` method declared alongside the property.
// */
// public interface Setter<R> : KProperty.Accessor<R>, KFunction<Unit>
}
@FixmeReflection
public class KPropertyImpl<out R>(override val name: String) : KProperty<R> {
}