diff --git a/compiler/fir/java/src/org/jetbrains/kotlin/fir/java/scopes/JavaClassUseSiteMemberScope.kt b/compiler/fir/java/src/org/jetbrains/kotlin/fir/java/scopes/JavaClassUseSiteMemberScope.kt index e6e44b255b8..bcd732e2e84 100644 --- a/compiler/fir/java/src/org/jetbrains/kotlin/fir/java/scopes/JavaClassUseSiteMemberScope.kt +++ b/compiler/fir/java/src/org/jetbrains/kotlin/fir/java/scopes/JavaClassUseSiteMemberScope.kt @@ -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>, - naturalName: Name, - explicitlyDeclaredFunctionsWithNaturalName: Collection, + name: Name, destination: MutableCollection, resultOfIntersectionWithNaturalName: ResultOfIntersection, 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( diff --git a/compiler/fir/java/src/org/jetbrains/kotlin/fir/java/scopes/JavaScopeUtils.kt b/compiler/fir/java/src/org/jetbrains/kotlin/fir/java/scopes/JavaScopeUtils.kt index e7556bbf5c2..5da17a9ea29 100644 --- a/compiler/fir/java/src/org/jetbrains/kotlin/fir/java/scopes/JavaScopeUtils.kt +++ b/compiler/fir/java/src/org/jetbrains/kotlin/fir/java/scopes/JavaScopeUtils.kt @@ -60,13 +60,6 @@ object BuiltinMethodsWithSpecialGenericSignature { private val FirNamedFunctionSymbol.hasErasedValueParametersInJava: Boolean get() = fir.computeJvmSignature() in ERASED_VALUE_PARAMETERS_SIGNATURES - fun getOverriddenBuiltinFunctionWithErasedValueParametersInJava( - memberWithBaseScope: MemberWithBaseScope - ): FirNamedFunctionSymbol? { - return getOverriddenBuiltinFunctionWithErasedValueParametersInJava(memberWithBaseScope.member, memberWithBaseScope.baseScope) - } - - @JvmStatic fun getOverriddenBuiltinFunctionWithErasedValueParametersInJava( functionSymbol: FirNamedFunctionSymbol, diff --git a/compiler/fir/providers/src/org/jetbrains/kotlin/fir/scopes/impl/FirTypeIntersectionScopeContext.kt b/compiler/fir/providers/src/org/jetbrains/kotlin/fir/scopes/impl/FirTypeIntersectionScopeContext.kt index d44d0b7c322..ad957682535 100644 --- a/compiler/fir/providers/src/org/jetbrains/kotlin/fir/scopes/impl/FirTypeIntersectionScopeContext.kt +++ b/compiler/fir/providers/src/org/jetbrains/kotlin/fir/scopes/impl/FirTypeIntersectionScopeContext.kt @@ -45,7 +45,8 @@ class FirTypeIntersectionScopeContext( sealed class ResultOfIntersection>( val overriddenMembers: List>, - val containingScope: FirTypeScope? + // This member is for debug-purposes only + private val containingScope: FirTypeScope? ) { abstract val chosenSymbol: D