BinaryOperationIntrinsic as typealias
This commit is contained in:
committed by
Anton Bannykh
parent
2352dc3d1c
commit
757649d6da
+4
-9
@@ -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
|
||||
}
|
||||
|
||||
+49
-40
@@ -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) })
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
+64
-64
@@ -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
|
||||
}
|
||||
|
||||
-90
@@ -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
|
||||
}
|
||||
}
|
||||
+3
-4
@@ -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]
|
||||
|
||||
+13
-13
@@ -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);
|
||||
|
||||
Reference in New Issue
Block a user