diff --git a/compiler/fir/checkers/src/org/jetbrains/kotlin/fir/analysis/checkers/expression/FirOptInUsageAccessChecker.kt b/compiler/fir/checkers/src/org/jetbrains/kotlin/fir/analysis/checkers/expression/FirOptInUsageAccessChecker.kt index 35cf9d084ee..b3316808782 100644 --- a/compiler/fir/checkers/src/org/jetbrains/kotlin/fir/analysis/checkers/expression/FirOptInUsageAccessChecker.kt +++ b/compiler/fir/checkers/src/org/jetbrains/kotlin/fir/analysis/checkers/expression/FirOptInUsageAccessChecker.kt @@ -10,8 +10,11 @@ import org.jetbrains.kotlin.fir.analysis.checkers.context.CheckerContext import org.jetbrains.kotlin.fir.analysis.diagnostics.DiagnosticReporter import org.jetbrains.kotlin.fir.expressions.FirQualifiedAccess import org.jetbrains.kotlin.fir.expressions.FirVariableAssignment +import org.jetbrains.kotlin.fir.expressions.impl.FirNoReceiverExpression import org.jetbrains.kotlin.fir.references.FirResolvedNamedReference +import org.jetbrains.kotlin.fir.resolve.fullyExpandedType import org.jetbrains.kotlin.fir.symbols.impl.FirPropertySymbol +import org.jetbrains.kotlin.fir.types.coneType object FirOptInUsageAccessChecker : FirQualifiedAccessChecker() { override fun check(expression: FirQualifiedAccess, context: CheckerContext, reporter: DiagnosticReporter) { @@ -21,14 +24,16 @@ object FirOptInUsageAccessChecker : FirQualifiedAccessChecker() { ) return val reference = expression.calleeReference as? FirResolvedNamedReference ?: return val resolvedSymbol = reference.resolvedSymbol + val dispatchReceiverType = + expression.dispatchReceiver.takeIf { it !is FirNoReceiverExpression }?.typeRef?.coneType?.fullyExpandedType(context.session) with(FirOptInUsageBaseChecker) { if (expression is FirVariableAssignment && resolvedSymbol is FirPropertySymbol) { - val experimentalities = resolvedSymbol.loadExperimentalities(context, fromSetter = true) + + val experimentalities = resolvedSymbol.loadExperimentalities(context, fromSetter = true, dispatchReceiverType) + loadExperimentalitiesFromTypeArguments(context, expression.typeArguments) reportNotAcceptedExperimentalities(experimentalities, expression.lValue, context, reporter) return } - val experimentalities = resolvedSymbol.loadExperimentalities(context, fromSetter = false) + + val experimentalities = resolvedSymbol.loadExperimentalities(context, fromSetter = false, dispatchReceiverType) + loadExperimentalitiesFromTypeArguments(context, expression.typeArguments) reportNotAcceptedExperimentalities(experimentalities, expression, context, reporter) } diff --git a/compiler/fir/checkers/src/org/jetbrains/kotlin/fir/analysis/checkers/expression/FirOptInUsageBaseChecker.kt b/compiler/fir/checkers/src/org/jetbrains/kotlin/fir/analysis/checkers/expression/FirOptInUsageBaseChecker.kt index ee9e5c78677..0b99e35d9a8 100644 --- a/compiler/fir/checkers/src/org/jetbrains/kotlin/fir/analysis/checkers/expression/FirOptInUsageBaseChecker.kt +++ b/compiler/fir/checkers/src/org/jetbrains/kotlin/fir/analysis/checkers/expression/FirOptInUsageBaseChecker.kt @@ -75,9 +75,9 @@ object FirOptInUsageBaseChecker { } fun FirBasedSymbol<*>.loadExperimentalities( - context: CheckerContext, fromSetter: Boolean + context: CheckerContext, fromSetter: Boolean, dispatchReceiverType: ConeKotlinType? ): Set = loadExperimentalities( - context, knownExperimentalities = null, visited = mutableSetOf(), fromSetter + context, knownExperimentalities = null, visited = mutableSetOf(), fromSetter, dispatchReceiverType ) @OptIn(SymbolInternals::class) @@ -86,6 +86,7 @@ object FirOptInUsageBaseChecker { knownExperimentalities: SmartSet?, visited: MutableSet, fromSetter: Boolean, + dispatchReceiverType: ConeKotlinType?, ): Set { ensureResolved(FirResolvePhase.STATUS) val fir = this.fir as? FirAnnotatedDeclaration ?: return emptySet() @@ -99,12 +100,12 @@ object FirOptInUsageBaseChecker { val parentClassScope = parentClassSymbol?.unsubstitutedScope(context) if (this is FirNamedFunctionSymbol) { parentClassScope?.processDirectlyOverriddenFunctions(this) { - it.loadExperimentalities(context, result, visited, fromSetter = false) + it.loadExperimentalities(context, result, visited, fromSetter = false, dispatchReceiverType = null) ProcessorAction.NEXT } } else if (this is FirPropertySymbol) { parentClassScope?.processDirectlyOverriddenProperties(this) { - it.loadExperimentalities(context, result, visited, fromSetter) + it.loadExperimentalities(context, result, visited, fromSetter, dispatchReceiverType = null) ProcessorAction.NEXT } } @@ -119,13 +120,17 @@ object FirOptInUsageBaseChecker { } } } - parentClassSymbol?.loadExperimentalities(context, result, visited, fromSetter = false) + if (dispatchReceiverType == null) { + parentClassSymbol?.loadExperimentalities(context, result, visited, fromSetter = false, dispatchReceiverType = null) + } else { + dispatchReceiverType.addExperimentalities(context, result, visited) + } if (fromSetter && this is FirPropertySymbol) { - setterSymbol?.loadExperimentalities(context, result, visited, fromSetter = false) + setterSymbol?.loadExperimentalities(context, result, visited, fromSetter = false, dispatchReceiverType) } } else if (this is FirRegularClassSymbol && fir is FirRegularClass && !fir.isLocal) { val parentClassSymbol = outerClassSymbol(context) - parentClassSymbol?.loadExperimentalities(context, result, visited, fromSetter = false) + parentClassSymbol?.loadExperimentalities(context, result, visited, fromSetter = false, dispatchReceiverType = null) } for (annotation in fir.annotations) { @@ -164,7 +169,7 @@ object FirOptInUsageBaseChecker { ) { if (this !is ConeClassLikeType) return lookupTag.toSymbol(context.session)?.loadExperimentalities( - context, result, visited, fromSetter = false + context, result, visited, fromSetter = false, dispatchReceiverType = null ) fullyExpandedType(context.session).typeArguments.forEach { if (!it.isStarProjection) it.type?.addExperimentalities(context, result, visited) diff --git a/compiler/fir/checkers/src/org/jetbrains/kotlin/fir/analysis/checkers/expression/FirOptInUsageQualifierChecker.kt b/compiler/fir/checkers/src/org/jetbrains/kotlin/fir/analysis/checkers/expression/FirOptInUsageQualifierChecker.kt index 9eb4f34de9e..645dd643aa3 100644 --- a/compiler/fir/checkers/src/org/jetbrains/kotlin/fir/analysis/checkers/expression/FirOptInUsageQualifierChecker.kt +++ b/compiler/fir/checkers/src/org/jetbrains/kotlin/fir/analysis/checkers/expression/FirOptInUsageQualifierChecker.kt @@ -13,7 +13,7 @@ object FirOptInUsageQualifierChecker : FirResolvedQualifierChecker() { override fun check(expression: FirResolvedQualifier, context: CheckerContext, reporter: DiagnosticReporter) { val symbol = expression.symbol ?: return with(FirOptInUsageBaseChecker) { - val experimentalities = symbol.loadExperimentalities(context, fromSetter = false) + val experimentalities = symbol.loadExperimentalities(context, fromSetter = false, dispatchReceiverType = null) reportNotAcceptedExperimentalities(experimentalities, expression, context, reporter) } } 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 260f4b82786..07abcec71da 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 @@ -59,7 +59,7 @@ object FirOptInUsageTypeRefChecker : FirTypeRefChecker() { } with(FirOptInUsageBaseChecker) { - val experimentalities = symbol.loadExperimentalities(context, fromSetter = false) + + val experimentalities = symbol.loadExperimentalities(context, fromSetter = false, dispatchReceiverType = null) + loadExperimentalitiesFromConeArguments(context, coneType.typeArguments.toList()) reportNotAcceptedExperimentalities(experimentalities, typeRef, context, reporter) } diff --git a/compiler/testData/diagnostics/testsWithStdLib/experimental/deeplyNestedClass.fir.kt b/compiler/testData/diagnostics/testsWithStdLib/experimental/deeplyNestedClass.fir.kt index 4c28838a242..1884562c93a 100644 --- a/compiler/testData/diagnostics/testsWithStdLib/experimental/deeplyNestedClass.fir.kt +++ b/compiler/testData/diagnostics/testsWithStdLib/experimental/deeplyNestedClass.fir.kt @@ -55,4 +55,4 @@ fun use1() { C.D.E.F() } -fun use2(f: C.D.E.F) = f.hashCode() +fun use2(f: C.D.E.F) = f.hashCode() diff --git a/compiler/testData/diagnostics/testsWithStdLib/experimental/implicitUsages.fir.kt b/compiler/testData/diagnostics/testsWithStdLib/experimental/implicitUsages.fir.kt index 583b5c52909..df89b3fd858 100644 --- a/compiler/testData/diagnostics/testsWithStdLib/experimental/implicitUsages.fir.kt +++ b/compiler/testData/diagnostics/testsWithStdLib/experimental/implicitUsages.fir.kt @@ -49,7 +49,7 @@ interface NotExperimentalExtension : ExperimentalType { fun use(arg: NotExperimentalExtension) { arg.foo() - arg.bar() + arg.bar() } @Marker @@ -120,5 +120,5 @@ fun operatorContainerUsage(s: String, a: AnotherContainer) { val res1 = s - s val res2 = s() val res3 = res1 > res2 - for (c in a) {} + for (c in a) {} } \ No newline at end of file diff --git a/compiler/testData/diagnostics/testsWithStdLib/experimental/implicitUsagesFuture.fir.kt b/compiler/testData/diagnostics/testsWithStdLib/experimental/implicitUsagesFuture.fir.kt index babe66f5732..13029a3f52e 100644 --- a/compiler/testData/diagnostics/testsWithStdLib/experimental/implicitUsagesFuture.fir.kt +++ b/compiler/testData/diagnostics/testsWithStdLib/experimental/implicitUsagesFuture.fir.kt @@ -49,7 +49,7 @@ interface NotExperimentalExtension : ExperimentalType { fun use(arg: NotExperimentalExtension) { arg.foo() - arg.bar() + arg.bar() } @Marker @@ -120,5 +120,5 @@ fun operatorContainerUsage(s: String, a: AnotherContainer) { val res1 = s - s val res2 = s() val res3 = res1 > res2 - for (c in a) {} + for (c in a) {} }