initial basic implementation of object literals; move anonymous class name mapping to JetTypeMapper; cleanup many usages of JetTypeMapper
This commit is contained in:
@@ -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();
|
||||
|
||||
@@ -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<String, NamespaceCodegen> ns2codegen = new HashMap<String, NamespaceCodegen>();
|
||||
private final Map<String, ClassVisitor> generators = new LinkedHashMap<String, ClassVisitor>();
|
||||
private final Map<String, Integer> closuresCount = new HashMap<String, Integer>();
|
||||
private boolean isDone = false;
|
||||
public final GenerationState state;
|
||||
|
||||
@@ -42,14 +40,8 @@ public class ClassFileFactory {
|
||||
return visitor;
|
||||
}
|
||||
|
||||
Pair<String, ClassVisitor> 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<String, ClassVisitor>(className, newVisitor(className + ".class"));
|
||||
ClassVisitor forAnonymousSubclass(String className) {
|
||||
return newVisitor(className + ".class");
|
||||
}
|
||||
|
||||
NamespaceCodegen forNamespace(JetNamespace namespace) {
|
||||
|
||||
@@ -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<String, ClassVisitor> 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<String, ClassVisitor> 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());
|
||||
|
||||
@@ -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(), "<init>", descriptor.getConstructor().getDescriptor());
|
||||
}
|
||||
|
||||
private void generateBlock(List<JetElement> 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;
|
||||
|
||||
+2
-2
@@ -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<StackValue> args = new ArrayList<StackValue>();
|
||||
|
||||
public GeneratedClosureDescriptor(String classname, Method constructor) {
|
||||
public GeneratedAnonymousClassDescriptor(String classname, Method constructor) {
|
||||
this.classname = classname;
|
||||
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.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<String, ClassVisitor> forClosureIn(ClassDescriptor aClass) {
|
||||
return factory.forClosureIn(JetTypeMapper.jvmNameForInterface(aClass));
|
||||
}
|
||||
|
||||
public Pair<String, ClassVisitor> forClosureIn(JetNamespace namespace) {
|
||||
return factory.forClosureIn(NamespaceCodegen.getJVMClassName(namespace.getFQName()));
|
||||
public Pair<String, ClassVisitor> 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<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) {
|
||||
final ClosureCodegen top = closureContexts.peek();
|
||||
return top != null ? top.lookupInContext(d) : null;
|
||||
|
||||
@@ -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();
|
||||
|
||||
@@ -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<JetExpression, String> classNamesForAnonymousClasses = new HashMap<JetExpression, String>();
|
||||
private final Map<String, Integer> anonymousSubclassesCount = new HashMap<String, Integer>();
|
||||
|
||||
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;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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<JetDeclaration> getDeclarations();
|
||||
|
||||
@Nullable
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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 {
|
||||
blackBoxFile("objects/simpleObject.jet");
|
||||
}
|
||||
|
||||
public void testObjectLiteral() throws Exception {
|
||||
blackBoxFile("objects/objectLiteral.jet");
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user