diff --git a/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/calls/CallKind.kt b/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/calls/CallKind.kt index 4130ffe8933..b44811646c2 100644 --- a/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/calls/CallKind.kt +++ b/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/calls/CallKind.kt @@ -20,6 +20,7 @@ sealed class CallKind(vararg resolutionSequence: ResolutionStage) { CheckDslScopeViolation, CheckLowPriorityInOverloadResolution, PostponedVariablesInitializerResolutionStage, + ProcessDynamicExtensionAnnotation, LowerPriorityIfDynamic, ConstraintSystemForks, CheckIncompatibleTypeVariableUpperBounds, @@ -54,6 +55,7 @@ sealed class CallKind(vararg resolutionSequence: ResolutionStage) { EagerResolveOfCallableReferences, CheckLowPriorityInOverloadResolution, PostponedVariablesInitializerResolutionStage, + ProcessDynamicExtensionAnnotation, LowerPriorityIfDynamic, ConstraintSystemForks, CheckIncompatibleTypeVariableUpperBounds, diff --git a/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/calls/ResolutionStages.kt b/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/calls/ResolutionStages.kt index 52ab9ea0c83..3935022aa40 100644 --- a/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/calls/ResolutionStages.kt +++ b/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/calls/ResolutionStages.kt @@ -40,6 +40,7 @@ import org.jetbrains.kotlin.resolve.calls.inference.model.SimpleConstraintSystem import org.jetbrains.kotlin.resolve.calls.tasks.ExplicitReceiverKind.* import org.jetbrains.kotlin.resolve.calls.tower.CandidateApplicability import org.jetbrains.kotlin.resolve.deprecation.DeprecationLevelValue +import org.jetbrains.kotlin.resolve.descriptorUtil.DYNAMIC_EXTENSION_FQ_NAME import org.jetbrains.kotlin.types.* import org.jetbrains.kotlin.util.OperatorNameConventions @@ -652,6 +653,21 @@ internal object CheckDeprecatedSinceKotlin : ResolutionStage() { } } +private val DYNAMIC_EXTENSION_ANNOTATION_CLASS_ID: ClassId = ClassId.topLevel(DYNAMIC_EXTENSION_FQ_NAME) + +internal object ProcessDynamicExtensionAnnotation : ResolutionStage() { + override suspend fun check(candidate: Candidate, callInfo: CallInfo, sink: CheckerSink, context: ResolutionContext) { + if (candidate.symbol.origin === FirDeclarationOrigin.DynamicScope) return + val extensionReceiver = candidate.chosenExtensionReceiverValue ?: return + val argumentIsDynamic = extensionReceiver.type is ConeDynamicType + val parameterIsDynamic = (candidate.symbol as? FirCallableSymbol)?.resolvedReceiverTypeRef?.type is ConeDynamicType + if (parameterIsDynamic != argumentIsDynamic || + parameterIsDynamic && !candidate.symbol.hasAnnotation(DYNAMIC_EXTENSION_ANNOTATION_CLASS_ID)) { + candidate.addDiagnostic(HiddenCandidate) + } + } +} + internal object LowerPriorityIfDynamic : ResolutionStage() { override suspend fun check(candidate: Candidate, callInfo: CallInfo, sink: CheckerSink, context: ResolutionContext) { when {