diff --git a/.idea/misc.xml b/.idea/misc.xml index c1a7618d01a..90689171e5b 100644 --- a/.idea/misc.xml +++ b/.idea/misc.xml @@ -1,8 +1,5 @@ - - diff --git a/idea/src/org/jetbrains/jet/codegen/ClassBodyCodegen.java b/idea/src/org/jetbrains/jet/codegen/ClassBodyCodegen.java index 548b4985891..fa7e219dbd7 100644 --- a/idea/src/org/jetbrains/jet/codegen/ClassBodyCodegen.java +++ b/idea/src/org/jetbrains/jet/codegen/ClassBodyCodegen.java @@ -19,14 +19,16 @@ public abstract class ClassBodyCodegen { protected final BindingContext bindingContext; protected final JetStandardLibrary stdlib; protected final JetTypeMapper typeMapper; + protected final Codegens factory; protected final JetClassOrObject myClass; protected final OwnerKind kind; protected final ClassDescriptor descriptor; protected final ClassVisitor v; - public ClassBodyCodegen(BindingContext bindingContext, JetStandardLibrary stdlib, JetClassOrObject aClass, OwnerKind kind, ClassVisitor v) { + public ClassBodyCodegen(BindingContext bindingContext, JetStandardLibrary stdlib, JetClassOrObject aClass, OwnerKind kind, ClassVisitor v, Codegens factory) { this.bindingContext = bindingContext; this.stdlib = stdlib; + this.factory = factory; this.typeMapper = new JetTypeMapper(stdlib, bindingContext); descriptor = bindingContext.getClassDescriptor(aClass); myClass = aClass; @@ -50,7 +52,7 @@ public abstract class ClassBodyCodegen { } private void generateClassBody() { - final FunctionCodegen functionCodegen = new FunctionCodegen((JetDeclaration) myClass, v, stdlib, bindingContext); + final FunctionCodegen functionCodegen = new FunctionCodegen((JetDeclaration) myClass, v, stdlib, bindingContext, factory); final PropertyCodegen propertyCodegen = new PropertyCodegen(v, stdlib, bindingContext, functionCodegen); for (JetDeclaration declaration : myClass.getDeclarations()) { diff --git a/idea/src/org/jetbrains/jet/codegen/ClassCodegen.java b/idea/src/org/jetbrains/jet/codegen/ClassCodegen.java index 6595f171e96..2c85846dd89 100644 --- a/idea/src/org/jetbrains/jet/codegen/ClassCodegen.java +++ b/idea/src/org/jetbrains/jet/codegen/ClassCodegen.java @@ -45,7 +45,7 @@ public class ClassCodegen { private void generateInterface(JetClassOrObject aClass) { final ClassVisitor visitor = factory.forClassInterface(bindingContext.getClassDescriptor(aClass)); - new InterfaceBodyCodegen(bindingContext, JetStandardLibrary.getJetStandardLibrary(project), aClass, visitor).generate(); + new InterfaceBodyCodegen(bindingContext, JetStandardLibrary.getJetStandardLibrary(project), aClass, visitor, factory).generate(); } private void generateImplementation(JetClassOrObject aClass, OwnerKind kind) { @@ -53,7 +53,7 @@ public class ClassCodegen { ClassVisitor v = kind == OwnerKind.IMPLEMENTATION ? factory.forClassImplementation(descriptor) : factory.forClassDelegatingImplementation(descriptor); - new ImplementationBodyCodegen(bindingContext, JetStandardLibrary.getJetStandardLibrary(project), aClass, kind, v).generate(); + new ImplementationBodyCodegen(bindingContext, JetStandardLibrary.getJetStandardLibrary(project), aClass, kind, v, factory).generate(); } diff --git a/idea/src/org/jetbrains/jet/codegen/ClosureCodegen.java b/idea/src/org/jetbrains/jet/codegen/ClosureCodegen.java new file mode 100644 index 00000000000..26b020119ff --- /dev/null +++ b/idea/src/org/jetbrains/jet/codegen/ClosureCodegen.java @@ -0,0 +1,164 @@ +/* + * @author max + */ +package org.jetbrains.jet.codegen; + +import com.intellij.openapi.project.Project; +import com.intellij.openapi.util.Pair; +import com.intellij.psi.util.PsiTreeUtil; +import org.jetbrains.jet.lang.descriptors.FunctionDescriptor; +import org.jetbrains.jet.lang.descriptors.ValueParameterDescriptor; +import org.jetbrains.jet.lang.psi.*; +import org.jetbrains.jet.lang.resolve.BindingContext; +import org.jetbrains.jet.lang.types.JetStandardLibrary; +import org.jetbrains.jet.lang.types.JetType; +import org.objectweb.asm.ClassVisitor; +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; +import org.objectweb.asm.signature.SignatureWriter; + +import java.util.Arrays; +import java.util.List; + +public class ClosureCodegen { + private final BindingContext bindingContext; + private final JetTypeMapper typeMapper; + private final Codegens factory; + + public ClosureCodegen(BindingContext bindingContext, JetTypeMapper typeMapper, Codegens factory) { + this.bindingContext = bindingContext; + this.typeMapper = typeMapper; + this.factory = factory; + } + + public static Method erasedInvokeSignature(FunctionDescriptor fd) { + boolean isExtensionFunction = fd.getReceiverType() != null; + int paramCount = fd.getUnsubstitutedValueParameters().size(); + if (isExtensionFunction) { + paramCount++; + } + + Type[] args = new Type[paramCount]; + Arrays.fill(args, JetTypeMapper.TYPE_OBJECT); + return new Method("invoke", JetTypeMapper.TYPE_OBJECT, args); + } + + public Method invokeSignature(FunctionDescriptor fd) { + return typeMapper.mapSignature("invoke", fd); + } + + public GeneratedClosureDescriptor gen(JetFunctionLiteralExpression fun) { + JetNamedDeclaration container = PsiTreeUtil.getParentOfType(fun, JetNamespace.class, JetClass.class, JetObjectDeclaration.class); + + final Pair nameAndVisitor; + if (container instanceof JetNamespace) { + nameAndVisitor = factory.forClosureIn((JetNamespace) container); + } + else { + nameAndVisitor = factory.forClosureIn(bindingContext.getClassDescriptor((JetClassOrObject) container)); + } + + + final FunctionDescriptor funDescriptor = (FunctionDescriptor) bindingContext.getDeclarationDescriptor(fun); + + final ClassVisitor cv = nameAndVisitor.getSecond(); + final String name = nameAndVisitor.getFirst(); + + SignatureWriter signatureWriter = new SignatureWriter(); + + final List parameters = funDescriptor.getUnsubstitutedValueParameters(); + final String funClass = getInternalClassName(funDescriptor); + signatureWriter.visitClassType(funClass); + for (ValueParameterDescriptor parameter : parameters) { + appendType(signatureWriter, parameter.getOutType(), '='); + } + + appendType(signatureWriter, funDescriptor.getUnsubstitutedReturnType(), '='); + signatureWriter.visitEnd(); + + cv.visit(Opcodes.V1_6, + Opcodes.ACC_PUBLIC, + name, + null, + funClass, + new String[0] + ); + + final Method constructor = generateConstructor(cv, funClass); + + generateBridge(name, funDescriptor, cv); + generateBody(name, funDescriptor, cv, container.getProject(), fun.getBody()); + + cv.visitEnd(); + + return new GeneratedClosureDescriptor(name, constructor); + } + + private void generateBody(String className, FunctionDescriptor funDescriptor, ClassVisitor cv, Project project, List body) { + FunctionCodegen fc = new FunctionCodegen(null, cv, JetStandardLibrary.getJetStandardLibrary(project), bindingContext, factory); + fc.generatedMethod(body, OwnerKind.IMPLEMENTATION, invokeSignature(funDescriptor), null, funDescriptor.getUnsubstitutedValueParameters(), null); + } + + private void generateBridge(String className, FunctionDescriptor funDescriptor, ClassVisitor cv) { + final Method bridge = erasedInvokeSignature(funDescriptor); + + final MethodVisitor mv = cv.visitMethod(Opcodes.ACC_PUBLIC, "invoke", bridge.getDescriptor(), typeMapper.genericSignature(funDescriptor), new String[0]); + mv.visitCode(); + + InstructionAdapter iv = new InstructionAdapter(mv); + + iv.load(0, Type.getObjectType(className)); + + final List params = funDescriptor.getUnsubstitutedValueParameters(); + int count = 1; + for (ValueParameterDescriptor param : params) { + iv.load(count, JetTypeMapper.TYPE_OBJECT); + iv.checkcast(typeMapper.mapType(param.getOutType())); + count++; + } + + iv.invokespecial(className, "invoke", invokeSignature(funDescriptor).getDescriptor()); + iv.areturn(JetTypeMapper.TYPE_OBJECT); + + mv.visitMaxs(0, 0); + mv.visitEnd(); + } + + private Method generateConstructor(ClassVisitor cv, String funClass) { + final Method constructor = new Method("", Type.VOID_TYPE, new Type[0]); // TODO: + final MethodVisitor mv = cv.visitMethod(Opcodes.ACC_PUBLIC, "", constructor.getDescriptor(), null, new String[0]); + mv.visitCode(); + InstructionAdapter iv = new InstructionAdapter(mv); + + iv.load(0, Type.getObjectType(funClass)); + iv.invokespecial(funClass, "", "()V"); + + iv.visitInsn(Opcodes.RETURN); + + + mv.visitMaxs(0, 0); + mv.visitEnd(); + return constructor; + } + + public static String getInternalClassName(FunctionDescriptor descriptor) { + final int paramCount = descriptor.getUnsubstitutedValueParameters().size(); + if (descriptor.getReceiverType() != null) { + return "jet/ExtensionFunction" + paramCount; + } + else { + return "jet/Function" + paramCount; + } + } + + private void appendType(SignatureWriter signatureWriter, JetType type, char variance) { + signatureWriter.visitTypeArgument(variance); + + final Type rawRetType = typeMapper.boxType(typeMapper.mapType(type)); + signatureWriter.visitClassType(rawRetType.getInternalName()); + signatureWriter.visitEnd(); + } +} diff --git a/idea/src/org/jetbrains/jet/codegen/Codegens.java b/idea/src/org/jetbrains/jet/codegen/Codegens.java index 5eddebfec55..b92392cd0c8 100644 --- a/idea/src/org/jetbrains/jet/codegen/Codegens.java +++ b/idea/src/org/jetbrains/jet/codegen/Codegens.java @@ -1,6 +1,7 @@ package org.jetbrains.jet.codegen; import com.intellij.openapi.project.Project; +import com.intellij.openapi.util.Pair; import org.jetbrains.jet.lang.descriptors.ClassDescriptor; import org.jetbrains.jet.lang.psi.JetNamespace; import org.jetbrains.jet.lang.resolve.BindingContext; @@ -20,6 +21,7 @@ public class Codegens { private final boolean isText; private final Map ns2codegen = new HashMap(); private final Map generators = new LinkedHashMap(); + private final Map closuresCount = new HashMap(); private boolean isDone = false; public Codegens(Project project, boolean text) { @@ -56,6 +58,24 @@ public class Codegens { return newVisitor(JetTypeMapper.jvmNameForDelegatingImplementation(aClass) + ".class"); } + public Pair forClosureIn(ClassDescriptor aClass) { + return forClosureIn(JetTypeMapper.jvmNameForInterface(aClass)); + } + + public Pair forClosureIn(JetNamespace namespace) { + return forClosureIn(NamespaceCodegen.getJVMClassName(namespace.getFQName())); + } + + private Pair forClosureIn(String baseName) { + Integer count = closuresCount.get(baseName); + if (count == null) count = 0; + + closuresCount.put(baseName, count + 1); + + final String className = baseName + "$" + (count + 1); + return new Pair(className, newVisitor(className + ".class")); + } + public NamespaceCodegen forNamespace(JetNamespace namespace) { assert !isDone : "Already done!"; String fqName = namespace.getFQName(); diff --git a/idea/src/org/jetbrains/jet/codegen/ExpressionCodegen.java b/idea/src/org/jetbrains/jet/codegen/ExpressionCodegen.java index 7ef61c429ef..a14ad3bed92 100644 --- a/idea/src/org/jetbrains/jet/codegen/ExpressionCodegen.java +++ b/idea/src/org/jetbrains/jet/codegen/ExpressionCodegen.java @@ -12,10 +12,7 @@ import org.jetbrains.annotations.Nullable; import org.jetbrains.jet.lang.descriptors.*; 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.lang.types.TypeProjection; -import org.jetbrains.jet.lang.types.TypeUtils; +import org.jetbrains.jet.lang.types.*; import org.jetbrains.jet.lexer.JetTokens; import org.jetbrains.jet.resolve.DescriptorRenderer; import org.objectweb.asm.Label; @@ -64,6 +61,7 @@ public class ExpressionCodegen extends JetVisitor { private final InstructionAdapter v; private final FrameMap myMap; private final JetTypeMapper typeMapper; + private final Codegens factory; private final Type returnType; private final DeclarationDescriptor contextType; private final OwnerKind contextKind; @@ -78,12 +76,14 @@ public class ExpressionCodegen extends JetVisitor { Type returnType, DeclarationDescriptor contextType, OwnerKind contextKind, - @Nullable StackValue thisExpression) { + @Nullable StackValue thisExpression, + Codegens factory) { this.myMap = myMap; this.typeMapper = typeMapper; this.returnType = returnType; this.contextType = contextType; this.contextKind = contextKind; + this.factory = factory; this.v = new InstructionAdapter(v); this.bindingContext = bindingContext; this.thisExpression = thisExpression; @@ -481,7 +481,10 @@ public class ExpressionCodegen extends JetVisitor { generateBlock(expression.getBody()); } else { - throw new UnsupportedOperationException("don't know how to generate non-block function literals"); + final GeneratedClosureDescriptor closure = new ClosureCodegen(bindingContext, typeMapper, factory).gen(expression); + v.anew(Type.getObjectType(closure.getClassname())); + v.dup(); + v.invokespecial(closure.getClassname(), "", closure.getConstructor().getDescriptor()); } } @@ -543,7 +546,12 @@ public class ExpressionCodegen extends JetVisitor { @Override public void visitSimpleNameExpression(JetSimpleNameExpression expression) { - final DeclarationDescriptor descriptor = bindingContext.resolveReferenceExpression(expression); + DeclarationDescriptor descriptor = bindingContext.resolveReferenceExpression(expression); + + if (descriptor instanceof VariableAsFunctionDescriptor) { + descriptor = ((VariableAsFunctionDescriptor) descriptor).getVariableDescriptor(); + } + final DeclarationDescriptor container = descriptor.getContainingDeclaration(); if (descriptor instanceof VariableDescriptor) { if (isClass(container, "Number")) { @@ -702,13 +710,14 @@ public class ExpressionCodegen extends JetVisitor { PsiElement declarationPsiElement = bindingContext.getDeclarationPsiElement(funDescriptor); + final FunctionDescriptor fd = (FunctionDescriptor) funDescriptor; if (declarationPsiElement == null && isClass(functionParent, "String")) { final Project project = expression.getProject(); PsiClass jlString = JavaPsiFacade.getInstance(project).findClass("java.lang.String", ProjectScope.getAllScope(project)); // TODO better overload mapping final PsiMethod[] methods = jlString.findMethodsByName(funDescriptor.getName(), false); - final int arity = ((FunctionDescriptor) funDescriptor).getUnsubstitutedValueParameters().size(); + final int arity = fd.getUnsubstitutedValueParameters().size(); for (PsiMethod method : methods) { if (method.getParameterList().getParametersCount() == arity) { declarationPsiElement = method; @@ -744,7 +753,7 @@ public class ExpressionCodegen extends JetVisitor { methodDescriptor.getName(), methodDescriptor.getDescriptor()); } - else { + else if(declarationPsiElement instanceof JetFunction) { final JetFunction jetFunction = (JetFunction) declarationPsiElement; methodDescriptor = typeMapper.mapSignature(jetFunction); if (functionParent instanceof NamespaceDescriptorImpl) { @@ -765,8 +774,25 @@ public class ExpressionCodegen extends JetVisitor { throw new UnsupportedOperationException("don't know how to generate call to " + declarationPsiElement); } } + else { + gen(callee, Type.getObjectType(ClosureCodegen.getInternalClassName(fd))); + + boolean isExtensionFunction = fd.getReceiverType() != null; + int paramCount = fd.getUnsubstitutedValueParameters().size(); + if (isExtensionFunction) { + ensureReceiverOnStack(expression, null); + paramCount++; + } + + methodDescriptor = ClosureCodegen.erasedInvokeSignature(fd); + pushMethodArguments(expression, methodDescriptor); + v.invokevirtual(ClosureCodegen.getInternalClassName(fd), "invoke", methodDescriptor.getDescriptor()); + } + if (methodDescriptor.getReturnType() != Type.VOID_TYPE) { - myStack.push(StackValue.onStack(methodDescriptor.getReturnType())); + final Type retType = typeMapper.mapType(fd.getUnsubstitutedReturnType()); + StackValue.onStack(methodDescriptor.getReturnType()).put(retType, v); + myStack.push(StackValue.onStack(retType)); } } else { diff --git a/idea/src/org/jetbrains/jet/codegen/FunctionCodegen.java b/idea/src/org/jetbrains/jet/codegen/FunctionCodegen.java index 3423fc8fe14..0f2bf036782 100644 --- a/idea/src/org/jetbrains/jet/codegen/FunctionCodegen.java +++ b/idea/src/org/jetbrains/jet/codegen/FunctionCodegen.java @@ -14,6 +14,7 @@ import org.objectweb.asm.Type; import org.objectweb.asm.commons.InstructionAdapter; import org.objectweb.asm.commons.Method; +import java.util.Collections; import java.util.List; /** @@ -24,11 +25,13 @@ public class FunctionCodegen { private final ClassVisitor v; private final BindingContext bindingContext; private final JetTypeMapper typeMapper; + private final Codegens factory; - public FunctionCodegen(JetDeclaration owner, ClassVisitor v, JetStandardLibrary standardLibrary, BindingContext bindingContext) { + public FunctionCodegen(JetDeclaration owner, ClassVisitor v, JetStandardLibrary standardLibrary, BindingContext bindingContext, Codegens factory) { this.owner = owner; this.v = v; this.bindingContext = bindingContext; + this.factory = factory; typeMapper = new JetTypeMapper(standardLibrary, bindingContext); } @@ -45,23 +48,33 @@ public class FunctionCodegen { Method jvmSignature, @Nullable JetType receiverType, List paramDescrs) { + final DeclarationDescriptor contextDesc = owner instanceof JetClassOrObject + ? bindingContext.getClassDescriptor((JetClassOrObject) owner) + : bindingContext.getNamespaceDescriptor((JetNamespace) owner); + final JetExpression bodyExpression = f.getBodyExpression(); + final List bodyExpressions = bodyExpression != null ? Collections.singletonList(bodyExpression) : null; + generatedMethod(bodyExpressions, kind, jvmSignature, receiverType, paramDescrs, contextDesc); + } + + public void generatedMethod(List bodyExpressions, + OwnerKind kind, + Method jvmSignature, + JetType receiverType, + List paramDescrs, + DeclarationDescriptor contextDesc) + { int flags = Opcodes.ACC_PUBLIC; // TODO. boolean isStatic = kind == OwnerKind.NAMESPACE; if (isStatic) flags |= Opcodes.ACC_STATIC; - final JetExpression bodyExpression = f.getBodyExpression(); - boolean isAbstract = kind == OwnerKind.INTERFACE || bodyExpression == null; + boolean isAbstract = kind == OwnerKind.INTERFACE || bodyExpressions == null; if (isAbstract) flags |= Opcodes.ACC_ABSTRACT; if (isAbstract && (kind == OwnerKind.IMPLEMENTATION || kind == OwnerKind.DELEGATING_IMPLEMENTATION)) { return; } - DeclarationDescriptor contextDescriptor = owner instanceof JetClassOrObject - ? bindingContext.getClassDescriptor((JetClassOrObject) owner) - : bindingContext.getNamespaceDescriptor((JetNamespace) owner); - final MethodVisitor mv = v.visitMethod(flags, jvmSignature.getName(), jvmSignature.getDescriptor(), null, null); if (kind != OwnerKind.INTERFACE) { mv.visitCode(); @@ -79,7 +92,7 @@ public class FunctionCodegen { StackValue thisExpression = receiverType == null ? null : StackValue.local(0, typeMapper.mapType(receiverType)); ExpressionCodegen codegen = new ExpressionCodegen(mv, bindingContext, frameMap, typeMapper, - jvmSignature.getReturnType(), contextDescriptor, kind, thisExpression); + jvmSignature.getReturnType(), contextDesc, kind, thisExpression, factory); if (kind instanceof OwnerKind.DelegateKind) { OwnerKind.DelegateKind dk = (OwnerKind.DelegateKind) kind; InstructionAdapter iv = new InstructionAdapter(mv); @@ -93,15 +106,19 @@ public class FunctionCodegen { iv.areturn(jvmSignature.getReturnType()); } else if (!isAbstract) { - bodyExpression.accept(codegen); - generateReturn(mv, bodyExpression, codegen, jvmSignature); + JetElement last = null; + for (JetElement expression : bodyExpressions) { + expression.accept(codegen); + last = expression; + } + generateReturn(mv, last, codegen, jvmSignature); } mv.visitMaxs(0, 0); mv.visitEnd(); } } - private void generateReturn(MethodVisitor mv, JetExpression bodyExpression, ExpressionCodegen codegen, Method jvmSignature) { + private void generateReturn(MethodVisitor mv, JetElement bodyExpression, ExpressionCodegen codegen, Method jvmSignature) { if (!endsWithReturn(bodyExpression)) { if (jvmSignature.getReturnType() == Type.VOID_TYPE) { mv.visitInsn(Opcodes.RETURN); @@ -112,11 +129,12 @@ public class FunctionCodegen { } } - private static boolean endsWithReturn(JetExpression bodyExpression) { + private static boolean endsWithReturn(JetElement bodyExpression) { if (bodyExpression instanceof JetBlockExpression) { final List statements = ((JetBlockExpression) bodyExpression).getStatements(); return statements.size() > 0 && statements.get(statements.size()-1) instanceof JetReturnExpression; } - return false; + + return bodyExpression instanceof JetReturnExpression; } } diff --git a/idea/src/org/jetbrains/jet/codegen/GeneratedClosureDescriptor.java b/idea/src/org/jetbrains/jet/codegen/GeneratedClosureDescriptor.java new file mode 100644 index 00000000000..d37bc3c3c56 --- /dev/null +++ b/idea/src/org/jetbrains/jet/codegen/GeneratedClosureDescriptor.java @@ -0,0 +1,24 @@ +/* + * @author max + */ +package org.jetbrains.jet.codegen; + +import org.objectweb.asm.commons.Method; + +public class GeneratedClosureDescriptor { + private final String classname; + private Method constructor; + + public GeneratedClosureDescriptor(String classname, Method constructor) { + this.classname = classname; + this.constructor = constructor; + } + + public String getClassname() { + return classname; + } + + public Method getConstructor() { + return constructor; + } +} diff --git a/idea/src/org/jetbrains/jet/codegen/ImplementationBodyCodegen.java b/idea/src/org/jetbrains/jet/codegen/ImplementationBodyCodegen.java index f2d90d0edbe..d973b8c888b 100644 --- a/idea/src/org/jetbrains/jet/codegen/ImplementationBodyCodegen.java +++ b/idea/src/org/jetbrains/jet/codegen/ImplementationBodyCodegen.java @@ -22,8 +22,8 @@ import java.util.*; */ public class ImplementationBodyCodegen extends ClassBodyCodegen { public ImplementationBodyCodegen(BindingContext bindingContext, JetStandardLibrary stdlib, JetClassOrObject aClass, - OwnerKind kind, ClassVisitor v) { - super(bindingContext, stdlib, aClass, kind, v); + OwnerKind kind, ClassVisitor v, Codegens factory) { + super(bindingContext, stdlib, aClass, kind, v, factory); } @Override @@ -109,7 +109,7 @@ public class ImplementationBodyCodegen extends ClassBodyCodegen { final InstructionAdapter iv = new InstructionAdapter(mv); ExpressionCodegen codegen = new ExpressionCodegen(mv, bindingContext, frameMap, typeMapper, Type.VOID_TYPE, - descriptor, kind, StackValue.local(0, typeMapper.jvmType(descriptor, kind))); + descriptor, kind, StackValue.local(0, typeMapper.jvmType(descriptor, kind)), factory); String classname = typeMapper.jvmName(descriptor, kind); final Type classType = Type.getType("L" + classname + ";"); @@ -289,7 +289,7 @@ public class ImplementationBodyCodegen extends ClassBodyCodegen { final InstructionAdapter iv = new InstructionAdapter(mv); ExpressionCodegen codegen = new ExpressionCodegen(mv, bindingContext, frameMap, typeMapper, Type.VOID_TYPE, - descriptor, kind, StackValue.local(0, typeMapper.jvmType(descriptor, kind))); + descriptor, kind, StackValue.local(0, typeMapper.jvmType(descriptor, kind)), factory); for (JetDelegationSpecifier initializer : constructor.getInitializers()) { if (initializer instanceof JetDelegatorToThisCall) { @@ -355,7 +355,7 @@ public class ImplementationBodyCodegen extends ClassBodyCodegen { } protected void generateDelegates(JetClassOrObject inClass, JetClass toClass, OwnerKind kind, Set overriden) { - final FunctionCodegen functionCodegen = new FunctionCodegen(toClass, v, stdlib, bindingContext); + final FunctionCodegen functionCodegen = new FunctionCodegen(toClass, v, stdlib, bindingContext, factory); final PropertyCodegen propertyCodegen = new PropertyCodegen(v, stdlib, bindingContext, functionCodegen); for (JetDeclaration declaration : toClass.getDeclarations()) { diff --git a/idea/src/org/jetbrains/jet/codegen/InterfaceBodyCodegen.java b/idea/src/org/jetbrains/jet/codegen/InterfaceBodyCodegen.java index 5514043d665..c54071af164 100644 --- a/idea/src/org/jetbrains/jet/codegen/InterfaceBodyCodegen.java +++ b/idea/src/org/jetbrains/jet/codegen/InterfaceBodyCodegen.java @@ -19,8 +19,8 @@ import java.util.Set; * @author yole */ public class InterfaceBodyCodegen extends ClassBodyCodegen { - public InterfaceBodyCodegen(BindingContext bindingContext, JetStandardLibrary stdlib, JetClassOrObject aClass, ClassVisitor v) { - super(bindingContext, stdlib, aClass, OwnerKind.INTERFACE, v); + public InterfaceBodyCodegen(BindingContext bindingContext, JetStandardLibrary stdlib, JetClassOrObject aClass, ClassVisitor v, Codegens factory) { + super(bindingContext, stdlib, aClass, OwnerKind.INTERFACE, v, factory); } protected void generateDeclaration() { diff --git a/idea/src/org/jetbrains/jet/codegen/JetTypeMapper.java b/idea/src/org/jetbrains/jet/codegen/JetTypeMapper.java index de54ff43817..3b3b47b05dc 100644 --- a/idea/src/org/jetbrains/jet/codegen/JetTypeMapper.java +++ b/idea/src/org/jetbrains/jet/codegen/JetTypeMapper.java @@ -219,6 +219,38 @@ public class JetTypeMapper { throw new UnsupportedOperationException("Unknown type " + jetType); } + public Type boxType(Type asmType) { + switch (asmType.getSort()) { + case Type.VOID: + return Type.getObjectType("java/lang/Void"); + case Type.BYTE: + return Type.getObjectType("java/lang/Byte"); + case Type.BOOLEAN: + return Type.getObjectType("java/lang/Boolean"); + case Type.SHORT: + return Type.getObjectType("java/lang.Short"); + case Type.CHAR: + return Type.getObjectType("java/lang/Character"); + case Type.INT: + return Type.getObjectType("java/lang/Integer"); + case Type.FLOAT: + return Type.getObjectType("java/lang/Float"); + case Type.LONG: + return Type.getObjectType("java/lang/Long"); + case Type.DOUBLE: + return Type.getObjectType("java/lang/Double"); + } + + return asmType; + } + + + private static Type getBoxedType(final Type type) { + switch (type.getSort()) { + } + return type; + } + public Method mapSignature(JetFunction f) { final JetTypeReference receiverTypeRef = f.getReceiverTypeRef(); final JetType receiverType = receiverTypeRef == null ? null : bindingContext.resolveTypeReference(receiverTypeRef); @@ -243,6 +275,50 @@ public class JetTypeMapper { return new Method(f.getName(), returnType, parameterTypes.toArray(new Type[parameterTypes.size()])); } + public Method mapSignature(String name, FunctionDescriptor f) { + final JetType receiverType = f.getReceiverType(); + final List parameters = f.getUnsubstitutedValueParameters(); + List parameterTypes = new ArrayList(); + if (receiverType != null) { + parameterTypes.add(mapType(receiverType)); + } + for (ValueParameterDescriptor parameter : parameters) { + parameterTypes.add(mapType(parameter.getOutType())); + } + Type returnType = mapType(f.getUnsubstitutedReturnType()); + return new Method(name, returnType, parameterTypes.toArray(new Type[parameterTypes.size()])); + } + + public String genericSignature(FunctionDescriptor f) { + StringBuffer answer = new StringBuffer(); + final List typeParameters = f.getTypeParameters(); + if (!typeParameters.isEmpty()) { + answer.append('<'); + for (TypeParameterDescriptor p : typeParameters) { + appendTypeParameterSignature(answer, p); + } + answer.append('>'); + } + + answer.append('('); + for (ValueParameterDescriptor p : f.getUnsubstitutedValueParameters()) { + appendType(answer, p.getOutType()); + } + answer.append(')'); + + appendType(answer, f.getUnsubstitutedReturnType()); + + return answer.toString(); + } + + private void appendType(StringBuffer answer, JetType type) { + answer.append(mapType(type).getDescriptor()); // TODO: type parameter references! + } + + private void appendTypeParameterSignature(StringBuffer answer, TypeParameterDescriptor p) { + answer.append(p.getName()); // TODO: BOUND! + } + public Method mapGetterSignature(PropertyDescriptor descriptor) { Type returnType = mapType(descriptor.getOutType()); return new Method(PropertyCodegen.getterName(descriptor.getName()), returnType, new Type[0]); diff --git a/idea/src/org/jetbrains/jet/codegen/NamespaceCodegen.java b/idea/src/org/jetbrains/jet/codegen/NamespaceCodegen.java index e4c9af2102a..25a46ad5c44 100644 --- a/idea/src/org/jetbrains/jet/codegen/NamespaceCodegen.java +++ b/idea/src/org/jetbrains/jet/codegen/NamespaceCodegen.java @@ -45,7 +45,7 @@ public class NamespaceCodegen { AnalyzingUtils.applyHandler(ErrorHandler.THROW_EXCEPTION, bindingContext); final JetStandardLibrary standardLibrary = JetStandardLibrary.getJetStandardLibrary(project); - final FunctionCodegen functionCodegen = new FunctionCodegen(namespace, v, standardLibrary, bindingContext); + final FunctionCodegen functionCodegen = new FunctionCodegen(namespace, v, standardLibrary, bindingContext, codegens); final PropertyCodegen propertyCodegen = new PropertyCodegen(v, standardLibrary, bindingContext, functionCodegen); final ClassCodegen classCodegen = codegens.forClass(bindingContext); @@ -81,7 +81,7 @@ public class NamespaceCodegen { FrameMap frameMap = new FrameMap(); JetTypeMapper typeMapper = new JetTypeMapper(JetStandardLibrary.getJetStandardLibrary(namespace.getProject()), bindingContext); - ExpressionCodegen codegen = new ExpressionCodegen(mv, bindingContext, frameMap, typeMapper, Type.VOID_TYPE, null, OwnerKind.NAMESPACE, null); + ExpressionCodegen codegen = new ExpressionCodegen(mv, bindingContext, frameMap, typeMapper, Type.VOID_TYPE, null, OwnerKind.NAMESPACE, null, codegens); for (JetDeclaration declaration : namespace.getDeclarations()) { if (declaration instanceof JetProperty) { diff --git a/idea/src/org/jetbrains/jet/codegen/StackValue.java b/idea/src/org/jetbrains/jet/codegen/StackValue.java index a962ad9d611..35132cddfaf 100644 --- a/idea/src/org/jetbrains/jet/codegen/StackValue.java +++ b/idea/src/org/jetbrains/jet/codegen/StackValue.java @@ -131,13 +131,18 @@ public abstract class StackValue { } protected void coerce(Type type, InstructionAdapter v) { - if (type.getSort() == Type.OBJECT) { + if (type.equals(this.type)) return; + + if (type.getSort() == Type.OBJECT && this.type.getSort() == Type.OBJECT) { + v.checkcast(type); + } + else if (type.getSort() == Type.OBJECT) { box(this.type, type, v); } else if (this.type.getSort() == Type.OBJECT && type.getSort() <= Type.DOUBLE) { unbox(type, v); } - else if (type != this.type) { + else { v.cast(this.type, type); } } diff --git a/idea/testData/codegen/classes/simplestClosure.jet b/idea/testData/codegen/classes/simplestClosure.jet index b8b4a9d032a..20682dfc10a 100644 --- a/idea/testData/codegen/classes/simplestClosure.jet +++ b/idea/testData/codegen/classes/simplestClosure.jet @@ -1,7 +1,7 @@ fun box() : String { - return if (invoker({49}) == 49) "OK" else "fail" + return invoker( {"OK"} ) } -fun invoker(gen : {() : Int}) : Int { +fun invoker(gen : {() : String}) : String { return gen() -} \ No newline at end of file +} diff --git a/idea/tests/org/jetbrains/jet/codegen/CodegenTestCase.java b/idea/tests/org/jetbrains/jet/codegen/CodegenTestCase.java index 29d32ce1b0d..f38ffc9800c 100644 --- a/idea/tests/org/jetbrains/jet/codegen/CodegenTestCase.java +++ b/idea/tests/org/jetbrains/jet/codegen/CodegenTestCase.java @@ -71,9 +71,9 @@ public abstract class CodegenTestCase extends LightCodeInsightFixtureTestCase { } catch (NoClassDefFoundError e) { System.out.println(generateToText()); throw e; - } catch (Exception e) { + } catch (Throwable e) { System.out.println(generateToText()); - throw e; + throw new RuntimeException(e); } assertEquals("OK", actual); } diff --git a/stdlib/src/jet/ExtensionFunction0.java b/stdlib/src/jet/ExtensionFunction0.java new file mode 100644 index 00000000000..099f3bbe3a4 --- /dev/null +++ b/stdlib/src/jet/ExtensionFunction0.java @@ -0,0 +1,13 @@ +/* + * @author max + */ +package jet; + +public abstract class ExtensionFunction0 { + public abstract R invoke(E receiver); + + @Override + public String toString() { + return "{E.() : R}"; + } +} diff --git a/stdlib/src/jet/ExtensionFunction1.java b/stdlib/src/jet/ExtensionFunction1.java new file mode 100644 index 00000000000..782b8ec3948 --- /dev/null +++ b/stdlib/src/jet/ExtensionFunction1.java @@ -0,0 +1,13 @@ +/* + * @author max + */ +package jet; + +public abstract class ExtensionFunction1 { + public abstract R invoke(E receiver, D d); + + @Override + public String toString() { + return "{E.(d: D) : R}"; + } +} diff --git a/stdlib/src/jet/ExtensionFunction2.java b/stdlib/src/jet/ExtensionFunction2.java new file mode 100644 index 00000000000..7c885c741fa --- /dev/null +++ b/stdlib/src/jet/ExtensionFunction2.java @@ -0,0 +1,13 @@ +/* + * @author max + */ +package jet; + +public abstract class ExtensionFunction2 { + public abstract R invoke(E receiver, D1 d1, D2 d2); + + @Override + public String toString() { + return "{E.(d1: D1, d2: D2) : R}"; + } +} diff --git a/stdlib/src/jet/ExtensionFunction3.java b/stdlib/src/jet/ExtensionFunction3.java new file mode 100644 index 00000000000..0b034418dc5 --- /dev/null +++ b/stdlib/src/jet/ExtensionFunction3.java @@ -0,0 +1,13 @@ +/* + * @author max + */ +package jet; + +public abstract class ExtensionFunction3 { + public abstract R invoke(E receiver, D1 d1, D2 d2, D3 d3); + + @Override + public String toString() { + return "{E.(d1: D1, d2: D2, d3: D3) : R}"; + } +} diff --git a/stdlib/src/jet/Function0.java b/stdlib/src/jet/Function0.java new file mode 100644 index 00000000000..917010163f2 --- /dev/null +++ b/stdlib/src/jet/Function0.java @@ -0,0 +1,13 @@ +/* + * @author max + */ +package jet; + +public abstract class Function0 { + public abstract R invoke(); + + @Override + public String toString() { + return "{() : R}"; + } +} diff --git a/stdlib/src/jet/Function1.java b/stdlib/src/jet/Function1.java new file mode 100644 index 00000000000..ba1846107e1 --- /dev/null +++ b/stdlib/src/jet/Function1.java @@ -0,0 +1,13 @@ +/* + * @author max + */ +package jet; + +public abstract class Function1 { + public abstract R invoke(D d); + + @Override + public String toString() { + return "{(d: D) : R}"; + } +} diff --git a/stdlib/src/jet/Function2.java b/stdlib/src/jet/Function2.java new file mode 100644 index 00000000000..801e95c63f0 --- /dev/null +++ b/stdlib/src/jet/Function2.java @@ -0,0 +1,13 @@ +/* + * @author max + */ +package jet; + +public abstract class Function2 { + public abstract R invoke(D1 d1, D2 d2); + + @Override + public String toString() { + return "{(d1: D1, d2: D2) : R}"; + } +} diff --git a/stdlib/src/jet/Function3.java b/stdlib/src/jet/Function3.java new file mode 100644 index 00000000000..81963444c97 --- /dev/null +++ b/stdlib/src/jet/Function3.java @@ -0,0 +1,13 @@ +/* + * @author max + */ +package jet; + +public abstract class Function3 { + public abstract R invoke(D1 d1, D2 d2, D3 d3); + + @Override + public String toString() { + return "{(d1: D1, d2: D2, d3: D3) : R}"; + } +}