Skip to content

Commit 05d2aa7

Browse files
author
Mikhael Bogdanov
committed
Support default property reference inlining
1 parent a96fada commit 05d2aa7

File tree

9 files changed

+151
-9
lines changed

9 files changed

+151
-9
lines changed

compiler/backend/src/org/jetbrains/kotlin/codegen/inline/LambdaInfo.kt

Lines changed: 24 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -33,6 +33,8 @@ import org.jetbrains.kotlin.resolve.BindingContext
3333
import org.jetbrains.kotlin.resolve.calls.callUtil.getResolvedCallWithAssert
3434
import org.jetbrains.kotlin.resolve.jvm.AsmTypes
3535
import org.jetbrains.kotlin.util.OperatorNameConventions
36+
import org.jetbrains.org.objectweb.asm.ClassReader
37+
import org.jetbrains.org.objectweb.asm.ClassVisitor
3638
import org.jetbrains.org.objectweb.asm.Type
3739
import org.jetbrains.org.objectweb.asm.commons.Method
3840
import org.jetbrains.org.objectweb.asm.tree.FieldInsnNode
@@ -90,10 +92,7 @@ class DefaultLambda(
9092
override lateinit var invokeMethod: Method
9193
private set
9294

93-
94-
override val invokeMethodDescriptor: FunctionDescriptor =
95-
parameterDescriptor.type.memberScope.getContributedFunctions(OperatorNameConventions.INVOKE, NoLookupLocation.FROM_BACKEND).single()
96-
95+
override lateinit var invokeMethodDescriptor: FunctionDescriptor
9796

9897
override lateinit var capturedVars: List<CapturedParamDesc>
9998
private set
@@ -102,6 +101,25 @@ class DefaultLambda(
102101

103102
override fun generateLambdaBody(codegen: ExpressionCodegen, reifiedTypeInliner: ReifiedTypeInliner) {
104103
val classReader = InlineCodegenUtil.buildClassReaderByInternalName(codegen.state, lambdaClassType.internalName)
104+
var isPropertyReference = false
105+
var isFunctionReference = false
106+
classReader.accept(object: ClassVisitor(InlineCodegenUtil.API){
107+
override fun visit(version: Int, access: Int, name: String, signature: String?, superName: String?, interfaces: Array<out String>?) {
108+
isPropertyReference = superName?.startsWith("kotlin/jvm/internal/PropertyReference") ?: false
109+
isFunctionReference = "kotlin/jvm/internal/FunctionReference" == superName
110+
111+
super.visit(version, access, name, signature, superName, interfaces)
112+
}
113+
}, ClassReader.SKIP_CODE or ClassReader.SKIP_FRAMES or ClassReader.SKIP_DEBUG)
114+
115+
invokeMethodDescriptor =
116+
parameterDescriptor.type.memberScope
117+
.getContributedFunctions(OperatorNameConventions.INVOKE, NoLookupLocation.FROM_BACKEND)
118+
.single()
119+
.let {
120+
//property reference generates erased 'get' method
121+
if (isPropertyReference) it.original else it
122+
}
105123

106124
val descriptor = Type.getMethodDescriptor(Type.VOID_TYPE, *capturedArgs)
107125
val constructor = InlineCodegenUtil.getMethodNode(
@@ -121,7 +139,7 @@ class DefaultLambda(
121139

122140

123141
invokeMethod = Method(
124-
OperatorNameConventions.INVOKE.asString(),
142+
(if (isPropertyReference) OperatorNameConventions.GET else OperatorNameConventions.INVOKE).asString(),
125143
codegen.state.typeMapper.mapSignatureSkipGeneric(invokeMethodDescriptor).asmMethod.descriptor
126144
)
127145

@@ -252,4 +270,4 @@ class ExpressionLambda(
252270
SMAPAndMethodNode(methodNode, smap)
253271
}
254272
}
255-
}
273+
}

compiler/backend/src/org/jetbrains/kotlin/codegen/inline/SMAPParser.kt

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -25,7 +25,7 @@ object SMAPParser {
2525
}
2626

2727
val mapping =
28-
if (source == null || source.isEmpty())
28+
if (source == null || source.isEmpty() || methodStartLine > methodEndLine)
2929
FileMapping.SKIP
3030
else
3131
FileMapping(source, path).apply {

compiler/testData/codegen/boxInline/defaultValues/lambdaInlining/functionReferenceFromClass.kt

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -3,8 +3,6 @@
33
// SKIP_INLINE_CHECK_IN: inlineFun$default
44
package test
55

6-
fun ok() = "OK"
7-
86
class A(val value: String) {
97
fun ok() = value
108
}
Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
// FILE: 1.kt
2+
// LANGUAGE_VERSION: 1.2
3+
// SKIP_INLINE_CHECK_IN: inlineFun$default
4+
package test
5+
6+
fun ok() = "OK"
7+
8+
object A {
9+
fun ok() = "OK"
10+
}
11+
12+
inline fun inlineFun(lambda: () -> String = A::ok): String {
13+
return lambda()
14+
}
15+
16+
// FILE: 2.kt
17+
18+
import test.*
19+
20+
fun box(): String {
21+
return inlineFun()
22+
}
Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
// FILE: 1.kt
2+
// LANGUAGE_VERSION: 1.2
3+
// SKIP_INLINE_CHECK_IN: inlineFun$default
4+
package test
5+
6+
val ok = "OK"
7+
8+
inline fun inlineFun(lambda: () -> String = ::ok): String {
9+
return lambda()
10+
}
11+
12+
// FILE: 2.kt
13+
14+
import test.*
15+
16+
fun box(): String {
17+
return inlineFun()
18+
}
Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
// FILE: 1.kt
2+
// LANGUAGE_VERSION: 1.2
3+
// SKIP_INLINE_CHECK_IN: inlineFun$default
4+
package test
5+
6+
class A(val ok: String)
7+
8+
inline fun inlineFun(a: A, lambda: (A) -> String = A::ok): String {
9+
return lambda(a)
10+
}
11+
12+
// FILE: 2.kt
13+
14+
import test.*
15+
16+
fun box(): String {
17+
return inlineFun(A("OK"))
18+
}
Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
// FILE: 1.kt
2+
// LANGUAGE_VERSION: 1.2
3+
// SKIP_INLINE_CHECK_IN: inlineFun$default
4+
package test
5+
6+
object A {
7+
val ok = "OK"
8+
}
9+
10+
inline fun inlineFun(lambda: () -> String = A::ok): String {
11+
return lambda()
12+
}
13+
14+
// FILE: 2.kt
15+
16+
import test.*
17+
18+
fun box(): String {
19+
return inlineFun()
20+
}

compiler/tests/org/jetbrains/kotlin/codegen/BlackBoxInlineCodegenTestGenerated.java

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -979,6 +979,12 @@ public void testFunctionReferenceFromClass() throws Exception {
979979
doTest(fileName);
980980
}
981981

982+
@TestMetadata("functionReferenceFromObject.kt")
983+
public void testFunctionReferenceFromObject() throws Exception {
984+
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/boxInline/defaultValues/lambdaInlining/functionReferenceFromObject.kt");
985+
doTest(fileName);
986+
}
987+
982988
@TestMetadata("instanceCapuredInClass.kt")
983989
public void testInstanceCapuredInClass() throws Exception {
984990
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/boxInline/defaultValues/lambdaInlining/instanceCapuredInClass.kt");
@@ -1009,6 +1015,24 @@ public void testNonDefaultInlineInNoInline() throws Exception {
10091015
doTest(fileName);
10101016
}
10111017

1018+
@TestMetadata("propertyReference.kt")
1019+
public void testPropertyReference() throws Exception {
1020+
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/boxInline/defaultValues/lambdaInlining/propertyReference.kt");
1021+
doTest(fileName);
1022+
}
1023+
1024+
@TestMetadata("propertyReferenceFromClass.kt")
1025+
public void testPropertyReferenceFromClass() throws Exception {
1026+
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/boxInline/defaultValues/lambdaInlining/propertyReferenceFromClass.kt");
1027+
doTest(fileName);
1028+
}
1029+
1030+
@TestMetadata("propertyReferenceFromObject.kt")
1031+
public void testPropertyReferenceFromObject() throws Exception {
1032+
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/boxInline/defaultValues/lambdaInlining/propertyReferenceFromObject.kt");
1033+
doTest(fileName);
1034+
}
1035+
10121036
@TestMetadata("simple.kt")
10131037
public void testSimple() throws Exception {
10141038
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/boxInline/defaultValues/lambdaInlining/simple.kt");

compiler/tests/org/jetbrains/kotlin/codegen/CompileKotlinAgainstInlineKotlinTestGenerated.java

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -979,6 +979,12 @@ public void testFunctionReferenceFromClass() throws Exception {
979979
doTest(fileName);
980980
}
981981

982+
@TestMetadata("functionReferenceFromObject.kt")
983+
public void testFunctionReferenceFromObject() throws Exception {
984+
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/boxInline/defaultValues/lambdaInlining/functionReferenceFromObject.kt");
985+
doTest(fileName);
986+
}
987+
982988
@TestMetadata("instanceCapuredInClass.kt")
983989
public void testInstanceCapuredInClass() throws Exception {
984990
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/boxInline/defaultValues/lambdaInlining/instanceCapuredInClass.kt");
@@ -1009,6 +1015,24 @@ public void testNonDefaultInlineInNoInline() throws Exception {
10091015
doTest(fileName);
10101016
}
10111017

1018+
@TestMetadata("propertyReference.kt")
1019+
public void testPropertyReference() throws Exception {
1020+
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/boxInline/defaultValues/lambdaInlining/propertyReference.kt");
1021+
doTest(fileName);
1022+
}
1023+
1024+
@TestMetadata("propertyReferenceFromClass.kt")
1025+
public void testPropertyReferenceFromClass() throws Exception {
1026+
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/boxInline/defaultValues/lambdaInlining/propertyReferenceFromClass.kt");
1027+
doTest(fileName);
1028+
}
1029+
1030+
@TestMetadata("propertyReferenceFromObject.kt")
1031+
public void testPropertyReferenceFromObject() throws Exception {
1032+
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/boxInline/defaultValues/lambdaInlining/propertyReferenceFromObject.kt");
1033+
doTest(fileName);
1034+
}
1035+
10121036
@TestMetadata("simple.kt")
10131037
public void testSimple() throws Exception {
10141038
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/boxInline/defaultValues/lambdaInlining/simple.kt");

0 commit comments

Comments
 (0)