[FE 1.0] Prohibit implicit Java actualization in K1
^KT-58545 Fixed Review: https://jetbrains.team/p/kt/reviews/10561 It's not yet supported in K2 KT-59213 Related tests: - ApiTest.testStdlib - RuntimePublicAPITest.kotlinStdlibRuntimeMerged - KotlinProjectViewTestGenerated.test_Arrays (in Kotlin plugin)
This commit is contained in:
@@ -817,6 +817,8 @@ public interface Errors {
|
||||
DiagnosticFactory3<KtNamedDeclaration, MemberDescriptor, ModuleDescriptor,
|
||||
Map<Incompatible<MemberDescriptor>, Collection<MemberDescriptor>>> NO_ACTUAL_FOR_EXPECT =
|
||||
DiagnosticFactory3.create(ERROR, INCOMPATIBLE_DECLARATION);
|
||||
DiagnosticFactory2<KtNamedDeclaration, MemberDescriptor, ModuleDescriptor> IMPLICIT_JVM_ACTUALIZATION =
|
||||
DiagnosticFactory2.create(ERROR, INCOMPATIBLE_DECLARATION);
|
||||
DiagnosticFactory2<KtNamedDeclaration, MemberDescriptor,
|
||||
Map<Incompatible<MemberDescriptor>, Collection<MemberDescriptor>>> ACTUAL_WITHOUT_EXPECT =
|
||||
DiagnosticFactory2.create(ERROR, INCOMPATIBLE_DECLARATION);
|
||||
|
||||
+4
@@ -374,6 +374,10 @@ public class DefaultErrorMessages {
|
||||
|
||||
MAP.put(NO_ACTUAL_FOR_EXPECT, "Expected {0} has no actual declaration in module {1}{2}", DECLARATION_NAME_WITH_KIND,
|
||||
MODULE_WITH_PLATFORM, adaptGenerics1(PlatformIncompatibilityDiagnosticRenderer.TEXT));
|
||||
MAP.put(IMPLICIT_JVM_ACTUALIZATION, "Expected {0} is implicitly actualized by Java declaration in module {1}. " +
|
||||
"Please migrate to explicit ''actual typealias''. See: https://youtrack.jetbrains.com/issue/KT-58545",
|
||||
DECLARATION_NAME_WITH_KIND,
|
||||
MODULE_WITH_PLATFORM);
|
||||
MAP.put(ACTUAL_WITHOUT_EXPECT, "{0} has no corresponding expected declaration{1}", CAPITALIZED_DECLARATION_NAME_WITH_KIND_AND_PLATFORM,
|
||||
adaptGenerics1(PlatformIncompatibilityDiagnosticRenderer.TEXT));
|
||||
MAP.put(AMBIGUOUS_ACTUALS, "{0} has several compatible actual declarations in modules {1}", CAPITALIZED_DECLARATION_NAME_WITH_KIND_AND_PLATFORM, CommonRenderers.commaSeparated(
|
||||
|
||||
+33
-3
@@ -23,6 +23,8 @@ import org.jetbrains.kotlin.config.LanguageFeature
|
||||
import org.jetbrains.kotlin.descriptors.*
|
||||
import org.jetbrains.kotlin.diagnostics.Errors
|
||||
import org.jetbrains.kotlin.incremental.components.ExpectActualTracker
|
||||
import org.jetbrains.kotlin.mpp.MppJavaImplicitActualizatorMarker
|
||||
import org.jetbrains.kotlin.name.FqName
|
||||
import org.jetbrains.kotlin.psi.*
|
||||
import org.jetbrains.kotlin.psi.psiUtil.hasActualModifier
|
||||
import org.jetbrains.kotlin.resolve.*
|
||||
@@ -40,6 +42,8 @@ import org.jetbrains.kotlin.types.KotlinType
|
||||
import org.jetbrains.kotlin.utils.addToStdlib.cast
|
||||
import java.io.File
|
||||
|
||||
private val implicitlyActualizedAnnotationFqn = FqName("kotlin.jvm.ImplicitlyActualizedByJvmDeclaration")
|
||||
|
||||
class ExpectedActualDeclarationChecker(
|
||||
val moduleStructureOracle: ModuleStructureOracle,
|
||||
val argumentExtractors: Iterable<ActualAnnotationArgumentExtractor>
|
||||
@@ -64,7 +68,7 @@ class ExpectedActualDeclarationChecker(
|
||||
if (descriptor.isExpect) {
|
||||
checkExpectedDeclarationHasProperActuals(
|
||||
declaration, descriptor, context.trace,
|
||||
checkActualModifier, context.expectActualTracker
|
||||
checkActualModifier, context
|
||||
)
|
||||
checkOptInAnnotation(declaration, descriptor, descriptor, context.trace)
|
||||
}
|
||||
@@ -93,7 +97,7 @@ class ExpectedActualDeclarationChecker(
|
||||
descriptor: MemberDescriptor,
|
||||
trace: BindingTrace,
|
||||
checkActualModifier: Boolean,
|
||||
expectActualTracker: ExpectActualTracker
|
||||
context: DeclarationCheckerContext
|
||||
) {
|
||||
val allActualizationPaths = moduleStructureOracle.findAllReversedDependsOnPaths(descriptor.module)
|
||||
val allLeafModules = allActualizationPaths.map { it.nodes.last() }.toSet()
|
||||
@@ -102,15 +106,41 @@ class ExpectedActualDeclarationChecker(
|
||||
val actuals = ExpectedActualResolver.findActualForExpected(descriptor, leafModule) ?: return@forEach
|
||||
|
||||
checkExpectedDeclarationHasAtLeastOneActual(
|
||||
reportOn, descriptor, actuals, trace, leafModule, checkActualModifier, expectActualTracker
|
||||
reportOn, descriptor, actuals, trace, leafModule, checkActualModifier, context.expectActualTracker
|
||||
)
|
||||
|
||||
checkImplicitJavaActualization(reportOn, descriptor, actuals, leafModule, context)
|
||||
|
||||
checkExpectedDeclarationHasAtMostOneActual(
|
||||
reportOn, descriptor, actuals, allActualizationPaths, trace
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
private fun checkImplicitJavaActualization(
|
||||
expectPsi: KtNamedDeclaration,
|
||||
expect: MemberDescriptor,
|
||||
actuals: ActualsMap,
|
||||
module: ModuleDescriptor,
|
||||
context: DeclarationCheckerContext
|
||||
) {
|
||||
val actualMembers = actuals
|
||||
.filter { (compatibility, _) -> compatibility.isCompatibleOrWeakCompatible() }
|
||||
.flatMap { (_, members) -> members }
|
||||
.takeIf(List<MemberDescriptor>::isNotEmpty)
|
||||
?: return
|
||||
|
||||
if (actualMembers.any {
|
||||
it is MppJavaImplicitActualizatorMarker &&
|
||||
with(OptInUsageChecker) {
|
||||
!expectPsi.isDeclarationAnnotatedWith(implicitlyActualizedAnnotationFqn, context.trace.bindingContext)
|
||||
}
|
||||
}
|
||||
) {
|
||||
context.trace.report(Errors.IMPLICIT_JVM_ACTUALIZATION.on(expectPsi, expect, module))
|
||||
}
|
||||
}
|
||||
|
||||
private fun checkExpectedDeclarationHasAtMostOneActual(
|
||||
reportOn: KtNamedDeclaration,
|
||||
expectDescriptor: MemberDescriptor,
|
||||
|
||||
@@ -343,7 +343,7 @@ class OptInUsageChecker(project: Project) : CallChecker {
|
||||
}
|
||||
}
|
||||
|
||||
private fun PsiElement.isDeclarationAnnotatedWith(annotationFqName: FqName, bindingContext: BindingContext): Boolean {
|
||||
internal fun PsiElement.isDeclarationAnnotatedWith(annotationFqName: FqName, bindingContext: BindingContext): Boolean {
|
||||
if (this !is KtDeclaration) return false
|
||||
|
||||
val descriptor = bindingContext.get(BindingContext.DECLARATION_TO_DESCRIPTOR, this)
|
||||
|
||||
Reference in New Issue
Block a user