FIR: use Java 8 rules in not implemented checker
This commit is contained in:
+5
@@ -2789,6 +2789,11 @@ public class LazyBodyIsNotTouchedTilContractsPhaseTestGenerated extends Abstract
|
||||
runTest("compiler/fir/analysis-tests/testData/resolve/problems/secondaryConstructorCfg.kt");
|
||||
}
|
||||
|
||||
@TestMetadata("symbolsAndDescriptors.kt")
|
||||
public void testSymbolsAndDescriptors() throws Exception {
|
||||
runTest("compiler/fir/analysis-tests/testData/resolve/problems/symbolsAndDescriptors.kt");
|
||||
}
|
||||
|
||||
@TestMetadata("transform.kt")
|
||||
public void testTransform() throws Exception {
|
||||
runTest("compiler/fir/analysis-tests/testData/resolve/problems/transform.kt");
|
||||
|
||||
+46
@@ -0,0 +1,46 @@
|
||||
FILE: symbolsAndDescriptors.kt
|
||||
public final class IrClassSymbolImpl : R|IrBindableSymbolBase<kotlin/String>|, R|IrClassSymbol| {
|
||||
public constructor(descriptor: R|kotlin/String?| = Null(null)): R|IrClassSymbolImpl| {
|
||||
super<R|IrBindableSymbolBase<kotlin/String>|>(R|<local>/descriptor|)
|
||||
}
|
||||
|
||||
}
|
||||
public abstract interface IrClassSymbol : R|IrClassifierSymbol|, R|IrBindableSymbol<kotlin/String>| {
|
||||
}
|
||||
public abstract interface IrClassifierSymbol : R|IrSymbol|, R|TypeConstructorMarker| {
|
||||
public abstract override val descriptor: R|kotlin/CharSequence|
|
||||
public get(): R|kotlin/CharSequence|
|
||||
|
||||
}
|
||||
public abstract interface IrSymbol : R|kotlin/Any| {
|
||||
public abstract val descriptor: R|kotlin/Any|
|
||||
public get(): R|kotlin/Any|
|
||||
|
||||
}
|
||||
public abstract interface TypeConstructorMarker : R|kotlin/Any| {
|
||||
}
|
||||
public abstract interface IrBindableSymbol<out D : R|kotlin/Any|> : R|IrSymbol| {
|
||||
public abstract override val descriptor: R|D|
|
||||
public get(): R|D|
|
||||
|
||||
}
|
||||
public abstract class IrBindableSymbolBase<out D : R|kotlin/Any|> : R|IrBindableSymbol<D>|, R|IrSymbolBase<D>| {
|
||||
public constructor<out D : R|kotlin/Any|>(descriptor: R|D?|): R|IrBindableSymbolBase<D>| {
|
||||
super<R|IrSymbolBase<D>|>(R|<local>/descriptor|)
|
||||
}
|
||||
|
||||
}
|
||||
public abstract class IrSymbolBase<out D : R|kotlin/Any|> : R|IrSymbol| {
|
||||
public constructor<out D : R|kotlin/Any|>(_descriptor: R|D?|): R|IrSymbolBase<D>| {
|
||||
super<R|kotlin/Any|>()
|
||||
}
|
||||
|
||||
private final val _descriptor: R|D?| = R|<local>/_descriptor|
|
||||
private get(): R|D?|
|
||||
|
||||
public open override val descriptor: R|D|
|
||||
public get(): R|D| {
|
||||
^ this@R|/IrSymbolBase|.R|/IrSymbolBase._descriptor|!!
|
||||
}
|
||||
|
||||
}
|
||||
+33
@@ -0,0 +1,33 @@
|
||||
class IrClassSymbolImpl(descriptor: String? = null) :
|
||||
IrBindableSymbolBase<String>(descriptor),
|
||||
IrClassSymbol
|
||||
|
||||
interface IrClassSymbol : IrClassifierSymbol, IrBindableSymbol<String>
|
||||
|
||||
interface IrClassifierSymbol : IrSymbol, TypeConstructorMarker {
|
||||
override val descriptor: CharSequence
|
||||
}
|
||||
|
||||
interface IrSymbol {
|
||||
val descriptor: Any
|
||||
}
|
||||
|
||||
interface TypeConstructorMarker
|
||||
|
||||
interface IrBindableSymbol<out D : Any> : IrSymbol {
|
||||
override val descriptor: D
|
||||
}
|
||||
|
||||
abstract class IrBindableSymbolBase<out D : Any>(descriptor: D?) :
|
||||
IrBindableSymbol<D>, IrSymbolBase<D>(descriptor)
|
||||
|
||||
abstract class IrSymbolBase<out D : Any>(
|
||||
private val _descriptor: D?
|
||||
) : IrSymbol {
|
||||
override val descriptor: D
|
||||
get() = _descriptor!!
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
+6
@@ -3159,6 +3159,12 @@ public class FirDiagnosticTestGenerated extends AbstractFirDiagnosticTest {
|
||||
runTest("compiler/fir/analysis-tests/testData/resolve/problems/secondaryConstructorCfg.kt");
|
||||
}
|
||||
|
||||
@Test
|
||||
@TestMetadata("symbolsAndDescriptors.kt")
|
||||
public void testSymbolsAndDescriptors() throws Exception {
|
||||
runTest("compiler/fir/analysis-tests/testData/resolve/problems/symbolsAndDescriptors.kt");
|
||||
}
|
||||
|
||||
@Test
|
||||
@TestMetadata("transform.kt")
|
||||
public void testTransform() throws Exception {
|
||||
|
||||
+6
@@ -3159,6 +3159,12 @@ public class FirDiagnosticsWithLightTreeTestGenerated extends AbstractFirDiagnos
|
||||
runTest("compiler/fir/analysis-tests/testData/resolve/problems/secondaryConstructorCfg.kt");
|
||||
}
|
||||
|
||||
@Test
|
||||
@TestMetadata("symbolsAndDescriptors.kt")
|
||||
public void testSymbolsAndDescriptors() throws Exception {
|
||||
runTest("compiler/fir/analysis-tests/testData/resolve/problems/symbolsAndDescriptors.kt");
|
||||
}
|
||||
|
||||
@Test
|
||||
@TestMetadata("transform.kt")
|
||||
public void testTransform() throws Exception {
|
||||
|
||||
+53
-8
@@ -63,11 +63,58 @@ object FirNotImplementedOverrideChecker : FirClassChecker() {
|
||||
return false
|
||||
}
|
||||
|
||||
fun FirIntersectionCallableSymbol.subjectToManyNotImplemented(): Boolean {
|
||||
var nonAbstractCountInClass = 0
|
||||
var nonAbstractCountInInterface = 0
|
||||
var abstractCountInInterface = 0
|
||||
for (intersectionSymbol in intersections) {
|
||||
val intersection = intersectionSymbol.fir as FirCallableMemberDeclaration
|
||||
val containingClass = intersection.getContainingClass(context) as? FirRegularClass
|
||||
val hasInterfaceContainer = containingClass?.classKind == ClassKind.INTERFACE
|
||||
if (intersection.modality != Modality.ABSTRACT) {
|
||||
if (hasInterfaceContainer) {
|
||||
nonAbstractCountInInterface++
|
||||
} else {
|
||||
nonAbstractCountInClass++
|
||||
}
|
||||
} else if (hasInterfaceContainer) {
|
||||
abstractCountInInterface++
|
||||
}
|
||||
if (nonAbstractCountInClass + nonAbstractCountInInterface > 1) {
|
||||
return true
|
||||
}
|
||||
if (nonAbstractCountInInterface > 0 && abstractCountInInterface > 0) {
|
||||
return true
|
||||
}
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
fun FirIntersectionCallableSymbol.shouldBeImplemented(): Boolean {
|
||||
// In Java 8, non-abstract intersection overrides having abstract symbol from base class
|
||||
// still should be implemented in current class (even when they have default interface implementation)
|
||||
if (intersections.none {
|
||||
val fir = (it.fir as FirCallableMemberDeclaration).unwrapFakeOverrides()
|
||||
fir.isAbstract && (fir.getContainingClass(context) as? FirRegularClass)?.classKind == ClassKind.CLASS
|
||||
}
|
||||
) return false
|
||||
// Exception from the rule above: interface implementation via delegation
|
||||
if (intersections.any {
|
||||
val fir = (it.fir as FirCallableMemberDeclaration)
|
||||
fir.origin == FirDeclarationOrigin.Delegated && !fir.isAbstract
|
||||
}
|
||||
) return false
|
||||
return true
|
||||
}
|
||||
|
||||
fun FirCallableMemberDeclaration<*>.shouldBeImplemented(): Boolean {
|
||||
if (!isAbstract) return false
|
||||
val containingClass = getContainingClass(context)
|
||||
if (containingClass === declaration && origin == FirDeclarationOrigin.Source) return false
|
||||
if (containingClass is FirRegularClass && containingClass.isExpect) return false
|
||||
if (!isAbstract) {
|
||||
val symbol = symbol as? FirIntersectionCallableSymbol ?: return false
|
||||
return symbol.shouldBeImplemented()
|
||||
}
|
||||
if (containingClass === declaration && origin == FirDeclarationOrigin.Source) return false
|
||||
return true
|
||||
}
|
||||
|
||||
@@ -75,9 +122,8 @@ object FirNotImplementedOverrideChecker : FirClassChecker() {
|
||||
classScope.processFunctionsByName(name) { namedFunctionSymbol ->
|
||||
val simpleFunction = namedFunctionSymbol.fir
|
||||
if (namedFunctionSymbol is FirIntersectionOverrideFunctionSymbol) {
|
||||
if (namedFunctionSymbol.intersections.count {
|
||||
(it.fir as FirCallableMemberDeclaration).modality != Modality.ABSTRACT
|
||||
} > 1 && simpleFunction.getContainingClass(context) === declaration
|
||||
if (simpleFunction.getContainingClass(context) === declaration &&
|
||||
namedFunctionSymbol.subjectToManyNotImplemented()
|
||||
) {
|
||||
notImplementedIntersectionSymbols += namedFunctionSymbol
|
||||
return@processFunctionsByName
|
||||
@@ -99,9 +145,8 @@ object FirNotImplementedOverrideChecker : FirClassChecker() {
|
||||
classScope.processPropertiesByName(name) { propertySymbol ->
|
||||
val property = propertySymbol.fir as? FirProperty ?: return@processPropertiesByName
|
||||
if (propertySymbol is FirIntersectionOverridePropertySymbol) {
|
||||
if (propertySymbol.intersections.count {
|
||||
(it.fir as FirCallableMemberDeclaration).modality != Modality.ABSTRACT
|
||||
} > 1 && property.getContainingClass(context) === declaration
|
||||
if (property.getContainingClass(context) === declaration &&
|
||||
propertySymbol.subjectToManyNotImplemented()
|
||||
) {
|
||||
notImplementedIntersectionSymbols += propertySymbol
|
||||
return@processPropertiesByName
|
||||
|
||||
+3
@@ -1,3 +1,6 @@
|
||||
// IGNORE_BACKEND_FIR: JVM_IR
|
||||
|
||||
// Note: this test will fail in Kotlin 1.6 (see AbstractClassMemberNotImplementedWithIntermediateAbstractClass feature)
|
||||
interface A {
|
||||
fun foo(): Any
|
||||
}
|
||||
|
||||
@@ -1,3 +1,6 @@
|
||||
// IGNORE_BACKEND_FIR: JVM_IR
|
||||
|
||||
// Note: this test will fail in Kotlin 1.6 (see AbstractClassMemberNotImplementedWithIntermediateAbstractClass feature)
|
||||
// FILE: 1.kt
|
||||
class Test: Impl(), CProvider
|
||||
|
||||
|
||||
Vendored
+4
-4
@@ -8,11 +8,11 @@ interface IRight {
|
||||
fun foo() {}
|
||||
}
|
||||
|
||||
class CDerived : ALeft(), IRight
|
||||
<!ABSTRACT_CLASS_MEMBER_NOT_IMPLEMENTED!>class CDerived<!> : ALeft(), IRight
|
||||
|
||||
abstract class CAbstract : ALeft(), IRight
|
||||
|
||||
class CDerivedFromAbstract : CAbstract()
|
||||
<!ABSTRACT_CLASS_MEMBER_NOT_IMPLEMENTED!>class CDerivedFromAbstract<!> : CAbstract()
|
||||
|
||||
interface ILeft {
|
||||
fun foo()
|
||||
@@ -21,10 +21,10 @@ interface ILeft {
|
||||
abstract class AILeft : ILeft
|
||||
|
||||
// Should be ERROR
|
||||
class AILeftImpl : AILeft(), IRight
|
||||
<!MANY_INTERFACES_MEMBER_NOT_IMPLEMENTED!>class AILeftImpl<!> : AILeft(), IRight
|
||||
|
||||
// Should be ERROR
|
||||
class RightLeft : ILeft, IRight
|
||||
<!MANY_INTERFACES_MEMBER_NOT_IMPLEMENTED!>class RightLeft<!> : ILeft, IRight
|
||||
|
||||
interface IBase {
|
||||
fun foo()
|
||||
|
||||
Vendored
+4
-4
@@ -8,11 +8,11 @@ interface IRight {
|
||||
fun foo() {}
|
||||
}
|
||||
|
||||
class CDerived : ALeft(), IRight
|
||||
<!ABSTRACT_CLASS_MEMBER_NOT_IMPLEMENTED!>class CDerived<!> : ALeft(), IRight
|
||||
|
||||
abstract class CAbstract : ALeft(), IRight
|
||||
|
||||
class CDerivedFromAbstract : CAbstract()
|
||||
<!ABSTRACT_CLASS_MEMBER_NOT_IMPLEMENTED!>class CDerivedFromAbstract<!> : CAbstract()
|
||||
|
||||
interface ILeft {
|
||||
fun foo()
|
||||
@@ -21,10 +21,10 @@ interface ILeft {
|
||||
abstract class AILeft : ILeft
|
||||
|
||||
// Should be ERROR
|
||||
class AILeftImpl : AILeft(), IRight
|
||||
<!MANY_INTERFACES_MEMBER_NOT_IMPLEMENTED!>class AILeftImpl<!> : AILeft(), IRight
|
||||
|
||||
// Should be ERROR
|
||||
class RightLeft : ILeft, IRight
|
||||
<!MANY_INTERFACES_MEMBER_NOT_IMPLEMENTED!>class RightLeft<!> : ILeft, IRight
|
||||
|
||||
interface IBase {
|
||||
fun foo()
|
||||
|
||||
+1
-1
@@ -8,6 +8,6 @@ interface IRight {
|
||||
|
||||
interface IDerived : ILeft, IRight
|
||||
|
||||
class CDerived : ILeft, IRight
|
||||
<!MANY_INTERFACES_MEMBER_NOT_IMPLEMENTED!>class CDerived<!> : ILeft, IRight
|
||||
|
||||
abstract class ADerived : ILeft, IRight
|
||||
@@ -8,11 +8,11 @@ interface B {
|
||||
|
||||
open class D: B
|
||||
|
||||
open class C: D(), A
|
||||
open <!MANY_INTERFACES_MEMBER_NOT_IMPLEMENTED!>class C<!>: D(), A
|
||||
|
||||
// ------------
|
||||
|
||||
class Test: Impl(), CProvider
|
||||
<!MANY_INTERFACES_MEMBER_NOT_IMPLEMENTED!>class Test<!>: Impl(), CProvider
|
||||
|
||||
open class CC
|
||||
|
||||
|
||||
@@ -1,18 +0,0 @@
|
||||
interface A {
|
||||
fun foo() {}
|
||||
}
|
||||
|
||||
interface B : A {
|
||||
abstract override fun foo()
|
||||
}
|
||||
|
||||
interface C : A {
|
||||
abstract override fun foo()
|
||||
}
|
||||
|
||||
interface D : A {
|
||||
override fun foo() = super.foo()
|
||||
}
|
||||
|
||||
// Fake override Z#foo should be open
|
||||
class Z : B, C, D
|
||||
@@ -1,3 +1,4 @@
|
||||
// FIR_IDENTICAL
|
||||
interface A {
|
||||
fun foo() {}
|
||||
}
|
||||
|
||||
Vendored
-13
@@ -1,13 +0,0 @@
|
||||
// FILE: JavaInterface.java
|
||||
|
||||
interface JavaInterface {
|
||||
void foo(int javaName);
|
||||
}
|
||||
|
||||
// FILE: kotlin.kt
|
||||
|
||||
interface KotlinTrait {
|
||||
public fun foo(someOtherName: Int) {}
|
||||
}
|
||||
|
||||
class BothTraitsSubclass : JavaInterface, KotlinTrait
|
||||
Vendored
+1
@@ -1,3 +1,4 @@
|
||||
// FIR_IDENTICAL
|
||||
// FILE: JavaInterface.java
|
||||
|
||||
interface JavaInterface {
|
||||
|
||||
Vendored
+1
-1
@@ -25,7 +25,7 @@ class D : B, A {
|
||||
}
|
||||
}
|
||||
|
||||
class E: B, A {
|
||||
<!MANY_INTERFACES_MEMBER_NOT_IMPLEMENTED!>class E<!>: B, A {
|
||||
fun foo() {
|
||||
super<B>.test()
|
||||
}
|
||||
|
||||
Vendored
+1
-1
@@ -24,7 +24,7 @@ class D : B, A {
|
||||
}
|
||||
}
|
||||
|
||||
class E: B, A {
|
||||
<!MANY_INTERFACES_MEMBER_NOT_IMPLEMENTED!>class E<!>: B, A {
|
||||
fun foo() {
|
||||
super<A>.test()
|
||||
}
|
||||
|
||||
+1
-1
@@ -4,7 +4,7 @@
|
||||
// FULL_JDK
|
||||
|
||||
// TESTCASE NUMBER: 1
|
||||
class Case1() : BaseCase1(), InterfaceCase1 {}
|
||||
<!ABSTRACT_CLASS_MEMBER_NOT_IMPLEMENTED!>class Case1<!>() : BaseCase1(), InterfaceCase1 {}
|
||||
|
||||
abstract class BaseCase1() {
|
||||
abstract fun foo(): String
|
||||
|
||||
Reference in New Issue
Block a user