From 314784f4351fb61bc916cfc3ca27b16e807ec2ac Mon Sep 17 00:00:00 2001 From: Kirill Rakhman Date: Fri, 3 Feb 2023 12:08:17 +0100 Subject: [PATCH] [FIR] Introduce FirDeclarationStatus.hasStableParameterNames This flag is true by default but is set to false for - Java methods and constructors - interface delegation methods that delegate to Java The NAMED_ARGUMENTS_NOT_ALLOWED logic is mostly refactored to use the new flag though some custom logic remains for determining the correct message and to work around a corner case with fake overrides. The flag is (de)serialized from/to metadata. For backward compatibility with K1, delegated methods to Java types are deserialized as stable. ^KT-40480 Fixed --- .../symbols/KtFirAnonymousFunctionSymbol.kt | 4 +- .../api/fir/symbols/KtFirConstructorSymbol.kt | 4 +- .../api/fir/symbols/KtFirFunctionSymbol.kt | 3 +- .../fir/symbols/KtFirSamConstructorSymbol.kt | 4 +- ...CompilerTestFE10TestdataTestGenerated.java | 12 ++++++ ...irOldFrontendDiagnosticsTestGenerated.java | 12 ++++++ ...DiagnosticsWithLightTreeTestGenerated.java | 12 ++++++ .../deserialization/FirMemberDeserializer.kt | 2 + .../fir/serialization/FirElementSerializer.kt | 14 ++++++- .../kotlin/fir/java/FirJavaFacade.kt | 2 + .../java/enhancement/SignatureEnhancement.kt | 7 ++-- ...nsionSyntheticFunctionInterfaceProvider.kt | 10 +++-- .../kotlin/fir/resolve/ResolveUtils.kt | 39 +++++-------------- .../fir/declarations/FirDeclarationStatus.kt | 1 + .../FirResolvedDeclarationStatus.kt | 1 + .../src/org/jetbrains/kotlin/fir/Utils.kt | 2 + .../impl/FirDeclarationStatusImpl.kt | 11 +++++- .../fir/declarations/utils/FirStatusUtils.kt | 1 + .../fir/tree/generator/NodeConfigurator.kt | 2 +- .../context/AbstractFieldConfigurator.kt | 2 +- .../library/JavaInterface.java | 3 ++ .../library/JavaSuperClass.java | 4 ++ .../library/KtClass.kt | 1 + .../hasStableParameterNames/output.txt | 1 + .../hasStableParameterNames/source.kt | 6 +++ .../disallowForDelegationToJavaMethods.kt | 24 ++++++++++++ .../disallowForFunctionTypes.kt | 6 +++ .../test/runners/DiagnosticTestGenerated.java | 12 ++++++ .../CompileKotlinAgainstCustomBinariesTest.kt | 5 +++ 29 files changed, 156 insertions(+), 51 deletions(-) create mode 100644 compiler/testData/compileKotlinAgainstCustomBinaries/hasStableParameterNames/library/JavaInterface.java create mode 100644 compiler/testData/compileKotlinAgainstCustomBinaries/hasStableParameterNames/library/JavaSuperClass.java create mode 100644 compiler/testData/compileKotlinAgainstCustomBinaries/hasStableParameterNames/library/KtClass.kt create mode 100644 compiler/testData/compileKotlinAgainstCustomBinaries/hasStableParameterNames/output.txt create mode 100644 compiler/testData/compileKotlinAgainstCustomBinaries/hasStableParameterNames/source.kt create mode 100644 compiler/testData/diagnostics/tests/namedArguments/disallowForDelegationToJavaMethods.kt create mode 100644 compiler/testData/diagnostics/tests/namedArguments/disallowForFunctionTypes.kt diff --git a/analysis/analysis-api-fir/src/org/jetbrains/kotlin/analysis/api/fir/symbols/KtFirAnonymousFunctionSymbol.kt b/analysis/analysis-api-fir/src/org/jetbrains/kotlin/analysis/api/fir/symbols/KtFirAnonymousFunctionSymbol.kt index f685f088ffc..0412a052ca9 100644 --- a/analysis/analysis-api-fir/src/org/jetbrains/kotlin/analysis/api/fir/symbols/KtFirAnonymousFunctionSymbol.kt +++ b/analysis/analysis-api-fir/src/org/jetbrains/kotlin/analysis/api/fir/symbols/KtFirAnonymousFunctionSymbol.kt @@ -21,7 +21,7 @@ import org.jetbrains.kotlin.analysis.api.symbols.pointers.CanNotCreateSymbolPoin import org.jetbrains.kotlin.analysis.api.symbols.pointers.KtPsiBasedSymbolPointer import org.jetbrains.kotlin.analysis.api.symbols.pointers.KtSymbolPointer import org.jetbrains.kotlin.analysis.api.types.KtType -import org.jetbrains.kotlin.fir.resolve.getHasStableParameterNames +import org.jetbrains.kotlin.fir.declarations.utils.hasStableParameterNames import org.jetbrains.kotlin.fir.symbols.impl.FirAnonymousFunctionSymbol import org.jetbrains.kotlin.fir.symbols.impl.isExtension @@ -46,7 +46,7 @@ internal class KtFirAnonymousFunctionSymbol( override val hasStableParameterNames: Boolean get() = withValidityAssertion { - firSymbol.fir.getHasStableParameterNames(firSymbol.moduleData.session) + firSymbol.fir.hasStableParameterNames } override val isExtension: Boolean get() = withValidityAssertion { firSymbol.isExtension } diff --git a/analysis/analysis-api-fir/src/org/jetbrains/kotlin/analysis/api/fir/symbols/KtFirConstructorSymbol.kt b/analysis/analysis-api-fir/src/org/jetbrains/kotlin/analysis/api/fir/symbols/KtFirConstructorSymbol.kt index 3cf6df0e162..4c5af2d2584 100644 --- a/analysis/analysis-api-fir/src/org/jetbrains/kotlin/analysis/api/fir/symbols/KtFirConstructorSymbol.kt +++ b/analysis/analysis-api-fir/src/org/jetbrains/kotlin/analysis/api/fir/symbols/KtFirConstructorSymbol.kt @@ -24,8 +24,8 @@ import org.jetbrains.kotlin.analysis.api.symbols.pointers.KtSymbolPointer import org.jetbrains.kotlin.analysis.api.types.KtType import org.jetbrains.kotlin.descriptors.Visibility import org.jetbrains.kotlin.fir.containingClassLookupTag +import org.jetbrains.kotlin.fir.declarations.utils.hasStableParameterNames import org.jetbrains.kotlin.fir.declarations.utils.visibility -import org.jetbrains.kotlin.fir.resolve.getHasStableParameterNames import org.jetbrains.kotlin.fir.symbols.impl.FirConstructorSymbol import org.jetbrains.kotlin.name.ClassId @@ -41,7 +41,7 @@ internal class KtFirConstructorSymbol( override val hasStableParameterNames: Boolean get() = withValidityAssertion { - firSymbol.fir.getHasStableParameterNames(firSymbol.moduleData.session) + firSymbol.fir.hasStableParameterNames } override val visibility: Visibility get() = withValidityAssertion { firSymbol.visibility } diff --git a/analysis/analysis-api-fir/src/org/jetbrains/kotlin/analysis/api/fir/symbols/KtFirFunctionSymbol.kt b/analysis/analysis-api-fir/src/org/jetbrains/kotlin/analysis/api/fir/symbols/KtFirFunctionSymbol.kt index 6668983bd2b..a5c60c6fad1 100644 --- a/analysis/analysis-api-fir/src/org/jetbrains/kotlin/analysis/api/fir/symbols/KtFirFunctionSymbol.kt +++ b/analysis/analysis-api-fir/src/org/jetbrains/kotlin/analysis/api/fir/symbols/KtFirFunctionSymbol.kt @@ -34,7 +34,6 @@ import org.jetbrains.kotlin.descriptors.Visibility import org.jetbrains.kotlin.fir.containingClassLookupTag import org.jetbrains.kotlin.fir.contracts.FirEffectDeclaration import org.jetbrains.kotlin.fir.declarations.utils.* -import org.jetbrains.kotlin.fir.resolve.getHasStableParameterNames import org.jetbrains.kotlin.fir.symbols.impl.FirNamedFunctionSymbol import org.jetbrains.kotlin.fir.symbols.impl.isExtension import org.jetbrains.kotlin.name.CallableId @@ -65,7 +64,7 @@ internal class KtFirFunctionSymbol( override val valueParameters: List by cached { firSymbol.createKtValueParameters(builder) } override val hasStableParameterNames: Boolean - get() = withValidityAssertion { firSymbol.fir.getHasStableParameterNames(firSymbol.moduleData.session) } + get() = withValidityAssertion { firSymbol.fir.hasStableParameterNames } override val annotationsList by cached { KtFirAnnotationListForDeclaration.create( diff --git a/analysis/analysis-api-fir/src/org/jetbrains/kotlin/analysis/api/fir/symbols/KtFirSamConstructorSymbol.kt b/analysis/analysis-api-fir/src/org/jetbrains/kotlin/analysis/api/fir/symbols/KtFirSamConstructorSymbol.kt index 8a569fa9ee3..25b67078512 100644 --- a/analysis/analysis-api-fir/src/org/jetbrains/kotlin/analysis/api/fir/symbols/KtFirSamConstructorSymbol.kt +++ b/analysis/analysis-api-fir/src/org/jetbrains/kotlin/analysis/api/fir/symbols/KtFirSamConstructorSymbol.kt @@ -22,7 +22,7 @@ import org.jetbrains.kotlin.analysis.api.symbols.KtTypeParameterSymbol import org.jetbrains.kotlin.analysis.api.symbols.KtValueParameterSymbol import org.jetbrains.kotlin.analysis.api.symbols.pointers.KtSymbolPointer import org.jetbrains.kotlin.analysis.api.types.KtType -import org.jetbrains.kotlin.fir.resolve.getHasStableParameterNames +import org.jetbrains.kotlin.fir.declarations.utils.hasStableParameterNames import org.jetbrains.kotlin.fir.symbols.impl.FirNamedFunctionSymbol import org.jetbrains.kotlin.fir.symbols.impl.isExtension import org.jetbrains.kotlin.name.CallableId @@ -54,7 +54,7 @@ internal class KtFirSamConstructorSymbol( override val hasStableParameterNames: Boolean get() = withValidityAssertion { - firSymbol.fir.getHasStableParameterNames(firSymbol.moduleData.session) + firSymbol.fir.hasStableParameterNames } override val isExtension: Boolean get() = withValidityAssertion { firSymbol.isExtension } diff --git a/analysis/low-level-api-fir/tests/org/jetbrains/kotlin/analysis/low/level/api/fir/diagnostic/compiler/based/DiagnosisCompilerTestFE10TestdataTestGenerated.java b/analysis/low-level-api-fir/tests/org/jetbrains/kotlin/analysis/low/level/api/fir/diagnostic/compiler/based/DiagnosisCompilerTestFE10TestdataTestGenerated.java index 2d0d8d8e14c..fab12e47397 100644 --- a/analysis/low-level-api-fir/tests/org/jetbrains/kotlin/analysis/low/level/api/fir/diagnostic/compiler/based/DiagnosisCompilerTestFE10TestdataTestGenerated.java +++ b/analysis/low-level-api-fir/tests/org/jetbrains/kotlin/analysis/low/level/api/fir/diagnostic/compiler/based/DiagnosisCompilerTestFE10TestdataTestGenerated.java @@ -22094,6 +22094,18 @@ public class DiagnosisCompilerTestFE10TestdataTestGenerated extends AbstractDiag runTest("compiler/testData/diagnostics/tests/namedArguments/ambiguousNamedArgumentsWithGenerics3.kt"); } + @Test + @TestMetadata("disallowForDelegationToJavaMethods.kt") + public void testDisallowForDelegationToJavaMethods() throws Exception { + runTest("compiler/testData/diagnostics/tests/namedArguments/disallowForDelegationToJavaMethods.kt"); + } + + @Test + @TestMetadata("disallowForFunctionTypes.kt") + public void testDisallowForFunctionTypes() throws Exception { + runTest("compiler/testData/diagnostics/tests/namedArguments/disallowForFunctionTypes.kt"); + } + @Test @TestMetadata("disallowForJavaConstructor.kt") public void testDisallowForJavaConstructor() throws Exception { diff --git a/compiler/fir/analysis-tests/tests-gen/org/jetbrains/kotlin/test/runners/FirOldFrontendDiagnosticsTestGenerated.java b/compiler/fir/analysis-tests/tests-gen/org/jetbrains/kotlin/test/runners/FirOldFrontendDiagnosticsTestGenerated.java index 64ba948aceb..71a3df46a9b 100644 --- a/compiler/fir/analysis-tests/tests-gen/org/jetbrains/kotlin/test/runners/FirOldFrontendDiagnosticsTestGenerated.java +++ b/compiler/fir/analysis-tests/tests-gen/org/jetbrains/kotlin/test/runners/FirOldFrontendDiagnosticsTestGenerated.java @@ -22100,6 +22100,18 @@ public class FirOldFrontendDiagnosticsTestGenerated extends AbstractFirDiagnosti runTest("compiler/testData/diagnostics/tests/namedArguments/ambiguousNamedArgumentsWithGenerics3.kt"); } + @Test + @TestMetadata("disallowForDelegationToJavaMethods.kt") + public void testDisallowForDelegationToJavaMethods() throws Exception { + runTest("compiler/testData/diagnostics/tests/namedArguments/disallowForDelegationToJavaMethods.kt"); + } + + @Test + @TestMetadata("disallowForFunctionTypes.kt") + public void testDisallowForFunctionTypes() throws Exception { + runTest("compiler/testData/diagnostics/tests/namedArguments/disallowForFunctionTypes.kt"); + } + @Test @TestMetadata("disallowForJavaConstructor.kt") public void testDisallowForJavaConstructor() throws Exception { diff --git a/compiler/fir/analysis-tests/tests-gen/org/jetbrains/kotlin/test/runners/FirOldFrontendDiagnosticsWithLightTreeTestGenerated.java b/compiler/fir/analysis-tests/tests-gen/org/jetbrains/kotlin/test/runners/FirOldFrontendDiagnosticsWithLightTreeTestGenerated.java index 93e79b941db..69b4dd8f523 100644 --- a/compiler/fir/analysis-tests/tests-gen/org/jetbrains/kotlin/test/runners/FirOldFrontendDiagnosticsWithLightTreeTestGenerated.java +++ b/compiler/fir/analysis-tests/tests-gen/org/jetbrains/kotlin/test/runners/FirOldFrontendDiagnosticsWithLightTreeTestGenerated.java @@ -22094,6 +22094,18 @@ public class FirOldFrontendDiagnosticsWithLightTreeTestGenerated extends Abstrac runTest("compiler/testData/diagnostics/tests/namedArguments/ambiguousNamedArgumentsWithGenerics3.kt"); } + @Test + @TestMetadata("disallowForDelegationToJavaMethods.kt") + public void testDisallowForDelegationToJavaMethods() throws Exception { + runTest("compiler/testData/diagnostics/tests/namedArguments/disallowForDelegationToJavaMethods.kt"); + } + + @Test + @TestMetadata("disallowForFunctionTypes.kt") + public void testDisallowForFunctionTypes() throws Exception { + runTest("compiler/testData/diagnostics/tests/namedArguments/disallowForFunctionTypes.kt"); + } + @Test @TestMetadata("disallowForJavaConstructor.kt") public void testDisallowForJavaConstructor() throws Exception { diff --git a/compiler/fir/fir-deserialization/src/org/jetbrains/kotlin/fir/deserialization/FirMemberDeserializer.kt b/compiler/fir/fir-deserialization/src/org/jetbrains/kotlin/fir/deserialization/FirMemberDeserializer.kt index 288c6e03583..75c62548959 100644 --- a/compiler/fir/fir-deserialization/src/org/jetbrains/kotlin/fir/deserialization/FirMemberDeserializer.kt +++ b/compiler/fir/fir-deserialization/src/org/jetbrains/kotlin/fir/deserialization/FirMemberDeserializer.kt @@ -502,6 +502,7 @@ class FirMemberDeserializer(private val c: FirDeserializationContext) { isTailRec = Flags.IS_TAILREC.get(flags) isExternal = Flags.IS_EXTERNAL_FUNCTION.get(flags) isSuspend = Flags.IS_SUSPEND.get(flags) + hasStableParameterNames = !Flags.IS_FUNCTION_WITH_NON_STABLE_PARAMETER_NAMES.get(flags) } this.symbol = symbol dispatchReceiverType = c.dispatchReceiver @@ -571,6 +572,7 @@ class FirMemberDeserializer(private val c: FirDeserializationContext) { visibility.toEffectiveVisibility(classBuilder.symbol) ).apply { isExpect = Flags.IS_EXPECT_FUNCTION.get(flags) + hasStableParameterNames = !Flags.IS_CONSTRUCTOR_WITH_NON_STABLE_PARAMETER_NAMES.get(flags) isActual = false isOverride = false this.isInner = isInner diff --git a/compiler/fir/fir-serialization/src/org/jetbrains/kotlin/fir/serialization/FirElementSerializer.kt b/compiler/fir/fir-serialization/src/org/jetbrains/kotlin/fir/serialization/FirElementSerializer.kt index 26a2c85286f..46e19df8222 100644 --- a/compiler/fir/fir-serialization/src/org/jetbrains/kotlin/fir/serialization/FirElementSerializer.kt +++ b/compiler/fir/fir-serialization/src/org/jetbrains/kotlin/fir/serialization/FirElementSerializer.kt @@ -433,8 +433,9 @@ class FirElementSerializer private constructor( simpleFunction?.isExternal == true, simpleFunction?.isSuspend == true, simpleFunction?.isExpect == true, - true // TODO: supply 'hasStableParameterNames' flag for metadata + shouldSetStableParameterNames(simpleFunction), ) + if (flags != builder.flags) { builder.flags = flags } @@ -507,6 +508,15 @@ class FirElementSerializer private constructor( return builder } + private fun shouldSetStableParameterNames(simpleFunction: FirSimpleFunction?): Boolean { + return when { + simpleFunction?.hasStableParameterNames == true -> true + // for backward compatibility with K1, remove this line to fix KT-4758 + simpleFunction?.origin == FirDeclarationOrigin.Delegated -> true + else -> false + } + } + private fun typeAliasProto(typeAlias: FirTypeAlias): ProtoBuf.TypeAlias.Builder? = whileAnalysing(session, typeAlias) { if (!extension.shouldSerializeTypeAlias(typeAlias)) return null @@ -570,7 +580,7 @@ class FirElementSerializer private constructor( constructor.nonSourceAnnotations(session).isNotEmpty(), ProtoEnumFlags.visibility(normalizeVisibility(constructor)), !constructor.isPrimary, - true // TODO: supply 'hasStableParameterNames' flag for metadata + constructor.hasStableParameterNames, ) if (flags != builder.flags) { builder.flags = flags diff --git a/compiler/fir/java/src/org/jetbrains/kotlin/fir/java/FirJavaFacade.kt b/compiler/fir/java/src/org/jetbrains/kotlin/fir/java/FirJavaFacade.kt index 084c2500247..611ce865210 100644 --- a/compiler/fir/java/src/org/jetbrains/kotlin/fir/java/FirJavaFacade.kt +++ b/compiler/fir/java/src/org/jetbrains/kotlin/fir/java/FirJavaFacade.kt @@ -572,6 +572,7 @@ abstract class FirJavaFacade( // Approximation: all Java methods with name that allows to use it in operator form are considered operators // We need here more detailed checks (see modifierChecks.kt) isOperator = name in ALL_JAVA_OPERATION_NAMES || OperatorNameConventions.COMPONENT_REGEX.matches(name.asString()) + hasStableParameterNames = false } if (!javaMethod.isStatic) { @@ -628,6 +629,7 @@ abstract class FirJavaFacade( visibility.toEffectiveVisibility(ownerClassBuilder.symbol) ).apply { isInner = isThisInner + hasStableParameterNames = false } this.visibility = visibility isPrimary = javaConstructor == null diff --git a/compiler/fir/java/src/org/jetbrains/kotlin/fir/java/enhancement/SignatureEnhancement.kt b/compiler/fir/java/src/org/jetbrains/kotlin/fir/java/enhancement/SignatureEnhancement.kt index 27f544f7931..cd8045c668f 100644 --- a/compiler/fir/java/src/org/jetbrains/kotlin/fir/java/enhancement/SignatureEnhancement.kt +++ b/compiler/fir/java/src/org/jetbrains/kotlin/fir/java/enhancement/SignatureEnhancement.kt @@ -21,10 +21,7 @@ import org.jetbrains.kotlin.fir.declarations.impl.FirDeclarationStatusImpl import org.jetbrains.kotlin.fir.declarations.impl.FirResolvedDeclarationStatusImpl import org.jetbrains.kotlin.fir.declarations.synthetic.FirSyntheticProperty import org.jetbrains.kotlin.fir.declarations.synthetic.buildSyntheticProperty -import org.jetbrains.kotlin.fir.declarations.utils.isInner -import org.jetbrains.kotlin.fir.declarations.utils.isStatic -import org.jetbrains.kotlin.fir.declarations.utils.modality -import org.jetbrains.kotlin.fir.declarations.utils.visibility +import org.jetbrains.kotlin.fir.declarations.utils.* import org.jetbrains.kotlin.fir.expressions.FirAnnotation import org.jetbrains.kotlin.fir.expressions.FirConstExpression import org.jetbrains.kotlin.fir.expressions.unexpandedClassId @@ -262,6 +259,8 @@ class FirSignatureEnhancement( FirDeclarationStatusImpl(firMethod.visibility, Modality.FINAL) }.apply { isInner = firMethod.isInner + // Java annotation class constructors have stable names, copy flag. + hasStableParameterNames = firMethod.hasStableParameterNames } this.symbol = symbol dispatchReceiverType = firMethod.dispatchReceiverType diff --git a/compiler/fir/providers/src/org/jetbrains/kotlin/fir/resolve/providers/impl/FirExtensionSyntheticFunctionInterfaceProvider.kt b/compiler/fir/providers/src/org/jetbrains/kotlin/fir/resolve/providers/impl/FirExtensionSyntheticFunctionInterfaceProvider.kt index 8c6788e3151..43980f75e55 100644 --- a/compiler/fir/providers/src/org/jetbrains/kotlin/fir/resolve/providers/impl/FirExtensionSyntheticFunctionInterfaceProvider.kt +++ b/compiler/fir/providers/src/org/jetbrains/kotlin/fir/resolve/providers/impl/FirExtensionSyntheticFunctionInterfaceProvider.kt @@ -74,13 +74,16 @@ abstract class FirSyntheticFunctionInterfaceProviderBase( } @FirSymbolProviderInternals - override fun getTopLevelCallableSymbolsTo(destination: MutableList>, packageFqName: FqName, name: Name) {} + override fun getTopLevelCallableSymbolsTo(destination: MutableList>, packageFqName: FqName, name: Name) { + } @FirSymbolProviderInternals - override fun getTopLevelFunctionSymbolsTo(destination: MutableList, packageFqName: FqName, name: Name) {} + override fun getTopLevelFunctionSymbolsTo(destination: MutableList, packageFqName: FqName, name: Name) { + } @FirSymbolProviderInternals - override fun getTopLevelPropertySymbolsTo(destination: MutableList, packageFqName: FqName, name: Name) {} + override fun getTopLevelPropertySymbolsTo(destination: MutableList, packageFqName: FqName, name: Name) { + } override fun getPackage(fqName: FqName): FqName? { return fqName.takeIf { session.functionTypeService.hasKindWithSpecificPackage(it) } @@ -162,6 +165,7 @@ abstract class FirSyntheticFunctionInterfaceProviderBase( ).apply { isOperator = true isSuspend = kind.isSuspendOrKSuspendFunction + hasStableParameterNames = false } val typeArguments = typeParameters.map { ConeTypeParameterTypeImpl(it.symbol.toLookupTag(), false).toFirResolvedTypeRef() diff --git a/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/ResolveUtils.kt b/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/ResolveUtils.kt index ed4d886b024..1c1ea82c42e 100644 --- a/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/ResolveUtils.kt +++ b/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/ResolveUtils.kt @@ -14,10 +14,7 @@ import org.jetbrains.kotlin.descriptors.Modality import org.jetbrains.kotlin.fakeElement import org.jetbrains.kotlin.fir.* import org.jetbrains.kotlin.fir.declarations.* -import org.jetbrains.kotlin.fir.declarations.utils.canNarrowDownGetterType -import org.jetbrains.kotlin.fir.declarations.utils.expandedConeType -import org.jetbrains.kotlin.fir.declarations.utils.isFinal -import org.jetbrains.kotlin.fir.declarations.utils.modality +import org.jetbrains.kotlin.fir.declarations.utils.* import org.jetbrains.kotlin.fir.diagnostics.* import org.jetbrains.kotlin.fir.expressions.* import org.jetbrains.kotlin.fir.expressions.builder.* @@ -560,20 +557,14 @@ fun FirFunction.getAsForbiddenNamedArgumentsTarget( // for intersection/substitution overrides originScope: FirTypeScope? = null ): ForbiddenNamedArgumentsTarget? { - if (this is FirConstructor && this.isPrimary) { - this.getContainingClass(session)?.let { containingClass -> - if (containingClass.classKind == ClassKind.ANNOTATION_CLASS) { - // Java annotation classes allow (actually require) named parameters. - return null - } - } - } + if (hasStableParameterNames) return null + return when (origin) { - FirDeclarationOrigin.Source, FirDeclarationOrigin.Precompiled, FirDeclarationOrigin.Library -> null FirDeclarationOrigin.Delegated -> delegatedWrapperData?.wrapped?.getAsForbiddenNamedArgumentsTarget(session) - FirDeclarationOrigin.ImportedFromObjectOrStatic -> importedFromObjectOrStaticData?.original?.getAsForbiddenNamedArgumentsTarget(session) - is FirDeclarationOrigin.Java, FirDeclarationOrigin.Enhancement -> ForbiddenNamedArgumentsTarget.NON_KOTLIN_FUNCTION - FirDeclarationOrigin.SamConstructor -> null + + FirDeclarationOrigin.ImportedFromObjectOrStatic -> + importedFromObjectOrStaticData?.original?.getAsForbiddenNamedArgumentsTarget(session) + FirDeclarationOrigin.IntersectionOverride, FirDeclarationOrigin.SubstitutionOverride -> { var result: ForbiddenNamedArgumentsTarget? = originalIfFakeOverride()?.getAsForbiddenNamedArgumentsTarget(session) ?: return null @@ -587,25 +578,13 @@ fun FirFunction.getAsForbiddenNamedArgumentsTarget( } result } - // referenced function of a Kotlin function type - FirDeclarationOrigin.BuiltIns -> runIf(dispatchReceiverClassLookupTagOrNull()?.isSomeFunctionType(session) == true) { - ForbiddenNamedArgumentsTarget.INVOKE_ON_FUNCTION_TYPE - } - FirDeclarationOrigin.Synthetic, - FirDeclarationOrigin.DynamicScope, - FirDeclarationOrigin.RenamedForOverride, - FirDeclarationOrigin.WrappedIntegerOperator, - FirDeclarationOrigin.ScriptCustomization, + FirDeclarationOrigin.BuiltIns -> ForbiddenNamedArgumentsTarget.INVOKE_ON_FUNCTION_TYPE is FirDeclarationOrigin.Plugin -> null // TODO: figure out what to do with plugin generated functions + else -> ForbiddenNamedArgumentsTarget.NON_KOTLIN_FUNCTION } } -// TODO: handle functions with non-stable parameter names, see also -// org.jetbrains.kotlin.fir.serialization.FirElementSerializer.functionProto -// org.jetbrains.kotlin.fir.serialization.FirElementSerializer.constructorProto -fun FirFunction.getHasStableParameterNames(session: FirSession): Boolean = getAsForbiddenNamedArgumentsTarget(session) == null - @OptIn(ExperimentalContracts::class) fun FirExpression?.isIntegerLiteralOrOperatorCall(): Boolean { contract { diff --git a/compiler/fir/tree/gen/org/jetbrains/kotlin/fir/declarations/FirDeclarationStatus.kt b/compiler/fir/tree/gen/org/jetbrains/kotlin/fir/declarations/FirDeclarationStatus.kt index d626f997d72..8766ff7168f 100644 --- a/compiler/fir/tree/gen/org/jetbrains/kotlin/fir/declarations/FirDeclarationStatus.kt +++ b/compiler/fir/tree/gen/org/jetbrains/kotlin/fir/declarations/FirDeclarationStatus.kt @@ -38,6 +38,7 @@ interface FirDeclarationStatus : FirElement { val isFromSealedClass: Boolean val isFromEnumClass: Boolean val isFun: Boolean + val hasStableParameterNames: Boolean override fun accept(visitor: FirVisitor, data: D): R = visitor.visitDeclarationStatus(this, data) diff --git a/compiler/fir/tree/gen/org/jetbrains/kotlin/fir/declarations/FirResolvedDeclarationStatus.kt b/compiler/fir/tree/gen/org/jetbrains/kotlin/fir/declarations/FirResolvedDeclarationStatus.kt index ac246bf91ae..0c1698f25e6 100644 --- a/compiler/fir/tree/gen/org/jetbrains/kotlin/fir/declarations/FirResolvedDeclarationStatus.kt +++ b/compiler/fir/tree/gen/org/jetbrains/kotlin/fir/declarations/FirResolvedDeclarationStatus.kt @@ -39,6 +39,7 @@ interface FirResolvedDeclarationStatus : FirDeclarationStatus { override val isFromSealedClass: Boolean override val isFromEnumClass: Boolean override val isFun: Boolean + override val hasStableParameterNames: Boolean val effectiveVisibility: EffectiveVisibility override fun accept(visitor: FirVisitor, data: D): R = visitor.visitResolvedDeclarationStatus(this, data) diff --git a/compiler/fir/tree/src/org/jetbrains/kotlin/fir/Utils.kt b/compiler/fir/tree/src/org/jetbrains/kotlin/fir/Utils.kt index f52bfe2c21e..8cdc0be5a84 100644 --- a/compiler/fir/tree/src/org/jetbrains/kotlin/fir/Utils.kt +++ b/compiler/fir/tree/src/org/jetbrains/kotlin/fir/Utils.kt @@ -110,6 +110,7 @@ fun FirDeclarationStatus.copy( isFromSealedClass: Boolean = this.isFromSealedClass, isFromEnumClass: Boolean = this.isFromEnumClass, isFun: Boolean = this.isFun, + hasStableParameterNames: Boolean = this.hasStableParameterNames, ): FirDeclarationStatus { val newVisibility = visibility ?: this.visibility val newModality = modality ?: this.modality @@ -137,6 +138,7 @@ fun FirDeclarationStatus.copy( this.isFromSealedClass = isFromSealedClass this.isFromEnumClass = isFromEnumClass this.isFun = isFun + this.hasStableParameterNames = hasStableParameterNames } } diff --git a/compiler/fir/tree/src/org/jetbrains/kotlin/fir/declarations/impl/FirDeclarationStatusImpl.kt b/compiler/fir/tree/src/org/jetbrains/kotlin/fir/declarations/impl/FirDeclarationStatusImpl.kt index 557ab3a332f..242c32217a3 100644 --- a/compiler/fir/tree/src/org/jetbrains/kotlin/fir/declarations/impl/FirDeclarationStatusImpl.kt +++ b/compiler/fir/tree/src/org/jetbrains/kotlin/fir/declarations/impl/FirDeclarationStatusImpl.kt @@ -20,7 +20,7 @@ open class FirDeclarationStatusImpl( override val modality: Modality? ) : FirPureAbstractElement(), FirDeclarationStatus { override val source: KtSourceElement? get() = null - protected var flags: Int = 0 + protected var flags: Int = HAS_STABLE_PARAMETER_NAMES.mask operator fun get(modifier: Modifier): Boolean = (flags and modifier.mask) != 0 @@ -140,6 +140,12 @@ open class FirDeclarationStatusImpl( this[FUN] = value } + override var hasStableParameterNames: Boolean + get() = this[HAS_STABLE_PARAMETER_NAMES] + set(value) { + this[HAS_STABLE_PARAMETER_NAMES] = value + } + enum class Modifier(val mask: Int) { EXPECT(0x1), ACTUAL(0x2), @@ -158,7 +164,8 @@ open class FirDeclarationStatusImpl( STATIC(0x4000), FROM_SEALED(0x8000), FROM_ENUM(0x10000), - FUN(0x20000) + FUN(0x20000), + HAS_STABLE_PARAMETER_NAMES(0x40000), } override fun acceptChildren(visitor: FirVisitor, data: D) {} diff --git a/compiler/fir/tree/src/org/jetbrains/kotlin/fir/declarations/utils/FirStatusUtils.kt b/compiler/fir/tree/src/org/jetbrains/kotlin/fir/declarations/utils/FirStatusUtils.kt index 55b1d256426..f6e72ae3453 100644 --- a/compiler/fir/tree/src/org/jetbrains/kotlin/fir/declarations/utils/FirStatusUtils.kt +++ b/compiler/fir/tree/src/org/jetbrains/kotlin/fir/declarations/utils/FirStatusUtils.kt @@ -46,6 +46,7 @@ inline val FirMemberDeclaration.isLateInit: Boolean get() = status.isLateInit inline val FirMemberDeclaration.isFromSealedClass: Boolean get() = status.isFromSealedClass inline val FirMemberDeclaration.isFromEnumClass: Boolean get() = status.isFromEnumClass inline val FirMemberDeclaration.isFun: Boolean get() = status.isFun +inline val FirMemberDeclaration.hasStableParameterNames: Boolean get() = status.hasStableParameterNames inline val FirClassLikeDeclaration.isLocal: Boolean get() = symbol.classId.isLocal diff --git a/compiler/fir/tree/tree-generator/src/org/jetbrains/kotlin/fir/tree/generator/NodeConfigurator.kt b/compiler/fir/tree/tree-generator/src/org/jetbrains/kotlin/fir/tree/generator/NodeConfigurator.kt index 0ef60cf998f..6acdc4caa2e 100644 --- a/compiler/fir/tree/tree-generator/src/org/jetbrains/kotlin/fir/tree/generator/NodeConfigurator.kt +++ b/compiler/fir/tree/tree-generator/src/org/jetbrains/kotlin/fir/tree/generator/NodeConfigurator.kt @@ -382,7 +382,7 @@ object NodeConfigurator : AbstractFieldConfigurator(FirTreeBuild generateBooleanFields( "expect", "actual", "override", "operator", "infix", "inline", "tailRec", "external", "const", "lateInit", "inner", "companion", "data", "suspend", "static", - "fromSealedClass", "fromEnumClass", "fun" + "fromSealedClass", "fromEnumClass", "fun", "hasStableParameterNames", ) } diff --git a/compiler/fir/tree/tree-generator/src/org/jetbrains/kotlin/fir/tree/generator/context/AbstractFieldConfigurator.kt b/compiler/fir/tree/tree-generator/src/org/jetbrains/kotlin/fir/tree/generator/context/AbstractFieldConfigurator.kt index 8021b117468..2b5aa4d101b 100644 --- a/compiler/fir/tree/tree-generator/src/org/jetbrains/kotlin/fir/tree/generator/context/AbstractFieldConfigurator.kt +++ b/compiler/fir/tree/tree-generator/src/org/jetbrains/kotlin/fir/tree/generator/context/AbstractFieldConfigurator.kt @@ -22,7 +22,7 @@ abstract class AbstractFieldConfigurator(private val fun generateBooleanFields(vararg names: String) { names.forEach { - +booleanField("is${it.replaceFirstChar(Char::uppercaseChar)}") + +booleanField(if (it.startsWith("is") || it.startsWith("has")) it else "is${it.replaceFirstChar(Char::uppercaseChar)}") } } diff --git a/compiler/testData/compileKotlinAgainstCustomBinaries/hasStableParameterNames/library/JavaInterface.java b/compiler/testData/compileKotlinAgainstCustomBinaries/hasStableParameterNames/library/JavaInterface.java new file mode 100644 index 00000000000..b44a2ee65d3 --- /dev/null +++ b/compiler/testData/compileKotlinAgainstCustomBinaries/hasStableParameterNames/library/JavaInterface.java @@ -0,0 +1,3 @@ +public interface JavaInterface { + public void foo(int javaName); +} diff --git a/compiler/testData/compileKotlinAgainstCustomBinaries/hasStableParameterNames/library/JavaSuperClass.java b/compiler/testData/compileKotlinAgainstCustomBinaries/hasStableParameterNames/library/JavaSuperClass.java new file mode 100644 index 00000000000..2cdda286ec9 --- /dev/null +++ b/compiler/testData/compileKotlinAgainstCustomBinaries/hasStableParameterNames/library/JavaSuperClass.java @@ -0,0 +1,4 @@ +public class JavaSuperClass implements JavaInterface { + @Override + public void foo(int javaName) {} +} diff --git a/compiler/testData/compileKotlinAgainstCustomBinaries/hasStableParameterNames/library/KtClass.kt b/compiler/testData/compileKotlinAgainstCustomBinaries/hasStableParameterNames/library/KtClass.kt new file mode 100644 index 00000000000..cfe2800e024 --- /dev/null +++ b/compiler/testData/compileKotlinAgainstCustomBinaries/hasStableParameterNames/library/KtClass.kt @@ -0,0 +1 @@ +class KtClass : JavaInterface by JavaSuperClass() diff --git a/compiler/testData/compileKotlinAgainstCustomBinaries/hasStableParameterNames/output.txt b/compiler/testData/compileKotlinAgainstCustomBinaries/hasStableParameterNames/output.txt new file mode 100644 index 00000000000..d86bac9de59 --- /dev/null +++ b/compiler/testData/compileKotlinAgainstCustomBinaries/hasStableParameterNames/output.txt @@ -0,0 +1 @@ +OK diff --git a/compiler/testData/compileKotlinAgainstCustomBinaries/hasStableParameterNames/source.kt b/compiler/testData/compileKotlinAgainstCustomBinaries/hasStableParameterNames/source.kt new file mode 100644 index 00000000000..6a3c6ee043f --- /dev/null +++ b/compiler/testData/compileKotlinAgainstCustomBinaries/hasStableParameterNames/source.kt @@ -0,0 +1,6 @@ +fun test() { + val ktInstance = KtClass() + // Shouldn't work but is kept for backward compatibility with K1 + // When KT-4758 is fixed, this should break. + ktInstance.foo(javaName = 1) +} diff --git a/compiler/testData/diagnostics/tests/namedArguments/disallowForDelegationToJavaMethods.kt b/compiler/testData/diagnostics/tests/namedArguments/disallowForDelegationToJavaMethods.kt new file mode 100644 index 00000000000..e54670aa101 --- /dev/null +++ b/compiler/testData/diagnostics/tests/namedArguments/disallowForDelegationToJavaMethods.kt @@ -0,0 +1,24 @@ +// FIR_IDENTICAL +// SKIP_TXT + +// FILE: JavaInterface.java + +public interface JavaInterface { + public void foo(int javaName); +} + +// FILE: JavaClass.java + +public class JavaSuperClass implements JavaInterface { + @Override + public void foo(int javaName) {} +} + +// FILE: 1.kt + +class KtClass: JavaInterface by JavaSuperClass() + +fun test() { + val ktInstance = KtClass() + ktInstance.foo(javaName = 1) +} diff --git a/compiler/testData/diagnostics/tests/namedArguments/disallowForFunctionTypes.kt b/compiler/testData/diagnostics/tests/namedArguments/disallowForFunctionTypes.kt new file mode 100644 index 00000000000..3a193b8d0ba --- /dev/null +++ b/compiler/testData/diagnostics/tests/namedArguments/disallowForFunctionTypes.kt @@ -0,0 +1,6 @@ +// FIR_IDENTICAL +// SKIP_TXT + +fun test(f: (String) -> Unit) { + f(p1 = "") +} diff --git a/compiler/tests-common-new/tests-gen/org/jetbrains/kotlin/test/runners/DiagnosticTestGenerated.java b/compiler/tests-common-new/tests-gen/org/jetbrains/kotlin/test/runners/DiagnosticTestGenerated.java index 8555dbca32e..01c43569fa4 100644 --- a/compiler/tests-common-new/tests-gen/org/jetbrains/kotlin/test/runners/DiagnosticTestGenerated.java +++ b/compiler/tests-common-new/tests-gen/org/jetbrains/kotlin/test/runners/DiagnosticTestGenerated.java @@ -22100,6 +22100,18 @@ public class DiagnosticTestGenerated extends AbstractDiagnosticTest { runTest("compiler/testData/diagnostics/tests/namedArguments/ambiguousNamedArgumentsWithGenerics3.kt"); } + @Test + @TestMetadata("disallowForDelegationToJavaMethods.kt") + public void testDisallowForDelegationToJavaMethods() throws Exception { + runTest("compiler/testData/diagnostics/tests/namedArguments/disallowForDelegationToJavaMethods.kt"); + } + + @Test + @TestMetadata("disallowForFunctionTypes.kt") + public void testDisallowForFunctionTypes() throws Exception { + runTest("compiler/testData/diagnostics/tests/namedArguments/disallowForFunctionTypes.kt"); + } + @Test @TestMetadata("disallowForJavaConstructor.kt") public void testDisallowForJavaConstructor() throws Exception { diff --git a/compiler/tests/org/jetbrains/kotlin/jvm/compiler/CompileKotlinAgainstCustomBinariesTest.kt b/compiler/tests/org/jetbrains/kotlin/jvm/compiler/CompileKotlinAgainstCustomBinariesTest.kt index 9b7c98e5f68..597d4f8999f 100644 --- a/compiler/tests/org/jetbrains/kotlin/jvm/compiler/CompileKotlinAgainstCustomBinariesTest.kt +++ b/compiler/tests/org/jetbrains/kotlin/jvm/compiler/CompileKotlinAgainstCustomBinariesTest.kt @@ -371,6 +371,11 @@ class CompileKotlinAgainstCustomBinariesTest : AbstractKotlinCompilerIntegration compileKotlin("source.kt", tmpdir, listOf(compileLibrary("library"))) } + fun testHasStableParameterNames() { + val library = compileLibrary("library", additionalOptions = listOf("-language-version", "2.0")) + compileKotlin("source.kt", tmpdir, listOf(library), additionalOptions = listOf("-language-version", "2.0")) + } + fun testRequireKotlinInNestedClasses() { compileKotlin("source.kt", tmpdir, listOf(compileLibrary("library"))) }