[FIR, IR] Convert FirDefaultArgumentsInExpectActualizedByFakeOverrideChecker into ExpectActualCheckingCompatibility
FirDefaultArgumentsInExpectActualizedByFakeOverrideChecker is an adhoc checker which can be converted to ExpectActualCheckingCompatibility to reuse common expect-actual checking infrastructure. ^KT-62913 Fixed Review: https://jetbrains.team/p/kt/reviews/13094/timeline Tests that were broken by one of my previous commits are now fixed: - actualFakeOverride_paramsAreCompatibleViaSharedMethodWithDefaultParams.kt - inheritedJavaMembers.kt DEFAULT_ARGUMENTS_IN_EXPECT_ACTUALIZED_BY_FAKE_OVERRIDE diagnostic disappeared in delegation.fir.kt because only one AbstractExpectActualChecker incompatibility can be reported at a time (DEFAULT_ARGUMENTS_IN_EXPECT_ACTUALIZED_BY_FAKE_OVERRIDE is now reported not by adhoc checker but by common AbstractExpectActualChecker). It would be nice to report both of them, but it's a separate issue KT-62631 delegation2 test makes sure that DEFAULT_ARGUMENTS_IN_EXPECT_ACTUALIZED_BY_FAKE_OVERRIDE is reported when NO_ACTUAL_CLASS_MEMBER_FOR_EXPECTED_CLASS is fixed
This commit is contained in:
+6
@@ -24882,6 +24882,12 @@ public class DiagnosticCompilerTestFE10TestdataTestGenerated extends AbstractDia
|
||||
runTest("compiler/testData/diagnostics/tests/multiplatform/defaultArguments/methodDefaultArgsViaActualFakeOverride/delegation.kt");
|
||||
}
|
||||
|
||||
@Test
|
||||
@TestMetadata("delegation2.kt")
|
||||
public void testDelegation2() throws Exception {
|
||||
runTest("compiler/testData/diagnostics/tests/multiplatform/defaultArguments/methodDefaultArgsViaActualFakeOverride/delegation2.kt");
|
||||
}
|
||||
|
||||
@Test
|
||||
@TestMetadata("disabledFeature.kt")
|
||||
public void testDisabledFeature() throws Exception {
|
||||
|
||||
+6
@@ -24882,6 +24882,12 @@ public class LLFirPreresolvedReversedDiagnosticCompilerFE10TestDataTestGenerated
|
||||
runTest("compiler/testData/diagnostics/tests/multiplatform/defaultArguments/methodDefaultArgsViaActualFakeOverride/delegation.kt");
|
||||
}
|
||||
|
||||
@Test
|
||||
@TestMetadata("delegation2.kt")
|
||||
public void testDelegation2() throws Exception {
|
||||
runTest("compiler/testData/diagnostics/tests/multiplatform/defaultArguments/methodDefaultArgsViaActualFakeOverride/delegation2.kt");
|
||||
}
|
||||
|
||||
@Test
|
||||
@TestMetadata("disabledFeature.kt")
|
||||
public void testDisabledFeature() throws Exception {
|
||||
|
||||
+6
@@ -1243,6 +1243,12 @@ public class FirOldFrontendMPPDiagnosticsWithLightTreeTestGenerated extends Abst
|
||||
runTest("compiler/testData/diagnostics/tests/multiplatform/defaultArguments/methodDefaultArgsViaActualFakeOverride/delegation.kt");
|
||||
}
|
||||
|
||||
@Test
|
||||
@TestMetadata("delegation2.kt")
|
||||
public void testDelegation2() throws Exception {
|
||||
runTest("compiler/testData/diagnostics/tests/multiplatform/defaultArguments/methodDefaultArgsViaActualFakeOverride/delegation2.kt");
|
||||
}
|
||||
|
||||
@Test
|
||||
@TestMetadata("disabledFeature.kt")
|
||||
public void testDisabledFeature() throws Exception {
|
||||
|
||||
+6
@@ -1243,6 +1243,12 @@ public class FirOldFrontendMPPDiagnosticsWithPsiTestGenerated extends AbstractFi
|
||||
runTest("compiler/testData/diagnostics/tests/multiplatform/defaultArguments/methodDefaultArgsViaActualFakeOverride/delegation.kt");
|
||||
}
|
||||
|
||||
@Test
|
||||
@TestMetadata("delegation2.kt")
|
||||
public void testDelegation2() throws Exception {
|
||||
runTest("compiler/testData/diagnostics/tests/multiplatform/defaultArguments/methodDefaultArgsViaActualFakeOverride/delegation2.kt");
|
||||
}
|
||||
|
||||
@Test
|
||||
@TestMetadata("disabledFeature.kt")
|
||||
public void testDisabledFeature() throws Exception {
|
||||
|
||||
-1
@@ -142,7 +142,6 @@ object CommonDeclarationCheckers : DeclarationCheckers() {
|
||||
FirMultipleDefaultsInheritedFromSupertypesChecker,
|
||||
FirFiniteBoundRestrictionChecker,
|
||||
FirNonExpansiveInheritanceRestrictionChecker,
|
||||
FirDefaultArgumentsInExpectActualizedByFakeOverrideChecker,
|
||||
)
|
||||
|
||||
override val constructorCheckers: Set<FirConstructorChecker>
|
||||
|
||||
-89
@@ -1,89 +0,0 @@
|
||||
/*
|
||||
* Copyright 2010-2023 JetBrains s.r.o. and Kotlin Programming Language contributors.
|
||||
* Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
|
||||
*/
|
||||
|
||||
package org.jetbrains.kotlin.fir.analysis.checkers.declaration
|
||||
|
||||
import org.jetbrains.kotlin.config.LanguageFeature
|
||||
import org.jetbrains.kotlin.diagnostics.DiagnosticReporter
|
||||
import org.jetbrains.kotlin.diagnostics.reportOn
|
||||
import org.jetbrains.kotlin.fir.FirExpectActualMatchingContext
|
||||
import org.jetbrains.kotlin.fir.analysis.checkers.context.CheckerContext
|
||||
import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors
|
||||
import org.jetbrains.kotlin.fir.declarations.FirRegularClass
|
||||
import org.jetbrains.kotlin.fir.declarations.getSingleMatchedExpectForActualOrNull
|
||||
import org.jetbrains.kotlin.fir.declarations.utils.isActual
|
||||
import org.jetbrains.kotlin.fir.expectActualMatchingContextFactory
|
||||
import org.jetbrains.kotlin.fir.isDelegated
|
||||
import org.jetbrains.kotlin.fir.isSubstitutionOrIntersectionOverride
|
||||
import org.jetbrains.kotlin.fir.symbols.impl.FirFunctionSymbol
|
||||
import org.jetbrains.kotlin.fir.symbols.impl.FirNamedFunctionSymbol
|
||||
import org.jetbrains.kotlin.fir.symbols.impl.FirRegularClassSymbol
|
||||
import org.jetbrains.kotlin.fir.types.classId
|
||||
import org.jetbrains.kotlin.mpp.DeclarationSymbolMarker
|
||||
import org.jetbrains.kotlin.resolve.calls.mpp.AbstractExpectActualMatcher
|
||||
import org.jetbrains.kotlin.resolve.multiplatform.ExpectActualMatchingCompatibility
|
||||
|
||||
// TODO KT-62913 create one more ExpectActualCheckingCompatibility incompatibility, and replace this checker with this incompatibility
|
||||
internal object FirDefaultArgumentsInExpectActualizedByFakeOverrideChecker : FirRegularClassChecker() {
|
||||
override fun check(declaration: FirRegularClass, context: CheckerContext, reporter: DiagnosticReporter) {
|
||||
if (!context.languageVersionSettings.supportsFeature(LanguageFeature.MultiPlatformProjects) ||
|
||||
!context.languageVersionSettings.supportsFeature(LanguageFeature.ProhibitDefaultArgumentsInExpectActualizedByFakeOverride)) {
|
||||
return
|
||||
}
|
||||
if (!declaration.isActual) {
|
||||
return
|
||||
}
|
||||
val actualClassSymbol = declaration.symbol
|
||||
// We want to report errors even if a candidate is incompatible, but it's single
|
||||
val expectedSingleCandidate = actualClassSymbol.getSingleMatchedExpectForActualOrNull() ?: return
|
||||
val expectClassSymbol = expectedSingleCandidate as FirRegularClassSymbol
|
||||
|
||||
val expectActualMatchingContext = context.session.expectActualMatchingContextFactory.create(
|
||||
context.session, context.scopeSession,
|
||||
allowedWritingMemberExpectForActualMapping = true,
|
||||
)
|
||||
AbstractExpectActualMatcher.recursivelyMatchClassScopes(expectClassSymbol, actualClassSymbol, expectActualMatchingContext)
|
||||
|
||||
val matchingContext = context.session.expectActualMatchingContextFactory.create(context.session, context.scopeSession)
|
||||
val problematicExpectMembers = with(matchingContext) { findProblematicExpectMembers(expectClassSymbol, actualClassSymbol) }
|
||||
if (problematicExpectMembers.isNotEmpty()) {
|
||||
reporter.reportOn(
|
||||
declaration.source, FirErrors.DEFAULT_ARGUMENTS_IN_EXPECT_ACTUALIZED_BY_FAKE_OVERRIDE,
|
||||
expectClassSymbol, problematicExpectMembers, context
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
private fun FirExpectActualMatchingContext.findProblematicExpectMembers(
|
||||
expectClassSymbol: FirRegularClassSymbol, actualClassSymbol: FirRegularClassSymbol,
|
||||
): List<FirNamedFunctionSymbol> {
|
||||
val actualFakeOverrideMembers = actualClassSymbol.collectAllMembers(isActualDeclaration = true)
|
||||
.filterIsInstance<FirNamedFunctionSymbol>()
|
||||
.filter { it.isFakeOverride(actualClassSymbol) || it.isDelegated }
|
||||
|
||||
return actualFakeOverrideMembers
|
||||
.mapNotNull { getSingleMatchingExpect(it, expectClassSymbol, actualClassSymbol) }
|
||||
.filter(::hasDefaultArgumentValues)
|
||||
}
|
||||
|
||||
private fun FirExpectActualMatchingContext.getSingleMatchingExpect(
|
||||
actualMember: FirNamedFunctionSymbol,
|
||||
expectSymbol: FirRegularClassSymbol,
|
||||
actualSymbol: FirRegularClassSymbol
|
||||
): FirNamedFunctionSymbol? {
|
||||
val potentialExpects = findPotentialExpectClassMembersForActual(
|
||||
expectSymbol, actualSymbol, actualMember,
|
||||
)
|
||||
val expectMember: DeclarationSymbolMarker = potentialExpects.entries
|
||||
.singleOrNull { it.value == ExpectActualMatchingCompatibility.MatchedSuccessfully }?.key
|
||||
?: potentialExpects.keys.singleOrNull()
|
||||
?: return null
|
||||
return expectMember as FirNamedFunctionSymbol
|
||||
}
|
||||
|
||||
private fun hasDefaultArgumentValues(function: FirFunctionSymbol<*>): Boolean {
|
||||
return function.valueParameterSymbols.any { it.hasDefaultValue }
|
||||
}
|
||||
}
|
||||
+30
-7
@@ -6,6 +6,7 @@
|
||||
package org.jetbrains.kotlin.fir.analysis.checkers.declaration
|
||||
|
||||
import org.jetbrains.kotlin.KtFakeSourceElementKind
|
||||
import org.jetbrains.kotlin.KtSourceElement
|
||||
import org.jetbrains.kotlin.config.LanguageFeature
|
||||
import org.jetbrains.kotlin.descriptors.ClassKind
|
||||
import org.jetbrains.kotlin.diagnostics.DiagnosticReporter
|
||||
@@ -25,10 +26,7 @@ import org.jetbrains.kotlin.fir.expectActualMatchingContextFactory
|
||||
import org.jetbrains.kotlin.fir.languageVersionSettings
|
||||
import org.jetbrains.kotlin.fir.symbols.FirBasedSymbol
|
||||
import org.jetbrains.kotlin.fir.symbols.SymbolInternals
|
||||
import org.jetbrains.kotlin.fir.symbols.impl.FirCallableSymbol
|
||||
import org.jetbrains.kotlin.fir.symbols.impl.FirClassLikeSymbol
|
||||
import org.jetbrains.kotlin.fir.symbols.impl.FirRegularClassSymbol
|
||||
import org.jetbrains.kotlin.fir.symbols.impl.FirTypeAliasSymbol
|
||||
import org.jetbrains.kotlin.fir.symbols.impl.*
|
||||
import org.jetbrains.kotlin.lexer.KtTokens
|
||||
import org.jetbrains.kotlin.mpp.RegularClassSymbolMarker
|
||||
import org.jetbrains.kotlin.name.StandardClassIds
|
||||
@@ -157,7 +155,7 @@ object FirExpectActualDeclarationChecker : FirBasicDeclarationChecker() {
|
||||
|
||||
when {
|
||||
checkingCompatibility is ExpectActualCheckingCompatibility.ClassScopes -> {
|
||||
require(symbol is FirRegularClassSymbol || symbol is FirTypeAliasSymbol) {
|
||||
require((symbol is FirRegularClassSymbol || symbol is FirTypeAliasSymbol) && expectedSingleCandidate is FirRegularClassSymbol) {
|
||||
"Incompatible.ClassScopes is only possible for a class or a typealias: $declaration"
|
||||
}
|
||||
|
||||
@@ -178,10 +176,35 @@ object FirExpectActualDeclarationChecker : FirBasicDeclarationChecker() {
|
||||
val nonTrivialIncompatibleMembers = checkingCompatibility.incompatibleMembers.filterNot(::hasSingleActualSuspect)
|
||||
|
||||
if (nonTrivialIncompatibleMembers.isNotEmpty()) {
|
||||
reporter.reportOn(source, FirErrors.NO_ACTUAL_CLASS_MEMBER_FOR_EXPECTED_CLASS, symbol, nonTrivialIncompatibleMembers, context)
|
||||
val (defaultArgsIncompatibleMembers, otherIncompatibleMembers) =
|
||||
nonTrivialIncompatibleMembers.partition { it.second.contains(ExpectActualCheckingCompatibility.DefaultArgumentsInExpectActualizedByFakeOverride) }
|
||||
|
||||
if (defaultArgsIncompatibleMembers.isNotEmpty()) { // report a nicer diagnostic for DefaultArgumentsInExpectActualizedByFakeOverride
|
||||
val problematicExpectMembers = defaultArgsIncompatibleMembers
|
||||
.map {
|
||||
it.first as? FirNamedFunctionSymbol
|
||||
?: error("${ExpectActualCheckingCompatibility.DefaultArgumentsInExpectActualizedByFakeOverride} can be reported only for ${FirNamedFunctionSymbol::class}")
|
||||
}
|
||||
reporter.reportOn(
|
||||
source,
|
||||
FirErrors.DEFAULT_ARGUMENTS_IN_EXPECT_ACTUALIZED_BY_FAKE_OVERRIDE,
|
||||
expectedSingleCandidate,
|
||||
problematicExpectMembers,
|
||||
context
|
||||
)
|
||||
}
|
||||
if (otherIncompatibleMembers.isNotEmpty()) {
|
||||
reporter.reportOn(source, FirErrors.NO_ACTUAL_CLASS_MEMBER_FOR_EXPECTED_CLASS, symbol, otherIncompatibleMembers, context)
|
||||
}
|
||||
}
|
||||
if (checkingCompatibility.mismatchedMembers.isNotEmpty()) {
|
||||
reporter.reportOn(source, FirErrors.NO_ACTUAL_CLASS_MEMBER_FOR_EXPECTED_CLASS, symbol, checkingCompatibility.mismatchedMembers, context)
|
||||
reporter.reportOn(
|
||||
source,
|
||||
FirErrors.NO_ACTUAL_CLASS_MEMBER_FOR_EXPECTED_CLASS,
|
||||
symbol,
|
||||
checkingCompatibility.mismatchedMembers,
|
||||
context
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
+8
-2
@@ -43,7 +43,7 @@ class FirExpectActualMatchingContextImpl private constructor(
|
||||
private val actualScopeSession: ScopeSession,
|
||||
private val allowedWritingMemberExpectForActualMapping: Boolean,
|
||||
) : FirExpectActualMatchingContext, TypeSystemContext by actualSession.typeContext {
|
||||
override val shouldCheckAbsenceOfDefaultParamsInActual: Boolean
|
||||
override val shouldCheckDefaultParams: Boolean
|
||||
get() = true
|
||||
|
||||
override val allowClassActualizationWithWiderVisibility: Boolean
|
||||
@@ -257,7 +257,7 @@ class FirExpectActualMatchingContextImpl private constructor(
|
||||
override val CallableSymbolMarker.typeParameters: List<TypeParameterSymbolMarker>
|
||||
get() = asSymbol().typeParameterSymbols
|
||||
|
||||
override fun FunctionSymbolMarker.allOverriddenDeclarationsRecursive(): Sequence<CallableSymbolMarker> {
|
||||
override fun FunctionSymbolMarker.allRecursivelyOverriddenDeclarationsIncludingSelf(): Sequence<CallableSymbolMarker> {
|
||||
return when (val symbol = asSymbol()) {
|
||||
is FirConstructorSymbol, is FirFunctionWithoutNameSymbol -> sequenceOf(this)
|
||||
is FirNamedFunctionSymbol -> {
|
||||
@@ -285,6 +285,9 @@ class FirExpectActualMatchingContextImpl private constructor(
|
||||
override val ValueParameterSymbolMarker.hasDefaultValue: Boolean
|
||||
get() = asSymbol().hasDefaultValue
|
||||
|
||||
override val ValueParameterSymbolMarker.hasDefaultValueNonRecursive: Boolean
|
||||
get() = asSymbol().hasDefaultValue
|
||||
|
||||
override fun CallableSymbolMarker.isAnnotationConstructor(): Boolean {
|
||||
val symbol = asSymbol()
|
||||
return symbol.isAnnotationConstructor(symbol.moduleData.session)
|
||||
@@ -375,6 +378,9 @@ class FirExpectActualMatchingContextImpl private constructor(
|
||||
return symbol.isSubstitutionOrIntersectionOverride
|
||||
}
|
||||
|
||||
override val CallableSymbolMarker.isDelegatedMember: Boolean
|
||||
get() = asSymbol().isDelegated
|
||||
|
||||
override val CallableSymbolMarker.hasStableParameterNames: Boolean
|
||||
get() = asSymbol().rawStatus.hasStableParameterNames
|
||||
|
||||
|
||||
+17
-3
@@ -50,7 +50,7 @@ internal abstract class IrExpectActualMatchingContext(
|
||||
// This incompatibility is often suppressed in the source code (e.g. in kotlin-stdlib).
|
||||
// The backend must be able to do expect-actual matching to emit bytecode
|
||||
// That's why we disable the checker here. Probably, this checker can be enabled once KT-60426 is fixed
|
||||
override val shouldCheckAbsenceOfDefaultParamsInActual: Boolean
|
||||
override val shouldCheckDefaultParams: Boolean
|
||||
get() = false
|
||||
|
||||
private inline fun <R> CallableSymbolMarker.processIr(
|
||||
@@ -298,8 +298,16 @@ internal abstract class IrExpectActualMatchingContext(
|
||||
onEnumEntry = { emptyList() }
|
||||
)
|
||||
|
||||
override fun FunctionSymbolMarker.allOverriddenDeclarationsRecursive(): Sequence<CallableSymbolMarker> =
|
||||
throw NotImplementedError("Not implemented because it's unused")
|
||||
override fun FunctionSymbolMarker.allRecursivelyOverriddenDeclarationsIncludingSelf(): Sequence<CallableSymbolMarker> =
|
||||
when (val node = asIr()) {
|
||||
is IrConstructor -> sequenceOf(this)
|
||||
is IrSimpleFunction -> (sequenceOf(this) + node.overriddenSymbols)
|
||||
// Tests work even if you don't filter out fake-overrides. Filtering fake-overrides is needed because
|
||||
// the returned descriptors are compared by `equals`. And `equals` for fake-overrides is weird.
|
||||
// I didn't manage to invent a test that would check this condition
|
||||
.filter { !it.asIr().isFakeOverride }
|
||||
else -> error("Unknown IR node: $node")
|
||||
}
|
||||
|
||||
override val FunctionSymbolMarker.valueParameters: List<ValueParameterSymbolMarker>
|
||||
get() = asIr().valueParameters.map { it.symbol }
|
||||
@@ -313,6 +321,9 @@ internal abstract class IrExpectActualMatchingContext(
|
||||
override val ValueParameterSymbolMarker.hasDefaultValue: Boolean
|
||||
get() = asIr().hasDefaultValue()
|
||||
|
||||
override val ValueParameterSymbolMarker.hasDefaultValueNonRecursive: Boolean
|
||||
get() = asIr().defaultValue != null
|
||||
|
||||
override fun CallableSymbolMarker.isAnnotationConstructor(): Boolean {
|
||||
val irConstructor = safeAsIr<IrConstructor>() ?: return false
|
||||
return irConstructor.constructedClass.isAnnotationClass
|
||||
@@ -458,6 +469,9 @@ internal abstract class IrExpectActualMatchingContext(
|
||||
return asIr().isFakeOverride
|
||||
}
|
||||
|
||||
override val CallableSymbolMarker.isDelegatedMember: Boolean
|
||||
get() = asIr().origin == IrDeclarationOrigin.DELEGATED_MEMBER
|
||||
|
||||
override val CallableSymbolMarker.hasStableParameterNames: Boolean
|
||||
get() {
|
||||
var ir = asIr()
|
||||
|
||||
+25
-13
@@ -369,19 +369,31 @@ object AbstractExpectActualChecker {
|
||||
|
||||
getTypeParametersVarianceOrReifiedIncompatibility(expectedTypeParameters, actualTypeParameters)?.let { return it }
|
||||
|
||||
if (shouldCheckAbsenceOfDefaultParamsInActual) {
|
||||
// "Default parameters in actual" check is required only for functions, because only functions can have parameters
|
||||
if (actualDeclaration is FunctionSymbolMarker && expectDeclaration is FunctionSymbolMarker) {
|
||||
// Actual annotation constructors can have default argument values; their consistency with arguments in the expected annotation
|
||||
// is checked in ExpectedActualDeclarationChecker.checkAnnotationConstructors
|
||||
if (!actualDeclaration.isAnnotationConstructor() &&
|
||||
// If default params came from common supertypes of actual class and expect class then it's a valid code.
|
||||
// Here we filter out such default params.
|
||||
(actualDeclaration.allOverriddenDeclarationsRecursive() - expectDeclaration.allOverriddenDeclarationsRecursive().toSet())
|
||||
.flatMap { it.valueParameters }.any { it.hasDefaultValue }
|
||||
) {
|
||||
return ExpectActualCheckingCompatibility.ActualFunctionWithDefaultParameters
|
||||
}
|
||||
if (shouldCheckDefaultParams &&
|
||||
// "parameters" checks are required only for functions, because only functions can have parameters
|
||||
actualDeclaration is FunctionSymbolMarker && expectDeclaration is FunctionSymbolMarker
|
||||
) {
|
||||
if (languageVersionSettings.supportsFeature(LanguageFeature.ProhibitDefaultArgumentsInExpectActualizedByFakeOverride) &&
|
||||
(actualDeclaration.isFakeOverride(actualContainingClass) || actualDeclaration.isDelegatedMember) &&
|
||||
// If default params came from common supertypes of actual class and expect class then it's a valid code.
|
||||
// Here we filter out such default params.
|
||||
(expectDeclaration.allRecursivelyOverriddenDeclarationsIncludingSelf() -
|
||||
actualDeclaration.allRecursivelyOverriddenDeclarationsIncludingSelf().toSet())
|
||||
.flatMap { it.valueParameters }.any { it.hasDefaultValueNonRecursive }
|
||||
) {
|
||||
return ExpectActualCheckingCompatibility.DefaultArgumentsInExpectActualizedByFakeOverride
|
||||
}
|
||||
|
||||
// Actual annotation constructors can have default argument values; their consistency with arguments in the expected annotation
|
||||
// is checked in ExpectedActualDeclarationChecker.checkAnnotationConstructors
|
||||
if (!actualDeclaration.isAnnotationConstructor() &&
|
||||
// If default params came from common supertypes of actual class and expect class then it's a valid code.
|
||||
// Here we filter out such default params.
|
||||
(actualDeclaration.allRecursivelyOverriddenDeclarationsIncludingSelf() -
|
||||
expectDeclaration.allRecursivelyOverriddenDeclarationsIncludingSelf().toSet())
|
||||
.flatMap { it.valueParameters }.any { it.hasDefaultValue }
|
||||
) {
|
||||
return ExpectActualCheckingCompatibility.ActualFunctionWithDefaultParameters
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
-30
@@ -74,36 +74,6 @@ object AbstractExpectActualMatcher {
|
||||
ExpectActualMatchingCompatibility.MatchedSuccessfully
|
||||
}
|
||||
|
||||
fun recursivelyMatchClassScopes( // todo drop KT-62913
|
||||
expectClassSymbol: RegularClassSymbolMarker,
|
||||
actualClassSymbol: RegularClassSymbolMarker,
|
||||
context: ExpectActualMatchingContext<*>,
|
||||
): Unit = with(context) {
|
||||
val expectTypeParameterSymbols = expectClassSymbol.typeParameters
|
||||
val actualTypeParameterSymbols = actualClassSymbol.typeParameters
|
||||
val substitutor = createExpectActualTypeParameterSubstitutor(
|
||||
(expectTypeParameterSymbols zipIfSizesAreEqual actualTypeParameterSymbols) ?: return,
|
||||
parentSubstitutor = null,
|
||||
)
|
||||
|
||||
val actualMembersByName = actualClassSymbol.collectAllMembers(isActualDeclaration = true).groupBy { it.name }
|
||||
|
||||
outer@ for (expectMember in expectClassSymbol.collectAllMembers(isActualDeclaration = false)) {
|
||||
val actualMembers = getPossibleActualsByExpectName(expectMember, actualMembersByName)
|
||||
|
||||
matchSingleExpectAgainstPotentialActuals(
|
||||
expectMember,
|
||||
actualMembers,
|
||||
substitutor,
|
||||
expectClassSymbol,
|
||||
actualClassSymbol,
|
||||
mismatchedMembers = null,
|
||||
)
|
||||
}
|
||||
|
||||
// TODO: check static scope?
|
||||
}
|
||||
|
||||
/**
|
||||
* Besides returning the matched declaration
|
||||
*
|
||||
|
||||
+6
-3
@@ -40,7 +40,7 @@ interface ExpectActualMatchingContext<T : DeclarationSymbolMarker> : TypeSystemC
|
||||
// Known clients that do suppress:
|
||||
// - stdlib
|
||||
// - coroutines
|
||||
val shouldCheckAbsenceOfDefaultParamsInActual: Boolean
|
||||
val shouldCheckDefaultParams: Boolean
|
||||
|
||||
/**
|
||||
* This flag determines, how visibilities for classes/typealiases will be matched
|
||||
@@ -123,9 +123,9 @@ interface ExpectActualMatchingContext<T : DeclarationSymbolMarker> : TypeSystemC
|
||||
val FunctionSymbolMarker.valueParameters: List<ValueParameterSymbolMarker>
|
||||
|
||||
/**
|
||||
* Returns all symbols that are overridden by [this] symbol
|
||||
* Returns all symbols that are overridden by [this] symbol, including self
|
||||
*/
|
||||
fun FunctionSymbolMarker.allOverriddenDeclarationsRecursive(): Sequence<CallableSymbolMarker>
|
||||
fun FunctionSymbolMarker.allRecursivelyOverriddenDeclarationsIncludingSelf(): Sequence<CallableSymbolMarker>
|
||||
|
||||
val CallableSymbolMarker.valueParameters: List<ValueParameterSymbolMarker>
|
||||
get() = (this as? FunctionSymbolMarker)?.valueParameters ?: emptyList()
|
||||
@@ -134,6 +134,7 @@ interface ExpectActualMatchingContext<T : DeclarationSymbolMarker> : TypeSystemC
|
||||
val ValueParameterSymbolMarker.isNoinline: Boolean
|
||||
val ValueParameterSymbolMarker.isCrossinline: Boolean
|
||||
val ValueParameterSymbolMarker.hasDefaultValue: Boolean
|
||||
val ValueParameterSymbolMarker.hasDefaultValueNonRecursive: Boolean
|
||||
|
||||
fun CallableSymbolMarker.isAnnotationConstructor(): Boolean
|
||||
|
||||
@@ -158,6 +159,8 @@ interface ExpectActualMatchingContext<T : DeclarationSymbolMarker> : TypeSystemC
|
||||
|
||||
fun CallableSymbolMarker.isFakeOverride(containingExpectClass: RegularClassSymbolMarker?): Boolean
|
||||
|
||||
val CallableSymbolMarker.isDelegatedMember: Boolean
|
||||
|
||||
val CallableSymbolMarker.hasStableParameterNames: Boolean
|
||||
|
||||
fun onMatchedMembers(
|
||||
|
||||
+1
-1
@@ -9,4 +9,4 @@ expect class Foo : Shared
|
||||
|
||||
// MODULE: m2-jvm()()(m1-common)
|
||||
// FILE: jvm.kt
|
||||
actual class Foo : <!DEFAULT_ARGUMENTS_IN_EXPECT_ACTUALIZED_BY_FAKE_OVERRIDE!>Shared<!>
|
||||
actual class Foo : Shared
|
||||
|
||||
+1
-1
@@ -14,4 +14,4 @@ object BaseImpl : Base {
|
||||
override fun foo(p: Int) {}
|
||||
}
|
||||
|
||||
actual class <!NO_ACTUAL_CLASS_MEMBER_FOR_EXPECTED_CLASS!>Foo<!> : <!DEFAULT_ARGUMENTS_IN_EXPECT_ACTUALIZED_BY_FAKE_OVERRIDE!>Base by BaseImpl<!>
|
||||
actual class <!NO_ACTUAL_CLASS_MEMBER_FOR_EXPECTED_CLASS!>Foo<!> : Base by BaseImpl
|
||||
|
||||
+1
-1
@@ -14,4 +14,4 @@ object BaseImpl : Base {
|
||||
override fun foo(p: Int) {}
|
||||
}
|
||||
|
||||
actual class <!NO_ACTUAL_CLASS_MEMBER_FOR_EXPECTED_CLASS!>Foo<!> : <!DEFAULT_ARGUMENTS_IN_EXPECT_ACTUALIZED_BY_FAKE_OVERRIDE!>Base by BaseImpl<!>
|
||||
actual class <!NO_ACTUAL_CLASS_MEMBER_FOR_EXPECTED_CLASS!>Foo<!> : Base by BaseImpl
|
||||
|
||||
+17
@@ -0,0 +1,17 @@
|
||||
// MODULE: m1-common
|
||||
// FILE: common.kt
|
||||
expect class Foo {
|
||||
fun foo(p: Int = 1)
|
||||
}
|
||||
|
||||
// MODULE: m2-jvm()()(m1-common)
|
||||
// FILE: jvm.kt
|
||||
interface Base {
|
||||
fun foo(p: Int)
|
||||
}
|
||||
|
||||
object BaseImpl : Base {
|
||||
override fun foo(p: Int) {}
|
||||
}
|
||||
|
||||
actual class Foo : <!DEFAULT_ARGUMENTS_IN_EXPECT_ACTUALIZED_BY_FAKE_OVERRIDE!>Base by BaseImpl<!>
|
||||
+17
@@ -0,0 +1,17 @@
|
||||
// MODULE: m1-common
|
||||
// FILE: common.kt
|
||||
expect class Foo {
|
||||
fun foo(p: Int = 1)
|
||||
}
|
||||
|
||||
// MODULE: m2-jvm()()(m1-common)
|
||||
// FILE: jvm.kt
|
||||
interface Base {
|
||||
fun foo(p: Int)
|
||||
}
|
||||
|
||||
object BaseImpl : Base {
|
||||
override fun foo(p: Int) {}
|
||||
}
|
||||
|
||||
actual class Foo : Base by BaseImpl
|
||||
+1
-1
@@ -51,7 +51,7 @@ public actual open class FastArrayList<E> internal constructor(
|
||||
var array: Array<Any?>,
|
||||
var _size: Int = array.size,
|
||||
var arrayCapacity: Int = array.size,
|
||||
) : <!DEFAULT_ARGUMENTS_IN_EXPECT_ACTUALIZED_BY_FAKE_OVERRIDE!>AbstractMutableList<E>(), MutableListEx<E>, RandomAccess<!> {
|
||||
) : AbstractMutableList<E>(), MutableListEx<E>, RandomAccess {
|
||||
public actual constructor() : this(arrayOfNulls(16), 0) {}
|
||||
public actual constructor(initialCapacity: Int) : this(arrayOfNulls(initialCapacity), 0) {}
|
||||
public actual constructor(elements: Collection<E>) : this(elements.toTypedArray<Any?>()) {}
|
||||
|
||||
Generated
+6
@@ -24882,6 +24882,12 @@ public class DiagnosticTestGenerated extends AbstractDiagnosticTest {
|
||||
runTest("compiler/testData/diagnostics/tests/multiplatform/defaultArguments/methodDefaultArgsViaActualFakeOverride/delegation.kt");
|
||||
}
|
||||
|
||||
@Test
|
||||
@TestMetadata("delegation2.kt")
|
||||
public void testDelegation2() throws Exception {
|
||||
runTest("compiler/testData/diagnostics/tests/multiplatform/defaultArguments/methodDefaultArgsViaActualFakeOverride/delegation2.kt");
|
||||
}
|
||||
|
||||
@Test
|
||||
@TestMetadata("disabledFeature.kt")
|
||||
public void testDisabledFeature() throws Exception {
|
||||
|
||||
+2
@@ -69,6 +69,8 @@ sealed class ExpectActualCheckingCompatibility<out D> : ExpectActualCompatibilit
|
||||
Incompatible<Nothing>("some modifiers on expected declaration are missing on the actual one (infix, inline, operator)")
|
||||
object ActualFunctionWithDefaultParameters :
|
||||
Incompatible<Nothing>("actual function cannot have default argument values, they should be declared in the expected function")
|
||||
object DefaultArgumentsInExpectActualizedByFakeOverride :
|
||||
Incompatible<Nothing>("default argument values inside expect declaration are not allowed for methods actualized via fake override")
|
||||
|
||||
// Properties
|
||||
object PropertyKind : Incompatible<Nothing>("property kinds are different (val vs var)")
|
||||
|
||||
Reference in New Issue
Block a user