K2/Java: cleanup code around processOverridesForFunctionsWithErasedValueParameter

#KT-64846 In Progress
This commit is contained in:
Mikhail Glukhikh
2024-01-26 11:35:39 +01:00
committed by Space Team
parent ac729e28da
commit c0e0b4d32b
3 changed files with 81 additions and 61 deletions
@@ -415,9 +415,7 @@ class JavaClassUseSiteMemberScope(
}
if (processOverridesForFunctionsWithErasedValueParameter(
resultOfIntersectionWithNaturalName.overriddenMembers,
requestedName,
explicitlyDeclaredFunctionsWithNaturalName,
destination,
resultOfIntersectionWithNaturalName,
explicitlyDeclaredFunctionWithNaturalName
@@ -444,93 +442,121 @@ class JavaClassUseSiteMemberScope(
functionsFromSupertypes[requestedName] = resultsOfIntersectionToSaveInCache
}
/**
* This function collects in [destination] an overriding method for base method group [resultOfIntersectionWithNaturalName],
* in case base methods should have their value parameters erased in Java,
* e.g. Collection.contains(T) in Kotlin is paired with Collection.contains(Object) in Java.
*
* Given we have a Java class [klass] and some its method(s) name [name]
* with base method group [resultOfIntersectionWithNaturalName] and (maybe)
* explicitly declared [explicitlyDeclaredFunctionWithNaturalName],
* this function builds a synthetic override for [resultOfIntersectionWithNaturalName] in the Java class,
* binds it with this intersection result using the override relation,
* and collects it as a matching method with this name.
*
* Important: all explicitly declared functions are already collected at this point, there is no reason to collect them once more!
*
* @param name a given method name
* @param destination used to collect base functions for [explicitlyDeclaredFunctionWithNaturalName] with erased value parameters in Java
* @param resultOfIntersectionWithNaturalName one group of intersected base methods, each "overridden member" inside is a pair of (base method, its scope)
* @param explicitlyDeclaredFunctionWithNaturalName the function in the Java class [klass] with the name [name], which overrides [resultOfIntersectionWithNaturalName] (if any)
* @return true if we collected something, false otherwise
* @see [SpecialGenericSignatures.GENERIC_PARAMETERS_METHODS_TO_DEFAULT_VALUES_MAP] and
* [SpecialGenericSignatures.ERASED_COLLECTION_PARAMETER_NAME_AND_SIGNATURES]
*/
private fun processOverridesForFunctionsWithErasedValueParameter(
overriddenMembers: List<MemberWithBaseScope<FirNamedFunctionSymbol>>,
naturalName: Name,
explicitlyDeclaredFunctionsWithNaturalName: Collection<FirNamedFunctionSymbol>,
name: Name,
destination: MutableCollection<FirNamedFunctionSymbol>,
resultOfIntersectionWithNaturalName: ResultOfIntersection<FirNamedFunctionSymbol>,
explicitlyDeclaredFunctionWithNaturalName: FirNamedFunctionSymbol?
): Boolean {
val overriddenMemberWithErasedValueParameters = overriddenMembers.firstOrNull {
BuiltinMethodsWithSpecialGenericSignature.getOverriddenBuiltinFunctionWithErasedValueParametersInJava(it) != null
val membersFromSupertypesWithScopes = resultOfIntersectionWithNaturalName.overriddenMembers
// E.g. contains(String) or contains(T)
val memberFromSupertypeWithValueParametersToBeErased = membersFromSupertypesWithScopes.firstOrNull { (member, scope) ->
BuiltinMethodsWithSpecialGenericSignature.getOverriddenBuiltinFunctionWithErasedValueParametersInJava(member, scope) != null
}?.member ?: return false
val unwrappedSubstitutionOverride = overriddenMemberWithErasedValueParameters.fir.originalForSubstitutionOverride
?: overriddenMemberWithErasedValueParameters.fir
// E.g. contains(T)
val unwrappedMemberFromSupertypeWithValueParametersToBeErased =
memberFromSupertypeWithValueParametersToBeErased.fir.originalForSubstitutionOverride
?: memberFromSupertypeWithValueParametersToBeErased.fir
val functionFromSupertypeWithErasedParameterType = unwrappedSubstitutionOverride
val functionFromSupertypeWithValueParametersToBeErased = unwrappedMemberFromSupertypeWithValueParametersToBeErased
.initialSignatureAttr
?.symbol as? FirNamedFunctionSymbol
?: unwrappedSubstitutionOverride.symbol
val originalDeclaredFunction = declaredMemberScope.getFunctions(naturalName).firstOrNull {
it.hasSameJvmDescriptor(functionFromSupertypeWithErasedParameterType) && it.hasErasedParameters() &&
javaOverrideChecker.doesReturnTypesHaveSameKind(functionFromSupertypeWithErasedParameterType.fir, it.fir)
} ?: return false
/*
* See the comment to shouldBeVisibleAsOverrideOfBuiltInWithErasedValueParameters function
?: unwrappedMemberFromSupertypeWithValueParametersToBeErased.symbol
// E.g. contains(Object) from Java
val explicitlyDeclaredFunctionWithErasedValueParameters =
declaredMemberScope.getFunctions(name).firstOrNull { declaredFunction ->
declaredFunction.hasSameJvmDescriptor(functionFromSupertypeWithValueParametersToBeErased) &&
declaredFunction.hasErasedParameters() &&
javaOverrideChecker.doesReturnTypesHaveSameKind(
functionFromSupertypeWithValueParametersToBeErased.fir,
declaredFunction.fir
)
} ?: return false // No declared functions with erased parameters => no additional processing needed
/**
* See the comment to [shouldBeVisibleAsOverrideOfBuiltInWithErasedValueParameters] function
* It explains why we should check value parameters for `Any` type
*/
var allParametersAreAny = true
val renamedDeclaredFunction = buildJavaMethodCopy(originalDeclaredFunction.fir as FirJavaMethod) {
name = naturalName
symbol = FirNamedFunctionSymbol(originalDeclaredFunction.callableId)
// It's a copy like contains(T) or contains(String) in Java, we perform "unerasing" here
val declaredFunctionCopyWithParameterTypesFromSupertype = buildJavaMethodCopy(
explicitlyDeclaredFunctionWithErasedValueParameters.fir as FirJavaMethod
) {
this.name = name
symbol = FirNamedFunctionSymbol(explicitlyDeclaredFunctionWithErasedValueParameters.callableId)
this.valueParameters.clear()
originalDeclaredFunction.fir.valueParameters.zip(overriddenMemberWithErasedValueParameters.fir.valueParameters)
.mapTo(this.valueParameters) { (overrideParameter, parameterFromSupertype) ->
if (!parameterFromSupertype.returnTypeRef.coneType.lowerBoundIfFlexible().isAny) {
allParametersAreAny = false
}
buildJavaValueParameterCopy(overrideParameter) {
this@buildJavaValueParameterCopy.returnTypeRef = parameterFromSupertype.returnTypeRef
}
explicitlyDeclaredFunctionWithErasedValueParameters.fir.valueParameters.zip(
memberFromSupertypeWithValueParametersToBeErased.fir.valueParameters
).mapTo(this.valueParameters) { (overrideParameter, parameterFromSupertype) ->
if (!parameterFromSupertype.returnTypeRef.coneType.lowerBoundIfFlexible().isAny) {
allParametersAreAny = false
}
buildJavaValueParameterCopy(overrideParameter) {
this@buildJavaValueParameterCopy.returnTypeRef = parameterFromSupertype.returnTypeRef
}
}
}.apply {
initialSignatureAttr = originalDeclaredFunction.fir
initialSignatureAttr = explicitlyDeclaredFunctionWithErasedValueParameters.fir
}.symbol
if (allParametersAreAny) {
return false
}
val accidentalOverrideWithDeclaredFunction = explicitlyDeclaredFunctionsWithNaturalName.find {
// E.g. contains(String) from Java, if any
val accidentalOverrideWithDeclaredFunction = explicitlyDeclaredFunctionWithNaturalName?.takeIf {
overrideChecker.isOverriddenFunction(
renamedDeclaredFunction,
declaredFunctionCopyWithParameterTypesFromSupertype,
it
)
}
if (accidentalOverrideWithDeclaredFunction == null) {
destination += renamedDeclaredFunction
directOverriddenFunctions[renamedDeclaredFunction] = listOf(resultOfIntersectionWithNaturalName)
for (overriddenMember in overriddenMembers) {
overrideByBase[overriddenMember.member] = renamedDeclaredFunction
}
if (explicitlyDeclaredFunctionWithNaturalName != null) {
destination += explicitlyDeclaredFunctionWithNaturalName
}
return true
val symbolToBeCollected = if (accidentalOverrideWithDeclaredFunction == null) {
// Collect synthetic function which is an "unerased" copy of declared one with erased parameters
declaredFunctionCopyWithParameterTypesFromSupertype
} else {
val newSymbol = FirNamedFunctionSymbol(accidentalOverrideWithDeclaredFunction.callableId)
val original = accidentalOverrideWithDeclaredFunction.fir
val hiddenFunction = buildSimpleFunctionCopy(original) {
name = naturalName
val accidentalOverrideWithDeclaredFunctionHiddenCopy = buildSimpleFunctionCopy(original) {
this.name = name
symbol = newSymbol
dispatchReceiverType = klass.defaultType()
}.apply {
initialSignatureAttr = original
isHiddenToOvercomeSignatureClash = true
}
destination += hiddenFunction.symbol
directOverriddenFunctions[hiddenFunction.symbol] = listOf(resultOfIntersectionWithNaturalName)
for (overriddenMember in overriddenMembers) {
overrideByBase[overriddenMember.member] = hiddenFunction.symbol
}
if (explicitlyDeclaredFunctionWithNaturalName != null) {
destination += explicitlyDeclaredFunctionWithNaturalName
}
return true
// Collect synthetic function which is a hidden copy of declared one with unerased parameters
accidentalOverrideWithDeclaredFunctionHiddenCopy.symbol
}
destination += symbolToBeCollected
directOverriddenFunctions[symbolToBeCollected] = listOf(resultOfIntersectionWithNaturalName)
for ((member, _) in membersFromSupertypesWithScopes) {
overrideByBase[member] = symbolToBeCollected
}
return true
}
private fun FirNamedFunctionSymbol.hasSameJvmDescriptor(
@@ -60,13 +60,6 @@ object BuiltinMethodsWithSpecialGenericSignature {
private val FirNamedFunctionSymbol.hasErasedValueParametersInJava: Boolean
get() = fir.computeJvmSignature() in ERASED_VALUE_PARAMETERS_SIGNATURES
fun getOverriddenBuiltinFunctionWithErasedValueParametersInJava(
memberWithBaseScope: MemberWithBaseScope<FirNamedFunctionSymbol>
): FirNamedFunctionSymbol? {
return getOverriddenBuiltinFunctionWithErasedValueParametersInJava(memberWithBaseScope.member, memberWithBaseScope.baseScope)
}
@JvmStatic
fun getOverriddenBuiltinFunctionWithErasedValueParametersInJava(
functionSymbol: FirNamedFunctionSymbol,
@@ -45,7 +45,8 @@ class FirTypeIntersectionScopeContext(
sealed class ResultOfIntersection<D : FirCallableSymbol<*>>(
val overriddenMembers: List<MemberWithBaseScope<D>>,
val containingScope: FirTypeScope?
// This member is for debug-purposes only
private val containingScope: FirTypeScope?
) {
abstract val chosenSymbol: D