From 445ed7abc9aedb5e41b832a453398a6deb1f0937 Mon Sep 17 00:00:00 2001 From: "Anastasia.Nekrasova" Date: Tue, 31 Oct 2023 11:29:21 +0200 Subject: [PATCH] [K2] Disappeared OPT_IN_MARKER_CAN_ONLY_BE_USED_AS_ANNOTATION_OR_ARGUMENT_IN_OPT_IN (1) Added error propagation for the type-aliased type. ^KT-59998 --- .../type/FirOptInUsageTypeRefChecker.kt | 41 +++++++++++++------ .../experimental/implicitUsages.fir.kt | 6 ++- .../experimental/implicitUsages.kt | 4 ++ .../experimental/implicitUsages.txt | 2 + .../experimental/implicitUsagesFuture.fir.kt | 6 ++- .../experimental/implicitUsagesFuture.kt | 4 ++ .../experimental/implicitUsagesFuture.txt | 2 + .../experimental/usageNotAsAnnotation.fir.kt | 6 +-- 8 files changed, 53 insertions(+), 18 deletions(-) diff --git a/compiler/fir/checkers/src/org/jetbrains/kotlin/fir/analysis/checkers/type/FirOptInUsageTypeRefChecker.kt b/compiler/fir/checkers/src/org/jetbrains/kotlin/fir/analysis/checkers/type/FirOptInUsageTypeRefChecker.kt index 2507e6235a8..6a24fe1cf0e 100644 --- a/compiler/fir/checkers/src/org/jetbrains/kotlin/fir/analysis/checkers/type/FirOptInUsageTypeRefChecker.kt +++ b/compiler/fir/checkers/src/org/jetbrains/kotlin/fir/analysis/checkers/type/FirOptInUsageTypeRefChecker.kt @@ -8,18 +8,21 @@ package org.jetbrains.kotlin.fir.analysis.checkers.type import org.jetbrains.kotlin.KtRealSourceElementKind import org.jetbrains.kotlin.diagnostics.DiagnosticReporter import org.jetbrains.kotlin.diagnostics.reportOn +import org.jetbrains.kotlin.fir.FirSession import org.jetbrains.kotlin.fir.analysis.checkers.context.CheckerContext import org.jetbrains.kotlin.fir.analysis.checkers.expression.FirOptInUsageBaseChecker +import org.jetbrains.kotlin.fir.analysis.checkers.expression.FirOptInUsageBaseChecker.loadExperimentalities +import org.jetbrains.kotlin.fir.analysis.checkers.expression.FirOptInUsageBaseChecker.loadExperimentalitiesFromSupertype import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors.OPT_IN_CAN_ONLY_BE_USED_AS_ANNOTATION import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors.OPT_IN_MARKER_CAN_ONLY_BE_USED_AS_ANNOTATION_OR_ARGUMENT_IN_OPT_IN import org.jetbrains.kotlin.fir.declarations.FirClass -import org.jetbrains.kotlin.fir.declarations.FirResolvePhase import org.jetbrains.kotlin.fir.declarations.getAnnotationByClassId import org.jetbrains.kotlin.fir.expressions.FirAnnotation import org.jetbrains.kotlin.fir.resolve.toSymbol import org.jetbrains.kotlin.fir.symbols.SymbolInternals +import org.jetbrains.kotlin.fir.symbols.impl.FirClassLikeSymbol import org.jetbrains.kotlin.fir.symbols.impl.FirRegularClassSymbol -import org.jetbrains.kotlin.fir.symbols.lazyResolveToPhase +import org.jetbrains.kotlin.fir.symbols.impl.FirTypeAliasSymbol import org.jetbrains.kotlin.fir.types.ConeClassLikeType import org.jetbrains.kotlin.fir.types.FirTypeRef import org.jetbrains.kotlin.fir.types.coneTypeSafe @@ -30,18 +33,18 @@ object FirOptInUsageTypeRefChecker : FirTypeRefChecker() { override fun check(typeRef: FirTypeRef, context: CheckerContext, reporter: DiagnosticReporter) { val source = typeRef.source if (source?.kind !is KtRealSourceElementKind) return - // coneTypeSafe filters out all delegatedTypeRefs from here val coneType = typeRef.coneTypeSafe() ?: return + val symbol = typeRef.findSymbol(context.session) ?: return - val symbol = coneType.lookupTag.toSymbol(context.session) ?: return - symbol.lazyResolveToPhase(FirResolvePhase.STATUS) - val classId = symbol.classId + val typeAliasExpandedSymbol = (symbol as? FirTypeAliasSymbol)?.resolvedExpandedTypeRef?.findSymbol(context.session) + val processedSymbol = typeAliasExpandedSymbol ?: symbol + val classId = processedSymbol.classId val lastAnnotationCall = context.callsOrAssignments.lastOrNull() as? FirAnnotation if (lastAnnotationCall == null || lastAnnotationCall.annotationTypeRef !== typeRef) { if (classId == OptInNames.REQUIRES_OPT_IN_CLASS_ID || classId == OptInNames.OPT_IN_CLASS_ID) { reporter.reportOn(source, OPT_IN_CAN_ONLY_BE_USED_AS_ANNOTATION, context) - } else if (symbol is FirRegularClassSymbol && - symbol.fir.getAnnotationByClassId(OptInNames.REQUIRES_OPT_IN_CLASS_ID, context.session) != null + } else if (processedSymbol is FirRegularClassSymbol && + processedSymbol.fir.getAnnotationByClassId(OptInNames.REQUIRES_OPT_IN_CLASS_ID, context.session) != null ) { reporter.reportOn(source, OPT_IN_MARKER_CAN_ONLY_BE_USED_AS_ANNOTATION_OR_ARGUMENT_IN_OPT_IN, context) } @@ -49,12 +52,24 @@ object FirOptInUsageTypeRefChecker : FirTypeRefChecker() { val isSupertypeRef = typeRef in (context.containingDeclarations.lastOrNull() as? FirClass)?.superTypeRefs.orEmpty() with(FirOptInUsageBaseChecker) { - val classifierExperimentalities = - if (isSupertypeRef) symbol.loadExperimentalitiesFromSupertype(context) - else symbol.loadExperimentalities(context, fromSetter = false, dispatchReceiverType = null) - val experimentalities = - classifierExperimentalities + loadExperimentalitiesFromConeArguments(context, coneType.typeArguments.toList()) + val experimentalities = mutableSetOf() + experimentalities.addAll(symbol.loadClassifierExperimentalities(context, isSupertypeRef)) + if (typeAliasExpandedSymbol != null) experimentalities.addAll(typeAliasExpandedSymbol.loadClassifierExperimentalities(context, isSupertypeRef)) + experimentalities.addAll(loadExperimentalitiesFromConeArguments(context, coneType.typeArguments.toList())) reportNotAcceptedExperimentalities(experimentalities, typeRef, context, reporter) } } + + private fun FirClassLikeSymbol<*>.loadClassifierExperimentalities(context: CheckerContext, isSupertypeRef: Boolean) = + if (isSupertypeRef) loadExperimentalitiesFromSupertype(context) else loadExperimentalities( + context, + fromSetter = false, + dispatchReceiverType = null + ) + + private fun FirTypeRef.findSymbol(session: FirSession): FirClassLikeSymbol<*>? { + // coneTypeSafe filters out all delegatedTypeRefs from here + val coneType = coneTypeSafe() ?: return null + return coneType.lookupTag.toSymbol(session) + } } diff --git a/compiler/testData/diagnostics/testsWithStdLib/experimental/implicitUsages.fir.kt b/compiler/testData/diagnostics/testsWithStdLib/experimental/implicitUsages.fir.kt index a8c769b2775..2a41fcbf22c 100644 --- a/compiler/testData/diagnostics/testsWithStdLib/experimental/implicitUsages.fir.kt +++ b/compiler/testData/diagnostics/testsWithStdLib/experimental/implicitUsages.fir.kt @@ -32,7 +32,7 @@ fun useDataClass(d: DataClass) { typealias My = Some -fun my(my: My) {} +fun my(my: My) {} fun your(my: Some) {} @@ -70,6 +70,10 @@ typealias AList = ArrayList @Marker typealias YourList = ArrayList +fun my2(my: MyList) {} + +fun my3(my: YourList) {} + fun main() { val x = listOf(A(), B()) val y = MyList() diff --git a/compiler/testData/diagnostics/testsWithStdLib/experimental/implicitUsages.kt b/compiler/testData/diagnostics/testsWithStdLib/experimental/implicitUsages.kt index a38aa22afc8..0a2831f5c97 100644 --- a/compiler/testData/diagnostics/testsWithStdLib/experimental/implicitUsages.kt +++ b/compiler/testData/diagnostics/testsWithStdLib/experimental/implicitUsages.kt @@ -70,6 +70,10 @@ typealias AList = ArrayList @Marker typealias YourList = ArrayList +fun my2(my: MyList) {} + +fun my3(my: YourList) {} + fun main() { val x = listOf(A(), B()) val y = MyList() diff --git a/compiler/testData/diagnostics/testsWithStdLib/experimental/implicitUsages.txt b/compiler/testData/diagnostics/testsWithStdLib/experimental/implicitUsages.txt index efe28d2a08c..ca460930ad1 100644 --- a/compiler/testData/diagnostics/testsWithStdLib/experimental/implicitUsages.txt +++ b/compiler/testData/diagnostics/testsWithStdLib/experimental/implicitUsages.txt @@ -3,6 +3,8 @@ package public val x: kotlin.String public fun main(): kotlin.Unit public fun my(/*0*/ my: My /* = Some */): kotlin.Unit +public fun my2(/*0*/ my: MyList /* = java.util.ArrayList */): kotlin.Unit +public fun my3(/*0*/ my: YourList /* = java.util.ArrayList */): kotlin.Unit public fun operatorContainerUsage(/*0*/ s: kotlin.String, /*1*/ a: AnotherContainer): kotlin.Unit public fun use(/*0*/ arg: NotExperimentalExtension): kotlin.Unit public fun useDataClass(/*0*/ d: DataClass): kotlin.Unit diff --git a/compiler/testData/diagnostics/testsWithStdLib/experimental/implicitUsagesFuture.fir.kt b/compiler/testData/diagnostics/testsWithStdLib/experimental/implicitUsagesFuture.fir.kt index e37bf0c204b..19479626343 100644 --- a/compiler/testData/diagnostics/testsWithStdLib/experimental/implicitUsagesFuture.fir.kt +++ b/compiler/testData/diagnostics/testsWithStdLib/experimental/implicitUsagesFuture.fir.kt @@ -32,7 +32,7 @@ fun useDataClass(d: DataClass) { typealias My = Some -fun my(my: My) {} +fun my(my: My) {} fun your(my: Some) {} @@ -78,6 +78,10 @@ fun main() { YourList().add("") } +fun my2(my: MyList) {} + +fun my3(my: YourList) {} + @Marker class C { operator fun getValue(x: Any?, y: Any?): String = "" diff --git a/compiler/testData/diagnostics/testsWithStdLib/experimental/implicitUsagesFuture.kt b/compiler/testData/diagnostics/testsWithStdLib/experimental/implicitUsagesFuture.kt index ff023ded4d0..674aa099a96 100644 --- a/compiler/testData/diagnostics/testsWithStdLib/experimental/implicitUsagesFuture.kt +++ b/compiler/testData/diagnostics/testsWithStdLib/experimental/implicitUsagesFuture.kt @@ -78,6 +78,10 @@ fun main() { YourList().add("") } +fun my2(my: MyList) {} + +fun my3(my: YourList) {} + @Marker class C { operator fun getValue(x: Any?, y: Any?): String = "" diff --git a/compiler/testData/diagnostics/testsWithStdLib/experimental/implicitUsagesFuture.txt b/compiler/testData/diagnostics/testsWithStdLib/experimental/implicitUsagesFuture.txt index efe28d2a08c..ca460930ad1 100644 --- a/compiler/testData/diagnostics/testsWithStdLib/experimental/implicitUsagesFuture.txt +++ b/compiler/testData/diagnostics/testsWithStdLib/experimental/implicitUsagesFuture.txt @@ -3,6 +3,8 @@ package public val x: kotlin.String public fun main(): kotlin.Unit public fun my(/*0*/ my: My /* = Some */): kotlin.Unit +public fun my2(/*0*/ my: MyList /* = java.util.ArrayList */): kotlin.Unit +public fun my3(/*0*/ my: YourList /* = java.util.ArrayList */): kotlin.Unit public fun operatorContainerUsage(/*0*/ s: kotlin.String, /*1*/ a: AnotherContainer): kotlin.Unit public fun use(/*0*/ arg: NotExperimentalExtension): kotlin.Unit public fun useDataClass(/*0*/ d: DataClass): kotlin.Unit diff --git a/compiler/testData/diagnostics/testsWithStdLib/experimental/usageNotAsAnnotation.fir.kt b/compiler/testData/diagnostics/testsWithStdLib/experimental/usageNotAsAnnotation.fir.kt index cbecde9d646..03b97f3d347 100644 --- a/compiler/testData/diagnostics/testsWithStdLib/experimental/usageNotAsAnnotation.fir.kt +++ b/compiler/testData/diagnostics/testsWithStdLib/experimental/usageNotAsAnnotation.fir.kt @@ -26,8 +26,8 @@ fun f2(u: OptIn?) {} typealias Experimental0 = RequiresOptIn typealias OptIn0 = OptIn -fun f3(e: Experimental0 /* TODO */) {} -fun f4(u: OptIn0 /* TODO */) {} +fun f3(e: Experimental0 /* TODO */) {} +fun f4(u: OptIn0 /* TODO */) {} // Usages as ::class literals should be errors @@ -60,7 +60,7 @@ fun f8(): typealias Marker0 = Marker -fun f9(m: Marker0) {} +fun f9(m: Marker0) {} // Usages of markers as qualifiers are errors as well (we can lift this restriction for select cases)