diff --git a/compiler/frontend/src/org/jetbrains/kotlin/resolve/BindingContext.java b/compiler/frontend/src/org/jetbrains/kotlin/resolve/BindingContext.java index 6d3336c42dc..4c0d0c901c3 100644 --- a/compiler/frontend/src/org/jetbrains/kotlin/resolve/BindingContext.java +++ b/compiler/frontend/src/org/jetbrains/kotlin/resolve/BindingContext.java @@ -120,6 +120,7 @@ public interface BindingContext { WritableSlice DOUBLE_COLON_LHS = new BasicWritableSlice<>(DO_NOTHING); WritableSlice THIS_TYPE_FOR_SUPER_EXPRESSION = new BasicWritableSlice<>(DO_NOTHING); + WritableSlice SUPER_EXPRESSION_FROM_ANY_MIGRATION = Slices.createSimpleSlice(); WritableSlice REFERENCE_TARGET = new BasicWritableSlice<>(DO_NOTHING); // if 'A' really means 'A.Companion' then this slice stores class descriptor for A, REFERENCE_TARGET stores descriptor Companion in this case diff --git a/compiler/frontend/src/org/jetbrains/kotlin/resolve/calls/DiagnosticReporterByTrackingStrategy.kt b/compiler/frontend/src/org/jetbrains/kotlin/resolve/calls/DiagnosticReporterByTrackingStrategy.kt index 843c82bf358..b6cfeeb863b 100644 --- a/compiler/frontend/src/org/jetbrains/kotlin/resolve/calls/DiagnosticReporterByTrackingStrategy.kt +++ b/compiler/frontend/src/org/jetbrains/kotlin/resolve/calls/DiagnosticReporterByTrackingStrategy.kt @@ -76,12 +76,22 @@ class DiagnosticReporterByTrackingStrategy( (diagnostic as NoValueForParameter).parameterDescriptor ) InstantiationOfAbstractClass::class.java -> tracingStrategy.instantiationOfAbstractClass(trace) - AbstractSuperCall::class.java -> tracingStrategy.abstractSuperCall(trace) + AbstractSuperCall::class.java -> { + val superExpression = (diagnostic as AbstractSuperCall).receiver.psiExpression as? KtSuperExpression + if (context.languageVersionSettings.supportsFeature(LanguageFeature.ForbidSuperDelegationToAbstractAnyMethod) || + superExpression == null || + trace[BindingContext.SUPER_EXPRESSION_FROM_ANY_MIGRATION, superExpression] != true + ) { + tracingStrategy.abstractSuperCall(trace) + } else { + tracingStrategy.abstractSuperCallWarning(trace) + } + } AbstractFakeOverrideSuperCall::class.java -> { if (context.languageVersionSettings.supportsFeature(LanguageFeature.ForbidSuperDelegationToAbstractFakeOverride)) { tracingStrategy.abstractSuperCall(trace) } else { - tracingStrategy.abstractFakeOverrideSuperCall(trace) + tracingStrategy.abstractSuperCallWarning(trace) } } NonApplicableCallForBuilderInferenceDiagnostic::class.java -> { diff --git a/compiler/frontend/src/org/jetbrains/kotlin/resolve/calls/tasks/AbstractTracingStrategy.java b/compiler/frontend/src/org/jetbrains/kotlin/resolve/calls/tasks/AbstractTracingStrategy.java index 66e920b8053..baf7d4f2e29 100644 --- a/compiler/frontend/src/org/jetbrains/kotlin/resolve/calls/tasks/AbstractTracingStrategy.java +++ b/compiler/frontend/src/org/jetbrains/kotlin/resolve/calls/tasks/AbstractTracingStrategy.java @@ -143,7 +143,7 @@ public abstract class AbstractTracingStrategy implements TracingStrategy { } @Override - public void abstractFakeOverrideSuperCall(@NotNull BindingTrace trace) { + public void abstractSuperCallWarning(@NotNull BindingTrace trace) { trace.report(ABSTRACT_SUPER_CALL_WARNING.on(reference)); } diff --git a/compiler/frontend/src/org/jetbrains/kotlin/resolve/calls/tasks/TracingStrategy.java b/compiler/frontend/src/org/jetbrains/kotlin/resolve/calls/tasks/TracingStrategy.java index 3b01a0351e5..04ab20a8ee9 100644 --- a/compiler/frontend/src/org/jetbrains/kotlin/resolve/calls/tasks/TracingStrategy.java +++ b/compiler/frontend/src/org/jetbrains/kotlin/resolve/calls/tasks/TracingStrategy.java @@ -148,7 +148,7 @@ public interface TracingStrategy { void abstractSuperCall(@NotNull BindingTrace trace); - default void abstractFakeOverrideSuperCall(@NotNull BindingTrace trace) { + default void abstractSuperCallWarning(@NotNull BindingTrace trace) { abstractSuperCall(trace); } diff --git a/compiler/frontend/src/org/jetbrains/kotlin/types/expressions/BasicExpressionTypingVisitor.java b/compiler/frontend/src/org/jetbrains/kotlin/types/expressions/BasicExpressionTypingVisitor.java index de0e8a1aa19..526f2965155 100644 --- a/compiler/frontend/src/org/jetbrains/kotlin/types/expressions/BasicExpressionTypingVisitor.java +++ b/compiler/frontend/src/org/jetbrains/kotlin/types/expressions/BasicExpressionTypingVisitor.java @@ -22,6 +22,7 @@ import com.intellij.psi.StubBasedPsiElement; import com.intellij.psi.tree.IElementType; import com.intellij.psi.tree.TokenSet; import com.intellij.psi.util.PsiTreeUtil; +import kotlin.Pair; import kotlin.TuplesKt; import kotlin.collections.CollectionsKt; import org.jetbrains.annotations.NotNull; @@ -46,7 +47,6 @@ import org.jetbrains.kotlin.resolve.*; import org.jetbrains.kotlin.resolve.bindingContextUtil.BindingContextUtilsKt; import org.jetbrains.kotlin.resolve.calls.ArgumentTypeResolver; import org.jetbrains.kotlin.resolve.calls.CallExpressionResolver; -import org.jetbrains.kotlin.resolve.calls.util.CallUtilKt; import org.jetbrains.kotlin.resolve.calls.checkers.*; import org.jetbrains.kotlin.resolve.calls.model.DataFlowInfoForArgumentsImpl; import org.jetbrains.kotlin.resolve.calls.model.ResolvedCall; @@ -62,13 +62,13 @@ import org.jetbrains.kotlin.resolve.calls.tasks.OldResolutionCandidate; import org.jetbrains.kotlin.resolve.calls.tasks.TracingStrategy; import org.jetbrains.kotlin.resolve.calls.tower.NewAbstractResolvedCall; import org.jetbrains.kotlin.resolve.calls.util.CallMaker; +import org.jetbrains.kotlin.resolve.calls.util.CallUtilKt; import org.jetbrains.kotlin.resolve.checkers.UnderscoreChecker; import org.jetbrains.kotlin.resolve.constants.*; import org.jetbrains.kotlin.resolve.scopes.LexicalScopeKind; import org.jetbrains.kotlin.resolve.scopes.LexicalWritableScope; import org.jetbrains.kotlin.resolve.scopes.receivers.ContextReceiver; import org.jetbrains.kotlin.resolve.scopes.receivers.ExpressionReceiver; -import org.jetbrains.kotlin.resolve.scopes.receivers.ExtensionReceiver; import org.jetbrains.kotlin.resolve.scopes.receivers.ReceiverValue; import org.jetbrains.kotlin.resolve.scopes.utils.ScopeUtilsKt; import org.jetbrains.kotlin.types.*; @@ -512,9 +512,13 @@ public class BasicExpressionTypingVisitor extends ExpressionTypingVisitor { } else { if (UnqualifiedSuperKt.isPossiblyAmbiguousUnqualifiedSuper(expression, supertypes)) { - Collection supertypesResolvedFromContext = + Pair, Boolean> supertypesResolvedFromContextWithEqualsMigration = UnqualifiedSuperKt.resolveUnqualifiedSuperFromExpressionContext( expression, supertypes, components.builtIns.getAnyType()); + Collection supertypesResolvedFromContext = supertypesResolvedFromContextWithEqualsMigration.getFirst(); + if (supertypesResolvedFromContextWithEqualsMigration.getSecond()) { + context.trace.record(SUPER_EXPRESSION_FROM_ANY_MIGRATION, expression, true); + } if (supertypesResolvedFromContext.size() == 1) { KotlinType singleResolvedType = supertypesResolvedFromContext.iterator().next(); result = substitutor.substitute(singleResolvedType, Variance.INVARIANT); diff --git a/compiler/frontend/src/org/jetbrains/kotlin/types/expressions/unqualifiedSuper/unqualifiedSuper.kt b/compiler/frontend/src/org/jetbrains/kotlin/types/expressions/unqualifiedSuper/unqualifiedSuper.kt index 9383d176dc7..99abfe86d78 100644 --- a/compiler/frontend/src/org/jetbrains/kotlin/types/expressions/unqualifiedSuper/unqualifiedSuper.kt +++ b/compiler/frontend/src/org/jetbrains/kotlin/types/expressions/unqualifiedSuper/unqualifiedSuper.kt @@ -37,7 +37,7 @@ fun resolveUnqualifiedSuperFromExpressionContext( superExpression: KtSuperExpression, supertypes: Collection, anyType: KotlinType -): Collection { +): Pair, Boolean> { val parentElement = superExpression.parent if (parentElement is KtDotQualifiedExpression) { @@ -50,19 +50,19 @@ fun resolveUnqualifiedSuperFromExpressionContext( return if (isCallingMethodOfAny(selectorExpression, calleeName)) { resolveSupertypesForMethodOfAny(supertypes, calleeName, anyType) } else { - resolveSupertypesByCalleeName(supertypes, calleeName) + resolveSupertypesByCalleeName(supertypes, calleeName) to false } } } is KtSimpleNameExpression -> { // super.x: x can be a property only // NB there are no properties in kotlin.Any - return resolveSupertypesByPropertyName(supertypes, selectorExpression.getReferencedNameAsName()) + return resolveSupertypesByPropertyName(supertypes, selectorExpression.getReferencedNameAsName()) to false } } } - return emptyList() + return emptyList() to false } private val ARITY_OF_METHODS_OF_ANY = hashMapOf("hashCode" to 0, "equals" to 1, "toString" to 0) @@ -99,29 +99,29 @@ private fun resolveSupertypesForMethodOfAny( supertypes: Collection, calleeName: Name, anyType: KotlinType -): Collection { - val typesWithConcreteOverride = resolveSupertypesByMembers(supertypes, allowNonConcreteInterfaceMembers = false) { +): Pair, Boolean> { + val (typesWithConcreteOverride, isEqualsMigration) = resolveSupertypesByMembers(supertypes, allowNonConcreteInterfaceMembers = false) { getFunctionMembers(it, calleeName) } - return typesWithConcreteOverride.ifEmpty { listOf(anyType) } + return typesWithConcreteOverride.ifEmpty { listOf(anyType) } to isEqualsMigration } private fun resolveSupertypesByCalleeName(supertypes: Collection, calleeName: Name): Collection = resolveSupertypesByMembers(supertypes, allowNonConcreteInterfaceMembers = true) { getFunctionMembers(it, calleeName) + getPropertyMembers(it, calleeName) - } + }.first private fun resolveSupertypesByPropertyName(supertypes: Collection, propertyName: Name): Collection = resolveSupertypesByMembers(supertypes, allowNonConcreteInterfaceMembers = true) { getPropertyMembers(it, propertyName) - } + }.first private inline fun resolveSupertypesByMembers( supertypes: Collection, allowNonConcreteInterfaceMembers: Boolean, getMembers: (KotlinType) -> Collection -): Collection { +): Pair, Boolean> { val typesWithConcreteMembers = SmartList() val typesWithNonConcreteMembers = SmartList() @@ -143,13 +143,13 @@ private inline fun resolveSupertypesByMembers( return when { typesWithConcreteMembers.isNotEmpty() -> - typesWithConcreteMembers + typesWithConcreteMembers to false allowNonConcreteInterfaceMembers -> - typesWithNonConcreteMembers + typesWithNonConcreteMembers to false else -> typesWithNonConcreteMembers.filter { TypeUtils.getClassDescriptor(it)?.kind == ClassKind.CLASS - } + } to true } } diff --git a/compiler/resolution/src/org/jetbrains/kotlin/resolve/calls/components/ResolutionParts.kt b/compiler/resolution/src/org/jetbrains/kotlin/resolve/calls/components/ResolutionParts.kt index 8ddd12ebde6..1cabfa42dcc 100644 --- a/compiler/resolution/src/org/jetbrains/kotlin/resolve/calls/components/ResolutionParts.kt +++ b/compiler/resolution/src/org/jetbrains/kotlin/resolve/calls/components/ResolutionParts.kt @@ -812,9 +812,8 @@ internal object CheckSuperExpressionCallPart : ResolutionPart() { if (callComponents.statelessCallbacks.isSuperExpression(resolvedCall.dispatchReceiverArgument)) { if (candidateDescriptor is CallableMemberDescriptor) { if (candidateDescriptor.modality == Modality.ABSTRACT) { - addDiagnostic(AbstractSuperCall) - } - if (candidateDescriptor.kind == CallableMemberDescriptor.Kind.FAKE_OVERRIDE && + addDiagnostic(AbstractSuperCall(resolvedCall.dispatchReceiverArgument!!)) + } else if (candidateDescriptor.kind == CallableMemberDescriptor.Kind.FAKE_OVERRIDE && candidateDescriptor.overriddenDescriptors.size > 1 ) { if (candidateDescriptor.overriddenDescriptors.firstOrNull { !it.isInsideInterface }?.modality == Modality.ABSTRACT) { diff --git a/compiler/resolution/src/org/jetbrains/kotlin/resolve/calls/model/KotlinCallDiagnostics.kt b/compiler/resolution/src/org/jetbrains/kotlin/resolve/calls/model/KotlinCallDiagnostics.kt index 437a2fc9a8b..ca5051393a6 100644 --- a/compiler/resolution/src/org/jetbrains/kotlin/resolve/calls/model/KotlinCallDiagnostics.kt +++ b/compiler/resolution/src/org/jetbrains/kotlin/resolve/calls/model/KotlinCallDiagnostics.kt @@ -202,7 +202,7 @@ object InstantiationOfAbstractClass : KotlinCallDiagnostic(RUNTIME_ERROR) { override fun report(reporter: DiagnosticReporter) = reporter.onCall(this) } -object AbstractSuperCall : KotlinCallDiagnostic(RUNTIME_ERROR) { +class AbstractSuperCall(val receiver: SimpleKotlinCallArgument) : KotlinCallDiagnostic(RUNTIME_ERROR) { override fun report(reporter: DiagnosticReporter) { reporter.onCall(this) } diff --git a/compiler/testData/diagnostics/tests/java8Overrides/abstractFakeOverrideSuperCall.fir.kt b/compiler/testData/diagnostics/tests/java8Overrides/abstractFakeOverrideSuperCall.fir.kt new file mode 100644 index 00000000000..101d135ec42 --- /dev/null +++ b/compiler/testData/diagnostics/tests/java8Overrides/abstractFakeOverrideSuperCall.fir.kt @@ -0,0 +1,25 @@ +// !LANGUAGE: -ForbidSuperDelegationToAbstractFakeOverride -ForbidSuperDelegationToAbstractAnyMethod +interface Foo { + fun check(): String = "OK" +} +abstract class Base { + abstract fun check(): String +} +abstract class Derived : Base(), Foo + +class Derived2 : Derived() { + override fun check(): String { + super.check() + return super.check() + } +} + +abstract class A { + abstract override fun hashCode(): Int +} + +interface I + +class B : A(), I { // I is necessary here + override fun hashCode() = super.hashCode() +} diff --git a/compiler/testData/diagnostics/tests/java8Overrides/abstractFakeOverrideSuperCall.kt b/compiler/testData/diagnostics/tests/java8Overrides/abstractFakeOverrideSuperCall.kt index e162e5c822d..2610525053a 100644 --- a/compiler/testData/diagnostics/tests/java8Overrides/abstractFakeOverrideSuperCall.kt +++ b/compiler/testData/diagnostics/tests/java8Overrides/abstractFakeOverrideSuperCall.kt @@ -1,5 +1,4 @@ -// FIR_IDENTICAL -// !LANGUAGE: -ForbidSuperDelegationToAbstractFakeOverride +// !LANGUAGE: -ForbidSuperDelegationToAbstractFakeOverride -ForbidSuperDelegationToAbstractAnyMethod interface Foo { fun check(): String = "OK" } @@ -22,5 +21,5 @@ abstract class A { interface I class B : A(), I { // I is necessary here - override fun hashCode() = super.hashCode() + override fun hashCode() = super.hashCode() } diff --git a/compiler/testData/diagnostics/tests/java8Overrides/abstractFakeOverrideSuperCallForbidden.kt b/compiler/testData/diagnostics/tests/java8Overrides/abstractFakeOverrideSuperCallForbidden.kt index 2cefc989e18..f6e0c951df5 100644 --- a/compiler/testData/diagnostics/tests/java8Overrides/abstractFakeOverrideSuperCallForbidden.kt +++ b/compiler/testData/diagnostics/tests/java8Overrides/abstractFakeOverrideSuperCallForbidden.kt @@ -1,5 +1,5 @@ // FIR_IDENTICAL -// !LANGUAGE: +ForbidSuperDelegationToAbstractFakeOverride +// !LANGUAGE: +ForbidSuperDelegationToAbstractFakeOverride +ForbidSuperDelegationToAbstractAnyMethod interface Foo { fun check(): String = "OK" } diff --git a/compiler/util/src/org/jetbrains/kotlin/config/LanguageVersionSettings.kt b/compiler/util/src/org/jetbrains/kotlin/config/LanguageVersionSettings.kt index b4ddb326ed2..409db41e497 100644 --- a/compiler/util/src/org/jetbrains/kotlin/config/LanguageVersionSettings.kt +++ b/compiler/util/src/org/jetbrains/kotlin/config/LanguageVersionSettings.kt @@ -253,7 +253,8 @@ enum class LanguageFeature( ProhibitConfusingSyntaxInWhenBranches(KOTLIN_1_8, kind = BUG_FIX), // KT-48385 UseConsistentRulesForPrivateConstructorsOfSealedClasses(sinceVersion = KOTLIN_1_8, kind = BUG_FIX), // KT-44866 ProgressionsChangingResolve(KOTLIN_1_8), // KT-49276 - ForbidSuperDelegationToAbstractFakeOverride(KOTLIN_1_8), // KT-49017 (+ KT-38078) + ForbidSuperDelegationToAbstractFakeOverride(KOTLIN_1_8), // KT-49017 + ForbidSuperDelegationToAbstractAnyMethod(KOTLIN_1_8), // KT-38078 // 1.9