All the special types are now handled by SpecialTypes class

- this concept used to be called "known types" before
This commit is contained in:
Andrey Breslav
2012-08-13 11:56:26 +04:00
parent f7321a40e0
commit 3b3f1aa016
2 changed files with 110 additions and 123 deletions
@@ -217,7 +217,7 @@ public class CodegenContexts {
final Type type = enclosingClassType(typeMapper); final Type type = enclosingClassType(typeMapper);
outerExpression = type != null outerExpression = type != null
? StackValue.field(type, typeMapper.getClassFQName(contextDescriptor), "this$0", false) ? StackValue.field(type, typeMapper.getJvmClassName(contextDescriptor), "this$0", false)
: null; : null;
} }
@@ -83,11 +83,78 @@ public class JetTypeMapper {
public static final Type TYPE_FUNCTION0 = Type.getObjectType("jet/Function0"); public static final Type TYPE_FUNCTION0 = Type.getObjectType("jet/Function0");
public static final Type TYPE_FUNCTION1 = Type.getObjectType("jet/Function1"); public static final Type TYPE_FUNCTION1 = Type.getObjectType("jet/Function1");
public static class SpecialTypes {
private static final class SpecialTypeKey {
@NotNull
private final FqNameUnsafe className;
private final boolean nullable;
private SpecialTypeKey(@NotNull FqNameUnsafe className, boolean nullable) {
this.className = className;
this.nullable = nullable;
}
@Override
public boolean equals(Object o) {
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false;
SpecialTypeKey that = (SpecialTypeKey) o;
if (nullable != that.nullable) return false;
if (!className.equals(that.className)) return false;
return true;
}
@Override
public int hashCode() {
int result = className.hashCode();
result = 31 * result + (nullable ? 1 : 0);
return result;
}
}
private final Map<SpecialTypeKey, Type> asmTypes = Maps.newHashMap();
@Nullable
public Type get(@NotNull JetType type) {
ClassifierDescriptor classifier = type.getConstructor().getDeclarationDescriptor();
return asmTypes.get(new SpecialTypeKey(DescriptorUtils.getFQName(classifier), type.isNullable()));
}
private void register(@NotNull ClassName className, @NotNull Type nonNullType, @NotNull Type nullableType) {
asmTypes.put(new SpecialTypeKey(className.getFqName().toUnsafe(), true), nullableType);
asmTypes.put(new SpecialTypeKey(className.getFqName().toUnsafe(), false), nonNullType);
}
public void init() {
register(JetStandardLibraryNames.NOTHING, TYPE_NOTHING, TYPE_NOTHING);
for (JvmPrimitiveType jvmPrimitiveType : JvmPrimitiveType.values()) {
PrimitiveType primitiveType = jvmPrimitiveType.getPrimitiveType();
register(primitiveType.getClassName(), jvmPrimitiveType.getAsmType(), jvmPrimitiveType.getWrapper().getAsmType());
}
register(JetStandardLibraryNames.NUMBER, JL_NUMBER_TYPE, JL_NUMBER_TYPE);
register(JetStandardLibraryNames.STRING, JL_STRING_TYPE, JL_STRING_TYPE);
register(JetStandardLibraryNames.CHAR_SEQUENCE, JL_CHAR_SEQUENCE_TYPE, JL_CHAR_SEQUENCE_TYPE);
register(JetStandardLibraryNames.THROWABLE, TYPE_THROWABLE, TYPE_THROWABLE);
register(JetStandardLibraryNames.COMPARABLE, JL_COMPARABLE_TYPE, JL_COMPARABLE_TYPE);
for (JvmPrimitiveType jvmPrimitiveType : JvmPrimitiveType.values()) {
PrimitiveType primitiveType = jvmPrimitiveType.getPrimitiveType();
register(primitiveType.getArrayClassName(), jvmPrimitiveType.getAsmArrayType(), jvmPrimitiveType.getAsmArrayType());
}
}
}
public BindingContext bindingContext; public BindingContext bindingContext;
private ClosureAnnotator closureAnnotator; private ClosureAnnotator closureAnnotator;
private boolean mapBuiltinsToJava; private boolean mapBuiltinsToJava;
private ClassBuilderMode classBuilderMode; private ClassBuilderMode classBuilderMode;
private final SpecialTypes specialTypes = new SpecialTypes();
@Inject @Inject
public void setBindingContext(BindingContext bindingContext) { public void setBindingContext(BindingContext bindingContext) {
@@ -111,12 +178,9 @@ public class JetTypeMapper {
@PostConstruct @PostConstruct
public void init() { public void init() {
initKnownTypes(); specialTypes.init();
} }
public boolean hasThis0(ClassDescriptor classDescriptor) { public boolean hasThis0(ClassDescriptor classDescriptor) {
return closureAnnotator.hasThis0(classDescriptor); return closureAnnotator.hasThis0(classDescriptor);
} }
@@ -125,40 +189,6 @@ public class JetTypeMapper {
return closureAnnotator; return closureAnnotator;
} }
private static final class KnownTypeKey {
@NotNull
private final FqNameUnsafe className;
private final boolean nullable;
private KnownTypeKey(@NotNull FqNameUnsafe className, boolean nullable) {
this.className = className;
this.nullable = nullable;
}
@Override
public boolean equals(Object o) {
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false;
KnownTypeKey that = (KnownTypeKey) o;
if (nullable != that.nullable) return false;
if (!className.equals(that.className)) return false;
return true;
}
@Override
public int hashCode() {
int result = className.hashCode();
result = 31 * result + (nullable ? 1 : 0);
return result;
}
}
private final HashMap<KnownTypeKey, Type> knowTypes = Maps.newHashMap();
public static boolean isIntPrimitive(Type type) { public static boolean isIntPrimitive(Type type) {
return type == Type.INT_TYPE || type == Type.SHORT_TYPE || type == Type.BYTE_TYPE || type == Type.CHAR_TYPE; return type == Type.INT_TYPE || type == Type.SHORT_TYPE || type == Type.BYTE_TYPE || type == Type.CHAR_TYPE;
} }
@@ -308,17 +338,12 @@ public class JetTypeMapper {
return null; return null;
} }
public JvmClassName getClassFQName(ClassDescriptor classDescriptor) { public JvmClassName getJvmClassName(ClassDescriptor classDescriptor) {
return JvmClassName.byInternalName(getFQName(classDescriptor)); return JvmClassName.byInternalName(getJvmInternalFQName(classDescriptor));
} }
/**
* @return Internal name
*
* @see DescriptorUtils#getFQName(DeclarationDescriptor)
*/
@NotNull @NotNull
private String getFQName(@NotNull DeclarationDescriptor descriptor) { private String getJvmInternalFQName(@NotNull DeclarationDescriptor descriptor) {
descriptor = descriptor.getOriginal(); descriptor = descriptor.getOriginal();
if (descriptor instanceof FunctionDescriptor) { if (descriptor instanceof FunctionDescriptor) {
@@ -339,15 +364,15 @@ public class JetTypeMapper {
if (klass.getContainingDeclaration() instanceof ClassDescriptor) { if (klass.getContainingDeclaration() instanceof ClassDescriptor) {
ClassDescriptor containingKlass = (ClassDescriptor) klass.getContainingDeclaration(); ClassDescriptor containingKlass = (ClassDescriptor) klass.getContainingDeclaration();
if (containingKlass.getKind() == ClassKind.ENUM_CLASS) { if (containingKlass.getKind() == ClassKind.ENUM_CLASS) {
return getFQName(containingKlass); return getJvmInternalFQName(containingKlass);
} }
else { else {
return getFQName(containingKlass) + JvmAbi.CLASS_OBJECT_SUFFIX; return getJvmInternalFQName(containingKlass) + JvmAbi.CLASS_OBJECT_SUFFIX;
} }
} }
} }
else if (klass.getKind() == ClassKind.ENUM_ENTRY) { else if (klass.getKind() == ClassKind.ENUM_ENTRY) {
return getFQName(klass.getContainingDeclaration()); return getJvmInternalFQName(klass.getContainingDeclaration());
} }
} }
@@ -365,7 +390,7 @@ public class JetTypeMapper {
return className.getInternalName(); return className.getInternalName();
} }
String baseName = getFQName(container); String baseName = getJvmInternalFQName(container);
if (!baseName.isEmpty()) { if (!baseName.isEmpty()) {
return baseName + (container instanceof NamespaceDescriptor ? "/" : "$") + name.getIdentifier(); return baseName + (container instanceof NamespaceDescriptor ? "/" : "$") + name.getIdentifier();
} }
@@ -385,17 +410,16 @@ public class JetTypeMapper {
if (mapBuiltinsToJava) { if (mapBuiltinsToJava) {
if (classifier instanceof ClassDescriptor) { if (classifier instanceof ClassDescriptor) {
KnownTypeKey key = new KnownTypeKey(DescriptorUtils.getFQName(classifier), jetType.isNullable()); known = specialTypes.get(jetType);
known = knowTypes.get(key);
} }
} }
if (known != null) { if (known != null) {
if (kind == MapTypeMode.VALUE) { if (kind == MapTypeMode.VALUE) {
return mapKnownAsmType(jetType, known, signatureVisitor, false); return mapKnownAsmType(jetType, known, signatureVisitor);
} }
else if (kind == MapTypeMode.TYPE_PARAMETER) { else if (kind == MapTypeMode.TYPE_PARAMETER) {
return mapKnownAsmType(jetType, known, signatureVisitor, true); return mapKnownAsmType(jetType, boxType(known), signatureVisitor);
} }
else if (kind == MapTypeMode.TRAIT_IMPL) { else if (kind == MapTypeMode.TRAIT_IMPL) {
throw new IllegalStateException("TRAIT_IMPL is not possible for " + jetType); throw new IllegalStateException("TRAIT_IMPL is not possible for " + jetType);
@@ -428,7 +452,7 @@ public class JetTypeMapper {
} }
Type asmType = Type.getObjectType("error/NonExistentClass"); Type asmType = Type.getObjectType("error/NonExistentClass");
if (signatureVisitor != null) { if (signatureVisitor != null) {
visitAsmType(signatureVisitor, asmType, true); writeSimpleType(signatureVisitor, asmType, true);
} }
checkValidType(asmType); checkValidType(asmType);
return asmType; return asmType;
@@ -461,7 +485,7 @@ public class JetTypeMapper {
if (JetStandardClasses.getAny().equals(descriptor)) { if (JetStandardClasses.getAny().equals(descriptor)) {
if (signatureVisitor != null) { if (signatureVisitor != null) {
visitAsmType(signatureVisitor, TYPE_OBJECT, jetType.isNullable()); writeSimpleType(signatureVisitor, TYPE_OBJECT, jetType.isNullable());
} }
checkValidType(TYPE_OBJECT); checkValidType(TYPE_OBJECT);
return TYPE_OBJECT; return TYPE_OBJECT;
@@ -469,33 +493,12 @@ public class JetTypeMapper {
if (descriptor instanceof ClassDescriptor) { if (descriptor instanceof ClassDescriptor) {
Type asmType;
boolean forceReal;
if (JetStandardLibraryNames.COMPARABLE.is((ClassDescriptor) descriptor) && mapBuiltinsToJava) { JvmClassName name = getJvmClassName((ClassDescriptor) descriptor);
if (jetType.getArguments().size() != 1) { Type asmType = Type.getObjectType(name.getInternalName() + (kind == MapTypeMode.TRAIT_IMPL ? JvmAbi.TRAIT_IMPL_SUFFIX : ""));
throw new UnsupportedOperationException("Comparable must have one type argument"); boolean forceReal = isForceReal(name);
}
asmType = JL_COMPARABLE_TYPE; writeGenericType(jetType, signatureVisitor, asmType, forceReal);
forceReal = false;
}
else {
JvmClassName name = getClassFQName((ClassDescriptor) descriptor);
asmType = Type.getObjectType(name.getInternalName() + (kind == MapTypeMode.TRAIT_IMPL ? JvmAbi.TRAIT_IMPL_SUFFIX : ""));
forceReal = isForceReal(name);
}
if (signatureVisitor != null) {
signatureVisitor.writeClassBegin(asmType.getInternalName(), jetType.isNullable(), forceReal);
for (TypeProjection proj : jetType.getArguments()) {
// TODO: +-
signatureVisitor.writeTypeArgument(proj.getProjectionKind());
mapType(proj.getType(), signatureVisitor, MapTypeMode.TYPE_PARAMETER);
signatureVisitor.writeTypeArgumentEnd();
}
signatureVisitor.writeClassEnd();
}
checkValidType(asmType); checkValidType(asmType);
return asmType; return asmType;
@@ -515,26 +518,34 @@ public class JetTypeMapper {
throw new UnsupportedOperationException("Unknown type " + jetType); throw new UnsupportedOperationException("Unknown type " + jetType);
} }
private Type mapKnownAsmType(JetType jetType, Type asmType, @Nullable BothSignatureWriter signatureVisitor, boolean boxPrimitive) { private void writeGenericType(JetType jetType, BothSignatureWriter signatureVisitor, Type asmType, boolean forceReal) {
if (boxPrimitive) { if (signatureVisitor != null) {
Type boxed = boxType(asmType); signatureVisitor.writeClassBegin(asmType.getInternalName(), jetType.isNullable(), forceReal);
if (signatureVisitor != null) { for (TypeProjection proj : jetType.getArguments()) {
visitAsmType(signatureVisitor, boxed, jetType.isNullable()); // TODO: +-
signatureVisitor.writeTypeArgument(proj.getProjectionKind());
mapType(proj.getType(), signatureVisitor, MapTypeMode.TYPE_PARAMETER);
signatureVisitor.writeTypeArgumentEnd();
} }
checkValidType(boxed); signatureVisitor.writeClassEnd();
return boxed;
}
else {
if (signatureVisitor != null) {
visitAsmType(signatureVisitor, asmType, jetType.isNullable());
}
checkValidType(asmType);
return asmType;
} }
} }
public static void visitAsmType(BothSignatureWriter visitor, Type asmType, boolean nullable) { private Type mapKnownAsmType(JetType jetType, Type asmType, @Nullable BothSignatureWriter signatureVisitor) {
if (signatureVisitor != null) {
if (jetType.getArguments().isEmpty()) {
writeSimpleType(signatureVisitor, asmType, jetType.isNullable());
}
else {
writeGenericType(jetType, signatureVisitor, asmType, false);
}
}
checkValidType(asmType);
return asmType;
}
public static void writeSimpleType(BothSignatureWriter visitor, Type asmType, boolean nullable) {
visitor.writeAsmType(asmType, nullable); visitor.writeAsmType(asmType, nullable);
} }
@@ -1029,30 +1040,6 @@ public class JetTypeMapper {
return result; return result;
} }
private void registerKnownType(@NotNull ClassName className, @NotNull Type nonNullType, @NotNull Type nullableType) {
knowTypes.put(new KnownTypeKey(className.getFqName().toUnsafe(), true), nullableType);
knowTypes.put(new KnownTypeKey(className.getFqName().toUnsafe(), false), nonNullType);
}
private void initKnownTypes() {
registerKnownType(JetStandardLibraryNames.NOTHING, TYPE_NOTHING, TYPE_NOTHING);
for (JvmPrimitiveType jvmPrimitiveType : JvmPrimitiveType.values()) {
PrimitiveType primitiveType = jvmPrimitiveType.getPrimitiveType();
registerKnownType(primitiveType.getClassName(), jvmPrimitiveType.getAsmType(), jvmPrimitiveType.getWrapper().getAsmType());
}
registerKnownType(JetStandardLibraryNames.NUMBER, JL_NUMBER_TYPE, JL_NUMBER_TYPE);
registerKnownType(JetStandardLibraryNames.STRING, JL_STRING_TYPE, JL_STRING_TYPE);
registerKnownType(JetStandardLibraryNames.CHAR_SEQUENCE, JL_CHAR_SEQUENCE_TYPE, JL_CHAR_SEQUENCE_TYPE);
registerKnownType(JetStandardLibraryNames.THROWABLE, TYPE_THROWABLE, TYPE_THROWABLE);
for (JvmPrimitiveType jvmPrimitiveType : JvmPrimitiveType.values()) {
PrimitiveType primitiveType = jvmPrimitiveType.getPrimitiveType();
registerKnownType(primitiveType.getArrayClassName(), jvmPrimitiveType.getAsmArrayType(), jvmPrimitiveType.getAsmArrayType());
}
}
private static boolean isForceReal(JvmClassName className) { private static boolean isForceReal(JvmClassName className) {
return JvmPrimitiveType.getByWrapperClass(className) != null return JvmPrimitiveType.getByWrapperClass(className) != null
|| className.getFqName().getFqName().equals("java.lang.String") || className.getFqName().getFqName().equals("java.lang.String")