diff --git a/compiler/fir/analysis-tests/testData/resolve/extendedCheckers/RedundantModalityModifierChecker.fir.txt b/compiler/fir/analysis-tests/testData/resolve/extendedCheckers/RedundantModalityModifierChecker.fir.txt index 81abe698f01..e21c1110b95 100644 --- a/compiler/fir/analysis-tests/testData/resolve/extendedCheckers/RedundantModalityModifierChecker.fir.txt +++ b/compiler/fir/analysis-tests/testData/resolve/extendedCheckers/RedundantModalityModifierChecker.fir.txt @@ -38,10 +38,6 @@ FILE: RedundantModalityModifierChecker.kt public abstract interface Foo : R|kotlin/Any| { } public abstract expect class AbstractClass : R|Foo| { - public expect constructor(): R|AbstractClass| { - super() - } - public abstract expect override fun foo(): R|kotlin/Unit| public abstract expect fun bar(): R|kotlin/Unit| diff --git a/compiler/fir/analysis-tests/testData/resolve/multifile/simpleStarImport.fir.txt b/compiler/fir/analysis-tests/testData/resolve/multifile/simpleStarImport.fir.txt index 0da7210adf1..e8407a7c501 100644 --- a/compiler/fir/analysis-tests/testData/resolve/multifile/simpleStarImport.fir.txt +++ b/compiler/fir/analysis-tests/testData/resolve/multifile/simpleStarImport.fir.txt @@ -2,10 +2,6 @@ FILE: B.kt public abstract expect interface Other : R|kotlin/Any| { } public final expect class Another : R|kotlin/Any| { - public expect constructor(): R|b/d/Another| { - super() - } - } public final fun baz(): R|kotlin/Unit| { } diff --git a/compiler/fir/analysis-tests/testData/resolveWithStdlib/multiModule/MemberType.fir.txt b/compiler/fir/analysis-tests/testData/resolveWithStdlib/multiModule/MemberType.fir.txt index 4c3ffb3d1ef..c3aead86d34 100644 --- a/compiler/fir/analysis-tests/testData/resolveWithStdlib/multiModule/MemberType.fir.txt +++ b/compiler/fir/analysis-tests/testData/resolveWithStdlib/multiModule/MemberType.fir.txt @@ -1,10 +1,6 @@ Module: m1-common FILE: common.kt public final expect class MyList : R|kotlin/Any| { - public expect constructor(): R|MyList| { - super() - } - public final expect fun get(i: R|kotlin/Int|): R|kotlin/Int| } diff --git a/compiler/fir/checkers/checkers-component-generator/build.gradle.kts b/compiler/fir/checkers/checkers-component-generator/build.gradle.kts index 776e72b47a6..8cfa7e69d96 100644 --- a/compiler/fir/checkers/checkers-component-generator/build.gradle.kts +++ b/compiler/fir/checkers/checkers-component-generator/build.gradle.kts @@ -7,6 +7,7 @@ plugins { dependencies { implementation(project(":compiler:fir:tree")) implementation(project(":compiler:fir:tree:tree-generator")) + implementation(project(":compiler:resolution.common")) implementation(project(":kotlin-reflect")) implementation(project(":kotlin-reflect-api")) diff --git a/compiler/fir/checkers/checkers-component-generator/src/org/jetbrains/kotlin/fir/checkers/generator/diagnostics/FirDiagnosticsList.kt b/compiler/fir/checkers/checkers-component-generator/src/org/jetbrains/kotlin/fir/checkers/generator/diagnostics/FirDiagnosticsList.kt index de96d0b26c2..b8715598d21 100644 --- a/compiler/fir/checkers/checkers-component-generator/src/org/jetbrains/kotlin/fir/checkers/generator/diagnostics/FirDiagnosticsList.kt +++ b/compiler/fir/checkers/checkers-component-generator/src/org/jetbrains/kotlin/fir/checkers/generator/diagnostics/FirDiagnosticsList.kt @@ -13,6 +13,7 @@ import org.jetbrains.kotlin.contracts.description.EventOccurrencesRange import org.jetbrains.kotlin.descriptors.EffectiveVisibility import org.jetbrains.kotlin.descriptors.Visibility import org.jetbrains.kotlin.diagnostics.WhenMissingCase +import org.jetbrains.kotlin.fir.FirModuleData import org.jetbrains.kotlin.fir.PrivateForInline import org.jetbrains.kotlin.fir.checkers.generator.diagnostics.model.* import org.jetbrains.kotlin.fir.declarations.* @@ -26,6 +27,7 @@ import org.jetbrains.kotlin.name.FqName import org.jetbrains.kotlin.name.Name import org.jetbrains.kotlin.psi.* import org.jetbrains.kotlin.resolve.ForbiddenNamedArgumentsTarget +import org.jetbrains.kotlin.resolve.multiplatform.ExpectActualCompatibility.Incompatible import org.jetbrains.kotlin.types.Variance import kotlin.properties.PropertyDelegateProvider import kotlin.properties.ReadOnlyProperty @@ -785,7 +787,6 @@ object DIAGNOSTICS_LIST : DiagnosticList("FirErrors") { val ABSTRACT_PROPERTY_WITH_SETTER by error() val PRIVATE_SETTER_FOR_ABSTRACT_PROPERTY by error(PositioningStrategy.PRIVATE_MODIFIER) val PRIVATE_SETTER_FOR_OPEN_PROPERTY by error(PositioningStrategy.PRIVATE_MODIFIER) - val EXPECTED_PRIVATE_DECLARATION by error(PositioningStrategy.VISIBILITY_MODIFIER) val VAL_WITH_SETTER by error() val CONST_VAL_NOT_TOP_LEVEL_OR_OBJECT by error(PositioningStrategy.CONST_MODIFIER) val CONST_VAL_WITH_GETTER by error() @@ -815,11 +816,56 @@ object DIAGNOSTICS_LIST : DiagnosticList("FirErrors") { val MPP_PROJECTS by object : DiagnosticGroup("Multi-platform projects") { val EXPECTED_DECLARATION_WITH_BODY by error(PositioningStrategy.DECLARATION_SIGNATURE) + val EXPECTED_CLASS_CONSTRUCTOR_DELEGATION_CALL by error() + val EXPECTED_CLASS_CONSTRUCTOR_PROPERTY_PARAMETER by error() + val EXPECTED_ENUM_CONSTRUCTOR by error>() + val EXPECTED_ENUM_ENTRY_WITH_BODY by error() val EXPECTED_PROPERTY_INITIALIZER by error() - // TODO: need to cover `by` as well as delegate expression val EXPECTED_DELEGATED_PROPERTY by error() val EXPECTED_LATEINIT_PROPERTY by error(PositioningStrategy.LATEINIT_MODIFIER) + val SUPERTYPE_INITIALIZED_IN_EXPECTED_CLASS by error() + val EXPECTED_PRIVATE_DECLARATION by error(PositioningStrategy.VISIBILITY_MODIFIER) + val IMPLEMENTATION_BY_DELEGATION_IN_EXPECT_CLASS by error() + + val ACTUAL_TYPE_ALIAS_NOT_TO_CLASS by error(PositioningStrategy.DECLARATION_SIGNATURE) + val ACTUAL_TYPE_ALIAS_TO_CLASS_WITH_DECLARATION_SITE_VARIANCE by error(PositioningStrategy.DECLARATION_SIGNATURE) + val ACTUAL_TYPE_ALIAS_WITH_USE_SITE_VARIANCE by error(PositioningStrategy.DECLARATION_SIGNATURE) + val ACTUAL_TYPE_ALIAS_WITH_COMPLEX_SUBSTITUTION by error(PositioningStrategy.DECLARATION_SIGNATURE) + val ACTUAL_FUNCTION_WITH_DEFAULT_ARGUMENTS by error() + val ACTUAL_ANNOTATION_CONFLICTING_DEFAULT_ARGUMENT_VALUE by error { + parameter>("parameter") + } + + val EXPECTED_FUNCTION_SOURCE_WITH_DEFAULT_ARGUMENTS_NOT_FOUND by error() + + val NO_ACTUAL_FOR_EXPECT by error(PositioningStrategy.INCOMPATIBLE_DECLARATION) { + parameter("declaration") + parameter("module") + parameter, Collection>>("compatibility") + } + + val ACTUAL_WITHOUT_EXPECT by error { + parameter("declaration") + parameter, Collection>>("compatibility") + } + + val AMBIGUOUS_ACTUALS by error(PositioningStrategy.INCOMPATIBLE_DECLARATION) { + parameter("declaration") + parameter>("candidates") + } + + val AMBIGUOUS_EXPECTS by error(PositioningStrategy.INCOMPATIBLE_DECLARATION) { + parameter("declaration") + parameter>("modules") + } + + val NO_ACTUAL_CLASS_MEMBER_FOR_EXPECTED_CLASS by error(PositioningStrategy.ACTUAL_DECLARATION_NAME) { + parameter("declaration") + parameter, Collection>>>>("members") + } + + val ACTUAL_MISSING by error(PositioningStrategy.ACTUAL_DECLARATION_NAME) } val DESTRUCTING_DECLARATION by object : DiagnosticGroup("Destructuring declaration") { diff --git a/compiler/fir/checkers/checkers-component-generator/src/org/jetbrains/kotlin/fir/checkers/generator/diagnostics/model/DiagnosticData.kt b/compiler/fir/checkers/checkers-component-generator/src/org/jetbrains/kotlin/fir/checkers/generator/diagnostics/model/DiagnosticData.kt index 7d4a5ad5291..75839603bc5 100644 --- a/compiler/fir/checkers/checkers-component-generator/src/org/jetbrains/kotlin/fir/checkers/generator/diagnostics/model/DiagnosticData.kt +++ b/compiler/fir/checkers/checkers-component-generator/src/org/jetbrains/kotlin/fir/checkers/generator/diagnostics/model/DiagnosticData.kt @@ -77,6 +77,8 @@ enum class PositioningStrategy(private val strategy: String? = null) { DATA_MODIFIER, SPREAD_OPERATOR, DECLARATION_WITH_BODY, + INCOMPATIBLE_DECLARATION, + ACTUAL_DECLARATION_NAME, ; diff --git a/compiler/fir/checkers/gen/org/jetbrains/kotlin/fir/analysis/diagnostics/FirErrors.kt b/compiler/fir/checkers/gen/org/jetbrains/kotlin/fir/analysis/diagnostics/FirErrors.kt index 9a7eeb5ba51..eb9b445bc3f 100644 --- a/compiler/fir/checkers/gen/org/jetbrains/kotlin/fir/analysis/diagnostics/FirErrors.kt +++ b/compiler/fir/checkers/gen/org/jetbrains/kotlin/fir/analysis/diagnostics/FirErrors.kt @@ -13,6 +13,7 @@ import org.jetbrains.kotlin.contracts.description.EventOccurrencesRange import org.jetbrains.kotlin.descriptors.EffectiveVisibility import org.jetbrains.kotlin.descriptors.Visibility import org.jetbrains.kotlin.diagnostics.WhenMissingCase +import org.jetbrains.kotlin.fir.FirModuleData import org.jetbrains.kotlin.fir.analysis.diagnostics.SourceElementPositioningStrategies import org.jetbrains.kotlin.fir.declarations.FirSimpleFunction import org.jetbrains.kotlin.fir.expressions.FirExpression @@ -40,10 +41,14 @@ import org.jetbrains.kotlin.psi.KtBinaryExpressionWithTypeRHS import org.jetbrains.kotlin.psi.KtCallExpression import org.jetbrains.kotlin.psi.KtClass import org.jetbrains.kotlin.psi.KtClassOrObject +import org.jetbrains.kotlin.psi.KtConstructor +import org.jetbrains.kotlin.psi.KtConstructorDelegationCall import org.jetbrains.kotlin.psi.KtDeclaration import org.jetbrains.kotlin.psi.KtDeclarationWithBody +import org.jetbrains.kotlin.psi.KtDelegatedSuperTypeEntry import org.jetbrains.kotlin.psi.KtDestructuringDeclaration import org.jetbrains.kotlin.psi.KtElement +import org.jetbrains.kotlin.psi.KtEnumEntry import org.jetbrains.kotlin.psi.KtExpression import org.jetbrains.kotlin.psi.KtFunction import org.jetbrains.kotlin.psi.KtIfExpression @@ -66,6 +71,7 @@ import org.jetbrains.kotlin.psi.KtWhenCondition import org.jetbrains.kotlin.psi.KtWhenEntry import org.jetbrains.kotlin.psi.KtWhenExpression import org.jetbrains.kotlin.resolve.ForbiddenNamedArgumentsTarget +import org.jetbrains.kotlin.resolve.multiplatform.ExpectActualCompatibility.Incompatible import org.jetbrains.kotlin.types.Variance /* @@ -425,7 +431,6 @@ object FirErrors { val ABSTRACT_PROPERTY_WITH_SETTER by error0() val PRIVATE_SETTER_FOR_ABSTRACT_PROPERTY by error0(SourceElementPositioningStrategies.PRIVATE_MODIFIER) val PRIVATE_SETTER_FOR_OPEN_PROPERTY by error0(SourceElementPositioningStrategies.PRIVATE_MODIFIER) - val EXPECTED_PRIVATE_DECLARATION by error0(SourceElementPositioningStrategies.VISIBILITY_MODIFIER) val VAL_WITH_SETTER by error0() val CONST_VAL_NOT_TOP_LEVEL_OR_OBJECT by error0(SourceElementPositioningStrategies.CONST_MODIFIER) val CONST_VAL_WITH_GETTER by error0() @@ -443,9 +448,29 @@ object FirErrors { // Multi-platform projects val EXPECTED_DECLARATION_WITH_BODY by error0(SourceElementPositioningStrategies.DECLARATION_SIGNATURE) + val EXPECTED_CLASS_CONSTRUCTOR_DELEGATION_CALL by error0() + val EXPECTED_CLASS_CONSTRUCTOR_PROPERTY_PARAMETER by error0() + val EXPECTED_ENUM_CONSTRUCTOR by error0>() + val EXPECTED_ENUM_ENTRY_WITH_BODY by error0() val EXPECTED_PROPERTY_INITIALIZER by error0() val EXPECTED_DELEGATED_PROPERTY by error0() val EXPECTED_LATEINIT_PROPERTY by error0(SourceElementPositioningStrategies.LATEINIT_MODIFIER) + val SUPERTYPE_INITIALIZED_IN_EXPECTED_CLASS by error0() + val EXPECTED_PRIVATE_DECLARATION by error0(SourceElementPositioningStrategies.VISIBILITY_MODIFIER) + val IMPLEMENTATION_BY_DELEGATION_IN_EXPECT_CLASS by error0() + val ACTUAL_TYPE_ALIAS_NOT_TO_CLASS by error0(SourceElementPositioningStrategies.DECLARATION_SIGNATURE) + val ACTUAL_TYPE_ALIAS_TO_CLASS_WITH_DECLARATION_SITE_VARIANCE by error0(SourceElementPositioningStrategies.DECLARATION_SIGNATURE) + val ACTUAL_TYPE_ALIAS_WITH_USE_SITE_VARIANCE by error0(SourceElementPositioningStrategies.DECLARATION_SIGNATURE) + val ACTUAL_TYPE_ALIAS_WITH_COMPLEX_SUBSTITUTION by error0(SourceElementPositioningStrategies.DECLARATION_SIGNATURE) + val ACTUAL_FUNCTION_WITH_DEFAULT_ARGUMENTS by error0() + val ACTUAL_ANNOTATION_CONFLICTING_DEFAULT_ARGUMENT_VALUE by error1>() + val EXPECTED_FUNCTION_SOURCE_WITH_DEFAULT_ARGUMENTS_NOT_FOUND by error0() + val NO_ACTUAL_FOR_EXPECT by error3, FirModuleData, Map>, Collection>>>(SourceElementPositioningStrategies.INCOMPATIBLE_DECLARATION) + val ACTUAL_WITHOUT_EXPECT by error2, Map>, Collection>>>() + val AMBIGUOUS_ACTUALS by error2, Collection>>(SourceElementPositioningStrategies.INCOMPATIBLE_DECLARATION) + val AMBIGUOUS_EXPECTS by error2, Collection>(SourceElementPositioningStrategies.INCOMPATIBLE_DECLARATION) + val NO_ACTUAL_CLASS_MEMBER_FOR_EXPECTED_CLASS by error2, List, Map>, Collection>>>>>(SourceElementPositioningStrategies.ACTUAL_DECLARATION_NAME) + val ACTUAL_MISSING by error0(SourceElementPositioningStrategies.ACTUAL_DECLARATION_NAME) // Destructuring declaration val INITIALIZER_REQUIRED_FOR_DESTRUCTURING_DECLARATION by error0() 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 12636814870..ef569281fc0 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 @@ -30,6 +30,7 @@ object CommonDeclarationCheckers : DeclarationCheckers() { FirInfixFunctionDeclarationChecker, FirExposedVisibilityDeclarationChecker, FirCyclicTypeBoundsChecker, + FirExpectActualDeclarationChecker ) override val functionCheckers: Set 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 new file mode 100644 index 00000000000..98b74df7ba2 --- /dev/null +++ b/compiler/fir/checkers/src/org/jetbrains/kotlin/fir/analysis/checkers/declaration/FirExpectActualDeclarationChecker.kt @@ -0,0 +1,242 @@ +/* + * Copyright 2010-2021 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.fir.FirSession +import org.jetbrains.kotlin.fir.FirSourceElement +import org.jetbrains.kotlin.fir.analysis.checkers.context.CheckerContext +import org.jetbrains.kotlin.fir.analysis.diagnostics.DiagnosticReporter +import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors +import org.jetbrains.kotlin.fir.analysis.diagnostics.reportOn +import org.jetbrains.kotlin.fir.declarations.FirDeclaration +import org.jetbrains.kotlin.fir.declarations.FirMemberDeclaration +import org.jetbrains.kotlin.fir.declarations.utils.isActual +import org.jetbrains.kotlin.fir.languageVersionSettings +import org.jetbrains.kotlin.fir.resolve.ScopeSession +import org.jetbrains.kotlin.fir.resolve.fullyExpandedType +import org.jetbrains.kotlin.fir.symbols.FirBasedSymbol +import org.jetbrains.kotlin.fir.symbols.impl.FirConstructorSymbol +import org.jetbrains.kotlin.fir.symbols.impl.FirRegularClassSymbol +import org.jetbrains.kotlin.fir.symbols.impl.FirTypeAliasSymbol +import org.jetbrains.kotlin.fir.types.coneType +import org.jetbrains.kotlin.fir.types.toSymbol +import org.jetbrains.kotlin.resolve.multiplatform.ExpectActualCompatibility +import org.jetbrains.kotlin.resolve.multiplatform.ExpectActualCompatibility.* +import org.jetbrains.kotlin.utils.addToStdlib.cast +import org.jetbrains.kotlin.utils.addToStdlib.firstIsInstanceOrNull + +@Suppress("DuplicatedCode") +object FirExpectActualDeclarationChecker : FirBasicDeclarationChecker() { + override fun check(declaration: FirDeclaration, context: CheckerContext, reporter: DiagnosticReporter) { + if (!context.session.languageVersionSettings.supportsFeature(LanguageFeature.MultiPlatformProjects)) return + if (declaration !is FirMemberDeclaration) return + if (declaration.isActual) { + checkActualDeclarationHasExpected(declaration, context, reporter) + } + } + + private fun checkActualDeclarationHasExpected( + declaration: T, + context: CheckerContext, + reporter: DiagnosticReporter, + checkActual: Boolean = true + ) where T : FirDeclaration, T : FirMemberDeclaration { + val scopeSession = ScopeSession() + val symbol = declaration.symbol + val compatibilityToMembersMap = FirExpectActualResolver.findExpectForActual(symbol, context.session, scopeSession) ?: return + val session = context.session + + checkAmbiguousExpects(symbol, compatibilityToMembersMap, symbol, context, reporter) + + val source = declaration.source + if (!declaration.isActual) { + if (compatibilityToMembersMap.allStrongIncompatibilities()) return + + if (Compatible in compatibilityToMembersMap) { + if (checkActual && requireActualModifier(symbol, session)) { + reporter.reportOn(source, FirErrors.ACTUAL_MISSING, context) + } + return + } + } + + val singleIncompatibility = compatibilityToMembersMap.keys.singleOrNull() + when { + singleIncompatibility is Incompatible.ClassScopes -> { + assert(symbol is FirRegularClassSymbol || symbol is FirTypeAliasSymbol) { + "Incompatible.ClassScopes is only possible for a class or a typealias: $declaration" + } + + // Do not report "expected members have no actual ones" for those expected members, for which there's a clear + // (albeit maybe incompatible) single actual suspect, declared in the actual class. + // This is needed only to reduce the number of errors. Incompatibility errors for those members will be reported + // later when this checker is called for them + fun hasSingleActualSuspect( + expectedWithIncompatibility: Pair, Map>, Collection>>> + ): Boolean { + val (expectedMember, incompatibility) = expectedWithIncompatibility + val actualMember = incompatibility.values.singleOrNull()?.singleOrNull() + return actualMember != null && + actualMember.isExplicitActualDeclaration() && + !incompatibility.allStrongIncompatibilities() && + FirExpectActualResolver.findExpectForActual( + actualMember, + session, + scopeSession + )?.values?.singleOrNull()?.singleOrNull() == expectedMember + } + + val nonTrivialUnfulfilled = singleIncompatibility.unfulfilled.filterNot(::hasSingleActualSuspect) + + if (nonTrivialUnfulfilled.isNotEmpty()) { + reporter.reportOn(source, FirErrors.NO_ACTUAL_CLASS_MEMBER_FOR_EXPECTED_CLASS, symbol, nonTrivialUnfulfilled, context) + } + } + + Compatible !in compatibilityToMembersMap -> { + reporter.reportOn(source, FirErrors.ACTUAL_WITHOUT_EXPECT, symbol, compatibilityToMembersMap.cast(), context) + } + + else -> { + val expected = compatibilityToMembersMap[Compatible]!!.first() + if (expected is FirRegularClassSymbol && expected.classKind == ClassKind.ANNOTATION_CLASS) { + val klass = symbol.expandedClass(session) + val actualConstructor = klass?.declarationSymbols?.firstIsInstanceOrNull() + val expectedConstructor = expected.declarationSymbols.firstIsInstanceOrNull() + if (expectedConstructor != null && actualConstructor != null) { + checkAnnotationConstructors(source, expectedConstructor, actualConstructor, context, reporter) + } + } + } + } + } + + @Suppress("UNUSED_PARAMETER") + private fun checkAnnotationConstructors( + source: FirSourceElement?, + expected: FirConstructorSymbol, + actual: FirConstructorSymbol, + context: CheckerContext, + reporter: DiagnosticReporter + ) { + for (expectedValueParameter in expected.valueParameterSymbols) { + // Actual parameter with the same name is guaranteed to exist because this method is only called for compatible annotations + val actualValueDescriptor = actual.valueParameterSymbols.first { it.name == expectedValueParameter.name } + + if (expectedValueParameter.hasDefaultValue && actualValueDescriptor.hasDefaultValue) { +// TODO +// val expectedParameter = +// DescriptorToSourceUtils.descriptorToDeclaration(expectedValueParameter) as? KtParameter ?: continue +// +// val expectedValue = trace.bindingContext.get(BindingContext.COMPILE_TIME_VALUE, expectedParameter.defaultValue) +// ?.toConstantValue(expectedValueParameter.type) +// +// val actualValue = +// getActualAnnotationParameterValue(actualValueDescriptor, trace.bindingContext, expectedValueParameter.type) +// if (expectedValue != actualValue) { +// val ktParameter = DescriptorToSourceUtils.descriptorToDeclaration(actualValueDescriptor) +// val target = (ktParameter as? KtParameter)?.defaultValue ?: (reportOn as? KtTypeAlias)?.nameIdentifier ?: reportOn +// trace.report(Errors.ACTUAL_ANNOTATION_CONFLICTING_DEFAULT_ARGUMENT_VALUE.on(target, actualValueDescriptor)) +// } + } + } + } + + + private fun checkAmbiguousExpects( + actualDeclaration: FirBasedSymbol<*>, + compatibility: Map>, List>>, + symbol: FirBasedSymbol<*>, + context: CheckerContext, + reporter: DiagnosticReporter + ) { + val filesWithAtLeastWeaklyCompatibleExpects = compatibility.asSequence() + .filter { (compatibility, _) -> + compatibility.isCompatibleOrWeakCompatible() + } + .map { (_, members) -> members } + .flatten() + .map { it.moduleData } + .sortedBy { it.name.asString() } + .toList() + + if (filesWithAtLeastWeaklyCompatibleExpects.size > 1) { + reporter.reportOn( + actualDeclaration.source, + FirErrors.AMBIGUOUS_EXPECTS, + symbol, + filesWithAtLeastWeaklyCompatibleExpects, + context + ) + } + } + + fun Map, *>.allStrongIncompatibilities(): Boolean { + return keys.all { it is Incompatible && it.kind == IncompatibilityKind.STRONG } + } + + private fun ExpectActualCompatibility>.isCompatibleOrWeakCompatible(): Boolean { + return this is Compatible || + this is Incompatible && kind == IncompatibilityKind.WEAK + } + + // we don't require `actual` modifier on + // - annotation constructors, because annotation classes can only have one constructor + // - inline class primary constructors, because inline class must have primary constructor + // - value parameter inside primary constructor of inline class, because inline class must have one value parameter + private fun requireActualModifier(declaration: FirBasedSymbol<*>, session: FirSession): Boolean { + return !declaration.isAnnotationConstructor(session) && + !declaration.isPrimaryConstructorOfInlineClass(session) && + !isUnderlyingPropertyOfInlineClass(declaration) + } + + @Suppress("UNUSED_PARAMETER") + private fun isUnderlyingPropertyOfInlineClass(declaration: FirBasedSymbol<*>): Boolean { + // TODO + // return declaration is PropertyDescriptor && declaration.isUnderlyingPropertyOfInlineClass() + return false + } + + private fun FirBasedSymbol<*>.isExplicitActualDeclaration(): Boolean { +// return when (this) { +// is FirConstructor -> DescriptorToSourceUtils.getSourceFromDescriptor(this) is KtConstructor<*> +// is FirCallableMemberDeclaration<*> -> kind == CallableMemberDescriptor.Kind.DECLARATION +// else -> true +// } + return true + } +} + +fun FirBasedSymbol<*>.isAnnotationConstructor(session: FirSession): Boolean { + if (this !is FirConstructorSymbol) return false + return getConstructedClass(session)?.classKind == ClassKind.ANNOTATION_CLASS +} + +fun FirBasedSymbol<*>.isEnumConstructor(session: FirSession): Boolean { + if (this !is FirConstructorSymbol) return false + return getConstructedClass(session)?.classKind == ClassKind.ENUM_CLASS +} + +fun FirBasedSymbol<*>.isPrimaryConstructorOfInlineClass(session: FirSession): Boolean { + if (this !is FirConstructorSymbol) return false + return getConstructedClass(session)?.isInlineOrValueClass() == true && this.isPrimary +} + +fun FirConstructorSymbol.getConstructedClass(session: FirSession): FirRegularClassSymbol? { + return resolvedReturnTypeRef.coneType + .fullyExpandedType(session) + .toSymbol(session) as? FirRegularClassSymbol? +} + +fun FirBasedSymbol<*>.expandedClass(session: FirSession): FirRegularClassSymbol? { + return when (this) { + is FirTypeAliasSymbol -> resolvedExpandedTypeRef.coneType.fullyExpandedType(session).toSymbol(session) as? FirRegularClassSymbol + is FirRegularClassSymbol -> this + else -> null + } +} diff --git a/compiler/fir/checkers/src/org/jetbrains/kotlin/fir/analysis/checkers/declaration/FirExpectActualResolver.kt b/compiler/fir/checkers/src/org/jetbrains/kotlin/fir/analysis/checkers/declaration/FirExpectActualResolver.kt new file mode 100644 index 00000000000..d28cc31bdf4 --- /dev/null +++ b/compiler/fir/checkers/src/org/jetbrains/kotlin/fir/analysis/checkers/declaration/FirExpectActualResolver.kt @@ -0,0 +1,658 @@ +/* + * Copyright 2010-2021 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.descriptors.ClassKind +import org.jetbrains.kotlin.descriptors.Modality +import org.jetbrains.kotlin.descriptors.Visibilities +import org.jetbrains.kotlin.fir.FirSession +import org.jetbrains.kotlin.fir.analysis.checkers.collectEnumEntries +import org.jetbrains.kotlin.fir.analysis.checkers.fullyExpandedClass +import org.jetbrains.kotlin.fir.declarations.* +import org.jetbrains.kotlin.fir.declarations.utils.* +import org.jetbrains.kotlin.fir.resolve.* +import org.jetbrains.kotlin.fir.resolve.substitution.ConeSubstitutor +import org.jetbrains.kotlin.fir.resolve.substitution.ConeSubstitutorByMap +import org.jetbrains.kotlin.fir.resolve.substitution.chain +import org.jetbrains.kotlin.fir.scopes.* +import org.jetbrains.kotlin.fir.scopes.impl.FirPackageMemberScope +import org.jetbrains.kotlin.fir.symbols.FirBasedSymbol +import org.jetbrains.kotlin.fir.symbols.ConeClassifierLookupTag +import org.jetbrains.kotlin.fir.symbols.impl.* +import org.jetbrains.kotlin.fir.types.* +import org.jetbrains.kotlin.name.Name +import org.jetbrains.kotlin.resolve.multiplatform.ExpectActualCompatibility +import org.jetbrains.kotlin.types.AbstractTypeChecker +import org.jetbrains.kotlin.types.model.TypeConstructorMarker +import org.jetbrains.kotlin.utils.SmartList +import org.jetbrains.kotlin.utils.addIfNotNull +import org.jetbrains.kotlin.utils.keysToMap + +object FirExpectActualResolver { + @OptIn(ExperimentalStdlibApi::class) + fun findExpectForActual( + actualSymbol: FirBasedSymbol<*>, + useSiteSession: FirSession, + scopeSession: ScopeSession + ): Map>, List>>? { + return when (actualSymbol) { + is FirCallableSymbol<*> -> { + val callableId = actualSymbol.callableId + val classId = callableId.classId + var parentSubstitutor: ConeSubstitutor? = null + var expectContainingClass: FirRegularClassSymbol? = null + var actualContainingClass: FirRegularClassSymbol? = null + val candidates = when { + classId != null -> { + expectContainingClass = useSiteSession.dependenciesSymbolProvider.getClassLikeSymbolByFqName(classId)?.let { + it.fullyExpandedClass(it.moduleData.session) + } + actualContainingClass = useSiteSession.symbolProvider.getClassLikeSymbolByFqName(classId) + ?.fullyExpandedClass(useSiteSession) + + val expectTypeParameters = expectContainingClass?.typeParameterSymbols.orEmpty() + val actualTypeParameters = actualContainingClass + ?.typeParameterSymbols + .orEmpty() + parentSubstitutor = createTypeParameterSubstitutor(expectTypeParameters, actualTypeParameters, useSiteSession) + when (actualSymbol) { + is FirConstructorSymbol -> expectContainingClass?.getConstructors(scopeSession) + else -> expectContainingClass?.getMembers(callableId.callableName, scopeSession) + }.orEmpty() + } + callableId.isLocal -> return null + else -> { + val scope = FirPackageMemberScope(callableId.packageName, useSiteSession, useSiteSession.dependenciesSymbolProvider) + mutableListOf>().apply { + scope.processFunctionsByName(callableId.callableName) { add(it) } + scope.processPropertiesByName(callableId.callableName) { add(it) } + } + } + } + candidates.filter { expectSymbol -> + actualSymbol != expectSymbol && expectSymbol.isExpect + }.groupBy { expectDeclaration -> + areCompatibleCallables( + expectDeclaration, + actualSymbol, + useSiteSession, + parentSubstitutor, + expectContainingClass, + actualContainingClass + ) + } + } + is FirClassLikeSymbol<*> -> { + val expectClassSymbol = useSiteSession.dependenciesSymbolProvider + .getClassLikeSymbolByFqName(actualSymbol.classId) as? FirRegularClassSymbol ?: return null + val compatibility = areCompatibleClassifiers(expectClassSymbol, actualSymbol, useSiteSession, scopeSession) + mapOf(compatibility to listOf(expectClassSymbol)) + } + else -> null + } + } + + private fun areCompatibleClassifiers( + expectClassSymbol: FirRegularClassSymbol, + actualClassLikeSymbol: FirClassLikeSymbol<*>, + actualSession: FirSession, + scopeSession: ScopeSession + ): ExpectActualCompatibility> { + // Can't check FQ names here because nested expected class may be implemented via actual typealias's expansion with the other FQ name + assert(expectClassSymbol.classId.shortClassName == actualClassLikeSymbol.classId.shortClassName) { + "This function should be invoked only for declarations with the same name: $expectClassSymbol, $actualClassLikeSymbol" + } + + val actualClass = when (actualClassLikeSymbol) { + is FirRegularClassSymbol -> actualClassLikeSymbol + is FirTypeAliasSymbol -> actualClassLikeSymbol.resolvedExpandedTypeRef.coneType.fullyExpandedType(actualSession) + .toSymbol(actualSession) as? FirRegularClassSymbol + ?: return ExpectActualCompatibility.Compatible // do not report extra error on erroneous typealias + else -> throw IllegalArgumentException("Incorrect actual classifier for $expectClassSymbol: $actualClassLikeSymbol") + } + + if (expectClassSymbol.classKind != actualClass.classKind) return ExpectActualCompatibility.Incompatible.ClassKind + + if (!equalBy(expectClassSymbol, actualClass) { listOf(it.isCompanion, it.isInner, it.isInline /*|| it.isValue*/) }) { + return ExpectActualCompatibility.Incompatible.ClassModifiers + } + + val expectTypeParameterSymbols = expectClassSymbol.typeParameterSymbols + val actualTypeParameterSymbols = actualClass.typeParameterSymbols + if (expectTypeParameterSymbols.size != actualTypeParameterSymbols.size) { + return ExpectActualCompatibility.Incompatible.TypeParameterCount + } + + if (!areCompatibleModalities(expectClassSymbol.modality, actualClass.modality)) { + return ExpectActualCompatibility.Incompatible.Modality + } + + if (expectClassSymbol.visibility != actualClass.visibility) { + return ExpectActualCompatibility.Incompatible.Visibility + } + + val substitutor = createTypeParameterSubstitutor(expectTypeParameterSymbols, actualTypeParameterSymbols, actualSession) + + val expectSession = expectClassSymbol.moduleData.session + areCompatibleTypeParameters(expectTypeParameterSymbols, actualTypeParameterSymbols, actualSession, expectSession, substitutor).let { + if (it != ExpectActualCompatibility.Compatible) { + return it + } + } + + // Subtract kotlin.Any from supertypes because it's implicitly added if no explicit supertype is specified, + // and not added if an explicit supertype _is_ specified + val expectSupertypes = expectClassSymbol.superConeTypes.filterNot { it.classId == actualSession.builtinTypes.anyType.id } + val actualSupertypes = actualClass.superConeTypes.filterNot { it.classId == actualSession.builtinTypes.anyType.id } + if ( + expectSupertypes.map(substitutor::substituteOrSelf).any { expectSupertype -> + actualSupertypes.none { actualSupertype -> + areCompatibleTypes(expectSupertype, actualSupertype, expectSession, actualSession) + } + } + ) { + return ExpectActualCompatibility.Incompatible.Supertypes + } + + areCompatibleClassScopes(expectClassSymbol, actualClass, actualSession, scopeSession, substitutor).let { + if (it != ExpectActualCompatibility.Compatible) { + return it + } + } + + return ExpectActualCompatibility.Compatible + } + + private fun areCompatibleClassScopes( + expectClassSymbol: FirRegularClassSymbol, + actualClassSymbol: FirRegularClassSymbol, + actualSession: FirSession, + scopeSession: ScopeSession, + substitutor: ConeSubstitutor + ): ExpectActualCompatibility> { + val unfulfilled = + mutableListOf, Map>, MutableCollection>>>>() + + val allActualMembers = actualClassSymbol.getMembers(scopeSession, actualSession) + val actualMembersByName = allActualMembers.groupBy { it.name } + val actualConstructors = allActualMembers.filterIsInstance() + + outer@ for (expectMember in expectClassSymbol.getMembers(scopeSession)) { + // if (expectMember is CallableMemberDescriptor && !expectMember.kind.isReal) continue + + val actualMembers = when (expectMember) { + is FirConstructorSymbol -> actualConstructors + else -> actualMembersByName[expectMember.name]?.filter { actualMember -> + expectMember is FirRegularClassSymbol && actualMember is FirRegularClassSymbol || + expectMember is FirCallableSymbol<*> && actualMember is FirCallableSymbol<*> + }.orEmpty() + } + + val mapping = actualMembers.keysToMap { actualMember -> + when (expectMember) { + is FirCallableSymbol<*> -> + areCompatibleCallables( + expectMember, + actualMember as FirCallableSymbol<*>, + actualSession, + substitutor, + expectClassSymbol, + actualClassSymbol + ) + is FirRegularClassSymbol -> + areCompatibleClassifiers(expectMember, actualMember as FirRegularClassSymbol, actualSession, scopeSession) + else -> throw UnsupportedOperationException("Unsupported declaration: $expectMember ($actualMembers)") + } + } + if (mapping.values.any { it == ExpectActualCompatibility.Compatible }) continue + + val incompatibilityMap = + mutableMapOf>, MutableCollection>>() + for ((declaration, compatibility) in mapping) { + when (compatibility) { + ExpectActualCompatibility.Compatible -> continue@outer + is ExpectActualCompatibility.Incompatible -> incompatibilityMap.getOrPut(compatibility) { SmartList() }.add(declaration) + } + } + + unfulfilled.add(expectMember to incompatibilityMap) + } + + if (expectClassSymbol.classKind == ClassKind.ENUM_CLASS) { + val expectEntries = expectClassSymbol.collectEnumEntries().map { it.name } + val actualEntries = actualClassSymbol.collectEnumEntries().map { it.name } + + if (!actualEntries.containsAll(expectEntries)) { + return ExpectActualCompatibility.Incompatible.EnumEntries + } + } + + // TODO: check static scope? + + if (unfulfilled.isEmpty()) return ExpectActualCompatibility.Compatible + + return ExpectActualCompatibility.Incompatible.ClassScopes(unfulfilled) + } + + private fun areCompatibleCallables( + expectDeclaration: FirCallableSymbol<*>, + actualDeclaration: FirCallableSymbol<*>, + actualSession: FirSession, + parentSubstitutor: ConeSubstitutor?, + expectContainingClass: FirRegularClassSymbol?, + actualContainingClass: FirRegularClassSymbol?, + ): ExpectActualCompatibility> { + assert( + (expectDeclaration is FirConstructorSymbol && actualDeclaration is FirConstructorSymbol) || + expectDeclaration.callableId.callableName == actualDeclaration.callableId.callableName + ) { + "This function should be invoked only for declarations with the same name: $expectDeclaration, $actualDeclaration" + } + assert((expectDeclaration.dispatchReceiverType == null) == (actualDeclaration.dispatchReceiverType == null)) { + "This function should be invoked only for declarations in the same kind of container (both members or both top level): $expectDeclaration, $actualDeclaration" + } + + val expectSession = expectDeclaration.moduleData.session + + if ( + expectDeclaration is FirConstructorSymbol && + actualDeclaration is FirConstructorSymbol && + expectContainingClass?.classKind == ClassKind.ENUM_CLASS && + actualContainingClass?.classKind == ClassKind.ENUM_CLASS + ) { + return ExpectActualCompatibility.Compatible + } + + if (expectDeclaration is FirNamedFunctionSymbol != actualDeclaration is FirNamedFunctionSymbol) { + return ExpectActualCompatibility.Incompatible.CallableKind + } + + val expectedReceiverType = expectDeclaration.resolvedReceiverTypeRef + val actualReceiverType = actualDeclaration.resolvedReceiverTypeRef + if ((expectedReceiverType != null) != (actualReceiverType != null)) { + return ExpectActualCompatibility.Incompatible.ParameterShape + } + + val expectedValueParameters = expectDeclaration.valueParameterSymbols + val actualValueParameters = actualDeclaration.valueParameterSymbols + if (!valueParametersCountCompatible(expectDeclaration, actualDeclaration, expectedValueParameters, actualValueParameters)) { + return ExpectActualCompatibility.Incompatible.ParameterCount + } + + val expectedTypeParameters = expectDeclaration.typeParameterSymbols + val actualTypeParameters = actualDeclaration.typeParameterSymbols + if (expectedTypeParameters.size != actualTypeParameters.size) { + return ExpectActualCompatibility.Incompatible.TypeParameterCount + } + + val substitutor = createTypeParameterSubstitutor(expectedTypeParameters, actualTypeParameters, actualSession, parentSubstitutor) + + if ( + !areCompatibleTypeLists( + expectedValueParameters.toTypeList(substitutor), + actualValueParameters.toTypeList(ConeSubstitutor.Empty), + expectSession, + actualSession + ) || + !areCompatibleTypes( + expectedReceiverType?.coneType?.let { substitutor.substituteOrSelf(it) }, + actualReceiverType?.coneType, + expectSession, + actualSession + ) + ) { + return ExpectActualCompatibility.Incompatible.ParameterTypes + } + if ( + !areCompatibleTypes( + substitutor.substituteOrSelf(expectDeclaration.resolvedReturnTypeRef.coneType), + actualDeclaration.resolvedReturnTypeRef.coneType, + expectSession, + actualSession + ) + ) { + return ExpectActualCompatibility.Incompatible.ReturnType + } + + // TODO: implement hasStableParameterNames calculation + // if (actualDeclaration.hasStableParameterNames() && !equalsBy(expectedValueParameters, actualValueParameters, ValueParameterDescriptor::getName)) return Incompatible.ParameterNames + + if (!equalsBy(expectedTypeParameters, actualTypeParameters) { it.name }) { + return ExpectActualCompatibility.Incompatible.TypeParameterNames + } + + if ( + !areCompatibleModalities( + expectDeclaration.modality, + actualDeclaration.modality, + (expectDeclaration.dispatchReceiverType?.toSymbol(expectSession) as? FirRegularClassSymbol)?.modality, + actualContainingClass?.modality + ) + ) { + return ExpectActualCompatibility.Incompatible.Modality + } + + if (!areDeclarationsWithCompatibleVisibilities(expectDeclaration.resolvedStatus, actualDeclaration.resolvedStatus)) { + return ExpectActualCompatibility.Incompatible.Visibility + } + + areCompatibleTypeParameters(expectedTypeParameters, actualTypeParameters, actualSession, expectSession, substitutor).let { + if (it != ExpectActualCompatibility.Compatible) { + return it + } + } + + if (!equalsBy(expectedValueParameters, actualValueParameters) { it.isVararg }) { + return ExpectActualCompatibility.Incompatible.ValueParameterVararg + } + + // Adding noinline/crossinline to parameters is disallowed, except if the expected declaration was not inline at all + if (expectDeclaration is FirNamedFunctionSymbol && expectDeclaration.isInline) { + if (expectedValueParameters.indices.any { i -> !expectedValueParameters[i].isNoinline && actualValueParameters[i].isNoinline }) { + return ExpectActualCompatibility.Incompatible.ValueParameterNoinline + } + if (expectedValueParameters.indices.any { i -> !expectedValueParameters[i].isCrossinline && actualValueParameters[i].isCrossinline }) { + return ExpectActualCompatibility.Incompatible.ValueParameterCrossinline + } + } + + when { + expectDeclaration is FirNamedFunctionSymbol && actualDeclaration is FirNamedFunctionSymbol -> areCompatibleFunctions( + expectDeclaration, + actualDeclaration + ).let { if (it != ExpectActualCompatibility.Compatible) return it } + + expectDeclaration is FirConstructorSymbol && actualDeclaration is FirConstructorSymbol -> areCompatibleFunctions( + expectDeclaration, + actualDeclaration + ).let { if (it != ExpectActualCompatibility.Compatible) return it } + + expectDeclaration is FirPropertySymbol && actualDeclaration is FirPropertySymbol -> areCompatibleProperties( + expectDeclaration, + actualDeclaration + ).let { if (it != ExpectActualCompatibility.Compatible) return it } + + else -> throw AssertionError("Unsupported declarations: $expectDeclaration, $actualDeclaration") + } + + return ExpectActualCompatibility.Compatible + } + + private fun createTypeParameterSubstitutor( + expectedTypeParameters: List, + actualTypeParameters: List, + useSiteSession: FirSession, + parentSubstitutor: ConeSubstitutor? = null + ): ConeSubstitutor { + val substitution = expectedTypeParameters.zip(actualTypeParameters).associate { (expectedParameterSymbol, actualParameterSymbol) -> + expectedParameterSymbol to actualParameterSymbol.toLookupTag().constructType(emptyArray(), isNullable = false) + } + val substitutor = ConeSubstitutorByMap( + substitution, + useSiteSession + ) + if (parentSubstitutor == null) { + return substitutor + } + return substitutor.chain(parentSubstitutor) + } + + private fun valueParametersCountCompatible( + expectDeclaration: FirCallableSymbol<*>, + actualDeclaration: FirCallableSymbol<*>, + expectValueParameters: List, + actualValueParameters: List + ): Boolean { + if (expectValueParameters.size == actualValueParameters.size) return true + + return if ( + expectDeclaration.isAnnotationConstructor(expectDeclaration.moduleData.session) && + actualDeclaration.isAnnotationConstructor(actualDeclaration.moduleData.session) + ) { + expectValueParameters.isEmpty() && actualValueParameters.all { it.hasDefaultValue } + } else { + false + } + } + + private fun areCompatibleTypeLists( + expectedTypes: List, + actualTypes: List, + expectSession: FirSession, + actualSession: FirSession + ): Boolean { + for (i in expectedTypes.indices) { + if (!areCompatibleTypes(expectedTypes[i], actualTypes[i], expectSession, actualSession)) { + return false + } + } + return true + } + + private fun areCompatibleTypes( + expectedType: ConeKotlinType?, + actualType: ConeKotlinType?, + expectSession: FirSession, + actualSession: FirSession + ): Boolean { + if (expectedType == null) return actualType == null + if (actualType == null) return false + + val typeCheckerContext = ConeInferenceContextForExpectActual(expectSession, actualSession).newBaseTypeCheckerContext( + errorTypesEqualToAnything = false, + stubTypesEqualToAnything = true + ) + return AbstractTypeChecker.equalTypes( + typeCheckerContext, + expectedType, + actualType + ) + } + + private fun areCompatibleModalities( + expectModality: Modality?, + actualModality: Modality?, + expectContainingClassModality: Modality? = null, + actualContainingClassModality: Modality? = null + ): Boolean { + val result = (expectModality == actualModality) || + (expectModality == Modality.FINAL && (actualModality == Modality.OPEN || actualModality == Modality.ABSTRACT)) + if (result) return true + if (expectContainingClassModality == null || actualContainingClassModality == null) return result + return expectModality == expectContainingClassModality && actualModality == actualContainingClassModality + } + + private fun areDeclarationsWithCompatibleVisibilities( + expectStatus: FirDeclarationStatus, + actualStatus: FirDeclarationStatus + ): Boolean { + val compare = Visibilities.compare(expectStatus.visibility, actualStatus.visibility) + return if (expectStatus.modality != Modality.FINAL) { + // For overridable declarations visibility should match precisely, see KT-19664 + compare == 0 + } else { + // For non-overridable declarations actuals are allowed to have more permissive visibility + compare != null && compare <= 0 + } + } + + private fun areCompatibleTypeParameters( + expectTypeParameterSymbols: List, + actualTypeParameterSymbols: List, + actualSession: FirSession, + expectSession: FirSession, + substitutor: ConeSubstitutor + ): ExpectActualCompatibility> { + for (i in expectTypeParameterSymbols.indices) { + val expectBounds = expectTypeParameterSymbols[i].resolvedBounds.map { it.coneType } + val actualBounds = actualTypeParameterSymbols[i].resolvedBounds.map { it.coneType } + if ( + expectBounds.size != actualBounds.size || + !areCompatibleTypeLists(expectBounds.map(substitutor::substituteOrSelf), actualBounds, expectSession, actualSession) + ) { + return ExpectActualCompatibility.Incompatible.TypeParameterUpperBounds + } + } + + if (!equalsBy(expectTypeParameterSymbols, actualTypeParameterSymbols) { it.variance }) { + return ExpectActualCompatibility.Incompatible.TypeParameterVariance + } + + // Removing "reified" from an expected function's type parameter is fine + if ( + expectTypeParameterSymbols.indices.any { i -> + !expectTypeParameterSymbols[i].isReified && actualTypeParameterSymbols[i].isReified + } + ) { + return ExpectActualCompatibility.Incompatible.TypeParameterReified + } + + return ExpectActualCompatibility.Compatible + } + + private fun areCompatibleFunctions( + expectFunction: FirCallableSymbol<*>, + actualFunction: FirCallableSymbol<*> + ): ExpectActualCompatibility> { + if (!equalBy(expectFunction, actualFunction) { f -> f.isSuspend }) { + return ExpectActualCompatibility.Incompatible.FunctionModifiersDifferent + } + + if ( + expectFunction.isExternal && !actualFunction.isExternal || + expectFunction.isInfix && !actualFunction.isInfix || + expectFunction.isInline && !actualFunction.isInline || + expectFunction.isOperator && !actualFunction.isOperator || + expectFunction.isTailRec && !actualFunction.isTailRec + ) { + return ExpectActualCompatibility.Incompatible.FunctionModifiersNotSubset + } + + return ExpectActualCompatibility.Compatible + } + + private fun areCompatibleProperties(a: FirPropertySymbol, b: FirPropertySymbol): ExpectActualCompatibility> { + if (!equalBy(a, b) { p -> p.isVar }) { + return ExpectActualCompatibility.Incompatible.PropertyKind + } + if (!equalBy(a, b) { p -> listOf(p.isConst, p.isLateInit) }) { + return ExpectActualCompatibility.Incompatible.PropertyModifiers + } + return ExpectActualCompatibility.Compatible + } + + // ---------------------------------------- Utils ---------------------------------------- + + private class ConeInferenceContextForExpectActual(val expectSession: FirSession, val actualSession: FirSession) : ConeInferenceContext { + override val session: FirSession + get() = actualSession + + override fun areEqualTypeConstructors(c1: TypeConstructorMarker, c2: TypeConstructorMarker): Boolean { + if (c1 !is ConeClassifierLookupTag || c2 !is ConeClassifierLookupTag) { + return c1 == c2 + } + return isExpectedClassAndActualTypeAlias(c1, c2) || + isExpectedClassAndActualTypeAlias(c2, c1) || + c1 == c2 + } + + // For example, expectedTypeConstructor may be the expected class kotlin.text.StringBuilder, while actualTypeConstructor + // is java.lang.StringBuilder. For the purposes of type compatibility checking, we must consider these types equal here. + // Note that the case of an "actual class" works as expected though, because the actual class by definition has the same FQ name + // as the corresponding expected class, so their type constructors are equal as per AbstractClassTypeConstructor#equals + private fun isExpectedClassAndActualTypeAlias( + expectLookupTag: ConeClassifierLookupTag, + actualLookupTag: ConeClassifierLookupTag + ): Boolean { + val expectDeclaration = expectLookupTag.toClassLikeDeclaration(expectSession) ?: return false + val actualDeclaration = actualLookupTag.toClassLikeDeclaration(actualSession) ?: return false + + if (!expectDeclaration.isExpect) return false + val expectClassId = when (expectDeclaration) { + is FirRegularClassSymbol -> expectDeclaration.classId + is FirTypeAliasSymbol -> expectDeclaration.resolvedExpandedTypeRef.coneType.classId + else -> null + } ?: return false + return expectClassId == actualDeclaration.classId + } + + private fun ConeClassifierLookupTag.toClassLikeDeclaration(session: FirSession): FirClassLikeSymbol<*>? { + return this.toSymbol(session) as? FirClassLikeSymbol<*> + } + } + + private fun List.toTypeList(substitutor: ConeSubstitutor): List { + return this.map { substitutor.substituteOrSelf(it.resolvedReturnTypeRef.coneType) } + } + + private val FirCallableSymbol<*>.valueParameterSymbols: List + get() = (this as? FirFunctionSymbol<*>)?.valueParameterSymbols ?: emptyList() + + private inline fun equalsBy(first: List, second: List, selector: (T) -> K): Boolean { + for (i in first.indices) { + if (selector(first[i]) != selector(second[i])) return false + } + + return true + } + + private inline fun equalBy(first: T, second: T, selector: (T) -> K): Boolean = + selector(first) == selector(second) + + private fun FirClassSymbol<*>.getMembers( + scopeSession: ScopeSession, + session: FirSession = moduleData.session + ): Collection> { + val scope = defaultType().scope(useSiteSession = session, scopeSession, FakeOverrideTypeCalculator.DoNothing) + ?: return emptyList() + return mutableListOf>().apply { + for (name in scope.getCallableNames()) { + scope.getMembersTo(this, name) + } + for (name in declarationSymbols.mapNotNull { (it as? FirRegularClassSymbol)?.classId?.shortClassName }) { + addIfNotNull(scope.getSingleClassifier(name) as? FirRegularClassSymbol) + } + getConstructorsTo(this, scope) + } + } + + private fun FirClassSymbol<*>.getConstructors( + scopeSession: ScopeSession, + session: FirSession = moduleData.session + ): Collection { + return mutableListOf().apply { + getConstructorsTo(this, unsubstitutedScope(session, scopeSession, withForcedTypeCalculator = false)) + } + } + + private fun getConstructorsTo(destination: MutableList, scope: FirTypeScope) { + scope.getDeclaredConstructors().mapTo(destination) { it } + } + + private fun FirClassSymbol<*>.getMembers(name: Name, scopeSession: ScopeSession): Collection> { + val scope = defaultType().scope(useSiteSession = moduleData.session, scopeSession, FakeOverrideTypeCalculator.DoNothing) + ?: return emptyList() + return mutableListOf>().apply { + scope.getMembersTo(this, name) + } + } + + @OptIn(ExperimentalStdlibApi::class) + private fun FirTypeScope.getMembersTo( + destination: MutableList>, + name: Name, + ) { + processFunctionsByName(name) { destination.add(it) } + processPropertiesByName(name) { destination.add(it) } + } + + private val FirBasedSymbol<*>.name: Name + get() = when (this) { + is FirCallableSymbol<*> -> name + is FirRegularClassSymbol -> classId.shortClassName + else -> error("Should not be here") + } +} diff --git a/compiler/fir/checkers/src/org/jetbrains/kotlin/fir/analysis/diagnostics/FirDefaultErrorMessages.kt b/compiler/fir/checkers/src/org/jetbrains/kotlin/fir/analysis/diagnostics/FirDefaultErrorMessages.kt index aadd39e773a..b8a2a8753a1 100644 --- a/compiler/fir/checkers/src/org/jetbrains/kotlin/fir/analysis/diagnostics/FirDefaultErrorMessages.kt +++ b/compiler/fir/checkers/src/org/jetbrains/kotlin/fir/analysis/diagnostics/FirDefaultErrorMessages.kt @@ -13,6 +13,8 @@ import org.jetbrains.kotlin.fir.analysis.diagnostics.FirDiagnosticRenderers.AMBI import org.jetbrains.kotlin.fir.analysis.diagnostics.FirDiagnosticRenderers.DECLARATION_NAME import org.jetbrains.kotlin.fir.analysis.diagnostics.FirDiagnosticRenderers.FIR import org.jetbrains.kotlin.fir.analysis.diagnostics.FirDiagnosticRenderers.FQ_NAMES_IN_TYPES +import org.jetbrains.kotlin.fir.analysis.diagnostics.FirDiagnosticRenderers.COLLECTION +import org.jetbrains.kotlin.fir.analysis.diagnostics.FirDiagnosticRenderers.MODULE_DATA import org.jetbrains.kotlin.fir.analysis.diagnostics.FirDiagnosticRenderers.FUNCTION_PARAMETERS import org.jetbrains.kotlin.fir.analysis.diagnostics.FirDiagnosticRenderers.NOT_RENDERED import org.jetbrains.kotlin.fir.analysis.diagnostics.FirDiagnosticRenderers.NULLABLE_STRING @@ -38,6 +40,16 @@ import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors.ABSTRACT_PROPERTY import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors.ABSTRACT_PROPERTY_WITH_SETTER import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors.ABSTRACT_SUPER_CALL import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors.ACCESSOR_FOR_DELEGATED_PROPERTY +import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors.ACTUAL_ANNOTATION_CONFLICTING_DEFAULT_ARGUMENT_VALUE +import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors.ACTUAL_FUNCTION_WITH_DEFAULT_ARGUMENTS +import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors.ACTUAL_MISSING +import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors.ACTUAL_TYPE_ALIAS_NOT_TO_CLASS +import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors.ACTUAL_TYPE_ALIAS_TO_CLASS_WITH_DECLARATION_SITE_VARIANCE +import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors.ACTUAL_TYPE_ALIAS_WITH_COMPLEX_SUBSTITUTION +import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors.ACTUAL_TYPE_ALIAS_WITH_USE_SITE_VARIANCE +import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors.ACTUAL_WITHOUT_EXPECT +import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors.AMBIGUOUS_ACTUALS +import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors.AMBIGUOUS_EXPECTS import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors.ANNOTATION_ARGUMENT_MUST_BE_CONST import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors.ANNOTATION_CLASS_CONSTRUCTOR_CALL import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors.ANNOTATION_CLASS_MEMBER @@ -124,9 +136,14 @@ import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors.EQUALITY_NOT_APPL import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors.ERROR_FROM_JAVA_RESOLUTION import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors.ERROR_IN_CONTRACT_DESCRIPTION import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors.EXPANDED_TYPE_CANNOT_BE_INHERITED +import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors.EXPECTED_CLASS_CONSTRUCTOR_DELEGATION_CALL +import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors.EXPECTED_CLASS_CONSTRUCTOR_PROPERTY_PARAMETER import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors.EXPECTED_CONDITION import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors.EXPECTED_DECLARATION_WITH_BODY import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors.EXPECTED_DELEGATED_PROPERTY +import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors.EXPECTED_ENUM_CONSTRUCTOR +import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors.EXPECTED_ENUM_ENTRY_WITH_BODY +import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors.EXPECTED_FUNCTION_SOURCE_WITH_DEFAULT_ARGUMENTS_NOT_FOUND import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors.EXPECTED_LATEINIT_PROPERTY import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors.EXPECTED_PRIVATE_DECLARATION import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors.EXPECTED_PROPERTY_INITIALIZER @@ -171,6 +188,7 @@ import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors.ILLEGAL_CONST_EXP import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors.ILLEGAL_KOTLIN_VERSION_STRING_VALUE import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors.ILLEGAL_SELECTOR import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors.ILLEGAL_UNDERSCORE +import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors.IMPLEMENTATION_BY_DELEGATION_IN_EXPECT_CLASS import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors.INAPPLICABLE_CANDIDATE import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors.INAPPLICABLE_FILE_TARGET import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors.INAPPLICABLE_INFIX_MODIFIER @@ -244,6 +262,8 @@ import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors.NOT_A_LOOP_LABEL import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors.NOT_A_SUPERTYPE import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors.NOT_NULL_ASSERTION_ON_CALLABLE_REFERENCE import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors.NOT_NULL_ASSERTION_ON_LAMBDA_EXPRESSION +import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors.NO_ACTUAL_CLASS_MEMBER_FOR_EXPECTED_CLASS +import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors.NO_ACTUAL_FOR_EXPECT import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors.NO_COMPANION_OBJECT import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors.NO_ELSE_IN_WHEN import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors.NO_GET_METHOD @@ -321,6 +341,7 @@ import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors.SPREAD_OF_NULLABL import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors.SUPERCLASS_NOT_ACCESSIBLE_FROM_INTERFACE import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors.SUPERTYPES_FOR_ANNOTATION_CLASS import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors.SUPERTYPE_APPEARS_TWICE +import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors.SUPERTYPE_INITIALIZED_IN_EXPECTED_CLASS import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors.SUPERTYPE_INITIALIZED_IN_INTERFACE import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors.SUPERTYPE_INITIALIZED_WITHOUT_PRIMARY_CONSTRUCTOR import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors.SUPERTYPE_IS_EXTENSION_FUNCTION_TYPE @@ -1134,10 +1155,30 @@ class FirDefaultErrorMessages { // Multi-platform projects map.put(EXPECTED_DECLARATION_WITH_BODY, "Expected declaration must not have a body") + map.put(EXPECTED_CLASS_CONSTRUCTOR_DELEGATION_CALL, "Explicit delegation call for constructor of an expected class is not allowed") + map.put(EXPECTED_CLASS_CONSTRUCTOR_PROPERTY_PARAMETER, "Expected class constructor cannot have a property parameter") + map.put(EXPECTED_ENUM_CONSTRUCTOR, "Expected enum class cannot have a constructor") + map.put(EXPECTED_ENUM_ENTRY_WITH_BODY, "Expected enum entry cannot have a body") map.put(EXPECTED_PROPERTY_INITIALIZER, "Expected property cannot have an initializer") map.put(EXPECTED_DELEGATED_PROPERTY, "Expected property cannot be delegated") - map.put(EXPECTED_PRIVATE_DECLARATION, "Expected declaration cannot be private") map.put(EXPECTED_LATEINIT_PROPERTY, "Expected property cannot be lateinit") + map.put(EXPECTED_PRIVATE_DECLARATION, "Expected declaration cannot be private") + map.put(SUPERTYPE_INITIALIZED_IN_EXPECTED_CLASS, "Expected classes cannot initialize supertypes") + map.put(EXPECTED_PRIVATE_DECLARATION, "Expected declaration cannot be private") + map.put(IMPLEMENTATION_BY_DELEGATION_IN_EXPECT_CLASS, "Implementation by delegation in expected classes is prohibited") + map.put(ACTUAL_TYPE_ALIAS_NOT_TO_CLASS, "Right-hand side of actual type alias should be a class, not another type alias") + map.put(ACTUAL_TYPE_ALIAS_TO_CLASS_WITH_DECLARATION_SITE_VARIANCE, "Aliased class should not have type parameters with declaration-site variance") + map.put(ACTUAL_TYPE_ALIAS_WITH_USE_SITE_VARIANCE, "Right-hand side of actual type alias cannot contain use-site variance or star projections") + map.put(ACTUAL_TYPE_ALIAS_WITH_COMPLEX_SUBSTITUTION, "Type arguments in the right-hand side of actual type alias should be its type parameters in the same order, e.g. 'actual typealias Foo = Bar'") + map.put(ACTUAL_FUNCTION_WITH_DEFAULT_ARGUMENTS, "Actual function cannot have default argument values, they should be declared in the expected function") + map.put(ACTUAL_ANNOTATION_CONFLICTING_DEFAULT_ARGUMENT_VALUE, "Parameter ''{0}'' has conflicting values in the expected and actual annotation", SYMBOL) + map.put(EXPECTED_FUNCTION_SOURCE_WITH_DEFAULT_ARGUMENTS_NOT_FOUND, "Expected function source is not found, therefore it's impossible to generate default argument values declared there. Please add the corresponding file to compilation sources") + map.put(NO_ACTUAL_FOR_EXPECT, "Expected {0} has no actual declaration in module {1}{2}", SYMBOL, MODULE_DATA, FirPlatformIncompatibilityDiagnosticRenderer.TEXT) + map.put(ACTUAL_WITHOUT_EXPECT, "{0} has no corresponding expected declaration{1}", SYMBOL, FirPlatformIncompatibilityDiagnosticRenderer.TEXT) + map.put(AMBIGUOUS_ACTUALS, "{0} has several compatible actual declarations in modules {1}", SYMBOL, SYMBOLS) + map.put(AMBIGUOUS_EXPECTS, "{0} has several compatible expect declarations in modules {1}", SYMBOL, COLLECTION(MODULE_DATA)) + map.put(NO_ACTUAL_CLASS_MEMBER_FOR_EXPECTED_CLASS, "Actual class ''{0}'' has no corresponding members for expected class members:{1}", SYMBOL, FirIncompatibleExpectedActualClassScopesRenderer.TEXT) + map.put(ACTUAL_MISSING, "Declaration must be marked with 'actual'") // Destructuring declaration map.put(INITIALIZER_REQUIRED_FOR_DESTRUCTURING_DECLARATION, "Initializer required for destructuring declaration") diff --git a/compiler/fir/checkers/src/org/jetbrains/kotlin/fir/analysis/diagnostics/FirDiagnosticRenderers.kt b/compiler/fir/checkers/src/org/jetbrains/kotlin/fir/analysis/diagnostics/FirDiagnosticRenderers.kt index 97094359202..6a95fc363bd 100644 --- a/compiler/fir/checkers/src/org/jetbrains/kotlin/fir/analysis/diagnostics/FirDiagnosticRenderers.kt +++ b/compiler/fir/checkers/src/org/jetbrains/kotlin/fir/analysis/diagnostics/FirDiagnosticRenderers.kt @@ -8,8 +8,10 @@ package org.jetbrains.kotlin.fir.analysis.diagnostics import org.jetbrains.kotlin.descriptors.ClassKind import org.jetbrains.kotlin.descriptors.Visibility import org.jetbrains.kotlin.diagnostics.WhenMissingCase +import org.jetbrains.kotlin.diagnostics.rendering.ContextIndependentParameterRenderer import org.jetbrains.kotlin.diagnostics.rendering.Renderer import org.jetbrains.kotlin.fir.FirElement +import org.jetbrains.kotlin.fir.FirModuleData import org.jetbrains.kotlin.fir.FirRenderer import org.jetbrains.kotlin.fir.declarations.* import org.jetbrains.kotlin.fir.declarations.utils.* @@ -34,11 +36,7 @@ object FirDiagnosticRenderers { } } - val SYMBOLS = Renderer { symbols: Collection> -> - symbols.joinToString(prefix = "[", postfix = "]", separator = ", ", limit = 3, truncated = "...") { symbol -> - SYMBOL.render(symbol) - } - } + val SYMBOLS = COLLECTION(SYMBOL) val RENDER_COLLECTION_OF_TYPES = Renderer { types: Collection -> types.joinToString(separator = ", ") { type -> @@ -133,4 +131,17 @@ object FirDiagnosticRenderers { } val FUNCTION_PARAMETERS = Renderer { hasValueParameters: Boolean -> if (hasValueParameters) "..." else "" } + + val MODULE_DATA = Renderer { + "Module ${it.name}" + } + + @Suppress("FunctionName") + fun COLLECTION(renderer: ContextIndependentParameterRenderer): ContextIndependentParameterRenderer> { + return Renderer { list -> + list.joinToString(prefix = "[", postfix = "]", separator = ", ", limit = 3, truncated = "...") { + renderer.render(it) + } + } + } } diff --git a/compiler/fir/checkers/src/org/jetbrains/kotlin/fir/analysis/diagnostics/FirPlatformIncompatibilityDiagnosticRenderer.kt b/compiler/fir/checkers/src/org/jetbrains/kotlin/fir/analysis/diagnostics/FirPlatformIncompatibilityDiagnosticRenderer.kt new file mode 100644 index 00000000000..8b09ad5ce90 --- /dev/null +++ b/compiler/fir/checkers/src/org/jetbrains/kotlin/fir/analysis/diagnostics/FirPlatformIncompatibilityDiagnosticRenderer.kt @@ -0,0 +1,128 @@ +/* + * Copyright 2010-2016 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. + */ + +package org.jetbrains.kotlin.fir.analysis.diagnostics + +import org.jetbrains.kotlin.diagnostics.rendering.ContextIndependentParameterRenderer +import org.jetbrains.kotlin.fir.symbols.FirBasedSymbol +import org.jetbrains.kotlin.resolve.multiplatform.ExpectActualCompatibility.Incompatible + +class FirPlatformIncompatibilityDiagnosticRenderer( + private val mode: MultiplatformDiagnosticRenderingMode +) : ContextIndependentParameterRenderer>, Collection>>> { + override fun render( + obj: Map>, Collection>>, + ): String { + if (obj.isEmpty()) return "" + + return buildString { + mode.newLine(this) + renderIncompatibilityInformation(obj, "", mode) + } + } + + companion object { + @JvmField + val TEXT = FirPlatformIncompatibilityDiagnosticRenderer(MultiplatformDiagnosticRenderingMode()) + } +} + +class FirIncompatibleExpectedActualClassScopesRenderer( + private val mode: MultiplatformDiagnosticRenderingMode +) : ContextIndependentParameterRenderer, Map>, Collection>>>>> { + override fun render( + obj: List, Map>, Collection>>>> + ): String { + if (obj.isEmpty()) return "" + + return buildString { + mode.newLine(this) + renderIncompatibleClassScopes(obj, "", mode) + } + } + + companion object { + @JvmField + val TEXT = FirIncompatibleExpectedActualClassScopesRenderer(MultiplatformDiagnosticRenderingMode()) + } +} + +open class MultiplatformDiagnosticRenderingMode { + open fun newLine(sb: StringBuilder) { + sb.appendLine() + } + + open fun renderList(sb: StringBuilder, elements: List<() -> Unit>) { + sb.appendLine() + for (element in elements) { + element() + } + } + + open fun renderSymbol(sb: StringBuilder, symbol: FirBasedSymbol<*>, indent: String) { + sb.append(indent) + sb.append(INDENTATION_UNIT) + sb.appendLine(FirDiagnosticRenderers.SYMBOL.render(symbol)) + } +} + +private fun StringBuilder.renderIncompatibilityInformation( + map: Map>, Collection>>, + indent: String, + mode: MultiplatformDiagnosticRenderingMode +) { + for ((incompatibility, descriptors) in map) { + append(indent) + append("The following declaration") + if (descriptors.size == 1) append(" is") else append("s are") + append(" incompatible") + incompatibility.reason?.let { append(" because $it") } + append(":") + + mode.renderList(this, descriptors.map { descriptor -> + { mode.renderSymbol(this, descriptor, indent) } + }) + + if (incompatibility is Incompatible.ClassScopes) { + append(indent) + append("No actual members are found for expected members listed below:") + mode.newLine(this) + renderIncompatibleClassScopes(incompatibility.unfulfilled, indent, mode) + } + } +} + +private fun StringBuilder.renderIncompatibleClassScopes( + unfulfilled: List, Map>, Collection>>>>, + indent: String, + mode: MultiplatformDiagnosticRenderingMode +) { + mode.renderList(this, unfulfilled.indices.map { index -> + { + val (descriptor, mapping) = unfulfilled[index] + mode.renderSymbol(this, descriptor, indent) + if (mapping.isNotEmpty()) { + mode.newLine(this) + renderIncompatibilityInformation(mapping, indent + INDENTATION_UNIT, mode) + } + if (index != unfulfilled.lastIndex) { + mode.newLine(this) + } + } + }) +} + +private const val INDENTATION_UNIT = " " diff --git a/compiler/fir/checkers/src/org/jetbrains/kotlin/fir/analysis/diagnostics/SourceElementPositioningStrategies.kt b/compiler/fir/checkers/src/org/jetbrains/kotlin/fir/analysis/diagnostics/SourceElementPositioningStrategies.kt index 0a437dcd6ff..80de9f41df6 100644 --- a/compiler/fir/checkers/src/org/jetbrains/kotlin/fir/analysis/diagnostics/SourceElementPositioningStrategies.kt +++ b/compiler/fir/checkers/src/org/jetbrains/kotlin/fir/analysis/diagnostics/SourceElementPositioningStrategies.kt @@ -272,4 +272,8 @@ object SourceElementPositioningStrategies { LightTreePositioningStrategies.DECLARATION_WITH_BODY, PositioningStrategies.DECLARATION_WITH_BODY ) + + // TODO + val ACTUAL_DECLARATION_NAME = DEFAULT + val INCOMPATIBLE_DECLARATION = DEFAULT } diff --git a/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/ScopeUtils.kt b/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/ScopeUtils.kt index a49af0477ef..ba8f9bc5170 100644 --- a/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/ScopeUtils.kt +++ b/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/ScopeUtils.kt @@ -21,6 +21,7 @@ import org.jetbrains.kotlin.fir.scopes.impl.FirStandardOverrideChecker import org.jetbrains.kotlin.fir.scopes.impl.FirTypeIntersectionScope import org.jetbrains.kotlin.fir.scopes.scopeForClass import org.jetbrains.kotlin.fir.symbols.impl.ConeClassLikeLookupTagImpl +import org.jetbrains.kotlin.fir.symbols.impl.FirClassSymbol import org.jetbrains.kotlin.fir.symbols.impl.FirTypeParameterSymbol import org.jetbrains.kotlin.fir.typeContext import org.jetbrains.kotlin.fir.types.* @@ -95,6 +96,7 @@ private fun ConeKotlinType.scope(useSiteSession: FirSession, scopeSession: Scope } } +fun FirClassSymbol<*>.defaultType(): ConeClassLikeType = fir.defaultType() fun FirClass.defaultType(): ConeClassLikeType = when (this) { diff --git a/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/scopes/impl/FirPackageMemberScope.kt b/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/scopes/impl/FirPackageMemberScope.kt index d99f678cd1a..3775c6c4fed 100644 --- a/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/scopes/impl/FirPackageMemberScope.kt +++ b/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/scopes/impl/FirPackageMemberScope.kt @@ -6,6 +6,7 @@ package org.jetbrains.kotlin.fir.scopes.impl import org.jetbrains.kotlin.fir.FirSession +import org.jetbrains.kotlin.fir.resolve.providers.FirSymbolProvider import org.jetbrains.kotlin.fir.resolve.symbolProvider import org.jetbrains.kotlin.fir.resolve.substitution.ConeSubstitutor import org.jetbrains.kotlin.fir.resolve.transformers.ensureResolvedForCalls @@ -19,8 +20,11 @@ import org.jetbrains.kotlin.name.FqName import org.jetbrains.kotlin.name.Name import org.jetbrains.kotlin.utils.SmartList -class FirPackageMemberScope(val fqName: FqName, val session: FirSession) : FirScope() { - private val symbolProvider = session.symbolProvider +class FirPackageMemberScope( + val fqName: FqName, + val session: FirSession, + private val symbolProvider: FirSymbolProvider = session.symbolProvider +) : FirScope() { private val classifierCache: MutableMap?> = mutableMapOf() private val functionCache: MutableMap> = mutableMapOf() private val propertyCache: MutableMap> = mutableMapOf() diff --git a/compiler/fir/tree/src/org/jetbrains/kotlin/fir/declarations/utils/FirSymbolStatusUtils.kt b/compiler/fir/tree/src/org/jetbrains/kotlin/fir/declarations/utils/FirSymbolStatusUtils.kt index fdc48860c05..8faf6ceefbb 100644 --- a/compiler/fir/tree/src/org/jetbrains/kotlin/fir/declarations/utils/FirSymbolStatusUtils.kt +++ b/compiler/fir/tree/src/org/jetbrains/kotlin/fir/declarations/utils/FirSymbolStatusUtils.kt @@ -107,6 +107,20 @@ inline val FirClassLikeSymbol<*>.isLocal: Boolean get() = classId.isLocal inline val FirClassSymbol<*>.isLocalClassOrAnonymousObject: Boolean get() = classId.isLocal || this is FirAnonymousObjectSymbol +inline val FirClassLikeSymbol<*>.isExpect: Boolean + get() = when (this) { + is FirRegularClassSymbol -> isExpect + is FirTypeAliasSymbol -> isExpect + else -> false + } + +inline val FirClassLikeSymbol<*>.isActual: Boolean + get() = when (this) { + is FirRegularClassSymbol -> isActual + is FirTypeAliasSymbol -> isActual + else -> false + } + inline val FirClassSymbol<*>.isInterface: Boolean get() = classKind.isInterface diff --git a/compiler/resolution.common/src/org/jetbrains/kotlin/types/AbstractTypeApproximator.kt b/compiler/resolution.common/src/org/jetbrains/kotlin/types/AbstractTypeApproximator.kt index 156fe9beb1d..9a94420093b 100644 --- a/compiler/resolution.common/src/org/jetbrains/kotlin/types/AbstractTypeApproximator.kt +++ b/compiler/resolution.common/src/org/jetbrains/kotlin/types/AbstractTypeApproximator.kt @@ -568,4 +568,10 @@ abstract class AbstractTypeApproximator( // Nothing or Nothing! private fun KotlinTypeMarker.isTrivialSub() = lowerBoundIfFlexible().isNothing() + + override fun CapturedTypeMarker.typeParameter(): TypeParameterMarker? { + with(ctx) { + return typeParameter() + } + } } diff --git a/compiler/testData/diagnostics/tests/modifiers/openInExpectInterface.fir.kt b/compiler/testData/diagnostics/tests/modifiers/openInExpectInterface.fir.kt index 1957883d6de..a92c510d027 100644 --- a/compiler/testData/diagnostics/tests/modifiers/openInExpectInterface.fir.kt +++ b/compiler/testData/diagnostics/tests/modifiers/openInExpectInterface.fir.kt @@ -30,7 +30,7 @@ class MyImpl2: My { expect interface Outer { interface Inner { open fun bar() - open fun bas() {} + open fun bas() {} open abstract fun bat(): Int fun foo() } diff --git a/compiler/testData/diagnostics/tests/multiplatform/enum/enumEntryWithBody.fir.kt b/compiler/testData/diagnostics/tests/multiplatform/enum/enumEntryWithBody.fir.kt index 0e3986250ee..c2a35bfb500 100644 --- a/compiler/testData/diagnostics/tests/multiplatform/enum/enumEntryWithBody.fir.kt +++ b/compiler/testData/diagnostics/tests/multiplatform/enum/enumEntryWithBody.fir.kt @@ -5,7 +5,7 @@ expect enum class En { E1, E2 { - fun foo() = "" + fun foo() = "" }, E3 { }; } diff --git a/compiler/testData/diagnostics/tests/multiplatform/expectInterfaceApplicability.fir.kt b/compiler/testData/diagnostics/tests/multiplatform/expectInterfaceApplicability.fir.kt index d98211adfd1..66ca3c86597 100644 --- a/compiler/testData/diagnostics/tests/multiplatform/expectInterfaceApplicability.fir.kt +++ b/compiler/testData/diagnostics/tests/multiplatform/expectInterfaceApplicability.fir.kt @@ -16,10 +16,10 @@ expect interface My { // FILE: jvm.kt actual interface My { actual fun openFunPositive() = Unit - actual fun openFunNegative() + actual fun openFunNegative() actual fun abstractFun() actual val openValPositive: Int get() = 0 - actual val openValNegative: Int + actual val openValNegative: Int actual val abstractVal: Int } diff --git a/compiler/testData/diagnostics/tests/multiplatform/headerClass/actualClassWithDefaultValuesInAnnotationViaTypealias.fir.kt b/compiler/testData/diagnostics/tests/multiplatform/headerClass/actualClassWithDefaultValuesInAnnotationViaTypealias.fir.kt index 3157b28af6b..b61579ea250 100644 --- a/compiler/testData/diagnostics/tests/multiplatform/headerClass/actualClassWithDefaultValuesInAnnotationViaTypealias.fir.kt +++ b/compiler/testData/diagnostics/tests/multiplatform/headerClass/actualClassWithDefaultValuesInAnnotationViaTypealias.fir.kt @@ -10,7 +10,7 @@ expect annotation class Foo5() expect annotation class Foo6() expect annotation class Foo7() -@Foo1 +@Foo1 fun foo() {} @Foo5 @@ -45,4 +45,4 @@ actual annotation class Foo5 actual annotation class Foo6(val s: String = "value") -actual typealias Foo7 = Bar2 +actual typealias Foo7 = Bar2 diff --git a/compiler/testData/diagnostics/tests/multiplatform/headerClass/actualClassWithDifferentConstructors.fir.kt b/compiler/testData/diagnostics/tests/multiplatform/headerClass/actualClassWithDifferentConstructors.fir.kt index 8d52588efd7..3affe50a99f 100644 --- a/compiler/testData/diagnostics/tests/multiplatform/headerClass/actualClassWithDifferentConstructors.fir.kt +++ b/compiler/testData/diagnostics/tests/multiplatform/headerClass/actualClassWithDifferentConstructors.fir.kt @@ -34,9 +34,9 @@ actual class Foo1(val s: String) actual class Foo2(val p: String = "value", i: Int) actual typealias Foo3 = JavaFoo -actual class Bar1(val s: String) -actual class Bar2(val p: String = "value", i: Int) -actual typealias Bar3 = JavaBar +actual class Bar1(val s: String) +actual class Bar2(val p: String = "value", i: Int) +actual typealias Bar3 = JavaBar actual class Bar4(val s: String) { constructor() : this("") } diff --git a/compiler/testData/diagnostics/tests/multiplatform/headerClass/baseExpectClassWithoutConstructor.fir.kt b/compiler/testData/diagnostics/tests/multiplatform/headerClass/baseExpectClassWithoutConstructor.fir.kt index 59ded755697..5a849c42c94 100644 --- a/compiler/testData/diagnostics/tests/multiplatform/headerClass/baseExpectClassWithoutConstructor.fir.kt +++ b/compiler/testData/diagnostics/tests/multiplatform/headerClass/baseExpectClassWithoutConstructor.fir.kt @@ -4,7 +4,7 @@ expect open class A expect class B : A -open class C : A +open class C : A // MODULE: m1-jvm()()(m1-common) // FILE: jvm.kt diff --git a/compiler/testData/diagnostics/tests/multiplatform/headerClass/expectClassWithoutConstructor.fir.kt b/compiler/testData/diagnostics/tests/multiplatform/headerClass/expectClassWithoutConstructor.fir.kt index a547ba440ae..efe285ac1af 100644 --- a/compiler/testData/diagnostics/tests/multiplatform/headerClass/expectClassWithoutConstructor.fir.kt +++ b/compiler/testData/diagnostics/tests/multiplatform/headerClass/expectClassWithoutConstructor.fir.kt @@ -10,7 +10,7 @@ expect class FooBar { } fun test() { - Foo() + Foo() Bar() Baz() FooBar() diff --git a/compiler/testData/diagnostics/tests/multiplatform/headerClass/expectDeclarationWithStrongIncompatibilities.fir.kt b/compiler/testData/diagnostics/tests/multiplatform/headerClass/expectDeclarationWithStrongIncompatibilities.fir.kt index 38e62017325..e8ea7de0c4d 100644 --- a/compiler/testData/diagnostics/tests/multiplatform/headerClass/expectDeclarationWithStrongIncompatibilities.fir.kt +++ b/compiler/testData/diagnostics/tests/multiplatform/headerClass/expectDeclarationWithStrongIncompatibilities.fir.kt @@ -23,11 +23,11 @@ fun foo1(x: String) {} fun foo2(x: Int, y: Int) {} fun foo2(x: String) {} -actual fun foo3(): String = "" +actual fun foo3(): String = "" fun foo4(x: Int): String = "" actual class NoArgConstructor { actual constructor() - actual constructor(x: Int) + actual constructor(x: Int) constructor(x: String) } diff --git a/compiler/testData/diagnostics/tests/multiplatform/headerClass/expectDeclarationWithWeakIncompatibilities.fir.kt b/compiler/testData/diagnostics/tests/multiplatform/headerClass/expectDeclarationWithWeakIncompatibilities.fir.kt index 1e69f28d2b1..04562c0e29e 100644 --- a/compiler/testData/diagnostics/tests/multiplatform/headerClass/expectDeclarationWithWeakIncompatibilities.fir.kt +++ b/compiler/testData/diagnostics/tests/multiplatform/headerClass/expectDeclarationWithWeakIncompatibilities.fir.kt @@ -17,12 +17,12 @@ expect open class Foo3 // FILE: jvm.kt interface Foo1 -actual interface Foo2 +actual interface Foo2 -actual var s: String = "value" +actual var s: String = "value" fun foo2(): Int = 0 -actual class Foo3 +actual class Foo3 class Foo3 diff --git a/compiler/testData/diagnostics/tests/multiplatform/headerClass/morePermissiveVisibilityOnActual.fir.kt b/compiler/testData/diagnostics/tests/multiplatform/headerClass/morePermissiveVisibilityOnActual.fir.kt index 256d471e411..d910ce8f090 100644 --- a/compiler/testData/diagnostics/tests/multiplatform/headerClass/morePermissiveVisibilityOnActual.fir.kt +++ b/compiler/testData/diagnostics/tests/multiplatform/headerClass/morePermissiveVisibilityOnActual.fir.kt @@ -31,9 +31,9 @@ actual open class Container { actual fun protectedFun1() {} // OK: protected -> public actual protected fun protectedFun2() {} // OK: protected -> protected - actual internal fun protectedFun3() {} // BAD: protected -> internal - actual protected fun internalFun3() {} // BAD: internal -> protected + actual internal fun protectedFun3() {} // BAD: protected -> internal + actual protected fun internalFun3() {} // BAD: internal -> protected - actual open fun openInternalFun() {} // BAD: internal+open -> public - actual internal fun openPublicFun() {} // BAD: open+public -> internal + actual open fun openInternalFun() {} // BAD: internal+open -> public + actual internal fun openPublicFun() {} // BAD: open+public -> internal } diff --git a/compiler/testData/diagnostics/tests/multiplatform/headerClass/nestedClassesWithErrors.fir.kt b/compiler/testData/diagnostics/tests/multiplatform/headerClass/nestedClassesWithErrors.fir.kt index 703eaa28ad0..5431aebb3bf 100644 --- a/compiler/testData/diagnostics/tests/multiplatform/headerClass/nestedClassesWithErrors.fir.kt +++ b/compiler/testData/diagnostics/tests/multiplatform/headerClass/nestedClassesWithErrors.fir.kt @@ -4,7 +4,7 @@ expect class B { class N { - fun body() {} + fun body() {} expect fun extraHeader() } } @@ -39,7 +39,7 @@ actual class C { actual inner class I } -actual class D +actual class D actual class E { class N diff --git a/compiler/testData/diagnostics/tests/multiplatform/headerClass/superClass.fir.kt b/compiler/testData/diagnostics/tests/multiplatform/headerClass/superClass.fir.kt index 585e6581411..ff212e1f801 100644 --- a/compiler/testData/diagnostics/tests/multiplatform/headerClass/superClass.fir.kt +++ b/compiler/testData/diagnostics/tests/multiplatform/headerClass/superClass.fir.kt @@ -8,13 +8,13 @@ interface J expect class Foo : I, C, J -expect class Bar : C() +expect class Bar : C() // MODULE: m2-jvm()()(m1-common) // FILE: jvm.kt actual class Foo : I, C(), J -actual class Bar +actual class Bar // MODULE: m3-js()()(m1-common) // FILE: js.kt diff --git a/compiler/testData/diagnostics/tests/multiplatform/hmpp/sealedInheritorsInComplexModuleStructure.fir.kt b/compiler/testData/diagnostics/tests/multiplatform/hmpp/sealedInheritorsInComplexModuleStructure.fir.kt index a9136fe9824..1de8c07d0d6 100644 --- a/compiler/testData/diagnostics/tests/multiplatform/hmpp/sealedInheritorsInComplexModuleStructure.fir.kt +++ b/compiler/testData/diagnostics/tests/multiplatform/hmpp/sealedInheritorsInComplexModuleStructure.fir.kt @@ -13,10 +13,10 @@ expect sealed class SealedWithPlatformActuals : SealedWithSharedActual package foo actual sealed class SealedWithSharedActual -class SimpleShared : SealedWithPlatformActuals() +class SimpleShared : SealedWithPlatformActuals() // MODULE: main()()(intermediate) // TARGET_PLATFORM: JVM package foo -actual sealed class SealedWithPlatformActuals actual constructor(): SealedWithSharedActual() +actual sealed class SealedWithPlatformActuals actual constructor(): SealedWithSharedActual() diff --git a/compiler/testData/diagnostics/tests/multiplatform/implDynamic.fir.kt b/compiler/testData/diagnostics/tests/multiplatform/implDynamic.fir.kt new file mode 100644 index 00000000000..799d38c08d1 --- /dev/null +++ b/compiler/testData/diagnostics/tests/multiplatform/implDynamic.fir.kt @@ -0,0 +1,29 @@ +// !LANGUAGE: +MultiPlatformProjects +// !DIAGNOSTICS: -UNSUPPORTED +// MODULE: m1-common +// FILE: common.kt + +expect class Foo { + constructor(p: Any) + + fun f1(s: String): Int + + fun f2(s: List?): MutableMap + + fun > f3(t: T): T? +} + +// MODULE: m2-js()()(m1-common) +// FILE: js.kt + +// TODO: do not suppress UNSUPPORTED once JS files in multi-platform tests are analyzed with JS analyzer facade + +actual class Foo { + actual constructor(p: dynamic) {} + + actual fun f1(s: dynamic): dynamic = null!! + + actual fun f2(s: dynamic): MutableMap = null!! + + actual fun > f3(t: T): dynamic = null!! +} diff --git a/compiler/testData/diagnostics/tests/multiplatform/implDynamic.kt b/compiler/testData/diagnostics/tests/multiplatform/implDynamic.kt index 895b81496ee..06012e5431e 100644 --- a/compiler/testData/diagnostics/tests/multiplatform/implDynamic.kt +++ b/compiler/testData/diagnostics/tests/multiplatform/implDynamic.kt @@ -1,4 +1,3 @@ -// FIR_IDENTICAL // !LANGUAGE: +MultiPlatformProjects // !DIAGNOSTICS: -UNSUPPORTED // MODULE: m1-common diff --git a/compiler/testData/diagnostics/tests/multiplatform/inlineClasses/expectActualInlineClass.fir.kt b/compiler/testData/diagnostics/tests/multiplatform/inlineClasses/expectActualInlineClass.fir.kt index 32a95b1b683..ed45beb8df1 100644 --- a/compiler/testData/diagnostics/tests/multiplatform/inlineClasses/expectActualInlineClass.fir.kt +++ b/compiler/testData/diagnostics/tests/multiplatform/inlineClasses/expectActualInlineClass.fir.kt @@ -20,9 +20,9 @@ expect inline class NonInlineActual(val x: Int) actual inline class Foo1(val x: Int) { actual fun bar(): String = "Hello" } -actual inline class Foo2(val x: String) +actual inline class Foo2(val x: String) actual inline class Foo3 -actual inline class NonInlineExpect(val x: Int) +actual inline class NonInlineExpect(val x: Int) -actual class NonInlineActual actual constructor(actual val x: Int) +actual class NonInlineActual actual constructor(actual val x: Int) diff --git a/compiler/testData/diagnostics/tests/multiplatform/modifierApplicability.fir.kt b/compiler/testData/diagnostics/tests/multiplatform/modifierApplicability.fir.kt index cbfc524646a..e39ba9469a4 100644 --- a/compiler/testData/diagnostics/tests/multiplatform/modifierApplicability.fir.kt +++ b/compiler/testData/diagnostics/tests/multiplatform/modifierApplicability.fir.kt @@ -22,7 +22,7 @@ fun foo() { // MODULE: m2-jvm // FILE: jvm.kt -class Outer actual constructor() { +class Outer actual constructor() { actual class Nested actual init {} diff --git a/compiler/testData/diagnostics/tests/multiplatform/topLevelFun/headerAndImplInDIfferentPackages.fir.kt b/compiler/testData/diagnostics/tests/multiplatform/topLevelFun/headerAndImplInDIfferentPackages.fir.kt index 302141d41ed..ec334a67cd0 100644 --- a/compiler/testData/diagnostics/tests/multiplatform/topLevelFun/headerAndImplInDIfferentPackages.fir.kt +++ b/compiler/testData/diagnostics/tests/multiplatform/topLevelFun/headerAndImplInDIfferentPackages.fir.kt @@ -9,10 +9,10 @@ expect fun foo() // FILE: jvm.kt package jvm -actual fun foo() {} +actual fun foo() {} // MODULE: m3-js()()(m1-common) // FILE: js.kt package js -actual fun foo() {} +actual fun foo() {} diff --git a/compiler/testData/diagnostics/tests/multiplatform/topLevelFun/implDeclarationWithoutBody.fir.kt b/compiler/testData/diagnostics/tests/multiplatform/topLevelFun/implDeclarationWithoutBody.fir.kt index 8638c4b1309..4aa5dc4d9e5 100644 --- a/compiler/testData/diagnostics/tests/multiplatform/topLevelFun/implDeclarationWithoutBody.fir.kt +++ b/compiler/testData/diagnostics/tests/multiplatform/topLevelFun/implDeclarationWithoutBody.fir.kt @@ -9,4 +9,4 @@ expect fun foo() actual fun foo() -actual fun bar() +actual fun bar() diff --git a/compiler/testData/diagnostics/tests/multiplatform/topLevelFun/implWithoutHeader.fir.kt b/compiler/testData/diagnostics/tests/multiplatform/topLevelFun/implWithoutHeader.fir.kt index fb7e5052f0e..bcad4bd6c2f 100644 --- a/compiler/testData/diagnostics/tests/multiplatform/topLevelFun/implWithoutHeader.fir.kt +++ b/compiler/testData/diagnostics/tests/multiplatform/topLevelFun/implWithoutHeader.fir.kt @@ -2,4 +2,4 @@ // MODULE: m1-jvm // FILE: jvm.kt -actual fun foo() { } +actual fun foo() { } diff --git a/compiler/testData/diagnostics/tests/multiplatform/topLevelFun/inlineFun.fir.kt b/compiler/testData/diagnostics/tests/multiplatform/topLevelFun/inlineFun.fir.kt index 7e18691d4b1..b658c02c41a 100644 --- a/compiler/testData/diagnostics/tests/multiplatform/topLevelFun/inlineFun.fir.kt +++ b/compiler/testData/diagnostics/tests/multiplatform/topLevelFun/inlineFun.fir.kt @@ -8,7 +8,7 @@ expect fun nonInlineFun() // MODULE: m2-jvm()()(m1-common) // FILE: jvm.kt -actual fun inlineFun() { } +actual fun inlineFun() { } actual fun nonInlineFun() { } // MODULE: m3-js()()(m1-common) diff --git a/compiler/testData/diagnostics/tests/multiplatform/topLevelFun/valueParameterModifiers.fir.kt b/compiler/testData/diagnostics/tests/multiplatform/topLevelFun/valueParameterModifiers.fir.kt index 3c7f861d418..b1c7ea1ff53 100644 --- a/compiler/testData/diagnostics/tests/multiplatform/topLevelFun/valueParameterModifiers.fir.kt +++ b/compiler/testData/diagnostics/tests/multiplatform/topLevelFun/valueParameterModifiers.fir.kt @@ -18,10 +18,10 @@ expect fun f8(vararg x: Any) // FILE: jvm.kt actual inline fun f1(noinline s: () -> String) {} -actual inline fun f2(noinline s: () -> String) {} +actual inline fun f2(noinline s: () -> String) {} actual inline fun f3(s: () -> String) {} actual inline fun f4(crossinline s: () -> String) {} -actual inline fun f5(crossinline s: () -> String) {} +actual inline fun f5(crossinline s: () -> String) {} actual inline fun f6(s: () -> String) {} -actual fun f7(vararg x: Any) {} -actual fun f8(x: Any) {} +actual fun f7(vararg x: Any) {} +actual fun f8(x: Any) {} diff --git a/idea/idea-frontend-fir/idea-frontend-fir-generator/build.gradle.kts b/idea/idea-frontend-fir/idea-frontend-fir-generator/build.gradle.kts index a2106197946..d173e0c77ab 100644 --- a/idea/idea-frontend-fir/idea-frontend-fir-generator/build.gradle.kts +++ b/idea/idea-frontend-fir/idea-frontend-fir-generator/build.gradle.kts @@ -5,6 +5,7 @@ plugins { } dependencies { + implementation(project(":compiler:resolution.common")) implementation(project(":compiler:fir:tree")) implementation(project(":compiler:fir:tree:tree-generator")) implementation(project(":compiler:fir:checkers:checkers-component-generator")) diff --git a/idea/idea-frontend-fir/idea-frontend-fir-generator/src/org/jetbrains/kotlin/idea/frontend/api/fir/generator/HLDiagnosticConverter.kt b/idea/idea-frontend-fir/idea-frontend-fir-generator/src/org/jetbrains/kotlin/idea/frontend/api/fir/generator/HLDiagnosticConverter.kt index 595594f0f9b..8ec61cff58c 100644 --- a/idea/idea-frontend-fir/idea-frontend-fir-generator/src/org/jetbrains/kotlin/idea/frontend/api/fir/generator/HLDiagnosticConverter.kt +++ b/idea/idea-frontend-fir/idea-frontend-fir-generator/src/org/jetbrains/kotlin/idea/frontend/api/fir/generator/HLDiagnosticConverter.kt @@ -12,6 +12,7 @@ import org.jetbrains.kotlin.contracts.description.EventOccurrencesRange import org.jetbrains.kotlin.descriptors.EffectiveVisibility import org.jetbrains.kotlin.descriptors.Visibility import org.jetbrains.kotlin.diagnostics.WhenMissingCase +import org.jetbrains.kotlin.fir.FirModuleData import org.jetbrains.kotlin.fir.checkers.generator.diagnostics.model.DiagnosticData import org.jetbrains.kotlin.fir.checkers.generator.diagnostics.model.DiagnosticList import org.jetbrains.kotlin.fir.checkers.generator.diagnostics.model.DiagnosticParameter @@ -30,6 +31,7 @@ import org.jetbrains.kotlin.name.FqName import org.jetbrains.kotlin.name.Name import org.jetbrains.kotlin.psi.KtExpression import org.jetbrains.kotlin.resolve.ForbiddenNamedArgumentsTarget +import org.jetbrains.kotlin.resolve.multiplatform.ExpectActualCompatibility import org.jetbrains.kotlin.types.Variance import kotlin.reflect.KClass import kotlin.reflect.KType @@ -296,6 +298,8 @@ private object FirToKtConversionCreator { LanguageVersionSettings::class, Variance::class, FqName::class, + FirModuleData::class, + ExpectActualCompatibility.Incompatible::class, ) private val KType.kClass: KClass<*> diff --git a/idea/idea-frontend-fir/src/org/jetbrains/kotlin/idea/frontend/api/fir/diagnostics/KtFirDataClassConverters.kt b/idea/idea-frontend-fir/src/org/jetbrains/kotlin/idea/frontend/api/fir/diagnostics/KtFirDataClassConverters.kt index ca5f55ab27d..d8399b61ecb 100644 --- a/idea/idea-frontend-fir/src/org/jetbrains/kotlin/idea/frontend/api/fir/diagnostics/KtFirDataClassConverters.kt +++ b/idea/idea-frontend-fir/src/org/jetbrains/kotlin/idea/frontend/api/fir/diagnostics/KtFirDataClassConverters.kt @@ -26,10 +26,14 @@ import org.jetbrains.kotlin.psi.KtBinaryExpressionWithTypeRHS import org.jetbrains.kotlin.psi.KtCallExpression import org.jetbrains.kotlin.psi.KtClass import org.jetbrains.kotlin.psi.KtClassOrObject +import org.jetbrains.kotlin.psi.KtConstructor +import org.jetbrains.kotlin.psi.KtConstructorDelegationCall import org.jetbrains.kotlin.psi.KtDeclaration import org.jetbrains.kotlin.psi.KtDeclarationWithBody +import org.jetbrains.kotlin.psi.KtDelegatedSuperTypeEntry import org.jetbrains.kotlin.psi.KtDestructuringDeclaration import org.jetbrains.kotlin.psi.KtElement +import org.jetbrains.kotlin.psi.KtEnumEntry import org.jetbrains.kotlin.psi.KtExpression import org.jetbrains.kotlin.psi.KtFunction import org.jetbrains.kotlin.psi.KtIfExpression @@ -2129,12 +2133,6 @@ internal val KT_DIAGNOSTIC_CONVERTER = KtDiagnosticConverterBuilder.buildConvert token, ) } - add(FirErrors.EXPECTED_PRIVATE_DECLARATION) { firDiagnostic -> - ExpectedPrivateDeclarationImpl( - firDiagnostic as FirPsiDiagnostic, - token, - ) - } add(FirErrors.VAL_WITH_SETTER) { firDiagnostic -> ValWithSetterImpl( firDiagnostic as FirPsiDiagnostic, @@ -2232,6 +2230,30 @@ internal val KT_DIAGNOSTIC_CONVERTER = KtDiagnosticConverterBuilder.buildConvert token, ) } + add(FirErrors.EXPECTED_CLASS_CONSTRUCTOR_DELEGATION_CALL) { firDiagnostic -> + ExpectedClassConstructorDelegationCallImpl( + firDiagnostic as FirPsiDiagnostic, + token, + ) + } + add(FirErrors.EXPECTED_CLASS_CONSTRUCTOR_PROPERTY_PARAMETER) { firDiagnostic -> + ExpectedClassConstructorPropertyParameterImpl( + firDiagnostic as FirPsiDiagnostic, + token, + ) + } + add(FirErrors.EXPECTED_ENUM_CONSTRUCTOR) { firDiagnostic -> + ExpectedEnumConstructorImpl( + firDiagnostic as FirPsiDiagnostic, + token, + ) + } + add(FirErrors.EXPECTED_ENUM_ENTRY_WITH_BODY) { firDiagnostic -> + ExpectedEnumEntryWithBodyImpl( + firDiagnostic as FirPsiDiagnostic, + token, + ) + } add(FirErrors.EXPECTED_PROPERTY_INITIALIZER) { firDiagnostic -> ExpectedPropertyInitializerImpl( firDiagnostic as FirPsiDiagnostic, @@ -2250,6 +2272,138 @@ internal val KT_DIAGNOSTIC_CONVERTER = KtDiagnosticConverterBuilder.buildConvert token, ) } + add(FirErrors.SUPERTYPE_INITIALIZED_IN_EXPECTED_CLASS) { firDiagnostic -> + SupertypeInitializedInExpectedClassImpl( + firDiagnostic as FirPsiDiagnostic, + token, + ) + } + add(FirErrors.EXPECTED_PRIVATE_DECLARATION) { firDiagnostic -> + ExpectedPrivateDeclarationImpl( + firDiagnostic as FirPsiDiagnostic, + token, + ) + } + add(FirErrors.IMPLEMENTATION_BY_DELEGATION_IN_EXPECT_CLASS) { firDiagnostic -> + ImplementationByDelegationInExpectClassImpl( + firDiagnostic as FirPsiDiagnostic, + token, + ) + } + add(FirErrors.ACTUAL_TYPE_ALIAS_NOT_TO_CLASS) { firDiagnostic -> + ActualTypeAliasNotToClassImpl( + firDiagnostic as FirPsiDiagnostic, + token, + ) + } + add(FirErrors.ACTUAL_TYPE_ALIAS_TO_CLASS_WITH_DECLARATION_SITE_VARIANCE) { firDiagnostic -> + ActualTypeAliasToClassWithDeclarationSiteVarianceImpl( + firDiagnostic as FirPsiDiagnostic, + token, + ) + } + add(FirErrors.ACTUAL_TYPE_ALIAS_WITH_USE_SITE_VARIANCE) { firDiagnostic -> + ActualTypeAliasWithUseSiteVarianceImpl( + firDiagnostic as FirPsiDiagnostic, + token, + ) + } + add(FirErrors.ACTUAL_TYPE_ALIAS_WITH_COMPLEX_SUBSTITUTION) { firDiagnostic -> + ActualTypeAliasWithComplexSubstitutionImpl( + firDiagnostic as FirPsiDiagnostic, + token, + ) + } + add(FirErrors.ACTUAL_FUNCTION_WITH_DEFAULT_ARGUMENTS) { firDiagnostic -> + ActualFunctionWithDefaultArgumentsImpl( + firDiagnostic as FirPsiDiagnostic, + token, + ) + } + add(FirErrors.ACTUAL_ANNOTATION_CONFLICTING_DEFAULT_ARGUMENT_VALUE) { firDiagnostic -> + ActualAnnotationConflictingDefaultArgumentValueImpl( + firSymbolBuilder.variableLikeBuilder.buildVariableLikeSymbol(firDiagnostic.a.fir), + firDiagnostic as FirPsiDiagnostic, + token, + ) + } + add(FirErrors.EXPECTED_FUNCTION_SOURCE_WITH_DEFAULT_ARGUMENTS_NOT_FOUND) { firDiagnostic -> + ExpectedFunctionSourceWithDefaultArgumentsNotFoundImpl( + firDiagnostic as FirPsiDiagnostic, + token, + ) + } + add(FirErrors.NO_ACTUAL_FOR_EXPECT) { firDiagnostic -> + NoActualForExpectImpl( + firSymbolBuilder.buildSymbol(firDiagnostic.a.fir), + firDiagnostic.b, + firDiagnostic.c.mapKeys { (incompatible, _) -> + incompatible + }.mapValues { (_, collection) -> + collection.map { firBasedSymbol -> + firSymbolBuilder.buildSymbol(firBasedSymbol.fir) + } + }, + firDiagnostic as FirPsiDiagnostic, + token, + ) + } + add(FirErrors.ACTUAL_WITHOUT_EXPECT) { firDiagnostic -> + ActualWithoutExpectImpl( + firSymbolBuilder.buildSymbol(firDiagnostic.a.fir), + firDiagnostic.b.mapKeys { (incompatible, _) -> + incompatible + }.mapValues { (_, collection) -> + collection.map { firBasedSymbol -> + firSymbolBuilder.buildSymbol(firBasedSymbol.fir) + } + }, + firDiagnostic as FirPsiDiagnostic, + token, + ) + } + add(FirErrors.AMBIGUOUS_ACTUALS) { firDiagnostic -> + AmbiguousActualsImpl( + firSymbolBuilder.buildSymbol(firDiagnostic.a.fir), + firDiagnostic.b.map { firBasedSymbol -> + firSymbolBuilder.buildSymbol(firBasedSymbol.fir) + }, + firDiagnostic as FirPsiDiagnostic, + token, + ) + } + add(FirErrors.AMBIGUOUS_EXPECTS) { firDiagnostic -> + AmbiguousExpectsImpl( + firSymbolBuilder.buildSymbol(firDiagnostic.a.fir), + firDiagnostic.b.map { firModuleData -> + firModuleData + }, + firDiagnostic as FirPsiDiagnostic, + token, + ) + } + add(FirErrors.NO_ACTUAL_CLASS_MEMBER_FOR_EXPECTED_CLASS) { firDiagnostic -> + NoActualClassMemberForExpectedClassImpl( + firSymbolBuilder.buildSymbol(firDiagnostic.a.fir), + firDiagnostic.b.map { pair -> + firSymbolBuilder.buildSymbol(pair.first.fir) to pair.second.mapKeys { (incompatible, _) -> + incompatible + }.mapValues { (_, collection) -> + collection.map { firBasedSymbol -> + firSymbolBuilder.buildSymbol(firBasedSymbol.fir) + } + } + }, + firDiagnostic as FirPsiDiagnostic, + token, + ) + } + add(FirErrors.ACTUAL_MISSING) { firDiagnostic -> + ActualMissingImpl( + firDiagnostic as FirPsiDiagnostic, + token, + ) + } add(FirErrors.INITIALIZER_REQUIRED_FOR_DESTRUCTURING_DECLARATION) { firDiagnostic -> InitializerRequiredForDestructuringDeclarationImpl( firDiagnostic as FirPsiDiagnostic, diff --git a/idea/idea-frontend-fir/src/org/jetbrains/kotlin/idea/frontend/api/fir/diagnostics/KtFirDiagnostics.kt b/idea/idea-frontend-fir/src/org/jetbrains/kotlin/idea/frontend/api/fir/diagnostics/KtFirDiagnostics.kt index 3e2434cd563..4d86c29ad21 100644 --- a/idea/idea-frontend-fir/src/org/jetbrains/kotlin/idea/frontend/api/fir/diagnostics/KtFirDiagnostics.kt +++ b/idea/idea-frontend-fir/src/org/jetbrains/kotlin/idea/frontend/api/fir/diagnostics/KtFirDiagnostics.kt @@ -13,6 +13,8 @@ import org.jetbrains.kotlin.contracts.description.EventOccurrencesRange import org.jetbrains.kotlin.descriptors.EffectiveVisibility import org.jetbrains.kotlin.descriptors.Visibility import org.jetbrains.kotlin.diagnostics.WhenMissingCase +import org.jetbrains.kotlin.fir.FirModuleData +import org.jetbrains.kotlin.fir.symbols.FirBasedSymbol import org.jetbrains.kotlin.idea.frontend.api.diagnostics.KtDiagnosticWithPsi import org.jetbrains.kotlin.idea.frontend.api.symbols.KtCallableSymbol import org.jetbrains.kotlin.idea.frontend.api.symbols.KtClassLikeSymbol @@ -33,10 +35,14 @@ import org.jetbrains.kotlin.psi.KtBinaryExpressionWithTypeRHS import org.jetbrains.kotlin.psi.KtCallExpression import org.jetbrains.kotlin.psi.KtClass import org.jetbrains.kotlin.psi.KtClassOrObject +import org.jetbrains.kotlin.psi.KtConstructor +import org.jetbrains.kotlin.psi.KtConstructorDelegationCall import org.jetbrains.kotlin.psi.KtDeclaration import org.jetbrains.kotlin.psi.KtDeclarationWithBody +import org.jetbrains.kotlin.psi.KtDelegatedSuperTypeEntry import org.jetbrains.kotlin.psi.KtDestructuringDeclaration import org.jetbrains.kotlin.psi.KtElement +import org.jetbrains.kotlin.psi.KtEnumEntry import org.jetbrains.kotlin.psi.KtExpression import org.jetbrains.kotlin.psi.KtFunction import org.jetbrains.kotlin.psi.KtIfExpression @@ -59,6 +65,7 @@ import org.jetbrains.kotlin.psi.KtWhenCondition import org.jetbrains.kotlin.psi.KtWhenEntry import org.jetbrains.kotlin.psi.KtWhenExpression import org.jetbrains.kotlin.resolve.ForbiddenNamedArgumentsTarget +import org.jetbrains.kotlin.resolve.multiplatform.ExpectActualCompatibility.Incompatible import org.jetbrains.kotlin.types.Variance /* @@ -1504,10 +1511,6 @@ sealed class KtFirDiagnostic : KtDiagnosticWithPsi { override val diagnosticClass get() = PrivateSetterForOpenProperty::class } - abstract class ExpectedPrivateDeclaration : KtFirDiagnostic() { - override val diagnosticClass get() = ExpectedPrivateDeclaration::class - } - abstract class ValWithSetter : KtFirDiagnostic() { override val diagnosticClass get() = ValWithSetter::class } @@ -1575,6 +1578,22 @@ sealed class KtFirDiagnostic : KtDiagnosticWithPsi { override val diagnosticClass get() = ExpectedDeclarationWithBody::class } + abstract class ExpectedClassConstructorDelegationCall : KtFirDiagnostic() { + override val diagnosticClass get() = ExpectedClassConstructorDelegationCall::class + } + + abstract class ExpectedClassConstructorPropertyParameter : KtFirDiagnostic() { + override val diagnosticClass get() = ExpectedClassConstructorPropertyParameter::class + } + + abstract class ExpectedEnumConstructor : KtFirDiagnostic>() { + override val diagnosticClass get() = ExpectedEnumConstructor::class + } + + abstract class ExpectedEnumEntryWithBody : KtFirDiagnostic() { + override val diagnosticClass get() = ExpectedEnumEntryWithBody::class + } + abstract class ExpectedPropertyInitializer : KtFirDiagnostic() { override val diagnosticClass get() = ExpectedPropertyInitializer::class } @@ -1587,6 +1606,82 @@ sealed class KtFirDiagnostic : KtDiagnosticWithPsi { override val diagnosticClass get() = ExpectedLateinitProperty::class } + abstract class SupertypeInitializedInExpectedClass : KtFirDiagnostic() { + override val diagnosticClass get() = SupertypeInitializedInExpectedClass::class + } + + abstract class ExpectedPrivateDeclaration : KtFirDiagnostic() { + override val diagnosticClass get() = ExpectedPrivateDeclaration::class + } + + abstract class ImplementationByDelegationInExpectClass : KtFirDiagnostic() { + override val diagnosticClass get() = ImplementationByDelegationInExpectClass::class + } + + abstract class ActualTypeAliasNotToClass : KtFirDiagnostic() { + override val diagnosticClass get() = ActualTypeAliasNotToClass::class + } + + abstract class ActualTypeAliasToClassWithDeclarationSiteVariance : KtFirDiagnostic() { + override val diagnosticClass get() = ActualTypeAliasToClassWithDeclarationSiteVariance::class + } + + abstract class ActualTypeAliasWithUseSiteVariance : KtFirDiagnostic() { + override val diagnosticClass get() = ActualTypeAliasWithUseSiteVariance::class + } + + abstract class ActualTypeAliasWithComplexSubstitution : KtFirDiagnostic() { + override val diagnosticClass get() = ActualTypeAliasWithComplexSubstitution::class + } + + abstract class ActualFunctionWithDefaultArguments : KtFirDiagnostic() { + override val diagnosticClass get() = ActualFunctionWithDefaultArguments::class + } + + abstract class ActualAnnotationConflictingDefaultArgumentValue : KtFirDiagnostic() { + override val diagnosticClass get() = ActualAnnotationConflictingDefaultArgumentValue::class + abstract val parameter: KtVariableLikeSymbol + } + + abstract class ExpectedFunctionSourceWithDefaultArgumentsNotFound : KtFirDiagnostic() { + override val diagnosticClass get() = ExpectedFunctionSourceWithDefaultArgumentsNotFound::class + } + + abstract class NoActualForExpect : KtFirDiagnostic() { + override val diagnosticClass get() = NoActualForExpect::class + abstract val declaration: KtSymbol + abstract val module: FirModuleData + abstract val compatibility: Map>, List> + } + + abstract class ActualWithoutExpect : KtFirDiagnostic() { + override val diagnosticClass get() = ActualWithoutExpect::class + abstract val declaration: KtSymbol + abstract val compatibility: Map>, List> + } + + abstract class AmbiguousActuals : KtFirDiagnostic() { + override val diagnosticClass get() = AmbiguousActuals::class + abstract val declaration: KtSymbol + abstract val candidates: List + } + + abstract class AmbiguousExpects : KtFirDiagnostic() { + override val diagnosticClass get() = AmbiguousExpects::class + abstract val declaration: KtSymbol + abstract val modules: List + } + + abstract class NoActualClassMemberForExpectedClass : KtFirDiagnostic() { + override val diagnosticClass get() = NoActualClassMemberForExpectedClass::class + abstract val declaration: KtSymbol + abstract val members: List>, List>>> + } + + abstract class ActualMissing : KtFirDiagnostic() { + override val diagnosticClass get() = ActualMissing::class + } + abstract class InitializerRequiredForDestructuringDeclaration : KtFirDiagnostic() { override val diagnosticClass get() = InitializerRequiredForDestructuringDeclaration::class } diff --git a/idea/idea-frontend-fir/src/org/jetbrains/kotlin/idea/frontend/api/fir/diagnostics/KtFirDiagnosticsImpl.kt b/idea/idea-frontend-fir/src/org/jetbrains/kotlin/idea/frontend/api/fir/diagnostics/KtFirDiagnosticsImpl.kt index 10d48f1252f..5110a976a1d 100644 --- a/idea/idea-frontend-fir/src/org/jetbrains/kotlin/idea/frontend/api/fir/diagnostics/KtFirDiagnosticsImpl.kt +++ b/idea/idea-frontend-fir/src/org/jetbrains/kotlin/idea/frontend/api/fir/diagnostics/KtFirDiagnosticsImpl.kt @@ -13,7 +13,9 @@ import org.jetbrains.kotlin.contracts.description.EventOccurrencesRange import org.jetbrains.kotlin.descriptors.EffectiveVisibility import org.jetbrains.kotlin.descriptors.Visibility import org.jetbrains.kotlin.diagnostics.WhenMissingCase +import org.jetbrains.kotlin.fir.FirModuleData import org.jetbrains.kotlin.fir.analysis.diagnostics.FirPsiDiagnostic +import org.jetbrains.kotlin.fir.symbols.FirBasedSymbol import org.jetbrains.kotlin.idea.frontend.api.fir.utils.weakRef import org.jetbrains.kotlin.idea.frontend.api.symbols.KtCallableSymbol import org.jetbrains.kotlin.idea.frontend.api.symbols.KtClassLikeSymbol @@ -35,10 +37,14 @@ import org.jetbrains.kotlin.psi.KtBinaryExpressionWithTypeRHS import org.jetbrains.kotlin.psi.KtCallExpression import org.jetbrains.kotlin.psi.KtClass import org.jetbrains.kotlin.psi.KtClassOrObject +import org.jetbrains.kotlin.psi.KtConstructor +import org.jetbrains.kotlin.psi.KtConstructorDelegationCall import org.jetbrains.kotlin.psi.KtDeclaration import org.jetbrains.kotlin.psi.KtDeclarationWithBody +import org.jetbrains.kotlin.psi.KtDelegatedSuperTypeEntry import org.jetbrains.kotlin.psi.KtDestructuringDeclaration import org.jetbrains.kotlin.psi.KtElement +import org.jetbrains.kotlin.psi.KtEnumEntry import org.jetbrains.kotlin.psi.KtExpression import org.jetbrains.kotlin.psi.KtFunction import org.jetbrains.kotlin.psi.KtIfExpression @@ -61,6 +67,7 @@ import org.jetbrains.kotlin.psi.KtWhenCondition import org.jetbrains.kotlin.psi.KtWhenEntry import org.jetbrains.kotlin.psi.KtWhenExpression import org.jetbrains.kotlin.resolve.ForbiddenNamedArgumentsTarget +import org.jetbrains.kotlin.resolve.multiplatform.ExpectActualCompatibility.Incompatible import org.jetbrains.kotlin.types.Variance /* @@ -2423,13 +2430,6 @@ internal class PrivateSetterForOpenPropertyImpl( override val firDiagnostic: FirPsiDiagnostic by weakRef(firDiagnostic) } -internal class ExpectedPrivateDeclarationImpl( - firDiagnostic: FirPsiDiagnostic, - override val token: ValidityToken, -) : KtFirDiagnostic.ExpectedPrivateDeclaration(), KtAbstractFirDiagnostic { - override val firDiagnostic: FirPsiDiagnostic by weakRef(firDiagnostic) -} - internal class ValWithSetterImpl( firDiagnostic: FirPsiDiagnostic, override val token: ValidityToken, @@ -2542,6 +2542,34 @@ internal class ExpectedDeclarationWithBodyImpl( override val firDiagnostic: FirPsiDiagnostic by weakRef(firDiagnostic) } +internal class ExpectedClassConstructorDelegationCallImpl( + firDiagnostic: FirPsiDiagnostic, + override val token: ValidityToken, +) : KtFirDiagnostic.ExpectedClassConstructorDelegationCall(), KtAbstractFirDiagnostic { + override val firDiagnostic: FirPsiDiagnostic by weakRef(firDiagnostic) +} + +internal class ExpectedClassConstructorPropertyParameterImpl( + firDiagnostic: FirPsiDiagnostic, + override val token: ValidityToken, +) : KtFirDiagnostic.ExpectedClassConstructorPropertyParameter(), KtAbstractFirDiagnostic { + override val firDiagnostic: FirPsiDiagnostic by weakRef(firDiagnostic) +} + +internal class ExpectedEnumConstructorImpl( + firDiagnostic: FirPsiDiagnostic, + override val token: ValidityToken, +) : KtFirDiagnostic.ExpectedEnumConstructor(), KtAbstractFirDiagnostic> { + override val firDiagnostic: FirPsiDiagnostic by weakRef(firDiagnostic) +} + +internal class ExpectedEnumEntryWithBodyImpl( + firDiagnostic: FirPsiDiagnostic, + override val token: ValidityToken, +) : KtFirDiagnostic.ExpectedEnumEntryWithBody(), KtAbstractFirDiagnostic { + override val firDiagnostic: FirPsiDiagnostic by weakRef(firDiagnostic) +} + internal class ExpectedPropertyInitializerImpl( firDiagnostic: FirPsiDiagnostic, override val token: ValidityToken, @@ -2563,6 +2591,130 @@ internal class ExpectedLateinitPropertyImpl( override val firDiagnostic: FirPsiDiagnostic by weakRef(firDiagnostic) } +internal class SupertypeInitializedInExpectedClassImpl( + firDiagnostic: FirPsiDiagnostic, + override val token: ValidityToken, +) : KtFirDiagnostic.SupertypeInitializedInExpectedClass(), KtAbstractFirDiagnostic { + override val firDiagnostic: FirPsiDiagnostic by weakRef(firDiagnostic) +} + +internal class ExpectedPrivateDeclarationImpl( + firDiagnostic: FirPsiDiagnostic, + override val token: ValidityToken, +) : KtFirDiagnostic.ExpectedPrivateDeclaration(), KtAbstractFirDiagnostic { + override val firDiagnostic: FirPsiDiagnostic by weakRef(firDiagnostic) +} + +internal class ImplementationByDelegationInExpectClassImpl( + firDiagnostic: FirPsiDiagnostic, + override val token: ValidityToken, +) : KtFirDiagnostic.ImplementationByDelegationInExpectClass(), KtAbstractFirDiagnostic { + override val firDiagnostic: FirPsiDiagnostic by weakRef(firDiagnostic) +} + +internal class ActualTypeAliasNotToClassImpl( + firDiagnostic: FirPsiDiagnostic, + override val token: ValidityToken, +) : KtFirDiagnostic.ActualTypeAliasNotToClass(), KtAbstractFirDiagnostic { + override val firDiagnostic: FirPsiDiagnostic by weakRef(firDiagnostic) +} + +internal class ActualTypeAliasToClassWithDeclarationSiteVarianceImpl( + firDiagnostic: FirPsiDiagnostic, + override val token: ValidityToken, +) : KtFirDiagnostic.ActualTypeAliasToClassWithDeclarationSiteVariance(), KtAbstractFirDiagnostic { + override val firDiagnostic: FirPsiDiagnostic by weakRef(firDiagnostic) +} + +internal class ActualTypeAliasWithUseSiteVarianceImpl( + firDiagnostic: FirPsiDiagnostic, + override val token: ValidityToken, +) : KtFirDiagnostic.ActualTypeAliasWithUseSiteVariance(), KtAbstractFirDiagnostic { + override val firDiagnostic: FirPsiDiagnostic by weakRef(firDiagnostic) +} + +internal class ActualTypeAliasWithComplexSubstitutionImpl( + firDiagnostic: FirPsiDiagnostic, + override val token: ValidityToken, +) : KtFirDiagnostic.ActualTypeAliasWithComplexSubstitution(), KtAbstractFirDiagnostic { + override val firDiagnostic: FirPsiDiagnostic by weakRef(firDiagnostic) +} + +internal class ActualFunctionWithDefaultArgumentsImpl( + firDiagnostic: FirPsiDiagnostic, + override val token: ValidityToken, +) : KtFirDiagnostic.ActualFunctionWithDefaultArguments(), KtAbstractFirDiagnostic { + override val firDiagnostic: FirPsiDiagnostic by weakRef(firDiagnostic) +} + +internal class ActualAnnotationConflictingDefaultArgumentValueImpl( + override val parameter: KtVariableLikeSymbol, + firDiagnostic: FirPsiDiagnostic, + override val token: ValidityToken, +) : KtFirDiagnostic.ActualAnnotationConflictingDefaultArgumentValue(), KtAbstractFirDiagnostic { + override val firDiagnostic: FirPsiDiagnostic by weakRef(firDiagnostic) +} + +internal class ExpectedFunctionSourceWithDefaultArgumentsNotFoundImpl( + firDiagnostic: FirPsiDiagnostic, + override val token: ValidityToken, +) : KtFirDiagnostic.ExpectedFunctionSourceWithDefaultArgumentsNotFound(), KtAbstractFirDiagnostic { + override val firDiagnostic: FirPsiDiagnostic by weakRef(firDiagnostic) +} + +internal class NoActualForExpectImpl( + override val declaration: KtSymbol, + override val module: FirModuleData, + override val compatibility: Map>, List>, + firDiagnostic: FirPsiDiagnostic, + override val token: ValidityToken, +) : KtFirDiagnostic.NoActualForExpect(), KtAbstractFirDiagnostic { + override val firDiagnostic: FirPsiDiagnostic by weakRef(firDiagnostic) +} + +internal class ActualWithoutExpectImpl( + override val declaration: KtSymbol, + override val compatibility: Map>, List>, + firDiagnostic: FirPsiDiagnostic, + override val token: ValidityToken, +) : KtFirDiagnostic.ActualWithoutExpect(), KtAbstractFirDiagnostic { + override val firDiagnostic: FirPsiDiagnostic by weakRef(firDiagnostic) +} + +internal class AmbiguousActualsImpl( + override val declaration: KtSymbol, + override val candidates: List, + firDiagnostic: FirPsiDiagnostic, + override val token: ValidityToken, +) : KtFirDiagnostic.AmbiguousActuals(), KtAbstractFirDiagnostic { + override val firDiagnostic: FirPsiDiagnostic by weakRef(firDiagnostic) +} + +internal class AmbiguousExpectsImpl( + override val declaration: KtSymbol, + override val modules: List, + firDiagnostic: FirPsiDiagnostic, + override val token: ValidityToken, +) : KtFirDiagnostic.AmbiguousExpects(), KtAbstractFirDiagnostic { + override val firDiagnostic: FirPsiDiagnostic by weakRef(firDiagnostic) +} + +internal class NoActualClassMemberForExpectedClassImpl( + override val declaration: KtSymbol, + override val members: List>, List>>>, + firDiagnostic: FirPsiDiagnostic, + override val token: ValidityToken, +) : KtFirDiagnostic.NoActualClassMemberForExpectedClass(), KtAbstractFirDiagnostic { + override val firDiagnostic: FirPsiDiagnostic by weakRef(firDiagnostic) +} + +internal class ActualMissingImpl( + firDiagnostic: FirPsiDiagnostic, + override val token: ValidityToken, +) : KtFirDiagnostic.ActualMissing(), KtAbstractFirDiagnostic { + override val firDiagnostic: FirPsiDiagnostic by weakRef(firDiagnostic) +} + internal class InitializerRequiredForDestructuringDeclarationImpl( firDiagnostic: FirPsiDiagnostic, override val token: ValidityToken,