KT-894 wrong string concatenation

This commit is contained in:
Alex Tkachman
2012-01-02 09:27:32 +02:00
parent 12af19e991
commit a25416e5cf
7 changed files with 79 additions and 55 deletions
@@ -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");
}
} }