KT-6942: in JS backed for value equalitity patterns in when generate structural equality check (i.e. Any.equals) instead of referential check (===).
(cherry picked from commit 97228e5)
This commit is contained in:
@@ -137,4 +137,8 @@ public final class WhenTest extends AbstractExpressionTest {
|
|||||||
public void testEmpty() throws Exception {
|
public void testEmpty() throws Exception {
|
||||||
checkFooBoxIsOk();
|
checkFooBoxIsOk();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public void testWhenEqualsPattern() throws Exception {
|
||||||
|
checkFooBoxIsOk();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
+44
-2
@@ -20,6 +20,8 @@ import com.google.dart.compiler.backend.js.ast.*;
|
|||||||
import org.jetbrains.annotations.NotNull;
|
import org.jetbrains.annotations.NotNull;
|
||||||
import org.jetbrains.annotations.Nullable;
|
import org.jetbrains.annotations.Nullable;
|
||||||
import org.jetbrains.kotlin.KtNodeTypes;
|
import org.jetbrains.kotlin.KtNodeTypes;
|
||||||
|
import org.jetbrains.kotlin.builtins.KotlinBuiltIns;
|
||||||
|
import org.jetbrains.kotlin.builtins.PrimitiveType;
|
||||||
import org.jetbrains.kotlin.descriptors.CallableDescriptor;
|
import org.jetbrains.kotlin.descriptors.CallableDescriptor;
|
||||||
import org.jetbrains.kotlin.descriptors.ClassDescriptor;
|
import org.jetbrains.kotlin.descriptors.ClassDescriptor;
|
||||||
import org.jetbrains.kotlin.descriptors.DeclarationDescriptor;
|
import org.jetbrains.kotlin.descriptors.DeclarationDescriptor;
|
||||||
@@ -31,7 +33,10 @@ import org.jetbrains.kotlin.js.translate.context.TemporaryVariable;
|
|||||||
import org.jetbrains.kotlin.js.translate.context.TranslationContext;
|
import org.jetbrains.kotlin.js.translate.context.TranslationContext;
|
||||||
import org.jetbrains.kotlin.js.translate.general.AbstractTranslator;
|
import org.jetbrains.kotlin.js.translate.general.AbstractTranslator;
|
||||||
import org.jetbrains.kotlin.js.translate.general.Translation;
|
import org.jetbrains.kotlin.js.translate.general.Translation;
|
||||||
|
import org.jetbrains.kotlin.js.translate.intrinsic.functions.factories.TopLevelFIF;
|
||||||
|
import org.jetbrains.kotlin.js.translate.utils.BindingUtils;
|
||||||
import org.jetbrains.kotlin.js.translate.utils.JsAstUtils;
|
import org.jetbrains.kotlin.js.translate.utils.JsAstUtils;
|
||||||
|
import org.jetbrains.kotlin.js.translate.utils.TranslationUtils;
|
||||||
import org.jetbrains.kotlin.lexer.KtTokens;
|
import org.jetbrains.kotlin.lexer.KtTokens;
|
||||||
import org.jetbrains.kotlin.name.Name;
|
import org.jetbrains.kotlin.name.Name;
|
||||||
import org.jetbrains.kotlin.psi.KtBinaryExpressionWithTypeRHS;
|
import org.jetbrains.kotlin.psi.KtBinaryExpressionWithTypeRHS;
|
||||||
@@ -39,10 +44,13 @@ import org.jetbrains.kotlin.psi.KtExpression;
|
|||||||
import org.jetbrains.kotlin.psi.KtIsExpression;
|
import org.jetbrains.kotlin.psi.KtIsExpression;
|
||||||
import org.jetbrains.kotlin.psi.KtTypeReference;
|
import org.jetbrains.kotlin.psi.KtTypeReference;
|
||||||
import org.jetbrains.kotlin.resolve.DescriptorUtils;
|
import org.jetbrains.kotlin.resolve.DescriptorUtils;
|
||||||
|
import org.jetbrains.kotlin.resolve.descriptorUtil.DescriptorUtilsKt;
|
||||||
import org.jetbrains.kotlin.types.DynamicTypesKt;
|
import org.jetbrains.kotlin.types.DynamicTypesKt;
|
||||||
import org.jetbrains.kotlin.types.KotlinType;
|
import org.jetbrains.kotlin.types.KotlinType;
|
||||||
import org.jetbrains.kotlin.types.typeUtil.TypeUtilsKt;
|
import org.jetbrains.kotlin.types.typeUtil.TypeUtilsKt;
|
||||||
|
|
||||||
|
import java.util.Collections;
|
||||||
|
|
||||||
import static org.jetbrains.kotlin.builtins.FunctionTypesKt.isFunctionTypeOrSubtype;
|
import static org.jetbrains.kotlin.builtins.FunctionTypesKt.isFunctionTypeOrSubtype;
|
||||||
import static org.jetbrains.kotlin.builtins.KotlinBuiltIns.isAnyOrNullableAny;
|
import static org.jetbrains.kotlin.builtins.KotlinBuiltIns.isAnyOrNullableAny;
|
||||||
import static org.jetbrains.kotlin.builtins.KotlinBuiltIns.isArray;
|
import static org.jetbrains.kotlin.builtins.KotlinBuiltIns.isArray;
|
||||||
@@ -235,9 +243,43 @@ public final class PatternTranslator extends AbstractTranslator {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@NotNull
|
@NotNull
|
||||||
public JsExpression translateExpressionPattern(@NotNull JsExpression expressionToMatch, @NotNull KtExpression patternExpression) {
|
public JsExpression translateExpressionPattern(
|
||||||
|
@NotNull KotlinType type,
|
||||||
|
@NotNull JsExpression expressionToMatch,
|
||||||
|
@NotNull KtExpression patternExpression
|
||||||
|
) {
|
||||||
JsExpression expressionToMatchAgainst = translateExpressionForExpressionPattern(patternExpression);
|
JsExpression expressionToMatchAgainst = translateExpressionForExpressionPattern(patternExpression);
|
||||||
return equality(expressionToMatch, expressionToMatchAgainst);
|
KotlinType patternType = BindingUtils.getTypeForExpression(bindingContext(), patternExpression);
|
||||||
|
|
||||||
|
EqualityType matchEquality = equalityType(type);
|
||||||
|
EqualityType patternEquality = equalityType(patternType);
|
||||||
|
|
||||||
|
if (matchEquality == EqualityType.PRIMITIVE && patternEquality == EqualityType.PRIMITIVE) {
|
||||||
|
return equality(expressionToMatch, expressionToMatchAgainst);
|
||||||
|
}
|
||||||
|
else if (expressionToMatchAgainst == JsLiteral.NULL) {
|
||||||
|
return TranslationUtils.nullCheck(expressionToMatch, false);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
return TopLevelFIF.KOTLIN_EQUALS.apply(expressionToMatch, Collections.singletonList(expressionToMatchAgainst), context());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@NotNull
|
||||||
|
private static EqualityType equalityType(@NotNull KotlinType type) {
|
||||||
|
DeclarationDescriptor descriptor = type.getConstructor().getDeclarationDescriptor();
|
||||||
|
if (!(descriptor instanceof ClassDescriptor)) return EqualityType.GENERAL;
|
||||||
|
|
||||||
|
PrimitiveType primitive = KotlinBuiltIns.getPrimitiveTypeByFqName(DescriptorUtilsKt.getFqNameUnsafe(descriptor));
|
||||||
|
if (primitive == null) return EqualityType.GENERAL;
|
||||||
|
|
||||||
|
return primitive == PrimitiveType.LONG ? EqualityType.LONG : EqualityType.PRIMITIVE;
|
||||||
|
}
|
||||||
|
|
||||||
|
private enum EqualityType {
|
||||||
|
PRIMITIVE,
|
||||||
|
LONG,
|
||||||
|
GENERAL
|
||||||
}
|
}
|
||||||
|
|
||||||
@NotNull
|
@NotNull
|
||||||
|
|||||||
+5
-1
@@ -200,7 +200,11 @@ public final class WhenTranslator extends AbstractTranslator {
|
|||||||
return Translation.patternTranslator(context).translateExpressionForExpressionPattern(patternExpression);
|
return Translation.patternTranslator(context).translateExpressionForExpressionPattern(patternExpression);
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
return Translation.patternTranslator(context).translateExpressionPattern(expressionToMatch, patternExpression);
|
KtExpression subject = whenExpression.getSubjectExpression();
|
||||||
|
assert subject != null : "Subject must be non-null since expressionToMatch is non-null: " +
|
||||||
|
PsiUtilsKt.getTextWithLocation(condition);
|
||||||
|
KotlinType type = BindingUtils.getTypeForExpression(bindingContext(), whenExpression.getSubjectExpression());
|
||||||
|
return Translation.patternTranslator(context).translateExpressionPattern(type, expressionToMatch, patternExpression);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -0,0 +1,87 @@
|
|||||||
|
package foo
|
||||||
|
|
||||||
|
data class A(val bar: Int)
|
||||||
|
|
||||||
|
@native class B
|
||||||
|
|
||||||
|
fun makeB(): B = js("new Object();")
|
||||||
|
|
||||||
|
fun intAgainstInt(x: Int) = when (x) {
|
||||||
|
1 -> "a"
|
||||||
|
2 -> "b"
|
||||||
|
else -> "*"
|
||||||
|
}
|
||||||
|
|
||||||
|
fun intAgainstNullableInt(x: Int?) = when (x) {
|
||||||
|
1 -> "a"
|
||||||
|
2 -> "b"
|
||||||
|
null -> "c"
|
||||||
|
else -> "*"
|
||||||
|
}
|
||||||
|
|
||||||
|
fun anyAgainstInt(x: Any?) = when (x) {
|
||||||
|
1 -> "a"
|
||||||
|
2 -> "b"
|
||||||
|
else -> "*"
|
||||||
|
}
|
||||||
|
|
||||||
|
fun longAgainstLong(x: Long) = when (x) {
|
||||||
|
1L -> "a"
|
||||||
|
2L -> "b"
|
||||||
|
else -> "*"
|
||||||
|
}
|
||||||
|
|
||||||
|
fun anyAgainstLong(x: Any?) = when (x) {
|
||||||
|
1L -> "a"
|
||||||
|
2L -> "b"
|
||||||
|
null -> "c"
|
||||||
|
else -> "*"
|
||||||
|
}
|
||||||
|
|
||||||
|
fun anyAgainstAny(x: Any) = when (x) {
|
||||||
|
A(1) -> "a"
|
||||||
|
1 -> "b"
|
||||||
|
else -> "*"
|
||||||
|
}
|
||||||
|
|
||||||
|
fun dynamicAgainstPattern(x: dynamic) = when(x) {
|
||||||
|
1 -> "a"
|
||||||
|
"2" -> "b"
|
||||||
|
else -> "*"
|
||||||
|
}
|
||||||
|
|
||||||
|
fun box(): String {
|
||||||
|
assertEquals("a", intAgainstInt(1))
|
||||||
|
assertEquals("b", intAgainstInt(2))
|
||||||
|
assertEquals("*", intAgainstInt(23))
|
||||||
|
|
||||||
|
assertEquals("a", intAgainstNullableInt(1))
|
||||||
|
assertEquals("b", intAgainstNullableInt(2))
|
||||||
|
assertEquals("c", intAgainstNullableInt(null))
|
||||||
|
assertEquals("*", intAgainstNullableInt(23))
|
||||||
|
|
||||||
|
assertEquals("a", anyAgainstInt(1))
|
||||||
|
assertEquals("b", anyAgainstInt(2))
|
||||||
|
assertEquals("*", anyAgainstInt(A(23)))
|
||||||
|
|
||||||
|
assertEquals("a", longAgainstLong(1))
|
||||||
|
assertEquals("b", longAgainstLong(2))
|
||||||
|
assertEquals("*", longAgainstLong(23))
|
||||||
|
|
||||||
|
assertEquals("a", anyAgainstLong(1L))
|
||||||
|
assertEquals("b", anyAgainstLong(2L))
|
||||||
|
assertEquals("c", anyAgainstLong(null))
|
||||||
|
assertEquals("*", anyAgainstLong(A(23)))
|
||||||
|
|
||||||
|
assertEquals("a", anyAgainstAny(A(1)))
|
||||||
|
assertEquals("b", anyAgainstAny(1))
|
||||||
|
assertEquals("*", anyAgainstAny(listOf(1)))
|
||||||
|
|
||||||
|
assertEquals("a", dynamicAgainstPattern(1))
|
||||||
|
assertEquals("a", dynamicAgainstPattern(js("1")))
|
||||||
|
assertEquals("b", dynamicAgainstPattern("2"))
|
||||||
|
assertEquals("b", dynamicAgainstPattern(js("'2'")))
|
||||||
|
assertEquals("*", dynamicAgainstPattern(js("{}")))
|
||||||
|
|
||||||
|
return "OK"
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user