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
This commit is contained in:
@@ -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()
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -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<R|kotlin/Any|>()
|
||||||
|
}
|
||||||
|
|
||||||
|
public open override fun equals(other: R|kotlin/Any?|): R|kotlin/Boolean| {
|
||||||
|
^equals this@R|/B|.super<R|kotlin/Any|>.R|kotlin/Any.equals|(R|<local>/other|)
|
||||||
|
}
|
||||||
|
|
||||||
|
public open override fun hashCode(): R|kotlin/Int| {
|
||||||
|
^hashCode this@R|/B|.super<R|kotlin/Any|>.R|kotlin/Any.hashCode|()
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
public final class C : R|A|, R|B| {
|
||||||
|
public constructor(): R|C| {
|
||||||
|
super<R|B|>()
|
||||||
|
}
|
||||||
|
|
||||||
|
public final override fun equals(other: R|kotlin/Any?|): R|kotlin/Boolean| {
|
||||||
|
^equals this@R|/C|.super<R|B|>.R|/B.equals|(R|<local>/other|)
|
||||||
|
}
|
||||||
|
|
||||||
|
public final override fun hashCode(): R|kotlin/Int| {
|
||||||
|
^hashCode this@R|/C|.super<R|B|>.R|/B.hashCode|()
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
@@ -15,7 +15,7 @@ class C : A, B() {
|
|||||||
override fun foo() {
|
override fun foo() {
|
||||||
super.foo()
|
super.foo()
|
||||||
|
|
||||||
super.<!AMBIGUITY!>bar<!>() // should be ambiguity (NB: really we should have overridden bar in C)
|
super.<!UNRESOLVED_REFERENCE!>bar<!>() // should be ambiguity (NB: really we should have overridden bar in C)
|
||||||
|
|
||||||
super.baz() // Ok
|
super.baz() // Ok
|
||||||
baz() // Ok
|
baz() // Ok
|
||||||
|
|||||||
@@ -27,9 +27,9 @@ FILE: incorrectSuperCall.kt
|
|||||||
}
|
}
|
||||||
|
|
||||||
public final override fun foo(): R|kotlin/Unit| {
|
public final override fun foo(): R|kotlin/Unit| {
|
||||||
this@R|/C|.super<R|A|R|B|>.R|/B.foo|()
|
this@R|/C|.super<R|B|>.R|/B.foo|()
|
||||||
this@R|/C|.super<R|A|R|B|>.<Ambiguity: bar, [/A.bar, /B.bar]>#()
|
this@R|/C|.super<<ERROR TYPE REF: Ambiguous supertype>>.<Unresolved name: bar>#()
|
||||||
this@R|/C|.super<R|A|R|B|>.R|/B.baz|()
|
this@R|/C|.super<R|B|>.R|/B.baz|()
|
||||||
this@R|/C|.R|/A.baz|()
|
this@R|/C|.R|/A.baz|()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
Generated
+5
@@ -654,6 +654,11 @@ public class FirDiagnosticsTestGenerated extends AbstractFirDiagnosticsTest {
|
|||||||
runTest("compiler/fir/analysis-tests/testData/resolve/callResolution/safeCallOnTypeAlias.kt");
|
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")
|
@TestMetadata("syntheticPropertiesWrongImplicitReceiver.kt")
|
||||||
public void testSyntheticPropertiesWrongImplicitReceiver() throws Exception {
|
public void testSyntheticPropertiesWrongImplicitReceiver() throws Exception {
|
||||||
runTest("compiler/fir/analysis-tests/testData/resolve/callResolution/syntheticPropertiesWrongImplicitReceiver.kt");
|
runTest("compiler/fir/analysis-tests/testData/resolve/callResolution/syntheticPropertiesWrongImplicitReceiver.kt");
|
||||||
|
|||||||
+5
@@ -654,6 +654,11 @@ public class FirDiagnosticsWithLightTreeTestGenerated extends AbstractFirDiagnos
|
|||||||
runTest("compiler/fir/analysis-tests/testData/resolve/callResolution/safeCallOnTypeAlias.kt");
|
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")
|
@TestMetadata("syntheticPropertiesWrongImplicitReceiver.kt")
|
||||||
public void testSyntheticPropertiesWrongImplicitReceiver() throws Exception {
|
public void testSyntheticPropertiesWrongImplicitReceiver() throws Exception {
|
||||||
runTest("compiler/fir/analysis-tests/testData/resolve/callResolution/syntheticPropertiesWrongImplicitReceiver.kt");
|
runTest("compiler/fir/analysis-tests/testData/resolve/callResolution/syntheticPropertiesWrongImplicitReceiver.kt");
|
||||||
|
|||||||
+2
-2
@@ -20,7 +20,7 @@ import org.jetbrains.kotlin.utils.addToStdlib.safeAs
|
|||||||
|
|
||||||
object FirNotASupertypeChecker : FirQualifiedAccessChecker() {
|
object FirNotASupertypeChecker : FirQualifiedAccessChecker() {
|
||||||
override fun check(functionCall: FirQualifiedAccessExpression, context: CheckerContext, reporter: DiagnosticReporter) {
|
override fun check(functionCall: FirQualifiedAccessExpression, context: CheckerContext, reporter: DiagnosticReporter) {
|
||||||
val superReference = functionCall.calleeReference.safeAs<FirSuperReference>()
|
val superReference = functionCall.calleeReference.safeAs<FirSuperReference>()?.takeIf { it.hadExplicitTypeInSource() }
|
||||||
|
|
||||||
val targetClass = superReference
|
val targetClass = superReference
|
||||||
?.superTypeRef
|
?.superTypeRef
|
||||||
@@ -57,4 +57,4 @@ object FirNotASupertypeChecker : FirQualifiedAccessChecker() {
|
|||||||
report(FirErrors.NOT_A_SUPERTYPE.on(it))
|
report(FirErrors.NOT_A_SUPERTYPE.on(it))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
+2
-1
@@ -23,6 +23,7 @@ object FirQualifiedSupertypeExtendedByOtherSupertypeChecker : FirQualifiedAccess
|
|||||||
override fun check(functionCall: FirQualifiedAccessExpression, context: CheckerContext, reporter: DiagnosticReporter) {
|
override fun check(functionCall: FirQualifiedAccessExpression, context: CheckerContext, reporter: DiagnosticReporter) {
|
||||||
// require to be called over a super reference
|
// require to be called over a super reference
|
||||||
val superReference = functionCall.calleeReference.safeAs<FirSuperReference>()
|
val superReference = functionCall.calleeReference.safeAs<FirSuperReference>()
|
||||||
|
?.takeIf { it.hadExplicitTypeInSource() }
|
||||||
?: return
|
?: return
|
||||||
|
|
||||||
val explicitType = superReference.superTypeRef.safeAs<FirResolvedTypeRef>()
|
val explicitType = superReference.superTypeRef.safeAs<FirResolvedTypeRef>()
|
||||||
@@ -62,4 +63,4 @@ object FirQualifiedSupertypeExtendedByOtherSupertypeChecker : FirQualifiedAccess
|
|||||||
report(FirErrors.QUALIFIED_SUPERTYPE_EXTENDED_BY_OTHER_SUPERTYPE.on(it))
|
report(FirErrors.QUALIFIED_SUPERTYPE_EXTENDED_BY_OTHER_SUPERTYPE.on(it))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
+12
-9
@@ -5,23 +5,26 @@
|
|||||||
|
|
||||||
package org.jetbrains.kotlin.fir.analysis.checkers.expression
|
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.FirSourceElement
|
||||||
import org.jetbrains.kotlin.fir.analysis.checkers.context.CheckerContext
|
import org.jetbrains.kotlin.fir.analysis.checkers.context.CheckerContext
|
||||||
import org.jetbrains.kotlin.fir.analysis.diagnostics.DiagnosticReporter
|
import org.jetbrains.kotlin.fir.analysis.diagnostics.DiagnosticReporter
|
||||||
import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors
|
import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors
|
||||||
import org.jetbrains.kotlin.fir.expressions.FirQualifiedAccessExpression
|
import org.jetbrains.kotlin.fir.expressions.FirQualifiedAccessExpression
|
||||||
|
import org.jetbrains.kotlin.fir.references.FirSuperReference
|
||||||
|
import org.jetbrains.kotlin.utils.addToStdlib.safeAs
|
||||||
|
|
||||||
object FirSuperNotAvailableChecker : FirQualifiedAccessChecker() {
|
object FirSuperNotAvailableChecker : FirQualifiedAccessChecker() {
|
||||||
override fun check(functionCall: FirQualifiedAccessExpression, context: CheckerContext, reporter: DiagnosticReporter) {
|
override fun check(functionCall: FirQualifiedAccessExpression, context: CheckerContext, reporter: DiagnosticReporter) {
|
||||||
if (functionCall.source?.elementType == SUPER_EXPRESSION) {
|
if (functionCall.calleeReference.safeAs<FirSuperReference>()?.hadExplicitTypeInSource() != true) return
|
||||||
val isInsideClass = context.containingDeclarations.any {
|
|
||||||
it.source?.elementType == CLASS || it.source?.elementType == OBJECT_LITERAL
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!isInsideClass) {
|
val isInsideClass = context.containingDeclarations.any {
|
||||||
reporter.report(functionCall.source)
|
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))
|
report(FirErrors.SUPER_NOT_AVAILABLE.on(it))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
+11
@@ -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
|
||||||
@@ -117,7 +117,7 @@ class FirCallResolver(
|
|||||||
explicitReceiver.calleeReference as? FirSuperReference
|
explicitReceiver.calleeReference as? FirSuperReference
|
||||||
?: return transformExplicitReceiver(transformer, ResolutionMode.ContextIndependent) as Q
|
?: return transformExplicitReceiver(transformer, ResolutionMode.ContextIndependent) as Q
|
||||||
|
|
||||||
transformer.transformSuperReceiver(callee, explicitReceiver)
|
transformer.transformSuperReceiver(callee, explicitReceiver, this)
|
||||||
|
|
||||||
return this
|
return this
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -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<FirTypeRef>,
|
||||||
|
containingCall: FirQualifiedAccess,
|
||||||
|
): Collection<ConeKotlinType> {
|
||||||
|
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<ConeKotlinType>,
|
||||||
|
calleeName: Name
|
||||||
|
): Collection<ConeKotlinType> {
|
||||||
|
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<ConeKotlinType>, calleeName: Name): Collection<ConeKotlinType> =
|
||||||
|
resolveSupertypesByMembers(supertypes, true) {
|
||||||
|
getFunctionMembers(it, calleeName) +
|
||||||
|
getPropertyMembers(it, calleeName)
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun BodyResolveComponents.resolveSupertypesByPropertyName(supertypes: Collection<ConeKotlinType>, propertyName: Name): Collection<ConeKotlinType> =
|
||||||
|
resolveSupertypesByMembers(supertypes, true) {
|
||||||
|
getPropertyMembers(it, propertyName)
|
||||||
|
}
|
||||||
|
|
||||||
|
private inline fun BodyResolveComponents.resolveSupertypesByMembers(
|
||||||
|
supertypes: Collection<ConeKotlinType>,
|
||||||
|
allowNonConcreteMembers: Boolean,
|
||||||
|
getMembers: (ConeKotlinType) -> Collection<FirCallableMemberDeclaration<*>>
|
||||||
|
): Collection<ConeKotlinType> {
|
||||||
|
val typesWithConcreteMembers = SmartList<ConeKotlinType>()
|
||||||
|
val typesWithNonConcreteMembers = SmartList<ConeKotlinType>()
|
||||||
|
|
||||||
|
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<FirCallableMemberDeclaration<*>> = buildList {
|
||||||
|
type.scope(session, scopeSession)?.processFunctionsByName(name) {
|
||||||
|
addIfNotNull(it.fir as? FirSimpleFunction)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@OptIn(ExperimentalStdlibApi::class)
|
||||||
|
private fun BodyResolveComponents.getPropertyMembers(type: ConeKotlinType, name: Name): Collection<FirCallableMemberDeclaration<*>> = 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
|
||||||
|
}
|
||||||
+16
-12
@@ -15,7 +15,6 @@ import org.jetbrains.kotlin.fir.diagnostics.DiagnosticKind
|
|||||||
import org.jetbrains.kotlin.fir.expressions.*
|
import org.jetbrains.kotlin.fir.expressions.*
|
||||||
import org.jetbrains.kotlin.fir.expressions.builder.buildErrorExpression
|
import org.jetbrains.kotlin.fir.expressions.builder.buildErrorExpression
|
||||||
import org.jetbrains.kotlin.fir.expressions.builder.buildFunctionCall
|
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.expressions.builder.buildVariableAssignment
|
||||||
import org.jetbrains.kotlin.fir.references.*
|
import org.jetbrains.kotlin.fir.references.*
|
||||||
import org.jetbrains.kotlin.fir.references.builder.buildErrorNamedReference
|
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.ClassId
|
||||||
import org.jetbrains.kotlin.name.Name
|
import org.jetbrains.kotlin.name.Name
|
||||||
import org.jetbrains.kotlin.types.Variance
|
import org.jetbrains.kotlin.types.Variance
|
||||||
import kotlin.math.min
|
|
||||||
|
|
||||||
open class FirExpressionsResolveTransformer(transformer: FirBodyResolveTransformer) : FirPartialBodyResolveTransformer(transformer) {
|
open class FirExpressionsResolveTransformer(transformer: FirBodyResolveTransformer) : FirPartialBodyResolveTransformer(transformer) {
|
||||||
private inline val builtinTypes: BuiltinTypes get() = session.builtinTypes
|
private inline val builtinTypes: BuiltinTypes get() = session.builtinTypes
|
||||||
@@ -84,7 +82,7 @@ open class FirExpressionsResolveTransformer(transformer: FirBodyResolveTransform
|
|||||||
qualifiedAccessExpression
|
qualifiedAccessExpression
|
||||||
}
|
}
|
||||||
is FirSuperReference -> {
|
is FirSuperReference -> {
|
||||||
transformSuperReceiver(callee, qualifiedAccessExpression)
|
transformSuperReceiver(callee, qualifiedAccessExpression, null)
|
||||||
}
|
}
|
||||||
is FirDelegateFieldReference -> {
|
is FirDelegateFieldReference -> {
|
||||||
val delegateFieldSymbol = callee.resolvedSymbol
|
val delegateFieldSymbol = callee.resolvedSymbol
|
||||||
@@ -126,7 +124,8 @@ open class FirExpressionsResolveTransformer(transformer: FirBodyResolveTransform
|
|||||||
|
|
||||||
fun transformSuperReceiver(
|
fun transformSuperReceiver(
|
||||||
superReference: FirSuperReference,
|
superReference: FirSuperReference,
|
||||||
superReferenceContainer: FirQualifiedAccessExpression
|
superReferenceContainer: FirQualifiedAccessExpression,
|
||||||
|
containingCall: FirQualifiedAccess?
|
||||||
): FirQualifiedAccessExpression {
|
): FirQualifiedAccessExpression {
|
||||||
val labelName = superReference.labelName
|
val labelName = superReference.labelName
|
||||||
val implicitReceiver =
|
val implicitReceiver =
|
||||||
@@ -146,21 +145,26 @@ open class FirExpressionsResolveTransformer(transformer: FirBodyResolveTransform
|
|||||||
else -> {
|
else -> {
|
||||||
val superTypeRefs = implicitReceiver?.boundSymbol?.phasedFir?.superTypeRefs
|
val superTypeRefs = implicitReceiver?.boundSymbol?.phasedFir?.superTypeRefs
|
||||||
val resultType = when {
|
val resultType = when {
|
||||||
superTypeRefs?.isNotEmpty() != true -> {
|
superTypeRefs?.isNotEmpty() != true || containingCall == null -> {
|
||||||
buildErrorTypeRef {
|
buildErrorTypeRef {
|
||||||
source = superReferenceContainer.source
|
source = superReferenceContainer.source
|
||||||
// NB: NOT_A_SUPERTYPE is reported by a separate checker
|
// NB: NOT_A_SUPERTYPE is reported by a separate checker
|
||||||
diagnostic = ConeStubDiagnostic(ConeSimpleDiagnostic("No super type", DiagnosticKind.Other))
|
diagnostic = ConeStubDiagnostic(ConeSimpleDiagnostic("No super type", DiagnosticKind.Other))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
superTypeRefs.size == 1 -> {
|
|
||||||
superTypeRefs.single()
|
|
||||||
}
|
|
||||||
else -> {
|
else -> {
|
||||||
buildComposedSuperTypeRef {
|
val types = components.findTypesForSuperCandidates(superTypeRefs, containingCall)
|
||||||
source = superReferenceContainer.source
|
if (types.size == 1)
|
||||||
superTypeRefs.mapTo(this.superTypeRefs) { it as FirResolvedTypeRef }
|
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
|
superReferenceContainer.resultType = resultType
|
||||||
|
|||||||
@@ -138,6 +138,10 @@ sealed class FirFakeSourceElementKind : FirSourceElementKind() {
|
|||||||
// a ?: b --> when(val $subj = a) { .... }
|
// a ?: b --> when(val $subj = a) { .... }
|
||||||
// where `val $subj = a` has a fake source
|
// where `val $subj = a` has a fake source
|
||||||
object WhenGeneratedSubject : FirFakeSourceElementKind()
|
object WhenGeneratedSubject : FirFakeSourceElementKind()
|
||||||
|
|
||||||
|
// super.foo() --> super<Supertype>.foo()
|
||||||
|
// where `Supertype` has a fake source
|
||||||
|
object SuperCallImplicitType : FirFakeSourceElementKind()
|
||||||
}
|
}
|
||||||
|
|
||||||
sealed class FirSourceElement {
|
sealed class FirSourceElement {
|
||||||
|
|||||||
@@ -1,4 +1,3 @@
|
|||||||
// IGNORE_BACKEND_FIR: JVM_IR
|
|
||||||
interface ISomething
|
interface ISomething
|
||||||
|
|
||||||
open class ClassWithToString {
|
open class ClassWithToString {
|
||||||
@@ -23,4 +22,4 @@ fun box(): String {
|
|||||||
C2().toString() != "C" -> "Failed #2"
|
C2().toString() != "C" -> "Failed #2"
|
||||||
else -> "OK"
|
else -> "OK"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -6,6 +6,6 @@ open class A {
|
|||||||
|
|
||||||
class B : A() {
|
class B : A() {
|
||||||
fun g() {
|
fun g() {
|
||||||
super?.f()
|
super?.<!UNRESOLVED_REFERENCE!>f<!>()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -2,6 +2,6 @@
|
|||||||
enum class E : Cloneable {
|
enum class E : Cloneable {
|
||||||
A;
|
A;
|
||||||
override fun clone(): Any {
|
override fun clone(): Any {
|
||||||
return super.<!AMBIGUITY!>clone<!>()
|
return super.<!UNRESOLVED_REFERENCE!>clone<!>()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Vendored
+6
-6
@@ -14,7 +14,7 @@ class GenericDerivedClass<T> : GenericBaseClass<T>(), GenericBaseInterface<T> {
|
|||||||
override fun bar(x: T): T = super.bar(x)
|
override fun bar(x: T): T = super.bar(x)
|
||||||
|
|
||||||
override fun ambiguous(x: T): T =
|
override fun ambiguous(x: T): T =
|
||||||
super.<!AMBIGUITY!>ambiguous<!>(x)
|
super.<!UNRESOLVED_REFERENCE!>ambiguous<!>(x)
|
||||||
}
|
}
|
||||||
|
|
||||||
class SpecializedDerivedClass : GenericBaseClass<Int>(), GenericBaseInterface<String> {
|
class SpecializedDerivedClass : GenericBaseClass<Int>(), GenericBaseInterface<String> {
|
||||||
@@ -22,9 +22,9 @@ class SpecializedDerivedClass : GenericBaseClass<Int>(), GenericBaseInterface<St
|
|||||||
override fun bar(x: String): String = super.bar(x)
|
override fun bar(x: String): String = super.bar(x)
|
||||||
|
|
||||||
override fun ambiguous(x: String): String =
|
override fun ambiguous(x: String): String =
|
||||||
super.ambiguous(x)
|
super.<!UNRESOLVED_REFERENCE!>ambiguous<!>(x)
|
||||||
override fun ambiguous(x: Int): Int =
|
override fun ambiguous(x: Int): Int =
|
||||||
super.ambiguous(x)
|
super.<!UNRESOLVED_REFERENCE!>ambiguous<!>(x)
|
||||||
}
|
}
|
||||||
|
|
||||||
class MixedDerivedClass<T> : GenericBaseClass<Int>(), GenericBaseInterface<T> {
|
class MixedDerivedClass<T> : GenericBaseClass<Int>(), GenericBaseInterface<T> {
|
||||||
@@ -32,7 +32,7 @@ class MixedDerivedClass<T> : GenericBaseClass<Int>(), GenericBaseInterface<T> {
|
|||||||
override fun bar(x: T): T = super.bar(x)
|
override fun bar(x: T): T = super.bar(x)
|
||||||
|
|
||||||
override fun ambiguous(x: Int): Int =
|
override fun ambiguous(x: Int): Int =
|
||||||
super.ambiguous(x)
|
super.<!UNRESOLVED_REFERENCE!>ambiguous<!>(x)
|
||||||
override fun ambiguous(x: T): T =
|
override fun ambiguous(x: T): T =
|
||||||
super.ambiguous(x)
|
super.<!UNRESOLVED_REFERENCE!>ambiguous<!>(x)
|
||||||
}
|
}
|
||||||
|
|||||||
+2
-2
@@ -45,13 +45,13 @@ class Derived : Base(), Interface {
|
|||||||
super.prop
|
super.prop
|
||||||
|
|
||||||
fun getAmbiguousSuperProp(): Int =
|
fun getAmbiguousSuperProp(): Int =
|
||||||
super.<!AMBIGUITY!>ambiguousProp<!>
|
super.<!UNRESOLVED_REFERENCE!>ambiguousProp<!>
|
||||||
|
|
||||||
fun callsFunFromSuperInterface() {
|
fun callsFunFromSuperInterface() {
|
||||||
super.bar()
|
super.bar()
|
||||||
}
|
}
|
||||||
|
|
||||||
fun callsAmbiguousSuperFun() {
|
fun callsAmbiguousSuperFun() {
|
||||||
super.<!AMBIGUITY!>ambiguous<!>()
|
super.<!UNRESOLVED_REFERENCE!>ambiguous<!>()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
+1
-1
@@ -34,6 +34,6 @@ class B : A(), I {
|
|||||||
}
|
}
|
||||||
|
|
||||||
override fun qux() {
|
override fun qux() {
|
||||||
super.<!AMBIGUITY!>qux<!>()
|
super.<!UNRESOLVED_REFERENCE!>qux<!>()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
+2
-2
@@ -14,8 +14,8 @@ interface InterfaceWithFun {
|
|||||||
|
|
||||||
class DerivedUsingFun : BaseWithCallableProp(), InterfaceWithFun {
|
class DerivedUsingFun : BaseWithCallableProp(), InterfaceWithFun {
|
||||||
fun foo(): String =
|
fun foo(): String =
|
||||||
super.fn()
|
super.<!UNRESOLVED_REFERENCE!>fn<!>()
|
||||||
|
|
||||||
override fun bar(): String =
|
override fun bar(): String =
|
||||||
super.bar()
|
super.bar()
|
||||||
}
|
}
|
||||||
|
|||||||
+2
-2
@@ -20,9 +20,9 @@ interface AnotherInterface {
|
|||||||
interface DerivedInterface: Interface, AnotherInterface {
|
interface DerivedInterface: Interface, AnotherInterface {
|
||||||
override fun foo() { super.foo() }
|
override fun foo() { super.foo() }
|
||||||
override fun ambiguous() {
|
override fun ambiguous() {
|
||||||
super.<!AMBIGUITY!>ambiguous<!>()
|
super.<!UNRESOLVED_REFERENCE!>ambiguous<!>()
|
||||||
}
|
}
|
||||||
override val ambiguousProp: Int
|
override val ambiguousProp: Int
|
||||||
get() = super.<!AMBIGUITY!>ambiguousProp<!>
|
get() = super.<!UNRESOLVED_REFERENCE!>ambiguousProp<!>
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
+2
-2
@@ -41,13 +41,13 @@ class ClassDerivedFromUnresolved : Base(), Interface, Unresolved {
|
|||||||
super.prop
|
super.prop
|
||||||
|
|
||||||
fun getAmbiguousSuperProp(): Int =
|
fun getAmbiguousSuperProp(): Int =
|
||||||
super.<!AMBIGUITY!>ambiguousProp<!>
|
super.<!UNRESOLVED_REFERENCE!>ambiguousProp<!>
|
||||||
|
|
||||||
fun callsFunFromSuperInterface() {
|
fun callsFunFromSuperInterface() {
|
||||||
super.bar()
|
super.bar()
|
||||||
}
|
}
|
||||||
|
|
||||||
fun callsAmbiguousSuperFun() {
|
fun callsAmbiguousSuperFun() {
|
||||||
super.<!AMBIGUITY!>ambiguous<!>()
|
super.<!UNRESOLVED_REFERENCE!>ambiguous<!>()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
-29
@@ -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.<!AMBIGUITY!>foo<!>()
|
|
||||||
super<Unrelated>.foo()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
+1
@@ -1,3 +1,4 @@
|
|||||||
|
// FIR_IDENTICAL
|
||||||
interface A {
|
interface A {
|
||||||
fun foo() {}
|
fun foo() {}
|
||||||
}
|
}
|
||||||
|
|||||||
+4
-4
@@ -41,7 +41,7 @@ class ManySupers: Foo2(), B {
|
|||||||
fun foo() {
|
fun foo() {
|
||||||
super<Foo2>.test()
|
super<Foo2>.test()
|
||||||
super<<!QUALIFIED_SUPERTYPE_EXTENDED_BY_OTHER_SUPERTYPE!>B<!>>.test()
|
super<<!QUALIFIED_SUPERTYPE_EXTENDED_BY_OTHER_SUPERTYPE!>B<!>>.test()
|
||||||
super.test()
|
super.<!UNRESOLVED_REFERENCE!>test<!>()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -49,7 +49,7 @@ class ManySupers2: Foo2(), C {
|
|||||||
fun foo() {
|
fun foo() {
|
||||||
super<Foo2>.test()
|
super<Foo2>.test()
|
||||||
super<C>.test()
|
super<C>.test()
|
||||||
super.<!AMBIGUITY!>test<!>()
|
super.<!UNRESOLVED_REFERENCE!>test<!>()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -57,6 +57,6 @@ class ManySupers3: Bar2(), C {
|
|||||||
fun foo() {
|
fun foo() {
|
||||||
super<Bar2>.test()
|
super<Bar2>.test()
|
||||||
super<C>.test()
|
super<C>.test()
|
||||||
super.<!AMBIGUITY!>test<!>()
|
super.<!UNRESOLVED_REFERENCE!>test<!>()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user