From 812d2a185b29199bcf2fc1489cec9cb31fdcfb01 Mon Sep 17 00:00:00 2001 From: Dmitry Jemerov Date: Thu, 7 Apr 2011 17:03:21 +0200 Subject: [PATCH] casts for constants --- .../jet/codegen/ExpressionCodegen.java | 103 ++++++++++++---- .../org/jetbrains/jet/codegen/StackValue.java | 115 ++++++++---------- .../jet/codegen/NamespaceGenTest.java | 13 ++ 3 files changed, 141 insertions(+), 90 deletions(-) diff --git a/idea/src/org/jetbrains/jet/codegen/ExpressionCodegen.java b/idea/src/org/jetbrains/jet/codegen/ExpressionCodegen.java index 08ed66ffaee..7a0db199799 100644 --- a/idea/src/org/jetbrains/jet/codegen/ExpressionCodegen.java +++ b/idea/src/org/jetbrains/jet/codegen/ExpressionCodegen.java @@ -2,6 +2,7 @@ package org.jetbrains.jet.codegen; import com.intellij.psi.*; import com.intellij.psi.tree.IElementType; +import org.jetbrains.annotations.Nullable; import org.jetbrains.jet.lang.psi.*; import org.jetbrains.jet.lang.resolve.BindingContext; import org.jetbrains.jet.lang.types.*; @@ -186,7 +187,7 @@ public class ExpressionCodegen extends JetVisitor { @Override public void visitConstantExpression(JetConstantExpression expression) { - myStack.push(StackValue.constant(expression.getValue())); + myStack.push(StackValue.constant(expression.getValue(), expressionType(expression))); } @Override @@ -259,6 +260,18 @@ public class ExpressionCodegen extends JetVisitor { @Override public void visitSimpleNameExpression(JetSimpleNameExpression expression) { final DeclarationDescriptor descriptor = bindingContext.resolveReferenceExpression(expression); + if (descriptor instanceof PropertyDescriptor) { + final DeclarationDescriptor container = descriptor.getContainingDeclaration(); + if (isClass(container, "Number")) { + Type castType = getCastType(expression.getReferencedName()); + if (castType != null) { + final StackValue value = myStack.pop(); + value.put(castType, v); + myStack.push(StackValue.onStack(castType)); + return; + } + } + } PsiElement declaration = bindingContext.getDeclarationPsiElement(descriptor); if (declaration instanceof PsiField) { PsiField psiField = (PsiField) declaration; @@ -284,6 +297,32 @@ public class ExpressionCodegen extends JetVisitor { } } + @Nullable + private static Type getCastType(String castMethodName) { + if ("dbl".equals(castMethodName)) { + return Type.DOUBLE_TYPE; + } + if ("flt".equals(castMethodName)) { + return Type.FLOAT_TYPE; + } + if ("lng".equals(castMethodName)) { + return Type.LONG_TYPE; + } + if ("int".equals(castMethodName)) { + return Type.INT_TYPE; + } + if ("chr".equals(castMethodName)) { + return Type.CHAR_TYPE; + } + if ("sht".equals(castMethodName)) { + return Type.SHORT_TYPE; + } + if ("byt".equals(castMethodName)) { + return Type.BYTE_TYPE; + } + return null; + } + @Override public void visitCallExpression(JetCallExpression expression) { JetExpression callee = expression.getCalleeExpression(); @@ -354,6 +393,10 @@ public class ExpressionCodegen extends JetVisitor { return Type.getMethodDescriptor(returnType, parameterTypes); } + private Type expressionType(JetExpression expr) { + return typeMapper.mapType(bindingContext.getExpressionType(expr)); + } + private static Type psiTypeToAsm(PsiType type) { if (type instanceof PsiPrimitiveType) { if (type == PsiType.VOID) { @@ -444,45 +487,51 @@ public class ExpressionCodegen extends JetVisitor { JetType returnType = bindingContext.getExpressionType(expression); final Type asmType = typeMapper.mapType(returnType); DeclarationDescriptor cls = op.getContainingDeclaration(); - if (cls instanceof ClassDescriptor) { - final String className = cls.getName(); - if (isNumberPrimitive(className)) { - if (op.getName().equals("compareTo")) { - generateCompareOp(expression, opToken, asmType); - } - else { - int opcode = opcodeForMethod(op.getName()); - generateBinaryOp(expression, (FunctionDescriptor) op, opcode); - } - return; - } - else if (className.equals("Hashable")) { - if (op.getName().equals("equals")) { - final Type leftType = typeMapper.mapType(bindingContext.getExpressionType(expression.getLeft())); - final Type rightType = typeMapper.mapType(bindingContext.getExpressionType(expression.getRight())); - if (isNumberPrimitive(leftType) && leftType == rightType) { - generateCompareOp(expression, opToken, leftType); - return; - } - else { - throw new UnsupportedOperationException("Don't know how to generate equality for these types"); - } - } + if (isNumberPrimitive(cls)) { + if (op.getName().equals("compareTo")) { + generateCompareOp(expression, opToken, asmType); } else { - throw new UnsupportedOperationException("Don't know how to generate binary op for class " + className); + int opcode = opcodeForMethod(op.getName()); + generateBinaryOp(expression, (FunctionDescriptor) op, opcode); + } + return; + } + else if (isClass(cls, "Hashable")) { + if (op.getName().equals("equals")) { + final Type leftType = typeMapper.mapType(bindingContext.getExpressionType(expression.getLeft())); + final Type rightType = typeMapper.mapType(bindingContext.getExpressionType(expression.getRight())); + if (isNumberPrimitive(leftType) && leftType == rightType) { + generateCompareOp(expression, opToken, leftType); + return; + } + else { + throw new UnsupportedOperationException("Don't know how to generate equality for these types"); + } } } } throw new UnsupportedOperationException("Don't know how to generate binary op " + expression); } - private static boolean isNumberPrimitive(String className) { + private static boolean isNumberPrimitive(DeclarationDescriptor descriptor) { + if (!(descriptor instanceof ClassDescriptor)) { + return false; + } + String className = descriptor.getName(); return className.equals("Int") || className.equals("Long") || className.equals("Short") || className.equals("Byte") || className.equals("Char") || className.equals("Float") || className.equals("Double"); } + private static boolean isClass(DeclarationDescriptor descriptor, String name) { + if (!(descriptor instanceof ClassDescriptor)) { + return false; + } + String className = descriptor.getName(); + return className.equals(name); + } + private static boolean isNumberPrimitive(Type type) { return type == Type.INT_TYPE || type == Type.SHORT_TYPE || type == Type.BYTE_TYPE || type == Type.CHAR_TYPE || type == Type.FLOAT_TYPE || type == Type.DOUBLE_TYPE || type == Type.LONG_TYPE; diff --git a/idea/src/org/jetbrains/jet/codegen/StackValue.java b/idea/src/org/jetbrains/jet/codegen/StackValue.java index 8366208bbee..f2bafda7e6b 100644 --- a/idea/src/org/jetbrains/jet/codegen/StackValue.java +++ b/idea/src/org/jetbrains/jet/codegen/StackValue.java @@ -11,6 +11,12 @@ import org.objectweb.asm.commons.InstructionAdapter; * @author yole */ public abstract class StackValue { + protected final Type type; + + public StackValue(Type type) { + this.type = type; + } + public abstract void put(Type type, InstructionAdapter v); public static StackValue local(int index, Type type) { @@ -22,8 +28,8 @@ public abstract class StackValue { return new OnStack(type); } - public static StackValue constant(Object value) { - return new Constant(value); + public static StackValue constant(Object value, Type type) { + return new Constant(value, type); } public static StackValue cmp(IElementType opToken, Type type) { @@ -32,44 +38,54 @@ public abstract class StackValue { public abstract void condJump(Label label, boolean jumpIfFalse, InstructionAdapter v); + private static void box(final Type type, InstructionAdapter v) { + if (type == Type.INT_TYPE) { + v.invokestatic("java/lang/Integer", "valueOf", "(I)Ljava/lang/Integer;"); + } + else if (type == Type.BOOLEAN_TYPE) { + v.invokestatic("java/lang/Boolean", "valueOf", "(Z)Ljava/lang/Boolean;"); + } + else if (type == Type.CHAR_TYPE) { + v.invokestatic("java/lang/Character", "valueOf", "(C)Ljava/lang/Character;"); + } + else if (type == Type.SHORT_TYPE) { + v.invokestatic("java/lang/Short", "valueOf", "(S)Ljava/lang/Short;"); + } + else if (type == Type.LONG_TYPE) { + v.invokestatic("java/lang/Long", "valueOf", "(J)Ljava/lang/Long;"); + } + else if (type == Type.BYTE_TYPE) { + v.invokestatic("java/lang/Byte", "valueOf", "(B)Ljava/lang/Byte;"); + } + else if (type == Type.FLOAT_TYPE) { + v.invokestatic("java/lang/Float", "valueOf", "(F)Ljava/lang/Float;"); + } + else if (type == Type.DOUBLE_TYPE) { + v.invokestatic("java/lang/Double", "valueOf", "(D)Ljava/lang/Double;"); + } + } + + protected void coerce(Type type, InstructionAdapter v) { + if (type.getSort() == Type.OBJECT) { + box(this.type, v); + } + else if (type != this.type) { + v.cast(this.type, type); + } + } + public static class Local extends StackValue { private final int index; - private final Type type; public Local(int index, Type type) { + super(type); this.index = index; - this.type = type; } @Override public void put(Type type, InstructionAdapter v) { v.load(index, this.type); - if (type.getSort() == Type.OBJECT) { - if (this.type == Type.INT_TYPE) { - v.invokestatic("java/lang/Integer", "valueOf", "(I)Ljava/lang/Integer;"); - } - else if (this.type == Type.BOOLEAN_TYPE) { - v.invokestatic("java/lang/Boolean", "valueOf", "(Z)Ljava/lang/Boolean;"); - } - else if (this.type == Type.CHAR_TYPE) { - v.invokestatic("java/lang/Character", "valueOf", "(C)Ljava/lang/Character;"); - } - else if (this.type == Type.SHORT_TYPE) { - v.invokestatic("java/lang/Short", "valueOf", "(S)Ljava/lang/Short;"); - } - else if (this.type == Type.LONG_TYPE) { - v.invokestatic("java/lang/Long", "valueOf", "(J)Ljava/lang/Long;"); - } - else if (this.type == Type.BYTE_TYPE) { - v.invokestatic("java/lang/Byte", "valueOf", "(B)Ljava/lang/Byte;"); - } - else if (this.type == Type.FLOAT_TYPE) { - v.invokestatic("java/lang/Float", "valueOf", "(F)Ljava/lang/Float;"); - } - else if (this.type == Type.DOUBLE_TYPE) { - v.invokestatic("java/lang/Double", "valueOf", "(D)Ljava/lang/Double;"); - } - } + coerce(type, v); // TODO unbox } @@ -86,10 +102,8 @@ public abstract class StackValue { } public static class OnStack extends StackValue { - private final Type type; - public OnStack(Type type) { - this.type = type; + super(type); } @Override @@ -98,7 +112,7 @@ public abstract class StackValue { @Override public void condJump(Label label, boolean jumpIfFalse, InstructionAdapter v) { - if (type == Type.BOOLEAN_TYPE) { + if (this.type == Type.BOOLEAN_TYPE) { if (jumpIfFalse) { v.ifeq(label); } @@ -115,39 +129,15 @@ public abstract class StackValue { public static class Constant extends StackValue { private final Object value; - public Constant(Object value) { + public Constant(Object value, Type type) { + super(type); this.value = value; } @Override public void put(Type type, InstructionAdapter v) { v.aconst(value); - if (type.getSort() == Type.OBJECT) { - if (value instanceof Integer) { - v.invokestatic("java/lang/Integer", "valueOf", "(I)Ljava/lang/Integer;"); - } - else if (value instanceof Boolean) { - v.invokestatic("java/lang/Boolean", "valueOf", "(Z)Ljava/lang/Boolean;"); - } - else if (value instanceof Character) { - v.invokestatic("java/lang/Character", "valueOf", "(C)Ljava/lang/Character;"); - } - else if (value instanceof Short) { - v.invokestatic("java/lang/Short", "valueOf", "(S)Ljava/lang/Short;"); - } - else if (value instanceof Long) { - v.invokestatic("java/lang/Long", "valueOf", "(J)Ljava/lang/Long;"); - } - else if (value instanceof Byte) { - v.invokestatic("java/lang/Byte", "valueOf", "(B)Ljava/lang/Byte;"); - } - else if (value instanceof Float) { - v.invokestatic("java/lang/Float", "valueOf", "(F)Ljava/lang/Float;"); - } - else if (value instanceof Double) { - v.invokestatic("java/lang/Double", "valueOf", "(D)Ljava/lang/Double;"); - } - } + coerce(type, v); } @Override @@ -166,11 +156,10 @@ public abstract class StackValue { private static class NumberCompare extends StackValue { private final IElementType opToken; - private final Type type; public NumberCompare(IElementType opToken, Type type) { + super(type); this.opToken = opToken; - this.type = type; } @Override diff --git a/idea/tests/org/jetbrains/jet/codegen/NamespaceGenTest.java b/idea/tests/org/jetbrains/jet/codegen/NamespaceGenTest.java index a0719af4887..46a3de975e2 100644 --- a/idea/tests/org/jetbrains/jet/codegen/NamespaceGenTest.java +++ b/idea/tests/org/jetbrains/jet/codegen/NamespaceGenTest.java @@ -314,6 +314,19 @@ public class NamespaceGenTest extends LightCodeInsightFixtureTestCase { assertEquals("1.0", main.invoke(null, 1.0)); } + public void testDoubleToInt() throws Exception { + loadText("fun foo(a: Double): Int = a.int"); + System.out.println(generateToText()); + final Method main = generateFunction(); + assertEquals(1, main.invoke(null, 1.0)); + } + + public void testCastConstant() throws Exception { + loadText("fun foo(): Double = 1.dbl"); + final Method main = generateFunction(); + assertEquals(1.0, main.invoke(null)); + } + private void binOpTest(final String text, final Object arg1, final Object arg2, final Object expected) throws Exception { loadText(text); System.out.println(generateToText());