diff --git a/core/descriptors/src/org/jetbrains/kotlin/name/FqNameUnsafe.java b/core/descriptors/src/org/jetbrains/kotlin/name/FqNameUnsafe.java index 83509322b5f..1c31d782b90 100644 --- a/core/descriptors/src/org/jetbrains/kotlin/name/FqNameUnsafe.java +++ b/core/descriptors/src/org/jetbrains/kotlin/name/FqNameUnsafe.java @@ -159,8 +159,11 @@ public final class FqNameUnsafe { } public boolean startsWith(@NotNull Name segment) { + if (isRoot()) + return false; + int firstDot = fqName.indexOf('.'); - return !isRoot() && fqName.regionMatches(0, segment.asString(), 0, firstDot == -1 ? fqName.length() : firstDot); + return fqName.regionMatches(0, segment.asString(), 0, firstDot == -1 ? fqName.length() : firstDot); } @NotNull diff --git a/konan/commonizer/src/org/jetbrains/kotlin/descriptors/commonizer/builder/CommonizedClassDescriptor.kt b/konan/commonizer/src/org/jetbrains/kotlin/descriptors/commonizer/builder/CommonizedClassDescriptor.kt new file mode 100644 index 00000000000..79f60312099 --- /dev/null +++ b/konan/commonizer/src/org/jetbrains/kotlin/descriptors/commonizer/builder/CommonizedClassDescriptor.kt @@ -0,0 +1,128 @@ +/* + * 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.* +import org.jetbrains.kotlin.descriptors.annotations.Annotations +import org.jetbrains.kotlin.descriptors.impl.ClassConstructorDescriptorImpl +import org.jetbrains.kotlin.descriptors.impl.ClassDescriptorBase +import org.jetbrains.kotlin.incremental.components.NoLookupLocation +import org.jetbrains.kotlin.name.Name +import org.jetbrains.kotlin.resolve.DescriptorFactory.* +import org.jetbrains.kotlin.resolve.descriptorUtil.computeSealedSubclasses +import org.jetbrains.kotlin.resolve.scopes.MemberScope +import org.jetbrains.kotlin.resolve.scopes.StaticScopeForKotlinEnum +import org.jetbrains.kotlin.storage.StorageManager +import org.jetbrains.kotlin.types.AbstractClassTypeConstructor +import org.jetbrains.kotlin.types.KotlinType +import org.jetbrains.kotlin.types.TypeConstructor +import org.jetbrains.kotlin.types.checker.KotlinTypeRefiner + +class CommonizedClassDescriptor( + storageManager: StorageManager, + containingDeclaration: DeclarationDescriptor, + override val annotations: Annotations, + name: Name, + private val kind: ClassKind, + private val modality: Modality, + private val visibility: Visibility, + private val isCompanion: Boolean, + private val isData: Boolean, + private val isInline: Boolean, + private val isInner: Boolean, + isExternal: Boolean, + private val isExpect: Boolean, + private val isActual: Boolean, + companionObjectName: Name?, + supertypes: Collection +) : ClassDescriptorBase(storageManager, containingDeclaration, name, SourceElement.NO_SOURCE, isExternal) { + private lateinit var _unsubstitutedMemberScope: MemberScope + private lateinit var constructors: Collection + private var primaryConstructor: ClassConstructorDescriptor? = null + private val staticScope = if (kind == ClassKind.ENUM_CLASS) StaticScopeForKotlinEnum(storageManager, this) else MemberScope.Empty + private lateinit var declaredTypeParameters: List + private val typeConstructor = CommonizedClassTypeConstructor(storageManager, supertypes) + private val sealedSubclasses = storageManager.createLazyValue { computeSealedSubclasses(this) } + + private val companionObjectDescriptor = storageManager.createNullableLazyValue { + if (companionObjectName != null) + unsubstitutedMemberScope.getContributedClassifier(companionObjectName, NoLookupLocation.FOR_ALREADY_TRACKED) as? ClassDescriptor + else + null + } + + override fun getKind() = kind + override fun getModality() = modality + override fun getVisibility() = visibility + override fun isCompanionObject() = isCompanion + override fun isData() = isData + override fun isInline() = isInline + override fun isInner() = isInner + override fun isExpect() = isExpect + override fun isActual() = isActual + + override fun getUnsubstitutedMemberScope(kotlinTypeRefiner: KotlinTypeRefiner): MemberScope { + check(kotlinTypeRefiner == KotlinTypeRefiner.Default) { + "${kotlinTypeRefiner::class.java} is not supported in ${this::class.java}" + } + return _unsubstitutedMemberScope + } + + override fun getDeclaredTypeParameters() = declaredTypeParameters + fun setDeclaredTypeParameters(declaredTypeParameters: List) { + this.declaredTypeParameters = declaredTypeParameters + } + + override fun getConstructors() = constructors + override fun getUnsubstitutedPrimaryConstructor() = primaryConstructor + override fun getStaticScope(): MemberScope = staticScope + override fun getTypeConstructor(): TypeConstructor = typeConstructor + override fun getCompanionObjectDescriptor() = companionObjectDescriptor() + override fun getSealedSubclasses() = sealedSubclasses() + + fun initialize( + unsubstitutedMemberScope: MemberScope, + constructors: Collection + ) { + _unsubstitutedMemberScope = unsubstitutedMemberScope + + if (isExpect && kind.isSingleton) { + check(constructors.isEmpty()) + + primaryConstructor = createPrimaryConstructorForObject(this, SourceElement.NO_SOURCE).apply { returnType = getDefaultType() } + this.constructors = listOf(primaryConstructor!!) + } else { + constructors.forEach { it.returnType = getDefaultType() } + + primaryConstructor = constructors.firstOrNull { it.isPrimary } + this.constructors = constructors + } + } + + override fun toString() = (if (isExpect) "expect " else if (isActual) "actual " else "") + "class " + name.toString() + + private inner class CommonizedClassTypeConstructor( + storageManager: StorageManager, + private val computedSupertypes: Collection + ) : AbstractClassTypeConstructor(storageManager) { + private val parameters = storageManager.createLazyValue { + this@CommonizedClassDescriptor.computeConstructorTypeParameters() + } + + override fun getParameters() = parameters() + override fun computeSupertypes() = computedSupertypes + override fun isDenotable() = true + override fun getDeclarationDescriptor() = this@CommonizedClassDescriptor + override val supertypeLoopChecker get() = SupertypeLoopChecker.EMPTY + } +} + +class CommonizedClassConstructorDescriptor( + containingDeclaration: ClassDescriptor, + annotations: Annotations, + isPrimary: Boolean, + kind: CallableMemberDescriptor.Kind +) : ClassConstructorDescriptorImpl(containingDeclaration, null, annotations, isPrimary, kind, SourceElement.NO_SOURCE) diff --git a/konan/commonizer/src/org/jetbrains/kotlin/descriptors/commonizer/builder/CommonizedTypeAliasDescriptor.kt b/konan/commonizer/src/org/jetbrains/kotlin/descriptors/commonizer/builder/CommonizedTypeAliasDescriptor.kt new file mode 100644 index 00000000000..e08755b067c --- /dev/null +++ b/konan/commonizer/src/org/jetbrains/kotlin/descriptors/commonizer/builder/CommonizedTypeAliasDescriptor.kt @@ -0,0 +1,68 @@ +/* + * 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.* +import org.jetbrains.kotlin.descriptors.annotations.Annotations +import org.jetbrains.kotlin.descriptors.impl.AbstractTypeAliasDescriptor +import org.jetbrains.kotlin.descriptors.impl.TypeAliasConstructorDescriptor +import org.jetbrains.kotlin.name.Name +import org.jetbrains.kotlin.storage.StorageManager +import org.jetbrains.kotlin.types.SimpleType +import org.jetbrains.kotlin.types.TypeSubstitutor +import org.jetbrains.kotlin.types.Variance +import org.jetbrains.kotlin.types.asSimpleType + +class CommonizedTypeAliasDescriptor( + override val storageManager: StorageManager, + containingDeclaration: DeclarationDescriptor, + annotations: Annotations, + name: Name, + visibility: Visibility, + private val isActual: Boolean +) : AbstractTypeAliasDescriptor(containingDeclaration, annotations, name, SourceElement.NO_SOURCE, visibility) { + + override lateinit var underlyingType: SimpleType + override lateinit var expandedType: SimpleType + + private lateinit var defaultType: SimpleType + override fun getDefaultType() = defaultType + + override val classDescriptor get() = expandedType.constructor.declarationDescriptor as? ClassDescriptor + + private lateinit var typeConstructorParameters: List + override fun getTypeConstructorTypeParameters() = typeConstructorParameters + + override lateinit var constructors: Collection + + override fun isActual() = isActual + + fun initialize(underlyingType: SimpleType, expandedType: SimpleType) { + super.initialize(emptyList()) + this.underlyingType = underlyingType + this.expandedType = expandedType + typeConstructorParameters = computeConstructorTypeParameters() + defaultType = computeDefaultType() + constructors = getTypeAliasConstructors() + } + + override fun substitute(substitutor: TypeSubstitutor): ClassifierDescriptorWithTypeParameters { + if (substitutor.isEmpty) return this + val substituted = CommonizedTypeAliasDescriptor( + storageManager = storageManager, + containingDeclaration = containingDeclaration, + annotations = annotations, + name = name, + visibility = visibility, + isActual = isActual + ) + substituted.initialize( + substitutor.safeSubstitute(underlyingType, Variance.INVARIANT).asSimpleType(), + substitutor.safeSubstitute(expandedType, Variance.INVARIANT).asSimpleType() + ) + return substituted + } +} diff --git a/konan/commonizer/src/org/jetbrains/kotlin/descriptors/commonizer/builder/DeclarationsBuilderVisitor.kt b/konan/commonizer/src/org/jetbrains/kotlin/descriptors/commonizer/builder/DeclarationsBuilderVisitor.kt index 7e55a5177ce..1e3cd5b2d29 100644 --- a/konan/commonizer/src/org/jetbrains/kotlin/descriptors/commonizer/builder/DeclarationsBuilderVisitor.kt +++ b/konan/commonizer/src/org/jetbrains/kotlin/descriptors/commonizer/builder/DeclarationsBuilderVisitor.kt @@ -13,16 +13,18 @@ import org.jetbrains.kotlin.descriptors.commonizer.builder.CommonizedMemberScope import org.jetbrains.kotlin.descriptors.commonizer.builder.CommonizedPackageFragmentProvider.Companion.plusAssign import org.jetbrains.kotlin.descriptors.commonizer.mergedtree.ir.* import org.jetbrains.kotlin.descriptors.impl.ModuleDescriptorImpl +import org.jetbrains.kotlin.resolve.scopes.MemberScope import org.jetbrains.kotlin.storage.StorageManager import org.jetbrains.kotlin.utils.addIfNotNull +/** Builds and initializes the new tree of common descriptors */ internal class DeclarationsBuilderVisitor( private val storageManager: StorageManager, private val builtIns: KotlinBuiltIns, private val collector: (TargetId, Collection) -> Unit ) : NodeVisitor, List> { override fun visitRootNode(node: RootNode, data: List): List { - val allTargets = (node.target + node.common).map { it.targetId } + val allTargets = (node.target + node.common()!!).map { it.targetId } val modulesByTargets = HashMap>() @@ -63,7 +65,7 @@ internal class DeclarationsBuilderVisitor( } // initialize module descriptors: - moduleDescriptors.asListContaining().forEachIndexed { index, moduleDescriptor -> + moduleDescriptors.forEachIndexed { index, moduleDescriptor -> moduleDescriptor?.initialize(packageFragmentProviders[index]) } @@ -86,6 +88,12 @@ internal class DeclarationsBuilderVisitor( for (functionNode in node.functions) { packageMemberScopes += functionNode.accept(this, packageFragments) } + for (classNode in node.classes) { + packageMemberScopes += classNode.accept(this, packageFragments) + } + for (typeAliasNode in node.typeAliases) { + packageMemberScopes += typeAliasNode.accept(this, packageFragments) + } // initialize package fragments: packageFragments.forEachIndexed { index, packageFragment -> @@ -109,6 +117,60 @@ internal class DeclarationsBuilderVisitor( return functionDescriptorsGroup.toList() } + override fun visitClassNode(node: ClassNode, data: List): List { + val classesGroup = CommonizedGroup(node.dimension) + node.buildDescriptors(classesGroup, data, storageManager) + val classes = classesGroup.toList().asListContaining() + + // build class constructors: + val allConstructorsByTargets = Array>(node.dimension) { ArrayList() } + for (constructorNode in node.constructors) { + val constructorsByTargets = constructorNode.accept(this, classes).asListContaining() + constructorsByTargets.forEachIndexed { index, constructor -> + if (constructor != null) allConstructorsByTargets[index].add(constructor) + } + } + + // build class members: + val classMemberScopes = CommonizedMemberScope.createArray(node.dimension) + for (propertyNode in node.properties) { + classMemberScopes += propertyNode.accept(this, classes) + } + for (functionNode in node.functions) { + classMemberScopes += functionNode.accept(this, classes) + } + for (classNode in node.classes) { + classMemberScopes += classNode.accept(this, classes) + } + + // initialize classes + classes.forEachIndexed { index, clazz -> + clazz?.initialize(classMemberScopes[index], allConstructorsByTargets[index]) + } + + return classes + } + + override fun visitClassConstructorNode(node: ClassConstructorNode, data: List): List { + val containingDeclarations = data.asListContaining() + + val constructorsGroup = CommonizedGroup(node.dimension) + node.buildDescriptors(constructorsGroup, containingDeclarations) + + return constructorsGroup.toList() + } + + override fun visitTypeAliasNode(node: TypeAliasNode, data: List): List { + val typeAliasesGroup = CommonizedGroup(node.dimension) + node.buildDescriptors(typeAliasesGroup, data, storageManager) + val typeAliases = typeAliasesGroup.toList() + + val commonClass = typeAliases[node.indexOfCommon] as CommonizedClassDescriptor? + commonClass?.initialize(MemberScope.Empty, emptyList()) + + return typeAliases + } + companion object { inline fun noContainingDeclarations() = emptyList() inline fun noReturningDeclarations() = emptyList() diff --git a/konan/commonizer/src/org/jetbrains/kotlin/descriptors/commonizer/builder/classDescriptors.kt b/konan/commonizer/src/org/jetbrains/kotlin/descriptors/commonizer/builder/classDescriptors.kt new file mode 100644 index 00000000000..37f0e0741f8 --- /dev/null +++ b/konan/commonizer/src/org/jetbrains/kotlin/descriptors/commonizer/builder/classDescriptors.kt @@ -0,0 +1,108 @@ +/* + * 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.ClassConstructorDescriptor +import org.jetbrains.kotlin.descriptors.ClassDescriptor +import org.jetbrains.kotlin.descriptors.ClassifierDescriptorWithTypeParameters +import org.jetbrains.kotlin.descriptors.DeclarationDescriptor +import org.jetbrains.kotlin.descriptors.commonizer.CommonizedGroup +import org.jetbrains.kotlin.descriptors.commonizer.mergedtree.ir.* +import org.jetbrains.kotlin.descriptors.commonizer.mergedtree.ir.indexOfCommon +import org.jetbrains.kotlin.storage.StorageManager + +internal fun ClassNode.buildDescriptors( + output: CommonizedGroup, + containingDeclarations: List, + storageManager: StorageManager +) { + val commonClass = common() + + target.forEachIndexed { index, clazz -> + clazz?.buildDescriptor(output, index, containingDeclarations, storageManager, isActual = commonClass != null) + } + + commonClass?.buildDescriptor(output, indexOfCommon, containingDeclarations, storageManager, isExpect = true) +} + +internal fun ClassDeclaration.buildDescriptor( + output: CommonizedGroup, + index: Int, + containingDeclarations: List, + storageManager: StorageManager, + isExpect: Boolean = false, + isActual: Boolean = false +) { + val containingDeclaration = containingDeclarations[index] ?: error("No containing declaration for class $this") + + val classDescriptor = CommonizedClassDescriptor( + storageManager = storageManager, + containingDeclaration = containingDeclaration, + annotations = annotations, + name = name, + kind = kind, + modality = modality, + visibility = visibility, + isCompanion = isCompanion, + isData = isData, + isInline = isInline, + isInner = isInner, + isExternal = isExternal, + isExpect = isExpect, + isActual = isActual, + companionObjectName = companion?.shortName(), + supertypes = supertypes + ) + + classDescriptor.declaredTypeParameters = typeParameters.buildDescriptors(classDescriptor) + + output[index] = classDescriptor +} + +internal fun ClassConstructorNode.buildDescriptors( + output: CommonizedGroup, + containingDeclarations: List +) { + val commonConstructor = common() + + target.forEachIndexed { index, constructor -> + constructor?.buildDescriptor(output, index, containingDeclarations, isActual = commonConstructor != null) + } + + commonConstructor?.buildDescriptor(output, indexOfCommon, containingDeclarations, isExpect = true) + +} + +private fun ClassConstructor.buildDescriptor( + output: CommonizedGroup, + index: Int, + containingDeclarations: List, + isExpect: Boolean = false, + isActual: Boolean = false +) { + val containingDeclaration = containingDeclarations[index] ?: error("No containing declaration for constructor $this") + + val constructorDescriptor = CommonizedClassConstructorDescriptor( + containingDeclaration = containingDeclaration, + annotations = annotations, + isPrimary = isPrimary, + kind = kind + ) + + constructorDescriptor.isExpect = isExpect + constructorDescriptor.isActual = isActual + + constructorDescriptor.setHasStableParameterNames(hasStableParameterNames) + constructorDescriptor.setHasSynthesizedParameterNames(hasSynthesizedParameterNames) + + constructorDescriptor.initialize( + valueParameters.buildDescriptors(constructorDescriptor), + visibility, + typeParameters.buildDescriptors(constructorDescriptor) + ) + + output[index] = constructorDescriptor +} 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 18b4b8efbf8..9c8e39f53f8 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 @@ -8,28 +8,23 @@ package org.jetbrains.kotlin.descriptors.commonizer.builder import org.jetbrains.kotlin.descriptors.DeclarationDescriptor import org.jetbrains.kotlin.descriptors.SimpleFunctionDescriptor 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.Function import org.jetbrains.kotlin.descriptors.commonizer.mergedtree.ir.FunctionNode -import org.jetbrains.kotlin.descriptors.commonizer.mergedtree.ir.ValueParameter import org.jetbrains.kotlin.descriptors.commonizer.mergedtree.ir.indexOfCommon import org.jetbrains.kotlin.descriptors.impl.SimpleFunctionDescriptorImpl -import org.jetbrains.kotlin.descriptors.impl.ValueParameterDescriptorImpl -import org.jetbrains.kotlin.resolve.DescriptorFactory -import org.jetbrains.kotlin.resolve.DescriptorUtils internal fun FunctionNode.buildDescriptors( output: CommonizedGroup, containingDeclarations: List ) { - val isCommonized = common != null + val commonFunction = common() target.forEachIndexed { index, function -> - function?.buildDescriptor(output, index, containingDeclarations, isActual = isCommonized) + function?.buildDescriptor(output, index, containingDeclarations, isActual = commonFunction != null) } - common?.buildDescriptor(output, indexOfCommon, containingDeclarations, isExpect = isCommonized) + commonFunction?.buildDescriptor(output, indexOfCommon, containingDeclarations, isExpect = true) } private fun Function.buildDescriptor( @@ -39,7 +34,7 @@ private fun Function.buildDescriptor( isExpect: Boolean = false, isActual: Boolean = false ) { - val containingDeclaration = containingDeclarations[index] ?: error("No containing declaration for property $this") + val containingDeclaration = containingDeclarations[index] ?: error("No containing declaration for function $this") val functionDescriptor = SimpleFunctionDescriptorImpl.create( containingDeclaration, @@ -59,11 +54,14 @@ private fun Function.buildDescriptor( functionDescriptor.isExpect = isExpect functionDescriptor.isActual = isActual + functionDescriptor.setHasStableParameterNames(hasStableParameterNames) + functionDescriptor.setHasSynthesizedParameterNames(hasSynthesizedParameterNames) + functionDescriptor.initialize( extensionReceiver?.buildExtensionReceiver(functionDescriptor), buildDispatchReceiver(functionDescriptor), typeParameters.buildDescriptors(functionDescriptor), - valueParameters.buildValueParameters(functionDescriptor), + valueParameters.buildDescriptors(functionDescriptor), returnType, modality, visibility @@ -71,21 +69,3 @@ private fun Function.buildDescriptor( output[index] = functionDescriptor } - -private fun List.buildValueParameters( - functionDescriptor: SimpleFunctionDescriptor -) = mapIndexed { index, param -> - ValueParameterDescriptorImpl( - functionDescriptor, - null, - index, - param.annotations, - param.name, - param.returnType, - param.declaresDefaultValue, - param.isCrossinline, - param.isNoinline, - param.varargElementType, - SourceElement.NO_SOURCE - ) -} diff --git a/konan/commonizer/src/org/jetbrains/kotlin/descriptors/commonizer/builder/moduleDescriptors.kt b/konan/commonizer/src/org/jetbrains/kotlin/descriptors/commonizer/builder/moduleDescriptors.kt index 9eb4609ed66..cf09f568431 100644 --- a/konan/commonizer/src/org/jetbrains/kotlin/descriptors/commonizer/builder/moduleDescriptors.kt +++ b/konan/commonizer/src/org/jetbrains/kotlin/descriptors/commonizer/builder/moduleDescriptors.kt @@ -22,7 +22,7 @@ internal fun ModuleNode.buildDescriptors( module?.buildDescriptor(output, index, storageManager, builtIns) } - common?.buildDescriptor(output, indexOfCommon, storageManager, builtIns) + common()?.buildDescriptor(output, indexOfCommon, storageManager, builtIns) } private fun Module.buildDescriptor( diff --git a/konan/commonizer/src/org/jetbrains/kotlin/descriptors/commonizer/builder/packageFragments.kt b/konan/commonizer/src/org/jetbrains/kotlin/descriptors/commonizer/builder/packageFragments.kt index d909dbf3598..5bbbd742425 100644 --- a/konan/commonizer/src/org/jetbrains/kotlin/descriptors/commonizer/builder/packageFragments.kt +++ b/konan/commonizer/src/org/jetbrains/kotlin/descriptors/commonizer/builder/packageFragments.kt @@ -23,7 +23,7 @@ internal fun PackageNode.buildDescriptors( pkg?.buildDescriptor(output, index, modules) } - common?.buildDescriptor(output, indexOfCommon, modules) + common()?.buildDescriptor(output, indexOfCommon, modules) } private fun Package.buildDescriptor( 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 ec7fe2bdc5f..4c5ef4e92a4 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 @@ -22,13 +22,13 @@ internal fun PropertyNode.buildDescriptors( containingDeclarations: List, storageManager: StorageManager ) { - val isCommonized = common != null + val commonProperty = common() target.forEachIndexed { index, property -> - property?.buildDescriptor(output, index, containingDeclarations, storageManager, isActual = isCommonized) + property?.buildDescriptor(output, index, containingDeclarations, storageManager, isActual = commonProperty != null) } - common?.buildDescriptor(output, indexOfCommon, containingDeclarations, storageManager, isExpect = isCommonized) + commonProperty?.buildDescriptor(output, indexOfCommon, containingDeclarations, storageManager, isExpect = true) } private fun Property.buildDescriptor( @@ -50,7 +50,7 @@ private fun Property.buildDescriptor( name, kind, SourceElement.NO_SOURCE, - lateInit, + isLateInit, isConst, isExpect, isActual, diff --git a/konan/commonizer/src/org/jetbrains/kotlin/descriptors/commonizer/builder/typeAliasDescriptors.kt b/konan/commonizer/src/org/jetbrains/kotlin/descriptors/commonizer/builder/typeAliasDescriptors.kt new file mode 100644 index 00000000000..61b0789092a --- /dev/null +++ b/konan/commonizer/src/org/jetbrains/kotlin/descriptors/commonizer/builder/typeAliasDescriptors.kt @@ -0,0 +1,52 @@ +/* + * 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.ClassifierDescriptorWithTypeParameters +import org.jetbrains.kotlin.descriptors.DeclarationDescriptor +import org.jetbrains.kotlin.descriptors.commonizer.CommonizedGroup +import org.jetbrains.kotlin.descriptors.commonizer.mergedtree.ir.ClassDeclaration +import org.jetbrains.kotlin.descriptors.commonizer.mergedtree.ir.TypeAlias +import org.jetbrains.kotlin.descriptors.commonizer.mergedtree.ir.TypeAliasNode +import org.jetbrains.kotlin.descriptors.commonizer.mergedtree.ir.indexOfCommon +import org.jetbrains.kotlin.storage.StorageManager + +internal fun TypeAliasNode.buildDescriptors( + output: CommonizedGroup, + containingDeclarations: List, + storageManager: StorageManager +) { + val commonClass: ClassDeclaration? = common() + + target.forEachIndexed { index, typeAlias -> + typeAlias?.buildDescriptor(output, index, containingDeclarations, storageManager, isActual = commonClass != null) + } + + commonClass?.buildDescriptor(output, indexOfCommon, containingDeclarations, storageManager, isExpect = true) +} + +private fun TypeAlias.buildDescriptor( + output: CommonizedGroup, + index: Int, + containingDeclarations: List, + storageManager: StorageManager, + isActual: Boolean = false +) { + val containingDeclaration = containingDeclarations[index] ?: error("No containing declaration for type alias $this") + + val typeAliasDescriptor = CommonizedTypeAliasDescriptor( + storageManager = storageManager, + containingDeclaration = containingDeclaration, + annotations = annotations, + name = name, + visibility = visibility, + isActual = isActual + ) + + typeAliasDescriptor.initialize(underlyingType, expandedType) + + output[index] = typeAliasDescriptor +} 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 index 02ea97986ff..fecfe4ce149 100644 --- a/konan/commonizer/src/org/jetbrains/kotlin/descriptors/commonizer/builder/utils.kt +++ b/konan/commonizer/src/org/jetbrains/kotlin/descriptors/commonizer/builder/utils.kt @@ -5,13 +5,12 @@ 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.* import org.jetbrains.kotlin.descriptors.commonizer.mergedtree.ir.ExtensionReceiver import org.jetbrains.kotlin.descriptors.commonizer.mergedtree.ir.TypeParameter +import org.jetbrains.kotlin.descriptors.commonizer.mergedtree.ir.ValueParameter import org.jetbrains.kotlin.descriptors.impl.TypeParameterDescriptorImpl +import org.jetbrains.kotlin.descriptors.impl.ValueParameterDescriptorImpl import org.jetbrains.kotlin.resolve.DescriptorFactory import org.jetbrains.kotlin.resolve.DescriptorUtils @@ -36,6 +35,24 @@ internal fun List.buildDescriptors( } } +internal fun List.buildDescriptors( + containingDeclaration: CallableDescriptor +) = mapIndexed { index, param -> + ValueParameterDescriptorImpl( + containingDeclaration, + null, + index, + param.annotations, + param.name, + param.returnType, + param.declaresDefaultValue, + param.isCrossinline, + param.isNoinline, + param.varargElementType, + SourceElement.NO_SOURCE + ) +} + internal fun ExtensionReceiver.buildExtensionReceiver( containingDeclaration: CallableDescriptor ) = DescriptorFactory.createExtensionReceiverParameterForCallable( diff --git a/konan/commonizer/src/org/jetbrains/kotlin/descriptors/commonizer/commonizedGroup.kt b/konan/commonizer/src/org/jetbrains/kotlin/descriptors/commonizer/commonizedGroup.kt index 0ca599d3a74..583fc98d14b 100644 --- a/konan/commonizer/src/org/jetbrains/kotlin/descriptors/commonizer/commonizedGroup.kt +++ b/konan/commonizer/src/org/jetbrains/kotlin/descriptors/commonizer/commonizedGroup.kt @@ -5,7 +5,7 @@ package org.jetbrains.kotlin.descriptors.commonizer -// Fixed-size list that represents a commonized group of same-rank elements +/** Fixed-size ordered collection that represents a commonized group of same-rank elements */ internal class CommonizedGroup( val size: Int, initialize: (Int) -> T? diff --git a/konan/commonizer/src/org/jetbrains/kotlin/descriptors/commonizer/core/AbstractCallableMemberCommonizer.kt b/konan/commonizer/src/org/jetbrains/kotlin/descriptors/commonizer/core/AbstractCallableMemberCommonizer.kt deleted file mode 100644 index 7d2b38c8710..00000000000 --- a/konan/commonizer/src/org/jetbrains/kotlin/descriptors/commonizer/core/AbstractCallableMemberCommonizer.kt +++ /dev/null @@ -1,51 +0,0 @@ -/* - * 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.CallableMemberDescriptor -import org.jetbrains.kotlin.descriptors.commonizer.mergedtree.ir.CallableMember -import org.jetbrains.kotlin.name.Name - -abstract class AbstractCallableMemberCommonizer : Commonizer { - protected enum class State { - EMPTY, - ERROR, - IN_PROGRESS - } - - protected lateinit var name: Name - protected val modality = ModalityCommonizer.default() - // TODO: visibility - what if virtual declaration? - protected val visibility = VisibilityCommonizer.lowering() - protected val extensionReceiver = ExtensionReceiverCommonizer.default() - protected val returnType = TypeCommonizer.default() - protected val typeParameters = TypeParameterListCommonizer.default() - - protected var state = State.EMPTY - - final override fun commonizeWith(next: T): Boolean { - if (state == State.ERROR) - return false - - if (state == State.EMPTY) - name = next.name - - val result = canBeCommonized(next) - && modality.commonizeWith(next.modality) - && visibility.commonizeWith(next.visibility) - && extensionReceiver.commonizeWith(next.extensionReceiverParameter) - && returnType.commonizeWith(next.returnType!!) - && typeParameters.commonizeWith(next.typeParameters) - && commonizeSpecifics(next) - - state = if (!result) State.ERROR else State.IN_PROGRESS - - return result - } - - protected abstract fun canBeCommonized(next: T): Boolean - protected abstract fun commonizeSpecifics(next: T): Boolean -} diff --git a/konan/commonizer/src/org/jetbrains/kotlin/descriptors/commonizer/core/AbstractFunctionOrPropertyCommonizer.kt b/konan/commonizer/src/org/jetbrains/kotlin/descriptors/commonizer/core/AbstractFunctionOrPropertyCommonizer.kt new file mode 100644 index 00000000000..ac7b641f1b5 --- /dev/null +++ b/konan/commonizer/src/org/jetbrains/kotlin/descriptors/commonizer/core/AbstractFunctionOrPropertyCommonizer.kt @@ -0,0 +1,31 @@ +/* + * 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.commonizer.mergedtree.ir.ClassifiersCache +import org.jetbrains.kotlin.descriptors.commonizer.mergedtree.ir.FunctionOrProperty +import org.jetbrains.kotlin.name.Name + +abstract class AbstractFunctionOrPropertyCommonizer(cache: ClassifiersCache) : AbstractStandardCommonizer() { + protected lateinit var name: Name + protected val modality = ModalityCommonizer.default() + protected val visibility = VisibilityCommonizer.lowering() + protected val extensionReceiver = ExtensionReceiverCommonizer.default(cache) + protected val returnType = TypeCommonizer.default(cache) + protected val typeParameters = TypeParameterListCommonizer.default(cache) + + override fun initialize(first: T) { + name = first.name + } + + override fun doCommonizeWith(next: T) = + !next.isNonAbstractCallableMemberInInterface // non-abstract callable members declared in interface can't be commonized + && modality.commonizeWith(next.modality) + && visibility.commonizeWith(next) + && extensionReceiver.commonizeWith(next.extensionReceiver) + && returnType.commonizeWith(next.returnType) + && typeParameters.commonizeWith(next.typeParameters) +} diff --git a/konan/commonizer/src/org/jetbrains/kotlin/descriptors/commonizer/core/AbstractListCommonizer.kt b/konan/commonizer/src/org/jetbrains/kotlin/descriptors/commonizer/core/AbstractListCommonizer.kt index 527bf4ced1a..9f411320703 100644 --- a/konan/commonizer/src/org/jetbrains/kotlin/descriptors/commonizer/core/AbstractListCommonizer.kt +++ b/konan/commonizer/src/org/jetbrains/kotlin/descriptors/commonizer/core/AbstractListCommonizer.kt @@ -5,6 +5,17 @@ package org.jetbrains.kotlin.descriptors.commonizer.core +import org.jetbrains.kotlin.types.KotlinType +import org.jetbrains.kotlin.types.UnwrappedType + +/** + * Unlike [Commonizer] which commonizes only single elements, this [AbstractListCommonizer] commonizes lists of elements using + * [Commonizer]s produced by [singleElementCommonizerFactory]. + * + * Example: + * Input: N lists of [KotlinType] + * Output: list of [UnwrappedType] + */ abstract class AbstractListCommonizer( private val singleElementCommonizerFactory: () -> Commonizer ) : Commonizer, List> { @@ -27,13 +38,14 @@ abstract class AbstractListCommonizer( this.commonizers = it } - if (commonizers.size != next.size) + if (commonizers.size != next.size) // lists must be of the same size error = true else for (index in 0 until next.size) { val commonizer = commonizers[index] val nextElement = next[index] + // commonize each element in the list: if (!commonizer.commonizeWith(nextElement)) { error = true break diff --git a/konan/commonizer/src/org/jetbrains/kotlin/descriptors/commonizer/core/AbstractNamedListCommonizer.kt b/konan/commonizer/src/org/jetbrains/kotlin/descriptors/commonizer/core/AbstractNamedListCommonizer.kt deleted file mode 100644 index 45deafbdd22..00000000000 --- a/konan/commonizer/src/org/jetbrains/kotlin/descriptors/commonizer/core/AbstractNamedListCommonizer.kt +++ /dev/null @@ -1,42 +0,0 @@ -/* - * 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.Named -import org.jetbrains.kotlin.name.Name - -abstract class AbstractNamedListCommonizer( - 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.second.result } ?: throw IllegalCommonizerStateException() - - final override fun commonizeWith(next: List): Boolean { - if (error) - return false - - val commonizers = commonizers - ?: next.map { it.name to singleElementCommonizerFactory() }.also { this.commonizers = it } - - if (commonizers.size != next.size) - error = true - else - for (index in 0 until next.size) { - val (name, commonizer) = commonizers[index] - val nextElement = next[index] - - if (name != nextElement.name || !commonizer.commonizeWith(nextElement)) { - error = true - break - } - } - - return !error - } -} diff --git a/konan/commonizer/src/org/jetbrains/kotlin/descriptors/commonizer/core/AbstractNullableCommonizer.kt b/konan/commonizer/src/org/jetbrains/kotlin/descriptors/commonizer/core/AbstractNullableCommonizer.kt index 16b85fdfa38..f883db32aa9 100644 --- a/konan/commonizer/src/org/jetbrains/kotlin/descriptors/commonizer/core/AbstractNullableCommonizer.kt +++ b/konan/commonizer/src/org/jetbrains/kotlin/descriptors/commonizer/core/AbstractNullableCommonizer.kt @@ -5,6 +5,11 @@ package org.jetbrains.kotlin.descriptors.commonizer.core +/** + * A wrapper around [Commonizer] that checks that + * - either all commonized elements are null + * - or all commonized elements are non-null and can be commonized according to the wrapped commonized + */ abstract class AbstractNullableCommonizer( private val wrappedCommonizerFactory: () -> Commonizer, private val extractor: (T) -> WT, @@ -41,6 +46,7 @@ abstract class AbstractNullableCommonizer( return state != State.ERROR } - private fun doCommonizeWith(next: T) = + @Suppress("NOTHING_TO_INLINE") + private inline fun doCommonizeWith(next: T) = if (wrapped.commonizeWith(extractor(next))) State.WITH_WRAPPED else State.ERROR } diff --git a/konan/commonizer/src/org/jetbrains/kotlin/descriptors/commonizer/core/ClassCommonizer.kt b/konan/commonizer/src/org/jetbrains/kotlin/descriptors/commonizer/core/ClassCommonizer.kt new file mode 100644 index 00000000000..c9296a08d47 --- /dev/null +++ b/konan/commonizer/src/org/jetbrains/kotlin/descriptors/commonizer/core/ClassCommonizer.kt @@ -0,0 +1,52 @@ +/* + * 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.ClassKind +import org.jetbrains.kotlin.descriptors.commonizer.mergedtree.ir.ClassDeclaration +import org.jetbrains.kotlin.descriptors.commonizer.mergedtree.ir.ClassifiersCache +import org.jetbrains.kotlin.descriptors.commonizer.mergedtree.ir.CommonClassDeclaration +import org.jetbrains.kotlin.name.Name + +class ClassCommonizer(cache: ClassifiersCache) : AbstractStandardCommonizer() { + private lateinit var name: Name + private lateinit var kind: ClassKind + private val typeParameters = TypeParameterListCommonizer.default(cache) + private val modality = ModalityCommonizer.default() + private val visibility = VisibilityCommonizer.equalizing() + private var isInner = false + private var isInline = false + private var isCompanion = false + + override fun commonizationResult() = CommonClassDeclaration( + name = name, + typeParameters = typeParameters.result, + kind = kind, + modality = modality.result, + visibility = visibility.result, + isCompanion = isCompanion, + isInline = isInline, + isInner = isInner + ) + + override fun initialize(first: ClassDeclaration) { + name = first.name + kind = first.kind + isInner = first.isInner + isInline = first.isInline + isCompanion = first.isCompanion + } + + override fun doCommonizeWith(next: ClassDeclaration) = + kind == next.kind + && isInner == next.isInner + && isInline == next.isInline + && isCompanion == next.isCompanion + && next.sealedSubclasses.isEmpty() // commonization of sealed classes is not supported, but their subclasses can be commonized + && modality.commonizeWith(next.modality) + && visibility.commonizeWith(next) + && typeParameters.commonizeWith(next.typeParameters) +} diff --git a/konan/commonizer/src/org/jetbrains/kotlin/descriptors/commonizer/core/ClassConstructorCommonizer.kt b/konan/commonizer/src/org/jetbrains/kotlin/descriptors/commonizer/core/ClassConstructorCommonizer.kt new file mode 100644 index 00000000000..784484803fd --- /dev/null +++ b/konan/commonizer/src/org/jetbrains/kotlin/descriptors/commonizer/core/ClassConstructorCommonizer.kt @@ -0,0 +1,51 @@ +/* + * 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.CallableMemberDescriptor +import org.jetbrains.kotlin.descriptors.commonizer.mergedtree.ir.ClassConstructor +import org.jetbrains.kotlin.descriptors.commonizer.mergedtree.ir.ClassifiersCache +import org.jetbrains.kotlin.descriptors.commonizer.mergedtree.ir.CommonClassConstructor + +class ClassConstructorCommonizer(cache: ClassifiersCache) : AbstractStandardCommonizer() { + private var isPrimary = false + private lateinit var kind: CallableMemberDescriptor.Kind + private val visibility = VisibilityCommonizer.equalizing() + private val typeParameters = TypeParameterListCommonizer.default(cache) + private val valueParameters = ValueParameterListCommonizer.default(cache) + private var hasStableParameterNames = true + private var hasSynthesizedParameterNames = false + + override fun commonizationResult() = CommonClassConstructor( + isPrimary = isPrimary, + kind = kind, + visibility = visibility.result, + typeParameters = typeParameters.result, + valueParameters = valueParameters.result, + hasStableParameterNames = hasStableParameterNames, + hasSynthesizedParameterNames = hasSynthesizedParameterNames + ) + + override fun initialize(first: ClassConstructor) { + isPrimary = first.isPrimary + kind = first.kind + } + + override fun doCommonizeWith(next: ClassConstructor): Boolean { + val result = isPrimary == next.isPrimary + && kind == next.kind + && visibility.commonizeWith(next) + && typeParameters.commonizeWith(next.typeParameters) + && valueParameters.commonizeWith(next.valueParameters) + + if (result) { + hasStableParameterNames = hasStableParameterNames && next.hasStableParameterNames + hasSynthesizedParameterNames = hasSynthesizedParameterNames || next.hasSynthesizedParameterNames + } + + return result + } +} diff --git a/konan/commonizer/src/org/jetbrains/kotlin/descriptors/commonizer/core/CommonizationVisitor.kt b/konan/commonizer/src/org/jetbrains/kotlin/descriptors/commonizer/core/CommonizationVisitor.kt new file mode 100644 index 00000000000..10b5277924e --- /dev/null +++ b/konan/commonizer/src/org/jetbrains/kotlin/descriptors/commonizer/core/CommonizationVisitor.kt @@ -0,0 +1,117 @@ +/* + * 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.commonizer.CommonizedGroupMap +import org.jetbrains.kotlin.descriptors.commonizer.fqNameWithTypeParameters +import org.jetbrains.kotlin.descriptors.commonizer.mergedtree.ir.* +import org.jetbrains.kotlin.types.KotlinType +import java.lang.IllegalStateException + +internal class CommonizationVisitor( + private val root: RootNode +) : NodeVisitor { + override fun visitRootNode(node: RootNode, data: Unit) { + check(node === root) + check(node.common() != null) // root should already be commonized + + node.modules.forEach { module -> + module.accept(this, Unit) + } + } + + override fun visitModuleNode(node: ModuleNode, data: Unit) { + node.common() // commonize module + + node.packages.forEach { pkg -> + pkg.accept(this, Unit) + } + } + + override fun visitPackageNode(node: PackageNode, data: Unit) { + node.common() // commonize package + + node.properties.forEach { property -> + property.accept(this, Unit) + } + + node.functions.forEach { function -> + function.accept(this, Unit) + } + + node.classes.forEach { clazz -> + clazz.accept(this, Unit) + } + + node.typeAliases.forEach { typeAlias -> + typeAlias.accept(this, Unit) + } + } + + override fun visitPropertyNode(node: PropertyNode, data: Unit) { + node.common() // commonize property + } + + override fun visitFunctionNode(node: FunctionNode, data: Unit) { + node.common() // commonize function + } + + override fun visitClassNode(node: ClassNode, data: Unit) { + val commonClass = node.common() as CommonClassDeclaration? // commonize class + + node.constructors.forEach { constructor -> + constructor.accept(this, Unit) + } + + node.properties.forEach { property -> + property.accept(this, Unit) + } + + node.functions.forEach { function -> + function.accept(this, Unit) + } + + node.classes.forEach { clazz -> + clazz.accept(this, Unit) + } + + if (commonClass != null) { + // companion object should have the same FQ name for each target class, then it could be set to common class + val companionObjectFqName = node.target.mapTo(HashSet()) { it!!.companion }.singleOrNull() + if (companionObjectFqName != null) { + val companionObjectNode = root.cache.classes[companionObjectFqName] + ?: throw IllegalStateException("Can't find companion object with FQ name $companionObjectFqName") + + if (companionObjectNode.common() != null) { + // companion object has been successfully commonized + commonClass.companion = companionObjectFqName + } + } + + // find out common (and commonized) supertypes + val supertypesMap = CommonizedGroupMap(node.target.size) + node.target.forEachIndexed { index, clazz -> + for (supertype in clazz!!.supertypes) { + supertypesMap[supertype.fqNameWithTypeParameters][index] = supertype + } + } + + for ((_, supertypesGroup) in supertypesMap) { + val commonSupertype = commonize(supertypesGroup.toList(), TypeCommonizer.default(root.cache)) + if (commonSupertype != null) + commonClass.supertypes += commonSupertype + } + } + } + + override fun visitClassConstructorNode(node: ClassConstructorNode, data: Unit) { + node.common() // commonize constructor + } + + override fun visitTypeAliasNode(node: TypeAliasNode, data: Unit) { + node.common() // commonize type alias + } +} diff --git a/konan/commonizer/src/org/jetbrains/kotlin/descriptors/commonizer/core/Commonizer.kt b/konan/commonizer/src/org/jetbrains/kotlin/descriptors/commonizer/core/Commonizer.kt index 6ca0efe4514..fa1b38bd587 100644 --- a/konan/commonizer/src/org/jetbrains/kotlin/descriptors/commonizer/core/Commonizer.kt +++ b/konan/commonizer/src/org/jetbrains/kotlin/descriptors/commonizer/core/Commonizer.kt @@ -10,4 +10,38 @@ interface Commonizer { fun commonizeWith(next: T): Boolean } +abstract class AbstractStandardCommonizer : Commonizer { + private enum class State { + EMPTY, + ERROR, + IN_PROGRESS + } + + private var state = State.EMPTY + + final override val result: R + get() = when (state) { + State.EMPTY, State.ERROR -> throw IllegalCommonizerStateException() + State.IN_PROGRESS -> commonizationResult() + } + + final override fun commonizeWith(next: T): Boolean { + if (state == State.ERROR) + return false + + if (state == State.EMPTY) + initialize(next) + + val result = doCommonizeWith(next) + state = if (!result) State.ERROR else State.IN_PROGRESS + + return result + } + + protected abstract fun commonizationResult(): R + + protected abstract fun initialize(first: T) + protected abstract fun doCommonizeWith(next: T): Boolean +} + class IllegalCommonizerStateException : IllegalStateException("Illegal commonizer state: error or empty") diff --git a/konan/commonizer/src/org/jetbrains/kotlin/descriptors/commonizer/core/ExtensionReceiverCommonizer.kt b/konan/commonizer/src/org/jetbrains/kotlin/descriptors/commonizer/core/ExtensionReceiverCommonizer.kt index af02cde578d..2adde57d5cc 100644 --- a/konan/commonizer/src/org/jetbrains/kotlin/descriptors/commonizer/core/ExtensionReceiverCommonizer.kt +++ b/konan/commonizer/src/org/jetbrains/kotlin/descriptors/commonizer/core/ExtensionReceiverCommonizer.kt @@ -5,47 +5,21 @@ package org.jetbrains.kotlin.descriptors.commonizer.core -import org.jetbrains.kotlin.descriptors.ReceiverParameterDescriptor +import org.jetbrains.kotlin.descriptors.commonizer.mergedtree.ir.ClassifiersCache +import org.jetbrains.kotlin.descriptors.commonizer.mergedtree.ir.ExtensionReceiver +import org.jetbrains.kotlin.types.KotlinType import org.jetbrains.kotlin.types.UnwrappedType -interface ExtensionReceiverCommonizer : Commonizer { +interface ExtensionReceiverCommonizer : Commonizer { companion object { - fun default(): ExtensionReceiverCommonizer = DefaultExtensionReceiverCommonizer() + fun default(cache: ClassifiersCache): ExtensionReceiverCommonizer = DefaultExtensionReceiverCommonizer(cache) } } -private class DefaultExtensionReceiverCommonizer : ExtensionReceiverCommonizer { - private enum class State { - EMPTY, - ERROR, - WITH_RECEIVER, - WITHOUT_RECEIVER - } - - private var state = State.EMPTY - private lateinit var receiverType: TypeCommonizer - - override val result: UnwrappedType? - get() = when (state) { - State.EMPTY, State.ERROR -> throw IllegalCommonizerStateException() - State.WITH_RECEIVER -> receiverType.result - State.WITHOUT_RECEIVER -> null // null receiverType means there is no extension receiver - } - - override fun commonizeWith(next: ReceiverParameterDescriptor?): Boolean { - state = when (state) { - State.ERROR -> State.ERROR - State.EMPTY -> next?.let { - receiverType = TypeCommonizer.default() - doCommonizeWith(next) - } ?: State.WITHOUT_RECEIVER - State.WITH_RECEIVER -> next?.let(::doCommonizeWith) ?: State.ERROR - State.WITHOUT_RECEIVER -> next?.let { State.ERROR } ?: State.WITHOUT_RECEIVER - } - - return state != State.ERROR - } - - private fun doCommonizeWith(receiverParameter: ReceiverParameterDescriptor) = - if (receiverType.commonizeWith(receiverParameter.type)) State.WITH_RECEIVER else State.ERROR -} +private class DefaultExtensionReceiverCommonizer(cache: ClassifiersCache) : + ExtensionReceiverCommonizer, + AbstractNullableCommonizer( + wrappedCommonizerFactory = { TypeCommonizer.default(cache) }, + extractor = { it.type }, + builder = { it } + ) 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 e732a47b1b9..05120892983 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 @@ -5,32 +5,40 @@ package org.jetbrains.kotlin.descriptors.commonizer.core -import org.jetbrains.kotlin.descriptors.SimpleFunctionDescriptor +import org.jetbrains.kotlin.descriptors.commonizer.mergedtree.ir.ClassifiersCache 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 : AbstractCallableMemberCommonizer() { +class FunctionCommonizer(cache: ClassifiersCache) : AbstractFunctionOrPropertyCommonizer(cache) { private val modifiers = FunctionModifiersCommonizer.default() - private val valueParameters = ValueParameterListCommonizer.default() + private val valueParameters = ValueParameterListCommonizer.default(cache) + private var hasStableParameterNames = true + private var hasSynthesizedParameterNames = false - override val result: Function - get() = when (state) { - State.EMPTY, State.ERROR -> throw IllegalCommonizerStateException() - State.IN_PROGRESS -> CommonFunction( - name = name, - modality = modality.result, - visibility = visibility.result, - extensionReceiver = extensionReceiver.result?.toReceiverNoAnnotations(), - returnType = returnType.result, - modifiers = modifiers.result, - valueParameters = valueParameters.result, - typeParameters = typeParameters.result - ) + override fun commonizationResult() = CommonFunction( + name = name, + modality = modality.result, + visibility = visibility.result, + extensionReceiver = extensionReceiver.result?.toReceiverNoAnnotations(), + returnType = returnType.result, + modifiers = modifiers.result, + valueParameters = valueParameters.result, + typeParameters = typeParameters.result, + hasStableParameterNames = hasStableParameterNames, + hasSynthesizedParameterNames = hasSynthesizedParameterNames + ) + + override fun doCommonizeWith(next: Function): Boolean { + val result = super.doCommonizeWith(next) + && modifiers.commonizeWith(next) + && valueParameters.commonizeWith(next.valueParameters) + + if (result) { + hasStableParameterNames = hasStableParameterNames && next.hasStableParameterNames + hasSynthesizedParameterNames = hasSynthesizedParameterNames || next.hasSynthesizedParameterNames } - override fun canBeCommonized(next: SimpleFunctionDescriptor) = true - - override fun commonizeSpecifics(next: SimpleFunctionDescriptor) = - modifiers.commonizeWith(next) && valueParameters.commonizeWith(next.valueParameters) + return result + } } diff --git a/konan/commonizer/src/org/jetbrains/kotlin/descriptors/commonizer/core/FunctionModifiersCommonizer.kt b/konan/commonizer/src/org/jetbrains/kotlin/descriptors/commonizer/core/FunctionModifiersCommonizer.kt index 15e69e8d75a..d4f1b937f5d 100644 --- a/konan/commonizer/src/org/jetbrains/kotlin/descriptors/commonizer/core/FunctionModifiersCommonizer.kt +++ b/konan/commonizer/src/org/jetbrains/kotlin/descriptors/commonizer/core/FunctionModifiersCommonizer.kt @@ -5,10 +5,9 @@ package org.jetbrains.kotlin.descriptors.commonizer.core -import org.jetbrains.kotlin.descriptors.SimpleFunctionDescriptor import org.jetbrains.kotlin.descriptors.commonizer.mergedtree.ir.FunctionModifiers -interface FunctionModifiersCommonizer : Commonizer { +interface FunctionModifiersCommonizer : Commonizer { companion object { fun default(): FunctionModifiersCommonizer = DefaultFunctionModifiersCommonizer() } @@ -21,7 +20,7 @@ private class DefaultFunctionModifiersCommonizer : FunctionModifiersCommonizer { override val result: FunctionModifiers get() = modifiers?.takeIf { !error } ?: throw IllegalCommonizerStateException() - override fun commonizeWith(next: SimpleFunctionDescriptor): Boolean { + override fun commonizeWith(next: FunctionModifiers): Boolean { if (error) return false @@ -51,7 +50,7 @@ private class DefaultFunctionModifiersCommonizer : FunctionModifiersCommonizer { override var isSuspend: Boolean, override var isExternal: Boolean ) : FunctionModifiers { - constructor(function: SimpleFunctionDescriptor) : this( + constructor(function: FunctionModifiers) : this( function.isOperator, function.isInfix, function.isInline, diff --git a/konan/commonizer/src/org/jetbrains/kotlin/descriptors/commonizer/core/PropertyCommonizer.kt b/konan/commonizer/src/org/jetbrains/kotlin/descriptors/commonizer/core/PropertyCommonizer.kt index 7b89358871e..78f22a352a4 100644 --- a/konan/commonizer/src/org/jetbrains/kotlin/descriptors/commonizer/core/PropertyCommonizer.kt +++ b/konan/commonizer/src/org/jetbrains/kotlin/descriptors/commonizer/core/PropertyCommonizer.kt @@ -5,39 +5,39 @@ package org.jetbrains.kotlin.descriptors.commonizer.core -import org.jetbrains.kotlin.descriptors.PropertyDescriptor +import org.jetbrains.kotlin.descriptors.commonizer.mergedtree.ir.ClassifiersCache import org.jetbrains.kotlin.descriptors.commonizer.mergedtree.ir.CommonProperty import org.jetbrains.kotlin.descriptors.commonizer.mergedtree.ir.ExtensionReceiver.Companion.toReceiverNoAnnotations import org.jetbrains.kotlin.descriptors.commonizer.mergedtree.ir.Property -class PropertyCommonizer : AbstractCallableMemberCommonizer() { +class PropertyCommonizer(cache: ClassifiersCache) : AbstractFunctionOrPropertyCommonizer(cache) { private val setter = PropertySetterCommonizer.default() private var isExternal = true - override val result: Property - get() = when (state) { - State.EMPTY, State.ERROR -> throw IllegalCommonizerStateException() - State.IN_PROGRESS -> CommonProperty( - name = name, - modality = modality.result, - visibility = visibility.result, - isExternal = isExternal, - extensionReceiver = extensionReceiver.result?.toReceiverNoAnnotations(), - returnType = returnType.result, - setter = setter.result, - typeParameters = typeParameters.result - ) + override fun commonizationResult() = CommonProperty( + name = name, + modality = modality.result, + visibility = visibility.result, + isExternal = isExternal, + extensionReceiver = extensionReceiver.result?.toReceiverNoAnnotations(), + returnType = returnType.result, + setter = setter.result, + typeParameters = typeParameters.result + ) + + override fun doCommonizeWith(next: Property): Boolean { + when { + next.isConst -> return false // expect property can't be const because expect can't have initializer + next.isLateInit -> return false // expect property can't be lateinit } - override fun canBeCommonized(next: PropertyDescriptor) = when { - next.isConst -> false // expect property can't be const because expect can't have initializer - next.isLateInit -> false // expect property can't be lateinit - else -> true - } + val result = super.doCommonizeWith(next) + && setter.commonizeWith(next.setter) - override fun commonizeSpecifics(next: PropertyDescriptor): Boolean { - isExternal = isExternal && next.isExternal + if (result) { + isExternal = isExternal && next.isExternal + } - return setter.commonizeWith(next.setter) + return result } } diff --git a/konan/commonizer/src/org/jetbrains/kotlin/descriptors/commonizer/core/PropertySetterCommonizer.kt b/konan/commonizer/src/org/jetbrains/kotlin/descriptors/commonizer/core/PropertySetterCommonizer.kt index 45fb9070ef4..4d5e76c4ae5 100644 --- a/konan/commonizer/src/org/jetbrains/kotlin/descriptors/commonizer/core/PropertySetterCommonizer.kt +++ b/konan/commonizer/src/org/jetbrains/kotlin/descriptors/commonizer/core/PropertySetterCommonizer.kt @@ -5,11 +5,11 @@ package org.jetbrains.kotlin.descriptors.commonizer.core -import org.jetbrains.kotlin.descriptors.PropertySetterDescriptor import org.jetbrains.kotlin.descriptors.Visibility +import org.jetbrains.kotlin.descriptors.commonizer.mergedtree.ir.DeclarationWithVisibility import org.jetbrains.kotlin.descriptors.commonizer.mergedtree.ir.Setter -interface PropertySetterCommonizer : Commonizer { +interface PropertySetterCommonizer : Commonizer { companion object { fun default(): PropertySetterCommonizer = DefaultPropertySetterCommonizer() } @@ -17,8 +17,8 @@ interface PropertySetterCommonizer : Commonizer( + AbstractNullableCommonizer( wrappedCommonizerFactory = { VisibilityCommonizer.equalizing() }, - extractor = { it.visibility }, + extractor = { it }, builder = { Setter.createDefaultNoAnnotations(it) } ) diff --git a/konan/commonizer/src/org/jetbrains/kotlin/descriptors/commonizer/core/TypeAliasCommonizer.kt b/konan/commonizer/src/org/jetbrains/kotlin/descriptors/commonizer/core/TypeAliasCommonizer.kt new file mode 100644 index 00000000000..ed2451e9558 --- /dev/null +++ b/konan/commonizer/src/org/jetbrains/kotlin/descriptors/commonizer/core/TypeAliasCommonizer.kt @@ -0,0 +1,40 @@ +/* + * 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.ClassKind +import org.jetbrains.kotlin.descriptors.Modality +import org.jetbrains.kotlin.descriptors.commonizer.mergedtree.ir.* +import org.jetbrains.kotlin.name.Name +import org.jetbrains.kotlin.types.checker.isClassType + +class TypeAliasCommonizer(cache: ClassifiersCache) : AbstractStandardCommonizer() { + private lateinit var name: Name + private val underlyingType = TypeCommonizer.default(cache) + private val visibility = VisibilityCommonizer.lowering(allowPrivate = true) + + override fun commonizationResult() = CommonClassDeclaration( + name = name, + typeParameters = emptyList(), + kind = ClassKind.CLASS, + modality = Modality.FINAL, + visibility = visibility.result, + isCompanion = false, + isInline = false, + isInner = false + ) + + override fun initialize(first: TypeAlias) { + name = first.name + } + + override fun doCommonizeWith(next: TypeAlias) = + next.typeParameters.isEmpty() // TAs with declared type parameters can't be commonized + && next.underlyingType.arguments.isEmpty() // TAs with functional types or types with parameters at the right-hand side can't be commonized + && next.underlyingType.isClassType // right-hand side could have only class + && underlyingType.commonizeWith(next.underlyingType) + && visibility.commonizeWith(next) +} 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 9045e260b50..37fb24dce3c 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 @@ -5,73 +5,60 @@ package org.jetbrains.kotlin.descriptors.commonizer.core -import org.jetbrains.kotlin.builtins.KotlinBuiltIns import org.jetbrains.kotlin.descriptors.* -import org.jetbrains.kotlin.name.FqName -import org.jetbrains.kotlin.name.Name +import org.jetbrains.kotlin.descriptors.commonizer.isUnderStandardKotlinPackages +import org.jetbrains.kotlin.descriptors.commonizer.mergedtree.ir.ClassifiersCache +import org.jetbrains.kotlin.descriptors.commonizer.mergedtree.ir.Node import org.jetbrains.kotlin.resolve.descriptorUtil.fqNameSafe -import org.jetbrains.kotlin.resolve.descriptorUtil.parentsWithSelf import org.jetbrains.kotlin.types.* -import org.jetbrains.kotlin.types.checker.isClassType interface TypeCommonizer : Commonizer { companion object { - fun default(): TypeCommonizer = DefaultTypeCommonizer() + fun default(cache: ClassifiersCache): TypeCommonizer = DefaultTypeCommonizer(cache) } } -private class DefaultTypeCommonizer : TypeCommonizer { - private enum class State { - EMPTY, - ERROR, - IN_PROGRESS - } +private class DefaultTypeCommonizer(private val cache: ClassifiersCache) : + TypeCommonizer, + AbstractStandardCommonizer() { - private var state = State.EMPTY private lateinit var temp: UnwrappedType - override val result: UnwrappedType - get() = when (state) { - State.EMPTY, State.ERROR -> throw IllegalCommonizerStateException() - State.IN_PROGRESS -> temp - } + override fun commonizationResult() = temp - override fun commonizeWith(next: KotlinType): Boolean { - state = when (state) { - State.ERROR -> State.ERROR - State.EMPTY -> { - temp = next.unwrap() - State.IN_PROGRESS - } - // TODO: maybe cache type comparison results? - State.IN_PROGRESS -> { - if (!areTypesEqual(temp, next.unwrap())) State.ERROR else State.IN_PROGRESS - } - } - - return state != State.ERROR + override fun initialize(first: KotlinType) { + temp = first.unwrap() } + + override fun doCommonizeWith(next: KotlinType) = areTypesEqual(cache, temp, next.unwrap()) } /** * See also [AbstractStrictEqualityTypeChecker]. */ -internal fun areTypesEqual(a: UnwrappedType, b: UnwrappedType): Boolean = when { +internal fun areTypesEqual(cache: ClassifiersCache, a: UnwrappedType, b: UnwrappedType): Boolean = when { a === b -> true - a is SimpleType -> (b is SimpleType) && areSimpleTypesEqual(a, b) + a is SimpleType -> (b is SimpleType) && areSimpleTypesEqual(cache, a, b) a is FlexibleType -> (b is FlexibleType) - && areSimpleTypesEqual(a.lowerBound, b.lowerBound) && areSimpleTypesEqual(a.upperBound, b.upperBound) + && areSimpleTypesEqual(cache, a.lowerBound, b.lowerBound) && areSimpleTypesEqual(cache, a.upperBound, b.upperBound) else -> false } -private fun areSimpleTypesEqual(a: SimpleType, b: SimpleType): Boolean = areAbbreviatedTypesEqual( +private fun areSimpleTypesEqual(cache: ClassifiersCache, a: SimpleType, b: SimpleType): Boolean = areAbbreviatedTypesEqual( + cache, a = a.getAbbreviation() ?: a, aExpanded = a, b = b.getAbbreviation() ?: b, bExpandedType = b ) -private fun areAbbreviatedTypesEqual(a: SimpleType, aExpanded: SimpleType, b: SimpleType, bExpandedType: SimpleType): Boolean { +private fun areAbbreviatedTypesEqual( + cache: ClassifiersCache, + a: SimpleType, + aExpanded: SimpleType, + b: SimpleType, + bExpandedType: SimpleType +): Boolean { if (a.arguments.size != b.arguments.size || a.isMarkedNullable != b.isMarkedNullable || a.isDefinitelyNotNullType != b.isDefinitelyNotNullType @@ -82,27 +69,36 @@ 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 isUnderStandardKotlinPackages = if ( + val aFqName = aDescriptor.fqNameSafe + val bFqName = bDescriptor.fqNameSafe + + if (aFqName != bFqName) + return false + + val isClassOrTypeAliasUnderStandardKotlinPackages = + // N.B. only for descriptors that represent classes or type aliases, but not type parameters! aDescriptor is ClassifierDescriptorWithTypeParameters - && bDescriptor is ClassifierDescriptorWithTypeParameters - ) { - // N.B. only for descriptors that represent classes or type aliases, but not type parameters: - - val aFqName = aDescriptor.fqNameSafe - - aFqName.isUnderStandardKotlinPackages - // make sure that FQ names of abbreviated types (e.g. representing type aliases) are equal - && aFqName == bDescriptor.fqNameSafe - // 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 + && bDescriptor is ClassifierDescriptorWithTypeParameters + && aFqName.isUnderStandardKotlinPackages + // 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 = 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) + val descriptorsCanBeCommonized = + /* either class or type alias from Kotlin stdlib */ isClassOrTypeAliasUnderStandardKotlinPackages + || /* or descriptors themselves can be commonized */ when (aDescriptor) { + is TypeParameterDescriptor -> { + // Real type parameter commonization is performed in TypeParameterCommonizer. + // Here it is enough to check that FQ names are equal (already done above). + bDescriptor is TypeParameterDescriptor + } + is ClassDescriptor -> { + (bDescriptor is ClassDescriptor) && cache.classes[aFqName].canBeCommonized() + } + is TypeAliasDescriptor -> { + (bDescriptor is TypeAliasDescriptor) && cache.typeAliases[aFqName].canBeCommonized() + } else -> false } @@ -121,7 +117,7 @@ private fun areAbbreviatedTypesEqual(a: SimpleType, aExpanded: SimpleType, b: Si if (aArg.projectionKind != bArg.projectionKind) return false - if (!areTypesEqual(aArg.type.unwrap(), bArg.type.unwrap())) + if (!areTypesEqual(cache, aArg.type.unwrap(), bArg.type.unwrap())) return false } } @@ -133,59 +129,13 @@ private fun areAbbreviatedTypesEqual(a: SimpleType, aExpanded: SimpleType, b: Si private inline fun SimpleType.nonNullDescriptorExpectedErrorMessage() = "${TypeCommonizer::class} couldn't obtain non-null descriptor from: $this, ${this::class}" -private val standardKotlinPackages = setOf( - KotlinBuiltIns.BUILT_INS_PACKAGE_NAME, - Name.identifier("kotlinx") -) - -private val FqName.isUnderStandardKotlinPackages: Boolean - get() = pathSegments().firstOrNull() in standardKotlinPackages - -// TODO: extract this method to class commonizer -private fun canBeCommonized(a: ClassDescriptor, b: ClassDescriptor) = when { - a.kind != b.kind -> false - !areFqNamesEqual(a, b) -> false - // TODO: compare class descriptors (visibility, modifiers, etc) - else -> true -} - -// TODO: extract this method to type alias commonizer -private fun canBeCommonized(a: TypeAliasDescriptor, b: TypeAliasDescriptor): Boolean { - if (!areFqNamesEqual(a, b)) - return false - - val aUnderlyingType = a.underlyingType - val bUnderlyingType = b.underlyingType - - if (aUnderlyingType.arguments.isNotEmpty() || bUnderlyingType.arguments.isNotEmpty()) - return false // type aliases with functional types at the right-hand side can't be commonized - - if (!aUnderlyingType.isClassType || !bUnderlyingType.isClassType) - return false // right-hand side could have only classes - - return areTypesEqual(aUnderlyingType, bUnderlyingType) -} - -private fun canBeCommonized(a: TypeParameterDescriptor, b: TypeParameterDescriptor): Boolean { - // 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() - - while (p1.hasNext() && p2.hasNext()) { - val n1 = p1.next() - val n2 = p2.next() - - when (n1) { - is ModuleDescriptor -> return n2 is ModuleDescriptor - is PackageFragmentDescriptor -> return (n2 is PackageFragmentDescriptor) && n1.fqName == n2.fqName - else -> if (n1.name != n2.name) return false - } +@Suppress("NOTHING_TO_INLINE") +private inline fun Node<*, *>?.canBeCommonized() = + if (this == null) { + // No node means that the class or type alias was not subject for commonization at all, probably it lays + // not in commonized module descriptors but somewhere in their dependencies. + true + } else { + // If entry is present, then contents (common declaration) should not be null. + common() != null } - - return false -} 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 index df4b3ac4fe5..0161173db1a 100644 --- a/konan/commonizer/src/org/jetbrains/kotlin/descriptors/commonizer/core/TypeParameterCommonizer.kt +++ b/konan/commonizer/src/org/jetbrains/kotlin/descriptors/commonizer/core/TypeParameterCommonizer.kt @@ -5,7 +5,7 @@ package org.jetbrains.kotlin.descriptors.commonizer.core -import org.jetbrains.kotlin.descriptors.TypeParameterDescriptor +import org.jetbrains.kotlin.descriptors.commonizer.mergedtree.ir.ClassifiersCache import org.jetbrains.kotlin.descriptors.commonizer.mergedtree.ir.CommonTypeParameter import org.jetbrains.kotlin.descriptors.commonizer.mergedtree.ir.TypeParameter import org.jetbrains.kotlin.name.Name @@ -13,70 +13,53 @@ import org.jetbrains.kotlin.types.KotlinType import org.jetbrains.kotlin.types.UnwrappedType import org.jetbrains.kotlin.types.Variance -interface TypeParameterCommonizer : Commonizer { +interface TypeParameterCommonizer : Commonizer { companion object { - fun default(): TypeParameterCommonizer = DefaultTypeParameterCommonizer() + fun default(cache: ClassifiersCache): TypeParameterCommonizer = DefaultTypeParameterCommonizer(cache) } } -private class DefaultTypeParameterCommonizer : TypeParameterCommonizer { - private enum class State { - EMPTY, - ERROR, - IN_PROGRESS - } +private class DefaultTypeParameterCommonizer(cache: ClassifiersCache) : + TypeParameterCommonizer, + AbstractStandardCommonizer() { - private var state = State.EMPTY private lateinit var name: Name private var isReified = false private lateinit var variance: Variance - private val upperBounds = TypeParameterUpperBoundsCommonizer() + private val upperBounds = TypeParameterUpperBoundsCommonizer(cache) - override val result: TypeParameter - get() = when (state) { - State.EMPTY, State.ERROR -> throw IllegalCommonizerStateException() - State.IN_PROGRESS -> CommonTypeParameter( - name = name, - isReified = isReified, - variance = variance, - upperBounds = upperBounds.result - ) - } + override fun commonizationResult() = 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 + override fun initialize(first: TypeParameter) { + name = first.name + isReified = first.isReified + variance = first.variance } + + override fun doCommonizeWith(next: TypeParameter) = + name == next.name + && isReified == next.isReified + && variance == next.variance + && upperBounds.commonizeWith(next.upperBounds) } -private class TypeParameterUpperBoundsCommonizer : AbstractListCommonizer( - singleElementCommonizerFactory = { TypeCommonizer.default() } +private class TypeParameterUpperBoundsCommonizer(cache: ClassifiersCache) : AbstractListCommonizer( + singleElementCommonizerFactory = { TypeCommonizer.default(cache) } ) -interface TypeParameterListCommonizer : Commonizer, List> { +interface TypeParameterListCommonizer : Commonizer, List> { companion object { - fun default(): TypeParameterListCommonizer = DefaultTypeParameterListCommonizer() + fun default(cache: ClassifiersCache): TypeParameterListCommonizer = DefaultTypeParameterListCommonizer(cache) } } -private class DefaultTypeParameterListCommonizer : +private class DefaultTypeParameterListCommonizer(cache: ClassifiersCache) : TypeParameterListCommonizer, - AbstractNamedListCommonizer( - singleElementCommonizerFactory = { TypeParameterCommonizer.default() } + AbstractListCommonizer( + singleElementCommonizerFactory = { TypeParameterCommonizer.default(cache) } ) 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 01811851b9b..2f69b632ab4 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 @@ -5,83 +5,67 @@ package org.jetbrains.kotlin.descriptors.commonizer.core -import org.jetbrains.kotlin.descriptors.ValueParameterDescriptor import org.jetbrains.kotlin.descriptors.commonizer.mergedtree.ir.CommonValueParameter import org.jetbrains.kotlin.descriptors.commonizer.mergedtree.ir.ValueParameter import org.jetbrains.kotlin.descriptors.commonizer.isNull +import org.jetbrains.kotlin.descriptors.commonizer.mergedtree.ir.ClassifiersCache import org.jetbrains.kotlin.name.Name import org.jetbrains.kotlin.types.UnwrappedType -interface ValueParameterCommonizer : Commonizer { +interface ValueParameterCommonizer : Commonizer { companion object { - fun default(): ValueParameterCommonizer = DefaultValueParameterCommonizer() + fun default(cache: ClassifiersCache): ValueParameterCommonizer = DefaultValueParameterCommonizer(cache) } } -private class DefaultValueParameterCommonizer : ValueParameterCommonizer { - private enum class State { - EMPTY, - ERROR, - IN_PROGRESS - } +private class DefaultValueParameterCommonizer(cache: ClassifiersCache) : + ValueParameterCommonizer, + AbstractStandardCommonizer() { private lateinit var name: Name - private val returnType = TypeCommonizer.default() + private val returnType = TypeCommonizer.default(cache) private var varargElementType: UnwrappedType? = null private var isCrossinline = true private var isNoinline = true - private var state = State.EMPTY - - override val result: ValueParameter - get() = when (state) { - State.EMPTY, State.ERROR -> throw IllegalCommonizerStateException() - State.IN_PROGRESS -> CommonValueParameter( - name = name, - returnType = returnType.result, - varargElementType = varargElementType, - isCrossinline = isCrossinline, - isNoinline = isNoinline - ) - } - - override fun commonizeWith(next: ValueParameterDescriptor): Boolean { - if (state == State.ERROR) - return true - - val result = !next.declaresDefaultValue() && returnType.commonizeWith(next.type) - state = if (!result) - State.ERROR - else when { - state == State.EMPTY -> { - name = next.name - varargElementType = next.varargElementType?.unwrap() - isCrossinline = next.isCrossinline - isNoinline = next.isNoinline - - State.IN_PROGRESS - } - varargElementType.isNull() != next.varargElementType.isNull() -> State.ERROR - else -> { - isCrossinline = isCrossinline && next.isCrossinline - isNoinline = isNoinline && next.isNoinline - - State.IN_PROGRESS - } - } - - return state != State.ERROR - } -} - -interface ValueParameterListCommonizer : Commonizer, List> { - companion object { - fun default(): ValueParameterListCommonizer = DefaultValueParameterListCommonizer() - } -} - -private class DefaultValueParameterListCommonizer : - ValueParameterListCommonizer, - AbstractNamedListCommonizer( - singleElementCommonizerFactory = { ValueParameterCommonizer.default() } + override fun commonizationResult() = CommonValueParameter( + name = name, + returnType = returnType.result, + varargElementType = varargElementType, + isCrossinline = isCrossinline, + isNoinline = isNoinline + ) + + override fun initialize(first: ValueParameter) { + name = first.name + varargElementType = first.varargElementType + isCrossinline = first.isCrossinline + isNoinline = first.isNoinline + } + + override fun doCommonizeWith(next: ValueParameter): Boolean { + val result = !next.declaresDefaultValue + && varargElementType.isNull() == next.varargElementType.isNull() + && name == next.name + && returnType.commonizeWith(next.returnType) + + if (result) { + isCrossinline = isCrossinline && next.isCrossinline + isNoinline = isNoinline && next.isNoinline + } + + return result + } +} + +interface ValueParameterListCommonizer : Commonizer, List> { + companion object { + fun default(cache: ClassifiersCache): ValueParameterListCommonizer = DefaultValueParameterListCommonizer(cache) + } +} + +private class DefaultValueParameterListCommonizer(cache: ClassifiersCache) : + ValueParameterListCommonizer, + AbstractListCommonizer( + singleElementCommonizerFactory = { ValueParameterCommonizer.default(cache) } ) diff --git a/konan/commonizer/src/org/jetbrains/kotlin/descriptors/commonizer/core/VisibilityCommonizer.kt b/konan/commonizer/src/org/jetbrains/kotlin/descriptors/commonizer/core/VisibilityCommonizer.kt index 1ec9c58d68f..5e71e7109a5 100644 --- a/konan/commonizer/src/org/jetbrains/kotlin/descriptors/commonizer/core/VisibilityCommonizer.kt +++ b/konan/commonizer/src/org/jetbrains/kotlin/descriptors/commonizer/core/VisibilityCommonizer.kt @@ -5,13 +5,14 @@ package org.jetbrains.kotlin.descriptors.commonizer.core -import org.jetbrains.kotlin.descriptors.Visibilities -import org.jetbrains.kotlin.descriptors.Visibility +import org.jetbrains.kotlin.descriptors.* +import org.jetbrains.kotlin.descriptors.commonizer.mergedtree.ir.DeclarationWithVisibility +import org.jetbrains.kotlin.descriptors.commonizer.mergedtree.ir.MaybeVirtualCallableMember -abstract class VisibilityCommonizer : Commonizer { +abstract class VisibilityCommonizer(private val allowPrivate: Boolean) : Commonizer { companion object { - fun lowering(): VisibilityCommonizer = LoweringVisibilityCommonizer() + fun lowering(allowPrivate: Boolean = false): VisibilityCommonizer = LoweringVisibilityCommonizer(allowPrivate) fun equalizing(): VisibilityCommonizer = EqualizingVisibilityCommonizer() } @@ -22,33 +23,60 @@ abstract class VisibilityCommonizer : Commonizer { return temp?.takeIf { it != Visibilities.UNKNOWN } ?: throw IllegalCommonizerStateException() } - override fun commonizeWith(next: Visibility): Boolean { + override fun commonizeWith(next: DeclarationWithVisibility): Boolean { if (temp == Visibilities.UNKNOWN) return false - if (Visibilities.isPrivate(next)) { + val nextVisibility = next.visibility + if (!allowPrivate && Visibilities.isPrivate(nextVisibility) || !canBeCommonized(next)) { temp = Visibilities.UNKNOWN return false } - temp = temp?.let { temp -> getNext(temp, next) } ?: next + temp = temp?.let { temp -> getNext(temp, nextVisibility) } ?: nextVisibility return temp != Visibilities.UNKNOWN } + protected abstract fun canBeCommonized(next: DeclarationWithVisibility): Boolean protected abstract fun getNext(current: Visibility, next: Visibility): Visibility } -private class LoweringVisibilityCommonizer : VisibilityCommonizer() { +/** + * Choose the lowest possible visibility ignoring private for all given member descriptors, if possible. + * If at least one member descriptor is virtual, then the commonizer succeeds only if all visibilities are equal. + */ +private class LoweringVisibilityCommonizer(allowPrivate: Boolean) : VisibilityCommonizer(allowPrivate) { + private var atLeastOneVirtualCallableMet = false + private var atLeastTwoVisibilitiesMet = false + + override fun canBeCommonized(next: DeclarationWithVisibility): Boolean { + if (!atLeastOneVirtualCallableMet) + atLeastOneVirtualCallableMet = (next as? MaybeVirtualCallableMember)?.isVirtual == true + + return !atLeastOneVirtualCallableMet || !atLeastTwoVisibilitiesMet + } + override fun getNext(current: Visibility, next: Visibility): Visibility { val comparisonResult: Int = Visibilities.compare(current, next) ?: return Visibilities.UNKNOWN // two visibilities that can't be compared against each one, ex: protected vs internal + if (!atLeastTwoVisibilitiesMet) + atLeastTwoVisibilitiesMet = comparisonResult != 0 + + if (atLeastOneVirtualCallableMet && atLeastTwoVisibilitiesMet) + return Visibilities.UNKNOWN + return if (comparisonResult <= 0) current else next } } -private class EqualizingVisibilityCommonizer : VisibilityCommonizer() { +/** + * Make sure that visibilities of all member descriptors are equal are not private according to [Visibilities.isPrivate]. + */ +private class EqualizingVisibilityCommonizer : VisibilityCommonizer(false) { + override fun canBeCommonized(next: DeclarationWithVisibility) = true + override fun getNext(current: Visibility, next: Visibility) = if (Visibilities.compare(current, next) == 0) current else Visibilities.UNKNOWN } diff --git a/konan/commonizer/src/org/jetbrains/kotlin/descriptors/commonizer/facade.kt b/konan/commonizer/src/org/jetbrains/kotlin/descriptors/commonizer/facade.kt index 0b300da5a59..190db97da9a 100644 --- a/konan/commonizer/src/org/jetbrains/kotlin/descriptors/commonizer/facade.kt +++ b/konan/commonizer/src/org/jetbrains/kotlin/descriptors/commonizer/facade.kt @@ -8,12 +8,13 @@ package org.jetbrains.kotlin.descriptors.commonizer import org.jetbrains.kotlin.builtins.DefaultBuiltIns import org.jetbrains.kotlin.descriptors.ModuleDescriptor import org.jetbrains.kotlin.descriptors.commonizer.builder.DeclarationsBuilderVisitor +import org.jetbrains.kotlin.descriptors.commonizer.core.CommonizationVisitor import org.jetbrains.kotlin.descriptors.commonizer.mergedtree.mergeRoots import org.jetbrains.kotlin.storage.LockBasedStorageManager class CommonizationSession { - // TODO: add progress tracker - // TODO: add logger + // TODO (???): add progress tracker + // TODO (???): add logger } class CommonizationParameters { @@ -63,13 +64,17 @@ fun runCommonization(parameters: CommonizationParameters): CommonizationResult { if (!parameters.hasIntersection()) return NothingToCommonize - val mergedTree = mergeRoots(parameters.getModulesByTargets()) - + // build merged tree: val storageManager = LockBasedStorageManager("Declaration descriptors commonization") + val mergedTree = mergeRoots(storageManager, parameters.getModulesByTargets()) + + // commonize: + mergedTree.accept(CommonizationVisitor(mergedTree), Unit) var commonModules: Collection? = null val otherModulesByTargets = LinkedHashMap>() + // build resulting descriptors: val visitor = DeclarationsBuilderVisitor(storageManager, DefaultBuiltIns.Instance) { targetId, commonizedModules -> when (targetId) { is CommonTargetId -> { diff --git a/konan/commonizer/src/org/jetbrains/kotlin/descriptors/commonizer/mergedtree/callableMembers.kt b/konan/commonizer/src/org/jetbrains/kotlin/descriptors/commonizer/mergedtree/callableMembers.kt new file mode 100644 index 00000000000..498bdaf57d6 --- /dev/null +++ b/konan/commonizer/src/org/jetbrains/kotlin/descriptors/commonizer/mergedtree/callableMembers.kt @@ -0,0 +1,37 @@ +/* + * 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 + +import org.jetbrains.kotlin.descriptors.ClassConstructorDescriptor +import org.jetbrains.kotlin.descriptors.PropertyDescriptor +import org.jetbrains.kotlin.descriptors.SimpleFunctionDescriptor +import org.jetbrains.kotlin.descriptors.commonizer.mergedtree.ir.ClassifiersCache +import org.jetbrains.kotlin.descriptors.commonizer.mergedtree.ir.buildClassConstructorNode +import org.jetbrains.kotlin.descriptors.commonizer.mergedtree.ir.buildFunctionNode +import org.jetbrains.kotlin.descriptors.commonizer.mergedtree.ir.buildPropertyNode +import org.jetbrains.kotlin.storage.NullableLazyValue +import org.jetbrains.kotlin.storage.StorageManager + +internal fun mergeProperties( + storageManager: StorageManager, + cache: ClassifiersCache, + containingDeclarationCommon: NullableLazyValue<*>?, + properties: List +) = buildPropertyNode(storageManager, cache, containingDeclarationCommon, properties) + +internal fun mergeFunctions( + storageManager: StorageManager, + cache: ClassifiersCache, + containingDeclarationCommon: NullableLazyValue<*>?, + properties: List +) = buildFunctionNode(storageManager, cache, containingDeclarationCommon, properties) + +internal fun mergeClassConstructors( + storageManager: StorageManager, + cache: ClassifiersCache, + containingDeclarationCommon: NullableLazyValue<*>?, + constructors: List +) = buildClassConstructorNode(storageManager, cache, containingDeclarationCommon, constructors) diff --git a/konan/commonizer/src/org/jetbrains/kotlin/descriptors/commonizer/mergedtree/classifiers.kt b/konan/commonizer/src/org/jetbrains/kotlin/descriptors/commonizer/mergedtree/classifiers.kt new file mode 100644 index 00000000000..96614e7451c --- /dev/null +++ b/konan/commonizer/src/org/jetbrains/kotlin/descriptors/commonizer/mergedtree/classifiers.kt @@ -0,0 +1,64 @@ +/* + * 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 + +import org.jetbrains.kotlin.descriptors.* +import org.jetbrains.kotlin.descriptors.commonizer.CommonizedGroupMap +import org.jetbrains.kotlin.descriptors.commonizer.mergedtree.ir.* +import org.jetbrains.kotlin.descriptors.commonizer.mergedtree.ir.RootNode.ClassifiersCacheImpl +import org.jetbrains.kotlin.descriptors.commonizer.mergedtree.ir.buildClassNode +import org.jetbrains.kotlin.descriptors.commonizer.mergedtree.ir.buildTypeAliasNode +import org.jetbrains.kotlin.name.Name +import org.jetbrains.kotlin.storage.NullableLazyValue +import org.jetbrains.kotlin.storage.StorageManager + +internal fun mergeClasses( + storageManager: StorageManager, + cacheRW: ClassifiersCacheImpl, + containingDeclarationCommon: NullableLazyValue<*>?, + classes: List +): ClassNode { + val node = buildClassNode(storageManager, cacheRW, containingDeclarationCommon, classes) + + val constructorsMap = CommonizedGroupMap(classes.size) + val propertiesMap = CommonizedGroupMap(classes.size) + val functionsMap = CommonizedGroupMap(classes.size) + val classesMap = CommonizedGroupMap(classes.size) + + classes.forEachIndexed { index, clazz -> + clazz?.constructors?.forEach { constructorsMap[ConstructorApproximationKey(it)][index] = it } + clazz?.unsubstitutedMemberScope?.collectMembers( + CallableMemberCollector { propertiesMap[PropertyApproximationKey(it)][index] = it }, + CallableMemberCollector { functionsMap[FunctionApproximationKey(it)][index] = it }, + Collector { classesMap[it.name][index] = it } + ) + } + + for ((_, constructorsGroup) in constructorsMap) { + node.constructors += mergeClassConstructors(storageManager, cacheRW, node.common, constructorsGroup.toList()) + } + + for ((_, propertiesGroup) in propertiesMap) { + node.properties += mergeProperties(storageManager, cacheRW, node.common, propertiesGroup.toList()) + } + + for ((_, functionsGroup) in functionsMap) { + node.functions += mergeFunctions(storageManager, cacheRW, node.common, functionsGroup.toList()) + } + + for ((_, classesGroup) in classesMap) { + node.classes += mergeClasses(storageManager, cacheRW, node.common, classesGroup.toList()) + } + + return node +} + +internal fun mergeTypeAliases( + storageManager: StorageManager, + cacheRW: ClassifiersCacheImpl, + typeAliases: List +) = buildTypeAliasNode(storageManager, cacheRW, typeAliases) + diff --git a/konan/commonizer/src/org/jetbrains/kotlin/descriptors/commonizer/mergedtree/functions.kt b/konan/commonizer/src/org/jetbrains/kotlin/descriptors/commonizer/mergedtree/functions.kt deleted file mode 100644 index 27b4070bc7b..00000000000 --- a/konan/commonizer/src/org/jetbrains/kotlin/descriptors/commonizer/mergedtree/functions.kt +++ /dev/null @@ -1,11 +0,0 @@ -/* - * 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 - -import org.jetbrains.kotlin.descriptors.SimpleFunctionDescriptor -import org.jetbrains.kotlin.descriptors.commonizer.mergedtree.ir.buildFunctionNode - -internal fun mergeFunctions(properties: List) = buildFunctionNode(properties) 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 deleted file mode 100644 index 836ed8f4b90..00000000000 --- a/konan/commonizer/src/org/jetbrains/kotlin/descriptors/commonizer/mergedtree/ir/CallableMember.kt +++ /dev/null @@ -1,53 +0,0 @@ -/* - * 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.CallableMemberDescriptor -import org.jetbrains.kotlin.descriptors.Modality -import org.jetbrains.kotlin.descriptors.ReceiverParameterDescriptor -import org.jetbrains.kotlin.descriptors.Visibility -import org.jetbrains.kotlin.descriptors.annotations.Annotations -import org.jetbrains.kotlin.descriptors.commonizer.mergedtree.ir.ExtensionReceiver.Companion.toReceiver -import org.jetbrains.kotlin.name.Name -import org.jetbrains.kotlin.types.UnwrappedType - -interface CallableMember : DeclarationWithTypeParameters { - val annotations: Annotations - val name: Name - val modality: Modality - val visibility: Visibility - val isExternal: Boolean - val extensionReceiver: ExtensionReceiver? - val returnType: UnwrappedType - val kind: CallableMemberDescriptor.Kind -} - -abstract class CommonCallableMember : CallableMember { - final override val annotations: Annotations get() = Annotations.EMPTY - final override val kind get() = CallableMemberDescriptor.Kind.DECLARATION -} - -abstract class TargetCallableMember(protected val descriptor: T) : CallableMember { - final override val annotations: Annotations get() = descriptor.annotations - final override val name: Name get() = descriptor.name - final override val modality: Modality get() = descriptor.modality - final override val visibility: Visibility get() = descriptor.visibility - final override val isExternal: Boolean get() = descriptor.isExternal - 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( - val annotations: Annotations, - val type: UnwrappedType -) { - companion object { - fun UnwrappedType.toReceiverNoAnnotations() = ExtensionReceiver(Annotations.EMPTY, this) - fun ReceiverParameterDescriptor.toReceiver() = ExtensionReceiver(annotations, type.unwrap()) - } -} diff --git a/konan/commonizer/src/org/jetbrains/kotlin/descriptors/commonizer/mergedtree/ir/ClassDeclaration.kt b/konan/commonizer/src/org/jetbrains/kotlin/descriptors/commonizer/mergedtree/ir/ClassDeclaration.kt new file mode 100644 index 00000000000..23e17ce4ded --- /dev/null +++ b/konan/commonizer/src/org/jetbrains/kotlin/descriptors/commonizer/mergedtree/ir/ClassDeclaration.kt @@ -0,0 +1,107 @@ +/* + * 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.* +import org.jetbrains.kotlin.descriptors.annotations.Annotations +import org.jetbrains.kotlin.name.FqName +import org.jetbrains.kotlin.name.Name +import org.jetbrains.kotlin.resolve.descriptorUtil.fqNameSafe +import org.jetbrains.kotlin.types.KotlinType +import kotlin.LazyThreadSafetyMode.PUBLICATION + +interface ClassDeclaration : AnnotatedDeclaration, NamedDeclaration, DeclarationWithTypeParameters, DeclarationWithVisibility { + val companion: FqName? // null means no companion object + val kind: ClassKind + val modality: Modality + val isCompanion: Boolean + val isData: Boolean + val isInline: Boolean + val isInner: Boolean + val isExternal: Boolean + val sealedSubclasses: Collection + val supertypes: Collection +} + +interface ClassConstructor : AnnotatedDeclaration, DeclarationWithTypeParameters, DeclarationWithVisibility, CallableMemberWithParameters { + val isPrimary: Boolean + val kind: CallableMemberDescriptor.Kind +} + +data class CommonClassDeclaration( + override val name: Name, + override val typeParameters: List, + override val kind: ClassKind, + override val modality: Modality, + override val visibility: Visibility, + override val isCompanion: Boolean, + override val isInline: Boolean, + override val isInner: Boolean +) : ClassDeclaration { + override val annotations get() = Annotations.EMPTY + override val isData get() = false + override val isExternal get() = false + override var companion: FqName? = null + override val sealedSubclasses: Collection get() = emptyList() + override val supertypes: MutableCollection = ArrayList() +} + +data class CommonClassConstructor( + override val isPrimary: Boolean, + override val kind: CallableMemberDescriptor.Kind, + override val visibility: Visibility, + override val typeParameters: List, + override val valueParameters: List, + override val hasStableParameterNames: Boolean, + override val hasSynthesizedParameterNames: Boolean +) : ClassConstructor { + override val annotations: Annotations get() = Annotations.EMPTY +} + +class TargetClassDeclaration(private val descriptor: ClassDescriptor) : ClassDeclaration { + override val annotations get() = descriptor.annotations + override val name get() = descriptor.name + override val typeParameters by lazy(PUBLICATION) { descriptor.declaredTypeParameters.map(::TargetTypeParameter) } + override val companion by lazy(PUBLICATION) { descriptor.companionObjectDescriptor?.fqNameSafe } + override val kind get() = descriptor.kind + override val modality get() = descriptor.modality + override val visibility get() = descriptor.visibility + override val isCompanion get() = descriptor.isCompanionObject + override val isData get() = descriptor.isData + override val isInline get() = descriptor.isInline + override val isInner get() = descriptor.isInner + override val isExternal get() = descriptor.isExternal + override val sealedSubclasses by lazy(PUBLICATION) { descriptor.sealedSubclasses.map { it.fqNameSafe } } + override val supertypes: Collection get() = descriptor.typeConstructor.supertypes +} + +class TargetClassConstructor(private val descriptor: ClassConstructorDescriptor) : ClassConstructor { + override val isPrimary: Boolean get() = descriptor.isPrimary + override val kind: CallableMemberDescriptor.Kind get() = descriptor.kind + override val annotations: Annotations get() = descriptor.annotations + override val visibility: Visibility get() = descriptor.visibility + override val typeParameters: List by lazy(PUBLICATION) { descriptor.typeParameters.map(::TargetTypeParameter) } + override val valueParameters: List by lazy(PUBLICATION) { descriptor.valueParameters.map(::PlatformValueParameter) } + override val hasStableParameterNames: Boolean get() = descriptor.hasStableParameterNames() + override val hasSynthesizedParameterNames: Boolean get() = descriptor.hasSynthesizedParameterNames() +} + +object ClassDeclarationRecursionMarker : ClassDeclaration, RecursionMarker { + override val companion: FqName? get() = unsupported() + override val kind: ClassKind get() = unsupported() + override val modality: Modality get() = unsupported() + override val isCompanion: Boolean get() = unsupported() + override val isData: Boolean get() = unsupported() + override val isInline: Boolean get() = unsupported() + override val isInner: Boolean get() = unsupported() + override val isExternal: Boolean get() = unsupported() + override val sealedSubclasses: Collection get() = unsupported() + override val supertypes: Collection get() = unsupported() + override val annotations: Annotations get() = unsupported() + override val name: Name get() = unsupported() + override val visibility: Visibility get() = unsupported() + override val typeParameters: List get() = unsupported() +} diff --git a/konan/commonizer/src/org/jetbrains/kotlin/descriptors/commonizer/mergedtree/ir/Declaration.kt b/konan/commonizer/src/org/jetbrains/kotlin/descriptors/commonizer/mergedtree/ir/Declaration.kt new file mode 100644 index 00000000000..eb75c600ef2 --- /dev/null +++ b/konan/commonizer/src/org/jetbrains/kotlin/descriptors/commonizer/mergedtree/ir/Declaration.kt @@ -0,0 +1,51 @@ +/* + * 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.* +import org.jetbrains.kotlin.descriptors.annotations.Annotations +import org.jetbrains.kotlin.name.FqName +import org.jetbrains.kotlin.name.Name + +/** + * An intermediate representation of [DeclarationDescriptor]s for commonization purposes. + * + * The most essential subclasses are: + * - [ClassDeclaration] - represents [ClassDescriptor] + * - [TypeAlias] - [TypeAliasDescriptor] + * - [Function] - [SimpleFunctionDescriptor] + * - [Property] - [PropertyDescriptor] + * - [Package] - union of multiple [PackageFragmentDescriptor]s with the same [FqName] contributed by commonized [ModuleDescriptor]s + * - [Module] - [ModuleDescriptor] + * - [Root] - the root of the whole IR tree + */ +interface Declaration + +interface AnnotatedDeclaration : Declaration { + val annotations: Annotations +} + +interface NamedDeclaration : Declaration { + val name: Name +} + +interface DeclarationWithVisibility : Declaration { + val visibility: Visibility +} + +interface MaybeVirtualCallableMember : DeclarationWithVisibility { + val isVirtual: Boolean +} + +interface DeclarationWithTypeParameters : Declaration { + val typeParameters: List +} + +/** Indicates presence of recursion in lazy calculations. */ +interface RecursionMarker : Declaration + +@Suppress("unused") +internal fun Declaration.unsupported(): Nothing = error("This method should never be called") 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 e3562b98267..ba5be2966aa 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 @@ -12,6 +12,7 @@ import org.jetbrains.kotlin.descriptors.Visibility import org.jetbrains.kotlin.descriptors.annotations.Annotations import org.jetbrains.kotlin.name.Name import org.jetbrains.kotlin.types.UnwrappedType +import kotlin.LazyThreadSafetyMode.PUBLICATION interface FunctionModifiers { val isOperator: Boolean @@ -22,10 +23,14 @@ interface FunctionModifiers { val isExternal: Boolean } -interface Function : CallableMember, FunctionModifiers, Declaration { +interface CallableMemberWithParameters { val valueParameters: List + val hasStableParameterNames: Boolean + val hasSynthesizedParameterNames: Boolean } +interface Function : FunctionOrProperty, FunctionModifiers, CallableMemberWithParameters + data class CommonFunction( override val name: Name, override val modality: Modality, @@ -34,16 +39,20 @@ data class CommonFunction( override val returnType: UnwrappedType, private val modifiers: FunctionModifiers, override val valueParameters: List, - override val typeParameters: List -) : CommonCallableMember(), Function, FunctionModifiers by modifiers + override val typeParameters: List, + override val hasStableParameterNames: Boolean, + override val hasSynthesizedParameterNames: Boolean +) : CommonFunctionOrProperty(), Function, FunctionModifiers by modifiers -class TargetFunction(descriptor: SimpleFunctionDescriptor) : TargetCallableMember(descriptor), Function { - override val isOperator: Boolean get() = descriptor.isOperator - override val isInfix: Boolean get() = descriptor.isInfix - override val isInline: Boolean get() = descriptor.isInline - override val isTailrec: Boolean get() = descriptor.isTailrec - override val isSuspend: Boolean get() = descriptor.isSuspend - override val valueParameters: List get() = descriptor.valueParameters.map(::PlatformValueParameter) +class TargetFunction(descriptor: SimpleFunctionDescriptor) : TargetFunctionOrProperty(descriptor), Function { + override val isOperator get() = descriptor.isOperator + override val isInfix get() = descriptor.isInfix + override val isInline get() = descriptor.isInline + override val isTailrec get() = descriptor.isTailrec + override val isSuspend get() = descriptor.isSuspend + override val valueParameters by lazy(PUBLICATION) { descriptor.valueParameters.map(::PlatformValueParameter) } + override val hasStableParameterNames: Boolean get() = descriptor.hasStableParameterNames() + override val hasSynthesizedParameterNames: Boolean get() = descriptor.hasSynthesizedParameterNames() } interface ValueParameter { @@ -63,16 +72,16 @@ data class CommonValueParameter( override val isCrossinline: Boolean, override val isNoinline: Boolean ) : ValueParameter { - override val annotations: Annotations get() = Annotations.EMPTY - override val declaresDefaultValue: Boolean get() = false + override val annotations get() = Annotations.EMPTY + override val declaresDefaultValue get() = false } data class PlatformValueParameter(private val descriptor: ValueParameterDescriptor) : ValueParameter { - override val name: Name get() = descriptor.name - override val annotations: Annotations get() = descriptor.annotations - override val returnType: UnwrappedType get() = descriptor.returnType!!.unwrap() - override val varargElementType: UnwrappedType? get() = descriptor.varargElementType?.unwrap() - override val declaresDefaultValue: Boolean get() = descriptor.declaresDefaultValue() - override val isCrossinline: Boolean get() = descriptor.isCrossinline - override val isNoinline: Boolean get() = descriptor.isNoinline + override val name get() = descriptor.name + override val annotations get() = descriptor.annotations + override val returnType by lazy(PUBLICATION) { descriptor.returnType!!.unwrap() } + override val varargElementType by lazy(PUBLICATION) { descriptor.varargElementType?.unwrap() } + override val declaresDefaultValue get() = descriptor.declaresDefaultValue() + override val isCrossinline get() = descriptor.isCrossinline + override val isNoinline get() = descriptor.isNoinline } diff --git a/konan/commonizer/src/org/jetbrains/kotlin/descriptors/commonizer/mergedtree/ir/FunctionOrProperty.kt b/konan/commonizer/src/org/jetbrains/kotlin/descriptors/commonizer/mergedtree/ir/FunctionOrProperty.kt new file mode 100644 index 00000000000..897afcd96bc --- /dev/null +++ b/konan/commonizer/src/org/jetbrains/kotlin/descriptors/commonizer/mergedtree/ir/FunctionOrProperty.kt @@ -0,0 +1,53 @@ +/* + * 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.* +import org.jetbrains.kotlin.descriptors.annotations.Annotations +import org.jetbrains.kotlin.descriptors.commonizer.mergedtree.ir.ExtensionReceiver.Companion.toReceiver +import org.jetbrains.kotlin.types.UnwrappedType +import kotlin.LazyThreadSafetyMode.PUBLICATION + +interface FunctionOrProperty : AnnotatedDeclaration, NamedDeclaration, DeclarationWithTypeParameters, MaybeVirtualCallableMember { + val modality: Modality + val isExternal: Boolean + val extensionReceiver: ExtensionReceiver? + val returnType: UnwrappedType + val kind: CallableMemberDescriptor.Kind + val isNonAbstractCallableMemberInInterface: Boolean +} + +abstract class CommonFunctionOrProperty : FunctionOrProperty { + final override val annotations get() = Annotations.EMPTY + final override val kind get() = CallableMemberDescriptor.Kind.DECLARATION + final override val isVirtual get() = unsupported() + final override val isNonAbstractCallableMemberInInterface get() = unsupported() +} + +abstract class TargetFunctionOrProperty(protected val descriptor: T) : FunctionOrProperty { + final override val annotations get() = descriptor.annotations + final override val name get() = descriptor.name + final override val modality get() = descriptor.modality + final override val visibility get() = descriptor.visibility + final override val isExternal get() = descriptor.isExternal + final override val extensionReceiver by lazy(PUBLICATION) { descriptor.extensionReceiverParameter?.toReceiver() } + final override val returnType by lazy(PUBLICATION) { descriptor.returnType!!.unwrap() } + final override val kind get() = descriptor.kind + final override val isVirtual get() = descriptor.isOverridable + final override val isNonAbstractCallableMemberInInterface + get() = modality != Modality.ABSTRACT && (descriptor.containingDeclaration as? ClassDescriptor)?.kind == ClassKind.INTERFACE + final override val typeParameters by lazy(PUBLICATION) { descriptor.typeParameters.map(::TargetTypeParameter) } +} + +data class ExtensionReceiver( + val annotations: Annotations, + val type: UnwrappedType +) { + companion object { + fun UnwrappedType.toReceiverNoAnnotations() = ExtensionReceiver(Annotations.EMPTY, this) + fun ReceiverParameterDescriptor.toReceiver() = ExtensionReceiver(annotations, type.unwrap()) + } +} diff --git a/konan/commonizer/src/org/jetbrains/kotlin/descriptors/commonizer/mergedtree/ir/NodeVisitor.kt b/konan/commonizer/src/org/jetbrains/kotlin/descriptors/commonizer/mergedtree/ir/NodeVisitor.kt index 9c0b415f492..7636120bb6f 100644 --- a/konan/commonizer/src/org/jetbrains/kotlin/descriptors/commonizer/mergedtree/ir/NodeVisitor.kt +++ b/konan/commonizer/src/org/jetbrains/kotlin/descriptors/commonizer/mergedtree/ir/NodeVisitor.kt @@ -11,4 +11,7 @@ interface NodeVisitor { fun visitPackageNode(node: PackageNode, data: T): R fun visitPropertyNode(node: PropertyNode, data: T): R fun visitFunctionNode(node: FunctionNode, data: T): R + fun visitClassNode(node: ClassNode, data: T): R + fun visitClassConstructorNode(node: ClassConstructorNode, data: T): R + fun visitTypeAliasNode(node: TypeAliasNode, data: T): R } 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 8e1e62e861f..b3db717f50e 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 @@ -12,10 +12,11 @@ import org.jetbrains.kotlin.types.UnwrappedType import org.jetbrains.kotlin.descriptors.commonizer.mergedtree.ir.Getter.Companion.toGetter import org.jetbrains.kotlin.descriptors.commonizer.mergedtree.ir.Setter.Companion.toSetter import org.jetbrains.kotlin.resolve.constants.ConstantValue +import kotlin.LazyThreadSafetyMode.PUBLICATION -interface Property : CallableMember, Declaration { +interface Property : FunctionOrProperty { val isVar: Boolean - val lateInit: Boolean + val isLateInit: Boolean val isConst: Boolean val isDelegate: Boolean val getter: Getter? @@ -34,28 +35,27 @@ data class CommonProperty( override val returnType: UnwrappedType, override val setter: Setter?, override val typeParameters: List -) : CommonCallableMember(), Property { - override val isVar: Boolean get() = setter != null - override val lateInit: Boolean get() = false - override val isConst: Boolean get() = false - override val isDelegate: Boolean get() = false - override val getter: Getter get() = Getter.DEFAULT_NO_ANNOTATIONS +) : CommonFunctionOrProperty(), Property { + override val isVar get() = setter != null + override val isLateInit get() = false + override val isConst get() = false + override val isDelegate get() = false + override val getter get() = Getter.DEFAULT_NO_ANNOTATIONS override val backingFieldAnnotations: Annotations? get() = null override val delegateFieldAnnotations: Annotations? get() = null override val compileTimeInitializer: ConstantValue<*>? get() = null } -class TargetProperty(descriptor: PropertyDescriptor) : TargetCallableMember(descriptor), Property { - override val isVar: Boolean get() = descriptor.isVar - override val lateInit: Boolean get() = descriptor.isLateInit - override val isConst: Boolean get() = descriptor.isConst - @Suppress("DEPRECATION") - override val isDelegate: Boolean get() = descriptor.isDelegated - override val getter: Getter? get() = descriptor.getter?.toGetter() - override val setter: Setter? get() = descriptor.setter?.toSetter() - override val backingFieldAnnotations: Annotations? get() = descriptor.backingField?.annotations - override val delegateFieldAnnotations: Annotations? get() = descriptor.delegateField?.annotations - override val compileTimeInitializer: ConstantValue<*>? get() = descriptor.compileTimeInitializer +class TargetProperty(descriptor: PropertyDescriptor) : TargetFunctionOrProperty(descriptor), Property { + override val isVar get() = descriptor.isVar + override val isLateInit get() = descriptor.isLateInit + override val isConst get() = descriptor.isConst + override val isDelegate get() = @Suppress("DEPRECATION") descriptor.isDelegated + override val getter by lazy(PUBLICATION) { descriptor.getter?.toGetter() } + override val setter by lazy(PUBLICATION) { descriptor.setter?.toSetter() } + override val backingFieldAnnotations get() = descriptor.backingField?.annotations + override val delegateFieldAnnotations get() = descriptor.delegateField?.annotations + override val compileTimeInitializer get() = descriptor.compileTimeInitializer } interface PropertyAccessor { @@ -85,11 +85,13 @@ data class Getter( data class Setter( override val annotations: Annotations, val parameterAnnotations: Annotations, - val visibility: Visibility, + override val visibility: Visibility, override val isDefault: Boolean, override val isExternal: Boolean, override val isInline: Boolean -) : PropertyAccessor { +) : PropertyAccessor, MaybeVirtualCallableMember { + override val isVirtual get() = false + companion object { fun createDefaultNoAnnotations(visibility: Visibility) = Setter( Annotations.EMPTY, diff --git a/konan/commonizer/src/org/jetbrains/kotlin/descriptors/commonizer/mergedtree/ir/TypeAlias.kt b/konan/commonizer/src/org/jetbrains/kotlin/descriptors/commonizer/mergedtree/ir/TypeAlias.kt new file mode 100644 index 00000000000..c4bd59f4b22 --- /dev/null +++ b/konan/commonizer/src/org/jetbrains/kotlin/descriptors/commonizer/mergedtree/ir/TypeAlias.kt @@ -0,0 +1,24 @@ +/* + * 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.TypeAliasDescriptor +import org.jetbrains.kotlin.types.SimpleType +import kotlin.LazyThreadSafetyMode.PUBLICATION + +interface TypeAlias : AnnotatedDeclaration, NamedDeclaration, DeclarationWithTypeParameters, DeclarationWithVisibility { + val underlyingType: SimpleType + val expandedType: SimpleType +} + +class TargetTypeAlias(private val descriptor: TypeAliasDescriptor) : TypeAlias { + override val annotations get() = descriptor.annotations + override val name get() = descriptor.name + override val typeParameters by lazy(PUBLICATION) { descriptor.declaredTypeParameters.map(::TargetTypeParameter) } + override val visibility get() = descriptor.visibility + override val underlyingType get() = descriptor.underlyingType + override val expandedType get() = descriptor.expandedType +} 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 index bdab7d02701..b7113caef13 100644 --- 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 @@ -10,6 +10,7 @@ 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 +import kotlin.LazyThreadSafetyMode.PUBLICATION interface TypeParameter { val annotations: Annotations @@ -19,23 +20,19 @@ interface TypeParameter { 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 + override val 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() } + override val annotations get() = descriptor.annotations + override val name get() = descriptor.name + override val isReified get() = descriptor.isReified + override val variance get() = descriptor.variance + override val upperBounds by lazy(PUBLICATION) { descriptor.upperBounds.map { it.unwrap() } } } diff --git a/konan/commonizer/src/org/jetbrains/kotlin/descriptors/commonizer/mergedtree/ir/nodeBuilders.kt b/konan/commonizer/src/org/jetbrains/kotlin/descriptors/commonizer/mergedtree/ir/nodeBuilders.kt index d3199f5ec30..93b421fa5d2 100644 --- a/konan/commonizer/src/org/jetbrains/kotlin/descriptors/commonizer/mergedtree/ir/nodeBuilders.kt +++ b/konan/commonizer/src/org/jetbrains/kotlin/descriptors/commonizer/mergedtree/ir/nodeBuilders.kt @@ -5,77 +5,193 @@ package org.jetbrains.kotlin.descriptors.commonizer.mergedtree.ir -import org.jetbrains.kotlin.descriptors.ModuleDescriptor -import org.jetbrains.kotlin.descriptors.PropertyDescriptor -import org.jetbrains.kotlin.descriptors.SimpleFunctionDescriptor +import org.jetbrains.kotlin.descriptors.* import org.jetbrains.kotlin.descriptors.commonizer.* import org.jetbrains.kotlin.descriptors.commonizer.CommonizedGroup -import org.jetbrains.kotlin.descriptors.commonizer.core.Commonizer -import org.jetbrains.kotlin.descriptors.commonizer.core.PropertyCommonizer -import org.jetbrains.kotlin.descriptors.commonizer.core.FunctionCommonizer +import org.jetbrains.kotlin.descriptors.commonizer.core.* import org.jetbrains.kotlin.descriptors.commonizer.firstNonNull +import org.jetbrains.kotlin.descriptors.commonizer.mergedtree.ir.RootNode.ClassifiersCacheImpl import org.jetbrains.kotlin.name.FqName +import org.jetbrains.kotlin.name.Name +import org.jetbrains.kotlin.resolve.descriptorUtil.fqNameSafe import org.jetbrains.kotlin.resolve.scopes.MemberScope +import org.jetbrains.kotlin.storage.LockBasedStorageManager +import org.jetbrains.kotlin.storage.NullableLazyValue +import org.jetbrains.kotlin.storage.StorageManager -internal fun buildRootNode(targets: List): RootNode = RootNode( - targets.map { Root(it) }, - Root(CommonTargetId(targets.toSet())) +internal fun buildRootNode( + targets: List +): RootNode = RootNode( + target = targets.map { Root(it) }, + common = LockBasedStorageManager.NO_LOCKS.createNullableLazyValue { + Root(CommonTargetId(targets.toSet())) + } ) -internal fun buildModuleNode(modules: List): ModuleNode = buildNode( - modules, - { Module(it.name) }, - { Module(it.firstNonNull().name) }, - ::ModuleNode +internal fun buildModuleNode( + moduleName: Name, + modules: List +): ModuleNode = buildNode( + storageManager = LockBasedStorageManager.NO_LOCKS, + descriptors = modules, + targetDeclarationProducer = { Module(moduleName) }, + commonValueProducer = { Module(moduleName) }, + recursionMarker = null, + nodeProducer = ::ModuleNode ) -internal fun buildPackageNode(packageFqName: FqName, packageMemberScopes: List): PackageNode = buildNode( - packageMemberScopes, - { Package(packageFqName) }, - { Package(packageFqName) }, - ::PackageNode +internal fun buildPackageNode( + packageFqName: FqName, + packageMemberScopes: List +): PackageNode = buildNode( + storageManager = LockBasedStorageManager.NO_LOCKS, + descriptors = packageMemberScopes, + targetDeclarationProducer = { Package(packageFqName) }, + commonValueProducer = { Package(packageFqName) }, + recursionMarker = null, + nodeProducer = ::PackageNode ) -internal fun buildPropertyNode(properties: List): PropertyNode = buildNode( - properties, - { TargetProperty(it) }, - { commonize(it, PropertyCommonizer()) }, - ::PropertyNode +internal fun buildPropertyNode( + storageManager: StorageManager, + cache: ClassifiersCache, + containingDeclarationCommon: NullableLazyValue<*>?, + properties: List +): PropertyNode = buildNode( + storageManager = storageManager, + descriptors = properties, + targetDeclarationProducer = ::TargetProperty, + commonValueProducer = { commonize(containingDeclarationCommon, it, PropertyCommonizer(cache)) }, + recursionMarker = null, + nodeProducer = ::PropertyNode ) -internal fun buildFunctionNode(functions: List): FunctionNode = buildNode( - functions, - { TargetFunction(it) }, - { commonize(it, FunctionCommonizer()) }, - ::FunctionNode +internal fun buildFunctionNode( + storageManager: StorageManager, + cache: ClassifiersCache, + containingDeclarationCommon: NullableLazyValue<*>?, + functions: List +): FunctionNode = buildNode( + storageManager = storageManager, + descriptors = functions, + targetDeclarationProducer = ::TargetFunction, + commonValueProducer = { commonize(containingDeclarationCommon, it, FunctionCommonizer(cache)) }, + recursionMarker = null, + nodeProducer = ::FunctionNode ) -private fun > buildNode( - descriptors: List, - targetDeclarationProducer: (T) -> D, - commonDeclarationProducer: (List) -> D?, - nodeProducer: (List, D?) -> N +internal fun buildClassNode( + storageManager: StorageManager, + cacheRW: ClassifiersCacheImpl, + containingDeclarationCommon: NullableLazyValue<*>?, + classes: List +): ClassNode { + val fqName = classes.firstNonNull().fqNameSafe + + return buildNode( + storageManager = storageManager, + descriptors = classes, + targetDeclarationProducer = ::TargetClassDeclaration, + commonValueProducer = { commonize(containingDeclarationCommon, it, ClassCommonizer(cacheRW)) }, + recursionMarker = ClassDeclarationRecursionMarker, + nodeProducer = ::ClassNode + ).also { node -> + node.fqName = fqName + cacheRW.classes.put(fqName, node)?.let { oldNode -> + throw IllegalStateException("Class node with FQ name $fqName has been overwritten: $oldNode") + } + } +} + +internal fun buildClassConstructorNode( + storageManager: StorageManager, + cache: ClassifiersCache, + containingDeclarationCommon: NullableLazyValue<*>?, + constructors: List +): ClassConstructorNode = buildNode( + storageManager = storageManager, + descriptors = constructors, + targetDeclarationProducer = ::TargetClassConstructor, + commonValueProducer = { commonize(containingDeclarationCommon, it, ClassConstructorCommonizer(cache)) }, + recursionMarker = null, + nodeProducer = ::ClassConstructorNode +) + +internal fun buildTypeAliasNode( + storageManager: StorageManager, + cacheRW: ClassifiersCacheImpl, + typeAliases: List +): TypeAliasNode { + val fqName = typeAliases.firstNonNull().fqNameSafe + + return buildNode( + storageManager = storageManager, + descriptors = typeAliases, + targetDeclarationProducer = ::TargetTypeAlias, + commonValueProducer = { commonize(it, TypeAliasCommonizer(cacheRW)) }, + recursionMarker = ClassDeclarationRecursionMarker, + nodeProducer = ::TypeAliasNode + ).also { node -> + node.fqName = fqName + cacheRW.typeAliases.put(fqName, node)?.let { oldNode -> + throw IllegalStateException("Type alias node with FQ name $fqName has been overwritten: $oldNode") + } + } +} + +private fun > buildNode( + storageManager: StorageManager, + descriptors: List, + targetDeclarationProducer: (D) -> T, + commonValueProducer: (List) -> R?, + recursionMarker: R?, + nodeProducer: (List, NullableLazyValue) -> N ): N { - val target = CommonizedGroup(descriptors.size) + val declarationsGroup = CommonizedGroup(descriptors.size) var canHaveCommon = descriptors.size > 1 descriptors.forEachIndexed { index, descriptor -> if (descriptor != null) - target[index] = targetDeclarationProducer(descriptor) + declarationsGroup[index] = targetDeclarationProducer(descriptor) else canHaveCommon = false } - val common = if (canHaveCommon) commonDeclarationProducer(descriptors) else null + val declarations = declarationsGroup.toList() - return nodeProducer(target.toList(), common) + val commonComputable: () -> R? = if (canHaveCommon) { + { commonValueProducer(declarations) } + } else { + { null } + } + + val commonLazyValue = if (recursionMarker != null) + storageManager.createRecursionTolerantNullableLazyValue(commonComputable, recursionMarker) + else + storageManager.createNullableLazyValue(commonComputable) + + return nodeProducer(declarations, commonLazyValue) } -private fun commonize(descriptors: List, commonizer: Commonizer): R? { - for (item in descriptors) { - if (item == null || !commonizer.commonizeWith(item)) +internal fun commonize(declarations: List, commonizer: Commonizer): R? { + for (declaration in declarations) { + if (declaration == null || !commonizer.commonizeWith(declaration)) return null } return commonizer.result } + +@Suppress("NOTHING_TO_INLINE") +private inline fun commonize( + containingDeclarationCommon: NullableLazyValue<*>?, + declarations: List, + commonizer: Commonizer +): R? { + if (containingDeclarationCommon != null && containingDeclarationCommon.invoke() == null) { + // don't commonize declaration if it has commonizable containing declaration that has not been successfully commonized + return null + } + + return commonize(declarations, commonizer) +} diff --git a/konan/commonizer/src/org/jetbrains/kotlin/descriptors/commonizer/mergedtree/ir/nodes.kt b/konan/commonizer/src/org/jetbrains/kotlin/descriptors/commonizer/mergedtree/ir/nodes.kt index d74efeaa82c..80496e7e1d8 100644 --- a/konan/commonizer/src/org/jetbrains/kotlin/descriptors/commonizer/mergedtree/ir/nodes.kt +++ b/konan/commonizer/src/org/jetbrains/kotlin/descriptors/commonizer/mergedtree/ir/nodes.kt @@ -5,20 +5,27 @@ package org.jetbrains.kotlin.descriptors.commonizer.mergedtree.ir -interface Declaration +import org.jetbrains.kotlin.name.FqName +import org.jetbrains.kotlin.storage.NullableLazyValue -interface Node { - val target: List - val common: D? +interface Node { + val target: List + val common: NullableLazyValue fun accept(visitor: NodeVisitor, data: T): R } class RootNode( override val target: List, - override val common: Root -) : Node { + override val common: NullableLazyValue +) : Node { + class ClassifiersCacheImpl : ClassifiersCache { + override val classes = HashMap() + override val typeAliases = HashMap() + } + val modules: MutableList = ArrayList() + val cache = ClassifiersCacheImpl() override fun accept(visitor: NodeVisitor, data: T): R = visitor.visitRootNode(this, data) @@ -26,8 +33,8 @@ class RootNode( class ModuleNode( override val target: List, - override val common: Module? -) : Node { + override val common: NullableLazyValue +) : Node { val packages: MutableList = ArrayList() override fun accept(visitor: NodeVisitor, data: T) = @@ -36,10 +43,12 @@ class ModuleNode( class PackageNode( override val target: List, - override val common: Package? -) : Node { + override val common: NullableLazyValue +) : Node { val properties: MutableList = ArrayList() val functions: MutableList = ArrayList() + val classes: MutableList = ArrayList() + val typeAliases: MutableList = ArrayList() override fun accept(visitor: NodeVisitor, data: T) = visitor.visitPackageNode(this, data) @@ -47,22 +56,60 @@ class PackageNode( class PropertyNode( override val target: List, - override val common: Property? -) : Node { + override val common: NullableLazyValue +) : Node { override fun accept(visitor: NodeVisitor, data: T) = visitor.visitPropertyNode(this, data) } class FunctionNode( override val target: List, - override val common: Function? -) : Node { + override val common: NullableLazyValue +) : Node { override fun accept(visitor: NodeVisitor, data: T) = visitor.visitFunctionNode(this, data) } -internal val Node.indexOfCommon: Int +class ClassNode( + override val target: List, + override val common: NullableLazyValue +) : Node { + lateinit var fqName: FqName + + val constructors: MutableList = ArrayList() + val properties: MutableList = ArrayList() + val functions: MutableList = ArrayList() + val classes: MutableList = ArrayList() + + override fun accept(visitor: NodeVisitor, data: T): R = + visitor.visitClassNode(this, data) +} + +class ClassConstructorNode( + override val target: List, + override val common: NullableLazyValue +) : Node { + override fun accept(visitor: NodeVisitor, data: T): R = + visitor.visitClassConstructorNode(this, data) +} + +class TypeAliasNode( + override val target: List, + override val common: NullableLazyValue +) : Node { + lateinit var fqName: FqName + + override fun accept(visitor: NodeVisitor, data: T): R = + visitor.visitTypeAliasNode(this, data) +} + +interface ClassifiersCache { + val classes: Map + val typeAliases: Map +} + +internal inline val Node<*, *>.indexOfCommon: Int get() = target.size -internal val Node.dimension: Int +internal inline val Node<*, *>.dimension: Int get() = target.size + 1 diff --git a/konan/commonizer/src/org/jetbrains/kotlin/descriptors/commonizer/mergedtree/memberScopes.kt b/konan/commonizer/src/org/jetbrains/kotlin/descriptors/commonizer/mergedtree/memberScopes.kt new file mode 100644 index 00000000000..77e770888a3 --- /dev/null +++ b/konan/commonizer/src/org/jetbrains/kotlin/descriptors/commonizer/mergedtree/memberScopes.kt @@ -0,0 +1,71 @@ +/* + * 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 + +import org.jetbrains.kotlin.descriptors.* +import org.jetbrains.kotlin.descriptors.commonizer.core.Commonizer +import org.jetbrains.kotlin.descriptors.commonizer.fqNameWithTypeParameters +import org.jetbrains.kotlin.name.Name +import org.jetbrains.kotlin.resolve.scopes.MemberScope + +internal fun MemberScope.collectMembers(vararg collectors: (DeclarationDescriptor) -> Boolean) = + getContributedDescriptors().forEach { member -> + collectors.any { it(member) } + // each member must be consumed, otherwise - error + || throw IllegalStateException("Unhandled member declaration: $member") + } + +@Suppress("FunctionName") +internal inline fun Collector( + crossinline typedCollector: (T) -> Unit +): (DeclarationDescriptor) -> Boolean = { candidate -> + if (candidate is T) { + typedCollector(candidate) + true + } else + false +} + +@Suppress("FunctionName") +internal inline fun CallableMemberCollector( + crossinline typedCollector: (T) -> Unit +): (DeclarationDescriptor) -> Boolean = Collector { candidate -> + if (candidate.kind.isReal) // omit fake overrides + typedCollector(candidate) +} + +/** Used for approximation of [PropertyDescriptor]s before running concrete [Commonizer]s */ +internal data class PropertyApproximationKey( + val name: Name, + val extensionReceiverParameter: String? +) { + constructor(property: PropertyDescriptor) : this( + property.name, + property.extensionReceiverParameter?.type?.fqNameWithTypeParameters + ) +} + +/** Used for approximation of [SimpleFunctionDescriptor]s before running concrete [Commonizer]s */ +internal data class FunctionApproximationKey( + val name: Name, + val valueParameters: List>, + val extensionReceiverParameter: String? +) { + constructor(function: SimpleFunctionDescriptor) : this( + function.name, + function.valueParameters.map { it.name to it.type.fqNameWithTypeParameters }, + function.extensionReceiverParameter?.type?.fqNameWithTypeParameters + ) +} + +/** Used for approximation of [ConstructorDescriptor]s before running concrete [Commonizer]s */ +internal data class ConstructorApproximationKey( + val valueParameters: List> +) { + constructor(constructor: ConstructorDescriptor) : this( + constructor.valueParameters.map { it.name to it.type.fqNameWithTypeParameters } + ) +} \ No newline at end of file diff --git a/konan/commonizer/src/org/jetbrains/kotlin/descriptors/commonizer/mergedtree/modules.kt b/konan/commonizer/src/org/jetbrains/kotlin/descriptors/commonizer/mergedtree/modules.kt index 033fa36b57d..7a0d5539fc1 100644 --- a/konan/commonizer/src/org/jetbrains/kotlin/descriptors/commonizer/mergedtree/modules.kt +++ b/konan/commonizer/src/org/jetbrains/kotlin/descriptors/commonizer/mergedtree/modules.kt @@ -8,16 +8,24 @@ package org.jetbrains.kotlin.descriptors.commonizer.mergedtree import org.jetbrains.kotlin.descriptors.ModuleDescriptor import org.jetbrains.kotlin.descriptors.commonizer.CommonizedGroupMap import org.jetbrains.kotlin.descriptors.commonizer.mergedtree.ir.ModuleNode +import org.jetbrains.kotlin.descriptors.commonizer.mergedtree.ir.RootNode import org.jetbrains.kotlin.descriptors.commonizer.mergedtree.ir.buildModuleNode import org.jetbrains.kotlin.descriptors.commonizer.toList import org.jetbrains.kotlin.descriptors.impl.ModuleDescriptorImpl import org.jetbrains.kotlin.name.FqName +import org.jetbrains.kotlin.name.Name import org.jetbrains.kotlin.resolve.scopes.ChainedMemberScope import org.jetbrains.kotlin.resolve.scopes.MemberScope +import org.jetbrains.kotlin.storage.StorageManager import org.jetbrains.kotlin.utils.alwaysTrue -internal fun mergeModules(modules: List): ModuleNode { - val node = buildModuleNode(modules) +internal fun mergeModules( + storageManager: StorageManager, + cacheRW: RootNode.ClassifiersCacheImpl, + moduleName: Name, + modules: List +): ModuleNode { + val node = buildModuleNode(moduleName, modules) val packageMemberScopesMap = CommonizedGroupMap(modules.size) @@ -28,7 +36,7 @@ internal fun mergeModules(modules: List): ModuleNode { } for ((packageFqName, packageMemberScopesGroup) in packageMemberScopesMap) { - node.packages += mergePackages(packageFqName, packageMemberScopesGroup.toList()) + node.packages += mergePackages(storageManager, cacheRW, packageFqName, packageMemberScopesGroup.toList()) } return node 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 0b48552d246..206aa00b72f 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 @@ -5,82 +5,56 @@ package org.jetbrains.kotlin.descriptors.commonizer.mergedtree +import org.jetbrains.kotlin.descriptors.ClassDescriptor import org.jetbrains.kotlin.descriptors.PropertyDescriptor import org.jetbrains.kotlin.descriptors.SimpleFunctionDescriptor +import org.jetbrains.kotlin.descriptors.TypeAliasDescriptor import org.jetbrains.kotlin.descriptors.commonizer.CommonizedGroupMap -import org.jetbrains.kotlin.descriptors.commonizer.fqNameWithTypeParameters +import org.jetbrains.kotlin.descriptors.commonizer.mergedtree.ir.PackageNode +import org.jetbrains.kotlin.descriptors.commonizer.mergedtree.ir.RootNode +import org.jetbrains.kotlin.descriptors.commonizer.mergedtree.ir.buildPackageNode import org.jetbrains.kotlin.name.FqName import org.jetbrains.kotlin.name.Name -import org.jetbrains.kotlin.resolve.scopes.DescriptorKindFilter import org.jetbrains.kotlin.resolve.scopes.MemberScope -import org.jetbrains.kotlin.descriptors.commonizer.mergedtree.ir.PackageNode -import org.jetbrains.kotlin.descriptors.commonizer.mergedtree.ir.buildPackageNode +import org.jetbrains.kotlin.storage.StorageManager internal fun mergePackages( + storageManager: StorageManager, + cacheRW: RootNode.ClassifiersCacheImpl, packageFqName: FqName, packageMemberScopes: List ): PackageNode { val node = buildPackageNode(packageFqName, packageMemberScopes) - val propertiesMap = CommonizedGroupMap(packageMemberScopes.size) - val functionsMap = CommonizedGroupMap(packageMemberScopes.size) + val propertiesMap = CommonizedGroupMap(packageMemberScopes.size) + val functionsMap = CommonizedGroupMap(packageMemberScopes.size) + val classesMap = CommonizedGroupMap(packageMemberScopes.size) + val typeAliasesMap = CommonizedGroupMap(packageMemberScopes.size) packageMemberScopes.forEachIndexed { index, memberScope -> - memberScope?.collectProperties { propertyKey, property -> - propertiesMap[propertyKey][index] = property - } - memberScope?.collectFunctions { functionKey, function -> - functionsMap[functionKey][index] = function - } + memberScope?.collectMembers( + CallableMemberCollector { propertiesMap[PropertyApproximationKey(it)][index] = it }, + CallableMemberCollector { functionsMap[FunctionApproximationKey(it)][index] = it }, + Collector { classesMap[it.name][index] = it }, + Collector { typeAliasesMap[it.name][index] = it } + ) } for ((_, propertiesGroup) in propertiesMap) { - node.properties += mergeProperties(propertiesGroup.toList()) + node.properties += mergeProperties(storageManager, cacheRW, null, propertiesGroup.toList()) } for ((_, functionsGroup) in functionsMap) { - node.functions += mergeFunctions(functionsGroup.toList()) + node.functions += mergeFunctions(storageManager, cacheRW, null, functionsGroup.toList()) } - // FIXME: traverse the rest - classes, typealiases + for ((_, classesGroup) in classesMap) { + node.classes += mergeClasses(storageManager, cacheRW, null, classesGroup.toList()) + } + + for ((_, typeAliasesGroup) in typeAliasesMap) { + node.typeAliases += mergeTypeAliases(storageManager, cacheRW, typeAliasesGroup.toList()) + } return node } - -internal data class PropertyKey( - val name: Name, - val extensionReceiverParameter: String? -) { - constructor(property: PropertyDescriptor) : this( - property.name, - property.extensionReceiverParameter?.type?.fqNameWithTypeParameters - ) -} - -internal fun MemberScope.collectProperties(collector: (PropertyKey, PropertyDescriptor) -> Unit) { - getContributedDescriptors(DescriptorKindFilter.VARIABLES).asSequence() - .filterIsInstance() - .forEach { property -> - collector(PropertyKey(property), property) - } -} - -internal data class FunctionKey( - val name: Name, - val valueParameters: List>, - val extensionReceiverParameter: String? -) { - constructor(function: SimpleFunctionDescriptor) : this( - function.name, - function.valueParameters.map { it.name to it.type.fqNameWithTypeParameters }, - function.extensionReceiverParameter?.type?.fqNameWithTypeParameters - ) -} - -internal fun MemberScope.collectFunctions(collector: (FunctionKey, SimpleFunctionDescriptor) -> Unit) { - getContributedDescriptors(DescriptorKindFilter.FUNCTIONS).asSequence() - .filterIsInstance() - .forEach { function -> - collector(FunctionKey(function), function) - } -} diff --git a/konan/commonizer/src/org/jetbrains/kotlin/descriptors/commonizer/mergedtree/properties.kt b/konan/commonizer/src/org/jetbrains/kotlin/descriptors/commonizer/mergedtree/properties.kt deleted file mode 100644 index 8fb1c50b6e8..00000000000 --- a/konan/commonizer/src/org/jetbrains/kotlin/descriptors/commonizer/mergedtree/properties.kt +++ /dev/null @@ -1,11 +0,0 @@ -/* - * 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 - -import org.jetbrains.kotlin.descriptors.PropertyDescriptor -import org.jetbrains.kotlin.descriptors.commonizer.mergedtree.ir.buildPropertyNode - -internal fun mergeProperties(properties: List) = buildPropertyNode(properties) diff --git a/konan/commonizer/src/org/jetbrains/kotlin/descriptors/commonizer/mergedtree/root.kt b/konan/commonizer/src/org/jetbrains/kotlin/descriptors/commonizer/mergedtree/root.kt index e33295feee8..08d17c44a47 100644 --- a/konan/commonizer/src/org/jetbrains/kotlin/descriptors/commonizer/mergedtree/root.kt +++ b/konan/commonizer/src/org/jetbrains/kotlin/descriptors/commonizer/mergedtree/root.kt @@ -11,8 +11,12 @@ import org.jetbrains.kotlin.descriptors.commonizer.ConcreteTargetId import org.jetbrains.kotlin.descriptors.commonizer.mergedtree.ir.RootNode import org.jetbrains.kotlin.descriptors.commonizer.mergedtree.ir.buildRootNode import org.jetbrains.kotlin.name.Name +import org.jetbrains.kotlin.storage.StorageManager -internal fun mergeRoots(modulesByTargets: List>>): RootNode { +internal fun mergeRoots( + storageManager: StorageManager, + modulesByTargets: List>> +): RootNode { val node = buildRootNode(modulesByTargets.map { it.first }) val modulesMap = CommonizedGroupMap(modulesByTargets.size) @@ -23,8 +27,8 @@ internal fun mergeRoots(modulesByTargets: List Sequence.toList(expectedCapacity: Int): List { internal inline fun Iterable.firstNonNull() = firstIsInstance() internal val KotlinType.fqName: FqName - get() = constructor.declarationDescriptor!!.fqNameSafe + get() = (constructor.declarationDescriptor ?: throw IllegalStateException("No declaration descriptor found for $constructor")).fqNameSafe internal val KotlinType.fqNameWithTypeParameters: String get() = buildString { buildFqNameWithTypeParameters(this@fqNameWithTypeParameters) } @@ -48,4 +50,9 @@ private fun StringBuilder.buildFqNameWithTypeParameters(type: KotlinType) { } } -internal fun Any?.isNull() = this == null +internal fun Any?.isNull(): Boolean = this == null + +private val KOTLINX_PACKAGE_NAME = Name.identifier("kotlinx") + +internal val FqName.isUnderStandardKotlinPackages: Boolean + get() = startsWith(KotlinBuiltIns.BUILT_INS_PACKAGE_NAME) || startsWith(KOTLINX_PACKAGE_NAME) 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 d24c2db01d7..72e4b8144f1 100644 --- a/konan/commonizer/testData/callableMemberCommonization/extensionReceivers/commonized/common/package_root.kt +++ b/konan/commonizer/testData/callableMemberCommonization/extensionReceivers/commonized/common/package_root.kt @@ -1,4 +1,7 @@ -class Planet(val name: String, val diameter: Double) +expect class Planet(name: String, diameter: Double) { + val name: String + val diameter: Double +} expect val intProperty: Int expect val Int.intProperty: Int 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 67605009382..658d08e94bd 100644 --- a/konan/commonizer/testData/callableMemberCommonization/extensionReceivers/commonized/js/package_root.kt +++ b/konan/commonizer/testData/callableMemberCommonization/extensionReceivers/commonized/js/package_root.kt @@ -1,4 +1,4 @@ -class Planet(val name: String, val diameter: Double) +actual class Planet actual constructor(actual val name: String, actual val diameter: Double) actual val intProperty get() = 42 actual val Int.intProperty get() = this 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 bc36bd5a764..bd1e9f617ab 100644 --- a/konan/commonizer/testData/callableMemberCommonization/extensionReceivers/commonized/jvm/package_root.kt +++ b/konan/commonizer/testData/callableMemberCommonization/extensionReceivers/commonized/jvm/package_root.kt @@ -1,4 +1,4 @@ -class Planet(val name: String, val diameter: Double) +actual class Planet actual constructor(actual val name: String, actual val diameter: Double) actual val intProperty get() = 42 actual val Int.intProperty get() = this 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 a21faee290c..41c762dab07 100644 --- a/konan/commonizer/testData/callableMemberCommonization/returnTypes/commonized/common/package_root.kt +++ b/konan/commonizer/testData/callableMemberCommonization/returnTypes/commonized/common/package_root.kt @@ -1,4 +1,7 @@ -class Planet(val name: String, val diameter: Double) +expect class Planet(name: String, diameter: Double) { + val name: String + val diameter: Double +} expect val propertyWithInferredType1: Int expect val propertyWithInferredType2: String @@ -6,7 +9,7 @@ expect val propertyWithInferredType3: String expect val propertyWithInferredType4: Nothing? expect val propertyWithInferredType5: Planet -typealias C = Planet +expect class C expect val property1: Int expect val property2: String @@ -20,8 +23,10 @@ expect fun function3(): Planet expect fun function6(): Planet expect fun function7(): C -class Box(val value: T) -class Fox +expect class Box(value: T) { + val value: T +} +expect class Fox() expect fun functionWithTypeParametersInReturnType1(): Array expect fun functionWithTypeParametersInReturnType3(): Array 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 dbfd9e282c7..642d4597288 100644 --- a/konan/commonizer/testData/callableMemberCommonization/returnTypes/commonized/js/package_root.kt +++ b/konan/commonizer/testData/callableMemberCommonization/returnTypes/commonized/js/package_root.kt @@ -1,4 +1,4 @@ -class Planet(val name: String, val diameter: Double) +actual class Planet actual constructor(actual val name: String, actual val diameter: Double) actual val propertyWithInferredType1 = 1 actual val propertyWithInferredType2 = "hello" @@ -7,7 +7,7 @@ actual val propertyWithInferredType4 = null actual val propertyWithInferredType5 = Planet("Earth", 12742) typealias A = Planet -typealias C = Planet +actual typealias C = Planet actual val property1 = 1 actual val property2 = "hello" @@ -37,8 +37,8 @@ fun functionWithMismatchedType3(): Int = 1 fun functionWithMismatchedType4(): Int = 1 fun functionWithMismatchedType5(): Int = 1 -class Box(val value: T) -class Fox +actual class Box actual constructor(actual val value: T) +actual class Fox actual constructor() actual fun functionWithTypeParametersInReturnType1() = arrayOf(1) fun functionWithTypeParametersInReturnType2() = arrayOf(1) 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 4dd157e6412..339a68b80dd 100644 --- a/konan/commonizer/testData/callableMemberCommonization/returnTypes/commonized/jvm/package_root.kt +++ b/konan/commonizer/testData/callableMemberCommonization/returnTypes/commonized/jvm/package_root.kt @@ -1,4 +1,4 @@ -class Planet(val name: String, val diameter: Double) +actual class Planet actual constructor(actual val name: String, actual val diameter: Double) actual val propertyWithInferredType1 get() = 1 actual val propertyWithInferredType2 get() = "hello" @@ -7,7 +7,7 @@ actual val propertyWithInferredType4 get() = null actual val propertyWithInferredType5 get() = Planet("Earth", 12742) typealias B = Planet -typealias C = Planet +actual typealias C = Planet actual val property1 = 1 actual val property2 = "hello" @@ -37,8 +37,8 @@ fun functionWithMismatchedType3(): Number = 1 fun functionWithMismatchedType4(): Comparable = 1 fun functionWithMismatchedType5(): String = 1.toString() -class Box(val value: T) -class Fox +actual class Box actual constructor(actual val value: T) +actual class Fox actual constructor() actual fun functionWithTypeParametersInReturnType1() = arrayOf(1) fun functionWithTypeParametersInReturnType2() = arrayOf("hello") diff --git a/konan/commonizer/testData/functionCommonization/specifics/commonized/common/package_root.kt b/konan/commonizer/testData/functionCommonization/specifics/commonized/common/package_root.kt index f96445f8ae0..43d5aa82a9f 100644 --- a/konan/commonizer/testData/functionCommonization/specifics/commonized/common/package_root.kt +++ b/konan/commonizer/testData/functionCommonization/specifics/commonized/common/package_root.kt @@ -1,6 +1,6 @@ expect suspend fun suspendFunction1(): Int -class Qux +expect class Qux() expect operator fun Qux.get(index: Int): String expect fun Qux.set(index: Int, value: String) diff --git a/konan/commonizer/testData/functionCommonization/specifics/commonized/js/package_root.kt b/konan/commonizer/testData/functionCommonization/specifics/commonized/js/package_root.kt index 263e46df3a3..b4d1d29b05b 100644 --- a/konan/commonizer/testData/functionCommonization/specifics/commonized/js/package_root.kt +++ b/konan/commonizer/testData/functionCommonization/specifics/commonized/js/package_root.kt @@ -1,7 +1,7 @@ actual suspend fun suspendFunction1() = 1 suspend fun suspendFunction2() = 1 -class Qux +actual class Qux actual constructor() actual operator fun Qux.get(index: Int) = "$index" actual operator fun Qux.set(index: Int, value: String) = Unit diff --git a/konan/commonizer/testData/functionCommonization/specifics/commonized/jvm/package_root.kt b/konan/commonizer/testData/functionCommonization/specifics/commonized/jvm/package_root.kt index a2026c786f5..9559cf2288a 100644 --- a/konan/commonizer/testData/functionCommonization/specifics/commonized/jvm/package_root.kt +++ b/konan/commonizer/testData/functionCommonization/specifics/commonized/jvm/package_root.kt @@ -1,7 +1,7 @@ actual suspend fun suspendFunction1() = 1 fun suspendFunction2() = 1 -class Qux +actual class Qux actual constructor() actual operator fun Qux.get(index: Int) = "$index" actual fun Qux.set(index: Int, value: String) = Unit 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 e4ad46dd6f6..2e91596c66f 100644 --- a/konan/commonizer/tests/org/jetbrains/kotlin/descriptors/commonizer/assertions.kt +++ b/konan/commonizer/tests/org/jetbrains/kotlin/descriptors/commonizer/assertions.kt @@ -10,8 +10,10 @@ import org.jetbrains.kotlin.descriptors.* import org.jetbrains.kotlin.descriptors.annotations.Annotations import org.jetbrains.kotlin.descriptors.commonizer.mergedtree.* import org.jetbrains.kotlin.name.FqName +import org.jetbrains.kotlin.resolve.descriptorUtil.fqNameSafe import org.jetbrains.kotlin.resolve.scopes.MemberScope import org.jetbrains.kotlin.types.KotlinType +import org.jetbrains.kotlin.types.getAbbreviation import java.io.File import kotlin.contracts.ExperimentalContracts import kotlin.contracts.contract @@ -90,15 +92,29 @@ private class ComparingDeclarationsVisitor( } fun visitMemberScopes(expected: MemberScope, actual: MemberScope, context: Context) { - fun collectProperties(memberScope: MemberScope): Map = - mutableMapOf().also { - memberScope.collectProperties { propertyKey, property -> - it[propertyKey] = property - } - } + val expectedProperties = mutableMapOf() + val expectedFunctions = mutableMapOf() + val expectedClasses = mutableMapOf() + val expectedTypeAliases = mutableMapOf() - val expectedProperties = collectProperties(expected) - val actualProperties = collectProperties(actual) + expected.collectMembers( + CallableMemberCollector { expectedProperties[PropertyApproximationKey(it)] = it }, + CallableMemberCollector { expectedFunctions[FunctionApproximationKey(it)] = it }, + Collector { expectedClasses[it.fqNameSafe] = it }, + Collector { expectedTypeAliases[it.fqNameSafe] = it } + ) + + val actualProperties = mutableMapOf() + val actualFunctions = mutableMapOf() + val actualClasses = mutableMapOf() + val actualTypeAliases = mutableMapOf() + + actual.collectMembers( + CallableMemberCollector { actualProperties[PropertyApproximationKey(it)] = it }, + CallableMemberCollector { actualFunctions[FunctionApproximationKey(it)] = it }, + Collector { actualClasses[it.fqNameSafe] = it }, + Collector { actualTypeAliases[it.fqNameSafe] = it } + ) context.assertSetsEqual(expectedProperties.keys, actualProperties.keys, "sets of properties") @@ -107,16 +123,6 @@ private class ComparingDeclarationsVisitor( expectedProperty.accept(this, context.nextLevel(actualProperty)) } - fun collectFunctions(memberScope: MemberScope): Map = - mutableMapOf().also { - memberScope.collectFunctions { functionKey, function -> - it[functionKey] = function - } - } - - val expectedFunctions = collectFunctions(expected) - val actualFunctions = collectFunctions(actual) - context.assertSetsEqual(expectedFunctions.keys, actualFunctions.keys, "sets of functions") expectedFunctions.forEach { (functionKey, expectedFunction) -> @@ -124,9 +130,20 @@ private class ComparingDeclarationsVisitor( expectedFunction.accept(this, context.nextLevel(actualFunction)) } - // FIXME: traverse the rest - classes, typealiases - } + context.assertSetsEqual(expectedClasses.keys, actualClasses.keys, "sets of classes") + expectedClasses.forEach { (classFqName, expectedClass) -> + val actualClass = actualClasses.getValue(classFqName) + expectedClass.accept(this, context.nextLevel(actualClass)) + } + + context.assertSetsEqual(expectedTypeAliases.keys, actualTypeAliases.keys, "sets of type aliases") + + expectedTypeAliases.forEach { (typeAliasFqName, expectedTypeAlias) -> + val actualTypeAlias = actualTypeAliases.getValue(typeAliasFqName) + expectedTypeAlias.accept(this, context.nextLevel(actualTypeAlias)) + } + } override fun visitFunctionDescriptor(expected: FunctionDescriptor, context: Context) { @Suppress("NAME_SHADOWING") @@ -146,6 +163,8 @@ private class ComparingDeclarationsVisitor( context.assertFieldsEqual(expected::isExternal, actual::isExternal) context.assertFieldsEqual(expected::isExpect, actual::isExpect) context.assertFieldsEqual(expected::isActual, actual::isActual) + context.assertFieldsEqual(expected::hasStableParameterNames, actual::hasStableParameterNames) + context.assertFieldsEqual(expected::hasSynthesizedParameterNames, actual::hasSynthesizedParameterNames) visitType(expected.returnType, actual.returnType, context.nextLevel("Function type")) @@ -214,15 +233,97 @@ private class ComparingDeclarationsVisitor( } override fun visitClassDescriptor(expected: ClassDescriptor, context: Context) { - TODO("not implemented") + val actual = context.getActualAs() + + visitAnnotations(expected.annotations, actual.annotations, context.nextLevel("Class annotations")) + context.assertFieldsEqual(expected::getName, actual::getName) + context.assertFieldsEqual(expected::getVisibility, actual::getVisibility) + context.assertFieldsEqual(expected::getModality, actual::getModality) + context.assertFieldsEqual(expected::getKind, actual::getKind) + context.assertFieldsEqual(expected::isCompanionObject, actual::isCompanionObject) + context.assertFieldsEqual(expected::isData, actual::isData) + context.assertFieldsEqual(expected::isInline, actual::isInline) + context.assertFieldsEqual(expected::isInner, actual::isInner) + context.assertFieldsEqual(expected::isExternal, actual::isExternal) + context.assertFieldsEqual(expected::isExpect, actual::isExpect) + context.assertFieldsEqual(expected::isActual, actual::isActual) + + visitTypeParameters( + expected.declaredTypeParameters, + actual.declaredTypeParameters, + context.nextLevel("Class declared type parameters") + ) + + if (expected.sealedSubclasses.isNotEmpty() || actual.sealedSubclasses.isNotEmpty()) { + val expectedSealedSubclassesFqNames = expected.sealedSubclasses.mapTo(HashSet()) { it.fqNameSafe } + val actualSealedSubclassesFqNames = actual.sealedSubclasses.mapTo(HashSet()) { it.fqNameSafe } + + context.assertSetsEqual(expectedSealedSubclassesFqNames, actualSealedSubclassesFqNames, "Sealed subclasses FQ names") + } + + val expectedSupertypeFqNames = expected.typeConstructor.supertypes.mapTo(HashSet()) { it.fqNameWithTypeParameters } + val actualSupertypeFqNames = actual.typeConstructor.supertypes.mapTo(HashSet()) { it.fqNameWithTypeParameters } + + context.assertSetsEqual(expectedSupertypeFqNames, actualSupertypeFqNames, "Supertypes FQ names") + + if (expected.constructors.isNotEmpty() || actual.constructors.isNotEmpty()) { + val expectedConstructors = expected.constructors.associateBy { ConstructorApproximationKey(it) } + val actualConstructors = actual.constructors.associateBy { ConstructorApproximationKey(it) } + + context.assertSetsEqual(expectedConstructors.keys, actualConstructors.keys, "sets of class constructors") + + for (key in expectedConstructors.keys) { + val expectedConstructor = expectedConstructors.getValue(key) + val actualConstructor = actualConstructors.getValue(key) + + visitConstructorDescriptor(expectedConstructor, context.nextLevel(actualConstructor)) + } + } + + visitMemberScopes( + expected.unsubstitutedMemberScope, + actual.unsubstitutedMemberScope, + context.nextLevel("class member scope [${expected.fqNameSafe}]") + ) } override fun visitConstructorDescriptor(expected: ConstructorDescriptor, context: Context) { - TODO("not implemented") + val actual = context.getActualAs() + + visitAnnotations(expected.annotations, actual.annotations, context.nextLevel("Constructor annotations")) + context.assertFieldsEqual(expected::getVisibility, actual::getVisibility) + context.assertFieldsEqual(expected::isPrimary, actual::isPrimary) + context.assertFieldsEqual(expected::getKind, actual::getKind) + context.assertFieldsEqual(expected::hasStableParameterNames, actual::hasStableParameterNames) + context.assertFieldsEqual(expected::hasSynthesizedParameterNames, actual::hasSynthesizedParameterNames) + context.assertFieldsEqual(expected::isExpect, actual::isExpect) + context.assertFieldsEqual(expected::isActual, actual::isActual) + + visitValueParameterDescriptorList( + expected.valueParameters, + actual.valueParameters, + context.nextLevel("Constructor value parameters") + ) + + visitTypeParameters(expected.typeParameters, actual.typeParameters, context.nextLevel("Constructor type parameters")) } override fun visitTypeAliasDescriptor(expected: TypeAliasDescriptor, context: Context) { - TODO("not implemented") + val actual = context.getActualAs() + + visitAnnotations(expected.annotations, actual.annotations, context.nextLevel("Type alias annotations")) + context.assertFieldsEqual(expected::getName, actual::getName) + context.assertFieldsEqual(expected::getVisibility, actual::getVisibility) + context.assertFieldsEqual(expected::isActual, actual::isActual) + + visitTypeParameters( + expected.declaredTypeParameters, + actual.declaredTypeParameters, + context.nextLevel("Type alias declared type parameters") + ) + + visitType(expected.underlyingType, actual.underlyingType, context.nextLevel("Type alias underlying type")) + visitType(expected.expandedType, actual.expandedType, context.nextLevel("Type alias expanded type")) } override fun visitPropertyDescriptor(expected: PropertyDescriptor, context: Context) { @@ -305,10 +406,10 @@ private class ComparingDeclarationsVisitor( private fun visitAnnotations(expected: Annotations?, actual: Annotations?, context: Context) { - if (expected === actual) return + if (expected === actual || (expected?.isEmpty() != false && actual?.isEmpty() != false)) return - val expectedAnnotationFqNames = (expected ?: Annotations.EMPTY).map { it.fqName }.toSet() - val actualAnnotationFqNames = (actual ?: Annotations.EMPTY).map { it.fqName }.toSet() + val expectedAnnotationFqNames: Set = expected?.mapTo(HashSet()) { it.fqName } ?: emptySet() + val actualAnnotationFqNames: Set = actual?.mapTo(HashSet()) { it.fqName } ?: emptySet() context.assertSetsEqual(expectedAnnotationFqNames, actualAnnotationFqNames, "annotations") } @@ -318,8 +419,8 @@ private class ComparingDeclarationsVisitor( check(actual != null && expected != null) - val expectedUnwrapped = expected.unwrap() - val actualUnwrapped = actual.unwrap() + val expectedUnwrapped = expected.getAbbreviation() ?: expected.unwrap() + val actualUnwrapped = actual.getAbbreviation() ?: actual.unwrap() if (expectedUnwrapped === actualUnwrapped) return diff --git a/konan/commonizer/tests/org/jetbrains/kotlin/descriptors/commonizer/core/AbstractCommonizerTest.kt b/konan/commonizer/tests/org/jetbrains/kotlin/descriptors/commonizer/core/AbstractCommonizerTest.kt index 34fd9496763..21549f2b61f 100644 --- a/konan/commonizer/tests/org/jetbrains/kotlin/descriptors/commonizer/core/AbstractCommonizerTest.kt +++ b/konan/commonizer/tests/org/jetbrains/kotlin/descriptors/commonizer/core/AbstractCommonizerTest.kt @@ -20,7 +20,7 @@ abstract class AbstractCommonizerTest { protected open fun isEqual(a: R?, b: R?): Boolean = a == b - protected fun doTestSuccess(expected: R, vararg variants: T) { + protected open fun doTestSuccess(expected: R, vararg variants: T) { check(variants.isNotEmpty()) val commonized = createCommonizer().apply { @@ -34,7 +34,7 @@ abstract class AbstractCommonizerTest { } // should fail on the last variant - protected fun doTestFailure(vararg variants: T) { + protected open fun doTestFailure(vararg variants: T) { check(variants.isNotEmpty()) val commonized = createCommonizer().apply { diff --git a/konan/commonizer/tests/org/jetbrains/kotlin/descriptors/commonizer/core/DefaultExtensionReceiverCommonizerTest.kt b/konan/commonizer/tests/org/jetbrains/kotlin/descriptors/commonizer/core/DefaultExtensionReceiverCommonizerTest.kt index 5dd887d43a8..919ea145e59 100644 --- a/konan/commonizer/tests/org/jetbrains/kotlin/descriptors/commonizer/core/DefaultExtensionReceiverCommonizerTest.kt +++ b/konan/commonizer/tests/org/jetbrains/kotlin/descriptors/commonizer/core/DefaultExtensionReceiverCommonizerTest.kt @@ -5,60 +5,59 @@ package org.jetbrains.kotlin.descriptors.commonizer.core -import org.jetbrains.kotlin.descriptors.ReceiverParameterDescriptor +import org.jetbrains.kotlin.descriptors.annotations.Annotations +import org.jetbrains.kotlin.descriptors.commonizer.EMPTY_CLASSIFIERS_CACHE +import org.jetbrains.kotlin.descriptors.commonizer.mergedtree.ir.ExtensionReceiver import org.jetbrains.kotlin.descriptors.commonizer.mockClassType -import org.jetbrains.kotlin.descriptors.commonizer.mockProperty import org.jetbrains.kotlin.types.UnwrappedType import org.jetbrains.kotlin.types.refinement.TypeRefinement import org.junit.Test @TypeRefinement -class DefaultExtensionReceiverCommonizerTest : AbstractCommonizerTest() { +class DefaultExtensionReceiverCommonizerTest : AbstractCommonizerTest() { @Test fun nullReceiver() = doTestSuccess( null, - mock().extensionReceiverParameter, - mock().extensionReceiverParameter, - mock().extensionReceiverParameter + null, + null, + null ) @Test fun sameReceiver() = doTestSuccess( mockClassType("kotlin.String").unwrap(), - mock(receiverTypeFqName = "kotlin.String").extensionReceiverParameter, - mock(receiverTypeFqName = "kotlin.String").extensionReceiverParameter, - mock(receiverTypeFqName = "kotlin.String").extensionReceiverParameter + mockExtensionReceiver("kotlin.String"), + mockExtensionReceiver("kotlin.String"), + mockExtensionReceiver("kotlin.String") ) @Test(expected = IllegalCommonizerStateException::class) fun differentReceivers() = doTestFailure( - mock(receiverTypeFqName = "kotlin.String").extensionReceiverParameter, - mock(receiverTypeFqName = "kotlin.String").extensionReceiverParameter, - mock(receiverTypeFqName = "kotlin.Int").extensionReceiverParameter + mockExtensionReceiver("kotlin.String"), + mockExtensionReceiver("kotlin.String"), + mockExtensionReceiver("kotlin.Int") ) @Test(expected = IllegalCommonizerStateException::class) fun nullAndNonNullReceivers1() = doTestFailure( - mock(receiverTypeFqName = "kotlin.String").extensionReceiverParameter, - mock(receiverTypeFqName = "kotlin.String").extensionReceiverParameter, - mock(receiverTypeFqName = null).extensionReceiverParameter + mockExtensionReceiver("kotlin.String"), + mockExtensionReceiver("kotlin.String"), + null ) @Test(expected = IllegalCommonizerStateException::class) fun nullAndNonNullReceivers2() = doTestFailure( - mock(receiverTypeFqName = null).extensionReceiverParameter, - mock(receiverTypeFqName = null).extensionReceiverParameter, - mock(receiverTypeFqName = "kotlin.String").extensionReceiverParameter + null, + null, + mockExtensionReceiver("kotlin.String") ) - override fun createCommonizer() = ExtensionReceiverCommonizer.default() + override fun createCommonizer() = ExtensionReceiverCommonizer.default(EMPTY_CLASSIFIERS_CACHE) } @TypeRefinement -private fun mock(name: String = "myLength", receiverTypeFqName: String? = null) = mockProperty( - name = name, - setterVisibility = null, - extensionReceiverType = receiverTypeFqName?.let { mockClassType(receiverTypeFqName) }, - returnType = mockClassType("kotlin.Int") +private fun mockExtensionReceiver(typeFqName: String) = ExtensionReceiver( + annotations = Annotations.EMPTY, + type = mockClassType(typeFqName).unwrap() ) diff --git a/konan/commonizer/tests/org/jetbrains/kotlin/descriptors/commonizer/core/DefaultFunctionModifiersCommonizerTest.kt b/konan/commonizer/tests/org/jetbrains/kotlin/descriptors/commonizer/core/DefaultFunctionModifiersCommonizerTest.kt index 223e574eea8..9b311303a3b 100644 --- a/konan/commonizer/tests/org/jetbrains/kotlin/descriptors/commonizer/core/DefaultFunctionModifiersCommonizerTest.kt +++ b/konan/commonizer/tests/org/jetbrains/kotlin/descriptors/commonizer/core/DefaultFunctionModifiersCommonizerTest.kt @@ -5,177 +5,179 @@ package org.jetbrains.kotlin.descriptors.commonizer.core -import org.jetbrains.kotlin.descriptors.SimpleFunctionDescriptor -import org.jetbrains.kotlin.descriptors.commonizer.TestFunctionModifiers -import org.jetbrains.kotlin.descriptors.commonizer.TestFunctionModifiers.Companion.areEqual +import org.jetbrains.kotlin.descriptors.commonizer.core.TestFunctionModifiers.Companion.areEqual import org.jetbrains.kotlin.descriptors.commonizer.mergedtree.ir.FunctionModifiers -import org.jetbrains.kotlin.descriptors.commonizer.mockClassType -import org.jetbrains.kotlin.descriptors.commonizer.mockFunction -import org.jetbrains.kotlin.types.refinement.TypeRefinement import org.junit.Test -@TypeRefinement -class DefaultFunctionModifiersCommonizerTest : AbstractCommonizerTest() { +class DefaultFunctionModifiersCommonizerTest : AbstractCommonizerTest() { @Test fun allDefault() = doTestSuccess( - create(), - create().toMockFunction(), - create().toMockFunction(), - create().toMockFunction() + mockFunctionModifiers(), + mockFunctionModifiers(), + mockFunctionModifiers(), + mockFunctionModifiers() ) @Test fun allSuspend() = doTestSuccess( - create(isSuspend = true), - create(isSuspend = true).toMockFunction(), - create(isSuspend = true).toMockFunction(), - create(isSuspend = true).toMockFunction() + mockFunctionModifiers(isSuspend = true), + mockFunctionModifiers(isSuspend = true), + mockFunctionModifiers(isSuspend = true), + mockFunctionModifiers(isSuspend = true) ) @Test(expected = IllegalCommonizerStateException::class) fun suspendAndNotSuspend() = doTestFailure( - create(isSuspend = true).toMockFunction(), - create(isSuspend = true).toMockFunction(), - create().toMockFunction() + mockFunctionModifiers(isSuspend = true), + mockFunctionModifiers(isSuspend = true), + mockFunctionModifiers() ) @Test(expected = IllegalCommonizerStateException::class) fun notSuspendAndSuspend() = doTestFailure( - create().toMockFunction(), - create().toMockFunction(), - create(isSuspend = true).toMockFunction() + mockFunctionModifiers(), + mockFunctionModifiers(), + mockFunctionModifiers(isSuspend = true) ) @Test fun allOperator() = doTestSuccess( - create(isOperator = true), - create(isOperator = true).toMockFunction(), - create(isOperator = true).toMockFunction(), - create(isOperator = true).toMockFunction() + mockFunctionModifiers(isOperator = true), + mockFunctionModifiers(isOperator = true), + mockFunctionModifiers(isOperator = true), + mockFunctionModifiers(isOperator = true) ) @Test fun notOperatorAndOperator() = doTestSuccess( - create(), - create().toMockFunction(), - create(isOperator = true).toMockFunction(), - create(isOperator = true).toMockFunction() + mockFunctionModifiers(), + mockFunctionModifiers(), + mockFunctionModifiers(isOperator = true), + mockFunctionModifiers(isOperator = true) ) @Test fun operatorAndNotOperator() = doTestSuccess( - create(), - create(isOperator = true).toMockFunction(), - create(isOperator = true).toMockFunction(), - create().toMockFunction() + mockFunctionModifiers(), + mockFunctionModifiers(isOperator = true), + mockFunctionModifiers(isOperator = true), + mockFunctionModifiers() ) @Test fun allInfix() = doTestSuccess( - create(isInfix = true), - create(isInfix = true).toMockFunction(), - create(isInfix = true).toMockFunction(), - create(isInfix = true).toMockFunction() + mockFunctionModifiers(isInfix = true), + mockFunctionModifiers(isInfix = true), + mockFunctionModifiers(isInfix = true), + mockFunctionModifiers(isInfix = true) ) @Test fun notInfixAndInfix() = doTestSuccess( - create(), - create().toMockFunction(), - create(isInfix = true).toMockFunction(), - create(isInfix = true).toMockFunction() + mockFunctionModifiers(), + mockFunctionModifiers(), + mockFunctionModifiers(isInfix = true), + mockFunctionModifiers(isInfix = true) ) @Test fun infixAndNotInfix() = doTestSuccess( - create(), - create(isInfix = true).toMockFunction(), - create(isInfix = true).toMockFunction(), - create().toMockFunction() + mockFunctionModifiers(), + mockFunctionModifiers(isInfix = true), + mockFunctionModifiers(isInfix = true), + mockFunctionModifiers() ) @Test fun allInline() = doTestSuccess( - create(isInline = true), - create(isInline = true).toMockFunction(), - create(isInline = true).toMockFunction(), - create(isInline = true).toMockFunction() + mockFunctionModifiers(isInline = true), + mockFunctionModifiers(isInline = true), + mockFunctionModifiers(isInline = true), + mockFunctionModifiers(isInline = true) ) @Test fun notInlineAndInline() = doTestSuccess( - create(), - create().toMockFunction(), - create(isInline = true).toMockFunction(), - create(isInline = true).toMockFunction() + mockFunctionModifiers(), + mockFunctionModifiers(), + mockFunctionModifiers(isInline = true), + mockFunctionModifiers(isInline = true) ) @Test fun inlineAndNotInline() = doTestSuccess( - create(), - create(isInline = true).toMockFunction(), - create(isInline = true).toMockFunction(), - create().toMockFunction() + mockFunctionModifiers(), + mockFunctionModifiers(isInline = true), + mockFunctionModifiers(isInline = true), + mockFunctionModifiers() ) @Test fun allTailrec() = doTestSuccess( - create(isTailrec = true), - create(isTailrec = true).toMockFunction(), - create(isTailrec = true).toMockFunction(), - create(isTailrec = true).toMockFunction() + mockFunctionModifiers(isTailrec = true), + mockFunctionModifiers(isTailrec = true), + mockFunctionModifiers(isTailrec = true), + mockFunctionModifiers(isTailrec = true) ) @Test fun notTailrecAndTailrec() = doTestSuccess( - create(), - create().toMockFunction(), - create(isTailrec = true).toMockFunction(), - create(isTailrec = true).toMockFunction() + mockFunctionModifiers(), + mockFunctionModifiers(), + mockFunctionModifiers(isTailrec = true), + mockFunctionModifiers(isTailrec = true) ) @Test fun tailrecAndNotTailrec() = doTestSuccess( - create(), - create(isTailrec = true).toMockFunction(), - create(isTailrec = true).toMockFunction(), - create().toMockFunction() + mockFunctionModifiers(), + mockFunctionModifiers(isTailrec = true), + mockFunctionModifiers(isTailrec = true), + mockFunctionModifiers() ) @Test fun allExternal() = doTestSuccess( - create(isExternal = true), - create(isExternal = true).toMockFunction(), - create(isExternal = true).toMockFunction(), - create(isExternal = true).toMockFunction() + mockFunctionModifiers(isExternal = true), + mockFunctionModifiers(isExternal = true), + mockFunctionModifiers(isExternal = true), + mockFunctionModifiers(isExternal = true) ) @Test fun notExternalAndExternal() = doTestSuccess( - create(), - create().toMockFunction(), - create(isExternal = true).toMockFunction(), - create(isExternal = true).toMockFunction() + mockFunctionModifiers(), + mockFunctionModifiers(), + mockFunctionModifiers(isExternal = true), + mockFunctionModifiers(isExternal = true) ) @Test fun externalAndNotExternal() = doTestSuccess( - create(), - create(isExternal = true).toMockFunction(), - create(isExternal = true).toMockFunction(), - create().toMockFunction() + mockFunctionModifiers(), + mockFunctionModifiers(isExternal = true), + mockFunctionModifiers(isExternal = true), + mockFunctionModifiers() ) override fun createCommonizer() = FunctionModifiersCommonizer.default() override fun isEqual(a: FunctionModifiers?, b: FunctionModifiers?) = (a === b) || (a != null && b != null && areEqual(a, b)) } -private typealias create = TestFunctionModifiers +private typealias mockFunctionModifiers = TestFunctionModifiers -@TypeRefinement -private fun TestFunctionModifiers.toMockFunction() = mockFunction( - name = "myFunction", - returnType = mockClassType("kotlin.String"), - modifiers = this -) +private data class TestFunctionModifiers( + override val isOperator: Boolean = false, + override val isInfix: Boolean = false, + override val isInline: Boolean = false, + override val isTailrec: Boolean = false, + override val isSuspend: Boolean = false, + override val isExternal: Boolean = false +) : FunctionModifiers { + companion object { + fun areEqual(a: FunctionModifiers, b: FunctionModifiers) = + a.isOperator == b.isOperator && a.isInfix == b.isInfix && a.isInline == b.isInline + && a.isTailrec == b.isTailrec && a.isSuspend == b.isSuspend && a.isExternal == b.isExternal + } +} diff --git a/konan/commonizer/tests/org/jetbrains/kotlin/descriptors/commonizer/core/DefaultPropertySetterCommonizerTest.kt b/konan/commonizer/tests/org/jetbrains/kotlin/descriptors/commonizer/core/DefaultPropertySetterCommonizerTest.kt index dc5eaffd1ea..5ee900340a1 100644 --- a/konan/commonizer/tests/org/jetbrains/kotlin/descriptors/commonizer/core/DefaultPropertySetterCommonizerTest.kt +++ b/konan/commonizer/tests/org/jetbrains/kotlin/descriptors/commonizer/core/DefaultPropertySetterCommonizerTest.kt @@ -5,16 +5,12 @@ package org.jetbrains.kotlin.descriptors.commonizer.core -import org.jetbrains.kotlin.descriptors.PropertySetterDescriptor import org.jetbrains.kotlin.descriptors.Visibilities.* import org.jetbrains.kotlin.descriptors.Visibility import org.jetbrains.kotlin.descriptors.commonizer.mergedtree.ir.Setter -import org.jetbrains.kotlin.descriptors.commonizer.mockClassType -import org.jetbrains.kotlin.descriptors.commonizer.mockProperty -import org.jetbrains.kotlin.types.refinement.TypeRefinement import org.junit.Test -class DefaultPropertySetterCommonizerTest : AbstractCommonizerTest() { +class DefaultPropertySetterCommonizerTest : AbstractCommonizerTest() { @Test fun absentOnly() = super.doTestSuccess(null, null, null, null) @@ -61,22 +57,13 @@ class DefaultPropertySetterCommonizerTest : AbstractCommonizerTest() { + private lateinit var cache: ClassifiersCacheImpl + + @Before + fun initialize() { + cache = ClassifiersCacheImpl() // reset cache + } + @Test fun classTypesInKotlinPackageWithSameName() = doTestSuccess( mockClassType("kotlin.collections.List").unwrap(), @@ -84,21 +101,18 @@ class DefaultTypeCommonizerTest : AbstractCommonizerTest(variants.size) + val typeAliasesMap = CommonizedGroupMap(variants.size) + + fun recurse(type: KotlinType, index: Int) { + @Suppress("MoveVariableDeclarationIntoWhen") + val descriptor = (type.getAbbreviation() ?: type).constructor.declarationDescriptor + when (descriptor) { + is ClassDescriptor -> classesMap[descriptor.fqNameSafe][index] = descriptor + is TypeAliasDescriptor -> { + typeAliasesMap[descriptor.fqNameSafe][index] = descriptor + recurse(descriptor.underlyingType, index) // expand underlying types recursively + } + else -> IllegalStateException("Unexpected descriptor of KotlinType: $descriptor, $type") + } + } + + variants.forEachIndexed { index, type -> + recurse(type, index) + } + + for ((_, classesGroup) in classesMap) { + buildClassNode(LockBasedStorageManager.NO_LOCKS, cache, null, classesGroup.toList()) + } + + for ((_, typeAliasesGroup) in typeAliasesMap) { + buildTypeAliasNode(LockBasedStorageManager.NO_LOCKS, cache, typeAliasesGroup.toList()) + } + } + + override fun doTestSuccess(expected: UnwrappedType, vararg variants: KotlinType) { + prepareCache(*variants) + super.doTestSuccess(expected, *variants) + } + + override fun doTestFailure(vararg variants: KotlinType) { + prepareCache(*variants) + super.doTestFailure(*variants) + } + + override fun createCommonizer() = TypeCommonizer.default(cache) + + override fun isEqual(a: UnwrappedType?, b: UnwrappedType?) = (a === b) || (a != null && b != null && areTypesEqual(cache, a, b)) } 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 index 402441c0d8d..5a8161fdf0c 100644 --- a/konan/commonizer/tests/org/jetbrains/kotlin/descriptors/commonizer/core/DefaultTypeParameterCommonizerTest.kt +++ b/konan/commonizer/tests/org/jetbrains/kotlin/descriptors/commonizer/core/DefaultTypeParameterCommonizerTest.kt @@ -5,87 +5,86 @@ package org.jetbrains.kotlin.descriptors.commonizer.core -import org.jetbrains.kotlin.descriptors.TypeParameterDescriptor +import org.jetbrains.kotlin.descriptors.commonizer.EMPTY_CLASSIFIERS_CACHE 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() +class DefaultTypeParameterCommonizerTest : AbstractCommonizerTest() { + override fun createCommonizer() = TypeParameterCommonizer.default(EMPTY_CLASSIFIERS_CACHE) @Test fun allAreReified() = doTestSuccess( - create(isReified = true), - create(isReified = true).toMockParam(), - create(isReified = true).toMockParam(), - create(isReified = true).toMockParam() + mockTypeParam(isReified = true), + mockTypeParam(isReified = true), + mockTypeParam(isReified = true), + mockTypeParam(isReified = true) ) @Test fun allAreNotReified() = doTestSuccess( - create(isReified = false), - create(isReified = false).toMockParam(), - create(isReified = false).toMockParam(), - create(isReified = false).toMockParam() + mockTypeParam(isReified = false), + mockTypeParam(isReified = false), + mockTypeParam(isReified = false), + mockTypeParam(isReified = false) ) @Test(expected = IllegalCommonizerStateException::class) fun someAreReified1() = doTestFailure( - create(isReified = true).toMockParam(), - create(isReified = true).toMockParam(), - create(isReified = false).toMockParam() + mockTypeParam(isReified = true), + mockTypeParam(isReified = true), + mockTypeParam(isReified = false) ) @Test(expected = IllegalCommonizerStateException::class) fun someAreReified2() = doTestFailure( - create(isReified = false).toMockParam(), - create(isReified = false).toMockParam(), - create(isReified = true).toMockParam() + mockTypeParam(isReified = false), + mockTypeParam(isReified = false), + mockTypeParam(isReified = true) ) @Test(expected = IllegalCommonizerStateException::class) fun differentVariance1() = doTestFailure( - create(variance = Variance.IN_VARIANCE).toMockParam(), - create(variance = Variance.IN_VARIANCE).toMockParam(), - create(variance = Variance.OUT_VARIANCE).toMockParam() + mockTypeParam(variance = Variance.IN_VARIANCE), + mockTypeParam(variance = Variance.IN_VARIANCE), + mockTypeParam(variance = Variance.OUT_VARIANCE) ) @Test(expected = IllegalCommonizerStateException::class) fun differentVariance2() = doTestFailure( - create(variance = Variance.OUT_VARIANCE).toMockParam(), - create(variance = Variance.OUT_VARIANCE).toMockParam(), - create(variance = Variance.INVARIANT).toMockParam() + mockTypeParam(variance = Variance.OUT_VARIANCE), + mockTypeParam(variance = Variance.OUT_VARIANCE), + mockTypeParam(variance = Variance.INVARIANT) ) @Test(expected = IllegalCommonizerStateException::class) fun differentUpperBounds1() = doTestFailure( - create(upperBounds = listOf("kotlin.String")).toMockParam(), - create(upperBounds = listOf("kotlin.String")).toMockParam(), - create(upperBounds = listOf("kotlin.Int")).toMockParam() + mockTypeParam(upperBounds = listOf("kotlin.String")), + mockTypeParam(upperBounds = listOf("kotlin.String")), + mockTypeParam(upperBounds = listOf("kotlin.Int")) ) @Test(expected = IllegalCommonizerStateException::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() + mockTypeParam(upperBounds = listOf("kotlin.String", "kotlin.Int")), + mockTypeParam(upperBounds = listOf("kotlin.String", "kotlin.Int")), + mockTypeParam(upperBounds = listOf("kotlin.String")) ) @Test(expected = IllegalCommonizerStateException::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() + mockTypeParam(upperBounds = listOf("kotlin.String", "kotlin.Int")), + mockTypeParam(upperBounds = listOf("kotlin.String", "kotlin.Int")), + mockTypeParam(upperBounds = listOf("kotlin.Int", "kotlin.String")) ) internal companion object { - fun create( + fun mockTypeParam( name: String = "T", isReified: Boolean = false, variance: Variance = Variance.INVARIANT, @@ -96,15 +95,5 @@ class DefaultTypeParameterCommonizerTest : AbstractCommonizerTest, List>() { +class DefaultTypeParameterListCommonizerTest : AbstractCommonizerTest, List>() { @Test fun emptyValueParameters() = doTestSuccess( @@ -23,108 +23,104 @@ class DefaultTypeParameterListCommonizerTest : AbstractCommonizerTest): List { + fun mockTypeParams(vararg params: Pair): List { check(params.isNotEmpty()) return params.map { (name, returnTypeFqName) -> - DefaultTypeParameterCommonizerTest.create( + DefaultTypeParameterCommonizerTest.mockTypeParam( 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 5bc12b166f3..123ba791781 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 @@ -5,172 +5,197 @@ package org.jetbrains.kotlin.descriptors.commonizer.core -import org.jetbrains.kotlin.descriptors.ValueParameterDescriptor -import org.jetbrains.kotlin.descriptors.commonizer.mergedtree.ir.CommonValueParameter +import org.jetbrains.kotlin.descriptors.annotations.Annotations +import org.jetbrains.kotlin.descriptors.commonizer.EMPTY_CLASSIFIERS_CACHE +import org.jetbrains.kotlin.descriptors.commonizer.core.TestValueParameter.Companion.areEqual +import org.jetbrains.kotlin.descriptors.commonizer.mergedtree.ir.ClassifiersCache import org.jetbrains.kotlin.descriptors.commonizer.mergedtree.ir.ValueParameter import org.jetbrains.kotlin.descriptors.commonizer.mockClassType -import org.jetbrains.kotlin.descriptors.commonizer.mockValueParameter import org.jetbrains.kotlin.name.Name +import org.jetbrains.kotlin.types.UnwrappedType import org.jetbrains.kotlin.types.refinement.TypeRefinement import org.junit.Test @TypeRefinement -class DefaultValueParameterCommonizerTest : AbstractCommonizerTest() { +class DefaultValueParameterCommonizerTest : AbstractCommonizerTest() { @Test fun sameReturnType1() = doTestSuccess( - create("kotlin.String"), - create("kotlin.String").toMockParam(), - create("kotlin.String").toMockParam(), - create("kotlin.String").toMockParam() + mockValueParam("kotlin.String"), + mockValueParam("kotlin.String"), + mockValueParam("kotlin.String"), + mockValueParam("kotlin.String") ) @Test fun sameReturnType2() = doTestSuccess( - create("org.sample.Foo"), - create("org.sample.Foo").toMockParam(), - create("org.sample.Foo").toMockParam(), - create("org.sample.Foo").toMockParam() + mockValueParam("org.sample.Foo"), + mockValueParam("org.sample.Foo"), + mockValueParam("org.sample.Foo"), + mockValueParam("org.sample.Foo") ) @Test(expected = IllegalCommonizerStateException::class) fun differentReturnTypes1() = doTestFailure( - create("kotlin.String").toMockParam(), - create("kotlin.String").toMockParam(), - create("kotlin.Int").toMockParam() + mockValueParam("kotlin.String"), + mockValueParam("kotlin.String"), + mockValueParam("kotlin.Int") ) @Test(expected = IllegalCommonizerStateException::class) fun differentReturnTypes2() = doTestFailure( - create("kotlin.String").toMockParam(), - create("kotlin.String").toMockParam(), - create("org.sample.Foo").toMockParam() + mockValueParam("kotlin.String"), + mockValueParam("kotlin.String"), + mockValueParam("org.sample.Foo") ) @Test(expected = IllegalCommonizerStateException::class) fun differentReturnTypes3() = doTestFailure( - create("org.sample.Foo").toMockParam(), - create("org.sample.Foo").toMockParam(), - create("org.sample.Bar").toMockParam() + mockValueParam("org.sample.Foo"), + mockValueParam("org.sample.Foo"), + mockValueParam("org.sample.Bar") ) @Test fun allHaveVararg1() = doTestSuccess( - create("kotlin.String", hasVarargElementType = true), - create("kotlin.String", hasVarargElementType = true).toMockParam(), - create("kotlin.String", hasVarargElementType = true).toMockParam(), - create("kotlin.String", hasVarargElementType = true).toMockParam() + mockValueParam("kotlin.String", hasVarargElementType = true), + mockValueParam("kotlin.String", hasVarargElementType = true), + mockValueParam("kotlin.String", hasVarargElementType = true), + mockValueParam("kotlin.String", hasVarargElementType = true) ) @Test fun allHaveVararg2() = doTestSuccess( - create("org.sample.Foo", hasVarargElementType = true), - create("org.sample.Foo", hasVarargElementType = true).toMockParam(), - create("org.sample.Foo", hasVarargElementType = true).toMockParam(), - create("org.sample.Foo", hasVarargElementType = true).toMockParam() + mockValueParam("org.sample.Foo", hasVarargElementType = true), + mockValueParam("org.sample.Foo", hasVarargElementType = true), + mockValueParam("org.sample.Foo", hasVarargElementType = true), + mockValueParam("org.sample.Foo", hasVarargElementType = true) ) @Test(expected = IllegalCommonizerStateException::class) fun someDoesNotHaveVararg1() = doTestFailure( - create("kotlin.String", hasVarargElementType = true).toMockParam(), - create("kotlin.String", hasVarargElementType = true).toMockParam(), - create("kotlin.String", hasVarargElementType = false).toMockParam() + mockValueParam("kotlin.String", hasVarargElementType = true), + mockValueParam("kotlin.String", hasVarargElementType = true), + mockValueParam("kotlin.String", hasVarargElementType = false) ) @Test(expected = IllegalCommonizerStateException::class) fun someDoesNotHaveVararg2() = doTestFailure( - create("org.sample.Foo", hasVarargElementType = false).toMockParam(), - create("org.sample.Foo", hasVarargElementType = false).toMockParam(), - create("org.sample.Foo", hasVarargElementType = true).toMockParam() + mockValueParam("org.sample.Foo", hasVarargElementType = false), + mockValueParam("org.sample.Foo", hasVarargElementType = false), + mockValueParam("org.sample.Foo", hasVarargElementType = true) ) @Test fun allHaveCrossinline() = doTestSuccess( - create("kotlin.String", isCrossinline = true), - create("kotlin.String", isCrossinline = true).toMockParam(), - create("kotlin.String", isCrossinline = true).toMockParam(), - create("kotlin.String", isCrossinline = true).toMockParam() + mockValueParam("kotlin.String", isCrossinline = true), + mockValueParam("kotlin.String", isCrossinline = true), + mockValueParam("kotlin.String", isCrossinline = true), + mockValueParam("kotlin.String", isCrossinline = true) ) @Test fun someHaveCrossinline1() = doTestSuccess( - create("kotlin.String", isCrossinline = false), - create("kotlin.String", isCrossinline = true).toMockParam(), - create("kotlin.String", isCrossinline = true).toMockParam(), - create("kotlin.String", isCrossinline = false).toMockParam() + mockValueParam("kotlin.String", isCrossinline = false), + mockValueParam("kotlin.String", isCrossinline = true), + mockValueParam("kotlin.String", isCrossinline = true), + mockValueParam("kotlin.String", isCrossinline = false) ) @Test fun someHaveCrossinline2() = doTestSuccess( - create("kotlin.String", isCrossinline = false), - create("kotlin.String", isCrossinline = false).toMockParam(), - create("kotlin.String", isCrossinline = true).toMockParam(), - create("kotlin.String", isCrossinline = true).toMockParam() + mockValueParam("kotlin.String", isCrossinline = false), + mockValueParam("kotlin.String", isCrossinline = false), + mockValueParam("kotlin.String", isCrossinline = true), + mockValueParam("kotlin.String", isCrossinline = true) ) @Test fun allHaveNoinline() = doTestSuccess( - create("kotlin.String", isNoinline = true), - create("kotlin.String", isNoinline = true).toMockParam(), - create("kotlin.String", isNoinline = true).toMockParam(), - create("kotlin.String", isNoinline = true).toMockParam() + mockValueParam("kotlin.String", isNoinline = true), + mockValueParam("kotlin.String", isNoinline = true), + mockValueParam("kotlin.String", isNoinline = true), + mockValueParam("kotlin.String", isNoinline = true) ) @Test fun someHaveNoinline1() = doTestSuccess( - create("kotlin.String", isNoinline = false), - create("kotlin.String", isNoinline = true).toMockParam(), - create("kotlin.String", isNoinline = true).toMockParam(), - create("kotlin.String", isNoinline = false).toMockParam() + mockValueParam("kotlin.String", isNoinline = false), + mockValueParam("kotlin.String", isNoinline = true), + mockValueParam("kotlin.String", isNoinline = true), + mockValueParam("kotlin.String", isNoinline = false) ) @Test fun someHaveNoinline2() = doTestSuccess( - create("kotlin.String", isNoinline = false), - create("kotlin.String", isNoinline = false).toMockParam(), - create("kotlin.String", isNoinline = true).toMockParam(), - create("kotlin.String", isNoinline = true).toMockParam() + mockValueParam("kotlin.String", isNoinline = false), + mockValueParam("kotlin.String", isNoinline = false), + mockValueParam("kotlin.String", isNoinline = true), + mockValueParam("kotlin.String", isNoinline = true) ) @Test(expected = IllegalCommonizerStateException::class) fun anyDeclaresDefaultValue() = doTestFailure( - create("kotlin.String").toMockParam(declaresDefaultValue = false), - create("kotlin.String").toMockParam(declaresDefaultValue = false), - create("kotlin.String").toMockParam(declaresDefaultValue = true) + mockValueParam("kotlin.String", declaresDefaultValue = false), + mockValueParam("kotlin.String", declaresDefaultValue = false), + mockValueParam("kotlin.String", declaresDefaultValue = true) ) - override fun createCommonizer() = ValueParameterCommonizer.default() + override fun createCommonizer() = ValueParameterCommonizer.default(EMPTY_CLASSIFIERS_CACHE) + + override fun isEqual(a: ValueParameter?, b: ValueParameter?) = + (a === b) || (a != null && b != null && areEqual(EMPTY_CLASSIFIERS_CACHE, a, b)) internal companion object { - fun create( + fun mockValueParam( returnTypeFqName: String, name: String = "myParameter", hasVarargElementType: Boolean = false, isCrossinline: Boolean = false, - isNoinline: Boolean = false + isNoinline: Boolean = false, + declaresDefaultValue: Boolean = false ): ValueParameter { val returnType = mockClassType(returnTypeFqName).unwrap() - return CommonValueParameter( + return TestValueParameter( name = Name.identifier(name), + annotations = Annotations.EMPTY, returnType = returnType, varargElementType = returnType.takeIf { hasVarargElementType }, // the vararg type itself does not matter here, only it's presence matters isCrossinline = isCrossinline, - isNoinline = isNoinline + isNoinline = isNoinline, + declaresDefaultValue = declaresDefaultValue ) } - - fun ValueParameter.toMockParam( - index: Int = 0, - declaresDefaultValue: Boolean = false - ): ValueParameterDescriptor = mockValueParameter( - name = name.asString(), - index = index, - returnType = returnType, - varargElementType = varargElementType, - declaresDefaultValue = declaresDefaultValue, - isCrossinline = isCrossinline, - isNoinline = isNoinline - ) + } +} + +internal data class TestValueParameter( + override val name: Name, + override val annotations: Annotations, + override val returnType: UnwrappedType, + override val varargElementType: UnwrappedType?, + override val declaresDefaultValue: Boolean, + override val isCrossinline: Boolean, + override val isNoinline: Boolean +) : ValueParameter { + companion object { + fun areEqual(cache: ClassifiersCache, a: ValueParameter, b: ValueParameter): Boolean { + if (a.name != b.name + || !areTypesEqual(cache, a.returnType, b.returnType) + || a.declaresDefaultValue != b.declaresDefaultValue + || a.isCrossinline != b.isCrossinline + || a.isNoinline != b.isNoinline + ) { + return false + } + + val aVarargElementType = a.varargElementType + val bVarargElementType = b.varargElementType + + return (aVarargElementType === bVarargElementType) + || (aVarargElementType != null && bVarargElementType != null + && areTypesEqual(cache, aVarargElementType, bVarargElementType)) + } } } diff --git a/konan/commonizer/tests/org/jetbrains/kotlin/descriptors/commonizer/core/DefaultValueParameterListCommonizerTest.kt b/konan/commonizer/tests/org/jetbrains/kotlin/descriptors/commonizer/core/DefaultValueParameterListCommonizerTest.kt index 2d9b98e6831..e4d04627602 100644 --- a/konan/commonizer/tests/org/jetbrains/kotlin/descriptors/commonizer/core/DefaultValueParameterListCommonizerTest.kt +++ b/konan/commonizer/tests/org/jetbrains/kotlin/descriptors/commonizer/core/DefaultValueParameterListCommonizerTest.kt @@ -5,13 +5,14 @@ package org.jetbrains.kotlin.descriptors.commonizer.core -import org.jetbrains.kotlin.descriptors.ValueParameterDescriptor +import org.jetbrains.kotlin.descriptors.commonizer.EMPTY_CLASSIFIERS_CACHE +import org.jetbrains.kotlin.descriptors.commonizer.core.TestValueParameter.Companion.areEqual import org.jetbrains.kotlin.descriptors.commonizer.mergedtree.ir.ValueParameter import org.jetbrains.kotlin.types.refinement.TypeRefinement import org.junit.Test @TypeRefinement -class DefaultValueParameterListCommonizerTest : AbstractCommonizerTest, List>() { +class DefaultValueParameterListCommonizerTest : AbstractCommonizerTest, List>() { @Test fun emptyValueParameters() = doTestSuccess( @@ -23,163 +24,173 @@ class DefaultValueParameterListCommonizerTest : AbstractCommonizerTest?, b: List?): Boolean { + if (a === b) + return true + else if (a == null || b == null || a.size != b.size) + return false + + for (i in 0 until a.size) { + if (!areEqual(EMPTY_CLASSIFIERS_CACHE, a[i], b[i])) + return false + } + + return true + } private companion object { - fun create(vararg params: Pair): List { + fun mockValueParams(vararg params: Pair): List { check(params.isNotEmpty()) return params.map { (name, returnTypeFqName) -> - DefaultValueParameterCommonizerTest.create( + DefaultValueParameterCommonizerTest.mockValueParam( name = name, returnTypeFqName = returnTypeFqName ) } } - - fun List.toMockParams() = DefaultValueParameterCommonizerTest.run { - mapIndexed { index, param -> param.toMockParam(index) } - } } } diff --git a/konan/commonizer/tests/org/jetbrains/kotlin/descriptors/commonizer/core/EqualizingVisibilityCommonizerTest.kt b/konan/commonizer/tests/org/jetbrains/kotlin/descriptors/commonizer/core/EqualizingVisibilityCommonizerTest.kt index 6a5e6ca3775..472322fcc6c 100644 --- a/konan/commonizer/tests/org/jetbrains/kotlin/descriptors/commonizer/core/EqualizingVisibilityCommonizerTest.kt +++ b/konan/commonizer/tests/org/jetbrains/kotlin/descriptors/commonizer/core/EqualizingVisibilityCommonizerTest.kt @@ -7,36 +7,41 @@ package org.jetbrains.kotlin.descriptors.commonizer.core import org.jetbrains.kotlin.descriptors.Visibilities.* import org.jetbrains.kotlin.descriptors.Visibility +import org.jetbrains.kotlin.descriptors.commonizer.mergedtree.ir.DeclarationWithVisibility import org.junit.Test -class EqualizingVisibilityCommonizerTest : AbstractCommonizerTest() { +class EqualizingVisibilityCommonizerTest : AbstractCommonizerTest() { @Test - fun publicOnly() = doTestSuccess(PUBLIC, PUBLIC, PUBLIC, PUBLIC) + fun publicOnly() = doTestSuccess(PUBLIC, PUBLIC.toMock(), PUBLIC.toMock(), PUBLIC.toMock()) @Test - fun protectedOnly() = doTestSuccess(PROTECTED, PROTECTED, PROTECTED, PROTECTED) + fun protectedOnly() = doTestSuccess(PROTECTED, PROTECTED.toMock(), PROTECTED.toMock(), PROTECTED.toMock()) @Test - fun internalOnly() = doTestSuccess(INTERNAL, INTERNAL, INTERNAL, INTERNAL) + fun internalOnly() = doTestSuccess(INTERNAL, INTERNAL.toMock(), INTERNAL.toMock(), INTERNAL.toMock()) @Test(expected = IllegalCommonizerStateException::class) - fun privateOnly() = doTestFailure(PRIVATE) + fun privateOnly() = doTestFailure(PRIVATE.toMock()) @Test(expected = IllegalCommonizerStateException::class) - fun publicAndProtected() = doTestFailure(PROTECTED, PROTECTED, PROTECTED, PUBLIC) + fun publicAndProtected() = doTestFailure(PROTECTED.toMock(), PROTECTED.toMock(), PUBLIC.toMock()) @Test(expected = IllegalCommonizerStateException::class) - fun publicAndInternal() = doTestFailure(INTERNAL, INTERNAL, INTERNAL, PUBLIC) + fun publicAndInternal() = doTestFailure(INTERNAL.toMock(), INTERNAL.toMock(), PUBLIC.toMock()) @Test(expected = IllegalCommonizerStateException::class) - fun protectedAndInternal() = doTestFailure(PROTECTED, PROTECTED, PROTECTED, INTERNAL) + fun protectedAndInternal() = doTestFailure(PROTECTED.toMock(), PROTECTED.toMock(), INTERNAL.toMock()) @Test(expected = IllegalCommonizerStateException::class) - fun publicAndPrivate() = doTestFailure(PUBLIC, PUBLIC, PRIVATE) + fun publicAndPrivate() = doTestFailure(PUBLIC.toMock(), PUBLIC.toMock(), PRIVATE.toMock()) @Test(expected = IllegalCommonizerStateException::class) - fun somethingUnexpected() = doTestFailure(PUBLIC, LOCAL) + fun somethingUnexpected() = doTestFailure(PUBLIC.toMock(), LOCAL.toMock()) override fun createCommonizer() = VisibilityCommonizer.equalizing() } + +private fun Visibility.toMock() = object : DeclarationWithVisibility { + override val visibility: Visibility = this@toMock +} diff --git a/konan/commonizer/tests/org/jetbrains/kotlin/descriptors/commonizer/core/LoweringVisibilityCommonizerTest.kt b/konan/commonizer/tests/org/jetbrains/kotlin/descriptors/commonizer/core/LoweringVisibilityCommonizerTest.kt index 9264a141925..1353a390e41 100644 --- a/konan/commonizer/tests/org/jetbrains/kotlin/descriptors/commonizer/core/LoweringVisibilityCommonizerTest.kt +++ b/konan/commonizer/tests/org/jetbrains/kotlin/descriptors/commonizer/core/LoweringVisibilityCommonizerTest.kt @@ -5,38 +5,96 @@ package org.jetbrains.kotlin.descriptors.commonizer.core +import org.jetbrains.kotlin.descriptors.* import org.jetbrains.kotlin.descriptors.Visibilities.* -import org.jetbrains.kotlin.descriptors.Visibility +import org.jetbrains.kotlin.descriptors.commonizer.mergedtree.ir.DeclarationWithVisibility +import org.jetbrains.kotlin.descriptors.commonizer.mergedtree.ir.MaybeVirtualCallableMember import org.junit.Test -class LoweringVisibilityCommonizerTest : AbstractCommonizerTest() { +abstract class LoweringVisibilityCommonizerTest( + private val allowPrivate: Boolean, + private val areMembersVirtual: Boolean +) : AbstractCommonizerTest() { @Test - fun publicOnly() = doTestSuccess(PUBLIC, PUBLIC, PUBLIC, PUBLIC) + fun publicOnly() = doTestSuccess(PUBLIC, PUBLIC.toMock(), PUBLIC.toMock(), PUBLIC.toMock()) @Test - fun protectedOnly() = doTestSuccess(PROTECTED, PROTECTED, PROTECTED, PROTECTED) + fun protectedOnly() = doTestSuccess(PROTECTED, PROTECTED.toMock(), PROTECTED.toMock(), PROTECTED.toMock()) @Test - fun internalOnly() = doTestSuccess(INTERNAL, INTERNAL, INTERNAL, INTERNAL) + fun internalOnly() = doTestSuccess(INTERNAL, INTERNAL.toMock(), INTERNAL.toMock(), INTERNAL.toMock()) @Test(expected = IllegalCommonizerStateException::class) - fun privateOnly() = doTestFailure(PRIVATE) + fun somethingUnexpected() = doTestFailure(PUBLIC.toMock(), LOCAL.toMock()) - @Test - fun publicAndProtected() = doTestSuccess(PROTECTED, PUBLIC, PROTECTED, PUBLIC) + final override fun createCommonizer() = VisibilityCommonizer.lowering(allowPrivate = allowPrivate) - @Test - fun publicAndInternal() = doTestSuccess(INTERNAL, PUBLIC, INTERNAL, PUBLIC) + protected fun Visibility.toMock() = object : MaybeVirtualCallableMember { + override val visibility: Visibility = this@toMock + override val isVirtual: Boolean = !isPrivate(visibility) && areMembersVirtual + } - @Test(expected = IllegalCommonizerStateException::class) - fun protectedAndInternal() = doTestFailure(PUBLIC, INTERNAL, PROTECTED) + class PrivateMembers : LoweringVisibilityCommonizerTest(true, false) { - @Test(expected = IllegalCommonizerStateException::class) - fun publicAndPrivate() = doTestFailure(PUBLIC, INTERNAL, PRIVATE) + @Test + fun publicAndProtected() = doTestSuccess(PROTECTED, PUBLIC.toMock(), PROTECTED.toMock(), PUBLIC.toMock()) - @Test(expected = IllegalCommonizerStateException::class) - fun somethingUnexpected() = doTestFailure(PUBLIC, LOCAL) + @Test + fun publicAndInternal() = doTestSuccess(INTERNAL, PUBLIC.toMock(), INTERNAL.toMock(), PUBLIC.toMock()) - override fun createCommonizer() = VisibilityCommonizer.lowering() + @Test(expected = IllegalCommonizerStateException::class) + fun publicAndInternalAndProtected() = doTestFailure(PUBLIC.toMock(), INTERNAL.toMock(), PROTECTED.toMock()) + + @Test + fun publicAndInternalAndPrivate() = doTestSuccess(PRIVATE, PUBLIC.toMock(), INTERNAL.toMock(), PRIVATE.toMock()) + + @Test + fun privateOnly() = doTestSuccess(PRIVATE, PRIVATE.toMock(), PRIVATE.toMock(), PRIVATE.toMock()) + } + + class NonVirtualMembers : LoweringVisibilityCommonizerTest(false, false) { + + @Test + fun publicAndProtected() = doTestSuccess(PROTECTED, PUBLIC.toMock(), PROTECTED.toMock(), PUBLIC.toMock()) + + @Test + fun publicAndInternal() = doTestSuccess(INTERNAL, PUBLIC.toMock(), INTERNAL.toMock(), PUBLIC.toMock()) + + @Test(expected = IllegalCommonizerStateException::class) + fun publicAndInternalAndProtected() = doTestFailure(PUBLIC.toMock(), INTERNAL.toMock(), PROTECTED.toMock()) + + @Test(expected = IllegalCommonizerStateException::class) + fun publicAndInternalAndPrivate() = doTestFailure(PUBLIC.toMock(), INTERNAL.toMock(), PRIVATE.toMock()) + + @Test(expected = IllegalCommonizerStateException::class) + fun privateOnly() = doTestFailure(PRIVATE.toMock()) + } + + class VirtualMembers : LoweringVisibilityCommonizerTest(false, true) { + + @Test(expected = IllegalCommonizerStateException::class) + fun publicAndProtected1() = doTestFailure(PUBLIC.toMock(), PROTECTED.toMock()) + + @Test(expected = IllegalCommonizerStateException::class) + fun publicAndProtected2() = doTestFailure(PUBLIC.toMock(), PUBLIC.toMock(), PROTECTED.toMock()) + + @Test(expected = IllegalCommonizerStateException::class) + fun publicAndInternal1() = doTestFailure(PUBLIC.toMock(), INTERNAL.toMock()) + + @Test(expected = IllegalCommonizerStateException::class) + fun publicAndInternal2() = doTestFailure(PUBLIC.toMock(), PUBLIC.toMock(), INTERNAL.toMock()) + + @Test(expected = IllegalCommonizerStateException::class) + fun protectedAndInternal1() = doTestFailure(PROTECTED.toMock(), INTERNAL.toMock()) + + @Test(expected = IllegalCommonizerStateException::class) + fun protectedAndInternal2() = doTestFailure(PROTECTED.toMock(), PROTECTED.toMock(), INTERNAL.toMock()) + + @Test(expected = IllegalCommonizerStateException::class) + fun publicAndPrivate() = doTestFailure(PUBLIC.toMock(), PRIVATE.toMock()) + + @Test(expected = IllegalCommonizerStateException::class) + fun privateOnly() = doTestFailure(PRIVATE.toMock()) + } } 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 7e44a3f668e..127325316fe 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,12 @@ 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.descriptors.commonizer.mergedtree.ir.* +import org.jetbrains.kotlin.descriptors.impl.AbstractTypeAliasDescriptor +import org.jetbrains.kotlin.descriptors.impl.ClassDescriptorBase +import org.jetbrains.kotlin.descriptors.impl.TypeAliasConstructorDescriptor 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.scopes.MemberScope import org.jetbrains.kotlin.storage.LockBasedStorageManager import org.jetbrains.kotlin.test.KotlinTestUtils @@ -105,186 +104,13 @@ internal fun mockTAType( override val constructors: Collection = emptyList() override fun substitute(substitutor: TypeSubstitutor) = this override val expandedType by lazy { rightHandSideType } + }.apply { + initialize(emptyList()) } (rightHandSideType.getAbbreviatedType()?.expandedType ?: rightHandSideType).withAbbreviation(typeAliasDescriptor.defaultType) } -internal fun mockProperty( - name: String, - setterVisibility: Visibility?, - extensionReceiverType: KotlinType?, - returnType: KotlinType -): PropertyDescriptor { - val propertyName = Name.identifier(name) - - val propertyDescriptor = PropertyDescriptorImpl.create( - /*containingDeclaration =*/ fakeContainingDeclaration(), - /*annotations =*/ Annotations.EMPTY, - /*modality =*/ Modality.FINAL, - /*visibility =*/ Visibilities.PUBLIC, - /*isVar =*/ setterVisibility != null, - /*name =*/ propertyName, - /*kind =*/ CallableMemberDescriptor.Kind.DECLARATION, - /*source =*/ SourceElement.NO_SOURCE, - /*lateInit =*/ false, - /*isConst =*/ false, - /*isExpect =*/ false, - /*isActual =*/ false, - /*isExternal =*/ false, - /*isDelegated =*/ false - ) - - val extensionReceiverDescriptor = DescriptorFactory.createExtensionReceiverParameterForCallable( - /*owner =*/ propertyDescriptor, - /*receiverParameterType =*/ extensionReceiverType, - /*annotations =*/ Annotations.EMPTY - ) - - val dispatchReceiverDescriptor = buildDispatchReceiver(propertyDescriptor) - - propertyDescriptor.setType( - /*outType =*/ returnType, - /*typeParameters =*/ emptyList(), - /*dispatchReceiverParameter =*/ dispatchReceiverDescriptor, - /*extensionReceiverParameter =*/ extensionReceiverDescriptor - ) - - val getter = DescriptorFactory.createDefaultGetter( - /*propertyDescriptor =*/ propertyDescriptor, - /*annotations =*/ Annotations.EMPTY - ).apply { - initialize(null) // use return type from the property descriptor - } - - val setter = setterVisibility?.let { - DescriptorFactory.createSetter( - /*propertyDescriptor =*/ propertyDescriptor, - /*annotations =*/ Annotations.EMPTY, - /*parameterAnnotations =*/ Annotations.EMPTY, - /*isDefault =*/ false, - /*isExternal =*/ false, - /*isInline =*/ false, - /*visibility =*/ setterVisibility, - /*sourceElement =*/ SourceElement.NO_SOURCE - ) - } - - propertyDescriptor.initialize(getter, setter) - - return propertyDescriptor -} - -internal data class TestFunctionModifiers( - override val isOperator: Boolean = false, - override val isInfix: Boolean = false, - override val isInline: Boolean = false, - override val isTailrec: Boolean = false, - override val isSuspend: Boolean = false, - override val isExternal: Boolean = false -) : FunctionModifiers { - companion object { - fun areEqual(a: FunctionModifiers, b: FunctionModifiers) = - a.isOperator == b.isOperator && a.isInfix == b.isInfix && a.isInline == b.isInline - && a.isTailrec == b.isTailrec && a.isSuspend == b.isSuspend && a.isExternal == b.isExternal - } -} - -internal fun mockFunction( - name: String, - returnType: KotlinType, - modifiers: FunctionModifiers -): SimpleFunctionDescriptor { - val functionName = Name.identifier(name) - - val functionDescriptor = SimpleFunctionDescriptorImpl.create( - /*containingDeclaration =*/ fakeContainingDeclaration(), - /*annotations =*/ Annotations.EMPTY, - /*name =*/ functionName, - /*kind =*/ CallableMemberDescriptor.Kind.DECLARATION, - /*source =*/ SourceElement.NO_SOURCE - ) - - functionDescriptor.isOperator = modifiers.isOperator - functionDescriptor.isInfix = modifiers.isInfix - functionDescriptor.isInline = modifiers.isInline - functionDescriptor.isTailrec = modifiers.isTailrec - functionDescriptor.isSuspend = modifiers.isSuspend - functionDescriptor.isExternal = modifiers.isExternal - - val dispatchReceiverDescriptor = buildDispatchReceiver(functionDescriptor) - - functionDescriptor.initialize( - /*extensionReceiverParameter =*/ null, - /*dispatchReceiverDescriptor =*/ dispatchReceiverDescriptor, - /*typeParameters =*/ emptyList(), - /*unsubstitutedValueParameters =*/ emptyList(), - /*returnType =*/ returnType, - /*modality =*/ Modality.FINAL, - /*visibility =*/ Visibilities.PUBLIC - ) - - return functionDescriptor -} - -internal fun mockValueParameter( - containingDeclaration: CallableDescriptor? = null, - name: String, - index: Int, - returnType: KotlinType, - varargElementType: KotlinType?, - declaresDefaultValue: Boolean, - isCrossinline: Boolean, - isNoinline: Boolean -): ValueParameterDescriptor { - check(index >= 0) - - val effectiveContainingDeclaration = containingDeclaration - ?: /* use fake function if no real containing declaration specified */ mockFunction( - "fakeFunction", - returnType, - TestFunctionModifiers() - ) - - return ValueParameterDescriptorImpl( - containingDeclaration = effectiveContainingDeclaration, - original = null, - index = index, - annotations = Annotations.EMPTY, - name = Name.identifier(name), - outType = returnType, - declaresDefaultValue = declaresDefaultValue, - isCrossinline = isCrossinline, - isNoinline = isNoinline, - varargElementType = varargElementType, - source = SourceElement.NO_SOURCE - ) -} - -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 { private val module: ModuleDescriptor by lazy { mockEmptyModule("") } @@ -310,8 +136,7 @@ private fun createSimpleType(typeConstructor: TypeConstructor, nullable: Boolean 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") - } +internal val EMPTY_CLASSIFIERS_CACHE = object : ClassifiersCache { + override val classes: Map get() = emptyMap() + override val typeAliases: Map get() = emptyMap() +}