[FE 1.0] Provide implementation of ExpectActualMatchingContext for FE 1.0
^KT-58578
This commit is contained in:
committed by
Space Team
parent
b26b649d4e
commit
8338370fbd
+326
@@ -0,0 +1,326 @@
|
||||
/*
|
||||
* Copyright 2010-2023 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.resolve.multiplatform
|
||||
|
||||
import org.jetbrains.kotlin.descriptors.*
|
||||
import org.jetbrains.kotlin.incremental.components.NoLookupLocation
|
||||
import org.jetbrains.kotlin.mpp.*
|
||||
import org.jetbrains.kotlin.name.CallableId
|
||||
import org.jetbrains.kotlin.name.ClassId
|
||||
import org.jetbrains.kotlin.name.Name
|
||||
import org.jetbrains.kotlin.resolve.DescriptorUtils
|
||||
import org.jetbrains.kotlin.resolve.calls.components.ClassicTypeSystemContextForCS
|
||||
import org.jetbrains.kotlin.resolve.calls.mpp.ExpectActualMatchingContext
|
||||
import org.jetbrains.kotlin.resolve.descriptorUtil.classId
|
||||
import org.jetbrains.kotlin.resolve.descriptorUtil.getKotlinTypeRefiner
|
||||
import org.jetbrains.kotlin.resolve.descriptorUtil.isTypeRefinementEnabled
|
||||
import org.jetbrains.kotlin.resolve.scopes.DescriptorKindFilter
|
||||
import org.jetbrains.kotlin.resolve.scopes.MemberScope
|
||||
import org.jetbrains.kotlin.resolve.scopes.getDescriptorsFiltered
|
||||
import org.jetbrains.kotlin.types.*
|
||||
import org.jetbrains.kotlin.types.checker.*
|
||||
import org.jetbrains.kotlin.types.model.KotlinTypeMarker
|
||||
import org.jetbrains.kotlin.types.model.TypeConstructorMarker
|
||||
import org.jetbrains.kotlin.types.model.TypeSubstitutorMarker
|
||||
import org.jetbrains.kotlin.types.model.TypeSystemInferenceExtensionContext
|
||||
import org.jetbrains.kotlin.types.typeUtil.asTypeProjection
|
||||
import org.jetbrains.kotlin.utils.addToStdlib.UnsafeCastFunction
|
||||
import org.jetbrains.kotlin.utils.addToStdlib.castAll
|
||||
import org.jetbrains.kotlin.utils.keysToMap
|
||||
|
||||
class ClassicExpectActualMatchingContext(val platformModule: ModuleDescriptor) : ExpectActualMatchingContext<MemberDescriptor>,
|
||||
TypeSystemInferenceExtensionContext by ClassicTypeSystemContextForCS(platformModule.builtIns, KotlinTypeRefiner.Default)
|
||||
{
|
||||
override val shouldCheckReturnTypesOfCallables: Boolean
|
||||
get() = true
|
||||
|
||||
private fun CallableSymbolMarker.asDescriptor(): CallableDescriptor = this as CallableDescriptor
|
||||
private fun FunctionSymbolMarker.asDescriptor(): FunctionDescriptor = this as FunctionDescriptor
|
||||
private fun PropertySymbolMarker.asDescriptor(): PropertyDescriptor = this as PropertyDescriptor
|
||||
private fun ValueParameterSymbolMarker.asDescriptor(): ValueParameterDescriptor = this as ValueParameterDescriptor
|
||||
private fun TypeParameterSymbolMarker.asDescriptor(): TypeParameterDescriptor = this as TypeParameterDescriptor
|
||||
private fun ClassLikeSymbolMarker.asDescriptor(): ClassifierDescriptorWithTypeParameters = this as ClassifierDescriptorWithTypeParameters
|
||||
private fun RegularClassSymbolMarker.asDescriptor(): ClassDescriptor = this as ClassDescriptor
|
||||
private fun TypeAliasSymbolMarker.asDescriptor(): TypeAliasDescriptor = this as TypeAliasDescriptor
|
||||
private inline fun <reified T : DeclarationDescriptor> DeclarationSymbolMarker.safeAsDescriptor(): T? = this as? T
|
||||
|
||||
override val RegularClassSymbolMarker.classId: ClassId
|
||||
get() = (this as ClassifierDescriptor).classId!!
|
||||
override val TypeAliasSymbolMarker.classId: ClassId
|
||||
get() = (this as ClassifierDescriptor).classId!!
|
||||
override val CallableSymbolMarker.callableId: CallableId
|
||||
get() {
|
||||
val descriptor = asDescriptor()
|
||||
return when (val parent = descriptor.containingDeclaration) {
|
||||
is PackageFragmentDescriptor -> CallableId(parent.fqName, descriptor.name)
|
||||
is ClassifierDescriptor -> CallableId(parent.classId!!, descriptor.name)
|
||||
else -> error("Callable descriptor without callableId: $descriptor")
|
||||
}
|
||||
}
|
||||
override val TypeParameterSymbolMarker.parameterName: Name
|
||||
get() = asDescriptor().name
|
||||
override val ValueParameterSymbolMarker.parameterName: Name
|
||||
get() = asDescriptor().name
|
||||
|
||||
override fun TypeAliasSymbolMarker.expandToRegularClass(): RegularClassSymbolMarker? {
|
||||
return asDescriptor().classDescriptor
|
||||
}
|
||||
|
||||
override val RegularClassSymbolMarker.classKind: ClassKind
|
||||
get() = asDescriptor().kind
|
||||
override val RegularClassSymbolMarker.isCompanion: Boolean
|
||||
get() = safeAsDescriptor<ClassDescriptor>()?.isCompanionObject == true
|
||||
override val RegularClassSymbolMarker.isInner: Boolean
|
||||
get() = asDescriptor().isInner
|
||||
override val RegularClassSymbolMarker.isInline: Boolean
|
||||
get() = safeAsDescriptor<ClassDescriptor>()?.isInline == true
|
||||
override val RegularClassSymbolMarker.isValue: Boolean
|
||||
get() = safeAsDescriptor<ClassDescriptor>()?.isValue == true
|
||||
override val RegularClassSymbolMarker.isFun: Boolean
|
||||
get() = safeAsDescriptor<ClassDescriptor>()?.isFun == true
|
||||
override val ClassLikeSymbolMarker.typeParameters: List<TypeParameterSymbolMarker>
|
||||
get() = asDescriptor().declaredTypeParameters
|
||||
override val ClassLikeSymbolMarker.modality: Modality
|
||||
get() = asDescriptor().modality
|
||||
override val ClassLikeSymbolMarker.visibility: Visibility
|
||||
get() = asDescriptor().visibility.delegate
|
||||
override val CallableSymbolMarker.modality: Modality?
|
||||
get() = safeAsDescriptor<CallableMemberDescriptor>()?.modality
|
||||
override val CallableSymbolMarker.visibility: Visibility
|
||||
get() = asDescriptor().visibility.delegate
|
||||
override val RegularClassSymbolMarker.superTypes: List<KotlinTypeMarker>
|
||||
get() = asDescriptor().typeConstructor.supertypes.toList()
|
||||
override val CallableSymbolMarker.isExpect: Boolean
|
||||
get() = safeAsDescriptor<MemberDescriptor>()?.isExpect == true
|
||||
|
||||
override val CallableSymbolMarker.isInline: Boolean
|
||||
get() = when (this) {
|
||||
is FunctionDescriptor -> isInline
|
||||
is PropertyDescriptor -> getter?.isInline == true
|
||||
else -> false
|
||||
}
|
||||
|
||||
override val CallableSymbolMarker.isSuspend: Boolean
|
||||
get() = when (this) {
|
||||
is FunctionDescriptor -> isSuspend
|
||||
is PropertyDescriptor -> getter?.isSuspend == true
|
||||
else -> false
|
||||
}
|
||||
|
||||
override val CallableSymbolMarker.isExternal: Boolean
|
||||
get() = safeAsDescriptor<MemberDescriptor>()?.isExternal == true
|
||||
override val CallableSymbolMarker.isInfix: Boolean
|
||||
get() = safeAsDescriptor<FunctionDescriptor>()?.isInfix == true
|
||||
override val CallableSymbolMarker.isOperator: Boolean
|
||||
get() = safeAsDescriptor<FunctionDescriptor>()?.isOperator == true
|
||||
override val CallableSymbolMarker.isTailrec: Boolean
|
||||
get() = safeAsDescriptor<FunctionDescriptor>()?.isTailrec == true
|
||||
override val PropertySymbolMarker.isVar: Boolean
|
||||
get() = asDescriptor().isVar
|
||||
override val PropertySymbolMarker.isLateinit: Boolean
|
||||
get() = asDescriptor().isLateInit
|
||||
override val PropertySymbolMarker.isConst: Boolean
|
||||
get() = asDescriptor().isConst
|
||||
override val PropertySymbolMarker.setter: FunctionSymbolMarker?
|
||||
get() = asDescriptor().setter
|
||||
|
||||
@OptIn(UnsafeCastFunction::class)
|
||||
override fun createExpectActualTypeParameterSubstitutor(
|
||||
expectTypeParameters: List<TypeParameterSymbolMarker>,
|
||||
actualTypeParameters: List<TypeParameterSymbolMarker>,
|
||||
parentSubstitutor: TypeSubstitutorMarker?,
|
||||
): TypeSubstitutorMarker {
|
||||
val expectParameters = expectTypeParameters.castAll<TypeParameterDescriptor>()
|
||||
val actualParameters = actualTypeParameters.castAll<TypeParameterDescriptor>()
|
||||
val substitutor = TypeSubstitutor.create(
|
||||
TypeConstructorSubstitution.createByParametersMap(expectParameters.keysToMap {
|
||||
actualParameters[it.index].defaultType.asTypeProjection()
|
||||
})
|
||||
)
|
||||
return when (parentSubstitutor) {
|
||||
null -> substitutor
|
||||
is TypeSubstitutor -> TypeSubstitutor.createChainedSubstitutor(parentSubstitutor.substitution, substitutor.substitution)
|
||||
else -> error("Unsupported substitutor type: $parentSubstitutor")
|
||||
}
|
||||
}
|
||||
|
||||
override fun RegularClassSymbolMarker.collectAllMembers(isActualDeclaration: Boolean): List<DeclarationSymbolMarker> {
|
||||
return asDescriptor().getMembers(name = null)
|
||||
}
|
||||
|
||||
override fun RegularClassSymbolMarker.getMembersForExpectClass(name: Name): List<DeclarationSymbolMarker> {
|
||||
return asDescriptor().getMembers(name)
|
||||
}
|
||||
|
||||
private fun ClassDescriptor.getMembers(name: Name? = null): List<MemberDescriptor> {
|
||||
val nameFilter = if (name != null) { it -> it == name } else MemberScope.ALL_NAME_FILTER
|
||||
return defaultType.memberScope
|
||||
.getDescriptorsFiltered(nameFilter = nameFilter)
|
||||
.filterIsInstance<MemberDescriptor>()
|
||||
.filterNot(DescriptorUtils::isEnumEntry)
|
||||
.plus(constructors.filter { nameFilter(it.name) })
|
||||
}
|
||||
|
||||
override fun RegularClassSymbolMarker.collectEnumEntryNames(): List<Name> {
|
||||
return asDescriptor()
|
||||
.unsubstitutedMemberScope
|
||||
.getDescriptorsFiltered()
|
||||
.filter(DescriptorUtils::isEnumEntry)
|
||||
.map { it.name }
|
||||
}
|
||||
|
||||
override val CallableSymbolMarker.dispatchReceiverType: KotlinTypeMarker?
|
||||
get() = asDescriptor().dispatchReceiverParameter?.type
|
||||
override val CallableSymbolMarker.extensionReceiverType: KotlinTypeMarker?
|
||||
get() = asDescriptor().extensionReceiverParameter?.type
|
||||
override val CallableSymbolMarker.returnType: KotlinTypeMarker
|
||||
get() = asDescriptor().returnType!!
|
||||
override val CallableSymbolMarker.typeParameters: List<TypeParameterSymbolMarker>
|
||||
get() = asDescriptor().typeParameters
|
||||
override val FunctionSymbolMarker.valueParameters: List<ValueParameterSymbolMarker>
|
||||
get() = asDescriptor().valueParameters
|
||||
override val ValueParameterSymbolMarker.isVararg: Boolean
|
||||
get() = asDescriptor().varargElementType != null
|
||||
override val ValueParameterSymbolMarker.isNoinline: Boolean
|
||||
get() = asDescriptor().isNoinline
|
||||
override val ValueParameterSymbolMarker.isCrossinline: Boolean
|
||||
get() = asDescriptor().isCrossinline
|
||||
override val ValueParameterSymbolMarker.hasDefaultValue: Boolean
|
||||
get() = asDescriptor().declaresDefaultValue()
|
||||
|
||||
override fun CallableSymbolMarker.isAnnotationConstructor(): Boolean {
|
||||
val descriptor = safeAsDescriptor<ConstructorDescriptor>() ?: return false
|
||||
return DescriptorUtils.isAnnotationClass(descriptor.constructedClass)
|
||||
}
|
||||
|
||||
override val TypeParameterSymbolMarker.bounds: List<KotlinTypeMarker>
|
||||
get() = asDescriptor().upperBounds
|
||||
override val TypeParameterSymbolMarker.variance: Variance
|
||||
get() = asDescriptor().variance
|
||||
override val TypeParameterSymbolMarker.isReified: Boolean
|
||||
get() = asDescriptor().isReified
|
||||
|
||||
override fun areCompatibleExpectActualTypes(expectType: KotlinTypeMarker?, actualType: KotlinTypeMarker?): Boolean {
|
||||
if (expectType == null) return actualType == null
|
||||
if (actualType == null) return false
|
||||
|
||||
require(expectType is KotlinType && actualType is KotlinType)
|
||||
return if (platformModule.isTypeRefinementEnabled()) {
|
||||
areCompatibleTypesViaTypeRefinement(expectType, actualType)
|
||||
} else {
|
||||
areCompatibleTypesViaTypeContext(expectType, actualType)
|
||||
}
|
||||
}
|
||||
|
||||
@OptIn(TypeRefinement::class)
|
||||
private fun areCompatibleTypesViaTypeRefinement(a: KotlinType, b: KotlinType): Boolean {
|
||||
val typeRefinerForPlatformModule = platformModule.getKotlinTypeRefiner().let { moduleRefiner ->
|
||||
if (moduleRefiner is KotlinTypeRefiner.Default)
|
||||
KotlinTypeRefinerImpl.createStandaloneInstanceFor(platformModule)
|
||||
else
|
||||
moduleRefiner
|
||||
}
|
||||
|
||||
return areCompatibleTypes(
|
||||
a, b,
|
||||
typeSystemContext = SimpleClassicTypeSystemContext,
|
||||
kotlinTypeRefiner = typeRefinerForPlatformModule,
|
||||
)
|
||||
}
|
||||
|
||||
private fun areCompatibleTypesViaTypeContext(a: KotlinType, b: KotlinType): Boolean {
|
||||
val typeSystemContext = object : ClassicTypeSystemContext {
|
||||
override fun areEqualTypeConstructors(c1: TypeConstructorMarker, c2: TypeConstructorMarker): Boolean {
|
||||
require(c1 is TypeConstructor)
|
||||
require(c2 is TypeConstructor)
|
||||
return isExpectedClassAndActualTypeAlias(c1, c2, platformModule) ||
|
||||
isExpectedClassAndActualTypeAlias(c2, c1, platformModule) ||
|
||||
super.areEqualTypeConstructors(c1, c2)
|
||||
}
|
||||
}
|
||||
|
||||
return areCompatibleTypes(
|
||||
a, b,
|
||||
typeSystemContext = typeSystemContext,
|
||||
kotlinTypeRefiner = KotlinTypeRefiner.Default,
|
||||
)
|
||||
}
|
||||
|
||||
private fun areCompatibleTypes(
|
||||
a: KotlinType,
|
||||
b: KotlinType,
|
||||
typeSystemContext: ClassicTypeSystemContext,
|
||||
kotlinTypeRefiner: KotlinTypeRefiner,
|
||||
): Boolean {
|
||||
with(NewKotlinTypeCheckerImpl(kotlinTypeRefiner)) {
|
||||
return createClassicTypeCheckerState(
|
||||
isErrorTypeEqualsToAnything = false,
|
||||
typeSystemContext = typeSystemContext,
|
||||
kotlinTypeRefiner = kotlinTypeRefiner,
|
||||
).equalTypes(a.unwrap(), b.unwrap())
|
||||
}
|
||||
}
|
||||
|
||||
// For example, expectedTypeConstructor may be the expected class kotlin.text.StringBuilder, while actualTypeConstructor
|
||||
// is java.lang.StringBuilder. For the purposes of type compatibility checking, we must consider these types equal here.
|
||||
// Note that the case of an "actual class" works as expected though, because the actual class by definition has the same FQ name
|
||||
// as the corresponding expected class, so their type constructors are equal as per AbstractClassTypeConstructor#equals
|
||||
private fun isExpectedClassAndActualTypeAlias(
|
||||
expectedTypeConstructor: TypeConstructor,
|
||||
actualTypeConstructor: TypeConstructor,
|
||||
platformModule: ModuleDescriptor
|
||||
): Boolean {
|
||||
val expected = expectedTypeConstructor.declarationDescriptor
|
||||
val actual = actualTypeConstructor.declarationDescriptor
|
||||
return expected is ClassifierDescriptorWithTypeParameters &&
|
||||
expected.isExpect &&
|
||||
actual is ClassifierDescriptorWithTypeParameters &&
|
||||
findClassifiersFromModule(expected.classId, platformModule, moduleFilter = ALL_MODULES).any { classifier ->
|
||||
// Note that it's fine to only check that this "actual typealias" expands to the expected class, without checking
|
||||
// whether the type arguments in the expansion are in the correct order or have the correct variance, because we only
|
||||
// allow simple cases like "actual typealias Foo<A, B> = FooImpl<A, B>", see DeclarationsChecker#checkActualTypeAlias
|
||||
(classifier as? TypeAliasDescriptor)?.classDescriptor == actual
|
||||
}
|
||||
}
|
||||
|
||||
fun findClassifiersFromModule(
|
||||
classId: ClassId?,
|
||||
module: ModuleDescriptor,
|
||||
moduleFilter: (ModuleDescriptor) -> Boolean
|
||||
): Collection<ClassifierDescriptorWithTypeParameters> {
|
||||
if (classId == null) return emptyList()
|
||||
|
||||
fun MemberScope.getAllClassifiers(name: Name): Collection<ClassifierDescriptorWithTypeParameters> =
|
||||
getDescriptorsFiltered(DescriptorKindFilter.CLASSIFIERS) { it == name }
|
||||
.filterIsInstance<ClassifierDescriptorWithTypeParameters>()
|
||||
|
||||
val segments = classId.relativeClassName.pathSegments()
|
||||
var classifiers = module.getPackage(classId.packageFqName).memberScope.getAllClassifiers(segments.first())
|
||||
classifiers = classifiers.applyFilter(moduleFilter)
|
||||
|
||||
for (name in segments.subList(1, segments.size)) {
|
||||
classifiers = classifiers.mapNotNull { classifier ->
|
||||
(classifier as? ClassDescriptor)?.unsubstitutedInnerClassesScope?.getContributedClassifier(
|
||||
name, NoLookupLocation.FOR_ALREADY_TRACKED
|
||||
) as? ClassifierDescriptorWithTypeParameters
|
||||
}
|
||||
}
|
||||
|
||||
return classifiers
|
||||
}
|
||||
|
||||
override fun RegularClassSymbolMarker.isNotSamInterface(): Boolean {
|
||||
val descriptor = asDescriptor()
|
||||
return descriptor.isDefinitelyNotSamInterface || descriptor.defaultFunctionTypeForSamInterface == null
|
||||
}
|
||||
|
||||
override fun CallableSymbolMarker.shouldSkipMatching(containingExpectClass: RegularClassSymbolMarker): Boolean {
|
||||
return safeAsDescriptor<CallableMemberDescriptor>()?.kind?.isReal == false
|
||||
}
|
||||
|
||||
override val CallableSymbolMarker.hasStableParameterNames: Boolean
|
||||
get() = asDescriptor().hasStableParameterNames()
|
||||
}
|
||||
+58
-442
@@ -5,48 +5,49 @@
|
||||
|
||||
package org.jetbrains.kotlin.resolve.multiplatform
|
||||
|
||||
import org.jetbrains.kotlin.builtins.KotlinBuiltIns
|
||||
import org.jetbrains.kotlin.descriptors.*
|
||||
import org.jetbrains.kotlin.incremental.components.NoLookupLocation
|
||||
import org.jetbrains.kotlin.name.Name
|
||||
import org.jetbrains.kotlin.resolve.DescriptorUtils
|
||||
import org.jetbrains.kotlin.resolve.descriptorUtil.*
|
||||
import org.jetbrains.kotlin.resolve.calls.mpp.AbstractExpectActualCompatibilityChecker
|
||||
import org.jetbrains.kotlin.resolve.descriptorUtil.classId
|
||||
import org.jetbrains.kotlin.resolve.descriptorUtil.module
|
||||
import org.jetbrains.kotlin.resolve.multiplatform.ExpectActualCompatibility.Compatible
|
||||
import org.jetbrains.kotlin.resolve.multiplatform.ExpectActualCompatibility.Incompatible
|
||||
import org.jetbrains.kotlin.resolve.scopes.DescriptorKindFilter
|
||||
import org.jetbrains.kotlin.resolve.scopes.MemberScope
|
||||
import org.jetbrains.kotlin.resolve.scopes.getDescriptorsFiltered
|
||||
import org.jetbrains.kotlin.types.*
|
||||
import org.jetbrains.kotlin.types.checker.*
|
||||
import org.jetbrains.kotlin.types.model.TypeConstructorMarker
|
||||
import org.jetbrains.kotlin.types.typeUtil.asTypeProjection
|
||||
import org.jetbrains.kotlin.utils.SmartList
|
||||
import org.jetbrains.kotlin.utils.keysToMap
|
||||
import org.jetbrains.kotlin.utils.addToStdlib.runIf
|
||||
|
||||
object ExpectedActualResolver {
|
||||
|
||||
fun findActualForExpected(
|
||||
expected: MemberDescriptor,
|
||||
platformModule: ModuleDescriptor,
|
||||
moduleVisibilityFilter: ModuleFilter = allModulesProvidingActualsFor(expected.module, platformModule),
|
||||
): Map<ExpectActualCompatibility<MemberDescriptor>, List<MemberDescriptor>>? {
|
||||
val context = ClassicExpectActualMatchingContext(platformModule)
|
||||
return when (expected) {
|
||||
is CallableMemberDescriptor -> {
|
||||
expected.findNamesakesFromModule(platformModule, moduleVisibilityFilter).filter { actual ->
|
||||
expected.findNamesakesFromModule(context, platformModule, moduleVisibilityFilter).filter { actual ->
|
||||
expected != actual && !actual.isExpect &&
|
||||
// TODO: use some other way to determine that the declaration is from Kotlin.
|
||||
// This way behavior differs between fast and PSI-based Java class reading mode
|
||||
// TODO: support non-source definitions (e.g. from Java)
|
||||
actual.couldHaveASource
|
||||
}.groupBy { actual ->
|
||||
areCompatibleCallables(expected, actual, platformModule)
|
||||
AbstractExpectActualCompatibilityChecker.areCompatibleCallables(
|
||||
expected,
|
||||
actual,
|
||||
parentSubstitutor = null,
|
||||
expectContainingClass = null,
|
||||
actualContainingClass = null,
|
||||
context
|
||||
)
|
||||
}
|
||||
}
|
||||
is ClassDescriptor -> {
|
||||
expected.findClassifiersFromModule(platformModule, moduleVisibilityFilter).filter { actual ->
|
||||
context.findClassifiersFromModule(expected.classId, platformModule, moduleVisibilityFilter).filter { actual ->
|
||||
expected != actual && !actual.isExpect && actual.couldHaveASource
|
||||
}.groupBy { actual ->
|
||||
areCompatibleClassifiers(expected, actual)
|
||||
AbstractExpectActualCompatibilityChecker.areCompatibleClassifiers(
|
||||
expected,
|
||||
actual,
|
||||
context
|
||||
)
|
||||
}
|
||||
}
|
||||
else -> null
|
||||
@@ -57,6 +58,7 @@ object ExpectedActualResolver {
|
||||
actual: MemberDescriptor,
|
||||
moduleFilter: (ModuleDescriptor) -> Boolean = allModulesProvidingExpectsFor(actual.module)
|
||||
): Map<ExpectActualCompatibility<MemberDescriptor>, List<MemberDescriptor>>? {
|
||||
val context = ClassicExpectActualMatchingContext(actual.module)
|
||||
return when (actual) {
|
||||
is CallableMemberDescriptor -> {
|
||||
val container = actual.containingDeclaration
|
||||
@@ -65,9 +67,11 @@ object ExpectedActualResolver {
|
||||
// TODO: replace with 'singleOrNull' as soon as multi-module diagnostic tests are refactored
|
||||
val expectedClass =
|
||||
findExpectedForActual(container, moduleFilter)?.values?.firstOrNull()?.firstOrNull() as? ClassDescriptor
|
||||
expectedClass?.getMembers(actual.name)?.filterIsInstance<CallableMemberDescriptor>().orEmpty()
|
||||
with(context) {
|
||||
expectedClass?.getMembersForExpectClass(actual.name)?.filterIsInstance<CallableMemberDescriptor>().orEmpty()
|
||||
}
|
||||
}
|
||||
is PackageFragmentDescriptor -> actual.findNamesakesFromModule(actual.module, moduleFilter)
|
||||
is PackageFragmentDescriptor -> actual.findNamesakesFromModule(context, actual.module, moduleFilter)
|
||||
else -> return null // do not report anything for incorrect code, e.g. 'actual' local function
|
||||
}
|
||||
|
||||
@@ -75,22 +79,43 @@ object ExpectedActualResolver {
|
||||
actual != declaration && declaration.kind != CallableMemberDescriptor.Kind.FAKE_OVERRIDE && declaration.isExpect
|
||||
}.groupBy { declaration ->
|
||||
// TODO: optimize by caching this per actual-expected class pair, do not create a new substitutor for each actual member
|
||||
var expectedClass: ClassDescriptor? = null
|
||||
var actualClass: ClassDescriptor? = null
|
||||
val substitutor =
|
||||
if (container is ClassDescriptor) {
|
||||
val expectedClass = declaration.containingDeclaration as ClassDescriptor
|
||||
// TODO: this might not work for members of inner generic classes
|
||||
if (expectedClass.declaredTypeParameters.size == container.declaredTypeParameters.size) {
|
||||
Substitutor(expectedClass.declaredTypeParameters, container.declaredTypeParameters)
|
||||
} else null
|
||||
} else null
|
||||
areCompatibleCallables(declaration, actual, parentSubstitutor = substitutor)
|
||||
when (container) {
|
||||
is ClassDescriptor -> {
|
||||
actualClass = container
|
||||
expectedClass = declaration.containingDeclaration as ClassDescriptor
|
||||
// TODO: this might not work for members of inner generic classes
|
||||
runIf(expectedClass.declaredTypeParameters.size == container.declaredTypeParameters.size) {
|
||||
context.createExpectActualTypeParameterSubstitutor(
|
||||
expectedClass.declaredTypeParameters,
|
||||
container.declaredTypeParameters,
|
||||
parentSubstitutor = null
|
||||
)
|
||||
}
|
||||
}
|
||||
else -> null
|
||||
}
|
||||
AbstractExpectActualCompatibilityChecker.areCompatibleCallables(
|
||||
expectDeclaration = declaration,
|
||||
actualDeclaration = actual,
|
||||
parentSubstitutor = substitutor,
|
||||
expectContainingClass = expectedClass,
|
||||
actualContainingClass = actualClass,
|
||||
context
|
||||
)
|
||||
}
|
||||
}
|
||||
is ClassifierDescriptorWithTypeParameters -> {
|
||||
actual.findClassifiersFromModule(actual.module, moduleFilter).filter { declaration ->
|
||||
context.findClassifiersFromModule(actual.classId, actual.module, moduleFilter).filter { declaration ->
|
||||
actual != declaration && declaration is ClassDescriptor && declaration.isExpect
|
||||
}.groupBy { expected ->
|
||||
areCompatibleClassifiers(expected as ClassDescriptor, actual)
|
||||
AbstractExpectActualCompatibilityChecker.areCompatibleClassifiers(
|
||||
expected as ClassDescriptor,
|
||||
actual,
|
||||
context
|
||||
)
|
||||
}
|
||||
}
|
||||
else -> null
|
||||
@@ -98,6 +123,7 @@ object ExpectedActualResolver {
|
||||
}
|
||||
|
||||
private fun CallableMemberDescriptor.findNamesakesFromModule(
|
||||
context: ClassicExpectActualMatchingContext,
|
||||
module: ModuleDescriptor,
|
||||
moduleFilter: (ModuleDescriptor) -> Boolean
|
||||
): Collection<CallableMemberDescriptor> {
|
||||
@@ -106,7 +132,7 @@ object ExpectedActualResolver {
|
||||
listOf(module.getPackage(containingDeclaration.fqName).memberScope)
|
||||
}
|
||||
is ClassDescriptor -> {
|
||||
val classes = containingDeclaration.findClassifiersFromModule(module, moduleFilter)
|
||||
val classes = context.findClassifiersFromModule(containingDeclaration.classId, module, moduleFilter)
|
||||
.mapNotNull { if (it is TypeAliasDescriptor) it.classDescriptor else it }
|
||||
.filterIsInstance<ClassDescriptor>()
|
||||
if (this is ConstructorDescriptor) return classes.flatMap { it.constructors }
|
||||
@@ -132,412 +158,6 @@ object ExpectedActualResolver {
|
||||
else -> throw AssertionError("Unsupported declaration: $this")
|
||||
}.applyFilter(moduleFilter)
|
||||
}
|
||||
|
||||
private fun ClassifierDescriptorWithTypeParameters.findClassifiersFromModule(
|
||||
module: ModuleDescriptor,
|
||||
moduleFilter: (ModuleDescriptor) -> Boolean
|
||||
): Collection<ClassifierDescriptorWithTypeParameters> {
|
||||
val classId = classId ?: return emptyList()
|
||||
|
||||
fun MemberScope.getAllClassifiers(name: Name): Collection<ClassifierDescriptorWithTypeParameters> =
|
||||
getDescriptorsFiltered(DescriptorKindFilter.CLASSIFIERS) { it == name }
|
||||
.filterIsInstance<ClassifierDescriptorWithTypeParameters>()
|
||||
|
||||
val segments = classId.relativeClassName.pathSegments()
|
||||
var classifiers = module.getPackage(classId.packageFqName).memberScope.getAllClassifiers(segments.first())
|
||||
classifiers = classifiers.applyFilter(moduleFilter)
|
||||
|
||||
for (name in segments.subList(1, segments.size)) {
|
||||
classifiers = classifiers.mapNotNull { classifier ->
|
||||
(classifier as? ClassDescriptor)?.unsubstitutedInnerClassesScope?.getContributedClassifier(
|
||||
name, NoLookupLocation.FOR_ALREADY_TRACKED
|
||||
) as? ClassifierDescriptorWithTypeParameters
|
||||
}
|
||||
}
|
||||
|
||||
return classifiers
|
||||
}
|
||||
|
||||
// a is the declaration in common code, b is the definition in the platform-specific code
|
||||
private fun areCompatibleCallables(
|
||||
a: CallableMemberDescriptor,
|
||||
b: CallableMemberDescriptor,
|
||||
platformModule: ModuleDescriptor = b.module,
|
||||
parentSubstitutor: Substitutor? = null
|
||||
): ExpectActualCompatibility<MemberDescriptor> {
|
||||
assert(a.name == b.name) {
|
||||
"This function should be invoked only for declarations with the same name: $a, $b"
|
||||
}
|
||||
assert(a.containingDeclaration is ClassifierDescriptorWithTypeParameters == b.containingDeclaration is ClassifierDescriptorWithTypeParameters) {
|
||||
"This function should be invoked only for declarations in the same kind of container (both members or both top level): $a, $b"
|
||||
}
|
||||
|
||||
if (a is FunctionDescriptor && b !is FunctionDescriptor ||
|
||||
a !is FunctionDescriptor && b is FunctionDescriptor
|
||||
) return Incompatible.CallableKind
|
||||
|
||||
val aExtensionReceiver = a.extensionReceiverParameter
|
||||
val bExtensionReceiver = b.extensionReceiverParameter
|
||||
if ((aExtensionReceiver != null) != (bExtensionReceiver != null)) return Incompatible.ParameterShape
|
||||
|
||||
val aParams = a.valueParameters
|
||||
val bParams = b.valueParameters
|
||||
if (!valueParametersCountCompatible(a, b, aParams, bParams)) {
|
||||
return Incompatible.ParameterCount
|
||||
}
|
||||
|
||||
val aTypeParams = a.typeParameters
|
||||
val bTypeParams = b.typeParameters
|
||||
if (aTypeParams.size != bTypeParams.size) return Incompatible.TypeParameterCount
|
||||
|
||||
val substitutor = Substitutor(aTypeParams, bTypeParams, parentSubstitutor)
|
||||
|
||||
if (!areCompatibleTypeLists(aParams.map { substitutor(it.type) }, bParams.map { it.type }, platformModule) ||
|
||||
!areCompatibleTypes(aExtensionReceiver?.type?.let(substitutor), bExtensionReceiver?.type, platformModule)
|
||||
) return Incompatible.ParameterTypes
|
||||
if (!areCompatibleTypes(substitutor(a.returnType), b.returnType, platformModule)) return Incompatible.ReturnType
|
||||
|
||||
if (b.hasStableParameterNames() &&
|
||||
!equalsBy(aParams, bParams, ValueParameterDescriptor::getName)
|
||||
) return Incompatible.ParameterNames
|
||||
if (!equalsBy(aTypeParams, bTypeParams, TypeParameterDescriptor::getName)) return Incompatible.TypeParameterNames
|
||||
|
||||
if (!areCompatibleModalities(a.modality, b.modality)) return Incompatible.Modality
|
||||
if (!areDeclarationsWithCompatibleVisibilities(a, b)) return Incompatible.Visibility
|
||||
|
||||
areCompatibleTypeParameters(aTypeParams, bTypeParams, platformModule, substitutor).let { if (it != Compatible) return it }
|
||||
|
||||
if (!equalsBy(aParams, bParams) { p -> listOf(p.varargElementType != null) }) return Incompatible.ValueParameterVararg
|
||||
|
||||
// Adding noinline/crossinline to parameters is disallowed, except if the expected declaration was not inline at all
|
||||
if (a is FunctionDescriptor && a.isInline) {
|
||||
if (aParams.indices.any { i -> !aParams[i].isNoinline && bParams[i].isNoinline }) return Incompatible.ValueParameterNoinline
|
||||
if (aParams.indices.any { i -> !aParams[i].isCrossinline && bParams[i].isCrossinline }) return Incompatible.ValueParameterCrossinline
|
||||
}
|
||||
|
||||
when {
|
||||
a is FunctionDescriptor && b is FunctionDescriptor -> areCompatibleFunctions(a, b).let { if (it != Compatible) return it }
|
||||
a is PropertyDescriptor && b is PropertyDescriptor -> areCompatibleProperties(a, b).let { if (it != Compatible) return it }
|
||||
else -> throw AssertionError("Unsupported declarations: $a, $b")
|
||||
}
|
||||
|
||||
return Compatible
|
||||
}
|
||||
|
||||
private fun valueParametersCountCompatible(
|
||||
a: CallableMemberDescriptor,
|
||||
b: CallableMemberDescriptor,
|
||||
aParams: List<ValueParameterDescriptor>,
|
||||
bParams: List<ValueParameterDescriptor>
|
||||
): Boolean {
|
||||
if (aParams.size == bParams.size) return true
|
||||
|
||||
return if (a.isAnnotationConstructor() && b.isAnnotationConstructor())
|
||||
aParams.isEmpty() && bParams.all { it.declaresDefaultValue() }
|
||||
else
|
||||
false
|
||||
}
|
||||
|
||||
private fun areCompatibleTypes(a: KotlinType?, b: KotlinType?, platformModule: ModuleDescriptor): Boolean {
|
||||
if (a == null) return b == null
|
||||
if (b == null) return false
|
||||
|
||||
return if (platformModule.isTypeRefinementEnabled()) {
|
||||
areCompatibleTypesViaTypeRefinement(a, b, platformModule)
|
||||
} else {
|
||||
areCompatibleTypesViaTypeContext(a, b, platformModule)
|
||||
}
|
||||
}
|
||||
|
||||
@OptIn(TypeRefinement::class)
|
||||
private fun areCompatibleTypesViaTypeRefinement(a: KotlinType, b: KotlinType, platformModule: ModuleDescriptor): Boolean {
|
||||
val typeRefinerForPlatformModule = platformModule.getKotlinTypeRefiner().let { moduleRefiner ->
|
||||
if (moduleRefiner is KotlinTypeRefiner.Default)
|
||||
KotlinTypeRefinerImpl.createStandaloneInstanceFor(platformModule)
|
||||
else
|
||||
moduleRefiner
|
||||
}
|
||||
|
||||
return areCompatibleTypes(
|
||||
a, b,
|
||||
typeSystemContext = SimpleClassicTypeSystemContext,
|
||||
kotlinTypeRefiner = typeRefinerForPlatformModule,
|
||||
)
|
||||
}
|
||||
|
||||
private fun areCompatibleTypesViaTypeContext(a: KotlinType, b: KotlinType, platformModule: ModuleDescriptor): Boolean {
|
||||
val typeSystemContext = object : ClassicTypeSystemContext {
|
||||
override fun areEqualTypeConstructors(c1: TypeConstructorMarker, c2: TypeConstructorMarker): Boolean {
|
||||
require(c1 is TypeConstructor)
|
||||
require(c2 is TypeConstructor)
|
||||
return isExpectedClassAndActualTypeAlias(c1, c2, platformModule) ||
|
||||
isExpectedClassAndActualTypeAlias(c2, c1, platformModule) ||
|
||||
super.areEqualTypeConstructors(c1, c2)
|
||||
}
|
||||
}
|
||||
|
||||
return areCompatibleTypes(
|
||||
a, b,
|
||||
typeSystemContext = typeSystemContext,
|
||||
kotlinTypeRefiner = KotlinTypeRefiner.Default,
|
||||
)
|
||||
}
|
||||
|
||||
private fun areCompatibleTypes(
|
||||
a: KotlinType,
|
||||
b: KotlinType,
|
||||
typeSystemContext: ClassicTypeSystemContext,
|
||||
kotlinTypeRefiner: KotlinTypeRefiner,
|
||||
): Boolean {
|
||||
with(NewKotlinTypeCheckerImpl(kotlinTypeRefiner)) {
|
||||
return createClassicTypeCheckerState(
|
||||
isErrorTypeEqualsToAnything = false,
|
||||
typeSystemContext = typeSystemContext,
|
||||
kotlinTypeRefiner = kotlinTypeRefiner,
|
||||
).equalTypes(a.unwrap(), b.unwrap())
|
||||
}
|
||||
}
|
||||
|
||||
// For example, expectedTypeConstructor may be the expected class kotlin.text.StringBuilder, while actualTypeConstructor
|
||||
// is java.lang.StringBuilder. For the purposes of type compatibility checking, we must consider these types equal here.
|
||||
// Note that the case of an "actual class" works as expected though, because the actual class by definition has the same FQ name
|
||||
// as the corresponding expected class, so their type constructors are equal as per AbstractClassTypeConstructor#equals
|
||||
private fun isExpectedClassAndActualTypeAlias(
|
||||
expectedTypeConstructor: TypeConstructor,
|
||||
actualTypeConstructor: TypeConstructor,
|
||||
platformModule: ModuleDescriptor
|
||||
): Boolean {
|
||||
val expected = expectedTypeConstructor.declarationDescriptor
|
||||
val actual = actualTypeConstructor.declarationDescriptor
|
||||
return expected is ClassifierDescriptorWithTypeParameters &&
|
||||
expected.isExpect &&
|
||||
actual is ClassifierDescriptorWithTypeParameters &&
|
||||
expected.findClassifiersFromModule(platformModule, moduleFilter = ALL_MODULES).any { classifier ->
|
||||
// Note that it's fine to only check that this "actual typealias" expands to the expected class, without checking
|
||||
// whether the type arguments in the expansion are in the correct order or have the correct variance, because we only
|
||||
// allow simple cases like "actual typealias Foo<A, B> = FooImpl<A, B>", see DeclarationsChecker#checkActualTypeAlias
|
||||
(classifier as? TypeAliasDescriptor)?.classDescriptor == actual
|
||||
}
|
||||
}
|
||||
|
||||
private fun areCompatibleTypeLists(a: List<KotlinType?>, b: List<KotlinType?>, platformModule: ModuleDescriptor): Boolean {
|
||||
for (i in a.indices) {
|
||||
if (!areCompatibleTypes(a[i], b[i], platformModule)) return false
|
||||
}
|
||||
return true
|
||||
}
|
||||
|
||||
private fun areCompatibleTypeParameters(
|
||||
a: List<TypeParameterDescriptor>,
|
||||
b: List<TypeParameterDescriptor>,
|
||||
platformModule: ModuleDescriptor,
|
||||
substitutor: Substitutor
|
||||
): ExpectActualCompatibility<MemberDescriptor> {
|
||||
for (i in a.indices) {
|
||||
val aBounds = a[i].upperBounds
|
||||
val bBounds = b[i].upperBounds
|
||||
if (aBounds.size != bBounds.size || !areCompatibleTypeLists(aBounds.map(substitutor), bBounds, platformModule)) {
|
||||
return Incompatible.TypeParameterUpperBounds
|
||||
}
|
||||
}
|
||||
|
||||
if (!equalsBy(a, b, TypeParameterDescriptor::getVariance)) return Incompatible.TypeParameterVariance
|
||||
|
||||
// Removing "reified" from an expected function's type parameter is fine
|
||||
if (a.indices.any { i -> !a[i].isReified && b[i].isReified }) return Incompatible.TypeParameterReified
|
||||
|
||||
return Compatible
|
||||
}
|
||||
|
||||
private fun areCompatibleFunctions(a: FunctionDescriptor, b: FunctionDescriptor): ExpectActualCompatibility<MemberDescriptor> {
|
||||
if (!equalBy(a, b) { f -> f.isSuspend }) return Incompatible.FunctionModifiersDifferent
|
||||
|
||||
if (a.isExternal && !b.isExternal ||
|
||||
a.isInfix && !b.isInfix ||
|
||||
a.isInline && !b.isInline ||
|
||||
a.isOperator && !b.isOperator ||
|
||||
a.isTailrec && !b.isTailrec
|
||||
) return Incompatible.FunctionModifiersNotSubset
|
||||
|
||||
return Compatible
|
||||
}
|
||||
|
||||
private fun areCompatibleProperties(
|
||||
expected: PropertyDescriptor,
|
||||
actual: PropertyDescriptor,
|
||||
): ExpectActualCompatibility<MemberDescriptor> {
|
||||
return when {
|
||||
!equalBy(expected, actual) { p -> p.isVar } -> Incompatible.PropertyKind
|
||||
!equalBy(expected, actual) { p -> p.isLateInit } -> Incompatible.PropertyLateinitModifier
|
||||
expected.isConst && !actual.isConst -> Incompatible.PropertyConstModifier
|
||||
!arePropertySettersWithCompatibleVisibilities(expected, actual) -> Incompatible.PropertySetterVisibility
|
||||
else -> Compatible
|
||||
}
|
||||
}
|
||||
|
||||
private fun arePropertySettersWithCompatibleVisibilities(expected: PropertyDescriptor, actual: PropertyDescriptor): Boolean {
|
||||
val expectedSetter = expected.setter
|
||||
val actualSetter = actual.setter
|
||||
if (expectedSetter == null || actualSetter == null) {
|
||||
return true
|
||||
}
|
||||
return areDeclarationsWithCompatibleVisibilities(expectedSetter, actualSetter)
|
||||
}
|
||||
|
||||
private fun areCompatibleClassifiers(a: ClassDescriptor, other: ClassifierDescriptor): ExpectActualCompatibility<MemberDescriptor> {
|
||||
// Can't check FQ names here because nested expected class may be implemented via actual typealias's expansion with the other FQ name
|
||||
assert(a.name == other.name) { "This function should be invoked only for declarations with the same name: $a, $other" }
|
||||
|
||||
val b = when (other) {
|
||||
is ClassDescriptor -> other
|
||||
is TypeAliasDescriptor -> other.classDescriptor ?: return Compatible // do not report extra error on erroneous typealias
|
||||
else -> throw AssertionError("Incorrect actual classifier for $a: $other")
|
||||
}
|
||||
|
||||
if (a.kind != b.kind) return Incompatible.ClassKind
|
||||
|
||||
if (!equalBy(a, b) { listOf(it.isCompanionObject, it.isInner, it.isInline || it.isValue) }) return Incompatible.ClassModifiers
|
||||
if (a.isFun && !b.isFun && b.isNotJavaSamInterface()) {
|
||||
return Incompatible.FunInterfaceModifier
|
||||
}
|
||||
|
||||
val aTypeParams = a.declaredTypeParameters
|
||||
val bTypeParams = b.declaredTypeParameters
|
||||
if (aTypeParams.size != bTypeParams.size) return Incompatible.TypeParameterCount
|
||||
|
||||
if (!areCompatibleModalities(a.modality, b.modality)) return Incompatible.Modality
|
||||
|
||||
if (a.visibility != b.visibility) return Incompatible.Visibility
|
||||
|
||||
val platformModule = other.module
|
||||
val substitutor = Substitutor(aTypeParams, bTypeParams)
|
||||
areCompatibleTypeParameters(aTypeParams, bTypeParams, platformModule, substitutor).let { if (it != Compatible) return it }
|
||||
|
||||
// Subtract kotlin.Any from supertypes because it's implicitly added if no explicit supertype is specified,
|
||||
// and not added if an explicit supertype _is_ specified
|
||||
val aSupertypes = a.typeConstructor.supertypes.filterNot(KotlinBuiltIns::isAny)
|
||||
val bSupertypes = b.typeConstructor.supertypes.filterNot(KotlinBuiltIns::isAny)
|
||||
if (aSupertypes.map(substitutor).any { aSupertype ->
|
||||
bSupertypes.none { bSupertype -> areCompatibleTypes(aSupertype, bSupertype, platformModule) }
|
||||
}
|
||||
) return Incompatible.Supertypes
|
||||
|
||||
areCompatibleClassScopes(a, b, platformModule, substitutor).let { if (it != Compatible) return it }
|
||||
|
||||
return Compatible
|
||||
}
|
||||
|
||||
private fun areCompatibleModalities(a: Modality, b: Modality): Boolean {
|
||||
return a == Modality.FINAL && b == Modality.OPEN ||
|
||||
a == b
|
||||
}
|
||||
|
||||
private fun areDeclarationsWithCompatibleVisibilities(
|
||||
a: CallableMemberDescriptor,
|
||||
b: CallableMemberDescriptor
|
||||
): Boolean {
|
||||
val compare = DescriptorVisibilities.compare(a.visibility, b.visibility)
|
||||
return if (a.isOverridable) {
|
||||
// For overridable declarations visibility should match precisely, see KT-19664
|
||||
compare == 0
|
||||
} else {
|
||||
// For non-overridable declarations actuals are allowed to have more permissive visibility
|
||||
compare != null && compare <= 0
|
||||
}
|
||||
}
|
||||
|
||||
private fun areCompatibleClassScopes(
|
||||
a: ClassDescriptor,
|
||||
b: ClassDescriptor,
|
||||
platformModule: ModuleDescriptor,
|
||||
substitutor: Substitutor
|
||||
): ExpectActualCompatibility<MemberDescriptor> {
|
||||
val unfulfilled = arrayListOf<Pair<MemberDescriptor, Map<Incompatible<MemberDescriptor>, MutableCollection<MemberDescriptor>>>>()
|
||||
|
||||
val bMembersByName = b.getMembers().groupBy { it.name }
|
||||
|
||||
outer@ for (aMember in a.getMembers()) {
|
||||
if (aMember is CallableMemberDescriptor && !aMember.kind.isReal) continue
|
||||
|
||||
val bMembers = bMembersByName[aMember.name]?.filter { bMember ->
|
||||
aMember is CallableMemberDescriptor && bMember is CallableMemberDescriptor ||
|
||||
aMember is ClassDescriptor && bMember is ClassDescriptor
|
||||
}.orEmpty()
|
||||
|
||||
val mapping = bMembers.keysToMap { bMember ->
|
||||
when (aMember) {
|
||||
is CallableMemberDescriptor ->
|
||||
areCompatibleCallables(aMember, bMember as CallableMemberDescriptor, platformModule, substitutor)
|
||||
is ClassDescriptor ->
|
||||
areCompatibleClassifiers(aMember, bMember as ClassDescriptor)
|
||||
else -> throw UnsupportedOperationException("Unsupported declaration: $aMember ($bMembers)")
|
||||
}
|
||||
}
|
||||
if (mapping.values.any { it == Compatible }) continue
|
||||
|
||||
val incompatibilityMap = mutableMapOf<Incompatible<MemberDescriptor>, MutableCollection<MemberDescriptor>>()
|
||||
for ((descriptor, compatibility) in mapping) {
|
||||
when (compatibility) {
|
||||
Compatible -> continue@outer
|
||||
is Incompatible -> incompatibilityMap.getOrPut(compatibility) { SmartList() }.add(descriptor)
|
||||
}
|
||||
}
|
||||
|
||||
unfulfilled.add(aMember to incompatibilityMap)
|
||||
}
|
||||
|
||||
if (a.kind == ClassKind.ENUM_CLASS) {
|
||||
fun ClassDescriptor.enumEntries() =
|
||||
unsubstitutedMemberScope.getDescriptorsFiltered().filter(DescriptorUtils::isEnumEntry).map { it.name }
|
||||
|
||||
val aEntries = a.enumEntries()
|
||||
val bEntries = b.enumEntries()
|
||||
|
||||
if (!bEntries.containsAll(aEntries)) return Incompatible.EnumEntries
|
||||
}
|
||||
|
||||
// TODO: check static scope?
|
||||
|
||||
if (unfulfilled.isEmpty()) return Compatible
|
||||
|
||||
return Incompatible.ClassScopes(unfulfilled)
|
||||
}
|
||||
|
||||
private fun ClassDescriptor.getMembers(name: Name? = null): Collection<MemberDescriptor> {
|
||||
val nameFilter = if (name != null) { it -> it == name } else MemberScope.ALL_NAME_FILTER
|
||||
return defaultType.memberScope
|
||||
.getDescriptorsFiltered(nameFilter = nameFilter)
|
||||
.filterIsInstance<MemberDescriptor>()
|
||||
.filterNot(DescriptorUtils::isEnumEntry)
|
||||
.plus(constructors.filter { nameFilter(it.name) })
|
||||
}
|
||||
|
||||
private inline fun <T, K> equalBy(first: T, second: T, selector: (T) -> K): Boolean =
|
||||
selector(first) == selector(second)
|
||||
|
||||
private inline fun <T, K> equalsBy(first: List<T>, second: List<T>, selector: (T) -> K): Boolean {
|
||||
for (i in first.indices) {
|
||||
if (selector(first[i]) != selector(second[i])) return false
|
||||
}
|
||||
|
||||
return true
|
||||
}
|
||||
|
||||
// This substitutor takes the type from A's signature and returns the type that should be in that place in B's signature
|
||||
private class Substitutor(
|
||||
aTypeParams: List<TypeParameterDescriptor>,
|
||||
bTypeParams: List<TypeParameterDescriptor>,
|
||||
private val parent: Substitutor? = null
|
||||
) : (KotlinType?) -> KotlinType? {
|
||||
private val typeSubstitutor = TypeSubstitutor.create(
|
||||
TypeConstructorSubstitution.createByParametersMap(aTypeParams.keysToMap {
|
||||
bTypeParams[it.index].defaultType.asTypeProjection()
|
||||
})
|
||||
)
|
||||
|
||||
override fun invoke(type: KotlinType?): KotlinType? =
|
||||
(parent?.invoke(type) ?: type)?.asTypeProjection()?.let(typeSubstitutor::substitute)?.type
|
||||
}
|
||||
}
|
||||
|
||||
// FIXME(dsavvinov): review clients, as they won't work properly in HMPP projects
|
||||
@@ -576,7 +196,3 @@ fun DeclarationDescriptor.findActuals(inModule: ModuleDescriptor): List<MemberDe
|
||||
val DeclarationDescriptorWithSource.couldHaveASource: Boolean
|
||||
get() = this.source.containingFile != SourceFile.NO_SOURCE_FILE ||
|
||||
this is DeserializedDescriptor
|
||||
|
||||
private fun ClassDescriptor.isNotJavaSamInterface(): Boolean {
|
||||
return isDefinitelyNotSamInterface || defaultFunctionTypeForSamInterface == null
|
||||
}
|
||||
@@ -19,13 +19,14 @@ package org.jetbrains.kotlin.descriptors;
|
||||
import kotlin.annotations.jvm.ReadOnly;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
import org.jetbrains.kotlin.mpp.CallableSymbolMarker;
|
||||
import org.jetbrains.kotlin.types.KotlinType;
|
||||
|
||||
import java.util.Collection;
|
||||
import java.util.List;
|
||||
|
||||
public interface CallableDescriptor extends DeclarationDescriptorWithVisibility, DeclarationDescriptorNonRoot,
|
||||
Substitutable<CallableDescriptor> {
|
||||
Substitutable<CallableDescriptor>, CallableSymbolMarker {
|
||||
@NotNull
|
||||
@ReadOnly
|
||||
List<ReceiverParameterDescriptor> getContextReceiverParameters();
|
||||
|
||||
@@ -16,10 +16,11 @@
|
||||
|
||||
package org.jetbrains.kotlin.descriptors
|
||||
|
||||
import org.jetbrains.kotlin.mpp.ConstructorSymbolMarker
|
||||
import org.jetbrains.kotlin.types.TypeSubstitutor
|
||||
|
||||
|
||||
interface ClassConstructorDescriptor : ConstructorDescriptor {
|
||||
interface ClassConstructorDescriptor : ConstructorDescriptor, ConstructorSymbolMarker {
|
||||
override fun getContainingDeclaration(): ClassDescriptor
|
||||
|
||||
override fun getOriginal(): ClassConstructorDescriptor
|
||||
|
||||
@@ -8,6 +8,7 @@ package org.jetbrains.kotlin.descriptors;
|
||||
import kotlin.annotations.jvm.ReadOnly;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
import org.jetbrains.kotlin.mpp.RegularClassSymbolMarker;
|
||||
import org.jetbrains.kotlin.resolve.scopes.MemberScope;
|
||||
import org.jetbrains.kotlin.types.SimpleType;
|
||||
import org.jetbrains.kotlin.types.TypeProjection;
|
||||
@@ -16,7 +17,8 @@ import org.jetbrains.kotlin.types.TypeSubstitution;
|
||||
import java.util.Collection;
|
||||
import java.util.List;
|
||||
|
||||
public interface ClassDescriptor extends ClassifierDescriptorWithTypeParameters, ClassOrPackageFragmentDescriptor {
|
||||
public interface ClassDescriptor extends ClassifierDescriptorWithTypeParameters, ClassOrPackageFragmentDescriptor,
|
||||
RegularClassSymbolMarker {
|
||||
@NotNull
|
||||
MemberScope getMemberScope(@NotNull List<? extends TypeProjection> typeArguments);
|
||||
|
||||
|
||||
@@ -17,10 +17,11 @@
|
||||
package org.jetbrains.kotlin.descriptors;
|
||||
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.kotlin.mpp.ClassifierSymbolMarker;
|
||||
import org.jetbrains.kotlin.types.SimpleType;
|
||||
import org.jetbrains.kotlin.types.TypeConstructor;
|
||||
|
||||
public interface ClassifierDescriptor extends DeclarationDescriptorNonRoot {
|
||||
public interface ClassifierDescriptor extends DeclarationDescriptorNonRoot, ClassifierSymbolMarker {
|
||||
@NotNull
|
||||
TypeConstructor getTypeConstructor();
|
||||
|
||||
|
||||
+3
-1
@@ -18,12 +18,14 @@ package org.jetbrains.kotlin.descriptors;
|
||||
|
||||
import kotlin.annotations.jvm.ReadOnly;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.kotlin.mpp.ClassLikeSymbolMarker;
|
||||
import org.jetbrains.kotlin.mpp.ClassifierSymbolMarker;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
public interface ClassifierDescriptorWithTypeParameters
|
||||
extends ClassifierDescriptor, DeclarationDescriptorWithVisibility, MemberDescriptor,
|
||||
Substitutable<ClassifierDescriptorWithTypeParameters> {
|
||||
Substitutable<ClassifierDescriptorWithTypeParameters>, ClassLikeSymbolMarker, ClassifierSymbolMarker {
|
||||
/**
|
||||
* @return <code>true</code> if this class contains a reference to its outer class (as opposed to static nested class)
|
||||
*/
|
||||
|
||||
@@ -19,8 +19,9 @@ package org.jetbrains.kotlin.descriptors;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
import org.jetbrains.kotlin.descriptors.annotations.Annotated;
|
||||
import org.jetbrains.kotlin.mpp.DeclarationSymbolMarker;
|
||||
|
||||
public interface DeclarationDescriptor extends Annotated, Named, ValidateableDescriptor {
|
||||
public interface DeclarationDescriptor extends Annotated, Named, ValidateableDescriptor, DeclarationSymbolMarker {
|
||||
/**
|
||||
* @return The descriptor that corresponds to the original declaration of this element.
|
||||
* A descriptor can be obtained from its original by substituting type arguments (of the declaring class
|
||||
|
||||
@@ -8,6 +8,7 @@ package org.jetbrains.kotlin.descriptors;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
import org.jetbrains.kotlin.descriptors.annotations.Annotations;
|
||||
import org.jetbrains.kotlin.mpp.FunctionSymbolMarker;
|
||||
import org.jetbrains.kotlin.name.Name;
|
||||
import org.jetbrains.kotlin.types.KotlinType;
|
||||
import org.jetbrains.kotlin.types.TypeSubstitution;
|
||||
@@ -16,7 +17,7 @@ import org.jetbrains.kotlin.types.TypeSubstitutor;
|
||||
import java.util.Collection;
|
||||
import java.util.List;
|
||||
|
||||
public interface FunctionDescriptor extends CallableMemberDescriptor {
|
||||
public interface FunctionDescriptor extends CallableMemberDescriptor, FunctionSymbolMarker {
|
||||
@Override
|
||||
@NotNull
|
||||
DeclarationDescriptor getContainingDeclaration();
|
||||
|
||||
@@ -18,13 +18,14 @@ package org.jetbrains.kotlin.descriptors;
|
||||
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
import org.jetbrains.kotlin.mpp.PropertySymbolMarker;
|
||||
import org.jetbrains.kotlin.types.KotlinType;
|
||||
import org.jetbrains.kotlin.types.TypeSubstitutor;
|
||||
|
||||
import java.util.Collection;
|
||||
import java.util.List;
|
||||
|
||||
public interface PropertyDescriptor extends VariableDescriptorWithAccessors, CallableMemberDescriptor {
|
||||
public interface PropertyDescriptor extends VariableDescriptorWithAccessors, CallableMemberDescriptor, PropertySymbolMarker {
|
||||
@Override
|
||||
@Nullable
|
||||
PropertyGetterDescriptor getGetter();
|
||||
|
||||
@@ -17,11 +17,12 @@
|
||||
package org.jetbrains.kotlin.descriptors;
|
||||
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.kotlin.mpp.SimpleFunctionSymbolMarker;
|
||||
|
||||
/**
|
||||
* Simple functions are the ones with 'fun' keyword and function literals
|
||||
*/
|
||||
public interface SimpleFunctionDescriptor extends FunctionDescriptor {
|
||||
public interface SimpleFunctionDescriptor extends FunctionDescriptor, SimpleFunctionSymbolMarker {
|
||||
@NotNull
|
||||
@Override
|
||||
SimpleFunctionDescriptor copy(DeclarationDescriptor newOwner, Modality modality, DescriptorVisibility visibility, Kind kind, boolean copyOverrides);
|
||||
|
||||
@@ -17,9 +17,10 @@
|
||||
package org.jetbrains.kotlin.descriptors
|
||||
|
||||
import org.jetbrains.kotlin.descriptors.impl.TypeAliasConstructorDescriptor
|
||||
import org.jetbrains.kotlin.mpp.TypeAliasSymbolMarker
|
||||
import org.jetbrains.kotlin.types.SimpleType
|
||||
|
||||
interface TypeAliasDescriptor : ClassifierDescriptorWithTypeParameters {
|
||||
interface TypeAliasDescriptor : ClassifierDescriptorWithTypeParameters, TypeAliasSymbolMarker {
|
||||
/// Right-hand side of the type alias definition.
|
||||
/// May contain type aliases.
|
||||
val underlyingType: SimpleType
|
||||
|
||||
@@ -17,6 +17,7 @@
|
||||
package org.jetbrains.kotlin.descriptors;
|
||||
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.kotlin.mpp.TypeParameterSymbolMarker;
|
||||
import org.jetbrains.kotlin.storage.StorageManager;
|
||||
import org.jetbrains.kotlin.types.KotlinType;
|
||||
import org.jetbrains.kotlin.types.TypeConstructor;
|
||||
@@ -25,7 +26,7 @@ import org.jetbrains.kotlin.types.model.TypeParameterMarker;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
public interface TypeParameterDescriptor extends ClassifierDescriptor, TypeParameterMarker {
|
||||
public interface TypeParameterDescriptor extends ClassifierDescriptor, TypeParameterMarker, TypeParameterSymbolMarker {
|
||||
boolean isReified();
|
||||
|
||||
@NotNull
|
||||
|
||||
@@ -16,11 +16,12 @@
|
||||
|
||||
package org.jetbrains.kotlin.descriptors
|
||||
|
||||
import org.jetbrains.kotlin.mpp.ValueParameterSymbolMarker
|
||||
import org.jetbrains.kotlin.name.Name
|
||||
import org.jetbrains.kotlin.types.KotlinType
|
||||
import org.jetbrains.kotlin.types.TypeSubstitutor
|
||||
|
||||
interface ValueParameterDescriptor : VariableDescriptor, ParameterDescriptor {
|
||||
interface ValueParameterDescriptor : VariableDescriptor, ParameterDescriptor, ValueParameterSymbolMarker {
|
||||
override fun getContainingDeclaration(): CallableDescriptor
|
||||
|
||||
/**
|
||||
|
||||
Reference in New Issue
Block a user