diff --git a/compiler/backend/src/org/jetbrains/kotlin/codegen/state/KotlinTypeMapper.java b/compiler/backend/src/org/jetbrains/kotlin/codegen/state/KotlinTypeMapper.java index 0d54f7bc657..349f27bfe30 100644 --- a/compiler/backend/src/org/jetbrains/kotlin/codegen/state/KotlinTypeMapper.java +++ b/compiler/backend/src/org/jetbrains/kotlin/codegen/state/KotlinTypeMapper.java @@ -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 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 diff --git a/compiler/backend/src/org/jetbrains/kotlin/codegen/state/typeMappingUtil.kt b/compiler/backend/src/org/jetbrains/kotlin/codegen/state/typeMappingUtil.kt index 32a52f2fb9a..72acdac9bb2 100644 --- a/compiler/backend/src/org/jetbrains/kotlin/codegen/state/typeMappingUtil.kt +++ b/compiler/backend/src/org/jetbrains/kotlin/codegen/state/typeMappingUtil.kt @@ -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") diff --git a/compiler/light-classes/src/org/jetbrains/kotlin/asJava/classes/ultraLightPsi.kt b/compiler/light-classes/src/org/jetbrains/kotlin/asJava/classes/ultraLightPsi.kt index 3bfc9157966..2894f336537 100644 --- a/compiler/light-classes/src/org/jetbrains/kotlin/asJava/classes/ultraLightPsi.kt +++ b/compiler/light-classes/src/org/jetbrains/kotlin/asJava/classes/ultraLightPsi.kt @@ -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 { + private fun propertyAccessors(declaration: KtCallableDeclaration, mutable: Boolean, onlyJvmStatic: Boolean): List { 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 diff --git a/compiler/testData/asJava/ultraLightClasses/jvmWildcardAnnotations.kt b/compiler/testData/asJava/ultraLightClasses/jvmWildcardAnnotations.kt new file mode 100644 index 00000000000..5185c2dba22 --- /dev/null +++ b/compiler/testData/asJava/ultraLightClasses/jvmWildcardAnnotations.kt @@ -0,0 +1,38 @@ +class Inv +class Out +class OutPair +class In + +class Final +open class Open + +class Container { + @JvmSuppressWildcards(true) + fun deepOpen(x: Out>>) {} + + + @JvmSuppressWildcards(false) + fun bar(): Out = null!! + + fun simpleOut(x: Out<@JvmWildcard Final>) {} + fun simpleIn(x: In<@JvmWildcard Any?>) {} + + fun falseTrueFalse(): @JvmSuppressWildcards(false) OutPair, Out<@JvmSuppressWildcards(false) Final>>> = null!! + fun combination(): @JvmSuppressWildcards OutPair>> = null!! + + @JvmSuppressWildcards(false) + fun foo(x: Boolean, y: Out): Int = 1 + + @JvmSuppressWildcards(true) + fun bar(x: Boolean, y: In, z: @JvmSuppressWildcards(false) Long): Int = 1 +} + +interface A { + @JvmSuppressWildcards(true) + fun foo(): Out +} + +interface B { + @JvmSuppressWildcards(true) + fun foo(): In +} diff --git a/compiler/testData/asJava/ultraLightClasses/wildcardOptimization.kt b/compiler/testData/asJava/ultraLightClasses/wildcardOptimization.kt new file mode 100644 index 00000000000..28118caf952 --- /dev/null +++ b/compiler/testData/asJava/ultraLightClasses/wildcardOptimization.kt @@ -0,0 +1,53 @@ +class Inv +class Out +class OutPair +class In + +class Final +open class Open + +class Container { + // The signatures are obtained from compiler/testData/writeSignature/declarationSiteVariance/wildcardOptimization + fun openClassArgument(x: Out, y: In) {} + fun finalClassArgument(x: Out, y: In) {} + fun oneArgumentFinal(x: OutPair) {} + + fun arrayOfOutOpen(x: Array>) {} + fun arrayOfOutFinal(x: Array>) {} + fun outOfArrayOpen(x: Out>) {} + fun outOfArrayOutOpen(x: Out>) {} + + fun deepOpen(x: Out>>) {} + fun deepFinal(x: Out>>) {} + + fun skipAllOutInvWildcards(): Inv>>> = null!! + fun skipAllInvWildcards(): Inv>> = null!! + fun notDeepIn(): In = null!! + fun skipWildcardsUntilIn0(): Out>> = null!! + fun skipWildcardsUntilIn1(): Out>> = null!! + fun skipWildcardsUntilIn2(): Out>>> = null!! + fun skipWildcardsUntilInProjection(): Inv> = null!! + + fun outIn(x: Out>) {} + fun outInAny(x: Out>) {} + + fun invInv(x: Out>) {} + fun invOut(x: Out>) {} + fun invOutFinal(x: Out>) {} + fun invIn(x: Out>) {} + fun invInAny(x: Out>) {} + + fun inFinal(x: In) {} + fun inAny(x: In) {} + fun inOutFinal(x: In>) {} + + fun invOpen(x: Inv) {} + fun invFinal(x: Inv) {} + fun invOutOpen(x: Inv>) {} + fun invOutFinal(x: Inv>) {} + fun invInOutOpen(x: Inv>>) {} + fun invInOutFinal(x: Inv>>) {} + fun invOutProjectedOutFinal(x: Inv>) {} + + fun typeParameter(x: Out, y: In) {} +} diff --git a/idea/idea-analysis/src/org/jetbrains/kotlin/idea/caches/resolve/IDELightClassGenerationSupport.kt b/idea/idea-analysis/src/org/jetbrains/kotlin/idea/caches/resolve/IDELightClassGenerationSupport.kt index 06003d1d1a0..e6d97095d17 100644 --- a/idea/idea-analysis/src/org/jetbrains/kotlin/idea/caches/resolve/IDELightClassGenerationSupport.kt +++ b/idea/idea-analysis/src/org/jetbrains/kotlin/idea/caches/resolve/IDELightClassGenerationSupport.kt @@ -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() || diff --git a/idea/tests/org/jetbrains/kotlin/asJava/classes/UltraLightClassLoadingTestGenerated.java b/idea/tests/org/jetbrains/kotlin/asJava/classes/UltraLightClassLoadingTestGenerated.java index 2607b732a9f..256ca924b6b 100644 --- a/idea/tests/org/jetbrains/kotlin/asJava/classes/UltraLightClassLoadingTestGenerated.java +++ b/idea/tests/org/jetbrains/kotlin/asJava/classes/UltraLightClassLoadingTestGenerated.java @@ -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"); + } }