From c3f3a4192c55f2eff957e5390c36f74b82e0e518 Mon Sep 17 00:00:00 2001 From: Dmitriy Novozhilov Date: Fri, 6 Oct 2023 12:44:07 +0300 Subject: [PATCH] [FIR] Check supertypes hierarchy for java classes during creation of synhtetic properies ^KT-62394 Fixed --- .../kotlin/fir/resolve/calls/Synthetics.kt | 58 +++++++++++++++++-- .../box/fir/syntheticPropertyThroughJava.kt | 2 - .../syntheticPropertyThroughJavaWithSetter.kt | 2 - .../javaProperties/Bases.fir.kt | 31 ++++++++++ .../javaProperties/Bases.kt | 1 - .../ir/irText/firProblems/kt43342.fir.ir.txt | 17 ++++-- .../ir/irText/firProblems/kt43342.fir.kt.txt | 4 -- 7 files changed, 95 insertions(+), 20 deletions(-) create mode 100644 compiler/testData/diagnostics/tests/syntheticExtensions/javaProperties/Bases.fir.kt diff --git a/compiler/fir/providers/src/org/jetbrains/kotlin/fir/resolve/calls/Synthetics.kt b/compiler/fir/providers/src/org/jetbrains/kotlin/fir/resolve/calls/Synthetics.kt index 0bbfa63df12..1944eb0153d 100644 --- a/compiler/fir/providers/src/org/jetbrains/kotlin/fir/resolve/calls/Synthetics.kt +++ b/compiler/fir/providers/src/org/jetbrains/kotlin/fir/resolve/calls/Synthetics.kt @@ -6,13 +6,12 @@ package org.jetbrains.kotlin.fir.resolve.calls import org.jetbrains.kotlin.fir.* -import org.jetbrains.kotlin.fir.declarations.FirDeclarationOrigin -import org.jetbrains.kotlin.fir.declarations.FirSimpleFunction -import org.jetbrains.kotlin.fir.declarations.getDeprecationsProviderFromAccessors -import org.jetbrains.kotlin.fir.declarations.isHiddenEverywhereBesideSuperCalls +import org.jetbrains.kotlin.fir.declarations.* import org.jetbrains.kotlin.fir.declarations.synthetic.FirSyntheticProperty import org.jetbrains.kotlin.fir.declarations.synthetic.buildSyntheticProperty import org.jetbrains.kotlin.fir.declarations.utils.isStatic +import org.jetbrains.kotlin.fir.resolve.lookupSuperTypes +import org.jetbrains.kotlin.fir.resolve.toSymbol import org.jetbrains.kotlin.fir.resolve.transformers.ReturnTypeCalculator import org.jetbrains.kotlin.fir.scopes.* import org.jetbrains.kotlin.fir.symbols.SyntheticSymbol @@ -248,7 +247,56 @@ class FirSyntheticPropertiesScope private constructor( ProcessorAction.NEXT } - + result = result || isJavaTypeOnThePath(this.dispatchReceiverType) return result && !isHiddenEverywhereBesideSuperCalls } + + /* + * We should check the whole hierarchy between dispatch receiver type of found getter and our dispatch receiver type, because + * synthetic properly should be created if there is a java class on this way (KT-62394) + * + * // FILE: Base.kt + * abstract class Base(private val x: String) { + * fun getFoo() = x + * } + * + * // FILE: Intermediate.java + * public class Intermediate extends Base { + * public Intermediate(String x) { + * super(x); + * } + * } + * + * // FILE: Final.kt + * class Final(x: String) : Intermediate(x) + * + * fun test(f: Final) { + * f.foo // <------- + * } + */ + private fun isJavaTypeOnThePath(baseType: ConeSimpleKotlinType?): Boolean { + val lookupTagToStop = (baseType as? ConeLookupTagBasedType)?.lookupTag ?: return false + val dispatchReceiverClass = (dispatchReceiverType as? ConeLookupTagBasedType)?.lookupTag?.toSymbol(session) ?: return false + + val typeContext = session.typeContext + fun checkType(type: ConeClassLikeType): Boolean { + val state = typeContext.newTypeCheckerState(errorTypesEqualToAnything = false, stubTypesEqualToAnything = false) + if (type.toRegularClassSymbol(session)?.isJavaOrEnhancement == true) { + if (AbstractTypeChecker.isSubtypeOfClass(state, type.lookupTag, lookupTagToStop)) { + return true + } + } + return false + } + + if (dispatchReceiverType is ConeClassLikeType && checkType(dispatchReceiverType)) { + return true + } + + val superTypes = lookupSuperTypes(dispatchReceiverClass, lookupInterfaces = true, deep = true, session) + for (superType in superTypes) { + if (checkType(superType)) return true + } + return false + } } diff --git a/compiler/testData/codegen/box/fir/syntheticPropertyThroughJava.kt b/compiler/testData/codegen/box/fir/syntheticPropertyThroughJava.kt index 4cbb2e4b9e1..211921b2520 100644 --- a/compiler/testData/codegen/box/fir/syntheticPropertyThroughJava.kt +++ b/compiler/testData/codegen/box/fir/syntheticPropertyThroughJava.kt @@ -1,7 +1,5 @@ // TARGET_BACKEND: JVM_IR // ISSUE: KT-59550 -// IGNORE_BACKEND_K2: ANY -// Ignore reason: KT-62393 and KT-62394 // FILE: Intermediate.java public class Intermediate extends Base { public Intermediate(String foo) { diff --git a/compiler/testData/codegen/box/fir/syntheticPropertyThroughJavaWithSetter.kt b/compiler/testData/codegen/box/fir/syntheticPropertyThroughJavaWithSetter.kt index 00309465f8d..4e6e0b0bc0d 100644 --- a/compiler/testData/codegen/box/fir/syntheticPropertyThroughJavaWithSetter.kt +++ b/compiler/testData/codegen/box/fir/syntheticPropertyThroughJavaWithSetter.kt @@ -1,7 +1,5 @@ // TARGET_BACKEND: JVM_IR // ISSUE: KT-59550 -// IGNORE_BACKEND_K2: ANY -// Ignore reason: KT-62393 and KT-62394 // FILE: Intermediate.java public class Intermediate extends Base { diff --git a/compiler/testData/diagnostics/tests/syntheticExtensions/javaProperties/Bases.fir.kt b/compiler/testData/diagnostics/tests/syntheticExtensions/javaProperties/Bases.fir.kt new file mode 100644 index 00000000000..d486307633e --- /dev/null +++ b/compiler/testData/diagnostics/tests/syntheticExtensions/javaProperties/Bases.fir.kt @@ -0,0 +1,31 @@ +// FILE: KotlinFile.kt +open class KotlinClass1 : JavaClass1() { + public fun getSomethingKotlin1(): Int = 1 +} + +class KotlinClass2 : JavaClass2() { + public fun getSomethingKotlin2(): Int = 1 +} + +fun foo(k: KotlinClass2) { + useInt(k.getSomething1()) + useInt(k.something1) + useInt(k.getSomething2()) + useInt(k.something2) + useInt(k.getSomethingKotlin1()) + useInt(k.getSomethingKotlin2()) + k.somethingKotlin1 + k.somethingKotlin2 +} + +fun useInt(i: Int) {} + +// FILE: JavaClass1.java +public class JavaClass1 { + public int getSomething1() { return 1; } +} + +// FILE: JavaClass2.java +public class JavaClass2 extends KotlinClass1 { + public int getSomething2() { return 1; } +} diff --git a/compiler/testData/diagnostics/tests/syntheticExtensions/javaProperties/Bases.kt b/compiler/testData/diagnostics/tests/syntheticExtensions/javaProperties/Bases.kt index 63b910a94f9..7371bbcfc79 100644 --- a/compiler/testData/diagnostics/tests/syntheticExtensions/javaProperties/Bases.kt +++ b/compiler/testData/diagnostics/tests/syntheticExtensions/javaProperties/Bases.kt @@ -1,4 +1,3 @@ -// FIR_IDENTICAL // FILE: KotlinFile.kt open class KotlinClass1 : JavaClass1() { public fun getSomethingKotlin1(): Int = 1 diff --git a/compiler/testData/ir/irText/firProblems/kt43342.fir.ir.txt b/compiler/testData/ir/irText/firProblems/kt43342.fir.ir.txt index 81485426f65..d6b7f90045a 100644 --- a/compiler/testData/ir/irText/firProblems/kt43342.fir.ir.txt +++ b/compiler/testData/ir/irText/firProblems/kt43342.fir.ir.txt @@ -113,6 +113,15 @@ FILE fqName: fileName:/kt43342.kt CALL 'public abstract fun (): kotlin.collections.Collection declared in kotlin.collections.Map' type=kotlin.collections.Collection origin=null $this: GET_FIELD 'FIELD PROPERTY_BACKING_FIELD name:map type:kotlin.collections.Map.ControlFlowInfo, V of .ControlFlowInfo> visibility:private [final]' type=kotlin.collections.Map.ControlFlowInfo, V of .ControlFlowInfo> origin=null receiver: GET_VAR ': .ControlFlowInfo.ControlFlowInfo, V of .ControlFlowInfo> declared in .ControlFlowInfo.' type=.ControlFlowInfo.ControlFlowInfo, V of .ControlFlowInfo> origin=null + FUN FAKE_OVERRIDE name:getOrDefault visibility:public modality:OPEN <> ($this:kotlin.collections.Map.ControlFlowInfo, V of .ControlFlowInfo>, key:K of .ControlFlowInfo, defaultValue:V of .ControlFlowInfo) returnType:V of .ControlFlowInfo [fake_override] + annotations: + SinceKotlin(version = '1.1') + PlatformDependent + overridden: + public open fun getOrDefault (key: K of kotlin.collections.Map, defaultValue: V of kotlin.collections.Map): V of kotlin.collections.Map declared in kotlin.collections.Map + $this: VALUE_PARAMETER name: type:kotlin.collections.Map.ControlFlowInfo, V of .ControlFlowInfo> + VALUE_PARAMETER name:key index:0 type:K of .ControlFlowInfo + VALUE_PARAMETER name:defaultValue index:1 type:V of .ControlFlowInfo FUN FAKE_OVERRIDE name:equals visibility:public modality:OPEN <> ($this:kotlin.Any, other:kotlin.Any?) returnType:kotlin.Boolean [fake_override,operator] overridden: public open fun equals (other: kotlin.Any?): kotlin.Boolean declared in kotlin.collections.Map @@ -126,10 +135,6 @@ FILE fqName: fileName:/kt43342.kt overridden: public open fun toString (): kotlin.String declared in kotlin.collections.Map $this: VALUE_PARAMETER name: type:kotlin.Any - FUN name:getOrDefault visibility:public modality:OPEN <> ($this:.ControlFlowInfo.ControlFlowInfo, V of .ControlFlowInfo>, key:K of .ControlFlowInfo, defaultValue:V of .ControlFlowInfo) returnType:V of .ControlFlowInfo - $this: VALUE_PARAMETER name: type:.ControlFlowInfo.ControlFlowInfo, V of .ControlFlowInfo> - VALUE_PARAMETER name:key index:0 type:K of .ControlFlowInfo - VALUE_PARAMETER name:defaultValue index:1 type:V of .ControlFlowInfo CLASS CLASS name:StringFlowInfo modality:FINAL visibility:public superTypes:[.ControlFlowInfo] $this: VALUE_PARAMETER INSTANCE_RECEIVER name: type:.StringFlowInfo CONSTRUCTOR visibility:public <> (map:kotlin.collections.Map) returnType:.StringFlowInfo [primary] @@ -173,13 +178,13 @@ FILE fqName: fileName:/kt43342.kt public open fun get (key: K of .ControlFlowInfo): V of .ControlFlowInfo? declared in .ControlFlowInfo $this: VALUE_PARAMETER name: type:.ControlFlowInfo VALUE_PARAMETER name:key index:0 type:kotlin.String - FUN FAKE_OVERRIDE name:getOrDefault visibility:public modality:OPEN <> ($this:.ControlFlowInfo, key:kotlin.String, defaultValue:kotlin.String) returnType:kotlin.String [fake_override] + FUN FAKE_OVERRIDE name:getOrDefault visibility:public modality:OPEN <> ($this:kotlin.collections.Map, key:kotlin.String, defaultValue:kotlin.String) returnType:kotlin.String [fake_override] annotations: SinceKotlin(version = '1.1') PlatformDependent overridden: public open fun getOrDefault (key: K of .ControlFlowInfo, defaultValue: V of .ControlFlowInfo): V of .ControlFlowInfo declared in .ControlFlowInfo - $this: VALUE_PARAMETER name: type:.ControlFlowInfo + $this: VALUE_PARAMETER name: type:kotlin.collections.Map VALUE_PARAMETER name:key index:0 type:kotlin.String VALUE_PARAMETER name:defaultValue index:1 type:kotlin.String FUN FAKE_OVERRIDE name:isEmpty visibility:public modality:OPEN <> ($this:.ControlFlowInfo) returnType:kotlin.Boolean [fake_override] diff --git a/compiler/testData/ir/irText/firProblems/kt43342.fir.kt.txt b/compiler/testData/ir/irText/firProblems/kt43342.fir.kt.txt index d116a480063..65a62c7531c 100644 --- a/compiler/testData/ir/irText/firProblems/kt43342.fir.kt.txt +++ b/compiler/testData/ir/irText/firProblems/kt43342.fir.kt.txt @@ -45,10 +45,6 @@ open class ControlFlowInfo : Map { return .#map.() } - val map: Map - field = map - get - } class StringFlowInfo : ControlFlowInfo {