diff --git a/compiler/backend/src/org/jetbrains/jet/codegen/ExpressionCodegen.java b/compiler/backend/src/org/jetbrains/jet/codegen/ExpressionCodegen.java index 9a9577e39d4c713ae093beeb86147bfa9962e9f9..e497db59abbb7c5f0574ffbc3b10cba88815584b 100644 --- a/compiler/backend/src/org/jetbrains/jet/codegen/ExpressionCodegen.java +++ b/compiler/backend/src/org/jetbrains/jet/codegen/ExpressionCodegen.java @@ -1529,15 +1529,55 @@ public class ExpressionCodegen extends JetVisitor { Type type = asmType(outType); assert type.getSort() == Type.ARRAY; Type elementType = correctElementType(type); - int size = valueArgument.getArguments().size(); + List arguments = valueArgument.getArguments(); + int size = arguments.size(); - v.iconst(valueArgument.getArguments().size()); - v.newarray(elementType); + boolean hasSpread = false; for(int i = 0; i != size; ++i) { - v.dup(); - v.iconst(i); - gen(valueArgument.getArguments().get(i).getArgumentExpression(), elementType); - StackValue.arrayElement(elementType, false).store(v); + if(arguments.get(i).getSpreadElement() != null) { + hasSpread = true; + break; + } + } + + if(hasSpread) { + if(size == 1) { + gen(arguments.get(0).getArgumentExpression(), type); + } + else { + String owner = "jet/runtime/Intrinsics$SpreadBuilder"; + v.anew(Type.getObjectType(owner)); + v.dup(); + v.invokespecial(owner, "", "()V"); + for(int i = 0; i != size; ++i) { + v.dup(); + ValueArgument argument = arguments.get(i); + if(argument.getSpreadElement() != null) { + gen(argument.getArgumentExpression(),JetTypeMapper.TYPE_OBJECT); + v.invokevirtual(owner, "addSpread", "(Ljava/lang/Object;)V"); + } + else { + gen(argument.getArgumentExpression(), elementType); + v.invokevirtual(owner, "add", "(Ljava/lang/Object;)Z"); + v.pop(); + } + } + v.dup(); + v.invokevirtual(owner, "size", "()I"); + v.newarray(elementType); + v.invokevirtual(owner, "toArray", "([Ljava/lang/Object;)[Ljava/lang/Object;"); + v.checkcast(type); + } + } + else { + v.iconst(arguments.size()); + v.newarray(elementType); + for(int i = 0; i != size; ++i) { + v.dup(); + v.iconst(i); + gen(arguments.get(i).getArgumentExpression(), elementType); + StackValue.arrayElement(elementType, false).store(v); + } } } diff --git a/compiler/backend/src/org/jetbrains/jet/codegen/JetTypeMapper.java b/compiler/backend/src/org/jetbrains/jet/codegen/JetTypeMapper.java index c19b4e25aa9b8c441126e4fee87da03aff5f5f03..68bf1345e79a3bc45c42e92f3afe3eaa819a7288 100644 --- a/compiler/backend/src/org/jetbrains/jet/codegen/JetTypeMapper.java +++ b/compiler/backend/src/org/jetbrains/jet/codegen/JetTypeMapper.java @@ -54,6 +54,7 @@ public class JetTypeMapper { public static final Type TYPE_NOTHING = Type.getObjectType("jet/Nothing"); public static final Type JL_NUMBER_TYPE = Type.getObjectType("java/lang/Number"); public static final Type JL_STRING_BUILDER = Type.getObjectType("java/lang/StringBuilder"); + public static final Type JL_ARRAY_LIST = Type.getObjectType("java/util/ArrayList"); public static final Type JL_STRING_TYPE = Type.getObjectType("java/lang/String"); public static final Type JL_CHAR_SEQUENCE_TYPE = Type.getObjectType("java/lang/CharSequence"); private static final Type JL_COMPARABLE_TYPE = Type.getObjectType("java/lang/Comparable"); diff --git a/compiler/tests/org/jetbrains/jet/codegen/VarArgTest.java b/compiler/tests/org/jetbrains/jet/codegen/VarArgTest.java index 1d3832af4fa77409d3e619e955ff76551ab42726..6164d2dcadaf1e91babf4baa08cb28fa74c29778 100644 --- a/compiler/tests/org/jetbrains/jet/codegen/VarArgTest.java +++ b/compiler/tests/org/jetbrains/jet/codegen/VarArgTest.java @@ -16,8 +16,10 @@ package org.jetbrains.jet.codegen; +import java.lang.reflect.Array; import java.lang.reflect.InvocationTargetException; import java.lang.reflect.Method; +import java.util.Arrays; /** * @author alex.tkachman @@ -94,4 +96,23 @@ public class VarArgTest extends CodegenTestCase { public void testKt797() { blackBoxFile("regressions/kt796_797.jet"); } + + public void testArrayAsVararg () throws InvocationTargetException, IllegalAccessException { + loadText("private fun asList(vararg elems: String) = elems; fun test(ts: Array) = asList(*ts); "); + //System.out.println(generateToText()); + final Method main = generateFunction("test"); + String[] args = {"mama", "papa"}; + assertTrue(args == main.invoke(null, new Object[]{ args } )); + } + + public void testArrayAsVararg2 () throws InvocationTargetException, IllegalAccessException { + loadText("private fun asList(vararg elems: String) = elems; fun test(ts1: Array, ts2: String) = asList(*ts1, ts2); "); + System.out.println(generateToText()); + final Method main = generateFunction("test"); + Object invoke = main.invoke(null, new Object[] {new String[] {"mama"}, "papa" }); + assertInstanceOf(invoke, String[].class); + assertEquals(2, Array.getLength(invoke)); + assertEquals("mama", Array.get(invoke, 0)); + assertEquals("papa", Array.get(invoke, 1)); + } } diff --git a/runtime/src/jet/runtime/Intrinsics.java b/runtime/src/jet/runtime/Intrinsics.java index 1dec800bde7b71e93b4b2dfed5af2fb4b58a02cb..111ef84aa5db459729b45daaf4ec5842cc315f88 100644 --- a/runtime/src/jet/runtime/Intrinsics.java +++ b/runtime/src/jet/runtime/Intrinsics.java @@ -19,6 +19,8 @@ package jet.runtime; import jet.Function0; import java.util.ArrayList; +import java.util.Collection; +import java.util.Iterator; /** * @author alex.tkachman @@ -82,4 +84,36 @@ public class Intrinsics { return sanitizeStackTrace(this); } } + + public static class SpreadBuilder extends ArrayList { + public void addSpread(Object array) { + if(array != null) { + if(array instanceof Object[]) { + Object[] arr = (Object[]) array; + if(arr.length > 0) { + ensureCapacity(size() + arr.length); + for (int i = 0; i < arr.length; i++) { + add(arr[i]); + } + } + } + else if(array instanceof Collection) { + addAll((Collection) array); + } + else if(array instanceof Iterable) { + for(Iterator iterator = ((Iterable) array).iterator(); iterator.hasNext(); ) { + add(iterator.next()); + } + } + else if(array instanceof Iterator) { + for(Iterator iterator = ((Iterator) array); iterator.hasNext(); ) { + add(iterator.next()); + } + } + else { + throw new UnsupportedOperationException("Don't know how to spread " + array.getClass()); + } + } + } + } }