Support JvmWildcard/JvmSuppressWildcard in ultra-light classes

The idea is reusing logic from KotlinTypeMapper for that
This commit is contained in:
Denis Zharkov
2018-11-16 15:26:51 +03:00
parent ce3b489fa9
commit 580d03be5f
7 changed files with 156 additions and 25 deletions
@@ -1464,14 +1464,22 @@ public class KotlinTypeMapper {
public String mapFieldSignature(@NotNull KotlinType backingFieldType, @NotNull PropertyDescriptor propertyDescriptor) {
JvmSignatureWriter sw = new BothSignatureWriter(BothSignatureWriter.Mode.TYPE);
writeFieldSignature(backingFieldType, propertyDescriptor, sw);
return sw.makeJavaGenericSignature();
}
public void writeFieldSignature(
@NotNull KotlinType backingFieldType,
@NotNull PropertyDescriptor propertyDescriptor,
JvmSignatureWriter sw
) {
if (!propertyDescriptor.isVar()) {
mapReturnType(propertyDescriptor, sw, backingFieldType);
}
else {
writeParameterType(sw, backingFieldType, propertyDescriptor);
}
return sw.makeJavaGenericSignature();
}
public void writeFormalTypeParameters(@NotNull List<TypeParameterDescriptor> typeParameters, @NotNull JvmSignatureWriter sw) {
@@ -1550,7 +1558,7 @@ public class KotlinTypeMapper {
sw.writeParameterTypeEnd();
}
private void writeParameterType(
public void writeParameterType(
@NotNull JvmSignatureWriter sw,
@NotNull KotlinType type,
@Nullable CallableDescriptor callableDescriptor
@@ -125,5 +125,5 @@ private fun AnnotationDescriptor?.suppressWildcardsMode(): Boolean? {
return (this ?: return null).allValueArguments.values.firstOrNull()?.value as? Boolean ?: true
}
private val JVM_SUPPRESS_WILDCARDS_ANNOTATION_FQ_NAME = FqName("kotlin.jvm.JvmSuppressWildcards")
private val JVM_WILDCARD_ANNOTATION_FQ_NAME = FqName("kotlin.jvm.JvmWildcard")
val JVM_SUPPRESS_WILDCARDS_ANNOTATION_FQ_NAME = FqName("kotlin.jvm.JvmSuppressWildcards")
val JVM_WILDCARD_ANNOTATION_FQ_NAME = FqName("kotlin.jvm.JvmWildcard")
@@ -323,7 +323,7 @@ class KtUltraLightClass(classOrObject: KtClassOrObject, private val support: Ult
val wrapper = KtUltraLightMethod(method, ktFunction, support, this)
addReceiverParameter(ktFunction, wrapper)
for (parameter in ktFunction.valueParameters) {
method.addParameter(KtUltraLightParameter(parameter.name.orEmpty(), parameter, support, wrapper, null))
method.addParameter(KtUltraLightParameter(parameter.name.orEmpty(), parameter, support, wrapper, null, ktFunction))
}
val returnType: PsiType? by lazyPub {
if (isConstructor) null
@@ -333,11 +333,9 @@ class KtUltraLightClass(classOrObject: KtClassOrObject, private val support: Ult
return wrapper
}
private fun addReceiverParameter(f: KtDeclaration, method: KtUltraLightMethod) {
val receiver = (f as? KtCallableDeclaration)?.receiverTypeReference
if (receiver != null) {
method.delegate.addParameter(KtUltraLightParameter("\$self", f, support, method, receiver))
}
private fun addReceiverParameter(callable: KtCallableDeclaration, method: KtUltraLightMethod) {
val receiver = callable.receiverTypeReference ?: return
method.delegate.addParameter(KtUltraLightParameter("\$self", callable, support, method, receiver, callable))
}
private fun methodReturnType(ktDeclaration: KtDeclaration, wrapper: KtUltraLightMethod): PsiType {
@@ -434,7 +432,7 @@ class KtUltraLightClass(classOrObject: KtClassOrObject, private val support: Ult
return f.hasModifier(INTERNAL_KEYWORD)
}
private fun propertyAccessors(declaration: KtNamedDeclaration, mutable: Boolean, onlyJvmStatic: Boolean): List<KtLightMethod> {
private fun propertyAccessors(declaration: KtCallableDeclaration, mutable: Boolean, onlyJvmStatic: Boolean): List<KtLightMethod> {
val propertyName = declaration.name
if (declaration.hasModifier(CONST_KEYWORD) || propertyName == null) return emptyList()
@@ -478,7 +476,9 @@ class KtUltraLightClass(classOrObject: KtClassOrObject, private val support: Ult
val setterWrapper = KtUltraLightMethod(setterPrototype, declaration, support, this)
addReceiverParameter(declaration, setterWrapper)
val parameterOrigin = ktSetter?.parameter ?: declaration
setterPrototype.addParameter(KtUltraLightParameter(propertyName, parameterOrigin, support, setterWrapper, null))
setterPrototype.addParameter(
KtUltraLightParameter(propertyName, parameterOrigin, support, setterWrapper, null, declaration)
)
result.add(setterWrapper)
}
return result
@@ -535,9 +535,14 @@ private class KtUltraLightField(
private val _type: PsiType by lazyPub {
fun nonExistent() = JavaPsiFacade.getElementFactory(project).createTypeFromText("error.NonExistentClass", declaration)
val propertyDescriptor: PropertyDescriptor? by lazyPub {
declaration.resolve() as? PropertyDescriptor
}
when {
declaration is KtProperty && declaration.hasDelegate() ->
(declaration.resolve() as? PropertyDescriptor)
propertyDescriptor
?.let {
val context = LightClassGenerationSupport.getInstance(project).analyze(declaration)
PropertyCodegen.getDelegateTypeForProperty(declaration, it, context)
@@ -548,14 +553,14 @@ private class KtUltraLightField(
declaration is KtObjectDeclaration ->
KtLightClassForSourceDeclaration.create(declaration)?.let { JavaPsiFacade.getElementFactory(project).createType(it) }
?: nonExistent()
else ->
declaration.getKotlinType()?.let {
val mode = when {
(declaration.resolve() as? PropertyDescriptor)?.isVar == true -> TypeMappingMode.getOptimalModeForValueParameter(it)
else -> TypeMappingMode.getOptimalModeForReturnType(it, false)
}
it.asPsiType(support, mode, this)
} ?: PsiType.NULL
else -> {
val kotlinType = declaration.getKotlinType() ?: return@lazyPub PsiType.NULL
val descriptor = propertyDescriptor ?: return@lazyPub PsiType.NULL
support.mapType(this) { typeMapper, sw ->
typeMapper.writeFieldSignature(kotlinType, descriptor, sw)
}
}
}
}
@@ -633,7 +638,8 @@ internal class KtUltraLightParameter(
override val kotlinOrigin: KtDeclaration,
private val support: UltraLightSupport,
method: KtLightMethod,
private val receiver: KtTypeReference?
private val receiver: KtTypeReference?,
private val containingFunction: KtCallableDeclaration
) : org.jetbrains.kotlin.asJava.elements.LightParameter(
name,
PsiType.NULL,
@@ -661,7 +667,11 @@ internal class KtUltraLightParameter(
}
}
private val _type: PsiType by lazyPub {
kotlinType?.let { it.asPsiType(support, TypeMappingMode.getOptimalModeForValueParameter(it), this) } ?: PsiType.NULL
val kotlinType = kotlinType ?: return@lazyPub PsiType.NULL
val containingDescriptor = containingFunction.resolve() as? CallableDescriptor ?: return@lazyPub PsiType.NULL
support.mapType(this) { typeMapper, sw ->
typeMapper.writeParameterType(sw, kotlinType, containingDescriptor)
}
}
override fun getType(): PsiType = _type
@@ -0,0 +1,38 @@
class Inv<E>
class Out<out T>
class OutPair<out Final, out Y>
class In<in Z>
class Final
open class Open
class Container {
@JvmSuppressWildcards(true)
fun deepOpen(x: Out<Out<Out<Open>>>) {}
@JvmSuppressWildcards(false)
fun bar(): Out<Open> = null!!
fun simpleOut(x: Out<@JvmWildcard Final>) {}
fun simpleIn(x: In<@JvmWildcard Any?>) {}
fun falseTrueFalse(): @JvmSuppressWildcards(false) OutPair<Final, @JvmSuppressWildcards OutPair<Out<Final>, Out<@JvmSuppressWildcards(false) Final>>> = null!!
fun combination(): @JvmSuppressWildcards OutPair<Open, @JvmWildcard OutPair<Open, @JvmWildcard Out<Open>>> = null!!
@JvmSuppressWildcards(false)
fun foo(x: Boolean, y: Out<Int>): Int = 1
@JvmSuppressWildcards(true)
fun bar(x: Boolean, y: In<Long>, z: @JvmSuppressWildcards(false) Long): Int = 1
}
interface A<T> {
@JvmSuppressWildcards(true)
fun foo(): Out<T>
}
interface B {
@JvmSuppressWildcards(true)
fun foo(): In<Open>
}
@@ -0,0 +1,53 @@
class Inv<E>
class Out<out T>
class OutPair<out Final, out Y>
class In<in Z>
class Final
open class Open
class Container {
// The signatures are obtained from compiler/testData/writeSignature/declarationSiteVariance/wildcardOptimization
fun openClassArgument(x: Out<Open>, y: In<Open>) {}
fun finalClassArgument(x: Out<Final>, y: In<Final>) {}
fun oneArgumentFinal(x: OutPair<Final, Open>) {}
fun arrayOfOutOpen(x: Array<Out<Open>>) {}
fun arrayOfOutFinal(x: Array<Out<Final>>) {}
fun outOfArrayOpen(x: Out<Array<Open>>) {}
fun outOfArrayOutOpen(x: Out<Array<out Open>>) {}
fun deepOpen(x: Out<Out<Out<Open>>>) {}
fun deepFinal(x: Out<Out<Out<Final>>>) {}
fun skipAllOutInvWildcards(): Inv<OutPair<Open, Out<Out<Open>>>> = null!!
fun skipAllInvWildcards(): Inv<In<Out<Open>>> = null!!
fun notDeepIn(): In<Final> = null!!
fun skipWildcardsUntilIn0(): Out<In<Out<Open>>> = null!!
fun skipWildcardsUntilIn1(): Out<In<Out<Final>>> = null!!
fun skipWildcardsUntilIn2(): Out<In<OutPair<Final, Out<Open>>>> = null!!
fun skipWildcardsUntilInProjection(): Inv<in Out<Open>> = null!!
fun outIn(x: Out<In<Final>>) {}
fun outInAny(x: Out<In<Any?>>) {}
fun invInv(x: Out<Inv<Open>>) {}
fun invOut(x: Out<Inv<out Open>>) {}
fun invOutFinal(x: Out<Inv<out Final>>) {}
fun invIn(x: Out<Inv<in Final>>) {}
fun invInAny(x: Out<Inv<in Any>>) {}
fun inFinal(x: In<Final>) {}
fun inAny(x: In<Any>) {}
fun inOutFinal(x: In<Out<Final>>) {}
fun invOpen(x: Inv<Open>) {}
fun invFinal(x: Inv<Final>) {}
fun invOutOpen(x: Inv<Out<Open>>) {}
fun invOutFinal(x: Inv<Out<Final>>) {}
fun invInOutOpen(x: Inv<In<Out<Open>>>) {}
fun invInOutFinal(x: Inv<In<Out<Final>>>) {}
fun invOutProjectedOutFinal(x: Inv<out Out<Final>>) {}
fun <Q : Final> typeParameter(x: Out<Q>, y: In<Q>) {}
}
@@ -37,6 +37,8 @@ import org.jetbrains.kotlin.asJava.classes.lazyPub
import org.jetbrains.kotlin.asJava.classes.shouldNotBeVisibleAsLightClass
import org.jetbrains.kotlin.asJava.finder.JavaElementFinder
import org.jetbrains.kotlin.codegen.JvmCodegenUtil
import org.jetbrains.kotlin.codegen.state.JVM_SUPPRESS_WILDCARDS_ANNOTATION_FQ_NAME
import org.jetbrains.kotlin.codegen.state.JVM_WILDCARD_ANNOTATION_FQ_NAME
import org.jetbrains.kotlin.descriptors.ClassifierDescriptor
import org.jetbrains.kotlin.descriptors.DeclarationDescriptor
import org.jetbrains.kotlin.descriptors.annotations.AnnotationDescriptor
@@ -52,6 +54,7 @@ import org.jetbrains.kotlin.psi.*
import org.jetbrains.kotlin.psi.psiUtil.hasExpectModifier
import org.jetbrains.kotlin.psi.stubs.elements.KtStubElementTypes
import org.jetbrains.kotlin.resolve.BindingContext
import org.jetbrains.kotlin.resolve.annotations.JVM_STATIC_ANNOTATION_FQ_NAME
import org.jetbrains.kotlin.resolve.descriptorUtil.fqNameSafe
import org.jetbrains.kotlin.resolve.descriptorUtil.getAllSuperClassifiers
import org.jetbrains.kotlin.resolve.lazy.BodyResolveMode
@@ -107,9 +110,18 @@ class IDELightClassGenerationSupport(private val project: Project) : LightClassG
}
private fun findTooComplexDeclaration(declaration: KtDeclaration): PsiElement? {
fun isNameOfUnsupportedJvmAnnotation(name: Name): Boolean {
if (!name.asString().startsWith("Jvm")) return false
if (name == JVM_STATIC_ANNOTATION_FQ_NAME.shortName()) return false
if (name == JVM_SUPPRESS_WILDCARDS_ANNOTATION_FQ_NAME.shortName()) return false
if (name == JVM_WILDCARD_ANNOTATION_FQ_NAME.shortName()) return false
return true
}
fun KtAnnotationEntry.seemsNonTrivial(): Boolean {
val name = shortName
return name == null || hasAlias(declaration, name) || name.asString().startsWith("Jvm") && name.asString() != "JvmStatic"
return name == null || hasAlias(declaration, name) || isNameOfUnsupportedJvmAnnotation(name)
}
if (declaration.hasExpectModifier() ||
@@ -109,6 +109,11 @@ public class UltraLightClassLoadingTestGenerated extends AbstractUltraLightClass
runTest("compiler/testData/asJava/ultraLightClasses/jvmOverloads.kt");
}
@TestMetadata("jvmWildcardAnnotations.kt")
public void testJvmWildcardAnnotations() throws Exception {
runTest("compiler/testData/asJava/ultraLightClasses/jvmWildcardAnnotations.kt");
}
@TestMetadata("lateinitProperty.kt")
public void testLateinitProperty() throws Exception {
runTest("compiler/testData/asJava/ultraLightClasses/lateinitProperty.kt");
@@ -138,4 +143,9 @@ public class UltraLightClassLoadingTestGenerated extends AbstractUltraLightClass
public void testTypeAliases() throws Exception {
runTest("compiler/testData/asJava/ultraLightClasses/typeAliases.kt");
}
@TestMetadata("wildcardOptimization.kt")
public void testWildcardOptimization() throws Exception {
runTest("compiler/testData/asJava/ultraLightClasses/wildcardOptimization.kt");
}
}