- Fix code generation for inlined String::plus
#KT-10131 Fixed. - Make extra factory methods in IntrinsicMethod protected. This ensures that any of them can be properly overridden.
This commit is contained in:
@@ -17,18 +17,17 @@
|
|||||||
package org.jetbrains.kotlin.codegen.intrinsics
|
package org.jetbrains.kotlin.codegen.intrinsics
|
||||||
|
|
||||||
import com.intellij.psi.PsiElement
|
import com.intellij.psi.PsiElement
|
||||||
|
import org.jetbrains.kotlin.codegen.*
|
||||||
import org.jetbrains.kotlin.codegen.AsmUtil.genInvokeAppendMethod
|
import org.jetbrains.kotlin.codegen.AsmUtil.genInvokeAppendMethod
|
||||||
import org.jetbrains.kotlin.codegen.AsmUtil.genStringBuilderConstructor
|
import org.jetbrains.kotlin.codegen.AsmUtil.genStringBuilderConstructor
|
||||||
import org.jetbrains.kotlin.codegen.Callable
|
|
||||||
import org.jetbrains.kotlin.codegen.CallableMethod
|
|
||||||
import org.jetbrains.kotlin.codegen.ExpressionCodegen
|
|
||||||
import org.jetbrains.kotlin.codegen.StackValue
|
|
||||||
import org.jetbrains.kotlin.lexer.KtTokens
|
import org.jetbrains.kotlin.lexer.KtTokens
|
||||||
import org.jetbrains.kotlin.psi.KtBinaryExpression
|
import org.jetbrains.kotlin.psi.KtBinaryExpression
|
||||||
|
import org.jetbrains.kotlin.psi.KtCallableReferenceExpression
|
||||||
import org.jetbrains.kotlin.psi.KtExpression
|
import org.jetbrains.kotlin.psi.KtExpression
|
||||||
import org.jetbrains.kotlin.resolve.calls.model.ResolvedCall
|
import org.jetbrains.kotlin.resolve.calls.model.ResolvedCall
|
||||||
import org.jetbrains.kotlin.resolve.jvm.AsmTypes
|
import org.jetbrains.kotlin.resolve.jvm.AsmTypes
|
||||||
import org.jetbrains.kotlin.resolve.jvm.AsmTypes.JAVA_STRING_TYPE
|
import org.jetbrains.kotlin.resolve.jvm.AsmTypes.JAVA_STRING_TYPE
|
||||||
|
import org.jetbrains.org.objectweb.asm.Opcodes
|
||||||
import org.jetbrains.org.objectweb.asm.Type
|
import org.jetbrains.org.objectweb.asm.Type
|
||||||
import org.jetbrains.org.objectweb.asm.commons.InstructionAdapter
|
import org.jetbrains.org.objectweb.asm.commons.InstructionAdapter
|
||||||
|
|
||||||
@@ -41,11 +40,11 @@ public class Concat : IntrinsicMethod() {
|
|||||||
arguments: List<KtExpression>,
|
arguments: List<KtExpression>,
|
||||||
receiver: StackValue
|
receiver: StackValue
|
||||||
): Type {
|
): Type {
|
||||||
if (element is KtBinaryExpression && element.getOperationReference().getReferencedNameElementType() == KtTokens.PLUS) {
|
if (element is KtBinaryExpression && element.operationReference.getReferencedNameElementType() == KtTokens.PLUS) {
|
||||||
// LHS + RHS
|
// LHS + RHS
|
||||||
genStringBuilderConstructor(v)
|
genStringBuilderConstructor(v)
|
||||||
codegen.invokeAppend(element.getLeft())
|
codegen.invokeAppend(element.left)
|
||||||
codegen.invokeAppend(element.getRight())
|
codegen.invokeAppend(element.right)
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
// LHS?.plus(RHS)
|
// LHS?.plus(RHS)
|
||||||
@@ -60,7 +59,6 @@ public class Concat : IntrinsicMethod() {
|
|||||||
return JAVA_STRING_TYPE
|
return JAVA_STRING_TYPE
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
override fun toCallable(method: CallableMethod): Callable =
|
override fun toCallable(method: CallableMethod): Callable =
|
||||||
object : IntrinsicCallable(method) {
|
object : IntrinsicCallable(method) {
|
||||||
override fun invokeMethodWithArguments(
|
override fun invokeMethodWithArguments(
|
||||||
@@ -68,16 +66,37 @@ public class Concat : IntrinsicMethod() {
|
|||||||
receiver: StackValue,
|
receiver: StackValue,
|
||||||
codegen: ExpressionCodegen
|
codegen: ExpressionCodegen
|
||||||
): StackValue {
|
): StackValue {
|
||||||
|
if (resolvedCall.call.callElement.parent is KtCallableReferenceExpression) {
|
||||||
|
// NB we come here only in case of inlined callable reference to String::plus.
|
||||||
|
// This will map arguments properly, invoking callbacks defined in Callable.
|
||||||
|
return super.invokeMethodWithArguments(resolvedCall, receiver, codegen)
|
||||||
|
}
|
||||||
return StackValue.operation(returnType) {
|
return StackValue.operation(returnType) {
|
||||||
val arguments = resolvedCall.getCall().getValueArguments().map { it.getArgumentExpression()!! }
|
val arguments = resolvedCall.call.valueArguments.map { it.getArgumentExpression()!! }
|
||||||
val actualType = generateImpl(
|
val actualType = generateImpl(
|
||||||
codegen, it, returnType,
|
codegen, it, returnType,
|
||||||
resolvedCall.getCall().getCallElement(),
|
resolvedCall.call.callElement,
|
||||||
arguments,
|
arguments,
|
||||||
StackValue.receiver(resolvedCall, receiver, codegen, this)
|
StackValue.receiver(resolvedCall, receiver, codegen, this)
|
||||||
)
|
)
|
||||||
StackValue.coerce(actualType, returnType, it)
|
StackValue.coerce(actualType, returnType, it)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
override fun afterReceiverGeneration(v: InstructionAdapter) {
|
||||||
|
v.visitTypeInsn(Opcodes.NEW, "java/lang/StringBuilder")
|
||||||
|
v.dupX1()
|
||||||
|
v.swap()
|
||||||
|
v.invokespecial("java/lang/StringBuilder", "<init>", "(Ljava/lang/String;)V", false)
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun invokeIntrinsic(v: InstructionAdapter) {
|
||||||
|
// String::plus has type String.(Any?) -> String, thus we have no argument type information
|
||||||
|
// in case of callable reference passed to a generic function, e.g.:
|
||||||
|
// charArrayOf('O', 'K').fold("", String::plus)
|
||||||
|
// TODO Make String::plus generic, and invoke proper StringBuilder#append.
|
||||||
|
AsmUtil.genInvokeAppendMethod(v, AsmTypes.OBJECT_TYPE)
|
||||||
|
v.invokevirtual("java/lang/StringBuilder", "toString", "()Ljava/lang/String;", false)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -37,17 +37,17 @@ public abstract class IntrinsicMethod {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@NotNull
|
@NotNull
|
||||||
public Callable toCallable(@NotNull CallableMethod method, boolean isSuper, @NotNull ResolvedCall resolvedCall) {
|
protected Callable toCallable(@NotNull CallableMethod method, boolean isSuper, @NotNull ResolvedCall resolvedCall) {
|
||||||
return toCallable(method, isSuper);
|
return toCallable(method, isSuper);
|
||||||
}
|
}
|
||||||
|
|
||||||
@NotNull
|
@NotNull
|
||||||
public Callable toCallable(@NotNull CallableMethod method, boolean isSuperCall) {
|
protected Callable toCallable(@NotNull CallableMethod method, boolean isSuperCall) {
|
||||||
return toCallable(method);
|
return toCallable(method);
|
||||||
}
|
}
|
||||||
|
|
||||||
@NotNull
|
@NotNull
|
||||||
public Callable toCallable(@NotNull CallableMethod method) {
|
protected Callable toCallable(@NotNull CallableMethod method) {
|
||||||
throw new UnsupportedOperationException("Not implemented");
|
throw new UnsupportedOperationException("Not implemented");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -0,0 +1,2 @@
|
|||||||
|
fun box(): String =
|
||||||
|
listOf('O', 'K').fold("", String::plus)
|
||||||
@@ -0,0 +1,2 @@
|
|||||||
|
fun box(): String =
|
||||||
|
charArrayOf('O', 'K').fold("", String::plus)
|
||||||
+12
@@ -1996,6 +1996,18 @@ public class BlackBoxWithStdlibCodegenTestGenerated extends AbstractBlackBoxCode
|
|||||||
doTestWithStdlib(fileName);
|
doTestWithStdlib(fileName);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@TestMetadata("kt10131.kt")
|
||||||
|
public void testKt10131() throws Exception {
|
||||||
|
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/boxWithStdlib/intrinsics/kt10131.kt");
|
||||||
|
doTestWithStdlib(fileName);
|
||||||
|
}
|
||||||
|
|
||||||
|
@TestMetadata("kt10131a.kt")
|
||||||
|
public void testKt10131a() throws Exception {
|
||||||
|
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/boxWithStdlib/intrinsics/kt10131a.kt");
|
||||||
|
doTestWithStdlib(fileName);
|
||||||
|
}
|
||||||
|
|
||||||
@TestMetadata("kt5937.kt")
|
@TestMetadata("kt5937.kt")
|
||||||
public void testKt5937() throws Exception {
|
public void testKt5937() throws Exception {
|
||||||
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/boxWithStdlib/intrinsics/kt5937.kt");
|
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/boxWithStdlib/intrinsics/kt5937.kt");
|
||||||
|
|||||||
Reference in New Issue
Block a user