diff --git a/.idea/inspectionProfiles/idea_default.xml b/.idea/inspectionProfiles/idea_default.xml
new file mode 100644
index 00000000000..1dfe9e84ad8
--- /dev/null
+++ b/.idea/inspectionProfiles/idea_default.xml
@@ -0,0 +1,418 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/.idea/inspectionProfiles/profiles_settings.xml b/.idea/inspectionProfiles/profiles_settings.xml
new file mode 100644
index 00000000000..78f1346b901
--- /dev/null
+++ b/.idea/inspectionProfiles/profiles_settings.xml
@@ -0,0 +1,7 @@
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/.idea/scopes/scope_settings.xml b/.idea/scopes/scope_settings.xml
new file mode 100644
index 00000000000..922003b8433
--- /dev/null
+++ b/.idea/scopes/scope_settings.xml
@@ -0,0 +1,5 @@
+
+
+
+
+
\ No newline at end of file
diff --git a/idea/src/org/jetbrains/jet/codegen/ClosureCodegen.java b/idea/src/org/jetbrains/jet/codegen/ClosureCodegen.java
index 1fd2018aebc..cf3055f7505 100644
--- a/idea/src/org/jetbrains/jet/codegen/ClosureCodegen.java
+++ b/idea/src/org/jetbrains/jet/codegen/ClosureCodegen.java
@@ -3,11 +3,12 @@
*/
package org.jetbrains.jet.codegen;
-import com.intellij.openapi.project.Project;
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;
+import org.jetbrains.jet.lang.descriptors.VariableDescriptor;
import org.jetbrains.jet.lang.psi.*;
import org.jetbrains.jet.lang.types.JetType;
import org.objectweb.asm.ClassVisitor;
@@ -19,13 +20,21 @@ import org.objectweb.asm.commons.Method;
import org.objectweb.asm.signature.SignatureWriter;
import java.util.Arrays;
+import java.util.LinkedHashMap;
import java.util.List;
+import java.util.Map;
public class ClosureCodegen {
private final GenerationState state;
+ private final ExpressionCodegen context;
+ private ClassVisitor cv = null;
+ private String name = null;
- public ClosureCodegen(GenerationState state) {
+ private Map closure = new LinkedHashMap();
+
+ public ClosureCodegen(GenerationState state, ExpressionCodegen context) {
this.state = state;
+ this.context = context;
}
public static Method erasedInvokeSignature(FunctionDescriptor fd) {
@@ -44,6 +53,31 @@ public class ClosureCodegen {
return state.getTypeMapper().mapSignature("invoke", fd);
}
+ public StackValue lookupInContext(DeclarationDescriptor d) {
+ if (d instanceof VariableDescriptor) {
+ VariableDescriptor vd = (VariableDescriptor) d;
+
+ EnclosedValueDescriptor answer = closure.get(vd);
+ if (answer != null) return answer.getInnerValue();
+
+ final int idx = context.lookupLocal(vd);
+ if (idx < 0) return null;
+
+ final Type type = state.getTypeMapper().mapType(vd.getOutType());
+
+ StackValue outerValue = StackValue.local(idx, type);
+ final String fieldName = "$" + (closure.size() + 1);
+ StackValue innerValue = StackValue.field(type, name, fieldName, false);
+ cv.visitField(Opcodes.ACC_PUBLIC, fieldName, type.getDescriptor(), null, null);
+ answer = new EnclosedValueDescriptor(d, innerValue, outerValue);
+ closure.put(d, answer);
+
+ return innerValue;
+ }
+
+ return null;
+ }
+
public GeneratedClosureDescriptor gen(JetFunctionLiteralExpression fun) {
JetNamedDeclaration container = PsiTreeUtil.getParentOfType(fun, JetNamespace.class, JetClass.class, JetObjectDeclaration.class);
@@ -58,8 +92,8 @@ public class ClosureCodegen {
final FunctionDescriptor funDescriptor = (FunctionDescriptor) state.getBindingContext().getDeclarationDescriptor(fun);
- final ClassVisitor cv = nameAndVisitor.getSecond();
- final String name = nameAndVisitor.getFirst();
+ cv = nameAndVisitor.getSecond();
+ name = nameAndVisitor.getFirst();
SignatureWriter signatureWriter = new SignatureWriter();
@@ -79,19 +113,25 @@ public class ClosureCodegen {
null,
funClass,
new String[0]
- );
+ );
- final Method constructor = generateConstructor(cv, funClass);
generateBridge(name, funDescriptor, cv);
- generateBody(name, funDescriptor, cv, container.getProject(), fun.getFunctionLiteral().getBodyExpression().getStatements());
+ generateBody(funDescriptor, cv, fun.getFunctionLiteral().getBodyExpression().getStatements());
+
+ final Method constructor = generateConstructor(funClass);
cv.visitEnd();
- return new GeneratedClosureDescriptor(name, constructor);
+ final GeneratedClosureDescriptor answer = new GeneratedClosureDescriptor(name, constructor);
+ for (DeclarationDescriptor descriptor : closure.keySet()) {
+ final EnclosedValueDescriptor valueDescriptor = closure.get(descriptor);
+ answer.addArg(valueDescriptor.getOuterValue());
+ }
+ return answer;
}
- private void generateBody(String className, FunctionDescriptor funDescriptor, ClassVisitor cv, Project project, List body) {
+ private void generateBody(FunctionDescriptor funDescriptor, ClassVisitor cv, List body) {
FunctionCodegen fc = new FunctionCodegen(null, cv, state);
fc.generatedMethod(body, OwnerKind.IMPLEMENTATION, invokeSignature(funDescriptor), funDescriptor.getReceiverType(), funDescriptor.getUnsubstitutedValueParameters(), null);
}
@@ -131,8 +171,14 @@ public class ClosureCodegen {
mv.visitEnd();
}
- private Method generateConstructor(ClassVisitor cv, String funClass) {
- final Method constructor = new Method("", Type.VOID_TYPE, new Type[0]); // TODO:
+ private Method generateConstructor(String funClass) {
+ Type[] argTypes = new Type[closure.size()];
+ int i = 0;
+ for (DeclarationDescriptor descriptor : closure.keySet()) {
+ argTypes[i++] = state.getTypeMapper().mapType(((VariableDescriptor) descriptor).getOutType());
+ }
+
+ final Method constructor = new Method("", Type.VOID_TYPE, argTypes);
final MethodVisitor mv = cv.visitMethod(Opcodes.ACC_PUBLIC, "", constructor.getDescriptor(), null, new String[0]);
mv.visitCode();
InstructionAdapter iv = new InstructionAdapter(mv);
@@ -140,8 +186,14 @@ public class ClosureCodegen {
iv.load(0, Type.getObjectType(funClass));
iv.invokespecial(funClass, "", "()V");
- iv.visitInsn(Opcodes.RETURN);
+ for (int j = 0; j < argTypes.length; j++) {
+ Type type = argTypes[j];
+ StackValue.local(0, JetTypeMapper.TYPE_OBJECT).put(JetTypeMapper.TYPE_OBJECT, iv);
+ StackValue.local(j + 1, type).put(type, iv);
+ StackValue.field(type, name, "$" + (j + 1), false).store(iv);
+ }
+ iv.visitInsn(Opcodes.RETURN);
mv.visitMaxs(0, 0);
mv.visitEnd();
diff --git a/idea/src/org/jetbrains/jet/codegen/EnclosedValueDescriptor.java b/idea/src/org/jetbrains/jet/codegen/EnclosedValueDescriptor.java
new file mode 100644
index 00000000000..3782d859fc4
--- /dev/null
+++ b/idea/src/org/jetbrains/jet/codegen/EnclosedValueDescriptor.java
@@ -0,0 +1,30 @@
+/*
+ * @author max
+ */
+package org.jetbrains.jet.codegen;
+
+import org.jetbrains.jet.lang.descriptors.DeclarationDescriptor;
+
+public class EnclosedValueDescriptor {
+ private final DeclarationDescriptor descriptor;
+ private final StackValue innerValue;
+ private final StackValue outerValue;
+
+ public EnclosedValueDescriptor(DeclarationDescriptor descriptor, StackValue innerValue, StackValue outerValue) {
+ this.descriptor = descriptor;
+ this.innerValue = innerValue;
+ this.outerValue = outerValue;
+ }
+
+ public DeclarationDescriptor getDescriptor() {
+ return descriptor;
+ }
+
+ public StackValue getInnerValue() {
+ return innerValue;
+ }
+
+ public StackValue getOuterValue() {
+ return outerValue;
+ }
+}
diff --git a/idea/src/org/jetbrains/jet/codegen/ExpressionCodegen.java b/idea/src/org/jetbrains/jet/codegen/ExpressionCodegen.java
index 9e4a967a99e..9374ee0dfe2 100644
--- a/idea/src/org/jetbrains/jet/codegen/ExpressionCodegen.java
+++ b/idea/src/org/jetbrains/jet/codegen/ExpressionCodegen.java
@@ -289,7 +289,7 @@ public class ExpressionCodegen extends JetVisitor {
if (asmParamType.getSort() == Type.OBJECT && !"java.lang.Object".equals(asmParamType.getClassName())) {
v.checkcast(asmParamType);
}
- v.store(myMap.getIndex(parameterDescriptor), asmParamType);
+ v.store(lookupLocal(parameterDescriptor), asmParamType);
gen(expression.getBody(), Type.VOID_TYPE);
@@ -384,7 +384,7 @@ public class ExpressionCodegen extends JetVisitor {
v.load(myIndexVar, Type.INT_TYPE);
v.aload(loopRangeType.getElementType());
StackValue.onStack(loopRangeType.getElementType()).put(asmParamType, v);
- v.store(myMap.getIndex(parameterDescriptor), asmParamType);
+ v.store(lookupLocal(parameterDescriptor), asmParamType);
}
protected void generateIncrement() {
@@ -414,21 +414,21 @@ public class ExpressionCodegen extends JetVisitor {
v.store(myRangeVar, loopRangeType);
v.invokevirtual("jet/IntRange", "getStartValue", "()I");
- v.store(myMap.getIndex(parameterDescriptor), Type.INT_TYPE);
+ v.store(lookupLocal(parameterDescriptor), Type.INT_TYPE);
v.invokevirtual("jet/IntRange", "getEndValue", "()I");
v.store(myEndVar, Type.INT_TYPE);
}
@Override
protected void generateCondition(Type asmParamType, Label end) {
- v.load(myMap.getIndex(parameterDescriptor), Type.INT_TYPE);
+ v.load(lookupLocal(parameterDescriptor), Type.INT_TYPE);
v.load(myEndVar, Type.INT_TYPE);
v.ificmpgt(end);
}
@Override
protected void generateIncrement() {
- v.iinc(myMap.getIndex(parameterDescriptor), 1); // TODO support decreasing order
+ v.iinc(lookupLocal(parameterDescriptor), 1); // TODO support decreasing order
}
@Override
@@ -482,10 +482,19 @@ public class ExpressionCodegen extends JetVisitor {
generateBlock(expression.getFunctionLiteral().getBodyExpression().getStatements());
}
else {
- final GeneratedClosureDescriptor closure = new ClosureCodegen(state).gen(expression);
+ final GeneratedClosureDescriptor closure = state.generateClosure(expression, this);
+
v.anew(Type.getObjectType(closure.getClassname()));
v.dup();
- v.invokespecial(closure.getClassname(), "", closure.getConstructor().getDescriptor());
+
+ final Method cons = closure.getConstructor();
+
+ for (int i = 0; i < closure.getArgs().size(); i++) {
+ StackValue arg = closure.getArgs().get(i);
+ arg.put(cons.getArgumentTypes()[i], v);
+ }
+
+ v.invokespecial(closure.getClassname(), "", cons.getDescriptor());
}
}
@@ -548,6 +557,7 @@ public class ExpressionCodegen extends JetVisitor {
@Override
public void visitSimpleNameExpression(JetSimpleNameExpression expression) {
DeclarationDescriptor descriptor = bindingContext.resolveReferenceExpression(expression);
+ if (descriptor instanceof NamespaceDescriptor) return; // No code to generate
if (descriptor instanceof VariableAsFunctionDescriptor) {
descriptor = ((VariableAsFunctionDescriptor) descriptor).getVariableDescriptor();
@@ -577,7 +587,7 @@ public class ExpressionCodegen extends JetVisitor {
myStack.push(StackValue.field(fieldType, owner, psiField.getName(), isStatic));
}
else {
- int index = myMap.getIndex(descriptor);
+ int index = lookupLocal(descriptor);
if (index >= 0) {
final JetType outType = ((VariableDescriptor) descriptor).getOutType();
myStack.push(StackValue.local(index, typeMapper.mapType(outType)));
@@ -594,7 +604,7 @@ public class ExpressionCodegen extends JetVisitor {
for (ValueParameterDescriptor parameter : parameters) {
if (parameter.getName().equals(descriptor.getName())) {
final JetType outType = ((VariableDescriptor) descriptor).getOutType();
- myStack.push(StackValue.local(myMap.getIndex(parameter), typeMapper.mapType(outType)));
+ myStack.push(StackValue.local(lookupLocal(parameter), typeMapper.mapType(outType)));
return;
}
}
@@ -626,12 +636,22 @@ public class ExpressionCodegen extends JetVisitor {
myStack.push(iValue);
}
}
- else if (!(descriptor instanceof NamespaceDescriptor)) {
- throw new UnsupportedOperationException("don't know how to generate reference " + descriptor);
+ else {
+ final StackValue value = state.lookupInContext(descriptor);
+ 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);
}
}
}
+ public int lookupLocal(DeclarationDescriptor descriptor) {
+ return myMap.getIndex(descriptor);
+ }
+
public StackValue intermediateValueForProperty(PropertyDescriptor propertyDescriptor, final boolean forceField, boolean forceInterface) {
DeclarationDescriptor containingDeclaration = propertyDescriptor.getContainingDeclaration();
boolean isStatic = containingDeclaration instanceof NamespaceDescriptorImpl;
@@ -890,7 +910,7 @@ public class ExpressionCodegen extends JetVisitor {
private int indexOfLocal(JetReferenceExpression lhs) {
final DeclarationDescriptor declarationDescriptor = bindingContext.resolveReferenceExpression(lhs);
- return myMap.getIndex(declarationDescriptor);
+ return lookupLocal(declarationDescriptor);
}
private static Type psiTypeToAsm(PsiType type) {
@@ -1369,7 +1389,7 @@ public class ExpressionCodegen extends JetVisitor {
@Override
public void visitProperty(JetProperty property) {
VariableDescriptor variableDescriptor = bindingContext.getVariableDescriptor(property);
- int index = myMap.getIndex(variableDescriptor);
+ int index = lookupLocal(variableDescriptor);
assert index >= 0;
@@ -1538,7 +1558,7 @@ public class ExpressionCodegen extends JetVisitor {
VariableDescriptor descriptor = bindingContext.getVariableDescriptor(clause.getCatchParameter());
Type descriptorType = typeMapper.mapType(descriptor.getOutType());
myMap.enter(descriptor, 1);
- int index = myMap.getIndex(descriptor);
+ int index = lookupLocal(descriptor);
v.store(index, descriptorType);
gen(clause.getCatchBody(), Type.VOID_TYPE);
diff --git a/idea/src/org/jetbrains/jet/codegen/GeneratedClosureDescriptor.java b/idea/src/org/jetbrains/jet/codegen/GeneratedClosureDescriptor.java
index d37bc3c3c56..0aaba59a48b 100644
--- a/idea/src/org/jetbrains/jet/codegen/GeneratedClosureDescriptor.java
+++ b/idea/src/org/jetbrains/jet/codegen/GeneratedClosureDescriptor.java
@@ -5,9 +5,13 @@ package org.jetbrains.jet.codegen;
import org.objectweb.asm.commons.Method;
+import java.util.ArrayList;
+import java.util.List;
+
public class GeneratedClosureDescriptor {
private final String classname;
private Method constructor;
+ private List args = new ArrayList();
public GeneratedClosureDescriptor(String classname, Method constructor) {
this.classname = classname;
@@ -21,4 +25,12 @@ public class GeneratedClosureDescriptor {
public Method getConstructor() {
return constructor;
}
+
+ public void addArg(StackValue local) {
+ args.add(local);
+ }
+
+ public List getArgs() {
+ return args;
+ }
}
diff --git a/idea/src/org/jetbrains/jet/codegen/GenerationState.java b/idea/src/org/jetbrains/jet/codegen/GenerationState.java
index a668d2c6473..e7723c90abf 100644
--- a/idea/src/org/jetbrains/jet/codegen/GenerationState.java
+++ b/idea/src/org/jetbrains/jet/codegen/GenerationState.java
@@ -9,7 +9,9 @@ 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.JetFile;
+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.BindingContext;
@@ -21,12 +23,12 @@ public class GenerationState {
private final Project project;
private JetTypeMapper typeMapper;
- private final Stack bindingContexts;
+ private final Stack bindingContexts = new Stack();
+ private final Stack closureContexts = new Stack();
private final JetStandardLibrary standardLibrary;
public GenerationState(Project project, boolean text) {
this.project = project;
- this.bindingContexts = new Stack();
this.standardLibrary = JetStandardLibrary.getJetStandardLibrary(project);
this.factory = new ClassFileFactory(project, text, this);
}
@@ -94,4 +96,21 @@ public class GenerationState {
typeMapper = null;
}
}
+
+ public GeneratedClosureDescriptor 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;
+ }
+ }
+
+ public StackValue lookupInContext(DeclarationDescriptor d) {
+ final ClosureCodegen top = closureContexts.peek();
+ return top != null ? top.lookupInContext(d) : null;
+ }
}
diff --git a/idea/testData/codegen/classes/enclosingLocalVariable.jet b/idea/testData/codegen/classes/enclosingLocalVariable.jet
index 57ce1d33833..7f48c3828d6 100644
--- a/idea/testData/codegen/classes/enclosingLocalVariable.jet
+++ b/idea/testData/codegen/classes/enclosingLocalVariable.jet
@@ -1,6 +1,6 @@
fun box() : String {
val cl = 39
- return if (sum(200, { cl }) == 2) "OK" else "FAIL"
+ return if (sum(200, { cl }) == 239) "OK" else "FAIL"
}
fun sum(arg:Int, f : {() : Int}) : Int {