Drop unneeded hack relating to matching header class to impl typealias

This is not needed anymore because we use a special TypeCheckerContext
which correctly matches header class to impl typealias.

Also fix 'platformModule' in areCompatibleClassifiers: it's not b's
module (b is already the expansion of a typealias), but the module of
"other", original 'impl' classifier
This commit is contained in:
Alexander Udalov
2017-04-20 15:33:45 +03:00
parent ea727ff3f0
commit db3f70cfe9
@@ -276,6 +276,7 @@ object HeaderImplDeclarationChecker : DeclarationChecker {
a: CallableMemberDescriptor, a: CallableMemberDescriptor,
b: CallableMemberDescriptor, b: CallableMemberDescriptor,
checkImpl: Boolean, checkImpl: Boolean,
platformModule: ModuleDescriptor = b.module,
parentSubstitutor: Substitutor? = null parentSubstitutor: Substitutor? = null
): Compatibility { ): Compatibility {
assert(a.name == b.name) { "This function should be invoked only for declarations with the same name: $a, $b" } assert(a.name == b.name) { "This function should be invoked only for declarations with the same name: $a, $b" }
@@ -295,7 +296,6 @@ object HeaderImplDeclarationChecker : DeclarationChecker {
val bTypeParams = b.typeParameters val bTypeParams = b.typeParameters
if (aTypeParams.size != bTypeParams.size) return Incompatible.TypeParameterCount if (aTypeParams.size != bTypeParams.size) return Incompatible.TypeParameterCount
val platformModule = b.module
val substitutor = Substitutor(aTypeParams, bTypeParams, parentSubstitutor) val substitutor = Substitutor(aTypeParams, bTypeParams, parentSubstitutor)
if (!areCompatibleTypeLists(aParams.map { substitutor(it.type) }, bParams.map { it.type }, platformModule) || if (!areCompatibleTypeLists(aParams.map { substitutor(it.type) }, bParams.map { it.type }, platformModule) ||
@@ -406,23 +406,12 @@ object HeaderImplDeclarationChecker : DeclarationChecker {
private fun areCompatibleClassifiers(a: ClassDescriptor, other: ClassifierDescriptor, checkImpl: Boolean): Compatibility { private fun areCompatibleClassifiers(a: ClassDescriptor, other: ClassifierDescriptor, checkImpl: Boolean): Compatibility {
assert(a.fqNameUnsafe == other.fqNameUnsafe) { "This function should be invoked only for declarations with the same name: $a, $other" } assert(a.fqNameUnsafe == other.fqNameUnsafe) { "This function should be invoked only for declarations with the same name: $a, $other" }
var parentSubstitutor: Substitutor? = null
var implTypealias = false var implTypealias = false
val b = when (other) { val b = when (other) {
is ClassDescriptor -> other is ClassDescriptor -> other
is TypeAliasDescriptor -> { is TypeAliasDescriptor -> {
val classDescriptor = other.classDescriptor ?: return Compatible // do not report extra error on erroneous typealias
implTypealias = true implTypealias = true
// If a header class test.C is implemented by a typealias test.C = test.CImpl, we must now state that any occurrence other.classDescriptor ?: return Compatible // do not report extra error on erroneous typealias
// of the type "test.C" in the header class scope should be replaced with "test.CImpl".
// Otherwise the types would not be equal and e.g. test.C's constructor is not going to be found in test.CImpl's scope.
// For this, we construct an additional substitutor with a single mapping test.C -> test.CImpl
// TODO: this looks like a dirty hack
parentSubstitutor = Substitutor(null, TypeSubstitutor.create(TypeConstructorSubstitution.createByConstructorsMap(
mapOf(a.typeConstructor to classDescriptor.defaultType.asTypeProjection())
)))
classDescriptor
} }
else -> throw AssertionError("Incorrect impl classifier for $a: $other") else -> throw AssertionError("Incorrect impl classifier for $a: $other")
} }
@@ -439,8 +428,8 @@ object HeaderImplDeclarationChecker : DeclarationChecker {
if (a.visibility != b.visibility) return Incompatible.Visibility if (a.visibility != b.visibility) return Incompatible.Visibility
val platformModule = b.module val platformModule = other.module
val substitutor = Substitutor(aTypeParams, bTypeParams, parentSubstitutor) val substitutor = Substitutor(aTypeParams, bTypeParams)
areCompatibleTypeParameters(aTypeParams, bTypeParams, platformModule, substitutor).let { if (it != Compatible) return it } 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, // Subtract kotlin.Any from supertypes because it's implicitly added if no explicit supertype is specified,
@@ -451,7 +440,7 @@ object HeaderImplDeclarationChecker : DeclarationChecker {
bSupertypes.none { bSupertype -> areCompatibleTypes(aSupertype, bSupertype, platformModule) } bSupertypes.none { bSupertype -> areCompatibleTypes(aSupertype, bSupertype, platformModule) }
}) return Incompatible.Supertypes }) return Incompatible.Supertypes
areCompatibleClassScopes(a, b, checkImpl && !implTypealias, substitutor).let { if (it != Compatible) return it } areCompatibleClassScopes(a, b, checkImpl && !implTypealias, platformModule, substitutor).let { if (it != Compatible) return it }
if (checkImpl && !b.isImpl && !implTypealias) return Incompatible.NoImpl if (checkImpl && !b.isImpl && !implTypealias) return Incompatible.NoImpl
@@ -462,6 +451,7 @@ object HeaderImplDeclarationChecker : DeclarationChecker {
a: ClassDescriptor, a: ClassDescriptor,
b: ClassDescriptor, b: ClassDescriptor,
checkImpl: Boolean, checkImpl: Boolean,
platformModule: ModuleDescriptor,
substitutor: Substitutor substitutor: Substitutor
): Compatibility { ): Compatibility {
val unimplemented = arrayListOf<Pair<CallableMemberDescriptor, Map<Incompatible, MutableCollection<CallableMemberDescriptor>>>>() val unimplemented = arrayListOf<Pair<CallableMemberDescriptor, Map<Incompatible, MutableCollection<CallableMemberDescriptor>>>>()
@@ -472,7 +462,7 @@ object HeaderImplDeclarationChecker : DeclarationChecker {
if (!aMember.kind.isReal) continue if (!aMember.kind.isReal) continue
val mapping = bMembersByName[aMember.name].orEmpty().keysToMap { bMember -> val mapping = bMembersByName[aMember.name].orEmpty().keysToMap { bMember ->
areCompatibleCallables(aMember, bMember, checkImpl, substitutor) areCompatibleCallables(aMember, bMember, checkImpl, platformModule, substitutor)
} }
if (mapping.values.any { it == Compatible }) continue if (mapping.values.any { it == Compatible }) continue
@@ -522,18 +512,15 @@ object HeaderImplDeclarationChecker : DeclarationChecker {
// This substitutor takes the type from A's signature and returns the type that should be in that place in B's signature // 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( private class Substitutor(
private val parent: Substitutor?, aTypeParams: List<TypeParameterDescriptor>,
private val typeSubstitutor: TypeSubstitutor bTypeParams: List<TypeParameterDescriptor>,
private val parent: Substitutor? = null
) : (KotlinType?) -> KotlinType? { ) : (KotlinType?) -> KotlinType? {
constructor( private val typeSubstitutor = TypeSubstitutor.create(
aTypeParams: List<TypeParameterDescriptor>,
bTypeParams: List<TypeParameterDescriptor>,
parent: Substitutor? = null
) : this(parent, TypeSubstitutor.create(
TypeConstructorSubstitution.createByParametersMap(aTypeParams.keysToMap { TypeConstructorSubstitution.createByParametersMap(aTypeParams.keysToMap {
bTypeParams[it.index].defaultType.asTypeProjection() bTypeParams[it.index].defaultType.asTypeProjection()
}) })
)) )
override fun invoke(type: KotlinType?): KotlinType? = override fun invoke(type: KotlinType?): KotlinType? =
(parent?.invoke(type) ?: type)?.asTypeProjection()?.let(typeSubstitutor::substitute)?.type (parent?.invoke(type) ?: type)?.asTypeProjection()?.let(typeSubstitutor::substitute)?.type