Extract JVM descriptors type mapping from backend to core

Also unbind it from ASM types
This commit is contained in:
Denis Zharkov
2016-04-20 15:40:52 +03:00
parent 12bbbb6ff1
commit 8cf29ea4f3
8 changed files with 338 additions and 223 deletions
@@ -0,0 +1,32 @@
/*
* Copyright 2010-2016 JetBrains s.r.o.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.jetbrains.kotlin.codegen.signature
import org.jetbrains.kotlin.codegen.AsmUtil
import org.jetbrains.kotlin.load.kotlin.JvmTypeFactory
import org.jetbrains.kotlin.resolve.jvm.AsmTypes
import org.jetbrains.org.objectweb.asm.Type
object AsmTypeFactory : JvmTypeFactory<Type> {
override fun boxType(possiblyPrimitiveType: Type) = AsmUtil.boxType(possiblyPrimitiveType)
override fun createFromString(representation: String) = Type.getType(representation)
override fun createObjectType(internalName: String) = Type.getObjectType(internalName)
override fun toString(type: Type) = type.descriptor
override val javaLangClassType: Type
get() = AsmTypes.JAVA_CLASS_TYPE
}
@@ -67,7 +67,7 @@ public class BothSignatureWriter extends JvmSignatureWriter {
* Shortcut
*/
@Override
public void writeAsmType(Type asmType) {
public void writeAsmType(@NotNull Type asmType) {
if (asmType.getSort() != Type.OBJECT && asmType.getSort() != Type.ARRAY) {
signatureVisitor().visitBaseType(asmType.getDescriptor().charAt(0));
}
@@ -141,7 +141,7 @@ public class BothSignatureWriter extends JvmSignatureWriter {
}
@Override
public void writeTypeVariable(Name name, Type asmType) {
public void writeTypeVariable(@NotNull Name name, @NotNull Type asmType) {
signatureVisitor().visitTypeVariable(name.asString());
generic = true;
super.writeTypeVariable(name, asmType);
@@ -18,11 +18,10 @@ package org.jetbrains.kotlin.codegen.signature;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import org.jetbrains.kotlin.name.Name;
import org.jetbrains.kotlin.load.kotlin.JvmDescriptorTypeWriter;
import org.jetbrains.kotlin.resolve.jvm.jvmSignature.JvmMethodGenericSignature;
import org.jetbrains.kotlin.resolve.jvm.jvmSignature.JvmMethodParameterKind;
import org.jetbrains.kotlin.resolve.jvm.jvmSignature.JvmMethodParameterSignature;
import org.jetbrains.kotlin.resolve.jvm.jvmSignature.JvmMethodSignature;
import org.jetbrains.kotlin.types.Variance;
import org.jetbrains.org.objectweb.asm.Type;
import org.jetbrains.org.objectweb.asm.commons.Method;
@@ -30,22 +29,27 @@ import org.jetbrains.org.objectweb.asm.commons.Method;
import java.util.ArrayList;
import java.util.List;
public class JvmSignatureWriter {
public class JvmSignatureWriter extends JvmDescriptorTypeWriter<Type> {
private final List<JvmMethodParameterSignature> kotlinParameterTypes = new ArrayList<JvmMethodParameterSignature>();
private int jvmCurrentTypeArrayLevel;
private Type jvmCurrentType;
private Type jvmReturnType;
private JvmMethodParameterKind currentParameterKind;
private int currentSignatureSize = 0;
/**
* Shortcut
*/
public void writeAsmType(Type asmType) {
public JvmSignatureWriter() {
super(AsmTypeFactory.INSTANCE);
}
@Override
public void writeClass(@NotNull Type objectType) {
writeClassBegin(objectType);
writeClassEnd();
}
public void writeAsmType(@NotNull Type asmType) {
switch (asmType.getSort()) {
case Type.OBJECT:
writeClassBegin(asmType);
@@ -57,30 +61,16 @@ public class JvmSignatureWriter {
writeArrayEnd();
return;
default:
writeAsmType0(asmType);
}
}
private String makeArrayPrefix() {
StringBuilder sb = new StringBuilder();
for (int i = 0; i < jvmCurrentTypeArrayLevel; ++i) {
sb.append('[');
}
return sb.toString();
}
protected void writeAsmType0(Type type) {
if (jvmCurrentType == null) {
jvmCurrentType = Type.getType(makeArrayPrefix() + type.getDescriptor());
writeJvmTypeAsIs(asmType);
}
}
public void writeClassBegin(Type asmType) {
writeAsmType0(asmType);
writeJvmTypeAsIs(asmType);
}
public void writeOuterClassBegin(Type resultingAsmType, String outerInternalName) {
writeAsmType0(resultingAsmType);
writeJvmTypeAsIs(resultingAsmType);
}
public void writeInnerClass(String name) {
@@ -89,15 +79,6 @@ public class JvmSignatureWriter {
public void writeClassEnd() {
}
public void writeArrayType() {
if (jvmCurrentType == null) {
++jvmCurrentTypeArrayLevel;
}
}
public void writeArrayEnd() {
}
public void writeTypeArgument(@NotNull Variance projectionKind) {
}
@@ -107,10 +88,6 @@ public class JvmSignatureWriter {
public void writeTypeArgumentEnd() {
}
public void writeTypeVariable(Name name, Type asmType) {
writeAsmType0(asmType);
}
public void writeFormalTypeParameter(String name) {
}
@@ -128,8 +105,7 @@ public class JvmSignatureWriter {
public void writeParametersStart() {
// hacks
jvmCurrentType = null;
jvmCurrentTypeArrayLevel = 0;
clearCurrentType();
}
public void writeParameterType(JvmMethodParameterKind parameterKind) {
@@ -137,21 +113,20 @@ public class JvmSignatureWriter {
}
public void writeParameterTypeEnd() {
kotlinParameterTypes.add(new JvmMethodParameterSignature(jvmCurrentType, currentParameterKind));
currentSignatureSize += jvmCurrentType.getSize();
//noinspection ConstantConditions
kotlinParameterTypes.add(new JvmMethodParameterSignature(getJvmCurrentType(), currentParameterKind));
currentSignatureSize += getJvmCurrentType().getSize();
currentParameterKind = null;
jvmCurrentType = null;
jvmCurrentTypeArrayLevel = 0;
clearCurrentType();
}
public void writeReturnType() {
}
public void writeReturnTypeEnd() {
jvmReturnType = jvmCurrentType;
jvmCurrentType = null;
jvmCurrentTypeArrayLevel = 0;
jvmReturnType = getJvmCurrentType();
clearCurrentType();
}
public void writeSuperclass() {
@@ -19,17 +19,19 @@ package org.jetbrains.kotlin.codegen.state;
import com.intellij.openapi.util.text.StringUtil;
import com.intellij.psi.PsiElement;
import kotlin.Pair;
import kotlin.Unit;
import kotlin.collections.CollectionsKt;
import kotlin.jvm.functions.Function2;
import kotlin.jvm.functions.Function3;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import org.jetbrains.kotlin.builtins.BuiltInsPackageFragment;
import org.jetbrains.kotlin.builtins.KotlinBuiltIns;
import org.jetbrains.kotlin.builtins.PrimitiveType;
import org.jetbrains.kotlin.builtins.functions.FunctionClassDescriptor;
import org.jetbrains.kotlin.codegen.*;
import org.jetbrains.kotlin.codegen.binding.CodegenBinding;
import org.jetbrains.kotlin.codegen.binding.MutableClosure;
import org.jetbrains.kotlin.codegen.binding.PsiCodegenPredictor;
import org.jetbrains.kotlin.codegen.signature.AsmTypeFactory;
import org.jetbrains.kotlin.codegen.signature.BothSignatureWriter;
import org.jetbrains.kotlin.codegen.signature.JvmSignatureWriter;
import org.jetbrains.kotlin.descriptors.*;
@@ -45,13 +47,13 @@ import org.jetbrains.kotlin.load.java.SpecialBuiltinMembers;
import org.jetbrains.kotlin.load.java.descriptors.JavaCallableMemberDescriptor;
import org.jetbrains.kotlin.load.java.descriptors.JavaClassDescriptor;
import org.jetbrains.kotlin.load.java.lazy.descriptors.LazyJavaPackageFragment;
import org.jetbrains.kotlin.load.java.typeEnhancement.TypeEnhancementKt;
import org.jetbrains.kotlin.load.kotlin.KotlinJvmBinaryClass;
import org.jetbrains.kotlin.load.kotlin.KotlinJvmBinaryPackageSourceElement;
import org.jetbrains.kotlin.load.kotlin.KotlinJvmBinarySourceElement;
import org.jetbrains.kotlin.load.kotlin.*;
import org.jetbrains.kotlin.load.kotlin.incremental.IncrementalPackageFragmentProvider;
import org.jetbrains.kotlin.load.kotlin.incremental.components.IncrementalCache;
import org.jetbrains.kotlin.name.*;
import org.jetbrains.kotlin.name.ClassId;
import org.jetbrains.kotlin.name.FqName;
import org.jetbrains.kotlin.name.Name;
import org.jetbrains.kotlin.name.SpecialNames;
import org.jetbrains.kotlin.platform.JavaToKotlinClassMap;
import org.jetbrains.kotlin.psi.KtExpression;
import org.jetbrains.kotlin.psi.KtFile;
@@ -63,9 +65,7 @@ import org.jetbrains.kotlin.resolve.calls.model.DefaultValueArgument;
import org.jetbrains.kotlin.resolve.calls.model.ResolvedCall;
import org.jetbrains.kotlin.resolve.calls.model.ResolvedValueArgument;
import org.jetbrains.kotlin.resolve.descriptorUtil.DescriptorUtilsKt;
import org.jetbrains.kotlin.resolve.jvm.AsmTypes;
import org.jetbrains.kotlin.resolve.jvm.JvmClassName;
import org.jetbrains.kotlin.resolve.jvm.JvmPrimitiveType;
import org.jetbrains.kotlin.resolve.jvm.jvmSignature.JvmMethodGenericSignature;
import org.jetbrains.kotlin.resolve.jvm.jvmSignature.JvmMethodParameterKind;
import org.jetbrains.kotlin.resolve.jvm.jvmSignature.JvmMethodParameterSignature;
@@ -74,12 +74,11 @@ import org.jetbrains.kotlin.serialization.deserialization.DeserializedType;
import org.jetbrains.kotlin.serialization.deserialization.descriptors.DeserializedCallableMemberDescriptor;
import org.jetbrains.kotlin.serialization.deserialization.descriptors.DeserializedClassDescriptor;
import org.jetbrains.kotlin.types.*;
import org.jetbrains.kotlin.types.typeUtil.TypeUtilsKt;
import org.jetbrains.kotlin.util.OperatorNameConventions;
import org.jetbrains.org.objectweb.asm.Type;
import org.jetbrains.org.objectweb.asm.commons.Method;
import java.util.ArrayList;
import java.util.Collection;
import java.util.List;
import static org.jetbrains.kotlin.builtins.KotlinBuiltIns.isUnit;
@@ -101,6 +100,26 @@ public class KotlinTypeMapper {
private final IncrementalCache incrementalCache;
private final IncompatibleClassTracker incompatibleClassTracker;
private final String moduleName;
private final TypeMappingConfiguration<Type> typeMappingConfiguration = new TypeMappingConfiguration<Type>() {
@NotNull
@Override
public KotlinType commonSupertype(@NotNull Collection<KotlinType> types) {
return CommonSupertypes.commonSupertype(types);
}
@Nullable
@Override
public Type getPredefinedTypeForClass(@NotNull ClassDescriptor classDescriptor) {
return bindingContext.get(ASM_TYPE, classDescriptor);
}
@Override
public void processErrorType(@NotNull KotlinType kotlinType, @NotNull ClassDescriptor descriptor) {
if (classBuilderMode != ClassBuilderMode.LIGHT_CLASSES) {
throw new IllegalStateException(generateErrorMessageForErrorType(kotlinType, descriptor));
}
}
};
public KotlinTypeMapper(
@NotNull BindingContext bindingContext,
@@ -364,11 +383,6 @@ public class KotlinTypeMapper {
return mapType(returnType, sw, mappingMode);
}
@NotNull
private Type mapType(@NotNull KotlinType jetType, @NotNull TypeMappingMode mode) {
return mapType(jetType, null, mode);
}
@NotNull
public Type mapSupertype(@NotNull KotlinType jetType, @Nullable JvmSignatureWriter signatureVisitor) {
return mapType(jetType, signatureVisitor, TypeMappingMode.SUPER_TYPE);
@@ -411,161 +425,19 @@ public class KotlinTypeMapper {
@NotNull
private Type mapType(
@NotNull KotlinType jetType,
@Nullable JvmSignatureWriter signatureVisitor,
@NotNull KotlinType kotlinType,
@Nullable final JvmSignatureWriter signatureVisitor,
@NotNull TypeMappingMode mode
) {
Type builtinType = mapBuiltinType(jetType);
if (builtinType != null) {
Type asmType = mode.getNeedPrimitiveBoxing() ? boxType(builtinType) : builtinType;
writeGenericType(jetType, asmType, signatureVisitor, mode);
return asmType;
}
TypeConstructor constructor = jetType.getConstructor();
if (constructor instanceof IntersectionTypeConstructor) {
jetType = CommonSupertypes.commonSupertype(new ArrayList<KotlinType>(constructor.getSupertypes()));
// interface In<in E>
// open class A : In<A>
// open class B : In<B>
// commonSupertype(A, B) = In<A & B>
// So replace arguments with star-projections to prevent infinite recursive mapping
// It's not very important because such types anyway are prohibited in declarations
jetType = TypeUtilsKt.replaceArgumentsWithStarProjections(jetType);
constructor = jetType.getConstructor();
}
DeclarationDescriptor descriptor = constructor.getDeclarationDescriptor();
if (descriptor == null) {
throw new UnsupportedOperationException("no descriptor for type constructor of " + jetType);
}
if (ErrorUtils.isError(descriptor)) {
if (classBuilderMode != ClassBuilderMode.LIGHT_CLASSES) {
throw new IllegalStateException(generateErrorMessageForErrorType(jetType, descriptor));
}
Type asmType = Type.getObjectType("error/NonExistentClass");
if (signatureVisitor != null) {
signatureVisitor.writeAsmType(asmType);
}
return asmType;
}
if (descriptor instanceof ClassDescriptor && KotlinBuiltIns.isArray(jetType)) {
if (jetType.getArguments().size() != 1) {
throw new UnsupportedOperationException("arrays must have one type argument");
}
TypeProjection memberProjection = jetType.getArguments().get(0);
KotlinType memberType = memberProjection.getType();
Type arrayElementType;
if (memberProjection.getProjectionKind() == Variance.IN_VARIANCE) {
arrayElementType = AsmTypes.OBJECT_TYPE;
if (signatureVisitor != null) {
signatureVisitor.writeArrayType();
signatureVisitor.writeAsmType(arrayElementType);
signatureVisitor.writeArrayEnd();
}
}
else {
arrayElementType = boxType(mapType(memberType, mode));
if (signatureVisitor != null) {
signatureVisitor.writeArrayType();
mapType(memberType, signatureVisitor, mode.toGenericArgumentMode(memberProjection.getProjectionKind()));
signatureVisitor.writeArrayEnd();
}
}
return Type.getType("[" + arrayElementType.getDescriptor());
}
if (descriptor instanceof ClassDescriptor) {
Type asmType = mode.isForAnnotationParameter() && KotlinBuiltIns.isKClass((ClassDescriptor) descriptor) ?
AsmTypes.JAVA_CLASS_TYPE :
computeAsmType((ClassDescriptor) descriptor.getOriginal());
writeGenericType(jetType, asmType, signatureVisitor, mode);
return asmType;
}
if (descriptor instanceof TypeParameterDescriptor) {
Type type = mapType(getRepresentativeUpperBound((TypeParameterDescriptor) descriptor), mode);
if (signatureVisitor != null) {
signatureVisitor.writeTypeVariable(descriptor.getName(), type);
}
return type;
}
throw new UnsupportedOperationException("Unknown type " + jetType);
}
@NotNull
private static KotlinType getRepresentativeUpperBound(@NotNull TypeParameterDescriptor descriptor) {
List<KotlinType> upperBounds = descriptor.getUpperBounds();
assert !upperBounds.isEmpty() : "Upper bounds should not be empty: " + descriptor;
for (KotlinType upperBound : upperBounds) {
if (!isJvmInterface(upperBound)) {
return upperBound;
}
}
return CollectionsKt.first(upperBounds);
}
@Nullable
private static Type mapBuiltinType(@NotNull KotlinType type) {
DeclarationDescriptor descriptor = type.getConstructor().getDeclarationDescriptor();
if (!(descriptor instanceof ClassDescriptor)) return null;
FqNameUnsafe fqName = DescriptorUtils.getFqName(descriptor);
PrimitiveType primitiveType = KotlinBuiltIns.getPrimitiveTypeByFqName(fqName);
if (primitiveType != null) {
Type asmType = Type.getType(JvmPrimitiveType.get(primitiveType).getDesc());
boolean isNullableInJava = TypeUtils.isNullableType(type) || TypeEnhancementKt.hasEnhancedNullability(type);
return isNullableInJava ? boxType(asmType) : asmType;
}
PrimitiveType arrayElementType = KotlinBuiltIns.getPrimitiveTypeByArrayClassFqName(fqName);
if (arrayElementType != null) {
return Type.getType("[" + JvmPrimitiveType.get(arrayElementType).getDesc());
}
ClassId classId = JavaToKotlinClassMap.INSTANCE.mapKotlinToJava(fqName);
if (classId != null) {
return Type.getObjectType(JvmClassName.byClassId(classId).getInternalName());
}
return null;
}
@NotNull
private Type computeAsmType(@NotNull ClassDescriptor klass) {
Type alreadyComputedType = bindingContext.get(ASM_TYPE, klass);
if (alreadyComputedType != null) {
return alreadyComputedType;
}
Type asmType = Type.getObjectType(computeAsmTypeImpl(klass));
assert PsiCodegenPredictor.checkPredictedNameFromPsi(klass, asmType, fileClassesProvider);
return asmType;
}
@NotNull
private String computeAsmTypeImpl(@NotNull ClassDescriptor klass) {
DeclarationDescriptor container = klass.getContainingDeclaration();
String name = SpecialNames.safeIdentifier(klass.getName()).getIdentifier();
if (container instanceof PackageFragmentDescriptor) {
FqName fqName = ((PackageFragmentDescriptor) container).getFqName();
return fqName.isRoot() ? name : fqName.asString().replace('.', '/') + '/' + name;
}
assert container instanceof ClassDescriptor : "Unexpected container: " + container + " for " + klass;
String containerInternalName = computeAsmTypeImpl((ClassDescriptor) container);
return klass.getKind() == ClassKind.ENUM_ENTRY ? containerInternalName : containerInternalName + "$" + name;
return TypeSignatureMappingKt.mapType(
kotlinType, AsmTypeFactory.INSTANCE, mode, typeMappingConfiguration, signatureVisitor,
new Function3<KotlinType, Type, TypeMappingMode, Unit>() {
@Override
public Unit invoke(KotlinType kotlinType, Type type, TypeMappingMode mode) {
writeGenericType(kotlinType, type, signatureVisitor, mode);
return Unit.INSTANCE;
}
});
}
@NotNull
@@ -21,6 +21,7 @@ import org.jetbrains.kotlin.builtins.KotlinBuiltIns
import org.jetbrains.kotlin.builtins.KotlinBuiltIns.FQ_NAMES as BUILTIN_NAMES
import org.jetbrains.kotlin.descriptors.*
import org.jetbrains.kotlin.descriptors.annotations.AnnotationDescriptor
import org.jetbrains.kotlin.load.kotlin.TypeMappingMode
import org.jetbrains.kotlin.name.FqName
import org.jetbrains.kotlin.name.Name
import org.jetbrains.kotlin.resolve.descriptorUtil.firstOverridden
@@ -1,5 +1,5 @@
/*
* Copyright 2010-2015 JetBrains s.r.o.
* Copyright 2010-2016 JetBrains s.r.o.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -14,12 +14,12 @@
* limitations under the License.
*/
package org.jetbrains.kotlin.codegen.state
package org.jetbrains.kotlin.load.kotlin
import org.jetbrains.kotlin.types.KotlinType
import org.jetbrains.kotlin.types.Variance
internal class TypeMappingMode private constructor(
class TypeMappingMode private constructor(
val needPrimitiveBoxing: Boolean = true,
val isForAnnotationParameter: Boolean = false,
// Here DeclarationSiteWildcards means wildcard generated because of declaration-site variance
@@ -120,7 +120,7 @@ internal class TypeMappingMode private constructor(
fun toGenericArgumentMode(effectiveVariance: Variance): TypeMappingMode =
when (effectiveVariance) {
Variance.IN_VARIANCE -> genericContravariantArgumentMode ?: this
Variance.INVARIANT -> genericInvariantArgumentMode ?: this
Variance.INVARIANT -> genericInvariantArgumentMode ?: this
else -> genericArgumentMode ?: this
}
}
@@ -0,0 +1,234 @@
/*
* Copyright 2010-2016 JetBrains s.r.o.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.jetbrains.kotlin.load.kotlin
import org.jetbrains.kotlin.builtins.KotlinBuiltIns
import org.jetbrains.kotlin.descriptors.ClassDescriptor
import org.jetbrains.kotlin.descriptors.ClassKind
import org.jetbrains.kotlin.descriptors.PackageFragmentDescriptor
import org.jetbrains.kotlin.descriptors.TypeParameterDescriptor
import org.jetbrains.kotlin.load.java.typeEnhancement.hasEnhancedNullability
import org.jetbrains.kotlin.name.Name
import org.jetbrains.kotlin.name.SpecialNames
import org.jetbrains.kotlin.platform.JavaToKotlinClassMap
import org.jetbrains.kotlin.resolve.descriptorUtil.fqNameUnsafe
import org.jetbrains.kotlin.resolve.jvm.JvmClassName
import org.jetbrains.kotlin.resolve.jvm.JvmPrimitiveType
import org.jetbrains.kotlin.types.*
import org.jetbrains.kotlin.types.typeUtil.replaceArgumentsWithStarProjections
import org.jetbrains.kotlin.utils.DO_NOTHING_3
interface JvmTypeFactory<T : Any> {
fun boxType(possiblyPrimitiveType: T): T
fun createFromString(representation: String): T
fun createObjectType(internalName: String): T
fun toString(type: T): String
val javaLangClassType: T
}
private fun <T : Any> JvmTypeFactory<T>.boxTypeIfNeeded(possiblyPrimitiveType: T, needBoxedType: Boolean) =
if (needBoxedType) boxType(possiblyPrimitiveType) else possiblyPrimitiveType
interface TypeMappingConfiguration<out T : Any> {
fun commonSupertype(types: Collection<@JvmSuppressWildcards KotlinType>): KotlinType
fun getPredefinedTypeForClass(classDescriptor: ClassDescriptor): T?
fun processErrorType(kotlinType: KotlinType, descriptor: ClassDescriptor)
}
fun <T : Any> mapType(
kotlinType: KotlinType,
factory: JvmTypeFactory<T>,
mode: TypeMappingMode,
typeMappingConfiguration: TypeMappingConfiguration<T>,
descriptorTypeWriter: JvmDescriptorTypeWriter<T>?,
writeGenericType: (KotlinType, T, TypeMappingMode) -> Unit = DO_NOTHING_3
): T {
mapBuiltInType(kotlinType, factory)?.let { builtInType ->
val jvmType = factory.boxTypeIfNeeded(builtInType, mode.needPrimitiveBoxing)
writeGenericType(kotlinType, jvmType, mode)
return jvmType
}
val constructor = kotlinType.constructor
if (constructor is IntersectionTypeConstructor) {
val commonSupertype = typeMappingConfiguration.commonSupertype(constructor.supertypes)
// interface In<in E>
// open class A : In<A>
// open class B : In<B>
// commonSupertype(A, B) = In<A & B>
// So replace arguments with star-projections to prevent infinite recursive mapping
// It's not very important because such types anyway are prohibited in declarations
return mapType(
commonSupertype.replaceArgumentsWithStarProjections(),
factory, mode, typeMappingConfiguration, descriptorTypeWriter, writeGenericType)
}
val descriptor =
constructor.declarationDescriptor
?: throw UnsupportedOperationException("no descriptor for type constructor of " + kotlinType)
when {
ErrorUtils.isError(descriptor) -> {
val jvmType = factory.createObjectType("error/NonExistentClass")
typeMappingConfiguration.processErrorType(kotlinType, descriptor as ClassDescriptor)
descriptorTypeWriter?.writeClass(jvmType)
return jvmType
}
descriptor is ClassDescriptor && KotlinBuiltIns.isArray(kotlinType) -> {
if (kotlinType.arguments.size != 1) {
throw UnsupportedOperationException("arrays must have one type argument")
}
val memberProjection = kotlinType.arguments[0]
val memberType = memberProjection.type
val arrayElementType: T
if (memberProjection.projectionKind === Variance.IN_VARIANCE) {
arrayElementType = factory.createObjectType("java/lang/Object")
descriptorTypeWriter?.apply {
writeArrayType()
writeClass(arrayElementType)
writeArrayEnd()
}
}
else {
descriptorTypeWriter?.writeArrayType()
arrayElementType =
mapType(
memberType, factory,
mode.toGenericArgumentMode(memberProjection.projectionKind),
typeMappingConfiguration, descriptorTypeWriter, writeGenericType)
descriptorTypeWriter?.writeArrayEnd()
}
return factory.createFromString("[" + factory.toString(arrayElementType))
}
descriptor is ClassDescriptor -> {
val jvmType =
if (mode.isForAnnotationParameter && KotlinBuiltIns.isKClass(descriptor))
factory.javaLangClassType
else
typeMappingConfiguration.getPredefinedTypeForClass(descriptor.original)
?: factory.createObjectType(computeInternalName(descriptor.original))
writeGenericType(kotlinType, jvmType, mode)
return jvmType
}
descriptor is TypeParameterDescriptor -> {
val type = mapType(getRepresentativeUpperBound(descriptor),
factory, mode, typeMappingConfiguration, writeGenericType = DO_NOTHING_3, descriptorTypeWriter = null)
descriptorTypeWriter?.writeTypeVariable(descriptor.getName(), type);
return type
}
else -> throw UnsupportedOperationException("Unknown type " + kotlinType)
}
}
private fun <T : Any> mapBuiltInType(
type: KotlinType,
typeFactory: JvmTypeFactory<T>
): T? {
val descriptor = type.constructor.declarationDescriptor as? ClassDescriptor ?: return null
val fqName = descriptor.fqNameUnsafe
val primitiveType = KotlinBuiltIns.getPrimitiveTypeByFqName(fqName)
if (primitiveType != null) {
val jvmType = typeFactory.createFromString(JvmPrimitiveType.get(primitiveType).desc)
val isNullableInJava = TypeUtils.isNullableType(type) || type.hasEnhancedNullability()
return typeFactory.boxTypeIfNeeded(jvmType, isNullableInJava)
}
val arrayElementType = KotlinBuiltIns.getPrimitiveTypeByArrayClassFqName(fqName)
if (arrayElementType != null) {
return typeFactory.createFromString("[" + JvmPrimitiveType.get(arrayElementType).desc)
}
val classId = JavaToKotlinClassMap.INSTANCE.mapKotlinToJava(fqName)
if (classId != null) {
return typeFactory.createObjectType(JvmClassName.byClassId(classId).internalName)
}
return null
}
private fun computeInternalName(klass: ClassDescriptor): String {
val container = klass.containingDeclaration
val name = SpecialNames.safeIdentifier(klass.name).identifier
if (container is PackageFragmentDescriptor) {
val fqName = container.fqName
return if (fqName.isRoot) name else fqName.asString().replace('.', '/') + '/' + name
}
assert(container is ClassDescriptor) { "Unexpected container: $container for $klass" }
val containerInternalName = computeInternalName(container as ClassDescriptor)
return if (klass.kind == ClassKind.ENUM_ENTRY) containerInternalName else containerInternalName + "$" + name
}
private fun getRepresentativeUpperBound(descriptor: TypeParameterDescriptor): KotlinType {
val upperBounds = descriptor.upperBounds
assert(!upperBounds.isEmpty()) { "Upper bounds should not be empty: " + descriptor }
return upperBounds.firstOrNull {
val classDescriptor = it.constructor.declarationDescriptor as? ClassDescriptor ?: return@firstOrNull false
classDescriptor.kind != ClassKind.INTERFACE && classDescriptor.kind != ClassKind.ANNOTATION_CLASS
} ?: upperBounds.first()
}
open class JvmDescriptorTypeWriter<T : Any>(private val jvmTypeFactory: JvmTypeFactory<T>) {
private var jvmCurrentTypeArrayLevel: Int = 0
protected var jvmCurrentType: T? = null
private set
protected fun clearCurrentType() {
jvmCurrentType = null
jvmCurrentTypeArrayLevel = 0
}
open fun writeArrayType() {
if (jvmCurrentType == null) {
++jvmCurrentTypeArrayLevel
}
}
open fun writeArrayEnd() {
}
open public fun writeClass(objectType: T) {
writeJvmTypeAsIs(objectType)
}
protected fun writeJvmTypeAsIs(type: T) {
if (jvmCurrentType == null) {
jvmCurrentType = jvmTypeFactory.createFromString("[".repeat(jvmCurrentTypeArrayLevel) + jvmTypeFactory.toString(type))
}
}
open fun writeTypeVariable(name: Name, type: T) {
writeJvmTypeAsIs(type)
}
}
@@ -31,5 +31,6 @@ private val ALWAYS_NULL: (Any?) -> Any? = { null }
fun <T, R: Any> alwaysNull(): (T) -> R? = ALWAYS_NULL as (T) -> R?
val DO_NOTHING: (Any?) -> Unit = { }
val DO_NOTHING_3: (Any?, Any?, Any?) -> Unit = { x, y, z -> }
fun <T> doNothing(): (T) -> Unit = DO_NOTHING