[FIR] Don't map java functions which override kotlin builtin function with erased parameter type if it's not needed
There is a case when we shouldn't hide a function even if it overrides
builtin member with value parameter erasure: if substituted kotlin
overridden has the same parameters as current java override. Such
situation may happen only in case when `Any`/`Object` is used as
parameterization of supertype:
// java
class MySuperMap extends java.util.Map<Object, Object> {
@Override
public boolean containsKey(Object key) {...}
@Override
public boolean containsValue(Object key) {...}
}
In this case, the signature of override, made based on the correct
kotlin signature, will be the same (because of { K -> Any, V -> Any }
substitution for both functions). And since the list of all such
functions is well-known, the only case when this may happen is when
value parameter types of kotlin overridden are `Any`
This change doesn't affect any tests in the moment, because it's part of
bigger refactoring of proper storing IR declarations during FIR2IR
conversion (KT-61637)
Without this change, there is one test break in branch for KT-61637:
`FirPsiBlackBoxCodegenTestGenerated.SpecialBuiltins.testMapGetOrDefault`
This commit is contained in:
committed by
Space Team
parent
cf98fb5612
commit
1868b29cc9
+36
-5
@@ -290,14 +290,33 @@ class JavaClassUseSiteMemberScope(
|
||||
* Examples:
|
||||
* - boolean containsKey(Object key) -> true
|
||||
* - boolean containsKey(K key) -> false // Wrong JDK method override, while it's a valid Kotlin built-in override
|
||||
*
|
||||
* There is a case when we shouldn't hide a function even if it overrides builtin member with value parameter erasure:
|
||||
* if substituted kotlin overridden has the same parameters as current java override. Such situation may happen only in
|
||||
* case when `Any`/`Object` is used as parameterization of supertype:
|
||||
*
|
||||
* // java
|
||||
* class MySuperMap extends java.util.Map<Object, Object> {
|
||||
* @Override
|
||||
* public boolean containsKey(Object key) {...}
|
||||
*
|
||||
* @Override
|
||||
* public boolean containsValue(Object key) {...}
|
||||
* }
|
||||
*
|
||||
* In this case, the signature of override, made based on the correct kotlin signature, will be the same (because of { K -> Any, V -> Any }
|
||||
* substitution for both functions).
|
||||
* And since the list of all such functions is well-known, the only case when this may happen is when value parameter types of kotlin
|
||||
* overridden are `Any`
|
||||
*/
|
||||
private fun FirNamedFunctionSymbol.shouldBeVisibleAsOverrideOfBuiltInWithErasedValueParameters(): Boolean {
|
||||
if (!name.sameAsBuiltinMethodWithErasedValueParameters) return false
|
||||
val candidatesToOverride = supertypeScopeContext.collectMembersGroupedByScope(name, FirScope::processFunctionsByName)
|
||||
.flatMap { (scope, symbols) ->
|
||||
symbols.mapNotNull {
|
||||
BuiltinMethodsWithSpecialGenericSignature.getOverriddenBuiltinFunctionWithErasedValueParametersInJava(it, scope)
|
||||
}
|
||||
val candidatesToOverride = supertypeScopeContext.collectIntersectionResultsForCallables(name, FirScope::processFunctionsByName)
|
||||
.flatMap { it.overriddenMembers }
|
||||
.filterNot { (member, _) ->
|
||||
member.valueParameterSymbols.all { it.resolvedReturnType.lowerBoundIfFlexible().isAny }
|
||||
}.mapNotNull { (member, scope) ->
|
||||
BuiltinMethodsWithSpecialGenericSignature.getOverriddenBuiltinFunctionWithErasedValueParametersInJava(member, scope)
|
||||
}
|
||||
|
||||
val jvmDescriptor = fir.computeJvmDescriptor()
|
||||
@@ -439,12 +458,20 @@ class JavaClassUseSiteMemberScope(
|
||||
it.hasSameJvmDescriptor(functionFromSupertypeWithErasedParameterType) && it.hasErasedParameters() &&
|
||||
javaOverrideChecker.doesReturnTypesHaveSameKind(functionFromSupertypeWithErasedParameterType.fir, it.fir)
|
||||
} ?: return false
|
||||
/*
|
||||
* 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)
|
||||
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
|
||||
}
|
||||
@@ -453,6 +480,10 @@ class JavaClassUseSiteMemberScope(
|
||||
initialSignatureAttr = originalDeclaredFunction.fir
|
||||
}.symbol
|
||||
|
||||
if (allParametersAreAny) {
|
||||
return false
|
||||
}
|
||||
|
||||
val hasAccidentalOverrideWithDeclaredFunction = explicitlyDeclaredFunctionsWithNaturalName.any {
|
||||
overrideChecker.isOverriddenFunction(
|
||||
renamedDeclaredFunction,
|
||||
|
||||
Reference in New Issue
Block a user