diff --git a/compiler/frontend/src/org/jetbrains/kotlin/resolve/calls/checkers/ApiVersionCallChecker.kt b/compiler/frontend/src/org/jetbrains/kotlin/resolve/calls/checkers/ApiVersionCallChecker.kt index c5f85eacabe..99263434575 100644 --- a/compiler/frontend/src/org/jetbrains/kotlin/resolve/calls/checkers/ApiVersionCallChecker.kt +++ b/compiler/frontend/src/org/jetbrains/kotlin/resolve/calls/checkers/ApiVersionCallChecker.kt @@ -20,6 +20,7 @@ import com.intellij.psi.PsiElement import org.jetbrains.kotlin.descriptors.CallableDescriptor import org.jetbrains.kotlin.descriptors.PropertyDescriptor import org.jetbrains.kotlin.diagnostics.Errors.API_NOT_AVAILABLE +import org.jetbrains.kotlin.resolve.SinceKotlinAccessibility import org.jetbrains.kotlin.resolve.calls.model.ResolvedCall import org.jetbrains.kotlin.resolve.calls.util.FakeCallableDescriptorForObject import org.jetbrains.kotlin.resolve.checkSinceKotlinVersionAccessibility @@ -34,13 +35,15 @@ object ApiVersionCallChecker : CallChecker { // Objects will be checked by ApiVersionClassifierUsageChecker if (targetDescriptor is FakeCallableDescriptorForObject) return - val accessible = targetDescriptor.checkSinceKotlinVersionAccessibility(context.languageVersionSettings) { version -> + val accessibility = targetDescriptor.checkSinceKotlinVersionAccessibility(context.languageVersionSettings) + if (accessibility is SinceKotlinAccessibility.NotAccessible) { context.trace.report( - API_NOT_AVAILABLE.on(element, version.versionString, context.languageVersionSettings.apiVersion.versionString) + API_NOT_AVAILABLE.on(element, accessibility.version.versionString, context.languageVersionSettings.apiVersion.versionString) ) } - if (accessible && targetDescriptor is PropertyDescriptor && DeprecatedCallChecker.shouldCheckPropertyGetter(element)) { + if (accessibility == SinceKotlinAccessibility.Accessible && + targetDescriptor is PropertyDescriptor && DeprecatedCallChecker.shouldCheckPropertyGetter(element)) { targetDescriptor.getter?.let { check(it, context, element) } } } diff --git a/compiler/frontend/src/org/jetbrains/kotlin/resolve/calls/tower/KotlinResolutionStatelessCallbacksImpl.kt b/compiler/frontend/src/org/jetbrains/kotlin/resolve/calls/tower/KotlinResolutionStatelessCallbacksImpl.kt index 0cfac7393d6..7b2467b2891 100644 --- a/compiler/frontend/src/org/jetbrains/kotlin/resolve/calls/tower/KotlinResolutionStatelessCallbacksImpl.kt +++ b/compiler/frontend/src/org/jetbrains/kotlin/resolve/calls/tower/KotlinResolutionStatelessCallbacksImpl.kt @@ -26,6 +26,7 @@ import org.jetbrains.kotlin.resolve.DescriptorToSourceUtils import org.jetbrains.kotlin.resolve.calls.callResolverUtil.isConventionCall import org.jetbrains.kotlin.resolve.calls.callResolverUtil.isInfixCall import org.jetbrains.kotlin.resolve.calls.callResolverUtil.isSuperOrDelegatingConstructorCall +import org.jetbrains.kotlin.resolve.calls.components.KotlinResolutionCallbacks import org.jetbrains.kotlin.resolve.calls.components.KotlinResolutionStatelessCallbacks import org.jetbrains.kotlin.resolve.calls.inference.isCoroutineCallWithAdditionalInference import org.jetbrains.kotlin.resolve.calls.model.CallableReferenceKotlinCallArgument @@ -51,8 +52,15 @@ class KotlinResolutionStatelessCallbacksImpl( override fun isSuperOrDelegatingConstructorCall(kotlinCall: KotlinCall) = kotlinCall is PSIKotlinCallImpl && isSuperOrDelegatingConstructorCall(kotlinCall.psiCall) - override fun isHiddenInResolution(descriptor: DeclarationDescriptor, kotlinCall: KotlinCall) = - deprecationResolver.isHiddenInResolution(descriptor, isSuperOrDelegatingConstructorCall(kotlinCall)) + override fun isHiddenInResolution( + descriptor: DeclarationDescriptor, kotlinCall: KotlinCall, resolutionCallbacks: KotlinResolutionCallbacks + ) = + deprecationResolver.isHiddenInResolution( + descriptor, + (kotlinCall as? PSIKotlinCall)?.psiCall, + (resolutionCallbacks as? KotlinResolutionCallbacksImpl)?.trace?.bindingContext, + isSuperOrDelegatingConstructorCall(kotlinCall) + ) override fun isSuperExpression(receiver: SimpleKotlinCallArgument?): Boolean = receiver?.psiExpression is KtSuperExpression diff --git a/compiler/frontend/src/org/jetbrains/kotlin/resolve/calls/tower/NewResolutionOldInference.kt b/compiler/frontend/src/org/jetbrains/kotlin/resolve/calls/tower/NewResolutionOldInference.kt index aed561f8a68..6f64a896695 100644 --- a/compiler/frontend/src/org/jetbrains/kotlin/resolve/calls/tower/NewResolutionOldInference.kt +++ b/compiler/frontend/src/org/jetbrains/kotlin/resolve/calls/tower/NewResolutionOldInference.kt @@ -35,7 +35,10 @@ import org.jetbrains.kotlin.resolve.calls.callResolverUtil.isInfixCall import org.jetbrains.kotlin.resolve.calls.callUtil.createLookupLocation import org.jetbrains.kotlin.resolve.calls.context.* import org.jetbrains.kotlin.resolve.calls.inference.CoroutineInferenceSupport -import org.jetbrains.kotlin.resolve.calls.model.* +import org.jetbrains.kotlin.resolve.calls.model.KotlinCallDiagnostic +import org.jetbrains.kotlin.resolve.calls.model.MutableResolvedCall +import org.jetbrains.kotlin.resolve.calls.model.ResolvedCallImpl +import org.jetbrains.kotlin.resolve.calls.model.VariableAsFunctionResolvedCallImpl import org.jetbrains.kotlin.resolve.calls.results.OverloadResolutionResultsImpl import org.jetbrains.kotlin.resolve.calls.results.ResolutionResultsHandler import org.jetbrains.kotlin.resolve.calls.results.ResolutionStatus @@ -219,7 +222,10 @@ class NewResolutionOldInference( val candidateTrace = TemporaryBindingTrace.create(basicCallContext.trace, "Context for resolve candidate") val resolvedCall = ResolvedCallImpl.create(candidate, candidateTrace, tracing, basicCallContext.dataFlowInfoForArguments) - if (deprecationResolver.isHiddenInResolution(candidate.descriptor, basicCallContext.isSuperCall)) { + if (deprecationResolver.isHiddenInResolution( + candidate.descriptor, basicCallContext.call, basicCallContext.trace.bindingContext, basicCallContext.isSuperCall + ) + ) { return@map MyCandidate(listOf(HiddenDescriptor), resolvedCall) } @@ -448,8 +454,10 @@ class NewResolutionOldInference( } } - - if (deprecationResolver.isHiddenInResolution(towerCandidate.descriptor, basicCallContext.isSuperCall)) { + if (deprecationResolver.isHiddenInResolution( + towerCandidate.descriptor, basicCallContext.call, basicCallContext.trace.bindingContext, basicCallContext.isSuperCall + ) + ) { return MyCandidate(listOf(HiddenDescriptor), candidateCall) } diff --git a/compiler/frontend/src/org/jetbrains/kotlin/resolve/calls/tower/PSICallResolver.kt b/compiler/frontend/src/org/jetbrains/kotlin/resolve/calls/tower/PSICallResolver.kt index 9f4e5dd1488..63308b9a6cf 100644 --- a/compiler/frontend/src/org/jetbrains/kotlin/resolve/calls/tower/PSICallResolver.kt +++ b/compiler/frontend/src/org/jetbrains/kotlin/resolve/calls/tower/PSICallResolver.kt @@ -385,7 +385,7 @@ class PSICallResolver( override fun factoryForVariable(stripExplicitReceiver: Boolean): CandidateFactory { val explicitReceiver = if (stripExplicitReceiver) null else kotlinCall.explicitReceiver val variableCall = PSIKotlinCallForVariable(kotlinCall, explicitReceiver, kotlinCall.name) - return SimpleCandidateFactory(callComponents, scopeTower, variableCall, context.inferenceSession) + return SimpleCandidateFactory(callComponents, scopeTower, variableCall, createResolutionCallbacks(context)) } override fun factoryForInvoke(variable: KotlinResolutionCandidate, useExplicitReceiver: Boolean): @@ -406,7 +406,7 @@ class PSICallResolver( } return variableCallArgument.receiver to SimpleCandidateFactory( - callComponents, scopeTower, callForInvoke, context.inferenceSession + callComponents, scopeTower, callForInvoke, createResolutionCallbacks(context) ) } diff --git a/compiler/frontend/src/org/jetbrains/kotlin/resolve/checkers/ApiVersionClassifierUsageChecker.kt b/compiler/frontend/src/org/jetbrains/kotlin/resolve/checkers/ApiVersionClassifierUsageChecker.kt index a4f27fe9974..a3b7609de85 100644 --- a/compiler/frontend/src/org/jetbrains/kotlin/resolve/checkers/ApiVersionClassifierUsageChecker.kt +++ b/compiler/frontend/src/org/jetbrains/kotlin/resolve/checkers/ApiVersionClassifierUsageChecker.kt @@ -19,13 +19,17 @@ package org.jetbrains.kotlin.resolve.checkers import com.intellij.psi.PsiElement import org.jetbrains.kotlin.descriptors.ClassifierDescriptor import org.jetbrains.kotlin.diagnostics.Errors +import org.jetbrains.kotlin.resolve.SinceKotlinAccessibility import org.jetbrains.kotlin.resolve.checkSinceKotlinVersionAccessibility object ApiVersionClassifierUsageChecker : ClassifierUsageChecker { override fun check(targetDescriptor: ClassifierDescriptor, element: PsiElement, context: ClassifierUsageCheckerContext) { - targetDescriptor.checkSinceKotlinVersionAccessibility(context.languageVersionSettings) { version -> + val accessibility = targetDescriptor.checkSinceKotlinVersionAccessibility(context.languageVersionSettings) + if (accessibility is SinceKotlinAccessibility.NotAccessible) { context.trace.report( - Errors.API_NOT_AVAILABLE.on(element, version.versionString, context.languageVersionSettings.apiVersion.versionString) + Errors.API_NOT_AVAILABLE.on( + element, accessibility.version.versionString, context.languageVersionSettings.apiVersion.versionString + ) ) } } diff --git a/compiler/frontend/src/org/jetbrains/kotlin/resolve/checkers/ExperimentalUsageChecker.kt b/compiler/frontend/src/org/jetbrains/kotlin/resolve/checkers/ExperimentalUsageChecker.kt index a0e002982f2..8ef86c387ce 100644 --- a/compiler/frontend/src/org/jetbrains/kotlin/resolve/checkers/ExperimentalUsageChecker.kt +++ b/compiler/frontend/src/org/jetbrains/kotlin/resolve/checkers/ExperimentalUsageChecker.kt @@ -21,6 +21,7 @@ import com.intellij.psi.PsiElement import org.jetbrains.kotlin.config.AnalysisFlag import org.jetbrains.kotlin.config.LanguageVersionSettings import org.jetbrains.kotlin.descriptors.* +import org.jetbrains.kotlin.descriptors.annotations.Annotated import org.jetbrains.kotlin.diagnostics.Errors import org.jetbrains.kotlin.incremental.components.NoLookupLocation import org.jetbrains.kotlin.name.FqName @@ -62,7 +63,9 @@ class ExperimentalUsageChecker(project: Project) : CallChecker { companion object { val EXPERIMENTAL_FQ_NAME = FqName("kotlin.Experimental") internal val USE_EXPERIMENTAL_FQ_NAME = FqName("kotlin.UseExperimental") + private val WAS_EXPERIMENTAL_FQ_NAME = FqName("kotlin.WasExperimental") internal val USE_EXPERIMENTAL_ANNOTATION_CLASS = Name.identifier("markerClass") + private val WAS_EXPERIMENTAL_ANNOTATION_CLASS = Name.identifier("markerClass") private val LEVEL = Name.identifier("level") private val WARNING_LEVEL = Name.identifier("WARNING") @@ -119,21 +122,24 @@ class ExperimentalUsageChecker(project: Project) : CallChecker { return Experimentality(fqNameSafe, severity) } + private fun PsiElement.isExperimentalityAccepted(annotationFqName: FqName, context: CheckerContext): Boolean = + isExperimentalityAccepted(annotationFqName, context.languageVersionSettings, context.trace.bindingContext) + /** * Checks whether there's an element lexically above in the tree, annotated with `@UseExperimental(X::class)`, or a declaration * annotated with `@X` where [annotationFqName] is the FQ name of X */ - private fun PsiElement.isExperimentalityAccepted(annotationFqName: FqName, context: CheckerContext): Boolean { - val languageVersionSettings = context.languageVersionSettings - val bindingContext = context.trace.bindingContext - - return annotationFqName.asString() in languageVersionSettings.getFlag(AnalysisFlag.experimental) || + fun PsiElement.isExperimentalityAccepted( + annotationFqName: FqName, + languageVersionSettings: LanguageVersionSettings, + bindingContext: BindingContext + ): Boolean = + annotationFqName.asString() in languageVersionSettings.getFlag(AnalysisFlag.experimental) || annotationFqName.asString() in languageVersionSettings.getFlag(AnalysisFlag.useExperimental) || anyParentMatches { element -> element.isDeclarationAnnotatedWith(annotationFqName, bindingContext) || element.isElementAnnotatedWithUseExperimentalOf(annotationFqName, bindingContext) } - } private fun PsiElement.isDeclarationAnnotatedWith(annotationFqName: FqName, bindingContext: BindingContext): Boolean { if (this !is KtDeclaration) return false @@ -163,6 +169,20 @@ class ExperimentalUsageChecker(project: Project) : CallChecker { } } + internal fun Annotated.loadWasExperimentalMarkerFqNames(): List { + val wasExperimental = annotations.findAnnotation(WAS_EXPERIMENTAL_FQ_NAME) + if (wasExperimental != null) { + val annotationClasses = wasExperimental.allValueArguments[WAS_EXPERIMENTAL_ANNOTATION_CLASS] + if (annotationClasses is ArrayValue) { + return annotationClasses.value.mapNotNull { annotationClass -> + (annotationClass as? KClassValue)?.value?.constructor?.declarationDescriptor?.fqNameSafe + } + } + } + + return emptyList() + } + fun checkCompilerArguments( module: ModuleDescriptor, languageVersionSettings: LanguageVersionSettings, diff --git a/compiler/frontend/src/org/jetbrains/kotlin/resolve/deprecationUtil.kt b/compiler/frontend/src/org/jetbrains/kotlin/resolve/deprecationUtil.kt index 6674214e7d6..ab5c91ae716 100644 --- a/compiler/frontend/src/org/jetbrains/kotlin/resolve/deprecationUtil.kt +++ b/compiler/frontend/src/org/jetbrains/kotlin/resolve/deprecationUtil.kt @@ -32,10 +32,12 @@ import org.jetbrains.kotlin.diagnostics.Errors import org.jetbrains.kotlin.metadata.ProtoBuf import org.jetbrains.kotlin.metadata.deserialization.VersionRequirement import org.jetbrains.kotlin.name.FqName +import org.jetbrains.kotlin.psi.Call import org.jetbrains.kotlin.resolve.DeprecationLevelValue.* import org.jetbrains.kotlin.resolve.annotations.argumentValue import org.jetbrains.kotlin.resolve.calls.checkers.isOperatorMod import org.jetbrains.kotlin.resolve.calls.checkers.shouldWarnAboutDeprecatedModFromBuiltIns +import org.jetbrains.kotlin.resolve.checkers.ExperimentalUsageChecker import org.jetbrains.kotlin.resolve.constants.AnnotationValue import org.jetbrains.kotlin.resolve.constants.EnumValue import org.jetbrains.kotlin.resolve.constants.StringValue @@ -210,6 +212,8 @@ class DeprecationResolver( @JvmOverloads fun isHiddenInResolution( descriptor: DeclarationDescriptor, + call: Call? = null, + bindingContext: BindingContext? = null, isSuperCall: Boolean = false ): Boolean { if (descriptor is FunctionDescriptor) { @@ -217,7 +221,19 @@ class DeprecationResolver( if (descriptor.isHiddenForResolutionEverywhereBesideSupercalls && !isSuperCall) return true } - if (!isHiddenBecauseOfKotlinVersionAccessibility(descriptor.original)) return true + val sinceKotlinAccessibility = isHiddenBecauseOfKotlinVersionAccessibility(descriptor.original) + if (sinceKotlinAccessibility is SinceKotlinAccessibility.NotAccessible) return true + + if (sinceKotlinAccessibility is SinceKotlinAccessibility.NotAccessibleButWasExperimental) { + if (call != null && bindingContext != null) { + return with(ExperimentalUsageChecker) { + sinceKotlinAccessibility.annotationFqNames.any { fqName -> + !call.callElement.isExperimentalityAccepted(fqName, languageVersionSettings, bindingContext) + } + } + } + return true + } return isDeprecatedHidden(descriptor) } diff --git a/compiler/frontend/src/org/jetbrains/kotlin/resolve/lazy/DefaultImportProvider.kt b/compiler/frontend/src/org/jetbrains/kotlin/resolve/lazy/DefaultImportProvider.kt index a79c31afc02..f9e8334ad73 100644 --- a/compiler/frontend/src/org/jetbrains/kotlin/resolve/lazy/DefaultImportProvider.kt +++ b/compiler/frontend/src/org/jetbrains/kotlin/resolve/lazy/DefaultImportProvider.kt @@ -26,6 +26,7 @@ import org.jetbrains.kotlin.name.FqName import org.jetbrains.kotlin.name.isChildOf import org.jetbrains.kotlin.name.isSubpackageOf import org.jetbrains.kotlin.resolve.ImportPath +import org.jetbrains.kotlin.resolve.SinceKotlinAccessibility import org.jetbrains.kotlin.resolve.TargetPlatform import org.jetbrains.kotlin.resolve.checkSinceKotlinVersionAccessibility import org.jetbrains.kotlin.resolve.descriptorUtil.fqNameSafe @@ -69,7 +70,7 @@ class DefaultImportProvider( val excludedImports: List by storageManager.createLazyValue { val builtinTypeAliases = moduleDescriptor.findTypeAliasesInPackages(PACKAGES_WITH_ALIASES) - .filter { it.checkSinceKotlinVersionAccessibility(languageVersionSettings) } + .filter { it.checkSinceKotlinVersionAccessibility(languageVersionSettings) == SinceKotlinAccessibility.Accessible } val nonKotlinDefaultImportedPackages = defaultImports diff --git a/compiler/resolution/src/org/jetbrains/kotlin/resolve/sinceKotlinUtil.kt b/compiler/frontend/src/org/jetbrains/kotlin/resolve/sinceKotlinUtil.kt similarity index 70% rename from compiler/resolution/src/org/jetbrains/kotlin/resolve/sinceKotlinUtil.kt rename to compiler/frontend/src/org/jetbrains/kotlin/resolve/sinceKotlinUtil.kt index bfc5da11d17..e8da09e259b 100644 --- a/compiler/resolution/src/org/jetbrains/kotlin/resolve/sinceKotlinUtil.kt +++ b/compiler/frontend/src/org/jetbrains/kotlin/resolve/sinceKotlinUtil.kt @@ -1,17 +1,6 @@ /* - * Copyright 2010-2017 JetBrains s.r.o. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. + * Copyright 2010-2018 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license + * that can be found in the license/LICENSE.txt file. */ package org.jetbrains.kotlin.resolve @@ -22,17 +11,22 @@ import org.jetbrains.kotlin.descriptors.* import org.jetbrains.kotlin.descriptors.impl.TypeAliasConstructorDescriptor import org.jetbrains.kotlin.name.FqName import org.jetbrains.kotlin.resolve.calls.util.FakeCallableDescriptorForTypeAliasObject +import org.jetbrains.kotlin.resolve.checkers.ExperimentalUsageChecker -val SINCE_KOTLIN_FQ_NAME = FqName("kotlin.SinceKotlin") +sealed class SinceKotlinAccessibility { + object Accessible : SinceKotlinAccessibility() -/** - * @return true if the descriptor is accessible according to [languageVersionSettings], or false otherwise. The [actionIfInaccessible] - * callback is called with the version specified in the [SinceKotlin] annotation if the descriptor is inaccessible. - */ -fun DeclarationDescriptor.checkSinceKotlinVersionAccessibility( - languageVersionSettings: LanguageVersionSettings, - actionIfInaccessible: ((ApiVersion) -> Unit)? = null -): Boolean { + data class NotAccessibleButWasExperimental( + val version: ApiVersion, + val annotationFqNames: List + ) : SinceKotlinAccessibility() + + data class NotAccessible( + val version: ApiVersion + ) : SinceKotlinAccessibility() +} + +fun DeclarationDescriptor.checkSinceKotlinVersionAccessibility(languageVersionSettings: LanguageVersionSettings): SinceKotlinAccessibility { val version = if (this is CallableMemberDescriptor && !kind.isReal) getSinceKotlinVersionByOverridden(this) else getOwnSinceKotlinVersion() @@ -41,11 +35,14 @@ fun DeclarationDescriptor.checkSinceKotlinVersionAccessibility( // 1) There's no @SinceKotlin annotation for this descriptor // 2) There's a @SinceKotlin annotation but its value is some unrecognizable nonsense // 3) The value as a version is not greater than our API version - if (version == null || version <= languageVersionSettings.apiVersion) return true + if (version == null || version <= languageVersionSettings.apiVersion) return SinceKotlinAccessibility.Accessible - actionIfInaccessible?.invoke(version) + val wasExperimentalFqNames = with(ExperimentalUsageChecker) { loadWasExperimentalMarkerFqNames() } + if (wasExperimentalFqNames.isNotEmpty()) { + return SinceKotlinAccessibility.NotAccessibleButWasExperimental(version, wasExperimentalFqNames) + } - return false + return SinceKotlinAccessibility.NotAccessible(version) } /** diff --git a/compiler/resolution/src/org/jetbrains/kotlin/resolve/Annotations.kt b/compiler/resolution/src/org/jetbrains/kotlin/resolve/Annotations.kt new file mode 100644 index 00000000000..08f0724583b --- /dev/null +++ b/compiler/resolution/src/org/jetbrains/kotlin/resolve/Annotations.kt @@ -0,0 +1,10 @@ +/* + * Copyright 2010-2018 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license + * that can be found in the license/LICENSE.txt file. + */ + +package org.jetbrains.kotlin.resolve + +import org.jetbrains.kotlin.name.FqName + +val SINCE_KOTLIN_FQ_NAME = FqName("kotlin.SinceKotlin") diff --git a/compiler/resolution/src/org/jetbrains/kotlin/resolve/calls/KotlinCallResolver.kt b/compiler/resolution/src/org/jetbrains/kotlin/resolve/calls/KotlinCallResolver.kt index 9a5b028433b..8f44463cc9f 100644 --- a/compiler/resolution/src/org/jetbrains/kotlin/resolve/calls/KotlinCallResolver.kt +++ b/compiler/resolution/src/org/jetbrains/kotlin/resolve/calls/KotlinCallResolver.kt @@ -45,7 +45,7 @@ class KotlinCallResolver( ): CallResolutionResult { kotlinCall.checkCallInvariants() - val candidateFactory = SimpleCandidateFactory(callComponents, scopeTower, kotlinCall, resolutionCallbacks.inferenceSession) + val candidateFactory = SimpleCandidateFactory(callComponents, scopeTower, kotlinCall, resolutionCallbacks) val processor = when (kotlinCall.callKind) { KotlinCallKind.VARIABLE -> { createVariableAndObjectProcessor(scopeTower, kotlinCall.name, candidateFactory, kotlinCall.explicitReceiver?.receiver) @@ -96,7 +96,7 @@ class KotlinCallResolver( collectAllCandidates: Boolean ): CallResolutionResult { kotlinCall.checkCallInvariants() - val candidateFactory = SimpleCandidateFactory(callComponents, scopeTower, kotlinCall, resolutionCallbacks.inferenceSession) + val candidateFactory = SimpleCandidateFactory(callComponents, scopeTower, kotlinCall, resolutionCallbacks) val resolutionCandidates = givenCandidates.map { candidateFactory.createCandidate(it).forceResolution() } diff --git a/compiler/resolution/src/org/jetbrains/kotlin/resolve/calls/components/ExternalComponents.kt b/compiler/resolution/src/org/jetbrains/kotlin/resolve/calls/components/ExternalComponents.kt index c9c482bec5b..ca9c6bf36ac 100644 --- a/compiler/resolution/src/org/jetbrains/kotlin/resolve/calls/components/ExternalComponents.kt +++ b/compiler/resolution/src/org/jetbrains/kotlin/resolve/calls/components/ExternalComponents.kt @@ -21,7 +21,10 @@ interface KotlinResolutionStatelessCallbacks { fun isInfixCall(kotlinCall: KotlinCall): Boolean fun isOperatorCall(kotlinCall: KotlinCall): Boolean fun isSuperOrDelegatingConstructorCall(kotlinCall: KotlinCall): Boolean - fun isHiddenInResolution(descriptor: DeclarationDescriptor, kotlinCall: KotlinCall): Boolean + fun isHiddenInResolution( + descriptor: DeclarationDescriptor, kotlinCall: KotlinCall, resolutionCallbacks: KotlinResolutionCallbacks + ): Boolean + fun isSuperExpression(receiver: SimpleKotlinCallArgument?): Boolean fun getScopeTowerForCallableReferenceArgument(argument: CallableReferenceKotlinCallArgument): ImplicitScopeTower fun getVariableCandidateIfInvoke(functionCall: KotlinCall): KotlinResolutionCandidate? diff --git a/compiler/resolution/src/org/jetbrains/kotlin/resolve/calls/model/KotlinResolverContext.kt b/compiler/resolution/src/org/jetbrains/kotlin/resolve/calls/model/KotlinResolverContext.kt index 36f83c41599..2e92f3381e0 100644 --- a/compiler/resolution/src/org/jetbrains/kotlin/resolve/calls/model/KotlinResolverContext.kt +++ b/compiler/resolution/src/org/jetbrains/kotlin/resolve/calls/model/KotlinResolverContext.kt @@ -49,8 +49,10 @@ class SimpleCandidateFactory( val callComponents: KotlinCallComponents, val scopeTower: ImplicitScopeTower, val kotlinCall: KotlinCall, - val inferenceSession: InferenceSession + val resolutionCallbacks: KotlinResolutionCallbacks ) : CandidateFactory { + val inferenceSession: InferenceSession = resolutionCallbacks.inferenceSession + val baseSystem: ConstraintStorage init { @@ -144,7 +146,7 @@ class SimpleCandidateFactory( initialDiagnostics.forEach(candidate::addDiagnostic) - if (callComponents.statelessCallbacks.isHiddenInResolution(descriptor, kotlinCall)) { + if (callComponents.statelessCallbacks.isHiddenInResolution(descriptor, kotlinCall, resolutionCallbacks)) { candidate.addDiagnostic(HiddenDescriptor) } diff --git a/compiler/testData/diagnostics/testsWithStdLib/experimental/wasExperimental.kt b/compiler/testData/diagnostics/testsWithStdLib/experimental/wasExperimental.kt new file mode 100644 index 00000000000..5df8444b7be --- /dev/null +++ b/compiler/testData/diagnostics/testsWithStdLib/experimental/wasExperimental.kt @@ -0,0 +1,45 @@ +// !API_VERSION: 1.2 +// !USE_EXPERIMENTAL: kotlin.Experimental +// !DIAGNOSTICS: -INVISIBLE_MEMBER -INVISIBLE_REFERENCE -NEWER_VERSION_IN_SINCE_KOTLIN -UNUSED_PARAMETER + +@SinceKotlin("1.3") +fun newPublishedFun() {} + + +@Experimental +annotation class Marker + +@SinceKotlin("1.3") +@WasExperimental(Marker::class) +fun newFunExperimentalInThePast() {} + +@SinceKotlin("1.3") +@WasExperimental(Marker::class) +val newValExperimentalInThePast = "" + +@SinceKotlin("1.3") +@WasExperimental(Marker::class) +class NewClassExperimentalInThePast + +fun use1(c: NewClassExperimentalInThePast) { + newPublishedFun() + newFunExperimentalInThePast() + newValExperimentalInThePast + NewClassExperimentalInThePast() +} + +@UseExperimental(Marker::class) +fun use2(c: NewClassExperimentalInThePast) { + newPublishedFun() + newFunExperimentalInThePast() + newValExperimentalInThePast + NewClassExperimentalInThePast() +} + +@Marker +fun use3(c: NewClassExperimentalInThePast) { + newPublishedFun() + newFunExperimentalInThePast() + newValExperimentalInThePast + NewClassExperimentalInThePast() +} diff --git a/compiler/testData/diagnostics/testsWithStdLib/experimental/wasExperimental.txt b/compiler/testData/diagnostics/testsWithStdLib/experimental/wasExperimental.txt new file mode 100644 index 00000000000..1b19b2717ff --- /dev/null +++ b/compiler/testData/diagnostics/testsWithStdLib/experimental/wasExperimental.txt @@ -0,0 +1,14 @@ +package + +@kotlin.SinceKotlin(version = "1.3") @kotlin.WasExperimental(markerClass = {Marker::class}) public fun newFunExperimentalInThePast(): kotlin.Unit +@kotlin.SinceKotlin(version = "1.3") public fun newPublishedFun(): kotlin.Unit +public fun use1(): kotlin.Unit +@kotlin.UseExperimental(markerClass = {Marker::class}) public fun use2(): kotlin.Unit +@Marker public fun use3(): kotlin.Unit + +@kotlin.Experimental public final annotation class Marker : kotlin.Annotation { + public constructor Marker() + public open override /*1*/ /*fake_override*/ fun equals(/*0*/ other: kotlin.Any?): kotlin.Boolean + public open override /*1*/ /*fake_override*/ fun hashCode(): kotlin.Int + public open override /*1*/ /*fake_override*/ fun toString(): kotlin.String +} diff --git a/compiler/tests/org/jetbrains/kotlin/checkers/DiagnosticsTestWithStdLibGenerated.java b/compiler/tests/org/jetbrains/kotlin/checkers/DiagnosticsTestWithStdLibGenerated.java index e3569b7a1fc..1d94eb05276 100644 --- a/compiler/tests/org/jetbrains/kotlin/checkers/DiagnosticsTestWithStdLibGenerated.java +++ b/compiler/tests/org/jetbrains/kotlin/checkers/DiagnosticsTestWithStdLibGenerated.java @@ -2196,6 +2196,11 @@ public class DiagnosticsTestWithStdLibGenerated extends AbstractDiagnosticsTestW public void testUseExperimentalWithSeveralAnnotations() throws Exception { runTest("compiler/testData/diagnostics/testsWithStdLib/experimental/useExperimentalWithSeveralAnnotations.kt"); } + + @TestMetadata("wasExperimental.kt") + public void testWasExperimental() throws Exception { + runTest("compiler/testData/diagnostics/testsWithStdLib/experimental/wasExperimental.kt"); + } } @TestMetadata("compiler/testData/diagnostics/testsWithStdLib/forInArrayLoop") diff --git a/compiler/tests/org/jetbrains/kotlin/checkers/javac/DiagnosticsTestWithStdLibUsingJavacGenerated.java b/compiler/tests/org/jetbrains/kotlin/checkers/javac/DiagnosticsTestWithStdLibUsingJavacGenerated.java index 42ce493f8e3..09ff9829b24 100644 --- a/compiler/tests/org/jetbrains/kotlin/checkers/javac/DiagnosticsTestWithStdLibUsingJavacGenerated.java +++ b/compiler/tests/org/jetbrains/kotlin/checkers/javac/DiagnosticsTestWithStdLibUsingJavacGenerated.java @@ -2196,6 +2196,11 @@ public class DiagnosticsTestWithStdLibUsingJavacGenerated extends AbstractDiagno public void testUseExperimentalWithSeveralAnnotations() throws Exception { runTest("compiler/testData/diagnostics/testsWithStdLib/experimental/useExperimentalWithSeveralAnnotations.kt"); } + + @TestMetadata("wasExperimental.kt") + public void testWasExperimental() throws Exception { + runTest("compiler/testData/diagnostics/testsWithStdLib/experimental/wasExperimental.kt"); + } } @TestMetadata("compiler/testData/diagnostics/testsWithStdLib/forInArrayLoop") diff --git a/libraries/stdlib/src/kotlin/annotations/Experimental.kt b/libraries/stdlib/src/kotlin/annotations/Experimental.kt index 352900f4de2..c59339066f3 100644 --- a/libraries/stdlib/src/kotlin/annotations/Experimental.kt +++ b/libraries/stdlib/src/kotlin/annotations/Experimental.kt @@ -50,3 +50,10 @@ annotation class Experimental(val level: Level = Level.ERROR) { annotation class UseExperimental( vararg val markerClass: KClass ) + + +@Target(CLASS, PROPERTY, CONSTRUCTOR, FUNCTION) +@Retention(BINARY) +internal annotation class WasExperimental( + vararg val markerClass: KClass +)