Fix written generic signature in case of inner types
This commit is contained in:
@@ -118,6 +118,15 @@ public class BothSignatureWriter {
|
|||||||
writeAsmType0(asmType);
|
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() {
|
public void writeClassEnd() {
|
||||||
signatureVisitor().visitEnd();
|
signatureVisitor().visitEnd();
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -19,6 +19,7 @@ package org.jetbrains.kotlin.codegen.state;
|
|||||||
import com.intellij.openapi.util.text.StringUtil;
|
import com.intellij.openapi.util.text.StringUtil;
|
||||||
import com.intellij.psi.PsiElement;
|
import com.intellij.psi.PsiElement;
|
||||||
import kotlin.CollectionsKt;
|
import kotlin.CollectionsKt;
|
||||||
|
import kotlin.Pair;
|
||||||
import kotlin.jvm.functions.Function1;
|
import kotlin.jvm.functions.Function1;
|
||||||
import org.jetbrains.annotations.NotNull;
|
import org.jetbrains.annotations.NotNull;
|
||||||
import org.jetbrains.annotations.Nullable;
|
import org.jetbrains.annotations.Nullable;
|
||||||
@@ -628,45 +629,91 @@ public class JetTypeMapper {
|
|||||||
private void writeGenericType(
|
private void writeGenericType(
|
||||||
BothSignatureWriter signatureVisitor,
|
BothSignatureWriter signatureVisitor,
|
||||||
Type asmType,
|
Type asmType,
|
||||||
KotlinType jetType,
|
KotlinType type,
|
||||||
Variance howThisTypeIsUsed,
|
Variance howThisTypeIsUsed,
|
||||||
boolean projectionsAllowed
|
boolean projectionsAllowed
|
||||||
) {
|
) {
|
||||||
if (signatureVisitor != null) {
|
if (signatureVisitor != null) {
|
||||||
if (hasNothingInArguments(jetType)) {
|
if (hasNothingInArguments(type) || type.getArguments().isEmpty()) {
|
||||||
signatureVisitor.writeAsmType(asmType);
|
signatureVisitor.writeAsmType(asmType);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
signatureVisitor.writeClassBegin(asmType);
|
PossiblyInnerType possiblyInnerType = TypeParameterUtilsKt.buildPossiblyInnerType(type);
|
||||||
|
assert possiblyInnerType != null : "possiblyInnerType with arguments should not be null";
|
||||||
|
|
||||||
List<TypeProjection> arguments = jetType.getArguments();
|
List<PossiblyInnerType> innerTypesAsList = possiblyInnerType.segments();
|
||||||
for (TypeParameterDescriptor parameter : jetType.getConstructor().getParameters()) {
|
PossiblyInnerType outermostInnerType = innerTypesAsList.get(0);
|
||||||
if (parameter.isCopyFromOuterDeclaration()) continue;
|
ClassDescriptor outermostClass = outermostInnerType.getClassDescriptor();
|
||||||
|
|
||||||
TypeProjection argument = arguments.get(parameter.getIndex());
|
if (innerTypesAsList.size() == 1) {
|
||||||
|
signatureVisitor.writeClassBegin(asmType);
|
||||||
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();
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
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();
|
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) {
|
private static boolean hasNothingInArguments(KotlinType jetType) {
|
||||||
boolean hasNothingInArguments = CollectionsKt.any(jetType.getArguments(), new Function1<TypeProjection, Boolean>() {
|
boolean hasNothingInArguments = CollectionsKt.any(jetType.getArguments(), new Function1<TypeProjection, Boolean>() {
|
||||||
@Override
|
@Override
|
||||||
|
|||||||
@@ -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);
|
doTest(fileName);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@TestMetadata("GenericInnerClass.kt")
|
||||||
|
public void testGenericInnerClass() throws Exception {
|
||||||
|
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/writeSignature/GenericInnerClass.kt");
|
||||||
|
doTest(fileName);
|
||||||
|
}
|
||||||
|
|
||||||
@TestMetadata("Int.kt")
|
@TestMetadata("Int.kt")
|
||||||
public void testInt() throws Exception {
|
public void testInt() throws Exception {
|
||||||
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/writeSignature/Int.kt");
|
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/writeSignature/Int.kt");
|
||||||
|
|||||||
Reference in New Issue
Block a user