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( if (processOverridesForFunctionsWithErasedValueParameter(
resultOfIntersectionWithNaturalName.overriddenMembers,
requestedName, requestedName,
explicitlyDeclaredFunctionsWithNaturalName,
destination, destination,
resultOfIntersectionWithNaturalName, resultOfIntersectionWithNaturalName,
explicitlyDeclaredFunctionWithNaturalName explicitlyDeclaredFunctionWithNaturalName
@@ -444,93 +442,121 @@ class JavaClassUseSiteMemberScope(
functionsFromSupertypes[requestedName] = resultsOfIntersectionToSaveInCache 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( private fun processOverridesForFunctionsWithErasedValueParameter(
overriddenMembers: List<MemberWithBaseScope<FirNamedFunctionSymbol>>, name: Name,
naturalName: Name,
explicitlyDeclaredFunctionsWithNaturalName: Collection<FirNamedFunctionSymbol>,
destination: MutableCollection<FirNamedFunctionSymbol>, destination: MutableCollection<FirNamedFunctionSymbol>,
resultOfIntersectionWithNaturalName: ResultOfIntersection<FirNamedFunctionSymbol>, resultOfIntersectionWithNaturalName: ResultOfIntersection<FirNamedFunctionSymbol>,
explicitlyDeclaredFunctionWithNaturalName: FirNamedFunctionSymbol? explicitlyDeclaredFunctionWithNaturalName: FirNamedFunctionSymbol?
): Boolean { ): Boolean {
val overriddenMemberWithErasedValueParameters = overriddenMembers.firstOrNull { val membersFromSupertypesWithScopes = resultOfIntersectionWithNaturalName.overriddenMembers
BuiltinMethodsWithSpecialGenericSignature.getOverriddenBuiltinFunctionWithErasedValueParametersInJava(it) != null // E.g. contains(String) or contains(T)
val memberFromSupertypeWithValueParametersToBeErased = membersFromSupertypesWithScopes.firstOrNull { (member, scope) ->
BuiltinMethodsWithSpecialGenericSignature.getOverriddenBuiltinFunctionWithErasedValueParametersInJava(member, scope) != null
}?.member ?: return false }?.member ?: return false
val unwrappedSubstitutionOverride = overriddenMemberWithErasedValueParameters.fir.originalForSubstitutionOverride // E.g. contains(T)
?: overriddenMemberWithErasedValueParameters.fir val unwrappedMemberFromSupertypeWithValueParametersToBeErased =
memberFromSupertypeWithValueParametersToBeErased.fir.originalForSubstitutionOverride
?: memberFromSupertypeWithValueParametersToBeErased.fir
val functionFromSupertypeWithErasedParameterType = unwrappedSubstitutionOverride val functionFromSupertypeWithValueParametersToBeErased = unwrappedMemberFromSupertypeWithValueParametersToBeErased
.initialSignatureAttr .initialSignatureAttr
?.symbol as? FirNamedFunctionSymbol ?.symbol as? FirNamedFunctionSymbol
?: unwrappedSubstitutionOverride.symbol ?: unwrappedMemberFromSupertypeWithValueParametersToBeErased.symbol
val originalDeclaredFunction = declaredMemberScope.getFunctions(naturalName).firstOrNull {
it.hasSameJvmDescriptor(functionFromSupertypeWithErasedParameterType) && it.hasErasedParameters() && // E.g. contains(Object) from Java
javaOverrideChecker.doesReturnTypesHaveSameKind(functionFromSupertypeWithErasedParameterType.fir, it.fir) val explicitlyDeclaredFunctionWithErasedValueParameters =
} ?: return false declaredMemberScope.getFunctions(name).firstOrNull { declaredFunction ->
/* declaredFunction.hasSameJvmDescriptor(functionFromSupertypeWithValueParametersToBeErased) &&
* See the comment to shouldBeVisibleAsOverrideOfBuiltInWithErasedValueParameters function 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 * It explains why we should check value parameters for `Any` type
*/ */
var allParametersAreAny = true var allParametersAreAny = true
val renamedDeclaredFunction = buildJavaMethodCopy(originalDeclaredFunction.fir as FirJavaMethod) { // It's a copy like contains(T) or contains(String) in Java, we perform "unerasing" here
name = naturalName val declaredFunctionCopyWithParameterTypesFromSupertype = buildJavaMethodCopy(
symbol = FirNamedFunctionSymbol(originalDeclaredFunction.callableId) explicitlyDeclaredFunctionWithErasedValueParameters.fir as FirJavaMethod
) {
this.name = name
symbol = FirNamedFunctionSymbol(explicitlyDeclaredFunctionWithErasedValueParameters.callableId)
this.valueParameters.clear() this.valueParameters.clear()
originalDeclaredFunction.fir.valueParameters.zip(overriddenMemberWithErasedValueParameters.fir.valueParameters) explicitlyDeclaredFunctionWithErasedValueParameters.fir.valueParameters.zip(
.mapTo(this.valueParameters) { (overrideParameter, parameterFromSupertype) -> memberFromSupertypeWithValueParametersToBeErased.fir.valueParameters
if (!parameterFromSupertype.returnTypeRef.coneType.lowerBoundIfFlexible().isAny) { ).mapTo(this.valueParameters) { (overrideParameter, parameterFromSupertype) ->
allParametersAreAny = false if (!parameterFromSupertype.returnTypeRef.coneType.lowerBoundIfFlexible().isAny) {
} allParametersAreAny = false
buildJavaValueParameterCopy(overrideParameter) {
this@buildJavaValueParameterCopy.returnTypeRef = parameterFromSupertype.returnTypeRef
}
} }
buildJavaValueParameterCopy(overrideParameter) {
this@buildJavaValueParameterCopy.returnTypeRef = parameterFromSupertype.returnTypeRef
}
}
}.apply { }.apply {
initialSignatureAttr = originalDeclaredFunction.fir initialSignatureAttr = explicitlyDeclaredFunctionWithErasedValueParameters.fir
}.symbol }.symbol
if (allParametersAreAny) { if (allParametersAreAny) {
return false return false
} }
val accidentalOverrideWithDeclaredFunction = explicitlyDeclaredFunctionsWithNaturalName.find { // E.g. contains(String) from Java, if any
val accidentalOverrideWithDeclaredFunction = explicitlyDeclaredFunctionWithNaturalName?.takeIf {
overrideChecker.isOverriddenFunction( overrideChecker.isOverriddenFunction(
renamedDeclaredFunction, declaredFunctionCopyWithParameterTypesFromSupertype,
it it
) )
} }
if (accidentalOverrideWithDeclaredFunction == null) { val symbolToBeCollected = if (accidentalOverrideWithDeclaredFunction == null) {
destination += renamedDeclaredFunction // Collect synthetic function which is an "unerased" copy of declared one with erased parameters
directOverriddenFunctions[renamedDeclaredFunction] = listOf(resultOfIntersectionWithNaturalName) declaredFunctionCopyWithParameterTypesFromSupertype
for (overriddenMember in overriddenMembers) {
overrideByBase[overriddenMember.member] = renamedDeclaredFunction
}
if (explicitlyDeclaredFunctionWithNaturalName != null) {
destination += explicitlyDeclaredFunctionWithNaturalName
}
return true
} else { } else {
val newSymbol = FirNamedFunctionSymbol(accidentalOverrideWithDeclaredFunction.callableId) val newSymbol = FirNamedFunctionSymbol(accidentalOverrideWithDeclaredFunction.callableId)
val original = accidentalOverrideWithDeclaredFunction.fir val original = accidentalOverrideWithDeclaredFunction.fir
val hiddenFunction = buildSimpleFunctionCopy(original) { val accidentalOverrideWithDeclaredFunctionHiddenCopy = buildSimpleFunctionCopy(original) {
name = naturalName this.name = name
symbol = newSymbol symbol = newSymbol
dispatchReceiverType = klass.defaultType() dispatchReceiverType = klass.defaultType()
}.apply { }.apply {
initialSignatureAttr = original initialSignatureAttr = original
isHiddenToOvercomeSignatureClash = true isHiddenToOvercomeSignatureClash = true
} }
destination += hiddenFunction.symbol // Collect synthetic function which is a hidden copy of declared one with unerased parameters
directOverriddenFunctions[hiddenFunction.symbol] = listOf(resultOfIntersectionWithNaturalName) accidentalOverrideWithDeclaredFunctionHiddenCopy.symbol
for (overriddenMember in overriddenMembers) {
overrideByBase[overriddenMember.member] = hiddenFunction.symbol
}
if (explicitlyDeclaredFunctionWithNaturalName != null) {
destination += explicitlyDeclaredFunctionWithNaturalName
}
return true
} }
destination += symbolToBeCollected
directOverriddenFunctions[symbolToBeCollected] = listOf(resultOfIntersectionWithNaturalName)
for ((member, _) in membersFromSupertypesWithScopes) {
overrideByBase[member] = symbolToBeCollected
}
return true
} }
private fun FirNamedFunctionSymbol.hasSameJvmDescriptor( private fun FirNamedFunctionSymbol.hasSameJvmDescriptor(
@@ -60,13 +60,6 @@ object BuiltinMethodsWithSpecialGenericSignature {
private val FirNamedFunctionSymbol.hasErasedValueParametersInJava: Boolean private val FirNamedFunctionSymbol.hasErasedValueParametersInJava: Boolean
get() = fir.computeJvmSignature() in ERASED_VALUE_PARAMETERS_SIGNATURES get() = fir.computeJvmSignature() in ERASED_VALUE_PARAMETERS_SIGNATURES
fun getOverriddenBuiltinFunctionWithErasedValueParametersInJava(
memberWithBaseScope: MemberWithBaseScope<FirNamedFunctionSymbol>
): FirNamedFunctionSymbol? {
return getOverriddenBuiltinFunctionWithErasedValueParametersInJava(memberWithBaseScope.member, memberWithBaseScope.baseScope)
}
@JvmStatic @JvmStatic
fun getOverriddenBuiltinFunctionWithErasedValueParametersInJava( fun getOverriddenBuiltinFunctionWithErasedValueParametersInJava(
functionSymbol: FirNamedFunctionSymbol, functionSymbol: FirNamedFunctionSymbol,
@@ -45,7 +45,8 @@ class FirTypeIntersectionScopeContext(
sealed class ResultOfIntersection<D : FirCallableSymbol<*>>( sealed class ResultOfIntersection<D : FirCallableSymbol<*>>(
val overriddenMembers: List<MemberWithBaseScope<D>>, val overriddenMembers: List<MemberWithBaseScope<D>>,
val containingScope: FirTypeScope? // This member is for debug-purposes only
private val containingScope: FirTypeScope?
) { ) {
abstract val chosenSymbol: D abstract val chosenSymbol: D