From 99d19a2f27b0273e0472e3e41cf4302a7f904fb6 Mon Sep 17 00:00:00 2001 From: Alex Tkachman Date: Wed, 2 Nov 2011 11:41:23 +0100 Subject: [PATCH 01/15] KT-33 --- .../jet/codegen/ExpressionCodegen.java | 30 ++++++++++--------- .../testData/codegen/regressions/kt33.jet | 6 ++++ .../jetbrains/jet/codegen/ArrayGenTest.java | 11 +++++++ 3 files changed, 33 insertions(+), 14 deletions(-) create mode 100644 compiler/testData/codegen/regressions/kt33.jet diff --git a/compiler/backend/src/org/jetbrains/jet/codegen/ExpressionCodegen.java b/compiler/backend/src/org/jetbrains/jet/codegen/ExpressionCodegen.java index 559b651abcd..13b47845a66 100644 --- a/compiler/backend/src/org/jetbrains/jet/codegen/ExpressionCodegen.java +++ b/compiler/backend/src/org/jetbrains/jet/codegen/ExpressionCodegen.java @@ -1970,23 +1970,25 @@ public class ExpressionCodegen extends JetVisitor { } } else { - final PsiElement declaration = BindingContextUtils.resolveToDeclarationPsiElement(bindingContext, expression); - assert declaration != null : "No declaration found for " + expression.getText(); - final CallableMethod accessor; - if (declaration instanceof PsiMethod) { - accessor = typeMapper.mapToCallableMethod((PsiMethod) declaration); - } - else if (declaration instanceof JetNamedFunction) { - accessor = typeMapper.mapToCallableMethod((JetNamedFunction) declaration, null); + DeclarationDescriptor operationDescriptor = bindingContext.get(BindingContext.REFERENCE_TARGET, expression); + CallableMethod accessor = typeMapper.mapToCallableMethod((FunctionDescriptor) operationDescriptor, OwnerKind.IMPLEMENTATION); + + boolean isGetter = accessor.getSignature().getName().equals("get"); + + if(isGetter) { + FunctionDescriptor setterDescriptor = bindingContext.get(BindingContext.INDEXED_LVALUE_SET, expression); + return StackValue.collectionElement( + accessor.getSignature().getReturnType(), + accessor, + setterDescriptor != null ? typeMapper.mapToCallableMethod(setterDescriptor, OwnerKind.IMPLEMENTATION) : null); } else { - throw new UnsupportedOperationException("unknown accessor type: " + declaration); + FunctionDescriptor getterDescriptor = bindingContext.get(BindingContext.INDEXED_LVALUE_GET, expression); + return StackValue.collectionElement( + accessor.getSignature().getArgumentTypes()[1], + getterDescriptor != null ? typeMapper.mapToCallableMethod(getterDescriptor, OwnerKind.IMPLEMENTATION) : null, + accessor); } - boolean isGetter = accessor.getSignature().getName().equals("get"); - return StackValue.collectionElement( - isGetter ? accessor.getSignature().getReturnType() : accessor.getSignature().getArgumentTypes()[1], - isGetter ? accessor : null, - isGetter ? null : accessor); } } diff --git a/compiler/testData/codegen/regressions/kt33.jet b/compiler/testData/codegen/regressions/kt33.jet new file mode 100644 index 00000000000..59cf1415c72 --- /dev/null +++ b/compiler/testData/codegen/regressions/kt33.jet @@ -0,0 +1,6 @@ +fun box () : String { + val s = java.util.ArrayList() + s.add("foo") + s[0] += "bar" + return if(s[0] == "foobar") "OK" else "fail" +} \ No newline at end of file diff --git a/compiler/tests/org/jetbrains/jet/codegen/ArrayGenTest.java b/compiler/tests/org/jetbrains/jet/codegen/ArrayGenTest.java index 76d4f93928c..6628d1d6358 100644 --- a/compiler/tests/org/jetbrains/jet/codegen/ArrayGenTest.java +++ b/compiler/tests/org/jetbrains/jet/codegen/ArrayGenTest.java @@ -96,4 +96,15 @@ public class ArrayGenTest extends CodegenTestCase { Method foo = generateFunction(); foo.invoke(null); } + + public void testCollectionPlusAssign () throws Exception { + blackBoxFile("regressions/kt33.jet"); + } + + public void testArrayPlusAssign () throws Exception { + loadText("fun box() : Int { val s = IntArray(1); s [0] = 5; s[0] += 7; return s[0] }"); + System.out.println(generateToText()); + Method foo = generateFunction(); + assertTrue((Integer)foo.invoke(null) == 12); + } } From 20233da7cf785e3d2a267a69f08148241cd69be1 Mon Sep 17 00:00:00 2001 From: Maxim Shafirov Date: Wed, 2 Nov 2011 18:24:53 +0300 Subject: [PATCH 02/15] Wrap ASM class generation so we can attribute generated classes with PSI origins when building kotlin-as-seen-from-java model --- .../jet/codegen/ClassBodyCodegen.java | 22 +++---- .../jetbrains/jet/codegen/ClassBuilder.java | 59 +++++++++++++++++ .../jetbrains/jet/codegen/ClassCodegen.java | 3 +- .../jet/codegen/ClassFileFactory.java | 19 +++--- .../jetbrains/jet/codegen/ClosureCodegen.java | 49 +++++++------- .../jet/codegen/FunctionCodegen.java | 25 +++---- .../jet/codegen/FunctionOrClosureCodegen.java | 5 +- .../jet/codegen/GenerationState.java | 17 ++--- .../codegen/ImplementationBodyCodegen.java | 65 ++++++++++--------- .../jet/codegen/NamespaceCodegen.java | 36 +++++----- .../jet/codegen/PropertyCodegen.java | 28 ++++---- .../jet/codegen/TraitImplBodyCodegen.java | 17 ++--- 12 files changed, 206 insertions(+), 139 deletions(-) create mode 100644 compiler/backend/src/org/jetbrains/jet/codegen/ClassBuilder.java diff --git a/compiler/backend/src/org/jetbrains/jet/codegen/ClassBodyCodegen.java b/compiler/backend/src/org/jetbrains/jet/codegen/ClassBodyCodegen.java index 4ab6dfeb815..7a9ff954f9c 100644 --- a/compiler/backend/src/org/jetbrains/jet/codegen/ClassBodyCodegen.java +++ b/compiler/backend/src/org/jetbrains/jet/codegen/ClassBodyCodegen.java @@ -1,10 +1,10 @@ package org.jetbrains.jet.codegen; +import com.intellij.psi.PsiElement; import org.jetbrains.jet.lang.descriptors.ClassDescriptor; import org.jetbrains.jet.lang.descriptors.PropertyDescriptor; import org.jetbrains.jet.lang.psi.*; import org.jetbrains.jet.lang.resolve.BindingContext; -import org.objectweb.asm.ClassVisitor; import org.objectweb.asm.MethodVisitor; import org.objectweb.asm.Opcodes; import org.objectweb.asm.commons.InstructionAdapter; @@ -23,12 +23,12 @@ public abstract class ClassBodyCodegen { protected final JetClassOrObject myClass; protected final OwnerKind kind; protected final ClassDescriptor descriptor; - protected final ClassVisitor v; + protected final ClassBuilder v; protected final ClassContext context; protected final List staticInitializerChunks = new ArrayList(); - public ClassBodyCodegen(JetClassOrObject aClass, ClassContext context, ClassVisitor v, GenerationState state) { + public ClassBodyCodegen(JetClassOrObject aClass, ClassContext context, ClassBuilder v, GenerationState state) { this.state = state; descriptor = state.getBindingContext().get(BindingContext.CLASS, aClass); myClass = aClass; @@ -46,7 +46,7 @@ public abstract class ClassBodyCodegen { generateStaticInitializer(); - v.visitEnd(); + v.done(); } protected abstract void generateDeclaration(); @@ -62,7 +62,7 @@ public abstract class ClassBodyCodegen { generateDeclaration(propertyCodegen, declaration, functionCodegen); } - generatePrimaryConstructorProperties(propertyCodegen); + generatePrimaryConstructorProperties(propertyCodegen, myClass); } protected void generateDeclaration(PropertyCodegen propertyCodegen, JetDeclaration declaration, FunctionCodegen functionCodegen) { @@ -82,20 +82,20 @@ public abstract class ClassBodyCodegen { functionCodegen.gen(declaration); } - private void generatePrimaryConstructorProperties(PropertyCodegen propertyCodegen) { + private void generatePrimaryConstructorProperties(PropertyCodegen propertyCodegen, PsiElement origin) { OwnerKind kind = context.getContextKind(); for (JetParameter p : getPrimaryConstructorParameters()) { if (p.getValOrVarNode() != null) { PropertyDescriptor propertyDescriptor = state.getBindingContext().get(BindingContext.PRIMARY_CONSTRUCTOR_PARAMETER, p); if (propertyDescriptor != null) { - propertyCodegen.generateDefaultGetter(propertyDescriptor, Opcodes.ACC_PUBLIC); + propertyCodegen.generateDefaultGetter(propertyDescriptor, Opcodes.ACC_PUBLIC, p); if (propertyDescriptor.isVar()) { - propertyCodegen.generateDefaultSetter(propertyDescriptor, Opcodes.ACC_PUBLIC); + propertyCodegen.generateDefaultSetter(propertyDescriptor, Opcodes.ACC_PUBLIC, origin); } //noinspection ConstantConditions if (!(kind instanceof OwnerKind.DelegateKind) && state.getBindingContext().get(BindingContext.BACKING_FIELD_REQUIRED, propertyDescriptor)) { - v.visitField(Opcodes.ACC_PRIVATE, p.getName(), state.getTypeMapper().mapType(propertyDescriptor.getOutType()).getDescriptor(), null, null); + v.newField(p, Opcodes.ACC_PRIVATE, p.getName(), state.getTypeMapper().mapType(propertyDescriptor.getOutType()).getDescriptor(), null, null); } } } @@ -111,8 +111,8 @@ public abstract class ClassBodyCodegen { private void generateStaticInitializer() { if (staticInitializerChunks.size() > 0) { - final MethodVisitor mv = v.visitMethod(Opcodes.ACC_PUBLIC | Opcodes.ACC_STATIC, - "", "()V", null, null); + final MethodVisitor mv = v.newMethod(null, Opcodes.ACC_PUBLIC | Opcodes.ACC_STATIC, + "", "()V", null, null); mv.visitCode(); InstructionAdapter v = new InstructionAdapter(mv); diff --git a/compiler/backend/src/org/jetbrains/jet/codegen/ClassBuilder.java b/compiler/backend/src/org/jetbrains/jet/codegen/ClassBuilder.java new file mode 100644 index 00000000000..ad49c8c56ce --- /dev/null +++ b/compiler/backend/src/org/jetbrains/jet/codegen/ClassBuilder.java @@ -0,0 +1,59 @@ +/* + * @author max + */ +package org.jetbrains.jet.codegen; + +import com.intellij.psi.PsiElement; +import org.jetbrains.annotations.Nullable; +import org.objectweb.asm.AnnotationVisitor; +import org.objectweb.asm.ClassVisitor; +import org.objectweb.asm.FieldVisitor; +import org.objectweb.asm.MethodVisitor; + +public class ClassBuilder { + private final ClassVisitor v; + + public ClassBuilder(ClassVisitor v) { + this.v = v; + } + + public FieldVisitor newField(@Nullable PsiElement origin, + int access, + String name, + String desc, + String signature, + Object value) { + return v.visitField(access, name, desc, signature, value); + } + + public MethodVisitor newMethod(@Nullable PsiElement origin, + int access, + String name, + String desc, + @Nullable String signature, + @Nullable String[] exceptions) { + return v.visitMethod(access, name, desc, signature, exceptions); + } + + public AnnotationVisitor newAnnotation(PsiElement origin, + String desc, + boolean visible) { + return v.visitAnnotation(desc, visible); + } + + public void done() { + v.visitEnd(); + } + + public ClassVisitor getVisitor() { + return v; + } + + public void defineClass(int version, int access, String name, String signature, String superName, String[] interfaces) { + v.visit(version, access, name, signature, superName, interfaces); + } + + public void visitSource(String name, String debug) { + v.visitSource(name, debug); + } +} diff --git a/compiler/backend/src/org/jetbrains/jet/codegen/ClassCodegen.java b/compiler/backend/src/org/jetbrains/jet/codegen/ClassCodegen.java index 86ebc6554ad..434fa8cf5f2 100644 --- a/compiler/backend/src/org/jetbrains/jet/codegen/ClassCodegen.java +++ b/compiler/backend/src/org/jetbrains/jet/codegen/ClassCodegen.java @@ -3,7 +3,6 @@ package org.jetbrains.jet.codegen; import org.jetbrains.jet.lang.descriptors.ClassDescriptor; import org.jetbrains.jet.lang.psi.*; import org.jetbrains.jet.lang.resolve.BindingContext; -import org.objectweb.asm.ClassVisitor; /** * @author max @@ -33,7 +32,7 @@ public class ClassCodegen { private void generateImplementation(ClassContext parentContext, JetClassOrObject aClass, OwnerKind kind) { ClassDescriptor descriptor = state.getBindingContext().get(BindingContext.CLASS, aClass); - ClassVisitor v = state.forClassImplementation(descriptor); + ClassBuilder v = state.forClassImplementation(descriptor); new ImplementationBodyCodegen(aClass, parentContext.intoClass(null, descriptor, kind), v, state).generate(); if(aClass instanceof JetClass && ((JetClass)aClass).isTrait()) { diff --git a/compiler/backend/src/org/jetbrains/jet/codegen/ClassFileFactory.java b/compiler/backend/src/org/jetbrains/jet/codegen/ClassFileFactory.java index bc00c386c08..0fadb452d83 100644 --- a/compiler/backend/src/org/jetbrains/jet/codegen/ClassFileFactory.java +++ b/compiler/backend/src/org/jetbrains/jet/codegen/ClassFileFactory.java @@ -17,7 +17,7 @@ public class ClassFileFactory { private final Project project; private final boolean isText; private final Map ns2codegen = new HashMap(); - private final Map generators = new LinkedHashMap(); + private final Map generators = new LinkedHashMap(); private boolean isDone = false; public final GenerationState state; @@ -27,7 +27,7 @@ public class ClassFileFactory { this.state = state; } - ClassVisitor newVisitor(String filePath) { + ClassBuilder newVisitor(String filePath) { ClassVisitor visitor; if (isText) { visitor = new TraceClassVisitor(new PrintWriter(new StringWriter())); @@ -36,11 +36,12 @@ public class ClassFileFactory { visitor = new ClassWriter(ClassWriter.COMPUTE_FRAMES | ClassWriter.COMPUTE_MAXS); } - generators.put(filePath, visitor); - return visitor; + final ClassBuilder answer = new ClassBuilder(visitor); + generators.put(filePath, answer); + return answer; } - ClassVisitor forAnonymousSubclass(String className) { + ClassBuilder forAnonymousSubclass(String className) { return newVisitor(className + ".class"); } @@ -49,8 +50,8 @@ public class ClassFileFactory { String fqName = namespace.getFQName(); NamespaceCodegen codegen = ns2codegen.get(fqName); if (codegen == null) { - final ClassVisitor classVisitor = newVisitor(NamespaceCodegen.getJVMClassName(fqName) + ".class"); - codegen = new NamespaceCodegen(classVisitor, fqName, state, namespace.getContainingFile()); + final ClassBuilder builder = newVisitor(NamespaceCodegen.getJVMClassName(fqName) + ".class"); + codegen = new NamespaceCodegen(builder, fqName, state, namespace.getContainingFile()); ns2codegen.put(fqName, codegen); } @@ -71,7 +72,7 @@ public class ClassFileFactory { done(); - TraceClassVisitor visitor = (TraceClassVisitor) generators.get(file); + TraceClassVisitor visitor = (TraceClassVisitor) generators.get(file).getVisitor(); StringWriter writer = new StringWriter(); visitor.print(new PrintWriter(writer)); @@ -84,7 +85,7 @@ public class ClassFileFactory { done(); - ClassWriter visitor = (ClassWriter) generators.get(file); + ClassWriter visitor = (ClassWriter) generators.get(file).getVisitor(); return visitor.toByteArray(); } diff --git a/compiler/backend/src/org/jetbrains/jet/codegen/ClosureCodegen.java b/compiler/backend/src/org/jetbrains/jet/codegen/ClosureCodegen.java index 3aa68b5b5ed..fa277df481e 100644 --- a/compiler/backend/src/org/jetbrains/jet/codegen/ClosureCodegen.java +++ b/compiler/backend/src/org/jetbrains/jet/codegen/ClosureCodegen.java @@ -5,13 +5,18 @@ 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.resolve.BindingContext; import org.jetbrains.jet.lang.resolve.scopes.receivers.ReceiverDescriptor; import org.jetbrains.jet.lang.types.JetType; -import org.objectweb.asm.*; +import org.objectweb.asm.Label; +import org.objectweb.asm.MethodVisitor; +import org.objectweb.asm.Type; import org.objectweb.asm.commons.InstructionAdapter; import org.objectweb.asm.commons.Method; import org.objectweb.asm.signature.SignatureWriter; @@ -44,7 +49,7 @@ public class ClosureCodegen extends FunctionOrClosureCodegen { } public GeneratedAnonymousClassDescriptor gen(JetFunctionLiteralExpression fun) { - final Pair nameAndVisitor = state.forAnonymousSubclass(fun); + final Pair nameAndVisitor = state.forAnonymousSubclass(fun); final FunctionDescriptor funDescriptor = (FunctionDescriptor) state.getBindingContext().get(BindingContext.DECLARATION_TO_DESCRIPTOR, fun); @@ -63,32 +68,32 @@ public class ClosureCodegen extends FunctionOrClosureCodegen { appendType(signatureWriter, funDescriptor.getReturnType(), '='); signatureWriter.visitEnd(); - cv.visit(V1_6, - ACC_PUBLIC, - name, - null, - funClass, - new String[0] + cv.defineClass(V1_6, + ACC_PUBLIC, + name, + null, + funClass, + new String[0] ); cv.visitSource(fun.getContainingFile().getName(), null); - generateBridge(name, funDescriptor, cv); + generateBridge(name, funDescriptor, fun, cv); captureThis = generateBody(funDescriptor, cv, fun.getFunctionLiteral()); final Type enclosingType = context.enclosingClassType(state.getTypeMapper()); if (enclosingType == null) captureThis = false; - final Method constructor = generateConstructor(funClass, captureThis, funDescriptor.getReturnType()); + final Method constructor = generateConstructor(funClass, captureThis, fun, funDescriptor.getReturnType()); if (captureThis) { - cv.visitField(0, "this$0", enclosingType.getDescriptor(), null, null); + cv.newField(fun, 0, "this$0", enclosingType.getDescriptor(), null, null); } if(isConst()) { - generateConstInstance(); + generateConstInstance(fun); } - cv.visitEnd(); + cv.done(); final GeneratedAnonymousClassDescriptor answer = new GeneratedAnonymousClassDescriptor(name, constructor, captureThis); for (DeclarationDescriptor descriptor : closure.keySet()) { @@ -98,10 +103,10 @@ public class ClosureCodegen extends FunctionOrClosureCodegen { return answer; } - private void generateConstInstance() { - cv.visitField(ACC_PRIVATE| ACC_STATIC, "$instance", "Ljava/lang/ref/SoftReference;", null, null); + private void generateConstInstance(JetFunctionLiteralExpression fun) { + cv.newField(fun, ACC_PRIVATE | ACC_STATIC, "$instance", "Ljava/lang/ref/SoftReference;", null, null); - MethodVisitor mv = cv.visitMethod(ACC_PUBLIC | ACC_STATIC, "$getInstance", "()L" + name + ";", null, new String[0]); + MethodVisitor mv = cv.newMethod(fun, ACC_PUBLIC | ACC_STATIC, "$getInstance", "()L" + name + ";", null, new String[0]); mv.visitCode(); mv.visitFieldInsn(GETSTATIC, name, "$instance", "Ljava/lang/ref/SoftReference;"); mv.visitInsn(DUP); @@ -140,21 +145,21 @@ public class ClosureCodegen extends FunctionOrClosureCodegen { mv.visitEnd(); } - private boolean generateBody(FunctionDescriptor funDescriptor, ClassVisitor cv, JetFunctionLiteral body) { + private boolean generateBody(FunctionDescriptor funDescriptor, ClassBuilder cv, JetFunctionLiteral body) { final ClassContext closureContext = context.intoClosure(name, this); FunctionCodegen fc = new FunctionCodegen(closureContext, cv, state); fc.generateMethod(body, invokeSignature(funDescriptor), funDescriptor); return closureContext.isThisWasUsed(); } - private void generateBridge(String className, FunctionDescriptor funDescriptor, ClassVisitor cv) { + private void generateBridge(String className, FunctionDescriptor funDescriptor, JetFunctionLiteralExpression fun, ClassBuilder cv) { final Method bridge = erasedInvokeSignature(funDescriptor); final Method delegate = invokeSignature(funDescriptor); if(bridge.getDescriptor().equals(delegate.getDescriptor())) return; - final MethodVisitor mv = cv.visitMethod(ACC_PUBLIC, "invoke", bridge.getDescriptor(), state.getTypeMapper().genericSignature(funDescriptor), new String[0]); + final MethodVisitor mv = cv.newMethod(fun, ACC_PUBLIC, "invoke", bridge.getDescriptor(), state.getTypeMapper().genericSignature(funDescriptor), new String[0]); mv.visitCode(); InstructionAdapter iv = new InstructionAdapter(mv); @@ -185,7 +190,7 @@ public class ClosureCodegen extends FunctionOrClosureCodegen { mv.visitEnd(); } - private Method generateConstructor(String funClass, boolean captureThis, JetType returnType) { + private Method generateConstructor(String funClass, boolean captureThis, JetFunctionLiteralExpression fun, JetType returnType) { int argCount = closure.size(); if (captureThis) { @@ -208,7 +213,7 @@ public class ClosureCodegen extends FunctionOrClosureCodegen { } final Method constructor = new Method("", Type.VOID_TYPE, argTypes); - final MethodVisitor mv = cv.visitMethod(ACC_PUBLIC, "", constructor.getDescriptor(), null, new String[0]); + final MethodVisitor mv = cv.newMethod(fun, ACC_PUBLIC, "", constructor.getDescriptor(), null, new String[0]); mv.visitCode(); InstructionAdapter iv = new InstructionAdapter(mv); ExpressionCodegen expressionCodegen = new ExpressionCodegen(mv, null, Type.VOID_TYPE, context, state); diff --git a/compiler/backend/src/org/jetbrains/jet/codegen/FunctionCodegen.java b/compiler/backend/src/org/jetbrains/jet/codegen/FunctionCodegen.java index a7724378b36..cd05790af27 100644 --- a/compiler/backend/src/org/jetbrains/jet/codegen/FunctionCodegen.java +++ b/compiler/backend/src/org/jetbrains/jet/codegen/FunctionCodegen.java @@ -4,7 +4,10 @@ import com.intellij.psi.PsiElement; import org.jetbrains.jet.lang.descriptors.*; import org.jetbrains.jet.lang.psi.*; import org.jetbrains.jet.lang.resolve.BindingContext; -import org.objectweb.asm.*; +import org.objectweb.asm.AnnotationVisitor; +import org.objectweb.asm.Label; +import org.objectweb.asm.MethodVisitor; +import org.objectweb.asm.Type; import org.objectweb.asm.commons.InstructionAdapter; import org.objectweb.asm.commons.Method; @@ -20,10 +23,10 @@ import static org.objectweb.asm.Opcodes.*; */ public class FunctionCodegen { private final ClassContext owner; - private final ClassVisitor v; + private final ClassBuilder v; private final GenerationState state; - public FunctionCodegen(ClassContext owner, ClassVisitor v, GenerationState state) { + public FunctionCodegen(ClassContext owner, ClassBuilder v, GenerationState state) { this.owner = owner; this.v = v; this.state = state; @@ -39,13 +42,13 @@ public class FunctionCodegen { ClassContext funContext = owner.intoFunction(functionDescriptor); final JetExpression bodyExpression = f.getBodyExpression(); - generatedMethod(bodyExpression, jvmMethod, funContext, functionDescriptor); + generatedMethod(bodyExpression, jvmMethod, funContext, functionDescriptor, f); } private void generatedMethod(JetExpression bodyExpressions, Method jvmSignature, ClassContext context, - FunctionDescriptor functionDescriptor) + FunctionDescriptor functionDescriptor, JetDeclarationWithBody fun) { List paramDescrs = functionDescriptor.getValueParameters(); List typeParameters = functionDescriptor.getTypeParameters(); @@ -62,7 +65,7 @@ public class FunctionCodegen { boolean isAbstract = !isStatic && (bodyExpressions == null || CodegenUtil.isInterface(functionDescriptor.getContainingDeclaration())); if (isAbstract) flags |= ACC_ABSTRACT; - final MethodVisitor mv = v.visitMethod(flags, jvmSignature.getName(), jvmSignature.getDescriptor(), null, null); + final MethodVisitor mv = v.newMethod(fun, flags, jvmSignature.getName(), jvmSignature.getDescriptor(), null, null); if(kind != OwnerKind.TRAIT_IMPL) { int start = functionDescriptor.getReceiverParameter().exists() ? 1 : 0; for(int i = 0; i != paramDescrs.size(); ++i) { @@ -135,7 +138,7 @@ public class FunctionCodegen { generateDefaultIfNeeded(context, state, v, jvmSignature, functionDescriptor, kind); } - static void generateBridgeIfNeeded(ClassContext owner, GenerationState state, ClassVisitor v, Method jvmSignature, FunctionDescriptor functionDescriptor, OwnerKind kind) { + static void generateBridgeIfNeeded(ClassContext owner, GenerationState state, ClassBuilder v, Method jvmSignature, FunctionDescriptor functionDescriptor, OwnerKind kind) { Set overriddenFunctions = functionDescriptor.getOverriddenDescriptors(); if(kind != OwnerKind.TRAIT_IMPL) { for (FunctionDescriptor overriddenFunction : overriddenFunctions) { @@ -146,7 +149,7 @@ public class FunctionCodegen { } } - static void generateDefaultIfNeeded(ClassContext owner, GenerationState state, ClassVisitor v, Method jvmSignature, FunctionDescriptor functionDescriptor, OwnerKind kind) { + static void generateDefaultIfNeeded(ClassContext owner, GenerationState state, ClassBuilder v, Method jvmSignature, FunctionDescriptor functionDescriptor, OwnerKind kind) { DeclarationDescriptor contextClass = owner.getContextClass(); if(kind != OwnerKind.TRAIT_IMPL) { @@ -187,7 +190,7 @@ public class FunctionCodegen { String descriptor = jvmSignature.getDescriptor().replace(")","I)"); if(!isStatic) descriptor = descriptor.replace("(","(L" + ownerInternalName + ";"); - final MethodVisitor mv = v.visitMethod(flags| ACC_STATIC, jvmSignature.getName() + "$default", descriptor, null, null); + final MethodVisitor mv = v.newMethod(null, flags | ACC_STATIC, jvmSignature.getName() + "$default", descriptor, null, null); InstructionAdapter iv = new InstructionAdapter(mv); mv.visitCode(); @@ -287,14 +290,14 @@ public class FunctionCodegen { } } - private static void checkOverride(ClassContext owner, GenerationState state, ClassVisitor v, Method jvmSignature, FunctionDescriptor functionDescriptor, FunctionDescriptor overriddenFunction) { + private static void checkOverride(ClassContext owner, GenerationState state, ClassBuilder v, Method jvmSignature, FunctionDescriptor functionDescriptor, FunctionDescriptor overriddenFunction) { Type type1 = state.getTypeMapper().mapType(overriddenFunction.getOriginal().getReturnType()); Type type2 = state.getTypeMapper().mapType(functionDescriptor.getReturnType()); if(!type1.equals(type2)) { Method overriden = state.getTypeMapper().mapSignature(overriddenFunction.getName(), overriddenFunction.getOriginal()); int flags = ACC_PUBLIC; // TODO. - final MethodVisitor mv = v.visitMethod(flags, jvmSignature.getName(), overriden.getDescriptor(), null, null); + final MethodVisitor mv = v.newMethod(null, flags, jvmSignature.getName(), overriden.getDescriptor(), null, null); mv.visitCode(); Type[] argTypes = jvmSignature.getArgumentTypes(); diff --git a/compiler/backend/src/org/jetbrains/jet/codegen/FunctionOrClosureCodegen.java b/compiler/backend/src/org/jetbrains/jet/codegen/FunctionOrClosureCodegen.java index a9834ed153d..2a0bd3be23f 100644 --- a/compiler/backend/src/org/jetbrains/jet/codegen/FunctionOrClosureCodegen.java +++ b/compiler/backend/src/org/jetbrains/jet/codegen/FunctionOrClosureCodegen.java @@ -2,7 +2,6 @@ package org.jetbrains.jet.codegen; import org.jetbrains.jet.lang.descriptors.DeclarationDescriptor; import org.jetbrains.jet.lang.descriptors.VariableDescriptor; -import org.objectweb.asm.ClassVisitor; import org.objectweb.asm.Opcodes; import org.objectweb.asm.Type; @@ -18,7 +17,7 @@ public class FunctionOrClosureCodegen { public final GenerationState state; protected final ExpressionCodegen exprContext; protected final ClassContext context; - protected ClassVisitor cv = null; + protected ClassBuilder cv = null; public String name = null; protected Map closure = new LinkedHashMap(); @@ -46,7 +45,7 @@ public class FunctionOrClosureCodegen { final String fieldName = "$" + (closure.size() + 1); // + "$" + vd.getName(); StackValue innerValue = sharedVarType != null ? StackValue.fieldForSharedVar(localType, name, fieldName) : StackValue.field(type, name, fieldName, false); - cv.visitField(Opcodes.ACC_PUBLIC, fieldName, type.getDescriptor(), null, null); + cv.newField(null, Opcodes.ACC_PUBLIC, fieldName, type.getDescriptor(), null, null); answer = new EnclosedValueDescriptor(d, innerValue, outerValue); closure.put(d, answer); diff --git a/compiler/backend/src/org/jetbrains/jet/codegen/GenerationState.java b/compiler/backend/src/org/jetbrains/jet/codegen/GenerationState.java index 51713dc8fb4..8a4ec90771a 100644 --- a/compiler/backend/src/org/jetbrains/jet/codegen/GenerationState.java +++ b/compiler/backend/src/org/jetbrains/jet/codegen/GenerationState.java @@ -15,8 +15,6 @@ import org.jetbrains.jet.lang.resolve.AnalyzingUtils; import org.jetbrains.jet.lang.resolve.BindingContext; import org.jetbrains.jet.lang.resolve.java.JavaDefaultImports; import org.jetbrains.jet.lang.types.JetStandardLibrary; -import org.objectweb.asm.ClassVisitor; -import org.objectweb.asm.commons.Method; import java.util.Collections; import java.util.List; @@ -61,26 +59,21 @@ public class GenerationState { return intrinsics; } - public ClassVisitor forClassInterface(ClassDescriptor aClass) { - return factory.newVisitor(JetTypeMapper.jvmNameForInterface(aClass) + ".class"); - } - public ClassCodegen forClass() { return new ClassCodegen(this); } - public ClassVisitor forClassImplementation(ClassDescriptor aClass) { + public ClassBuilder forClassImplementation(ClassDescriptor aClass) { return factory.newVisitor(typeMapper.jvmName(aClass, OwnerKind.IMPLEMENTATION) + ".class"); } - public ClassVisitor forTraitImplementation(ClassDescriptor aClass) { + public ClassBuilder forTraitImplementation(ClassDescriptor aClass) { return factory.newVisitor(typeMapper.jvmName(aClass, OwnerKind.TRAIT_IMPL) + ".class"); } - public Pair forAnonymousSubclass(JetExpression expression) { + public Pair forAnonymousSubclass(JetExpression expression) { String className = typeMapper.classNameForAnonymousClass(expression); - ClassVisitor visitor = factory.forAnonymousSubclass(className); - return Pair.create(className, visitor); + return Pair.create(className, factory.forAnonymousSubclass(className)); } public NamespaceCodegen forNamespace(JetNamespace namespace) { @@ -123,7 +116,7 @@ public class GenerationState { public GeneratedAnonymousClassDescriptor generateObjectLiteral(JetObjectLiteralExpression literal, FunctionOrClosureCodegen closure) { JetObjectDeclaration objectDeclaration = literal.getObjectDeclaration(); - Pair nameAndVisitor = forAnonymousSubclass(objectDeclaration); + Pair nameAndVisitor = forAnonymousSubclass(objectDeclaration); closure.cv = nameAndVisitor.getSecond(); closure.name = nameAndVisitor.getFirst(); diff --git a/compiler/backend/src/org/jetbrains/jet/codegen/ImplementationBodyCodegen.java b/compiler/backend/src/org/jetbrains/jet/codegen/ImplementationBodyCodegen.java index 69df0081b91..6834d94c79c 100644 --- a/compiler/backend/src/org/jetbrains/jet/codegen/ImplementationBodyCodegen.java +++ b/compiler/backend/src/org/jetbrains/jet/codegen/ImplementationBodyCodegen.java @@ -11,7 +11,10 @@ import org.jetbrains.jet.lang.resolve.constants.CompileTimeConstant; import org.jetbrains.jet.lang.types.JetType; import org.jetbrains.jet.lang.types.TypeProjection; import org.jetbrains.jet.lexer.JetTokens; -import org.objectweb.asm.*; +import org.objectweb.asm.AnnotationVisitor; +import org.objectweb.asm.MethodVisitor; +import org.objectweb.asm.Opcodes; +import org.objectweb.asm.Type; import org.objectweb.asm.commons.InstructionAdapter; import org.objectweb.asm.commons.Method; @@ -26,7 +29,7 @@ public class ImplementationBodyCodegen extends ClassBodyCodegen { private JetDelegationSpecifier superCall; private String superClass = "java/lang/Object"; - public ImplementationBodyCodegen(JetClassOrObject aClass, ClassContext context, ClassVisitor v, GenerationState state) { + public ImplementationBodyCodegen(JetClassOrObject aClass, ClassContext context, ClassBuilder v, GenerationState state) { super(aClass, context, v, state); } @@ -89,21 +92,23 @@ public class ImplementationBodyCodegen extends ClassBodyCodegen { } } - v.visit(Opcodes.V1_6, - Opcodes.ACC_PUBLIC | (isAbstract ? Opcodes.ACC_ABSTRACT : 0) | (isInterface ? Opcodes.ACC_INTERFACE : 0), - jvmName(), - null, - superClass, - interfaces.toArray(new String[interfaces.size()]) + v.defineClass(Opcodes.V1_6, + Opcodes.ACC_PUBLIC | (isAbstract ? Opcodes.ACC_ABSTRACT : 0) | (isInterface + ? Opcodes.ACC_INTERFACE + : 0), + jvmName(), + null, + superClass, + interfaces.toArray(new String[interfaces.size()]) ); v.visitSource(myClass.getContainingFile().getName(), null); if(descriptor.getContainingDeclaration() instanceof ClassDescriptor) { - v.visitOuterClass(state.getTypeMapper().jvmType((ClassDescriptor) descriptor.getContainingDeclaration(), OwnerKind.IMPLEMENTATION).getInternalName(), null, null); + v.getVisitor().visitOuterClass(state.getTypeMapper().jvmType((ClassDescriptor) descriptor.getContainingDeclaration(), OwnerKind.IMPLEMENTATION).getInternalName(), null, null); } if(myClass instanceof JetClass) { - AnnotationVisitor annotationVisitor = v.visitAnnotation("Ljet/typeinfo/JetSignature;", true); + AnnotationVisitor annotationVisitor = v.newAnnotation(myClass, "Ljet/typeinfo/JetSignature;", true); annotationVisitor.visit("value", SignatureUtil.classToSignature((JetClass)myClass, state.getBindingContext(), state.getTypeMapper())); annotationVisitor.visitEnd(); } @@ -162,7 +167,7 @@ public class ImplementationBodyCodegen extends ClassBodyCodegen { private void generateFieldForObjectInstance() { if (isNonLiteralObject()) { Type type = JetTypeMapper.jetImplementationType(descriptor); - v.visitField(Opcodes.ACC_PUBLIC | Opcodes.ACC_STATIC, "$instance", type.getDescriptor(), null, null); + v.newField(myClass, Opcodes.ACC_PUBLIC | Opcodes.ACC_STATIC, "$instance", type.getDescriptor(), null, null); staticInitializerChunks.add(new CodeChunk() { @Override @@ -182,7 +187,7 @@ public class ImplementationBodyCodegen extends ClassBodyCodegen { final JetClassObject classObject = getClassObject(); if (classObject != null) { Type type = Type.getObjectType(state.getTypeMapper().jvmName(classObject)); - v.visitField(Opcodes.ACC_PUBLIC | Opcodes.ACC_STATIC, "$classobj", type.getDescriptor(), null, null); + v.newField(classObject, Opcodes.ACC_PUBLIC | Opcodes.ACC_STATIC, "$classobj", type.getDescriptor(), null, null); staticInitializerChunks.add(new CodeChunk() { @Override @@ -242,7 +247,7 @@ public class ImplementationBodyCodegen extends ClassBodyCodegen { } int flags = Opcodes.ACC_PUBLIC; // TODO - final MethodVisitor mv = v.visitMethod(flags, "", method.getDescriptor(), null, null); + final MethodVisitor mv = v.newMethod(myClass, flags, "", method.getDescriptor(), null, null); mv.visitCode(); List paramDescrs = constructorDescriptor != null @@ -312,7 +317,7 @@ public class ImplementationBodyCodegen extends ClassBodyCodegen { String delegateField = "$delegate_" + n; Type fieldType = JetTypeMapper.jetInterfaceType(superClassDescriptor); String fieldDesc = fieldType.getDescriptor(); - v.visitField(Opcodes.ACC_PRIVATE, delegateField, fieldDesc, /*TODO*/null, null); + v.newField(specifier, Opcodes.ACC_PRIVATE, delegateField, fieldDesc, /*TODO*/null, null); iv.putfield(classname, delegateField, fieldDesc); JetClass superClass = (JetClass) state.getBindingContext().get(BindingContext.DESCRIPTOR_TO_DECLARATION, superClassDescriptor); @@ -328,7 +333,7 @@ public class ImplementationBodyCodegen extends ClassBodyCodegen { final Type type = JetTypeMapper.jetImplementationType(outerDescriptor); String interfaceDesc = type.getDescriptor(); final String fieldName = "this$0"; - v.visitField(Opcodes.ACC_PRIVATE | Opcodes.ACC_FINAL, fieldName, interfaceDesc, null, null); + v.newField(myClass, Opcodes.ACC_PRIVATE | Opcodes.ACC_FINAL, fieldName, interfaceDesc, null, null); iv.load(0, classType); iv.load(frameMap.getOuterThisIndex(), type); iv.putfield(classname, fieldName, interfaceDesc); @@ -393,7 +398,7 @@ public class ImplementationBodyCodegen extends ClassBodyCodegen { Method function = state.getTypeMapper().mapSignature(fun.getName(), fun); Method functionOriginal = state.getTypeMapper().mapSignature(fun.getName(), fun.getOriginal()); - final MethodVisitor mv = v.visitMethod(flags, function.getName(), function.getDescriptor(), null, null); + final MethodVisitor mv = v.newMethod(myClass, flags, function.getName(), function.getDescriptor(), null, null); mv.visitCode(); codegen.generateThisOrOuter(descriptor); @@ -475,7 +480,7 @@ public class ImplementationBodyCodegen extends ClassBodyCodegen { else if (declaration instanceof JetEnumEntry && !((JetEnumEntry) declaration).hasPrimaryConstructor()) { String name = declaration.getName(); final String desc = "L" + state.getTypeMapper().jvmName(descriptor, OwnerKind.IMPLEMENTATION) + ";"; - v.visitField(Opcodes.ACC_PUBLIC | Opcodes.ACC_STATIC | Opcodes.ACC_FINAL, name, desc, null, null); + v.newField(declaration, Opcodes.ACC_PUBLIC | Opcodes.ACC_STATIC | Opcodes.ACC_FINAL, name, desc, null, null); if (myEnumConstants.isEmpty()) { staticInitializerChunks.add(new CodeChunk() { @Override @@ -533,7 +538,7 @@ public class ImplementationBodyCodegen extends ClassBodyCodegen { } CallableMethod method = state.getTypeMapper().mapToCallableMethod(constructorDescriptor, kind); int flags = Opcodes.ACC_PUBLIC; // TODO - final MethodVisitor mv = v.visitMethod(flags, "", method.getSignature().getDescriptor(), null, null); + final MethodVisitor mv = v.newMethod(constructor, flags, "", method.getSignature().getDescriptor(), null, null); mv.visitCode(); ConstructorFrameMap frameMap = new ConstructorFrameMap(method, constructorDescriptor, descriptor, kind); @@ -677,9 +682,9 @@ public class ImplementationBodyCodegen extends ClassBodyCodegen { if (p.getValOrVarNode() != null) { PropertyDescriptor propertyDescriptor = state.getBindingContext().get(BindingContext.PRIMARY_CONSTRUCTOR_PARAMETER, p); if (propertyDescriptor != null) { - propertyCodegen.generateDefaultGetter(propertyDescriptor, Opcodes.ACC_PUBLIC); + propertyCodegen.generateDefaultGetter(propertyDescriptor, Opcodes.ACC_PUBLIC, p); if (propertyDescriptor.isVar()) { - propertyCodegen.generateDefaultSetter(propertyDescriptor, Opcodes.ACC_PUBLIC); + propertyCodegen.generateDefaultSetter(propertyDescriptor, Opcodes.ACC_PUBLIC, p); } } } @@ -703,9 +708,9 @@ public class ImplementationBodyCodegen extends ClassBodyCodegen { JetType defaultType = descriptor.getDefaultType(); if(CodegenUtil.hasTypeInfoField(defaultType)) { if(!CodegenUtil.hasDerivedTypeInfoField(defaultType, true)) { - v.visitField(Opcodes.ACC_PRIVATE, "$typeInfo", "Ljet/typeinfo/TypeInfo;", null, null); + v.newField(myClass, Opcodes.ACC_PRIVATE, "$typeInfo", "Ljet/typeinfo/TypeInfo;", null, null); - MethodVisitor mv = v.visitMethod(Opcodes.ACC_PUBLIC, "getTypeInfo", "()Ljet/typeinfo/TypeInfo;", null, null); + MethodVisitor mv = v.newMethod(myClass, Opcodes.ACC_PUBLIC, "getTypeInfo", "()Ljet/typeinfo/TypeInfo;", null, null); mv.visitCode(); InstructionAdapter iv = new InstructionAdapter(mv); String owner = state.getTypeMapper().jvmName(descriptor, OwnerKind.IMPLEMENTATION); @@ -715,7 +720,7 @@ public class ImplementationBodyCodegen extends ClassBodyCodegen { mv.visitMaxs(0, 0); mv.visitEnd(); - mv = v.visitMethod(Opcodes.ACC_PROTECTED|Opcodes.ACC_FINAL, "$setTypeInfo", "(Ljet/typeinfo/TypeInfo;)V", null, null); + mv = v.newMethod(myClass, Opcodes.ACC_PROTECTED | Opcodes.ACC_FINAL, "$setTypeInfo", "(Ljet/typeinfo/TypeInfo;)V", null, null); mv.visitCode(); iv = new InstructionAdapter(mv); owner = state.getTypeMapper().jvmName(descriptor, OwnerKind.IMPLEMENTATION); @@ -734,7 +739,7 @@ public class ImplementationBodyCodegen extends ClassBodyCodegen { } private void genGetStaticGetTypeInfoMethod() { - final MethodVisitor mv = v.visitMethod(Opcodes.ACC_PUBLIC, "getTypeInfo", "()Ljet/typeinfo/TypeInfo;", null, null); + final MethodVisitor mv = v.newMethod(myClass, Opcodes.ACC_PUBLIC, "getTypeInfo", "()Ljet/typeinfo/TypeInfo;", null, null); mv.visitCode(); InstructionAdapter v = new InstructionAdapter(mv); String owner = state.getTypeMapper().jvmName(descriptor, OwnerKind.IMPLEMENTATION); @@ -745,7 +750,7 @@ public class ImplementationBodyCodegen extends ClassBodyCodegen { } private void staticTypeInfoField() { - v.visitField(Opcodes.ACC_PUBLIC | Opcodes.ACC_FINAL | Opcodes.ACC_STATIC, "$staticTypeInfo", "Ljet/typeinfo/TypeInfo;", null, null); + v.newField(myClass, Opcodes.ACC_PUBLIC | Opcodes.ACC_FINAL | Opcodes.ACC_STATIC, "$staticTypeInfo", "Ljet/typeinfo/TypeInfo;", null, null); staticInitializerChunks.add(new CodeChunk() { @Override public void generate(InstructionAdapter v) { @@ -776,11 +781,11 @@ public class ImplementationBodyCodegen extends ClassBodyCodegen { String sig = getGetSuperTypesTypeInfoSignature(descriptor.getDefaultType()); - final MethodVisitor mv = v.visitMethod(Opcodes.ACC_PUBLIC|Opcodes.ACC_STATIC, - "$$getSuperTypesTypeInfo", - sig, - null /* TODO */, - null); + final MethodVisitor mv = v.newMethod(myClass, Opcodes.ACC_PUBLIC | Opcodes.ACC_STATIC, + "$$getSuperTypesTypeInfo", + sig, + null /* TODO */, + null); mv.visitCode(); InstructionAdapter v = new InstructionAdapter(mv); diff --git a/compiler/backend/src/org/jetbrains/jet/codegen/NamespaceCodegen.java b/compiler/backend/src/org/jetbrains/jet/codegen/NamespaceCodegen.java index 4974917fb30..a456c64b74a 100644 --- a/compiler/backend/src/org/jetbrains/jet/codegen/NamespaceCodegen.java +++ b/compiler/backend/src/org/jetbrains/jet/codegen/NamespaceCodegen.java @@ -9,10 +9,14 @@ import org.jetbrains.jet.lang.resolve.java.JavaClassDescriptor; import org.jetbrains.jet.lang.types.JetType; import org.jetbrains.jet.lang.types.TypeProjection; import org.jetbrains.jet.lang.types.TypeUtils; -import org.objectweb.asm.*; +import org.objectweb.asm.Label; +import org.objectweb.asm.MethodVisitor; +import org.objectweb.asm.Type; import org.objectweb.asm.commons.InstructionAdapter; -import java.util.*; +import java.util.Collections; +import java.util.List; +import java.util.Map; import static org.objectweb.asm.Opcodes.*; @@ -20,20 +24,20 @@ import static org.objectweb.asm.Opcodes.*; * @author max */ public class NamespaceCodegen { - private final ClassVisitor v; + private final ClassBuilder v; private final GenerationState state; - public NamespaceCodegen(ClassVisitor v, String fqName, GenerationState state, PsiFile sourceFile) { + public NamespaceCodegen(ClassBuilder v, String fqName, GenerationState state, PsiFile sourceFile) { this.v = v; this.state = state; - v.visit(V1_6, - ACC_PUBLIC, - getJVMClassName(fqName), - null, - //"jet/lang/Namespace", - "java/lang/Object", - new String[0] + v.defineClass(V1_6, + ACC_PUBLIC, + getJVMClassName(fqName), + null, + //"jet/lang/Namespace", + "java/lang/Object", + new String[0] ); // TODO figure something out for a namespace that spans multiple files v.visitSource(sourceFile.getName(), null); @@ -76,8 +80,8 @@ public class NamespaceCodegen { } private void generateStaticInitializers(JetNamespace namespace) { - MethodVisitor mv = v.visitMethod(ACC_PUBLIC | ACC_STATIC, - "", "()V", null, null); + MethodVisitor mv = v.newMethod(namespace, ACC_PUBLIC | ACC_STATIC, + "", "()V", null, null); mv.visitCode(); FrameMap frameMap = new FrameMap(); @@ -104,9 +108,9 @@ public class NamespaceCodegen { String jvmClassName = getJVMClassName(namespace.getName()); for(Map.Entry e : (context.typeInfoConstants != null ? context.typeInfoConstants : Collections.emptyMap()).entrySet()) { String fieldName = "$typeInfoCache$" + e.getValue(); - v.visitField(ACC_PRIVATE|ACC_STATIC|ACC_SYNTHETIC, fieldName, "Ljet/typeinfo/TypeInfo;", null, null); + v.newField(null, ACC_PRIVATE | ACC_STATIC | ACC_SYNTHETIC, fieldName, "Ljet/typeinfo/TypeInfo;", null, null); - MethodVisitor mmv = v.visitMethod(ACC_PUBLIC|ACC_STATIC|ACC_SYNTHETIC, "$getCachedTypeInfo$" + e.getValue(), "()Ljet/typeinfo/TypeInfo;", null, null); + MethodVisitor mmv = v.newMethod(null, ACC_PUBLIC | ACC_STATIC | ACC_SYNTHETIC, "$getCachedTypeInfo$" + e.getValue(), "()Ljet/typeinfo/TypeInfo;", null, null); InstructionAdapter v = new InstructionAdapter(mmv); v.visitFieldInsn(GETSTATIC, jvmClassName, fieldName, "Ljet/typeinfo/TypeInfo;"); v.visitInsn(DUP); @@ -185,7 +189,7 @@ public class NamespaceCodegen { } public void done() { - v.visitEnd(); + v.done(); } public static String getJVMClassName(String fqName) { diff --git a/compiler/backend/src/org/jetbrains/jet/codegen/PropertyCodegen.java b/compiler/backend/src/org/jetbrains/jet/codegen/PropertyCodegen.java index 6dc17c82643..be9733fac27 100644 --- a/compiler/backend/src/org/jetbrains/jet/codegen/PropertyCodegen.java +++ b/compiler/backend/src/org/jetbrains/jet/codegen/PropertyCodegen.java @@ -2,12 +2,14 @@ package org.jetbrains.jet.codegen; import com.intellij.openapi.util.text.StringUtil; import com.intellij.psi.PsiElement; -import org.jetbrains.jet.lang.descriptors.*; +import org.jetbrains.jet.lang.descriptors.DeclarationDescriptor; +import org.jetbrains.jet.lang.descriptors.PropertyDescriptor; +import org.jetbrains.jet.lang.descriptors.PropertySetterDescriptor; +import org.jetbrains.jet.lang.descriptors.VariableDescriptor; import org.jetbrains.jet.lang.psi.*; import org.jetbrains.jet.lang.resolve.BindingContext; import org.jetbrains.jet.lang.resolve.constants.CompileTimeConstant; import org.jetbrains.jet.lexer.JetTokens; -import org.objectweb.asm.ClassVisitor; import org.objectweb.asm.MethodVisitor; import org.objectweb.asm.Opcodes; import org.objectweb.asm.Type; @@ -19,10 +21,10 @@ import org.objectweb.asm.commons.InstructionAdapter; public class PropertyCodegen { private final GenerationState state; private final FunctionCodegen functionCodegen; - private final ClassVisitor v; + private final ClassBuilder v; private final OwnerKind kind; - public PropertyCodegen(ClassContext context, ClassVisitor v, FunctionCodegen functionCodegen, GenerationState state) { + public PropertyCodegen(ClassContext context, ClassBuilder v, FunctionCodegen functionCodegen, GenerationState state) { this.v = v; this.functionCodegen = functionCodegen; this.state = state; @@ -41,9 +43,9 @@ public class PropertyCodegen { generateSetter(p, propertyDescriptor); } else if (kind instanceof OwnerKind.DelegateKind) { - generateDefaultGetter(propertyDescriptor, Opcodes.ACC_PUBLIC); + generateDefaultGetter(propertyDescriptor, Opcodes.ACC_PUBLIC, p); if (propertyDescriptor.isVar()) { - generateDefaultSetter(propertyDescriptor, Opcodes.ACC_PUBLIC); + generateDefaultSetter(propertyDescriptor, Opcodes.ACC_PUBLIC, p); } } } @@ -71,7 +73,7 @@ public class PropertyCodegen { else { modifiers = Opcodes.ACC_PRIVATE; } - v.visitField(modifiers, p.getName(), state.getTypeMapper().mapType(propertyDescriptor.getOutType()).getDescriptor(), null, value); + v.newField(p, modifiers, p.getName(), state.getTypeMapper().mapType(propertyDescriptor.getOutType()).getDescriptor(), null, value); } } @@ -114,10 +116,10 @@ public class PropertyCodegen { private void generateDefaultGetter(JetProperty p, JetDeclaration declaration) { final PropertyDescriptor propertyDescriptor = (PropertyDescriptor) state.getBindingContext().get(BindingContext.VARIABLE, p); int flags = JetTypeMapper.getAccessModifiers(declaration, Opcodes.ACC_PUBLIC); - generateDefaultGetter(propertyDescriptor, flags); + generateDefaultGetter(propertyDescriptor, flags, p); } - public void generateDefaultGetter(PropertyDescriptor propertyDescriptor, int flags) { + public void generateDefaultGetter(PropertyDescriptor propertyDescriptor, int flags, PsiElement origin) { if (kind == OwnerKind.NAMESPACE) { flags |= Opcodes.ACC_STATIC; } @@ -129,7 +131,7 @@ public class PropertyCodegen { final String signature = state.getTypeMapper().mapGetterSignature(propertyDescriptor).getDescriptor(); String getterName = getterName(propertyDescriptor.getName()); - MethodVisitor mv = v.visitMethod(flags, getterName, signature, null, null); + MethodVisitor mv = v.newMethod(origin, flags, getterName, signature, null, null); if (!isTrait || kind instanceof OwnerKind.DelegateKind) { mv.visitCode(); InstructionAdapter iv = new InstructionAdapter(mv); @@ -156,10 +158,10 @@ public class PropertyCodegen { private void generateDefaultSetter(JetProperty p, JetDeclaration declaration) { final PropertyDescriptor propertyDescriptor = (PropertyDescriptor) state.getBindingContext().get(BindingContext.VARIABLE, p); int flags = JetTypeMapper.getAccessModifiers(declaration, Opcodes.ACC_PUBLIC); - generateDefaultSetter(propertyDescriptor, flags); + generateDefaultSetter(propertyDescriptor, flags, p); } - public void generateDefaultSetter(PropertyDescriptor propertyDescriptor, int flags) { + public void generateDefaultSetter(PropertyDescriptor propertyDescriptor, int flags, PsiElement origin) { if (kind == OwnerKind.NAMESPACE) { flags |= Opcodes.ACC_STATIC; } @@ -170,7 +172,7 @@ public class PropertyCodegen { flags |= Opcodes.ACC_ABSTRACT; final String signature = state.getTypeMapper().mapSetterSignature(propertyDescriptor).getDescriptor(); - MethodVisitor mv = v.visitMethod(flags, setterName(propertyDescriptor.getName()), signature, null, null); + MethodVisitor mv = v.newMethod(origin, flags, setterName(propertyDescriptor.getName()), signature, null, null); if (!isTrait || kind instanceof OwnerKind.DelegateKind) { mv.visitCode(); InstructionAdapter iv = new InstructionAdapter(mv); diff --git a/compiler/backend/src/org/jetbrains/jet/codegen/TraitImplBodyCodegen.java b/compiler/backend/src/org/jetbrains/jet/codegen/TraitImplBodyCodegen.java index 86a07215e04..1f084b731dc 100644 --- a/compiler/backend/src/org/jetbrains/jet/codegen/TraitImplBodyCodegen.java +++ b/compiler/backend/src/org/jetbrains/jet/codegen/TraitImplBodyCodegen.java @@ -7,15 +7,12 @@ import org.jetbrains.jet.lang.psi.*; import org.jetbrains.jet.lang.resolve.BindingContext; import org.jetbrains.jet.lang.types.JetStandardClasses; import org.jetbrains.jet.lang.types.JetType; -import org.jetbrains.jet.lexer.JetTokens; -import org.objectweb.asm.ClassVisitor; import org.objectweb.asm.Opcodes; -import java.util.ArrayList; import java.util.List; public class TraitImplBodyCodegen extends ClassBodyCodegen { - public TraitImplBodyCodegen(JetClassOrObject aClass, ClassContext context, ClassVisitor v, GenerationState state) { + public TraitImplBodyCodegen(JetClassOrObject aClass, ClassContext context, ClassBuilder v, GenerationState state) { super(aClass, context, v, state); } @@ -48,12 +45,12 @@ public class TraitImplBodyCodegen extends ClassBodyCodegen { @Override protected void generateDeclaration() { - v.visit(Opcodes.V1_6, - Opcodes.ACC_PUBLIC | Opcodes.ACC_FINAL, - jvmName(), - null, - "java/lang/Object", - new String[0] + v.defineClass(Opcodes.V1_6, + Opcodes.ACC_PUBLIC | Opcodes.ACC_FINAL, + jvmName(), + null, + "java/lang/Object", + new String[0] ); v.visitSource(myClass.getContainingFile().getName(), null); } From 29c4e2bddbb07f613bd3ba2b3a7d2cb1ab693574 Mon Sep 17 00:00:00 2001 From: Andrey Breslav Date: Wed, 2 Nov 2011 19:50:48 +0300 Subject: [PATCH 03/15] ResolvedCalls for indexed expressions --- .../jet/codegen/ExpressionCodegen.java | 7 +-- .../jet/lang/resolve/BindingContext.java | 4 +- .../jet/lang/resolve/calls/CallResolver.java | 7 +-- .../BasicExpressionTypingVisitor.java | 28 +++++------ .../expressions/ExpressionTypingContext.java | 9 +++- .../ExpressionTypingVisitorForStatements.java | 47 ++++++++++--------- .../references/JetArrayAccessReference.java | 13 ++--- 7 files changed, 64 insertions(+), 51 deletions(-) diff --git a/compiler/backend/src/org/jetbrains/jet/codegen/ExpressionCodegen.java b/compiler/backend/src/org/jetbrains/jet/codegen/ExpressionCodegen.java index 13b47845a66..ef356283043 100644 --- a/compiler/backend/src/org/jetbrains/jet/codegen/ExpressionCodegen.java +++ b/compiler/backend/src/org/jetbrains/jet/codegen/ExpressionCodegen.java @@ -12,7 +12,6 @@ import org.jetbrains.jet.lang.descriptors.*; import org.jetbrains.jet.lang.diagnostics.DiagnosticUtils; import org.jetbrains.jet.lang.psi.*; import org.jetbrains.jet.lang.resolve.BindingContext; -import org.jetbrains.jet.lang.resolve.BindingContextUtils; import org.jetbrains.jet.lang.resolve.calls.*; import org.jetbrains.jet.lang.resolve.constants.CompileTimeConstant; import org.jetbrains.jet.lang.resolve.java.JavaClassDescriptor; @@ -1976,14 +1975,16 @@ public class ExpressionCodegen extends JetVisitor { boolean isGetter = accessor.getSignature().getName().equals("get"); if(isGetter) { - FunctionDescriptor setterDescriptor = bindingContext.get(BindingContext.INDEXED_LVALUE_SET, expression); + ResolvedCall resolvedCall = bindingContext.get(BindingContext.INDEXED_LVALUE_SET, expression); + FunctionDescriptor setterDescriptor = resolvedCall == null ? null : resolvedCall.getResultingDescriptor(); return StackValue.collectionElement( accessor.getSignature().getReturnType(), accessor, setterDescriptor != null ? typeMapper.mapToCallableMethod(setterDescriptor, OwnerKind.IMPLEMENTATION) : null); } else { - FunctionDescriptor getterDescriptor = bindingContext.get(BindingContext.INDEXED_LVALUE_GET, expression); + ResolvedCall resolvedCall = bindingContext.get(BindingContext.INDEXED_LVALUE_GET, expression); + FunctionDescriptor getterDescriptor = resolvedCall == null ? null : resolvedCall.getResultingDescriptor(); return StackValue.collectionElement( accessor.getSignature().getArgumentTypes()[1], getterDescriptor != null ? typeMapper.mapToCallableMethod(getterDescriptor, OwnerKind.IMPLEMENTATION) : null, diff --git a/compiler/frontend/src/org/jetbrains/jet/lang/resolve/BindingContext.java b/compiler/frontend/src/org/jetbrains/jet/lang/resolve/BindingContext.java index bf967fee95b..fe0b5f8ace8 100644 --- a/compiler/frontend/src/org/jetbrains/jet/lang/resolve/BindingContext.java +++ b/compiler/frontend/src/org/jetbrains/jet/lang/resolve/BindingContext.java @@ -36,8 +36,8 @@ public interface BindingContext { WritableSlice LOOP_RANGE_HAS_NEXT = Slices.createSimpleSlice("LOOP_RANGE_HAS_NEXT"); WritableSlice LOOP_RANGE_NEXT = Slices.createSimpleSlice("LOOP_RANGE_NEXT"); - WritableSlice INDEXED_LVALUE_GET = Slices.createSimpleSlice("INDEXED_LVALUE_GET"); - WritableSlice INDEXED_LVALUE_SET = Slices.createSimpleSlice("INDEXED_LVALUE_SET"); + WritableSlice> INDEXED_LVALUE_GET = Slices.createSimpleSlice("INDEXED_LVALUE_GET"); + WritableSlice> INDEXED_LVALUE_SET = Slices.createSimpleSlice("INDEXED_LVALUE_SET"); WritableSlice AUTOCAST = Slices.createSimpleSlice("AUTOCAST"); WritableSlice RESOLUTION_SCOPE = Slices.createSimpleSlice("RESOLUTION_SCOPE"); diff --git a/compiler/frontend/src/org/jetbrains/jet/lang/resolve/calls/CallResolver.java b/compiler/frontend/src/org/jetbrains/jet/lang/resolve/calls/CallResolver.java index 5b93320fe05..f722e29c6b2 100644 --- a/compiler/frontend/src/org/jetbrains/jet/lang/resolve/calls/CallResolver.java +++ b/compiler/frontend/src/org/jetbrains/jet/lang/resolve/calls/CallResolver.java @@ -78,7 +78,7 @@ public class CallResolver { } @Nullable - public FunctionDescriptor resolveCallWithGivenName( + public ResolvedCall resolveCallWithGivenName( @NotNull BindingTrace trace, @NotNull JetScope scope, @NotNull final Call call, @@ -86,7 +86,7 @@ public class CallResolver { @NotNull String name, @NotNull JetType expectedType) { List> tasks = TaskPrioritizers.FUNCTION_TASK_PRIORITIZER.computePrioritizedTasks(scope, call, name, trace.getBindingContext(), dataFlowInfo); - return resolveCallToDescriptor(trace, scope, call, expectedType, tasks, functionReference); + return doResolveCall(trace, scope, call, expectedType, tasks, functionReference); } @Nullable @@ -174,7 +174,8 @@ public class CallResolver { prioritizedTasks = Collections.singletonList(new ResolutionTask(ResolvedCallImpl.convertCollection(constructors), call, DataFlowInfo.EMPTY)); } else { - throw new UnsupportedOperationException("Type argument inference not implemented for " + call); + trace.report(UNSUPPORTED.on(call.getCallNode(), "Type argument inference is not supported for this callee: " + calleeExpression)); + return null; } } diff --git a/compiler/frontend/src/org/jetbrains/jet/lang/types/expressions/BasicExpressionTypingVisitor.java b/compiler/frontend/src/org/jetbrains/jet/lang/types/expressions/BasicExpressionTypingVisitor.java index 8a5c6b3f531..2255ebe885d 100644 --- a/compiler/frontend/src/org/jetbrains/jet/lang/types/expressions/BasicExpressionTypingVisitor.java +++ b/compiler/frontend/src/org/jetbrains/jet/lang/types/expressions/BasicExpressionTypingVisitor.java @@ -11,6 +11,7 @@ import org.jetbrains.jet.lang.descriptors.*; import org.jetbrains.jet.lang.psi.*; import org.jetbrains.jet.lang.resolve.*; import org.jetbrains.jet.lang.resolve.calls.CallMaker; +import org.jetbrains.jet.lang.resolve.calls.ResolvedCall; import org.jetbrains.jet.lang.resolve.calls.autocasts.DataFlowInfo; import org.jetbrains.jet.lang.resolve.calls.OverloadResolutionResults; import org.jetbrains.jet.lang.resolve.constants.*; @@ -559,11 +560,10 @@ public class BasicExpressionTypingVisitor extends ExpressionTypingVisitor { ExpressionReceiver receiver = getExpressionReceiver(facade, baseExpression, context.replaceExpectedType(NO_EXPECTED_TYPE).replaceScope(context.scope)); if (receiver == null) return null; - FunctionDescriptor functionDescriptor = context.resolveCallWithGivenName( + FunctionDescriptor functionDescriptor = context.resolveCallWithGivenNameToDescriptor( CallMaker.makeCall(receiver, expression), expression.getOperationSign(), - name, - receiver); + name); if (functionDescriptor == null) return null; JetType returnType = functionDescriptor.getReturnType(); @@ -705,10 +705,10 @@ public class BasicExpressionTypingVisitor extends ExpressionTypingVisitor { public void checkInExpression(JetElement callElement, @NotNull JetSimpleNameExpression operationSign, @NotNull JetExpression left, @NotNull JetExpression right, ExpressionTypingContext context) { String name = "contains"; ExpressionReceiver receiver = safeGetExpressionReceiver(facade, right, context.replaceExpectedType(NO_EXPECTED_TYPE)); - FunctionDescriptor functionDescriptor = context.resolveCallWithGivenName( + FunctionDescriptor functionDescriptor = context.resolveCallWithGivenNameToDescriptor( CallMaker.makeCallWithExpressions(callElement, receiver, null, operationSign, Collections.singletonList(left)), operationSign, - name, receiver); + name); JetType containsType = functionDescriptor != null ? functionDescriptor.getReturnType() : null; ensureBooleanResult(operationSign, name, containsType, context); } @@ -752,14 +752,14 @@ public class BasicExpressionTypingVisitor extends ExpressionTypingVisitor { ExpressionReceiver receiver = getExpressionReceiver(facade, arrayExpression, context.replaceScope(context.scope)); if (receiver != null) { - FunctionDescriptor functionDescriptor = context.resolveCallWithGivenName( + ResolvedCall resolvedCall = context.resolveCallWithGivenName( CallMaker.makeCallWithExpressions(expression, receiver, null, expression, expression.getIndexExpressions()), expression, - "get", - receiver); - if (functionDescriptor != null) { - context.trace.record(INDEXED_LVALUE_GET, expression, functionDescriptor); - return DataFlowUtils.checkType(functionDescriptor.getReturnType(), expression, contextWithExpectedType); + "get" + ); + if (resolvedCall != null) { + context.trace.record(INDEXED_LVALUE_GET, expression, resolvedCall); + return DataFlowUtils.checkType(resolvedCall.getResultingDescriptor().getReturnType(), expression, contextWithExpectedType); } } return null; @@ -768,11 +768,11 @@ public class BasicExpressionTypingVisitor extends ExpressionTypingVisitor { @Nullable protected JetType getTypeForBinaryCall(JetScope scope, String name, ExpressionTypingContext context, JetBinaryExpression binaryExpression) { ExpressionReceiver receiver = safeGetExpressionReceiver(facade, binaryExpression.getLeft(), context.replaceScope(scope)); - FunctionDescriptor functionDescriptor = context.replaceScope(scope).resolveCallWithGivenName( + FunctionDescriptor functionDescriptor = context.replaceScope(scope).resolveCallWithGivenNameToDescriptor( CallMaker.makeCall(receiver, binaryExpression), binaryExpression.getOperationReference(), - name, - receiver); + name + ); if (functionDescriptor != null) { return functionDescriptor.getReturnType(); } diff --git a/compiler/frontend/src/org/jetbrains/jet/lang/types/expressions/ExpressionTypingContext.java b/compiler/frontend/src/org/jetbrains/jet/lang/types/expressions/ExpressionTypingContext.java index c84fbf93516..f81094254b2 100644 --- a/compiler/frontend/src/org/jetbrains/jet/lang/types/expressions/ExpressionTypingContext.java +++ b/compiler/frontend/src/org/jetbrains/jet/lang/types/expressions/ExpressionTypingContext.java @@ -12,6 +12,7 @@ import org.jetbrains.jet.lang.resolve.ClassDescriptorResolver; import org.jetbrains.jet.lang.resolve.TypeResolver; import org.jetbrains.jet.lang.resolve.calls.CallMaker; import org.jetbrains.jet.lang.resolve.calls.CallResolver; +import org.jetbrains.jet.lang.resolve.calls.ResolvedCall; import org.jetbrains.jet.lang.resolve.calls.autocasts.DataFlowInfo; import org.jetbrains.jet.lang.resolve.calls.OverloadResolutionResults; import org.jetbrains.jet.lang.resolve.constants.CompileTimeConstantResolver; @@ -172,10 +173,16 @@ import java.util.Map; ////////// Call resolution utilities @Nullable - public FunctionDescriptor resolveCallWithGivenName(@NotNull Call call, @NotNull JetReferenceExpression functionReference, @NotNull String name, @NotNull ReceiverDescriptor receiver) { + public ResolvedCall resolveCallWithGivenName(@NotNull Call call, @NotNull JetReferenceExpression functionReference, @NotNull String name) { return getCallResolver().resolveCallWithGivenName(trace, scope, call, functionReference, name, expectedType); } + @Nullable + public FunctionDescriptor resolveCallWithGivenNameToDescriptor(@NotNull Call call, @NotNull JetReferenceExpression functionReference, @NotNull String name) { + ResolvedCall resolvedCall = resolveCallWithGivenName(call, functionReference, name); + return resolvedCall == null ? null : resolvedCall.getResultingDescriptor(); + } + @Nullable public JetType resolveCall(@NotNull ReceiverDescriptor receiver, @Nullable ASTNode callOperationNode, @NotNull JetCallExpression callExpression) { return getCallResolver().resolveCall(trace, scope, CallMaker.makeCall(receiver, callOperationNode, callExpression), expectedType); diff --git a/compiler/frontend/src/org/jetbrains/jet/lang/types/expressions/ExpressionTypingVisitorForStatements.java b/compiler/frontend/src/org/jetbrains/jet/lang/types/expressions/ExpressionTypingVisitorForStatements.java index 1eea9c06ae8..ab79f9cb225 100644 --- a/compiler/frontend/src/org/jetbrains/jet/lang/types/expressions/ExpressionTypingVisitorForStatements.java +++ b/compiler/frontend/src/org/jetbrains/jet/lang/types/expressions/ExpressionTypingVisitorForStatements.java @@ -9,15 +9,16 @@ import org.jetbrains.jet.lang.resolve.BindingContext; import org.jetbrains.jet.lang.resolve.TemporaryBindingTrace; import org.jetbrains.jet.lang.resolve.TopDownAnalyzer; import org.jetbrains.jet.lang.resolve.calls.CallMaker; +import org.jetbrains.jet.lang.resolve.calls.ResolvedCall; import org.jetbrains.jet.lang.resolve.scopes.WritableScope; import org.jetbrains.jet.lang.resolve.scopes.receivers.ExpressionReceiver; +import org.jetbrains.jet.lang.types.ErrorUtils; import org.jetbrains.jet.lang.types.JetStandardClasses; import org.jetbrains.jet.lang.types.JetType; import org.jetbrains.jet.lang.types.TypeUtils; import org.jetbrains.jet.lexer.JetTokens; import static org.jetbrains.jet.lang.diagnostics.Errors.*; -import static org.jetbrains.jet.lang.resolve.BindingContext.INDEXED_LVALUE_GET; import static org.jetbrains.jet.lang.resolve.BindingContext.INDEXED_LVALUE_SET; import static org.jetbrains.jet.lang.resolve.BindingContext.REFERENCE_TARGET; import static org.jetbrains.jet.lang.types.expressions.ExpressionTypingUtils.getExpressionReceiver; @@ -123,7 +124,7 @@ public class ExpressionTypingVisitorForStatements extends BasicExpressionTypingV if (typeForBinaryCall != null) { JetExpression left = JetPsiUtil.deparenthesize(expression.getLeft()); if (left instanceof JetArrayAccessExpression) { - resolveArrayAccessToLValue((JetArrayAccessExpression) left, expression.getRight(), expression.getOperationReference(), context, true); + resolveArrayAccessToLValue((JetArrayAccessExpression) left, expression.getRight(), expression.getOperationReference(), context); } context.trace.record(BindingContext.VARIABLE_REASSIGNMENT, expression); @@ -138,14 +139,14 @@ public class ExpressionTypingVisitorForStatements extends BasicExpressionTypingV @Override protected JetType visitAssignment(JetBinaryExpression expression, ExpressionTypingContext context) { - boolean getterNeeded = false; JetExpression left = JetPsiUtil.deparenthesize(expression.getLeft()); JetExpression right = expression.getRight(); if (left instanceof JetArrayAccessExpression) { JetArrayAccessExpression arrayAccessExpression = (JetArrayAccessExpression) left; - return resolveArrayAccessToLValue(arrayAccessExpression, right, expression.getOperationReference(), context, getterNeeded); + return resolveArrayAccessToLValue(arrayAccessExpression, right, expression.getOperationReference(), context); } - JetType leftType = facade.getType(left, context.replaceExpectedType(TypeUtils.NO_EXPECTED_TYPE).replaceScope(scope)); + JetType leftType = left == null ? ErrorUtils.createErrorType("No expression") + : facade.getType(left, context.replaceExpectedType(TypeUtils.NO_EXPECTED_TYPE).replaceScope(scope)); if (right != null) { JetType rightType = facade.getType(right, context.replaceExpectedType(leftType).replaceScope(scope)); } @@ -164,30 +165,32 @@ public class ExpressionTypingVisitorForStatements extends BasicExpressionTypingV return checkExpectedType(expression, context); } - private JetType resolveArrayAccessToLValue(JetArrayAccessExpression arrayAccessExpression, JetExpression rightHandSide, JetSimpleNameExpression operationSign, ExpressionTypingContext context, boolean getterNeeded) { + private JetType resolveArrayAccessToLValue(JetArrayAccessExpression arrayAccessExpression, JetExpression rightHandSide, JetSimpleNameExpression operationSign, ExpressionTypingContext context) { ExpressionReceiver receiver = getExpressionReceiver(facade, arrayAccessExpression.getArrayExpression(), context.replaceScope(scope)); if (receiver == null) return null; Call call = CallMaker.makeArraySetCall(receiver, arrayAccessExpression, rightHandSide); - FunctionDescriptor setFunction = context.replaceScope(scope).replaceExpectedType(TypeUtils.NO_EXPECTED_TYPE).resolveCallWithGivenName( + ResolvedCall setFunctionCall = context.replaceScope(scope).replaceExpectedType(TypeUtils.NO_EXPECTED_TYPE).resolveCallWithGivenName( call, arrayAccessExpression, - "set", receiver); - if (setFunction == null) return null; - context.trace.record(INDEXED_LVALUE_SET, arrayAccessExpression, setFunction); + "set"); + if (setFunctionCall == null) return null; + FunctionDescriptor setFunctionDescriptor = setFunctionCall.getResultingDescriptor(); - if (getterNeeded) { - FunctionDescriptor getFunction = context.replaceScope(scope).replaceExpectedType(TypeUtils.NO_EXPECTED_TYPE).resolveCallWithGivenName( - CallMaker.makeArrayGetCall(receiver, arrayAccessExpression), - arrayAccessExpression, - "get", receiver); - if (getFunction == null) return null; - context.trace.record(INDEXED_LVALUE_GET, arrayAccessExpression, getFunction); - } - else { - context.trace.record(REFERENCE_TARGET, operationSign, setFunction); - } - return DataFlowUtils.checkType(setFunction.getReturnType(), arrayAccessExpression, context); + context.trace.record(INDEXED_LVALUE_SET, arrayAccessExpression, setFunctionCall); + +// if (getterNeeded) { +// ResolvedCall getFunctionCall = context.replaceScope(scope).replaceExpectedType(TypeUtils.NO_EXPECTED_TYPE).resolveCallWithGivenName( +// CallMaker.makeArrayGetCall(receiver, arrayAccessExpression), +// arrayAccessExpression, +// "get"); +// if (getFunctionCall == null) return null; +// context.trace.record(INDEXED_LVALUE_GET, arrayAccessExpression, getFunctionCall); +// } +// else { + context.trace.record(REFERENCE_TARGET, operationSign, setFunctionDescriptor); +// } + return DataFlowUtils.checkType(setFunctionDescriptor.getReturnType(), arrayAccessExpression, context); } @Override diff --git a/idea/src/org/jetbrains/jet/plugin/references/JetArrayAccessReference.java b/idea/src/org/jetbrains/jet/plugin/references/JetArrayAccessReference.java index cdc32fa6d6b..66c3f2eee31 100644 --- a/idea/src/org/jetbrains/jet/plugin/references/JetArrayAccessReference.java +++ b/idea/src/org/jetbrains/jet/plugin/references/JetArrayAccessReference.java @@ -8,6 +8,7 @@ import org.jetbrains.jet.lang.psi.JetArrayAccessExpression; import org.jetbrains.jet.lang.psi.JetContainerNode; import org.jetbrains.jet.lang.psi.JetFile; import org.jetbrains.jet.lang.resolve.BindingContext; +import org.jetbrains.jet.lang.resolve.calls.ResolvedCall; import org.jetbrains.jet.lexer.JetTokens; import org.jetbrains.jet.plugin.compiler.WholeProjectAnalyzerFacade; @@ -40,8 +41,8 @@ class JetArrayAccessReference extends JetPsiReference implements MultiRangeRefer @Override protected PsiElement doResolve() { BindingContext bindingContext = WholeProjectAnalyzerFacade.analyzeProjectWithCacheOnAFile((JetFile) getElement().getContainingFile()); - FunctionDescriptor getFunction = bindingContext.get(INDEXED_LVALUE_GET, expression); - FunctionDescriptor setFunction = bindingContext.get(INDEXED_LVALUE_SET, expression); + ResolvedCall getFunction = bindingContext.get(INDEXED_LVALUE_GET, expression); + ResolvedCall setFunction = bindingContext.get(INDEXED_LVALUE_SET, expression); if (getFunction != null && setFunction != null) { return null; // Call doMultiResolve } @@ -51,10 +52,10 @@ class JetArrayAccessReference extends JetPsiReference implements MultiRangeRefer @Override protected ResolveResult[] doMultiResolve() { BindingContext bindingContext = WholeProjectAnalyzerFacade.analyzeProjectWithCacheOnAFile((JetFile) getElement().getContainingFile()); - FunctionDescriptor getFunction = bindingContext.get(INDEXED_LVALUE_GET, expression); - PsiElement getFunctionElement = bindingContext.get(DESCRIPTOR_TO_DECLARATION, getFunction); - FunctionDescriptor setFunction = bindingContext.get(INDEXED_LVALUE_SET, expression); - PsiElement setFunctionElement = bindingContext.get(DESCRIPTOR_TO_DECLARATION, setFunction); + ResolvedCall getFunction = bindingContext.get(INDEXED_LVALUE_GET, expression); + PsiElement getFunctionElement = bindingContext.get(DESCRIPTOR_TO_DECLARATION, getFunction.getResultingDescriptor()); + ResolvedCall setFunction = bindingContext.get(INDEXED_LVALUE_SET, expression); + PsiElement setFunctionElement = bindingContext.get(DESCRIPTOR_TO_DECLARATION, setFunction.getResultingDescriptor()); return new ResolveResult[] {new PsiElementResolveResult(getFunctionElement, true), new PsiElementResolveResult(setFunctionElement, true)}; // return super.doMultiResolve(); } From c22b0f33917bde256b46f9ee42e9b81e284700c0 Mon Sep 17 00:00:00 2001 From: Andrey Breslav Date: Wed, 2 Nov 2011 19:56:43 +0300 Subject: [PATCH 04/15] Commented code removed --- .../org/jetbrains/jet/lang/resolve/java/JavaDefaultImports.java | 2 -- 1 file changed, 2 deletions(-) diff --git a/compiler/frontend.java/src/org/jetbrains/jet/lang/resolve/java/JavaDefaultImports.java b/compiler/frontend.java/src/org/jetbrains/jet/lang/resolve/java/JavaDefaultImports.java index 2176cb879b3..24d820330e6 100644 --- a/compiler/frontend.java/src/org/jetbrains/jet/lang/resolve/java/JavaDefaultImports.java +++ b/compiler/frontend.java/src/org/jetbrains/jet/lang/resolve/java/JavaDefaultImports.java @@ -13,8 +13,6 @@ public class JavaDefaultImports { public static final ImportingStrategy JAVA_DEFAULT_IMPORTS = new ImportingStrategy() { @Override public void addImports(Project project, JetSemanticServices semanticServices, BindingTrace trace, WritableScope rootScope) { -// scope.importScope(javaSemanticServices.getDescriptorResolver().resolveNamespace("").getMemberScope()); -// scope.importScope(javaSemanticServices.getDescriptorResolver().resolveNamespace("java.lang").getMemberScope()); JavaSemanticServices javaSemanticServices = new JavaSemanticServices(project, semanticServices, trace); rootScope.importScope(new JavaPackageScope("", null, javaSemanticServices)); rootScope.importScope(new JavaPackageScope("java.lang", null, javaSemanticServices)); From 5b146f6be4dff931784c82e6fddaef01bdff3eed Mon Sep 17 00:00:00 2001 From: Andrey Breslav Date: Wed, 2 Nov 2011 21:32:57 +0300 Subject: [PATCH 05/15] KT-342 'Redeclaration' error while compiling two empty files --- .../src/org/jetbrains/jet/lang/resolve/AnalyzingUtils.java | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/compiler/frontend/src/org/jetbrains/jet/lang/resolve/AnalyzingUtils.java b/compiler/frontend/src/org/jetbrains/jet/lang/resolve/AnalyzingUtils.java index 753b8709857..5834dd945b7 100644 --- a/compiler/frontend/src/org/jetbrains/jet/lang/resolve/AnalyzingUtils.java +++ b/compiler/frontend/src/org/jetbrains/jet/lang/resolve/AnalyzingUtils.java @@ -2,6 +2,7 @@ package org.jetbrains.jet.lang.resolve; import com.google.common.base.Predicate; import com.google.common.base.Predicates; +import com.google.common.collect.Maps; import com.intellij.openapi.project.Project; import com.intellij.psi.PsiElement; import com.intellij.psi.PsiElementVisitor; @@ -23,6 +24,7 @@ import org.jetbrains.jet.lang.resolve.scopes.WritableScopeImpl; import java.util.Collection; import java.util.Collections; import java.util.List; +import java.util.Map; /** * @author abreslav @@ -82,14 +84,17 @@ public class AnalyzingUtils { TopDownAnalyzer.process(semanticServices, bindingTraceContext, scope, new NamespaceLike.Adapter(owner) { + private Map declaredNamespaces = Maps.newHashMap(); + @Override public NamespaceDescriptorImpl getNamespace(String name) { - return null; + return declaredNamespaces.get(name); } @Override public void addNamespace(@NotNull NamespaceDescriptor namespaceDescriptor) { scope.addNamespace(namespaceDescriptor); + declaredNamespaces.put(namespaceDescriptor.getName(), (NamespaceDescriptorImpl) namespaceDescriptor); } @Override From 532af2639fd4589b5ed19d804e1a2139c67b0a28 Mon Sep 17 00:00:00 2001 From: Andrey Breslav Date: Wed, 2 Nov 2011 22:01:14 +0300 Subject: [PATCH 06/15] Tests fixed --- .../ExpressionTypingVisitorForStatements.java | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/compiler/frontend/src/org/jetbrains/jet/lang/types/expressions/ExpressionTypingVisitorForStatements.java b/compiler/frontend/src/org/jetbrains/jet/lang/types/expressions/ExpressionTypingVisitorForStatements.java index ab79f9cb225..b3de2c0511f 100644 --- a/compiler/frontend/src/org/jetbrains/jet/lang/types/expressions/ExpressionTypingVisitorForStatements.java +++ b/compiler/frontend/src/org/jetbrains/jet/lang/types/expressions/ExpressionTypingVisitorForStatements.java @@ -20,7 +20,6 @@ import org.jetbrains.jet.lexer.JetTokens; import static org.jetbrains.jet.lang.diagnostics.Errors.*; import static org.jetbrains.jet.lang.resolve.BindingContext.INDEXED_LVALUE_SET; -import static org.jetbrains.jet.lang.resolve.BindingContext.REFERENCE_TARGET; import static org.jetbrains.jet.lang.types.expressions.ExpressionTypingUtils.getExpressionReceiver; /** @@ -110,7 +109,8 @@ public class ExpressionTypingVisitorForStatements extends BasicExpressionTypingV @Override protected JetType visitAssignmentOperation(JetBinaryExpression expression, ExpressionTypingContext context) { // If there's += (or similar op) defined as such, we just call it. - IElementType operationType = expression.getOperationReference().getReferencedNameElementType(); + JetSimpleNameExpression operationSign = expression.getOperationReference(); + IElementType operationType = operationSign.getReferencedNameElementType(); String name = OperatorConventions.ASSIGNMENT_OPERATIONS.get(operationType); TemporaryBindingTrace temporaryBindingTrace = TemporaryBindingTrace.create(context.trace); @@ -120,13 +120,13 @@ public class ExpressionTypingVisitorForStatements extends BasicExpressionTypingV if (assignmentOperationType == null) { String counterpartName = OperatorConventions.BINARY_OPERATION_NAMES.get(OperatorConventions.ASSIGNMENT_OPERATION_COUNTERPARTS.get(operationType)); + JetExpression left = JetPsiUtil.deparenthesize(expression.getLeft()); + if (left instanceof JetArrayAccessExpression) { + JetArrayAccessExpression arrayAccessExpression = (JetArrayAccessExpression) left; + resolveArrayAccessToLValue(arrayAccessExpression, expression.getRight(), operationSign, context); + } JetType typeForBinaryCall = getTypeForBinaryCall(scope, counterpartName, context, expression); if (typeForBinaryCall != null) { - JetExpression left = JetPsiUtil.deparenthesize(expression.getLeft()); - if (left instanceof JetArrayAccessExpression) { - resolveArrayAccessToLValue((JetArrayAccessExpression) left, expression.getRight(), expression.getOperationReference(), context); - } - context.trace.record(BindingContext.VARIABLE_REASSIGNMENT, expression); ExpressionTypingUtils.checkWrappingInRef(expression.getLeft(), context); } @@ -188,7 +188,7 @@ public class ExpressionTypingVisitorForStatements extends BasicExpressionTypingV // context.trace.record(INDEXED_LVALUE_GET, arrayAccessExpression, getFunctionCall); // } // else { - context.trace.record(REFERENCE_TARGET, operationSign, setFunctionDescriptor); +// context.trace.record(REFERENCE_TARGET, operationSign, setFunctionDescriptor); // } return DataFlowUtils.checkType(setFunctionDescriptor.getReturnType(), arrayAccessExpression, context); } From 3ad5e74abb65e5b9daec7774a577ce9cf106f6b6 Mon Sep 17 00:00:00 2001 From: Alex Tkachman Date: Wed, 2 Nov 2011 23:51:27 +0100 Subject: [PATCH 07/15] multi-index array expressions and related fixes --- .../jet/codegen/ExpressionCodegen.java | 141 ++++++++++-------- .../jet/codegen/FunctionCodegen.java | 3 +- .../jetbrains/jet/codegen/JetTypeMapper.java | 3 + .../org/jetbrains/jet/codegen/StackValue.java | 115 +++++++++----- .../jet/codegen/intrinsics/Increment.java | 2 +- .../jetbrains/jet/codegen/ArrayGenTest.java | 59 ++++++++ 6 files changed, 221 insertions(+), 102 deletions(-) diff --git a/compiler/backend/src/org/jetbrains/jet/codegen/ExpressionCodegen.java b/compiler/backend/src/org/jetbrains/jet/codegen/ExpressionCodegen.java index ef356283043..545e9f9a791 100644 --- a/compiler/backend/src/org/jetbrains/jet/codegen/ExpressionCodegen.java +++ b/compiler/backend/src/org/jetbrains/jet/codegen/ExpressionCodegen.java @@ -52,7 +52,7 @@ public class ExpressionCodegen extends JetVisitor { private int myLastLineNumber = -1; private final InstructionAdapter v; - private final FrameMap myMap; + private final FrameMap myFrameMap; private final JetTypeMapper typeMapper; private final GenerationState state; @@ -68,7 +68,7 @@ public class ExpressionCodegen extends JetVisitor { Type returnType, ClassContext context, GenerationState state) { - this.myMap = myMap; + this.myFrameMap = myMap; this.typeMapper = state.getTypeMapper(); this.returnType = returnType; this.state = state; @@ -264,7 +264,7 @@ public class ExpressionCodegen extends JetVisitor { JetType paramType = parameterDescriptor.getOutType(); Type asmParamType = typeMapper.mapType(paramType); - int iteratorVar = myMap.enterTemp(); + int iteratorVar = myFrameMap.enterTemp(); gen(expression.getLoopRange(), loopRangeType); invokeFunctionNoParams(iteratorDescriptor, asmIterType, v); v.store(iteratorVar, asmIterType); @@ -289,7 +289,7 @@ public class ExpressionCodegen extends JetVisitor { } v.ifeq(end); - myMap.enter(parameterDescriptor, asmParamType.getSize()); + myFrameMap.enter(parameterDescriptor, asmParamType.getSize()); v.load(iteratorVar, asmIterType); invokeFunctionNoParams(nextDescriptor, asmParamType, v); @@ -304,10 +304,10 @@ public class ExpressionCodegen extends JetVisitor { v.goTo(begin); v.mark(end); - int paramIndex = myMap.leave(parameterDescriptor); + int paramIndex = myFrameMap.leave(parameterDescriptor); //noinspection ConstantConditions v.visitLocalVariable(loopParameter.getName(), asmParamType.getDescriptor(), null, begin, end, paramIndex); - myMap.leaveTemp(); + myFrameMap.leaveTemp(); myBreakTargets.pop(); myContinueTargets.pop(); } @@ -338,7 +338,7 @@ public class ExpressionCodegen extends JetVisitor { JetType paramType = parameterDescriptor.getOutType(); Type asmParamType = typeMapper.mapType(paramType); - myMap.enter(parameterDescriptor, asmParamType.getSize()); + myFrameMap.enter(parameterDescriptor, asmParamType.getSize()); generatePrologue(); Label condition = new Label(); @@ -358,7 +358,7 @@ public class ExpressionCodegen extends JetVisitor { v.mark(end); cleanupTemp(); - final int paramIndex = myMap.leave(parameterDescriptor); + final int paramIndex = myFrameMap.leave(parameterDescriptor); //noinspection ConstantConditions v.visitLocalVariable(expression.getLoopParameter().getName(), asmParamType.getDescriptor(), null, condition, end, paramIndex); myBreakTargets.pop(); @@ -386,11 +386,11 @@ public class ExpressionCodegen extends JetVisitor { @Override protected void generatePrologue() { - myLengthVar = myMap.enterTemp(); + myLengthVar = myFrameMap.enterTemp(); gen(expression.getLoopRange(), loopRangeType); v.arraylength(); v.store(myLengthVar, Type.INT_TYPE); - myIndexVar = myMap.enterTemp(); + myIndexVar = myFrameMap.enterTemp(); v.iconst(0); v.store(myIndexVar, Type.INT_TYPE); } @@ -414,7 +414,7 @@ public class ExpressionCodegen extends JetVisitor { } protected void cleanupTemp() { - myMap.leaveTemp(2); + myFrameMap.leaveTemp(2); } } @@ -427,7 +427,7 @@ public class ExpressionCodegen extends JetVisitor { @Override protected void generatePrologue() { - myEndVar = myMap.enterTemp(); + myEndVar = myFrameMap.enterTemp(); if(isIntRangeExpr(expression.getLoopRange())) { JetBinaryExpression rangeExpression = (JetBinaryExpression) expression.getLoopRange(); //noinspection ConstantConditions @@ -461,7 +461,7 @@ public class ExpressionCodegen extends JetVisitor { @Override protected void cleanupTemp() { - myMap.leaveTemp(1); + myFrameMap.leaveTemp(1); } } @@ -634,7 +634,7 @@ public class ExpressionCodegen extends JetVisitor { final Type sharedVarType = getSharedVarType(variableDescriptor); final Type type = sharedVarType != null ? sharedVarType : typeMapper.mapType(variableDescriptor.getOutType()); - myMap.enter(variableDescriptor, type.getSize()); + myFrameMap.enter(variableDescriptor, type.getSize()); } } @@ -658,7 +658,7 @@ public class ExpressionCodegen extends JetVisitor { VariableDescriptor variableDescriptor = bindingContext.get(BindingContext.VARIABLE, var); assert variableDescriptor != null; - int index = myMap.leave(variableDescriptor); + int index = myFrameMap.leave(variableDescriptor); final Type sharedVarType = getSharedVarType(variableDescriptor); final Type type = sharedVarType != null ? sharedVarType : typeMapper.mapType(variableDescriptor.getOutType()); @@ -859,7 +859,7 @@ public class ExpressionCodegen extends JetVisitor { } public int lookupLocal(DeclarationDescriptor descriptor) { - return myMap.getIndex(descriptor); + return myFrameMap.getIndex(descriptor); } public void invokeFunctionNoParams(FunctionDescriptor functionDescriptor, Type type, InstructionAdapter v) { @@ -1122,8 +1122,8 @@ public class ExpressionCodegen extends JetVisitor { if (isSubclass((ClassDescriptor) curContextType, calleeContainingClass)) break; final StackValue outer; - if (!thisDone && myMap instanceof ConstructorFrameMap) { - outer = StackValue.local(((ConstructorFrameMap) myMap).getOuterThisIndex(), JetTypeMapper.TYPE_OBJECT); + if (!thisDone && myFrameMap instanceof ConstructorFrameMap) { + outer = StackValue.local(((ConstructorFrameMap) myFrameMap).getOuterThisIndex(), JetTypeMapper.TYPE_OBJECT); } else { thisToStack(); @@ -1188,12 +1188,12 @@ public class ExpressionCodegen extends JetVisitor { else if(resolvedValueArgument instanceof VarargValueArgument) { VarargValueArgument valueArgument = (VarargValueArgument) resolvedValueArgument; JetType outType = valueParameterDescriptor.getOutType(); - + Type type = typeMapper.mapType(outType); assert type.getSort() == Type.ARRAY; Type elementType = type.getElementType(); int size = valueArgument.getArgumentExpressions().size(); - + v.iconst(valueArgument.getArgumentExpressions().size()); v.newarray(elementType); for(int i = 0; i != size; ++i) { @@ -1202,7 +1202,7 @@ public class ExpressionCodegen extends JetVisitor { gen(valueArgument.getArgumentExpressions().get(i), elementType); StackValue.arrayElement(elementType, false).store(v); } - + // throw new UnsupportedOperationException("Varargs are not supported yet"); } else { @@ -1631,12 +1631,20 @@ public class ExpressionCodegen extends JetVisitor { DeclarationDescriptor op = bindingContext.get(BindingContext.REFERENCE_TARGET, expression.getOperationReference()); final Callable callable = resolveToCallable(op); final JetExpression lhs = expression.getLeft(); + +// if(lhs instanceof JetArrayAccessExpression) { +// JetArrayAccessExpression arrayAccessExpression = (JetArrayAccessExpression) lhs; +// if(arrayAccessExpression.getIndexExpressions().size() != 1) { +// throw new UnsupportedOperationException("Augmented assignment with multi-index"); +// } +// } + Type lhsType = expressionType(lhs); //noinspection ConstantConditions if (bindingContext.get(BindingContext.VARIABLE_REASSIGNMENT, expression)) { if (callable instanceof IntrinsicMethod) { StackValue value = gen(lhs); // receiver - value.dupReceiver(v, 0); // receiver receiver + value.dupReceiver(v); // receiver receiver value.put(lhsType, v); // receiver lhs final IntrinsicMethod intrinsic = (IntrinsicMethod) callable; //noinspection NullableProblems @@ -1659,7 +1667,7 @@ public class ExpressionCodegen extends JetVisitor { private void callAugAssignMethod(JetBinaryExpression expression, CallableMethod callable, Type lhsType, final boolean keepReturnValue) { StackValue value = gen(expression.getLeft()); if (keepReturnValue) { - value.dupReceiver(v, 0); + value.dupReceiver(v); } value.put(lhsType, v); genToJVMStack(expression.getRight()); @@ -1747,7 +1755,7 @@ public class ExpressionCodegen extends JetVisitor { } } StackValue value = genQualified(receiver, operand); - value.dupReceiver(v, 0); + value.dupReceiver(v); value.put(asmType, v); if (asmType == Type.LONG_TYPE) { //noinspection UnnecessaryBoxing @@ -1914,7 +1922,7 @@ public class ExpressionCodegen extends JetVisitor { } if(args.size() == 2) { - int sizeIndex = myMap.enterTemp(2); + int sizeIndex = myFrameMap.enterTemp(2); int indexIndex = sizeIndex+1; v.dup(); @@ -1946,7 +1954,7 @@ public class ExpressionCodegen extends JetVisitor { v.visitLabel(end); v.pop(); - myMap.leaveTemp(2); + myFrameMap.leaveTemp(2); } } @@ -1956,8 +1964,12 @@ public class ExpressionCodegen extends JetVisitor { JetType type = bindingContext.get(BindingContext.EXPRESSION_TYPE, array); final Type arrayType = type == null ? Type.VOID_TYPE : typeMapper.mapType(type); gen(array, arrayType); - generateArrayIndex(expression); - if (arrayType.getSort() == Type.ARRAY) { + final List indices = expression.getIndexExpressions(); + FunctionDescriptor operationDescriptor = (FunctionDescriptor) bindingContext.get(BindingContext.REFERENCE_TARGET, expression); + if (arrayType.getSort() == Type.ARRAY && indices.size() == 1 && operationDescriptor.getValueParameters().get(0).getOutType().equals(state.getStandardLibrary().getIntType())) { + for (JetExpression index : indices) { + gen(index, Type.INT_TYPE); + } if(state.getStandardLibrary().getArray().equals(type.getConstructor().getDeclarationDescriptor())) { JetType elementType = type.getArguments().get(0).getType(); Type notBoxed = typeMapper.mapType(elementType); @@ -1969,27 +1981,39 @@ public class ExpressionCodegen extends JetVisitor { } } else { - DeclarationDescriptor operationDescriptor = bindingContext.get(BindingContext.REFERENCE_TARGET, expression); - CallableMethod accessor = typeMapper.mapToCallableMethod((FunctionDescriptor) operationDescriptor, OwnerKind.IMPLEMENTATION); + CallableMethod accessor = typeMapper.mapToCallableMethod(operationDescriptor, OwnerKind.IMPLEMENTATION); boolean isGetter = accessor.getSignature().getName().equals("get"); + ResolvedCall resolvedSetCall = bindingContext.get(BindingContext.INDEXED_LVALUE_SET, expression); + FunctionDescriptor setterDescriptor = resolvedSetCall == null ? null : resolvedSetCall.getResultingDescriptor(); + CallableMethod setter = resolvedSetCall == null ? null : typeMapper.mapToCallableMethod(setterDescriptor, OwnerKind.IMPLEMENTATION); + + ResolvedCall resolvedGetCall = bindingContext.get(BindingContext.INDEXED_LVALUE_GET, expression); + FunctionDescriptor getterDescriptor = resolvedGetCall == null ? null : resolvedGetCall.getResultingDescriptor(); + CallableMethod getter = resolvedGetCall == null ? null : typeMapper.mapToCallableMethod(getterDescriptor, OwnerKind.IMPLEMENTATION); + + Type asmType; + Type[] argumentTypes = accessor.getSignature().getArgumentTypes(); + int index = 0; if(isGetter) { - ResolvedCall resolvedCall = bindingContext.get(BindingContext.INDEXED_LVALUE_SET, expression); - FunctionDescriptor setterDescriptor = resolvedCall == null ? null : resolvedCall.getResultingDescriptor(); - return StackValue.collectionElement( - accessor.getSignature().getReturnType(), - accessor, - setterDescriptor != null ? typeMapper.mapToCallableMethod(setterDescriptor, OwnerKind.IMPLEMENTATION) : null); + if(getterDescriptor.getReceiverParameter().exists()) { + index++; + } + asmType = accessor.getSignature().getReturnType(); } else { - ResolvedCall resolvedCall = bindingContext.get(BindingContext.INDEXED_LVALUE_GET, expression); - FunctionDescriptor getterDescriptor = resolvedCall == null ? null : resolvedCall.getResultingDescriptor(); - return StackValue.collectionElement( - accessor.getSignature().getArgumentTypes()[1], - getterDescriptor != null ? typeMapper.mapToCallableMethod(getterDescriptor, OwnerKind.IMPLEMENTATION) : null, - accessor); + if(setterDescriptor.getReceiverParameter().exists()) { + index++; + } + asmType = argumentTypes[argumentTypes.length-1]; } + + for (JetExpression jetExpression : expression.getIndexExpressions()) { + gen(jetExpression, argumentTypes[index]); + index++; + } + return StackValue.collectionElement(asmType, getter, setter, myFrameMap); } } @@ -2033,13 +2057,6 @@ public class ExpressionCodegen extends JetVisitor { } } - private void generateArrayIndex(JetArrayAccessExpression expression) { - final List indices = expression.getIndexExpressions(); - for (JetExpression index : indices) { - gen(index, Type.INT_TYPE); - } - } - @Override public StackValue visitThrowExpression(JetThrowExpression expression, StackValue receiver) { gen(expression.getThrownExpression(), JetTypeMapper.TYPE_OBJECT); @@ -2082,21 +2099,21 @@ public class ExpressionCodegen extends JetVisitor { VariableDescriptor descriptor = bindingContext.get(BindingContext.VALUE_PARAMETER, clause.getCatchParameter()); assert descriptor != null; Type descriptorType = typeMapper.mapType(descriptor.getOutType()); - myMap.enter(descriptor, 1); + myFrameMap.enter(descriptor, 1); int index = lookupLocal(descriptor); v.store(index, descriptorType); gen(clause.getCatchBody(), Type.VOID_TYPE); v.goTo(end); // TODO don't generate goto if there's no code following try/catch - myMap.leave(descriptor); + myFrameMap.leave(descriptor); v.visitTryCatchBlock(tryStart, tryEnd, clauseStart, descriptorType.getInternalName()); } if (finallyBlock != null) { Label finallyStart = new Label(); v.mark(finallyStart); - int index = myMap.enterTemp(); + int index = myFrameMap.enterTemp(); v.store(index, THROWABLE_TYPE); gen(finallyBlock.getFinalExpression(), Type.VOID_TYPE); @@ -2104,7 +2121,7 @@ public class ExpressionCodegen extends JetVisitor { v.load(index, THROWABLE_TYPE); v.athrow(); - myMap.leaveTemp(); + myFrameMap.leaveTemp(); v.visitTryCatchBlock(tryStart, tryEnd, finallyStart, null); } @@ -2159,7 +2176,7 @@ public class ExpressionCodegen extends JetVisitor { if (pattern instanceof JetTypePattern) { JetTypeReference typeReference = ((JetTypePattern) pattern).getTypeReference(); JetType jetType = bindingContext.get(BindingContext.TYPE, typeReference); - expressionToMatch.dupReceiver(v, 0); + expressionToMatch.dupReceiver(v); generateInstanceOf(expressionToMatch, jetType, false); StackValue value = StackValue.onStack(Type.BOOLEAN_TYPE); return negated ? StackValue.not(value) : value; @@ -2169,7 +2186,7 @@ public class ExpressionCodegen extends JetVisitor { } else if (pattern instanceof JetExpressionPattern) { final Type subjectType = expressionToMatch.type; - expressionToMatch.dupReceiver(v, 0); + expressionToMatch.dupReceiver(v); expressionToMatch.put(subjectType, v); JetExpression condExpression = ((JetExpressionPattern) pattern).getExpression(); Type condType = isNumberPrimitive(subjectType) ? expressionType(condExpression) : OBJECT_TYPE; @@ -2184,10 +2201,10 @@ public class ExpressionCodegen extends JetVisitor { final VariableDescriptor variableDescriptor = bindingContext.get(BindingContext.VARIABLE, var); assert variableDescriptor != null; final Type varType = typeMapper.mapType(variableDescriptor.getOutType()); - myMap.enter(variableDescriptor, varType.getSize()); - expressionToMatch.dupReceiver(v, 0); + myFrameMap.enter(variableDescriptor, varType.getSize()); + expressionToMatch.dupReceiver(v); expressionToMatch.put(varType, v); - final int varIndex = myMap.getIndex(variableDescriptor); + final int varIndex = myFrameMap.getIndex(variableDescriptor); v.store(varIndex, varType); return generateWhenCondition(varType, varIndex, ((JetBindingPattern) pattern).getCondition(), null); } @@ -2202,7 +2219,7 @@ public class ExpressionCodegen extends JetVisitor { Label lblFail = new Label(); Label lblDone = new Label(); - expressionToMatch.dupReceiver(v, 0); + expressionToMatch.dupReceiver(v); expressionToMatch.put(OBJECT_TYPE, v); v.dup(); final String tupleClassName = "jet/Tuple" + entries.size(); @@ -2384,7 +2401,7 @@ public class ExpressionCodegen extends JetVisitor { public StackValue visitWhenExpression(JetWhenExpression expression, StackValue receiver) { JetExpression expr = expression.getSubjectExpression(); final Type subjectType = expressionType(expr); - final int subjectLocal = myMap.enterTemp(subjectType.getSize()); + final int subjectLocal = myFrameMap.enterTemp(subjectType.getSize()); gen(expr, subjectType); v.store(subjectLocal, subjectType); @@ -2396,7 +2413,7 @@ public class ExpressionCodegen extends JetVisitor { v.mark(nextCondition); } nextCondition = new Label(); - FrameMap.Mark mark = myMap.mark(); + FrameMap.Mark mark = myFrameMap.mark(); Label thisEntry = new Label(); if (!whenEntry.isElse()) { final JetWhenCondition[] conditions = whenEntry.getConditions(); @@ -2424,7 +2441,7 @@ public class ExpressionCodegen extends JetVisitor { } v.mark(end); - myMap.leaveTemp(subjectType.getSize()); + myFrameMap.leaveTemp(subjectType.getSize()); return StackValue.onStack(expressionType(expression)); } diff --git a/compiler/backend/src/org/jetbrains/jet/codegen/FunctionCodegen.java b/compiler/backend/src/org/jetbrains/jet/codegen/FunctionCodegen.java index cd05790af27..f71f58aef92 100644 --- a/compiler/backend/src/org/jetbrains/jet/codegen/FunctionCodegen.java +++ b/compiler/backend/src/org/jetbrains/jet/codegen/FunctionCodegen.java @@ -81,9 +81,10 @@ public class FunctionCodegen { ExpressionCodegen codegen = new ExpressionCodegen(mv, frameMap, jvmSignature.getReturnType(), context, state); Type[] argTypes = jvmSignature.getArgumentTypes(); + int add = functionDescriptor.getReceiverParameter().exists() ? state.getTypeMapper().mapType(functionDescriptor.getReceiverParameter().getType()).getSize() : 0; for (int i = 0; i < paramDescrs.size(); i++) { ValueParameterDescriptor parameter = paramDescrs.get(i); - frameMap.enter(parameter, argTypes[i].getSize()); + frameMap.enter(parameter, argTypes[i+add].getSize()); } for (final TypeParameterDescriptor typeParameterDescriptor : typeParameters) { diff --git a/compiler/backend/src/org/jetbrains/jet/codegen/JetTypeMapper.java b/compiler/backend/src/org/jetbrains/jet/codegen/JetTypeMapper.java index 0d44f856737..ad1521696de 100644 --- a/compiler/backend/src/org/jetbrains/jet/codegen/JetTypeMapper.java +++ b/compiler/backend/src/org/jetbrains/jet/codegen/JetTypeMapper.java @@ -547,6 +547,9 @@ public class JetTypeMapper { } public CallableMethod mapToCallableMethod(FunctionDescriptor functionDescriptor, OwnerKind kind) { + if(functionDescriptor == null) + return null; + final DeclarationDescriptor functionParent = functionDescriptor.getContainingDeclaration(); final List valueParameterTypes = new ArrayList(); Method descriptor = mapSignature(functionDescriptor.getOriginal(), valueParameterTypes, kind); diff --git a/compiler/backend/src/org/jetbrains/jet/codegen/StackValue.java b/compiler/backend/src/org/jetbrains/jet/codegen/StackValue.java index 5b2f2488b08..7938e019941 100644 --- a/compiler/backend/src/org/jetbrains/jet/codegen/StackValue.java +++ b/compiler/backend/src/org/jetbrains/jet/codegen/StackValue.java @@ -38,7 +38,7 @@ public abstract class StackValue { throw new UnsupportedOperationException("cannot store to value " + this); } - public void dupReceiver(InstructionAdapter v, int below) { + public void dupReceiver(InstructionAdapter v) { } public void condJump(Label label, boolean jumpIfFalse, InstructionAdapter v) { @@ -84,8 +84,8 @@ public abstract class StackValue { return new ArrayElement(type, unbox); } - public static StackValue collectionElement(Type type, CallableMethod getter, CallableMethod setter) { - return new CollectionElement(type, getter, setter); + public static StackValue collectionElement(Type type, CallableMethod getter, CallableMethod setter, FrameMap frame) { + return new CollectionElement(type, getter, setter, frame); } public static StackValue field(Type type, String owner, String name, boolean isStatic) { @@ -456,24 +456,21 @@ public abstract class StackValue { } @Override - public void dupReceiver(InstructionAdapter v, int below) { - if (below == 1) { - v.dup2X1(); - } - else { - v.dup2(); // array and index - } + public void dupReceiver(InstructionAdapter v) { + v.dup2(); // array and index } } private static class CollectionElement extends StackValue { private final CallableMethod getter; private final CallableMethod setter; + private final FrameMap frame; - public CollectionElement(Type type, CallableMethod getter, CallableMethod setter) { + public CollectionElement(Type type, CallableMethod getter, CallableMethod setter, FrameMap frame) { super(type); this.getter = getter; this.setter = setter; + this.frame = frame; } @Override @@ -494,13 +491,70 @@ public abstract class StackValue { } @Override - public void dupReceiver(InstructionAdapter v, int below) { - if (below == 1) { - v.dup2X1(); - } - else { + public void dupReceiver(InstructionAdapter v) { + int size = calcSize(); + + if(size == 2) { v.dup2(); // collection and index } + else { + Method signature = getter.getSignature(); + Type[] argumentTypes = signature.getArgumentTypes(); + + int firstIndex = frame.enterTemp(); + int lastIndex = firstIndex; + frame.leaveTemp(); + + for(int i = argumentTypes.length-1; i >= 0; i--) { + int sz = argumentTypes[i].getSize(); + frame.enterTemp(sz); + lastIndex += sz; + v.store(lastIndex-sz, argumentTypes[i]); + } + + if(getter.getInvokeOpcode() != Opcodes.INVOKESTATIC) { + frame.enterTemp(); + lastIndex++; + v.store(lastIndex-1, JetTypeMapper.TYPE_OBJECT); + } + + firstIndex = lastIndex; + int curIndex = lastIndex; + if(getter.getInvokeOpcode() != Opcodes.INVOKESTATIC) { + v.load(curIndex-1, JetTypeMapper.TYPE_OBJECT); + curIndex--; + } + + for(int i = 0; i != argumentTypes.length; i++) { + int sz = argumentTypes[i].getSize(); + v.load(curIndex-sz, argumentTypes[i]); + curIndex -= sz; + } + + curIndex = firstIndex; + if(getter.getInvokeOpcode() != Opcodes.INVOKESTATIC) { + v.load(curIndex-1, JetTypeMapper.TYPE_OBJECT); + curIndex--; + } + + for(int i = 0; i != argumentTypes.length; i++) { + int sz = argumentTypes[i].getSize(); + v.load(curIndex-sz, argumentTypes[i]); + curIndex -= sz; + } + + frame.leaveTemp(size); + } + } + + private int calcSize() { + assert getter != null; + int size = getter.getInvokeOpcode() == Opcodes.INVOKESTATIC ? 0 : 1; + Method signature = getter.getSignature(); + Type[] argumentTypes = signature.getArgumentTypes(); + for(int i = 0; i != argumentTypes.length; ++i) + size += argumentTypes[i].getSize(); + return size; } } @@ -523,14 +577,9 @@ public abstract class StackValue { } @Override - public void dupReceiver(InstructionAdapter v, int below) { + public void dupReceiver(InstructionAdapter v) { if (!isStatic) { - if (below == 1) { - v.dupX1(); - } - else { - v.dup(); - } + v.dup(); } } @@ -557,7 +606,7 @@ public abstract class StackValue { } @Override - public void dupReceiver(InstructionAdapter v, int below) { + public void dupReceiver(InstructionAdapter v) { } @Override @@ -607,14 +656,9 @@ public abstract class StackValue { } @Override - public void dupReceiver(InstructionAdapter v, int below) { + public void dupReceiver(InstructionAdapter v) { if (!isStatic) { - if (below == 1) { - v.dupX1(); - } - else { - v.dup(); - } + v.dup(); } } } @@ -716,13 +760,8 @@ public abstract class StackValue { } @Override - public void dupReceiver(InstructionAdapter v, int below) { - if (below == 1) { - v.dupX1(); - } - else { - v.dup(); - } + public void dupReceiver(InstructionAdapter v) { + v.dup(); } @Override diff --git a/compiler/backend/src/org/jetbrains/jet/codegen/intrinsics/Increment.java b/compiler/backend/src/org/jetbrains/jet/codegen/intrinsics/Increment.java index dfb68c2fd42..8c199a571a3 100644 --- a/compiler/backend/src/org/jetbrains/jet/codegen/intrinsics/Increment.java +++ b/compiler/backend/src/org/jetbrains/jet/codegen/intrinsics/Increment.java @@ -32,7 +32,7 @@ public class Increment implements IntrinsicMethod { } } StackValue value = codegen.genQualified(receiver, operand); - value.dupReceiver(v, 0); + value. dupReceiver(v); value.put(expectedType, v); if (expectedType == Type.LONG_TYPE) { v.lconst(myDelta); diff --git a/compiler/tests/org/jetbrains/jet/codegen/ArrayGenTest.java b/compiler/tests/org/jetbrains/jet/codegen/ArrayGenTest.java index 6628d1d6358..de66903a8e9 100644 --- a/compiler/tests/org/jetbrains/jet/codegen/ArrayGenTest.java +++ b/compiler/tests/org/jetbrains/jet/codegen/ArrayGenTest.java @@ -107,4 +107,63 @@ public class ArrayGenTest extends CodegenTestCase { Method foo = generateFunction(); assertTrue((Integer)foo.invoke(null) == 12); } + + public void testCollectionAssignGetMultiIndex () throws Exception { + loadText("import java.util.ArrayList\n" + + "fun box() : String { val s = ArrayList(1); s.add(\"\"); s [1, -1] = \"5\"; s[2, -2] += \"7\"; return s[2,-2] }\n" + + "fun ArrayList.get(index1: Int, index2 : Int) = this[index1+index2]\n" + + "fun ArrayList.set(index1: Int, index2 : Int, elem: String) { this[index1+index2] = elem }\n"); + System.out.println(generateToText()); + Method foo = generateFunction("box"); + assertTrue(foo.invoke(null).equals("57")); + } + + public void testArrayGetAssignMultiIndex () throws Exception { + loadText( + "fun box() : String? { val s = Array(1,{ \"\" }); s [1, -1] = \"5\"; s[2, -2] += \"7\"; return s[-3,3] }\n" + + "fun Array.get(index1: Int, index2 : Int) = this[index1+index2]\n" + + "fun Array.set(index1: Int, index2 : Int, elem: String) { this[index1+index2] = elem\n }"); + System.out.println(generateToText()); + Method foo = generateFunction("box"); + assertTrue(foo.invoke(null).equals("57")); + } + + public void testCollectionGetMultiIndex () throws Exception { + loadText("import java.util.ArrayList\n" + + "fun box() : String { val s = ArrayList(1); s.add(\"\"); s [1, -1] = \"5\"; return s[2, -2] }\n" + + "fun ArrayList.get(index1: Int, index2 : Int) = this[index1+index2]\n" + + "fun ArrayList.set(index1: Int, index2 : Int, elem: String) { this[index1+index2] = elem }\n"); + System.out.println(generateToText()); + Method foo = generateFunction("box"); + assertTrue(foo.invoke(null).equals("5")); + } + + public void testArrayGetMultiIndex () throws Exception { + loadText( + "fun box() : String? { val s = Array(1,{ \"\" }); s [1, -1] = \"5\"; return s[-2, 2] }\n" + + "fun Array.get(index1: Int, index2 : Int) = this[index1+index2]\n" + + "fun Array.set(index1: Int, index2 : Int, elem: String) { this[index1+index2] = elem\n }"); + System.out.println(generateToText()); + Method foo = generateFunction("box"); + assertTrue(foo.invoke(null).equals("5")); + } + + public void testMap () throws Exception { + loadText( + "fun box() : Int? { val s = java.util.HashMap(); s[\"239\"] = 239; return s[\"239\"] }\n" + + "fun java.util.HashMap.set(index: String, elem: Int?) { this.put(index, elem) }"); + System.out.println(generateToText()); + Method foo = generateFunction("box"); + assertTrue((Integer)foo.invoke(null) == 239); + } + + public void testLongDouble () throws Exception { + loadText( + "fun box() : Int { var l = IntArray(1); l[0.lng] = 4; l[0.lng] += 6; return l[0.lng];}\n" + + "fun IntArray.set(index: Long, elem: Int) { this[index.int] = elem }\n" + + "fun IntArray.get(index: Long) = this[index.int]"); + System.out.println(generateToText()); + Method foo = generateFunction("box"); + assertTrue((Integer)foo.invoke(null) == 10); + } } From 7d74443e1e812a65ff8b782486385edcb1d8448f Mon Sep 17 00:00:00 2001 From: Alex Tkachman Date: Thu, 3 Nov 2011 00:17:16 +0100 Subject: [PATCH 08/15] KT-426 soft refs removed in case of closure capturing nothing --- .../jetbrains/jet/codegen/ClosureCodegen.java | 32 ++++--------------- 1 file changed, 7 insertions(+), 25 deletions(-) diff --git a/compiler/backend/src/org/jetbrains/jet/codegen/ClosureCodegen.java b/compiler/backend/src/org/jetbrains/jet/codegen/ClosureCodegen.java index fa277df481e..33eaf4ec4e0 100644 --- a/compiler/backend/src/org/jetbrains/jet/codegen/ClosureCodegen.java +++ b/compiler/backend/src/org/jetbrains/jet/codegen/ClosureCodegen.java @@ -104,40 +104,22 @@ public class ClosureCodegen extends FunctionOrClosureCodegen { } private void generateConstInstance(JetFunctionLiteralExpression fun) { - cv.newField(fun, ACC_PRIVATE | ACC_STATIC, "$instance", "Ljava/lang/ref/SoftReference;", null, null); + String classDescr = "L" + name + ";"; + cv.newField(fun, ACC_PRIVATE | ACC_STATIC, "$instance", classDescr, null, null); - MethodVisitor mv = cv.newMethod(fun, ACC_PUBLIC | ACC_STATIC, "$getInstance", "()L" + name + ";", null, new String[0]); + MethodVisitor mv = cv.newMethod(fun, ACC_PUBLIC | ACC_STATIC, "$getInstance", "()" + classDescr, null, new String[0]); mv.visitCode(); - mv.visitFieldInsn(GETSTATIC, name, "$instance", "Ljava/lang/ref/SoftReference;"); + mv.visitFieldInsn(GETSTATIC, name, "$instance", classDescr); mv.visitInsn(DUP); - Label makeNew = new Label(); - mv.visitJumpInsn(IFNULL, makeNew); - - mv.visitMethodInsn(INVOKEVIRTUAL, "java/lang/ref/SoftReference", "get", "()Ljava/lang/Object;"); - mv.visitInsn(DUP); - Label ret = new Label(); - mv.visitJumpInsn(IFNULL, makeNew); - mv.visitTypeInsn(CHECKCAST, name); - mv.visitJumpInsn(GOTO, ret); + mv.visitJumpInsn(IFNONNULL, ret); - mv.visitLabel(makeNew); mv.visitInsn(POP); - - mv.visitTypeInsn(NEW, "java/lang/ref/SoftReference"); - mv.visitInsn(DUP); - mv.visitTypeInsn(NEW, name); - mv.visitInsn(DUP); - mv.visitVarInsn(ASTORE, 0); - mv.visitInsn(DUP); mv.visitMethodInsn(INVOKESPECIAL, name, "", "()V"); - - mv.visitMethodInsn(INVOKESPECIAL, "java/lang/ref/SoftReference", "", "(Ljava/lang/Object;)V"); - mv.visitFieldInsn(PUTSTATIC, name, "$instance", "Ljava/lang/ref/SoftReference;"); - - mv.visitVarInsn(ALOAD, 0); + mv.visitInsn(DUP); + mv.visitFieldInsn(PUTSTATIC, name, "$instance", classDescr); mv.visitLabel(ret); mv.visitInsn(ARETURN); From 970f66fc7cd9c00014647fc78a713c5bd2b2f966 Mon Sep 17 00:00:00 2001 From: Stepan Koltsov Date: Thu, 3 Nov 2011 12:28:37 +0400 Subject: [PATCH 09/15] ignore my settings --- .gitignore | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/.gitignore b/.gitignore index a8c12b02ece..0be1843eb48 100644 --- a/.gitignore +++ b/.gitignore @@ -3,3 +3,7 @@ examples/.idea/dictionaries examples/.idea/workspace.xml confluence/target confluence/target +out +.idea/dictionaries/yozh.xml +.idea/codeStyleSettings.xml +.idea/workspace.xml From f530dcb571b3a4d85cab87cd76e351cba0b19199 Mon Sep 17 00:00:00 2001 From: Andrey Breslav Date: Thu, 3 Nov 2011 13:52:40 +0300 Subject: [PATCH 10/15] A stub for standard library --- stdlib/ktSrc/StandardLibrary.kt | 5 +++++ 1 file changed, 5 insertions(+) create mode 100644 stdlib/ktSrc/StandardLibrary.kt diff --git a/stdlib/ktSrc/StandardLibrary.kt b/stdlib/ktSrc/StandardLibrary.kt new file mode 100644 index 00000000000..4ccd6b13838 --- /dev/null +++ b/stdlib/ktSrc/StandardLibrary.kt @@ -0,0 +1,5 @@ +namespace std + +fun println(message : Any?) { + System.out?.println(message) +} \ No newline at end of file From 9170d5c5352e6eb0a16e7dcbfe29ae796fdf2bf7 Mon Sep 17 00:00:00 2001 From: Andrey Breslav Date: Thu, 3 Nov 2011 14:35:30 +0300 Subject: [PATCH 11/15] IO primitives --- stdlib/ktSrc/StandardLibrary.kt | 36 ++++++++++++++++++++++++++++++++- 1 file changed, 35 insertions(+), 1 deletion(-) diff --git a/stdlib/ktSrc/StandardLibrary.kt b/stdlib/ktSrc/StandardLibrary.kt index 4ccd6b13838..bd0fab6b7d9 100644 --- a/stdlib/ktSrc/StandardLibrary.kt +++ b/stdlib/ktSrc/StandardLibrary.kt @@ -1,5 +1,39 @@ namespace std -fun println(message : Any?) { +namespace io { + import java.io.* + + fun print(message : Any?) { System.out?.print(message) } + fun print(message : Int) { System.out?.print(message) } + fun print(message : Long) { System.out?.print(message) } + fun print(message : Byte) { System.out?.print(message) } + fun print(message : Short) { System.out?.print(message) } + fun print(message : Char) { System.out?.print(message) } + fun print(message : Boolean) { System.out?.print(message) } + fun print(message : Float) { System.out?.print(message) } + fun print(message : Double) { System.out?.print(message) } + + fun println(message : Any?) { System.out?.println(message) + } + + fun println(message : Int) { System.out?.println(message) } + fun println(message : Long) { System.out?.println(message) } + fun println(message : Byte) { System.out?.println(message) } + fun println(message : Short) { System.out?.println(message) } + fun println(message : Char) { System.out?.println(message) } + fun println(message : Boolean) { System.out?.println(message) } + fun println(message : Float) { System.out?.println(message) } + fun println(message : Double) { System.out?.println(message) } + + private var systemIn : InputStream? = null // Unfortunately, System.in may change + private var stdin : BufferedReader? = null // This may introduce leaks of system.in objects... + + fun readLine() : String? { + if (stdin == null || systemIn != System.`in`) { + stdin = java.io.BufferedReader(java.io.InputStreamReader(System.`in`)) + systemIn = System.`in` + } + return stdin?.readLine() + } } \ No newline at end of file From 6fcf0729f3a00159b8147b486946da8ee95fbc92 Mon Sep 17 00:00:00 2001 From: Andrey Breslav Date: Thu, 3 Nov 2011 14:41:20 +0300 Subject: [PATCH 12/15] Standard IO functions --- stdlib/ktSrc/StandardLibrary.kt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/stdlib/ktSrc/StandardLibrary.kt b/stdlib/ktSrc/StandardLibrary.kt index bd0fab6b7d9..85c09473979 100644 --- a/stdlib/ktSrc/StandardLibrary.kt +++ b/stdlib/ktSrc/StandardLibrary.kt @@ -26,7 +26,7 @@ namespace io { fun println(message : Float) { System.out?.println(message) } fun println(message : Double) { System.out?.println(message) } - private var systemIn : InputStream? = null // Unfortunately, System.in may change + private var systemIn : InputStream? = null // Unfortunately, System.in may change Yt pf xn private var stdin : BufferedReader? = null // This may introduce leaks of system.in objects... fun readLine() : String? { From b4929b7091b55a3ddeaccb5a62ce74ab2dffbb56 Mon Sep 17 00:00:00 2001 From: Alex Tkachman Date: Thu, 3 Nov 2011 13:01:29 +0100 Subject: [PATCH 13/15] tweak of the test --- compiler/tests/org/jetbrains/jet/codegen/NamespaceGenTest.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/compiler/tests/org/jetbrains/jet/codegen/NamespaceGenTest.java b/compiler/tests/org/jetbrains/jet/codegen/NamespaceGenTest.java index ca762e92701..55bae64f839 100644 --- a/compiler/tests/org/jetbrains/jet/codegen/NamespaceGenTest.java +++ b/compiler/tests/org/jetbrains/jet/codegen/NamespaceGenTest.java @@ -366,7 +366,7 @@ public class NamespaceGenTest extends CodegenTestCase { } public void testArrayAugAssignLong() throws Exception { - loadText("fun foo(c: LongArray) { c[0] *= 2 }"); + loadText("fun foo(c: LongArray) { c[0] *= 2.lng }"); System.out.println(generateToText()); final Method main = generateFunction(); long[] data = new long[] { 5 }; From 95a2afcd1987974ec4a5a31aaf622ebb33cb5c93 Mon Sep 17 00:00:00 2001 From: Andrey Breslav Date: Thu, 3 Nov 2011 17:37:24 +0300 Subject: [PATCH 14/15] Support for function-valued expressions --- .../descriptors/FunctionDescriptorUtil.java | 9 ++++ .../VariableAsFunctionDescriptor.java | 6 +-- .../jet/lang/diagnostics/Errors.java | 1 + .../jet/lang/resolve/calls/CallResolver.java | 34 ++++++++++++- .../quick/ExtensionsCalledOnSuper.jet | 2 +- .../quick/FunctionCalleeExpressions.jet | 50 +++++++++++++++++++ .../quick/NamedArgumentsAndDefaultValues.jet | 6 +-- stdlib/ktSrc/StandardLibrary.kt | 2 +- 8 files changed, 98 insertions(+), 12 deletions(-) create mode 100644 compiler/testData/checkerWithErrorTypes/quick/FunctionCalleeExpressions.jet diff --git a/compiler/frontend/src/org/jetbrains/jet/lang/descriptors/FunctionDescriptorUtil.java b/compiler/frontend/src/org/jetbrains/jet/lang/descriptors/FunctionDescriptorUtil.java index cb193b40b69..32e19f286de 100644 --- a/compiler/frontend/src/org/jetbrains/jet/lang/descriptors/FunctionDescriptorUtil.java +++ b/compiler/frontend/src/org/jetbrains/jet/lang/descriptors/FunctionDescriptorUtil.java @@ -83,4 +83,13 @@ public class FunctionDescriptorUtil { return parameterScope; } + public static void initializeFromFunctionType(@NotNull FunctionDescriptorImpl functionDescriptor, @NotNull JetType functionType) { + assert JetStandardClasses.isFunctionType(functionType); + functionDescriptor.initialize(JetStandardClasses.getReceiverType(functionType), + ReceiverDescriptor.NO_RECEIVER, + Collections.emptyList(), + JetStandardClasses.getValueParameters(functionDescriptor, functionType), + JetStandardClasses.getReturnType(functionType), + Modality.FINAL, Visibility.LOCAL); + } } diff --git a/compiler/frontend/src/org/jetbrains/jet/lang/descriptors/VariableAsFunctionDescriptor.java b/compiler/frontend/src/org/jetbrains/jet/lang/descriptors/VariableAsFunctionDescriptor.java index 25b713cd607..fb9b6fcabae 100644 --- a/compiler/frontend/src/org/jetbrains/jet/lang/descriptors/VariableAsFunctionDescriptor.java +++ b/compiler/frontend/src/org/jetbrains/jet/lang/descriptors/VariableAsFunctionDescriptor.java @@ -2,8 +2,6 @@ package org.jetbrains.jet.lang.descriptors; import org.jetbrains.annotations.NotNull; import org.jetbrains.jet.lang.descriptors.annotations.AnnotationDescriptor; -import org.jetbrains.jet.lang.resolve.scopes.receivers.ReceiverDescriptor; -import org.jetbrains.jet.lang.types.JetStandardClasses; import org.jetbrains.jet.lang.types.JetType; import java.util.Collections; @@ -15,9 +13,8 @@ public class VariableAsFunctionDescriptor extends FunctionDescriptorImpl { public static VariableAsFunctionDescriptor create(@NotNull VariableDescriptor variableDescriptor) { JetType outType = variableDescriptor.getOutType(); assert outType != null; - assert JetStandardClasses.isFunctionType(outType); VariableAsFunctionDescriptor result = new VariableAsFunctionDescriptor(variableDescriptor); - result.initialize(JetStandardClasses.getReceiverType(outType), ReceiverDescriptor.NO_RECEIVER, Collections.emptyList(), JetStandardClasses.getValueParameters(result, outType), JetStandardClasses.getReturnType(outType), Modality.FINAL, Visibility.LOCAL); + FunctionDescriptorUtil.initializeFromFunctionType(result, outType); return result; } @@ -25,7 +22,6 @@ public class VariableAsFunctionDescriptor extends FunctionDescriptorImpl { private VariableAsFunctionDescriptor(VariableDescriptor variableDescriptor) { super(variableDescriptor.getContainingDeclaration(), Collections.emptyList(), variableDescriptor.getName()); -// super(variableDescriptor.getContainingDeclaration(), Collections.emptyList(), variableDescriptor.getName()); this.variableDescriptor = variableDescriptor; } diff --git a/compiler/frontend/src/org/jetbrains/jet/lang/diagnostics/Errors.java b/compiler/frontend/src/org/jetbrains/jet/lang/diagnostics/Errors.java index 11680129eb7..fbec7d4bf64 100644 --- a/compiler/frontend/src/org/jetbrains/jet/lang/diagnostics/Errors.java +++ b/compiler/frontend/src/org/jetbrains/jet/lang/diagnostics/Errors.java @@ -196,6 +196,7 @@ public interface Errors { AmbiguousDescriptorDiagnosticFactory ITERATOR_AMBIGUITY = AmbiguousDescriptorDiagnosticFactory.create("Method 'iterator()' is ambiguous for this expression: {0}"); ParameterizedDiagnosticFactory1 COMPARE_TO_TYPE_MISMATCH = ParameterizedDiagnosticFactory1.create(ERROR, "compareTo() must return Int, but returns {0}"); + ParameterizedDiagnosticFactory1 CALLEE_NOT_A_FUNCTION = ParameterizedDiagnosticFactory1.create(ERROR, "Expecting a function type, but found {0}"); SimpleDiagnosticFactory RETURN_IN_FUNCTION_WITH_EXPRESSION_BODY = SimpleDiagnosticFactory.create(ERROR, "Returns are not allowed for functions with expression body. Use block body in '{...}'"); SimpleDiagnosticFactory NO_RETURN_IN_FUNCTION_WITH_BLOCK_BODY = SimpleDiagnosticFactory.create(ERROR, "A 'return' expression required in a function with a block body ('{...}')"); diff --git a/compiler/frontend/src/org/jetbrains/jet/lang/resolve/calls/CallResolver.java b/compiler/frontend/src/org/jetbrains/jet/lang/resolve/calls/CallResolver.java index f722e29c6b2..5341725067d 100644 --- a/compiler/frontend/src/org/jetbrains/jet/lang/resolve/calls/CallResolver.java +++ b/compiler/frontend/src/org/jetbrains/jet/lang/resolve/calls/CallResolver.java @@ -9,6 +9,7 @@ import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; import org.jetbrains.jet.lang.JetSemanticServices; import org.jetbrains.jet.lang.descriptors.*; +import org.jetbrains.jet.lang.descriptors.annotations.AnnotationDescriptor; import org.jetbrains.jet.lang.psi.*; import org.jetbrains.jet.lang.resolve.*; import org.jetbrains.jet.lang.resolve.calls.autocasts.AutoCastServiceImpl; @@ -173,8 +174,29 @@ public class CallResolver { } prioritizedTasks = Collections.singletonList(new ResolutionTask(ResolvedCallImpl.convertCollection(constructors), call, DataFlowInfo.EMPTY)); } + else if (calleeExpression != null) { + // Here we handle the case where the callee expression must be something of type function, e.g. (foo.bar())(1, 2) + ExpressionTypingServices typingServices = new ExpressionTypingServices(semanticServices, trace); + JetType calleeType = typingServices.safeGetType(scope, calleeExpression, NO_EXPECTED_TYPE);// We are actually expecting a function, but there seems to be no easy way of expressing this + + if (!JetStandardClasses.isFunctionType(calleeType)) { + checkTypesWithNoCallee(trace, scope, call); + if (!ErrorUtils.isErrorType(calleeType)) { + trace.report(CALLEE_NOT_A_FUNCTION.on(calleeExpression, calleeType)); + } + return null; + } + + FunctionDescriptorImpl functionDescriptor = new FunctionDescriptorImpl(scope.getContainingDeclaration(), Collections.emptyList(), "for expression " + calleeExpression.getText()); + FunctionDescriptorUtil.initializeFromFunctionType(functionDescriptor, calleeType); + ResolvedCallImpl resolvedCall = ResolvedCallImpl.create(functionDescriptor); + prioritizedTasks = Collections.singletonList(new ResolutionTask( + Collections.singleton(resolvedCall), call, dataFlowInfo)); + functionReference = new JetReferenceExpression(calleeExpression.getNode()) { + }; + } else { - trace.report(UNSUPPORTED.on(call.getCallNode(), "Type argument inference is not supported for this callee: " + calleeExpression)); + checkTypesWithNoCallee(trace, scope, call); return null; } } @@ -233,7 +255,15 @@ public class CallResolver { @Override public void noValueForParameter(@NotNull BindingTrace trace, @NotNull ValueParameterDescriptor valueParameter) { - trace.report(NO_VALUE_FOR_PARAMETER.on(reference, valueParameter)); + PsiElement reportOn; + JetValueArgumentList valueArgumentList = call.getValueArgumentList(); + if (valueArgumentList != null) { + reportOn = valueArgumentList; + } + else { + reportOn = reference; + } + trace.report(NO_VALUE_FOR_PARAMETER.on(reportOn, valueParameter)); } @Override diff --git a/compiler/testData/checkerWithErrorTypes/quick/ExtensionsCalledOnSuper.jet b/compiler/testData/checkerWithErrorTypes/quick/ExtensionsCalledOnSuper.jet index fe072bcc632..775ec9bef9e 100644 --- a/compiler/testData/checkerWithErrorTypes/quick/ExtensionsCalledOnSuper.jet +++ b/compiler/testData/checkerWithErrorTypes/quick/ExtensionsCalledOnSuper.jet @@ -16,6 +16,6 @@ class C : T { super.foo() // OK super.bar() // Error super.buzz() // OK, resolved to a member - super.buzz1() // Resolved to a member, but error: no parameter passed where required + super.buzz1() // Resolved to a member, but error: no parameter passed where required } } \ No newline at end of file diff --git a/compiler/testData/checkerWithErrorTypes/quick/FunctionCalleeExpressions.jet b/compiler/testData/checkerWithErrorTypes/quick/FunctionCalleeExpressions.jet new file mode 100644 index 00000000000..581493762d3 --- /dev/null +++ b/compiler/testData/checkerWithErrorTypes/quick/FunctionCalleeExpressions.jet @@ -0,0 +1,50 @@ +namespace foo + +fun Any.foo() : fun() : Unit { + return {} +} + +fun Any.foo1() : fun(i : Int) : Unit { + return {} +} + +fun foo2() : fun(i : fun()) : Unit { + return {} +} + +fun fooT1(t : T) : fun() : T { + return {t} +} + +fun fooT2() : fun(t : T) : T { + return {it} +} + +fun main(args : Array) { + args.foo()() + args.foo1()() + a.foo1()() + a.foo1()(a) + + args.foo1()(1) + args.foo1()("1") + a.foo1()("1") + a.foo1()(a) + + foo2()({}) + foo2(){} + (foo2()){} + (foo2()){x => } + foo2()({x => }) + + val a = fooT1(1)() + a : Int + + val b = fooT2()(1) + b : Int + fooT2()(1) // : Any? + + 1() + 1{} + 1(){} +} \ No newline at end of file diff --git a/compiler/testData/checkerWithErrorTypes/quick/NamedArgumentsAndDefaultValues.jet b/compiler/testData/checkerWithErrorTypes/quick/NamedArgumentsAndDefaultValues.jet index 9e75a3ae821..f1d42c6b60d 100644 --- a/compiler/testData/checkerWithErrorTypes/quick/NamedArgumentsAndDefaultValues.jet +++ b/compiler/testData/checkerWithErrorTypes/quick/NamedArgumentsAndDefaultValues.jet @@ -14,10 +14,10 @@ fun test() { foo(1, "", "") bar(z = "") - bar() - bar("") + bar() + bar("") bar(1, 1, "") bar(1, 1, "") bar(1, z = "") - bar(1, zz = "", zz.foo) + bar(1, zz = "", zz.foo) } \ No newline at end of file diff --git a/stdlib/ktSrc/StandardLibrary.kt b/stdlib/ktSrc/StandardLibrary.kt index 85c09473979..bd0fab6b7d9 100644 --- a/stdlib/ktSrc/StandardLibrary.kt +++ b/stdlib/ktSrc/StandardLibrary.kt @@ -26,7 +26,7 @@ namespace io { fun println(message : Float) { System.out?.println(message) } fun println(message : Double) { System.out?.println(message) } - private var systemIn : InputStream? = null // Unfortunately, System.in may change Yt pf xn + private var systemIn : InputStream? = null // Unfortunately, System.in may change private var stdin : BufferedReader? = null // This may introduce leaks of system.in objects... fun readLine() : String? { From 84b216b88cf8e7cdbd9296fec1031e40dafb9039 Mon Sep 17 00:00:00 2001 From: Dmitry Jemerov Date: Thu, 3 Nov 2011 18:07:23 +0100 Subject: [PATCH 15/15] pull out code out of KotlinCompiler and into a testable CompileEnvironment; smoke test for CompileEnvironment --- .../jet/compiler/CompileEnvironment.java | 311 ++++++++++++++++++ .../compiler/CompileEnvironmentException.java | 18 + .../jet/compiler}/CompileSession.java | 11 +- .../jet/compiler}/ErrorCollector.java | 9 +- .../org/jetbrains/jet/cli/KotlinCompiler.java | 282 +--------------- compiler/testData/compiler/smoke/Smoke.kt | 4 + compiler/testData/compiler/smoke/Smoke.kts | 8 + .../jet/compiler/CompileEnvironmentTest.java | 25 ++ stdlib/ktSrc/ModuleBuilder.kt | 16 +- stdlib/src/jet/modules/IModuleBuilder.java | 1 + 10 files changed, 407 insertions(+), 278 deletions(-) create mode 100644 compiler/backend/src/org/jetbrains/jet/compiler/CompileEnvironment.java create mode 100644 compiler/backend/src/org/jetbrains/jet/compiler/CompileEnvironmentException.java rename compiler/{cli/src/org/jetbrains/jet/cli => backend/src/org/jetbrains/jet/compiler}/CompileSession.java (93%) rename compiler/{cli/src/org/jetbrains/jet/cli => backend/src/org/jetbrains/jet/compiler}/ErrorCollector.java (84%) create mode 100644 compiler/testData/compiler/smoke/Smoke.kt create mode 100644 compiler/testData/compiler/smoke/Smoke.kts create mode 100644 compiler/tests/org/jetbrains/jet/compiler/CompileEnvironmentTest.java diff --git a/compiler/backend/src/org/jetbrains/jet/compiler/CompileEnvironment.java b/compiler/backend/src/org/jetbrains/jet/compiler/CompileEnvironment.java new file mode 100644 index 00000000000..607bad3bd4e --- /dev/null +++ b/compiler/backend/src/org/jetbrains/jet/compiler/CompileEnvironment.java @@ -0,0 +1,311 @@ +package org.jetbrains.jet.compiler; + +import com.intellij.openapi.Disposable; +import com.intellij.openapi.application.PathManager; +import com.intellij.openapi.util.Disposer; +import com.intellij.openapi.util.io.FileUtil; +import com.intellij.openapi.vfs.VirtualFile; +import com.intellij.util.Processor; +import jet.modules.IModuleBuilder; +import jet.modules.IModuleSetBuilder; +import org.jetbrains.jet.JetCoreEnvironment; +import org.jetbrains.jet.codegen.ClassFileFactory; +import org.jetbrains.jet.codegen.GeneratedClassLoader; +import org.jetbrains.jet.lang.psi.JetNamespace; +import org.jetbrains.jet.plugin.JetMainDetector; + +import java.io.*; +import java.lang.reflect.Method; +import java.net.URL; +import java.net.URLClassLoader; +import java.util.List; +import java.util.jar.*; + +/** + * The environment for compiling a bunch of source files or + * + * @author yole + */ +public class CompileEnvironment { + private JetCoreEnvironment myEnvironment; + private final Disposable myRootDisposable; + private PrintStream myErrorStream = System.out; + + public CompileEnvironment() { + myRootDisposable = new Disposable() { + @Override + public void dispose() { + } + }; + myEnvironment = new JetCoreEnvironment(myRootDisposable); + } + + public void setMyErrorStream(PrintStream errorStream) { + myErrorStream = errorStream; + } + + public void dispose() { + Disposer.dispose(myRootDisposable); + } + + public boolean initializeKotlinRuntime() { + final File unpackedRuntimePath = getUnpackedRuntimePath(); + if (unpackedRuntimePath != null) { + myEnvironment.addToClasspath(unpackedRuntimePath); + } + else { + final File runtimeJarPath = getRuntimeJarPath(); + if (runtimeJarPath != null && runtimeJarPath.exists()) { + myEnvironment.addToClasspath(runtimeJarPath); + } + else { + return false; + } + } + return true; + } + + public static File getUnpackedRuntimePath() { + URL url = CompileEnvironment.class.getClassLoader().getResource("jet/JetObject.class"); + if (url != null && url.getProtocol().equals("file")) { + return new File(url.getPath()).getParentFile().getParentFile(); + } + return null; + } + + public static File getRuntimeJarPath() { + URL url = CompileEnvironment.class.getClassLoader().getResource("jet/JetObject.class"); + if (url != null && url.getProtocol().equals("jar")) { + String path = url.getPath(); + return new File(path.substring(path.indexOf(":") + 1, path.indexOf("!/"))); + } + return null; + } + + public void setJavaRuntime(File rtJarPath) { + myEnvironment.addToClasspath(rtJarPath); + } + + public static File findActiveRtJar() { + ClassLoader systemClassLoader = ClassLoader.getSystemClassLoader(); + if (systemClassLoader instanceof URLClassLoader) { + URLClassLoader loader = (URLClassLoader) systemClassLoader; + for (URL url: loader.getURLs()) { + if("file".equals(url.getProtocol())) { + if(url.getFile().endsWith("/lib/rt.jar")) { + return new File(url.getFile()); + } + if(url.getFile().endsWith("/Classes/classes.jar")) { + return new File(url.getFile()).getAbsoluteFile(); + } + } + } + } + return null; + } + + public void compileModuleScript(String moduleFile) { + final IModuleSetBuilder moduleSetBuilder = loadModuleScript(moduleFile); + if (moduleSetBuilder == null) { + return; + } + + final String directory = new File(moduleFile).getParent(); + for (IModuleBuilder moduleBuilder : moduleSetBuilder.getModules()) { + ClassFileFactory moduleFactory = compileModule(moduleBuilder, directory); + writeToJar(moduleFactory, new File(directory, moduleBuilder.getModuleName() + ".jar").getPath(), null, true); + } + } + + public IModuleSetBuilder loadModuleScript(String moduleFile) { + CompileSession scriptCompileSession = new CompileSession(myEnvironment); + scriptCompileSession.addSources(moduleFile); + + URL url = CompileEnvironment.class.getClassLoader().getResource("ModuleBuilder.kt"); + if (url != null) { + String path = url.getPath(); + if (path.startsWith("file:")) { + path = path.substring(5); + } + final VirtualFile vFile = myEnvironment.getJarFileSystem().findFileByPath(path); + if (vFile == null) { + throw new CompileEnvironmentException("Couldn't load ModuleBuilder.kt from runtime jar: "+ url); + } + scriptCompileSession.addSources(vFile); + } + else { + // building from source + final String homeDirectory = getHomeDirectory(); + final File file = new File(homeDirectory, "stdlib/ktSrc/ModuleBuilder.kt"); + scriptCompileSession.addSources(myEnvironment.getLocalFileSystem().findFileByPath(file.getPath())); + } + + if (!scriptCompileSession.analyze(myErrorStream)) { + return null; + } + final ClassFileFactory factory = scriptCompileSession.generate(); + + return runDefineModules(moduleFile, factory); + } + + private static IModuleSetBuilder runDefineModules(String moduleFile, ClassFileFactory factory) { + GeneratedClassLoader loader = new GeneratedClassLoader(factory); + try { + Class moduleSetBuilderClass = loader.loadClass("kotlin.modules.ModuleSetBuilder"); + final IModuleSetBuilder moduleSetBuilder = (IModuleSetBuilder) moduleSetBuilderClass.newInstance(); + + Class namespaceClass = loader.loadClass("namespace"); + final Method[] methods = namespaceClass.getMethods(); + boolean modulesDefined = false; + for (Method method : methods) { + if (method.getName().equals("defineModules")) { + method.invoke(null, moduleSetBuilder); + modulesDefined = true; + break; + } + } + if (!modulesDefined) { + throw new CompileEnvironmentException("Module script " + moduleFile + " must define a defineModules() method"); + } + return moduleSetBuilder; + } catch (Exception e) { + throw new CompileEnvironmentException(e); + } + } + + public ClassFileFactory compileModule(IModuleBuilder moduleBuilder, String directory) { + CompileSession moduleCompileSession = new CompileSession(myEnvironment); + for (String sourceFile : moduleBuilder.getSourceFiles()) { + moduleCompileSession.addSources(new File(directory, sourceFile).getPath()); + } + for (String classpathRoot : moduleBuilder.getClasspathRoots()) { + myEnvironment.addToClasspath(new File(classpathRoot)); + } + if (!moduleCompileSession.analyze(myErrorStream)) { + return null; + } + return moduleCompileSession.generate(); + } + + private static String getHomeDirectory() { + return new File(PathManager.getResourceRoot(CompileEnvironment.class, "/org/jetbrains/jet/compiler/CompileEnvironment.class")).getParentFile().getParentFile().getParent(); + } + + public static void writeToJar(ClassFileFactory factory, String jar, String mainClass, boolean includeRuntime) { + try { + Manifest manifest = new Manifest(); + final Attributes mainAttributes = manifest.getMainAttributes(); + mainAttributes.putValue("Manifest-Version", "1.0"); + mainAttributes.putValue("Created-By", "JetBrains Kotlin"); + if (mainClass != null) { + mainAttributes.putValue("Main-Class", mainClass); + } + FileOutputStream fos = new FileOutputStream(jar); + JarOutputStream stream = new JarOutputStream(fos, manifest); + try { + for (String file : factory.files()) { + stream.putNextEntry(new JarEntry(file)); + stream.write(factory.asBytes(file)); + } + if (includeRuntime) { + writeRuntimeToJar(stream); + } + } + finally { + stream.close(); + fos.close(); + } + + } catch (IOException e) { + throw new CompileEnvironmentException("Failed to generate jar file", e); + } + } + + private static void writeRuntimeToJar(final JarOutputStream stream) throws IOException { + final File unpackedRuntimePath = getUnpackedRuntimePath(); + if (unpackedRuntimePath != null) { + FileUtil.processFilesRecursively(unpackedRuntimePath, new Processor() { + @Override + public boolean process(File file) { + if (file.isDirectory()) return true; + final String relativePath = FileUtil.getRelativePath(unpackedRuntimePath, file); + try { + stream.putNextEntry(new JarEntry(FileUtil.toSystemIndependentName(relativePath))); + FileInputStream fis = new FileInputStream(file); + try { + FileUtil.copy(fis, stream); + } finally { + fis.close(); + } + } catch (IOException e) { + throw new RuntimeException(e); + } + return true; + } + }); + } + else { + File runtimeJarPath = getRuntimeJarPath(); + if (runtimeJarPath != null) { + JarInputStream jis = new JarInputStream(new FileInputStream(runtimeJarPath)); + try { + while (true) { + JarEntry e = jis.getNextJarEntry(); + if (e == null) { + break; + } + if (FileUtil.getExtension(e.getName()).equals("class")) { + stream.putNextEntry(e); + FileUtil.copy(jis, stream); + } + } + } finally { + jis.close(); + } + } + else { + throw new CompileEnvironmentException("Couldn't find runtime library"); + } + } + } + + public void compileBunchOfSources(String sourceFileOrDir, String jar, String outputDir) { + CompileSession session = new CompileSession(myEnvironment); + session.addSources(sourceFileOrDir); + + String mainClass = null; + for (JetNamespace namespace : session.getSourceFileNamespaces()) { + if (JetMainDetector.hasMain(namespace.getDeclarations())) { + mainClass = namespace.getFQName() + ".namespace"; + break; + } + } + if (!session.analyze(myErrorStream)) { + return; + } + + ClassFileFactory factory = session.generate(); + if (jar != null) { + writeToJar(factory, jar, mainClass, true); + } + else if (outputDir != null) { + writeToOutputDirectory(factory, outputDir); + } + else { + throw new CompileEnvironmentException("Output directory or jar file is not specified - no files will be saved to the disk"); + } + } + + private static void writeToOutputDirectory(ClassFileFactory factory, final String outputDir) { + List files = factory.files(); + for (String file : files) { + File target = new File(outputDir, file); + try { + FileUtil.writeToFile(target, factory.asBytes(file)); + } catch (IOException e) { + throw new CompileEnvironmentException(e); + } + } + } + +} diff --git a/compiler/backend/src/org/jetbrains/jet/compiler/CompileEnvironmentException.java b/compiler/backend/src/org/jetbrains/jet/compiler/CompileEnvironmentException.java new file mode 100644 index 00000000000..0962b68160e --- /dev/null +++ b/compiler/backend/src/org/jetbrains/jet/compiler/CompileEnvironmentException.java @@ -0,0 +1,18 @@ +package org.jetbrains.jet.compiler; + +/** + * @author yole + */ +public class CompileEnvironmentException extends RuntimeException { + public CompileEnvironmentException(String message) { + super(message); + } + + public CompileEnvironmentException(Throwable cause) { + super(cause); + } + + public CompileEnvironmentException(String message, Throwable cause) { + super(message, cause); + } +} diff --git a/compiler/cli/src/org/jetbrains/jet/cli/CompileSession.java b/compiler/backend/src/org/jetbrains/jet/compiler/CompileSession.java similarity index 93% rename from compiler/cli/src/org/jetbrains/jet/cli/CompileSession.java rename to compiler/backend/src/org/jetbrains/jet/compiler/CompileSession.java index 120a431fe08..c166906ed87 100644 --- a/compiler/cli/src/org/jetbrains/jet/cli/CompileSession.java +++ b/compiler/backend/src/org/jetbrains/jet/compiler/CompileSession.java @@ -1,4 +1,4 @@ -package org.jetbrains.jet.cli; +package org.jetbrains.jet.compiler; import com.google.common.base.Predicates; import com.intellij.openapi.vfs.VirtualFile; @@ -15,10 +15,13 @@ import org.jetbrains.jet.lang.resolve.BindingContext; import org.jetbrains.jet.lang.resolve.java.JavaDefaultImports; import org.jetbrains.jet.plugin.JetFileType; +import java.io.PrintStream; import java.util.ArrayList; import java.util.List; /** + * The session which handles analyzing and compiling a single module. + * * @author yole */ public class CompileSession { @@ -73,10 +76,10 @@ public class CompileSession { return mySourceFileNamespaces; } - public boolean analyze() { + public boolean analyze(final PrintStream out) { if (!myErrors.isEmpty()) { for (String error : myErrors) { - System.out.println(error); + out.println(error); } return false; } @@ -85,7 +88,7 @@ public class CompileSession { allNamespaces.addAll(myLibrarySourceFileNamespaces); myBindingContext = instance.analyzeNamespaces(myEnvironment.getProject(), allNamespaces, Predicates.alwaysTrue(), JetControlFlowDataTraceFactory.EMPTY); ErrorCollector errorCollector = new ErrorCollector(myBindingContext); - errorCollector.report(); + errorCollector.report(out); return !errorCollector.hasErrors; } diff --git a/compiler/cli/src/org/jetbrains/jet/cli/ErrorCollector.java b/compiler/backend/src/org/jetbrains/jet/compiler/ErrorCollector.java similarity index 84% rename from compiler/cli/src/org/jetbrains/jet/cli/ErrorCollector.java rename to compiler/backend/src/org/jetbrains/jet/compiler/ErrorCollector.java index 1da315a1b80..18573bede15 100644 --- a/compiler/cli/src/org/jetbrains/jet/cli/ErrorCollector.java +++ b/compiler/backend/src/org/jetbrains/jet/compiler/ErrorCollector.java @@ -1,4 +1,4 @@ -package org.jetbrains.jet.cli; +package org.jetbrains.jet.compiler; import com.google.common.collect.LinkedHashMultimap; import com.google.common.collect.Multimap; @@ -9,6 +9,7 @@ import org.jetbrains.jet.lang.diagnostics.DiagnosticWithTextRange; import org.jetbrains.jet.lang.diagnostics.Severity; import org.jetbrains.jet.lang.resolve.BindingContext; +import java.io.PrintStream; import java.util.Collection; /** @@ -36,14 +37,14 @@ class ErrorCollector { } } - void report() { + void report(final PrintStream out) { if(!maps.isEmpty()) { for (PsiFile psiFile : maps.keySet()) { - System.out.println(psiFile.getVirtualFile().getPath()); + out.println(psiFile.getVirtualFile().getPath()); Collection diagnosticWithTextRanges = maps.get(psiFile); for (DiagnosticWithTextRange diagnosticWithTextRange : diagnosticWithTextRanges) { String position = DiagnosticUtils.formatPosition(diagnosticWithTextRange); - System.out.println("\t" + diagnosticWithTextRange.getSeverity().toString() + ": " + position + " " + diagnosticWithTextRange.getMessage()); + out.println("\t" + diagnosticWithTextRange.getSeverity().toString() + ": " + position + " " + diagnosticWithTextRange.getMessage()); } } } diff --git a/compiler/cli/src/org/jetbrains/jet/cli/KotlinCompiler.java b/compiler/cli/src/org/jetbrains/jet/cli/KotlinCompiler.java index 7f047272fe2..22a1f6bc346 100644 --- a/compiler/cli/src/org/jetbrains/jet/cli/KotlinCompiler.java +++ b/compiler/cli/src/org/jetbrains/jet/cli/KotlinCompiler.java @@ -1,29 +1,11 @@ package org.jetbrains.jet.cli; -import com.intellij.openapi.Disposable; -import com.intellij.openapi.application.PathManager; -import com.intellij.openapi.util.io.FileUtil; -import com.intellij.openapi.vfs.VirtualFile; -import com.intellij.util.Processor; import com.sampullara.cli.Args; import com.sampullara.cli.Argument; -import jet.modules.IModuleBuilder; -import jet.modules.IModuleSetBuilder; -import org.jetbrains.jet.JetCoreEnvironment; -import org.jetbrains.jet.codegen.ClassFileFactory; -import org.jetbrains.jet.codegen.GeneratedClassLoader; -import org.jetbrains.jet.lang.psi.JetNamespace; -import org.jetbrains.jet.plugin.JetMainDetector; +import org.jetbrains.jet.compiler.CompileEnvironment; +import org.jetbrains.jet.compiler.CompileEnvironmentException; import java.io.File; -import java.io.FileInputStream; -import java.io.FileOutputStream; -import java.io.IOException; -import java.lang.reflect.Method; -import java.net.URL; -import java.net.URLClassLoader; -import java.util.List; -import java.util.jar.*; /** * @author yole @@ -54,273 +36,35 @@ public class KotlinCompiler { return; } - Disposable root = new Disposable() { - @Override - public void dispose() { - } - }; - JetCoreEnvironment environment = new JetCoreEnvironment(root); + CompileEnvironment environment = new CompileEnvironment(); File rtJar = initJdk(); if (rtJar == null) return; - environment.addToClasspath(rtJar); - final File unpackedRuntimePath = getUnpackedRuntimePath(); - if (unpackedRuntimePath != null) { - environment.addToClasspath(unpackedRuntimePath); - } - else { - final File runtimeJarPath = getRuntimeJarPath(); - if (runtimeJarPath != null && runtimeJarPath.exists()) { - environment.addToClasspath(runtimeJarPath); - } - else { + try { + environment.setJavaRuntime(rtJar); + if (!environment.initializeKotlinRuntime()) { System.out.println("No runtime library found"); return; } - } - if (arguments.module != null) { - compileModuleScript(environment, arguments.module); - return; - } - - CompileSession session = new CompileSession(environment); - session.addSources(arguments.src); - - String mainClass = null; - for (JetNamespace namespace : session.getSourceFileNamespaces()) { - if (JetMainDetector.hasMain(namespace.getDeclarations())) { - mainClass = namespace.getFQName() + ".namespace"; - break; - } - } - if (!session.analyze()) { - return; - } - - ClassFileFactory factory = session.generate(); - if (arguments.jar != null) { - writeToJar(factory, arguments.jar, mainClass, true); - } - else if (arguments.outputDir != null) { - writeToOutputDirectory(factory, arguments.outputDir); - } - else { - System.out.println("Output directory or jar file is not specified - no files will be saved to the disk"); - } - } - - private static void compileModuleScript(JetCoreEnvironment environment, String moduleFile) { - CompileSession scriptCompileSession = new CompileSession(environment); - scriptCompileSession.addSources(moduleFile); - - URL url = KotlinCompiler.class.getClassLoader().getResource("ModuleBuilder.kt"); - if (url != null) { - String path = url.getPath(); - if (path.startsWith("file:")) { - path = path.substring(5); - } - final VirtualFile vFile = environment.getJarFileSystem().findFileByPath(path); - if (vFile == null) { - System.out.println("Couldn't load ModuleBuilder.kt from runtime jar: "+ url); + if (arguments.module != null) { + environment.compileModuleScript(arguments.module); return; } - scriptCompileSession.addSources(vFile); - } - else { - // building from source - final String homeDirectory = getHomeDirectory(); - final File file = new File(homeDirectory, "stdlib/ktSrc/ModuleBuilder.kt"); - scriptCompileSession.addSources(environment.getLocalFileSystem().findFileByPath(file.getPath())); - } - - if (!scriptCompileSession.analyze()) { - return; - } - final ClassFileFactory factory = scriptCompileSession.generate(); - - final IModuleSetBuilder moduleSetBuilder = runDefineModules(moduleFile, factory); - - for (IModuleBuilder moduleBuilder : moduleSetBuilder.getModules()) { - compileModule(environment, moduleBuilder, new File(moduleFile).getParent()); - } - } - - private static IModuleSetBuilder runDefineModules(String moduleFile, ClassFileFactory factory) { - GeneratedClassLoader loader = new GeneratedClassLoader(factory); - try { - Class moduleSetBuilderClass = loader.loadClass("kotlin.modules.ModuleSetBuilder"); - final IModuleSetBuilder moduleSetBuilder = (IModuleSetBuilder) moduleSetBuilderClass.newInstance(); - - Class namespaceClass = loader.loadClass("namespace"); - final Method[] methods = namespaceClass.getMethods(); - boolean modulesDefined = false; - for (Method method : methods) { - if (method.getName().equals("defineModules")) { - method.invoke(null, moduleSetBuilder); - modulesDefined = true; - break; - } - } - if (!modulesDefined) { - System.out.println("Module script " + moduleFile + " must define a defineModules() method"); - return null; - } - return moduleSetBuilder; - } catch (Exception e) { - e.printStackTrace(); - return null; - } - } - - private static void compileModule(JetCoreEnvironment environment, IModuleBuilder moduleBuilder, String directory) { - CompileSession moduleCompileSession = new CompileSession(environment); - for (String sourceFile : moduleBuilder.getSourceFiles()) { - moduleCompileSession.addSources(new File(directory, sourceFile).getPath()); - } - for (String classpathRoot : moduleBuilder.getClasspathRoots()) { - environment.addToClasspath(new File(classpathRoot)); - } - if (!moduleCompileSession.analyze()) { - return; - } - ClassFileFactory factory = moduleCompileSession.generate(); - writeToJar(factory, new File(directory, moduleBuilder.getModuleName() + ".jar").getPath(), null, true); - } - - private static String getHomeDirectory() { - return new File(PathManager.getResourceRoot(KotlinCompiler.class, "/org/jetbrains/jet/cli/KotlinCompiler.class")).getParentFile().getParentFile().getParent(); - } - - private static void writeToJar(ClassFileFactory factory, String jar, String mainClass, boolean includeRuntime) { - try { - Manifest manifest = new Manifest(); - final Attributes mainAttributes = manifest.getMainAttributes(); - mainAttributes.putValue("Manifest-Version", "1.0"); - mainAttributes.putValue("Created-By", "JetBrains Kotlin"); - if (mainClass != null) { - mainAttributes.putValue("Main-Class", mainClass); - } - FileOutputStream fos = new FileOutputStream(jar); - JarOutputStream stream = new JarOutputStream(fos, manifest); - try { - for (String file : factory.files()) { - stream.putNextEntry(new JarEntry(file)); - stream.write(factory.asBytes(file)); - } - if (includeRuntime) { - writeRuntimeToJar(stream); - } - } - finally { - stream.close(); - fos.close(); - } - - } catch (IOException e) { - System.out.println("Failed to generate jar file: " + e.getMessage()); - } - } - - private static File getUnpackedRuntimePath() { - URL url = KotlinCompiler.class.getClassLoader().getResource("jet/JetObject.class"); - if (url != null && url.getProtocol().equals("file")) { - return new File(url.getPath()).getParentFile().getParentFile(); - } - return null; - } - - private static File getRuntimeJarPath() { - URL url = KotlinCompiler.class.getClassLoader().getResource("jet/JetObject.class"); - if (url != null && url.getProtocol().equals("jar")) { - String path = url.getPath(); - return new File(path.substring(path.indexOf(":") + 1, path.indexOf("!/"))); - } - return null; - } - - private static void writeRuntimeToJar(final JarOutputStream stream) throws IOException { - final File unpackedRuntimePath = getUnpackedRuntimePath(); - if (unpackedRuntimePath != null) { - FileUtil.processFilesRecursively(unpackedRuntimePath, new Processor() { - @Override - public boolean process(File file) { - if (file.isDirectory()) return true; - final String relativePath = FileUtil.getRelativePath(unpackedRuntimePath, file); - try { - stream.putNextEntry(new JarEntry(FileUtil.toSystemIndependentName(relativePath))); - FileInputStream fis = new FileInputStream(file); - try { - FileUtil.copy(fis, stream); - } finally { - fis.close(); - } - } catch (IOException e) { - throw new RuntimeException(e); - } - return true; - } - }); - } - else { - File runtimeJarPath = getRuntimeJarPath(); - if (runtimeJarPath != null) { - JarInputStream jis = new JarInputStream(new FileInputStream(runtimeJarPath)); - try { - while (true) { - JarEntry e = jis.getNextJarEntry(); - if (e == null) { - break; - } - if (FileUtil.getExtension(e.getName()).equals("class")) { - stream.putNextEntry(e); - FileUtil.copy(jis, stream); - } - } - } finally { - jis.close(); - } - } else { - System.out.println("Couldn't find runtime library"); - } - } - } - - private static void writeToOutputDirectory(ClassFileFactory factory, final String outputDir) { - List files = factory.files(); - for (String file : files) { - File target = new File(outputDir, file); - try { - FileUtil.writeToFile(target, factory.asBytes(file)); - System.out.println("Generated classfile: " + target); - } catch (IOException e) { - System.out.println(e.getMessage()); + environment.compileBunchOfSources(arguments.src, arguments.jar, arguments.outputDir); } + } catch (CompileEnvironmentException e) { + System.out.println(e.getMessage()); } } private static File initJdk() { String javaHome = System.getenv("JAVA_HOME"); - File rtJar = null; + File rtJar; if (javaHome == null) { - ClassLoader systemClassLoader = ClassLoader.getSystemClassLoader(); - if(systemClassLoader instanceof URLClassLoader) { - URLClassLoader loader = (URLClassLoader) systemClassLoader; - for(URL url: loader.getURLs()) { - if("file".equals(url.getProtocol())) { - if(url.getFile().endsWith("/lib/rt.jar")) { - rtJar = new File(url.getFile()); - break; - } - if(url.getFile().endsWith("/Classes/classes.jar")) { - rtJar = new File(url.getFile()).getAbsoluteFile(); - break; - } - } - } - } + rtJar = CompileEnvironment.findActiveRtJar(); if(rtJar == null) { System.out.println("JAVA_HOME environment variable needs to be defined"); diff --git a/compiler/testData/compiler/smoke/Smoke.kt b/compiler/testData/compiler/smoke/Smoke.kt new file mode 100644 index 00000000000..6da801d1fde --- /dev/null +++ b/compiler/testData/compiler/smoke/Smoke.kt @@ -0,0 +1,4 @@ +namespace Smoke + +fun main(args: Array) { +} diff --git a/compiler/testData/compiler/smoke/Smoke.kts b/compiler/testData/compiler/smoke/Smoke.kts new file mode 100644 index 00000000000..6cdcff74a64 --- /dev/null +++ b/compiler/testData/compiler/smoke/Smoke.kts @@ -0,0 +1,8 @@ +import kotlin.modules.ModuleSetBuilder + +fun ModuleSetBuilder.defineModules() { + module("smoke") { + source files "Smoke.kt" + jar name System.getProperty("java.io.tmpdir") + "/smoke.jar" + } +} diff --git a/compiler/tests/org/jetbrains/jet/compiler/CompileEnvironmentTest.java b/compiler/tests/org/jetbrains/jet/compiler/CompileEnvironmentTest.java new file mode 100644 index 00000000000..a7981989cdf --- /dev/null +++ b/compiler/tests/org/jetbrains/jet/compiler/CompileEnvironmentTest.java @@ -0,0 +1,25 @@ +package org.jetbrains.jet.compiler; + +import jet.modules.IModuleBuilder; +import jet.modules.IModuleSetBuilder; +import junit.framework.TestCase; +import org.jetbrains.jet.codegen.ClassFileFactory; +import org.jetbrains.jet.parsing.JetParsingTest; + +/** + * @author yole + */ +public class CompileEnvironmentTest extends TestCase { + public void testSmoke() { + CompileEnvironment environment = new CompileEnvironment(); + environment.setJavaRuntime(CompileEnvironment.findActiveRtJar()); + environment.initializeKotlinRuntime(); + final String testDataDir = JetParsingTest.getTestDataDir() + "/compiler/smoke/"; + final IModuleSetBuilder setBuilder = environment.loadModuleScript(testDataDir + "Smoke.kts"); + assertEquals(1, setBuilder.getModules().size()); + final IModuleBuilder moduleBuilder = setBuilder.getModules().get(0); + final ClassFileFactory factory = environment.compileModule(moduleBuilder, testDataDir); + assertNotNull(factory); + assertNotNull(factory.asBytes("Smoke/namespace.class")); + } +} diff --git a/stdlib/ktSrc/ModuleBuilder.kt b/stdlib/ktSrc/ModuleBuilder.kt index 7e2e25e8715..bee397cbb56 100644 --- a/stdlib/ktSrc/ModuleBuilder.kt +++ b/stdlib/ktSrc/ModuleBuilder.kt @@ -29,9 +29,16 @@ class ClasspathBuilder(val parent: ModuleBuilder) { } } +class JarBuilder(val parent: ModuleBuilder) { + fun name(jarName: String) { + parent.setJarName(jarName) + } +} + class ModuleBuilder(val name: String): IModuleBuilder { val sourceFiles: ArrayList = ArrayList() val classpathRoots: ArrayList = ArrayList() + var _jarName: String? = null val source: SourcesBuilder get() = SourcesBuilder(this) @@ -39,6 +46,9 @@ class ModuleBuilder(val name: String): IModuleBuilder { val classpath: ClasspathBuilder get() = ClasspathBuilder(this) + val jar: JarBuilder + get() = JarBuilder(this) + fun addSourceFiles(pattern: String) { sourceFiles.add(pattern) } @@ -47,9 +57,13 @@ class ModuleBuilder(val name: String): IModuleBuilder { classpathRoots.add(name) } + fun setJarName(name: String) { + _jarName = name + } + override fun getSourceFiles(): List? = sourceFiles override fun getClasspathRoots(): List? = classpathRoots override fun getModuleName(): String? = name -} + override fun getJarName(): String? = _jarName } \ No newline at end of file diff --git a/stdlib/src/jet/modules/IModuleBuilder.java b/stdlib/src/jet/modules/IModuleBuilder.java index c845e04a021..f455eb5fabc 100644 --- a/stdlib/src/jet/modules/IModuleBuilder.java +++ b/stdlib/src/jet/modules/IModuleBuilder.java @@ -9,4 +9,5 @@ public interface IModuleBuilder { String getModuleName(); List getSourceFiles(); List getClasspathRoots(); + String getJarName(); }