[Commonizer] Classifiers

This commit is contained in:
Dmitriy Dolovov
2019-09-09 15:50:32 +07:00
parent e6b17e4bb5
commit 1a49d88578
74 changed files with 2473 additions and 1316 deletions
@@ -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
@@ -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<KotlinType>
) : ClassDescriptorBase(storageManager, containingDeclaration, name, SourceElement.NO_SOURCE, isExternal) {
private lateinit var _unsubstitutedMemberScope: MemberScope
private lateinit var constructors: Collection<ClassConstructorDescriptor>
private var primaryConstructor: ClassConstructorDescriptor? = null
private val staticScope = if (kind == ClassKind.ENUM_CLASS) StaticScopeForKotlinEnum(storageManager, this) else MemberScope.Empty
private lateinit var declaredTypeParameters: List<TypeParameterDescriptor>
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<TypeParameterDescriptor>) {
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<CommonizedClassConstructorDescriptor>
) {
_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<KotlinType>
) : 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)
@@ -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<TypeParameterDescriptor>
override fun getTypeConstructorTypeParameters() = typeConstructorParameters
override lateinit var constructors: Collection<TypeAliasConstructorDescriptor>
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
}
}
@@ -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<ModuleDescriptor>) -> Unit
) : NodeVisitor<List<DeclarationDescriptor?>, List<DeclarationDescriptor?>> {
override fun visitRootNode(node: RootNode, data: List<DeclarationDescriptor?>): List<DeclarationDescriptor?> {
val allTargets = (node.target + node.common).map { it.targetId }
val allTargets = (node.target + node.common()!!).map { it.targetId }
val modulesByTargets = HashMap<TargetId, MutableList<ModuleDescriptorImpl>>()
@@ -63,7 +65,7 @@ internal class DeclarationsBuilderVisitor(
}
// initialize module descriptors:
moduleDescriptors.asListContaining<ModuleDescriptorImpl>().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<DeclarationDescriptor?>): List<DeclarationDescriptor?> {
val classesGroup = CommonizedGroup<ClassifierDescriptorWithTypeParameters>(node.dimension)
node.buildDescriptors(classesGroup, data, storageManager)
val classes = classesGroup.toList().asListContaining<CommonizedClassDescriptor>()
// build class constructors:
val allConstructorsByTargets = Array<MutableList<CommonizedClassConstructorDescriptor>>(node.dimension) { ArrayList() }
for (constructorNode in node.constructors) {
val constructorsByTargets = constructorNode.accept(this, classes).asListContaining<CommonizedClassConstructorDescriptor>()
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<DeclarationDescriptor?>): List<DeclarationDescriptor?> {
val containingDeclarations = data.asListContaining<ClassDescriptor>()
val constructorsGroup = CommonizedGroup<ClassConstructorDescriptor>(node.dimension)
node.buildDescriptors(constructorsGroup, containingDeclarations)
return constructorsGroup.toList()
}
override fun visitTypeAliasNode(node: TypeAliasNode, data: List<DeclarationDescriptor?>): List<DeclarationDescriptor?> {
val typeAliasesGroup = CommonizedGroup<ClassifierDescriptorWithTypeParameters>(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 <reified T : DeclarationDescriptor> noContainingDeclarations() = emptyList<T?>()
inline fun <reified T : DeclarationDescriptor> noReturningDeclarations() = emptyList<T?>()
@@ -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<ClassifierDescriptorWithTypeParameters>,
containingDeclarations: List<DeclarationDescriptor?>,
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<in ClassifierDescriptorWithTypeParameters>,
index: Int,
containingDeclarations: List<DeclarationDescriptor?>,
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<ClassConstructorDescriptor>,
containingDeclarations: List<ClassDescriptor?>
) {
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<ClassConstructorDescriptor>,
index: Int,
containingDeclarations: List<ClassDescriptor?>,
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
}
@@ -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<SimpleFunctionDescriptor>,
containingDeclarations: List<DeclarationDescriptor?>
) {
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<ValueParameter>.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
)
}
@@ -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(
@@ -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(
@@ -22,13 +22,13 @@ internal fun PropertyNode.buildDescriptors(
containingDeclarations: List<DeclarationDescriptor?>,
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,
@@ -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<ClassifierDescriptorWithTypeParameters>,
containingDeclarations: List<DeclarationDescriptor?>,
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<ClassifierDescriptorWithTypeParameters>,
index: Int,
containingDeclarations: List<DeclarationDescriptor?>,
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
}
@@ -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<TypeParameter>.buildDescriptors(
}
}
internal fun List<ValueParameter>.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(
@@ -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<T : Any>(
val size: Int,
initialize: (Int) -> T?
@@ -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<T : CallableMemberDescriptor, R: CallableMember> : Commonizer<T, R> {
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
}
@@ -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<T : FunctionOrProperty>(cache: ClassifiersCache) : AbstractStandardCommonizer<T, T>() {
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)
}
@@ -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<T, R>(
private val singleElementCommonizerFactory: () -> Commonizer<T, R>
) : Commonizer<List<T>, List<R>> {
@@ -27,13 +38,14 @@ abstract class AbstractListCommonizer<T, R>(
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
@@ -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<T : Named, R>(
private val singleElementCommonizerFactory: () -> Commonizer<T, R>
) : Commonizer<List<T>, List<R>> {
private var commonizers: List<Pair<Name, Commonizer<T, R>>>? = null
private var error = false
final override val result: List<R>
get() = commonizers?.takeIf { !error }?.map { it.second.result } ?: throw IllegalCommonizerStateException()
final override fun commonizeWith(next: List<T>): 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
}
}
@@ -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<T : Any, R : Any, WT, WR>(
private val wrappedCommonizerFactory: () -> Commonizer<WT, WR>,
private val extractor: (T) -> WT,
@@ -41,6 +46,7 @@ abstract class AbstractNullableCommonizer<T : Any, R : Any, WT, WR>(
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
}
@@ -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<ClassDeclaration, ClassDeclaration>() {
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)
}
@@ -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<ClassConstructor, ClassConstructor>() {
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
}
}
@@ -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<Unit, Unit> {
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<String, KotlinType>(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
}
}
@@ -10,4 +10,38 @@ interface Commonizer<T, R> {
fun commonizeWith(next: T): Boolean
}
abstract class AbstractStandardCommonizer<T, R> : Commonizer<T, R> {
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")
@@ -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<ReceiverParameterDescriptor?, UnwrappedType?> {
interface ExtensionReceiverCommonizer : Commonizer<ExtensionReceiver?, UnwrappedType?> {
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<ExtensionReceiver, UnwrappedType, KotlinType, UnwrappedType>(
wrappedCommonizerFactory = { TypeCommonizer.default(cache) },
extractor = { it.type },
builder = { it }
)
@@ -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<SimpleFunctionDescriptor, Function>() {
class FunctionCommonizer(cache: ClassifiersCache) : AbstractFunctionOrPropertyCommonizer<Function>(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
}
}
@@ -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<SimpleFunctionDescriptor, FunctionModifiers> {
interface FunctionModifiersCommonizer : Commonizer<FunctionModifiers, FunctionModifiers> {
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,
@@ -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<PropertyDescriptor, Property>() {
class PropertyCommonizer(cache: ClassifiersCache) : AbstractFunctionOrPropertyCommonizer<Property>(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
}
}
@@ -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<PropertySetterDescriptor?, Setter?> {
interface PropertySetterCommonizer : Commonizer<Setter?, Setter?> {
companion object {
fun default(): PropertySetterCommonizer = DefaultPropertySetterCommonizer()
}
@@ -17,8 +17,8 @@ interface PropertySetterCommonizer : Commonizer<PropertySetterDescriptor?, Sette
private class DefaultPropertySetterCommonizer :
PropertySetterCommonizer,
AbstractNullableCommonizer<PropertySetterDescriptor, Setter, Visibility, Visibility>(
AbstractNullableCommonizer<Setter, Setter, DeclarationWithVisibility, Visibility>(
wrappedCommonizerFactory = { VisibilityCommonizer.equalizing() },
extractor = { it.visibility },
extractor = { it },
builder = { Setter.createDefaultNoAnnotations(it) }
)
@@ -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<TypeAlias, ClassDeclaration>() {
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)
}
@@ -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<KotlinType, UnwrappedType> {
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<KotlinType, UnwrappedType>() {
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 <T : ClassifierDescriptor> 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
}
@@ -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<TypeParameterDescriptor, TypeParameter> {
interface TypeParameterCommonizer : Commonizer<TypeParameter, TypeParameter> {
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<TypeParameter, TypeParameter>() {
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<KotlinType, UnwrappedType>(
singleElementCommonizerFactory = { TypeCommonizer.default() }
private class TypeParameterUpperBoundsCommonizer(cache: ClassifiersCache) : AbstractListCommonizer<KotlinType, UnwrappedType>(
singleElementCommonizerFactory = { TypeCommonizer.default(cache) }
)
interface TypeParameterListCommonizer : Commonizer<List<TypeParameterDescriptor>, List<TypeParameter>> {
interface TypeParameterListCommonizer : Commonizer<List<TypeParameter>, List<TypeParameter>> {
companion object {
fun default(): TypeParameterListCommonizer = DefaultTypeParameterListCommonizer()
fun default(cache: ClassifiersCache): TypeParameterListCommonizer = DefaultTypeParameterListCommonizer(cache)
}
}
private class DefaultTypeParameterListCommonizer :
private class DefaultTypeParameterListCommonizer(cache: ClassifiersCache) :
TypeParameterListCommonizer,
AbstractNamedListCommonizer<TypeParameterDescriptor, TypeParameter>(
singleElementCommonizerFactory = { TypeParameterCommonizer.default() }
AbstractListCommonizer<TypeParameter, TypeParameter>(
singleElementCommonizerFactory = { TypeParameterCommonizer.default(cache) }
)
@@ -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<ValueParameterDescriptor, ValueParameter> {
interface ValueParameterCommonizer : Commonizer<ValueParameter, ValueParameter> {
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<ValueParameter, ValueParameter>() {
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<ValueParameterDescriptor>, List<ValueParameter>> {
companion object {
fun default(): ValueParameterListCommonizer = DefaultValueParameterListCommonizer()
}
}
private class DefaultValueParameterListCommonizer :
ValueParameterListCommonizer,
AbstractNamedListCommonizer<ValueParameterDescriptor, ValueParameter>(
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<ValueParameter>, List<ValueParameter>> {
companion object {
fun default(cache: ClassifiersCache): ValueParameterListCommonizer = DefaultValueParameterListCommonizer(cache)
}
}
private class DefaultValueParameterListCommonizer(cache: ClassifiersCache) :
ValueParameterListCommonizer,
AbstractListCommonizer<ValueParameter, ValueParameter>(
singleElementCommonizerFactory = { ValueParameterCommonizer.default(cache) }
)
@@ -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<Visibility, Visibility> {
abstract class VisibilityCommonizer(private val allowPrivate: Boolean) : Commonizer<DeclarationWithVisibility, Visibility> {
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<Visibility, Visibility> {
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
}
@@ -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<ModuleDescriptor>? = null
val otherModulesByTargets = LinkedHashMap<String, Collection<ModuleDescriptor>>()
// build resulting descriptors:
val visitor = DeclarationsBuilderVisitor(storageManager, DefaultBuiltIns.Instance) { targetId, commonizedModules ->
when (targetId) {
is CommonTargetId -> {
@@ -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<PropertyDescriptor?>
) = buildPropertyNode(storageManager, cache, containingDeclarationCommon, properties)
internal fun mergeFunctions(
storageManager: StorageManager,
cache: ClassifiersCache,
containingDeclarationCommon: NullableLazyValue<*>?,
properties: List<SimpleFunctionDescriptor?>
) = buildFunctionNode(storageManager, cache, containingDeclarationCommon, properties)
internal fun mergeClassConstructors(
storageManager: StorageManager,
cache: ClassifiersCache,
containingDeclarationCommon: NullableLazyValue<*>?,
constructors: List<ClassConstructorDescriptor?>
) = buildClassConstructorNode(storageManager, cache, containingDeclarationCommon, constructors)
@@ -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<ClassDescriptor?>
): ClassNode {
val node = buildClassNode(storageManager, cacheRW, containingDeclarationCommon, classes)
val constructorsMap = CommonizedGroupMap<ConstructorApproximationKey, ClassConstructorDescriptor>(classes.size)
val propertiesMap = CommonizedGroupMap<PropertyApproximationKey, PropertyDescriptor>(classes.size)
val functionsMap = CommonizedGroupMap<FunctionApproximationKey, SimpleFunctionDescriptor>(classes.size)
val classesMap = CommonizedGroupMap<Name, ClassDescriptor>(classes.size)
classes.forEachIndexed { index, clazz ->
clazz?.constructors?.forEach { constructorsMap[ConstructorApproximationKey(it)][index] = it }
clazz?.unsubstitutedMemberScope?.collectMembers(
CallableMemberCollector<PropertyDescriptor> { propertiesMap[PropertyApproximationKey(it)][index] = it },
CallableMemberCollector<SimpleFunctionDescriptor> { functionsMap[FunctionApproximationKey(it)][index] = it },
Collector<ClassDescriptor> { 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<TypeAliasDescriptor?>
) = buildTypeAliasNode(storageManager, cacheRW, typeAliases)
@@ -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<SimpleFunctionDescriptor?>) = buildFunctionNode(properties)
@@ -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<T : CallableMemberDescriptor>(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<TypeParameter> 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())
}
}
@@ -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<FqName>
val supertypes: Collection<KotlinType>
}
interface ClassConstructor : AnnotatedDeclaration, DeclarationWithTypeParameters, DeclarationWithVisibility, CallableMemberWithParameters {
val isPrimary: Boolean
val kind: CallableMemberDescriptor.Kind
}
data class CommonClassDeclaration(
override val name: Name,
override val typeParameters: List<TypeParameter>,
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<FqName> get() = emptyList()
override val supertypes: MutableCollection<KotlinType> = ArrayList()
}
data class CommonClassConstructor(
override val isPrimary: Boolean,
override val kind: CallableMemberDescriptor.Kind,
override val visibility: Visibility,
override val typeParameters: List<TypeParameter>,
override val valueParameters: List<ValueParameter>,
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<KotlinType> 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<TypeParameter> by lazy(PUBLICATION) { descriptor.typeParameters.map(::TargetTypeParameter) }
override val valueParameters: List<ValueParameter> 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<FqName> get() = unsupported()
override val supertypes: Collection<KotlinType> get() = unsupported()
override val annotations: Annotations get() = unsupported()
override val name: Name get() = unsupported()
override val visibility: Visibility get() = unsupported()
override val typeParameters: List<TypeParameter> get() = unsupported()
}
@@ -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<TypeParameter>
}
/** Indicates presence of recursion in lazy calculations. */
interface RecursionMarker : Declaration
@Suppress("unused")
internal fun Declaration.unsupported(): Nothing = error("This method should never be called")
@@ -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<ValueParameter>
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<ValueParameter>,
override val typeParameters: List<TypeParameter>
) : CommonCallableMember(), Function, FunctionModifiers by modifiers
override val typeParameters: List<TypeParameter>,
override val hasStableParameterNames: Boolean,
override val hasSynthesizedParameterNames: Boolean
) : CommonFunctionOrProperty(), Function, FunctionModifiers by modifiers
class TargetFunction(descriptor: SimpleFunctionDescriptor) : TargetCallableMember<SimpleFunctionDescriptor>(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<ValueParameter> get() = descriptor.valueParameters.map(::PlatformValueParameter)
class TargetFunction(descriptor: SimpleFunctionDescriptor) : TargetFunctionOrProperty<SimpleFunctionDescriptor>(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
}
@@ -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<T : CallableMemberDescriptor>(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())
}
}
@@ -11,4 +11,7 @@ interface NodeVisitor<R, T> {
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
}
@@ -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<TypeParameter>
) : 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<PropertyDescriptor>(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<PropertyDescriptor>(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,
@@ -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
}
@@ -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<UnwrappedType>
}
interface DeclarationWithTypeParameters : Declaration {
val typeParameters: List<TypeParameter>
}
data class CommonTypeParameter(
override val name: Name,
override val isReified: Boolean,
override val variance: Variance,
override val upperBounds: List<UnwrappedType>
) : 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<UnwrappedType> 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() } }
}
@@ -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<ConcreteTargetId>): RootNode = RootNode(
targets.map { Root(it) },
Root(CommonTargetId(targets.toSet()))
internal fun buildRootNode(
targets: List<ConcreteTargetId>
): RootNode = RootNode(
target = targets.map { Root(it) },
common = LockBasedStorageManager.NO_LOCKS.createNullableLazyValue {
Root(CommonTargetId(targets.toSet()))
}
)
internal fun buildModuleNode(modules: List<ModuleDescriptor?>): ModuleNode = buildNode(
modules,
{ Module(it.name) },
{ Module(it.firstNonNull().name) },
::ModuleNode
internal fun buildModuleNode(
moduleName: Name,
modules: List<ModuleDescriptor?>
): 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<MemberScope?>): PackageNode = buildNode(
packageMemberScopes,
{ Package(packageFqName) },
{ Package(packageFqName) },
::PackageNode
internal fun buildPackageNode(
packageFqName: FqName,
packageMemberScopes: List<MemberScope?>
): PackageNode = buildNode(
storageManager = LockBasedStorageManager.NO_LOCKS,
descriptors = packageMemberScopes,
targetDeclarationProducer = { Package(packageFqName) },
commonValueProducer = { Package(packageFqName) },
recursionMarker = null,
nodeProducer = ::PackageNode
)
internal fun buildPropertyNode(properties: List<PropertyDescriptor?>): PropertyNode = buildNode(
properties,
{ TargetProperty(it) },
{ commonize(it, PropertyCommonizer()) },
::PropertyNode
internal fun buildPropertyNode(
storageManager: StorageManager,
cache: ClassifiersCache,
containingDeclarationCommon: NullableLazyValue<*>?,
properties: List<PropertyDescriptor?>
): PropertyNode = buildNode(
storageManager = storageManager,
descriptors = properties,
targetDeclarationProducer = ::TargetProperty,
commonValueProducer = { commonize(containingDeclarationCommon, it, PropertyCommonizer(cache)) },
recursionMarker = null,
nodeProducer = ::PropertyNode
)
internal fun buildFunctionNode(functions: List<SimpleFunctionDescriptor?>): FunctionNode = buildNode(
functions,
{ TargetFunction(it) },
{ commonize(it, FunctionCommonizer()) },
::FunctionNode
internal fun buildFunctionNode(
storageManager: StorageManager,
cache: ClassifiersCache,
containingDeclarationCommon: NullableLazyValue<*>?,
functions: List<SimpleFunctionDescriptor?>
): FunctionNode = buildNode(
storageManager = storageManager,
descriptors = functions,
targetDeclarationProducer = ::TargetFunction,
commonValueProducer = { commonize(containingDeclarationCommon, it, FunctionCommonizer(cache)) },
recursionMarker = null,
nodeProducer = ::FunctionNode
)
private fun <T : Any, D : Declaration, N : Node<D>> buildNode(
descriptors: List<T?>,
targetDeclarationProducer: (T) -> D,
commonDeclarationProducer: (List<T?>) -> D?,
nodeProducer: (List<D?>, D?) -> N
internal fun buildClassNode(
storageManager: StorageManager,
cacheRW: ClassifiersCacheImpl,
containingDeclarationCommon: NullableLazyValue<*>?,
classes: List<ClassDescriptor?>
): 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<ClassConstructorDescriptor?>
): 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<TypeAliasDescriptor?>
): 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 <D : Any, T : Declaration, R : Declaration, N : Node<T, R>> buildNode(
storageManager: StorageManager,
descriptors: List<D?>,
targetDeclarationProducer: (D) -> T,
commonValueProducer: (List<T?>) -> R?,
recursionMarker: R?,
nodeProducer: (List<T?>, NullableLazyValue<R>) -> N
): N {
val target = CommonizedGroup<D>(descriptors.size)
val declarationsGroup = CommonizedGroup<T>(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 <T : Any, R : Declaration> commonize(descriptors: List<T?>, commonizer: Commonizer<T, R>): R? {
for (item in descriptors) {
if (item == null || !commonizer.commonizeWith(item))
internal fun <T, R> commonize(declarations: List<T?>, commonizer: Commonizer<T, R>): R? {
for (declaration in declarations) {
if (declaration == null || !commonizer.commonizeWith(declaration))
return null
}
return commonizer.result
}
@Suppress("NOTHING_TO_INLINE")
private inline fun <T, R> commonize(
containingDeclarationCommon: NullableLazyValue<*>?,
declarations: List<T?>,
commonizer: Commonizer<T, R>
): 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)
}
@@ -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<D : Declaration> {
val target: List<D?>
val common: D?
interface Node<T : Declaration, R : Declaration> {
val target: List<T?>
val common: NullableLazyValue<R>
fun <R, T> accept(visitor: NodeVisitor<R, T>, data: T): R
}
class RootNode(
override val target: List<Root>,
override val common: Root
) : Node<Root> {
override val common: NullableLazyValue<Root>
) : Node<Root, Root> {
class ClassifiersCacheImpl : ClassifiersCache {
override val classes = HashMap<FqName, ClassNode>()
override val typeAliases = HashMap<FqName, TypeAliasNode>()
}
val modules: MutableList<ModuleNode> = ArrayList()
val cache = ClassifiersCacheImpl()
override fun <R, T> accept(visitor: NodeVisitor<R, T>, data: T): R =
visitor.visitRootNode(this, data)
@@ -26,8 +33,8 @@ class RootNode(
class ModuleNode(
override val target: List<Module?>,
override val common: Module?
) : Node<Module> {
override val common: NullableLazyValue<Module>
) : Node<Module, Module> {
val packages: MutableList<PackageNode> = ArrayList()
override fun <R, T> accept(visitor: NodeVisitor<R, T>, data: T) =
@@ -36,10 +43,12 @@ class ModuleNode(
class PackageNode(
override val target: List<Package?>,
override val common: Package?
) : Node<Package> {
override val common: NullableLazyValue<Package>
) : Node<Package, Package> {
val properties: MutableList<PropertyNode> = ArrayList()
val functions: MutableList<FunctionNode> = ArrayList()
val classes: MutableList<ClassNode> = ArrayList()
val typeAliases: MutableList<TypeAliasNode> = ArrayList()
override fun <R, T> accept(visitor: NodeVisitor<R, T>, data: T) =
visitor.visitPackageNode(this, data)
@@ -47,22 +56,60 @@ class PackageNode(
class PropertyNode(
override val target: List<Property?>,
override val common: Property?
) : Node<Property> {
override val common: NullableLazyValue<Property>
) : Node<Property, Property> {
override fun <R, T> accept(visitor: NodeVisitor<R, T>, data: T) =
visitor.visitPropertyNode(this, data)
}
class FunctionNode(
override val target: List<Function?>,
override val common: Function?
) : Node<Function> {
override val common: NullableLazyValue<Function>
) : Node<Function, Function> {
override fun <R, T> accept(visitor: NodeVisitor<R, T>, data: T) =
visitor.visitFunctionNode(this, data)
}
internal val <D : Declaration> Node<D>.indexOfCommon: Int
class ClassNode(
override val target: List<ClassDeclaration?>,
override val common: NullableLazyValue<ClassDeclaration>
) : Node<ClassDeclaration, ClassDeclaration> {
lateinit var fqName: FqName
val constructors: MutableList<ClassConstructorNode> = ArrayList()
val properties: MutableList<PropertyNode> = ArrayList()
val functions: MutableList<FunctionNode> = ArrayList()
val classes: MutableList<ClassNode> = ArrayList()
override fun <R, T> accept(visitor: NodeVisitor<R, T>, data: T): R =
visitor.visitClassNode(this, data)
}
class ClassConstructorNode(
override val target: List<ClassConstructor?>,
override val common: NullableLazyValue<ClassConstructor>
) : Node<ClassConstructor, ClassConstructor> {
override fun <R, T> accept(visitor: NodeVisitor<R, T>, data: T): R =
visitor.visitClassConstructorNode(this, data)
}
class TypeAliasNode(
override val target: List<TypeAlias?>,
override val common: NullableLazyValue<ClassDeclaration>
) : Node<TypeAlias, ClassDeclaration> {
lateinit var fqName: FqName
override fun <R, T> accept(visitor: NodeVisitor<R, T>, data: T): R =
visitor.visitTypeAliasNode(this, data)
}
interface ClassifiersCache {
val classes: Map<FqName, ClassNode>
val typeAliases: Map<FqName, TypeAliasNode>
}
internal inline val Node<*, *>.indexOfCommon: Int
get() = target.size
internal val <D : Declaration> Node<D>.dimension: Int
internal inline val Node<*, *>.dimension: Int
get() = target.size + 1
@@ -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 <reified T : DeclarationDescriptor> Collector(
crossinline typedCollector: (T) -> Unit
): (DeclarationDescriptor) -> Boolean = { candidate ->
if (candidate is T) {
typedCollector(candidate)
true
} else
false
}
@Suppress("FunctionName")
internal inline fun <reified T : CallableMemberDescriptor> CallableMemberCollector(
crossinline typedCollector: (T) -> Unit
): (DeclarationDescriptor) -> Boolean = Collector<T> { 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<Pair<Name, String>>,
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<Pair<Name, String>>
) {
constructor(constructor: ConstructorDescriptor) : this(
constructor.valueParameters.map { it.name to it.type.fqNameWithTypeParameters }
)
}
@@ -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<ModuleDescriptor?>): ModuleNode {
val node = buildModuleNode(modules)
internal fun mergeModules(
storageManager: StorageManager,
cacheRW: RootNode.ClassifiersCacheImpl,
moduleName: Name,
modules: List<ModuleDescriptor?>
): ModuleNode {
val node = buildModuleNode(moduleName, modules)
val packageMemberScopesMap = CommonizedGroupMap<FqName, MemberScope>(modules.size)
@@ -28,7 +36,7 @@ internal fun mergeModules(modules: List<ModuleDescriptor?>): ModuleNode {
}
for ((packageFqName, packageMemberScopesGroup) in packageMemberScopesMap) {
node.packages += mergePackages(packageFqName, packageMemberScopesGroup.toList())
node.packages += mergePackages(storageManager, cacheRW, packageFqName, packageMemberScopesGroup.toList())
}
return node
@@ -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<MemberScope?>
): PackageNode {
val node = buildPackageNode(packageFqName, packageMemberScopes)
val propertiesMap = CommonizedGroupMap<PropertyKey, PropertyDescriptor>(packageMemberScopes.size)
val functionsMap = CommonizedGroupMap<FunctionKey, SimpleFunctionDescriptor>(packageMemberScopes.size)
val propertiesMap = CommonizedGroupMap<PropertyApproximationKey, PropertyDescriptor>(packageMemberScopes.size)
val functionsMap = CommonizedGroupMap<FunctionApproximationKey, SimpleFunctionDescriptor>(packageMemberScopes.size)
val classesMap = CommonizedGroupMap<Name, ClassDescriptor>(packageMemberScopes.size)
val typeAliasesMap = CommonizedGroupMap<Name, TypeAliasDescriptor>(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<PropertyDescriptor> { propertiesMap[PropertyApproximationKey(it)][index] = it },
CallableMemberCollector<SimpleFunctionDescriptor> { functionsMap[FunctionApproximationKey(it)][index] = it },
Collector<ClassDescriptor> { classesMap[it.name][index] = it },
Collector<TypeAliasDescriptor> { 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<PropertyDescriptor>()
.forEach { property ->
collector(PropertyKey(property), property)
}
}
internal data class FunctionKey(
val name: Name,
val valueParameters: List<Pair<Name, String>>,
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<SimpleFunctionDescriptor>()
.forEach { function ->
collector(FunctionKey(function), function)
}
}
@@ -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<PropertyDescriptor?>) = buildPropertyNode(properties)
@@ -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<Pair<ConcreteTargetId, Collection<ModuleDescriptor>>>): RootNode {
internal fun mergeRoots(
storageManager: StorageManager,
modulesByTargets: List<Pair<ConcreteTargetId, Collection<ModuleDescriptor>>>
): RootNode {
val node = buildRootNode(modulesByTargets.map { it.first })
val modulesMap = CommonizedGroupMap<Name, ModuleDescriptor>(modulesByTargets.size)
@@ -23,8 +27,8 @@ internal fun mergeRoots(modulesByTargets: List<Pair<ConcreteTargetId, Collection
}
}
for ((_, modulesGroup) in modulesMap) {
node.modules += mergeModules(modulesGroup.toList())
for ((moduleName, modulesGroup) in modulesMap) {
node.modules += mergeModules(storageManager, node.cache, moduleName, modulesGroup.toList())
}
return node
@@ -5,7 +5,9 @@
package org.jetbrains.kotlin.descriptors.commonizer
import org.jetbrains.kotlin.builtins.KotlinBuiltIns
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 org.jetbrains.kotlin.types.Variance
@@ -20,7 +22,7 @@ internal fun <T> Sequence<T>.toList(expectedCapacity: Int): List<T> {
internal inline fun <reified T> Iterable<T?>.firstNonNull() = firstIsInstance<T>()
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)
@@ -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
@@ -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
@@ -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
@@ -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<T>(val value: T)
class Fox
expect class Box<T>(value: T) {
val value: T
}
expect class Fox()
expect fun functionWithTypeParametersInReturnType1(): Array<Int>
expect fun functionWithTypeParametersInReturnType3(): Array<String>
@@ -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<T>(val value: T)
class Fox
actual class Box<T> actual constructor(actual val value: T)
actual class Fox actual constructor()
actual fun functionWithTypeParametersInReturnType1() = arrayOf(1)
fun functionWithTypeParametersInReturnType2() = arrayOf(1)
@@ -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<Int> = 1
fun functionWithMismatchedType5(): String = 1.toString()
class Box<T>(val value: T)
class Fox
actual class Box<T> actual constructor(actual val value: T)
actual class Fox actual constructor()
actual fun functionWithTypeParametersInReturnType1() = arrayOf(1)
fun functionWithTypeParametersInReturnType2() = arrayOf("hello")
@@ -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)
@@ -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
@@ -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
@@ -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<PropertyKey, PropertyDescriptor> =
mutableMapOf<PropertyKey, PropertyDescriptor>().also {
memberScope.collectProperties { propertyKey, property ->
it[propertyKey] = property
}
}
val expectedProperties = mutableMapOf<PropertyApproximationKey, PropertyDescriptor>()
val expectedFunctions = mutableMapOf<FunctionApproximationKey, SimpleFunctionDescriptor>()
val expectedClasses = mutableMapOf<FqName, ClassDescriptor>()
val expectedTypeAliases = mutableMapOf<FqName, TypeAliasDescriptor>()
val expectedProperties = collectProperties(expected)
val actualProperties = collectProperties(actual)
expected.collectMembers(
CallableMemberCollector<PropertyDescriptor> { expectedProperties[PropertyApproximationKey(it)] = it },
CallableMemberCollector<SimpleFunctionDescriptor> { expectedFunctions[FunctionApproximationKey(it)] = it },
Collector<ClassDescriptor> { expectedClasses[it.fqNameSafe] = it },
Collector<TypeAliasDescriptor> { expectedTypeAliases[it.fqNameSafe] = it }
)
val actualProperties = mutableMapOf<PropertyApproximationKey, PropertyDescriptor>()
val actualFunctions = mutableMapOf<FunctionApproximationKey, SimpleFunctionDescriptor>()
val actualClasses = mutableMapOf<FqName, ClassDescriptor>()
val actualTypeAliases = mutableMapOf<FqName, TypeAliasDescriptor>()
actual.collectMembers(
CallableMemberCollector<PropertyDescriptor> { actualProperties[PropertyApproximationKey(it)] = it },
CallableMemberCollector<SimpleFunctionDescriptor> { actualFunctions[FunctionApproximationKey(it)] = it },
Collector<ClassDescriptor> { actualClasses[it.fqNameSafe] = it },
Collector<TypeAliasDescriptor> { 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<FunctionKey, SimpleFunctionDescriptor> =
mutableMapOf<FunctionKey, SimpleFunctionDescriptor>().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<ClassDescriptor>()
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<ConstructorDescriptor>()
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<TypeAliasDescriptor>()
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<FqName?> = expected?.mapTo(HashSet()) { it.fqName } ?: emptySet()
val actualAnnotationFqNames: Set<FqName?> = 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
@@ -20,7 +20,7 @@ abstract class AbstractCommonizerTest<T, R> {
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<T, R> {
}
// 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 {
@@ -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<ReceiverParameterDescriptor?, UnwrappedType?>() {
class DefaultExtensionReceiverCommonizerTest : AbstractCommonizerTest<ExtensionReceiver?, UnwrappedType?>() {
@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()
)
@@ -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<SimpleFunctionDescriptor, FunctionModifiers>() {
class DefaultFunctionModifiersCommonizerTest : AbstractCommonizerTest<FunctionModifiers, FunctionModifiers>() {
@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
}
}
@@ -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<PropertySetterDescriptor?, Setter?>() {
class DefaultPropertySetterCommonizerTest : AbstractCommonizerTest<Setter?, Setter?>() {
@Test
fun absentOnly() = super.doTestSuccess(null, null, null, null)
@@ -61,22 +57,13 @@ class DefaultPropertySetterCommonizerTest : AbstractCommonizerTest<PropertySette
private fun doTestSuccess(expected: Visibility?, vararg variants: Visibility?) =
super.doTestSuccess(
expected?.let { Setter.createDefaultNoAnnotations(expected) },
*variants.map { it?.let(Visibility::toMockProperty) }.toTypedArray()
*variants.map { it?.let(Setter.Companion::createDefaultNoAnnotations) }.toTypedArray()
)
private fun doTestFailure(vararg variants: Visibility?) =
super.doTestFailure(
*variants.map { it?.let(Visibility::toMockProperty) }.toTypedArray()
*variants.map { it?.let(Setter.Companion::createDefaultNoAnnotations) }.toTypedArray()
)
override fun createCommonizer() = PropertySetterCommonizer.default()
}
@UseExperimental(TypeRefinement::class)
private fun Visibility.toMockProperty() = mockProperty(
name = "myProperty",
setterVisibility = this,
extensionReceiverType = null,
returnType = mockClassType("kotlin.String")
).setter!!
@@ -5,17 +5,34 @@
package org.jetbrains.kotlin.descriptors.commonizer.core
import org.jetbrains.kotlin.descriptors.ClassDescriptor
import org.jetbrains.kotlin.descriptors.TypeAliasDescriptor
import org.jetbrains.kotlin.descriptors.commonizer.CommonizedGroupMap
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.descriptors.commonizer.mockClassType
import org.jetbrains.kotlin.descriptors.commonizer.mockTAType
import org.jetbrains.kotlin.name.FqName
import org.jetbrains.kotlin.resolve.descriptorUtil.fqNameSafe
import org.jetbrains.kotlin.storage.LockBasedStorageManager
import org.jetbrains.kotlin.types.KotlinType
import org.jetbrains.kotlin.types.UnwrappedType
import org.jetbrains.kotlin.types.getAbbreviation
import org.jetbrains.kotlin.types.refinement.TypeRefinement
import org.junit.Before
import org.junit.Test
// TODO: add tests for type parameters
@TypeRefinement
class DefaultTypeCommonizerTest : AbstractCommonizerTest<KotlinType, UnwrappedType>() {
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<KotlinType, UnwrappedTy
@Test(expected = IllegalCommonizerStateException::class)
fun classTypesInUserPackageWithDifferentNames1() = doTestFailure(
mockClassType("org.sample.Foo"),
mockClassType("org.sample.Foo"),
mockClassType("org.fictitiousPackageName.Foo")
)
@Test(expected = IllegalCommonizerStateException::class)
fun classTypesInUserPackageWithDifferentNames2() = doTestFailure(
mockClassType("org.sample.Foo"),
mockClassType("org.sample.Foo"),
mockClassType("org.sample.Bar")
)
@Test(expected = IllegalCommonizerStateException::class)
fun classTypesInUserPackageWithDifferentNames3() = doTestFailure(
mockClassType("org.sample.Foo"),
mockClassType("org.sample.Foo"),
mockClassType("kotlin.String")
)
@@ -243,14 +257,12 @@ class DefaultTypeCommonizerTest : AbstractCommonizerTest<KotlinType, UnwrappedTy
@Test(expected = IllegalCommonizerStateException::class)
fun taTypesInUserPackageWithDifferentNames() = doTestFailure(
mockTAType("org.sample.FooAlias") { mockClassType("org.sample.Foo") },
mockTAType("org.sample.FooAlias") { mockClassType("org.sample.Foo") },
mockTAType("org.sample.BarAlias") { mockClassType("org.sample.Foo") }
)
@Test(expected = IllegalCommonizerStateException::class)
fun taTypesInUserPackageWithDifferentClasses() = doTestFailure(
mockTAType("org.sample.FooAlias") { mockClassType("org.sample.Foo") },
mockTAType("org.sample.FooAlias") { mockClassType("org.sample.Foo") },
mockTAType("org.sample.FooAlias") { mockClassType("org.sample.Bar") }
)
@@ -346,18 +358,59 @@ class DefaultTypeCommonizerTest : AbstractCommonizerTest<KotlinType, UnwrappedTy
@Test(expected = IllegalCommonizerStateException::class)
fun taTypesInUserPackageWithDifferentNullability3() = doTestFailure(
mockTAType("org.sample.FooAlias") { mockClassType("org.sample.Foo", nullable = false) },
mockTAType("org.sample.FooAlias") { mockClassType("org.sample.Foo", nullable = false) },
mockTAType("org.sample.FooAlias") { mockClassType("org.sample.Foo", nullable = true) }
)
@Test(expected = IllegalCommonizerStateException::class)
fun taTypesInUserPackageWithDifferentNullability4() = doTestFailure(
mockTAType("org.sample.FooAlias") { mockClassType("org.sample.Foo", nullable = true) },
mockTAType("org.sample.FooAlias") { mockClassType("org.sample.Foo", nullable = true) },
mockTAType("org.sample.FooAlias") { mockClassType("org.sample.Foo", nullable = false) }
)
override fun createCommonizer() = TypeCommonizer.default()
override fun isEqual(a: UnwrappedType?, b: UnwrappedType?) = (a === b) || (a != null && b != null && areTypesEqual(a, b))
private fun prepareCache(vararg variants: KotlinType) {
check(variants.isNotEmpty())
val classesMap = CommonizedGroupMap<FqName, ClassDescriptor>(variants.size)
val typeAliasesMap = CommonizedGroupMap<FqName, TypeAliasDescriptor>(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))
}
@@ -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<TypeParameterDescriptor, TypeParameter>() {
override fun createCommonizer() = TypeParameterCommonizer.default()
class DefaultTypeParameterCommonizerTest : AbstractCommonizerTest<TypeParameter, TypeParameter>() {
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<TypeParameterD
variance = variance,
upperBounds = upperBounds.map { mockClassType(it).unwrap() }
)
fun TypeParameter.toMockParam(
index: Int = 0
): TypeParameterDescriptor = mockTypeParameter(
name = name.asString(),
index = index,
isReified = isReified,
variance = variance,
upperBounds = upperBounds
)
}
}
@@ -5,13 +5,13 @@
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.TypeParameter
import org.jetbrains.kotlin.types.refinement.TypeRefinement
import org.junit.Test
@TypeRefinement
class DefaultTypeParameterListCommonizerTest : AbstractCommonizerTest<List<TypeParameterDescriptor>, List<TypeParameter>>() {
class DefaultTypeParameterListCommonizerTest : AbstractCommonizerTest<List<TypeParameter>, List<TypeParameter>>() {
@Test
fun emptyValueParameters() = doTestSuccess(
@@ -23,108 +23,104 @@ class DefaultTypeParameterListCommonizerTest : AbstractCommonizerTest<List<TypeP
@Test
fun matchedParameters() = doTestSuccess(
create(
mockTypeParams(
"T" to "kotlin.Any?",
"R" to "kotlin.CharSequence",
"Q" to "org.sample.Foo?"
),
create(
mockTypeParams(
"T" to "kotlin.Any?",
"R" to "kotlin.CharSequence",
"Q" to "org.sample.Foo?"
).toMockParams(),
create(
),
mockTypeParams(
"T" to "kotlin.Any?",
"R" to "kotlin.CharSequence",
"Q" to "org.sample.Foo?"
).toMockParams(),
create(
),
mockTypeParams(
"T" to "kotlin.Any?",
"R" to "kotlin.CharSequence",
"Q" to "org.sample.Foo?"
).toMockParams()
)
)
@Test(expected = IllegalCommonizerStateException::class)
fun mismatchedParameterListSize1() = doTestFailure(
create(
mockTypeParams(
"T" to "kotlin.Any?",
"R" to "kotlin.CharSequence",
"Q" to "org.sample.Foo?"
).toMockParams(),
create(
),
mockTypeParams(
"T" to "kotlin.Any?",
"R" to "kotlin.CharSequence",
"Q" to "org.sample.Foo?"
).toMockParams(),
),
emptyList()
)
@Test(expected = IllegalCommonizerStateException::class)
fun mismatchedParameterListSize2() = doTestFailure(
create(
mockTypeParams(
"T" to "kotlin.Any?",
"R" to "kotlin.CharSequence",
"Q" to "org.sample.Foo?"
).toMockParams(),
create(
),
mockTypeParams(
"T" to "kotlin.Any?",
"R" to "kotlin.CharSequence",
"Q" to "org.sample.Foo?"
).toMockParams(),
create(
),
mockTypeParams(
"T" to "kotlin.Any?",
"R" to "kotlin.CharSequence"
).toMockParams()
)
)
@Test(expected = IllegalCommonizerStateException::class)
fun mismatchedParameterListSize3() = doTestFailure(
create(
mockTypeParams(
"T" to "kotlin.Any?",
"R" to "kotlin.CharSequence",
"Q" to "org.sample.Foo?"
).toMockParams(),
create(
),
mockTypeParams(
"T" to "kotlin.Any?",
"R" to "kotlin.CharSequence",
"Q" to "org.sample.Foo?"
).toMockParams(),
create(
),
mockTypeParams(
"T" to "kotlin.Any?",
"R" to "kotlin.CharSequence",
"Q" to "org.sample.Foo?",
"V" to "org.sample.Bar"
).toMockParams()
)
)
@Test(expected = IllegalCommonizerStateException::class)
fun mismatchedParameterNames() = doTestFailure(
create(
mockTypeParams(
"T" to "kotlin.Any?",
"R" to "kotlin.CharSequence"
).toMockParams(),
create(
),
mockTypeParams(
"T" to "kotlin.Any?",
"Q" to "kotlin.CharSequence"
).toMockParams()
)
)
override fun createCommonizer() = TypeParameterListCommonizer.default()
override fun createCommonizer() = TypeParameterListCommonizer.default(EMPTY_CLASSIFIERS_CACHE)
private companion object {
fun create(vararg params: Pair<String, String>): List<TypeParameter> {
fun mockTypeParams(vararg params: Pair<String, String>): List<TypeParameter> {
check(params.isNotEmpty())
return params.map { (name, returnTypeFqName) ->
DefaultTypeParameterCommonizerTest.create(
DefaultTypeParameterCommonizerTest.mockTypeParam(
name = name,
upperBounds = listOf(returnTypeFqName)
)
}
}
fun List<TypeParameter>.toMockParams() = DefaultTypeParameterCommonizerTest.run {
mapIndexed { index, param -> param.toMockParam(index) }
}
}
}
@@ -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<ValueParameterDescriptor, ValueParameter>() {
class DefaultValueParameterCommonizerTest : AbstractCommonizerTest<ValueParameter, ValueParameter>() {
@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))
}
}
}
@@ -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<ValueParameterDescriptor>, List<ValueParameter>>() {
class DefaultValueParameterListCommonizerTest : AbstractCommonizerTest<List<ValueParameter>, List<ValueParameter>>() {
@Test
fun emptyValueParameters() = doTestSuccess(
@@ -23,163 +24,173 @@ class DefaultValueParameterListCommonizerTest : AbstractCommonizerTest<List<Valu
@Test
fun matchedParameters() = doTestSuccess(
create(
mockValueParams(
"a" to "kotlin.String",
"b" to "kotlin.Int",
"c" to "org.sample.Foo"
),
create(
mockValueParams(
"a" to "kotlin.String",
"b" to "kotlin.Int",
"c" to "org.sample.Foo"
).toMockParams(),
create(
),
mockValueParams(
"a" to "kotlin.String",
"b" to "kotlin.Int",
"c" to "org.sample.Foo"
).toMockParams(),
create(
),
mockValueParams(
"a" to "kotlin.String",
"b" to "kotlin.Int",
"c" to "org.sample.Foo"
).toMockParams()
)
)
@Test(expected = IllegalCommonizerStateException::class)
fun mismatchedParameterListSize1() = doTestFailure(
create(
mockValueParams(
"a" to "kotlin.String",
"b" to "kotlin.Int",
"c" to "org.sample.Foo"
).toMockParams(),
create(
),
mockValueParams(
"a" to "kotlin.String",
"b" to "kotlin.Int",
"c" to "org.sample.Foo"
).toMockParams(),
),
emptyList()
)
@Test(expected = IllegalCommonizerStateException::class)
fun mismatchedParameterListSize2() = doTestFailure(
create(
mockValueParams(
"a" to "kotlin.String",
"b" to "kotlin.Int",
"c" to "org.sample.Foo"
).toMockParams(),
create(
),
mockValueParams(
"a" to "kotlin.String",
"b" to "kotlin.Int",
"c" to "org.sample.Foo"
).toMockParams(),
create(
),
mockValueParams(
"a" to "kotlin.String",
"b" to "kotlin.Int",
"c" to "org.sample.Foo"
).toMockParams(),
create(
),
mockValueParams(
"a" to "kotlin.String",
"b" to "kotlin.Int"
).toMockParams()
)
)
@Test(expected = IllegalCommonizerStateException::class)
fun mismatchedParameterListSize3() = doTestFailure(
create(
mockValueParams(
"a" to "kotlin.String",
"b" to "kotlin.Int",
"c" to "org.sample.Foo"
).toMockParams(),
create(
),
mockValueParams(
"a" to "kotlin.String",
"b" to "kotlin.Int",
"c" to "org.sample.Foo"
).toMockParams(),
create(
),
mockValueParams(
"a" to "kotlin.String",
"b" to "kotlin.Int",
"c" to "org.sample.Foo"
).toMockParams(),
create(
),
mockValueParams(
"a" to "kotlin.String",
"b" to "kotlin.Int",
"c" to "org.sample.Foo",
"d" to "org.sample.Bar"
).toMockParams()
)
)
@Test(expected = IllegalCommonizerStateException::class)
fun mismatchedParameterNames1() = doTestFailure(
create(
mockValueParams(
"a" to "kotlin.String",
"b" to "kotlin.Int",
"c" to "org.sample.Foo"
).toMockParams(),
create(
),
mockValueParams(
"a" to "kotlin.String",
"b" to "kotlin.Int",
"c" to "org.sample.Foo"
).toMockParams(),
create(
),
mockValueParams(
"a1" to "kotlin.String",
"b" to "kotlin.Int",
"c" to "org.sample.Foo"
).toMockParams()
)
)
@Test(expected = IllegalCommonizerStateException::class)
fun mismatchedParameterNames2() = doTestFailure(
create(
mockValueParams(
"a" to "kotlin.String",
"b" to "kotlin.Int",
"c" to "org.sample.Foo"
).toMockParams(),
create(
),
mockValueParams(
"a" to "kotlin.String",
"b" to "kotlin.Int",
"c" to "org.sample.Foo"
).toMockParams(),
create(
),
mockValueParams(
"a" to "kotlin.String",
"b" to "kotlin.Int",
"c1" to "org.sample.Foo"
).toMockParams()
)
)
@Test(expected = IllegalCommonizerStateException::class)
fun mismatchedParameterTypes() = doTestFailure(
create(
mockValueParams(
"a" to "kotlin.String",
"b" to "kotlin.Int",
"c" to "org.sample.Foo"
).toMockParams(),
create(
),
mockValueParams(
"a" to "kotlin.String",
"b" to "kotlin.Int",
"c" to "org.sample.Foo"
).toMockParams(),
create(
),
mockValueParams(
"a" to "kotlin.Int",
"b" to "kotlin.String",
"c" to "org.sample.Bar"
).toMockParams()
)
)
override fun createCommonizer() = ValueParameterListCommonizer.default()
override fun createCommonizer() = ValueParameterListCommonizer.default(EMPTY_CLASSIFIERS_CACHE)
override fun isEqual(a: List<ValueParameter>?, b: List<ValueParameter>?): 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<String, String>): List<ValueParameter> {
fun mockValueParams(vararg params: Pair<String, String>): List<ValueParameter> {
check(params.isNotEmpty())
return params.map { (name, returnTypeFqName) ->
DefaultValueParameterCommonizerTest.create(
DefaultValueParameterCommonizerTest.mockValueParam(
name = name,
returnTypeFqName = returnTypeFqName
)
}
}
fun List<ValueParameter>.toMockParams() = DefaultValueParameterCommonizerTest.run {
mapIndexed { index, param -> param.toMockParam(index) }
}
}
}
@@ -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<Visibility, Visibility>() {
class EqualizingVisibilityCommonizerTest : AbstractCommonizerTest<DeclarationWithVisibility, Visibility>() {
@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
}
@@ -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<Visibility, Visibility>() {
abstract class LoweringVisibilityCommonizerTest(
private val allowPrivate: Boolean,
private val areMembersVirtual: Boolean
) : AbstractCommonizerTest<DeclarationWithVisibility, Visibility>() {
@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())
}
}
@@ -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<TypeAliasConstructorDescriptor> = 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<KotlinType>
): 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("<module4_${classifierFqName.shortName()}_x${Random.nextInt()}>") }
@@ -310,8 +136,7 @@ private fun createSimpleType(typeConstructor: TypeConstructor, nullable: Boolean
refinedTypeFactory = { null }
)
private fun fakeContainingDeclaration() =
object : DeclarationDescriptorImpl(Annotations.EMPTY, Name.special("<fake containing declaration>")) {
override fun getContainingDeclaration() = error("not supported")
override fun <R : Any?, D : Any?> accept(visitor: DeclarationDescriptorVisitor<R, D>?, data: D) = error("not supported")
}
internal val EMPTY_CLASSIFIERS_CACHE = object : ClassifiersCache {
override val classes: Map<FqName, ClassNode> get() = emptyMap()
override val typeAliases: Map<FqName, TypeAliasNode> get() = emptyMap()
}