Generate compareTo() properly
Take into account: 1) resolved call to compareTo (instead of always calling Comparable's method) 2) types of both caller and callee, when primitive, to avoid wrong casting (instead of always using caller's type) #KT-3078 Fixed
This commit is contained in:
@@ -311,15 +311,6 @@ public class AsmUtil {
|
||||
mv.visitInsn(L2I);
|
||||
}
|
||||
|
||||
static StackValue compareExpressionsOnStack(InstructionAdapter v, IElementType opToken, Type operandType) {
|
||||
if (operandType.getSort() == Type.OBJECT) {
|
||||
v.invokeinterface("java/lang/Comparable", "compareTo", "(Ljava/lang/Object;)I");
|
||||
v.iconst(0);
|
||||
operandType = Type.INT_TYPE;
|
||||
}
|
||||
return StackValue.cmp(opToken, operandType);
|
||||
}
|
||||
|
||||
static StackValue genNullSafeEquals(
|
||||
InstructionAdapter v,
|
||||
IElementType opToken,
|
||||
@@ -394,7 +385,7 @@ public class AsmUtil {
|
||||
boolean rightNullable
|
||||
) {
|
||||
if ((isNumberPrimitive(leftType) || leftType.getSort() == Type.BOOLEAN) && leftType == rightType) {
|
||||
return compareExpressionsOnStack(v, opToken, leftType);
|
||||
return StackValue.cmp(opToken, leftType);
|
||||
}
|
||||
else {
|
||||
if (opToken == JetTokens.EQEQEQ || opToken == JetTokens.EXCLEQEQEQ) {
|
||||
|
||||
@@ -2311,7 +2311,7 @@ public class ExpressionCodegen extends JetVisitor<StackValue, StackValue> implem
|
||||
}
|
||||
else if (opToken == JetTokens.LT || opToken == JetTokens.LTEQ ||
|
||||
opToken == JetTokens.GT || opToken == JetTokens.GTEQ) {
|
||||
return generateCompareOp(expression.getLeft(), expression.getRight(), opToken, expressionType(expression.getLeft()));
|
||||
return generateCompareTo(expression);
|
||||
}
|
||||
else if (opToken == JetTokens.ELVIS) {
|
||||
return generateElvis(expression);
|
||||
@@ -2519,10 +2519,25 @@ public class ExpressionCodegen extends JetVisitor<StackValue, StackValue> implem
|
||||
return StackValue.onStack(exprType);
|
||||
}
|
||||
|
||||
private StackValue generateCompareOp(JetExpression left, JetExpression right, IElementType opToken, Type operandType) {
|
||||
gen(left, operandType);
|
||||
gen(right, operandType);
|
||||
return compareExpressionsOnStack(v, opToken, operandType);
|
||||
private StackValue generateCompareTo(JetBinaryExpression expression) {
|
||||
DeclarationDescriptor target = bindingContext.get(BindingContext.REFERENCE_TARGET, expression.getOperationReference());
|
||||
assert target instanceof FunctionDescriptor : "compareTo target should be a function: " + target;
|
||||
FunctionDescriptor descriptor = (FunctionDescriptor) target;
|
||||
|
||||
StackValue receiver = gen(expression.getLeft());
|
||||
Callable callable = resolveToCallable(descriptor, false);
|
||||
|
||||
StackValue result;
|
||||
if (callable instanceof IntrinsicMethod) {
|
||||
result = ((IntrinsicMethod) callable).generate(
|
||||
this, v, Type.INT_TYPE, expression, Collections.singletonList(expression.getRight()), receiver, state);
|
||||
} else {
|
||||
result = invokeOperation(expression, descriptor, (CallableMethod) callable);
|
||||
}
|
||||
|
||||
result.put(Type.INT_TYPE, v);
|
||||
v.iconst(0);
|
||||
return StackValue.cmp(expression.getOperationToken(), Type.INT_TYPE);
|
||||
}
|
||||
|
||||
private StackValue generateAssignmentExpression(JetBinaryExpression expression) {
|
||||
|
||||
@@ -28,6 +28,8 @@ import org.jetbrains.jet.lang.psi.JetExpression;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
import static org.jetbrains.jet.codegen.AsmUtil.isPrimitive;
|
||||
|
||||
/**
|
||||
* @author alex.tkachman
|
||||
*/
|
||||
@@ -43,21 +45,25 @@ public class CompareTo implements IntrinsicMethod {
|
||||
@NotNull GenerationState state
|
||||
) {
|
||||
assert arguments != null;
|
||||
receiver.put(receiver.type, v);
|
||||
codegen.gen(arguments.get(0), receiver.type);
|
||||
if (receiver.type == Type.BYTE_TYPE || receiver.type == Type.SHORT_TYPE || receiver.type == Type.CHAR_TYPE) {
|
||||
JetExpression argument = arguments.get(0);
|
||||
Type type = comparisonOperandType(receiver.type, codegen.expressionType(argument));
|
||||
|
||||
receiver.put(type, v);
|
||||
codegen.gen(argument, type);
|
||||
|
||||
if (type == Type.BYTE_TYPE || type == Type.SHORT_TYPE || type == Type.CHAR_TYPE) {
|
||||
v.sub(Type.INT_TYPE);
|
||||
}
|
||||
else if (receiver.type == Type.INT_TYPE) {
|
||||
else if (type == Type.INT_TYPE) {
|
||||
v.invokestatic("jet/runtime/Intrinsics", "compare", "(II)I");
|
||||
}
|
||||
else if (receiver.type == Type.LONG_TYPE) {
|
||||
else if (type == Type.LONG_TYPE) {
|
||||
v.invokestatic("jet/runtime/Intrinsics", "compare", "(JJ)I");
|
||||
}
|
||||
else if (receiver.type == Type.FLOAT_TYPE) {
|
||||
else if (type == Type.FLOAT_TYPE) {
|
||||
v.invokestatic("java/lang/Float", "compare", "(FF)I");
|
||||
}
|
||||
else if (receiver.type == Type.DOUBLE_TYPE) {
|
||||
else if (type == Type.DOUBLE_TYPE) {
|
||||
v.invokestatic("java/lang/Double", "compare", "(DD)I");
|
||||
}
|
||||
else {
|
||||
@@ -65,4 +71,11 @@ public class CompareTo implements IntrinsicMethod {
|
||||
}
|
||||
return StackValue.onStack(Type.INT_TYPE);
|
||||
}
|
||||
|
||||
private static Type comparisonOperandType(Type left, Type right) {
|
||||
if (left == Type.DOUBLE_TYPE || right == Type.DOUBLE_TYPE) return Type.DOUBLE_TYPE;
|
||||
if (left == Type.FLOAT_TYPE || right == Type.FLOAT_TYPE) return Type.FLOAT_TYPE;
|
||||
if (left == Type.LONG_TYPE || right == Type.LONG_TYPE) return Type.LONG_TYPE;
|
||||
return Type.INT_TYPE;
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user