diff --git a/compiler/backend/src/org/jetbrains/kotlin/codegen/signature/BothSignatureWriter.java b/compiler/backend/src/org/jetbrains/kotlin/codegen/signature/BothSignatureWriter.java index f7ef4ab2e15..4a126e073f3 100644 --- a/compiler/backend/src/org/jetbrains/kotlin/codegen/signature/BothSignatureWriter.java +++ b/compiler/backend/src/org/jetbrains/kotlin/codegen/signature/BothSignatureWriter.java @@ -118,6 +118,15 @@ public class BothSignatureWriter { writeAsmType0(asmType); } + public void writeOuterClassBegin(Type resultingAsmType, String outerInternalName) { + signatureVisitor().visitClassType(outerInternalName); + writeAsmType0(resultingAsmType); + } + + public void writeInnerClass(String name) { + signatureVisitor().visitInnerClassType(name); + } + public void writeClassEnd() { signatureVisitor().visitEnd(); } diff --git a/compiler/backend/src/org/jetbrains/kotlin/codegen/state/JetTypeMapper.java b/compiler/backend/src/org/jetbrains/kotlin/codegen/state/JetTypeMapper.java index 0c5fd1545f3..b3a1a7fc80b 100644 --- a/compiler/backend/src/org/jetbrains/kotlin/codegen/state/JetTypeMapper.java +++ b/compiler/backend/src/org/jetbrains/kotlin/codegen/state/JetTypeMapper.java @@ -19,6 +19,7 @@ package org.jetbrains.kotlin.codegen.state; import com.intellij.openapi.util.text.StringUtil; import com.intellij.psi.PsiElement; import kotlin.CollectionsKt; +import kotlin.Pair; import kotlin.jvm.functions.Function1; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; @@ -628,45 +629,91 @@ public class JetTypeMapper { private void writeGenericType( BothSignatureWriter signatureVisitor, Type asmType, - KotlinType jetType, + KotlinType type, Variance howThisTypeIsUsed, boolean projectionsAllowed ) { if (signatureVisitor != null) { - if (hasNothingInArguments(jetType)) { + if (hasNothingInArguments(type) || type.getArguments().isEmpty()) { signatureVisitor.writeAsmType(asmType); return; } - signatureVisitor.writeClassBegin(asmType); + PossiblyInnerType possiblyInnerType = TypeParameterUtilsKt.buildPossiblyInnerType(type); + assert possiblyInnerType != null : "possiblyInnerType with arguments should not be null"; - List arguments = jetType.getArguments(); - for (TypeParameterDescriptor parameter : jetType.getConstructor().getParameters()) { - if (parameter.isCopyFromOuterDeclaration()) continue; + List innerTypesAsList = possiblyInnerType.segments(); + PossiblyInnerType outermostInnerType = innerTypesAsList.get(0); + ClassDescriptor outermostClass = outermostInnerType.getClassDescriptor(); - TypeProjection argument = arguments.get(parameter.getIndex()); - - if (projectionsAllowed && argument.isStarProjection()) { - signatureVisitor.writeUnboundedWildcard(); - } - else { - Variance projectionKind = projectionsAllowed - ? getEffectiveVariance( - parameter.getVariance(), - argument.getProjectionKind(), - howThisTypeIsUsed - ) - : Variance.INVARIANT; - signatureVisitor.writeTypeArgument(projectionKind); - - mapType(argument.getType(), signatureVisitor, JetTypeMapperMode.TYPE_PARAMETER); - signatureVisitor.writeTypeArgumentEnd(); - } + if (innerTypesAsList.size() == 1) { + signatureVisitor.writeClassBegin(asmType); } + else { + signatureVisitor.writeOuterClassBegin( + asmType, + mapType(outermostClass.getDefaultType()).getInternalName()); + } + + writeGenericArguments( + signatureVisitor, + outermostInnerType.getArguments(), outermostClass.getDeclaredTypeParameters(), + howThisTypeIsUsed, projectionsAllowed); + + for (PossiblyInnerType innerPart : innerTypesAsList.subList(1, innerTypesAsList.size())) { + ClassDescriptor classDescriptor = innerPart.getClassDescriptor(); + signatureVisitor.writeInnerClass(getJvmShortName(classDescriptor)); + writeGenericArguments( + signatureVisitor, innerPart.getArguments(), + classDescriptor.getDeclaredTypeParameters(), + howThisTypeIsUsed, projectionsAllowed + ); + } + signatureVisitor.writeClassEnd(); } } + @Nullable + private static String getJvmShortName(@NotNull ClassDescriptor klass) { + ClassId classId = JavaToKotlinClassMap.INSTANCE.mapKotlinToJava(DescriptorUtils.getFqName(klass)); + if (classId != null) { + return classId.getShortClassName().asString(); + } + + return SpecialNames.safeIdentifier(klass.getName()).getIdentifier(); + } + + private void writeGenericArguments( + BothSignatureWriter signatureVisitor, + List arguments, + List parameters, + Variance howThisTypeIsUsed, + boolean projectionsAllowed + ) { + for (Pair item : CollectionsKt.zip(parameters, arguments)) { + TypeParameterDescriptor parameter = item.getFirst(); + TypeProjection argument = item.getSecond(); + + if (projectionsAllowed && argument.isStarProjection()) { + signatureVisitor.writeUnboundedWildcard(); + } + else { + Variance projectionKind = projectionsAllowed + ? getEffectiveVariance( + parameter.getVariance(), + argument.getProjectionKind(), + howThisTypeIsUsed + ) + : Variance.INVARIANT; + signatureVisitor.writeTypeArgument(projectionKind); + + mapType(argument.getType(), signatureVisitor, JetTypeMapperMode.TYPE_PARAMETER); + signatureVisitor.writeTypeArgumentEnd(); + } + } + } + private static boolean hasNothingInArguments(KotlinType jetType) { boolean hasNothingInArguments = CollectionsKt.any(jetType.getArguments(), new Function1() { @Override diff --git a/compiler/testData/writeSignature/GenericInnerClass.kt b/compiler/testData/writeSignature/GenericInnerClass.kt new file mode 100644 index 00000000000..91ad6dd0729 --- /dev/null +++ b/compiler/testData/writeSignature/GenericInnerClass.kt @@ -0,0 +1,19 @@ +class Outer { + inner class Inner +} + +object Foo { + fun foo(x: Outer.Inner) = 1 +} + +// class: Outer +// jvm signature: Outer +// generic signature: Ljava/lang/Object; + +// class: Outer$Inner +// jvm signature: Outer$Inner +// generic signature: Ljava/lang/Object; + +// method: Foo::foo +// jvm signature: (LOuter$Inner;)I +// generic signature: (LOuter.Inner;)I diff --git a/compiler/tests/org/jetbrains/kotlin/jvm/compiler/WriteSignatureTestGenerated.java b/compiler/tests/org/jetbrains/kotlin/jvm/compiler/WriteSignatureTestGenerated.java index 49ba6eeeb3a..3cb77950f9e 100644 --- a/compiler/tests/org/jetbrains/kotlin/jvm/compiler/WriteSignatureTestGenerated.java +++ b/compiler/tests/org/jetbrains/kotlin/jvm/compiler/WriteSignatureTestGenerated.java @@ -53,6 +53,12 @@ public class WriteSignatureTestGenerated extends AbstractWriteSignatureTest { doTest(fileName); } + @TestMetadata("GenericInnerClass.kt") + public void testGenericInnerClass() throws Exception { + String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/writeSignature/GenericInnerClass.kt"); + doTest(fileName); + } + @TestMetadata("Int.kt") public void testInt() throws Exception { String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/writeSignature/Int.kt");