From 81eef5152ea1b87eea66579119f4b122b7f1f391 Mon Sep 17 00:00:00 2001 From: Dmitriy Dolovov Date: Fri, 6 Sep 2019 19:03:21 +0700 Subject: [PATCH] [Commonizer] Type parameters, type parameter tests --- .idea/dictionaries/dmitriy_dolovov.xml | 1 + .../commonizer/builder/functionDescriptors.kt | 14 +- .../commonizer/builder/propertyDescriptors.kt | 16 +-- .../descriptors/commonizer/builder/utils.kt | 48 +++++++ ...kt => AbstractCallableMemberCommonizer.kt} | 4 +- .../commonizer/core/AbstractListCommonizer.kt | 46 +++++++ ...izer.kt => AbstractNamedListCommonizer.kt} | 16 +-- ...nizer.kt => AbstractNullableCommonizer.kt} | 2 +- .../commonizer/core/FunctionCommonizer.kt | 13 +- .../commonizer/core/PropertyCommonizer.kt | 8 +- .../core/PropertySetterCommonizer.kt | 2 +- .../commonizer/core/TypeCommonizer.kt | 31 +++-- .../core/TypeParameterCommonizer.kt | 84 +++++++++++ .../core/ValueParameterCommonizer.kt | 4 +- .../mergedtree/ir/CallableMember.kt | 3 +- .../commonizer/mergedtree/ir/Function.kt | 3 +- .../commonizer/mergedtree/ir/Property.kt | 3 +- .../commonizer/mergedtree/ir/TypeParameter.kt | 41 ++++++ .../commonizer/mergedtree/packages.kt | 14 +- .../kotlin/descriptors/commonizer/utils.kt | 27 ++++ .../commonized/common/package_root.kt | 6 + .../commonized/js/package_root.kt | 15 ++ .../commonized/jvm/package_root.kt | 15 ++ .../original/js/package_root.kt | 15 ++ .../original/jvm/package_root.kt | 15 ++ .../commonized/common/package_root.kt | 16 +++ .../returnTypes/commonized/js/package_root.kt | 26 ++++ .../commonized/jvm/package_root.kt | 26 ++++ .../returnTypes/original/js/package_root.kt | 26 ++++ .../returnTypes/original/jvm/package_root.kt | 26 ++++ .../commonized/common/package_root.kt | 5 + .../commonized/js/package_root.kt | 14 +- .../commonized/jvm/package_root.kt | 14 +- .../original/js/package_root.kt | 14 +- .../original/jvm/package_root.kt | 14 +- .../commonized/common/package_root.kt | 4 +- .../annotations/commonized/js/package_root.kt | 4 +- .../commonized/jvm/package_root.kt | 4 +- .../annotations/original/js/package_root.kt | 6 +- .../annotations/original/jvm/package_root.kt | 4 +- .../descriptors/commonizer/assertions.kt | 85 ++++++++++-- .../DefaultTypeParameterCommonizerTest.kt | 110 +++++++++++++++ .../DefaultTypeParameterListCommonizerTest.kt | 130 ++++++++++++++++++ .../DefaultValueParameterCommonizerTest.kt | 6 +- ...DefaultValueParameterListCommonizerTest.kt | 2 +- .../kotlin/descriptors/commonizer/mocks.kt | 78 +++++------ 46 files changed, 922 insertions(+), 138 deletions(-) create mode 100644 konan/commonizer/src/org/jetbrains/kotlin/descriptors/commonizer/builder/utils.kt rename konan/commonizer/src/org/jetbrains/kotlin/descriptors/commonizer/core/{CallableMemberCommonizer.kt => AbstractCallableMemberCommonizer.kt} (86%) create mode 100644 konan/commonizer/src/org/jetbrains/kotlin/descriptors/commonizer/core/AbstractListCommonizer.kt rename konan/commonizer/src/org/jetbrains/kotlin/descriptors/commonizer/core/{NamedListWrappedCommonizer.kt => AbstractNamedListCommonizer.kt} (62%) rename konan/commonizer/src/org/jetbrains/kotlin/descriptors/commonizer/core/{NullableWrappedCommonizer.kt => AbstractNullableCommonizer.kt} (95%) create mode 100644 konan/commonizer/src/org/jetbrains/kotlin/descriptors/commonizer/core/TypeParameterCommonizer.kt create mode 100644 konan/commonizer/src/org/jetbrains/kotlin/descriptors/commonizer/mergedtree/ir/TypeParameter.kt create mode 100644 konan/commonizer/tests/org/jetbrains/kotlin/descriptors/commonizer/core/DefaultTypeParameterCommonizerTest.kt create mode 100644 konan/commonizer/tests/org/jetbrains/kotlin/descriptors/commonizer/core/DefaultTypeParameterListCommonizerTest.kt diff --git a/.idea/dictionaries/dmitriy_dolovov.xml b/.idea/dictionaries/dmitriy_dolovov.xml index 526e23fd489..83f71f606da 100644 --- a/.idea/dictionaries/dmitriy_dolovov.xml +++ b/.idea/dictionaries/dmitriy_dolovov.xml @@ -5,6 +5,7 @@ commonize commonized commonizer + commonizers konan diff --git a/konan/commonizer/src/org/jetbrains/kotlin/descriptors/commonizer/builder/functionDescriptors.kt b/konan/commonizer/src/org/jetbrains/kotlin/descriptors/commonizer/builder/functionDescriptors.kt index 0fcf3856835..18b4b8efbf8 100644 --- a/konan/commonizer/src/org/jetbrains/kotlin/descriptors/commonizer/builder/functionDescriptors.kt +++ b/konan/commonizer/src/org/jetbrains/kotlin/descriptors/commonizer/builder/functionDescriptors.kt @@ -59,18 +59,10 @@ private fun Function.buildDescriptor( functionDescriptor.isExpect = isExpect functionDescriptor.isActual = isActual - val extensionReceiverDescriptor = DescriptorFactory.createExtensionReceiverParameterForCallable( - functionDescriptor, - extensionReceiver?.type, - extensionReceiver?.annotations ?: Annotations.EMPTY - ) - - val dispatchReceiverDescriptor = DescriptorUtils.getDispatchReceiverParameterIfNeeded(containingDeclaration) - functionDescriptor.initialize( - extensionReceiverDescriptor, - dispatchReceiverDescriptor, - emptyList(), // TODO: support type parameters + extensionReceiver?.buildExtensionReceiver(functionDescriptor), + buildDispatchReceiver(functionDescriptor), + typeParameters.buildDescriptors(functionDescriptor), valueParameters.buildValueParameters(functionDescriptor), returnType, modality, diff --git a/konan/commonizer/src/org/jetbrains/kotlin/descriptors/commonizer/builder/propertyDescriptors.kt b/konan/commonizer/src/org/jetbrains/kotlin/descriptors/commonizer/builder/propertyDescriptors.kt index abb09930559..ec7fe2bdc5f 100644 --- a/konan/commonizer/src/org/jetbrains/kotlin/descriptors/commonizer/builder/propertyDescriptors.kt +++ b/konan/commonizer/src/org/jetbrains/kotlin/descriptors/commonizer/builder/propertyDescriptors.kt @@ -8,7 +8,6 @@ package org.jetbrains.kotlin.descriptors.commonizer.builder import org.jetbrains.kotlin.descriptors.DeclarationDescriptor import org.jetbrains.kotlin.descriptors.PropertyDescriptor import org.jetbrains.kotlin.descriptors.SourceElement -import org.jetbrains.kotlin.descriptors.annotations.Annotations import org.jetbrains.kotlin.descriptors.commonizer.CommonizedGroup import org.jetbrains.kotlin.descriptors.commonizer.mergedtree.ir.Property import org.jetbrains.kotlin.descriptors.commonizer.mergedtree.ir.PropertyNode @@ -16,7 +15,6 @@ import org.jetbrains.kotlin.descriptors.commonizer.mergedtree.ir.indexOfCommon import org.jetbrains.kotlin.descriptors.impl.FieldDescriptorImpl import org.jetbrains.kotlin.descriptors.impl.PropertyDescriptorImpl import org.jetbrains.kotlin.resolve.DescriptorFactory -import org.jetbrains.kotlin.resolve.DescriptorUtils import org.jetbrains.kotlin.storage.StorageManager internal fun PropertyNode.buildDescriptors( @@ -60,19 +58,11 @@ private fun Property.buildDescriptor( isDelegate ) - val extensionReceiverDescriptor = DescriptorFactory.createExtensionReceiverParameterForCallable( - propertyDescriptor, - extensionReceiver?.type, - extensionReceiver?.annotations ?: Annotations.EMPTY - ) - - val dispatchReceiverDescriptor = DescriptorUtils.getDispatchReceiverParameterIfNeeded(containingDeclaration) - propertyDescriptor.setType( returnType, - emptyList(), // TODO: support type parameters - dispatchReceiverDescriptor, - extensionReceiverDescriptor + typeParameters.buildDescriptors(propertyDescriptor), + buildDispatchReceiver(propertyDescriptor), + extensionReceiver?.buildExtensionReceiver(propertyDescriptor) ) val getterDescriptor = getter?.let { getter -> diff --git a/konan/commonizer/src/org/jetbrains/kotlin/descriptors/commonizer/builder/utils.kt b/konan/commonizer/src/org/jetbrains/kotlin/descriptors/commonizer/builder/utils.kt new file mode 100644 index 00000000000..02ea97986ff --- /dev/null +++ b/konan/commonizer/src/org/jetbrains/kotlin/descriptors/commonizer/builder/utils.kt @@ -0,0 +1,48 @@ +/* + * Copyright 2010-2019 JetBrains s.r.o. and Kotlin Programming Language contributors. + * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file. + */ + +package org.jetbrains.kotlin.descriptors.commonizer.builder + +import org.jetbrains.kotlin.descriptors.CallableDescriptor +import org.jetbrains.kotlin.descriptors.DeclarationDescriptor +import org.jetbrains.kotlin.descriptors.SourceElement +import org.jetbrains.kotlin.descriptors.TypeParameterDescriptor +import org.jetbrains.kotlin.descriptors.commonizer.mergedtree.ir.ExtensionReceiver +import org.jetbrains.kotlin.descriptors.commonizer.mergedtree.ir.TypeParameter +import org.jetbrains.kotlin.descriptors.impl.TypeParameterDescriptorImpl +import org.jetbrains.kotlin.resolve.DescriptorFactory +import org.jetbrains.kotlin.resolve.DescriptorUtils + +internal fun List.buildDescriptors( + containingDeclaration: DeclarationDescriptor +): List { + return mapIndexed { index, param -> + val descriptor = TypeParameterDescriptorImpl.createForFurtherModification( + containingDeclaration, + param.annotations, + param.isReified, + param.variance, + param.name, + index, + SourceElement.NO_SOURCE + ) + + param.upperBounds.forEach(descriptor::addUpperBound) + descriptor.setInitialized() + + descriptor + } +} + +internal fun ExtensionReceiver.buildExtensionReceiver( + containingDeclaration: CallableDescriptor +) = DescriptorFactory.createExtensionReceiverParameterForCallable( + containingDeclaration, + type, + annotations +) + +internal fun buildDispatchReceiver(callableDescriptor: CallableDescriptor) = + DescriptorUtils.getDispatchReceiverParameterIfNeeded(callableDescriptor.containingDeclaration) diff --git a/konan/commonizer/src/org/jetbrains/kotlin/descriptors/commonizer/core/CallableMemberCommonizer.kt b/konan/commonizer/src/org/jetbrains/kotlin/descriptors/commonizer/core/AbstractCallableMemberCommonizer.kt similarity index 86% rename from konan/commonizer/src/org/jetbrains/kotlin/descriptors/commonizer/core/CallableMemberCommonizer.kt rename to konan/commonizer/src/org/jetbrains/kotlin/descriptors/commonizer/core/AbstractCallableMemberCommonizer.kt index 939c4bce6ec..93cafb22721 100644 --- a/konan/commonizer/src/org/jetbrains/kotlin/descriptors/commonizer/core/CallableMemberCommonizer.kt +++ b/konan/commonizer/src/org/jetbrains/kotlin/descriptors/commonizer/core/AbstractCallableMemberCommonizer.kt @@ -9,7 +9,7 @@ import org.jetbrains.kotlin.descriptors.CallableMemberDescriptor import org.jetbrains.kotlin.descriptors.commonizer.mergedtree.ir.CallableMember import org.jetbrains.kotlin.name.Name -abstract class CallableMemberCommonizer : Commonizer { +abstract class AbstractCallableMemberCommonizer : Commonizer { protected enum class State { EMPTY, ERROR, @@ -22,6 +22,7 @@ abstract class CallableMemberCommonizer( + private val subject: String, + private val singleElementCommonizerFactory: () -> Commonizer +) : Commonizer, List> { + private var commonizers: List>? = null + private var error = false + + final override val result: List + get() = commonizers?.takeIf { !error }?.map { it.result } ?: error("Can't commonize list of $subject") + + final override fun commonizeWith(next: List): Boolean { + if (error) + return false + + val commonizers = commonizers + ?: mutableListOf>().apply { + repeat(next.size) { + this += singleElementCommonizerFactory() + } + }.also { + this.commonizers = it + } + + if (commonizers.size != next.size) + error = true + else + for (index in 0 until next.size) { + val commonizer = commonizers[index] + val nextElement = next[index] + + if (!commonizer.commonizeWith(nextElement)) { + error = true + break + } + } + + return !error + } +} diff --git a/konan/commonizer/src/org/jetbrains/kotlin/descriptors/commonizer/core/NamedListWrappedCommonizer.kt b/konan/commonizer/src/org/jetbrains/kotlin/descriptors/commonizer/core/AbstractNamedListCommonizer.kt similarity index 62% rename from konan/commonizer/src/org/jetbrains/kotlin/descriptors/commonizer/core/NamedListWrappedCommonizer.kt rename to konan/commonizer/src/org/jetbrains/kotlin/descriptors/commonizer/core/AbstractNamedListCommonizer.kt index af7a99c3d0d..4dd0b5dd6f4 100644 --- a/konan/commonizer/src/org/jetbrains/kotlin/descriptors/commonizer/core/NamedListWrappedCommonizer.kt +++ b/konan/commonizer/src/org/jetbrains/kotlin/descriptors/commonizer/core/AbstractNamedListCommonizer.kt @@ -8,28 +8,28 @@ package org.jetbrains.kotlin.descriptors.commonizer.core import org.jetbrains.kotlin.descriptors.Named import org.jetbrains.kotlin.name.Name -abstract class NamedListWrappedCommonizer( +abstract class AbstractNamedListCommonizer( private val subject: String, - private val wrappedCommonizerFactory: () -> Commonizer + private val singleElementCommonizerFactory: () -> Commonizer ) : Commonizer, List> { - private var wrapped: List>>? = null + private var commonizers: List>>? = null private var error = false final override val result: List - get() = wrapped?.takeIf { !error }?.map { it.second.result } ?: error("Can't commonize list of $subject") + get() = commonizers?.takeIf { !error }?.map { it.second.result } ?: error("Can't commonize list of $subject") final override fun commonizeWith(next: List): Boolean { if (error) return false - val wrapped = wrapped - ?: next.map { it.name to wrappedCommonizerFactory() }.also { this.wrapped = it } + val commonizers = commonizers + ?: next.map { it.name to singleElementCommonizerFactory() }.also { this.commonizers = it } - if (wrapped.size != next.size) + if (commonizers.size != next.size) error = true else for (index in 0 until next.size) { - val (name, commonizer) = wrapped[index] + val (name, commonizer) = commonizers[index] val nextElement = next[index] if (name != nextElement.name || !commonizer.commonizeWith(nextElement)) { diff --git a/konan/commonizer/src/org/jetbrains/kotlin/descriptors/commonizer/core/NullableWrappedCommonizer.kt b/konan/commonizer/src/org/jetbrains/kotlin/descriptors/commonizer/core/AbstractNullableCommonizer.kt similarity index 95% rename from konan/commonizer/src/org/jetbrains/kotlin/descriptors/commonizer/core/NullableWrappedCommonizer.kt rename to konan/commonizer/src/org/jetbrains/kotlin/descriptors/commonizer/core/AbstractNullableCommonizer.kt index e0008e4a6cf..acd251b581b 100644 --- a/konan/commonizer/src/org/jetbrains/kotlin/descriptors/commonizer/core/NullableWrappedCommonizer.kt +++ b/konan/commonizer/src/org/jetbrains/kotlin/descriptors/commonizer/core/AbstractNullableCommonizer.kt @@ -5,7 +5,7 @@ package org.jetbrains.kotlin.descriptors.commonizer.core -abstract class NullableWrappedCommonizer( +abstract class AbstractNullableCommonizer( private val subject: String, private val wrappedCommonizerFactory: () -> Commonizer, private val extractor: (T) -> WT, diff --git a/konan/commonizer/src/org/jetbrains/kotlin/descriptors/commonizer/core/FunctionCommonizer.kt b/konan/commonizer/src/org/jetbrains/kotlin/descriptors/commonizer/core/FunctionCommonizer.kt index cd540a94731..88789bd5ec0 100644 --- a/konan/commonizer/src/org/jetbrains/kotlin/descriptors/commonizer/core/FunctionCommonizer.kt +++ b/konan/commonizer/src/org/jetbrains/kotlin/descriptors/commonizer/core/FunctionCommonizer.kt @@ -10,7 +10,7 @@ import org.jetbrains.kotlin.descriptors.commonizer.mergedtree.ir.CommonFunction import org.jetbrains.kotlin.descriptors.commonizer.mergedtree.ir.ExtensionReceiver.Companion.toReceiverNoAnnotations import org.jetbrains.kotlin.descriptors.commonizer.mergedtree.ir.Function -class FunctionCommonizer : CallableMemberCommonizer() { +class FunctionCommonizer : AbstractCallableMemberCommonizer() { private val modifiers = FunctionModifiersCommonizer.default() private val valueParameters = ValueParameterListCommonizer.default() @@ -24,16 +24,13 @@ class FunctionCommonizer : CallableMemberCommonizer() { +class PropertyCommonizer : AbstractCallableMemberCommonizer() { private val setter = PropertySetterCommonizer.default() private var isExternal = true @@ -24,7 +24,8 @@ class PropertyCommonizer : CallableMemberCommonizer( + AbstractNullableCommonizer( subject = "Property", wrappedCommonizerFactory = { VisibilityCommonizer.equalizing() }, extractor = { it.visibility }, diff --git a/konan/commonizer/src/org/jetbrains/kotlin/descriptors/commonizer/core/TypeCommonizer.kt b/konan/commonizer/src/org/jetbrains/kotlin/descriptors/commonizer/core/TypeCommonizer.kt index f0f702ec88a..ff34421672d 100644 --- a/konan/commonizer/src/org/jetbrains/kotlin/descriptors/commonizer/core/TypeCommonizer.kt +++ b/konan/commonizer/src/org/jetbrains/kotlin/descriptors/commonizer/core/TypeCommonizer.kt @@ -82,19 +82,26 @@ private fun areAbbreviatedTypesEqual(a: SimpleType, aExpanded: SimpleType, b: Si val aDescriptor = requireNotNull(a.constructor.declarationDescriptor, a::nonNullDescriptorExpectedErrorMessage) val bDescriptor = requireNotNull(b.constructor.declarationDescriptor, b::nonNullDescriptorExpectedErrorMessage) - val aFqName = aDescriptor.fqNameSafe - val bFqName = bDescriptor.fqNameSafe + val isUnderStandardKotlinPackages = if ( + aDescriptor is ClassifierDescriptorWithTypeParameters + && bDescriptor is ClassifierDescriptorWithTypeParameters + ) { + // N.B. only for descriptors that represent classes or type aliases, but not type parameters: - if (aFqName.isUnderStandardKotlinPackages || bFqName.isUnderStandardKotlinPackages) { - // make sure that FQ names of abbreviated types (e.g. representing type aliases) are equal - return aFqName == bFqName + val aFqName = aDescriptor.fqNameSafe + val bFqName = bDescriptor.fqNameSafe + + aFqName.isUnderStandardKotlinPackages + // make sure that FQ names of abbreviated types (e.g. representing type aliases) are equal + && aFqName == bFqName // if classes are from the standard Kotlin packages, compare them only by type constructors // effectively, this includes 1) comparison of FQ names and 2) number of type constructor parameters // see org.jetbrains.kotlin.types.AbstractClassTypeConstructor.equals() for details && aExpanded.constructor == bExpandedType.constructor - } + } else false - val descriptorsCanBeCommonized = when (aDescriptor) { + val descriptorsCanBeCommonized = isUnderStandardKotlinPackages || when (aDescriptor) { + is TypeParameterDescriptor -> (bDescriptor is TypeParameterDescriptor) && canBeCommonized(aDescriptor, bDescriptor) is TypeAliasDescriptor -> (bDescriptor is TypeAliasDescriptor) && canBeCommonized(aDescriptor, bDescriptor) is ClassDescriptor -> (bDescriptor is ClassDescriptor) && canBeCommonized(aDescriptor, bDescriptor) else -> false @@ -103,8 +110,8 @@ private fun areAbbreviatedTypesEqual(a: SimpleType, aExpanded: SimpleType, b: Si if (!descriptorsCanBeCommonized) return false - if (a.arguments === b.arguments) - return true + if (a.arguments.size != b.arguments.size) + return false for (i in 0 until a.arguments.size) { val aArg = a.arguments[i] @@ -162,6 +169,12 @@ private fun canBeCommonized(a: TypeAliasDescriptor, b: TypeAliasDescriptor): Boo return areTypesEqual(aUnderlyingType, bUnderlyingType) } +private fun canBeCommonized(a: TypeParameterDescriptor, b: TypeParameterDescriptor): Boolean { + // N.B. real type parameter commonization is performed in TypeParameterCommonizer, + // here it is enough to check FQ names + return areFqNamesEqual(a, b) +} + private fun areFqNamesEqual(d1: T, d2: T): Boolean { val p1 = d1.parentsWithSelf.iterator() val p2 = d2.parentsWithSelf.iterator() diff --git a/konan/commonizer/src/org/jetbrains/kotlin/descriptors/commonizer/core/TypeParameterCommonizer.kt b/konan/commonizer/src/org/jetbrains/kotlin/descriptors/commonizer/core/TypeParameterCommonizer.kt new file mode 100644 index 00000000000..b41125cee26 --- /dev/null +++ b/konan/commonizer/src/org/jetbrains/kotlin/descriptors/commonizer/core/TypeParameterCommonizer.kt @@ -0,0 +1,84 @@ +/* + * Copyright 2010-2019 JetBrains s.r.o. and Kotlin Programming Language contributors. + * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file. + */ + +package org.jetbrains.kotlin.descriptors.commonizer.core + +import org.jetbrains.kotlin.descriptors.TypeParameterDescriptor +import org.jetbrains.kotlin.descriptors.commonizer.mergedtree.ir.CommonTypeParameter +import org.jetbrains.kotlin.descriptors.commonizer.mergedtree.ir.TypeParameter +import org.jetbrains.kotlin.name.Name +import org.jetbrains.kotlin.types.KotlinType +import org.jetbrains.kotlin.types.UnwrappedType +import org.jetbrains.kotlin.types.Variance + +interface TypeParameterCommonizer : Commonizer { + companion object { + fun default(): TypeParameterCommonizer = DefaultTypeParameterCommonizer() + } +} + +private class DefaultTypeParameterCommonizer : TypeParameterCommonizer { + private enum class State { + EMPTY, + ERROR, + IN_PROGRESS + } + + private var state = State.EMPTY + private lateinit var name: Name + private var isReified = false + private lateinit var variance: Variance + private val upperBounds = TypeParameterUpperBoundsCommonizer() + + override val result: TypeParameter + get() = when (state) { + State.EMPTY, State.ERROR -> error("Can't commonize type parameter") + State.IN_PROGRESS -> CommonTypeParameter( + name = name, + isReified = isReified, + variance = variance, + upperBounds = upperBounds.result + ) + } + + override fun commonizeWith(next: TypeParameterDescriptor): Boolean { + state = when (state) { + State.ERROR -> State.ERROR + State.EMPTY -> { + name = next.name + isReified = next.isReified + variance = next.variance + + if (!upperBounds.commonizeWith(next.upperBounds)) State.ERROR else State.IN_PROGRESS + } + State.IN_PROGRESS -> { + if (isReified != next.isReified + || variance != next.variance + || !upperBounds.commonizeWith(next.upperBounds) + ) State.ERROR else State.IN_PROGRESS + } + } + + return state != State.ERROR + } +} + +private class TypeParameterUpperBoundsCommonizer : AbstractListCommonizer( + subject = "type parameter upper bounds", + singleElementCommonizerFactory = { TypeCommonizer.default() } +) + +interface TypeParameterListCommonizer : Commonizer, List> { + companion object { + fun default(): TypeParameterListCommonizer = DefaultTypeParameterListCommonizer() + } +} + +private class DefaultTypeParameterListCommonizer : + TypeParameterListCommonizer, + AbstractNamedListCommonizer( + subject = "type parameters", + singleElementCommonizerFactory = { TypeParameterCommonizer.default() } + ) diff --git a/konan/commonizer/src/org/jetbrains/kotlin/descriptors/commonizer/core/ValueParameterCommonizer.kt b/konan/commonizer/src/org/jetbrains/kotlin/descriptors/commonizer/core/ValueParameterCommonizer.kt index f63cc75af8b..f2d8109d7b0 100644 --- a/konan/commonizer/src/org/jetbrains/kotlin/descriptors/commonizer/core/ValueParameterCommonizer.kt +++ b/konan/commonizer/src/org/jetbrains/kotlin/descriptors/commonizer/core/ValueParameterCommonizer.kt @@ -82,7 +82,7 @@ interface ValueParameterListCommonizer : Commonizer( + AbstractNamedListCommonizer( subject = "value parameters", - wrappedCommonizerFactory = { ValueParameterCommonizer.default() } + singleElementCommonizerFactory = { ValueParameterCommonizer.default() } ) diff --git a/konan/commonizer/src/org/jetbrains/kotlin/descriptors/commonizer/mergedtree/ir/CallableMember.kt b/konan/commonizer/src/org/jetbrains/kotlin/descriptors/commonizer/mergedtree/ir/CallableMember.kt index c237becb521..836ed8f4b90 100644 --- a/konan/commonizer/src/org/jetbrains/kotlin/descriptors/commonizer/mergedtree/ir/CallableMember.kt +++ b/konan/commonizer/src/org/jetbrains/kotlin/descriptors/commonizer/mergedtree/ir/CallableMember.kt @@ -14,7 +14,7 @@ import org.jetbrains.kotlin.descriptors.commonizer.mergedtree.ir.ExtensionReceiv import org.jetbrains.kotlin.name.Name import org.jetbrains.kotlin.types.UnwrappedType -interface CallableMember { +interface CallableMember : DeclarationWithTypeParameters { val annotations: Annotations val name: Name val modality: Modality @@ -39,6 +39,7 @@ abstract class TargetCallableMember(protected val final override val extensionReceiver: ExtensionReceiver? get() = descriptor.extensionReceiverParameter?.toReceiver() final override val returnType: UnwrappedType get() = descriptor.returnType!!.unwrap() final override val kind: CallableMemberDescriptor.Kind get() = descriptor.kind + final override val typeParameters: List get() = descriptor.typeParameters.map(::TargetTypeParameter) } data class ExtensionReceiver( diff --git a/konan/commonizer/src/org/jetbrains/kotlin/descriptors/commonizer/mergedtree/ir/Function.kt b/konan/commonizer/src/org/jetbrains/kotlin/descriptors/commonizer/mergedtree/ir/Function.kt index fe184f5a0db..e3562b98267 100644 --- a/konan/commonizer/src/org/jetbrains/kotlin/descriptors/commonizer/mergedtree/ir/Function.kt +++ b/konan/commonizer/src/org/jetbrains/kotlin/descriptors/commonizer/mergedtree/ir/Function.kt @@ -33,7 +33,8 @@ data class CommonFunction( override val extensionReceiver: ExtensionReceiver?, override val returnType: UnwrappedType, private val modifiers: FunctionModifiers, - override val valueParameters: List + override val valueParameters: List, + override val typeParameters: List ) : CommonCallableMember(), Function, FunctionModifiers by modifiers class TargetFunction(descriptor: SimpleFunctionDescriptor) : TargetCallableMember(descriptor), Function { diff --git a/konan/commonizer/src/org/jetbrains/kotlin/descriptors/commonizer/mergedtree/ir/Property.kt b/konan/commonizer/src/org/jetbrains/kotlin/descriptors/commonizer/mergedtree/ir/Property.kt index ac35725258d..8e1e62e861f 100644 --- a/konan/commonizer/src/org/jetbrains/kotlin/descriptors/commonizer/mergedtree/ir/Property.kt +++ b/konan/commonizer/src/org/jetbrains/kotlin/descriptors/commonizer/mergedtree/ir/Property.kt @@ -32,7 +32,8 @@ data class CommonProperty( override val isExternal: Boolean, override val extensionReceiver: ExtensionReceiver?, override val returnType: UnwrappedType, - override val setter: Setter? + override val setter: Setter?, + override val typeParameters: List ) : CommonCallableMember(), Property { override val isVar: Boolean get() = setter != null override val lateInit: Boolean get() = false diff --git a/konan/commonizer/src/org/jetbrains/kotlin/descriptors/commonizer/mergedtree/ir/TypeParameter.kt b/konan/commonizer/src/org/jetbrains/kotlin/descriptors/commonizer/mergedtree/ir/TypeParameter.kt new file mode 100644 index 00000000000..bdab7d02701 --- /dev/null +++ b/konan/commonizer/src/org/jetbrains/kotlin/descriptors/commonizer/mergedtree/ir/TypeParameter.kt @@ -0,0 +1,41 @@ +/* + * Copyright 2010-2019 JetBrains s.r.o. and Kotlin Programming Language contributors. + * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file. + */ + +package org.jetbrains.kotlin.descriptors.commonizer.mergedtree.ir + +import org.jetbrains.kotlin.descriptors.TypeParameterDescriptor +import org.jetbrains.kotlin.descriptors.annotations.Annotations +import org.jetbrains.kotlin.name.Name +import org.jetbrains.kotlin.types.UnwrappedType +import org.jetbrains.kotlin.types.Variance + +interface TypeParameter { + val annotations: Annotations + val name: Name + val isReified: Boolean + val variance: Variance + val upperBounds: List +} + +interface DeclarationWithTypeParameters : Declaration { + val typeParameters: List +} + +data class CommonTypeParameter( + override val name: Name, + override val isReified: Boolean, + override val variance: Variance, + override val upperBounds: List +) : TypeParameter { + override val annotations: Annotations get() = Annotations.EMPTY +} + +data class TargetTypeParameter(private val descriptor: TypeParameterDescriptor) : TypeParameter { + override val annotations: Annotations get() = descriptor.annotations + override val name: Name get() = descriptor.name + override val isReified: Boolean get() = descriptor.isReified + override val variance: Variance get() = descriptor.variance + override val upperBounds: List get() = descriptor.upperBounds.map { it.unwrap() } +} diff --git a/konan/commonizer/src/org/jetbrains/kotlin/descriptors/commonizer/mergedtree/packages.kt b/konan/commonizer/src/org/jetbrains/kotlin/descriptors/commonizer/mergedtree/packages.kt index 90486ade731..0b48552d246 100644 --- a/konan/commonizer/src/org/jetbrains/kotlin/descriptors/commonizer/mergedtree/packages.kt +++ b/konan/commonizer/src/org/jetbrains/kotlin/descriptors/commonizer/mergedtree/packages.kt @@ -8,7 +8,7 @@ package org.jetbrains.kotlin.descriptors.commonizer.mergedtree import org.jetbrains.kotlin.descriptors.PropertyDescriptor import org.jetbrains.kotlin.descriptors.SimpleFunctionDescriptor import org.jetbrains.kotlin.descriptors.commonizer.CommonizedGroupMap -import org.jetbrains.kotlin.descriptors.commonizer.fqName +import org.jetbrains.kotlin.descriptors.commonizer.fqNameWithTypeParameters import org.jetbrains.kotlin.name.FqName import org.jetbrains.kotlin.name.Name import org.jetbrains.kotlin.resolve.scopes.DescriptorKindFilter @@ -49,11 +49,11 @@ internal fun mergePackages( internal data class PropertyKey( val name: Name, - val extensionReceiverParameterFqName: FqName? + val extensionReceiverParameter: String? ) { constructor(property: PropertyDescriptor) : this( property.name, - property.extensionReceiverParameter?.type?.fqName + property.extensionReceiverParameter?.type?.fqNameWithTypeParameters ) } @@ -67,13 +67,13 @@ internal fun MemberScope.collectProperties(collector: (PropertyKey, PropertyDesc internal data class FunctionKey( val name: Name, - val valueParameters: List>, - val extensionReceiverParameterFqName: FqName? + val valueParameters: List>, + val extensionReceiverParameter: String? ) { constructor(function: SimpleFunctionDescriptor) : this( function.name, - function.valueParameters.map { it.name to it.type.fqName }, - function.extensionReceiverParameter?.type?.fqName + function.valueParameters.map { it.name to it.type.fqNameWithTypeParameters }, + function.extensionReceiverParameter?.type?.fqNameWithTypeParameters ) } diff --git a/konan/commonizer/src/org/jetbrains/kotlin/descriptors/commonizer/utils.kt b/konan/commonizer/src/org/jetbrains/kotlin/descriptors/commonizer/utils.kt index 1792a57f432..9046b96f29e 100644 --- a/konan/commonizer/src/org/jetbrains/kotlin/descriptors/commonizer/utils.kt +++ b/konan/commonizer/src/org/jetbrains/kotlin/descriptors/commonizer/utils.kt @@ -8,6 +8,7 @@ package org.jetbrains.kotlin.descriptors.commonizer import org.jetbrains.kotlin.name.FqName import org.jetbrains.kotlin.resolve.descriptorUtil.fqNameSafe import org.jetbrains.kotlin.types.KotlinType +import org.jetbrains.kotlin.types.Variance import org.jetbrains.kotlin.utils.addToStdlib.firstIsInstance internal fun Sequence.toList(expectedCapacity: Int): List { @@ -21,4 +22,30 @@ internal inline fun Iterable.firstNonNull() = firstIsInstance internal val KotlinType.fqName: FqName get() = constructor.declarationDescriptor!!.fqNameSafe +internal val KotlinType.fqNameWithTypeParameters: String + get() = buildString { buildFqNameWithTypeParameters(this@fqNameWithTypeParameters) } + +private fun StringBuilder.buildFqNameWithTypeParameters(type: KotlinType) { + append(type.fqName) + + val arguments = type.arguments + if (arguments.isNotEmpty()) { + append("<") + arguments.forEachIndexed { index, argument -> + if (index > 0) + append(",") + + if (argument.isStarProjection) + append("*") + else { + val variance = argument.projectionKind + if (variance != Variance.INVARIANT) + append(variance).append(" ") + buildFqNameWithTypeParameters(argument.type) + } + } + append(">") + } +} + internal fun Any?.isNull() = this == null diff --git a/konan/commonizer/testData/callableMemberCommonization/extensionReceivers/commonized/common/package_root.kt b/konan/commonizer/testData/callableMemberCommonization/extensionReceivers/commonized/common/package_root.kt index dfb3ae8a2a8..d24c2db01d7 100644 --- a/konan/commonizer/testData/callableMemberCommonization/extensionReceivers/commonized/common/package_root.kt +++ b/konan/commonizer/testData/callableMemberCommonization/extensionReceivers/commonized/common/package_root.kt @@ -13,3 +13,9 @@ expect fun Short.intFunction(): Int expect fun Long.intFunction(): Int expect fun String.intFunction(): Int expect fun Planet.intFunction(): Int + +expect val T.propertyWithTypeParameter1: Int +expect val T.propertyWithTypeParameter2: Int +expect val T.propertyWithTypeParameter4: Int + +expect fun T.functionWithTypeParameter1() diff --git a/konan/commonizer/testData/callableMemberCommonization/extensionReceivers/commonized/js/package_root.kt b/konan/commonizer/testData/callableMemberCommonization/extensionReceivers/commonized/js/package_root.kt index c5873e4300a..67605009382 100644 --- a/konan/commonizer/testData/callableMemberCommonization/extensionReceivers/commonized/js/package_root.kt +++ b/konan/commonizer/testData/callableMemberCommonization/extensionReceivers/commonized/js/package_root.kt @@ -19,3 +19,18 @@ val mismatchedProperty2 get() = 42 fun String.mismatchedFunction1() = 42 fun mismatchedFunction2() = 42 + +actual val T.propertyWithTypeParameter1 get() = 42 +actual val T.propertyWithTypeParameter2 get() = 42 +val T.propertyWithTypeParameter3 get() = 42 +actual val T.propertyWithTypeParameter4 get() = length +val T.propertyWithTypeParameter5 get() = length +val T.propertyWithTypeParameter6 get() = length +val T.propertyWithTypeParameter7 get() = length +val T.propertyWithTypeParameter8 get() = 42 +val T.propertyWithTypeParameter9 get() = 42 + +actual fun T.functionWithTypeParameter1() {} +fun T.functionWithTypeParameter2() {} +fun T.functionWithTypeParameter3() {} +fun T.functionWithTypeParameter4() {} diff --git a/konan/commonizer/testData/callableMemberCommonization/extensionReceivers/commonized/jvm/package_root.kt b/konan/commonizer/testData/callableMemberCommonization/extensionReceivers/commonized/jvm/package_root.kt index 22ff0baf6c2..bc36bd5a764 100644 --- a/konan/commonizer/testData/callableMemberCommonization/extensionReceivers/commonized/jvm/package_root.kt +++ b/konan/commonizer/testData/callableMemberCommonization/extensionReceivers/commonized/jvm/package_root.kt @@ -19,3 +19,18 @@ val Double.mismatchedProperty2 get() = 42 fun mismatchedFunction1() = 42 fun Double.mismatchedFunction2() = 42 + +actual val T.propertyWithTypeParameter1 get() = 42 +actual val T.propertyWithTypeParameter2 get() = 42 +val T.propertyWithTypeParameter3 get() = 42 +actual val T.propertyWithTypeParameter4 get() = length +val T.propertyWithTypeParameter5 get() = length +val T.propertyWithTypeParameter6 get() = length +val String.propertyWithTypeParameter7 get() = length +val Q.propertyWithTypeParameter8 get() = 42 +val T.propertyWithTypeParameter9 get() = 42 + +actual fun T.functionWithTypeParameter1() {} +fun Q.functionWithTypeParameter2() {} +fun T.functionWithTypeParameter3() {} +fun Q.functionWithTypeParameter4() {} diff --git a/konan/commonizer/testData/callableMemberCommonization/extensionReceivers/original/js/package_root.kt b/konan/commonizer/testData/callableMemberCommonization/extensionReceivers/original/js/package_root.kt index 7cab8a200ea..2cf7c3b4436 100644 --- a/konan/commonizer/testData/callableMemberCommonization/extensionReceivers/original/js/package_root.kt +++ b/konan/commonizer/testData/callableMemberCommonization/extensionReceivers/original/js/package_root.kt @@ -19,3 +19,18 @@ val mismatchedProperty2 get() = 42 fun String.mismatchedFunction1() = 42 fun mismatchedFunction2() = 42 + +val T.propertyWithTypeParameter1 get() = 42 +val T.propertyWithTypeParameter2 get() = 42 +val T.propertyWithTypeParameter3 get() = 42 +val T.propertyWithTypeParameter4 get() = length +val T.propertyWithTypeParameter5 get() = length +val T.propertyWithTypeParameter6 get() = length +val T.propertyWithTypeParameter7 get() = length +val T.propertyWithTypeParameter8 get() = 42 +val T.propertyWithTypeParameter9 get() = 42 + +fun T.functionWithTypeParameter1() {} +fun T.functionWithTypeParameter2() {} +fun T.functionWithTypeParameter3() {} +fun T.functionWithTypeParameter4() {} diff --git a/konan/commonizer/testData/callableMemberCommonization/extensionReceivers/original/jvm/package_root.kt b/konan/commonizer/testData/callableMemberCommonization/extensionReceivers/original/jvm/package_root.kt index daa1c272269..df3ce507794 100644 --- a/konan/commonizer/testData/callableMemberCommonization/extensionReceivers/original/jvm/package_root.kt +++ b/konan/commonizer/testData/callableMemberCommonization/extensionReceivers/original/jvm/package_root.kt @@ -19,3 +19,18 @@ val Double.mismatchedProperty2 get() = 42 fun mismatchedFunction1() = 42 fun Double.mismatchedFunction2() = 42 + +val T.propertyWithTypeParameter1 get() = 42 +val T.propertyWithTypeParameter2 get() = 42 +val T.propertyWithTypeParameter3 get() = 42 +val T.propertyWithTypeParameter4 get() = length +val T.propertyWithTypeParameter5 get() = length +val T.propertyWithTypeParameter6 get() = length +val String.propertyWithTypeParameter7 get() = length +val Q.propertyWithTypeParameter8 get() = 42 +val T.propertyWithTypeParameter9 get() = 42 + +fun T.functionWithTypeParameter1() {} +fun Q.functionWithTypeParameter2() {} +fun T.functionWithTypeParameter3() {} +fun Q.functionWithTypeParameter4() {} diff --git a/konan/commonizer/testData/callableMemberCommonization/returnTypes/commonized/common/package_root.kt b/konan/commonizer/testData/callableMemberCommonization/returnTypes/commonized/common/package_root.kt index 1d0cae72063..a21faee290c 100644 --- a/konan/commonizer/testData/callableMemberCommonization/returnTypes/commonized/common/package_root.kt +++ b/konan/commonizer/testData/callableMemberCommonization/returnTypes/commonized/common/package_root.kt @@ -19,3 +19,19 @@ expect fun function2(): String expect fun function3(): Planet expect fun function6(): Planet expect fun function7(): C + +class Box(val value: T) +class Fox + +expect fun functionWithTypeParametersInReturnType1(): Array +expect fun functionWithTypeParametersInReturnType3(): Array +expect fun functionWithTypeParametersInReturnType4(): List +expect fun functionWithTypeParametersInReturnType6(): List +expect fun functionWithTypeParametersInReturnType7(): Box +expect fun functionWithTypeParametersInReturnType9(): Box +expect fun functionWithTypeParametersInReturnType10(): Box +expect fun functionWithTypeParametersInReturnType12(): Box + +expect fun functionWithUnsubstitutedTypeParametersInReturnType1(): T +expect fun functionWithUnsubstitutedTypeParametersInReturnType2(): T +expect fun functionWithUnsubstitutedTypeParametersInReturnType8(): Box diff --git a/konan/commonizer/testData/callableMemberCommonization/returnTypes/commonized/js/package_root.kt b/konan/commonizer/testData/callableMemberCommonization/returnTypes/commonized/js/package_root.kt index a9e3e496f0c..dbfd9e282c7 100644 --- a/konan/commonizer/testData/callableMemberCommonization/returnTypes/commonized/js/package_root.kt +++ b/konan/commonizer/testData/callableMemberCommonization/returnTypes/commonized/js/package_root.kt @@ -36,3 +36,29 @@ fun functionWithMismatchedType2(): Int = 1 fun functionWithMismatchedType3(): Int = 1 fun functionWithMismatchedType4(): Int = 1 fun functionWithMismatchedType5(): Int = 1 + +class Box(val value: T) +class Fox + +actual fun functionWithTypeParametersInReturnType1() = arrayOf(1) +fun functionWithTypeParametersInReturnType2() = arrayOf(1) +actual fun functionWithTypeParametersInReturnType3() = arrayOf("hello") +actual fun functionWithTypeParametersInReturnType4(): List = listOf(1) +fun functionWithTypeParametersInReturnType5(): List = listOf(1) +actual fun functionWithTypeParametersInReturnType6(): List = listOf("hello") +actual fun functionWithTypeParametersInReturnType7() = Box(1) +fun functionWithTypeParametersInReturnType8() = Box(1) +actual fun functionWithTypeParametersInReturnType9() = Box("hello") +actual fun functionWithTypeParametersInReturnType10() = Box(Planet("Earth", 12742)) +fun functionWithTypeParametersInReturnType11() = Box(Planet("Earth", 12742)) +actual fun functionWithTypeParametersInReturnType12() = Box(Fox()) + +actual fun functionWithUnsubstitutedTypeParametersInReturnType1(): T = TODO() +actual fun functionWithUnsubstitutedTypeParametersInReturnType2(): T = TODO() +fun functionWithUnsubstitutedTypeParametersInReturnType3(): T = TODO() +fun functionWithUnsubstitutedTypeParametersInReturnType4(): T = TODO() +fun functionWithUnsubstitutedTypeParametersInReturnType5(): T = TODO() +fun functionWithUnsubstitutedTypeParametersInReturnType6(): T = TODO() +fun functionWithUnsubstitutedTypeParametersInReturnType7(): T = TODO() +actual fun functionWithUnsubstitutedTypeParametersInReturnType8(): Box = TODO() +fun functionWithUnsubstitutedTypeParametersInReturnType9(): Box = TODO() diff --git a/konan/commonizer/testData/callableMemberCommonization/returnTypes/commonized/jvm/package_root.kt b/konan/commonizer/testData/callableMemberCommonization/returnTypes/commonized/jvm/package_root.kt index 378a1be17ee..4dd157e6412 100644 --- a/konan/commonizer/testData/callableMemberCommonization/returnTypes/commonized/jvm/package_root.kt +++ b/konan/commonizer/testData/callableMemberCommonization/returnTypes/commonized/jvm/package_root.kt @@ -36,3 +36,29 @@ fun functionWithMismatchedType2(): Short = 1 fun functionWithMismatchedType3(): Number = 1 fun functionWithMismatchedType4(): Comparable = 1 fun functionWithMismatchedType5(): String = 1.toString() + +class Box(val value: T) +class Fox + +actual fun functionWithTypeParametersInReturnType1() = arrayOf(1) +fun functionWithTypeParametersInReturnType2() = arrayOf("hello") +actual fun functionWithTypeParametersInReturnType3() = arrayOf("hello") +actual fun functionWithTypeParametersInReturnType4(): List = listOf(1) +fun functionWithTypeParametersInReturnType5(): List = listOf("hello") +actual fun functionWithTypeParametersInReturnType6(): List = listOf("hello") +actual fun functionWithTypeParametersInReturnType7() = Box(1) +fun functionWithTypeParametersInReturnType8() = Box("hello") +actual fun functionWithTypeParametersInReturnType9() = Box("hello") +actual fun functionWithTypeParametersInReturnType10() = Box(Planet("Earth", 12742)) +fun functionWithTypeParametersInReturnType11() = Box(Fox()) +actual fun functionWithTypeParametersInReturnType12() = Box(Fox()) + +actual fun functionWithUnsubstitutedTypeParametersInReturnType1(): T = TODO() +actual fun functionWithUnsubstitutedTypeParametersInReturnType2(): T = TODO() +fun functionWithUnsubstitutedTypeParametersInReturnType3(): T = TODO() +fun functionWithUnsubstitutedTypeParametersInReturnType4(): Q = TODO() +fun functionWithUnsubstitutedTypeParametersInReturnType5(): T = TODO() +fun functionWithUnsubstitutedTypeParametersInReturnType6(): Q = TODO() +fun functionWithUnsubstitutedTypeParametersInReturnType7(): String = TODO() +actual fun functionWithUnsubstitutedTypeParametersInReturnType8(): Box = TODO() +fun functionWithUnsubstitutedTypeParametersInReturnType9(): Box = TODO() diff --git a/konan/commonizer/testData/callableMemberCommonization/returnTypes/original/js/package_root.kt b/konan/commonizer/testData/callableMemberCommonization/returnTypes/original/js/package_root.kt index f7680053299..1d8883f6b4c 100644 --- a/konan/commonizer/testData/callableMemberCommonization/returnTypes/original/js/package_root.kt +++ b/konan/commonizer/testData/callableMemberCommonization/returnTypes/original/js/package_root.kt @@ -38,3 +38,29 @@ fun functionWithMismatchedType2(): Int = 1 fun functionWithMismatchedType3(): Int = 1 fun functionWithMismatchedType4(): Int = 1 fun functionWithMismatchedType5(): Int = 1 + +class Box(val value: T) +class Fox + +fun functionWithTypeParametersInReturnType1() = arrayOf(1) +fun functionWithTypeParametersInReturnType2() = arrayOf(1) +fun functionWithTypeParametersInReturnType3() = arrayOf("hello") +fun functionWithTypeParametersInReturnType4(): List = listOf(1) +fun functionWithTypeParametersInReturnType5(): List = listOf(1) +fun functionWithTypeParametersInReturnType6(): List = listOf("hello") +fun functionWithTypeParametersInReturnType7() = Box(1) +fun functionWithTypeParametersInReturnType8() = Box(1) +fun functionWithTypeParametersInReturnType9() = Box("hello") +fun functionWithTypeParametersInReturnType10() = Box(Planet("Earth", 12742)) +fun functionWithTypeParametersInReturnType11() = Box(Planet("Earth", 12742)) +fun functionWithTypeParametersInReturnType12() = Box(Fox()) + +fun functionWithUnsubstitutedTypeParametersInReturnType1(): T = TODO() +fun functionWithUnsubstitutedTypeParametersInReturnType2(): T = TODO() +fun functionWithUnsubstitutedTypeParametersInReturnType3(): T = TODO() +fun functionWithUnsubstitutedTypeParametersInReturnType4(): T = TODO() +fun functionWithUnsubstitutedTypeParametersInReturnType5(): T = TODO() +fun functionWithUnsubstitutedTypeParametersInReturnType6(): T = TODO() +fun functionWithUnsubstitutedTypeParametersInReturnType7(): T = TODO() +fun functionWithUnsubstitutedTypeParametersInReturnType8(): Box = TODO() +fun functionWithUnsubstitutedTypeParametersInReturnType9(): Box = TODO() diff --git a/konan/commonizer/testData/callableMemberCommonization/returnTypes/original/jvm/package_root.kt b/konan/commonizer/testData/callableMemberCommonization/returnTypes/original/jvm/package_root.kt index 31ebb440109..820bab8f1fb 100644 --- a/konan/commonizer/testData/callableMemberCommonization/returnTypes/original/jvm/package_root.kt +++ b/konan/commonizer/testData/callableMemberCommonization/returnTypes/original/jvm/package_root.kt @@ -38,3 +38,29 @@ fun functionWithMismatchedType2(): Short = 1 fun functionWithMismatchedType3(): Number = 1 fun functionWithMismatchedType4(): Comparable = 1 fun functionWithMismatchedType5(): String = 1.toString() + +class Box(val value: T) +class Fox + +fun functionWithTypeParametersInReturnType1() = arrayOf(1) +fun functionWithTypeParametersInReturnType2() = arrayOf("hello") +fun functionWithTypeParametersInReturnType3() = arrayOf("hello") +fun functionWithTypeParametersInReturnType4(): List = listOf(1) +fun functionWithTypeParametersInReturnType5(): List = listOf("hello") +fun functionWithTypeParametersInReturnType6(): List = listOf("hello") +fun functionWithTypeParametersInReturnType7() = Box(1) +fun functionWithTypeParametersInReturnType8() = Box("hello") +fun functionWithTypeParametersInReturnType9() = Box("hello") +fun functionWithTypeParametersInReturnType10() = Box(Planet("Earth", 12742)) +fun functionWithTypeParametersInReturnType11() = Box(Fox()) +fun functionWithTypeParametersInReturnType12() = Box(Fox()) + +fun functionWithUnsubstitutedTypeParametersInReturnType1(): T = TODO() +fun functionWithUnsubstitutedTypeParametersInReturnType2(): T = TODO() +fun functionWithUnsubstitutedTypeParametersInReturnType3(): T = TODO() +fun functionWithUnsubstitutedTypeParametersInReturnType4(): Q = TODO() +fun functionWithUnsubstitutedTypeParametersInReturnType5(): T = TODO() +fun functionWithUnsubstitutedTypeParametersInReturnType6(): Q = TODO() +fun functionWithUnsubstitutedTypeParametersInReturnType7(): String = TODO() +fun functionWithUnsubstitutedTypeParametersInReturnType8(): Box = TODO() +fun functionWithUnsubstitutedTypeParametersInReturnType9(): Box = TODO() diff --git a/konan/commonizer/testData/functionCommonization/valueParameters/commonized/common/package_root.kt b/konan/commonizer/testData/functionCommonization/valueParameters/commonized/common/package_root.kt index 206bebb7cf3..9309949a571 100644 --- a/konan/commonizer/testData/functionCommonization/valueParameters/commonized/common/package_root.kt +++ b/konan/commonizer/testData/functionCommonization/valueParameters/commonized/common/package_root.kt @@ -11,3 +11,8 @@ expect inline fun inlineFunction5(noinline lazyMessage: () -> String) expect fun functionWithVararg1(vararg numbers: Int) expect fun functionWithVararg5(numbers: Array) +expect fun functionWithVararg6(vararg names: String) +expect fun functionWithVararg10(names: Array) + +expect fun functionWithTypeParameters1(p1: T, p2: String) +expect fun functionWithTypeParameters4(p1: Q, p2: R) diff --git a/konan/commonizer/testData/functionCommonization/valueParameters/commonized/js/package_root.kt b/konan/commonizer/testData/functionCommonization/valueParameters/commonized/js/package_root.kt index 8ea15f08a7a..d943a6fd75a 100644 --- a/konan/commonizer/testData/functionCommonization/valueParameters/commonized/js/package_root.kt +++ b/konan/commonizer/testData/functionCommonization/valueParameters/commonized/js/package_root.kt @@ -24,5 +24,17 @@ actual inline fun inlineFunction5(noinline lazyMessage: () -> String) {} actual fun functionWithVararg1(vararg numbers: Int) {} fun functionWithVararg2(vararg numbers: Int) {} fun functionWithVararg3(vararg numbers: Int) {} -//fun functionWithVararg4(numbers: Array) {} +fun functionWithVararg4(numbers: Array) {} actual fun functionWithVararg5(numbers: Array) {} +actual fun functionWithVararg6(vararg names: String) {} +fun functionWithVararg7(vararg names: String) {} +fun functionWithVararg8(vararg names: String) {} +fun functionWithVararg9(names: Array) {} +actual fun functionWithVararg10(names: Array) {} + +actual fun functionWithTypeParameters1(p1: T, p2: String) {} +fun functionWithTypeParameters2(p1: T, p2: String) {} +fun functionWithTypeParameters3(p1: T, p2: String) {} +actual fun functionWithTypeParameters4(p1: Q, p2: R) {} +fun functionWithTypeParameters5(p1: Q, p2: R) {} +fun functionWithTypeParameters6(p1: Q, p2: R) {} diff --git a/konan/commonizer/testData/functionCommonization/valueParameters/commonized/jvm/package_root.kt b/konan/commonizer/testData/functionCommonization/valueParameters/commonized/jvm/package_root.kt index b96b4ef91ce..2c23a79c97d 100644 --- a/konan/commonizer/testData/functionCommonization/valueParameters/commonized/jvm/package_root.kt +++ b/konan/commonizer/testData/functionCommonization/valueParameters/commonized/jvm/package_root.kt @@ -24,5 +24,17 @@ actual inline fun inlineFunction5(noinline lazyMessage: () -> String) {} actual fun functionWithVararg1(vararg numbers: Int) {} fun functionWithVararg2(numbers: Array) {} fun functionWithVararg3(numbers: Array) {} -//fun functionWithVararg4(numbers: Array) {} +fun functionWithVararg4(numbers: Array) {} actual fun functionWithVararg5(numbers: Array) {} +actual fun functionWithVararg6(vararg names: String) {} +fun functionWithVararg7(names: Array) {} +fun functionWithVararg8(names: Array) {} +fun functionWithVararg9(names: Array) {} +actual fun functionWithVararg10(names: Array) {} + +actual fun functionWithTypeParameters1(p1: T, p2: String) {} +fun functionWithTypeParameters2(p1: String, p2: String) {} +fun functionWithTypeParameters2(p1: String, p2: T) {} +actual fun functionWithTypeParameters4(p1: Q, p2: R) {} +fun functionWithTypeParameters5(p1: Q, p2: R) {} +fun functionWithTypeParameters6(p1: R, p2: Q) {} diff --git a/konan/commonizer/testData/functionCommonization/valueParameters/original/js/package_root.kt b/konan/commonizer/testData/functionCommonization/valueParameters/original/js/package_root.kt index 13e6c537b73..bde3e547660 100644 --- a/konan/commonizer/testData/functionCommonization/valueParameters/original/js/package_root.kt +++ b/konan/commonizer/testData/functionCommonization/valueParameters/original/js/package_root.kt @@ -24,5 +24,17 @@ inline fun inlineFunction5(noinline lazyMessage: () -> String) {} fun functionWithVararg1(vararg numbers: Int) {} fun functionWithVararg2(vararg numbers: Int) {} fun functionWithVararg3(vararg numbers: Int) {} -//fun functionWithVararg4(numbers: Array) {} +fun functionWithVararg4(numbers: Array) {} fun functionWithVararg5(numbers: Array) {} +fun functionWithVararg6(vararg names: String) {} +fun functionWithVararg7(vararg names: String) {} +fun functionWithVararg8(vararg names: String) {} +fun functionWithVararg9(names: Array) {} +fun functionWithVararg10(names: Array) {} + +fun functionWithTypeParameters1(p1: T, p2: String) {} +fun functionWithTypeParameters2(p1: T, p2: String) {} +fun functionWithTypeParameters3(p1: T, p2: String) {} +fun functionWithTypeParameters4(p1: Q, p2: R) {} +fun functionWithTypeParameters5(p1: Q, p2: R) {} +fun functionWithTypeParameters6(p1: Q, p2: R) {} diff --git a/konan/commonizer/testData/functionCommonization/valueParameters/original/jvm/package_root.kt b/konan/commonizer/testData/functionCommonization/valueParameters/original/jvm/package_root.kt index f6ac65c9287..e358bb08b0a 100644 --- a/konan/commonizer/testData/functionCommonization/valueParameters/original/jvm/package_root.kt +++ b/konan/commonizer/testData/functionCommonization/valueParameters/original/jvm/package_root.kt @@ -24,5 +24,17 @@ inline fun inlineFunction5(noinline lazyMessage: () -> String) {} fun functionWithVararg1(vararg numbers: Int) {} fun functionWithVararg2(numbers: Array) {} fun functionWithVararg3(numbers: Array) {} -//fun functionWithVararg4(numbers: Array) {} +fun functionWithVararg4(numbers: Array) {} fun functionWithVararg5(numbers: Array) {} +fun functionWithVararg6(vararg names: String) {} +fun functionWithVararg7(names: Array) {} +fun functionWithVararg8(names: Array) {} +fun functionWithVararg9(names: Array) {} +fun functionWithVararg10(names: Array) {} + +fun functionWithTypeParameters1(p1: T, p2: String) {} +fun functionWithTypeParameters2(p1: String, p2: String) {} +fun functionWithTypeParameters2(p1: String, p2: T) {} +fun functionWithTypeParameters4(p1: Q, p2: R) {} +fun functionWithTypeParameters5(p1: Q, p2: R) {} +fun functionWithTypeParameters6(p1: R, p2: Q) {} diff --git a/konan/commonizer/testData/generalCommonization/annotations/commonized/common/package_root.kt b/konan/commonizer/testData/generalCommonization/annotations/commonized/common/package_root.kt index 5a1759bfba7..9a686afc15a 100644 --- a/konan/commonizer/testData/generalCommonization/annotations/commonized/common/package_root.kt +++ b/konan/commonizer/testData/generalCommonization/annotations/commonized/common/package_root.kt @@ -1,7 +1,7 @@ expect var propertyWithoutBackingField: Double expect val propertyWithBackingField: Double expect val propertyWithDelegateField: Int -expect val String.propertyWithExtensionReceiver: Int +expect val T.propertyWithExtensionReceiver: Int expect fun function1(text: String): String -expect fun String.function2(): String +expect fun Q.function2(): Q diff --git a/konan/commonizer/testData/generalCommonization/annotations/commonized/js/package_root.kt b/konan/commonizer/testData/generalCommonization/annotations/commonized/js/package_root.kt index d505eede886..d35a86d583d 100644 --- a/konan/commonizer/testData/generalCommonization/annotations/commonized/js/package_root.kt +++ b/konan/commonizer/testData/generalCommonization/annotations/commonized/js/package_root.kt @@ -17,11 +17,11 @@ actual val propertyWithBackingField = 3.14 @delegate:Foo("field") actual val propertyWithDelegateField: Int by lazy { 42 } -actual val @receiver:Foo("receiver") String.propertyWithExtensionReceiver: Int +actual val <@Foo("type-parameter") T : CharSequence> @receiver:Foo("receiver") T.propertyWithExtensionReceiver: Int get() = length @Foo("function") actual fun function1(@Foo("parameter") text: String) = text @Foo("function") -actual fun @receiver:Foo("receiver") String.function2() = this +actual fun <@Foo("type-parameter") Q : Number> @receiver:Foo("receiver") Q.function2() = this diff --git a/konan/commonizer/testData/generalCommonization/annotations/commonized/jvm/package_root.kt b/konan/commonizer/testData/generalCommonization/annotations/commonized/jvm/package_root.kt index 7f422677aad..ddd2d2717a9 100644 --- a/konan/commonizer/testData/generalCommonization/annotations/commonized/jvm/package_root.kt +++ b/konan/commonizer/testData/generalCommonization/annotations/commonized/jvm/package_root.kt @@ -14,11 +14,11 @@ actual val propertyWithBackingField = 3.14 @delegate:Bar("field") actual val propertyWithDelegateField: Int by lazy { 42 } -actual val @receiver:Bar("receiver") String.propertyWithExtensionReceiver: Int +actual val <@Bar("type-parameter") T : CharSequence> @receiver:Bar("receiver") T.propertyWithExtensionReceiver: Int get() = length @Bar("function") actual fun function1(@Bar("parameter") text: String) = text @Bar("function") -actual fun @receiver:Foo("receiver") String.function2() = this +actual fun <@Bar("type-parameter") Q : Number> @receiver:Bar("receiver") Q.function2() = this diff --git a/konan/commonizer/testData/generalCommonization/annotations/original/js/package_root.kt b/konan/commonizer/testData/generalCommonization/annotations/original/js/package_root.kt index 48a4756e78a..fedae0e5d6e 100644 --- a/konan/commonizer/testData/generalCommonization/annotations/original/js/package_root.kt +++ b/konan/commonizer/testData/generalCommonization/annotations/original/js/package_root.kt @@ -1,6 +1,6 @@ import kotlin.annotation.AnnotationTarget.* -@Target(PROPERTY, PROPERTY_GETTER, PROPERTY_SETTER, FIELD, VALUE_PARAMETER, FUNCTION) +@Target(PROPERTY, PROPERTY_GETTER, PROPERTY_SETTER, FIELD, VALUE_PARAMETER, TYPE_PARAMETER, FUNCTION) annotation class Foo(val text: String) @Foo("property") @@ -14,11 +14,11 @@ val propertyWithBackingField = 3.14 @delegate:Foo("field") val propertyWithDelegateField: Int by lazy { 42 } -val @receiver:Foo("receiver") String.propertyWithExtensionReceiver: Int +val <@Foo("type-parameter") T : CharSequence> @receiver:Foo("receiver") T.propertyWithExtensionReceiver: Int get() = length @Foo("function") fun function1(@Foo("parameter") text: String) = text @Foo("function") -fun @receiver:Foo("receiver") String.function2() = this +fun <@Foo("type-parameter") Q : Number> @receiver:Foo("receiver") Q.function2() = this diff --git a/konan/commonizer/testData/generalCommonization/annotations/original/jvm/package_root.kt b/konan/commonizer/testData/generalCommonization/annotations/original/jvm/package_root.kt index c0668feb872..12f9416217d 100644 --- a/konan/commonizer/testData/generalCommonization/annotations/original/jvm/package_root.kt +++ b/konan/commonizer/testData/generalCommonization/annotations/original/jvm/package_root.kt @@ -14,11 +14,11 @@ val propertyWithBackingField = 3.14 @delegate:Bar("field") val propertyWithDelegateField: Int by lazy { 42 } -val @receiver:Bar("receiver") String.propertyWithExtensionReceiver: Int +val <@Bar("type-parameter") T : CharSequence> @receiver:Bar("receiver") T.propertyWithExtensionReceiver: Int get() = length @Bar("function") fun function1(@Bar("parameter") text: String) = text @Bar("function") -fun @receiver:Foo("receiver") String.function2() = this +fun <@Bar("type-parameter") Q : Number> @receiver:Bar("receiver") Q.function2() = this diff --git a/konan/commonizer/tests/org/jetbrains/kotlin/descriptors/commonizer/assertions.kt b/konan/commonizer/tests/org/jetbrains/kotlin/descriptors/commonizer/assertions.kt index dc33134bc1d..e4ad46dd6f6 100644 --- a/konan/commonizer/tests/org/jetbrains/kotlin/descriptors/commonizer/assertions.kt +++ b/konan/commonizer/tests/org/jetbrains/kotlin/descriptors/commonizer/assertions.kt @@ -67,7 +67,7 @@ private class ComparingDeclarationsVisitor( override fun visitModuleDeclaration(expected: ModuleDescriptor, context: Context) { val actual = context.getActualAs() - context.assertEquals(expected.name, actual.name, "module names") + context.assertFieldsEqual(expected::getName, actual::getName) fun collectPackageMemberScopes(module: ModuleDescriptor): Map = mutableMapOf().also { module.collectNonEmptyPackageMemberScopes { packageFqName, memberScope -> @@ -79,7 +79,7 @@ private class ComparingDeclarationsVisitor( val expectedPackageMemberScopes = collectPackageMemberScopes(expected) val actualPackageMemberScopes = collectPackageMemberScopes(actual) - context.assertEquals(expectedPackageMemberScopes.keys, actualPackageMemberScopes.keys, "sets of packages") + context.assertSetsEqual(expectedPackageMemberScopes.keys, actualPackageMemberScopes.keys, "sets of packages") for (packageFqName in expectedPackageMemberScopes.keys) { val expectedMemberScope = expectedPackageMemberScopes.getValue(packageFqName) @@ -100,7 +100,7 @@ private class ComparingDeclarationsVisitor( val expectedProperties = collectProperties(expected) val actualProperties = collectProperties(actual) - context.assertEquals(expectedProperties.keys, actualProperties.keys, "sets of properties") + context.assertSetsEqual(expectedProperties.keys, actualProperties.keys, "sets of properties") expectedProperties.forEach { (propertyKey, expectedProperty) -> val actualProperty = actualProperties.getValue(propertyKey) @@ -117,7 +117,7 @@ private class ComparingDeclarationsVisitor( val expectedFunctions = collectFunctions(expected) val actualFunctions = collectFunctions(actual) - context.assertEquals(expectedFunctions.keys, actualFunctions.keys, "sets of functions") + context.assertSetsEqual(expectedFunctions.keys, actualFunctions.keys, "sets of functions") expectedFunctions.forEach { (functionKey, expectedFunction) -> val actualFunction = actualFunctions.getValue(functionKey) @@ -153,6 +153,8 @@ private class ComparingDeclarationsVisitor( visitReceiverParameterDescriptor(expected.extensionReceiverParameter, context.nextLevel(actual.extensionReceiverParameter)) visitReceiverParameterDescriptor(expected.dispatchReceiverParameter, context.nextLevel(actual.dispatchReceiverParameter)) + + visitTypeParameters(expected.typeParameters, actual.typeParameters, context.nextLevel("Function type parameters")) } fun visitValueParameterDescriptorList( @@ -172,17 +174,43 @@ private class ComparingDeclarationsVisitor( val actual = context.getActualAs() visitAnnotations(expected.annotations, actual.annotations, context.nextLevel("Value parameter annotations")) - context.assertEquals(expected.name, actual.name, "Name") - context.assertEquals(expected.index, actual.index, "Index") - context.assertEquals(expected.declaresDefaultValue(), actual.declaresDefaultValue(), "Declares default value") - context.assertEquals(expected.isCrossinline, actual.isCrossinline, "Crossinline") - context.assertEquals(expected.isNoinline, actual.isNoinline, "Noinline") + context.assertFieldsEqual(expected::getName, actual::getName) + context.assertFieldsEqual(expected::index, actual::index) + context.assertFieldsEqual(expected::declaresDefaultValue, actual::declaresDefaultValue) + context.assertFieldsEqual(expected::isCrossinline, actual::isCrossinline) + context.assertFieldsEqual(expected::isNoinline, actual::isNoinline) visitType(expected.type, actual.type, context.nextLevel("Value parameter type")) visitType(expected.varargElementType, actual.varargElementType, context.nextLevel("Value parameter vararg element type")) } + private fun visitTypeParameters(expected: List, actual: List, context: Context) { + context.assertEquals(expected.size, actual.size, "Type parameters list size") + + expected.forEachIndexed { index, expectedParam -> + val actualParam = actual[index] + visitTypeParameterDescriptor(expectedParam, context.nextLevel(actualParam)) + } + } + override fun visitTypeParameterDescriptor(expected: TypeParameterDescriptor, context: Context) { - TODO("not implemented") + val actual = context.getActualAs() + + visitAnnotations(expected.annotations, actual.annotations, context.nextLevel("Type parameter annotations")) + context.assertFieldsEqual(expected::getName, actual::getName) + context.assertFieldsEqual(expected::getIndex, actual::getIndex) + context.assertFieldsEqual(expected::isCapturedFromOuterDeclaration, actual::isCapturedFromOuterDeclaration) + context.assertFieldsEqual(expected::isReified, actual::isReified) + context.assertFieldsEqual(expected::getVariance, actual::getVariance) + + val expectedUpperBounds = expected.upperBounds + val actualUpperBounds = actual.upperBounds + + context.assertEquals(expectedUpperBounds.size, actualUpperBounds.size, "Size of upper bound types") + + expectedUpperBounds.forEachIndexed { index, expectedType -> + val actualType = actualUpperBounds[index] + visitType(expectedType, actualType, context.nextLevel("Type parameter type")) + } } override fun visitClassDescriptor(expected: ClassDescriptor, context: Context) { @@ -231,6 +259,8 @@ private class ComparingDeclarationsVisitor( visitReceiverParameterDescriptor(expected.extensionReceiverParameter, context.nextLevel(actual.extensionReceiverParameter)) visitReceiverParameterDescriptor(expected.dispatchReceiverParameter, context.nextLevel(actual.dispatchReceiverParameter)) + + visitTypeParameters(expected.typeParameters, actual.typeParameters, context.nextLevel("Property type parameters")) } override fun visitPropertyGetterDescriptor(expected: PropertyGetterDescriptor?, context: Context) { @@ -280,7 +310,7 @@ private class ComparingDeclarationsVisitor( val expectedAnnotationFqNames = (expected ?: Annotations.EMPTY).map { it.fqName }.toSet() val actualAnnotationFqNames = (actual ?: Annotations.EMPTY).map { it.fqName }.toSet() - context.assertEquals(expectedAnnotationFqNames, actualAnnotationFqNames, "annotations") + context.assertSetsEqual(expectedAnnotationFqNames, actualAnnotationFqNames, "annotations") } private fun visitType(expected: KotlinType?, actual: KotlinType?, context: Context) { @@ -297,6 +327,21 @@ private class ComparingDeclarationsVisitor( val actualFqName = actualUnwrapped.fqName context.assertEquals(expectedFqName, actualFqName, "type FQN") + + val expectedArguments = expectedUnwrapped.arguments + val actualArguments = actualUnwrapped.arguments + + context.assertEquals(expectedArguments.size, actualArguments.size, "size of type arguments list") + + expectedArguments.forEachIndexed { index, expectedArgument -> + val actualArgument = actualArguments[index] + + context.assertFieldsEqual(expectedArgument::isStarProjection, actualArgument::isStarProjection) + if (!expectedArgument.isStarProjection) { + context.assertFieldsEqual(expectedArgument::getProjectionKind, actualArgument::getProjectionKind) + visitType(expectedArgument.type, actualArgument.type, context.nextLevel("Type argument type")) + } + } } private fun Context.assertEquals(expected: T?, actual: T?, subject: String) { @@ -317,6 +362,24 @@ private class ComparingDeclarationsVisitor( assertEquals(expectedValue, actualValue, "fields \"$expected\"") } + private fun Context.assertSetsEqual(expected: Set, actual: Set, subject: String) { + val expectedMinusActual = expected.subtract(actual) + val actualMinusExpected = actual.subtract(expected) + + if (expectedMinusActual.isNotEmpty() || actualMinusExpected.isNotEmpty()) + fail( + buildString { + append("Comparing $subject:\n") + append("$expected is not equal to $actual\n") + append("Expected size: ${expected.size}\n") + append("Actual size: ${actual.size}\n") + append("Expected minus actual: $expectedMinusActual\n") + append("Actual minus expected: $actualMinusExpected\n") + append(this@assertSetsEqual.toString()) + } + ) + } + override fun visitPackageViewDescriptor(expected: PackageViewDescriptor, context: Context) = fail("Comparison of package views not supported") diff --git a/konan/commonizer/tests/org/jetbrains/kotlin/descriptors/commonizer/core/DefaultTypeParameterCommonizerTest.kt b/konan/commonizer/tests/org/jetbrains/kotlin/descriptors/commonizer/core/DefaultTypeParameterCommonizerTest.kt new file mode 100644 index 00000000000..f5a0306eb7a --- /dev/null +++ b/konan/commonizer/tests/org/jetbrains/kotlin/descriptors/commonizer/core/DefaultTypeParameterCommonizerTest.kt @@ -0,0 +1,110 @@ +/* + * Copyright 2010-2019 JetBrains s.r.o. and Kotlin Programming Language contributors. + * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file. + */ + +package org.jetbrains.kotlin.descriptors.commonizer.core + +import org.jetbrains.kotlin.descriptors.TypeParameterDescriptor +import org.jetbrains.kotlin.descriptors.commonizer.mergedtree.ir.CommonTypeParameter +import org.jetbrains.kotlin.descriptors.commonizer.mergedtree.ir.TypeParameter +import org.jetbrains.kotlin.descriptors.commonizer.mockClassType +import org.jetbrains.kotlin.descriptors.commonizer.mockTypeParameter +import org.jetbrains.kotlin.name.Name +import org.jetbrains.kotlin.types.Variance +import org.jetbrains.kotlin.types.refinement.TypeRefinement +import org.junit.Test + +@TypeRefinement +class DefaultTypeParameterCommonizerTest : AbstractCommonizerTest() { + override fun createCommonizer() = TypeParameterCommonizer.default() + + @Test + fun allAreReified() = doTestSuccess( + create(isReified = true), + create(isReified = true).toMockParam(), + create(isReified = true).toMockParam(), + create(isReified = true).toMockParam() + ) + + @Test + fun allAreNotReified() = doTestSuccess( + create(isReified = false), + create(isReified = false).toMockParam(), + create(isReified = false).toMockParam(), + create(isReified = false).toMockParam() + ) + + @Test(expected = IllegalStateException::class) + fun someAreReified1() = doTestFailure( + create(isReified = true).toMockParam(), + create(isReified = true).toMockParam(), + create(isReified = false).toMockParam() + ) + + @Test(expected = IllegalStateException::class) + fun someAreReified2() = doTestFailure( + create(isReified = false).toMockParam(), + create(isReified = false).toMockParam(), + create(isReified = true).toMockParam() + ) + + @Test(expected = IllegalStateException::class) + fun differentVariance1() = doTestFailure( + create(variance = Variance.IN_VARIANCE).toMockParam(), + create(variance = Variance.IN_VARIANCE).toMockParam(), + create(variance = Variance.OUT_VARIANCE).toMockParam() + ) + + @Test(expected = IllegalStateException::class) + fun differentVariance2() = doTestFailure( + create(variance = Variance.OUT_VARIANCE).toMockParam(), + create(variance = Variance.OUT_VARIANCE).toMockParam(), + create(variance = Variance.INVARIANT).toMockParam() + ) + + @Test(expected = IllegalStateException::class) + fun differentUpperBounds1() = doTestFailure( + create(upperBounds = listOf("kotlin.String")).toMockParam(), + create(upperBounds = listOf("kotlin.String")).toMockParam(), + create(upperBounds = listOf("kotlin.Int")).toMockParam() + ) + + @Test(expected = IllegalStateException::class) + fun differentUpperBounds2() = doTestFailure( + create(upperBounds = listOf("kotlin.String", "kotlin.Int")).toMockParam(), + create(upperBounds = listOf("kotlin.String", "kotlin.Int")).toMockParam(), + create(upperBounds = listOf("kotlin.String")).toMockParam() + ) + + @Test(expected = IllegalStateException::class) + fun differentUpperBounds3() = doTestFailure( + create(upperBounds = listOf("kotlin.String", "kotlin.Int")).toMockParam(), + create(upperBounds = listOf("kotlin.String", "kotlin.Int")).toMockParam(), + create(upperBounds = listOf("kotlin.Int", "kotlin.String")).toMockParam() + ) + + internal companion object { + fun create( + name: String = "T", + isReified: Boolean = false, + variance: Variance = Variance.INVARIANT, + upperBounds: List = listOf("kotlin.Any") + ) = CommonTypeParameter( + name = Name.identifier(name), + isReified = isReified, + variance = variance, + upperBounds = upperBounds.map { mockClassType(it).unwrap() } + ) + + fun TypeParameter.toMockParam( + index: Int = 0 + ): TypeParameterDescriptor = mockTypeParameter( + name = name.asString(), + index = index, + isReified = isReified, + variance = variance, + upperBounds = upperBounds + ) + } +} diff --git a/konan/commonizer/tests/org/jetbrains/kotlin/descriptors/commonizer/core/DefaultTypeParameterListCommonizerTest.kt b/konan/commonizer/tests/org/jetbrains/kotlin/descriptors/commonizer/core/DefaultTypeParameterListCommonizerTest.kt new file mode 100644 index 00000000000..3f40649d9e0 --- /dev/null +++ b/konan/commonizer/tests/org/jetbrains/kotlin/descriptors/commonizer/core/DefaultTypeParameterListCommonizerTest.kt @@ -0,0 +1,130 @@ +/* + * Copyright 2010-2019 JetBrains s.r.o. and Kotlin Programming Language contributors. + * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file. + */ + +package org.jetbrains.kotlin.descriptors.commonizer.core + +import org.jetbrains.kotlin.descriptors.TypeParameterDescriptor +import org.jetbrains.kotlin.descriptors.commonizer.mergedtree.ir.TypeParameter +import org.jetbrains.kotlin.types.refinement.TypeRefinement +import org.junit.Test + +@TypeRefinement +class DefaultTypeParameterListCommonizerTest : AbstractCommonizerTest, List>() { + + @Test + fun emptyValueParameters() = doTestSuccess( + emptyList(), + emptyList(), + emptyList(), + emptyList() + ) + + @Test + fun matchedParameters() = doTestSuccess( + create( + "T" to "kotlin.Any?", + "R" to "kotlin.CharSequence", + "Q" to "org.sample.Foo?" + ), + create( + "T" to "kotlin.Any?", + "R" to "kotlin.CharSequence", + "Q" to "org.sample.Foo?" + ).toMockParams(), + create( + "T" to "kotlin.Any?", + "R" to "kotlin.CharSequence", + "Q" to "org.sample.Foo?" + ).toMockParams(), + create( + "T" to "kotlin.Any?", + "R" to "kotlin.CharSequence", + "Q" to "org.sample.Foo?" + ).toMockParams() + ) + + @Test(expected = IllegalStateException::class) + fun mismatchedParameterListSize1() = doTestFailure( + create( + "T" to "kotlin.Any?", + "R" to "kotlin.CharSequence", + "Q" to "org.sample.Foo?" + ).toMockParams(), + create( + "T" to "kotlin.Any?", + "R" to "kotlin.CharSequence", + "Q" to "org.sample.Foo?" + ).toMockParams(), + emptyList() + ) + + @Test(expected = IllegalStateException::class) + fun mismatchedParameterListSize2() = doTestFailure( + create( + "T" to "kotlin.Any?", + "R" to "kotlin.CharSequence", + "Q" to "org.sample.Foo?" + ).toMockParams(), + create( + "T" to "kotlin.Any?", + "R" to "kotlin.CharSequence", + "Q" to "org.sample.Foo?" + ).toMockParams(), + create( + "T" to "kotlin.Any?", + "R" to "kotlin.CharSequence" + ).toMockParams() + ) + + @Test(expected = IllegalStateException::class) + fun mismatchedParameterListSize3() = doTestFailure( + create( + "T" to "kotlin.Any?", + "R" to "kotlin.CharSequence", + "Q" to "org.sample.Foo?" + ).toMockParams(), + create( + "T" to "kotlin.Any?", + "R" to "kotlin.CharSequence", + "Q" to "org.sample.Foo?" + ).toMockParams(), + create( + "T" to "kotlin.Any?", + "R" to "kotlin.CharSequence", + "Q" to "org.sample.Foo?", + "V" to "org.sample.Bar" + ).toMockParams() + ) + + @Test(expected = IllegalStateException::class) + fun mismatchedParameterNames() = doTestFailure( + create( + "T" to "kotlin.Any?", + "R" to "kotlin.CharSequence" + ).toMockParams(), + create( + "T" to "kotlin.Any?", + "Q" to "kotlin.CharSequence" + ).toMockParams() + ) + + override fun createCommonizer() = TypeParameterListCommonizer.default() + + private companion object { + fun create(vararg params: Pair): List { + check(params.isNotEmpty()) + return params.map { (name, returnTypeFqName) -> + DefaultTypeParameterCommonizerTest.create( + name = name, + upperBounds = listOf(returnTypeFqName) + ) + } + } + + fun List.toMockParams() = DefaultTypeParameterCommonizerTest.run { + mapIndexed { index, param -> param.toMockParam(index) } + } + } +} diff --git a/konan/commonizer/tests/org/jetbrains/kotlin/descriptors/commonizer/core/DefaultValueParameterCommonizerTest.kt b/konan/commonizer/tests/org/jetbrains/kotlin/descriptors/commonizer/core/DefaultValueParameterCommonizerTest.kt index 9b9ef827af4..c4e59a50ee1 100644 --- a/konan/commonizer/tests/org/jetbrains/kotlin/descriptors/commonizer/core/DefaultValueParameterCommonizerTest.kt +++ b/konan/commonizer/tests/org/jetbrains/kotlin/descriptors/commonizer/core/DefaultValueParameterCommonizerTest.kt @@ -141,8 +141,8 @@ class DefaultValueParameterCommonizerTest : AbstractCommonizerTest): List { check(params.isNotEmpty()) return params.map { (name, returnTypeFqName) -> diff --git a/konan/commonizer/tests/org/jetbrains/kotlin/descriptors/commonizer/mocks.kt b/konan/commonizer/tests/org/jetbrains/kotlin/descriptors/commonizer/mocks.kt index 5a312db119a..7e44a3f668e 100644 --- a/konan/commonizer/tests/org/jetbrains/kotlin/descriptors/commonizer/mocks.kt +++ b/konan/commonizer/tests/org/jetbrains/kotlin/descriptors/commonizer/mocks.kt @@ -7,13 +7,13 @@ package org.jetbrains.kotlin.descriptors.commonizer import org.jetbrains.kotlin.descriptors.* import org.jetbrains.kotlin.descriptors.annotations.Annotations +import org.jetbrains.kotlin.descriptors.commonizer.builder.buildDispatchReceiver import org.jetbrains.kotlin.descriptors.commonizer.mergedtree.ir.FunctionModifiers import org.jetbrains.kotlin.descriptors.impl.* import org.jetbrains.kotlin.name.FqName import org.jetbrains.kotlin.name.Name import org.jetbrains.kotlin.name.parentOrNull import org.jetbrains.kotlin.resolve.DescriptorFactory -import org.jetbrains.kotlin.resolve.DescriptorUtils import org.jetbrains.kotlin.resolve.scopes.MemberScope import org.jetbrains.kotlin.storage.LockBasedStorageManager import org.jetbrains.kotlin.test.KotlinTestUtils @@ -118,13 +118,8 @@ internal fun mockProperty( ): PropertyDescriptor { val propertyName = Name.identifier(name) - val containingDeclaration = object : DeclarationDescriptorImpl(Annotations.EMPTY, Name.special("")) { - override fun getContainingDeclaration() = error("not supported") - override fun accept(visitor: DeclarationDescriptorVisitor?, data: D) = error("not supported") - } - val propertyDescriptor = PropertyDescriptorImpl.create( - /*containingDeclaration =*/ containingDeclaration, + /*containingDeclaration =*/ fakeContainingDeclaration(), /*annotations =*/ Annotations.EMPTY, /*modality =*/ Modality.FINAL, /*visibility =*/ Visibilities.PUBLIC, @@ -146,7 +141,7 @@ internal fun mockProperty( /*annotations =*/ Annotations.EMPTY ) - val dispatchReceiverDescriptor = DescriptorUtils.getDispatchReceiverParameterIfNeeded(containingDeclaration) + val dispatchReceiverDescriptor = buildDispatchReceiver(propertyDescriptor) propertyDescriptor.setType( /*outType =*/ returnType, @@ -202,13 +197,8 @@ internal fun mockFunction( ): SimpleFunctionDescriptor { val functionName = Name.identifier(name) - val containingDeclaration = object : DeclarationDescriptorImpl(Annotations.EMPTY, Name.special("")) { - override fun getContainingDeclaration() = error("not supported") - override fun accept(visitor: DeclarationDescriptorVisitor?, data: D) = error("not supported") - } - val functionDescriptor = SimpleFunctionDescriptorImpl.create( - /*containingDeclaration =*/ containingDeclaration, + /*containingDeclaration =*/ fakeContainingDeclaration(), /*annotations =*/ Annotations.EMPTY, /*name =*/ functionName, /*kind =*/ CallableMemberDescriptor.Kind.DECLARATION, @@ -222,7 +212,7 @@ internal fun mockFunction( functionDescriptor.isSuspend = modifiers.isSuspend functionDescriptor.isExternal = modifiers.isExternal - val dispatchReceiverDescriptor = DescriptorUtils.getDispatchReceiverParameterIfNeeded(containingDeclaration) + val dispatchReceiverDescriptor = buildDispatchReceiver(functionDescriptor) functionDescriptor.initialize( /*extensionReceiverParameter =*/ null, @@ -250,7 +240,11 @@ internal fun mockValueParameter( check(index >= 0) val effectiveContainingDeclaration = containingDeclaration - ?: mockFunction("fakeFunction", returnType, TestFunctionModifiers()) // use fake function if no real containing declaration specified + ?: /* use fake function if no real containing declaration specified */ mockFunction( + "fakeFunction", + returnType, + TestFunctionModifiers() + ) return ValueParameterDescriptorImpl( containingDeclaration = effectiveContainingDeclaration, @@ -267,29 +261,29 @@ internal fun mockValueParameter( ) } -//private fun mockTypeParameterType( -// name: String, -// containingDeclaration: DeclarationDescriptor, -// definitelyNotNull: Boolean = false -//): KotlinType { -// val typeParameterName = Name.identifier(name) -// -// val typeParameterDescriptor = TypeParameterDescriptorImpl.createWithDefaultBound( -// /*containingDeclaration =*/ containingDeclaration, -// /*annotations =*/ Annotations.EMPTY, -// /*reified =*/ false, -// /*variance =*/ Variance.INVARIANT, -// /*name =*/ typeParameterName, -// /*index =*/ 0 -// ) -// -// val simpleType = createSimpleType(typeParameterDescriptor.typeConstructor, false) -// -// return if (definitelyNotNull) -// simpleType.makeSimpleTypeDefinitelyNotNullOrNotNull().also { check(it.isDefinitelyNotNullType) } -// else -// simpleType -//} +internal fun mockTypeParameter( + containingDeclaration: CallableDescriptor? = null, + name: String, + index: Int, + isReified: Boolean, + variance: Variance, + upperBounds: List +): TypeParameterDescriptor { + check(index >= 0) + + return TypeParameterDescriptorImpl.createForFurtherModification( + containingDeclaration ?: fakeContainingDeclaration(), + Annotations.EMPTY, + isReified, + variance, + Name.identifier(name), + index, + SourceElement.NO_SOURCE + ).apply { + upperBounds.forEach(this::addUpperBound) + setInitialized() + } +} private fun createPackageFragmentForClassifier(classifierFqName: FqName): PackageFragmentDescriptor = object : PackageFragmentDescriptor { @@ -315,3 +309,9 @@ private fun createSimpleType(typeConstructor: TypeConstructor, nullable: Boolean memberScope = MemberScope.Empty, refinedTypeFactory = { null } ) + +private fun fakeContainingDeclaration() = + object : DeclarationDescriptorImpl(Annotations.EMPTY, Name.special("")) { + override fun getContainingDeclaration() = error("not supported") + override fun accept(visitor: DeclarationDescriptorVisitor?, data: D) = error("not supported") + }