Skip to content

Commit

Permalink
Fix assignable check for function types with deserialized descriptors.
Browse files Browse the repository at this point in the history
E.g. a `kotlin.Function0` type is a Kotlin "fictional" type;
the real JVM type it is backed by for JVM is `kotlin.jvm.functions.Function0`.
Inside the compiler the backing type is always converted into Kotlin's one.

Yet for KSP the `kotlin.jvm.functions.Function0` with its deserialized descriptor
 can be obtained directly (e.g. via `getJavaClassByName`) and used along with
 the `kotlin.Function0` type.

This CL fixes the assignability check between such types.

(cherry picked from commit beb57bc)
  • Loading branch information
Jeffset authored and KSP Auto Pick committed Jul 29, 2022
1 parent fc93fa5 commit 31ae1b7
Show file tree
Hide file tree
Showing 3 changed files with 29 additions and 1 deletion.
Expand Up @@ -507,9 +507,11 @@ internal val KSFunctionDeclaration.jvmAccessFlag: Int
// Compiler subtype checking does not convert Java types to Kotlin types, while getting super types
// from a java type does the conversion, therefore resulting in subtype checking for Java types to fail.
// Check if candidate super type is a Java type, convert to Kotlin type for subtype checking.
// Also, if the type is a generic deserialized type, that actually represents a function type,
// a conversion is also required to yield a type with a correctly recognised descriptor.
internal fun KotlinType.convertKotlinType(): KotlinType {
val declarationDescriptor = this.constructor.declarationDescriptor
val base = if (declarationDescriptor is JavaClassDescriptor) {
val base = if (declarationDescriptor?.shouldMapToKotlinForAssignabilityCheck() == true) {
JavaToKotlinClassMapper
.mapJavaToKotlin(declarationDescriptor.fqNameSafe, ResolverImpl.instance.module.builtIns)
?.defaultType
Expand All @@ -528,3 +530,16 @@ internal fun KotlinType.convertKotlinType(): KotlinType {
upperBound
)
}

private fun ClassifierDescriptor.shouldMapToKotlinForAssignabilityCheck(): Boolean {
return when (this) {
is JavaClassDescriptor -> true // All java types need to be mapped to kotlin
is DeserializedDescriptor -> {
// If this is a generic deserialized type descriptor, which actually is a kotlin function type.
// This may be the case if the client explicitly mapped a kotlin function type to the JVM one.
// Such types need to be remapped to be represented by a correct function class descriptor.
fqNameSafe.parent().asString() == "kotlin.jvm.functions"
}
else -> false
}
}
7 changes: 7 additions & 0 deletions compiler-plugin/testData/api/javaSubtype.kt
Expand Up @@ -27,3 +27,10 @@ class A
public class Container {
String str;
}

// FILE: IntSupplier.java
import kotlin.jvm.functions.Function0;

public class IntSupplier implements Function0<Integer> {
@Override public Integer invoke() { return 1; }
}
Expand Up @@ -18,8 +18,10 @@ class JavaSubtypeProcessor : AbstractTestProcessor() {
override fun process(resolver: Resolver): List<KSAnnotated> {
val javaCollection = resolver.getJavaClassByName("kotlin.collections.Collection")!!.asStarProjectedType()
val javaSet = resolver.getJavaClassByName("kotlin.collections.Set")!!.asStarProjectedType()
val ktFunctionJava = resolver.getJavaClassByName("kotlin.jvm.functions.Function0")!!.asStarProjectedType()
val ktCollection = resolver.getClassDeclarationByName("kotlin.collections.Collection")!!.asStarProjectedType()
val ktSet = resolver.getClassDeclarationByName("kotlin.collections.Set")!!.asStarProjectedType()
val ktFunction = resolver.getClassDeclarationByName("kotlin.jvm.functions.Function0")!!.asStarProjectedType()
val javaCollectionRef = resolver.createKSTypeReferenceFromKSType(javaCollection)
val ktCollectionRef = resolver.createKSTypeReferenceFromKSType(ktCollection)
val javaSetRef = resolver.createKSTypeReferenceFromKSType(javaSet)
Expand Down Expand Up @@ -47,6 +49,7 @@ class JavaSubtypeProcessor : AbstractTestProcessor() {
)
val javaStrCollection = javaCollection.replace(listOf(strRef))
val javaStrSet = javaSet.replace(listOf(strRef))
val kotlinFunctionImplementorJava = resolver.getClassDeclarationByName("IntSupplier")!!.asStarProjectedType()
isOk = isOk && javaCollection.isAssignableFrom(javaSet)
isOk = isOk && javaCollection.isAssignableFrom(javaStrCollection)
isOk = isOk && !javaStrCollection.isAssignableFrom(javaCollection)
Expand All @@ -67,6 +70,9 @@ class JavaSubtypeProcessor : AbstractTestProcessor() {
isOk = isOk && javaCollectionOfKtSet.isAssignableFrom(ktCollectionOfJavaSet)
isOk = isOk && ktCollectionOfJavaCollection.isAssignableFrom(javaSetOfKtCollection)
isOk = isOk && !javaSetOfKtCollection.isAssignableFrom(ktCollectionOfJavaCollection)
isOk = isOk && ktFunction.isAssignableFrom(kotlinFunctionImplementorJava)
isOk = isOk && ktFunctionJava.isAssignableFrom(ktFunction) && ktFunction.isAssignableFrom(ktFunctionJava)
isOk = isOk && ktFunctionJava.isAssignableFrom(kotlinFunctionImplementorJava)
return emptyList()
}
}

0 comments on commit 31ae1b7

Please sign in to comment.