Extract JVM descriptors type mapping from backend to core
Also unbind it from ASM types
This commit is contained in:
@@ -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
|
||||
}
|
||||
+2
-2
@@ -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);
|
||||
|
||||
+23
-48
@@ -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
|
||||
|
||||
+4
-4
@@ -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
|
||||
}
|
||||
}
|
||||
+234
@@ -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
|
||||
|
||||
Reference in New Issue
Block a user