BinaryOperationIntrinsic as typealias

This commit is contained in:
Anton Bannykh
2018-03-01 17:58:28 +03:00
committed by Anton Bannykh
parent 2352dc3d1c
commit 757649d6da
7 changed files with 138 additions and 220 deletions
@@ -30,19 +30,14 @@ import org.jetbrains.kotlin.psi.KtBinaryExpression
import org.jetbrains.kotlin.types.KotlinType
object AssignmentBOIF : BinaryOperationIntrinsicFactory {
private object CharAssignmentIntrinsic : BinaryOperationIntrinsic {
override fun apply(expression: KtBinaryExpression, left: JsExpression, right: JsExpression, context: TranslationContext): JsExpression {
val operator = OperatorTable.getBinaryOperator(PsiUtils.getOperationToken(expression))
return JsBinaryOperation(operator, left, TranslationUtils.charToBoxedChar(context, right))
}
}
override fun getSupportTokens() = ImmutableSet.of(KtTokens.EQ)
override fun getIntrinsic(descriptor: FunctionDescriptor, leftType: KotlinType?, rightType: KotlinType?): BinaryOperationIntrinsic? {
if (leftType != null && !KotlinBuiltIns.isCharOrNullableChar(leftType) && rightType != null && KotlinBuiltIns.isCharOrNullableChar(rightType)) {
return CharAssignmentIntrinsic
return { expression, left, right, context ->
val operator = OperatorTable.getBinaryOperator(PsiUtils.getOperationToken(expression))
JsBinaryOperation(operator, left, TranslationUtils.charToBoxedChar(context, right))
}
}
return null
}
@@ -17,66 +17,75 @@
package org.jetbrains.kotlin.js.translate.intrinsic.operation
import org.jetbrains.kotlin.builtins.KotlinBuiltIns
import org.jetbrains.kotlin.builtins.KotlinBuiltIns.isPrimitiveTypeOrNullablePrimitiveType
import org.jetbrains.kotlin.descriptors.FunctionDescriptor
import org.jetbrains.kotlin.js.backend.ast.JsBinaryOperation
import org.jetbrains.kotlin.js.backend.ast.JsExpression
import org.jetbrains.kotlin.js.backend.ast.JsIntLiteral
import org.jetbrains.kotlin.js.translate.context.TranslationContext
import org.jetbrains.kotlin.js.patterns.PatternBuilder.pattern
import org.jetbrains.kotlin.js.translate.operation.OperatorTable
import org.jetbrains.kotlin.js.translate.utils.JsAstUtils
import org.jetbrains.kotlin.js.translate.utils.JsAstUtils.*
import org.jetbrains.kotlin.js.translate.utils.PsiUtils.getOperationToken
import org.jetbrains.kotlin.lexer.KtSingleValueToken
import org.jetbrains.kotlin.psi.KtBinaryExpression
import org.jetbrains.kotlin.resolve.calls.tasks.isDynamic
import org.jetbrains.kotlin.types.KotlinType
import org.jetbrains.kotlin.types.expressions.OperatorConventions
import org.jetbrains.kotlin.utils.identity
object CompareToBOIF : BinaryOperationIntrinsicFactory {
private object CompareToIntrinsic : BinaryOperationIntrinsic {
override fun apply(expression: KtBinaryExpression, left: JsExpression, right: JsExpression, context: TranslationContext): JsExpression {
val operator = OperatorTable.getBinaryOperator(getOperationToken(expression))
return JsBinaryOperation(operator, left, right)
}
}
private object CompareToCharIntrinsic : BinaryOperationIntrinsic {
override fun apply(expression: KtBinaryExpression, left: JsExpression, right: JsExpression, context: TranslationContext): JsExpression {
val operator = OperatorTable.getBinaryOperator(getOperationToken(expression))
return JsBinaryOperation(operator, left, JsAstUtils.charToInt(right))
}
}
private object CompareCharToPrimitiveIntrinsic : BinaryOperationIntrinsic {
override fun apply(expression: KtBinaryExpression, left: JsExpression, right: JsExpression, context: TranslationContext): JsExpression {
val operator = OperatorTable.getBinaryOperator(getOperationToken(expression))
return JsBinaryOperation(operator, JsAstUtils.charToInt(left), right)
}
}
private object CompareToFunctionIntrinsic : BinaryOperationIntrinsic{
override fun apply(expression: KtBinaryExpression, left: JsExpression, right: JsExpression, context: TranslationContext): JsExpression {
val operator = OperatorTable.getBinaryOperator(getOperationToken(expression))
val compareTo = JsAstUtils.compareTo(left, right)
return JsBinaryOperation(operator, compareTo, JsIntLiteral(0))
}
}
override fun getSupportTokens(): Set<KtSingleValueToken> = OperatorConventions.COMPARISON_OPERATIONS
// toLeft(L, R) OP toRight(L, R)
private fun intrinsic(
toLeft: (JsExpression, JsExpression) -> JsExpression,
toRight: (JsExpression, JsExpression) -> JsExpression
): BinaryOperationIntrinsic = { expression, left, right, _ ->
val operator = OperatorTable.getBinaryOperator(getOperationToken(expression))
JsBinaryOperation(operator, toLeft(left, right), toRight(left, right))
}
// toLeft(L) OP toRight(R)
private fun primitiveIntrinsic(
toLeft: (JsExpression) -> JsExpression,
toRight: (JsExpression) -> JsExpression
): BinaryOperationIntrinsic = intrinsic({ l, _ -> toLeft(l) }, { _, r -> toRight(r) })
// toLeft(L).compareTo(toRight(R)) OP 0
private fun compareToIntrinsic(
toLeft: (JsExpression) -> JsExpression,
toRight: (JsExpression) -> JsExpression
): BinaryOperationIntrinsic = intrinsic({ l, r -> compareForObject(toLeft(l), toRight(r)) }, { _, _ -> JsIntLiteral(0) })
private fun unboxCharIfNeeded(type: KotlinType): (JsExpression) -> JsExpression = { e ->
if (KotlinBuiltIns.isCharOrNullableChar(type)) {
charToInt(e)
} else e
}
// TODO Couldn't Long be converted to Number in all cases except Long.compareTo(Long)?
private val patterns = listOf(
pattern("Double|Float.compareTo(Long)") to primitiveIntrinsic(identity(), ::longToNumber),
pattern("Long.compareTo(Float|Double)") to primitiveIntrinsic(::longToNumber, identity()),
pattern("Int|Short|Byte.compareTo(Long)") to compareToIntrinsic(::longFromInt, identity()),
pattern("Long.compareTo(Int|Short|Byte)") to compareToIntrinsic(identity(), ::longFromInt),
pattern("Char.compareTo(Long)") to compareToIntrinsic({ longFromInt(charToInt(it)) }, identity()),
pattern("Long.compareTo(Char)") to compareToIntrinsic(identity(), { longFromInt(JsAstUtils.charToInt(it)) }),
pattern("Long.compareTo(Long)") to compareToIntrinsic(identity(), identity())
)
override fun getIntrinsic(descriptor: FunctionDescriptor, leftType: KotlinType?, rightType: KotlinType?): BinaryOperationIntrinsic? {
if (descriptor.isDynamic()) return CompareToIntrinsic
if (descriptor.isDynamic()) return primitiveIntrinsic(identity(), identity())
if (leftType == null || rightType == null) return null
if (leftType == null || rightType == null || !KotlinBuiltIns.isBuiltIn(descriptor)) return null
if (!KotlinBuiltIns.isBuiltIn(descriptor)) return null
patterns.forEach { (p, i) -> if (p.test(descriptor)) return i }
// Types may be nullable if properIeeeComparisons are switched off, e.g. fun foo(a: Double?) = a != null && a < 0.0
return when {
KotlinBuiltIns.isCharOrNullableChar(rightType) -> CompareToCharIntrinsic
KotlinBuiltIns.isCharOrNullableChar(leftType) -> CompareCharToPrimitiveIntrinsic
KotlinBuiltIns.isPrimitiveTypeOrNullablePrimitiveType(leftType) &&
KotlinBuiltIns.isPrimitiveTypeOrNullablePrimitiveType(rightType) -> CompareToIntrinsic
else -> CompareToFunctionIntrinsic
return if (isPrimitiveTypeOrNullablePrimitiveType(leftType) && isPrimitiveTypeOrNullablePrimitiveType(rightType)) {
primitiveIntrinsic(unboxCharIfNeeded(leftType), unboxCharIfNeeded(rightType))
} else {
intrinsic({ l, r -> compareTo(l, r) }, { _, _ -> JsIntLiteral(0) })
}
}
}
@@ -40,88 +40,88 @@ import org.jetbrains.kotlin.types.typeUtil.makeNullable
import java.util.*
object EqualsBOIF : BinaryOperationIntrinsicFactory {
private object EqualsIntrinsic : BinaryOperationIntrinsic {
private val JS_NUMBER_PRIMITIVES =
EnumSet.of(PrimitiveType.BYTE, PrimitiveType.SHORT, PrimitiveType.INT, PrimitiveType.DOUBLE, PrimitiveType.FLOAT)
private val JS_NUMBER_PRIMITIVES =
EnumSet.of(PrimitiveType.BYTE, PrimitiveType.SHORT, PrimitiveType.INT, PrimitiveType.DOUBLE, PrimitiveType.FLOAT)
override fun apply(expression: KtBinaryExpression, left: JsExpression, right: JsExpression, context: TranslationContext): JsExpression {
val isNegated = expression.isNegated()
val anyType = context.currentModule.builtIns.anyType
if (right is JsNullLiteral || left is JsNullLiteral) {
val (subject, ktSubject) = if (right is JsNullLiteral) Pair(left, expression.left!!) else Pair(right, expression.right!!)
val type = context.bindingContext().getType(ktSubject) ?: anyType
val coercedSubject = TranslationUtils.coerce(context, subject, type.makeNullable())
return TranslationUtils.nullCheck(coercedSubject, isNegated)
}
val (leftKotlinType, rightKotlinType) = binaryOperationTypes(expression, context)
val leftType = leftKotlinType?.let { KotlinBuiltIns.getPrimitiveType(it) }
val rightType = rightKotlinType?.let { KotlinBuiltIns.getPrimitiveType(it) }
if (leftType != null && rightType != null && (
leftType in JS_NUMBER_PRIMITIVES && rightType in JS_NUMBER_PRIMITIVES ||
leftType in JS_NUMBER_PRIMITIVES && rightType == PrimitiveType.LONG ||
leftType == PrimitiveType.LONG && rightType in JS_NUMBER_PRIMITIVES ||
leftType == PrimitiveType.BOOLEAN && rightType == PrimitiveType.BOOLEAN ||
leftType == PrimitiveType.CHAR && rightType == PrimitiveType.CHAR
)) {
val useEq = leftType == PrimitiveType.LONG || rightType == PrimitiveType.LONG
val operator = when {
useEq && isNegated -> JsBinaryOperator.NEQ
useEq && !isNegated -> JsBinaryOperator.EQ
!useEq && isNegated -> JsBinaryOperator.REF_NEQ
else /* !useEq && !isNegated */ -> JsBinaryOperator.REF_EQ
}
val coercedLeft = TranslationUtils.coerce(context, left, leftKotlinType)
val coercedRight = TranslationUtils.coerce(context, right, rightKotlinType)
return JsBinaryOperation(operator, coercedLeft, coercedRight)
}
val resolvedCall = expression.getResolvedCall(context.bindingContext())
val appliedToDynamic =
resolvedCall != null &&
with(resolvedCall.dispatchReceiver) {
if (this != null) type.isDynamic() else false
}
if (appliedToDynamic) {
return JsBinaryOperation(if (isNegated) JsBinaryOperator.NEQ else JsBinaryOperator.EQ, left, right)
}
val coercedLeft = TranslationUtils.coerce(context, left, anyType)
val coercedRight = TranslationUtils.coerce(context, right, anyType)
val result = TopLevelFIF.KOTLIN_EQUALS.apply(coercedLeft, listOf(coercedRight), context)
return if (isNegated) JsAstUtils.not(result) else result
private fun equalsIntrinsic(expression: KtBinaryExpression, left: JsExpression, right: JsExpression, context: TranslationContext): JsExpression {
val isNegated = expression.isNegated()
val anyType = context.currentModule.builtIns.anyType
if (right is JsNullLiteral || left is JsNullLiteral) {
val (subject, ktSubject) = if (right is JsNullLiteral) Pair(left, expression.left!!) else Pair(right, expression.right!!)
val type = context.bindingContext().getType(ktSubject) ?: anyType
val coercedSubject = TranslationUtils.coerce(context, subject, type.makeNullable())
return TranslationUtils.nullCheck(coercedSubject, isNegated)
}
}
object EnumEqualsIntrinsic : BinaryOperationIntrinsic {
override fun apply(expression: KtBinaryExpression, left: JsExpression, right: JsExpression, context: TranslationContext): JsBinaryOperation {
val operator = if (expression.isNegated()) JsBinaryOperator.REF_NEQ else JsBinaryOperator.REF_EQ
return JsBinaryOperation(operator, left, right)
val (leftKotlinType, rightKotlinType) = binaryOperationTypes(expression, context)
val leftType = leftKotlinType?.let { KotlinBuiltIns.getPrimitiveType(it) }
val rightType = rightKotlinType?.let { KotlinBuiltIns.getPrimitiveType(it) }
if (leftType != null && rightType != null) {
}
if (leftType != null && rightType != null && (
leftType in JS_NUMBER_PRIMITIVES && rightType in JS_NUMBER_PRIMITIVES ||
leftType in JS_NUMBER_PRIMITIVES && rightType == PrimitiveType.LONG ||
leftType == PrimitiveType.LONG && rightType in JS_NUMBER_PRIMITIVES ||
leftType == PrimitiveType.BOOLEAN && rightType == PrimitiveType.BOOLEAN ||
leftType == PrimitiveType.CHAR && rightType == PrimitiveType.CHAR
)) {
val useEq = leftType == PrimitiveType.LONG || rightType == PrimitiveType.LONG
val operator = when {
useEq && isNegated -> JsBinaryOperator.NEQ
useEq && !isNegated -> JsBinaryOperator.EQ
!useEq && isNegated -> JsBinaryOperator.REF_NEQ
else /* !useEq && !isNegated */ -> JsBinaryOperator.REF_EQ
}
val coercedLeft = TranslationUtils.coerce(context, left, leftKotlinType)
val coercedRight = TranslationUtils.coerce(context, right, rightKotlinType)
return JsBinaryOperation(operator, coercedLeft, coercedRight)
}
val resolvedCall = expression.getResolvedCall(context.bindingContext())
val appliedToDynamic =
resolvedCall != null &&
with(resolvedCall.dispatchReceiver) {
if (this != null) type.isDynamic() else false
}
if (appliedToDynamic) {
return JsBinaryOperation(if (isNegated) JsBinaryOperator.NEQ else JsBinaryOperator.EQ, left, right)
}
val coercedLeft = TranslationUtils.coerce(context, left, anyType)
val coercedRight = TranslationUtils.coerce(context, right, anyType)
val result = TopLevelFIF.KOTLIN_EQUALS.apply(coercedLeft, listOf(coercedRight), context)
return if (isNegated) JsAstUtils.not(result) else result
}
override fun getSupportTokens() = OperatorConventions.EQUALS_OPERATIONS!!
override fun getIntrinsic(descriptor: FunctionDescriptor, leftType: KotlinType?, rightType: KotlinType?): BinaryOperationIntrinsic? =
when {
isEnumIntrinsicApplicable(descriptor, leftType, rightType) -> EnumEqualsIntrinsic
when {
isEnumEqualsIntrinsicApplicable(descriptor, leftType, rightType) -> { expression, left, right, _ ->
val operator = if (expression.isNegated()) JsBinaryOperator.REF_NEQ else JsBinaryOperator.REF_EQ
JsBinaryOperation(operator, left, right)
}
KotlinBuiltIns.isBuiltIn(descriptor) ||
TopLevelFIF.EQUALS_IN_ANY.test(descriptor) -> EqualsIntrinsic
TopLevelFIF.EQUALS_IN_ANY.test(descriptor) -> ::equalsIntrinsic
else -> null
}
private fun isEnumIntrinsicApplicable(descriptor: FunctionDescriptor, leftType: KotlinType?, rightType: KotlinType?): Boolean {
private fun isEnumEqualsIntrinsicApplicable(descriptor: FunctionDescriptor, leftType: KotlinType?, rightType: KotlinType?): Boolean {
return DescriptorUtils.isEnumClass(descriptor.containingDeclaration) && leftType != null && rightType != null &&
!TypeUtils.isNullableType(leftType) && !TypeUtils.isNullableType(rightType)
!TypeUtils.isNullableType(leftType) && !TypeUtils.isNullableType(rightType)
}
private fun KtBinaryExpression.isNegated() = getOperationToken(this) == KtTokens.EXCLEQ
}
@@ -1,90 +0,0 @@
/*
* Copyright 2010-2017 JetBrains s.r.o.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.jetbrains.kotlin.js.translate.intrinsic.operation
import org.jetbrains.kotlin.builtins.KotlinBuiltIns
import org.jetbrains.kotlin.descriptors.FunctionDescriptor
import org.jetbrains.kotlin.js.backend.ast.JsBinaryOperation
import org.jetbrains.kotlin.js.backend.ast.JsExpression
import org.jetbrains.kotlin.js.backend.ast.JsIntLiteral
import org.jetbrains.kotlin.js.patterns.PatternBuilder.pattern
import org.jetbrains.kotlin.js.translate.context.Namer
import org.jetbrains.kotlin.js.translate.context.TranslationContext
import org.jetbrains.kotlin.js.translate.operation.OperatorTable
import org.jetbrains.kotlin.js.translate.utils.JsAstUtils.*
import org.jetbrains.kotlin.js.translate.utils.PsiUtils.getOperationToken
import org.jetbrains.kotlin.psi.KtBinaryExpression
import org.jetbrains.kotlin.types.KotlinType
import org.jetbrains.kotlin.types.expressions.OperatorConventions
import org.jetbrains.kotlin.utils.identity as ID
object LongCompareToBOIF : BinaryOperationIntrinsicFactory {
val FLOATING_POINT_COMPARE_TO_LONG_PATTERN = pattern("Double|Float.compareTo(Long)")
val LONG_COMPARE_TO_FLOATING_POINT_PATTERN = pattern("Long.compareTo(Float|Double)")
val INTEGER_COMPARE_TO_LONG_PATTERN = pattern("Int|Short|Byte.compareTo(Long)")
val CHAR_COMPARE_TO_LONG_PATTERN = pattern("Char.compareTo(Long)")
val LONG_COMPARE_TO_INTEGER_PATTERN = pattern("Long.compareTo(Int|Short|Byte)")
val LONG_COMPARE_TO_CHAR_PATTERN = pattern("Long.compareTo(Char)")
val LONG_COMPARE_TO_LONG_PATTERN = pattern("Long.compareTo(Long)")
private object FLOATING_POINT_COMPARE_TO_LONG : BinaryOperationIntrinsic {
override fun apply(expression: KtBinaryExpression, left: JsExpression, right: JsExpression, context: TranslationContext): JsExpression {
val operator = OperatorTable.getBinaryOperator(getOperationToken(expression))
return JsBinaryOperation(operator, left, invokeMethod(right, Namer.LONG_TO_NUMBER))
}
}
private object LONG_COMPARE_TO_FLOATING_POINT : BinaryOperationIntrinsic {
override fun apply(expression: KtBinaryExpression, left: JsExpression, right: JsExpression, context: TranslationContext): JsExpression {
val operator = OperatorTable.getBinaryOperator(getOperationToken(expression))
return JsBinaryOperation(operator, invokeMethod(left, Namer.LONG_TO_NUMBER), right)
}
}
private class CompareToBinaryIntrinsic(val toLeft: (JsExpression) -> JsExpression, val toRight: (JsExpression) -> JsExpression) : BinaryOperationIntrinsic {
override fun apply(expression: KtBinaryExpression, left: JsExpression, right: JsExpression, context: TranslationContext): JsExpression {
val operator = OperatorTable.getBinaryOperator(getOperationToken(expression))
val compareInvocation = compareForObject(toLeft(left), toRight(right))
return JsBinaryOperation(operator, compareInvocation, JsIntLiteral(0))
}
}
private val INTEGER_COMPARE_TO_LONG = CompareToBinaryIntrinsic(::longFromInt, ID())
private val CHAR_COMPARE_TO_LONG = CompareToBinaryIntrinsic( { longFromInt(charToInt(it)) }, ID())
private val LONG_COMPARE_TO_INTEGER = CompareToBinaryIntrinsic(ID(), ::longFromInt)
private val LONG_COMPARE_TO_CHAR = CompareToBinaryIntrinsic( ID(), { longFromInt(charToInt(it)) })
private val LONG_COMPARE_TO_LONG = CompareToBinaryIntrinsic( ID(), ID() )
override fun getSupportTokens() = OperatorConventions.COMPARISON_OPERATIONS
override fun getIntrinsic(descriptor: FunctionDescriptor, leftType: KotlinType?, rightType: KotlinType?): BinaryOperationIntrinsic? {
if (KotlinBuiltIns.isBuiltIn(descriptor)) {
return when {
FLOATING_POINT_COMPARE_TO_LONG_PATTERN.test(descriptor) -> FLOATING_POINT_COMPARE_TO_LONG
LONG_COMPARE_TO_FLOATING_POINT_PATTERN.test(descriptor) -> LONG_COMPARE_TO_FLOATING_POINT
INTEGER_COMPARE_TO_LONG_PATTERN.test(descriptor) -> INTEGER_COMPARE_TO_LONG
CHAR_COMPARE_TO_LONG_PATTERN.test(descriptor) -> CHAR_COMPARE_TO_LONG
LONG_COMPARE_TO_INTEGER_PATTERN.test(descriptor) -> LONG_COMPARE_TO_INTEGER
LONG_COMPARE_TO_CHAR_PATTERN.test(descriptor) -> LONG_COMPARE_TO_CHAR
LONG_COMPARE_TO_LONG_PATTERN.test(descriptor) -> LONG_COMPARE_TO_LONG
else -> null
}
}
return null
}
}
@@ -28,9 +28,8 @@ import org.jetbrains.kotlin.psi.KtBinaryExpression
import org.jetbrains.kotlin.types.KotlinType
import org.jetbrains.kotlin.utils.addToStdlib.firstNotNullResult
interface BinaryOperationIntrinsic {
fun apply(expression: KtBinaryExpression, left: JsExpression, right: JsExpression, context: TranslationContext): JsExpression
}
typealias BinaryOperationIntrinsic
= (expression: KtBinaryExpression, left: JsExpression, right: JsExpression, context: TranslationContext) -> JsExpression
class BinaryOperationIntrinsics {
@@ -53,7 +52,7 @@ class BinaryOperationIntrinsics {
return computeAndCache(IntrinsicKey(token, descriptor, leftType, rightType))
}
private val factories = listOf(LongCompareToBOIF, EqualsBOIF, CompareToBOIF, AssignmentBOIF)
private val factories = listOf(CompareToBOIF, EqualsBOIF, AssignmentBOIF)
private fun computeAndCache(key: IntrinsicKey): BinaryOperationIntrinsic? {
if (key in intrinsicCache) return intrinsicCache[key]
@@ -16,6 +16,7 @@
package org.jetbrains.kotlin.js.translate.operation;
import kotlin.jvm.functions.Function4;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import org.jetbrains.kotlin.descriptors.CallableDescriptor;
@@ -27,7 +28,6 @@ import org.jetbrains.kotlin.js.translate.context.TranslationContext;
import org.jetbrains.kotlin.js.translate.general.AbstractTranslator;
import org.jetbrains.kotlin.js.translate.general.Translation;
import org.jetbrains.kotlin.js.translate.intrinsic.functions.factories.TopLevelFIF;
import org.jetbrains.kotlin.js.translate.intrinsic.operation.BinaryOperationIntrinsic;
import org.jetbrains.kotlin.js.translate.utils.JsAstUtils;
import org.jetbrains.kotlin.js.translate.utils.TranslationUtils;
import org.jetbrains.kotlin.lexer.KtToken;
@@ -100,21 +100,21 @@ public final class BinaryOperationTranslator extends AbstractTranslator {
@NotNull
private JsExpression translate() {
BinaryOperationIntrinsic intrinsic = getIntrinsicForExpression();
if (intrinsic != null) {
return applyIntrinsic(intrinsic);
JsExpression e = tryApplyIntrinsic();
if (e != null) {
return e;
}
if (operationToken == KtTokens.ELVIS) {
return translateElvis();
}
if (isAssignmentOperator(operationToken)) {
return AssignmentTranslator.translate(expression, context());
return AssignmentTranslator.translate(this.expression, context());
}
if (isNotOverloadable()) {
return translateAsUnOverloadableBinaryOperation();
}
if (isCompareToCall(operationToken, operationDescriptor)) {
return CompareToTranslator.translate(expression, context());
return CompareToTranslator.translate(this.expression, context());
}
if (isEquals()) {
return translateEquals();
@@ -159,25 +159,25 @@ public final class BinaryOperationTranslator extends AbstractTranslator {
}
@Nullable
private BinaryOperationIntrinsic getIntrinsicForExpression() {
return context().intrinsics().getBinaryOperationIntrinsic(expression, context());
}
private JsExpression tryApplyIntrinsic() {
Function4<KtBinaryExpression, JsExpression, JsExpression, TranslationContext, JsExpression> intrinsic =
context().intrinsics().getBinaryOperationIntrinsic(expression, context());
if (intrinsic == null) return null;
@NotNull
private JsExpression applyIntrinsic(@NotNull BinaryOperationIntrinsic intrinsic) {
JsExpression leftExpression = Translation.translateAsExpression(leftKtExpression, context());
JsBlock rightBlock = new JsBlock();
JsExpression rightExpression = Translation.translateAsExpression(rightKtExpression, context(), rightBlock);
if (rightBlock.isEmpty()) {
return intrinsic.apply(expression, leftExpression, rightExpression, context());
return intrinsic.invoke(expression, leftExpression, rightExpression, context());
}
leftExpression = context().cacheExpressionIfNeeded(leftExpression);
context().addStatementsToCurrentBlockFrom(rightBlock);
return intrinsic.apply(expression, leftExpression, rightExpression, context());
return intrinsic.invoke(expression, leftExpression, rightExpression, context());
}
private boolean isNotOverloadable() {
@@ -212,6 +212,11 @@ public final class JsAstUtils {
return invokeMethod(Namer.kotlinLong(), Namer.LONG_FROM_NUMBER, expression);
}
@NotNull
public static JsExpression longToNumber(@NotNull JsExpression expression) {
return invokeMethod(expression, Namer.LONG_TO_NUMBER);
}
@NotNull
public static JsExpression compareForObject(@NotNull JsExpression left, @NotNull JsExpression right) {
return invokeMethod(left, Namer.COMPARE_TO_METHOD_NAME, right);