FIR: generate operations map for CompileTimeConstantEvaluator

This commit is contained in:
Jinseong Jeon
2020-05-27 22:26:29 -07:00
parent 5e2525175e
commit a969924248
7 changed files with 500 additions and 211 deletions
-1
View File
@@ -5,7 +5,6 @@ plugins {
dependencies {
compile(project(":compiler:fir:tree"))
compileOnly(project(":kotlin-reflect-api"))
compileOnly(intellijCoreDep()) { includeJars("intellij-core", rootProject = rootProject) }
}
@@ -15,21 +15,20 @@ import org.jetbrains.kotlin.fir.symbols.AbstractFirBasedSymbol
import org.jetbrains.kotlin.fir.types.*
import org.jetbrains.kotlin.fir.types.impl.FirImplicitBuiltinTypeRef
import org.jetbrains.kotlin.fir.types.impl.FirImplicitIntTypeRef
import kotlin.reflect.full.declaredFunctions
import kotlin.reflect.full.valueParameters
import org.jetbrains.kotlin.resolve.constants.ConstantValue
/**
* An evaluator that transform numeric operation, such as div, into compile-time constant iff involved operands, such as explicit receiver
* and the argument, are compile-time constant as well.
*/
// TODO: Handle boolean operators and const property loading
class CompileTimeConstantEvaluator {
fun evaluate(expression: FirExpression): FirConstExpression<*>? =
if (expression is FirFunctionCall) {
evaluate(expression)
} else {
null
// TODO: Handle boolean operators, const property loading, class reference, array, annotation values, etc.
fun evaluate(expression: FirExpression): ConstantValue<*>? =
when (expression) {
is FirConstExpression<*> -> expression.value as? ConstantValue<*>
is FirFunctionCall -> evaluate(expression)?.value as? ConstantValue<*>
else -> null
}
private fun evaluate(functionCall: FirFunctionCall): FirConstExpression<*>? {
@@ -98,32 +97,13 @@ class CompileTimeConstantEvaluator {
// Unary operators
private fun FirConstExpression<out Number>.evaluate(function: FirSimpleFunction): FirConstExpression<out Number>? {
val number = typedValue
return when (function.name.asString()) {
"hashCode" ->
buildConstExpression(source, FirConstKind.Int, number.hashCode())
"dec" ->
kind.toConstExpression(source, number.dec())
"inc" ->
kind.toConstExpression(source, number.inc())
"unaryMinus" ->
kind.toConstExpression(source, number.unaryMinus())
"unaryPlus" ->
kind.toConstExpression(source, number.unaryPlus())
"toByte" ->
buildConstExpression(source, FirConstKind.Byte, number.toByte())
"toDouble" ->
buildConstExpression(source, FirConstKind.Double, number.toDouble())
"toFloat" ->
buildConstExpression(source, FirConstKind.Float, number.toFloat())
"toInt" ->
buildConstExpression(source, FirConstKind.Int, number.toInt())
"toLong" ->
buildConstExpression(source, FirConstKind.Long, number.toLong())
"toShort" ->
buildConstExpression(source, FirConstKind.Short, number.toShort())
else ->
null
val f = unaryOperations[UnaryOperationKey(kind, function.name.asString())] ?: return null
// TODO: need some systematic check, e.g., integer overflow
return try {
val r = f(typedValue)
r.toFirConstKind()!!.toConstExpression(source, r)
} catch (e: Exception) {
null
}
}
@@ -132,158 +112,16 @@ class CompileTimeConstantEvaluator {
function: FirSimpleFunction,
other: FirConstExpression<out Number>
): FirConstExpression<out Number>? {
val n1 = typedValue
val n2 = other.typedValue
return when (function.name.asString()) {
// TODO: more binary operators
"plus" ->
n1.plus(n2).let { v -> v.toFirConstKind()!!.toConstExpression(source, v) }
else ->
null
val f = binaryOperations[BinaryOperationKey(kind, other.kind, function.name.asString())] ?: return null
// TODO: need some systematic check, e.g., div by zero (1 / 0 v.s. 1 / 0.f)
return try {
val r = f(typedValue, other.typedValue)
r.toFirConstKind()!!.toConstExpression(source, r)
} catch (e: Exception) {
null
}
}
////// UNARY OPERATORS
private fun Number.dec(): Number =
when (this) {
is Byte -> this.dec()
is Double -> this.dec()
is Float -> this.dec()
is Int -> this.dec()
is Long -> this.dec()
is Short -> this.dec()
else -> error("Unexpected Number kind: ${this.javaClass}")
}
private fun Number.inc(): Number =
when (this) {
is Byte -> this.inc()
is Double -> this.inc()
is Float -> this.inc()
is Int -> this.inc()
is Long -> this.inc()
is Short -> this.inc()
else -> error("Unexpected Number kind: ${this.javaClass}")
}
private fun Number.unaryMinus(): Number =
when (this) {
is Byte -> this.unaryMinus()
is Double -> this.unaryMinus()
is Float -> this.unaryMinus()
is Int -> this.unaryMinus()
is Long -> this.unaryMinus()
is Short -> this.unaryMinus()
else -> error("Unexpected Number kind: ${this.javaClass}")
}
private fun Number.unaryPlus(): Number =
when (this) {
is Byte -> this.unaryPlus()
is Double -> this.unaryPlus()
is Float -> this.unaryPlus()
is Int -> this.unaryPlus()
is Long -> this.unaryPlus()
is Short -> this.unaryPlus()
else -> error("Unexpected Number kind: ${this.javaClass}")
}
////// BINARY OPERATORS
// Design choice: reflection, which requires iteration over all declared functions every time, v.s., exhaustive type matching.
private fun Number.binaryOperation(name: String, other: Number): Number? {
val otherType = when (other) {
is Byte -> Byte::class
is Double -> Double::class
is Float -> Float::class
is Int -> Int::class
is Long -> Long::class
is Short -> Short::class
else -> error("Unexpected Number kind: ${this.javaClass}")
}
return this::class.declaredFunctions.find { kFunction ->
kFunction.name == name && kFunction.valueParameters.size == 1 && kFunction.valueParameters[0].type.classifier == otherType
}?.call(other) as? Number
}
private fun Number.plus(other: Number): Number =
when (this) {
is Byte -> this.plus(other)
is Double -> this.plus(other)
is Float -> this.plus(other)
is Int -> this.plus(other)
is Long -> this.plus(other)
is Short -> this.plus(other)
else -> error("Unexpected Number kind: ${this.javaClass}")
}
private fun Byte.plus(other: Number): Number =
when (other) {
is Byte -> this.plus(other)
is Double -> this.plus(other)
is Float -> this.plus(other)
is Int -> this.plus(other)
is Long -> this.plus(other)
is Short -> this.plus(other)
else -> error("Unexpected Number kind: ${this.javaClass}")
}
private fun Double.plus(other: Number): Number =
when (other) {
is Byte -> this.plus(other)
is Double -> this.plus(other)
is Float -> this.plus(other)
is Int -> this.plus(other)
is Long -> this.plus(other)
is Short -> this.plus(other)
else -> error("Unexpected Number kind: ${this.javaClass}")
}
private fun Float.plus(other: Number): Number =
when (other) {
is Byte -> this.plus(other)
is Double -> this.plus(other)
is Float -> this.plus(other)
is Int -> this.plus(other)
is Long -> this.plus(other)
is Short -> this.plus(other)
else -> error("Unexpected Number kind: ${this.javaClass}")
}
private fun Int.plus(other: Number): Number =
when (other) {
is Byte -> this.plus(other)
is Double -> this.plus(other)
is Float -> this.plus(other)
is Int -> this.plus(other)
is Long -> this.plus(other)
is Short -> this.plus(other)
else -> error("Unexpected Number kind: ${this.javaClass}")
}
private fun Long.plus(other: Number): Number =
when (other) {
is Byte -> this.plus(other)
is Double -> this.plus(other)
is Float -> this.plus(other)
is Int -> this.plus(other)
is Long -> this.plus(other)
is Short -> this.plus(other)
else -> error("Unexpected Number kind: ${this.javaClass}")
}
private fun Short.plus(other: Number): Number =
when (other) {
is Byte -> this.plus(other)
is Double -> this.plus(other)
is Float -> this.plus(other)
is Int -> this.plus(other)
is Long -> this.plus(other)
is Short -> this.plus(other)
else -> error("Unexpected Number kind: ${this.javaClass}")
}
////// KINDS
private fun FirTypeRef.toFirConstKind(): FirConstKind<out Number>? =
@@ -357,7 +195,7 @@ class CompileTimeConstantEvaluator {
// TODO: rangeTo?
private val binaryOperatorNames: Set<String> = setOf(
"compareTo", "equals",
// TODO: "compareTo", "equals",
"div", "minus", "mod", "plus", "rem", "times"
)
}
@@ -0,0 +1,293 @@
/*
* Copyright 2010-2020 JetBrains s.r.o. and Kotlin Programming Language contributors.
*
* 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.fir.evaluate
import org.jetbrains.kotlin.fir.expressions.FirConstKind
/** This file is generated by org.jetbrains.kotlin.generators.evaluate:generateFirMap(). DO NOT MODIFY MANUALLY */
internal data class UnaryOperationKey<out T>(val opr: FirConstKind<out T>, val opName: String)
internal data class BinaryOperationKey<out T, out U>(val opr1: FirConstKind<out T>, val opr2: FirConstKind<out U>, val opName: String)
@Suppress("UNCHECKED_CAST")
private fun <T> unaryOperation(
t: FirConstKind<T>,
opName: String,
operation: Function1<T, Number>
) = UnaryOperationKey(t, opName) to operation as Function1<Number, Number>
@Suppress("UNCHECKED_CAST")
private fun <T, U> binaryOperation(
t: FirConstKind<T>,
u: FirConstKind<U>,
opName: String,
operation: Function2<T, U, Number>
) = BinaryOperationKey(t, u, opName) to operation as Function2<Number, Number, Number>
internal val unaryOperations: HashMap<UnaryOperationKey<*>, Function1<Number, Number>> = hashMapOf(
unaryOperation(FirConstKind.Byte, "dec", { a -> a.dec() }),
unaryOperation(FirConstKind.Byte, "hashCode", { a -> a.hashCode() }),
unaryOperation(FirConstKind.Byte, "inc", { a -> a.inc() }),
unaryOperation(FirConstKind.Byte, "toByte", { a -> a.toByte() }),
unaryOperation(FirConstKind.Byte, "toDouble", { a -> a.toDouble() }),
unaryOperation(FirConstKind.Byte, "toFloat", { a -> a.toFloat() }),
unaryOperation(FirConstKind.Byte, "toInt", { a -> a.toInt() }),
unaryOperation(FirConstKind.Byte, "toLong", { a -> a.toLong() }),
unaryOperation(FirConstKind.Byte, "toShort", { a -> a.toShort() }),
unaryOperation(FirConstKind.Byte, "unaryMinus", { a -> a.unaryMinus() }),
unaryOperation(FirConstKind.Byte, "unaryPlus", { a -> a.unaryPlus() }),
unaryOperation(FirConstKind.Double, "dec", { a -> a.dec() }),
unaryOperation(FirConstKind.Double, "hashCode", { a -> a.hashCode() }),
unaryOperation(FirConstKind.Double, "inc", { a -> a.inc() }),
unaryOperation(FirConstKind.Double, "toByte", { a -> a.toByte() }),
unaryOperation(FirConstKind.Double, "toDouble", { a -> a.toDouble() }),
unaryOperation(FirConstKind.Double, "toFloat", { a -> a.toFloat() }),
unaryOperation(FirConstKind.Double, "toInt", { a -> a.toInt() }),
unaryOperation(FirConstKind.Double, "toLong", { a -> a.toLong() }),
unaryOperation(FirConstKind.Double, "toShort", { a -> a.toShort() }),
unaryOperation(FirConstKind.Double, "unaryMinus", { a -> a.unaryMinus() }),
unaryOperation(FirConstKind.Double, "unaryPlus", { a -> a.unaryPlus() }),
unaryOperation(FirConstKind.Float, "dec", { a -> a.dec() }),
unaryOperation(FirConstKind.Float, "hashCode", { a -> a.hashCode() }),
unaryOperation(FirConstKind.Float, "inc", { a -> a.inc() }),
unaryOperation(FirConstKind.Float, "toByte", { a -> a.toByte() }),
unaryOperation(FirConstKind.Float, "toDouble", { a -> a.toDouble() }),
unaryOperation(FirConstKind.Float, "toFloat", { a -> a.toFloat() }),
unaryOperation(FirConstKind.Float, "toInt", { a -> a.toInt() }),
unaryOperation(FirConstKind.Float, "toLong", { a -> a.toLong() }),
unaryOperation(FirConstKind.Float, "toShort", { a -> a.toShort() }),
unaryOperation(FirConstKind.Float, "unaryMinus", { a -> a.unaryMinus() }),
unaryOperation(FirConstKind.Float, "unaryPlus", { a -> a.unaryPlus() }),
unaryOperation(FirConstKind.Int, "dec", { a -> a.dec() }),
unaryOperation(FirConstKind.Int, "hashCode", { a -> a.hashCode() }),
unaryOperation(FirConstKind.Int, "inc", { a -> a.inc() }),
unaryOperation(FirConstKind.Int, "inv", { a -> a.inv() }),
unaryOperation(FirConstKind.Int, "toByte", { a -> a.toByte() }),
unaryOperation(FirConstKind.Int, "toDouble", { a -> a.toDouble() }),
unaryOperation(FirConstKind.Int, "toFloat", { a -> a.toFloat() }),
unaryOperation(FirConstKind.Int, "toInt", { a -> a.toInt() }),
unaryOperation(FirConstKind.Int, "toLong", { a -> a.toLong() }),
unaryOperation(FirConstKind.Int, "toShort", { a -> a.toShort() }),
unaryOperation(FirConstKind.Int, "unaryMinus", { a -> a.unaryMinus() }),
unaryOperation(FirConstKind.Int, "unaryPlus", { a -> a.unaryPlus() }),
unaryOperation(FirConstKind.Long, "dec", { a -> a.dec() }),
unaryOperation(FirConstKind.Long, "hashCode", { a -> a.hashCode() }),
unaryOperation(FirConstKind.Long, "inc", { a -> a.inc() }),
unaryOperation(FirConstKind.Long, "inv", { a -> a.inv() }),
unaryOperation(FirConstKind.Long, "toByte", { a -> a.toByte() }),
unaryOperation(FirConstKind.Long, "toDouble", { a -> a.toDouble() }),
unaryOperation(FirConstKind.Long, "toFloat", { a -> a.toFloat() }),
unaryOperation(FirConstKind.Long, "toInt", { a -> a.toInt() }),
unaryOperation(FirConstKind.Long, "toLong", { a -> a.toLong() }),
unaryOperation(FirConstKind.Long, "toShort", { a -> a.toShort() }),
unaryOperation(FirConstKind.Long, "unaryMinus", { a -> a.unaryMinus() }),
unaryOperation(FirConstKind.Long, "unaryPlus", { a -> a.unaryPlus() }),
unaryOperation(FirConstKind.Short, "dec", { a -> a.dec() }),
unaryOperation(FirConstKind.Short, "hashCode", { a -> a.hashCode() }),
unaryOperation(FirConstKind.Short, "inc", { a -> a.inc() }),
unaryOperation(FirConstKind.Short, "toByte", { a -> a.toByte() }),
unaryOperation(FirConstKind.Short, "toDouble", { a -> a.toDouble() }),
unaryOperation(FirConstKind.Short, "toFloat", { a -> a.toFloat() }),
unaryOperation(FirConstKind.Short, "toInt", { a -> a.toInt() }),
unaryOperation(FirConstKind.Short, "toLong", { a -> a.toLong() }),
unaryOperation(FirConstKind.Short, "toShort", { a -> a.toShort() }),
unaryOperation(FirConstKind.Short, "unaryMinus", { a -> a.unaryMinus() }),
unaryOperation(FirConstKind.Short, "unaryPlus", { a -> a.unaryPlus() }),
)
internal val binaryOperations: HashMap<BinaryOperationKey<*, *>, Function2<Number, Number, Number>> = hashMapOf(
binaryOperation(FirConstKind.Byte, FirConstKind.Byte, "div", { a, b -> a.div(b) }),
binaryOperation(FirConstKind.Byte, FirConstKind.Double, "div", { a, b -> a.div(b) }),
binaryOperation(FirConstKind.Byte, FirConstKind.Float, "div", { a, b -> a.div(b) }),
binaryOperation(FirConstKind.Byte, FirConstKind.Int, "div", { a, b -> a.div(b) }),
binaryOperation(FirConstKind.Byte, FirConstKind.Long, "div", { a, b -> a.div(b) }),
binaryOperation(FirConstKind.Byte, FirConstKind.Short, "div", { a, b -> a.div(b) }),
binaryOperation(FirConstKind.Byte, FirConstKind.Byte, "minus", { a, b -> a.minus(b) }),
binaryOperation(FirConstKind.Byte, FirConstKind.Double, "minus", { a, b -> a.minus(b) }),
binaryOperation(FirConstKind.Byte, FirConstKind.Float, "minus", { a, b -> a.minus(b) }),
binaryOperation(FirConstKind.Byte, FirConstKind.Int, "minus", { a, b -> a.minus(b) }),
binaryOperation(FirConstKind.Byte, FirConstKind.Long, "minus", { a, b -> a.minus(b) }),
binaryOperation(FirConstKind.Byte, FirConstKind.Short, "minus", { a, b -> a.minus(b) }),
binaryOperation(FirConstKind.Byte, FirConstKind.Byte, "plus", { a, b -> a.plus(b) }),
binaryOperation(FirConstKind.Byte, FirConstKind.Double, "plus", { a, b -> a.plus(b) }),
binaryOperation(FirConstKind.Byte, FirConstKind.Float, "plus", { a, b -> a.plus(b) }),
binaryOperation(FirConstKind.Byte, FirConstKind.Int, "plus", { a, b -> a.plus(b) }),
binaryOperation(FirConstKind.Byte, FirConstKind.Long, "plus", { a, b -> a.plus(b) }),
binaryOperation(FirConstKind.Byte, FirConstKind.Short, "plus", { a, b -> a.plus(b) }),
binaryOperation(FirConstKind.Byte, FirConstKind.Byte, "rem", { a, b -> a.rem(b) }),
binaryOperation(FirConstKind.Byte, FirConstKind.Double, "rem", { a, b -> a.rem(b) }),
binaryOperation(FirConstKind.Byte, FirConstKind.Float, "rem", { a, b -> a.rem(b) }),
binaryOperation(FirConstKind.Byte, FirConstKind.Int, "rem", { a, b -> a.rem(b) }),
binaryOperation(FirConstKind.Byte, FirConstKind.Long, "rem", { a, b -> a.rem(b) }),
binaryOperation(FirConstKind.Byte, FirConstKind.Short, "rem", { a, b -> a.rem(b) }),
binaryOperation(FirConstKind.Byte, FirConstKind.Byte, "times", { a, b -> a.times(b) }),
binaryOperation(FirConstKind.Byte, FirConstKind.Double, "times", { a, b -> a.times(b) }),
binaryOperation(FirConstKind.Byte, FirConstKind.Float, "times", { a, b -> a.times(b) }),
binaryOperation(FirConstKind.Byte, FirConstKind.Int, "times", { a, b -> a.times(b) }),
binaryOperation(FirConstKind.Byte, FirConstKind.Long, "times", { a, b -> a.times(b) }),
binaryOperation(FirConstKind.Byte, FirConstKind.Short, "times", { a, b -> a.times(b) }),
binaryOperation(FirConstKind.Double, FirConstKind.Byte, "div", { a, b -> a.div(b) }),
binaryOperation(FirConstKind.Double, FirConstKind.Double, "div", { a, b -> a.div(b) }),
binaryOperation(FirConstKind.Double, FirConstKind.Float, "div", { a, b -> a.div(b) }),
binaryOperation(FirConstKind.Double, FirConstKind.Int, "div", { a, b -> a.div(b) }),
binaryOperation(FirConstKind.Double, FirConstKind.Long, "div", { a, b -> a.div(b) }),
binaryOperation(FirConstKind.Double, FirConstKind.Short, "div", { a, b -> a.div(b) }),
binaryOperation(FirConstKind.Double, FirConstKind.Byte, "minus", { a, b -> a.minus(b) }),
binaryOperation(FirConstKind.Double, FirConstKind.Double, "minus", { a, b -> a.minus(b) }),
binaryOperation(FirConstKind.Double, FirConstKind.Float, "minus", { a, b -> a.minus(b) }),
binaryOperation(FirConstKind.Double, FirConstKind.Int, "minus", { a, b -> a.minus(b) }),
binaryOperation(FirConstKind.Double, FirConstKind.Long, "minus", { a, b -> a.minus(b) }),
binaryOperation(FirConstKind.Double, FirConstKind.Short, "minus", { a, b -> a.minus(b) }),
binaryOperation(FirConstKind.Double, FirConstKind.Byte, "plus", { a, b -> a.plus(b) }),
binaryOperation(FirConstKind.Double, FirConstKind.Double, "plus", { a, b -> a.plus(b) }),
binaryOperation(FirConstKind.Double, FirConstKind.Float, "plus", { a, b -> a.plus(b) }),
binaryOperation(FirConstKind.Double, FirConstKind.Int, "plus", { a, b -> a.plus(b) }),
binaryOperation(FirConstKind.Double, FirConstKind.Long, "plus", { a, b -> a.plus(b) }),
binaryOperation(FirConstKind.Double, FirConstKind.Short, "plus", { a, b -> a.plus(b) }),
binaryOperation(FirConstKind.Double, FirConstKind.Byte, "rem", { a, b -> a.rem(b) }),
binaryOperation(FirConstKind.Double, FirConstKind.Double, "rem", { a, b -> a.rem(b) }),
binaryOperation(FirConstKind.Double, FirConstKind.Float, "rem", { a, b -> a.rem(b) }),
binaryOperation(FirConstKind.Double, FirConstKind.Int, "rem", { a, b -> a.rem(b) }),
binaryOperation(FirConstKind.Double, FirConstKind.Long, "rem", { a, b -> a.rem(b) }),
binaryOperation(FirConstKind.Double, FirConstKind.Short, "rem", { a, b -> a.rem(b) }),
binaryOperation(FirConstKind.Double, FirConstKind.Byte, "times", { a, b -> a.times(b) }),
binaryOperation(FirConstKind.Double, FirConstKind.Double, "times", { a, b -> a.times(b) }),
binaryOperation(FirConstKind.Double, FirConstKind.Float, "times", { a, b -> a.times(b) }),
binaryOperation(FirConstKind.Double, FirConstKind.Int, "times", { a, b -> a.times(b) }),
binaryOperation(FirConstKind.Double, FirConstKind.Long, "times", { a, b -> a.times(b) }),
binaryOperation(FirConstKind.Double, FirConstKind.Short, "times", { a, b -> a.times(b) }),
binaryOperation(FirConstKind.Float, FirConstKind.Byte, "div", { a, b -> a.div(b) }),
binaryOperation(FirConstKind.Float, FirConstKind.Double, "div", { a, b -> a.div(b) }),
binaryOperation(FirConstKind.Float, FirConstKind.Float, "div", { a, b -> a.div(b) }),
binaryOperation(FirConstKind.Float, FirConstKind.Int, "div", { a, b -> a.div(b) }),
binaryOperation(FirConstKind.Float, FirConstKind.Long, "div", { a, b -> a.div(b) }),
binaryOperation(FirConstKind.Float, FirConstKind.Short, "div", { a, b -> a.div(b) }),
binaryOperation(FirConstKind.Float, FirConstKind.Byte, "minus", { a, b -> a.minus(b) }),
binaryOperation(FirConstKind.Float, FirConstKind.Double, "minus", { a, b -> a.minus(b) }),
binaryOperation(FirConstKind.Float, FirConstKind.Float, "minus", { a, b -> a.minus(b) }),
binaryOperation(FirConstKind.Float, FirConstKind.Int, "minus", { a, b -> a.minus(b) }),
binaryOperation(FirConstKind.Float, FirConstKind.Long, "minus", { a, b -> a.minus(b) }),
binaryOperation(FirConstKind.Float, FirConstKind.Short, "minus", { a, b -> a.minus(b) }),
binaryOperation(FirConstKind.Float, FirConstKind.Byte, "plus", { a, b -> a.plus(b) }),
binaryOperation(FirConstKind.Float, FirConstKind.Double, "plus", { a, b -> a.plus(b) }),
binaryOperation(FirConstKind.Float, FirConstKind.Float, "plus", { a, b -> a.plus(b) }),
binaryOperation(FirConstKind.Float, FirConstKind.Int, "plus", { a, b -> a.plus(b) }),
binaryOperation(FirConstKind.Float, FirConstKind.Long, "plus", { a, b -> a.plus(b) }),
binaryOperation(FirConstKind.Float, FirConstKind.Short, "plus", { a, b -> a.plus(b) }),
binaryOperation(FirConstKind.Float, FirConstKind.Byte, "rem", { a, b -> a.rem(b) }),
binaryOperation(FirConstKind.Float, FirConstKind.Double, "rem", { a, b -> a.rem(b) }),
binaryOperation(FirConstKind.Float, FirConstKind.Float, "rem", { a, b -> a.rem(b) }),
binaryOperation(FirConstKind.Float, FirConstKind.Int, "rem", { a, b -> a.rem(b) }),
binaryOperation(FirConstKind.Float, FirConstKind.Long, "rem", { a, b -> a.rem(b) }),
binaryOperation(FirConstKind.Float, FirConstKind.Short, "rem", { a, b -> a.rem(b) }),
binaryOperation(FirConstKind.Float, FirConstKind.Byte, "times", { a, b -> a.times(b) }),
binaryOperation(FirConstKind.Float, FirConstKind.Double, "times", { a, b -> a.times(b) }),
binaryOperation(FirConstKind.Float, FirConstKind.Float, "times", { a, b -> a.times(b) }),
binaryOperation(FirConstKind.Float, FirConstKind.Int, "times", { a, b -> a.times(b) }),
binaryOperation(FirConstKind.Float, FirConstKind.Long, "times", { a, b -> a.times(b) }),
binaryOperation(FirConstKind.Float, FirConstKind.Short, "times", { a, b -> a.times(b) }),
binaryOperation(FirConstKind.Int, FirConstKind.Byte, "div", { a, b -> a.div(b) }),
binaryOperation(FirConstKind.Int, FirConstKind.Double, "div", { a, b -> a.div(b) }),
binaryOperation(FirConstKind.Int, FirConstKind.Float, "div", { a, b -> a.div(b) }),
binaryOperation(FirConstKind.Int, FirConstKind.Int, "div", { a, b -> a.div(b) }),
binaryOperation(FirConstKind.Int, FirConstKind.Long, "div", { a, b -> a.div(b) }),
binaryOperation(FirConstKind.Int, FirConstKind.Short, "div", { a, b -> a.div(b) }),
binaryOperation(FirConstKind.Int, FirConstKind.Byte, "minus", { a, b -> a.minus(b) }),
binaryOperation(FirConstKind.Int, FirConstKind.Double, "minus", { a, b -> a.minus(b) }),
binaryOperation(FirConstKind.Int, FirConstKind.Float, "minus", { a, b -> a.minus(b) }),
binaryOperation(FirConstKind.Int, FirConstKind.Int, "minus", { a, b -> a.minus(b) }),
binaryOperation(FirConstKind.Int, FirConstKind.Long, "minus", { a, b -> a.minus(b) }),
binaryOperation(FirConstKind.Int, FirConstKind.Short, "minus", { a, b -> a.minus(b) }),
binaryOperation(FirConstKind.Int, FirConstKind.Byte, "plus", { a, b -> a.plus(b) }),
binaryOperation(FirConstKind.Int, FirConstKind.Double, "plus", { a, b -> a.plus(b) }),
binaryOperation(FirConstKind.Int, FirConstKind.Float, "plus", { a, b -> a.plus(b) }),
binaryOperation(FirConstKind.Int, FirConstKind.Int, "plus", { a, b -> a.plus(b) }),
binaryOperation(FirConstKind.Int, FirConstKind.Long, "plus", { a, b -> a.plus(b) }),
binaryOperation(FirConstKind.Int, FirConstKind.Short, "plus", { a, b -> a.plus(b) }),
binaryOperation(FirConstKind.Int, FirConstKind.Byte, "rem", { a, b -> a.rem(b) }),
binaryOperation(FirConstKind.Int, FirConstKind.Double, "rem", { a, b -> a.rem(b) }),
binaryOperation(FirConstKind.Int, FirConstKind.Float, "rem", { a, b -> a.rem(b) }),
binaryOperation(FirConstKind.Int, FirConstKind.Int, "rem", { a, b -> a.rem(b) }),
binaryOperation(FirConstKind.Int, FirConstKind.Long, "rem", { a, b -> a.rem(b) }),
binaryOperation(FirConstKind.Int, FirConstKind.Short, "rem", { a, b -> a.rem(b) }),
binaryOperation(FirConstKind.Int, FirConstKind.Byte, "times", { a, b -> a.times(b) }),
binaryOperation(FirConstKind.Int, FirConstKind.Double, "times", { a, b -> a.times(b) }),
binaryOperation(FirConstKind.Int, FirConstKind.Float, "times", { a, b -> a.times(b) }),
binaryOperation(FirConstKind.Int, FirConstKind.Int, "times", { a, b -> a.times(b) }),
binaryOperation(FirConstKind.Int, FirConstKind.Long, "times", { a, b -> a.times(b) }),
binaryOperation(FirConstKind.Int, FirConstKind.Short, "times", { a, b -> a.times(b) }),
binaryOperation(FirConstKind.Long, FirConstKind.Byte, "div", { a, b -> a.div(b) }),
binaryOperation(FirConstKind.Long, FirConstKind.Double, "div", { a, b -> a.div(b) }),
binaryOperation(FirConstKind.Long, FirConstKind.Float, "div", { a, b -> a.div(b) }),
binaryOperation(FirConstKind.Long, FirConstKind.Int, "div", { a, b -> a.div(b) }),
binaryOperation(FirConstKind.Long, FirConstKind.Long, "div", { a, b -> a.div(b) }),
binaryOperation(FirConstKind.Long, FirConstKind.Short, "div", { a, b -> a.div(b) }),
binaryOperation(FirConstKind.Long, FirConstKind.Byte, "minus", { a, b -> a.minus(b) }),
binaryOperation(FirConstKind.Long, FirConstKind.Double, "minus", { a, b -> a.minus(b) }),
binaryOperation(FirConstKind.Long, FirConstKind.Float, "minus", { a, b -> a.minus(b) }),
binaryOperation(FirConstKind.Long, FirConstKind.Int, "minus", { a, b -> a.minus(b) }),
binaryOperation(FirConstKind.Long, FirConstKind.Long, "minus", { a, b -> a.minus(b) }),
binaryOperation(FirConstKind.Long, FirConstKind.Short, "minus", { a, b -> a.minus(b) }),
binaryOperation(FirConstKind.Long, FirConstKind.Byte, "plus", { a, b -> a.plus(b) }),
binaryOperation(FirConstKind.Long, FirConstKind.Double, "plus", { a, b -> a.plus(b) }),
binaryOperation(FirConstKind.Long, FirConstKind.Float, "plus", { a, b -> a.plus(b) }),
binaryOperation(FirConstKind.Long, FirConstKind.Int, "plus", { a, b -> a.plus(b) }),
binaryOperation(FirConstKind.Long, FirConstKind.Long, "plus", { a, b -> a.plus(b) }),
binaryOperation(FirConstKind.Long, FirConstKind.Short, "plus", { a, b -> a.plus(b) }),
binaryOperation(FirConstKind.Long, FirConstKind.Byte, "rem", { a, b -> a.rem(b) }),
binaryOperation(FirConstKind.Long, FirConstKind.Double, "rem", { a, b -> a.rem(b) }),
binaryOperation(FirConstKind.Long, FirConstKind.Float, "rem", { a, b -> a.rem(b) }),
binaryOperation(FirConstKind.Long, FirConstKind.Int, "rem", { a, b -> a.rem(b) }),
binaryOperation(FirConstKind.Long, FirConstKind.Long, "rem", { a, b -> a.rem(b) }),
binaryOperation(FirConstKind.Long, FirConstKind.Short, "rem", { a, b -> a.rem(b) }),
binaryOperation(FirConstKind.Long, FirConstKind.Byte, "times", { a, b -> a.times(b) }),
binaryOperation(FirConstKind.Long, FirConstKind.Double, "times", { a, b -> a.times(b) }),
binaryOperation(FirConstKind.Long, FirConstKind.Float, "times", { a, b -> a.times(b) }),
binaryOperation(FirConstKind.Long, FirConstKind.Int, "times", { a, b -> a.times(b) }),
binaryOperation(FirConstKind.Long, FirConstKind.Long, "times", { a, b -> a.times(b) }),
binaryOperation(FirConstKind.Long, FirConstKind.Short, "times", { a, b -> a.times(b) }),
binaryOperation(FirConstKind.Short, FirConstKind.Byte, "div", { a, b -> a.div(b) }),
binaryOperation(FirConstKind.Short, FirConstKind.Double, "div", { a, b -> a.div(b) }),
binaryOperation(FirConstKind.Short, FirConstKind.Float, "div", { a, b -> a.div(b) }),
binaryOperation(FirConstKind.Short, FirConstKind.Int, "div", { a, b -> a.div(b) }),
binaryOperation(FirConstKind.Short, FirConstKind.Long, "div", { a, b -> a.div(b) }),
binaryOperation(FirConstKind.Short, FirConstKind.Short, "div", { a, b -> a.div(b) }),
binaryOperation(FirConstKind.Short, FirConstKind.Byte, "minus", { a, b -> a.minus(b) }),
binaryOperation(FirConstKind.Short, FirConstKind.Double, "minus", { a, b -> a.minus(b) }),
binaryOperation(FirConstKind.Short, FirConstKind.Float, "minus", { a, b -> a.minus(b) }),
binaryOperation(FirConstKind.Short, FirConstKind.Int, "minus", { a, b -> a.minus(b) }),
binaryOperation(FirConstKind.Short, FirConstKind.Long, "minus", { a, b -> a.minus(b) }),
binaryOperation(FirConstKind.Short, FirConstKind.Short, "minus", { a, b -> a.minus(b) }),
binaryOperation(FirConstKind.Short, FirConstKind.Byte, "plus", { a, b -> a.plus(b) }),
binaryOperation(FirConstKind.Short, FirConstKind.Double, "plus", { a, b -> a.plus(b) }),
binaryOperation(FirConstKind.Short, FirConstKind.Float, "plus", { a, b -> a.plus(b) }),
binaryOperation(FirConstKind.Short, FirConstKind.Int, "plus", { a, b -> a.plus(b) }),
binaryOperation(FirConstKind.Short, FirConstKind.Long, "plus", { a, b -> a.plus(b) }),
binaryOperation(FirConstKind.Short, FirConstKind.Short, "plus", { a, b -> a.plus(b) }),
binaryOperation(FirConstKind.Short, FirConstKind.Byte, "rem", { a, b -> a.rem(b) }),
binaryOperation(FirConstKind.Short, FirConstKind.Double, "rem", { a, b -> a.rem(b) }),
binaryOperation(FirConstKind.Short, FirConstKind.Float, "rem", { a, b -> a.rem(b) }),
binaryOperation(FirConstKind.Short, FirConstKind.Int, "rem", { a, b -> a.rem(b) }),
binaryOperation(FirConstKind.Short, FirConstKind.Long, "rem", { a, b -> a.rem(b) }),
binaryOperation(FirConstKind.Short, FirConstKind.Short, "rem", { a, b -> a.rem(b) }),
binaryOperation(FirConstKind.Short, FirConstKind.Byte, "times", { a, b -> a.times(b) }),
binaryOperation(FirConstKind.Short, FirConstKind.Double, "times", { a, b -> a.times(b) }),
binaryOperation(FirConstKind.Short, FirConstKind.Float, "times", { a, b -> a.times(b) }),
binaryOperation(FirConstKind.Short, FirConstKind.Int, "times", { a, b -> a.times(b) }),
binaryOperation(FirConstKind.Short, FirConstKind.Long, "times", { a, b -> a.times(b) }),
binaryOperation(FirConstKind.Short, FirConstKind.Short, "times", { a, b -> a.times(b) }),
)