From a02d1b75b895295e631057c6088426fc5d9ba90d Mon Sep 17 00:00:00 2001 From: Alexander Udalov Date: Wed, 27 Jan 2016 19:52:39 +0300 Subject: [PATCH] Mark array constructors with 'inline' To allow non-local returns from lambdas passed to them --- .../kotlin/resolve/inline/InlineUtil.java | 32 +++++++++---------- compiler/testData/builtin-classes-kotlin.txt | 2 +- .../arrays/nonLocalReturnArrayConstructor.kt | 21 ++++++++++++ .../reified/arraysReification/jaggedArray.kt | 2 +- .../reified/arraysReification/jaggedDeep.kt | 2 +- ...lackBoxWithStdlibCodegenTestGenerated.java | 6 ++++ core/builtins/native/kotlin/Array.kt | 10 ++++-- core/builtins/native/kotlin/Arrays.kt | 16 +++++----- .../kotlin/generators/builtins/arrays.kt | 2 +- 9 files changed, 62 insertions(+), 31 deletions(-) create mode 100644 compiler/testData/codegen/boxWithStdlib/arrays/nonLocalReturnArrayConstructor.kt diff --git a/compiler/frontend/src/org/jetbrains/kotlin/resolve/inline/InlineUtil.java b/compiler/frontend/src/org/jetbrains/kotlin/resolve/inline/InlineUtil.java index 9ba18a80c66..b05db6a4e10 100644 --- a/compiler/frontend/src/org/jetbrains/kotlin/resolve/inline/InlineUtil.java +++ b/compiler/frontend/src/org/jetbrains/kotlin/resolve/inline/InlineUtil.java @@ -111,22 +111,22 @@ public class InlineUtil { if (!canBeInlineArgument(argument)) return null; KtExpression call = KtPsiUtil.getParentCallIfPresent(argument); - if (call != null) { - ResolvedCall resolvedCall = CallUtilKt.getResolvedCall(call, bindingContext); - if (resolvedCall != null && isInline(resolvedCall.getResultingDescriptor())) { - ValueArgument valueArgument = CallUtilKt.getValueArgumentForExpression(resolvedCall.getCall(), argument); - if (valueArgument != null) { - ArgumentMapping mapping = resolvedCall.getArgumentMapping(valueArgument); - if (mapping instanceof ArgumentMatch) { - ValueParameterDescriptor parameter = ((ArgumentMatch) mapping).getValueParameter(); - if (isInlineLambdaParameter(parameter)) { - return parameter; - } - } - } - } - } - return null; + if (call == null) return null; + + ResolvedCall resolvedCall = CallUtilKt.getResolvedCall(call, bindingContext); + if (resolvedCall == null) return null; + + CallableDescriptor descriptor = resolvedCall.getResultingDescriptor(); + if (!isInline(descriptor) && !isArrayConstructorWithLambda(descriptor)) return null; + + ValueArgument valueArgument = CallUtilKt.getValueArgumentForExpression(resolvedCall.getCall(), argument); + if (valueArgument == null) return null; + + ArgumentMapping mapping = resolvedCall.getArgumentMapping(valueArgument); + if (!(mapping instanceof ArgumentMatch)) return null; + + ValueParameterDescriptor parameter = ((ArgumentMatch) mapping).getValueParameter(); + return isInlineLambdaParameter(parameter) ? parameter : null; } public static boolean canBeInlineArgument(@Nullable PsiElement functionalExpression) { diff --git a/compiler/testData/builtin-classes-kotlin.txt b/compiler/testData/builtin-classes-kotlin.txt index 8c219a655e9..bc4f558fa6c 100644 --- a/compiler/testData/builtin-classes-kotlin.txt +++ b/compiler/testData/builtin-classes-kotlin.txt @@ -22,7 +22,7 @@ public open class Any { } public final class Array : kotlin.Cloneable { - /*primary*/ public constructor Array(/*0*/ size: kotlin.Int, /*1*/ init: (kotlin.Int) -> T) + public constructor Array(/*0*/ size: kotlin.Int, /*1*/ init: (kotlin.Int) -> T) public final val size: kotlin.Int public final fun (): kotlin.Int public open override /*1*/ fun clone(): kotlin.Array diff --git a/compiler/testData/codegen/boxWithStdlib/arrays/nonLocalReturnArrayConstructor.kt b/compiler/testData/codegen/boxWithStdlib/arrays/nonLocalReturnArrayConstructor.kt new file mode 100644 index 00000000000..af97eb16c72 --- /dev/null +++ b/compiler/testData/codegen/boxWithStdlib/arrays/nonLocalReturnArrayConstructor.kt @@ -0,0 +1,21 @@ +fun testArray() { + Array(5) { i -> + if (i == 3) return + i.toString() + } + throw AssertionError() +} + +fun testIntArray() { + IntArray(5) { i -> + if (i == 3) return + i + } + throw AssertionError() +} + +fun box(): String { + testArray() + testIntArray() + return "OK" +} diff --git a/compiler/testData/codegen/boxWithStdlib/reified/arraysReification/jaggedArray.kt b/compiler/testData/codegen/boxWithStdlib/reified/arraysReification/jaggedArray.kt index 9b20ee1ca1a..1a2bee24db9 100644 --- a/compiler/testData/codegen/boxWithStdlib/reified/arraysReification/jaggedArray.kt +++ b/compiler/testData/codegen/boxWithStdlib/reified/arraysReification/jaggedArray.kt @@ -1,4 +1,4 @@ -inline fun jaggedArray(crossinline x: (Int, Int) -> T): Array> = Array(1) { i -> +inline fun jaggedArray(x: (Int, Int) -> T): Array> = Array(1) { i -> Array(1) { j -> x(i, j) } } diff --git a/compiler/testData/codegen/boxWithStdlib/reified/arraysReification/jaggedDeep.kt b/compiler/testData/codegen/boxWithStdlib/reified/arraysReification/jaggedDeep.kt index 1ae45dea39b..aa8f36fc23e 100644 --- a/compiler/testData/codegen/boxWithStdlib/reified/arraysReification/jaggedDeep.kt +++ b/compiler/testData/codegen/boxWithStdlib/reified/arraysReification/jaggedDeep.kt @@ -1,4 +1,4 @@ -inline fun jaggedArray(crossinline x: (Int, Int, Int) -> T): Array>> = Array(1) { i -> +inline fun jaggedArray(x: (Int, Int, Int) -> T): Array>> = Array(1) { i -> Array(1) { j -> Array(1) { k -> x(i, j, k) } } diff --git a/compiler/tests/org/jetbrains/kotlin/codegen/generated/BlackBoxWithStdlibCodegenTestGenerated.java b/compiler/tests/org/jetbrains/kotlin/codegen/generated/BlackBoxWithStdlibCodegenTestGenerated.java index 201a877bb92..032979d892d 100644 --- a/compiler/tests/org/jetbrains/kotlin/codegen/generated/BlackBoxWithStdlibCodegenTestGenerated.java +++ b/compiler/tests/org/jetbrains/kotlin/codegen/generated/BlackBoxWithStdlibCodegenTestGenerated.java @@ -286,6 +286,12 @@ public class BlackBoxWithStdlibCodegenTestGenerated extends AbstractBlackBoxCode doTestWithStdlib(fileName); } + @TestMetadata("nonLocalReturnArrayConstructor.kt") + public void testNonLocalReturnArrayConstructor() throws Exception { + String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/boxWithStdlib/arrays/nonLocalReturnArrayConstructor.kt"); + doTestWithStdlib(fileName); + } + @TestMetadata("nonNullArray.kt") public void testNonNullArray() throws Exception { String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/boxWithStdlib/arrays/nonNullArray.kt"); diff --git a/core/builtins/native/kotlin/Array.kt b/core/builtins/native/kotlin/Array.kt index b2dfcbdd8c5..ec7b9191508 100644 --- a/core/builtins/native/kotlin/Array.kt +++ b/core/builtins/native/kotlin/Array.kt @@ -22,10 +22,14 @@ package kotlin * standard library functions. * See [Kotlin language documentation](http://kotlinlang.org/docs/reference/basic-types.html#arrays) * for more information on arrays. - * @constructor Creates a new array with the specified [size], where each element is calculated by calling the specified - * [init] function. The [init] function returns an array element given its index. */ -public class Array(size: Int, init: (Int) -> T): Cloneable { +public class Array : Cloneable { + /** + * Creates a new array with the specified [size], where each element is calculated by calling the specified + * [init] function. The [init] function returns an array element given its index. + */ + public inline constructor(size: Int, init: (Int) -> T) + /** * Returns the array element at the specified [index]. This method can be called using the * index operator: diff --git a/core/builtins/native/kotlin/Arrays.kt b/core/builtins/native/kotlin/Arrays.kt index 38e5c160637..2b77cb99976 100644 --- a/core/builtins/native/kotlin/Arrays.kt +++ b/core/builtins/native/kotlin/Arrays.kt @@ -27,7 +27,7 @@ public class ByteArray(size: Int) : Cloneable { * Creates a new array of the specified [size], where each element is calculated by calling the specified * [init] function. The [init] function returns an array element given its index. */ - public constructor(size: Int, init: (Int) -> Byte) + public inline constructor(size: Int, init: (Int) -> Byte) /** Returns the array element at the given [index]. This method can be called using the index operator. */ public operator fun get(index: Int): Byte @@ -52,7 +52,7 @@ public class CharArray(size: Int) : Cloneable { * Creates a new array of the specified [size], where each element is calculated by calling the specified * [init] function. The [init] function returns an array element given its index. */ - public constructor(size: Int, init: (Int) -> Char) + public inline constructor(size: Int, init: (Int) -> Char) /** Returns the array element at the given [index]. This method can be called using the index operator. */ public operator fun get(index: Int): Char @@ -77,7 +77,7 @@ public class ShortArray(size: Int) : Cloneable { * Creates a new array of the specified [size], where each element is calculated by calling the specified * [init] function. The [init] function returns an array element given its index. */ - public constructor(size: Int, init: (Int) -> Short) + public inline constructor(size: Int, init: (Int) -> Short) /** Returns the array element at the given [index]. This method can be called using the index operator. */ public operator fun get(index: Int): Short @@ -102,7 +102,7 @@ public class IntArray(size: Int) : Cloneable { * Creates a new array of the specified [size], where each element is calculated by calling the specified * [init] function. The [init] function returns an array element given its index. */ - public constructor(size: Int, init: (Int) -> Int) + public inline constructor(size: Int, init: (Int) -> Int) /** Returns the array element at the given [index]. This method can be called using the index operator. */ public operator fun get(index: Int): Int @@ -127,7 +127,7 @@ public class LongArray(size: Int) : Cloneable { * Creates a new array of the specified [size], where each element is calculated by calling the specified * [init] function. The [init] function returns an array element given its index. */ - public constructor(size: Int, init: (Int) -> Long) + public inline constructor(size: Int, init: (Int) -> Long) /** Returns the array element at the given [index]. This method can be called using the index operator. */ public operator fun get(index: Int): Long @@ -152,7 +152,7 @@ public class FloatArray(size: Int) : Cloneable { * Creates a new array of the specified [size], where each element is calculated by calling the specified * [init] function. The [init] function returns an array element given its index. */ - public constructor(size: Int, init: (Int) -> Float) + public inline constructor(size: Int, init: (Int) -> Float) /** Returns the array element at the given [index]. This method can be called using the index operator. */ public operator fun get(index: Int): Float @@ -177,7 +177,7 @@ public class DoubleArray(size: Int) : Cloneable { * Creates a new array of the specified [size], where each element is calculated by calling the specified * [init] function. The [init] function returns an array element given its index. */ - public constructor(size: Int, init: (Int) -> Double) + public inline constructor(size: Int, init: (Int) -> Double) /** Returns the array element at the given [index]. This method can be called using the index operator. */ public operator fun get(index: Int): Double @@ -202,7 +202,7 @@ public class BooleanArray(size: Int) : Cloneable { * Creates a new array of the specified [size], where each element is calculated by calling the specified * [init] function. The [init] function returns an array element given its index. */ - public constructor(size: Int, init: (Int) -> Boolean) + public inline constructor(size: Int, init: (Int) -> Boolean) /** Returns the array element at the given [index]. This method can be called using the index operator. */ public operator fun get(index: Int): Boolean diff --git a/generators/src/org/jetbrains/kotlin/generators/builtins/arrays.kt b/generators/src/org/jetbrains/kotlin/generators/builtins/arrays.kt index a84a905c29a..aa95a049474 100644 --- a/generators/src/org/jetbrains/kotlin/generators/builtins/arrays.kt +++ b/generators/src/org/jetbrains/kotlin/generators/builtins/arrays.kt @@ -37,7 +37,7 @@ class GenerateArrays(out: PrintWriter) : BuiltInsSourceGenerator(out) { out.println(" * Creates a new array of the specified [size], where each element is calculated by calling the specified") out.println(" * [init] function. The [init] function returns an array element given its index.") out.println(" */") - out.println(" public constructor(size: Int, init: (Int) -> $s)") + out.println(" public inline constructor(size: Int, init: (Int) -> $s)") out.println() out.println(" /** Returns the array element at the given [index]. This method can be called using the index operator. */") out.println(" public operator fun get(index: Int): $s")