Support default property reference inlining

This commit is contained in:
Mikhael Bogdanov
2017-05-15 18:21:10 +02:00
parent a96fada230
commit 05d2aa700b
9 changed files with 151 additions and 9 deletions
@@ -33,6 +33,8 @@ import org.jetbrains.kotlin.resolve.BindingContext
import org.jetbrains.kotlin.resolve.calls.callUtil.getResolvedCallWithAssert
import org.jetbrains.kotlin.resolve.jvm.AsmTypes
import org.jetbrains.kotlin.util.OperatorNameConventions
import org.jetbrains.org.objectweb.asm.ClassReader
import org.jetbrains.org.objectweb.asm.ClassVisitor
import org.jetbrains.org.objectweb.asm.Type
import org.jetbrains.org.objectweb.asm.commons.Method
import org.jetbrains.org.objectweb.asm.tree.FieldInsnNode
@@ -90,10 +92,7 @@ class DefaultLambda(
override lateinit var invokeMethod: Method
private set
override val invokeMethodDescriptor: FunctionDescriptor =
parameterDescriptor.type.memberScope.getContributedFunctions(OperatorNameConventions.INVOKE, NoLookupLocation.FROM_BACKEND).single()
override lateinit var invokeMethodDescriptor: FunctionDescriptor
override lateinit var capturedVars: List<CapturedParamDesc>
private set
@@ -102,6 +101,25 @@ class DefaultLambda(
override fun generateLambdaBody(codegen: ExpressionCodegen, reifiedTypeInliner: ReifiedTypeInliner) {
val classReader = InlineCodegenUtil.buildClassReaderByInternalName(codegen.state, lambdaClassType.internalName)
var isPropertyReference = false
var isFunctionReference = false
classReader.accept(object: ClassVisitor(InlineCodegenUtil.API){
override fun visit(version: Int, access: Int, name: String, signature: String?, superName: String?, interfaces: Array<out String>?) {
isPropertyReference = superName?.startsWith("kotlin/jvm/internal/PropertyReference") ?: false
isFunctionReference = "kotlin/jvm/internal/FunctionReference" == superName
super.visit(version, access, name, signature, superName, interfaces)
}
}, ClassReader.SKIP_CODE or ClassReader.SKIP_FRAMES or ClassReader.SKIP_DEBUG)
invokeMethodDescriptor =
parameterDescriptor.type.memberScope
.getContributedFunctions(OperatorNameConventions.INVOKE, NoLookupLocation.FROM_BACKEND)
.single()
.let {
//property reference generates erased 'get' method
if (isPropertyReference) it.original else it
}
val descriptor = Type.getMethodDescriptor(Type.VOID_TYPE, *capturedArgs)
val constructor = InlineCodegenUtil.getMethodNode(
@@ -121,7 +139,7 @@ class DefaultLambda(
invokeMethod = Method(
OperatorNameConventions.INVOKE.asString(),
(if (isPropertyReference) OperatorNameConventions.GET else OperatorNameConventions.INVOKE).asString(),
codegen.state.typeMapper.mapSignatureSkipGeneric(invokeMethodDescriptor).asmMethod.descriptor
)
@@ -252,4 +270,4 @@ class ExpressionLambda(
SMAPAndMethodNode(methodNode, smap)
}
}
}
}
@@ -25,7 +25,7 @@ object SMAPParser {
}
val mapping =
if (source == null || source.isEmpty())
if (source == null || source.isEmpty() || methodStartLine > methodEndLine)
FileMapping.SKIP
else
FileMapping(source, path).apply {
@@ -3,8 +3,6 @@
// SKIP_INLINE_CHECK_IN: inlineFun$default
package test
fun ok() = "OK"
class A(val value: String) {
fun ok() = value
}
@@ -0,0 +1,22 @@
// FILE: 1.kt
// LANGUAGE_VERSION: 1.2
// SKIP_INLINE_CHECK_IN: inlineFun$default
package test
fun ok() = "OK"
object A {
fun ok() = "OK"
}
inline fun inlineFun(lambda: () -> String = A::ok): String {
return lambda()
}
// FILE: 2.kt
import test.*
fun box(): String {
return inlineFun()
}
@@ -0,0 +1,18 @@
// FILE: 1.kt
// LANGUAGE_VERSION: 1.2
// SKIP_INLINE_CHECK_IN: inlineFun$default
package test
val ok = "OK"
inline fun inlineFun(lambda: () -> String = ::ok): String {
return lambda()
}
// FILE: 2.kt
import test.*
fun box(): String {
return inlineFun()
}
@@ -0,0 +1,18 @@
// FILE: 1.kt
// LANGUAGE_VERSION: 1.2
// SKIP_INLINE_CHECK_IN: inlineFun$default
package test
class A(val ok: String)
inline fun inlineFun(a: A, lambda: (A) -> String = A::ok): String {
return lambda(a)
}
// FILE: 2.kt
import test.*
fun box(): String {
return inlineFun(A("OK"))
}
@@ -0,0 +1,20 @@
// FILE: 1.kt
// LANGUAGE_VERSION: 1.2
// SKIP_INLINE_CHECK_IN: inlineFun$default
package test
object A {
val ok = "OK"
}
inline fun inlineFun(lambda: () -> String = A::ok): String {
return lambda()
}
// FILE: 2.kt
import test.*
fun box(): String {
return inlineFun()
}
@@ -979,6 +979,12 @@ public class BlackBoxInlineCodegenTestGenerated extends AbstractBlackBoxInlineCo
doTest(fileName);
}
@TestMetadata("functionReferenceFromObject.kt")
public void testFunctionReferenceFromObject() throws Exception {
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/boxInline/defaultValues/lambdaInlining/functionReferenceFromObject.kt");
doTest(fileName);
}
@TestMetadata("instanceCapuredInClass.kt")
public void testInstanceCapuredInClass() throws Exception {
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/boxInline/defaultValues/lambdaInlining/instanceCapuredInClass.kt");
@@ -1009,6 +1015,24 @@ public class BlackBoxInlineCodegenTestGenerated extends AbstractBlackBoxInlineCo
doTest(fileName);
}
@TestMetadata("propertyReference.kt")
public void testPropertyReference() throws Exception {
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/boxInline/defaultValues/lambdaInlining/propertyReference.kt");
doTest(fileName);
}
@TestMetadata("propertyReferenceFromClass.kt")
public void testPropertyReferenceFromClass() throws Exception {
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/boxInline/defaultValues/lambdaInlining/propertyReferenceFromClass.kt");
doTest(fileName);
}
@TestMetadata("propertyReferenceFromObject.kt")
public void testPropertyReferenceFromObject() throws Exception {
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/boxInline/defaultValues/lambdaInlining/propertyReferenceFromObject.kt");
doTest(fileName);
}
@TestMetadata("simple.kt")
public void testSimple() throws Exception {
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/boxInline/defaultValues/lambdaInlining/simple.kt");
@@ -979,6 +979,12 @@ public class CompileKotlinAgainstInlineKotlinTestGenerated extends AbstractCompi
doTest(fileName);
}
@TestMetadata("functionReferenceFromObject.kt")
public void testFunctionReferenceFromObject() throws Exception {
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/boxInline/defaultValues/lambdaInlining/functionReferenceFromObject.kt");
doTest(fileName);
}
@TestMetadata("instanceCapuredInClass.kt")
public void testInstanceCapuredInClass() throws Exception {
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/boxInline/defaultValues/lambdaInlining/instanceCapuredInClass.kt");
@@ -1009,6 +1015,24 @@ public class CompileKotlinAgainstInlineKotlinTestGenerated extends AbstractCompi
doTest(fileName);
}
@TestMetadata("propertyReference.kt")
public void testPropertyReference() throws Exception {
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/boxInline/defaultValues/lambdaInlining/propertyReference.kt");
doTest(fileName);
}
@TestMetadata("propertyReferenceFromClass.kt")
public void testPropertyReferenceFromClass() throws Exception {
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/boxInline/defaultValues/lambdaInlining/propertyReferenceFromClass.kt");
doTest(fileName);
}
@TestMetadata("propertyReferenceFromObject.kt")
public void testPropertyReferenceFromObject() throws Exception {
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/boxInline/defaultValues/lambdaInlining/propertyReferenceFromObject.kt");
doTest(fileName);
}
@TestMetadata("simple.kt")
public void testSimple() throws Exception {
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/boxInline/defaultValues/lambdaInlining/simple.kt");