KT-894 wrong string concatenation
This commit is contained in:
@@ -1853,7 +1853,7 @@ public class ExpressionCodegen extends JetVisitor<StackValue, StackValue> {
|
|||||||
value.put(lhsType, v); // receiver lhs
|
value.put(lhsType, v); // receiver lhs
|
||||||
final IntrinsicMethod intrinsic = (IntrinsicMethod) callable;
|
final IntrinsicMethod intrinsic = (IntrinsicMethod) callable;
|
||||||
//noinspection NullableProblems
|
//noinspection NullableProblems
|
||||||
intrinsic.generate(this, v, lhsType, expression, Arrays.asList(expression.getRight()), null);
|
intrinsic.generate(this, v, lhsType, expression, Arrays.asList(expression.getRight()), StackValue.onStack(lhsType));
|
||||||
value.store(v);
|
value.store(v);
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
|
|||||||
@@ -2,6 +2,7 @@ package org.jetbrains.jet.codegen.intrinsics;
|
|||||||
|
|
||||||
import com.intellij.psi.PsiElement;
|
import com.intellij.psi.PsiElement;
|
||||||
import org.jetbrains.jet.codegen.ExpressionCodegen;
|
import org.jetbrains.jet.codegen.ExpressionCodegen;
|
||||||
|
import org.jetbrains.jet.codegen.JetTypeMapper;
|
||||||
import org.jetbrains.jet.codegen.StackValue;
|
import org.jetbrains.jet.codegen.StackValue;
|
||||||
import org.jetbrains.jet.lang.psi.JetExpression;
|
import org.jetbrains.jet.lang.psi.JetExpression;
|
||||||
import org.objectweb.asm.Type;
|
import org.objectweb.asm.Type;
|
||||||
@@ -16,17 +17,18 @@ public class Concat implements IntrinsicMethod {
|
|||||||
@Override
|
@Override
|
||||||
public StackValue generate(ExpressionCodegen codegen, InstructionAdapter v, Type expectedType, PsiElement element, List<JetExpression> arguments, StackValue receiver) {
|
public StackValue generate(ExpressionCodegen codegen, InstructionAdapter v, Type expectedType, PsiElement element, List<JetExpression> arguments, StackValue receiver) {
|
||||||
codegen.generateStringBuilderConstructor();
|
codegen.generateStringBuilderConstructor();
|
||||||
if (receiver == null) { // LHS.plus(RHS)
|
if (receiver == null || receiver == StackValue.none()) { // LHS + RHS
|
||||||
|
codegen.invokeAppend(arguments.get(0)); // StringBuilder(LHS)
|
||||||
|
codegen.invokeAppend(arguments.get(1));
|
||||||
|
}
|
||||||
|
else { // LHS.plus(RHS)
|
||||||
v.swap(); // StringBuilder LHS
|
v.swap(); // StringBuilder LHS
|
||||||
codegen.invokeAppendMethod(expectedType); // StringBuilder(LHS)
|
codegen.invokeAppendMethod(expectedType); // StringBuilder(LHS)
|
||||||
codegen.invokeAppend(arguments.get(0));
|
codegen.invokeAppend(arguments.get(0));
|
||||||
}
|
}
|
||||||
else { // LHS + RHS
|
|
||||||
codegen.invokeAppend(arguments.get(0)); // StringBuilder(LHS)
|
|
||||||
codegen.invokeAppend(arguments.get(1));
|
|
||||||
}
|
|
||||||
|
|
||||||
v.invokevirtual("java/lang/StringBuilder", "toString", "()Ljava/lang/String;");
|
v.invokevirtual("java/lang/StringBuilder", "toString", "()Ljava/lang/String;");
|
||||||
return StackValue.onStack(Type.getObjectType("java/lang/String"));
|
StackValue.onStack(JetTypeMapper.JL_STRING_TYPE).put(expectedType, v);
|
||||||
|
return StackValue.onStack(expectedType);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -40,6 +40,7 @@ public class IntrinsicMethods {
|
|||||||
public static final IteratorNext ITERATOR_NEXT = new IteratorNext();
|
public static final IteratorNext ITERATOR_NEXT = new IteratorNext();
|
||||||
public static final ArraySet ARRAY_SET = new ArraySet();
|
public static final ArraySet ARRAY_SET = new ArraySet();
|
||||||
public static final ArrayGet ARRAY_GET = new ArrayGet();
|
public static final ArrayGet ARRAY_GET = new ArrayGet();
|
||||||
|
public static final StringPlus STRING_PLUS = new StringPlus();
|
||||||
|
|
||||||
private final Project myProject;
|
private final Project myProject;
|
||||||
private final JetStandardLibrary myStdLib;
|
private final JetStandardLibrary myStdLib;
|
||||||
@@ -87,7 +88,7 @@ public class IntrinsicMethods {
|
|||||||
declareOverload(myStdLib.getLibraryScope().getFunctions("toString"), 0, new ToString());
|
declareOverload(myStdLib.getLibraryScope().getFunctions("toString"), 0, new ToString());
|
||||||
declareOverload(myStdLib.getLibraryScope().getFunctions("equals"), 1, EQUALS);
|
declareOverload(myStdLib.getLibraryScope().getFunctions("equals"), 1, EQUALS);
|
||||||
declareOverload(myStdLib.getLibraryScope().getFunctions("identityEquals"), 1, EQUALS);
|
declareOverload(myStdLib.getLibraryScope().getFunctions("identityEquals"), 1, EQUALS);
|
||||||
declareOverload(myStdLib.getLibraryScope().getFunctions("plus"), 1, new StringPlus());
|
declareOverload(myStdLib.getLibraryScope().getFunctions("plus"), 1, STRING_PLUS);
|
||||||
declareOverload(myStdLib.getLibraryScope().getFunctions("Array"), 1, new NewArray());
|
declareOverload(myStdLib.getLibraryScope().getFunctions("Array"), 1, new NewArray());
|
||||||
declareOverload(myStdLib.getLibraryScope().getFunctions("sure"), 0, new Sure());
|
declareOverload(myStdLib.getLibraryScope().getFunctions("sure"), 0, new Sure());
|
||||||
declareOverload(myStdLib.getLibraryScope().getFunctions("synchronized"), 1, new StupidSync());
|
declareOverload(myStdLib.getLibraryScope().getFunctions("synchronized"), 1, new StupidSync());
|
||||||
|
|||||||
@@ -20,8 +20,14 @@ import java.util.List;
|
|||||||
public class StringPlus implements IntrinsicMethod {
|
public class StringPlus implements IntrinsicMethod {
|
||||||
@Override
|
@Override
|
||||||
public StackValue generate(ExpressionCodegen codegen, InstructionAdapter v, Type expectedType, PsiElement element, List<JetExpression> arguments, StackValue receiver) {
|
public StackValue generate(ExpressionCodegen codegen, InstructionAdapter v, Type expectedType, PsiElement element, List<JetExpression> arguments, StackValue receiver) {
|
||||||
codegen.gen(arguments.get(0)).put(JetTypeMapper.JL_STRING_TYPE, v);
|
if(receiver == null || receiver == StackValue.none()) {
|
||||||
codegen.gen(arguments.get(1)).put(JetTypeMapper.TYPE_OBJECT, v);
|
codegen.gen(arguments.get(0)).put(JetTypeMapper.JL_STRING_TYPE, v);
|
||||||
|
codegen.gen(arguments.get(1)).put(JetTypeMapper.TYPE_OBJECT, v);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
receiver.put(JetTypeMapper.JL_STRING_TYPE, v);
|
||||||
|
codegen.gen(arguments.get(0)).put(JetTypeMapper.TYPE_OBJECT, v);
|
||||||
|
}
|
||||||
v.invokestatic("jet/runtime/Intrinsics", "stringPlus", "(Ljava/lang/String;Ljava/lang/Object;)Ljava/lang/String;");
|
v.invokestatic("jet/runtime/Intrinsics", "stringPlus", "(Ljava/lang/String;Ljava/lang/Object;)Ljava/lang/String;");
|
||||||
return StackValue.onStack(JetTypeMapper.JL_STRING_TYPE);
|
return StackValue.onStack(JetTypeMapper.JL_STRING_TYPE);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -0,0 +1,8 @@
|
|||||||
|
fun stringConcat(n : Int) : String? {
|
||||||
|
var string : String? = ""
|
||||||
|
for (i in 0..(n - 1))
|
||||||
|
string += "LOL "
|
||||||
|
return string
|
||||||
|
}
|
||||||
|
|
||||||
|
fun box() = if(stringConcat(3) == "LOL LOL LOL ") "OK" else "fail"
|
||||||
@@ -17,50 +17,6 @@ public class FunctionGenTest extends CodegenTestCase {
|
|||||||
// System.out.println(generateToText());
|
// System.out.println(generateToText());
|
||||||
}
|
}
|
||||||
|
|
||||||
public void testAnyToString () throws InvocationTargetException, IllegalAccessException {
|
|
||||||
loadText("fun foo(x: Any) = x.toString()");
|
|
||||||
// System.out.println(generateToText());
|
|
||||||
Method foo = generateFunction();
|
|
||||||
assertEquals("something", foo.invoke(null, "something"));
|
|
||||||
assertEquals("null", foo.invoke(null, new Object[]{null}));
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
public void testNullableAnyToString () throws InvocationTargetException, IllegalAccessException {
|
|
||||||
loadText("fun foo(x: Any?) = x.toString()");
|
|
||||||
// System.out.println(generateToText());
|
|
||||||
Method foo = generateFunction();
|
|
||||||
assertEquals("something", foo.invoke(null, "something"));
|
|
||||||
assertEquals("null", foo.invoke(null, new Object[]{null}));
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
public void testNullableStringPlus () throws InvocationTargetException, IllegalAccessException {
|
|
||||||
loadText("fun foo(x: String?, y: Any?) = x + y");
|
|
||||||
String text = generateToText();
|
|
||||||
assertTrue(text.contains(".stringPlus"));
|
|
||||||
// System.out.println(text);
|
|
||||||
Method foo = generateFunction();
|
|
||||||
assertEquals("something239", foo.invoke(null, "something", 239));
|
|
||||||
assertEquals("null239", foo.invoke(null, null, 239));
|
|
||||||
assertEquals("239null", foo.invoke(null, "239", null));
|
|
||||||
assertEquals("nullnull", foo.invoke(null, null, null));
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
public void testNonNullableStringPlus () throws InvocationTargetException, IllegalAccessException {
|
|
||||||
loadText("fun foo(x: String, y: Any?) = x + y + 120");
|
|
||||||
String text = generateToText();
|
|
||||||
assertFalse(text.contains(".stringPlus"));
|
|
||||||
// System.out.println(text);
|
|
||||||
Method foo = generateFunction();
|
|
||||||
assertEquals("something239120", foo.invoke(null, "something", 239));
|
|
||||||
assertEquals("null239120", foo.invoke(null, null, 239));
|
|
||||||
assertEquals("239null120", foo.invoke(null, "239", null));
|
|
||||||
assertEquals("nullnull120", foo.invoke(null, null, null));
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
public void testAnyEqualsNullable () throws InvocationTargetException, IllegalAccessException {
|
public void testAnyEqualsNullable () throws InvocationTargetException, IllegalAccessException {
|
||||||
loadText("fun foo(x: Any?) = x.equals(\"lala\")");
|
loadText("fun foo(x: Any?) = x.equals(\"lala\")");
|
||||||
// System.out.println(generateToText());
|
// System.out.println(generateToText());
|
||||||
|
|||||||
@@ -1,11 +1,58 @@
|
|||||||
package org.jetbrains.jet.codegen;
|
package org.jetbrains.jet.codegen;
|
||||||
|
|
||||||
|
import java.lang.reflect.InvocationTargetException;
|
||||||
|
import java.lang.reflect.Method;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @author yole
|
* @author yole
|
||||||
* @author alex.tkachman
|
* @author alex.tkachman
|
||||||
*/
|
*/
|
||||||
public class StringsTest extends CodegenTestCase {
|
public class StringsTest extends CodegenTestCase {
|
||||||
|
|
||||||
|
public void testAnyToString () throws InvocationTargetException, IllegalAccessException {
|
||||||
|
loadText("fun foo(x: Any) = x.toString()");
|
||||||
|
// System.out.println(generateToText());
|
||||||
|
Method foo = generateFunction();
|
||||||
|
assertEquals("something", foo.invoke(null, "something"));
|
||||||
|
assertEquals("null", foo.invoke(null, new Object[]{null}));
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
public void testNullableAnyToString () throws InvocationTargetException, IllegalAccessException {
|
||||||
|
loadText("fun foo(x: Any?) = x.toString()");
|
||||||
|
// System.out.println(generateToText());
|
||||||
|
Method foo = generateFunction();
|
||||||
|
assertEquals("something", foo.invoke(null, "something"));
|
||||||
|
assertEquals("null", foo.invoke(null, new Object[]{null}));
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
public void testNullableStringPlus () throws InvocationTargetException, IllegalAccessException {
|
||||||
|
loadText("fun foo(x: String?, y: Any?) = x + y");
|
||||||
|
String text = generateToText();
|
||||||
|
assertTrue(text.contains(".stringPlus"));
|
||||||
|
// System.out.println(text);
|
||||||
|
Method foo = generateFunction();
|
||||||
|
assertEquals("something239", foo.invoke(null, "something", 239));
|
||||||
|
assertEquals("null239", foo.invoke(null, null, 239));
|
||||||
|
assertEquals("239null", foo.invoke(null, "239", null));
|
||||||
|
assertEquals("nullnull", foo.invoke(null, null, null));
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
public void testNonNullableStringPlus () throws InvocationTargetException, IllegalAccessException {
|
||||||
|
loadText("fun foo(x: String, y: Any?) = x + y + 120");
|
||||||
|
String text = generateToText();
|
||||||
|
assertFalse(text.contains(".stringPlus"));
|
||||||
|
// System.out.println(text);
|
||||||
|
Method foo = generateFunction();
|
||||||
|
assertEquals("something239120", foo.invoke(null, "something", 239));
|
||||||
|
assertEquals("null239120", foo.invoke(null, null, 239));
|
||||||
|
assertEquals("239null120", foo.invoke(null, "239", null));
|
||||||
|
assertEquals("nullnull120", foo.invoke(null, null, null));
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
public void testRawStrings() throws Exception {
|
public void testRawStrings() throws Exception {
|
||||||
blackBoxFile("rawStrings.jet");
|
blackBoxFile("rawStrings.jet");
|
||||||
}
|
}
|
||||||
@@ -13,4 +60,8 @@ public class StringsTest extends CodegenTestCase {
|
|||||||
public void testKt881() throws Exception {
|
public void testKt881() throws Exception {
|
||||||
blackBoxFile("regressions/kt881.jet");
|
blackBoxFile("regressions/kt881.jet");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public void testKt894() throws Exception {
|
||||||
|
blackBoxFile("regressions/kt894.jet");
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user