Do not generate accessor if private function is accessed from

coroutines intrinsic lambda.
The logic is if the lambda is crossinline we need to generate the
accessor. However, suspendCoroutine's and
suspendCoroutineUninterceptedOrReturn's parameter, despite being
crossinline, are effectively inline. Thus, we do not need to generate
the accessor.
 #KT-27503 Fixed
This commit is contained in:
Ilmir Usmanov
2019-07-24 20:50:50 +03:00
parent b3e80e6a14
commit a35d405892
21 changed files with 119 additions and 73 deletions
@@ -1,24 +1,20 @@
/*
* Copyright 2010-2015 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.
* Copyright 2010-2019 JetBrains s.r.o. and Kotlin Programming Language contributors.
* Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
*/
package org.jetbrains.kotlin.codegen.context
import org.jetbrains.kotlin.backend.common.isBuiltInSuspendCoroutineUninterceptedOrReturn
import org.jetbrains.kotlin.codegen.OwnerKind
import org.jetbrains.kotlin.codegen.binding.MutableClosure
import org.jetbrains.kotlin.config.coroutinesPackageFqName
import org.jetbrains.kotlin.descriptors.FunctionDescriptor
import org.jetbrains.kotlin.descriptors.impl.AnonymousFunctionDescriptor
import org.jetbrains.kotlin.descriptors.isTopLevelInPackage
import org.jetbrains.kotlin.psi.KtElement
import org.jetbrains.kotlin.resolve.calls.callUtil.getParentResolvedCall
import org.jetbrains.kotlin.resolve.source.getPsi
class InlineLambdaContext(
functionDescriptor: FunctionDescriptor,
@@ -30,7 +26,7 @@ class InlineLambdaContext(
) : MethodContext(functionDescriptor, contextKind, parentContext, closure, false) {
override fun getFirstCrossInlineOrNonInlineContext(): CodegenContext<*> {
if (isCrossInline) return this
if (isCrossInline && !isSuspendIntrinsicParameter()) return this
val parent = if (isPropertyReference) parentContext as? AnonymousClassContext else { parentContext as? ClosureContext } ?:
throw AssertionError(
@@ -43,4 +39,12 @@ class InlineLambdaContext(
return grandParent.firstCrossInlineOrNonInlineContext
}
// suspendCoroutine and suspendCoroutineUninterceptedOrReturn accept crossinline parameter, but it is effectively inline
private fun isSuspendIntrinsicParameter(): Boolean {
if (contextDescriptor !is AnonymousFunctionDescriptor) return false
val resolvedCall = (contextDescriptor.source.getPsi() as? KtElement).getParentResolvedCall(state.bindingContext) ?: return false
val descriptor = resolvedCall.resultingDescriptor as? FunctionDescriptor ?: return false
return descriptor.isBuiltInSuspendCoroutineUninterceptedOrReturn(state.languageVersionSettings)
|| descriptor.isTopLevelInPackage("suspendCoroutine", state.languageVersionSettings.coroutinesPackageFqName().asString())
}
}
@@ -0,0 +1,9 @@
// WITH_RUNTIME
// COMMON_COROUTINES_TEST
import COROUTINES_PACKAGE.*
private fun foo() {}
private suspend fun bar() = suspendCoroutine<Unit> {
foo()
}
@@ -0,0 +1,5 @@
@kotlin.Metadata
public final class PrivateAccessorKt {
synthetic final static @org.jetbrains.annotations.Nullable method bar(@org.jetbrains.annotations.NotNull p0: kotlin.coroutines.experimental.Continuation): java.lang.Object
private final static method foo(): void
}
@@ -0,0 +1,5 @@
@kotlin.Metadata
public final class PrivateAccessorKt {
synthetic final static @org.jetbrains.annotations.Nullable method bar(@org.jetbrains.annotations.NotNull p0: kotlin.coroutines.Continuation): java.lang.Object
private final static method foo(): void
}
@@ -25,10 +25,6 @@ public class BytecodeListingTestGenerated extends AbstractBytecodeListingTest {
KotlinTestUtils.runTest(this::doTest, TargetBackend.ANY, testDataFilePath);
}
private void runTestWithPackageReplacement(String testDataFilePath, String packageName) throws Exception {
KotlinTestUtils.runTest(filePath -> doTestWithCoroutinesPackageReplacement(filePath, packageName), TargetBackend.ANY, testDataFilePath);
}
public void testAllFilesPresentInBytecodeListing() throws Exception {
KotlinTestUtils.assertAllTestsPresentByMetadata(this.getClass(), new File("compiler/testData/codegen/bytecodeListing"), Pattern.compile("^(.+)\\.kt$"), TargetBackend.ANY, true);
}
@@ -53,26 +49,6 @@ public class BytecodeListingTestGenerated extends AbstractBytecodeListingTest {
runTest("compiler/testData/codegen/bytecodeListing/companionObjectVisibility_lv13.kt");
}
@TestMetadata("coroutineContextIntrinsic.kt")
public void testCoroutineContextIntrinsic_1_2() throws Exception {
runTestWithPackageReplacement("compiler/testData/codegen/bytecodeListing/coroutineContextIntrinsic.kt", "kotlin.coroutines.experimental");
}
@TestMetadata("coroutineContextIntrinsic.kt")
public void testCoroutineContextIntrinsic_1_3() throws Exception {
runTestWithPackageReplacement("compiler/testData/codegen/bytecodeListing/coroutineContextIntrinsic.kt", "kotlin.coroutines");
}
@TestMetadata("coroutineFields.kt")
public void testCoroutineFields_1_2() throws Exception {
runTestWithPackageReplacement("compiler/testData/codegen/bytecodeListing/coroutineFields.kt", "kotlin.coroutines.experimental");
}
@TestMetadata("coroutineFields.kt")
public void testCoroutineFields_1_3() throws Exception {
runTestWithPackageReplacement("compiler/testData/codegen/bytecodeListing/coroutineFields.kt", "kotlin.coroutines");
}
@TestMetadata("defaultImpls.kt")
public void testDefaultImpls() throws Exception {
runTest("compiler/testData/codegen/bytecodeListing/defaultImpls.kt");
@@ -118,51 +94,16 @@ public class BytecodeListingTestGenerated extends AbstractBytecodeListingTest {
runTest("compiler/testData/codegen/bytecodeListing/noToArrayInJava.kt");
}
@TestMetadata("oomInReturnUnit.kt")
public void testOomInReturnUnit_1_2() throws Exception {
runTestWithPackageReplacement("compiler/testData/codegen/bytecodeListing/oomInReturnUnit.kt", "kotlin.coroutines.experimental");
}
@TestMetadata("oomInReturnUnit.kt")
public void testOomInReturnUnit_1_3() throws Exception {
runTestWithPackageReplacement("compiler/testData/codegen/bytecodeListing/oomInReturnUnit.kt", "kotlin.coroutines");
}
@TestMetadata("privateDefaultSetter.kt")
public void testPrivateDefaultSetter() throws Exception {
runTest("compiler/testData/codegen/bytecodeListing/privateDefaultSetter.kt");
}
@TestMetadata("privateSuspendFun.kt")
public void testPrivateSuspendFun() throws Exception {
runTest("compiler/testData/codegen/bytecodeListing/privateSuspendFun.kt");
}
@TestMetadata("samAdapterAndInlinedOne.kt")
public void testSamAdapterAndInlinedOne() throws Exception {
runTest("compiler/testData/codegen/bytecodeListing/samAdapterAndInlinedOne.kt");
}
@TestMetadata("suspendReifiedFun.kt")
public void testSuspendReifiedFun_1_2() throws Exception {
runTestWithPackageReplacement("compiler/testData/codegen/bytecodeListing/suspendReifiedFun.kt", "kotlin.coroutines.experimental");
}
@TestMetadata("suspendReifiedFun.kt")
public void testSuspendReifiedFun_1_3() throws Exception {
runTestWithPackageReplacement("compiler/testData/codegen/bytecodeListing/suspendReifiedFun.kt", "kotlin.coroutines");
}
@TestMetadata("tcoContinuation.kt")
public void testTcoContinuation_1_2() throws Exception {
runTestWithPackageReplacement("compiler/testData/codegen/bytecodeListing/tcoContinuation.kt", "kotlin.coroutines.experimental");
}
@TestMetadata("tcoContinuation.kt")
public void testTcoContinuation_1_3() throws Exception {
runTestWithPackageReplacement("compiler/testData/codegen/bytecodeListing/tcoContinuation.kt", "kotlin.coroutines");
}
@TestMetadata("compiler/testData/codegen/bytecodeListing/annotations")
@TestDataPath("$PROJECT_ROOT")
@RunWith(JUnit3RunnerWithInners.class)
@@ -259,6 +200,88 @@ public class BytecodeListingTestGenerated extends AbstractBytecodeListingTest {
}
}
@TestMetadata("compiler/testData/codegen/bytecodeListing/coroutines")
@TestDataPath("$PROJECT_ROOT")
@RunWith(JUnit3RunnerWithInners.class)
public static class Coroutines extends AbstractBytecodeListingTest {
private void runTest(String testDataFilePath) throws Exception {
KotlinTestUtils.runTest(this::doTest, TargetBackend.ANY, testDataFilePath);
}
private void runTestWithPackageReplacement(String testDataFilePath, String packageName) throws Exception {
KotlinTestUtils.runTest(filePath -> doTestWithCoroutinesPackageReplacement(filePath, packageName), TargetBackend.ANY, testDataFilePath);
}
public void testAllFilesPresentInCoroutines() throws Exception {
KotlinTestUtils.assertAllTestsPresentByMetadata(this.getClass(), new File("compiler/testData/codegen/bytecodeListing/coroutines"), Pattern.compile("^(.+)\\.kt$"), TargetBackend.ANY, true);
}
@TestMetadata("coroutineContextIntrinsic.kt")
public void testCoroutineContextIntrinsic_1_2() throws Exception {
runTestWithPackageReplacement("compiler/testData/codegen/bytecodeListing/coroutines/coroutineContextIntrinsic.kt", "kotlin.coroutines.experimental");
}
@TestMetadata("coroutineContextIntrinsic.kt")
public void testCoroutineContextIntrinsic_1_3() throws Exception {
runTestWithPackageReplacement("compiler/testData/codegen/bytecodeListing/coroutines/coroutineContextIntrinsic.kt", "kotlin.coroutines");
}
@TestMetadata("coroutineFields.kt")
public void testCoroutineFields_1_2() throws Exception {
runTestWithPackageReplacement("compiler/testData/codegen/bytecodeListing/coroutines/coroutineFields.kt", "kotlin.coroutines.experimental");
}
@TestMetadata("coroutineFields.kt")
public void testCoroutineFields_1_3() throws Exception {
runTestWithPackageReplacement("compiler/testData/codegen/bytecodeListing/coroutines/coroutineFields.kt", "kotlin.coroutines");
}
@TestMetadata("oomInReturnUnit.kt")
public void testOomInReturnUnit_1_2() throws Exception {
runTestWithPackageReplacement("compiler/testData/codegen/bytecodeListing/coroutines/oomInReturnUnit.kt", "kotlin.coroutines.experimental");
}
@TestMetadata("oomInReturnUnit.kt")
public void testOomInReturnUnit_1_3() throws Exception {
runTestWithPackageReplacement("compiler/testData/codegen/bytecodeListing/coroutines/oomInReturnUnit.kt", "kotlin.coroutines");
}
@TestMetadata("privateAccessor.kt")
public void testPrivateAccessor_1_2() throws Exception {
runTestWithPackageReplacement("compiler/testData/codegen/bytecodeListing/coroutines/privateAccessor.kt", "kotlin.coroutines.experimental");
}
@TestMetadata("privateAccessor.kt")
public void testPrivateAccessor_1_3() throws Exception {
runTestWithPackageReplacement("compiler/testData/codegen/bytecodeListing/coroutines/privateAccessor.kt", "kotlin.coroutines");
}
@TestMetadata("privateSuspendFun.kt")
public void testPrivateSuspendFun() throws Exception {
runTest("compiler/testData/codegen/bytecodeListing/coroutines/privateSuspendFun.kt");
}
@TestMetadata("suspendReifiedFun.kt")
public void testSuspendReifiedFun_1_2() throws Exception {
runTestWithPackageReplacement("compiler/testData/codegen/bytecodeListing/coroutines/suspendReifiedFun.kt", "kotlin.coroutines.experimental");
}
@TestMetadata("suspendReifiedFun.kt")
public void testSuspendReifiedFun_1_3() throws Exception {
runTestWithPackageReplacement("compiler/testData/codegen/bytecodeListing/coroutines/suspendReifiedFun.kt", "kotlin.coroutines");
}
@TestMetadata("tcoContinuation.kt")
public void testTcoContinuation_1_2() throws Exception {
runTestWithPackageReplacement("compiler/testData/codegen/bytecodeListing/coroutines/tcoContinuation.kt", "kotlin.coroutines.experimental");
}
@TestMetadata("tcoContinuation.kt")
public void testTcoContinuation_1_3() throws Exception {
runTestWithPackageReplacement("compiler/testData/codegen/bytecodeListing/coroutines/tcoContinuation.kt", "kotlin.coroutines");
}
}
@TestMetadata("compiler/testData/codegen/bytecodeListing/inline")
@TestDataPath("$PROJECT_ROOT")
@RunWith(JUnit3RunnerWithInners.class)