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
|
//TODO: hack, will not need if resolve goes to right descriptor itself
|
||||||
if (declaration instanceof JetParameter) {
|
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);
|
JetClass aClass = PsiTreeUtil.getParentOfType(expression, JetClass.class);
|
||||||
ConstructorDescriptor constructorDescriptor = bindingContext.getConstructorDescriptor(aClass);
|
ConstructorDescriptor constructorDescriptor = bindingContext.getConstructorDescriptor(aClass);
|
||||||
List<ValueParameterDescriptor> parameters = constructorDescriptor.getValueParameters();
|
List<ValueParameterDescriptor> parameters = constructorDescriptor.getValueParameters();
|
||||||
@@ -667,6 +667,17 @@ public class ExpressionCodegen extends JetVisitor {
|
|||||||
myStack.push(iValue);
|
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 {
|
else {
|
||||||
// receiver
|
// receiver
|
||||||
StackValue.local(0, JetTypeMapper.TYPE_OBJECT).put(JetTypeMapper.TYPE_OBJECT, v);
|
StackValue.local(0, JetTypeMapper.TYPE_OBJECT).put(JetTypeMapper.TYPE_OBJECT, v);
|
||||||
|
|||||||
@@ -59,7 +59,7 @@ public class GenerationState {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public ClassVisitor forClassImplementation(ClassDescriptor aClass) {
|
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) {
|
public ClassVisitor forClassDelegatingImplementation(ClassDescriptor aClass) {
|
||||||
|
|||||||
@@ -2,6 +2,7 @@ package org.jetbrains.jet.codegen;
|
|||||||
|
|
||||||
import com.intellij.psi.PsiClass;
|
import com.intellij.psi.PsiClass;
|
||||||
import com.intellij.psi.PsiElement;
|
import com.intellij.psi.PsiElement;
|
||||||
|
import org.jetbrains.annotations.Nullable;
|
||||||
import org.jetbrains.jet.lang.descriptors.*;
|
import org.jetbrains.jet.lang.descriptors.*;
|
||||||
import org.jetbrains.jet.lang.psi.*;
|
import org.jetbrains.jet.lang.psi.*;
|
||||||
import org.jetbrains.jet.lang.types.JetType;
|
import org.jetbrains.jet.lang.types.JetType;
|
||||||
@@ -73,6 +74,11 @@ public class ImplementationBodyCodegen extends ClassBodyCodegen {
|
|||||||
Type type = JetTypeMapper.jetImplementationType(descriptor);
|
Type type = JetTypeMapper.jetImplementationType(descriptor);
|
||||||
v.visitField(Opcodes.ACC_PUBLIC | Opcodes.ACC_STATIC, "$instance", type.getDescriptor(), null, null);
|
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();
|
generateStaticInitializer();
|
||||||
|
|
||||||
@@ -133,7 +139,7 @@ public class ImplementationBodyCodegen extends ClassBodyCodegen {
|
|||||||
iv.invokespecial(superClass, "<init>", /* TODO super constructor descriptor */"()V");
|
iv.invokespecial(superClass, "<init>", /* TODO super constructor descriptor */"()V");
|
||||||
}
|
}
|
||||||
|
|
||||||
final DeclarationDescriptor outerDescriptor = descriptor.getContainingDeclaration();
|
final DeclarationDescriptor outerDescriptor = getOuterClassDescriptor();
|
||||||
if (outerDescriptor instanceof ClassDescriptor) {
|
if (outerDescriptor instanceof ClassDescriptor) {
|
||||||
final ClassDescriptor outerClassDescriptor = (ClassDescriptor) outerDescriptor;
|
final ClassDescriptor outerClassDescriptor = (ClassDescriptor) outerDescriptor;
|
||||||
final Type type = JetTypeMapper.jetImplementationType(outerClassDescriptor);
|
final Type type = JetTypeMapper.jetImplementationType(outerClassDescriptor);
|
||||||
@@ -220,6 +226,15 @@ public class ImplementationBodyCodegen extends ClassBodyCodegen {
|
|||||||
mv.visitEnd();
|
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,
|
private void generateDelegatorToConstructorCall(InstructionAdapter iv, ExpressionCodegen codegen, JetCall constructorCall,
|
||||||
ConstructorDescriptor constructorDescriptor, boolean isJavaSuperclass,
|
ConstructorDescriptor constructorDescriptor, boolean isJavaSuperclass,
|
||||||
ConstructorFrameMap frameMap) {
|
ConstructorFrameMap frameMap) {
|
||||||
@@ -272,6 +287,9 @@ public class ImplementationBodyCodegen extends ClassBodyCodegen {
|
|||||||
if (declaration instanceof JetConstructor) {
|
if (declaration instanceof JetConstructor) {
|
||||||
generateSecondaryConstructor((JetConstructor) declaration);
|
generateSecondaryConstructor((JetConstructor) declaration);
|
||||||
}
|
}
|
||||||
|
else if (declaration instanceof JetClassObject) {
|
||||||
|
generateClassObject((JetClassObject) declaration);
|
||||||
|
}
|
||||||
else {
|
else {
|
||||||
super.generateDeclaration(propertyCodegen, declaration, functionCodegen);
|
super.generateDeclaration(propertyCodegen, declaration, functionCodegen);
|
||||||
}
|
}
|
||||||
@@ -387,8 +405,8 @@ public class ImplementationBodyCodegen extends ClassBodyCodegen {
|
|||||||
private void generateStaticInitializer() {
|
private void generateStaticInitializer() {
|
||||||
boolean needTypeInfo = descriptor.getTypeConstructor().getParameters().size() == 0;
|
boolean needTypeInfo = descriptor.getTypeConstructor().getParameters().size() == 0;
|
||||||
boolean needInstance = isNonLiteralObject();
|
boolean needInstance = isNonLiteralObject();
|
||||||
if (!needTypeInfo && !needInstance) {
|
JetClassObject classObject = getClassObject();
|
||||||
// we will have a dynamic type info field
|
if (!needTypeInfo && !needInstance && classObject == null) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
final MethodVisitor mv = v.visitMethod(Opcodes.ACC_PUBLIC | Opcodes.ACC_STATIC,
|
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.invokespecial(name, "<init>", "()V");
|
||||||
v.putstatic(name, "$instance", JetTypeMapper.jetImplementationType(descriptor).getDescriptor());
|
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.visitInsn(Opcodes.RETURN);
|
||||||
mv.visitMaxs(0, 0);
|
mv.visitMaxs(0, 0);
|
||||||
@@ -416,8 +443,14 @@ public class ImplementationBodyCodegen extends ClassBodyCodegen {
|
|||||||
mv.visitEnd();
|
mv.visitEnd();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Nullable
|
||||||
|
private JetClassObject getClassObject() {
|
||||||
|
return myClass instanceof JetClass ? ((JetClass) myClass).getClassObject() : null;
|
||||||
|
}
|
||||||
|
|
||||||
private boolean isNonLiteralObject() {
|
private boolean isNonLiteralObject() {
|
||||||
return myClass instanceof JetObjectDeclaration && !((JetObjectDeclaration) myClass).isObjectLiteral();
|
return myClass instanceof JetObjectDeclaration && !((JetObjectDeclaration) myClass).isObjectLiteral() &&
|
||||||
|
!(myClass.getParent() instanceof JetClassObject);
|
||||||
}
|
}
|
||||||
|
|
||||||
private void generateGetTypeInfo() {
|
private void generateGetTypeInfo() {
|
||||||
@@ -433,4 +466,8 @@ public class ImplementationBodyCodegen extends ClassBodyCodegen {
|
|||||||
mv.visitMaxs(0, 0);
|
mv.visitMaxs(0, 0);
|
||||||
mv.visitEnd();
|
mv.visitEnd();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private void generateClassObject(JetClassObject declaration) {
|
||||||
|
state.forClass().generate(context, declaration.getObjectDeclaration());
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -141,6 +141,12 @@ public class JetTypeMapper {
|
|||||||
return jvmName((PsiClass) declaration);
|
return jvmName((PsiClass) declaration);
|
||||||
}
|
}
|
||||||
if (declaration instanceof JetObjectDeclaration && ((JetObjectDeclaration) declaration).isObjectLiteral()) {
|
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);
|
String className = classNamesForAnonymousClasses.get(declaration);
|
||||||
if (className == null) {
|
if (className == null) {
|
||||||
throw new UnsupportedOperationException("Unexpected forward reference to anonymous class " + declaration);
|
throw new UnsupportedOperationException("Unexpected forward reference to anonymous class " + declaration);
|
||||||
@@ -150,6 +156,11 @@ public class JetTypeMapper {
|
|||||||
return jetJvmName(jetClass, kind);
|
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) {
|
public boolean isInterface(ClassDescriptor jetClass, OwnerKind kind) {
|
||||||
PsiElement declaration = bindingContext.getDeclarationPsiElement(jetClass);
|
PsiElement declaration = bindingContext.getDeclarationPsiElement(jetClass);
|
||||||
if (declaration instanceof JetObjectDeclaration && ((JetObjectDeclaration) declaration).isObjectLiteral()) {
|
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);
|
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() {
|
public List<JetProperty> getProperties() {
|
||||||
JetClassBody body = (JetClassBody) findChildByType(JetNodeTypes.CLASS_BODY);
|
JetClassBody body = (JetClassBody) findChildByType(JetNodeTypes.CLASS_BODY);
|
||||||
if (body == null) return Collections.emptyList();
|
if (body == null) return Collections.emptyList();
|
||||||
|
|||||||
@@ -3,6 +3,7 @@ package org.jetbrains.jet.lang.psi;
|
|||||||
import com.intellij.lang.ASTNode;
|
import com.intellij.lang.ASTNode;
|
||||||
import com.intellij.psi.util.PsiTreeUtil;
|
import com.intellij.psi.util.PsiTreeUtil;
|
||||||
import org.jetbrains.annotations.NotNull;
|
import org.jetbrains.annotations.NotNull;
|
||||||
|
import org.jetbrains.annotations.Nullable;
|
||||||
import org.jetbrains.jet.JetNodeTypes;
|
import org.jetbrains.jet.JetNodeTypes;
|
||||||
|
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
@@ -37,4 +38,9 @@ public class JetClassBody extends JetElement {
|
|||||||
public List<JetProperty> getProperties() {
|
public List<JetProperty> getProperties() {
|
||||||
return findChildrenByType(JetNodeTypes.PROPERTY);
|
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");
|
final Class aClass = loadAllClasses(generateClassesInFile()).get("SimpleClass$$Impl");
|
||||||
assertTrue((aClass.getModifiers() & Modifier.ABSTRACT) != 0);
|
assertTrue((aClass.getModifiers() & Modifier.ABSTRACT) != 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public void testClassObject() throws Exception {
|
||||||
|
blackBoxFile("classes/classObject.jet");
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user