initial implementation of class objects
This commit is contained in:
@@ -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");
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user