FIR2IR: populate overriddenSymbols for overriding properties

This commit is contained in:
Jinseong Jeon
2020-04-29 08:21:43 -07:00
committed by Mikhail Glukhikh
parent 02aa11a0a0
commit a084c5bf7d
46 changed files with 112 additions and 59 deletions
@@ -304,18 +304,50 @@ private fun IrClass.findMatchingOverriddenSymbolsFromThisAndSupertypes(
target: IrDeclaration,
result: MutableList<IrSymbol>
): List<IrSymbol> {
val targetIsPropertyAccessor = target is IrFunction && target.isPropertyAccessor
for (declaration in declarations) {
if (declaration.isFakeOverride || declaration is IrConstructor) {
continue
}
when {
declaration is IrFunction && target is IrFunction ->
if (declaration !is IrConstructor &&
!declaration.isFakeOverride &&
declaration.descriptor.modality != Modality.FINAL &&
if (declaration.descriptor.modality != Modality.FINAL &&
!Visibilities.isPrivate(declaration.visibility) &&
isOverriding(irBuiltIns, target, declaration)
) {
result.add(declaration.symbol)
}
// TODO: property lookup to set overriddenSymbols for IrProperty (and accessors)?
declaration is IrProperty && (target is IrField || targetIsPropertyAccessor) -> {
val backingField = declaration.backingField
if (target is IrField && backingField != null) {
if (!backingField.isFinal && !backingField.isStatic &&
!Visibilities.isPrivate(backingField.visibility) &&
isOverriding(irBuiltIns, target, backingField)
) {
result.add(backingField.symbol)
}
}
if (targetIsPropertyAccessor) {
val getter = declaration.getter
if (getter != null) {
if (getter.descriptor.modality != Modality.FINAL &&
!Visibilities.isPrivate(getter.visibility) &&
isOverriding(irBuiltIns, target, getter)
) {
result.add(getter.symbol)
}
}
val setter = declaration.setter
if (setter != null) {
if (setter.descriptor.modality != Modality.FINAL &&
!Visibilities.isPrivate(setter.visibility) &&
isOverriding(irBuiltIns, target, setter)
) {
result.add(setter.symbol)
}
}
}
}
}
}
// Stop traversing upwards if we find matching overridden symbols at this level.
@@ -327,8 +359,8 @@ private fun IrClass.findMatchingOverriddenSymbolsFromThisAndSupertypes(
fun isOverriding(
irBuiltIns: IrBuiltIns,
target: IrFunction,
superCandidate: IrFunction
target: IrDeclaration,
superCandidate: IrDeclaration
): Boolean {
val typeCheckerContext = IrTypeCheckerContext(irBuiltIns) as AbstractTypeCheckerContext
fun equalTypes(first: IrType, second: IrType): Boolean {
@@ -340,16 +372,25 @@ fun isOverriding(
}
return target.name == superCandidate.name &&
return when {
target is IrFunction && superCandidate is IrFunction -> {
// Not checking the return type (they should match each other if everything other match, otherwise it's a compilation error)
target.extensionReceiverParameter?.type?.let {
val superCandidateReceiverType = superCandidate.extensionReceiverParameter?.type
superCandidateReceiverType != null && equalTypes(it, superCandidateReceiverType)
} != false &&
target.valueParameters.size == superCandidate.valueParameters.size &&
target.valueParameters.zip(superCandidate.valueParameters).all { (targetParameter, superCandidateParameter) ->
equalTypes(targetParameter.type, superCandidateParameter.type)
}
target.name == superCandidate.name &&
target.extensionReceiverParameter?.type?.let {
val superCandidateReceiverType = superCandidate.extensionReceiverParameter?.type
superCandidateReceiverType != null && equalTypes(it, superCandidateReceiverType)
} != false &&
target.valueParameters.size == superCandidate.valueParameters.size &&
target.valueParameters.zip(superCandidate.valueParameters).all { (targetParameter, superCandidateParameter) ->
equalTypes(targetParameter.type, superCandidateParameter.type)
}
}
target is IrField && superCandidate is IrField -> {
// Not checking the field type (they should match each other if everything other match, otherwise it's a compilation error)
target.name == superCandidate.name
}
else -> false
}
}
private val nameToOperationConventionOrigin = mutableMapOf(
@@ -10,8 +10,10 @@ import org.jetbrains.kotlin.builtins.KotlinBuiltIns.*
import org.jetbrains.kotlin.descriptors.*
import org.jetbrains.kotlin.descriptors.annotations.Annotations
import org.jetbrains.kotlin.fir.declarations.*
import org.jetbrains.kotlin.fir.declarations.impl.FirDefaultPropertyAccessor
import org.jetbrains.kotlin.fir.declarations.impl.FirDefaultPropertyGetter
import org.jetbrains.kotlin.fir.declarations.impl.FirDefaultPropertySetter
import org.jetbrains.kotlin.fir.declarations.impl.FirPropertyAccessorImpl
import org.jetbrains.kotlin.fir.descriptors.FirBuiltInsPackageFragment
import org.jetbrains.kotlin.fir.descriptors.FirModuleDescriptor
import org.jetbrains.kotlin.fir.descriptors.FirPackageFragmentDescriptor
@@ -454,11 +456,7 @@ class Fir2IrDeclarationStorage(
}
}
if (!created.isFakeOverride && simpleFunction?.isOverride == true && thisReceiverOwner != null) {
thisReceiverOwner.findMatchingOverriddenSymbolsFromSupertypes(components.irBuiltIns, created).forEach {
if (it is IrSimpleFunctionSymbol) {
created.overriddenSymbols += it
}
}
created.populateOverriddenSymbols(thisReceiverOwner)
}
functionCache[function] = created
return created
@@ -575,6 +573,14 @@ class Fir2IrDeclarationStorage(
parent = irParent
}
correspondingPropertySymbol = correspondingProperty.symbol
val isOverride = when (propertyAccessor) {
is FirDefaultPropertyAccessor -> property.isOverride
is FirPropertyAccessorImpl -> propertyAccessor.status.isOverride
else -> false
}
if (!isFakeOverride && isOverride && thisReceiverOwner != null) {
populateOverriddenSymbols(thisReceiverOwner)
}
}
}
}
@@ -587,6 +593,7 @@ class Fir2IrDeclarationStorage(
name: Name,
isFinal: Boolean,
firInitializerExpression: FirExpression?,
thisReceiverOwner: IrClass?,
type: IrType? = null
): IrField {
val inferredType = type ?: firInitializerExpression!!.typeRef.toIrType()
@@ -601,6 +608,9 @@ class Fir2IrDeclarationStorage(
isFakeOverride = origin == IrDeclarationOrigin.FAKE_OVERRIDE
).also {
it.correspondingPropertySymbol = this@createBackingField.symbol
if (!isFakeOverride && property.isOverride && thisReceiverOwner != null) {
it.populateOverriddenSymbols(thisReceiverOwner)
}
}
}
}
@@ -656,7 +666,8 @@ class Fir2IrDeclarationStorage(
) {
backingField = createBackingField(
property, IrDeclarationOrigin.PROPERTY_BACKING_FIELD, descriptor,
property.fieldVisibility, property.name, property.isVal, initializer, type
property.fieldVisibility, property.name, property.isVal, initializer,
thisReceiverOwner, type
).also { field ->
if (initializer is FirConstExpression<*>) {
// TODO: Normally we shouldn't have error type here
@@ -667,7 +678,8 @@ class Fir2IrDeclarationStorage(
} else if (delegate != null) {
backingField = createBackingField(
property, IrDeclarationOrigin.PROPERTY_DELEGATE, descriptor,
property.fieldVisibility, Name.identifier("${property.name}\$delegate"), true, delegate
property.fieldVisibility, Name.identifier("${property.name}\$delegate"), true, delegate,
thisReceiverOwner
)
}
if (irParent != null) {
@@ -926,6 +938,21 @@ class Fir2IrDeclarationStorage(
}
}
private fun IrSimpleFunction.populateOverriddenSymbols(thisReceiverOwner: IrClass) {
thisReceiverOwner.findMatchingOverriddenSymbolsFromSupertypes(components.irBuiltIns, this).forEach {
if (it is IrSimpleFunctionSymbol) {
overriddenSymbols += it
}
}
}
private fun IrField.populateOverriddenSymbols(thisReceiverOwner: IrClass) {
thisReceiverOwner.findMatchingOverriddenSymbolsFromSupertypes(components.irBuiltIns, this)
.filterIsInstance<IrFieldSymbol>().singleOrNull()?.let {
overriddenSymbols = listOf(it)
}
}
companion object {
internal val ENUM_SYNTHETIC_NAMES = mapOf(
Name.identifier("values") to IrSyntheticBodyKind.ENUM_VALUES,
-1
View File
@@ -1,4 +1,3 @@
// IGNORE_BACKEND_FIR: JVM_IR
package test
public interface FunDependencyEdge {
@@ -1,4 +1,3 @@
// IGNORE_BACKEND_FIR: JVM_IR
interface A<O, K> {
val o: O
val k: K
@@ -1,4 +1,3 @@
// IGNORE_BACKEND_FIR: JVM_IR
interface A<T> {
var x: T
}
@@ -1,4 +1,3 @@
// IGNORE_BACKEND_FIR: JVM_IR
interface A<T> {
var v: T
}
@@ -1,4 +1,3 @@
// IGNORE_BACKEND_FIR: JVM_IR
open class A<T>(val t: T) {
open val foo: T = t
}
-1
View File
@@ -1,4 +1,3 @@
// IGNORE_BACKEND_FIR: JVM_IR
// KJS_WITH_FULL_RUNTIME
// WITH_RUNTIME
// WITH_COROUTINES
@@ -1,4 +1,3 @@
// IGNORE_BACKEND_FIR: JVM_IR
// WITH_RUNTIME
// WITH_COROUTINES
// COMMON_COROUTINES_TEST
@@ -1,4 +1,3 @@
// IGNORE_BACKEND_FIR: JVM_IR
// WITH_RUNTIME
// WITH_COROUTINES
// COMMON_COROUTINES_TEST
@@ -1,4 +1,3 @@
// IGNORE_BACKEND_FIR: JVM_IR
// WITH_RUNTIME
// WITH_COROUTINES
// COMMON_COROUTINES_TEST
@@ -1,4 +1,3 @@
// IGNORE_BACKEND_FIR: JVM_IR
// WITH_RUNTIME
// WITH_COROUTINES
// COMMON_COROUTINES_TEST
@@ -1,4 +1,3 @@
// IGNORE_BACKEND_FIR: JVM_IR
// WITH_RUNTIME
// WITH_COROUTINES
// COMMON_COROUTINES_TEST
@@ -1,4 +1,3 @@
// IGNORE_BACKEND_FIR: JVM_IR
// WITH_RUNTIME
// WITH_COROUTINES
@@ -1,4 +1,3 @@
// IGNORE_BACKEND_FIR: JVM_IR
// WITH_RUNTIME
// WITH_COROUTINES
// COMMON_COROUTINES_TEST
@@ -1,4 +1,3 @@
// IGNORE_BACKEND_FIR: JVM_IR
// WITH_RUNTIME
// WITH_COROUTINES
// COMMON_COROUTINES_TEST
@@ -1,4 +1,3 @@
// IGNORE_BACKEND_FIR: JVM_IR
// WITH_RUNTIME
// WITH_COROUTINES
// COMMON_COROUTINES_TEST
@@ -1,4 +1,3 @@
// IGNORE_BACKEND_FIR: JVM_IR
// KJS_WITH_FULL_RUNTIME
// WITH_RUNTIME
// WITH_COROUTINES
-1
View File
@@ -1,4 +1,3 @@
// IGNORE_BACKEND_FIR: JVM_IR
// WITH_RUNTIME
// WITH_COROUTINES
// COMMON_COROUTINES_TEST
@@ -1,4 +1,3 @@
// IGNORE_BACKEND_FIR: JVM_IR
// WITH_RUNTIME
// WITH_COROUTINES
// COMMON_COROUTINES_TEST
@@ -1,4 +1,3 @@
// IGNORE_BACKEND_FIR: JVM_IR
// WITH_RUNTIME
// WITH_COROUTINES
// COMMON_COROUTINES_TEST
@@ -1,4 +1,3 @@
// IGNORE_BACKEND_FIR: JVM_IR
// WITH_RUNTIME
// WITH_COROUTINES
// COMMON_COROUTINES_TEST
@@ -1,4 +1,3 @@
// IGNORE_BACKEND_FIR: JVM_IR
// WITH_COROUTINES
// WITH_RUNTIME
// COMMON_COROUTINES_TEST
@@ -1,4 +1,3 @@
// IGNORE_BACKEND_FIR: JVM_IR
// WITH_COROUTINES
// WITH_RUNTIME
// COMMON_COROUTINES_TEST
@@ -1,4 +1,3 @@
// IGNORE_BACKEND_FIR: JVM_IR
// WITH_COROUTINES
// WITH_RUNTIME
// COMMON_COROUTINES_TEST
@@ -1,4 +1,3 @@
// IGNORE_BACKEND_FIR: JVM_IR
// IGNORE_BACKEND: NATIVE
// WITH_COROUTINES
// WITH_RUNTIME
@@ -1,4 +1,3 @@
// IGNORE_BACKEND_FIR: JVM_IR
// WITH_RUNTIME
// WITH_COROUTINES
// COMMON_COROUTINES_TEST
@@ -1,4 +1,3 @@
// IGNORE_BACKEND_FIR: JVM_IR
// WITH_RUNTIME
// WITH_COROUTINES
// COMMON_COROUTINES_TEST
@@ -1,4 +1,3 @@
// IGNORE_BACKEND_FIR: JVM_IR
// WITH_RUNTIME
// WITH_COROUTINES
// COMMON_COROUTINES_TEST
@@ -1,4 +1,3 @@
// IGNORE_BACKEND_FIR: JVM_IR
// WITH_RUNTIME
// WITH_COROUTINES
// COMMON_COROUTINES_TEST
@@ -1,4 +1,3 @@
// IGNORE_BACKEND_FIR: JVM_IR
// WITH_RUNTIME
// WITH_COROUTINES
// COMMON_COROUTINES_TEST
@@ -1,4 +1,3 @@
// IGNORE_BACKEND_FIR: JVM_IR
// TARGET_BACKEND: JVM
// WITH_RUNTIME
// WITH_COROUTINES
@@ -1,4 +1,3 @@
// IGNORE_BACKEND_FIR: JVM_IR
// KJS_WITH_FULL_RUNTIME
// WITH_RUNTIME
// WITH_COROUTINES
@@ -1,4 +1,3 @@
// IGNORE_BACKEND_FIR: JVM_IR
// KJS_WITH_FULL_RUNTIME
// WITH_RUNTIME
// WITH_COROUTINES
@@ -1,4 +1,3 @@
// IGNORE_BACKEND_FIR: JVM_IR
// WITH_RUNTIME
// WITH_COROUTINES
// COMMON_COROUTINES_TEST
@@ -1,4 +1,3 @@
// IGNORE_BACKEND_FIR: JVM_IR
open class A {
internal open val field = "AF"
@@ -1,3 +1,4 @@
// IGNORE_BACKEND_FIR: JVM_IR
open class A {
internal open val field = "F"
@@ -1,4 +1,3 @@
// IGNORE_BACKEND_FIR: JVM_IR
open class A {
internal open val field = "AF"
@@ -1,3 +1,4 @@
// IGNORE_BACKEND_FIR: JVM_IR
open class A {
internal open val field = "F"
@@ -1,4 +1,3 @@
// IGNORE_BACKEND_FIR: JVM_IR
// KJS_WITH_FULL_RUNTIME
// WITH_RUNTIME
import kotlin.test.*
@@ -1,4 +1,3 @@
// IGNORE_BACKEND_FIR: JVM_IR
// KJS_WITH_FULL_RUNTIME
// WITH_RUNTIME
import kotlin.test.*
@@ -122,6 +122,8 @@ FILE fqName:<root> fileName:/delegatedImplementation.kt
GET_VAR 'x0: kotlin.String declared in <root>.otherImpl' type=kotlin.String origin=null
FUN DEFAULT_PROPERTY_ACCESSOR name:<get-x> visibility:public modality:FINAL <> ($this:<root>.otherImpl.<no name provided>) returnType:kotlin.String
correspondingProperty: PROPERTY name:x visibility:public modality:FINAL [val]
overridden:
public abstract fun <get-x> (): kotlin.String declared in <root>.IOther
$this: VALUE_PARAMETER name:<this> type:<root>.otherImpl.<no name provided>
BLOCK_BODY
RETURN type=kotlin.Nothing from='public final fun <get-x> (): kotlin.String declared in <root>.otherImpl.<no name provided>'
@@ -133,6 +135,8 @@ FILE fqName:<root> fileName:/delegatedImplementation.kt
GET_VAR 'y0: kotlin.Int declared in <root>.otherImpl' type=kotlin.Int origin=null
FUN DEFAULT_PROPERTY_ACCESSOR name:<get-y> visibility:public modality:FINAL <> ($this:<root>.otherImpl.<no name provided>) returnType:kotlin.Int
correspondingProperty: PROPERTY name:y visibility:public modality:FINAL [var]
overridden:
public abstract fun <get-y> (): kotlin.Int declared in <root>.IOther
$this: VALUE_PARAMETER name:<this> type:<root>.otherImpl.<no name provided>
BLOCK_BODY
RETURN type=kotlin.Nothing from='public final fun <get-y> (): kotlin.Int declared in <root>.otherImpl.<no name provided>'
@@ -140,6 +144,8 @@ FILE fqName:<root> fileName:/delegatedImplementation.kt
receiver: GET_VAR '<this>: <root>.otherImpl.<no name provided> declared in <root>.otherImpl.<no name provided>.<get-y>' type=<root>.otherImpl.<no name provided> origin=null
FUN DEFAULT_PROPERTY_ACCESSOR name:<set-y> visibility:public modality:FINAL <> ($this:<root>.otherImpl.<no name provided>, <set-?>:kotlin.Int) returnType:kotlin.Unit
correspondingProperty: PROPERTY name:y visibility:public modality:FINAL [var]
overridden:
public abstract fun <set-y> (<set-?>: kotlin.Int): kotlin.Unit declared in <root>.IOther
$this: VALUE_PARAMETER name:<this> type:<root>.otherImpl.<no name provided>
VALUE_PARAMETER name:<set-?> index:0 type:kotlin.Int
BLOCK_BODY
@@ -73,6 +73,8 @@ FILE fqName:<root> fileName:/fakeOverrides.kt
CONST Int type=kotlin.Int value=42
FUN DEFAULT_PROPERTY_ACCESSOR name:<get-bar> visibility:public modality:FINAL <> ($this:<root>.Test1) returnType:kotlin.Int
correspondingProperty: PROPERTY name:bar visibility:public modality:FINAL [val]
overridden:
public abstract fun <get-bar> (): kotlin.Int declared in <root>.IBar
$this: VALUE_PARAMETER name:<this> type:<root>.Test1
BLOCK_BODY
RETURN type=kotlin.Nothing from='public final fun <get-bar> (): kotlin.Int declared in <root>.Test1'
@@ -51,6 +51,8 @@ FILE fqName:<root> fileName:/localClassWithOverrides.kt
CONST Int type=kotlin.Int value=1
FUN DEFAULT_PROPERTY_ACCESSOR name:<get-aval> visibility:public modality:FINAL <> ($this:<root>.outer.Local) returnType:kotlin.Int
correspondingProperty: PROPERTY name:aval visibility:public modality:FINAL [val]
overridden:
public abstract fun <get-aval> (): kotlin.Int declared in <root>.outer.ALocal
$this: VALUE_PARAMETER name:<this> type:<root>.outer.Local
BLOCK_BODY
RETURN type=kotlin.Nothing from='public final fun <get-aval> (): kotlin.Int declared in <root>.outer.Local'
@@ -62,6 +64,8 @@ FILE fqName:<root> fileName:/localClassWithOverrides.kt
CONST Int type=kotlin.Int value=2
FUN DEFAULT_PROPERTY_ACCESSOR name:<get-avar> visibility:public modality:FINAL <> ($this:<root>.outer.Local) returnType:kotlin.Int
correspondingProperty: PROPERTY name:avar visibility:public modality:FINAL [var]
overridden:
public abstract fun <get-avar> (): kotlin.Int declared in <root>.outer.ALocal
$this: VALUE_PARAMETER name:<this> type:<root>.outer.Local
BLOCK_BODY
RETURN type=kotlin.Nothing from='public final fun <get-avar> (): kotlin.Int declared in <root>.outer.Local'
@@ -69,6 +73,8 @@ FILE fqName:<root> fileName:/localClassWithOverrides.kt
receiver: GET_VAR '<this>: <root>.outer.Local declared in <root>.outer.Local.<get-avar>' type=<root>.outer.Local origin=null
FUN DEFAULT_PROPERTY_ACCESSOR name:<set-avar> visibility:public modality:FINAL <> ($this:<root>.outer.Local, <set-?>:kotlin.Int) returnType:kotlin.Unit
correspondingProperty: PROPERTY name:avar visibility:public modality:FINAL [var]
overridden:
public abstract fun <set-avar> (<set-?>: kotlin.Int): kotlin.Unit declared in <root>.outer.ALocal
$this: VALUE_PARAMETER name:<this> type:<root>.outer.Local
VALUE_PARAMETER name:<set-?> index:0 type:kotlin.Int
BLOCK_BODY
@@ -37,6 +37,8 @@ FILE fqName:<root> fileName:/enumEntryAsReceiver.kt
$this: GET_VAR '<this>: <root>.X.B declared in <root>.X.B' type=<root>.X.B origin=null
FUN DEFAULT_PROPERTY_ACCESSOR name:<get-value> visibility:public modality:FINAL <> ($this:<root>.X.B) returnType:kotlin.Function0<kotlin.String>
correspondingProperty: PROPERTY name:value visibility:public modality:FINAL [val]
overridden:
public abstract fun <get-value> (): kotlin.Function0<kotlin.String> declared in <root>.X
$this: VALUE_PARAMETER name:<this> type:<root>.X.B
BLOCK_BODY
RETURN type=kotlin.Nothing from='public final fun <get-value> (): kotlin.Function0<kotlin.String> declared in <root>.X.B'
@@ -25,6 +25,8 @@ FILE fqName:<root> fileName:/genericClassInDifferentModule_m2.kt
GET_VAR 'x: T of <root>.Derived1 declared in <root>.Derived1.<init>' type=T of <root>.Derived1 origin=null
FUN DEFAULT_PROPERTY_ACCESSOR name:<get-bar> visibility:public modality:FINAL <> ($this:<root>.Derived1<T of <root>.Derived1>) returnType:T of <root>.Derived1
correspondingProperty: PROPERTY name:bar visibility:public modality:FINAL [var]
overridden:
public abstract fun <get-bar> (): T of <root>.Base declared in <root>.Base
$this: VALUE_PARAMETER name:<this> type:<root>.Derived1<T of <root>.Derived1>
BLOCK_BODY
RETURN type=kotlin.Nothing from='public final fun <get-bar> (): T of <root>.Derived1 declared in <root>.Derived1'
@@ -32,6 +34,8 @@ FILE fqName:<root> fileName:/genericClassInDifferentModule_m2.kt
receiver: GET_VAR '<this>: <root>.Derived1<T of <root>.Derived1> declared in <root>.Derived1.<get-bar>' type=<root>.Derived1<T of <root>.Derived1> origin=null
FUN DEFAULT_PROPERTY_ACCESSOR name:<set-bar> visibility:public modality:FINAL <> ($this:<root>.Derived1<T of <root>.Derived1>, <set-?>:T of <root>.Derived1) returnType:kotlin.Unit
correspondingProperty: PROPERTY name:bar visibility:public modality:FINAL [var]
overridden:
public abstract fun <set-bar> (<set-?>: T of <root>.Base): kotlin.Unit declared in <root>.Base
$this: VALUE_PARAMETER name:<this> type:<root>.Derived1<T of <root>.Derived1>
VALUE_PARAMETER name:<set-?> index:0 type:T of <root>.Derived1
BLOCK_BODY