diff --git a/js/js.translator/src/org/jetbrains/kotlin/js/translate/intrinsic/operation/AssignmentBOIF.kt b/js/js.translator/src/org/jetbrains/kotlin/js/translate/intrinsic/operation/AssignmentBOIF.kt index 776fa0ff141..024e0862f03 100644 --- a/js/js.translator/src/org/jetbrains/kotlin/js/translate/intrinsic/operation/AssignmentBOIF.kt +++ b/js/js.translator/src/org/jetbrains/kotlin/js/translate/intrinsic/operation/AssignmentBOIF.kt @@ -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 } diff --git a/js/js.translator/src/org/jetbrains/kotlin/js/translate/intrinsic/operation/CompareToBOIF.kt b/js/js.translator/src/org/jetbrains/kotlin/js/translate/intrinsic/operation/CompareToBOIF.kt index 342a086ce32..36cfd15b956 100644 --- a/js/js.translator/src/org/jetbrains/kotlin/js/translate/intrinsic/operation/CompareToBOIF.kt +++ b/js/js.translator/src/org/jetbrains/kotlin/js/translate/intrinsic/operation/CompareToBOIF.kt @@ -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 = 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) }) } } } diff --git a/js/js.translator/src/org/jetbrains/kotlin/js/translate/intrinsic/operation/EqualsBOIF.kt b/js/js.translator/src/org/jetbrains/kotlin/js/translate/intrinsic/operation/EqualsBOIF.kt index 33b9b1b25cf..91d6ec8988b 100644 --- a/js/js.translator/src/org/jetbrains/kotlin/js/translate/intrinsic/operation/EqualsBOIF.kt +++ b/js/js.translator/src/org/jetbrains/kotlin/js/translate/intrinsic/operation/EqualsBOIF.kt @@ -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 } diff --git a/js/js.translator/src/org/jetbrains/kotlin/js/translate/intrinsic/operation/LongCompareToBOIF.kt b/js/js.translator/src/org/jetbrains/kotlin/js/translate/intrinsic/operation/LongCompareToBOIF.kt deleted file mode 100644 index 412e4818da0..00000000000 --- a/js/js.translator/src/org/jetbrains/kotlin/js/translate/intrinsic/operation/LongCompareToBOIF.kt +++ /dev/null @@ -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 - } -} diff --git a/js/js.translator/src/org/jetbrains/kotlin/js/translate/intrinsic/operation/binaryOperationIntrinsics.kt b/js/js.translator/src/org/jetbrains/kotlin/js/translate/intrinsic/operation/binaryOperationIntrinsics.kt index 8d08895341f..9760068b38d 100644 --- a/js/js.translator/src/org/jetbrains/kotlin/js/translate/intrinsic/operation/binaryOperationIntrinsics.kt +++ b/js/js.translator/src/org/jetbrains/kotlin/js/translate/intrinsic/operation/binaryOperationIntrinsics.kt @@ -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] diff --git a/js/js.translator/src/org/jetbrains/kotlin/js/translate/operation/BinaryOperationTranslator.java b/js/js.translator/src/org/jetbrains/kotlin/js/translate/operation/BinaryOperationTranslator.java index 1d7b95afe2f..d16ef6b9591 100644 --- a/js/js.translator/src/org/jetbrains/kotlin/js/translate/operation/BinaryOperationTranslator.java +++ b/js/js.translator/src/org/jetbrains/kotlin/js/translate/operation/BinaryOperationTranslator.java @@ -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 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() { diff --git a/js/js.translator/src/org/jetbrains/kotlin/js/translate/utils/JsAstUtils.java b/js/js.translator/src/org/jetbrains/kotlin/js/translate/utils/JsAstUtils.java index 790fb64898c..5ba3110b5e8 100644 --- a/js/js.translator/src/org/jetbrains/kotlin/js/translate/utils/JsAstUtils.java +++ b/js/js.translator/src/org/jetbrains/kotlin/js/translate/utils/JsAstUtils.java @@ -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);