initial implementation of class objects

This commit is contained in:
Dmitry Jemerov
2011-07-07 16:13:25 +02:00
parent 9e28fe70c1
commit 4e48e527b1
8 changed files with 93 additions and 6 deletions
@@ -628,7 +628,7 @@ public class ExpressionCodegen extends JetVisitor {
//TODO: hack, will not need if resolve goes to right descriptor itself
if (declaration instanceof JetParameter) {
if (PsiTreeUtil.getParentOfType(expression, JetDelegationSpecifier.class) != null) {
if (PsiTreeUtil.getParentOfType(expression, JetDelegationSpecifier.class) != null) {
JetClass aClass = PsiTreeUtil.getParentOfType(expression, JetClass.class);
ConstructorDescriptor constructorDescriptor = bindingContext.getConstructorDescriptor(aClass);
List<ValueParameterDescriptor> parameters = constructorDescriptor.getValueParameters();
@@ -667,6 +667,17 @@ public class ExpressionCodegen extends JetVisitor {
myStack.push(iValue);
}
}
else if (descriptor instanceof ClassDescriptor) {
final JetClassObject classObject = ((JetClass) declaration).getClassObject();
if (classObject == null) {
throw new UnsupportedOperationException("trying to reference a class which doesn't have a class object");
}
final String type = typeMapper.jvmName(classObject);
myStack.push(StackValue.field(Type.getObjectType(type),
typeMapper.jvmName((ClassDescriptor) descriptor, OwnerKind.IMPLEMENTATION),
"$classobj",
true));
}
else {
// receiver
StackValue.local(0, JetTypeMapper.TYPE_OBJECT).put(JetTypeMapper.TYPE_OBJECT, v);
@@ -59,7 +59,7 @@ public class GenerationState {
}
public ClassVisitor forClassImplementation(ClassDescriptor aClass) {
return factory.newVisitor(JetTypeMapper.jvmNameForImplementation(aClass) + ".class");
return factory.newVisitor(typeMapper.jvmName(aClass, OwnerKind.IMPLEMENTATION) + ".class");
}
public ClassVisitor forClassDelegatingImplementation(ClassDescriptor aClass) {
@@ -2,6 +2,7 @@ package org.jetbrains.jet.codegen;
import com.intellij.psi.PsiClass;
import com.intellij.psi.PsiElement;
import org.jetbrains.annotations.Nullable;
import org.jetbrains.jet.lang.descriptors.*;
import org.jetbrains.jet.lang.psi.*;
import org.jetbrains.jet.lang.types.JetType;
@@ -73,6 +74,11 @@ public class ImplementationBodyCodegen extends ClassBodyCodegen {
Type type = JetTypeMapper.jetImplementationType(descriptor);
v.visitField(Opcodes.ACC_PUBLIC | Opcodes.ACC_STATIC, "$instance", type.getDescriptor(), null, null);
}
final JetClassObject classObject = getClassObject();
if (classObject != null) {
Type type = Type.getObjectType(state.getTypeMapper().jvmName(classObject));
v.visitField(Opcodes.ACC_PUBLIC | Opcodes.ACC_STATIC, "$classobj", type.getDescriptor(), null, null);
}
generateStaticInitializer();
@@ -133,7 +139,7 @@ public class ImplementationBodyCodegen extends ClassBodyCodegen {
iv.invokespecial(superClass, "<init>", /* TODO super constructor descriptor */"()V");
}
final DeclarationDescriptor outerDescriptor = descriptor.getContainingDeclaration();
final DeclarationDescriptor outerDescriptor = getOuterClassDescriptor();
if (outerDescriptor instanceof ClassDescriptor) {
final ClassDescriptor outerClassDescriptor = (ClassDescriptor) outerDescriptor;
final Type type = JetTypeMapper.jetImplementationType(outerClassDescriptor);
@@ -220,6 +226,15 @@ public class ImplementationBodyCodegen extends ClassBodyCodegen {
mv.visitEnd();
}
@Nullable
private ClassDescriptor getOuterClassDescriptor() {
if (myClass.getParent() instanceof JetClassObject) {
return null;
}
final DeclarationDescriptor outerDescriptor = descriptor.getContainingDeclaration();
return outerDescriptor instanceof ClassDescriptor ? (ClassDescriptor) outerDescriptor : null;
}
private void generateDelegatorToConstructorCall(InstructionAdapter iv, ExpressionCodegen codegen, JetCall constructorCall,
ConstructorDescriptor constructorDescriptor, boolean isJavaSuperclass,
ConstructorFrameMap frameMap) {
@@ -272,6 +287,9 @@ public class ImplementationBodyCodegen extends ClassBodyCodegen {
if (declaration instanceof JetConstructor) {
generateSecondaryConstructor((JetConstructor) declaration);
}
else if (declaration instanceof JetClassObject) {
generateClassObject((JetClassObject) declaration);
}
else {
super.generateDeclaration(propertyCodegen, declaration, functionCodegen);
}
@@ -387,8 +405,8 @@ public class ImplementationBodyCodegen extends ClassBodyCodegen {
private void generateStaticInitializer() {
boolean needTypeInfo = descriptor.getTypeConstructor().getParameters().size() == 0;
boolean needInstance = isNonLiteralObject();
if (!needTypeInfo && !needInstance) {
// we will have a dynamic type info field
JetClassObject classObject = getClassObject();
if (!needTypeInfo && !needInstance && classObject == null) {
return;
}
final MethodVisitor mv = v.visitMethod(Opcodes.ACC_PUBLIC | Opcodes.ACC_STATIC,
@@ -409,6 +427,15 @@ public class ImplementationBodyCodegen extends ClassBodyCodegen {
v.invokespecial(name, "<init>", "()V");
v.putstatic(name, "$instance", JetTypeMapper.jetImplementationType(descriptor).getDescriptor());
}
if (classObject != null) {
String name = state.getTypeMapper().jvmName(classObject);
final Type classObjectType = Type.getObjectType(name);
v.anew(classObjectType);
v.dup();
v.invokespecial(name, "<init>", "()V");
v.putstatic(state.getTypeMapper().jvmName(descriptor, OwnerKind.IMPLEMENTATION), "$classobj",
classObjectType.getDescriptor());
}
mv.visitInsn(Opcodes.RETURN);
mv.visitMaxs(0, 0);
@@ -416,8 +443,14 @@ public class ImplementationBodyCodegen extends ClassBodyCodegen {
mv.visitEnd();
}
@Nullable
private JetClassObject getClassObject() {
return myClass instanceof JetClass ? ((JetClass) myClass).getClassObject() : null;
}
private boolean isNonLiteralObject() {
return myClass instanceof JetObjectDeclaration && !((JetObjectDeclaration) myClass).isObjectLiteral();
return myClass instanceof JetObjectDeclaration && !((JetObjectDeclaration) myClass).isObjectLiteral() &&
!(myClass.getParent() instanceof JetClassObject);
}
private void generateGetTypeInfo() {
@@ -433,4 +466,8 @@ public class ImplementationBodyCodegen extends ClassBodyCodegen {
mv.visitMaxs(0, 0);
mv.visitEnd();
}
private void generateClassObject(JetClassObject declaration) {
state.forClass().generate(context, declaration.getObjectDeclaration());
}
}
@@ -141,6 +141,12 @@ public class JetTypeMapper {
return jvmName((PsiClass) declaration);
}
if (declaration instanceof JetObjectDeclaration && ((JetObjectDeclaration) declaration).isObjectLiteral()) {
final PsiElement parent = declaration.getParent();
if (parent instanceof JetClassObject) {
JetClass containingClass = PsiTreeUtil.getParentOfType(parent, JetClass.class);
final ClassDescriptor containingClassDescriptor = bindingContext.getClassDescriptor(containingClass);
return jvmName(containingClassDescriptor, OwnerKind.INTERFACE) + "$$ClassObj";
}
String className = classNamesForAnonymousClasses.get(declaration);
if (className == null) {
throw new UnsupportedOperationException("Unexpected forward reference to anonymous class " + declaration);
@@ -150,6 +156,11 @@ public class JetTypeMapper {
return jetJvmName(jetClass, kind);
}
public String jvmName(JetClassObject classObject) {
final ClassDescriptor descriptor = bindingContext.getClassDescriptor(classObject.getObjectDeclaration());
return jvmName(descriptor, OwnerKind.IMPLEMENTATION);
}
public boolean isInterface(ClassDescriptor jetClass, OwnerKind kind) {
PsiElement declaration = bindingContext.getDeclarationPsiElement(jetClass);
if (declaration instanceof JetObjectDeclaration && ((JetObjectDeclaration) declaration).isObjectLiteral()) {
@@ -85,6 +85,13 @@ public class JetClass extends JetTypeParameterListOwner implements JetClassOrObj
return (JetObjectDeclarationName) findChildByType(JetNodeTypes.OBJECT_DECLARATION_NAME);
}
@Nullable
public JetClassObject getClassObject() {
JetClassBody body = (JetClassBody) findChildByType(JetNodeTypes.CLASS_BODY);
if (body == null) return null;
return body.getClassObject();
}
public List<JetProperty> getProperties() {
JetClassBody body = (JetClassBody) findChildByType(JetNodeTypes.CLASS_BODY);
if (body == null) return Collections.emptyList();
@@ -3,6 +3,7 @@ package org.jetbrains.jet.lang.psi;
import com.intellij.lang.ASTNode;
import com.intellij.psi.util.PsiTreeUtil;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import org.jetbrains.jet.JetNodeTypes;
import java.util.List;
@@ -37,4 +38,9 @@ public class JetClassBody extends JetElement {
public List<JetProperty> getProperties() {
return findChildrenByType(JetNodeTypes.PROPERTY);
}
@Nullable
public JetClassObject getClassObject() {
return (JetClassObject) findChildByType(JetNodeTypes.CLASS_OBJECT);
}
}
@@ -0,0 +1,11 @@
class C() {
class object {
fun create() = C()
}
}
fun box(): String {
val c = C.create()
return if (c is C) "OK" else "fail"
}
@@ -115,4 +115,8 @@ public class ClassGenTest extends CodegenTestCase {
final Class aClass = loadAllClasses(generateClassesInFile()).get("SimpleClass$$Impl");
assertTrue((aClass.getModifiers() & Modifier.ABSTRACT) != 0);
}
public void testClassObject() throws Exception {
blackBoxFile("classes/classObject.jet");
}
}