[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:
committed by
Space Team
parent
51b9059123
commit
d0854d5b45
+21
@@ -0,0 +1,21 @@
|
||||
// FILE: usage.kt
|
||||
<expr>
|
||||
val propertyToResolve: String
|
||||
get() = JavaClass.function()?.let { " ($it)" } ?: ""
|
||||
</expr>
|
||||
|
||||
// FILE: Anno.java
|
||||
import java.lang.annotation.ElementType;
|
||||
import java.lang.annotation.Target;
|
||||
|
||||
@Target(ElementType.TYPE_USE)
|
||||
public @interface Anno {
|
||||
String value();
|
||||
}
|
||||
|
||||
// FILE: JavaClass.java
|
||||
public class JavaClass {
|
||||
public static @Anno("outer") List<@Anno("middle") List<@Anno("inner") Integer>> function() {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
+23
@@ -0,0 +1,23 @@
|
||||
KT element: KtProperty
|
||||
FIR element: FirPropertyImpl
|
||||
FIR source kind: KtRealSourceElementKind
|
||||
|
||||
FIR element rendered:
|
||||
public final [ResolvedTo(BODY_RESOLVE)] val propertyToResolve: R|kotlin/String|
|
||||
public [ResolvedTo(BODY_RESOLVE)] get(): R|kotlin/String| {
|
||||
^ <Unresolved name: JavaClass>#.<Unresolved name: function>#()?.{ $subj$.<Unresolved name: let>#(<L> = [ResolvedTo(BODY_RESOLVE)] let@fun <anonymous>(): R|kotlin/String| <inline=Unknown> {
|
||||
^ <strcat>(String( (), <Unresolved name: it>#, String()))
|
||||
}
|
||||
) } ?: String()
|
||||
}
|
||||
|
||||
FIR FILE:
|
||||
FILE: [ResolvedTo(IMPORTS)] usage.kt
|
||||
[ResolvedTo(BODY_RESOLVE)] annotations container
|
||||
public final [ResolvedTo(BODY_RESOLVE)] val propertyToResolve: R|kotlin/String|
|
||||
public [ResolvedTo(BODY_RESOLVE)] get(): R|kotlin/String| {
|
||||
^ <Unresolved name: JavaClass>#.<Unresolved name: function>#()?.{ $subj$.<Unresolved name: let>#(<L> = [ResolvedTo(BODY_RESOLVE)] let@fun <anonymous>(): R|kotlin/String| <inline=Unknown> {
|
||||
^ <strcat>(String( (), <Unresolved name: it>#, String()))
|
||||
}
|
||||
) } ?: String()
|
||||
}
|
||||
+23
@@ -0,0 +1,23 @@
|
||||
KT element: KtProperty
|
||||
FIR element: FirPropertyImpl
|
||||
FIR source kind: KtRealSourceElementKind
|
||||
|
||||
FIR element rendered:
|
||||
public final [ResolvedTo(BODY_RESOLVE)] val propertyToResolve: R|kotlin/String|
|
||||
public [ResolvedTo(BODY_RESOLVE)] get(): R|kotlin/String| {
|
||||
^ Q|JavaClass|.R|/JavaClass.function|()?.{ $subj$.R|kotlin/let|<R|@R|Anno|(value = String(outer)) List|, R|kotlin/String|>(<L> = [ResolvedTo(BODY_RESOLVE)] [MatchingParameterFunctionTypeKey=kotlin/Function1<T, R>] let@fun <anonymous>([ResolvedTo(BODY_RESOLVE)] it: R|@R|Anno|(value = String(outer)) List|): R|kotlin/String| <inline=Inline, kind=EXACTLY_ONCE> {
|
||||
^ <strcat>(String( (), R|<local>/it|, String()))
|
||||
}
|
||||
) } ?: String()
|
||||
}
|
||||
|
||||
FIR FILE:
|
||||
FILE: [ResolvedTo(IMPORTS)] usage.kt
|
||||
[ResolvedTo(BODY_RESOLVE)] annotations container
|
||||
public final [ResolvedTo(BODY_RESOLVE)] val propertyToResolve: R|kotlin/String|
|
||||
public [ResolvedTo(BODY_RESOLVE)] get(): R|kotlin/String| {
|
||||
^ Q|JavaClass|.R|/JavaClass.function|()?.{ $subj$.R|kotlin/let|<R|@R|Anno|(value = String(outer)) List|, R|kotlin/String|>(<L> = [ResolvedTo(BODY_RESOLVE)] [MatchingParameterFunctionTypeKey=kotlin/Function1<T, R>] let@fun <anonymous>([ResolvedTo(BODY_RESOLVE)] it: R|@R|Anno|(value = String(outer)) List|): R|kotlin/String| <inline=Inline, kind=EXACTLY_ONCE> {
|
||||
^ <strcat>(String( (), R|<local>/it|, String()))
|
||||
}
|
||||
) } ?: String()
|
||||
}
|
||||
+21
@@ -0,0 +1,21 @@
|
||||
// FILE: usage.kt
|
||||
<expr>
|
||||
val propertyToResolve: String
|
||||
get() = JavaClass.function().let { " ($it)" }
|
||||
</expr>
|
||||
|
||||
// FILE: Anno.java
|
||||
import java.lang.annotation.ElementType;
|
||||
import java.lang.annotation.Target;
|
||||
|
||||
@Target(ElementType.TYPE_USE)
|
||||
public @interface Anno {
|
||||
String value();
|
||||
}
|
||||
|
||||
// FILE: JavaClass.java
|
||||
public class JavaClass {
|
||||
public static @Anno("outer") List<@Anno("middle") List<@Anno("inner") Integer>> function() {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
+23
@@ -0,0 +1,23 @@
|
||||
KT element: KtProperty
|
||||
FIR element: FirPropertyImpl
|
||||
FIR source kind: KtRealSourceElementKind
|
||||
|
||||
FIR element rendered:
|
||||
public final [ResolvedTo(BODY_RESOLVE)] val propertyToResolve: R|kotlin/String|
|
||||
public [ResolvedTo(BODY_RESOLVE)] get(): R|kotlin/String| {
|
||||
^ <Unresolved name: JavaClass>#.<Unresolved name: function>#().<Unresolved name: let>#(<L> = [ResolvedTo(BODY_RESOLVE)] let@fun <anonymous>(): R|kotlin/String| <inline=Unknown> {
|
||||
^ <strcat>(String( (), <Unresolved name: it>#, String()))
|
||||
}
|
||||
)
|
||||
}
|
||||
|
||||
FIR FILE:
|
||||
FILE: [ResolvedTo(IMPORTS)] usage.kt
|
||||
[ResolvedTo(BODY_RESOLVE)] annotations container
|
||||
public final [ResolvedTo(BODY_RESOLVE)] val propertyToResolve: R|kotlin/String|
|
||||
public [ResolvedTo(BODY_RESOLVE)] get(): R|kotlin/String| {
|
||||
^ <Unresolved name: JavaClass>#.<Unresolved name: function>#().<Unresolved name: let>#(<L> = [ResolvedTo(BODY_RESOLVE)] let@fun <anonymous>(): R|kotlin/String| <inline=Unknown> {
|
||||
^ <strcat>(String( (), <Unresolved name: it>#, String()))
|
||||
}
|
||||
)
|
||||
}
|
||||
+23
@@ -0,0 +1,23 @@
|
||||
KT element: KtProperty
|
||||
FIR element: FirPropertyImpl
|
||||
FIR source kind: KtRealSourceElementKind
|
||||
|
||||
FIR element rendered:
|
||||
public final [ResolvedTo(BODY_RESOLVE)] val propertyToResolve: R|kotlin/String|
|
||||
public [ResolvedTo(BODY_RESOLVE)] get(): R|kotlin/String| {
|
||||
^ Q|JavaClass|.R|/JavaClass.function|().R|kotlin/let|<R|@R|Anno|(value = String(outer)) List!|, R|kotlin/String|>(<L> = [ResolvedTo(BODY_RESOLVE)] [MatchingParameterFunctionTypeKey=kotlin/Function1<T, R>] let@fun <anonymous>([ResolvedTo(BODY_RESOLVE)] it: R|@R|Anno|(value = String(outer)) List!|): R|kotlin/String| <inline=Inline, kind=EXACTLY_ONCE> {
|
||||
^ <strcat>(String( (), R|<local>/it|, String()))
|
||||
}
|
||||
)
|
||||
}
|
||||
|
||||
FIR FILE:
|
||||
FILE: [ResolvedTo(IMPORTS)] usage.kt
|
||||
[ResolvedTo(BODY_RESOLVE)] annotations container
|
||||
public final [ResolvedTo(BODY_RESOLVE)] val propertyToResolve: R|kotlin/String|
|
||||
public [ResolvedTo(BODY_RESOLVE)] get(): R|kotlin/String| {
|
||||
^ Q|JavaClass|.R|/JavaClass.function|().R|kotlin/let|<R|@R|Anno|(value = String(outer)) List!|, R|kotlin/String|>(<L> = [ResolvedTo(BODY_RESOLVE)] [MatchingParameterFunctionTypeKey=kotlin/Function1<T, R>] let@fun <anonymous>([ResolvedTo(BODY_RESOLVE)] it: R|@R|Anno|(value = String(outer)) List!|): R|kotlin/String| <inline=Inline, kind=EXACTLY_ONCE> {
|
||||
^ <strcat>(String( (), R|<local>/it|, String()))
|
||||
}
|
||||
)
|
||||
}
|
||||
Vendored
+2
-2
@@ -229,8 +229,8 @@ FILE: [ResolvedTo(IMPORTS)] anonymousFunctionWithAnnotatedParameter.kt
|
||||
public [ResolvedTo(STATUS)] [ContainingClassKey=Anno] get(): R|kotlin/String|
|
||||
|
||||
}
|
||||
public final [ResolvedTo(CONTRACTS)] val nullablePropertyWithAnnotatedType: R|@R|Anno|(message = String(outer)) kotlin/collections/List<@R|Anno|(message = String(middle)) kotlin/collections/List<@R|Anno|(message = String(inner)) kotlin/Int>>?|
|
||||
public [ResolvedTo(CONTRACTS)] get(): R|@R|Anno|(message = String(outer)) kotlin/collections/List<@R|Anno|(message = String(middle)) kotlin/collections/List<@R|Anno|(message = String(inner)) kotlin/Int>>?| {
|
||||
public final [ResolvedTo(CONTRACTS)] val nullablePropertyWithAnnotatedType: R|@R|Anno|(String(outer)) kotlin/collections/List<@R|Anno|(String(middle)) kotlin/collections/List<@R|Anno|(String(inner)) kotlin/Int>>?|
|
||||
public [ResolvedTo(CONTRACTS)] get(): R|@R|Anno|(String(outer)) kotlin/collections/List<@R|Anno|(String(middle)) kotlin/collections/List<@R|Anno|(String(inner)) kotlin/Int>>?| {
|
||||
^ Null(null)
|
||||
}
|
||||
public final [ResolvedTo(BODY_RESOLVE)] val propertyToResolve: R|kotlin/String|
|
||||
|
||||
Vendored
+3
-3
@@ -229,13 +229,13 @@ FILE: [ResolvedTo(IMPORTS)] anonymousFunctionWithAnnotatedParameter2.kt
|
||||
public [ResolvedTo(STATUS)] [ContainingClassKey=Anno] get(): R|kotlin/String|
|
||||
|
||||
}
|
||||
public final [ResolvedTo(CONTRACTS)] val nullablePropertyWithAnnotatedType: R|@R|Anno|(message = String(outer)) kotlin/collections/List<@R|Anno|(message = String(middle)) kotlin/collections/List<@R|Anno|(message = String(inner)) kotlin/Int>>?|
|
||||
public [ResolvedTo(CONTRACTS)] get(): R|@R|Anno|(message = String(outer)) kotlin/collections/List<@R|Anno|(message = String(middle)) kotlin/collections/List<@R|Anno|(message = String(inner)) kotlin/Int>>?| {
|
||||
public final [ResolvedTo(CONTRACTS)] val nullablePropertyWithAnnotatedType: R|@R|Anno|(String(outer)) kotlin/collections/List<@R|Anno|(String(middle)) kotlin/collections/List<@R|Anno|(String(inner)) kotlin/Int>>?|
|
||||
public [ResolvedTo(CONTRACTS)] get(): R|@R|Anno|(String(outer)) kotlin/collections/List<@R|Anno|(String(middle)) kotlin/collections/List<@R|Anno|(String(inner)) kotlin/Int>>?| {
|
||||
^ Null(null)
|
||||
}
|
||||
public final [ResolvedTo(BODY_RESOLVE)] val propertyToResolve: R|kotlin/String|
|
||||
public [ResolvedTo(BODY_RESOLVE)] get(): R|kotlin/String| {
|
||||
^ R|/nullablePropertyWithAnnotatedType|.R|kotlin/let|<R|@R|Anno|(message = String(outer)) kotlin/collections/List<@R|Anno|(message = String(middle)) kotlin/collections/List<@R|Anno|(message = String(inner)) kotlin/Int>>?|, R|kotlin/String|>(<L> = [ResolvedTo(BODY_RESOLVE)] [MatchingParameterFunctionTypeKey=kotlin/Function1<T, R>] let@fun <anonymous>([ResolvedTo(BODY_RESOLVE)] it: R|@R|Anno|(message = String(outer)) kotlin/collections/List<@R|Anno|(message = String(middle)) kotlin/collections/List<@R|Anno|(message = String(inner)) kotlin/Int>>?|): R|kotlin/String| <inline=Inline, kind=EXACTLY_ONCE> {
|
||||
^ R|/nullablePropertyWithAnnotatedType|.R|kotlin/let|<R|@R|Anno|(String(outer)) kotlin/collections/List<@R|Anno|(String(middle)) kotlin/collections/List<@R|Anno|(String(inner)) kotlin/Int>>?|, R|kotlin/String|>(<L> = [ResolvedTo(BODY_RESOLVE)] [MatchingParameterFunctionTypeKey=kotlin/Function1<T, R>] let@fun <anonymous>([ResolvedTo(BODY_RESOLVE)] it: R|@R|Anno|(message = String(outer)) kotlin/collections/List<@R|Anno|(message = String(middle)) kotlin/collections/List<@R|Anno|(message = String(inner)) kotlin/Int>>?|): R|kotlin/String| <inline=Inline, kind=EXACTLY_ONCE> {
|
||||
^ <strcat>(String( (), R|<local>/it|, String()))
|
||||
}
|
||||
)
|
||||
|
||||
+6
-6
@@ -185,8 +185,8 @@ FILE: [ResolvedTo(IMPORTS)] anonymousFunctionWithAnnotatedParameterOnImplicitTyp
|
||||
public [ResolvedTo(STATUS)] [ContainingClassKey=Anno] get(): R|kotlin/String|
|
||||
|
||||
}
|
||||
public final [ResolvedTo(CONTRACTS)] val nullablePropertyWithAnnotatedType: R|@R|Anno|(message = String(str)) kotlin/String?|
|
||||
public [ResolvedTo(CONTRACTS)] get(): R|@R|Anno|(message = String(str)) kotlin/String?| {
|
||||
public final [ResolvedTo(CONTRACTS)] val nullablePropertyWithAnnotatedType: R|@R|Anno|(String(str)) kotlin/String?|
|
||||
public [ResolvedTo(CONTRACTS)] get(): R|@R|Anno|(String(str)) kotlin/String?| {
|
||||
^ Null(null)
|
||||
}
|
||||
public final [ResolvedTo(IMPLICIT_TYPES_BODY_RESOLVE)] val propertyToResolve: R|kotlin/String|
|
||||
@@ -209,8 +209,8 @@ FILE: [ResolvedTo(IMPORTS)] anonymousFunctionWithAnnotatedParameterOnImplicitTyp
|
||||
public [ResolvedTo(STATUS)] [ContainingClassKey=Anno] get(): R|kotlin/String|
|
||||
|
||||
}
|
||||
public final [ResolvedTo(CONTRACTS)] val nullablePropertyWithAnnotatedType: R|@R|Anno|(message = String(str)) kotlin/String?|
|
||||
public [ResolvedTo(CONTRACTS)] get(): R|@R|Anno|(message = String(str)) kotlin/String?| {
|
||||
public final [ResolvedTo(CONTRACTS)] val nullablePropertyWithAnnotatedType: R|@R|Anno|(String(str)) kotlin/String?|
|
||||
public [ResolvedTo(CONTRACTS)] get(): R|@R|Anno|(String(str)) kotlin/String?| {
|
||||
^ Null(null)
|
||||
}
|
||||
public final [ResolvedTo(ANNOTATIONS_ARGUMENTS_MAPPING)] val propertyToResolve: R|kotlin/String|
|
||||
@@ -233,8 +233,8 @@ FILE: [ResolvedTo(IMPORTS)] anonymousFunctionWithAnnotatedParameterOnImplicitTyp
|
||||
public [ResolvedTo(STATUS)] [ContainingClassKey=Anno] get(): R|kotlin/String|
|
||||
|
||||
}
|
||||
public final [ResolvedTo(CONTRACTS)] val nullablePropertyWithAnnotatedType: R|@R|Anno|(message = String(str)) kotlin/String?|
|
||||
public [ResolvedTo(CONTRACTS)] get(): R|@R|Anno|(message = String(str)) kotlin/String?| {
|
||||
public final [ResolvedTo(CONTRACTS)] val nullablePropertyWithAnnotatedType: R|@R|Anno|(String(str)) kotlin/String?|
|
||||
public [ResolvedTo(CONTRACTS)] get(): R|@R|Anno|(String(str)) kotlin/String?| {
|
||||
^ Null(null)
|
||||
}
|
||||
public final [ResolvedTo(BODY_RESOLVE)] val propertyToResolve: R|kotlin/String|
|
||||
|
||||
+12
@@ -1159,6 +1159,18 @@ public class OutOfContentRootGetOrBuildFirTestGenerated extends AbstractOutOfCon
|
||||
runTest("analysis/low-level-api-fir/testdata/getOrBuildFir/wholeDeclaration/primaryConstructorValueParameter.kt");
|
||||
}
|
||||
|
||||
@Test
|
||||
@TestMetadata("propagateFlexibleTypeToAnonymousFunction.kt")
|
||||
public void testPropagateFlexibleTypeToAnonymousFunction() throws Exception {
|
||||
runTest("analysis/low-level-api-fir/testdata/getOrBuildFir/wholeDeclaration/propagateFlexibleTypeToAnonymousFunction.kt");
|
||||
}
|
||||
|
||||
@Test
|
||||
@TestMetadata("propagateFlexibleTypeToAnonymousFunction2.kt")
|
||||
public void testPropagateFlexibleTypeToAnonymousFunction2() throws Exception {
|
||||
runTest("analysis/low-level-api-fir/testdata/getOrBuildFir/wholeDeclaration/propagateFlexibleTypeToAnonymousFunction2.kt");
|
||||
}
|
||||
|
||||
@Test
|
||||
@TestMetadata("secondaryConstructorValueParameter.kt")
|
||||
public void testSecondaryConstructorValueParameter() throws Exception {
|
||||
|
||||
+12
@@ -1159,6 +1159,18 @@ public class SourceGetOrBuildFirTestGenerated extends AbstractSourceGetOrBuildFi
|
||||
runTest("analysis/low-level-api-fir/testdata/getOrBuildFir/wholeDeclaration/primaryConstructorValueParameter.kt");
|
||||
}
|
||||
|
||||
@Test
|
||||
@TestMetadata("propagateFlexibleTypeToAnonymousFunction.kt")
|
||||
public void testPropagateFlexibleTypeToAnonymousFunction() throws Exception {
|
||||
runTest("analysis/low-level-api-fir/testdata/getOrBuildFir/wholeDeclaration/propagateFlexibleTypeToAnonymousFunction.kt");
|
||||
}
|
||||
|
||||
@Test
|
||||
@TestMetadata("propagateFlexibleTypeToAnonymousFunction2.kt")
|
||||
public void testPropagateFlexibleTypeToAnonymousFunction2() throws Exception {
|
||||
runTest("analysis/low-level-api-fir/testdata/getOrBuildFir/wholeDeclaration/propagateFlexibleTypeToAnonymousFunction2.kt");
|
||||
}
|
||||
|
||||
@Test
|
||||
@TestMetadata("secondaryConstructorValueParameter.kt")
|
||||
public void testSecondaryConstructorValueParameter() throws Exception {
|
||||
|
||||
+6
@@ -20258,6 +20258,12 @@ public class DiagnosticCompilerTestFE10TestdataTestGenerated extends AbstractDia
|
||||
runTest("compiler/testData/diagnostics/tests/j+k/privatePropertyAndSetterMultiModule.kt");
|
||||
}
|
||||
|
||||
@Test
|
||||
@TestMetadata("propagateFlexibleTypeToAnonymousFunction.kt")
|
||||
public void testPropagateFlexibleTypeToAnonymousFunction() throws Exception {
|
||||
runTest("compiler/testData/diagnostics/tests/j+k/propagateFlexibleTypeToAnonymousFunction.kt");
|
||||
}
|
||||
|
||||
@Test
|
||||
@TestMetadata("protectedStaticSamePackage.kt")
|
||||
public void testProtectedStaticSamePackage() throws Exception {
|
||||
|
||||
+6
@@ -20258,6 +20258,12 @@ public class LLFirPreresolvedReversedDiagnosticCompilerFE10TestDataTestGenerated
|
||||
runTest("compiler/testData/diagnostics/tests/j+k/privatePropertyAndSetterMultiModule.kt");
|
||||
}
|
||||
|
||||
@Test
|
||||
@TestMetadata("propagateFlexibleTypeToAnonymousFunction.kt")
|
||||
public void testPropagateFlexibleTypeToAnonymousFunction() throws Exception {
|
||||
runTest("compiler/testData/diagnostics/tests/j+k/propagateFlexibleTypeToAnonymousFunction.kt");
|
||||
}
|
||||
|
||||
@Test
|
||||
@TestMetadata("protectedStaticSamePackage.kt")
|
||||
public void testProtectedStaticSamePackage() throws Exception {
|
||||
|
||||
+6
@@ -20258,6 +20258,12 @@ public class FirLightTreeOldFrontendDiagnosticsTestGenerated extends AbstractFir
|
||||
runTest("compiler/testData/diagnostics/tests/j+k/privatePropertyAndSetterMultiModule.kt");
|
||||
}
|
||||
|
||||
@Test
|
||||
@TestMetadata("propagateFlexibleTypeToAnonymousFunction.kt")
|
||||
public void testPropagateFlexibleTypeToAnonymousFunction() throws Exception {
|
||||
runTest("compiler/testData/diagnostics/tests/j+k/propagateFlexibleTypeToAnonymousFunction.kt");
|
||||
}
|
||||
|
||||
@Test
|
||||
@TestMetadata("protectedStaticSamePackage.kt")
|
||||
public void testProtectedStaticSamePackage() throws Exception {
|
||||
|
||||
+6
@@ -20264,6 +20264,12 @@ public class FirPsiOldFrontendDiagnosticsTestGenerated extends AbstractFirPsiDia
|
||||
runTest("compiler/testData/diagnostics/tests/j+k/privatePropertyAndSetterMultiModule.kt");
|
||||
}
|
||||
|
||||
@Test
|
||||
@TestMetadata("propagateFlexibleTypeToAnonymousFunction.kt")
|
||||
public void testPropagateFlexibleTypeToAnonymousFunction() throws Exception {
|
||||
runTest("compiler/testData/diagnostics/tests/j+k/propagateFlexibleTypeToAnonymousFunction.kt");
|
||||
}
|
||||
|
||||
@Test
|
||||
@TestMetadata("protectedStaticSamePackage.kt")
|
||||
public void testProtectedStaticSamePackage() throws Exception {
|
||||
|
||||
@@ -100,6 +100,73 @@ fun ConeDefinitelyNotNullType.Companion.create(
|
||||
fun ConeDynamicType.Companion.create(session: FirSession): ConeDynamicType =
|
||||
ConeDynamicType(session.builtinTypes.nothingType.type, session.builtinTypes.nullableAnyType.type)
|
||||
|
||||
/**
|
||||
* This call is required if you want to use a type with annotations that are linked to a declaration from this declaration inside another
|
||||
* to avoid concurrent modification problems (see KT-60387).
|
||||
*
|
||||
* Otherwise, those annotations can be transformed from different threads simultaneously that is error-prone.
|
||||
* Example:
|
||||
* ```kotlin
|
||||
* val declaration: @Anno("outer") Int? get() = null
|
||||
* val anotherDeclaration: String get() = declaration?.let { "$it" }.toString()
|
||||
* ```
|
||||
* here for `declaration?.let { "$it" }` will be created an anonymous function with argument that
|
||||
* will have the same type as the return type of `declaration`.
|
||||
* So, now we have 2 possible scenarios:
|
||||
*
|
||||
* Wrong case 1 – The type was inserted to a new type ref as it is.
|
||||
* This means that a type reference from `declaration` and from the anonymous lambda will have the same instance of `Anno`.
|
||||
* Now we resole `anotherDeclaration` to [FirResolvePhase.BODY_RESOLVE] phase
|
||||
* and as a result we will have resolved annotation arguments in the type.
|
||||
* At the same time, `declaration` can be still in [FirResolvePhase.CONTRACTS] phase, because no one called a resolution yet.
|
||||
* So now imagine a situation when one thread (1) wants to read annotation arguments from the fully resolved anonymous function,
|
||||
* and another thread (2) wants to resolve `declaration` to [FirResolvePhase.ANNOTATIONS_ARGUMENTS_MAPPING] phase.
|
||||
* As a result, we will have a moment there thread 2 will replace arguments with a lazy expression
|
||||
* to be sure that we will have a safe basis for resolution (see StateKeeper concept in LL FIR).
|
||||
* And thread 1 will see unexpected unresolved annotation arguments in fully resolved function, because those type references
|
||||
* use the same instance of the type (`FirArgumentListImpl` cannot be cast to `FirResolvedArgumentList`).
|
||||
* So we lost here.
|
||||
*
|
||||
* Right case 2 – The type was "copied" by [independentInstance].
|
||||
* In this case, `declaration` and `anotherDeclaration` will have different instances of one `@Anno("outer") Int?` type.
|
||||
* This means that we can't come to a situation where we can modify a fully resolved annotation from another thread.
|
||||
*
|
||||
* @return an instance of a type that has no annotations associated with any declaration,
|
||||
* so it won't be changed from LL FIR lazy transformers concurrently
|
||||
*
|
||||
* @see CustomAnnotationTypeAttribute.independentInstance
|
||||
*/
|
||||
fun ConeKotlinType.independentInstance(): ConeKotlinType = instanceWithIndependentArguments().instanceWithIndependentAnnotations()
|
||||
|
||||
private fun ConeKotlinType.instanceWithIndependentArguments(): ConeKotlinType {
|
||||
val typeProjections = typeArguments
|
||||
if (typeProjections.isEmpty()) return this
|
||||
|
||||
var argumentsChanged = false
|
||||
val newArguments = type.typeArguments.map { originalArgument ->
|
||||
if (originalArgument !is ConeKotlinType)
|
||||
originalArgument
|
||||
else
|
||||
originalArgument.independentInstance().also {
|
||||
if (it !== originalArgument) {
|
||||
argumentsChanged = true
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return if (argumentsChanged) withArguments(newArguments.toTypedArray()) else this
|
||||
}
|
||||
|
||||
private fun ConeKotlinType.instanceWithIndependentAnnotations(): ConeKotlinType {
|
||||
val custom = attributes.custom ?: return this
|
||||
val newAnnotations = custom.independentInstance()
|
||||
if (newAnnotations === custom) {
|
||||
return this
|
||||
}
|
||||
|
||||
val newAttributes = attributes.remove(custom).plus(newAnnotations)
|
||||
return withAttributes(newAttributes)
|
||||
}
|
||||
|
||||
fun ConeKotlinType.makeConeTypeDefinitelyNotNullOrNotNull(
|
||||
typeContext: ConeTypeContext,
|
||||
|
||||
@@ -481,9 +481,8 @@ fun FirCheckedSafeCallSubject.propagateTypeFromOriginalReceiver(
|
||||
.coneTypeSafe<ConeKotlinType>() ?: return
|
||||
|
||||
val expandedReceiverType = receiverType.fullyExpandedType(session)
|
||||
|
||||
val resolvedTypeRef =
|
||||
typeRef.resolvedTypeFromPrototype(expandedReceiverType.makeConeTypeDefinitelyNotNullOrNotNull(session.typeContext))
|
||||
val updatedReceiverType = expandedReceiverType.makeConeTypeDefinitelyNotNullOrNotNull(session.typeContext).independentInstance()
|
||||
val resolvedTypeRef = typeRef.resolvedTypeFromPrototype(updatedReceiverType)
|
||||
replaceTypeRef(resolvedTypeRef)
|
||||
session.lookupTracker?.recordTypeResolveAsLookup(resolvedTypeRef, source, file.source)
|
||||
}
|
||||
@@ -506,7 +505,7 @@ fun FirSafeCallExpression.propagateTypeFromQualifiedAccessAfterNullCheck(
|
||||
}
|
||||
}
|
||||
|
||||
val resolvedTypeRef = typeRef.resolvedTypeFromPrototype(resultingType)
|
||||
val resolvedTypeRef = typeRef.resolvedTypeFromPrototype(resultingType.independentInstance())
|
||||
replaceTypeRef(resolvedTypeRef)
|
||||
session.lookupTracker?.recordTypeResolveAsLookup(resolvedTypeRef, source, file.source)
|
||||
}
|
||||
|
||||
+1
-1
@@ -118,7 +118,7 @@ class PostponedArgumentsAnalyzer(
|
||||
val stubsForPostponedVariables = c.bindingStubsForPostponedVariables()
|
||||
val currentSubstitutor = c.buildCurrentSubstitutor(stubsForPostponedVariables.mapKeys { it.key.freshTypeConstructor(c) })
|
||||
|
||||
fun substitute(type: ConeKotlinType) = currentSubstitutor.safeSubstitute(c, type) as ConeKotlinType
|
||||
fun substitute(type: ConeKotlinType) = (currentSubstitutor.safeSubstitute(c, type) as ConeKotlinType).independentInstance()
|
||||
|
||||
val receiver = lambda.receiver?.let(::substitute)
|
||||
val contextReceivers = lambda.contextReceivers.map(::substitute)
|
||||
|
||||
@@ -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>()
|
||||
|
||||
+22
@@ -0,0 +1,22 @@
|
||||
// FIR_IDENTICAL
|
||||
// FILE: usage.kt
|
||||
val propertyToResolve: String
|
||||
get() = JavaClass.function()?.let { " ($it)" } ?: ""
|
||||
|
||||
// FILE: Anno.java
|
||||
import java.lang.annotation.ElementType;
|
||||
import java.lang.annotation.Target;
|
||||
|
||||
@Target(ElementType.TYPE_USE)
|
||||
public @interface Anno {
|
||||
String value();
|
||||
}
|
||||
|
||||
// FILE: JavaClass.java
|
||||
import java.util.List;
|
||||
|
||||
public class JavaClass {
|
||||
public static @Anno("outer") List<@Anno("middle") List<@Anno("inner") Integer>> function() {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
Generated
+6
@@ -20264,6 +20264,12 @@ public class DiagnosticTestGenerated extends AbstractDiagnosticTest {
|
||||
runTest("compiler/testData/diagnostics/tests/j+k/privatePropertyAndSetterMultiModule.kt");
|
||||
}
|
||||
|
||||
@Test
|
||||
@TestMetadata("propagateFlexibleTypeToAnonymousFunction.kt")
|
||||
public void testPropagateFlexibleTypeToAnonymousFunction() throws Exception {
|
||||
runTest("compiler/testData/diagnostics/tests/j+k/propagateFlexibleTypeToAnonymousFunction.kt");
|
||||
}
|
||||
|
||||
@Test
|
||||
@TestMetadata("protectedStaticSamePackage.kt")
|
||||
public void testProtectedStaticSamePackage() throws Exception {
|
||||
|
||||
Reference in New Issue
Block a user