KT-13664: write values of long compile-time constants as constants. Fix #KT-13664

This commit is contained in:
Alexey Andreev
2016-09-06 18:28:15 +03:00
parent 1e5fb91d7d
commit 9dd6c9a65c
4 changed files with 81 additions and 27 deletions
@@ -119,6 +119,12 @@ public class CastTestGenerated extends AbstractCastTest {
doTest(fileName);
}
@TestMetadata("implicitCastToLong.kt")
public void testImplicitCastToLong() throws Exception {
String fileName = KotlinTestUtils.navigationMetadata("js/js.translator/testData/expression/cast/cases/implicitCastToLong.kt");
doTest(fileName);
}
@TestMetadata("noRuntimeTypeCheck.kt")
public void testNoRuntimeTypeCheck() throws Exception {
String fileName = KotlinTestUtils.navigationMetadata("js/js.translator/testData/expression/cast/cases/noRuntimeTypeCheck.kt");
@@ -86,34 +86,13 @@ public final class ExpressionVisitor extends TranslatorVisitor<JsNode> {
private static JsNode translateConstantExpression(@NotNull KtConstantExpression expression, @NotNull TranslationContext context) {
CompileTimeConstant<?> compileTimeValue = ConstantExpressionEvaluator.getConstant(expression, context.bindingContext());
assert compileTimeValue != null : message(expression, "Expression is not compile time value: " + expression.getText() + " ");
KotlinType expectedType = context.bindingContext().getType(expression);
ConstantValue<?> constant = compileTimeValue.toConstantValue(expectedType != null ? expectedType : TypeUtils.NO_EXPECTED_TYPE);
if (constant instanceof NullValue) {
return JsLiteral.NULL;
}
Object value = constant.getValue();
if (value instanceof Integer || value instanceof Short || value instanceof Byte) {
return context.program().getNumberLiteral(((Number) value).intValue());
}
else if (value instanceof Long) {
return JsAstUtils.newLong((Long) value, context);
}
else if (value instanceof Number) {
return context.program().getNumberLiteral(((Number) value).doubleValue());
}
else if (value instanceof Boolean) {
return JsLiteral.getBoolean((Boolean) value);
JsNode result = Translation.translateConstant(compileTimeValue, expression, context);
if (result == null) {
throw new AssertionError(message(expression, "Unsupported constant expression: " + expression.getText() + " "));
}
//TODO: test
if (value instanceof String) {
return context.program().getStringLiteral((String) value);
}
if (value instanceof Character) {
return context.program().getStringLiteral(value.toString());
}
throw new AssertionError(message(expression, "Unsupported constant expression: " + expression.getText() + " "));
return result;
}
@Override
@@ -19,6 +19,7 @@ package org.jetbrains.kotlin.js.translate.general;
import com.google.dart.compiler.backend.js.ast.*;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import org.jetbrains.kotlin.builtins.KotlinBuiltIns;
import org.jetbrains.kotlin.descriptors.FunctionDescriptor;
import org.jetbrains.kotlin.descriptors.ModuleDescriptor;
import org.jetbrains.kotlin.idea.MainFunctionDetector;
@@ -47,8 +48,15 @@ import org.jetbrains.kotlin.psi.KtDeclarationWithBody;
import org.jetbrains.kotlin.psi.KtExpression;
import org.jetbrains.kotlin.psi.KtFile;
import org.jetbrains.kotlin.psi.KtNamedFunction;
import org.jetbrains.kotlin.resolve.BindingContext;
import org.jetbrains.kotlin.resolve.BindingTrace;
import org.jetbrains.kotlin.resolve.bindingContextUtil.BindingContextUtilsKt;
import org.jetbrains.kotlin.resolve.constants.CompileTimeConstant;
import org.jetbrains.kotlin.resolve.constants.ConstantValue;
import org.jetbrains.kotlin.resolve.constants.NullValue;
import org.jetbrains.kotlin.resolve.constants.evaluate.ConstantExpressionEvaluator;
import org.jetbrains.kotlin.types.KotlinType;
import org.jetbrains.kotlin.types.TypeUtils;
import org.jetbrains.kotlin.utils.ExceptionUtilsKt;
import java.util.ArrayList;
@@ -56,8 +64,9 @@ import java.util.Collection;
import java.util.Collections;
import java.util.List;
import static org.jetbrains.kotlin.js.translate.general.ModuleWrapperTranslation.*;
import static org.jetbrains.kotlin.js.translate.general.ModuleWrapperTranslation.wrapIfNecessary;
import static org.jetbrains.kotlin.js.translate.utils.BindingUtils.getFunctionDescriptor;
import static org.jetbrains.kotlin.js.translate.utils.ErrorReportingUtils.message;
import static org.jetbrains.kotlin.js.translate.utils.JsAstUtils.convertToStatement;
import static org.jetbrains.kotlin.js.translate.utils.JsAstUtils.toStringLiteralList;
import static org.jetbrains.kotlin.js.translate.utils.mutator.LastExpressionMutator.mutateLastExpression;
@@ -102,6 +111,42 @@ public final class Translation {
return result;
}
@Nullable
public static JsExpression translateConstant(
@NotNull CompileTimeConstant compileTimeValue,
@NotNull KtExpression expression,
@NotNull TranslationContext context
) {
KotlinType expectedType = context.bindingContext().getType(expression);
ConstantValue<?> constant = compileTimeValue.toConstantValue(expectedType != null ? expectedType : TypeUtils.NO_EXPECTED_TYPE);
if (constant instanceof NullValue) {
return JsLiteral.NULL;
}
Object value = constant.getValue();
if (value instanceof Integer || value instanceof Short || value instanceof Byte) {
return context.program().getNumberLiteral(((Number) value).intValue());
}
else if (value instanceof Long) {
return JsAstUtils.newLong((Long) value, context);
}
else if (value instanceof Number) {
return context.program().getNumberLiteral(((Number) value).doubleValue());
}
else if (value instanceof Boolean) {
return JsLiteral.getBoolean((Boolean) value);
}
//TODO: test
if (value instanceof String) {
return context.program().getStringLiteral((String) value);
}
if (value instanceof Character) {
return context.program().getStringLiteral(value.toString());
}
return null;
}
@NotNull
private static JsNode doTranslateExpression(KtExpression expression, TranslationContext context) {
try {
@@ -129,6 +174,15 @@ public final class Translation {
@NotNull TranslationContext context,
@NotNull JsBlock block
) {
CompileTimeConstant<?> compileTimeValue = ConstantExpressionEvaluator.getConstant(expression, context.bindingContext());
if (compileTimeValue != null) {
KotlinType type = context.bindingContext().getType(expression);
if (type != null && KotlinBuiltIns.isLong(type)) {
JsExpression constantResult = translateConstant(compileTimeValue, expression, context);
if (constantResult != null) return constantResult;
}
}
JsNode jsNode = translateExpression(expression, context, block);
if (jsNode instanceof JsExpression) {
return (JsExpression) jsNode;
@@ -0,0 +1,15 @@
package foo
fun box(): String {
var a: Long = 23
var b: Long = 200 + 30
var c: Long = id((2000).plus(300))
assertEquals(24L, a + 1)
assertEquals(231L, b + 1)
assertEquals(2301L, c + 1)
return "OK"
}
fun id(x: Long) = x