Provide migration of Any functions via super in abstract case
Related to KT-38078
This commit is contained in:
@@ -120,6 +120,7 @@ public interface BindingContext {
|
||||
WritableSlice<KtExpression, DoubleColonLHS> DOUBLE_COLON_LHS = new BasicWritableSlice<>(DO_NOTHING);
|
||||
|
||||
WritableSlice<KtSuperExpression, KotlinType> THIS_TYPE_FOR_SUPER_EXPRESSION = new BasicWritableSlice<>(DO_NOTHING);
|
||||
WritableSlice<KtSuperExpression, Boolean> SUPER_EXPRESSION_FROM_ANY_MIGRATION = Slices.createSimpleSlice();
|
||||
|
||||
WritableSlice<KtReferenceExpression, DeclarationDescriptor> 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
|
||||
|
||||
+12
-2
@@ -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 -> {
|
||||
|
||||
+1
-1
@@ -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));
|
||||
}
|
||||
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
|
||||
+7
-3
@@ -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<KotlinType> supertypesResolvedFromContext =
|
||||
Pair<Collection<KotlinType>, Boolean> supertypesResolvedFromContextWithEqualsMigration =
|
||||
UnqualifiedSuperKt.resolveUnqualifiedSuperFromExpressionContext(
|
||||
expression, supertypes, components.builtIns.getAnyType());
|
||||
Collection<KotlinType> 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);
|
||||
|
||||
+13
-13
@@ -37,7 +37,7 @@ fun resolveUnqualifiedSuperFromExpressionContext(
|
||||
superExpression: KtSuperExpression,
|
||||
supertypes: Collection<KotlinType>,
|
||||
anyType: KotlinType
|
||||
): Collection<KotlinType> {
|
||||
): Pair<Collection<KotlinType>, 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<KotlinType>() 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<KotlinType>,
|
||||
calleeName: Name,
|
||||
anyType: KotlinType
|
||||
): Collection<KotlinType> {
|
||||
val typesWithConcreteOverride = resolveSupertypesByMembers(supertypes, allowNonConcreteInterfaceMembers = false) {
|
||||
): Pair<Collection<KotlinType>, 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<KotlinType>, calleeName: Name): Collection<KotlinType> =
|
||||
resolveSupertypesByMembers(supertypes, allowNonConcreteInterfaceMembers = true) {
|
||||
getFunctionMembers(it, calleeName) +
|
||||
getPropertyMembers(it, calleeName)
|
||||
}
|
||||
}.first
|
||||
|
||||
private fun resolveSupertypesByPropertyName(supertypes: Collection<KotlinType>, propertyName: Name): Collection<KotlinType> =
|
||||
resolveSupertypesByMembers(supertypes, allowNonConcreteInterfaceMembers = true) {
|
||||
getPropertyMembers(it, propertyName)
|
||||
}
|
||||
}.first
|
||||
|
||||
private inline fun resolveSupertypesByMembers(
|
||||
supertypes: Collection<KotlinType>,
|
||||
allowNonConcreteInterfaceMembers: Boolean,
|
||||
getMembers: (KotlinType) -> Collection<CallableMemberDescriptor>
|
||||
): Collection<KotlinType> {
|
||||
): Pair<Collection<KotlinType>, Boolean> {
|
||||
val typesWithConcreteMembers = SmartList<KotlinType>()
|
||||
val typesWithNonConcreteMembers = SmartList<KotlinType>()
|
||||
|
||||
@@ -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
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
+2
-3
@@ -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) {
|
||||
|
||||
+1
-1
@@ -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)
|
||||
}
|
||||
|
||||
+25
@@ -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<Derived>.<!ABSTRACT_SUPER_CALL_WARNING!>check<!>()
|
||||
return super.<!ABSTRACT_SUPER_CALL_WARNING!>check<!>()
|
||||
}
|
||||
}
|
||||
|
||||
abstract class A {
|
||||
abstract override fun hashCode(): Int
|
||||
}
|
||||
|
||||
interface I
|
||||
|
||||
class B : A(), I { // I is necessary here
|
||||
override fun hashCode() = super.<!ABSTRACT_SUPER_CALL!>hashCode<!>()
|
||||
}
|
||||
+2
-3
@@ -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.<!ABSTRACT_SUPER_CALL!>hashCode<!>()
|
||||
override fun hashCode() = super.<!ABSTRACT_SUPER_CALL_WARNING!>hashCode<!>()
|
||||
}
|
||||
|
||||
Vendored
+1
-1
@@ -1,5 +1,5 @@
|
||||
// FIR_IDENTICAL
|
||||
// !LANGUAGE: +ForbidSuperDelegationToAbstractFakeOverride
|
||||
// !LANGUAGE: +ForbidSuperDelegationToAbstractFakeOverride +ForbidSuperDelegationToAbstractAnyMethod
|
||||
interface Foo {
|
||||
fun check(): String = "OK"
|
||||
}
|
||||
|
||||
@@ -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
|
||||
|
||||
|
||||
Reference in New Issue
Block a user