JS: fix Long constant translation (KT-19228 fixed)
This commit is contained in:
@@ -65,6 +65,8 @@ public final class Namer {
|
||||
public static final String LONG_ZERO = "ZERO";
|
||||
public static final String LONG_ONE = "ONE";
|
||||
public static final String LONG_NEG_ONE = "NEG_ONE";
|
||||
public static final String LONG_MAX_VALUE = "MAX_VALUE";
|
||||
public static final String LONG_MIN_VALUE = "MIN_VALUE";
|
||||
public static final String PRIMITIVE_COMPARE_TO = "primitiveCompareTo";
|
||||
public static final String IS_CHAR = "isChar";
|
||||
public static final String IS_NUMBER = "isNumber";
|
||||
|
||||
@@ -465,7 +465,7 @@ public final class StaticContext {
|
||||
}
|
||||
|
||||
@NotNull
|
||||
private JsName importDeclaration(@NotNull String suggestedName, @NotNull String tag, @NotNull JsExpression declaration) {
|
||||
JsName importDeclaration(@NotNull String suggestedName, @NotNull String tag, @NotNull JsExpression declaration) {
|
||||
JsName result = importDeclarationImpl(suggestedName, tag, declaration);
|
||||
fragment.getNameBindings().add(new JsNameBinding(tag, result));
|
||||
return result;
|
||||
|
||||
+28
@@ -879,6 +879,34 @@ public class TranslationContext {
|
||||
return parent;
|
||||
}
|
||||
|
||||
@NotNull
|
||||
public JsExpression declareConstantValue(@NotNull DeclarationDescriptor descriptor, @NotNull JsExpression value) {
|
||||
if (!isPublicInlineFunction() && isFromCurrentModule(descriptor)) {
|
||||
return getQualifiedReference(descriptor);
|
||||
}
|
||||
|
||||
// Tag shouldn't be null if we cannot reference this descriptor locally.
|
||||
String tag = Objects.requireNonNull(staticContext.getTag(descriptor));
|
||||
String suggestedName = StaticContext.getSuggestedName(descriptor);
|
||||
|
||||
return declareConstantValue(suggestedName, tag, value);
|
||||
}
|
||||
|
||||
@NotNull
|
||||
public JsExpression declareConstantValue(@NotNull String suggestedName, @NotNull String tag, @NotNull JsExpression value) {
|
||||
if (inlineFunctionContext == null || !isPublicInlineFunction()) {
|
||||
return staticContext.importDeclaration(suggestedName, tag, value).makeRef();
|
||||
}
|
||||
else {
|
||||
return inlineFunctionContext.getImports().computeIfAbsent(tag, t -> {
|
||||
JsName result = JsScope.declareTemporaryName(suggestedName);
|
||||
MetadataProperties.setImported(result, true);
|
||||
inlineFunctionContext.getImportBlock().getStatements().add(JsAstUtils.newVar(result, value));
|
||||
return result;
|
||||
}).makeRef();
|
||||
}
|
||||
}
|
||||
|
||||
@NotNull
|
||||
public JsName getNameForSpecialFunction(@NotNull SpecialFunction function) {
|
||||
if (inlineFunctionContext == null || !isPublicInlineFunction()) {
|
||||
|
||||
@@ -31,6 +31,7 @@ import org.jetbrains.kotlin.js.facade.TranslationUnit;
|
||||
import org.jetbrains.kotlin.js.facade.exceptions.TranslationException;
|
||||
import org.jetbrains.kotlin.js.facade.exceptions.TranslationRuntimeException;
|
||||
import org.jetbrains.kotlin.js.facade.exceptions.UnsupportedFeatureException;
|
||||
import org.jetbrains.kotlin.js.naming.NameSuggestion;
|
||||
import org.jetbrains.kotlin.js.sourceMap.SourceFilePathResolver;
|
||||
import org.jetbrains.kotlin.js.translate.callTranslator.CallTranslator;
|
||||
import org.jetbrains.kotlin.js.translate.context.Namer;
|
||||
@@ -41,15 +42,9 @@ import org.jetbrains.kotlin.js.translate.declaration.FileDeclarationVisitor;
|
||||
import org.jetbrains.kotlin.js.translate.expression.ExpressionVisitor;
|
||||
import org.jetbrains.kotlin.js.translate.expression.PatternTranslator;
|
||||
import org.jetbrains.kotlin.js.translate.test.JSTestGenerator;
|
||||
import org.jetbrains.kotlin.js.translate.utils.AnnotationsUtils;
|
||||
import org.jetbrains.kotlin.js.translate.utils.BindingUtils;
|
||||
import org.jetbrains.kotlin.js.translate.utils.JsAstUtils;
|
||||
import org.jetbrains.kotlin.js.translate.utils.TranslationUtils;
|
||||
import org.jetbrains.kotlin.js.translate.utils.*;
|
||||
import org.jetbrains.kotlin.js.translate.utils.mutator.AssignToExpressionMutator;
|
||||
import org.jetbrains.kotlin.psi.KtDeclaration;
|
||||
import org.jetbrains.kotlin.psi.KtExpression;
|
||||
import org.jetbrains.kotlin.psi.KtFile;
|
||||
import org.jetbrains.kotlin.psi.KtUnaryExpression;
|
||||
import org.jetbrains.kotlin.psi.*;
|
||||
import org.jetbrains.kotlin.resolve.BindingTrace;
|
||||
import org.jetbrains.kotlin.resolve.bindingContextUtil.BindingContextUtilsKt;
|
||||
import org.jetbrains.kotlin.resolve.constants.CompileTimeConstant;
|
||||
@@ -99,12 +94,30 @@ public final class Translation {
|
||||
}
|
||||
|
||||
CompileTimeConstant<?> compileTimeValue = ConstantExpressionEvaluator.getConstant(expression, context.bindingContext());
|
||||
if (compileTimeValue != null) {
|
||||
if (compileTimeValue != null && !compileTimeValue.getUsesNonConstValAsConstant()) {
|
||||
KotlinType type = context.bindingContext().getType(expression);
|
||||
if (type != null) {
|
||||
if (KotlinBuiltIns.isLong(type) || (KotlinBuiltIns.isInt(type) && expression instanceof KtUnaryExpression)) {
|
||||
JsExpression constantResult = translateConstant(compileTimeValue, expression, context);
|
||||
if (constantResult != null) return constantResult.source(expression);
|
||||
if (type != null && (KotlinBuiltIns.isLong(type) || KotlinBuiltIns.isInt(type))) {
|
||||
JsExpression constantResult = translateConstant(compileTimeValue, expression, context);
|
||||
if (constantResult != null) {
|
||||
constantResult.setSource(expression);
|
||||
|
||||
if (KotlinBuiltIns.isLong(type)) {
|
||||
KtReferenceExpression referenceExpression = PsiUtils.getSimpleName(expression);
|
||||
if (referenceExpression != null) {
|
||||
DeclarationDescriptor descriptor =
|
||||
BindingUtils.getDescriptorForReferenceExpression(context.bindingContext(), referenceExpression);
|
||||
if (descriptor != null) {
|
||||
return context.declareConstantValue(descriptor, constantResult);
|
||||
}
|
||||
}
|
||||
|
||||
String name = NameSuggestion.sanitizeName("L" + compileTimeValue.getValue(type).toString());
|
||||
return context.declareConstantValue(name, "constant:" + name, constantResult);
|
||||
}
|
||||
|
||||
if (KotlinBuiltIns.isInt(type)) {
|
||||
return constantResult;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -169,12 +169,20 @@ public final class JsAstUtils {
|
||||
public static JsExpression newLong(long value) {
|
||||
JsExpression result;
|
||||
if (value < Integer.MIN_VALUE || value > Integer.MAX_VALUE) {
|
||||
int low = (int) value;
|
||||
int high = (int) (value >> 32);
|
||||
List<JsExpression> args = new SmartList<>();
|
||||
args.add(new JsIntLiteral(low));
|
||||
args.add(new JsIntLiteral(high));
|
||||
result = new JsNew(Namer.kotlinLong(), args);
|
||||
if (value == Long.MAX_VALUE) {
|
||||
return new JsNameRef(Namer.LONG_MAX_VALUE, Namer.kotlinLong());
|
||||
}
|
||||
else if (value == Long.MIN_VALUE) {
|
||||
return new JsNameRef(Namer.LONG_MIN_VALUE, Namer.kotlinLong());
|
||||
}
|
||||
else {
|
||||
int low = (int) value;
|
||||
int high = (int) (value >> 32);
|
||||
List<JsExpression> args = new SmartList<>();
|
||||
args.add(new JsIntLiteral(low));
|
||||
args.add(new JsIntLiteral(high));
|
||||
result = new JsNew(Namer.kotlinLong(), args);
|
||||
}
|
||||
}
|
||||
else {
|
||||
if (value == 0) {
|
||||
|
||||
@@ -0,0 +1,256 @@
|
||||
// EXPECTED_REACHABLE_NODES: 1126
|
||||
|
||||
// MODULE: lib1
|
||||
// FILE: lib1.kt
|
||||
|
||||
package foo
|
||||
|
||||
// PROPERTY_READ_COUNT: name=longValue count=4 scope=testLongVal
|
||||
// PROPERTY_READ_COUNT: name=L23 count=2 scope=testLongVal
|
||||
// PROPERTY_READ_COUNT: name=L_23 count=2 scope=testLongVal
|
||||
// PROPERTY_READ_COUNT: name=L46 count=1 scope=testLongVal
|
||||
fun testLongVal() {
|
||||
val longValue = 23L
|
||||
|
||||
val longValueCopy = longValue
|
||||
assertEquals(23L, longValueCopy)
|
||||
|
||||
val minusLongValue = -longValue
|
||||
assertEquals(-23L, minusLongValue)
|
||||
|
||||
val minusLongValueParenthesized = -(longValue)
|
||||
assertEquals(-23L, minusLongValueParenthesized)
|
||||
|
||||
val twiceLongValue = 2 * longValue
|
||||
assertEquals(46L, twiceLongValue)
|
||||
}
|
||||
|
||||
const val longConst = 42L
|
||||
|
||||
// PROPERTY_READ_COUNT: name=longConst count=1 scope=testLongConst
|
||||
// PROPERTY_READ_COUNT: name=L42 count=1 scope=testLongConst
|
||||
// PROPERTY_READ_COUNT: name=L_42 count=4 scope=testLongConst
|
||||
// PROPERTY_READ_COUNT: name=L84 count=2 scope=testLongConst
|
||||
fun testLongConst() {
|
||||
val longConstCopy = longConst
|
||||
assertEquals(42L, longConstCopy)
|
||||
|
||||
val minusLongConst = -longConst
|
||||
assertEquals(-42L, minusLongConst)
|
||||
|
||||
val minusLongConstParenthesized = -(longConst)
|
||||
assertEquals(-42L, minusLongConstParenthesized)
|
||||
|
||||
val twiceLongConst = 2 * longConst
|
||||
assertEquals(84L, twiceLongConst)
|
||||
}
|
||||
|
||||
// PROPERTY_READ_COUNT: name=Long$Companion$MAX_VALUE count=2 scope=testLongMaxMinValue
|
||||
// PROPERTY_READ_COUNT: name=L_9223372036854775807 count=2 scope=testLongMaxMinValue
|
||||
// PROPERTY_READ_COUNT: name=Long$Companion$MIN_VALUE count=4 scope=testLongMaxMinValue
|
||||
fun testLongMaxMinValue() {
|
||||
val longMaxValue = Long.MAX_VALUE
|
||||
assertEquals(9223372036854775807L, longMaxValue)
|
||||
|
||||
val minusLongMaxValue = -Long.MAX_VALUE
|
||||
assertEquals(-9223372036854775807L, minusLongMaxValue)
|
||||
|
||||
val longMinValue = Long.MIN_VALUE
|
||||
assertEquals(-9223372036854775807L - 1L, longMinValue)
|
||||
|
||||
val minusLongMinValue = -Long.MIN_VALUE
|
||||
assertEquals(-9223372036854775807L - 1L, minusLongMinValue)
|
||||
}
|
||||
|
||||
// PROPERTY_READ_COUNT: name=intValue count=4 scope=testIntVal
|
||||
fun testIntVal() {
|
||||
val intValue = 23
|
||||
|
||||
val intValueCopy = intValue
|
||||
assertEquals(23, intValueCopy)
|
||||
|
||||
val minusIntValue = -intValue
|
||||
assertEquals(-23, minusIntValue)
|
||||
|
||||
val minusIntValueParenthesized = -(intValue)
|
||||
assertEquals(-23, minusIntValueParenthesized)
|
||||
|
||||
val twiceIntValue = 2 * intValue
|
||||
assertEquals(46, twiceIntValue)
|
||||
}
|
||||
|
||||
const val intConst = 42
|
||||
|
||||
// PROPERTY_NOT_READ_FROM: intConst scope=testIntConst
|
||||
fun testIntConst() {
|
||||
val intConstCopy = intConst
|
||||
assertEquals(42, intConstCopy)
|
||||
|
||||
val minusIntConst = -intConst
|
||||
assertEquals(-42, minusIntConst)
|
||||
|
||||
val minusIntConstParenthesized = -(intConst)
|
||||
assertEquals(-42, minusIntConstParenthesized)
|
||||
|
||||
val twiceIntConst = 2 * intConst
|
||||
assertEquals(84, twiceIntConst)
|
||||
}
|
||||
|
||||
// PROPERTY_NOT_READ_FROM: MAX_VALUE scope=testIntMaxMinValue
|
||||
// PROPERTY_NOT_READ_FROM: MIN_VALUE scope=testIntMaxMinValue
|
||||
fun testIntMaxMinValue() {
|
||||
val intMaxValue = Int.MAX_VALUE
|
||||
assertEquals(2147483647, intMaxValue)
|
||||
|
||||
val minusIntMaxValue = -Int.MAX_VALUE
|
||||
assertEquals(-2147483647, minusIntMaxValue)
|
||||
|
||||
val intMinValue = Int.MIN_VALUE
|
||||
assertEquals(-2147483648, intMinValue)
|
||||
|
||||
val minusIntMinValue = -Int.MIN_VALUE
|
||||
assertEquals(-2147483648, minusIntMinValue)
|
||||
}
|
||||
|
||||
const val bigLongConst = 123456789012345L
|
||||
|
||||
// PROPERTY_READ_COUNT: name=longConst count=1 scope=testImportedLongConstInlineFunLib1
|
||||
// PROPERTY_READ_COUNT: name=bigLongConst count=1 scope=testImportedLongConstInlineFunLib1
|
||||
inline fun testImportedLongConstInlineFunLib1() {
|
||||
val longConstCopy = longConst
|
||||
assertEquals(42L, longConstCopy)
|
||||
|
||||
val minusLongConst = -longConst
|
||||
assertEquals(-42L, minusLongConst)
|
||||
|
||||
val minusLongConstParenthesized = -(longConst)
|
||||
assertEquals(-42L, minusLongConstParenthesized)
|
||||
|
||||
val twiceLongConst = 2 * longConst
|
||||
assertEquals(84L, twiceLongConst)
|
||||
|
||||
val bigLongConstCopy = bigLongConst
|
||||
assertEquals(123456789012345L, bigLongConstCopy)
|
||||
}
|
||||
|
||||
// PROPERTY_READ_COUNT: name=longConst_0 count=1 scope=testImportedLongConstInlinedLocally
|
||||
// PROPERTY_READ_COUNT: name=L42 count=1 scope=testImportedLongConstInlinedLocally
|
||||
// PROPERTY_READ_COUNT: name=L_42 count=4 scope=testImportedLongConstInlinedLocally
|
||||
// PROPERTY_READ_COUNT: name=L84 count=2 scope=testImportedLongConstInlinedLocally
|
||||
// PROPERTY_READ_COUNT: name=bigLongConst_0 count=1 scope=testImportedLongConstInlinedLocally
|
||||
// PROPERTY_READ_COUNT: name=L123456789012345 count=1 scope=testImportedLongConstInlinedLocally
|
||||
private fun testImportedLongConstInlinedLocally() {
|
||||
testImportedLongConstInlineFunLib1()
|
||||
}
|
||||
|
||||
fun testLib1() {
|
||||
testLongVal()
|
||||
testLongConst()
|
||||
testLongMaxMinValue()
|
||||
|
||||
testIntVal()
|
||||
testIntConst()
|
||||
testIntMaxMinValue()
|
||||
|
||||
testImportedLongConstInlinedLocally()
|
||||
}
|
||||
|
||||
// MODULE: lib2(lib1)
|
||||
// FILE: lib2.kt
|
||||
|
||||
package foo
|
||||
|
||||
// PROPERTY_NOT_READ_FROM: $module$lib1.foo.longConst
|
||||
|
||||
// PROPERTY_READ_COUNT: name=longConst count=1 scope=testImportedLongConst
|
||||
// PROPERTY_READ_COUNT: name=L42 count=1 scope=testImportedLongConst
|
||||
// PROPERTY_READ_COUNT: name=L_42 count=4 scope=testImportedLongConst
|
||||
// PROPERTY_READ_COUNT: name=L84 count=2 scope=testImportedLongConst
|
||||
// PROPERTY_READ_COUNT: name=bigLongConst count=1 scope=testImportedLongConst
|
||||
// PROPERTY_READ_COUNT: name=L123456789012345 count=1 scope=testImportedLongConst
|
||||
fun testImportedLongConst() {
|
||||
val longConstCopy = longConst
|
||||
assertEquals(42L, longConstCopy)
|
||||
|
||||
val minusLongConst = -longConst
|
||||
assertEquals(-42L, minusLongConst)
|
||||
|
||||
val minusLongConstParenthesized = -(longConst)
|
||||
assertEquals(-42L, minusLongConstParenthesized)
|
||||
|
||||
val twiceLongConst = 2 * longConst
|
||||
assertEquals(84L, twiceLongConst)
|
||||
|
||||
val bigLongConstCopy = bigLongConst
|
||||
assertEquals(123456789012345L, bigLongConstCopy)
|
||||
}
|
||||
|
||||
// PROPERTY_READ_COUNT: name=longConst count=1 scope=testImportedLongConstInlineFun
|
||||
// PROPERTY_READ_COUNT: name=bigLongConst count=1 scope=testImportedLongConstInlineFun
|
||||
inline fun testImportedLongConstInlineFun() {
|
||||
val longConstCopy = longConst
|
||||
assertEquals(42L, longConstCopy)
|
||||
|
||||
val minusLongConst = -longConst
|
||||
assertEquals(-42L, minusLongConst)
|
||||
|
||||
val minusLongConstParenthesized = -(longConst)
|
||||
assertEquals(-42L, minusLongConstParenthesized)
|
||||
|
||||
val twiceLongConst = 2 * longConst
|
||||
assertEquals(84L, twiceLongConst)
|
||||
|
||||
val bigLongConstCopy = bigLongConst
|
||||
assertEquals(123456789012345L, bigLongConstCopy)
|
||||
}
|
||||
|
||||
// PROPERTY_READ_COUNT: name=longConst count=1 scope=testImportedLongConstInlinedLocally
|
||||
// PROPERTY_READ_COUNT: name=L42 count=1 scope=testImportedLongConstInlinedLocally
|
||||
// PROPERTY_READ_COUNT: name=L_42 count=4 scope=testImportedLongConstInlinedLocally
|
||||
// PROPERTY_READ_COUNT: name=L84 count=2 scope=testImportedLongConstInlinedLocally
|
||||
// PROPERTY_READ_COUNT: name=bigLongConst count=1 scope=testImportedLongConstInlinedLocally
|
||||
// PROPERTY_READ_COUNT: name=L123456789012345 count=1 scope=testImportedLongConstInlinedLocally
|
||||
fun testImportedLongConstInlinedLocally() {
|
||||
testImportedLongConstInlineFun()
|
||||
}
|
||||
|
||||
// PROPERTY_READ_COUNT: name=longConst count=1 scope=testImportedLongConstInlinedLocallyFromOtherModule
|
||||
// PROPERTY_READ_COUNT: name=L42 count=1 scope=testImportedLongConstInlinedLocallyFromOtherModule
|
||||
// PROPERTY_READ_COUNT: name=L_42 count=4 scope=testImportedLongConstInlinedLocallyFromOtherModule
|
||||
// PROPERTY_READ_COUNT: name=L84 count=2 scope=testImportedLongConstInlinedLocallyFromOtherModule
|
||||
// PROPERTY_READ_COUNT: name=bigLongConst count=1 scope=testImportedLongConstInlinedLocallyFromOtherModule
|
||||
// PROPERTY_READ_COUNT: name=L123456789012345 count=1 scope=testImportedLongConstInlinedLocallyFromOtherModule
|
||||
private fun testImportedLongConstInlinedLocallyFromOtherModule() {
|
||||
testImportedLongConstInlineFunLib1()
|
||||
}
|
||||
|
||||
fun testLib2() {
|
||||
testLib1()
|
||||
|
||||
testImportedLongConst()
|
||||
testImportedLongConstInlinedLocallyFromOtherModule()
|
||||
}
|
||||
|
||||
// MODULE: main(lib2)
|
||||
// FILE: main.kt
|
||||
package foo
|
||||
|
||||
// PROPERTY_READ_COUNT: name=longConst count=1 scope=testImportedLongConstInlinedFromOtherModule
|
||||
// PROPERTY_READ_COUNT: name=L42 count=1 scope=testImportedLongConstInlinedFromOtherModule
|
||||
// PROPERTY_READ_COUNT: name=L_42 count=4 scope=testImportedLongConstInlinedFromOtherModule
|
||||
// PROPERTY_READ_COUNT: name=L84 count=2 scope=testImportedLongConstInlinedFromOtherModule
|
||||
// PROPERTY_READ_COUNT: name=bigLongConst count=1 scope=testImportedLongConstInlinedFromOtherModule
|
||||
// PROPERTY_READ_COUNT: name=L123456789012345 count=1 scope=testImportedLongConstInlinedFromOtherModule
|
||||
fun testImportedLongConstInlinedFromOtherModule() {
|
||||
testImportedLongConstInlineFun()
|
||||
}
|
||||
|
||||
|
||||
fun box(): String {
|
||||
testLib2()
|
||||
|
||||
testImportedLongConstInlinedLocally()
|
||||
testImportedLongConstInlinedFromOtherModule()
|
||||
|
||||
return "OK"
|
||||
}
|
||||
+1
-1
@@ -5,4 +5,4 @@ fun foo() {
|
||||
0L)
|
||||
}
|
||||
|
||||
// LINES: 6 2 3 4 5
|
||||
// LINES: 3 * 5 6 2 4
|
||||
Reference in New Issue
Block a user