[FE] Stop ignoring ABSTRACT_MEMBER_NOT_IMPLEMENTED for expect classes

^KT-59739 Fixed
Review: https://jetbrains.team/p/kt/reviews/11038/timeline
This commit is contained in:
Nikita Bobko
2023-07-10 11:23:25 +02:00
committed by Space Team
parent bfcb90c716
commit 4f3ecedbca
25 changed files with 161 additions and 42 deletions
@@ -386,7 +386,6 @@ fun FirCallableSymbol<*>.getImplementationStatus(
isFinal -> ImplementationStatus.CANNOT_BE_IMPLEMENTED
containingClassSymbol === parentClassSymbol && (origin == FirDeclarationOrigin.Source || origin == FirDeclarationOrigin.Precompiled) ->
ImplementationStatus.ALREADY_IMPLEMENTED
containingClassSymbol is FirRegularClassSymbol && containingClassSymbol.isExpect -> ImplementationStatus.CANNOT_BE_IMPLEMENTED
isAbstract -> ImplementationStatus.NOT_IMPLEMENTED
else -> ImplementationStatus.INHERITED_OR_SYNTHESIZED
}
@@ -23,7 +23,6 @@ import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors.VAR_IMPLEMENTED_B
import org.jetbrains.kotlin.fir.containingClassLookupTag
import org.jetbrains.kotlin.fir.declarations.FirClass
import org.jetbrains.kotlin.fir.declarations.FirDeclarationOrigin
import org.jetbrains.kotlin.fir.declarations.FirRegularClass
import org.jetbrains.kotlin.fir.declarations.utils.*
import org.jetbrains.kotlin.fir.delegatedWrapperData
import org.jetbrains.kotlin.fir.resolve.toSymbol
@@ -42,7 +41,6 @@ object FirNotImplementedOverrideChecker : FirClassChecker() {
if (sourceKind is KtFakeSourceElementKind && sourceKind != KtFakeSourceElementKind.EnumInitializer) return
val modality = declaration.modality()
val canHaveAbstractDeclarations = modality == Modality.ABSTRACT || modality == Modality.SEALED
if (declaration is FirRegularClass && declaration.isExpect) return
val classKind = declaration.classKind
if (classKind == ClassKind.ANNOTATION_CLASS || classKind == ClassKind.ENUM_CLASS) return
val classSymbol = declaration.symbol
@@ -36,7 +36,7 @@ import org.jetbrains.kotlin.incremental.components.NoLookupLocation
import org.jetbrains.kotlin.lexer.KtTokens
import org.jetbrains.kotlin.platform.PlatformSpecificDiagnosticComponents
import org.jetbrains.kotlin.psi.*
import org.jetbrains.kotlin.resolve.DescriptorUtils.classCanHaveAbstractFakeOverride
import org.jetbrains.kotlin.resolve.DescriptorUtils.classCanHaveAbstractDeclaration
import org.jetbrains.kotlin.resolve.OverridingUtil.OverrideCompatibilityInfo.Result.OVERRIDABLE
import org.jetbrains.kotlin.resolve.calls.util.isOrOverridesSynthesized
import org.jetbrains.kotlin.types.*
@@ -132,7 +132,7 @@ class OverrideResolver(
this(delegateStrategy.klass, delegateStrategy.classDescriptor)
override fun doReportErrors() {
val canHaveAbstractMembers = classCanHaveAbstractFakeOverride(classDescriptor)
val canHaveAbstractMembers = classCanHaveAbstractDeclaration(classDescriptor)
if (abstractInBaseClassNoImpl.isNotEmpty() && !canHaveAbstractMembers) {
if (languageVersionSettings.supportsFeature(AbstractClassMemberNotImplementedWithIntermediateAbstractClass)) {
trace.report(ABSTRACT_CLASS_MEMBER_NOT_IMPLEMENTED.on(klass, klass, abstractInBaseClassNoImpl.first()))
@@ -260,7 +260,7 @@ class OverrideResolver(
}
open fun doReportErrors() {
val canHaveAbstractMembers = classCanHaveAbstractFakeOverride(classDescriptor)
val canHaveAbstractMembers = classCanHaveAbstractDeclaration(classDescriptor)
if (abstractInBaseClassNoImpl.isNotEmpty() && !canHaveAbstractMembers) {
trace.report(ABSTRACT_CLASS_MEMBER_NOT_IMPLEMENTED.on(klass, klass, abstractInBaseClassNoImpl.first()))
} else if (abstractNoImpl.isNotEmpty() && !canHaveAbstractMembers) {
@@ -708,11 +708,9 @@ class OverrideResolver(
for (overridden in relevantDirectlyOverridden) {
val containingDeclaration = overridden.containingDeclaration as? ClassDescriptor ?: continue
if (containingDeclaration.kind == ClassKind.CLASS) {
if (overridden.kind == FAKE_OVERRIDE && !containingDeclaration.isExpect) {
if (overridden.kind == FAKE_OVERRIDE) {
// Fake override in a class in fact can mean an interface member
// We will process it at the end
// Note: with expect containing class, the situation is unclear, so we miss this case
// See extendExpectedClassWithAbstractMember.kt (BaseA, BaseAImpl, DerivedA1)
fakeOverrideInBaseClass = overridden
}
overridesClassMember = true
@@ -13,7 +13,9 @@ interface I2 {
fun f(): String
}
expect class C() : I1, I2
expect class C() : I1, I2 {
override fun f(): String
}
fun test() = C().f()
@@ -21,7 +23,7 @@ fun test() = C().f()
// FILE: platform.kt
actual class C : I1, I2 {
override fun f() = "OK"
actual override fun f() = "OK"
}
fun box() = test()
@@ -19,9 +19,9 @@ expect interface My {
val f: Int
}
class MyImpl1: My
<!ABSTRACT_MEMBER_NOT_IMPLEMENTED!>class MyImpl1<!>: My
class MyImpl2: My {
<!ABSTRACT_MEMBER_NOT_IMPLEMENTED!>class MyImpl2<!>: My {
override fun foo() {}
override val f = 0
override val e = 1
@@ -0,0 +1,22 @@
// WITH_STDLIB
// MODULE: m1-common
// FILE: common.kt
interface B {
override fun toString(): String
}
expect value <!ABSTRACT_MEMBER_NOT_IMPLEMENTED!>class C<!>(val s: String) : B
expect value <!ABSTRACT_MEMBER_NOT_IMPLEMENTED!>class D<!>(val s: String) : B
// MODULE: m1-jvm()()(m1-common)
// FILE: jvm.kt
@JvmInline
actual value class C(actual val s: String) : B {
override fun toString(): String = s
}
@JvmInline
actual value class D(actual val s: String) : B
@@ -1,4 +1,3 @@
// FIR_IDENTICAL
// WITH_STDLIB
// MODULE: m1-common
// FILE: common.kt
@@ -0,0 +1,17 @@
// MODULE: m1-common
// FILE: common.kt
interface Base {
fun foo()
}
expect <!ABSTRACT_MEMBER_NOT_IMPLEMENTED!>object Implementation<!> : Base
// MODULE: m1-jvm()()(m1-common)
// FILE: jvm.kt
abstract class RealImplementation : Base {
override fun foo() {}
}
actual object Implementation : RealImplementation(), Base
@@ -1,4 +1,3 @@
// FIR_IDENTICAL
// MODULE: m1-common
// FILE: common.kt
@@ -6,7 +5,7 @@ interface Base {
fun foo()
}
expect object Implementation : Base
expect <!ABSTRACT_MEMBER_NOT_IMPLEMENTED, ABSTRACT_MEMBER_NOT_IMPLEMENTED{JVM}!>object Implementation<!> : Base
// MODULE: m1-jvm()()(m1-common)
// FILE: jvm.kt
@@ -0,0 +1,27 @@
// MODULE: m1-common
// FILE: common.kt
interface Foo {
fun foo()
}
expect <!ABSTRACT_MEMBER_NOT_IMPLEMENTED!>class ImplicitFoo<!> : Foo
expect class ExplicitFoo : Foo {
override fun foo()
}
expect <!ABSTRACT_MEMBER_NOT_IMPLEMENTED!>class ImplicitFooCheck<!> : Foo
// MODULE: m2-jvm()()(m1-common)
// FILE: jvm.kt
actual class ImplicitFoo : Foo {
override fun foo() {}
}
actual class ExplicitFoo : Foo {
actual override fun foo() {}
}
actual <!ABSTRACT_MEMBER_NOT_IMPLEMENTED!>class ImplicitFooCheck<!> : Foo
@@ -1,4 +1,3 @@
// FIR_IDENTICAL
// MODULE: m1-common
// FILE: common.kt
@@ -6,13 +5,13 @@ interface Foo {
fun foo()
}
expect class ImplicitFoo : Foo
expect <!ABSTRACT_MEMBER_NOT_IMPLEMENTED, ABSTRACT_MEMBER_NOT_IMPLEMENTED{JVM}!>class ImplicitFoo<!> : Foo
expect class ExplicitFoo : Foo {
override fun foo()
}
expect class ImplicitFooCheck : Foo
expect <!ABSTRACT_MEMBER_NOT_IMPLEMENTED, ABSTRACT_MEMBER_NOT_IMPLEMENTED{JVM}!>class ImplicitFooCheck<!> : Foo
// MODULE: m2-jvm()()(m1-common)
// FILE: jvm.kt
@@ -4,9 +4,9 @@
<!NO_ACTUAL_FOR_EXPECT!>expect abstract class BaseA() {
abstract fun foo()
}<!>
<!NO_ACTUAL_FOR_EXPECT!>expect open class BaseAImpl() : BaseA<!>
<!NO_ACTUAL_FOR_EXPECT!>expect open <!ABSTRACT_CLASS_MEMBER_NOT_IMPLEMENTED!>class BaseAImpl<!>() : BaseA<!>
class DerivedA1 : BaseAImpl()
<!ABSTRACT_CLASS_MEMBER_NOT_IMPLEMENTED!>class DerivedA1<!> : BaseAImpl()
class DerivedA2 : BaseAImpl() {
override fun foo() = super.<!ABSTRACT_SUPER_CALL!>foo<!>()
}
@@ -16,9 +16,9 @@ class DerivedA2 : BaseAImpl() {
<!NO_ACTUAL_FOR_EXPECT!>expect interface BaseB {
fun foo()
}<!>
<!NO_ACTUAL_FOR_EXPECT!>expect open class BaseBImpl() : BaseB<!>
<!NO_ACTUAL_FOR_EXPECT!>expect open <!ABSTRACT_MEMBER_NOT_IMPLEMENTED!>class BaseBImpl<!>() : BaseB<!>
class DerivedB1 : BaseBImpl()
<!ABSTRACT_MEMBER_NOT_IMPLEMENTED!>class DerivedB1<!> : BaseBImpl()
class DerivedB2 : BaseBImpl() {
override fun foo() = super.<!ABSTRACT_SUPER_CALL!>foo<!>()
}
@@ -30,7 +30,7 @@ class DerivedB2 : BaseBImpl() {
}<!>
<!NO_ACTUAL_FOR_EXPECT!>expect abstract class BaseCImpl() : BaseC<!>
class DerivedC1 : BaseCImpl()
<!ABSTRACT_MEMBER_NOT_IMPLEMENTED!>class DerivedC1<!> : BaseCImpl()
class DerivedC2 : BaseCImpl() {
override fun foo() = super.<!ABSTRACT_SUPER_CALL!>foo<!>()
}
@@ -58,4 +58,14 @@ sealed class BaseEImpl() : BaseE {
<!NO_ACTUAL_FOR_EXPECT!>expect interface BaseF {
fun foo()
}<!>
<!NO_ACTUAL_FOR_EXPECT!>expect class BaseFImpl() : BaseF<!>
<!NO_ACTUAL_FOR_EXPECT!>expect <!ABSTRACT_MEMBER_NOT_IMPLEMENTED!>class BaseFImpl<!>() : BaseF<!>
<!NO_ACTUAL_FOR_EXPECT!>expect abstract class BaseG() {
abstract fun foo()
}<!>
<!NO_ACTUAL_FOR_EXPECT!>expect open class BaseGImpl() : BaseG {
override fun foo()
}<!>
class DerivedG1 : BaseGImpl()
@@ -4,9 +4,9 @@
expect abstract class BaseA() {
abstract fun foo()
}
expect open class BaseAImpl() : BaseA
expect open <!ABSTRACT_CLASS_MEMBER_NOT_IMPLEMENTED!>class BaseAImpl<!>() : BaseA
class DerivedA1 : BaseAImpl()
<!ABSTRACT_CLASS_MEMBER_NOT_IMPLEMENTED!>class DerivedA1<!> : BaseAImpl()
class DerivedA2 : BaseAImpl() {
override fun foo() = super.foo()
}
@@ -16,7 +16,7 @@ class DerivedA2 : BaseAImpl() {
expect interface BaseB {
fun foo()
}
expect open class BaseBImpl() : BaseB
expect open <!ABSTRACT_MEMBER_NOT_IMPLEMENTED!>class BaseBImpl<!>() : BaseB
class DerivedB1 : BaseBImpl()
class DerivedB2 : BaseBImpl() {
@@ -58,4 +58,14 @@ sealed class BaseEImpl() : BaseE {
expect interface BaseF {
fun foo()
}
expect class BaseFImpl() : BaseF
expect <!ABSTRACT_MEMBER_NOT_IMPLEMENTED!>class BaseFImpl<!>() : BaseF
expect abstract class BaseG() {
abstract fun foo()
}
expect open class BaseGImpl() : BaseG {
override fun foo()
}
class DerivedG1 : BaseGImpl()
@@ -93,6 +93,22 @@ public final expect class BaseFImpl : BaseF {
public open override /*1*/ /*fake_override*/ fun toString(): kotlin.String
}
public abstract expect class BaseG {
public constructor BaseG()
public open override /*1*/ /*fake_override*/ fun equals(/*0*/ other: kotlin.Any?): kotlin.Boolean
public abstract expect fun foo(): kotlin.Unit
public open override /*1*/ /*fake_override*/ fun hashCode(): kotlin.Int
public open override /*1*/ /*fake_override*/ fun toString(): kotlin.String
}
public open expect class BaseGImpl : BaseG {
public constructor BaseGImpl()
public open override /*1*/ /*fake_override*/ fun equals(/*0*/ other: kotlin.Any?): kotlin.Boolean
public open expect override /*1*/ fun foo(): kotlin.Unit
public open override /*1*/ /*fake_override*/ fun hashCode(): kotlin.Int
public open override /*1*/ /*fake_override*/ fun toString(): kotlin.String
}
public final class DerivedA1 : BaseAImpl {
public constructor DerivedA1()
public open override /*1*/ /*fake_override*/ fun equals(/*0*/ other: kotlin.Any?): kotlin.Boolean
@@ -141,3 +157,11 @@ public final class DerivedC2 : BaseCImpl {
public open override /*1*/ /*fake_override*/ fun toString(): kotlin.String
}
public final class DerivedG1 : BaseGImpl {
public constructor DerivedG1()
public open override /*1*/ /*fake_override*/ fun equals(/*0*/ other: kotlin.Any?): kotlin.Boolean
public open expect override /*1*/ /*fake_override*/ fun foo(): kotlin.Unit
public open override /*1*/ /*fake_override*/ fun hashCode(): kotlin.Int
public open override /*1*/ /*fake_override*/ fun toString(): kotlin.String
}
@@ -5,7 +5,7 @@ expect abstract class Base {
abstract fun foo()
}
expect class DerivedImplicit : Base
expect <!ABSTRACT_CLASS_MEMBER_NOT_IMPLEMENTED!>class DerivedImplicit<!> : Base
expect class DerivedExplicit : Base {
override fun foo()
@@ -5,7 +5,7 @@ expect abstract class Base {
abstract fun foo()
}
expect class DerivedImplicit : Base
expect <!ABSTRACT_CLASS_MEMBER_NOT_IMPLEMENTED, ABSTRACT_CLASS_MEMBER_NOT_IMPLEMENTED{JVM}!>class DerivedImplicit<!> : Base
expect class DerivedExplicit : Base {
override fun foo()
@@ -19,6 +19,7 @@ expect class FastArrayList<E> : MutableListEx<E>, RandomAccess {
constructor(elements: Collection<E>)
fun trimToSize()
override fun removeRange(fromIndex: Int, toIndex: Int)
fun ensureCapacity(minCapacity: Int)
override val size: Int
override fun isEmpty(): Boolean
@@ -66,7 +67,7 @@ public actual open class FastArrayList<E> internal constructor(
actual override fun addAll(index: Int, elements: Collection<E>): Boolean = true
actual override fun remove(element: E): Boolean = true
@Suppress("UNCHECKED_CAST") actual override fun removeAt(index: Int): E = array[0] as E
override fun removeRange(fromIndex: Int, toIndex: Int) {}
actual override fun removeRange(fromIndex: Int, toIndex: Int) {}
override fun setAll(index: Int, elements: FastArrayList<E>, offset: Int, size: Int) {}
override fun addAll(elements: FastArrayList<E>, offset: Int, size: Int) {}
actual override fun clear() {}
@@ -43,6 +43,8 @@ FILE fqName:<root> fileName:/common.kt
public open fun toString (): kotlin.String declared in kotlin.Any
$this: VALUE_PARAMETER name:<this> type:kotlin.Any
CLASS CLASS name:C modality:FINAL visibility:public [expect] superTypes:[<root>.I1; <root>.I2]
annotations:
Suppress(names = ['ABSTRACT_MEMBER_NOT_IMPLEMENTED'])
$this: VALUE_PARAMETER INSTANCE_RECEIVER name:<this> type:<root>.C
CONSTRUCTOR visibility:public <> () returnType:<root>.C [primary,expect]
FUN FAKE_OVERRIDE name:f visibility:public modality:ABSTRACT <> ($this:<root>.I1) returnType:kotlin.String [expect,fake_override]
@@ -17,6 +17,7 @@ interface I2 {
val p: Int
}
@Suppress("ABSTRACT_MEMBER_NOT_IMPLEMENTED") // Workaround for KT-60390
expect class C() : I1, I2
// MODULE: platform()()(common)
@@ -17,6 +17,7 @@ interface I2 {
}
@Suppress(names = ["ABSTRACT_MEMBER_NOT_IMPLEMENTED"])
expect class C : I1, I2 {
expect constructor() /* primary */
@@ -2,4 +2,6 @@ expect abstract class Base {
abstract fun foo()
}
expect class DerivedImplicit : Base
expect class DerivedImplicit : Base {
override fun foo()
}
@@ -3,5 +3,5 @@ actual abstract class Base {
}
actual class DerivedImplicit : Base() {
override fun foo() {}
}
actual override fun foo() {}
}
@@ -26,8 +26,7 @@ enum class ImplementationStatus {
ALREADY_IMPLEMENTED,
/**
* The symbol is not implemented in the class and it cannot be implemented. For example, it's final in super classes or the current
* class is `expect`.
* The symbol is not implemented in the class, and it cannot be implemented. For example, it's final in super classes.
*/
CANNOT_BE_IMPLEMENTED;
@@ -505,10 +505,6 @@ public class DescriptorUtils {
UnsignedTypes.INSTANCE.isUnsignedType(type);
}
public static boolean classCanHaveAbstractFakeOverride(@NotNull ClassDescriptor classDescriptor) {
return classCanHaveAbstractDeclaration(classDescriptor) || classDescriptor.isExpect();
}
public static boolean classCanHaveAbstractDeclaration(@NotNull ClassDescriptor classDescriptor) {
return classDescriptor.getModality() == Modality.ABSTRACT
|| isSealedClass(classDescriptor)
@@ -25,13 +25,19 @@ import org.jetbrains.kotlin.config.languageVersionSettings
import org.jetbrains.kotlin.descriptors.ModuleDescriptor
import org.jetbrains.kotlin.descriptors.PackageFragmentProvider
import org.jetbrains.kotlin.descriptors.impl.ModuleDescriptorImpl
import org.jetbrains.kotlin.diagnostics.Errors
import org.jetbrains.kotlin.diagnostics.Severity
import org.jetbrains.kotlin.lexer.KtToken
import org.jetbrains.kotlin.lexer.KtTokens
import org.jetbrains.kotlin.name.Name
import org.jetbrains.kotlin.platform.CommonPlatforms
import org.jetbrains.kotlin.platform.TargetPlatform
import org.jetbrains.kotlin.psi.KtClass
import org.jetbrains.kotlin.psi.KtFile
import org.jetbrains.kotlin.psi.KtPsiFactory
import org.jetbrains.kotlin.psi.psiUtil.endOffset
import org.jetbrains.kotlin.psi.psiUtil.hasExpectModifier
import org.jetbrains.kotlin.psi.psiUtil.isAbstract
import org.jetbrains.kotlin.psi.psiUtil.startOffset
import org.jetbrains.kotlin.resolve.CompilerEnvironment
import org.jetbrains.kotlin.resolve.PlatformDependentAnalyzerServices
@@ -95,7 +101,14 @@ class InlineSourceBuilderImpl(private val disposable: Disposable) : InlineSource
environment.createPackagePartProvider(content.moduleContentScope)
}
val errorDiagnostics = analysisResult.bindingContext.diagnostics.noSuppression().filter { it.severity == Severity.ERROR }
val errorDiagnostics = analysisResult.bindingContext.diagnostics.noSuppression()
.filter { it.severity == Severity.ERROR }
.filterNot { diagnostic ->
val psiElement = diagnostic.psiElement
// Mute KT-60378 problem
psiElement is KtClass && psiElement.hasExpectModifier() && !psiElement.hasModifier(KtTokens.OPEN_KEYWORD) &&
diagnostic.factory in listOf(Errors.ABSTRACT_CLASS_MEMBER_NOT_IMPLEMENTED, Errors.ABSTRACT_MEMBER_NOT_IMPLEMENTED)
}
check(errorDiagnostics.isEmpty()) {
val diagnosticInfos = errorDiagnostics.map { diagnostic ->
DiagnosticInfo(diagnostic.psiElement, diagnostic.factoryName)