From cd896ae6c8221db47d7ce91ce7dfdde2b9e429b1 Mon Sep 17 00:00:00 2001 From: Denis Zharkov Date: Mon, 20 Jul 2020 12:24:51 +0300 Subject: [PATCH] FIR: Implement FE 1.0 semantics for super unqualified calls See original logic at org.jetbrains.kotlin.types.expressions.unqualifiedSuper.UnqualifiedSuperKt#resolveUnqualifiedSuperFromExpressionContext ^KT-39070 Fixed ^KT-39599 Related --- .../resolve/callResolution/superAny.kt | 21 +++ .../resolve/callResolution/superAny.txt | 31 ++++ .../testData/resolve/incorrectSuperCall.kt | 2 +- .../testData/resolve/incorrectSuperCall.txt | 6 +- .../fir/FirDiagnosticsTestGenerated.java | 5 + ...DiagnosticsWithLightTreeTestGenerated.java | 5 + .../expression/FirNotASupertypeChecker.kt | 4 +- ...upertypeExtendedByOtherSupertypeChecker.kt | 3 +- .../expression/FirSuperNotAvailableChecker.kt | 21 +-- .../checkers/expression/SuperCallCheckers.kt | 11 ++ .../jetbrains/kotlin/fir/FirCallResolver.kt | 2 +- .../kotlin/fir/resolve/calls/SuperCalls.kt | 147 ++++++++++++++++++ .../FirExpressionsResolveTransformer.kt | 28 ++-- .../jetbrains/kotlin/fir/FirSourceElement.kt | 4 + .../super/unqualifiedSuperWithMethodsOfAny.kt | 3 +- .../tests/SafeCallOnSuperReceiver.fir.kt | 4 +- .../tests/enum/kt8972_cloneNotAllowed.fir.kt | 2 +- .../ambiguousSuperWithGenerics.fir.kt | 12 +- .../unqualifiedSuper/unqualifiedSuper.fir.kt | 4 +- ...unqualifiedSuperWithAbstractMembers.fir.kt | 2 +- ...nqualifiedSuperWithCallableProperty.fir.kt | 4 +- .../unqualifiedSuperWithInterfaces.fir.kt | 4 +- .../unqualifiedSuperWithUnresolvedBase.fir.kt | 4 +- ...hMethodOverriddenInAnotherSupertype.fir.kt | 29 ---- .../withMethodOverriddenInAnotherSupertype.kt | 1 + .../annotations/jvmDefault/superCall.fir.kt | 8 +- 26 files changed, 285 insertions(+), 82 deletions(-) create mode 100644 compiler/fir/analysis-tests/testData/resolve/callResolution/superAny.kt create mode 100644 compiler/fir/analysis-tests/testData/resolve/callResolution/superAny.txt create mode 100644 compiler/fir/checkers/src/org/jetbrains/kotlin/fir/analysis/checkers/expression/SuperCallCheckers.kt create mode 100644 compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/calls/SuperCalls.kt delete mode 100644 compiler/testData/diagnostics/tests/thisAndSuper/unqualifiedSuper/withMethodOverriddenInAnotherSupertype.fir.kt diff --git a/compiler/fir/analysis-tests/testData/resolve/callResolution/superAny.kt b/compiler/fir/analysis-tests/testData/resolve/callResolution/superAny.kt new file mode 100644 index 00000000000..efb6013f20e --- /dev/null +++ b/compiler/fir/analysis-tests/testData/resolve/callResolution/superAny.kt @@ -0,0 +1,21 @@ +interface A + +open class B { + override fun equals(other: Any?): Boolean { + return super.equals(other) + } + + override fun hashCode(): Int { + return super.hashCode() + } +} + +class C : A, B() { + override fun equals(other: Any?): Boolean { + return super.equals(other) + } + + override fun hashCode(): Int { + return super.hashCode() + } +} diff --git a/compiler/fir/analysis-tests/testData/resolve/callResolution/superAny.txt b/compiler/fir/analysis-tests/testData/resolve/callResolution/superAny.txt new file mode 100644 index 00000000000..c50d37d7cce --- /dev/null +++ b/compiler/fir/analysis-tests/testData/resolve/callResolution/superAny.txt @@ -0,0 +1,31 @@ +FILE: superAny.kt + public abstract interface A : R|kotlin/Any| { + } + public open class B : R|kotlin/Any| { + public constructor(): R|B| { + super() + } + + public open override fun equals(other: R|kotlin/Any?|): R|kotlin/Boolean| { + ^equals this@R|/B|.super.R|kotlin/Any.equals|(R|/other|) + } + + public open override fun hashCode(): R|kotlin/Int| { + ^hashCode this@R|/B|.super.R|kotlin/Any.hashCode|() + } + + } + public final class C : R|A|, R|B| { + public constructor(): R|C| { + super() + } + + public final override fun equals(other: R|kotlin/Any?|): R|kotlin/Boolean| { + ^equals this@R|/C|.super.R|/B.equals|(R|/other|) + } + + public final override fun hashCode(): R|kotlin/Int| { + ^hashCode this@R|/C|.super.R|/B.hashCode|() + } + + } diff --git a/compiler/fir/analysis-tests/testData/resolve/incorrectSuperCall.kt b/compiler/fir/analysis-tests/testData/resolve/incorrectSuperCall.kt index 10d7b51de68..923a96486fc 100644 --- a/compiler/fir/analysis-tests/testData/resolve/incorrectSuperCall.kt +++ b/compiler/fir/analysis-tests/testData/resolve/incorrectSuperCall.kt @@ -15,7 +15,7 @@ class C : A, B() { override fun foo() { super.foo() - super.bar() // should be ambiguity (NB: really we should have overridden bar in C) + super.bar() // should be ambiguity (NB: really we should have overridden bar in C) super.baz() // Ok baz() // Ok diff --git a/compiler/fir/analysis-tests/testData/resolve/incorrectSuperCall.txt b/compiler/fir/analysis-tests/testData/resolve/incorrectSuperCall.txt index 57a44c195d0..1bbaa0d412e 100644 --- a/compiler/fir/analysis-tests/testData/resolve/incorrectSuperCall.txt +++ b/compiler/fir/analysis-tests/testData/resolve/incorrectSuperCall.txt @@ -27,9 +27,9 @@ FILE: incorrectSuperCall.kt } public final override fun foo(): R|kotlin/Unit| { - this@R|/C|.super.R|/B.foo|() - this@R|/C|.super.#() - this@R|/C|.super.R|/B.baz|() + this@R|/C|.super.R|/B.foo|() + this@R|/C|.super<>.#() + this@R|/C|.super.R|/B.baz|() this@R|/C|.R|/A.baz|() } diff --git a/compiler/fir/analysis-tests/tests/org/jetbrains/kotlin/fir/FirDiagnosticsTestGenerated.java b/compiler/fir/analysis-tests/tests/org/jetbrains/kotlin/fir/FirDiagnosticsTestGenerated.java index a9f7a2f4a64..68961eeeeb1 100644 --- a/compiler/fir/analysis-tests/tests/org/jetbrains/kotlin/fir/FirDiagnosticsTestGenerated.java +++ b/compiler/fir/analysis-tests/tests/org/jetbrains/kotlin/fir/FirDiagnosticsTestGenerated.java @@ -654,6 +654,11 @@ public class FirDiagnosticsTestGenerated extends AbstractFirDiagnosticsTest { runTest("compiler/fir/analysis-tests/testData/resolve/callResolution/safeCallOnTypeAlias.kt"); } + @TestMetadata("superAny.kt") + public void testSuperAny() throws Exception { + runTest("compiler/fir/analysis-tests/testData/resolve/callResolution/superAny.kt"); + } + @TestMetadata("syntheticPropertiesWrongImplicitReceiver.kt") public void testSyntheticPropertiesWrongImplicitReceiver() throws Exception { runTest("compiler/fir/analysis-tests/testData/resolve/callResolution/syntheticPropertiesWrongImplicitReceiver.kt"); diff --git a/compiler/fir/analysis-tests/tests/org/jetbrains/kotlin/fir/FirDiagnosticsWithLightTreeTestGenerated.java b/compiler/fir/analysis-tests/tests/org/jetbrains/kotlin/fir/FirDiagnosticsWithLightTreeTestGenerated.java index 96d2b3867d2..8d9eb1da43f 100644 --- a/compiler/fir/analysis-tests/tests/org/jetbrains/kotlin/fir/FirDiagnosticsWithLightTreeTestGenerated.java +++ b/compiler/fir/analysis-tests/tests/org/jetbrains/kotlin/fir/FirDiagnosticsWithLightTreeTestGenerated.java @@ -654,6 +654,11 @@ public class FirDiagnosticsWithLightTreeTestGenerated extends AbstractFirDiagnos runTest("compiler/fir/analysis-tests/testData/resolve/callResolution/safeCallOnTypeAlias.kt"); } + @TestMetadata("superAny.kt") + public void testSuperAny() throws Exception { + runTest("compiler/fir/analysis-tests/testData/resolve/callResolution/superAny.kt"); + } + @TestMetadata("syntheticPropertiesWrongImplicitReceiver.kt") public void testSyntheticPropertiesWrongImplicitReceiver() throws Exception { runTest("compiler/fir/analysis-tests/testData/resolve/callResolution/syntheticPropertiesWrongImplicitReceiver.kt"); diff --git a/compiler/fir/checkers/src/org/jetbrains/kotlin/fir/analysis/checkers/expression/FirNotASupertypeChecker.kt b/compiler/fir/checkers/src/org/jetbrains/kotlin/fir/analysis/checkers/expression/FirNotASupertypeChecker.kt index 031eae45454..cd4ff94dfad 100644 --- a/compiler/fir/checkers/src/org/jetbrains/kotlin/fir/analysis/checkers/expression/FirNotASupertypeChecker.kt +++ b/compiler/fir/checkers/src/org/jetbrains/kotlin/fir/analysis/checkers/expression/FirNotASupertypeChecker.kt @@ -20,7 +20,7 @@ import org.jetbrains.kotlin.utils.addToStdlib.safeAs object FirNotASupertypeChecker : FirQualifiedAccessChecker() { override fun check(functionCall: FirQualifiedAccessExpression, context: CheckerContext, reporter: DiagnosticReporter) { - val superReference = functionCall.calleeReference.safeAs() + val superReference = functionCall.calleeReference.safeAs()?.takeIf { it.hadExplicitTypeInSource() } val targetClass = superReference ?.superTypeRef @@ -57,4 +57,4 @@ object FirNotASupertypeChecker : FirQualifiedAccessChecker() { report(FirErrors.NOT_A_SUPERTYPE.on(it)) } } -} \ No newline at end of file +} diff --git a/compiler/fir/checkers/src/org/jetbrains/kotlin/fir/analysis/checkers/expression/FirQualifiedSupertypeExtendedByOtherSupertypeChecker.kt b/compiler/fir/checkers/src/org/jetbrains/kotlin/fir/analysis/checkers/expression/FirQualifiedSupertypeExtendedByOtherSupertypeChecker.kt index b9e7a96ec1b..2de17d7c3d4 100644 --- a/compiler/fir/checkers/src/org/jetbrains/kotlin/fir/analysis/checkers/expression/FirQualifiedSupertypeExtendedByOtherSupertypeChecker.kt +++ b/compiler/fir/checkers/src/org/jetbrains/kotlin/fir/analysis/checkers/expression/FirQualifiedSupertypeExtendedByOtherSupertypeChecker.kt @@ -23,6 +23,7 @@ object FirQualifiedSupertypeExtendedByOtherSupertypeChecker : FirQualifiedAccess override fun check(functionCall: FirQualifiedAccessExpression, context: CheckerContext, reporter: DiagnosticReporter) { // require to be called over a super reference val superReference = functionCall.calleeReference.safeAs() + ?.takeIf { it.hadExplicitTypeInSource() } ?: return val explicitType = superReference.superTypeRef.safeAs() @@ -62,4 +63,4 @@ object FirQualifiedSupertypeExtendedByOtherSupertypeChecker : FirQualifiedAccess report(FirErrors.QUALIFIED_SUPERTYPE_EXTENDED_BY_OTHER_SUPERTYPE.on(it)) } } -} \ No newline at end of file +} diff --git a/compiler/fir/checkers/src/org/jetbrains/kotlin/fir/analysis/checkers/expression/FirSuperNotAvailableChecker.kt b/compiler/fir/checkers/src/org/jetbrains/kotlin/fir/analysis/checkers/expression/FirSuperNotAvailableChecker.kt index dcd3c8a3047..57889e5af0b 100644 --- a/compiler/fir/checkers/src/org/jetbrains/kotlin/fir/analysis/checkers/expression/FirSuperNotAvailableChecker.kt +++ b/compiler/fir/checkers/src/org/jetbrains/kotlin/fir/analysis/checkers/expression/FirSuperNotAvailableChecker.kt @@ -5,23 +5,26 @@ package org.jetbrains.kotlin.fir.analysis.checkers.expression -import org.jetbrains.kotlin.KtNodeTypes.* +import org.jetbrains.kotlin.KtNodeTypes.CLASS +import org.jetbrains.kotlin.KtNodeTypes.OBJECT_LITERAL 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.expressions.FirQualifiedAccessExpression +import org.jetbrains.kotlin.fir.references.FirSuperReference +import org.jetbrains.kotlin.utils.addToStdlib.safeAs object FirSuperNotAvailableChecker : FirQualifiedAccessChecker() { override fun check(functionCall: FirQualifiedAccessExpression, context: CheckerContext, reporter: DiagnosticReporter) { - if (functionCall.source?.elementType == SUPER_EXPRESSION) { - val isInsideClass = context.containingDeclarations.any { - it.source?.elementType == CLASS || it.source?.elementType == OBJECT_LITERAL - } + if (functionCall.calleeReference.safeAs()?.hadExplicitTypeInSource() != true) return - if (!isInsideClass) { - reporter.report(functionCall.source) - } + val isInsideClass = context.containingDeclarations.any { + it.source?.elementType == CLASS || it.source?.elementType == OBJECT_LITERAL + } + + if (!isInsideClass) { + reporter.report(functionCall.source) } } @@ -30,4 +33,4 @@ object FirSuperNotAvailableChecker : FirQualifiedAccessChecker() { report(FirErrors.SUPER_NOT_AVAILABLE.on(it)) } } -} \ No newline at end of file +} diff --git a/compiler/fir/checkers/src/org/jetbrains/kotlin/fir/analysis/checkers/expression/SuperCallCheckers.kt b/compiler/fir/checkers/src/org/jetbrains/kotlin/fir/analysis/checkers/expression/SuperCallCheckers.kt new file mode 100644 index 00000000000..96c2f386116 --- /dev/null +++ b/compiler/fir/checkers/src/org/jetbrains/kotlin/fir/analysis/checkers/expression/SuperCallCheckers.kt @@ -0,0 +1,11 @@ +/* + * Copyright 2010-2020 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.expression + +import org.jetbrains.kotlin.fir.FirFakeSourceElementKind +import org.jetbrains.kotlin.fir.references.FirSuperReference + +fun FirSuperReference.hadExplicitTypeInSource(): Boolean = superTypeRef.source?.kind != FirFakeSourceElementKind.SuperCallImplicitType diff --git a/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/FirCallResolver.kt b/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/FirCallResolver.kt index 708ffe48401..7257a27b4f0 100644 --- a/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/FirCallResolver.kt +++ b/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/FirCallResolver.kt @@ -117,7 +117,7 @@ class FirCallResolver( explicitReceiver.calleeReference as? FirSuperReference ?: return transformExplicitReceiver(transformer, ResolutionMode.ContextIndependent) as Q - transformer.transformSuperReceiver(callee, explicitReceiver) + transformer.transformSuperReceiver(callee, explicitReceiver, this) return this } diff --git a/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/calls/SuperCalls.kt b/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/calls/SuperCalls.kt new file mode 100644 index 00000000000..0722d6dbc53 --- /dev/null +++ b/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/calls/SuperCalls.kt @@ -0,0 +1,147 @@ +/* + * Copyright 2010-2020 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.resolve.calls + +import com.intellij.util.SmartList +import org.jetbrains.kotlin.descriptors.ClassKind +import org.jetbrains.kotlin.descriptors.Modality +import org.jetbrains.kotlin.fir.declarations.FirCallableMemberDeclaration +import org.jetbrains.kotlin.fir.declarations.FirProperty +import org.jetbrains.kotlin.fir.declarations.FirSimpleFunction +import org.jetbrains.kotlin.fir.declarations.modality +import org.jetbrains.kotlin.fir.expressions.FirFunctionCall +import org.jetbrains.kotlin.fir.expressions.FirQualifiedAccess +import org.jetbrains.kotlin.fir.references.FirNamedReference +import org.jetbrains.kotlin.fir.resolve.BodyResolveComponents +import org.jetbrains.kotlin.fir.resolve.scope +import org.jetbrains.kotlin.fir.resolve.toSymbol +import org.jetbrains.kotlin.fir.symbols.StandardClassIds +import org.jetbrains.kotlin.fir.symbols.impl.FirRegularClassSymbol +import org.jetbrains.kotlin.fir.symbols.impl.unwrapSubstitutionOverrides +import org.jetbrains.kotlin.fir.typeContext +import org.jetbrains.kotlin.fir.types.ConeClassLikeType +import org.jetbrains.kotlin.fir.types.ConeKotlinType +import org.jetbrains.kotlin.fir.types.FirResolvedTypeRef +import org.jetbrains.kotlin.fir.types.FirTypeRef +import org.jetbrains.kotlin.name.Name +import org.jetbrains.kotlin.types.AbstractTypeChecker +import org.jetbrains.kotlin.utils.addIfNotNull + +fun BodyResolveComponents.findTypesForSuperCandidates( + superTypeRefs: List, + containingCall: FirQualifiedAccess, +): Collection { + val supertypes = superTypeRefs.map { (it as FirResolvedTypeRef).type } + if (supertypes.size <= 1) return supertypes + + return when (containingCall) { + is FirFunctionCall -> { + val calleeName = containingCall.calleeReference.name + if (isCallingMethodOfAny(containingCall)) { + resolveSupertypesForMethodOfAny(supertypes, calleeName) + } else { + resolveSupertypesByCalleeName(supertypes, calleeName) + } + } + else -> { + resolveSupertypesByPropertyName( + supertypes, + (containingCall.calleeReference as? FirNamedReference)?.name ?: return emptyList() + ) + } + } +} + +private val ARITY_OF_METHODS_OF_ANY = hashMapOf("hashCode" to 0, "equals" to 1, "toString" to 0) + +private fun isCallingMethodOfAny(callExpression: FirFunctionCall): Boolean = + ARITY_OF_METHODS_OF_ANY.getOrElse(callExpression.calleeReference.name.asString(), { -1 }) == callExpression.argumentList.arguments.size + +private fun BodyResolveComponents.resolveSupertypesForMethodOfAny( + supertypes: Collection, + calleeName: Name +): Collection { + val typesWithConcreteOverride = resolveSupertypesByMembers(supertypes, false) { + getFunctionMembers(it, calleeName) + } + return if (typesWithConcreteOverride.isNotEmpty()) + typesWithConcreteOverride + else + listOf(session.builtinTypes.anyType.type) +} + +private fun BodyResolveComponents.resolveSupertypesByCalleeName(supertypes: Collection, calleeName: Name): Collection = + resolveSupertypesByMembers(supertypes, true) { + getFunctionMembers(it, calleeName) + + getPropertyMembers(it, calleeName) + } + +private fun BodyResolveComponents.resolveSupertypesByPropertyName(supertypes: Collection, propertyName: Name): Collection = + resolveSupertypesByMembers(supertypes, true) { + getPropertyMembers(it, propertyName) + } + +private inline fun BodyResolveComponents.resolveSupertypesByMembers( + supertypes: Collection, + allowNonConcreteMembers: Boolean, + getMembers: (ConeKotlinType) -> Collection> +): Collection { + val typesWithConcreteMembers = SmartList() + val typesWithNonConcreteMembers = SmartList() + + for (supertype in supertypes) { + val members = getMembers(supertype) + if (members.isNotEmpty()) { + if (members.any { isConcreteMember(supertype, it) }) + typesWithConcreteMembers.add(supertype) + else + typesWithNonConcreteMembers.add(supertype) + } + } + + typesWithConcreteMembers.removeAll { typeWithConcreteMember -> + typesWithNonConcreteMembers.any { typeWithNonConcreteMember -> + AbstractTypeChecker.isSubtypeOf(session.typeContext, typeWithNonConcreteMember, typeWithConcreteMember) + } + } + + return when { + typesWithConcreteMembers.isNotEmpty() -> + typesWithConcreteMembers + allowNonConcreteMembers -> + typesWithNonConcreteMembers + else -> + emptyList() + } +} + +@OptIn(ExperimentalStdlibApi::class) +private fun BodyResolveComponents.getFunctionMembers(type: ConeKotlinType, name: Name): Collection> = buildList { + type.scope(session, scopeSession)?.processFunctionsByName(name) { + addIfNotNull(it.fir as? FirSimpleFunction) + } +} + +@OptIn(ExperimentalStdlibApi::class) +private fun BodyResolveComponents.getPropertyMembers(type: ConeKotlinType, name: Name): Collection> = buildList { + type.scope(session, scopeSession)?.processPropertiesByName(name) { + addIfNotNull(it.fir as? FirProperty) + } +} + + +private fun BodyResolveComponents.isConcreteMember(supertype: ConeKotlinType, member: FirCallableMemberDeclaration<*>): Boolean { + // "Concrete member" is a function or a property that is not abstract, + // and is not an implicit fake override for a method of Any on an interface. + + if (member.modality == Modality.ABSTRACT) + return false + + val classSymbol = + (supertype as? ConeClassLikeType)?.lookupTag?.toSymbol(session) as? FirRegularClassSymbol ?: return true + if (classSymbol.fir.classKind != ClassKind.INTERFACE) return true + return member.symbol.unwrapSubstitutionOverrides().callableId.classId != StandardClassIds.Any +} diff --git a/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/transformers/body/resolve/FirExpressionsResolveTransformer.kt b/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/transformers/body/resolve/FirExpressionsResolveTransformer.kt index a270d2c3e40..d1b2700dee8 100644 --- a/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/transformers/body/resolve/FirExpressionsResolveTransformer.kt +++ b/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/transformers/body/resolve/FirExpressionsResolveTransformer.kt @@ -15,7 +15,6 @@ import org.jetbrains.kotlin.fir.diagnostics.DiagnosticKind import org.jetbrains.kotlin.fir.expressions.* import org.jetbrains.kotlin.fir.expressions.builder.buildErrorExpression import org.jetbrains.kotlin.fir.expressions.builder.buildFunctionCall -import org.jetbrains.kotlin.fir.expressions.builder.buildVarargArgumentsExpression import org.jetbrains.kotlin.fir.expressions.builder.buildVariableAssignment import org.jetbrains.kotlin.fir.references.* import org.jetbrains.kotlin.fir.references.builder.buildErrorNamedReference @@ -39,7 +38,6 @@ import org.jetbrains.kotlin.fir.visitors.* import org.jetbrains.kotlin.name.ClassId import org.jetbrains.kotlin.name.Name import org.jetbrains.kotlin.types.Variance -import kotlin.math.min open class FirExpressionsResolveTransformer(transformer: FirBodyResolveTransformer) : FirPartialBodyResolveTransformer(transformer) { private inline val builtinTypes: BuiltinTypes get() = session.builtinTypes @@ -84,7 +82,7 @@ open class FirExpressionsResolveTransformer(transformer: FirBodyResolveTransform qualifiedAccessExpression } is FirSuperReference -> { - transformSuperReceiver(callee, qualifiedAccessExpression) + transformSuperReceiver(callee, qualifiedAccessExpression, null) } is FirDelegateFieldReference -> { val delegateFieldSymbol = callee.resolvedSymbol @@ -126,7 +124,8 @@ open class FirExpressionsResolveTransformer(transformer: FirBodyResolveTransform fun transformSuperReceiver( superReference: FirSuperReference, - superReferenceContainer: FirQualifiedAccessExpression + superReferenceContainer: FirQualifiedAccessExpression, + containingCall: FirQualifiedAccess? ): FirQualifiedAccessExpression { val labelName = superReference.labelName val implicitReceiver = @@ -146,21 +145,26 @@ open class FirExpressionsResolveTransformer(transformer: FirBodyResolveTransform else -> { val superTypeRefs = implicitReceiver?.boundSymbol?.phasedFir?.superTypeRefs val resultType = when { - superTypeRefs?.isNotEmpty() != true -> { + superTypeRefs?.isNotEmpty() != true || containingCall == null -> { buildErrorTypeRef { source = superReferenceContainer.source // NB: NOT_A_SUPERTYPE is reported by a separate checker diagnostic = ConeStubDiagnostic(ConeSimpleDiagnostic("No super type", DiagnosticKind.Other)) } } - superTypeRefs.size == 1 -> { - superTypeRefs.single() - } else -> { - buildComposedSuperTypeRef { - source = superReferenceContainer.source - superTypeRefs.mapTo(this.superTypeRefs) { it as FirResolvedTypeRef } - } + val types = components.findTypesForSuperCandidates(superTypeRefs, containingCall) + if (types.size == 1) + buildResolvedTypeRef { + source = superReferenceContainer.source?.fakeElement(FirFakeSourceElementKind.SuperCallImplicitType) + type = types.single() + } + else + buildErrorTypeRef { + source = superReferenceContainer.source + // NB: NOT_A_SUPERTYPE is reported by a separate checker + diagnostic = ConeStubDiagnostic(ConeSimpleDiagnostic("Ambiguous supertype", DiagnosticKind.Other)) + } } } superReferenceContainer.resultType = resultType diff --git a/compiler/fir/tree/src/org/jetbrains/kotlin/fir/FirSourceElement.kt b/compiler/fir/tree/src/org/jetbrains/kotlin/fir/FirSourceElement.kt index b67f60730a5..22291a1f0aa 100644 --- a/compiler/fir/tree/src/org/jetbrains/kotlin/fir/FirSourceElement.kt +++ b/compiler/fir/tree/src/org/jetbrains/kotlin/fir/FirSourceElement.kt @@ -138,6 +138,10 @@ sealed class FirFakeSourceElementKind : FirSourceElementKind() { // a ?: b --> when(val $subj = a) { .... } // where `val $subj = a` has a fake source object WhenGeneratedSubject : FirFakeSourceElementKind() + + // super.foo() --> super.foo() + // where `Supertype` has a fake source + object SuperCallImplicitType : FirFakeSourceElementKind() } sealed class FirSourceElement { diff --git a/compiler/testData/codegen/box/super/unqualifiedSuperWithMethodsOfAny.kt b/compiler/testData/codegen/box/super/unqualifiedSuperWithMethodsOfAny.kt index 139f159c416..b1c70b0cb01 100644 --- a/compiler/testData/codegen/box/super/unqualifiedSuperWithMethodsOfAny.kt +++ b/compiler/testData/codegen/box/super/unqualifiedSuperWithMethodsOfAny.kt @@ -1,4 +1,3 @@ -// IGNORE_BACKEND_FIR: JVM_IR interface ISomething open class ClassWithToString { @@ -23,4 +22,4 @@ fun box(): String { C2().toString() != "C" -> "Failed #2" else -> "OK" } -} \ No newline at end of file +} diff --git a/compiler/testData/diagnostics/tests/SafeCallOnSuperReceiver.fir.kt b/compiler/testData/diagnostics/tests/SafeCallOnSuperReceiver.fir.kt index 0f1d94e9d7a..4051b477f9f 100644 --- a/compiler/testData/diagnostics/tests/SafeCallOnSuperReceiver.fir.kt +++ b/compiler/testData/diagnostics/tests/SafeCallOnSuperReceiver.fir.kt @@ -6,6 +6,6 @@ open class A { class B : A() { fun g() { - super?.f() + super?.f() } -} \ No newline at end of file +} diff --git a/compiler/testData/diagnostics/tests/enum/kt8972_cloneNotAllowed.fir.kt b/compiler/testData/diagnostics/tests/enum/kt8972_cloneNotAllowed.fir.kt index fe81d8c5036..b37092ccccf 100644 --- a/compiler/testData/diagnostics/tests/enum/kt8972_cloneNotAllowed.fir.kt +++ b/compiler/testData/diagnostics/tests/enum/kt8972_cloneNotAllowed.fir.kt @@ -2,6 +2,6 @@ enum class E : Cloneable { A; override fun clone(): Any { - return super.clone() + return super.clone() } } diff --git a/compiler/testData/diagnostics/tests/thisAndSuper/unqualifiedSuper/ambiguousSuperWithGenerics.fir.kt b/compiler/testData/diagnostics/tests/thisAndSuper/unqualifiedSuper/ambiguousSuperWithGenerics.fir.kt index 3ed2ab250f5..533cd0a0fe3 100644 --- a/compiler/testData/diagnostics/tests/thisAndSuper/unqualifiedSuper/ambiguousSuperWithGenerics.fir.kt +++ b/compiler/testData/diagnostics/tests/thisAndSuper/unqualifiedSuper/ambiguousSuperWithGenerics.fir.kt @@ -14,7 +14,7 @@ class GenericDerivedClass : GenericBaseClass(), GenericBaseInterface { override fun bar(x: T): T = super.bar(x) override fun ambiguous(x: T): T = - super.ambiguous(x) + super.ambiguous(x) } class SpecializedDerivedClass : GenericBaseClass(), GenericBaseInterface { @@ -22,9 +22,9 @@ class SpecializedDerivedClass : GenericBaseClass(), GenericBaseInterfaceambiguous(x) override fun ambiguous(x: Int): Int = - super.ambiguous(x) + super.ambiguous(x) } class MixedDerivedClass : GenericBaseClass(), GenericBaseInterface { @@ -32,7 +32,7 @@ class MixedDerivedClass : GenericBaseClass(), GenericBaseInterface { override fun bar(x: T): T = super.bar(x) override fun ambiguous(x: Int): Int = - super.ambiguous(x) + super.ambiguous(x) override fun ambiguous(x: T): T = - super.ambiguous(x) -} \ No newline at end of file + super.ambiguous(x) +} diff --git a/compiler/testData/diagnostics/tests/thisAndSuper/unqualifiedSuper/unqualifiedSuper.fir.kt b/compiler/testData/diagnostics/tests/thisAndSuper/unqualifiedSuper/unqualifiedSuper.fir.kt index 7d385c599cb..c313f2bce4f 100644 --- a/compiler/testData/diagnostics/tests/thisAndSuper/unqualifiedSuper/unqualifiedSuper.fir.kt +++ b/compiler/testData/diagnostics/tests/thisAndSuper/unqualifiedSuper/unqualifiedSuper.fir.kt @@ -45,13 +45,13 @@ class Derived : Base(), Interface { super.prop fun getAmbiguousSuperProp(): Int = - super.ambiguousProp + super.ambiguousProp fun callsFunFromSuperInterface() { super.bar() } fun callsAmbiguousSuperFun() { - super.ambiguous() + super.ambiguous() } } diff --git a/compiler/testData/diagnostics/tests/thisAndSuper/unqualifiedSuper/unqualifiedSuperWithAbstractMembers.fir.kt b/compiler/testData/diagnostics/tests/thisAndSuper/unqualifiedSuper/unqualifiedSuperWithAbstractMembers.fir.kt index a3435563189..71ac4fc5214 100644 --- a/compiler/testData/diagnostics/tests/thisAndSuper/unqualifiedSuper/unqualifiedSuperWithAbstractMembers.fir.kt +++ b/compiler/testData/diagnostics/tests/thisAndSuper/unqualifiedSuper/unqualifiedSuperWithAbstractMembers.fir.kt @@ -34,6 +34,6 @@ class B : A(), I { } override fun qux() { - super.qux() + super.qux() } } diff --git a/compiler/testData/diagnostics/tests/thisAndSuper/unqualifiedSuper/unqualifiedSuperWithCallableProperty.fir.kt b/compiler/testData/diagnostics/tests/thisAndSuper/unqualifiedSuper/unqualifiedSuperWithCallableProperty.fir.kt index 0fa5ad351c5..b1737bd4527 100644 --- a/compiler/testData/diagnostics/tests/thisAndSuper/unqualifiedSuper/unqualifiedSuperWithCallableProperty.fir.kt +++ b/compiler/testData/diagnostics/tests/thisAndSuper/unqualifiedSuper/unqualifiedSuperWithCallableProperty.fir.kt @@ -14,8 +14,8 @@ interface InterfaceWithFun { class DerivedUsingFun : BaseWithCallableProp(), InterfaceWithFun { fun foo(): String = - super.fn() + super.fn() override fun bar(): String = super.bar() -} \ No newline at end of file +} diff --git a/compiler/testData/diagnostics/tests/thisAndSuper/unqualifiedSuper/unqualifiedSuperWithInterfaces.fir.kt b/compiler/testData/diagnostics/tests/thisAndSuper/unqualifiedSuper/unqualifiedSuperWithInterfaces.fir.kt index 2febf879ae5..1161008ac0f 100644 --- a/compiler/testData/diagnostics/tests/thisAndSuper/unqualifiedSuper/unqualifiedSuperWithInterfaces.fir.kt +++ b/compiler/testData/diagnostics/tests/thisAndSuper/unqualifiedSuper/unqualifiedSuperWithInterfaces.fir.kt @@ -20,9 +20,9 @@ interface AnotherInterface { interface DerivedInterface: Interface, AnotherInterface { override fun foo() { super.foo() } override fun ambiguous() { - super.ambiguous() + super.ambiguous() } override val ambiguousProp: Int - get() = super.ambiguousProp + get() = super.ambiguousProp } diff --git a/compiler/testData/diagnostics/tests/thisAndSuper/unqualifiedSuper/unqualifiedSuperWithUnresolvedBase.fir.kt b/compiler/testData/diagnostics/tests/thisAndSuper/unqualifiedSuper/unqualifiedSuperWithUnresolvedBase.fir.kt index dc242d5da8f..655be3d83df 100644 --- a/compiler/testData/diagnostics/tests/thisAndSuper/unqualifiedSuper/unqualifiedSuperWithUnresolvedBase.fir.kt +++ b/compiler/testData/diagnostics/tests/thisAndSuper/unqualifiedSuper/unqualifiedSuperWithUnresolvedBase.fir.kt @@ -41,13 +41,13 @@ class ClassDerivedFromUnresolved : Base(), Interface, Unresolved { super.prop fun getAmbiguousSuperProp(): Int = - super.ambiguousProp + super.ambiguousProp fun callsFunFromSuperInterface() { super.bar() } fun callsAmbiguousSuperFun() { - super.ambiguous() + super.ambiguous() } } diff --git a/compiler/testData/diagnostics/tests/thisAndSuper/unqualifiedSuper/withMethodOverriddenInAnotherSupertype.fir.kt b/compiler/testData/diagnostics/tests/thisAndSuper/unqualifiedSuper/withMethodOverriddenInAnotherSupertype.fir.kt deleted file mode 100644 index 48e22295f09..00000000000 --- a/compiler/testData/diagnostics/tests/thisAndSuper/unqualifiedSuper/withMethodOverriddenInAnotherSupertype.fir.kt +++ /dev/null @@ -1,29 +0,0 @@ -interface A { - fun foo() {} -} - -abstract class C : A { - override abstract fun foo() -} - -interface Unrelated { - fun foo() {} -} - -class Test1 : C(), A { - override fun foo() { - // Abstract 'foo' defined in 'C' wins against non-abstract 'foo' defined in 'A', - // because 'C' is a subclass of 'A' (and 'C::foo' overrides 'A::foo'), - // even though 'A' is explicitly listed in supertypes list for 'D'. - super.foo() - } -} - -class Test2 : C(), A, Unrelated { - override fun foo() { - // This is ok, because there's a non-abstract 'foo' in 'Unrelated', - // which is not overridden by abstract 'foo' in 'C'. - super.foo() - super.foo() - } -} \ No newline at end of file diff --git a/compiler/testData/diagnostics/tests/thisAndSuper/unqualifiedSuper/withMethodOverriddenInAnotherSupertype.kt b/compiler/testData/diagnostics/tests/thisAndSuper/unqualifiedSuper/withMethodOverriddenInAnotherSupertype.kt index 3a004145de5..f90620586a3 100644 --- a/compiler/testData/diagnostics/tests/thisAndSuper/unqualifiedSuper/withMethodOverriddenInAnotherSupertype.kt +++ b/compiler/testData/diagnostics/tests/thisAndSuper/unqualifiedSuper/withMethodOverriddenInAnotherSupertype.kt @@ -1,3 +1,4 @@ +// FIR_IDENTICAL interface A { fun foo() {} } diff --git a/compiler/testData/diagnostics/testsWithStdLib/annotations/jvmDefault/superCall.fir.kt b/compiler/testData/diagnostics/testsWithStdLib/annotations/jvmDefault/superCall.fir.kt index 2100cb3dd5d..e9100064875 100644 --- a/compiler/testData/diagnostics/testsWithStdLib/annotations/jvmDefault/superCall.fir.kt +++ b/compiler/testData/diagnostics/testsWithStdLib/annotations/jvmDefault/superCall.fir.kt @@ -41,7 +41,7 @@ class ManySupers: Foo2(), B { fun foo() { super.test() super<B>.test() - super.test() + super.test() } } @@ -49,7 +49,7 @@ class ManySupers2: Foo2(), C { fun foo() { super.test() super.test() - super.test() + super.test() } } @@ -57,6 +57,6 @@ class ManySupers3: Bar2(), C { fun foo() { super.test() super.test() - super.test() + super.test() } -} \ No newline at end of file +}