diff --git a/compiler/fir/checkers/src/org/jetbrains/kotlin/fir/analysis/checkers/CommonDeclarationCheckers.kt b/compiler/fir/checkers/src/org/jetbrains/kotlin/fir/analysis/checkers/CommonDeclarationCheckers.kt index d8e766f9e04..ad1e9cdc814 100644 --- a/compiler/fir/checkers/src/org/jetbrains/kotlin/fir/analysis/checkers/CommonDeclarationCheckers.kt +++ b/compiler/fir/checkers/src/org/jetbrains/kotlin/fir/analysis/checkers/CommonDeclarationCheckers.kt @@ -174,6 +174,7 @@ object CommonDeclarationCheckers : DeclarationCheckers() { FirTopLevelTypeAliasChecker, FirActualTypeAliasChecker, FirActualTypealiasToSpecialAnnotationChecker, + FirDefaultArgumentsInExpectWithActualTypealiasChecker, FirTypeAliasExpandsToArrayOfNothingsChecker, ) diff --git a/compiler/fir/checkers/src/org/jetbrains/kotlin/fir/analysis/checkers/declaration/FirDefaultArgumentsInExpectWithActualTypealiasChecker.kt b/compiler/fir/checkers/src/org/jetbrains/kotlin/fir/analysis/checkers/declaration/FirDefaultArgumentsInExpectWithActualTypealiasChecker.kt new file mode 100644 index 00000000000..23024b1fc90 --- /dev/null +++ b/compiler/fir/checkers/src/org/jetbrains/kotlin/fir/analysis/checkers/declaration/FirDefaultArgumentsInExpectWithActualTypealiasChecker.kt @@ -0,0 +1,77 @@ +/* + * Copyright 2010-2023 JetBrains s.r.o. and Kotlin Programming Language contributors. + * 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.fir.analysis.checkers.declaration + +import org.jetbrains.kotlin.config.LanguageFeature +import org.jetbrains.kotlin.descriptors.ClassKind +import org.jetbrains.kotlin.diagnostics.DiagnosticReporter +import org.jetbrains.kotlin.diagnostics.reportOn +import org.jetbrains.kotlin.fir.analysis.checkers.context.CheckerContext +import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors +import org.jetbrains.kotlin.fir.declarations.FirTypeAlias +import org.jetbrains.kotlin.fir.declarations.getSingleCompatibleExpectForActualOrNull +import org.jetbrains.kotlin.fir.declarations.getSingleExpectForActualOrNull +import org.jetbrains.kotlin.fir.declarations.utils.isActual +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.impl.* + +internal object FirDefaultArgumentsInExpectWithActualTypealiasChecker : FirTypeAliasChecker() { + override fun check(declaration: FirTypeAlias, context: CheckerContext, reporter: DiagnosticReporter) { + if (!context.languageVersionSettings.supportsFeature(LanguageFeature.MultiPlatformProjects) || + !context.languageVersionSettings.supportsFeature(LanguageFeature.MultiplatformRestrictions) + ) { + return + } + if (!declaration.isActual) { + return + } + val actualTypealiasSymbol = declaration.symbol + // We want to report errors even if a candidate is incompatible, but it's single + val expectedSingleCandidate = actualTypealiasSymbol.getSingleCompatibleExpectForActualOrNull() + ?: actualTypealiasSymbol.getSingleExpectForActualOrNull() + ?: return + val expectClassSymbol = expectedSingleCandidate as FirRegularClassSymbol + + val membersWithDefaultValueParameters = getMembersWithDefaultValueParametersUnlessAnnotation(expectClassSymbol) + if (membersWithDefaultValueParameters.isEmpty()) return + + reporter.reportOn( + declaration.source, + FirErrors.DEFAULT_ARGUMENTS_IN_EXPECT_WITH_ACTUAL_TYPEALIAS, + expectClassSymbol, + membersWithDefaultValueParameters, + context + ) + } + + 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 + } +} \ No newline at end of file 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 560c054d536..cf6436e4655 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 @@ -22,13 +22,10 @@ import org.jetbrains.kotlin.fir.declarations.utils.isTailRec import org.jetbrains.kotlin.fir.expectActualMatchingContextFactory 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 -import org.jetbrains.kotlin.fir.symbols.impl.* +import org.jetbrains.kotlin.fir.symbols.impl.FirRegularClassSymbol +import org.jetbrains.kotlin.fir.symbols.impl.FirTypeAliasSymbol import org.jetbrains.kotlin.lexer.KtTokens import org.jetbrains.kotlin.name.StandardClassIds import org.jetbrains.kotlin.resolve.calls.mpp.AbstractExpectActualAnnotationMatchChecker @@ -191,12 +188,6 @@ object FirExpectActualDeclarationChecker : FirBasicDeclarationChecker() { val expectedSingleCandidate = symbol.getSingleCompatibleExpectForActualOrNull() ?: symbol.getSingleExpectForActualOrNull() if (expectedSingleCandidate != null) { - checkIfExpectHasDefaultArgumentsAndActualizedWithTypealias( - expectedSingleCandidate, - symbol, - context, - reporter, - ) checkOptInAnnotation(declaration, expectedSingleCandidate, context, reporter) checkAnnotationsMatch(expectedSingleCandidate, symbol, context, reporter) } @@ -230,52 +221,6 @@ object FirExpectActualDeclarationChecker : FirBasicDeclarationChecker() { } } - private fun checkIfExpectHasDefaultArgumentsAndActualizedWithTypealias( - expectSymbol: FirBasedSymbol<*>, - actualSymbol: FirBasedSymbol<*>, - context: CheckerContext, - reporter: DiagnosticReporter, - ) { - if (!context.languageVersionSettings.supportsFeature(LanguageFeature.MultiplatformRestrictions)) return - if (expectSymbol !is FirClassSymbol || actualSymbol !is FirTypeAliasSymbol) return - - val membersWithDefaultValueParameters = getMembersWithDefaultValueParametersUnlessAnnotation(expectSymbol) - if (membersWithDefaultValueParameters.isEmpty()) return - - reporter.reportOn( - actualSymbol.source, - FirErrors.DEFAULT_ARGUMENTS_IN_EXPECT_WITH_ACTUAL_TYPEALIAS, - expectSymbol, - membersWithDefaultValueParameters, - context - ) - } - - 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 - } - @OptIn(InternalDiagnosticFactoryMethod::class) private fun checkAnnotationsMatch( expectSymbol: FirBasedSymbol<*>,