Reflect Kotlin's declaration-site variance in Java signatures
This commit is contained in:
@@ -260,10 +260,12 @@ public class BothSignatureWriter {
|
||||
}
|
||||
}
|
||||
|
||||
public void writeTypeArgument(Variance variance) {
|
||||
JetSignatureVariance jsVariance = toJetSignatureVariance(variance);
|
||||
push(signatureVisitor().visitTypeArgument(jsVariance.getChar()));
|
||||
jetSignatureWriter.visitTypeArgument(jsVariance);
|
||||
public void writeTypeArgument(Variance projectionKindForKotlin, Variance projectionKindForJava) {
|
||||
push(signatureVisitor().visitTypeArgument(
|
||||
toJetSignatureVariance(projectionKindForJava).getChar()
|
||||
));
|
||||
|
||||
jetSignatureWriter.visitTypeArgument(toJetSignatureVariance(projectionKindForKotlin));
|
||||
generic = true;
|
||||
}
|
||||
|
||||
|
||||
@@ -184,7 +184,7 @@ public class JetTypeMapper extends BindingTraceAware {
|
||||
}
|
||||
return AsmTypeConstants.OBJECT_TYPE;
|
||||
}
|
||||
return mapType(jetType, signatureVisitor, JetTypeMapperMode.VALUE);
|
||||
return mapType(jetType, signatureVisitor, JetTypeMapperMode.VALUE, Variance.OUT_VARIANCE);
|
||||
}
|
||||
|
||||
@NotNull
|
||||
@@ -209,6 +209,16 @@ public class JetTypeMapper extends BindingTraceAware {
|
||||
|
||||
@NotNull
|
||||
public Type mapType(JetType jetType, @Nullable BothSignatureWriter signatureVisitor, @NotNull JetTypeMapperMode kind) {
|
||||
return mapType(jetType, signatureVisitor, kind, Variance.INVARIANT);
|
||||
}
|
||||
|
||||
@NotNull
|
||||
public Type mapType(
|
||||
JetType jetType,
|
||||
@Nullable BothSignatureWriter signatureVisitor,
|
||||
@NotNull JetTypeMapperMode kind,
|
||||
@NotNull Variance howThisTypeIsUsed
|
||||
) {
|
||||
Type known = null;
|
||||
DeclarationDescriptor descriptor = jetType.getConstructor().getDeclarationDescriptor();
|
||||
|
||||
@@ -220,10 +230,10 @@ public class JetTypeMapper extends BindingTraceAware {
|
||||
|
||||
if (known != null) {
|
||||
if (kind == JetTypeMapperMode.VALUE) {
|
||||
return mapKnownAsmType(jetType, known, signatureVisitor);
|
||||
return mapKnownAsmType(jetType, known, signatureVisitor, howThisTypeIsUsed);
|
||||
}
|
||||
else if (kind == JetTypeMapperMode.TYPE_PARAMETER) {
|
||||
return mapKnownAsmType(jetType, boxType(known), signatureVisitor);
|
||||
return mapKnownAsmType(jetType, boxType(known), signatureVisitor, howThisTypeIsUsed);
|
||||
}
|
||||
else if (kind == JetTypeMapperMode.TRAIT_IMPL) {
|
||||
throw new IllegalStateException("TRAIT_IMPL is not possible for " + jetType);
|
||||
@@ -234,7 +244,7 @@ public class JetTypeMapper extends BindingTraceAware {
|
||||
// TODO: enable and fix tests
|
||||
//throw new IllegalStateException("must not map known type to IMPL when not compiling builtins: " + jetType);
|
||||
}
|
||||
return mapKnownAsmType(jetType, known, signatureVisitor);
|
||||
return mapKnownAsmType(jetType, known, signatureVisitor, howThisTypeIsUsed);
|
||||
}
|
||||
else {
|
||||
throw new IllegalStateException("unknown kind: " + kind);
|
||||
@@ -297,7 +307,7 @@ public class JetTypeMapper extends BindingTraceAware {
|
||||
}
|
||||
boolean forceReal = KotlinToJavaTypesMap.getInstance().isForceReal(name);
|
||||
|
||||
writeGenericType(signatureVisitor, asmType, jetType, forceReal);
|
||||
writeGenericType(signatureVisitor, asmType, jetType, forceReal, howThisTypeIsUsed);
|
||||
|
||||
checkValidType(asmType);
|
||||
return asmType;
|
||||
@@ -334,28 +344,68 @@ public class JetTypeMapper extends BindingTraceAware {
|
||||
parentDeclarationElement != null ? parentDeclarationElement.getText() : "null");
|
||||
}
|
||||
|
||||
private void writeGenericType(BothSignatureWriter signatureVisitor, Type asmType, JetType jetType, boolean forceReal) {
|
||||
private void writeGenericType(
|
||||
BothSignatureWriter signatureVisitor,
|
||||
Type asmType,
|
||||
JetType jetType,
|
||||
boolean forceReal,
|
||||
Variance howThisTypeIsUsed
|
||||
) {
|
||||
if (signatureVisitor != null) {
|
||||
String kotlinTypeName = getKotlinTypeNameForSignature(jetType, asmType);
|
||||
signatureVisitor.writeClassBegin(asmType.getInternalName(), jetType.isNullable(), forceReal, kotlinTypeName);
|
||||
for (TypeProjection proj : jetType.getArguments()) {
|
||||
// TODO: +-
|
||||
signatureVisitor.writeTypeArgument(proj.getProjectionKind());
|
||||
mapType(proj.getType(), signatureVisitor, JetTypeMapperMode.TYPE_PARAMETER);
|
||||
|
||||
List<TypeProjection> arguments = jetType.getArguments();
|
||||
for (TypeParameterDescriptor parameter : jetType.getConstructor().getParameters()) {
|
||||
TypeProjection argument = arguments.get(parameter.getIndex());
|
||||
|
||||
Variance projectionKindForKotlin = argument.getProjectionKind();
|
||||
Variance projectionKindForJava = getEffectiveVariance(
|
||||
parameter.getVariance(),
|
||||
projectionKindForKotlin,
|
||||
howThisTypeIsUsed
|
||||
);
|
||||
signatureVisitor.writeTypeArgument(projectionKindForKotlin, projectionKindForJava);
|
||||
|
||||
mapType(argument.getType(), signatureVisitor, JetTypeMapperMode.TYPE_PARAMETER);
|
||||
signatureVisitor.writeTypeArgumentEnd();
|
||||
}
|
||||
signatureVisitor.writeClassEnd();
|
||||
}
|
||||
}
|
||||
|
||||
private Type mapKnownAsmType(JetType jetType, Type asmType, @Nullable BothSignatureWriter signatureVisitor) {
|
||||
private static Variance getEffectiveVariance(Variance parameterVariance, Variance projectionKind, Variance howThisTypeIsUsed) {
|
||||
// Return type must not contain wildcards
|
||||
if (howThisTypeIsUsed == Variance.OUT_VARIANCE) return projectionKind;
|
||||
|
||||
if (parameterVariance == Variance.INVARIANT) {
|
||||
return projectionKind;
|
||||
}
|
||||
if (projectionKind == Variance.INVARIANT) {
|
||||
return parameterVariance;
|
||||
}
|
||||
if (parameterVariance == projectionKind) {
|
||||
return parameterVariance;
|
||||
}
|
||||
|
||||
// In<out X> = In<*>
|
||||
// Out<in X> = Out<*>
|
||||
return Variance.OUT_VARIANCE;
|
||||
}
|
||||
|
||||
private Type mapKnownAsmType(
|
||||
JetType jetType,
|
||||
Type asmType,
|
||||
@Nullable BothSignatureWriter signatureVisitor,
|
||||
@NotNull Variance howThisTypeIsUsed
|
||||
) {
|
||||
if (signatureVisitor != null) {
|
||||
if (jetType.getArguments().isEmpty()) {
|
||||
String kotlinTypeName = getKotlinTypeNameForSignature(jetType, asmType);
|
||||
signatureVisitor.writeAsmType(asmType, jetType.isNullable(), kotlinTypeName);
|
||||
}
|
||||
else {
|
||||
writeGenericType(signatureVisitor, asmType, jetType, false);
|
||||
writeGenericType(signatureVisitor, asmType, jetType, false, howThisTypeIsUsed);
|
||||
}
|
||||
}
|
||||
checkValidType(asmType);
|
||||
@@ -695,7 +745,7 @@ public class JetTypeMapper extends BindingTraceAware {
|
||||
signatureWriter.writeParametersEnd();
|
||||
|
||||
signatureWriter.writeReturnType();
|
||||
mapType(descriptor.getType(), signatureWriter, JetTypeMapperMode.VALUE);
|
||||
mapType(descriptor.getType(), signatureWriter, JetTypeMapperMode.VALUE, Variance.OUT_VARIANCE);
|
||||
signatureWriter.writeReturnTypeEnd();
|
||||
|
||||
JvmMethodSignature jvmMethodSignature = signatureWriter.makeJvmMethodSignature(name);
|
||||
|
||||
@@ -2,6 +2,6 @@ class Question {
|
||||
// id2 is to prevent java type parameter type inference
|
||||
static <T> T id2(T p) { return p; }
|
||||
{
|
||||
java.util.List<String> s = id2(namespace.id(null));
|
||||
java.util.List<? extends String> s = id2(namespace.id(null));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -3,5 +3,5 @@ fun foo(p: List<CharSequence>) = 1
|
||||
|
||||
// method: namespace::foo
|
||||
// jvm signature: (Ljava/util/List;)I
|
||||
// generic signature: (Ljava/util/List<Ljava/lang/CharSequence;>;)I
|
||||
// generic signature: (Ljava/util/List<+Ljava/lang/CharSequence;>;)I
|
||||
// kotlin signature: (Ljet/List<Ljava/lang/CharSequence;>;)I // TODO: skip Kotlin signature
|
||||
|
||||
@@ -3,5 +3,5 @@ fun listOfStar(): List<*> = throw Exception()
|
||||
|
||||
// method: namespace::listOfStar
|
||||
// jvm signature: ()Ljava/util/List;
|
||||
// generic signature: ()Ljava/util/List<+Ljava/lang/Object;>;
|
||||
// kotlin signature: ()Ljet/List<+?Ljava/lang/Object;>;
|
||||
// generic signature: ()Ljava/util/List<Ljava/lang/Object;>;
|
||||
// kotlin signature: ()Ljet/List<?Ljava/lang/Object;>;
|
||||
|
||||
@@ -3,5 +3,5 @@ class TestingKotlinCollections(val arguments: Collection<String>)
|
||||
|
||||
// method: TestingKotlinCollections::<init>
|
||||
// jvm signature: (Ljava/util/Collection;)V
|
||||
// generic signature: (Ljava/util/Collection<Ljava/lang/String;>;)V
|
||||
// generic signature: (Ljava/util/Collection<+Ljava/lang/String;>;)V
|
||||
// kotlin signature: (Ljet/Collection<Ljava/lang/String;>;)null
|
||||
|
||||
@@ -0,0 +1,10 @@
|
||||
class M<in K, out V>
|
||||
|
||||
class X
|
||||
|
||||
fun f(m: M<X, X>): M<X, X> = throw Exception()
|
||||
|
||||
// method: namespace::f
|
||||
// jvm signature: (LM;)LM;
|
||||
// generic signature: (LM<-LX;+LX;>;)LM<LX;LX;>;
|
||||
// kotlin signature: (LM<LX;LX;>;)LM<LX;LX;>;
|
||||
@@ -0,0 +1,8 @@
|
||||
class In<in T>
|
||||
|
||||
fun f(p: In<String>) {}
|
||||
|
||||
// method: namespace::f
|
||||
// jvm signature: (LIn;)V
|
||||
// generic signature: (LIn<-Ljava/lang/String;>;)V
|
||||
// kotlin signature: (LIn<Ljava/lang/String;>;)V
|
||||
@@ -0,0 +1,8 @@
|
||||
class In<in T>
|
||||
|
||||
fun f(): In<String> = throw Exception()
|
||||
|
||||
// method: namespace::f
|
||||
// jvm signature: ()LIn;
|
||||
// generic signature: ()LIn<Ljava/lang/String;>;
|
||||
// kotlin signature: ()LIn<Ljava/lang/String;>;
|
||||
@@ -0,0 +1,9 @@
|
||||
class In<in T>
|
||||
class X
|
||||
|
||||
fun f(p: In<In<X>>) {}
|
||||
|
||||
// method: namespace::f
|
||||
// jvm signature: (LIn;)V
|
||||
// generic signature: (LIn<-LIn<-LX;>;>;)V
|
||||
// kotlin signature: (LIn<LIn<LX;>;>;)V
|
||||
@@ -0,0 +1,9 @@
|
||||
class In<in T>
|
||||
class X
|
||||
|
||||
fun f(): In<In<X>> = throw Exception()
|
||||
|
||||
// method: namespace::f
|
||||
// jvm signature: ()LIn;
|
||||
// generic signature: ()LIn<LIn<-LX;>;>;
|
||||
// kotlin signature: ()LIn<LIn<LX;>;>;
|
||||
@@ -0,0 +1,10 @@
|
||||
class In<in T>
|
||||
class Out<out T>
|
||||
class X
|
||||
|
||||
fun f(p: In<Out<X>>) {}
|
||||
|
||||
// method: namespace::f
|
||||
// jvm signature: (LIn;)V
|
||||
// generic signature: (LIn<-LOut<+LX;>;>;)V
|
||||
// kotlin signature: (LIn<LOut<LX;>;>;)V
|
||||
@@ -0,0 +1,10 @@
|
||||
class In<in T>
|
||||
class Out<out T>
|
||||
class X
|
||||
|
||||
fun f(): In<Out<X>> = throw Exception()
|
||||
|
||||
// method: namespace::f
|
||||
// jvm signature: ()LIn;
|
||||
// generic signature: ()LIn<LOut<+LX;>;>;
|
||||
// kotlin signature: ()LIn<LOut<LX;>;>;
|
||||
@@ -0,0 +1,6 @@
|
||||
fun f(p: List<String>) {}
|
||||
|
||||
// method: namespace::f
|
||||
// jvm signature: (Ljava/util/List;)V
|
||||
// generic signature: (Ljava/util/List<+Ljava/lang/String;>;)V
|
||||
// kotlin signature: (Ljet/List<Ljava/lang/String;>;)V
|
||||
@@ -0,0 +1,6 @@
|
||||
fun f(): List<String> = throw Exception()
|
||||
|
||||
// method: namespace::f
|
||||
// jvm signature: ()Ljava/util/List;
|
||||
// generic signature: ()Ljava/util/List<Ljava/lang/String;>;
|
||||
// kotlin signature: ()Ljet/List<Ljava/lang/String;>;
|
||||
@@ -0,0 +1,10 @@
|
||||
class In<in T>
|
||||
class Out<out T>
|
||||
class X
|
||||
|
||||
fun f(p: Out<In<X>>) {}
|
||||
|
||||
// method: namespace::f
|
||||
// jvm signature: (LOut;)V
|
||||
// generic signature: (LOut<+LIn<-LX;>;>;)V
|
||||
// kotlin signature: (LOut<LIn<LX;>;>;)V
|
||||
@@ -0,0 +1,10 @@
|
||||
class In<in T>
|
||||
class Out<out T>
|
||||
class X
|
||||
|
||||
fun f(): Out<In<X>> = throw Exception()
|
||||
|
||||
// method: namespace::f
|
||||
// jvm signature: ()LOut;
|
||||
// generic signature: ()LOut<LIn<-LX;>;>;
|
||||
// kotlin signature: ()LOut<LIn<LX;>;>;
|
||||
@@ -0,0 +1,9 @@
|
||||
class Out<out T>
|
||||
class X
|
||||
|
||||
fun f(p: Out<Out<X>>) {}
|
||||
|
||||
// method: namespace::f
|
||||
// jvm signature: (LOut;)V
|
||||
// generic signature: (LOut<+LOut<+LX;>;>;)V
|
||||
// kotlin signature: (LOut<LOut<LX;>;>;)V
|
||||
@@ -0,0 +1,19 @@
|
||||
class Out<out T>
|
||||
class X
|
||||
|
||||
// Why we want this to be translated to 'Out<Out<? extends X>> f()' instead of 'Out<Out<X>> f()'
|
||||
// There are two instantiations of 'In' in this test: outer Out<...> and inner Out<X>
|
||||
// So why do we want to put a wildcard on the inner one and not the outer?
|
||||
// People don't want wildcards in return types, because they are _long_. So we try our best to remove wildcards where possible
|
||||
// Not putting a wildcard on the outer occurrence is not imposing a restriction, actually it is removing one:
|
||||
// anything that can be done with Out<? extends X> in Java can be done with Out<X>
|
||||
// But omitting the wildcard on the inner occurrence is restrictive:
|
||||
// one can add a List<String> to a List<List<? extends CharSequence>>,
|
||||
// but not to a List<List<CharSequence>>,
|
||||
// thus removing the wildcard would be restricting the use of the return value of the method, and we don't want do this.
|
||||
fun f(): Out<Out<X>> = throw Exception()
|
||||
|
||||
// method: namespace::f
|
||||
// jvm signature: ()LOut;
|
||||
// generic signature: ()LOut<LOut<+LX;>;>;
|
||||
// kotlin signature: ()LOut<LOut<LX;>;>;
|
||||
@@ -0,0 +1,9 @@
|
||||
class M<in V>
|
||||
class X
|
||||
|
||||
val p: M<X> = throw Exception()
|
||||
|
||||
// method: namespace::getP
|
||||
// jvm signature: ()LM;
|
||||
// generic signature: ()LM<LX;>;
|
||||
// kotlin signature: null
|
||||
@@ -0,0 +1,9 @@
|
||||
class M<out V>
|
||||
class X
|
||||
|
||||
val p: M<X> = throw Exception()
|
||||
|
||||
// method: namespace::getP
|
||||
// jvm signature: ()LM;
|
||||
// generic signature: ()LM<LX;>;
|
||||
// kotlin signature: null
|
||||
@@ -0,0 +1,9 @@
|
||||
class M<in K, out V>
|
||||
class X
|
||||
|
||||
val p: M<X, X> = throw Exception()
|
||||
|
||||
// method: namespace::getP
|
||||
// jvm signature: ()LM;
|
||||
// generic signature: ()LM<LX;LX;>;
|
||||
// kotlin signature: null
|
||||
@@ -0,0 +1,9 @@
|
||||
class M<in V>
|
||||
class X
|
||||
|
||||
var p: M<X> = throw Exception()
|
||||
|
||||
// method: namespace::setP
|
||||
// jvm signature: (LM;)V
|
||||
// generic signature: (LM<-LX;>;)V
|
||||
// kotlin signature: null
|
||||
@@ -0,0 +1,9 @@
|
||||
class M<out V>
|
||||
class X
|
||||
|
||||
var p: M<X> = throw Exception()
|
||||
|
||||
// method: namespace::setP
|
||||
// jvm signature: (LM;)V
|
||||
// generic signature: (LM<+LX;>;)V
|
||||
// kotlin signature: null
|
||||
Reference in New Issue
Block a user