From ee1ea156842d8bb610f5c758208f2d2cb3b72716 Mon Sep 17 00:00:00 2001 From: Alexander Gorshenev Date: Tue, 12 May 2020 12:44:44 +0300 Subject: [PATCH] Adapted descriptor fake override construction from OverridingUtil.java to IR as IrOverridingUtil.kt --- .../kotlin/ir/declarations/IrDeclaration.kt | 2 + .../kotlin/ir/declarations/IrProperty.kt | 2 +- .../ir/declarations/IrSimpleFunction.kt | 2 +- .../common/serialization/IrOverridingUtil.kt | 655 ++++++++++++++++++ .../kotlin/resolve/OverridableMember.kt | 35 + 5 files changed, 694 insertions(+), 2 deletions(-) create mode 100644 compiler/ir/serialization.common/src/org/jetbrains/kotlin/backend/common/serialization/IrOverridingUtil.kt create mode 100644 core/descriptors/src/org/jetbrains/kotlin/resolve/OverridableMember.kt diff --git a/compiler/ir/ir.tree/src/org/jetbrains/kotlin/ir/declarations/IrDeclaration.kt b/compiler/ir/ir.tree/src/org/jetbrains/kotlin/ir/declarations/IrDeclaration.kt index b927c4d04fe..755631d1bc1 100644 --- a/compiler/ir/ir.tree/src/org/jetbrains/kotlin/ir/declarations/IrDeclaration.kt +++ b/compiler/ir/ir.tree/src/org/jetbrains/kotlin/ir/declarations/IrDeclaration.kt @@ -23,6 +23,7 @@ import org.jetbrains.kotlin.ir.IrStatement import org.jetbrains.kotlin.ir.symbols.IrSymbol import org.jetbrains.kotlin.ir.visitors.IrElementTransformer import org.jetbrains.kotlin.name.Name +import org.jetbrains.kotlin.resolve.OverridableMember interface IrSymbolOwner : IrElement { val symbol: IrSymbol @@ -60,3 +61,4 @@ interface IrDeclarationWithName : IrDeclaration { val name: Name } +interface IrOverridableMember: OverridableMember, IrDeclarationWithVisibility, IrDeclarationWithName, IrSymbolOwner diff --git a/compiler/ir/ir.tree/src/org/jetbrains/kotlin/ir/declarations/IrProperty.kt b/compiler/ir/ir.tree/src/org/jetbrains/kotlin/ir/declarations/IrProperty.kt index a41961acbd3..8b578d1cf86 100644 --- a/compiler/ir/ir.tree/src/org/jetbrains/kotlin/ir/declarations/IrProperty.kt +++ b/compiler/ir/ir.tree/src/org/jetbrains/kotlin/ir/declarations/IrProperty.kt @@ -24,12 +24,12 @@ import org.jetbrains.kotlin.ir.symbols.IrSimpleFunctionSymbol interface IrProperty : IrDeclarationWithName, IrDeclarationWithVisibility, + IrOverridableMember, IrSymbolOwner { override val descriptor: PropertyDescriptor override val symbol: IrPropertySymbol - val modality: Modality val isVar: Boolean val isConst: Boolean val isLateinit: Boolean diff --git a/compiler/ir/ir.tree/src/org/jetbrains/kotlin/ir/declarations/IrSimpleFunction.kt b/compiler/ir/ir.tree/src/org/jetbrains/kotlin/ir/declarations/IrSimpleFunction.kt index 6c2946fd45e..4c35fb26cbd 100644 --- a/compiler/ir/ir.tree/src/org/jetbrains/kotlin/ir/declarations/IrSimpleFunction.kt +++ b/compiler/ir/ir.tree/src/org/jetbrains/kotlin/ir/declarations/IrSimpleFunction.kt @@ -13,9 +13,9 @@ interface IrSimpleFunction : IrFunction, IrSymbolDeclaration, IrOverridableDeclaration, + IrOverridableMember, IrAttributeContainer { - val modality: Modality val isTailrec: Boolean val isSuspend: Boolean val isFakeOverride: Boolean diff --git a/compiler/ir/serialization.common/src/org/jetbrains/kotlin/backend/common/serialization/IrOverridingUtil.kt b/compiler/ir/serialization.common/src/org/jetbrains/kotlin/backend/common/serialization/IrOverridingUtil.kt new file mode 100644 index 00000000000..b825e51a975 --- /dev/null +++ b/compiler/ir/serialization.common/src/org/jetbrains/kotlin/backend/common/serialization/IrOverridingUtil.kt @@ -0,0 +1,655 @@ +/* + * Copyright 2010-2020 JetBrains s.r.o. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.jetbrains.kotlin.backend.common.serialization + +import org.jetbrains.kotlin.descriptors.CallableMemberDescriptor +import org.jetbrains.kotlin.descriptors.Modality +import org.jetbrains.kotlin.descriptors.Visibilities +import org.jetbrains.kotlin.ir.declarations.* +import org.jetbrains.kotlin.ir.declarations.impl.IrFakeOverrideFunctionImpl +import org.jetbrains.kotlin.ir.declarations.impl.IrFakeOverridePropertyImpl +import org.jetbrains.kotlin.ir.descriptors.IrBuiltIns +import org.jetbrains.kotlin.ir.symbols.IrPropertySymbol +import org.jetbrains.kotlin.ir.symbols.IrSimpleFunctionSymbol +import org.jetbrains.kotlin.ir.symbols.IrSymbol +import org.jetbrains.kotlin.ir.types.IrDynamicType +import org.jetbrains.kotlin.ir.types.IrType +import org.jetbrains.kotlin.ir.types.getClass +import org.jetbrains.kotlin.ir.util.isReal +import org.jetbrains.kotlin.ir.util.render +import org.jetbrains.kotlin.resolve.OverridingUtil.OverrideCompatibilityInfo +import org.jetbrains.kotlin.resolve.OverridingUtil.OverrideCompatibilityInfo.incompatible +import org.jetbrains.kotlin.types.AbstractTypeChecker +import org.jetbrains.kotlin.types.AbstractTypeCheckerContext + +interface FakeOverrideBuilderStrategy { + fun fakeOverrideMember(superType: IrType, member: IrOverridableMember, clazz: IrClass): IrOverridableMember + + // TODO: this one doesn't belong here. IrOverridingUtil shouldn't know about symbol table. + fun linkFakeOverride(fakeOverride: IrOverridableMember) + + // TODO: need to make IrProperty carry overriddenSymbols. + val propertyOverriddenSymbols: MutableMap> +} + +// TODO: +// The below pile of code is basically half of OverridingUtil.java +// adapted to IR and converted to Kotlin. +// Need to convert frontend's OverridingUtil to Kotlin and merge this codes +// to use abstract overridable member interfaces. + +class IrOverridingUtil( + private val irBuiltIns: IrBuiltIns, + private val fakeOverrideBuilder: FakeOverrideBuilderStrategy +) { + private val originals = mutableMapOf() + private val IrOverridableMember.original get() = originals[this] ?: error("No original for ${this.render()}") + private val originalSuperTypes = mutableMapOf() + + private var IrOverridableMember.overriddenSymbols: List + get() = when (this) { + is IrSimpleFunction -> this.overriddenSymbols + is IrProperty -> fakeOverrideBuilder.propertyOverriddenSymbols[this] + ?: error("No overridden symbols for ${this.render()}") + else -> error("Unexpected declaration for overriddenSymbols: $this") + } + set(value) { + when (this) { + is IrSimpleFunction -> this.overriddenSymbols = + value.map { it as? IrSimpleFunctionSymbol ?: error("Unexpected function overridden symbol: $it") } + is IrProperty -> { + fakeOverrideBuilder.propertyOverriddenSymbols[this] = + value.map { it as? IrPropertySymbol ?: error("Unexpected property overridden symbol: $it") } + this.getter!!.overriddenSymbols = value.map { (it.owner as IrProperty).getter!!.symbol } + this.setter?.let { setter -> + setter.overriddenSymbols = value.mapNotNull { (it.owner as IrProperty).setter?.symbol } + } + } + else -> error("Unexpected declaration for overriddenSymbols: $this") + } + } + + // We need to get Any's members if all the parents are private. + private fun allPublicApiSuperTypesOrAny(clazz: IrClass): List { + val superTypes = clazz.superTypes + val superClasses = superTypes.map { it.getClass() ?: error("Unexpected super type: $it") } + return if (superClasses.isEmpty() || superClasses.any { it.symbol.isPublicApi }) + superTypes + else + listOf(irBuiltIns.anyType) + } + + fun buildFakeOverridesForClass(clazz: IrClass) { + val superTypes = allPublicApiSuperTypesOrAny(clazz) + + val fromCurrent = clazz.declarations + .filterIsInstance() + .filter { it.symbol.isPublicApi } + + val allFromSuper = superTypes.flatMap { superType -> + val superClass = superType.getClass() ?: error("Unexpected super type: $superType") + superClass.declarations + .filterIsInstance() + .filter { it.symbol.isPublicApi } + .map { + val fakeOverride = fakeOverrideBuilder.fakeOverrideMember(superType, it, clazz) + originals[fakeOverride] = it + originalSuperTypes[fakeOverride] = superType + fakeOverride + } + } + + val allFromSuperByName = allFromSuper.groupBy { it.name } + + allFromSuperByName.forEach { group -> + generateOverridesInFunctionGroup( + group.value, + fromCurrent.filter { it.name == group.key }, + clazz + ) + } + } + + private fun generateOverridesInFunctionGroup( + membersFromSupertypes: List, + membersFromCurrent: List, + current: IrClass + ) { + val notOverridden = membersFromSupertypes.toMutableSet() + + for (fromCurrent in membersFromCurrent) { + val bound = extractAndBindOverridesForMember(fromCurrent, membersFromSupertypes) + notOverridden.removeAll(bound) + } + + createAndBindFakeOverrides(current, notOverridden) + } + + private fun extractAndBindOverridesForMember( + fromCurrent: IrOverridableMember, + descriptorsFromSuper: Collection + ): Collection { + val bound = ArrayList(descriptorsFromSuper.size) + val overridden = mutableSetOf() + for (fromSupertype in descriptorsFromSuper) { + val result = isOverridableBy(fromSupertype, fromCurrent/*, current*/).result + val isVisibleForOverride = isVisibleForOverride(fromCurrent, fromSupertype.original) + when (result) { + OverrideCompatibilityInfo.Result.OVERRIDABLE -> { + if (isVisibleForOverride) { + overridden.add(fromSupertype) + } + bound.add(fromSupertype) + } + OverrideCompatibilityInfo.Result.CONFLICT -> { + // if (isVisibleForOverride) { + // strategy.overrideConflict(fromSupertype, fromCurrent) + // } + + // Do nothing. + bound.add(fromSupertype) + } + OverrideCompatibilityInfo.Result.INCOMPATIBLE -> { + } + } + } + //strategy.setOverriddenDescriptors(fromCurrent, overridden) + fromCurrent.overriddenSymbols = overridden.map { it.original.symbol } + + return bound + } + + private fun createAndBindFakeOverrides( + current: IrClass, + notOverridden: Collection + ) { + val fromSuper = notOverridden.toMutableSet() + while (fromSuper.isNotEmpty()) { + val notOverriddenFromSuper = findMemberWithMaxVisibility(fromSuper) + val overridables = extractMembersOverridableInBothWays( + notOverriddenFromSuper, + fromSuper + ) + createAndBindFakeOverride(overridables, current) + } + } + + private fun filterVisibleFakeOverrides( + current: IrClass, + toFilter: Collection + ): Collection { + return toFilter.filter { member: IrOverridableMember -> + !Visibilities.isPrivate(member.visibility) && isVisibleIgnoringReceiver(member.original, current) + } + } + + private fun determineModalityForFakeOverride( + members: Collection, + current: IrClass + ): Modality { + // Optimization: avoid creating hash sets in frequent cases when modality can be computed trivially + var hasOpen = false + var hasAbstract = false + for (member in members) { + when (member.modality) { + Modality.FINAL -> return Modality.FINAL + Modality.SEALED -> throw IllegalStateException("Member cannot have SEALED modality: $member") + Modality.OPEN -> hasOpen = true + Modality.ABSTRACT -> hasAbstract = true + } + } + + // Fake overrides of abstract members in non-abstract expected classes should not be abstract, because otherwise it would be + // impossible to inherit a non-expected class from that expected class in common code. + // We're making their modality that of the containing class, because this is the least confusing behavior for the users. + // However, it may cause problems if we reuse resolution results of common code when compiling platform code (see KT-15220) + val transformAbstractToClassModality = + current.isExpect && current.modality !== Modality.ABSTRACT && current.modality !== Modality.SEALED + if (hasOpen && !hasAbstract) { + return Modality.OPEN + } + if (!hasOpen && hasAbstract) { + return if (transformAbstractToClassModality) current.modality else Modality.ABSTRACT + } + return getMinimalModality(members, transformAbstractToClassModality, current.modality) + } + + private fun areEquivalent(a: IrOverridableMember, b: IrOverridableMember) = (a == b) + + fun overrides(f: IrOverridableMember, g: IrOverridableMember): Boolean { + + if (f != g && areEquivalent(f.original, g.original)) return true + + for (overriddenFunction in getOverriddenDeclarations(f)) { + if (areEquivalent(g.original, overriddenFunction)) return true + } + return false + } + + private fun getOverriddenDeclarations(member: IrOverridableMember): Set { + val result = mutableSetOf() + collectOverriddenDeclarations(member.original, result) + return result + } + + private fun collectOverriddenDeclarations( + member: IrOverridableMember, + result: MutableSet + ) { + if (member.isReal) { + result.add(member) + } else { + check(member.overriddenSymbols.isNotEmpty()) { "No overridden descriptors found for (fake override) $member" } + for (overridden in member.original.overriddenSymbols.map { it.owner as IrOverridableMember }) { + val original = overridden.original + collectOverriddenDeclarations(original, result) + result.add(original) + } + } + } + + private fun getMinimalModality( + descriptors: Collection, + transformAbstractToClassModality: Boolean, + classModality: Modality + ): Modality { + var result = Modality.ABSTRACT + for (descriptor in descriptors) { + val effectiveModality = + if (transformAbstractToClassModality && descriptor.modality === Modality.ABSTRACT) classModality else descriptor.modality + if (effectiveModality < result) { + result = effectiveModality + } + } + return result + } + + private fun createAndBindFakeOverride( + overridables: Collection, + current: IrClass + ) { + val effectiveOverridden = filterVisibleFakeOverrides(current, overridables) + + // The descriptor based algorithm goes further building invisible fakes here, + // but we don't use invisible fakes in IR + if (effectiveOverridden.isEmpty()) return + + val modality = determineModalityForFakeOverride(effectiveOverridden, current) + val visibility = findMemberWithMaxVisibility(effectiveOverridden).visibility + val mostSpecific = selectMostSpecificMember(effectiveOverridden) + + val fakeOverride = mostSpecific.apply { + when (this) { + is IrFakeOverridePropertyImpl -> { + this.visibility = visibility + this.modality = modality + } + is IrFakeOverrideFunctionImpl -> { + this.visibility = visibility + this.modality = modality + } + else -> error("Unexpected fake override kind: $this") + } + } + + fakeOverride.overriddenSymbols = effectiveOverridden.map { it.original.symbol } + + assert( + fakeOverride.overriddenSymbols.isNotEmpty() + ) { "Overridden symbols should be set for " + CallableMemberDescriptor.Kind.FAKE_OVERRIDE } + + fakeOverrideBuilder.linkFakeOverride(fakeOverride) + current.declarations.add(fakeOverride) + } + + private fun isVisibilityMoreSpecific( + a: IrOverridableMember, + b: IrOverridableMember + ): Boolean { + val result = + Visibilities.compare(a.visibility, b.visibility) + return result == null || result >= 0 + } + + private fun isAccessorMoreSpecific( + a: IrSimpleFunction?, + b: IrSimpleFunction? + ): Boolean { + return if (a == null || b == null) true else isVisibilityMoreSpecific(a, b) + } + + private fun IrTypeCheckerContextWithAdditionalAxioms.isSubtypeOf(a: IrType, b: IrType) = + AbstractTypeChecker.isSubtypeOf(this as AbstractTypeCheckerContext, a, b) + + private fun IrTypeCheckerContextWithAdditionalAxioms.equalTypes(a: IrType, b: IrType) = + AbstractTypeChecker.equalTypes(this as AbstractTypeCheckerContext, a, b) + + private fun createTypeChecker(a: List, b: List) = + IrTypeCheckerContextWithAdditionalAxioms(irBuiltIns, a, b) + + private fun isReturnTypeMoreSpecific( + a: IrOverridableMember, + aReturnType: IrType, + b: IrOverridableMember, + bReturnType: IrType + ): Boolean { + val typeCheckerContext = createTypeChecker(a.typeParameters, b.typeParameters) + return typeCheckerContext.isSubtypeOf(aReturnType, bReturnType) + } + + private fun isMoreSpecific( + a: IrOverridableMember, + b: IrOverridableMember + ): Boolean { + val aReturnType = a.returnType + val bReturnType = b.returnType + if (!isVisibilityMoreSpecific(a, b)) return false + if (a is IrSimpleFunction) { + assert(b is IrSimpleFunction) { "b is " + b.javaClass } + return isReturnTypeMoreSpecific(a, aReturnType, b, bReturnType) + } + if (a is IrProperty) { + assert(b is IrProperty) { "b is " + b.javaClass } + val pa = a + val pb = b as IrProperty + if (!isAccessorMoreSpecific( + pa.setter, + pb.setter + ) + ) return false + return if (pa.isVar && pb.isVar) { + createTypeChecker( + a.getter!!.typeParameters, + b.getter!!.typeParameters + ).equalTypes(aReturnType, bReturnType) + } else { + // both vals or var vs val: val can't be more specific then var + !(!pa.isVar && pb.isVar) && isReturnTypeMoreSpecific( + a, aReturnType, + b, bReturnType + ) + } + } + error("Unexpected callable: $a") + } + + private fun isMoreSpecificThenAllOf( + candidate: IrOverridableMember, + descriptors: Collection + ): Boolean { + // NB subtyping relation in Kotlin is not transitive in presence of flexible types: + // String? <: String! <: String, but not String? <: String + for (descriptor in descriptors) { + if (!isMoreSpecific(candidate, descriptor)) { + return false + } + } + return true + } + + private fun selectMostSpecificMember( + overridables: Collection + ): IrOverridableMember { + assert(!overridables.isEmpty()) { "Should have at least one overridable descriptor" } + if (overridables.size == 1) { + return overridables.first() + } + val candidates = mutableListOf() + var transitivelyMostSpecific = overridables.first() + val transitivelyMostSpecificDescriptor = transitivelyMostSpecific + for (overridable in overridables) { + if (isMoreSpecificThenAllOf(overridable, overridables) + ) { + candidates.add(overridable) + } + if (isMoreSpecific( + overridable, + transitivelyMostSpecificDescriptor + ) + && !isMoreSpecific( + transitivelyMostSpecificDescriptor, + overridable + ) + ) { + transitivelyMostSpecific = overridable + } + } + if (candidates.isEmpty()) { + return transitivelyMostSpecific + } else if (candidates.size == 1) { + return candidates.first() + } + var firstNonFlexible: IrOverridableMember? = null + for (candidate in candidates) { + if (candidate.returnType !is IrDynamicType) { + firstNonFlexible = candidate + break + } + } + return firstNonFlexible ?: candidates.first() + } + + private fun extractMembersOverridableInBothWays( + overrider: IrOverridableMember, + extractFrom: MutableCollection + ): Collection { + val overridable = arrayListOf() + overridable.add(overrider) + val iterator = extractFrom.iterator() + while (iterator.hasNext()) { + val candidate = iterator.next() + if (overrider === candidate) { + iterator.remove() + continue + } + val finalResult = + getBothWaysOverridability( + overrider, + candidate + ) + if (finalResult == OverrideCompatibilityInfo.Result.OVERRIDABLE) { + overridable.add(candidate) + iterator.remove() + } else if (finalResult == OverrideCompatibilityInfo.Result.CONFLICT) { + iterator.remove() + } + } + return overridable + } + + private fun getBothWaysOverridability( + overriderDescriptor: IrOverridableMember, + candidateDescriptor: IrOverridableMember + ): OverrideCompatibilityInfo.Result { + val result1 = isOverridableBy( + candidateDescriptor, + overriderDescriptor + //null + ).result + val result2 = isOverridableBy( + overriderDescriptor, + candidateDescriptor + //null + ).result + return if (result1 == OverrideCompatibilityInfo.Result.OVERRIDABLE && result2 == OverrideCompatibilityInfo.Result.OVERRIDABLE) + OverrideCompatibilityInfo.Result.OVERRIDABLE + else if (result1 == OverrideCompatibilityInfo.Result.CONFLICT || result2 == OverrideCompatibilityInfo.Result.CONFLICT) + OverrideCompatibilityInfo.Result.CONFLICT + else + OverrideCompatibilityInfo.Result.INCOMPATIBLE + } + + private fun isOverridableBy( + superMember: IrOverridableMember, + subMember: IrOverridableMember, + // subClass: IrClass? + ): OverrideCompatibilityInfo { + return isOverridableBy(superMember, subMember/*, subClass*/, false) + } + + private fun isOverridableBy( + superMember: IrOverridableMember, + subMember: IrOverridableMember, + // subClass: IrClass?, Would only be needed for external overridability conditions. + checkReturnType: Boolean + ): OverrideCompatibilityInfo { + val basicResult = isOverridableByWithoutExternalConditions(superMember, subMember, checkReturnType) + return if (basicResult.result == OverrideCompatibilityInfo.Result.OVERRIDABLE) + OverrideCompatibilityInfo.success() + else + basicResult + // The frontend goes into external overridability condition details here, but don't deal with them in IR (yet?). + } + + private val IrOverridableMember.compiledValueParameters + get() = when (this) { + is IrSimpleFunction -> extensionReceiverParameter?.let { listOf(it) + valueParameters } ?: valueParameters + is IrProperty -> getter!!.extensionReceiverParameter?.let { listOf(it) } ?: emptyList() + else -> error("Unexpected declaration for compiledValueParameters: $this") + } + + private val IrOverridableMember.returnType + get() = when (this) { + is IrSimpleFunction -> this.returnType + is IrProperty -> this.getter!!.returnType + else -> error("Unexpected declaration for returnType: $this") + } + + private val IrOverridableMember.typeParameters + get() = when (this) { + is IrSimpleFunction -> this.typeParameters + is IrProperty -> this.getter!!.typeParameters + else -> error("Unexpected declaration for typeParameters: $this") + } + + private fun isOverridableByWithoutExternalConditions( + superMember: IrOverridableMember, + subMember: IrOverridableMember, + checkReturnType: Boolean + ): OverrideCompatibilityInfo { + val basicOverridability = getBasicOverridabilityProblem(superMember, subMember) + if (basicOverridability != null) return basicOverridability + + val superValueParameters = superMember.compiledValueParameters + val subValueParameters = subMember.compiledValueParameters + val superTypeParameters = superMember.typeParameters + val subTypeParameters = subMember.typeParameters + + if (superTypeParameters.size != subTypeParameters.size) { + /* TODO: do we need this in IR? + superValueParameters.forEachIndexed { index, superParameter -> + if (!AbstractTypeChecker.equalTypes( + defaultTypeCheckerContext as AbstractTypeCheckerContext, + superParameter.type, + subValueParameters[index].type + ) + ) { + return OverrideCompatibilityInfo.incompatible("Type parameter number mismatch") + } + } + return OverrideCompatibilityInfo.conflict("Type parameter number mismatch") + */ + + return incompatible("Type parameter number mismatch") + } + + val typeCheckerContext = + IrTypeCheckerContextWithAdditionalAxioms(irBuiltIns, superTypeParameters, subTypeParameters) + + /* TODO: check the bounds. See OverridingUtil.areTypeParametersEquivalent() + superTypeParameters.forEachIndexed { index, parameter -> + if (!AbstractTypeChecker.areTypeParametersEquivalent( + typeCheckerContext as AbstractTypeCheckerContext, + subTypeParameters[index].type, + parameter.type + ) + ) return OverrideCompatibilityInfo.incompatible("Type parameter bounds mismatch") + } + */ + + assert(superValueParameters.size == subValueParameters.size) + + superValueParameters.forEachIndexed { index, parameter -> + if (!AbstractTypeChecker.equalTypes( + typeCheckerContext as AbstractTypeCheckerContext, + subValueParameters[index].type, + parameter.type + ) + ) return incompatible("Value parameter type mismatch") + } + + if (superMember is IrSimpleFunction && subMember is IrSimpleFunction && superMember.isSuspend != subMember.isSuspend) { + return OverrideCompatibilityInfo.conflict("Incompatible suspendability") + } + + if (checkReturnType) { + if (!AbstractTypeChecker.isSubtypeOf( + typeCheckerContext as AbstractTypeCheckerContext, + subMember.returnType, + superMember.returnType + ) + ) return OverrideCompatibilityInfo.conflict("Return type mismatch") + } + return OverrideCompatibilityInfo.success() + } + + private fun getBasicOverridabilityProblem( + superMember: IrOverridableMember, + subMember: IrOverridableMember + ): OverrideCompatibilityInfo? { + if (superMember is IrSimpleFunction && subMember !is IrSimpleFunction || + superMember is IrProperty && subMember !is IrProperty + ) { + return incompatible("Member kind mismatch") + } + require((superMember is IrSimpleFunction || superMember is IrProperty)) { + "This type of IrDeclaration cannot be checked for overridability: $superMember" + } + + return if (superMember.name != subMember.name) { + incompatible("Name mismatch") + } else + checkReceiverAndParameterCount(superMember, subMember) + } + + private fun checkReceiverAndParameterCount( + superMember: IrOverridableMember, + subMember: IrOverridableMember + ): OverrideCompatibilityInfo? { + return when (superMember) { + is IrSimpleFunction -> { + require(subMember is IrSimpleFunction) + when { + superMember.extensionReceiverParameter == null != (subMember.extensionReceiverParameter == null) -> { + incompatible("Receiver presence mismatch") + } + superMember.valueParameters.size != subMember.valueParameters.size -> { + incompatible("Value parameter number mismatch") + } + else -> null + } + } + is IrProperty -> { + require(subMember is IrProperty) + if (superMember.getter?.extensionReceiverParameter == null != (subMember.getter?.extensionReceiverParameter == null)) { + incompatible("Receiver presence mismatch") + } else null + } + else -> error("Unxpected declaration for value parameter check: $this") + } + } +} \ No newline at end of file diff --git a/core/descriptors/src/org/jetbrains/kotlin/resolve/OverridableMember.kt b/core/descriptors/src/org/jetbrains/kotlin/resolve/OverridableMember.kt new file mode 100644 index 00000000000..28801c5673f --- /dev/null +++ b/core/descriptors/src/org/jetbrains/kotlin/resolve/OverridableMember.kt @@ -0,0 +1,35 @@ +/* + * Copyright 2010-2020 JetBrains s.r.o. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.jetbrains.kotlin.resolve + +import org.jetbrains.kotlin.descriptors.Modality +import org.jetbrains.kotlin.descriptors.Visibility +import org.jetbrains.kotlin.name.Name + +interface MemberWithName { + val name: Name +} + +interface MemberWithVisibility { + val visibility: Visibility +} + +interface MemberWithModality { + val modality: Modality +} + +interface OverridableMember: MemberWithVisibility, MemberWithModality, MemberWithName \ No newline at end of file