From 47bb3d6a2cb73c5882447dcff4e1cd5d61cf4ada Mon Sep 17 00:00:00 2001 From: Dmitry Jemerov Date: Wed, 29 Jun 2011 17:10:47 +0200 Subject: [PATCH] initial basic implementation of object literals; move anonymous class name mapping to JetTypeMapper; cleanup many usages of JetTypeMapper --- .../jetbrains/jet/codegen/ClassCodegen.java | 22 ++++++-- .../jet/codegen/ClassFileFactory.java | 12 +--- .../jetbrains/jet/codegen/ClosureCodegen.java | 16 +----- .../jet/codegen/ExpressionCodegen.java | 28 +++++++--- ...=> GeneratedAnonymousClassDescriptor.java} | 4 +- .../jet/codegen/GenerationState.java | 27 +++++---- .../codegen/ImplementationBodyCodegen.java | 17 ++++-- .../jetbrains/jet/codegen/JetTypeMapper.java | 55 +++++++++++++++++-- .../jet/lang/psi/JetClassOrObject.java | 3 +- .../jet/lang/psi/JetObjectDeclaration.java | 4 ++ .../codegen/objects/objectLiteral.jet | 10 ++++ .../jetbrains/jet/codegen/ObjectGenTest.java | 4 ++ 12 files changed, 140 insertions(+), 62 deletions(-) rename idea/src/org/jetbrains/jet/codegen/{GeneratedClosureDescriptor.java => GeneratedAnonymousClassDescriptor.java} (82%) create mode 100644 idea/testData/codegen/objects/objectLiteral.jet diff --git a/idea/src/org/jetbrains/jet/codegen/ClassCodegen.java b/idea/src/org/jetbrains/jet/codegen/ClassCodegen.java index 09d36e40bec..3c4c2cd578e 100644 --- a/idea/src/org/jetbrains/jet/codegen/ClassCodegen.java +++ b/idea/src/org/jetbrains/jet/codegen/ClassCodegen.java @@ -1,10 +1,7 @@ package org.jetbrains.jet.codegen; import org.jetbrains.jet.lang.descriptors.ClassDescriptor; -import org.jetbrains.jet.lang.psi.JetClass; -import org.jetbrains.jet.lang.psi.JetClassOrObject; -import org.jetbrains.jet.lang.psi.JetDeclaration; -import org.jetbrains.jet.lang.psi.JetObjectDeclaration; +import org.jetbrains.jet.lang.psi.*; import org.objectweb.asm.ClassVisitor; import org.objectweb.asm.Type; import org.objectweb.asm.commons.InstructionAdapter; @@ -20,6 +17,8 @@ public class ClassCodegen { } public void generate(JetClassOrObject aClass) { + prepareAnonymousClasses(aClass); + if (aClass instanceof JetObjectDeclaration) { 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) { final ClassVisitor visitor = state.forClassInterface(state.getBindingContext().getClassDescriptor(aClass)); new InterfaceBodyCodegen(aClass, visitor, state).generate(); diff --git a/idea/src/org/jetbrains/jet/codegen/ClassFileFactory.java b/idea/src/org/jetbrains/jet/codegen/ClassFileFactory.java index ab2a9753e33..c7fa87a0ae7 100644 --- a/idea/src/org/jetbrains/jet/codegen/ClassFileFactory.java +++ b/idea/src/org/jetbrains/jet/codegen/ClassFileFactory.java @@ -1,7 +1,6 @@ package org.jetbrains.jet.codegen; import com.intellij.openapi.project.Project; -import com.intellij.openapi.util.Pair; import org.jetbrains.jet.lang.psi.JetNamespace; import org.objectweb.asm.ClassVisitor; import org.objectweb.asm.ClassWriter; @@ -19,7 +18,6 @@ public class ClassFileFactory { private final boolean isText; private final Map ns2codegen = new HashMap(); private final Map generators = new LinkedHashMap(); - private final Map closuresCount = new HashMap(); private boolean isDone = false; public final GenerationState state; @@ -42,14 +40,8 @@ public class ClassFileFactory { return visitor; } - Pair forClosureIn(String baseName) { - Integer count = closuresCount.get(baseName); - if (count == null) count = 0; - - closuresCount.put(baseName, count + 1); - - final String className = baseName + "$" + (count + 1); - return new Pair(className, newVisitor(className + ".class")); + ClassVisitor forAnonymousSubclass(String className) { + return newVisitor(className + ".class"); } NamespaceCodegen forNamespace(JetNamespace namespace) { diff --git a/idea/src/org/jetbrains/jet/codegen/ClosureCodegen.java b/idea/src/org/jetbrains/jet/codegen/ClosureCodegen.java index cf3055f7505..de3765bdcf5 100644 --- a/idea/src/org/jetbrains/jet/codegen/ClosureCodegen.java +++ b/idea/src/org/jetbrains/jet/codegen/ClosureCodegen.java @@ -4,7 +4,6 @@ package org.jetbrains.jet.codegen; 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.FunctionDescriptor; import org.jetbrains.jet.lang.descriptors.ValueParameterDescriptor; @@ -78,17 +77,8 @@ public class ClosureCodegen { return null; } - public GeneratedClosureDescriptor gen(JetFunctionLiteralExpression fun) { - JetNamedDeclaration container = PsiTreeUtil.getParentOfType(fun, JetNamespace.class, JetClass.class, JetObjectDeclaration.class); - - final Pair nameAndVisitor; - if (container instanceof JetNamespace) { - nameAndVisitor = state.forClosureIn((JetNamespace) container); - } - else { - nameAndVisitor = state.forClosureIn(state.getBindingContext().getClassDescriptor((JetClassOrObject) container)); - } - + public GeneratedAnonymousClassDescriptor gen(JetFunctionLiteralExpression fun) { + final Pair nameAndVisitor = state.forAnonymousSubclass(fun); final FunctionDescriptor funDescriptor = (FunctionDescriptor) state.getBindingContext().getDeclarationDescriptor(fun); @@ -123,7 +113,7 @@ public class ClosureCodegen { cv.visitEnd(); - final GeneratedClosureDescriptor answer = new GeneratedClosureDescriptor(name, constructor); + final GeneratedAnonymousClassDescriptor answer = new GeneratedAnonymousClassDescriptor(name, constructor); for (DeclarationDescriptor descriptor : closure.keySet()) { final EnclosedValueDescriptor valueDescriptor = closure.get(descriptor); answer.addArg(valueDescriptor.getOuterValue()); diff --git a/idea/src/org/jetbrains/jet/codegen/ExpressionCodegen.java b/idea/src/org/jetbrains/jet/codegen/ExpressionCodegen.java index 9374ee0dfe2..4edbf4b725a 100644 --- a/idea/src/org/jetbrains/jet/codegen/ExpressionCodegen.java +++ b/idea/src/org/jetbrains/jet/codegen/ExpressionCodegen.java @@ -94,8 +94,8 @@ public class ExpressionCodegen extends JetVisitor { outerThisExpressions.put(outer, expression); } - static void loadTypeInfo(ClassDescriptor descriptor, InstructionAdapter v) { - String owner = JetTypeMapper.jvmNameForImplementation(descriptor); + static void loadTypeInfo(JetTypeMapper typeMapper, ClassDescriptor descriptor, InstructionAdapter v) { + String owner = typeMapper.jvmName(descriptor, OwnerKind.IMPLEMENTATION); if (descriptor.getTypeConstructor().getParameters().size() > 0) { v.load(0, JetTypeMapper.TYPE_OBJECT); v.getfield(owner, "$typeInfo", "Ljet/typeinfo/TypeInfo;"); @@ -482,7 +482,7 @@ public class ExpressionCodegen extends JetVisitor { generateBlock(expression.getFunctionLiteral().getBodyExpression().getStatements()); } else { - final GeneratedClosureDescriptor closure = state.generateClosure(expression, this); + final GeneratedAnonymousClassDescriptor closure = state.generateClosure(expression, this); v.anew(Type.getObjectType(closure.getClassname())); 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(), "", descriptor.getConstructor().getDescriptor()); + } + private void generateBlock(List statements) { Label blockStart = new Label(); v.mark(blockStart); @@ -778,7 +786,7 @@ public class ExpressionCodegen extends JetVisitor { methodDescriptor.getName(), methodDescriptor.getDescriptor()); } - else if(declarationPsiElement instanceof JetNamedFunction) { + else if (declarationPsiElement instanceof JetNamedFunction) { final JetNamedFunction jetFunction = (JetNamedFunction) declarationPsiElement; methodDescriptor = typeMapper.mapSignature(jetFunction); if (functionParent instanceof NamespaceDescriptorImpl) { @@ -790,10 +798,14 @@ public class ExpressionCodegen extends JetVisitor { v.invokestatic(owner, methodDescriptor.getName(), methodDescriptor.getDescriptor()); } else if (functionParent instanceof ClassDescriptor) { - ensureReceiverOnStack(expression, (ClassDescriptor) functionParent); + ClassDescriptor containingClass = (ClassDescriptor) functionParent; + ensureReceiverOnStack(expression, containingClass); pushMethodArguments(expression, methodDescriptor); - final String owner = JetTypeMapper.jvmNameForInterface((ClassDescriptor) functionParent); - v.invokeinterface(owner, methodDescriptor.getName(), methodDescriptor.getDescriptor()); + final String owner = typeMapper.jvmName(containingClass, OwnerKind.INTERFACE); + int opcode = typeMapper.isInterface(containingClass, OwnerKind.INTERFACE) + ? Opcodes.INVOKEINTERFACE + : Opcodes.INVOKEVIRTUAL; + v.visitMethodInsn(opcode,owner, methodDescriptor.getName(), methodDescriptor.getDescriptor()); } else { 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) { DeclarationDescriptor containingDeclaration = declarationDescriptor.getContainingDeclaration(); if (containingDeclaration == contextType && contextType instanceof ClassDescriptor) { - loadTypeInfo((ClassDescriptor) contextType, v); + loadTypeInfo(typeMapper, (ClassDescriptor) contextType, v); v.iconst(((TypeParameterDescriptor) declarationDescriptor).getIndex()); v.invokevirtual("jet/typeinfo/TypeInfo", "getTypeParameter", "(I)Ljet/typeinfo/TypeInfo;"); return; diff --git a/idea/src/org/jetbrains/jet/codegen/GeneratedClosureDescriptor.java b/idea/src/org/jetbrains/jet/codegen/GeneratedAnonymousClassDescriptor.java similarity index 82% rename from idea/src/org/jetbrains/jet/codegen/GeneratedClosureDescriptor.java rename to idea/src/org/jetbrains/jet/codegen/GeneratedAnonymousClassDescriptor.java index 0aaba59a48b..f02567b8802 100644 --- a/idea/src/org/jetbrains/jet/codegen/GeneratedClosureDescriptor.java +++ b/idea/src/org/jetbrains/jet/codegen/GeneratedAnonymousClassDescriptor.java @@ -8,12 +8,12 @@ import org.objectweb.asm.commons.Method; import java.util.ArrayList; import java.util.List; -public class GeneratedClosureDescriptor { +public class GeneratedAnonymousClassDescriptor { private final String classname; private Method constructor; private List args = new ArrayList(); - public GeneratedClosureDescriptor(String classname, Method constructor) { + public GeneratedAnonymousClassDescriptor(String classname, Method constructor) { this.classname = classname; this.constructor = constructor; } diff --git a/idea/src/org/jetbrains/jet/codegen/GenerationState.java b/idea/src/org/jetbrains/jet/codegen/GenerationState.java index e7723c90abf..f752144ea70 100644 --- a/idea/src/org/jetbrains/jet/codegen/GenerationState.java +++ b/idea/src/org/jetbrains/jet/codegen/GenerationState.java @@ -10,13 +10,12 @@ import org.jetbrains.jet.lang.ErrorHandler; import org.jetbrains.jet.lang.cfg.pseudocode.JetControlFlowDataTraceFactory; import org.jetbrains.jet.lang.descriptors.ClassDescriptor; import org.jetbrains.jet.lang.descriptors.DeclarationDescriptor; -import org.jetbrains.jet.lang.psi.JetFile; -import org.jetbrains.jet.lang.psi.JetFunctionLiteralExpression; -import org.jetbrains.jet.lang.psi.JetNamespace; +import org.jetbrains.jet.lang.psi.*; import org.jetbrains.jet.lang.resolve.AnalyzingUtils; import org.jetbrains.jet.lang.resolve.BindingContext; import org.jetbrains.jet.lang.types.JetStandardLibrary; import org.objectweb.asm.ClassVisitor; +import org.objectweb.asm.commons.Method; public class GenerationState { private final ClassFileFactory factory; @@ -69,12 +68,10 @@ public class GenerationState { return factory.newVisitor(JetTypeMapper.jvmNameForDelegatingImplementation(aClass) + ".class"); } - public Pair forClosureIn(ClassDescriptor aClass) { - return factory.forClosureIn(JetTypeMapper.jvmNameForInterface(aClass)); - } - - public Pair forClosureIn(JetNamespace namespace) { - return factory.forClosureIn(NamespaceCodegen.getJVMClassName(namespace.getFQName())); + public Pair forAnonymousSubclass(JetExpression expression) { + String className = typeMapper.classNameForAnonymousClass(expression); + ClassVisitor visitor = factory.forAnonymousSubclass(className); + return Pair.create(className, visitor); } 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); closureContexts.push(codegen); try { return codegen.gen(literal); } finally { - final ClosureCodegen pooped = closureContexts.pop(); - assert pooped == codegen; + final ClosureCodegen popped = closureContexts.pop(); + assert popped == codegen; } } + public GeneratedAnonymousClassDescriptor generateObjectLiteral(JetObjectLiteralExpression literal, ExpressionCodegen context) { + Pair nameAndVisitor = forAnonymousSubclass(literal.getObjectDeclaration()); + new ImplementationBodyCodegen(literal.getObjectDeclaration(), OwnerKind.IMPLEMENTATION, nameAndVisitor.getSecond(), this).generate(); + return new GeneratedAnonymousClassDescriptor(nameAndVisitor.first, new Method("", "()V")); + } + public StackValue lookupInContext(DeclarationDescriptor d) { final ClosureCodegen top = closureContexts.peek(); return top != null ? top.lookupInContext(d) : null; diff --git a/idea/src/org/jetbrains/jet/codegen/ImplementationBodyCodegen.java b/idea/src/org/jetbrains/jet/codegen/ImplementationBodyCodegen.java index efdc5ae47ce..aebceb809e1 100644 --- a/idea/src/org/jetbrains/jet/codegen/ImplementationBodyCodegen.java +++ b/idea/src/org/jetbrains/jet/codegen/ImplementationBodyCodegen.java @@ -42,7 +42,7 @@ public class ImplementationBodyCodegen extends ClassBodyCodegen { } private String jvmName() { - return JetTypeMapper.jetJvmName(descriptor, kind); + return state.getTypeMapper().jvmName(descriptor, kind); } protected String getSuperClass() { @@ -65,7 +65,7 @@ public class ImplementationBodyCodegen extends ClassBodyCodegen { int typeinfoStatic = descriptor.getTypeConstructor().getParameters().size() > 0 ? 0 : Opcodes.ACC_STATIC; v.visitField(Opcodes.ACC_PRIVATE | typeinfoStatic, "$typeInfo", "Ljet/typeinfo/TypeInfo;", null, null); - if (myClass instanceof JetObjectDeclaration) { + if (isNonLiteralObject()) { Type type = JetTypeMapper.jetImplementationType(descriptor); 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() { boolean needTypeInfo = descriptor.getTypeConstructor().getParameters().size() == 0; - boolean needInstance = myClass instanceof JetObjectDeclaration; + boolean needInstance = isNonLiteralObject(); if (!needTypeInfo && !needInstance) { // we will have a dynamic type info field return; @@ -393,8 +393,9 @@ public class ImplementationBodyCodegen extends ClassBodyCodegen { InstructionAdapter v = new InstructionAdapter(mv); if (needTypeInfo) { - ClassCodegen.newTypeInfo(v, state.getTypeMapper().jvmType(descriptor, OwnerKind.INTERFACE)); - v.putstatic(JetTypeMapper.jvmNameForImplementation(descriptor), "$typeInfo", "Ljet/typeinfo/TypeInfo;"); + JetTypeMapper typeMapper = state.getTypeMapper(); + ClassCodegen.newTypeInfo(v, typeMapper.jvmType(descriptor, OwnerKind.INTERFACE)); + v.putstatic(typeMapper.jvmName(descriptor, kind), "$typeInfo", "Ljet/typeinfo/TypeInfo;"); } if (needInstance) { String name = jvmName(); @@ -410,6 +411,10 @@ public class ImplementationBodyCodegen extends ClassBodyCodegen { mv.visitEnd(); } + private boolean isNonLiteralObject() { + return myClass instanceof JetObjectDeclaration && !((JetObjectDeclaration) myClass).isObjectLiteral(); + } + private void generateGetTypeInfo() { final MethodVisitor mv = v.visitMethod(Opcodes.ACC_PUBLIC, "getTypeInfo", @@ -418,7 +423,7 @@ public class ImplementationBodyCodegen extends ClassBodyCodegen { null); mv.visitCode(); InstructionAdapter v = new InstructionAdapter(mv); - ExpressionCodegen.loadTypeInfo(descriptor, v); + ExpressionCodegen.loadTypeInfo(state.getTypeMapper(), descriptor, v); v.areturn(JetTypeMapper.TYPE_TYPEINFO); mv.visitMaxs(0, 0); mv.visitEnd(); diff --git a/idea/src/org/jetbrains/jet/codegen/JetTypeMapper.java b/idea/src/org/jetbrains/jet/codegen/JetTypeMapper.java index a245ce2c5a3..4105a7f266f 100644 --- a/idea/src/org/jetbrains/jet/codegen/JetTypeMapper.java +++ b/idea/src/org/jetbrains/jet/codegen/JetTypeMapper.java @@ -2,6 +2,7 @@ package org.jetbrains.jet.codegen; import com.intellij.psi.PsiClass; import com.intellij.psi.PsiElement; +import com.intellij.psi.util.PsiTreeUtil; import jet.typeinfo.TypeInfo; import org.jetbrains.annotations.NotNull; import org.jetbrains.jet.lang.descriptors.*; @@ -15,7 +16,9 @@ import org.objectweb.asm.Type; import org.objectweb.asm.commons.Method; import java.util.ArrayList; +import java.util.HashMap; import java.util.List; +import java.util.Map; /** * @author yole @@ -26,6 +29,8 @@ public class JetTypeMapper { private final JetStandardLibrary standardLibrary; private final BindingContext bindingContext; + private final Map classNamesForAnonymousClasses = new HashMap(); + private final Map anonymousSubclassesCount = new HashMap(); public JetTypeMapper(JetStandardLibrary standardLibrary, BindingContext bindingContext) { this.standardLibrary = standardLibrary; @@ -49,10 +54,25 @@ public class JetTypeMapper { if (declaration instanceof PsiClass) { 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); } - 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()) { return jvmNameForImplementation(jetClass); } @@ -209,11 +229,7 @@ public class JetTypeMapper { } if (descriptor instanceof ClassDescriptor) { - final PsiElement declaration = bindingContext.getDeclarationPsiElement(descriptor); - if (declaration instanceof PsiClass) { - return psiClassType((PsiClass) declaration); - } - return Type.getObjectType(jetJvmName((ClassDescriptor) descriptor, kind)); + return Type.getObjectType(jvmName((ClassDescriptor) descriptor, kind)); } throw new UnsupportedOperationException("Unknown type " + jetType); @@ -370,4 +386,31 @@ public class JetTypeMapper { } 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; + } } diff --git a/idea/src/org/jetbrains/jet/lang/psi/JetClassOrObject.java b/idea/src/org/jetbrains/jet/lang/psi/JetClassOrObject.java index e361058a19d..07f0160cff6 100644 --- a/idea/src/org/jetbrains/jet/lang/psi/JetClassOrObject.java +++ b/idea/src/org/jetbrains/jet/lang/psi/JetClassOrObject.java @@ -1,5 +1,6 @@ package org.jetbrains.jet.lang.psi; +import com.intellij.psi.PsiElement; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; @@ -8,7 +9,7 @@ import java.util.List; /** * @author max */ -public interface JetClassOrObject { +public interface JetClassOrObject extends PsiElement { List getDeclarations(); @Nullable diff --git a/idea/src/org/jetbrains/jet/lang/psi/JetObjectDeclaration.java b/idea/src/org/jetbrains/jet/lang/psi/JetObjectDeclaration.java index 71c7c17caba..8b4401af2a4 100644 --- a/idea/src/org/jetbrains/jet/lang/psi/JetObjectDeclaration.java +++ b/idea/src/org/jetbrains/jet/lang/psi/JetObjectDeclaration.java @@ -82,4 +82,8 @@ public class JetObjectDeclaration extends JetNamedDeclaration implements JetClas public void accept(JetVisitor visitor) { visitor.visitObjectDeclaration(this); } + + public boolean isObjectLiteral() { + return getNameAsDeclaration() == null; + } } diff --git a/idea/testData/codegen/objects/objectLiteral.jet b/idea/testData/codegen/objects/objectLiteral.jet new file mode 100644 index 00000000000..1ea5a0355bc --- /dev/null +++ b/idea/testData/codegen/objects/objectLiteral.jet @@ -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" +} diff --git a/idea/tests/org/jetbrains/jet/codegen/ObjectGenTest.java b/idea/tests/org/jetbrains/jet/codegen/ObjectGenTest.java index 16e69b485cb..db7bfa6ef7a 100644 --- a/idea/tests/org/jetbrains/jet/codegen/ObjectGenTest.java +++ b/idea/tests/org/jetbrains/jet/codegen/ObjectGenTest.java @@ -7,4 +7,8 @@ public class ObjectGenTest extends CodegenTestCase { public void testSimpleObject() throws Exception { blackBoxFile("objects/simpleObject.jet"); } + + public void testObjectLiteral() throws Exception { + blackBoxFile("objects/objectLiteral.jet"); + } }