From 71386cc1170af3dabb5779419f1729aa44c7af05 Mon Sep 17 00:00:00 2001 From: Dmitrii Gridin Date: Tue, 16 May 2023 14:21:44 +0200 Subject: [PATCH] [FIR] SignatureEnhancement: fix CME from type parameters enhancement MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 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 --- .../kotlin/fir/java/FirJavaFacade.kt | 4 +- .../java/enhancement/SignatureEnhancement.kt | 54 ++++++++++++------- 2 files changed, 39 insertions(+), 19 deletions(-) diff --git a/compiler/fir/java/src/org/jetbrains/kotlin/fir/java/FirJavaFacade.kt b/compiler/fir/java/src/org/jetbrains/kotlin/fir/java/FirJavaFacade.kt index 25fdfd0b3a2..55d0c832cdc 100644 --- a/compiler/fir/java/src/org/jetbrains/kotlin/fir/java/FirJavaFacade.kt +++ b/compiler/fir/java/src/org/jetbrains/kotlin/fir/java/FirJavaFacade.kt @@ -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 diff --git a/compiler/fir/java/src/org/jetbrains/kotlin/fir/java/enhancement/SignatureEnhancement.kt b/compiler/fir/java/src/org/jetbrains/kotlin/fir/java/enhancement/SignatureEnhancement.kt index 9076ce7223a..b18fde82208 100644 --- a/compiler/fir/java/src/org/jetbrains/kotlin/fir/java/enhancement/SignatureEnhancement.kt +++ b/compiler/fir/java/src/org/jetbrains/kotlin/fir/java/enhancement/SignatureEnhancement.kt @@ -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?, ): 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): List> { + fun performFirstRoundOfBoundsResolution(typeParameters: List): Pair>, List> { val initialBounds: MutableList> = mutableListOf() - + val typeParametersCopy = ArrayList(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 { + val (initialBounds, copiedParameters) = performFirstRoundOfBoundsResolution(firMethod.typeParameters) + enhanceTypeParameterBoundsAfterFirstRound(copiedParameters, initialBounds) + return copiedParameters } private inline fun List.replaceBounds(block: (FirTypeParameter, FirTypeRef) -> FirTypeRef) {