- 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:
Dmitry Petrov
2015-11-23 15:16:08 +03:00
parent 2b4868c3ce
commit 931463af0d
5 changed files with 49 additions and 14 deletions
@@ -17,18 +17,17 @@
package org.jetbrains.kotlin.codegen.intrinsics
import com.intellij.psi.PsiElement
import org.jetbrains.kotlin.codegen.*
import org.jetbrains.kotlin.codegen.AsmUtil.genInvokeAppendMethod
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.psi.KtBinaryExpression
import org.jetbrains.kotlin.psi.KtCallableReferenceExpression
import org.jetbrains.kotlin.psi.KtExpression
import org.jetbrains.kotlin.resolve.calls.model.ResolvedCall
import org.jetbrains.kotlin.resolve.jvm.AsmTypes
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.commons.InstructionAdapter
@@ -41,11 +40,11 @@ public class Concat : IntrinsicMethod() {
arguments: List<KtExpression>,
receiver: StackValue
): Type {
if (element is KtBinaryExpression && element.getOperationReference().getReferencedNameElementType() == KtTokens.PLUS) {
if (element is KtBinaryExpression && element.operationReference.getReferencedNameElementType() == KtTokens.PLUS) {
// LHS + RHS
genStringBuilderConstructor(v)
codegen.invokeAppend(element.getLeft())
codegen.invokeAppend(element.getRight())
codegen.invokeAppend(element.left)
codegen.invokeAppend(element.right)
}
else {
// LHS?.plus(RHS)
@@ -60,7 +59,6 @@ public class Concat : IntrinsicMethod() {
return JAVA_STRING_TYPE
}
override fun toCallable(method: CallableMethod): Callable =
object : IntrinsicCallable(method) {
override fun invokeMethodWithArguments(
@@ -68,16 +66,37 @@ public class Concat : IntrinsicMethod() {
receiver: StackValue,
codegen: ExpressionCodegen
): 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) {
val arguments = resolvedCall.getCall().getValueArguments().map { it.getArgumentExpression()!! }
val arguments = resolvedCall.call.valueArguments.map { it.getArgumentExpression()!! }
val actualType = generateImpl(
codegen, it, returnType,
resolvedCall.getCall().getCallElement(),
resolvedCall.call.callElement,
arguments,
StackValue.receiver(resolvedCall, receiver, codegen, this)
)
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
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);
}
@NotNull
public Callable toCallable(@NotNull CallableMethod method, boolean isSuperCall) {
protected Callable toCallable(@NotNull CallableMethod method, boolean isSuperCall) {
return toCallable(method);
}
@NotNull
public Callable toCallable(@NotNull CallableMethod method) {
protected Callable toCallable(@NotNull CallableMethod method) {
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)
@@ -1996,6 +1996,18 @@ public class BlackBoxWithStdlibCodegenTestGenerated extends AbstractBlackBoxCode
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")
public void testKt5937() throws Exception {
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/boxWithStdlib/intrinsics/kt5937.kt");