diff --git a/compiler/fir/analysis-tests/tests-gen/org/jetbrains/kotlin/test/runners/FirOldFrontendMPPDiagnosticsWithLightTreeTestGenerated.java b/compiler/fir/analysis-tests/tests-gen/org/jetbrains/kotlin/test/runners/FirOldFrontendMPPDiagnosticsWithLightTreeTestGenerated.java index 3aed9d77a4b..c8c5a916cd5 100644 --- a/compiler/fir/analysis-tests/tests-gen/org/jetbrains/kotlin/test/runners/FirOldFrontendMPPDiagnosticsWithLightTreeTestGenerated.java +++ b/compiler/fir/analysis-tests/tests-gen/org/jetbrains/kotlin/test/runners/FirOldFrontendMPPDiagnosticsWithLightTreeTestGenerated.java @@ -982,6 +982,12 @@ public class FirOldFrontendMPPDiagnosticsWithLightTreeTestGenerated extends Abst runTest("compiler/testData/diagnostics/tests/multiplatform/defaultArguments/annotationsViaActualTypeAlias2.kt"); } + @Test + @TestMetadata("companionMethodViaActualTypealias.kt") + public void testCompanionMethodViaActualTypealias() throws Exception { + runTest("compiler/testData/diagnostics/tests/multiplatform/defaultArguments/companionMethodViaActualTypealias.kt"); + } + @Test @TestMetadata("constructor.kt") public void testConstructor() throws Exception { @@ -1029,6 +1035,12 @@ public class FirOldFrontendMPPDiagnosticsWithLightTreeTestGenerated extends Abst public void testMethodDefaultArgsViaActualTypealias_oldLanguageVersion() throws Exception { runTest("compiler/testData/diagnostics/tests/multiplatform/defaultArguments/methodDefaultArgsViaActualTypealias_oldLanguageVersion.kt"); } + + @Test + @TestMetadata("nestedClassMethodsViaActualTypealias.kt") + public void testNestedClassMethodsViaActualTypealias() throws Exception { + runTest("compiler/testData/diagnostics/tests/multiplatform/defaultArguments/nestedClassMethodsViaActualTypealias.kt"); + } } @Nested diff --git a/compiler/fir/analysis-tests/tests-gen/org/jetbrains/kotlin/test/runners/FirOldFrontendMPPDiagnosticsWithPsiTestGenerated.java b/compiler/fir/analysis-tests/tests-gen/org/jetbrains/kotlin/test/runners/FirOldFrontendMPPDiagnosticsWithPsiTestGenerated.java index d619887dc63..eda7d5248c1 100644 --- a/compiler/fir/analysis-tests/tests-gen/org/jetbrains/kotlin/test/runners/FirOldFrontendMPPDiagnosticsWithPsiTestGenerated.java +++ b/compiler/fir/analysis-tests/tests-gen/org/jetbrains/kotlin/test/runners/FirOldFrontendMPPDiagnosticsWithPsiTestGenerated.java @@ -982,6 +982,12 @@ public class FirOldFrontendMPPDiagnosticsWithPsiTestGenerated extends AbstractFi runTest("compiler/testData/diagnostics/tests/multiplatform/defaultArguments/annotationsViaActualTypeAlias2.kt"); } + @Test + @TestMetadata("companionMethodViaActualTypealias.kt") + public void testCompanionMethodViaActualTypealias() throws Exception { + runTest("compiler/testData/diagnostics/tests/multiplatform/defaultArguments/companionMethodViaActualTypealias.kt"); + } + @Test @TestMetadata("constructor.kt") public void testConstructor() throws Exception { @@ -1029,6 +1035,12 @@ public class FirOldFrontendMPPDiagnosticsWithPsiTestGenerated extends AbstractFi public void testMethodDefaultArgsViaActualTypealias_oldLanguageVersion() throws Exception { runTest("compiler/testData/diagnostics/tests/multiplatform/defaultArguments/methodDefaultArgsViaActualTypealias_oldLanguageVersion.kt"); } + + @Test + @TestMetadata("nestedClassMethodsViaActualTypealias.kt") + public void testNestedClassMethodsViaActualTypealias() throws Exception { + runTest("compiler/testData/diagnostics/tests/multiplatform/defaultArguments/nestedClassMethodsViaActualTypealias.kt"); + } } @Nested diff --git a/compiler/fir/checkers/src/org/jetbrains/kotlin/fir/analysis/checkers/declaration/FirExpectActualDeclarationChecker.kt b/compiler/fir/checkers/src/org/jetbrains/kotlin/fir/analysis/checkers/declaration/FirExpectActualDeclarationChecker.kt index f262e65352b..b4b943831ef 100644 --- a/compiler/fir/checkers/src/org/jetbrains/kotlin/fir/analysis/checkers/declaration/FirExpectActualDeclarationChecker.kt +++ b/compiler/fir/checkers/src/org/jetbrains/kotlin/fir/analysis/checkers/declaration/FirExpectActualDeclarationChecker.kt @@ -25,6 +25,7 @@ import org.jetbrains.kotlin.fir.expressions.FirAnnotation import org.jetbrains.kotlin.fir.languageVersionSettings import org.jetbrains.kotlin.fir.scopes.collectAllFunctions import org.jetbrains.kotlin.fir.scopes.getDeclaredConstructors +import org.jetbrains.kotlin.fir.scopes.getSingleClassifier import org.jetbrains.kotlin.fir.scopes.impl.declaredMemberScope import org.jetbrains.kotlin.fir.symbols.FirBasedSymbol import org.jetbrains.kotlin.fir.symbols.SymbolInternals @@ -236,16 +237,9 @@ object FirExpectActualDeclarationChecker : FirBasicDeclarationChecker() { reporter: DiagnosticReporter, ) { if (!context.languageVersionSettings.supportsFeature(LanguageFeature.MultiplatformRestrictions)) return - if (expectSymbol !is FirClassSymbol || - actualSymbol !is FirTypeAliasSymbol || - expectSymbol.classKind == ClassKind.ANNOTATION_CLASS - ) return - - val membersWithDefaultValueParameters = - expectSymbol.declaredMemberScope(expectSymbol.moduleData.session, memberRequiredPhase = null) - .run { collectAllFunctions() + getDeclaredConstructors() } - .filter { it.valueParameterSymbols.any(FirValueParameterSymbol::hasDefaultValue) } + if (expectSymbol !is FirClassSymbol || actualSymbol !is FirTypeAliasSymbol) return + val membersWithDefaultValueParameters = getMembersWithDefaultValueParametersUnlessAnnotation(expectSymbol) if (membersWithDefaultValueParameters.isEmpty()) return reporter.reportOn( @@ -257,6 +251,31 @@ object FirExpectActualDeclarationChecker : FirBasicDeclarationChecker() { ) } + private fun getMembersWithDefaultValueParametersUnlessAnnotation(classSymbol: FirClassSymbol<*>): List> { + val result = mutableListOf>() + + fun collectFunctions(classSymbol: FirClassSymbol<*>) { + if (classSymbol.classKind == ClassKind.ANNOTATION_CLASS) { + return + } + val memberScope = classSymbol.declaredMemberScope(classSymbol.moduleData.session, memberRequiredPhase = null) + val functionsAndConstructors = memberScope + .run { collectAllFunctions() + getDeclaredConstructors() } + + functionsAndConstructors.filterTo(result) { it.valueParameterSymbols.any(FirValueParameterSymbol::hasDefaultValue) } + + val nestedClasses = memberScope.getClassifierNames() + .mapNotNull { memberScope.getSingleClassifier(it) as? FirClassSymbol<*> } + + for (nestedClassSymbol in nestedClasses) { + collectFunctions(nestedClassSymbol) + } + } + + collectFunctions(classSymbol) + return result + } + private fun checkAnnotationsMatch( expectSymbol: FirBasedSymbol<*>, actualSymbol: FirBasedSymbol<*>, diff --git a/compiler/frontend/src/org/jetbrains/kotlin/resolve/checkers/ExpectedActualDeclarationChecker.kt b/compiler/frontend/src/org/jetbrains/kotlin/resolve/checkers/ExpectedActualDeclarationChecker.kt index 67094adc650..6d28f6a6476 100644 --- a/compiler/frontend/src/org/jetbrains/kotlin/resolve/checkers/ExpectedActualDeclarationChecker.kt +++ b/compiler/frontend/src/org/jetbrains/kotlin/resolve/checkers/ExpectedActualDeclarationChecker.kt @@ -244,18 +244,9 @@ class ExpectedActualDeclarationChecker( context: DeclarationCheckerContext, ) { if (!context.languageVersionSettings.supportsFeature(LanguageFeature.MultiplatformRestrictions)) return - if (expectDescriptor !is ClassDescriptor || - actualDeclaration !is KtTypeAlias || - expectDescriptor.kind == ClassKind.ANNOTATION_CLASS - ) return - - val members = expectDescriptor.constructors + expectDescriptor.unsubstitutedMemberScope - .getContributedDescriptors(DescriptorKindFilter.FUNCTIONS) - .filterIsInstance() - - val membersWithDefaultValueParameters = members - .filter { it.valueParameters.any { p -> p.declaresDefaultValue() }} + if (expectDescriptor !is ClassDescriptor || actualDeclaration !is KtTypeAlias) return + val membersWithDefaultValueParameters = getMembersWithDefaultValueParametersUnlessAnnotation(expectDescriptor) if (membersWithDefaultValueParameters.isEmpty()) return context.trace.report( @@ -267,6 +258,32 @@ class ExpectedActualDeclarationChecker( ) } + private fun getMembersWithDefaultValueParametersUnlessAnnotation(classDescriptor: ClassDescriptor): List { + val result = mutableListOf() + + fun collectFunctions(classDescriptor: ClassDescriptor) { + if (classDescriptor.kind == ClassKind.ANNOTATION_CLASS) { + return + } + val functionsAndConstructors = classDescriptor.constructors + classDescriptor.unsubstitutedMemberScope + .getContributedDescriptors(DescriptorKindFilter.FUNCTIONS) + .filterIsInstance() + + functionsAndConstructors.filterTo(result) { it.valueParameters.any { p -> p.declaresDefaultValue() } } + + val nestedClasses = classDescriptor.unsubstitutedMemberScope + .getContributedDescriptors(DescriptorKindFilter.CLASSIFIERS) + .filterIsInstance() + + for (nestedClass in nestedClasses) { + collectFunctions(nestedClass) + } + } + + collectFunctions(classDescriptor) + return result + } + private fun MemberDescriptor.hasNoActualWithDiagnostic( compatibility: Map, List> ): Boolean { diff --git a/compiler/testData/diagnostics/tests/multiplatform/defaultArguments/companionMethodViaActualTypealias.kt b/compiler/testData/diagnostics/tests/multiplatform/defaultArguments/companionMethodViaActualTypealias.kt new file mode 100644 index 00000000000..df933929a92 --- /dev/null +++ b/compiler/testData/diagnostics/tests/multiplatform/defaultArguments/companionMethodViaActualTypealias.kt @@ -0,0 +1,18 @@ +// FIR_IDENTICAL +// MODULE: m1-common +// FILE: common.kt +expect class DefaultArgsInCompanion { + companion object { + fun foo(p: String = "") + } +} + +// MODULE: m2-jvm()()(m1-common) +// FILE: jvm.kt +class DefaultArgsInCompanionImpl { + companion object { + fun foo(p: String) {} + } +} + +actual typealias DefaultArgsInCompanion = DefaultArgsInCompanionImpl diff --git a/compiler/testData/diagnostics/tests/multiplatform/defaultArguments/nestedClassMethodsViaActualTypealias.kt b/compiler/testData/diagnostics/tests/multiplatform/defaultArguments/nestedClassMethodsViaActualTypealias.kt new file mode 100644 index 00000000000..955ad91480a --- /dev/null +++ b/compiler/testData/diagnostics/tests/multiplatform/defaultArguments/nestedClassMethodsViaActualTypealias.kt @@ -0,0 +1,18 @@ +// FIR_IDENTICAL +// MODULE: m1-common +// FILE: common.kt +expect class DefaultArgsInNestedClass { + class Nested { + fun foo(p: String = "") + } +} + +// MODULE: m2-jvm()()(m1-common) +// FILE: jvm.kt +class DefaultArgsInNestedClassImpl { + class Nested { + fun foo(p: String) {} + } +} + +actual typealias DefaultArgsInNestedClass = DefaultArgsInNestedClassImpl 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 cb665fc356d..cc91cb7aa90 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 @@ -23977,6 +23977,12 @@ public class DiagnosticTestGenerated extends AbstractDiagnosticTest { runTest("compiler/testData/diagnostics/tests/multiplatform/defaultArguments/annotationsViaActualTypeAlias2.kt"); } + @Test + @TestMetadata("companionMethodViaActualTypealias.kt") + public void testCompanionMethodViaActualTypealias() throws Exception { + runTest("compiler/testData/diagnostics/tests/multiplatform/defaultArguments/companionMethodViaActualTypealias.kt"); + } + @Test @TestMetadata("constructor.kt") public void testConstructor() throws Exception { @@ -24024,6 +24030,12 @@ public class DiagnosticTestGenerated extends AbstractDiagnosticTest { public void testMethodDefaultArgsViaActualTypealias_oldLanguageVersion() throws Exception { runTest("compiler/testData/diagnostics/tests/multiplatform/defaultArguments/methodDefaultArgsViaActualTypealias_oldLanguageVersion.kt"); } + + @Test + @TestMetadata("nestedClassMethodsViaActualTypealias.kt") + public void testNestedClassMethodsViaActualTypealias() throws Exception { + runTest("compiler/testData/diagnostics/tests/multiplatform/defaultArguments/nestedClassMethodsViaActualTypealias.kt"); + } } @Nested