From 264a151676ecf41701e5ca54bcaa6fa01383f3cd Mon Sep 17 00:00:00 2001 From: Dmitrii Gridin Date: Fri, 24 Nov 2023 15:20:13 +0100 Subject: [PATCH] [FIR] do not copy annotations during type propagation We should share the original instance to be able to later resolve it in the original context. This commit returns the KT-60387 problem, but the root cause (concurrent modification) will be fixed in the context of KT-63042 ^KT-63042 --- .../lambdaAsSAMInterfaceWithAnnotation.txt | 2 +- ...nonymousFunctionWithAnnotatedParameter.txt | 4 +- ...onymousFunctionWithAnnotatedParameter2.txt | 6 +- ...sFunctionWithAnnotatedParameter2Script.txt | 7 +- ...hAnnotatedParameterOnImplicitTypePhase.txt | 12 +-- ...atedParameterOnImplicitTypePhaseScript.txt | 13 +-- ...usFunctionWithAnnotatedParameterScript.txt | 5 +- ...cessibleAnnotationArgument.lazyResolve.txt | 4 +- .../jetbrains/kotlin/fir/types/TypeUtils.kt | 83 ------------------- .../kotlin/fir/resolve/ResolveUtils.kt | 14 ++-- .../inference/PostponedArgumentsAnalyzer.kt | 4 +- .../types/CustomAnnotationTypeAttribute.kt | 24 ------ 12 files changed, 36 insertions(+), 142 deletions(-) diff --git a/analysis/low-level-api-fir/testData/getOrBuildFir/wholeDeclaration/lambdaAsSAMInterfaceWithAnnotation.txt b/analysis/low-level-api-fir/testData/getOrBuildFir/wholeDeclaration/lambdaAsSAMInterfaceWithAnnotation.txt index 3fefb311ba1..81e3801cfd8 100644 --- a/analysis/low-level-api-fir/testData/getOrBuildFir/wholeDeclaration/lambdaAsSAMInterfaceWithAnnotation.txt +++ b/analysis/low-level-api-fir/testData/getOrBuildFir/wholeDeclaration/lambdaAsSAMInterfaceWithAnnotation.txt @@ -32,7 +32,7 @@ FILE: [ResolvedTo(IMPORTS)] lambdaAsSAMInterfaceWithAnnotation.kt public final const [ResolvedTo(IMPLICIT_TYPES_BODY_RESOLVE)] val constant: R|kotlin/Int| = Int(0) public [ResolvedTo(IMPLICIT_TYPES_BODY_RESOLVE)] get(): R|kotlin/Int| public abstract fun [ResolvedTo(STATUS)] interface Foo : R|kotlin/Any| { - public abstract [ResolvedTo(STATUS)] fun foo([ResolvedTo(STATUS)] a: R|@R|foo/Anno|((String(foo param type ), R|foo/constant|)) foo/Arg|): R|@R|foo/Anno|((String(foo return type ), R|foo/constant|)) foo/Arg| + public abstract [ResolvedTo(STATUS)] fun foo([ResolvedTo(STATUS)] a: R|@R|foo/Anno|(position = (String(foo param type ), R|foo/constant|)) foo/Arg|): R|@R|foo/Anno|(position = (String(foo return type ), R|foo/constant|)) foo/Arg| } public final [ResolvedTo(CONTRACTS)] fun testMe([ResolvedTo(CONTRACTS)] f: R|@R|foo/Anno|((String(testMe param type ), constant#)) foo/Foo|): R|kotlin/Unit| { diff --git a/analysis/low-level-api-fir/testData/lazyResolve/anonymousFunctionWithAnnotatedParameter.txt b/analysis/low-level-api-fir/testData/lazyResolve/anonymousFunctionWithAnnotatedParameter.txt index 37cc018a894..498737b78af 100644 --- a/analysis/low-level-api-fir/testData/lazyResolve/anonymousFunctionWithAnnotatedParameter.txt +++ b/analysis/low-level-api-fir/testData/lazyResolve/anonymousFunctionWithAnnotatedParameter.txt @@ -200,8 +200,8 @@ FILE: [ResolvedTo(IMPORTS)] anonymousFunctionWithAnnotatedParameter.kt public [ResolvedTo(STATUS)] [ContainingClassKey=Anno] get(): R|kotlin/String| } - 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>>?| { + 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>>?| { ^ Null(null) } public final [ResolvedTo(BODY_RESOLVE)] val propertyToResolve: R|kotlin/String| diff --git a/analysis/low-level-api-fir/testData/lazyResolve/anonymousFunctionWithAnnotatedParameter2.txt b/analysis/low-level-api-fir/testData/lazyResolve/anonymousFunctionWithAnnotatedParameter2.txt index 5610fcfd410..9fd50c3c5f2 100644 --- a/analysis/low-level-api-fir/testData/lazyResolve/anonymousFunctionWithAnnotatedParameter2.txt +++ b/analysis/low-level-api-fir/testData/lazyResolve/anonymousFunctionWithAnnotatedParameter2.txt @@ -200,13 +200,13 @@ FILE: [ResolvedTo(IMPORTS)] anonymousFunctionWithAnnotatedParameter2.kt public [ResolvedTo(STATUS)] [ContainingClassKey=Anno] get(): R|kotlin/String| } - 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>>?| { + 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>>?| { ^ 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|kotlin/String|>( = [ResolvedTo(BODY_RESOLVE)] [MatchingParameterFunctionTypeKey=kotlin/Function1] let@fun ([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| { + ^ R|/nullablePropertyWithAnnotatedType|.R|kotlin/let|>?|, R|kotlin/String|>( = [ResolvedTo(BODY_RESOLVE)] [MatchingParameterFunctionTypeKey=kotlin/Function1] let@fun ([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| { ^ (String( (), R|/it|, String())) } ) diff --git a/analysis/low-level-api-fir/testData/lazyResolve/anonymousFunctionWithAnnotatedParameter2Script.txt b/analysis/low-level-api-fir/testData/lazyResolve/anonymousFunctionWithAnnotatedParameter2Script.txt index b016e48aeda..66ffb75a291 100644 --- a/analysis/low-level-api-fir/testData/lazyResolve/anonymousFunctionWithAnnotatedParameter2Script.txt +++ b/analysis/low-level-api-fir/testData/lazyResolve/anonymousFunctionWithAnnotatedParameter2Script.txt @@ -282,14 +282,14 @@ FILE: [ResolvedTo(IMPORTS)] anonymousFunctionWithAnnotatedParameter2Script.kts } - 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>>?| { + 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>>?| { ^ 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|kotlin/String|>( = [ResolvedTo(BODY_RESOLVE)] [MatchingParameterFunctionTypeKey=kotlin/Function1] let@fun ([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| { + ^ R|/nullablePropertyWithAnnotatedType|.R|kotlin/let|>?|, R|kotlin/String|>( = [ResolvedTo(BODY_RESOLVE)] [MatchingParameterFunctionTypeKey=kotlin/Function1] let@fun ([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| { ^ (String( (), R|/it|, String())) } ) @@ -324,3 +324,4 @@ FILE: [ResolvedTo(BODY_RESOLVE)] anonymousFunctionWithAnnotatedParameter2Script. } ) } + diff --git a/analysis/low-level-api-fir/testData/lazyResolve/anonymousFunctionWithAnnotatedParameterOnImplicitTypePhase.txt b/analysis/low-level-api-fir/testData/lazyResolve/anonymousFunctionWithAnnotatedParameterOnImplicitTypePhase.txt index ac78dfc6ba5..d169354c6be 100644 --- a/analysis/low-level-api-fir/testData/lazyResolve/anonymousFunctionWithAnnotatedParameterOnImplicitTypePhase.txt +++ b/analysis/low-level-api-fir/testData/lazyResolve/anonymousFunctionWithAnnotatedParameterOnImplicitTypePhase.txt @@ -158,8 +158,8 @@ FILE: [ResolvedTo(IMPORTS)] anonymousFunctionWithAnnotatedParameterOnImplicitTyp public [ResolvedTo(STATUS)] [ContainingClassKey=Anno] get(): R|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?| { + 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?| { ^ Null(null) } public final [ResolvedTo(IMPLICIT_TYPES_BODY_RESOLVE)] val propertyToResolve: R|kotlin/String| @@ -181,8 +181,8 @@ FILE: [ResolvedTo(IMPORTS)] anonymousFunctionWithAnnotatedParameterOnImplicitTyp public [ResolvedTo(STATUS)] [ContainingClassKey=Anno] get(): R|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?| { + 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?| { ^ Null(null) } public final [ResolvedTo(ANNOTATION_ARGUMENTS)] val propertyToResolve: R|kotlin/String| @@ -204,8 +204,8 @@ FILE: [ResolvedTo(IMPORTS)] anonymousFunctionWithAnnotatedParameterOnImplicitTyp public [ResolvedTo(STATUS)] [ContainingClassKey=Anno] get(): R|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?| { + 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?| { ^ Null(null) } public final [ResolvedTo(BODY_RESOLVE)] val propertyToResolve: R|kotlin/String| diff --git a/analysis/low-level-api-fir/testData/lazyResolve/anonymousFunctionWithAnnotatedParameterOnImplicitTypePhaseScript.txt b/analysis/low-level-api-fir/testData/lazyResolve/anonymousFunctionWithAnnotatedParameterOnImplicitTypePhaseScript.txt index dff18a6a9c3..aea8eddd415 100644 --- a/analysis/low-level-api-fir/testData/lazyResolve/anonymousFunctionWithAnnotatedParameterOnImplicitTypePhaseScript.txt +++ b/analysis/low-level-api-fir/testData/lazyResolve/anonymousFunctionWithAnnotatedParameterOnImplicitTypePhaseScript.txt @@ -226,8 +226,8 @@ FILE: [ResolvedTo(IMPORTS)] anonymousFunctionWithAnnotatedParameterOnImplicitTyp } - public final [ResolvedTo(CONTRACTS)] val nullablePropertyWithAnnotatedType: R|@R|Anno|(String(str)) kotlin/String?| - public [ResolvedTo(CONTRACTS)] get(): R|@R|Anno|(String(str)) 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?| { ^ Null(null) } @@ -256,8 +256,8 @@ FILE: [ResolvedTo(IMPORTS)] anonymousFunctionWithAnnotatedParameterOnImplicitTyp } - public final [ResolvedTo(CONTRACTS)] val nullablePropertyWithAnnotatedType: R|@R|Anno|(String(str)) kotlin/String?| - public [ResolvedTo(CONTRACTS)] get(): R|@R|Anno|(String(str)) 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?| { ^ Null(null) } @@ -286,8 +286,8 @@ FILE: [ResolvedTo(IMPORTS)] anonymousFunctionWithAnnotatedParameterOnImplicitTyp } - public final [ResolvedTo(CONTRACTS)] val nullablePropertyWithAnnotatedType: R|@R|Anno|(String(str)) kotlin/String?| - public [ResolvedTo(CONTRACTS)] get(): R|@R|Anno|(String(str)) 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?| { ^ Null(null) } @@ -328,3 +328,4 @@ FILE: [ResolvedTo(BODY_RESOLVE)] anonymousFunctionWithAnnotatedParameterOnImplic } ) } ?: String() } + diff --git a/analysis/low-level-api-fir/testData/lazyResolve/anonymousFunctionWithAnnotatedParameterScript.txt b/analysis/low-level-api-fir/testData/lazyResolve/anonymousFunctionWithAnnotatedParameterScript.txt index 74cc2e630ea..cbd451d7b3e 100644 --- a/analysis/low-level-api-fir/testData/lazyResolve/anonymousFunctionWithAnnotatedParameterScript.txt +++ b/analysis/low-level-api-fir/testData/lazyResolve/anonymousFunctionWithAnnotatedParameterScript.txt @@ -282,8 +282,8 @@ FILE: [ResolvedTo(IMPORTS)] anonymousFunctionWithAnnotatedParameterScript.kts } - 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>>?| { + 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>>?| { ^ Null(null) } @@ -324,3 +324,4 @@ FILE: [ResolvedTo(BODY_RESOLVE)] anonymousFunctionWithAnnotatedParameterScript.k } ) } ?: String() } + diff --git a/analysis/low-level-api-fir/testData/lazyResolveTypeAnnotations/function/typePropagationFromPropertyWithInaccessibleAnnotationArgument.lazyResolve.txt b/analysis/low-level-api-fir/testData/lazyResolveTypeAnnotations/function/typePropagationFromPropertyWithInaccessibleAnnotationArgument.lazyResolve.txt index 3ea2af3292b..efc66f79289 100644 --- a/analysis/low-level-api-fir/testData/lazyResolveTypeAnnotations/function/typePropagationFromPropertyWithInaccessibleAnnotationArgument.lazyResolve.txt +++ b/analysis/low-level-api-fir/testData/lazyResolveTypeAnnotations/function/typePropagationFromPropertyWithInaccessibleAnnotationArgument.lazyResolve.txt @@ -294,8 +294,8 @@ FILE: [ResolvedTo(IMPORTS)] declaration.kt public [ResolvedTo(STATUS)] [ContainingClassKey=Anno] get(): R|kotlin/String| } - public final [ResolvedTo(CONTRACTS)] val nullablePropertyWithAnnotatedType: R|@R|Anno|(R|/privateConstant#|) kotlin/collections/List<@R|Anno|(R|/internalConstant#|) kotlin/collections/List<@R|Anno|(R|/regularConstant|) kotlin/Int>>?| - public [ResolvedTo(CONTRACTS)] get(): R|@R|Anno|(R|/privateConstant#|) kotlin/collections/List<@R|Anno|(R|/internalConstant#|) kotlin/collections/List<@R|Anno|(R|/regularConstant|) kotlin/Int>>?| { + public final [ResolvedTo(CONTRACTS)] val nullablePropertyWithAnnotatedType: R|@R|Anno|(message = R|/privateConstant#|) kotlin/collections/List<@R|Anno|(message = R|/internalConstant#|) kotlin/collections/List<@R|Anno|(message = R|/regularConstant|) kotlin/Int>>?| + public [ResolvedTo(CONTRACTS)] get(): R|@R|Anno|(message = R|/privateConstant#|) kotlin/collections/List<@R|Anno|(message = R|/internalConstant#|) kotlin/collections/List<@R|Anno|(message = R|/regularConstant|) kotlin/Int>>?| { ^ Null(null) } diff --git a/compiler/fir/providers/src/org/jetbrains/kotlin/fir/types/TypeUtils.kt b/compiler/fir/providers/src/org/jetbrains/kotlin/fir/types/TypeUtils.kt index fa4bba4ca3b..453f354ed1f 100644 --- a/compiler/fir/providers/src/org/jetbrains/kotlin/fir/types/TypeUtils.kt +++ b/compiler/fir/providers/src/org/jetbrains/kotlin/fir/types/TypeUtils.kt @@ -106,89 +106,6 @@ fun ConeDynamicType.Companion.create( session.builtinTypes.nullableAnyType.type.withAttributes(attributes), ) -/** - * 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.ANNOTATION_ARGUMENTS] 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 - */ -@OptIn(DynamicTypeConstructor::class) -fun ConeKotlinType.independentInstance(): ConeKotlinType = if (this is ConeFlexibleType) { - val newLowerBound = lowerBound.independentInstance() as ConeSimpleKotlinType - val newUpperBound = upperBound.independentInstance() as ConeSimpleKotlinType - if (newLowerBound !== lowerBound || newUpperBound !== upperBound) { - when (this) { - is ConeRawType -> ConeRawType.create(newLowerBound, newUpperBound) - is ConeDynamicType -> ConeDynamicType(newLowerBound, newUpperBound) - else -> ConeFlexibleType(newLowerBound, newUpperBound) - } - } else { - this - } -} else { - 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, avoidComprehensiveCheck: Boolean = false, diff --git a/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/ResolveUtils.kt b/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/ResolveUtils.kt index b17c50e33fc..b8215593f92 100644 --- a/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/ResolveUtils.kt +++ b/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/ResolveUtils.kt @@ -1,5 +1,5 @@ /* - * Copyright 2010-2022 JetBrains s.r.o. and Kotlin Programming Language contributors. + * Copyright 2010-2023 JetBrains s.r.o. and Kotlin Programming Language contributors. * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file. */ @@ -476,10 +476,9 @@ fun FirCheckedSafeCallSubject.propagateTypeFromOriginalReceiver( ?.coneTypeSafe() ?: nullableReceiverExpression.resolvedType - val expandedReceiverType = receiverType.fullyExpandedType(session) - val updatedReceiverType = expandedReceiverType.makeConeTypeDefinitelyNotNullOrNotNull(session.typeContext).independentInstance() - replaceConeTypeOrNull(updatedReceiverType) - session.lookupTracker?.recordTypeResolveAsLookup(updatedReceiverType, source, file.source) + val expandedReceiverType = receiverType.fullyExpandedType(session).makeConeTypeDefinitelyNotNullOrNotNull(session.typeContext) + replaceConeTypeOrNull(expandedReceiverType) + session.lookupTracker?.recordTypeResolveAsLookup(expandedReceiverType, source, file.source) } fun FirSafeCallExpression.propagateTypeFromQualifiedAccessAfterNullCheck( @@ -500,9 +499,8 @@ fun FirSafeCallExpression.propagateTypeFromQualifiedAccessAfterNullCheck( } } - val independentInstance = resultingType.independentInstance() - replaceConeTypeOrNull(independentInstance) - session.lookupTracker?.recordTypeResolveAsLookup(independentInstance, source, file.source) + replaceConeTypeOrNull(resultingType) + session.lookupTracker?.recordTypeResolveAsLookup(resultingType, source, file.source) } fun FirAnnotation.getCorrespondingClassSymbolOrNull(session: FirSession): FirRegularClassSymbol? { diff --git a/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/inference/PostponedArgumentsAnalyzer.kt b/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/inference/PostponedArgumentsAnalyzer.kt index da59c999ec8..b0a7342c14c 100644 --- a/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/inference/PostponedArgumentsAnalyzer.kt +++ b/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/inference/PostponedArgumentsAnalyzer.kt @@ -1,5 +1,5 @@ /* - * Copyright 2010-2020 JetBrains s.r.o. and Kotlin Programming Language contributors. + * Copyright 2010-2023 JetBrains s.r.o. and Kotlin Programming Language contributors. * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file. */ @@ -110,7 +110,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).independentInstance() + fun substitute(type: ConeKotlinType) = currentSubstitutor.safeSubstitute(c, type) as ConeKotlinType val receiver = lambda.receiver?.let(::substitute) val contextReceivers = lambda.contextReceivers.map(::substitute) diff --git a/compiler/fir/tree/src/org/jetbrains/kotlin/fir/types/CustomAnnotationTypeAttribute.kt b/compiler/fir/tree/src/org/jetbrains/kotlin/fir/types/CustomAnnotationTypeAttribute.kt index c37ddfe7f8b..7b012379021 100644 --- a/compiler/fir/tree/src/org/jetbrains/kotlin/fir/types/CustomAnnotationTypeAttribute.kt +++ b/compiler/fir/tree/src/org/jetbrains/kotlin/fir/types/CustomAnnotationTypeAttribute.kt @@ -6,9 +6,6 @@ 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.renderer.FirRenderer import org.jetbrains.kotlin.fir.symbols.FirBasedSymbol @@ -63,27 +60,6 @@ class CustomAnnotationTypeAttribute( get() = CustomAnnotationTypeAttribute::class override val keepInInferredDeclarationType: Boolean get() = true - - /** - * 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()