Merge pull request #263 from JetBrains/class_delegation
Class delegation
This commit is contained in:
+18
-12
@@ -5,7 +5,10 @@ import llvm.LLVMModuleRef
|
||||
import org.jetbrains.kotlin.backend.jvm.descriptors.initialize
|
||||
import org.jetbrains.kotlin.backend.konan.descriptors.*
|
||||
import org.jetbrains.kotlin.backend.konan.ir.Ir
|
||||
import org.jetbrains.kotlin.backend.konan.llvm.*
|
||||
import org.jetbrains.kotlin.backend.konan.llvm.Llvm
|
||||
import org.jetbrains.kotlin.backend.konan.llvm.LlvmDeclarations
|
||||
import org.jetbrains.kotlin.backend.konan.llvm.functionName
|
||||
import org.jetbrains.kotlin.backend.konan.llvm.verifyModule
|
||||
import org.jetbrains.kotlin.descriptors.*
|
||||
import org.jetbrains.kotlin.descriptors.annotations.Annotations
|
||||
import org.jetbrains.kotlin.descriptors.impl.PropertyDescriptorImpl
|
||||
@@ -20,7 +23,7 @@ import java.lang.System.out
|
||||
|
||||
internal class SpecialDescriptorsFactory(val context: Context) {
|
||||
private val outerThisDescriptors = mutableMapOf<ClassDescriptor, PropertyDescriptor>()
|
||||
private val bridgesDescriptors = mutableMapOf<FunctionDescriptor, FunctionDescriptor>()
|
||||
private val bridgesDescriptors = mutableMapOf<Pair<FunctionDescriptor, BridgeDirections>, FunctionDescriptor>()
|
||||
|
||||
fun getOuterThisFieldDescriptor(innerClassDescriptor: ClassDescriptor): PropertyDescriptor =
|
||||
if (!innerClassDescriptor.isInner) throw AssertionError("Class is not inner: $innerClassDescriptor")
|
||||
@@ -34,24 +37,26 @@ internal class SpecialDescriptorsFactory(val context: Context) {
|
||||
false, false, false, false, false, false).initialize(outerClassDescriptor.defaultType, dispatchReceiverParameter = receiver)
|
||||
}
|
||||
|
||||
fun getBridgeDescriptor(descriptor: FunctionDescriptor): FunctionDescriptor {
|
||||
return bridgesDescriptors.getOrPut(descriptor) {
|
||||
fun getBridgeDescriptor(overriddenFunctionDescriptor: OverriddenFunctionDescriptor): FunctionDescriptor {
|
||||
val descriptor = overriddenFunctionDescriptor.descriptor.original
|
||||
assert(overriddenFunctionDescriptor.needBridge,
|
||||
{ "Function $descriptor is not needed in a bridge to call overridden function ${overriddenFunctionDescriptor.overriddenDescriptor}" })
|
||||
val bridgeDirections = overriddenFunctionDescriptor.bridgeDirections
|
||||
return bridgesDescriptors.getOrPut(descriptor to bridgeDirections) {
|
||||
SimpleFunctionDescriptorImpl.create(
|
||||
descriptor.containingDeclaration,
|
||||
Annotations.EMPTY,
|
||||
("<bridge-to>" + descriptor.functionName).synthesizedName,
|
||||
("<bridge-" + bridgeDirections.toString() + ">" + descriptor.functionName).synthesizedName,
|
||||
CallableMemberDescriptor.Kind.DECLARATION,
|
||||
SourceElement.NO_SOURCE).apply {
|
||||
initializeBridgeDescriptor(this, descriptor)
|
||||
initializeBridgeDescriptor(this, descriptor, bridgeDirections.array)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private fun initializeBridgeDescriptor(bridgeDescriptor: SimpleFunctionDescriptorImpl, descriptor: FunctionDescriptor) {
|
||||
val bridgeDirections = descriptor.bridgeDirections
|
||||
if (bridgeDirections.allNotNeeded())
|
||||
throw AssertionError("Function $descriptor is not needed in a bridge")
|
||||
|
||||
private fun initializeBridgeDescriptor(bridgeDescriptor: SimpleFunctionDescriptorImpl,
|
||||
descriptor: FunctionDescriptor,
|
||||
bridgeDirections: Array<BridgeDirection>) {
|
||||
val returnType = when (bridgeDirections[0]) {
|
||||
BridgeDirection.TO_VALUE_TYPE -> descriptor.returnType!!
|
||||
BridgeDirection.NOT_NEEDED -> descriptor.returnType
|
||||
@@ -66,7 +71,8 @@ internal class SpecialDescriptorsFactory(val context: Context) {
|
||||
|
||||
bridgeDescriptor.initialize(
|
||||
extensionReceiverType,
|
||||
descriptor.dispatchReceiverParameter,
|
||||
// TODO: bug in descriptor - https://youtrack.jetbrains.com/issue/KT-16438.
|
||||
(descriptor.containingDeclaration as ClassDescriptor).thisAsReceiverParameter,
|
||||
descriptor.typeParameters,
|
||||
descriptor.valueParameters.mapIndexed { index, valueParameterDescriptor ->
|
||||
when (bridgeDirections[index + 2]) {
|
||||
|
||||
+3
-1
@@ -56,7 +56,9 @@ internal class KonanLower(val context: Context) {
|
||||
VarargInjectionLowering(context).runOnFilePostfix(irFile)
|
||||
}
|
||||
phaser.phase(KonanPhase.BRIDGES_BUILDING) {
|
||||
BridgesBuilding(context).lower(irFile)
|
||||
DelegationLowering(context).runOnFilePostfix(irFile)
|
||||
BridgesBuilding(context).runOnFilePostfix(irFile)
|
||||
DirectBridgesCallsLowering(context).runOnFilePostfix(irFile)
|
||||
}
|
||||
phaser.phase(KonanPhase.AUTOBOX) {
|
||||
Autoboxing(context).lower(irFile)
|
||||
|
||||
+43
-31
@@ -15,15 +15,38 @@ internal class OverriddenFunctionDescriptor(val descriptor: FunctionDescriptor,
|
||||
val needBridge: Boolean
|
||||
get() {
|
||||
if (descriptor.modality == Modality.ABSTRACT) return false
|
||||
return descriptor.needBridgeTo(overriddenDescriptor)
|
||||
return descriptor.kind == CallableMemberDescriptor.Kind.DELEGATION
|
||||
|| descriptor.target.needBridgeTo(overriddenDescriptor)
|
||||
}
|
||||
|
||||
fun trivialOverride() = descriptor.original == overriddenDescriptor
|
||||
val bridgeDirections: BridgeDirections
|
||||
get() = descriptor.target.bridgeDirectionsTo(overriddenDescriptor)
|
||||
|
||||
val canBeCalledVirtually: Boolean
|
||||
// We check that either method is open, or one of declarations it overrides is open.
|
||||
get() = overriddenDescriptor.isOverridable
|
||||
|| DescriptorUtils.getAllOverriddenDeclarations(overriddenDescriptor).any { it.isOverridable }
|
||||
|
||||
|
||||
override fun toString(): String {
|
||||
return "(descriptor=$descriptor, overriddenDescriptor=$overriddenDescriptor)"
|
||||
}
|
||||
|
||||
override fun equals(other: Any?): Boolean {
|
||||
if (this === other) return true
|
||||
if (other !is OverriddenFunctionDescriptor) return false
|
||||
|
||||
if (descriptor != other.descriptor) return false
|
||||
if (overriddenDescriptor != other.overriddenDescriptor) return false
|
||||
|
||||
return true
|
||||
}
|
||||
|
||||
override fun hashCode(): Int {
|
||||
var result = descriptor.hashCode()
|
||||
result = 31 * result + overriddenDescriptor.hashCode()
|
||||
return result
|
||||
}
|
||||
}
|
||||
|
||||
internal class ClassVtablesBuilder(val classDescriptor: ClassDescriptor, val context: Context) {
|
||||
@@ -45,50 +68,39 @@ internal class ClassVtablesBuilder(val classDescriptor: ClassDescriptor, val con
|
||||
if (overridingMethod == null) {
|
||||
superMethod
|
||||
} else {
|
||||
if (!superMethod.trivialOverride())
|
||||
newVtableSlots.add(OverriddenFunctionDescriptor(overridingMethod, superMethod.descriptor))
|
||||
// Overriding method is defined in the current class and is not inherited - take it as is.
|
||||
newVtableSlots.add(OverriddenFunctionDescriptor(overridingMethod, overridingMethod))
|
||||
newVtableSlots.add(OverriddenFunctionDescriptor(overridingMethod, superMethod.descriptor))
|
||||
OverriddenFunctionDescriptor(overridingMethod, superMethod.overriddenDescriptor)
|
||||
}
|
||||
}
|
||||
|
||||
methods.filterNot { method -> inheritedVtableSlots.any { it.descriptor == method } } // Find newly defined methods.
|
||||
// Select target because method might be taken from default implementation of interface.
|
||||
.mapTo(newVtableSlots) { OverriddenFunctionDescriptor(it, it.target) }
|
||||
// Add all possible (descriptor, overriddenDescriptor) edges for now, redundant will be removed later.
|
||||
methods.mapTo(newVtableSlots) { OverriddenFunctionDescriptor(it, it) }
|
||||
|
||||
val list = inheritedVtableSlots + newVtableSlots.filter { it.descriptor.isOverridable }.sortedBy {
|
||||
it.overriddenDescriptor.functionName.localHash.value
|
||||
}
|
||||
list
|
||||
val inheritedVtableSlotsSet = inheritedVtableSlots.map { it.descriptor to it.bridgeDirections }.toSet()
|
||||
|
||||
val filteredNewVtableSlots = newVtableSlots
|
||||
.filterNot { inheritedVtableSlotsSet.contains(it.descriptor to it.bridgeDirections) }
|
||||
.distinctBy { it.descriptor to it.bridgeDirections }
|
||||
.filter { it.descriptor.isOverridable }
|
||||
|
||||
inheritedVtableSlots + filteredNewVtableSlots.sortedBy { it.overriddenDescriptor.functionName.localHash.value }
|
||||
}
|
||||
|
||||
fun vtableIndex(function: FunctionDescriptor): Int {
|
||||
val target = function.target
|
||||
val index = vtableEntries.indexOfFirst { it.overriddenDescriptor == target }
|
||||
val bridgeDirections = function.target.bridgeDirectionsTo(function.original)
|
||||
val index = vtableEntries.indexOfFirst { it.descriptor == function.original && it.bridgeDirections == bridgeDirections }
|
||||
if (index < 0) throw Error(function.toString() + " not in vtable of " + classDescriptor.toString())
|
||||
return index
|
||||
}
|
||||
|
||||
private val ClassDescriptor.contributedMethodsWithOverridden: List<OverriddenFunctionDescriptor>
|
||||
get() {
|
||||
return contributedMethods.flatMap { method ->
|
||||
method.allOverriddenDescriptors.map { OverriddenFunctionDescriptor(method, it) }
|
||||
}.distinctBy {
|
||||
Triple(it.overriddenDescriptor.functionName, it.descriptor, it.needBridge)
|
||||
}.sortedBy {
|
||||
it.overriddenDescriptor.functionName.localHash.value
|
||||
}
|
||||
}
|
||||
|
||||
val methodTableEntries: List<OverriddenFunctionDescriptor> by lazy {
|
||||
assert(!classDescriptor.isAbstract())
|
||||
|
||||
classDescriptor.contributedMethodsWithOverridden.filter {
|
||||
// We check that either method is open, or one of declarations it overrides
|
||||
// is open.
|
||||
it.overriddenDescriptor.isOverridable || DescriptorUtils.getAllOverriddenDeclarations(it.overriddenDescriptor).any { it.isOverridable }
|
||||
}
|
||||
classDescriptor.contributedMethods
|
||||
.flatMap { method -> method.allOverriddenDescriptors.map { OverriddenFunctionDescriptor(method, it) } }
|
||||
.filter { it.canBeCalledVirtually }
|
||||
.distinctBy { Triple(it.overriddenDescriptor.functionName, it.descriptor, it.needBridge) }
|
||||
.sortedBy { it.overriddenDescriptor.functionName.localHash.value }
|
||||
// TODO: probably method table should contain all accessible methods to improve binary compatibility
|
||||
}
|
||||
|
||||
|
||||
+52
-35
@@ -49,6 +49,7 @@ internal fun <T : CallableMemberDescriptor> T.resolveFakeOverride(): T {
|
||||
val overridden = OverridingUtil.getOverriddenDeclarations(this)
|
||||
val filtered = OverridingUtil.filterOutOverridden(overridden)
|
||||
// TODO: is it correct to take first?
|
||||
@Suppress("UNCHECKED_CAST")
|
||||
return filtered.first { it.modality != Modality.ABSTRACT } as T
|
||||
}
|
||||
}
|
||||
@@ -166,6 +167,7 @@ internal val <T : CallableMemberDescriptor> T.allOverriddenDescriptors: List<T>
|
||||
val result = mutableListOf<T>()
|
||||
fun traverse(descriptor: T) {
|
||||
result.add(descriptor)
|
||||
@Suppress("UNCHECKED_CAST")
|
||||
descriptor.overriddenDescriptors.forEach { traverse(it as T) }
|
||||
}
|
||||
traverse(this)
|
||||
@@ -209,12 +211,6 @@ internal fun FunctionDescriptor.hasReferenceAt(index: Int): Boolean {
|
||||
}
|
||||
}
|
||||
|
||||
private fun FunctionDescriptor.overridesFunWithReferenceAt(index: Int)
|
||||
= allOverriddenDescriptors.any { it.original.hasReferenceAt(index) }
|
||||
|
||||
private fun FunctionDescriptor.overridesFunWithValueTypeAt(index: Int)
|
||||
= allOverriddenDescriptors.any { it.original.hasValueTypeAt(index) }
|
||||
|
||||
private fun FunctionDescriptor.needBridgeToAt(target: FunctionDescriptor, index: Int)
|
||||
= hasValueTypeAt(index) xor target.hasValueTypeAt(index)
|
||||
|
||||
@@ -230,39 +226,60 @@ internal enum class BridgeDirection {
|
||||
TO_VALUE_TYPE
|
||||
}
|
||||
|
||||
private fun FunctionDescriptor.bridgeDirectionAt(index: Int) : BridgeDirection {
|
||||
if (kind.isReal) {
|
||||
if (hasValueTypeAt(index) && overridesFunWithReferenceAt(index))
|
||||
return BridgeDirection.FROM_VALUE_TYPE
|
||||
return BridgeDirection.NOT_NEEDED
|
||||
}
|
||||
|
||||
val target = this.target
|
||||
return when {
|
||||
hasValueTypeAt(index) && target.hasValueTypeAt(index) && overridesFunWithReferenceAt(index) -> BridgeDirection.FROM_VALUE_TYPE
|
||||
hasValueTypeAt(index) && target.hasReferenceAt(index) && overridesFunWithValueTypeAt(index) -> BridgeDirection.TO_VALUE_TYPE
|
||||
else -> BridgeDirection.NOT_NEEDED
|
||||
private fun FunctionDescriptor.bridgeDirectionToAt(target: FunctionDescriptor, index: Int): BridgeDirection {
|
||||
when {
|
||||
hasValueTypeAt(index) && target.hasReferenceAt(index) -> return BridgeDirection.FROM_VALUE_TYPE
|
||||
hasReferenceAt(index) && target.hasValueTypeAt(index) -> return BridgeDirection.TO_VALUE_TYPE
|
||||
else -> return BridgeDirection.NOT_NEEDED
|
||||
}
|
||||
}
|
||||
|
||||
private fun bridgesEqual(first: Array<BridgeDirection>, second: Array<BridgeDirection>)
|
||||
= first.indices.none { first[it] != second[it] }
|
||||
internal class BridgeDirections(val array: Array<BridgeDirection>) {
|
||||
constructor(parametersCount: Int): this(Array<BridgeDirection>(parametersCount + 2, { BridgeDirection.NOT_NEEDED }))
|
||||
|
||||
internal fun Array<BridgeDirection>.allNotNeeded() = this.all { it == BridgeDirection.NOT_NEEDED }
|
||||
fun allNotNeeded(): Boolean = array.all { it == BridgeDirection.NOT_NEEDED }
|
||||
|
||||
internal val FunctionDescriptor.bridgeDirections: Array<BridgeDirection>
|
||||
get() {
|
||||
val ourDirections = Array<BridgeDirection>(this.valueParameters.size + 2, { BridgeDirection.NOT_NEEDED })
|
||||
if (modality == Modality.ABSTRACT)
|
||||
return ourDirections
|
||||
for (index in ourDirections.indices)
|
||||
ourDirections[index] = this.bridgeDirectionAt(index)
|
||||
|
||||
if (!kind.isReal && bridgesEqual(ourDirections, this.target.bridgeDirections)) {
|
||||
// Bridge is inherited from supers
|
||||
for (index in ourDirections.indices)
|
||||
ourDirections[index] = BridgeDirection.NOT_NEEDED
|
||||
override fun toString(): String {
|
||||
val result = StringBuilder()
|
||||
array.forEach {
|
||||
result.append(when (it) {
|
||||
BridgeDirection.FROM_VALUE_TYPE -> 'U' // unbox
|
||||
BridgeDirection.TO_VALUE_TYPE -> 'B' // box
|
||||
BridgeDirection.NOT_NEEDED -> 'N' // none
|
||||
})
|
||||
}
|
||||
|
||||
return ourDirections
|
||||
return result.toString()
|
||||
}
|
||||
|
||||
override fun equals(other: Any?): Boolean {
|
||||
if (this === other) return true
|
||||
if (other !is BridgeDirections) return false
|
||||
|
||||
return array.size == other.array.size
|
||||
&& array.indices.all { array[it] == other.array[it] }
|
||||
}
|
||||
|
||||
override fun hashCode(): Int {
|
||||
var result = 0
|
||||
array.forEach { result = result * 31 + it.ordinal }
|
||||
return result
|
||||
}
|
||||
}
|
||||
|
||||
internal fun FunctionDescriptor.bridgeDirectionsTo(overriddenDescriptor: FunctionDescriptor): BridgeDirections {
|
||||
val ourDirections = BridgeDirections(this.valueParameters.size)
|
||||
if (modality == Modality.ABSTRACT)
|
||||
return ourDirections
|
||||
for (index in ourDirections.array.indices)
|
||||
ourDirections.array[index] = this.bridgeDirectionToAt(overriddenDescriptor, index)
|
||||
|
||||
val target = this.target
|
||||
if (!kind.isReal
|
||||
&& OverridingUtil.overrides(target, overriddenDescriptor)
|
||||
&& ourDirections == target.bridgeDirectionsTo(overriddenDescriptor)) {
|
||||
// Bridge is inherited from superclass.
|
||||
return BridgeDirections(this.valueParameters.size)
|
||||
}
|
||||
|
||||
return ourDirections
|
||||
}
|
||||
+15
-8
@@ -2,23 +2,25 @@ package org.jetbrains.kotlin.backend.konan.llvm
|
||||
|
||||
import kotlinx.cinterop.*
|
||||
import llvm.*
|
||||
import org.jetbrains.kotlin.backend.konan.*
|
||||
import org.jetbrains.kotlin.backend.konan.ir.*
|
||||
import org.jetbrains.kotlin.backend.konan.Context
|
||||
import org.jetbrains.kotlin.backend.konan.KonanConfigKeys
|
||||
import org.jetbrains.kotlin.backend.konan.KonanPhase
|
||||
import org.jetbrains.kotlin.backend.konan.PhaseManager
|
||||
import org.jetbrains.kotlin.backend.konan.descriptors.*
|
||||
import org.jetbrains.kotlin.backend.konan.ir.IrInlineFunctionBody
|
||||
import org.jetbrains.kotlin.backend.konan.ir.getArguments
|
||||
import org.jetbrains.kotlin.backend.konan.ir.ir2string
|
||||
import org.jetbrains.kotlin.builtins.KotlinBuiltIns
|
||||
import org.jetbrains.kotlin.descriptors.*
|
||||
import org.jetbrains.kotlin.incremental.components.NoLookupLocation
|
||||
import org.jetbrains.kotlin.ir.IrElement
|
||||
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.expressions.*
|
||||
import org.jetbrains.kotlin.ir.expressions.impl.IrSetterCallImpl
|
||||
import org.jetbrains.kotlin.ir.visitors.IrElementVisitorVoid
|
||||
import org.jetbrains.kotlin.ir.visitors.acceptChildrenVoid
|
||||
import org.jetbrains.kotlin.ir.visitors.acceptVoid
|
||||
import org.jetbrains.kotlin.name.FqName
|
||||
import org.jetbrains.kotlin.name.Name
|
||||
import org.jetbrains.kotlin.resolve.DescriptorUtils
|
||||
import org.jetbrains.kotlin.resolve.descriptorUtil.fqNameSafe
|
||||
import org.jetbrains.kotlin.resolve.descriptorUtil.fqNameUnsafe
|
||||
@@ -1222,7 +1224,9 @@ internal class CodeGeneratorVisitor(val context: Context) : IrElementVisitorVoid
|
||||
|
||||
private fun evaluateGetField(value: IrGetField): LLVMValueRef {
|
||||
context.log("evaluateGetField : ${ir2string(value)}")
|
||||
if (value.descriptor.dispatchReceiverParameter != null) {
|
||||
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) {
|
||||
val thisPtr = evaluateExpression(value.receiver!!)
|
||||
return codegen.loadSlot(
|
||||
fieldPtrOfClass(thisPtr, value.descriptor), value.descriptor.isVar())
|
||||
@@ -1251,7 +1255,10 @@ internal class CodeGeneratorVisitor(val context: Context) : IrElementVisitorVoid
|
||||
private fun evaluateSetField(value: IrSetField): LLVMValueRef {
|
||||
context.log("evaluateSetField : ${ir2string(value)}")
|
||||
val valueToAssign = evaluateExpression(value.value)
|
||||
if (value.descriptor.dispatchReceiverParameter != null) {
|
||||
|
||||
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) {
|
||||
val thisPtr = evaluateExpression(value.receiver!!)
|
||||
codegen.storeAnyGlobal(valueToAssign, fieldPtrOfClass(thisPtr, value.descriptor))
|
||||
}
|
||||
|
||||
+8
-2
@@ -7,6 +7,8 @@ import org.jetbrains.kotlin.backend.konan.descriptors.*
|
||||
import org.jetbrains.kotlin.descriptors.*
|
||||
import org.jetbrains.kotlin.ir.IrElement
|
||||
import org.jetbrains.kotlin.ir.declarations.*
|
||||
import org.jetbrains.kotlin.ir.descriptors.IrImplementingDelegateDescriptorImpl
|
||||
import org.jetbrains.kotlin.ir.descriptors.IrPropertyDelegateDescriptorImpl
|
||||
import org.jetbrains.kotlin.ir.visitors.IrElementVisitorVoid
|
||||
import org.jetbrains.kotlin.ir.visitors.acceptChildrenVoid
|
||||
import org.jetbrains.kotlin.name.FqName
|
||||
@@ -296,8 +298,12 @@ private class DeclarationsGeneratorVisitor(override val context: Context) :
|
||||
val descriptor = declaration.descriptor
|
||||
|
||||
val dispatchReceiverParameter = descriptor.dispatchReceiverParameter
|
||||
if (dispatchReceiverParameter != null) {
|
||||
val containingClass = dispatchReceiverParameter.containingDeclaration
|
||||
if (dispatchReceiverParameter != null
|
||||
// TODO: hack because of IR bug: https://github.com/JetBrains/kotlin/tree/rr/dispatch_receiver_for_delegate_descriptor.
|
||||
|| descriptor is IrImplementingDelegateDescriptorImpl) {
|
||||
val containingClass = dispatchReceiverParameter?.containingDeclaration
|
||||
// TODO: hack because of IR bug: https://github.com/JetBrains/kotlin/tree/rr/dispatch_receiver_for_delegate_descriptor.
|
||||
?: descriptor.containingDeclaration
|
||||
val classDeclarations = this.classes[containingClass] ?: error(containingClass.toString())
|
||||
|
||||
val allFields = classDeclarations.fields
|
||||
|
||||
+9
-2
@@ -6,6 +6,7 @@ import org.jetbrains.kotlin.backend.konan.descriptors.*
|
||||
import org.jetbrains.kotlin.builtins.KotlinBuiltIns
|
||||
import org.jetbrains.kotlin.descriptors.*
|
||||
import org.jetbrains.kotlin.name.FqName
|
||||
import org.jetbrains.kotlin.resolve.OverridingUtil
|
||||
import org.jetbrains.kotlin.resolve.constants.StringValue
|
||||
import org.jetbrains.kotlin.resolve.descriptorUtil.fqNameSafe
|
||||
import org.jetbrains.kotlin.resolve.descriptorUtil.getSuperClassOrAny
|
||||
@@ -169,7 +170,13 @@ internal class RTTIGenerator(override val context: Context) : ContextUtils {
|
||||
get() {
|
||||
val target = descriptor.target
|
||||
if (!needBridge) return target
|
||||
val bridgeOwner = if (descriptor.bridgeDirections.allNotNeeded()) target else descriptor
|
||||
return context.specialDescriptorsFactory.getBridgeDescriptor(bridgeOwner)
|
||||
val bridgeOwner = if (!descriptor.kind.isReal
|
||||
&& OverridingUtil.overrides(target, overriddenDescriptor)
|
||||
&& descriptor.bridgeDirectionsTo(overriddenDescriptor).allNotNeeded()) {
|
||||
target // Bridge is inherited from superclass.
|
||||
} else {
|
||||
descriptor
|
||||
}
|
||||
return context.specialDescriptorsFactory.getBridgeDescriptor(OverriddenFunctionDescriptor(bridgeOwner, overriddenDescriptor))
|
||||
}
|
||||
}
|
||||
|
||||
-32
@@ -91,38 +91,6 @@ private class AutoboxingTransformer(val context: Context) : AbstractValueUsageTr
|
||||
}
|
||||
}
|
||||
|
||||
override fun visitCall(expression: IrCall): IrExpression {
|
||||
val irCall = super.visitCall(expression) as IrCall
|
||||
|
||||
val descriptor = irCall.descriptor as? FunctionDescriptor ?: return irCall
|
||||
if (descriptor.modality == Modality.ABSTRACT || (irCall.superQualifier == null && descriptor.isOverridable))
|
||||
return irCall // A virtual call. box/unbox will be in the corresponding bridge.
|
||||
|
||||
val target = descriptor.target
|
||||
|
||||
if (!descriptor.original.needBridgeTo(target)) return irCall
|
||||
|
||||
val overriddenCall = IrCallImpl(irCall.startOffset, irCall.endOffset,
|
||||
target, remapTypeArguments(irCall, target)).apply {
|
||||
dispatchReceiver = irCall.dispatchReceiver
|
||||
extensionReceiver = irCall.extensionReceiver
|
||||
mapValueParameters { irCall.getValueArgument(it)!! }
|
||||
}
|
||||
|
||||
return super.visitCall(overriddenCall)
|
||||
}
|
||||
|
||||
private fun remapTypeArguments(oldExpression: IrMemberAccessExpression, newCallee: CallableDescriptor): Map<TypeParameterDescriptor, KotlinType>? {
|
||||
val oldCallee = oldExpression.descriptor
|
||||
|
||||
return if (oldCallee.typeParameters.isEmpty())
|
||||
null
|
||||
else oldCallee.typeParameters.associateBy(
|
||||
{ newCallee.typeParameters[it.index] },
|
||||
{ oldExpression.getTypeArgument(it)!! }
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
* @return the [ValueType] given type represented in generated code as,
|
||||
* or `null` if represented as object reference.
|
||||
|
||||
+145
-37
@@ -1,63 +1,171 @@
|
||||
package org.jetbrains.kotlin.backend.konan.lower
|
||||
|
||||
import org.jetbrains.kotlin.backend.common.FileLoweringPass
|
||||
import org.jetbrains.kotlin.backend.common.BodyLoweringPass
|
||||
import org.jetbrains.kotlin.backend.common.ClassLoweringPass
|
||||
import org.jetbrains.kotlin.backend.konan.Context
|
||||
import org.jetbrains.kotlin.backend.konan.descriptors.*
|
||||
import org.jetbrains.kotlin.builtins.KotlinBuiltIns
|
||||
import org.jetbrains.kotlin.descriptors.ClassDescriptor
|
||||
import org.jetbrains.kotlin.descriptors.FunctionDescriptor
|
||||
import org.jetbrains.kotlin.ir.IrStatement
|
||||
import org.jetbrains.kotlin.descriptors.*
|
||||
import org.jetbrains.kotlin.ir.UNDEFINED_OFFSET
|
||||
import org.jetbrains.kotlin.ir.declarations.*
|
||||
import org.jetbrains.kotlin.ir.declarations.IrClass
|
||||
import org.jetbrains.kotlin.ir.declarations.IrDeclarationOriginImpl
|
||||
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.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.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.types.typeUtil.isUnit
|
||||
import org.jetbrains.kotlin.types.KotlinType
|
||||
|
||||
internal class BridgesBuilding(val context: Context) : FileLoweringPass {
|
||||
override fun lower(irFile: IrFile) {
|
||||
irFile.transformChildrenVoid(object : IrElementTransformerVoid() {
|
||||
|
||||
override fun visitClass(declaration: IrClass): IrStatement {
|
||||
val irClass = super.visitClass(declaration) as IrClass
|
||||
|
||||
val functions = mutableSetOf<FunctionDescriptor?>()
|
||||
irClass.declarations.forEach {
|
||||
when (it) {
|
||||
is IrFunction -> functions.add(it.descriptor)
|
||||
is IrProperty -> {
|
||||
functions.add(it.getter?.descriptor)
|
||||
functions.add(it.setter?.descriptor)
|
||||
}
|
||||
}
|
||||
internal class DirectBridgesCallsLowering(val context: Context) : BodyLoweringPass {
|
||||
override fun lower(irBody: IrBody) {
|
||||
irBody.transformChildrenVoid(object : IrElementTransformerVoid() {
|
||||
override fun visitCall(expression: IrCall): IrExpression {
|
||||
expression.transformChildrenVoid(this)
|
||||
val descriptor = expression.descriptor as? FunctionDescriptor ?: return expression
|
||||
if (descriptor.modality == Modality.ABSTRACT
|
||||
|| (expression.superQualifier == null && descriptor.isOverridable)) {
|
||||
// A virtual call. boxing/unboxing will be in the corresponding bridge.
|
||||
return expression
|
||||
}
|
||||
|
||||
irClass.descriptor.contributedMethods.forEach { functions.add(it) }
|
||||
val target = descriptor.target
|
||||
val needBridge = descriptor.original.needBridgeTo(target)
|
||||
if (descriptor.kind != CallableMemberDescriptor.Kind.DELEGATION && !needBridge)
|
||||
return expression
|
||||
|
||||
functions.forEach { buildBridge(it, irClass) }
|
||||
val toCall = if (needBridge) {
|
||||
target
|
||||
} else {
|
||||
// Need to call delegating function.
|
||||
context.specialDescriptorsFactory.getBridgeDescriptor(OverriddenFunctionDescriptor(descriptor, target))
|
||||
}
|
||||
|
||||
return irClass
|
||||
return IrCallImpl(expression.startOffset, expression.endOffset,
|
||||
toCall, remapTypeArguments(expression, toCall)).apply {
|
||||
dispatchReceiver = expression.dispatchReceiver
|
||||
extensionReceiver = expression.extensionReceiver
|
||||
mapValueParameters { expression.getValueArgument(it)!! }
|
||||
}
|
||||
}
|
||||
|
||||
private fun remapTypeArguments(oldExpression: IrMemberAccessExpression, newCallee: CallableDescriptor)
|
||||
: Map<TypeParameterDescriptor, KotlinType>? {
|
||||
val oldCallee = oldExpression.descriptor
|
||||
|
||||
return if (oldCallee.typeParameters.isEmpty())
|
||||
null
|
||||
else oldCallee.typeParameters.associateBy(
|
||||
{ newCallee.typeParameters[it.index] },
|
||||
{ oldExpression.getTypeArgument(it)!! }
|
||||
)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
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
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private object DECLARATION_ORIGIN_BRIDGE_METHOD :
|
||||
IrDeclarationOriginImpl("BRIDGE_METHOD")
|
||||
// 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
|
||||
|
||||
private fun buildBridge(descriptor: FunctionDescriptor?, irClass: IrClass) {
|
||||
if (descriptor == null) return
|
||||
if (descriptor.bridgeDirections.allNotNeeded())
|
||||
return
|
||||
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?>()
|
||||
irClass.declarations.forEach {
|
||||
when (it) {
|
||||
is IrFunction -> functions.add(it.descriptor)
|
||||
is IrProperty -> {
|
||||
functions.add(it.getter?.descriptor)
|
||||
functions.add(it.setter?.descriptor)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
irClass.descriptor.contributedMethods.forEach { functions.add(it) }
|
||||
|
||||
functions.forEach {
|
||||
it?.let { function ->
|
||||
function.allOverriddenDescriptors
|
||||
.map { OverriddenFunctionDescriptor(function, it) }
|
||||
.filter { !it.bridgeDirections.allNotNeeded() }
|
||||
.filter { it.canBeCalledVirtually }
|
||||
.distinctBy { it.bridgeDirections }
|
||||
.forEach {
|
||||
buildBridge(it, irClass)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private fun buildBridge(descriptor: OverriddenFunctionDescriptor, irClass: IrClass) {
|
||||
val bridgeDescriptor = context.specialDescriptorsFactory.getBridgeDescriptor(descriptor)
|
||||
val target = descriptor.descriptor.target
|
||||
|
||||
val delegatingCall = IrCallImpl(UNDEFINED_OFFSET, UNDEFINED_OFFSET, descriptor.target,
|
||||
superQualifier = descriptor.target.containingDeclaration as ClassDescriptor /* Call non-virtually */).apply {
|
||||
val delegatingCall = IrCallImpl(UNDEFINED_OFFSET, UNDEFINED_OFFSET, target,
|
||||
superQualifier = target.containingDeclaration as ClassDescriptor /* Call non-virtually */).apply {
|
||||
val dispatchReceiverParameter = bridgeDescriptor.dispatchReceiverParameter
|
||||
if (dispatchReceiverParameter != null)
|
||||
dispatchReceiver = IrGetValueImpl(UNDEFINED_OFFSET, UNDEFINED_OFFSET, dispatchReceiverParameter)
|
||||
|
||||
+4
-1
@@ -2,6 +2,7 @@ package org.jetbrains.kotlin.backend.konan.lower
|
||||
|
||||
import org.jetbrains.kotlin.backend.common.ClassLoweringPass
|
||||
import org.jetbrains.kotlin.backend.common.FileLoweringPass
|
||||
import org.jetbrains.kotlin.backend.common.lower.SimpleMemberScope
|
||||
import org.jetbrains.kotlin.backend.common.runOnFilePostfix
|
||||
import org.jetbrains.kotlin.backend.jvm.descriptors.createValueParameter
|
||||
import org.jetbrains.kotlin.backend.jvm.descriptors.initialize
|
||||
@@ -37,6 +38,8 @@ import org.jetbrains.kotlin.types.*
|
||||
import org.jetbrains.kotlin.utils.addToStdlib.singletonList
|
||||
import org.jetbrains.kotlin.utils.addToStdlib.singletonOrEmptyList
|
||||
|
||||
// TODO: cross-module usage.
|
||||
|
||||
internal data class LoweredSyntheticFunction(val functionDescriptor: FunctionDescriptor, val containingClass: ClassDescriptor)
|
||||
|
||||
internal data class LoweredEnumEntry(val implObject: ClassDescriptor, val valuesProperty: PropertyDescriptor,
|
||||
@@ -173,7 +176,7 @@ internal class EnumClassLowering(val context: Context) : ClassLoweringPass {
|
||||
defaultEnumEntryConstructors.put(loweredEnumConstructor, constructorDescriptor)
|
||||
}
|
||||
|
||||
val memberScope = MemberScope.Empty
|
||||
val memberScope = SimpleMemberScope(irClass.descriptor.unsubstitutedMemberScope.getContributedDescriptors().toList())
|
||||
defaultClassDescriptor.initialize(memberScope, constructors, null)
|
||||
|
||||
return defaultClass
|
||||
|
||||
@@ -36,7 +36,11 @@ task clean {
|
||||
}
|
||||
|
||||
task run() {
|
||||
dependsOn(tasks.withType(KonanTest).matching { !(it instanceof RunExternalTestGroup) && it.enabled })
|
||||
String prefix = project.findProperty("prefix")
|
||||
if (prefix != null)
|
||||
dependsOn(tasks.withType(KonanTest).matching { !(it instanceof RunExternalTestGroup) && it.enabled && it.name.startsWith(prefix) })
|
||||
else
|
||||
dependsOn(tasks.withType(KonanTest).matching { !(it instanceof RunExternalTestGroup) && it.enabled })
|
||||
}
|
||||
|
||||
task run_external () {
|
||||
@@ -362,6 +366,16 @@ task enum_companionObject(type: RunKonanTest) {
|
||||
source = "codegen/enum/companionObject.kt"
|
||||
}
|
||||
|
||||
task enum_interfaceCallNoEntryClass(type: RunKonanTest) {
|
||||
goldValue = "('z3', 3)\n('z3', 3)\n"
|
||||
source = "codegen/enum/interfaceCallNoEntryClass.kt"
|
||||
}
|
||||
|
||||
task enum_interfaceCallWithEntryClass(type: RunKonanTest) {
|
||||
goldValue = "z1z2\nz1z2\n"
|
||||
source = "codegen/enum/interfaceCallWithEntryClass.kt"
|
||||
}
|
||||
|
||||
task innerClass_simple(type: RunKonanTest) {
|
||||
goldValue = "OK\n"
|
||||
source = "codegen/innerClass/simple.kt"
|
||||
@@ -537,6 +551,41 @@ task bridges_test13(type: RunKonanTest) {
|
||||
source = "codegen/bridges/test13.kt"
|
||||
}
|
||||
|
||||
task bridges_test14(type: RunKonanTest) {
|
||||
goldValue = "42\n56\n42\n56\n56\n42\n156\n142\n"
|
||||
source = "codegen/bridges/test14.kt"
|
||||
}
|
||||
|
||||
task bridges_test15(type: RunKonanTest) {
|
||||
goldValue = "OK\n"
|
||||
source = "codegen/bridges/test15.kt"
|
||||
}
|
||||
|
||||
task bridges_test16(type: RunKonanTest) {
|
||||
goldValue = "OK\nOK\n"
|
||||
source = "codegen/bridges/test16.kt"
|
||||
}
|
||||
|
||||
task classDelegation_method(type: RunKonanTest) {
|
||||
goldValue = "OKOK\n"
|
||||
source = "codegen/classDelegation/method.kt"
|
||||
}
|
||||
|
||||
task classDelegation_property(type: RunKonanTest) {
|
||||
goldValue = "4242\n"
|
||||
source = "codegen/classDelegation/property.kt"
|
||||
}
|
||||
|
||||
task classDelegation_generic(type: RunKonanTest) {
|
||||
goldValue = "OK\n"
|
||||
source = "codegen/classDelegation/generic.kt"
|
||||
}
|
||||
|
||||
task classDelegation_withBridge(type: RunKonanTest) {
|
||||
goldValue = "OK\n"
|
||||
source = "codegen/classDelegation/withBridge.kt"
|
||||
}
|
||||
|
||||
task array0(type: RunKonanTest) {
|
||||
goldValue = "5\n6\n7\n8\n9\n10\n11\n12\n13\n"
|
||||
source = "runtime/collections/array0.kt"
|
||||
|
||||
@@ -0,0 +1,44 @@
|
||||
open class A<T, U> {
|
||||
open fun foo(x: T, y: U) {
|
||||
println(x.toString())
|
||||
println(y.toString())
|
||||
}
|
||||
}
|
||||
|
||||
interface I1<T> {
|
||||
fun foo(x: Int, y: T)
|
||||
}
|
||||
|
||||
interface I2<T> {
|
||||
fun foo(x: T, y: Int)
|
||||
}
|
||||
|
||||
class B : A<Int, Int>(), I1<Int>, I2<Int> {
|
||||
var z: Int = 5
|
||||
var q: Int = 7
|
||||
override fun foo(x: Int, y: Int) {
|
||||
z = x
|
||||
q = y
|
||||
}
|
||||
}
|
||||
|
||||
fun zzz(a: A<Int, Int>) {
|
||||
a.foo(42, 56)
|
||||
}
|
||||
|
||||
fun main(args: Array<String>) {
|
||||
val b = B()
|
||||
zzz(b)
|
||||
val a = A<Int, Int>()
|
||||
zzz(a)
|
||||
println(b.z)
|
||||
println(b.q)
|
||||
val i1: I1<Int> = b
|
||||
i1.foo(56, 42)
|
||||
println(b.z)
|
||||
println(b.q)
|
||||
val i2: I2<Int> = b
|
||||
i2.foo(156, 142)
|
||||
println(b.z)
|
||||
println(b.q)
|
||||
}
|
||||
@@ -0,0 +1,35 @@
|
||||
// non-generic interface, generic impl, vtable call + interface call
|
||||
open class A<T> {
|
||||
open var size: T = 56 as T
|
||||
}
|
||||
|
||||
interface C {
|
||||
var size: Int
|
||||
}
|
||||
|
||||
open class B : C, A<Int>()
|
||||
|
||||
open class D: B() {
|
||||
override var size: Int = 117
|
||||
}
|
||||
|
||||
fun <T> foo(a: A<T>) {
|
||||
a.size = 42 as T
|
||||
}
|
||||
|
||||
fun box(): String {
|
||||
val b = B()
|
||||
|
||||
foo(b)
|
||||
if (b.size != 42) return "fail 1"
|
||||
val d = D()
|
||||
if (d.size != 117) return "fail 2"
|
||||
foo(d)
|
||||
if (d.size != 42) return "fail 3"
|
||||
|
||||
return "OK"
|
||||
}
|
||||
|
||||
fun main(args: Array<String>) {
|
||||
println(box())
|
||||
}
|
||||
@@ -0,0 +1,20 @@
|
||||
interface A {
|
||||
fun foo(): String
|
||||
}
|
||||
|
||||
abstract class C: A
|
||||
|
||||
open class B: C() {
|
||||
override fun foo(): String {
|
||||
return "OK"
|
||||
}
|
||||
}
|
||||
|
||||
fun bar(c: C) = c.foo()
|
||||
|
||||
fun main(args: Array<String>) {
|
||||
val b = B()
|
||||
val c: C = b
|
||||
println(bar(b))
|
||||
println(bar(c))
|
||||
}
|
||||
@@ -0,0 +1,21 @@
|
||||
open class Content() {
|
||||
override fun toString() = "OK"
|
||||
}
|
||||
|
||||
interface Box<E> {
|
||||
fun get(): E
|
||||
}
|
||||
|
||||
interface ContentBox<T : Content> : Box<T>
|
||||
|
||||
object Impl : ContentBox<Content> {
|
||||
override fun get(): Content = Content()
|
||||
}
|
||||
|
||||
class ContentBoxDelegate<T : Content>() : ContentBox<T> by (Impl as ContentBox<T>)
|
||||
|
||||
fun box() = ContentBoxDelegate<Content>().get().toString()
|
||||
|
||||
fun main(args: Array<String>) {
|
||||
println(box())
|
||||
}
|
||||
@@ -0,0 +1,19 @@
|
||||
interface A<T> {
|
||||
fun foo(): T
|
||||
}
|
||||
|
||||
class B : A<String> {
|
||||
override fun foo() = "OK"
|
||||
}
|
||||
|
||||
class C(a: A<String>) : A<String> by a
|
||||
|
||||
fun box(): String {
|
||||
val c = C(B())
|
||||
val a: A<String> = c
|
||||
return c.foo() + a.foo()
|
||||
}
|
||||
|
||||
fun main(args: Array<String>) {
|
||||
println(box())
|
||||
}
|
||||
@@ -0,0 +1,19 @@
|
||||
interface A {
|
||||
val x: Int
|
||||
}
|
||||
|
||||
class C: A {
|
||||
override val x: Int = 42
|
||||
}
|
||||
|
||||
class Q(a: A): A by a
|
||||
|
||||
fun box(): String {
|
||||
val q = Q(C())
|
||||
val a: A = q
|
||||
return q.x.toString() + a.x.toString()
|
||||
}
|
||||
|
||||
fun main(args: Array<String>) {
|
||||
println(box())
|
||||
}
|
||||
@@ -0,0 +1,28 @@
|
||||
interface A<T> {
|
||||
fun foo(t: T): String
|
||||
}
|
||||
|
||||
interface B {
|
||||
fun foo(t: Int) = "B"
|
||||
}
|
||||
|
||||
class Z : B
|
||||
|
||||
class Z1 : A<Int>, B by Z()
|
||||
|
||||
fun box(): String {
|
||||
val z1 = Z1()
|
||||
val z1a: A<Int> = z1
|
||||
val z1b: B = z1
|
||||
|
||||
return when {
|
||||
z1.foo( 0) != "B" -> "Fail #1"
|
||||
z1a.foo( 0) != "B" -> "Fail #2"
|
||||
z1b.foo( 0) != "B" -> "Fail #3"
|
||||
else -> "OK"
|
||||
}
|
||||
}
|
||||
|
||||
fun main(args: Array<String>) {
|
||||
println(box())
|
||||
}
|
||||
@@ -0,0 +1,19 @@
|
||||
interface A {
|
||||
fun foo(): String
|
||||
}
|
||||
|
||||
enum class Zzz(val zzz: String, val x: Int) : A {
|
||||
Z1("z1", 1),
|
||||
Z2("z2", 2),
|
||||
Z3("z3", 3);
|
||||
|
||||
override fun foo(): String{
|
||||
return "('$zzz', $x)"
|
||||
}
|
||||
}
|
||||
|
||||
fun main(args: Array<String>) {
|
||||
println(Zzz.Z3.foo())
|
||||
val a: A = Zzz.Z3
|
||||
println(a.foo())
|
||||
}
|
||||
@@ -0,0 +1,22 @@
|
||||
interface A {
|
||||
fun f(): String
|
||||
}
|
||||
|
||||
enum class Zzz: A {
|
||||
Z1 {
|
||||
override fun f() = "z1"
|
||||
},
|
||||
|
||||
Z2 {
|
||||
override fun f() = "z2"
|
||||
};
|
||||
|
||||
override fun f() = ""
|
||||
}
|
||||
|
||||
fun main(args: Array<String>) {
|
||||
println(Zzz.Z1.f() + Zzz.Z2.f())
|
||||
val a1: A = Zzz.Z1
|
||||
val a2: A = Zzz.Z2
|
||||
println(a1.f() + a2.f())
|
||||
}
|
||||
Reference in New Issue
Block a user