Fix written generic signature in case of inner types

This commit is contained in:
Denis Zharkov
2015-11-10 15:28:51 +03:00
parent eea898abb5
commit 8cb85759c7
4 changed files with 105 additions and 24 deletions
@@ -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();
}
@@ -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<TypeProjection> arguments = jetType.getArguments();
for (TypeParameterDescriptor parameter : jetType.getConstructor().getParameters()) {
if (parameter.isCopyFromOuterDeclaration()) continue;
List<PossiblyInnerType> 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<? extends TypeProjection> arguments,
List<? extends TypeParameterDescriptor> parameters,
Variance howThisTypeIsUsed,
boolean projectionsAllowed
) {
for (Pair<? extends TypeParameterDescriptor, ? extends TypeProjection> 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<TypeProjection, Boolean>() {
@Override
+19
View File
@@ -0,0 +1,19 @@
class Outer<E, F : Number> {
inner class Inner<G, H>
}
object Foo {
fun <Y> foo(x: Outer<String, Int>.Inner<Y, CharSequence>) = 1
}
// class: Outer
// jvm signature: Outer
// generic signature: <E:Ljava/lang/Object;F:Ljava/lang/Number;>Ljava/lang/Object;
// class: Outer$Inner
// jvm signature: Outer$Inner
// generic signature: <G:Ljava/lang/Object;H:Ljava/lang/Object;>Ljava/lang/Object;
// method: Foo::foo
// jvm signature: (LOuter$Inner;)I
// generic signature: <Y:Ljava/lang/Object;>(LOuter<Ljava/lang/String;Ljava/lang/Integer;>.Inner<TY;Ljava/lang/CharSequence;>;)I
@@ -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");