Temporarily prohibit non-local returns for some stdlib functions

Make InlineUtil work with FQ names, not descriptors

 #KT-5496 Fixed
 #KT-5497 Fixed
This commit is contained in:
Alexander Udalov
2014-07-18 20:03:57 +04:00
parent 540b87a1dc
commit 70adb0f4e2
8 changed files with 96 additions and 77 deletions
@@ -0,0 +1,42 @@
import java.io.Closeable
import java.util.concurrent.locks.Lock
import java.util.concurrent.locks.ReentrantReadWriteLock
import kotlin.concurrent.*
// Non-local returns for these functions are temporarily disabled because they contain try-finally blocks and
// the compiler doesn't correctly include the "finally" section into the inlined result.
// Once the compiler is fixed (KT-5506), non-local returns can be re-allowed for these functions
fun testSynchronized(): Int {
synchronized("") {
<!RETURN_NOT_ALLOWED!>return 1<!>
}
<!NO_RETURN_IN_FUNCTION_WITH_BLOCK_BODY!>}<!>
fun testUse(f: Closeable): Int {
f.use {
<!RETURN_NOT_ALLOWED!>return 2<!>
}
<!NO_RETURN_IN_FUNCTION_WITH_BLOCK_BODY!>}<!>
fun testWithLock(l: Lock): Int {
l.withLock {
<!RETURN_NOT_ALLOWED!>return 3<!>
}
<!NO_RETURN_IN_FUNCTION_WITH_BLOCK_BODY!>}<!>
fun testRead(l: ReentrantReadWriteLock): Int {
l.read {
<!RETURN_NOT_ALLOWED!>return 4<!>
}
<!NO_RETURN_IN_FUNCTION_WITH_BLOCK_BODY!>}<!>
fun testWrite(l: ReentrantReadWriteLock): Int {
l.write {
<!RETURN_NOT_ALLOWED!>return 5<!>
}
<!NO_RETURN_IN_FUNCTION_WITH_BLOCK_BODY!>}<!>
@@ -31,7 +31,7 @@ import org.jetbrains.jet.checkers.AbstractJetDiagnosticsTestWithStdLib;
/** This class is generated by {@link org.jetbrains.jet.generators.tests.TestsPackage}. DO NOT MODIFY MANUALLY */
@SuppressWarnings("all")
@TestMetadata("compiler/testData/diagnostics/testsWithStdLib")
@InnerTestClasses({JetDiagnosticsTestWithStdLibGenerated.Annotations.class, JetDiagnosticsTestWithStdLibGenerated.CallableReference.class, JetDiagnosticsTestWithStdLibGenerated.DuplicateJvmSignature.class, JetDiagnosticsTestWithStdLibGenerated.FunctionLiterals.class, JetDiagnosticsTestWithStdLibGenerated.KotlinSignature.class})
@InnerTestClasses({JetDiagnosticsTestWithStdLibGenerated.Annotations.class, JetDiagnosticsTestWithStdLibGenerated.CallableReference.class, JetDiagnosticsTestWithStdLibGenerated.DuplicateJvmSignature.class, JetDiagnosticsTestWithStdLibGenerated.FunctionLiterals.class, JetDiagnosticsTestWithStdLibGenerated.KotlinSignature.class, JetDiagnosticsTestWithStdLibGenerated.NonLocalReturns.class})
public class JetDiagnosticsTestWithStdLibGenerated extends AbstractJetDiagnosticsTestWithStdLib {
public void testAllFilesPresentInTestsWithStdLib() throws Exception {
JetTestUtils.assertAllTestsPresentByMetadata(this.getClass(), "org.jetbrains.jet.generators.tests.TestsPackage", new File("compiler/testData/diagnostics/testsWithStdLib"), Pattern.compile("^(.+)\\.kt$"), true);
@@ -495,6 +495,19 @@ public class JetDiagnosticsTestWithStdLibGenerated extends AbstractJetDiagnostic
}
@TestMetadata("compiler/testData/diagnostics/testsWithStdLib/nonLocalReturns")
public static class NonLocalReturns extends AbstractJetDiagnosticsTestWithStdLib {
public void testAllFilesPresentInNonLocalReturns() throws Exception {
JetTestUtils.assertAllTestsPresentByMetadata(this.getClass(), "org.jetbrains.jet.generators.tests.TestsPackage", new File("compiler/testData/diagnostics/testsWithStdLib/nonLocalReturns"), Pattern.compile("^(.+)\\.kt$"), true);
}
@TestMetadata("prohibitNonLocalReturnOutOfTryCatchFinally.kt")
public void testProhibitNonLocalReturnOutOfTryCatchFinally() throws Exception {
doTest("compiler/testData/diagnostics/testsWithStdLib/nonLocalReturns/prohibitNonLocalReturnOutOfTryCatchFinally.kt");
}
}
public static Test suite() {
TestSuite suite = new TestSuite("JetDiagnosticsTestWithStdLibGenerated");
suite.addTestSuite(JetDiagnosticsTestWithStdLibGenerated.class);
@@ -503,6 +516,7 @@ public class JetDiagnosticsTestWithStdLibGenerated extends AbstractJetDiagnostic
suite.addTestSuite(DuplicateJvmSignature.class);
suite.addTestSuite(FunctionLiterals.class);
suite.addTestSuite(KotlinSignature.class);
suite.addTestSuite(NonLocalReturns.class);
return suite;
}
}
@@ -1,49 +0,0 @@
/*
* Copyright 2010-2014 JetBrains s.r.o.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.jetbrains.jet.lang.types.lang
import org.jetbrains.jet.lang.descriptors.DeclarationDescriptor
import org.jetbrains.jet.lang.descriptors.ClassDescriptor
import org.jetbrains.jet.lang.descriptors.annotations.AnnotationDescriptor
import org.jetbrains.jet.lang.resolve.constants.CompileTimeConstant
import org.jetbrains.jet.lang.descriptors.annotations.Annotations
public object AnnotationUtil {
public fun getAnnotationSingleArgument(descriptor: DeclarationDescriptor, annotationClass: ClassDescriptor) : CompileTimeConstant<out Any?>? {
val annotation = getAnnotation(descriptor.getAnnotations(), annotationClass)
if (annotation != null) {
val parameterDescriptor = annotationClass.getConstructors().elementAt(0).getValueParameters().first
if (parameterDescriptor != null) {
return annotation.getValueArgument(parameterDescriptor)
}
}
return null
}
public fun getAnnotation(annotations: Annotations, annotationClass: ClassDescriptor): AnnotationDescriptor? {
for (annotation in annotations) {
if (annotationClass == annotation.getType().getConstructor().getDeclarationDescriptor()) {
return annotation
}
}
return null
}
}
@@ -16,12 +16,16 @@
package org.jetbrains.jet.lang.types.lang;
import kotlin.KotlinPackage;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import org.jetbrains.jet.lang.descriptors.CallableDescriptor;
import org.jetbrains.jet.lang.descriptors.ClassDescriptor;
import org.jetbrains.jet.lang.descriptors.DeclarationDescriptor;
import org.jetbrains.jet.lang.descriptors.ValueParameterDescriptor;
import org.jetbrains.jet.lang.descriptors.annotations.Annotated;
import org.jetbrains.jet.lang.descriptors.annotations.AnnotationDescriptor;
import org.jetbrains.jet.lang.resolve.DescriptorUtils;
import org.jetbrains.jet.lang.resolve.constants.ArrayValue;
import org.jetbrains.jet.lang.resolve.constants.CompileTimeConstant;
import org.jetbrains.jet.lang.resolve.constants.EnumValue;
@@ -31,29 +35,23 @@ import java.util.List;
public class InlineUtil {
public static boolean hasNoinlineAnnotation(@NotNull CallableDescriptor valueParameterDescriptor) {
KotlinBuiltIns builtIns = KotlinBuiltIns.getInstance();
return KotlinBuiltIns.containsAnnotation(valueParameterDescriptor, builtIns.getNoinlineClassAnnotation());
return KotlinBuiltIns.containsAnnotation(valueParameterDescriptor, KotlinBuiltIns.getInstance().getNoinlineClassAnnotation());
}
@NotNull
public static InlineStrategy getInlineType(@NotNull DeclarationDescriptor descriptor) {
ClassDescriptor annotationClass = KotlinBuiltIns.getInstance().getInlineClassAnnotation();
AnnotationDescriptor annotation = AnnotationUtil.instance$.getAnnotation(descriptor.getAnnotations(), annotationClass);
if (annotation != null) {
CompileTimeConstant<?> argument = AnnotationUtil.instance$.getAnnotationSingleArgument(descriptor, annotationClass);
if (argument == null) {
//default parameter
return InlineStrategy.AS_FUNCTION;
}
else {
assert argument instanceof EnumValue : "Inline annotation parameter should be inline entry but was: " + argument + "!";
String name = ((EnumValue) argument).getValue().getName().asString();
return name.equals(InlineStrategy.IN_PLACE.name()) ? InlineStrategy.IN_PLACE : InlineStrategy.AS_FUNCTION;
}
}
else {
ClassDescriptor inlineAnnotation = KotlinBuiltIns.getInstance().getInlineClassAnnotation();
AnnotationDescriptor annotation = descriptor.getAnnotations().findAnnotation(DescriptorUtils.getFqNameSafe(inlineAnnotation));
if (annotation == null) {
return InlineStrategy.NOT_INLINE;
}
CompileTimeConstant<?> argument = getAnnotationSingleArgument(descriptor, inlineAnnotation);
if (argument == null) {
return InlineStrategy.AS_FUNCTION;
}
assert argument instanceof EnumValue : "Inline annotation parameter should be enum entry but was: " + argument;
String name = ((EnumValue) argument).getValue().getName().asString();
return name.equals(InlineStrategy.IN_PLACE.name()) ? InlineStrategy.IN_PLACE : InlineStrategy.AS_FUNCTION;
}
public static boolean hasOnlyLocalContinueAndBreak(@NotNull ValueParameterDescriptor descriptor) {
@@ -66,8 +64,7 @@ public class InlineUtil {
private static boolean hasInlineOption(@NotNull ValueParameterDescriptor descriptor, @NotNull InlineOption option) {
CompileTimeConstant<?> argument =
AnnotationUtil.instance$.getAnnotationSingleArgument(descriptor, KotlinBuiltIns.getInstance()
.getInlineOptionsClassAnnotation());
getAnnotationSingleArgument(descriptor, KotlinBuiltIns.getInstance().getInlineOptionsClassAnnotation());
if (argument instanceof ArrayValue) {
List<CompileTimeConstant<?>> values = ((ArrayValue) argument).getValue();
@@ -83,5 +80,16 @@ public class InlineUtil {
return false;
}
}
@Nullable
private static CompileTimeConstant<?> getAnnotationSingleArgument(
@NotNull Annotated annotated,
@NotNull ClassDescriptor annotationClass
) {
AnnotationDescriptor annotation = annotated.getAnnotations().findAnnotation(DescriptorUtils.getFqNameSafe(annotationClass));
if (annotation != null) {
return KotlinPackage.firstOrNull(annotation.getAllValueArguments().values());
}
return null;
}
}
+2 -1
View File
@@ -4,6 +4,7 @@ import java.lang.annotation.Retention
import java.lang.annotation.RetentionPolicy
import kotlin.jvm.internal.unsafe.*
import kotlin.jvm.internal.Intrinsic
import kotlin.InlineOption.ONLY_LOCAL_RETURN
/**
* This annotation indicates what exceptions should be declared by a function when compiled to a JVM method
@@ -25,7 +26,7 @@ public annotation class throws(vararg val exceptionClasses: Class<out Throwable>
[Intrinsic("kotlin.javaClass.function")] fun <reified T> javaClass() : Class<T> = null as Class<T>
public inline fun <R> synchronized(lock: Any, block: () -> R): R {
public inline fun <R> synchronized(lock: Any, [inlineOptions(ONLY_LOCAL_RETURN)] block: () -> R): R {
monitorEnter(lock)
try {
return block()
@@ -5,12 +5,13 @@ import java.util.concurrent.locks.ReadWriteLock
import java.util.concurrent.locks.ReentrantReadWriteLock
import java.util.concurrent.locks.ReentrantReadWriteLock.ReadLock
import java.util.concurrent.CountDownLatch
import kotlin.InlineOption.ONLY_LOCAL_RETURN
/**
Executes given calculation under lock
Returns result of the calculation
*/
public inline fun <T> Lock.withLock(action: ()->T) : T {
public inline fun <T> Lock.withLock([inlineOptions(ONLY_LOCAL_RETURN)] action: () -> T): T {
lock()
try {
return action()
@@ -24,7 +25,7 @@ public inline fun <T> Lock.withLock(action: ()->T) : T {
Executes given calculation under read lock
Returns result of the calculation
*/
public inline fun <T> ReentrantReadWriteLock.read(action: ()->T) : T {
public inline fun <T> ReentrantReadWriteLock.read([inlineOptions(ONLY_LOCAL_RETURN)] action: () -> T): T {
val rl = readLock()
rl.lock()
try {
@@ -41,7 +42,7 @@ The method does upgrade from read to write lock if needed
If such write has been initiated by checking some condition, the condition must be rechecked inside the action to avoid possible races
Returns result of the calculation
*/
public inline fun <T> ReentrantReadWriteLock.write(action: ()->T) : T {
public inline fun <T> ReentrantReadWriteLock.write([inlineOptions(ONLY_LOCAL_RETURN)] action: () -> T): T {
val rl = readLock()
val readCount = if (getWriteHoldCount() == 0) getReadHoldCount() else 0
@@ -62,7 +63,7 @@ public inline fun <T> ReentrantReadWriteLock.write(action: ()->T) : T {
Execute given calculation and await for CountDownLatch
Returns result of the calculation
*/
fun <T> Int.latch(op: CountDownLatch.() -> T) : T {
fun <T> Int.latch(op: CountDownLatch.() -> T) : T {
val cdl = CountDownLatch(this)
val res = cdl.op()
cdl.await()
+2 -1
View File
@@ -1,9 +1,10 @@
package kotlin
import java.io.Closeable
import kotlin.InlineOption.ONLY_LOCAL_RETURN
/** Uses the given resource then closes it down correctly whether an exception is thrown or not */
public inline fun <T : Closeable, R> T.use(block: (T) -> R): R {
public inline fun <T : Closeable, R> T.use([inlineOptions(ONLY_LOCAL_RETURN)] block: (T) -> R): R {
var closed = false
try {
return block(this)
+2 -1
View File
@@ -4,6 +4,7 @@ import java.io.*
import java.nio.charset.*
import java.util.NoSuchElementException
import java.net.URL
import kotlin.InlineOption.ONLY_LOCAL_RETURN
/**
* Returns the default buffer size when working with buffered streams
@@ -198,7 +199,7 @@ public fun Writer.buffered(bufferSize: Int = defaultBufferSize): BufferedWriter
*/
public fun Reader.forEachLine(block: (String) -> Unit): Unit = useLines { lines -> lines.forEach(block) }
public inline fun <T> Reader.useLines(block: (Stream<String>) -> T): T =
public inline fun <T> Reader.useLines([inlineOptions(ONLY_LOCAL_RETURN)] block: (Stream<String>) -> T): T =
this.buffered().use { block(it.lines()) }
/**