Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -891,9 +891,28 @@ class ResolverAAImpl(
}
}

// Returns the class/interface that declares this member. For a fake or intersection override,
// closestClassDeclaration() resolves to the receiver's enclosing declaration rather than the real
// supertype that declares the member, which makes computeAsMemberOf()'s subtype precondition below
// fail spuriously. Unwrap to an overridden original whose containing class is a genuine supertype
// of the receiver so the precondition is checked against the actual declaring type.
@OptIn(KaExperimentalApi::class)
private fun KSDeclaration.declaringClassForAsMemberOf(): KSClassDeclaration? {
val symbol = when (this) {
is KSFunctionDeclarationImpl -> ktFunctionSymbol
is KSPropertyDeclarationImpl -> ktPropertySymbol
else -> null
} ?: return closestClassDeclaration()
val declarer = analyze {
val original = symbol.intersectionOverriddenSymbols.firstOrNull() ?: symbol.fakeOverrideOriginal
(original.containingSymbol as? KaNamedClassSymbol)?.let { KSClassDeclarationImpl.getCached(it) }
}
return declarer ?: closestClassDeclaration()
}

@OptIn(KaExperimentalApi::class)
internal fun computeAsMemberOf(property: KSPropertyDeclaration, containing: KSType): KSType {
val declaredIn = property.closestClassDeclaration()
val declaredIn = property.declaringClassForAsMemberOf()
?: throw IllegalArgumentException(
"Cannot call asMemberOf with a property that is not declared in a class or an interface"
)
Expand Down Expand Up @@ -943,7 +962,7 @@ class ResolverAAImpl(

@OptIn(KaExperimentalApi::class)
internal fun computeAsMemberOf(function: KSFunctionDeclaration, containing: KSType): KSFunction {
val propertyDeclaredIn = function.closestClassDeclaration()
val declaredIn = function.declaringClassForAsMemberOf()
?: throw IllegalArgumentException(
"Cannot call asMemberOf with a function that is not declared in a class or an interface"
)
Expand All @@ -953,14 +972,14 @@ class ResolverAAImpl(
recordLookupWithSupertypes(containing.type)
recordLookupForPropertyOrMethod(function)
val isSubTypeOf = analyze {
(propertyDeclaredIn.asStarProjectedType() as? KSTypeImpl)?.type?.let {
(declaredIn.asStarProjectedType() as? KSTypeImpl)?.type?.let {
containing.type.isSubtypeOf(it)
} ?: false
}
if (!isSubTypeOf) {
throw IllegalArgumentException(
"$containing is not a sub type of the class/interface that contains `$function` " +
"($propertyDeclaredIn)"
"($declaredIn)"
)
}
analyze {
Expand Down
5 changes: 5 additions & 0 deletions kotlin-analysis-api/testData/asMemberOf.kt
Original file line number Diff line number Diff line change
Expand Up @@ -122,6 +122,7 @@
// () -> kotlin.Int!!
// (kotlin.Int!!) -> kotlin.Unit!!
// Baz!!<kotlin.Long!!, kotlin.Number!!>
// C.Both.provideString: () -> kotlin.String!!
// END
// MODULE: lib
// FILE: Test.java
Expand Down Expand Up @@ -178,6 +179,10 @@ fun <T>fileLevelFunction():Unit = TODO()
val fileLevelProperty:Int = 3
val errorType: NonExistingType

class A { interface Foo { fun provideString(): String } }
class B { interface Bar { fun provideString(): String } }
class C { interface Both : A.Foo, B.Bar }

interface KotlinInterface {
val x:Int
var y:Int
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -119,6 +119,17 @@ class AsMemberOfProcessor : AbstractTestProcessor() {
results.add(f.asMemberOf(usage).returnType!!.toSignature())
}
}

// Intersection override: a member inherited with the same signature from two supertypes nested
// in different classes. asMemberOf() used to throw IllegalArgumentException for it because
// closestClassDeclaration() resolved the owner to the receiver's enclosing class.
resolver.getClassDeclarationByName("C.Both")?.let { both ->
val fn = both.getAllFunctions().single { it.simpleName.asString() == "provideString" }
results.add(
"C.Both.provideString: " +
resolver.asMemberOfSignature(fn, both.asStarProjectedType())
)
}
return emptyList()
}

Expand Down