[FIR] propagate copy of original ConeKotlinType to anonymous functions to avoid concurrent modification

It is required to avoid leakage of annotations instance from
the original type
It should be enough to just create a new instance of an annotation
without a deep copy, because transformer shouldn't touch it

^KT-60387 Fixed
This commit is contained in:
Dmitrii Gridin
2023-07-13 16:22:59 +02:00
committed by Space Team
parent 51b9059123
commit d0854d5b45
21 changed files with 336 additions and 16 deletions
@@ -6,10 +6,33 @@
package org.jetbrains.kotlin.fir.types
import org.jetbrains.kotlin.fir.expressions.FirAnnotation
import org.jetbrains.kotlin.fir.expressions.FirAnnotationCall
import org.jetbrains.kotlin.fir.expressions.builder.buildAnnotationCallCopy
import org.jetbrains.kotlin.fir.expressions.builder.buildAnnotationCopy
import org.jetbrains.kotlin.fir.render
import org.jetbrains.kotlin.fir.symbols.FirBasedSymbol
import kotlin.reflect.KClass
/**
* @param containerSymbols a list of symbols that should be resolved to make [annotations] are fully resolved.
* Required only for "lazy" resolve mode in AA FIR to make a type annotation lazily resolved.
* See KtFirAnnotationListForType for reference.
* Example:
* ```kotlin
* fun foo(): @Anno Type
* ```
* This `Anno` annotation will have `foo` function as [containerSymbols].
* More than one [containerSymbols] possible in case of type aliases:
* ```kotlin
* interface BaseInterface
* typealias FirstTypeAlias = @Anno1 BaseInterface
* typealias SecondTypeAlias = @Anno2 FirstTypeAlias
*
* fun foo(): @Anno3 SecondTypeAlias = TODO()
* ```
* here `@Anno3 SecondTypeAlias` will be expanded to ` @Anno1 @Anno2 @Anno3 BaseInterface`
* and will have all intermediate type-aliases as [containerSymbols].
*/
class CustomAnnotationTypeAttribute(
val annotations: List<FirAnnotation>,
val containerSymbols: List<FirBasedSymbol<*>> = emptyList(),
@@ -34,6 +57,27 @@ class CustomAnnotationTypeAttribute(
override val key: KClass<out CustomAnnotationTypeAttribute>
get() = CustomAnnotationTypeAttribute::class
/**
* Return an instance of the attribute that is not linked to any [containerSymbols].
* It is required to avoid concurrent modification of those annotations from the linked
* declaration and another call site (e.g., if a type was propagated to an anonymous function).
*
* See KT-60387 as an example of a possible concurrent problem.
*/
fun independentInstance(): CustomAnnotationTypeAttribute = if (containerSymbols.isEmpty()) {
this
} else {
CustomAnnotationTypeAttribute(
annotations = annotations.map {
if (it is FirAnnotationCall) {
buildAnnotationCallCopy(it) {}
} else {
buildAnnotationCopy(it) {}
}
}
)
}
}
val ConeAttributes.custom: CustomAnnotationTypeAttribute? by ConeAttributes.attributeAccessor<CustomAnnotationTypeAttribute>()