[FIR] Consider overridden getter for setter function for synthetic property
^KT-54662 Fixed
This commit is contained in:
committed by
Space Team
parent
1927369ae9
commit
b7da00744b
@@ -14,7 +14,6 @@ import org.jetbrains.kotlin.fir.scopes.*
|
|||||||
import org.jetbrains.kotlin.fir.symbols.SyntheticSymbol
|
import org.jetbrains.kotlin.fir.symbols.SyntheticSymbol
|
||||||
import org.jetbrains.kotlin.fir.symbols.impl.*
|
import org.jetbrains.kotlin.fir.symbols.impl.*
|
||||||
import org.jetbrains.kotlin.fir.types.*
|
import org.jetbrains.kotlin.fir.types.*
|
||||||
import org.jetbrains.kotlin.fir.types.ConeNullability.NOT_NULL
|
|
||||||
import org.jetbrains.kotlin.name.CallableId
|
import org.jetbrains.kotlin.name.CallableId
|
||||||
import org.jetbrains.kotlin.name.Name
|
import org.jetbrains.kotlin.name.Name
|
||||||
import org.jetbrains.kotlin.name.StandardClassIds
|
import org.jetbrains.kotlin.name.StandardClassIds
|
||||||
@@ -96,11 +95,10 @@ class FirSyntheticPropertiesScope private constructor(
|
|||||||
private fun checkGetAndCreateSynthetic(
|
private fun checkGetAndCreateSynthetic(
|
||||||
propertyName: Name,
|
propertyName: Name,
|
||||||
getterName: Name,
|
getterName: Name,
|
||||||
getterSymbol: FirFunctionSymbol<*>,
|
getterSymbol: FirNamedFunctionSymbol,
|
||||||
needCheckForSetter: Boolean,
|
needCheckForSetter: Boolean,
|
||||||
processor: (FirVariableSymbol<*>) -> Unit
|
processor: (FirVariableSymbol<*>) -> Unit
|
||||||
) {
|
) {
|
||||||
if (getterSymbol !is FirNamedFunctionSymbol) return
|
|
||||||
val getter = getterSymbol.fir
|
val getter = getterSymbol.fir
|
||||||
|
|
||||||
if (getter.typeParameters.isNotEmpty()) return
|
if (getter.typeParameters.isNotEmpty()) return
|
||||||
@@ -116,28 +114,14 @@ class FirSyntheticPropertiesScope private constructor(
|
|||||||
val setterName = syntheticNamesProvider.setterNameByGetterName(getterName)
|
val setterName = syntheticNamesProvider.setterNameByGetterName(getterName)
|
||||||
baseScope.processFunctionsByName(setterName, fun(setterSymbol: FirNamedFunctionSymbol) {
|
baseScope.processFunctionsByName(setterName, fun(setterSymbol: FirNamedFunctionSymbol) {
|
||||||
if (matchingSetter != null) return
|
if (matchingSetter != null) return
|
||||||
|
|
||||||
val setter = setterSymbol.fir
|
val setter = setterSymbol.fir
|
||||||
val parameter = setter.valueParameters.singleOrNull() ?: return
|
val parameter = setter.valueParameters.singleOrNull() ?: return
|
||||||
if (setter.typeParameters.isNotEmpty() || setter.isStatic) return
|
if (setter.typeParameters.isNotEmpty() || setter.isStatic) return
|
||||||
val parameterType = (parameter.returnTypeRef as? FirResolvedTypeRef)?.type ?: return
|
val parameterType = (parameter.returnTypeRef as? FirResolvedTypeRef)?.type ?: return
|
||||||
// TODO: at this moment it works for cases like
|
|
||||||
// class Base {
|
if (!setterTypeIsConsistentWithGetterType(getterSymbol, parameterType, baseScope)) return
|
||||||
// void setSomething(Object value) {}
|
matchingSetter = setterSymbol.fir
|
||||||
// }
|
|
||||||
// class Derived extends Base {
|
|
||||||
// String getSomething() { return ""; }
|
|
||||||
// }
|
|
||||||
// In FE 1.0, we should have also Object getSomething() in class Base for this to work
|
|
||||||
// I think details here are worth designing
|
|
||||||
if (!AbstractTypeChecker.isSubtypeOf(
|
|
||||||
session.typeContext,
|
|
||||||
getterReturnType.withNullability(NOT_NULL, session.typeContext),
|
|
||||||
parameterType.withNullability(NOT_NULL, session.typeContext)
|
|
||||||
)
|
|
||||||
) {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
matchingSetter = setter
|
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -165,6 +149,24 @@ class FirSyntheticPropertiesScope private constructor(
|
|||||||
processor(syntheticSymbol)
|
processor(syntheticSymbol)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private fun setterTypeIsConsistentWithGetterType(
|
||||||
|
getterSymbol: FirNamedFunctionSymbol,
|
||||||
|
parameterType: ConeKotlinType,
|
||||||
|
scopeOfGetter: FirTypeScope
|
||||||
|
): Boolean {
|
||||||
|
val getterReturnType = getterSymbol.resolvedReturnTypeRef.type
|
||||||
|
if (AbstractTypeChecker.equalTypes(session.typeContext, getterReturnType, parameterType)) return true
|
||||||
|
if (!AbstractTypeChecker.isSubtypeOf(session.typeContext, getterReturnType, parameterType)) return false
|
||||||
|
/*
|
||||||
|
* Here we search for some getter in overrides hierarchy which type is consistent with type of setter
|
||||||
|
*/
|
||||||
|
for ((overriddenGetter, scope) in scopeOfGetter.getDirectOverriddenFunctionsWithBaseScope(getterSymbol)) {
|
||||||
|
val foundGoodOverride = setterTypeIsConsistentWithGetterType(overriddenGetter, parameterType, scope)
|
||||||
|
if (foundGoodOverride) return true
|
||||||
|
}
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
private fun FirNamedFunctionSymbol.hasJavaOverridden(): Boolean {
|
private fun FirNamedFunctionSymbol.hasJavaOverridden(): Boolean {
|
||||||
var result = false
|
var result = false
|
||||||
baseScope.processOverriddenFunctionsAndSelf(this) {
|
baseScope.processOverriddenFunctionsAndSelf(this) {
|
||||||
|
|||||||
-20
@@ -1,20 +0,0 @@
|
|||||||
// WITH_STDLIB
|
|
||||||
// ISSUE: KT-54662
|
|
||||||
|
|
||||||
// FILE: Base.java
|
|
||||||
import java.util.Set;
|
|
||||||
|
|
||||||
public class Base {
|
|
||||||
public Set<Object> getDependsOn() {
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void setDependsOn(Iterable<?> dependsOn) {}
|
|
||||||
}
|
|
||||||
|
|
||||||
// FILE: main.kt
|
|
||||||
class Derived : Base() {
|
|
||||||
fun test(s: String) {
|
|
||||||
this.dependsOn <!ASSIGN_OPERATOR_AMBIGUITY!>+=<!> s
|
|
||||||
}
|
|
||||||
}
|
|
||||||
Vendored
+1
@@ -1,3 +1,4 @@
|
|||||||
|
// FIR_IDENTICAL
|
||||||
// WITH_STDLIB
|
// WITH_STDLIB
|
||||||
// ISSUE: KT-54662
|
// ISSUE: KT-54662
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user