[FIR] SignatureEnhancement: fix CME from type parameters enhancement

The problem was that type parameters of Java function were changed
without any synchronization.
In fact, we shouldn't mutate Java declarations at all.
So now we don't mutate type parameters – instead of this,
we mutate only its copy that is safe

^KT-58613 Fixed
^KTIJ-25242 Fixed
^KTIJ-21791 Fixed
This commit is contained in:
Dmitrii Gridin
2023-05-16 14:21:44 +02:00
committed by Space Team
parent fa6fc0e334
commit 71386cc117
2 changed files with 39 additions and 19 deletions
@@ -176,7 +176,9 @@ abstract class FirJavaFacade(
// as we have a nested ordering here.
val enhancement = FirSignatureEnhancement(firJavaClass, session) { emptyList() }
val initialBounds = enhancement.performFirstRoundOfBoundsResolution(firJavaClass.typeParameters)
val (initialBounds, enhancedTypeParameters) = enhancement.performFirstRoundOfBoundsResolution(firJavaClass.typeParameters)
firJavaClass.typeParameters.clear()
firJavaClass.typeParameters += enhancedTypeParameters
// 1. (will happen lazily in FirJavaClass.annotations) Resolve annotations
// 2. Enhance type parameter bounds - may refer to each other, take default nullability from annotations
@@ -154,7 +154,7 @@ class FirSignatureEnhancement(
val getterDelegate = firElement.getter.delegate
val enhancedGetterSymbol = if (getterDelegate is FirJavaMethod) {
enhanceMethod(
getterDelegate, getterDelegate.symbol.callableId, getterDelegate.name,
getterDelegate, getterDelegate.symbol.callableId, getterDelegate.name, enhancedTypeParameters = null,
)
} else {
getterDelegate.symbol
@@ -162,7 +162,7 @@ class FirSignatureEnhancement(
val setterDelegate = firElement.setter?.delegate
val enhancedSetterSymbol = if (setterDelegate is FirJavaMethod) {
enhanceMethod(
setterDelegate, setterDelegate.symbol.callableId, setterDelegate.name,
setterDelegate, setterDelegate.symbol.callableId, setterDelegate.name, enhancedTypeParameters = null,
)
} else {
setterDelegate?.symbol
@@ -195,14 +195,20 @@ class FirSignatureEnhancement(
if (firMethod !is FirJavaMethod && firMethod !is FirJavaConstructor) {
return original
}
enhanceTypeParameterBoundsForMethod(firMethod)
return enhanceMethod(firMethod, original.callableId, name)
val enhancedParameters = enhanceTypeParameterBoundsForMethod(firMethod)
return enhanceMethod(firMethod, original.callableId, name, enhancedParameters)
}
/**
* @param enhancedTypeParameters pass enhanced type parameters that will be used instead of original ones.
* **null** means that [enhanceMethod] will use the original type parameters to create an enhanced function
*/
private fun enhanceMethod(
firMethod: FirFunction,
methodId: CallableId,
name: Name?
name: Name?,
enhancedTypeParameters: List<FirTypeParameterRef>?,
): FirFunctionSymbol<*> {
val predefinedEnhancementInfo =
SignatureBuildingComponents.signature(
@@ -282,11 +288,11 @@ class FirSignatureEnhancement(
moduleData = this@FirSignatureEnhancement.moduleData
resolvePhase = FirResolvePhase.ANALYZED_DEPENDENCIES
origin = FirDeclarationOrigin.Enhancement
this.typeParameters += firMethod.typeParameters
this.typeParameters += (enhancedTypeParameters ?: firMethod.typeParameters)
}
}
is FirJavaMethod -> {
isJavaRecordComponent = firMethod.isJavaRecordComponent ?: false
isJavaRecordComponent = firMethod.isJavaRecordComponent == true
FirSimpleFunctionBuilder().apply {
source = firMethod.source
moduleData = this@FirSignatureEnhancement.moduleData
@@ -304,12 +310,18 @@ class FirSignatureEnhancement(
status = firMethod.status
symbol = FirNamedFunctionSymbol(methodId).also { functionSymbol = it }
resolvePhase = FirResolvePhase.ANALYZED_DEPENDENCIES
typeParameters += firMethod.typeParameters.map { typeParameter ->
typeParameters += (enhancedTypeParameters ?: firMethod.typeParameters).map { typeParameter ->
// FirJavaMethod contains only FirTypeParameter so [enhancedTypeParameters] must have the same type
require(typeParameter is FirTypeParameter) {
"Unexpected type parameter type: ${typeParameter::class.simpleName}"
}
buildTypeParameterCopy(typeParameter) {
origin = FirDeclarationOrigin.Enhancement
containingDeclarationSymbol = functionSymbol
}
}
dispatchReceiverType = firMethod.dispatchReceiverType
attributes = firMethod.attributes.copy()
}
@@ -369,19 +381,24 @@ class FirSignatureEnhancement(
*
* See the usages of FirJavaTypeConversionMode.TYPE_PARAMETER_BOUND_FIRST_ROUND
*/
fun performFirstRoundOfBoundsResolution(typeParameters: List<FirTypeParameterRef>): List<List<FirTypeRef>> {
fun performFirstRoundOfBoundsResolution(typeParameters: List<FirTypeParameterRef>): Pair<List<List<FirTypeRef>>, List<FirTypeParameterRef>> {
val initialBounds: MutableList<List<FirTypeRef>> = mutableListOf()
val typeParametersCopy = ArrayList<FirTypeParameterRef>(typeParameters.size)
for (typeParameter in typeParameters) {
if (typeParameter is FirTypeParameter) {
typeParametersCopy += if (typeParameter is FirTypeParameter) {
initialBounds.add(typeParameter.bounds.toList())
typeParameter.replaceBounds(typeParameter.bounds.map {
it.resolveIfJavaType(session, javaTypeParameterStack, FirJavaTypeConversionMode.TYPE_PARAMETER_BOUND_FIRST_ROUND)
})
buildTypeParameterCopy(typeParameter) {
bounds.clear()
typeParameter.bounds.mapTo(bounds) {
it.resolveIfJavaType(session, javaTypeParameterStack, FirJavaTypeConversionMode.TYPE_PARAMETER_BOUND_FIRST_ROUND)
}
}
} else {
typeParameter
}
}
return initialBounds
return initialBounds to typeParametersCopy
}
/**
@@ -437,9 +454,10 @@ class FirSignatureEnhancement(
}
}
private fun enhanceTypeParameterBoundsForMethod(firMethod: FirFunction) {
val initialBounds = performFirstRoundOfBoundsResolution(firMethod.typeParameters)
enhanceTypeParameterBoundsAfterFirstRound(firMethod.typeParameters, initialBounds)
private fun enhanceTypeParameterBoundsForMethod(firMethod: FirFunction): List<FirTypeParameterRef> {
val (initialBounds, copiedParameters) = performFirstRoundOfBoundsResolution(firMethod.typeParameters)
enhanceTypeParameterBoundsAfterFirstRound(copiedParameters, initialBounds)
return copiedParameters
}
private inline fun List<FirTypeParameterRef>.replaceBounds(block: (FirTypeParameter, FirTypeRef) -> FirTypeRef) {