Finally, green tests

This commit is contained in:
Maxim Shafirov
2011-07-08 14:34:48 +04:00
parent 704f153a31
commit 9e28fe70c1
4 changed files with 67 additions and 45 deletions
@@ -9,20 +9,23 @@ import org.jetbrains.jet.lang.descriptors.FunctionDescriptor;
import org.jetbrains.jet.lang.descriptors.NamespaceDescriptor;
import org.jetbrains.jet.lang.types.JetType;
import org.objectweb.asm.Type;
import org.objectweb.asm.commons.InstructionAdapter;
public class ClassContext {
public static final ClassContext STATIC = new ClassContext(null, OwnerKind.NAMESPACE, null, null);
public static final ClassContext STATIC = new ClassContext(null, OwnerKind.NAMESPACE, null, null, null);
private final DeclarationDescriptor contextType;
private final OwnerKind contextKind;
private final StackValue thisExpression;
private final ClassContext parentContext;
private final ClosureCodegen closure;
private boolean thisWasUsed = false;
public ClassContext(DeclarationDescriptor contextType, OwnerKind contextKind, StackValue thisExpression, ClassContext parentContext) {
public ClassContext(DeclarationDescriptor contextType, OwnerKind contextKind, StackValue thisExpression, ClassContext parentContext, ClosureCodegen closureCodegen) {
this.contextType = contextType;
this.contextKind = contextKind;
this.thisExpression = thisExpression;
this.parentContext = parentContext;
closure = closureCodegen;
}
public DeclarationDescriptor getContextDescriptor() {
@@ -34,13 +37,15 @@ public class ClassContext {
}
public StackValue getThisExpression() {
if (parentContext == null) return null;
thisWasUsed = true;
if (thisExpression != null) return thisExpression;
return parentContext != null ? parentContext.getThisExpression() : null;
return parentContext.getThisExpression();
}
public ClassContext intoNamespace(NamespaceDescriptor descriptor) {
return new ClassContext(descriptor, OwnerKind.NAMESPACE, null, this);
return new ClassContext(descriptor, OwnerKind.NAMESPACE, null, this, null);
}
public ClassContext intoClass(ClassDescriptor descriptor, OwnerKind kind) {
@@ -54,7 +59,7 @@ public class ClassContext {
thisValue = StackValue.local(0, JetTypeMapper.TYPE_OBJECT);
}
return new ClassContext(descriptor, kind, thisValue, this);
return new ClassContext(descriptor, kind, thisValue, this, null);
}
public ClassContext intoFunction(FunctionDescriptor descriptor) {
@@ -68,15 +73,15 @@ public class ClassContext {
thisIdx++;
}
return new ClassContext(descriptor, getContextKind(), hasReceiver ? StackValue.local(thisIdx, JetTypeMapper.TYPE_OBJECT) : null, this);
return new ClassContext(descriptor, getContextKind(), hasReceiver ? StackValue.local(thisIdx, JetTypeMapper.TYPE_OBJECT) : null, this, null);
}
public ClassContext intoClosure(String internalClassName) {
final DeclarationDescriptor contextDescriptor = getContextClass();
StackValue outerClass = contextDescriptor instanceof ClassDescriptor
? StackValue.instanceField(JetTypeMapper.jetInterfaceType((ClassDescriptor) contextDescriptor), internalClassName, "this$0")
public ClassContext intoClosure(String internalClassName, ClosureCodegen closureCodegen) {
final Type type = enclosingClassType(closureCodegen.state.getTypeMapper());
StackValue outerClass = type != null
? StackValue.instanceField(type, internalClassName, "this$0")
: StackValue.local(0, JetTypeMapper.TYPE_OBJECT);
return new ClassContext(null, OwnerKind.IMPLEMENTATION, outerClass, this);
return new ClassContext(null, OwnerKind.IMPLEMENTATION, outerClass, this, closureCodegen);
}
public FrameMap prepareFrame() {
@@ -109,6 +114,9 @@ public class ClassContext {
if (contextType instanceof ClassDescriptor) {
return mapper.jvmType((ClassDescriptor) contextType, contextKind);
}
else if (closure != null) {
return Type.getObjectType(closure.name);
}
else {
return parentContext != null ? parentContext.jvmType(mapper) : JetTypeMapper.TYPE_OBJECT;
}
@@ -125,4 +133,35 @@ public class ClassContext {
public boolean isThisWasUsed() {
return thisWasUsed;
}
public StackValue lookupInContext(DeclarationDescriptor d, InstructionAdapter v) {
final ClosureCodegen top = closure;
if (top != null) {
final StackValue answer = top.lookupInContext(d);
if (answer != null) return answer;
final StackValue thisContext = getThisExpression();
thisContext.put(thisContext.type, v);
}
return parentContext != null ? parentContext.lookupInContext(d, v) : null;
}
public Type enclosingClassType(JetTypeMapper mapper) {
DeclarationDescriptor descriptor = getContextDescriptor();
if (descriptor instanceof ClassDescriptor) {
return Type.getObjectType(mapper.jvmName((ClassDescriptor) descriptor, OwnerKind.INTERFACE));
}
if (descriptor instanceof NamespaceDescriptor) {
return null;
}
if (closure != null) {
return Type.getObjectType(closure.name);
}
final ClassContext parent = getParentContext();
return parent != null ? parent.enclosingClassType(mapper) : null;
}
}
@@ -4,7 +4,10 @@
package org.jetbrains.jet.codegen;
import com.intellij.openapi.util.Pair;
import org.jetbrains.jet.lang.descriptors.*;
import org.jetbrains.jet.lang.descriptors.DeclarationDescriptor;
import org.jetbrains.jet.lang.descriptors.FunctionDescriptor;
import org.jetbrains.jet.lang.descriptors.ValueParameterDescriptor;
import org.jetbrains.jet.lang.descriptors.VariableDescriptor;
import org.jetbrains.jet.lang.psi.JetFunctionLiteral;
import org.jetbrains.jet.lang.psi.JetFunctionLiteralExpression;
import org.jetbrains.jet.lang.types.JetType;
@@ -22,11 +25,11 @@ import java.util.List;
import java.util.Map;
public class ClosureCodegen {
private final GenerationState state;
public final GenerationState state;
private final ExpressionCodegen exprContext;
private final ClassContext context;
private ClassVisitor cv = null;
private String name = null;
public String name = null;
private Map<DeclarationDescriptor, EnclosedValueDescriptor> closure = new LinkedHashMap<DeclarationDescriptor, EnclosedValueDescriptor>();
@@ -107,12 +110,14 @@ public class ClosureCodegen {
generateBridge(name, funDescriptor, cv);
final boolean captureThis = generateBody(funDescriptor, cv, fun.getFunctionLiteral());
boolean captureThis = generateBody(funDescriptor, cv, fun.getFunctionLiteral());
final Type enclosingType = context.enclosingClassType(state.getTypeMapper());
if (enclosingType == null) captureThis = false;
final Method constructor = generateConstructor(funClass, captureThis);
if (captureThis) {
cv.visitField(Opcodes.ACC_PRIVATE, "this$0", enclosingClassType().getDescriptor(), null, null);
cv.visitField(Opcodes.ACC_PRIVATE, "this$0", enclosingType.getDescriptor(), null, null);
}
cv.visitEnd();
@@ -125,12 +130,8 @@ public class ClosureCodegen {
return answer;
}
private Type enclosingClassType() {
return Type.getObjectType(state.getTypeMapper().jvmName((ClassDescriptor) context.getContextClass(), OwnerKind.INTERFACE));
}
private boolean generateBody(FunctionDescriptor funDescriptor, ClassVisitor cv, JetFunctionLiteral body) {
final ClassContext closureContext = context.intoClosure(name);
final ClassContext closureContext = context.intoClosure(name, this);
FunctionCodegen fc = new FunctionCodegen(closureContext, cv, state);
fc.generateMethod(body, invokeSignature(funDescriptor), funDescriptor);
return closureContext.isThisWasUsed();
@@ -184,7 +185,7 @@ public class ClosureCodegen {
int i = 0;
if (captureThis) {
i = 1;
argTypes[0] = enclosingClassType();
argTypes[0] = context.enclosingClassType(state.getTypeMapper());
}
for (DeclarationDescriptor descriptor : closure.keySet()) {
@@ -501,7 +501,7 @@ public class ExpressionCodegen extends JetVisitor {
generateBlock(expression.getFunctionLiteral().getBodyExpression().getStatements());
}
else {
final GeneratedAnonymousClassDescriptor closure = state.generateClosure(expression, this, context);
final GeneratedAnonymousClassDescriptor closure = new ClosureCodegen(state, this, context).gen(expression);
v.anew(Type.getObjectType(closure.getClassname()));
v.dup();
@@ -668,12 +668,13 @@ public class ExpressionCodegen extends JetVisitor {
}
}
else {
final StackValue value = state.lookupInContext(descriptor);
// receiver
StackValue.local(0, JetTypeMapper.TYPE_OBJECT).put(JetTypeMapper.TYPE_OBJECT, v);
final StackValue value = context.lookupInContext(descriptor, v);
if (value == null) {
throw new UnsupportedOperationException("don't know how to generate reference " + descriptor);
}
// receiver
StackValue.local(0, JetTypeMapper.TYPE_OBJECT).put(JetTypeMapper.TYPE_OBJECT, v);
myStack.push(value);
}
}
@@ -9,7 +9,6 @@ import com.intellij.util.containers.Stack;
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.*;
import org.jetbrains.jet.lang.resolve.AnalyzingUtils;
import org.jetbrains.jet.lang.resolve.BindingContext;
@@ -23,7 +22,6 @@ public class GenerationState {
private JetTypeMapper typeMapper;
private final Stack<BindingContext> bindingContexts = new Stack<BindingContext>();
private final Stack<ClosureCodegen> closureContexts = new Stack<ClosureCodegen>();
private final JetStandardLibrary standardLibrary;
public GenerationState(Project project, boolean text) {
@@ -94,18 +92,6 @@ public class GenerationState {
}
}
public GeneratedAnonymousClassDescriptor generateClosure(JetFunctionLiteralExpression literal, ExpressionCodegen context, ClassContext classContext) {
final ClosureCodegen codegen = new ClosureCodegen(this, context, classContext);
closureContexts.push(codegen);
try {
return codegen.gen(literal);
}
finally {
final ClosureCodegen popped = closureContexts.pop();
assert popped == codegen;
}
}
public GeneratedAnonymousClassDescriptor generateObjectLiteral(JetObjectLiteralExpression literal, ExpressionCodegen context, ClassContext classContext) {
Pair<String, ClassVisitor> nameAndVisitor = forAnonymousSubclass(literal.getObjectDeclaration());
@@ -115,11 +101,6 @@ public class GenerationState {
return new GeneratedAnonymousClassDescriptor(nameAndVisitor.first, new Method("<init>", "()V"), false);
}
public StackValue lookupInContext(DeclarationDescriptor d) {
final ClosureCodegen top = closureContexts.peek();
return top != null ? top.lookupInContext(d) : null;
}
void prepareAnonymousClasses(JetElement aClass) {
aClass.acceptChildren(new JetVisitor() {
@Override