initial basic implementation of object literals; move anonymous class name mapping to JetTypeMapper; cleanup many usages of JetTypeMapper

This commit is contained in:
Dmitry Jemerov
2011-06-29 17:10:47 +02:00
parent f26d0b4af7
commit 47bb3d6a2c
12 changed files with 140 additions and 62 deletions
@@ -1,10 +1,7 @@
package org.jetbrains.jet.codegen; package org.jetbrains.jet.codegen;
import org.jetbrains.jet.lang.descriptors.ClassDescriptor; import org.jetbrains.jet.lang.descriptors.ClassDescriptor;
import org.jetbrains.jet.lang.psi.JetClass; import org.jetbrains.jet.lang.psi.*;
import org.jetbrains.jet.lang.psi.JetClassOrObject;
import org.jetbrains.jet.lang.psi.JetDeclaration;
import org.jetbrains.jet.lang.psi.JetObjectDeclaration;
import org.objectweb.asm.ClassVisitor; import org.objectweb.asm.ClassVisitor;
import org.objectweb.asm.Type; import org.objectweb.asm.Type;
import org.objectweb.asm.commons.InstructionAdapter; import org.objectweb.asm.commons.InstructionAdapter;
@@ -20,6 +17,8 @@ public class ClassCodegen {
} }
public void generate(JetClassOrObject aClass) { public void generate(JetClassOrObject aClass) {
prepareAnonymousClasses(aClass);
if (aClass instanceof JetObjectDeclaration) { if (aClass instanceof JetObjectDeclaration) {
generateImplementation(aClass, OwnerKind.IMPLEMENTATION); generateImplementation(aClass, OwnerKind.IMPLEMENTATION);
} }
@@ -36,6 +35,21 @@ public class ClassCodegen {
} }
} }
private void prepareAnonymousClasses(JetClassOrObject aClass) {
aClass.acceptChildren(new JetVisitor() {
@Override
public void visitJetElement(JetElement element) {
super.visitJetElement(element);
element.acceptChildren(this);
}
@Override
public void visitObjectLiteralExpression(JetObjectLiteralExpression expression) {
state.getTypeMapper().classNameForAnonymousClass(expression.getObjectDeclaration());
}
});
}
private void generateInterface(JetClassOrObject aClass) { private void generateInterface(JetClassOrObject aClass) {
final ClassVisitor visitor = state.forClassInterface(state.getBindingContext().getClassDescriptor(aClass)); final ClassVisitor visitor = state.forClassInterface(state.getBindingContext().getClassDescriptor(aClass));
new InterfaceBodyCodegen(aClass, visitor, state).generate(); new InterfaceBodyCodegen(aClass, visitor, state).generate();
@@ -1,7 +1,6 @@
package org.jetbrains.jet.codegen; package org.jetbrains.jet.codegen;
import com.intellij.openapi.project.Project; import com.intellij.openapi.project.Project;
import com.intellij.openapi.util.Pair;
import org.jetbrains.jet.lang.psi.JetNamespace; import org.jetbrains.jet.lang.psi.JetNamespace;
import org.objectweb.asm.ClassVisitor; import org.objectweb.asm.ClassVisitor;
import org.objectweb.asm.ClassWriter; import org.objectweb.asm.ClassWriter;
@@ -19,7 +18,6 @@ public class ClassFileFactory {
private final boolean isText; private final boolean isText;
private final Map<String, NamespaceCodegen> ns2codegen = new HashMap<String, NamespaceCodegen>(); private final Map<String, NamespaceCodegen> ns2codegen = new HashMap<String, NamespaceCodegen>();
private final Map<String, ClassVisitor> generators = new LinkedHashMap<String, ClassVisitor>(); private final Map<String, ClassVisitor> generators = new LinkedHashMap<String, ClassVisitor>();
private final Map<String, Integer> closuresCount = new HashMap<String, Integer>();
private boolean isDone = false; private boolean isDone = false;
public final GenerationState state; public final GenerationState state;
@@ -42,14 +40,8 @@ public class ClassFileFactory {
return visitor; return visitor;
} }
Pair<String, ClassVisitor> forClosureIn(String baseName) { ClassVisitor forAnonymousSubclass(String className) {
Integer count = closuresCount.get(baseName); return newVisitor(className + ".class");
if (count == null) count = 0;
closuresCount.put(baseName, count + 1);
final String className = baseName + "$" + (count + 1);
return new Pair<String, ClassVisitor>(className, newVisitor(className + ".class"));
} }
NamespaceCodegen forNamespace(JetNamespace namespace) { NamespaceCodegen forNamespace(JetNamespace namespace) {
@@ -4,7 +4,6 @@
package org.jetbrains.jet.codegen; package org.jetbrains.jet.codegen;
import com.intellij.openapi.util.Pair; import com.intellij.openapi.util.Pair;
import com.intellij.psi.util.PsiTreeUtil;
import org.jetbrains.jet.lang.descriptors.DeclarationDescriptor; import org.jetbrains.jet.lang.descriptors.DeclarationDescriptor;
import org.jetbrains.jet.lang.descriptors.FunctionDescriptor; import org.jetbrains.jet.lang.descriptors.FunctionDescriptor;
import org.jetbrains.jet.lang.descriptors.ValueParameterDescriptor; import org.jetbrains.jet.lang.descriptors.ValueParameterDescriptor;
@@ -78,17 +77,8 @@ public class ClosureCodegen {
return null; return null;
} }
public GeneratedClosureDescriptor gen(JetFunctionLiteralExpression fun) { public GeneratedAnonymousClassDescriptor gen(JetFunctionLiteralExpression fun) {
JetNamedDeclaration container = PsiTreeUtil.getParentOfType(fun, JetNamespace.class, JetClass.class, JetObjectDeclaration.class); final Pair<String, ClassVisitor> nameAndVisitor = state.forAnonymousSubclass(fun);
final Pair<String, ClassVisitor> nameAndVisitor;
if (container instanceof JetNamespace) {
nameAndVisitor = state.forClosureIn((JetNamespace) container);
}
else {
nameAndVisitor = state.forClosureIn(state.getBindingContext().getClassDescriptor((JetClassOrObject) container));
}
final FunctionDescriptor funDescriptor = (FunctionDescriptor) state.getBindingContext().getDeclarationDescriptor(fun); final FunctionDescriptor funDescriptor = (FunctionDescriptor) state.getBindingContext().getDeclarationDescriptor(fun);
@@ -123,7 +113,7 @@ public class ClosureCodegen {
cv.visitEnd(); cv.visitEnd();
final GeneratedClosureDescriptor answer = new GeneratedClosureDescriptor(name, constructor); final GeneratedAnonymousClassDescriptor answer = new GeneratedAnonymousClassDescriptor(name, constructor);
for (DeclarationDescriptor descriptor : closure.keySet()) { for (DeclarationDescriptor descriptor : closure.keySet()) {
final EnclosedValueDescriptor valueDescriptor = closure.get(descriptor); final EnclosedValueDescriptor valueDescriptor = closure.get(descriptor);
answer.addArg(valueDescriptor.getOuterValue()); answer.addArg(valueDescriptor.getOuterValue());
@@ -94,8 +94,8 @@ public class ExpressionCodegen extends JetVisitor {
outerThisExpressions.put(outer, expression); outerThisExpressions.put(outer, expression);
} }
static void loadTypeInfo(ClassDescriptor descriptor, InstructionAdapter v) { static void loadTypeInfo(JetTypeMapper typeMapper, ClassDescriptor descriptor, InstructionAdapter v) {
String owner = JetTypeMapper.jvmNameForImplementation(descriptor); String owner = typeMapper.jvmName(descriptor, OwnerKind.IMPLEMENTATION);
if (descriptor.getTypeConstructor().getParameters().size() > 0) { if (descriptor.getTypeConstructor().getParameters().size() > 0) {
v.load(0, JetTypeMapper.TYPE_OBJECT); v.load(0, JetTypeMapper.TYPE_OBJECT);
v.getfield(owner, "$typeInfo", "Ljet/typeinfo/TypeInfo;"); v.getfield(owner, "$typeInfo", "Ljet/typeinfo/TypeInfo;");
@@ -482,7 +482,7 @@ public class ExpressionCodegen extends JetVisitor {
generateBlock(expression.getFunctionLiteral().getBodyExpression().getStatements()); generateBlock(expression.getFunctionLiteral().getBodyExpression().getStatements());
} }
else { else {
final GeneratedClosureDescriptor closure = state.generateClosure(expression, this); final GeneratedAnonymousClassDescriptor closure = state.generateClosure(expression, this);
v.anew(Type.getObjectType(closure.getClassname())); v.anew(Type.getObjectType(closure.getClassname()));
v.dup(); v.dup();
@@ -498,6 +498,14 @@ public class ExpressionCodegen extends JetVisitor {
} }
} }
@Override
public void visitObjectLiteralExpression(JetObjectLiteralExpression expression) {
GeneratedAnonymousClassDescriptor descriptor = state.generateObjectLiteral(expression, this);
v.anew(Type.getObjectType(descriptor.getClassname()));
v.dup();
v.invokespecial(descriptor.getClassname(), "<init>", descriptor.getConstructor().getDescriptor());
}
private void generateBlock(List<JetElement> statements) { private void generateBlock(List<JetElement> statements) {
Label blockStart = new Label(); Label blockStart = new Label();
v.mark(blockStart); v.mark(blockStart);
@@ -778,7 +786,7 @@ public class ExpressionCodegen extends JetVisitor {
methodDescriptor.getName(), methodDescriptor.getName(),
methodDescriptor.getDescriptor()); methodDescriptor.getDescriptor());
} }
else if(declarationPsiElement instanceof JetNamedFunction) { else if (declarationPsiElement instanceof JetNamedFunction) {
final JetNamedFunction jetFunction = (JetNamedFunction) declarationPsiElement; final JetNamedFunction jetFunction = (JetNamedFunction) declarationPsiElement;
methodDescriptor = typeMapper.mapSignature(jetFunction); methodDescriptor = typeMapper.mapSignature(jetFunction);
if (functionParent instanceof NamespaceDescriptorImpl) { if (functionParent instanceof NamespaceDescriptorImpl) {
@@ -790,10 +798,14 @@ public class ExpressionCodegen extends JetVisitor {
v.invokestatic(owner, methodDescriptor.getName(), methodDescriptor.getDescriptor()); v.invokestatic(owner, methodDescriptor.getName(), methodDescriptor.getDescriptor());
} }
else if (functionParent instanceof ClassDescriptor) { else if (functionParent instanceof ClassDescriptor) {
ensureReceiverOnStack(expression, (ClassDescriptor) functionParent); ClassDescriptor containingClass = (ClassDescriptor) functionParent;
ensureReceiverOnStack(expression, containingClass);
pushMethodArguments(expression, methodDescriptor); pushMethodArguments(expression, methodDescriptor);
final String owner = JetTypeMapper.jvmNameForInterface((ClassDescriptor) functionParent); final String owner = typeMapper.jvmName(containingClass, OwnerKind.INTERFACE);
v.invokeinterface(owner, methodDescriptor.getName(), methodDescriptor.getDescriptor()); int opcode = typeMapper.isInterface(containingClass, OwnerKind.INTERFACE)
? Opcodes.INVOKEINTERFACE
: Opcodes.INVOKEVIRTUAL;
v.visitMethodInsn(opcode,owner, methodDescriptor.getName(), methodDescriptor.getDescriptor());
} }
else { else {
throw new UnsupportedOperationException("don't know how to generate call to " + declarationPsiElement); throw new UnsupportedOperationException("don't know how to generate call to " + declarationPsiElement);
@@ -1682,7 +1694,7 @@ public class ExpressionCodegen extends JetVisitor {
if (declarationDescriptor instanceof TypeParameterDescriptor) { if (declarationDescriptor instanceof TypeParameterDescriptor) {
DeclarationDescriptor containingDeclaration = declarationDescriptor.getContainingDeclaration(); DeclarationDescriptor containingDeclaration = declarationDescriptor.getContainingDeclaration();
if (containingDeclaration == contextType && contextType instanceof ClassDescriptor) { if (containingDeclaration == contextType && contextType instanceof ClassDescriptor) {
loadTypeInfo((ClassDescriptor) contextType, v); loadTypeInfo(typeMapper, (ClassDescriptor) contextType, v);
v.iconst(((TypeParameterDescriptor) declarationDescriptor).getIndex()); v.iconst(((TypeParameterDescriptor) declarationDescriptor).getIndex());
v.invokevirtual("jet/typeinfo/TypeInfo", "getTypeParameter", "(I)Ljet/typeinfo/TypeInfo;"); v.invokevirtual("jet/typeinfo/TypeInfo", "getTypeParameter", "(I)Ljet/typeinfo/TypeInfo;");
return; return;
@@ -8,12 +8,12 @@ import org.objectweb.asm.commons.Method;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.List; import java.util.List;
public class GeneratedClosureDescriptor { public class GeneratedAnonymousClassDescriptor {
private final String classname; private final String classname;
private Method constructor; private Method constructor;
private List<StackValue> args = new ArrayList<StackValue>(); private List<StackValue> args = new ArrayList<StackValue>();
public GeneratedClosureDescriptor(String classname, Method constructor) { public GeneratedAnonymousClassDescriptor(String classname, Method constructor) {
this.classname = classname; this.classname = classname;
this.constructor = constructor; this.constructor = constructor;
} }
@@ -10,13 +10,12 @@ import org.jetbrains.jet.lang.ErrorHandler;
import org.jetbrains.jet.lang.cfg.pseudocode.JetControlFlowDataTraceFactory; import org.jetbrains.jet.lang.cfg.pseudocode.JetControlFlowDataTraceFactory;
import org.jetbrains.jet.lang.descriptors.ClassDescriptor; import org.jetbrains.jet.lang.descriptors.ClassDescriptor;
import org.jetbrains.jet.lang.descriptors.DeclarationDescriptor; import org.jetbrains.jet.lang.descriptors.DeclarationDescriptor;
import org.jetbrains.jet.lang.psi.JetFile; import org.jetbrains.jet.lang.psi.*;
import org.jetbrains.jet.lang.psi.JetFunctionLiteralExpression;
import org.jetbrains.jet.lang.psi.JetNamespace;
import org.jetbrains.jet.lang.resolve.AnalyzingUtils; import org.jetbrains.jet.lang.resolve.AnalyzingUtils;
import org.jetbrains.jet.lang.resolve.BindingContext; import org.jetbrains.jet.lang.resolve.BindingContext;
import org.jetbrains.jet.lang.types.JetStandardLibrary; import org.jetbrains.jet.lang.types.JetStandardLibrary;
import org.objectweb.asm.ClassVisitor; import org.objectweb.asm.ClassVisitor;
import org.objectweb.asm.commons.Method;
public class GenerationState { public class GenerationState {
private final ClassFileFactory factory; private final ClassFileFactory factory;
@@ -69,12 +68,10 @@ public class GenerationState {
return factory.newVisitor(JetTypeMapper.jvmNameForDelegatingImplementation(aClass) + ".class"); return factory.newVisitor(JetTypeMapper.jvmNameForDelegatingImplementation(aClass) + ".class");
} }
public Pair<String, ClassVisitor> forClosureIn(ClassDescriptor aClass) { public Pair<String, ClassVisitor> forAnonymousSubclass(JetExpression expression) {
return factory.forClosureIn(JetTypeMapper.jvmNameForInterface(aClass)); String className = typeMapper.classNameForAnonymousClass(expression);
} ClassVisitor visitor = factory.forAnonymousSubclass(className);
return Pair.create(className, visitor);
public Pair<String, ClassVisitor> forClosureIn(JetNamespace namespace) {
return factory.forClosureIn(NamespaceCodegen.getJVMClassName(namespace.getFQName()));
} }
public NamespaceCodegen forNamespace(JetNamespace namespace) { public NamespaceCodegen forNamespace(JetNamespace namespace) {
@@ -97,18 +94,24 @@ public class GenerationState {
} }
} }
public GeneratedClosureDescriptor generateClosure(JetFunctionLiteralExpression literal, ExpressionCodegen context) { public GeneratedAnonymousClassDescriptor generateClosure(JetFunctionLiteralExpression literal, ExpressionCodegen context) {
final ClosureCodegen codegen = new ClosureCodegen(this, context); final ClosureCodegen codegen = new ClosureCodegen(this, context);
closureContexts.push(codegen); closureContexts.push(codegen);
try { try {
return codegen.gen(literal); return codegen.gen(literal);
} }
finally { finally {
final ClosureCodegen pooped = closureContexts.pop(); final ClosureCodegen popped = closureContexts.pop();
assert pooped == codegen; assert popped == codegen;
} }
} }
public GeneratedAnonymousClassDescriptor generateObjectLiteral(JetObjectLiteralExpression literal, ExpressionCodegen context) {
Pair<String, ClassVisitor> nameAndVisitor = forAnonymousSubclass(literal.getObjectDeclaration());
new ImplementationBodyCodegen(literal.getObjectDeclaration(), OwnerKind.IMPLEMENTATION, nameAndVisitor.getSecond(), this).generate();
return new GeneratedAnonymousClassDescriptor(nameAndVisitor.first, new Method("<init>", "()V"));
}
public StackValue lookupInContext(DeclarationDescriptor d) { public StackValue lookupInContext(DeclarationDescriptor d) {
final ClosureCodegen top = closureContexts.peek(); final ClosureCodegen top = closureContexts.peek();
return top != null ? top.lookupInContext(d) : null; return top != null ? top.lookupInContext(d) : null;
@@ -42,7 +42,7 @@ public class ImplementationBodyCodegen extends ClassBodyCodegen {
} }
private String jvmName() { private String jvmName() {
return JetTypeMapper.jetJvmName(descriptor, kind); return state.getTypeMapper().jvmName(descriptor, kind);
} }
protected String getSuperClass() { protected String getSuperClass() {
@@ -65,7 +65,7 @@ public class ImplementationBodyCodegen extends ClassBodyCodegen {
int typeinfoStatic = descriptor.getTypeConstructor().getParameters().size() > 0 ? 0 : Opcodes.ACC_STATIC; int typeinfoStatic = descriptor.getTypeConstructor().getParameters().size() > 0 ? 0 : Opcodes.ACC_STATIC;
v.visitField(Opcodes.ACC_PRIVATE | typeinfoStatic, "$typeInfo", "Ljet/typeinfo/TypeInfo;", null, null); v.visitField(Opcodes.ACC_PRIVATE | typeinfoStatic, "$typeInfo", "Ljet/typeinfo/TypeInfo;", null, null);
if (myClass instanceof JetObjectDeclaration) { if (isNonLiteralObject()) {
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);
} }
@@ -381,7 +381,7 @@ 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 = myClass instanceof JetObjectDeclaration; boolean needInstance = isNonLiteralObject();
if (!needTypeInfo && !needInstance) { if (!needTypeInfo && !needInstance) {
// we will have a dynamic type info field // we will have a dynamic type info field
return; return;
@@ -393,8 +393,9 @@ public class ImplementationBodyCodegen extends ClassBodyCodegen {
InstructionAdapter v = new InstructionAdapter(mv); InstructionAdapter v = new InstructionAdapter(mv);
if (needTypeInfo) { if (needTypeInfo) {
ClassCodegen.newTypeInfo(v, state.getTypeMapper().jvmType(descriptor, OwnerKind.INTERFACE)); JetTypeMapper typeMapper = state.getTypeMapper();
v.putstatic(JetTypeMapper.jvmNameForImplementation(descriptor), "$typeInfo", "Ljet/typeinfo/TypeInfo;"); ClassCodegen.newTypeInfo(v, typeMapper.jvmType(descriptor, OwnerKind.INTERFACE));
v.putstatic(typeMapper.jvmName(descriptor, kind), "$typeInfo", "Ljet/typeinfo/TypeInfo;");
} }
if (needInstance) { if (needInstance) {
String name = jvmName(); String name = jvmName();
@@ -410,6 +411,10 @@ public class ImplementationBodyCodegen extends ClassBodyCodegen {
mv.visitEnd(); mv.visitEnd();
} }
private boolean isNonLiteralObject() {
return myClass instanceof JetObjectDeclaration && !((JetObjectDeclaration) myClass).isObjectLiteral();
}
private void generateGetTypeInfo() { private void generateGetTypeInfo() {
final MethodVisitor mv = v.visitMethod(Opcodes.ACC_PUBLIC, final MethodVisitor mv = v.visitMethod(Opcodes.ACC_PUBLIC,
"getTypeInfo", "getTypeInfo",
@@ -418,7 +423,7 @@ public class ImplementationBodyCodegen extends ClassBodyCodegen {
null); null);
mv.visitCode(); mv.visitCode();
InstructionAdapter v = new InstructionAdapter(mv); InstructionAdapter v = new InstructionAdapter(mv);
ExpressionCodegen.loadTypeInfo(descriptor, v); ExpressionCodegen.loadTypeInfo(state.getTypeMapper(), descriptor, v);
v.areturn(JetTypeMapper.TYPE_TYPEINFO); v.areturn(JetTypeMapper.TYPE_TYPEINFO);
mv.visitMaxs(0, 0); mv.visitMaxs(0, 0);
mv.visitEnd(); mv.visitEnd();
@@ -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 com.intellij.psi.util.PsiTreeUtil;
import jet.typeinfo.TypeInfo; import jet.typeinfo.TypeInfo;
import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.NotNull;
import org.jetbrains.jet.lang.descriptors.*; import org.jetbrains.jet.lang.descriptors.*;
@@ -15,7 +16,9 @@ import org.objectweb.asm.Type;
import org.objectweb.asm.commons.Method; import org.objectweb.asm.commons.Method;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.HashMap;
import java.util.List; import java.util.List;
import java.util.Map;
/** /**
* @author yole * @author yole
@@ -26,6 +29,8 @@ public class JetTypeMapper {
private final JetStandardLibrary standardLibrary; private final JetStandardLibrary standardLibrary;
private final BindingContext bindingContext; private final BindingContext bindingContext;
private final Map<JetExpression, String> classNamesForAnonymousClasses = new HashMap<JetExpression, String>();
private final Map<String, Integer> anonymousSubclassesCount = new HashMap<String, Integer>();
public JetTypeMapper(JetStandardLibrary standardLibrary, BindingContext bindingContext) { public JetTypeMapper(JetStandardLibrary standardLibrary, BindingContext bindingContext) {
this.standardLibrary = standardLibrary; this.standardLibrary = standardLibrary;
@@ -49,10 +54,25 @@ public class JetTypeMapper {
if (declaration instanceof PsiClass) { if (declaration instanceof PsiClass) {
return jvmName((PsiClass) declaration); return jvmName((PsiClass) declaration);
} }
if (declaration instanceof JetObjectDeclaration && ((JetObjectDeclaration) declaration).isObjectLiteral()) {
String className = classNamesForAnonymousClasses.get(declaration);
if (className == null) {
throw new UnsupportedOperationException("Unexpected forward reference to anonymous class " + declaration);
}
return className;
}
return jetJvmName(jetClass, kind); return jetJvmName(jetClass, kind);
} }
public static String jetJvmName(ClassDescriptor jetClass, OwnerKind kind) { public boolean isInterface(ClassDescriptor jetClass, OwnerKind kind) {
PsiElement declaration = bindingContext.getDeclarationPsiElement(jetClass);
if (declaration instanceof JetObjectDeclaration && ((JetObjectDeclaration) declaration).isObjectLiteral()) {
return false;
}
return kind == OwnerKind.INTERFACE;
}
private static String jetJvmName(ClassDescriptor jetClass, OwnerKind kind) {
if (jetClass.isObject()) { if (jetClass.isObject()) {
return jvmNameForImplementation(jetClass); return jvmNameForImplementation(jetClass);
} }
@@ -209,11 +229,7 @@ public class JetTypeMapper {
} }
if (descriptor instanceof ClassDescriptor) { if (descriptor instanceof ClassDescriptor) {
final PsiElement declaration = bindingContext.getDeclarationPsiElement(descriptor); return Type.getObjectType(jvmName((ClassDescriptor) descriptor, kind));
if (declaration instanceof PsiClass) {
return psiClassType((PsiClass) declaration);
}
return Type.getObjectType(jetJvmName((ClassDescriptor) descriptor, kind));
} }
throw new UnsupportedOperationException("Unknown type " + jetType); throw new UnsupportedOperationException("Unknown type " + jetType);
@@ -370,4 +386,31 @@ public class JetTypeMapper {
} }
return flags; return flags;
} }
String classNameForAnonymousClass(JetExpression expression) {
String name = classNamesForAnonymousClasses.get(expression);
if (name != null) {
return name;
}
JetNamedDeclaration container = PsiTreeUtil.getParentOfType(expression, JetNamespace.class, JetClass.class, JetObjectDeclaration.class);
String baseName;
if (container instanceof JetNamespace) {
baseName = NamespaceCodegen.getJVMClassName(((JetNamespace) container).getFQName());
}
else {
ClassDescriptor aClass = bindingContext.getClassDescriptor((JetClassOrObject) container);
baseName = JetTypeMapper.jvmNameForInterface(aClass);
}
Integer count = anonymousSubclassesCount.get(baseName);
if (count == null) count = 0;
anonymousSubclassesCount.put(baseName, count + 1);
final String className = baseName + "$" + (count + 1);
classNamesForAnonymousClasses.put(expression, className);
return className;
}
} }
@@ -1,5 +1,6 @@
package org.jetbrains.jet.lang.psi; package org.jetbrains.jet.lang.psi;
import com.intellij.psi.PsiElement;
import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable; import org.jetbrains.annotations.Nullable;
@@ -8,7 +9,7 @@ import java.util.List;
/** /**
* @author max * @author max
*/ */
public interface JetClassOrObject { public interface JetClassOrObject extends PsiElement {
List<JetDeclaration> getDeclarations(); List<JetDeclaration> getDeclarations();
@Nullable @Nullable
@@ -82,4 +82,8 @@ public class JetObjectDeclaration extends JetNamedDeclaration implements JetClas
public void accept(JetVisitor visitor) { public void accept(JetVisitor visitor) {
visitor.visitObjectDeclaration(this); visitor.visitObjectDeclaration(this);
} }
public boolean isObjectLiteral() {
return getNameAsDeclaration() == null;
}
} }
@@ -0,0 +1,10 @@
class C() {
val child = object {
fun toString(): String = "child"
}
}
fun box(): String {
val c = C()
return if (c.child.toString() == "child") "OK" else "fail"
}
@@ -7,4 +7,8 @@ public class ObjectGenTest extends CodegenTestCase {
public void testSimpleObject() throws Exception { public void testSimpleObject() throws Exception {
blackBoxFile("objects/simpleObject.jet"); blackBoxFile("objects/simpleObject.jet");
} }
public void testObjectLiteral() throws Exception {
blackBoxFile("objects/objectLiteral.jet");
}
} }