diff --git a/compiler/fir/evaluate/build.gradle.kts b/compiler/fir/evaluate/build.gradle.kts index a13009c9139..bbe82714bb1 100644 --- a/compiler/fir/evaluate/build.gradle.kts +++ b/compiler/fir/evaluate/build.gradle.kts @@ -5,7 +5,6 @@ plugins { dependencies { compile(project(":compiler:fir:tree")) - compileOnly(project(":kotlin-reflect-api")) compileOnly(intellijCoreDep()) { includeJars("intellij-core", rootProject = rootProject) } } diff --git a/compiler/fir/evaluate/src/org/jetbrains/kotlin/fir/evaluate/CompileTimeConstantEvaluator.kt b/compiler/fir/evaluate/src/org/jetbrains/kotlin/fir/evaluate/CompileTimeConstantEvaluator.kt index be90bb04f30..3a58f5e7269 100644 --- a/compiler/fir/evaluate/src/org/jetbrains/kotlin/fir/evaluate/CompileTimeConstantEvaluator.kt +++ b/compiler/fir/evaluate/src/org/jetbrains/kotlin/fir/evaluate/CompileTimeConstantEvaluator.kt @@ -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.evaluate(function: FirSimpleFunction): FirConstExpression? { - 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 ): FirConstExpression? { - 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? = @@ -357,7 +195,7 @@ class CompileTimeConstantEvaluator { // TODO: rangeTo? private val binaryOperatorNames: Set = setOf( - "compareTo", "equals", + // TODO: "compareTo", "equals", "div", "minus", "mod", "plus", "rem", "times" ) } diff --git a/compiler/fir/evaluate/src/org/jetbrains/kotlin/fir/evaluate/FirOperationsMapGenerated.kt b/compiler/fir/evaluate/src/org/jetbrains/kotlin/fir/evaluate/FirOperationsMapGenerated.kt new file mode 100644 index 00000000000..a7f99c2118d --- /dev/null +++ b/compiler/fir/evaluate/src/org/jetbrains/kotlin/fir/evaluate/FirOperationsMapGenerated.kt @@ -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(val opr: FirConstKind, val opName: String) +internal data class BinaryOperationKey(val opr1: FirConstKind, val opr2: FirConstKind, val opName: String) + +@Suppress("UNCHECKED_CAST") +private fun unaryOperation( + t: FirConstKind, + opName: String, + operation: Function1 +) = UnaryOperationKey(t, opName) to operation as Function1 + +@Suppress("UNCHECKED_CAST") +private fun binaryOperation( + t: FirConstKind, + u: FirConstKind, + opName: String, + operation: Function2 +) = BinaryOperationKey(t, u, opName) to operation as Function2 + +internal val unaryOperations: HashMap, Function1> = 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, Function2> = 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) }), +) diff --git a/generators/evaluate/GenerateFirOperationsMap.kt b/generators/evaluate/GenerateFirOperationsMap.kt new file mode 100644 index 00000000000..9a0077a9270 --- /dev/null +++ b/generators/evaluate/GenerateFirOperationsMap.kt @@ -0,0 +1,117 @@ +/* + * Copyright 2010-2020 JetBrains s.r.o. and Kotlin Programming Language contributors. + * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file. + */ + +package org.jetbrains.kotlin.generators.evaluate + +import org.jetbrains.kotlin.generators.util.GeneratorsFileUtil +import org.jetbrains.kotlin.types.KotlinType +import org.jetbrains.kotlin.utils.Printer +import java.io.File + +val FIR_DEST_FILE: File = File("compiler/fir/evaluate/src/org/jetbrains/kotlin/fir/evaluate/FirOperationsMapGenerated.kt") +private val EXCLUDED_FUNCTIONS: List = listOf( + "not", "toChar", "toString", + "and", "or", "xor", "shl", "shr", "ushr", + "compareTo", "equals", + "rangeTo", "subSequence" +) +private val EXCLUDED_TYPES: List = listOf("Boolean", "Char", "String") + +fun main() { + GeneratorsFileUtil.writeFileIfContentChanged(FIR_DEST_FILE, generateFirMap()) +} + +fun generateFirMap(): String { + val sb = StringBuilder() + val p = Printer(sb) + p.println(File("license/COPYRIGHT.txt").readText()) + + p.println( + """ + |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(val opr: FirConstKind, val opName: String) + |internal data class BinaryOperationKey(val opr1: FirConstKind, val opr2: FirConstKind, val opName: String) + | + |@Suppress("UNCHECKED_CAST") + |private fun unaryOperation( + | t: FirConstKind, + | opName: String, + | operation: Function1 + |) = UnaryOperationKey(t, opName) to operation as Function1 + | + |@Suppress("UNCHECKED_CAST") + |private fun binaryOperation( + | t: FirConstKind, + | u: FirConstKind, + | opName: String, + | operation: Function2 + |) = BinaryOperationKey(t, u, opName) to operation as Function2 + """.trimMargin() + ) + p.println() + + val unaryOperationsMap = arrayListOf, Boolean>>() + val binaryOperationsMap = arrayListOf>>() + populateOperationsMap(unaryOperationsMap, binaryOperationsMap, EXCLUDED_FUNCTIONS) + + p.println("internal val unaryOperations: HashMap, Function1> = hashMapOf(") + p.pushIndent() + p.renderUnaryOperations(unaryOperationsMap) + p.popIndent() + p.println(")") + p.println() + + p.println("internal val binaryOperations: HashMap, Function2> = hashMapOf(") + p.pushIndent() + p.renderBinaryOperations(binaryOperationsMap) + p.popIndent() + p.println(")") + + return sb.toString() +} + +private fun Printer.renderUnaryOperations(unaryOperationsMap: List, Boolean>>) { + val unaryOperationsMapIterator = unaryOperationsMap.iterator() + while (unaryOperationsMapIterator.hasNext()) { + val (funcName, parameters, isFunction) = unaryOperationsMapIterator.next() + if (parameters.first().constructor.declarationDescriptor!!.name.asString() in EXCLUDED_TYPES) { + continue + } + val parenthesesOrBlank = if (isFunction) "()" else "" + this.println( + "unaryOperation(", + parameters.joinToString(", ") { it.asString() }, + ", ", + "\"$funcName\"", + ", { a -> a.$funcName$parenthesesOrBlank })", + if (unaryOperationsMapIterator.hasNext()) "," else "" + ) + } +} + +private fun Printer.renderBinaryOperations(binaryOperationsMap: List>>) { + val binaryOperationsMapIterator = binaryOperationsMap.iterator() + while (binaryOperationsMapIterator.hasNext()) { + val (funcName, parameters) = binaryOperationsMapIterator.next() + if (parameters.first().constructor.declarationDescriptor!!.name.asString() in EXCLUDED_TYPES) { + continue + } + this.println( + "binaryOperation(", + parameters.joinToString(", ") { it.asString() }, + ", ", + "\"$funcName\"", + ", { a, b -> a.$funcName(b) })", + if (binaryOperationsMapIterator.hasNext()) "," else "" + ) + } +} + +private fun KotlinType.asString(): String = "FirConstKind." + constructor.declarationDescriptor!!.name.asString() diff --git a/generators/evaluate/GenerateOperationsMap.kt b/generators/evaluate/GenerateOperationsMap.kt index a5f1c30240a..76d11ad7490 100644 --- a/generators/evaluate/GenerateOperationsMap.kt +++ b/generators/evaluate/GenerateOperationsMap.kt @@ -7,17 +7,14 @@ package org.jetbrains.kotlin.generators.evaluate import org.jetbrains.kotlin.builtins.DefaultBuiltIns import org.jetbrains.kotlin.builtins.KotlinBuiltIns -import org.jetbrains.kotlin.descriptors.CallableDescriptor import org.jetbrains.kotlin.descriptors.ClassDescriptor -import org.jetbrains.kotlin.descriptors.FunctionDescriptor import org.jetbrains.kotlin.generators.util.GeneratorsFileUtil import org.jetbrains.kotlin.types.KotlinType -import org.jetbrains.kotlin.types.typeUtil.makeNotNullable import org.jetbrains.kotlin.utils.Printer import java.io.File val DEST_FILE: File = File("compiler/frontend/src/org/jetbrains/kotlin/resolve/constants/evaluate/OperationsMapGenerated.kt") -private val EXCLUDED_FUNCTIONS = listOf("rangeTo", "hashCode", "inc", "dec", "subSequence") +private val EXCLUDED_FUNCTIONS: List = listOf("rangeTo", "hashCode", "inc", "dec", "subSequence") fun main() { GeneratorsFileUtil.writeFileIfContentChanged(DEST_FILE, generate()) @@ -40,6 +37,7 @@ fun generate(): String { val unaryOperationsMap = arrayListOf, Boolean>>() val binaryOperationsMap = arrayListOf>>() + populateOperationsMap(unaryOperationsMap, binaryOperationsMap, EXCLUDED_FUNCTIONS) val builtIns = DefaultBuiltIns.Instance @@ -50,24 +48,6 @@ fun generate(): String { val integerTypes = allPrimitiveTypes.map { it.defaultType }.filter { it.isIntegerType() } val fpTypes = allPrimitiveTypes.map { it.defaultType }.filter { it.isFpType() } - for (descriptor in allPrimitiveTypes + builtIns.string) { - @Suppress("UNCHECKED_CAST") - val functions = descriptor.getMemberScope(listOf()).getContributedDescriptors() - .filter { it is CallableDescriptor && !EXCLUDED_FUNCTIONS.contains(it.getName().asString()) } as List - - for (function in functions) { - val parametersTypes = function.getParametersTypes() - - when (parametersTypes.size) { - 1 -> unaryOperationsMap.add(Triple(function.name.asString(), parametersTypes, function is FunctionDescriptor)) - 2 -> binaryOperationsMap.add(function.name.asString() to parametersTypes) - else -> throw IllegalStateException( - "Couldn't add following method from builtins to operations map: ${function.name} in class ${descriptor.name}" - ) - } - } - } - unaryOperationsMap.add(Triple("code", listOf(builtIns.charType), false)) for (type in integerTypes) { @@ -186,10 +166,6 @@ private fun KotlinType.isIntegerType(): Boolean = private fun KotlinType.isFpType(): Boolean = KotlinBuiltIns.isDouble(this) || KotlinBuiltIns.isFloat(this) -private fun CallableDescriptor.getParametersTypes(): List = - listOf((containingDeclaration as ClassDescriptor).defaultType) + - valueParameters.map { it.type.makeNotNullable() } - private fun KotlinType.asString(): String = typeName.uppercase() private val KotlinType.typeName: String diff --git a/generators/evaluate/OperationsMapGeneratorsUtil.kt b/generators/evaluate/OperationsMapGeneratorsUtil.kt new file mode 100644 index 00000000000..c955c4778da --- /dev/null +++ b/generators/evaluate/OperationsMapGeneratorsUtil.kt @@ -0,0 +1,48 @@ +/* + * Copyright 2010-2020 JetBrains s.r.o. and Kotlin Programming Language contributors. + * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file. + */ + +package org.jetbrains.kotlin.generators.evaluate + +import org.jetbrains.kotlin.builtins.DefaultBuiltIns +import org.jetbrains.kotlin.builtins.KotlinBuiltIns +import org.jetbrains.kotlin.descriptors.CallableDescriptor +import org.jetbrains.kotlin.descriptors.ClassDescriptor +import org.jetbrains.kotlin.descriptors.FunctionDescriptor +import org.jetbrains.kotlin.types.KotlinType +import org.jetbrains.kotlin.types.typeUtil.makeNotNullable + +internal fun populateOperationsMap( + unaryOperationsMap: ArrayList, Boolean>>, + binaryOperationsMap: ArrayList>>, + excludedFunctions: List +) { + val builtIns = DefaultBuiltIns.Instance + + @Suppress("UNCHECKED_CAST") + val allPrimitiveTypes = builtIns.builtInsPackageScope.getContributedDescriptors() + .filter { it is ClassDescriptor && KotlinBuiltIns.isPrimitiveType(it.defaultType) } as List + + for (descriptor in allPrimitiveTypes + builtIns.string) { + @Suppress("UNCHECKED_CAST") + val functions = descriptor.getMemberScope(listOf()).getContributedDescriptors() + .filter { it is CallableDescriptor && !excludedFunctions.contains(it.getName().asString()) } as List + + for (function in functions) { + val parametersTypes = function.getParametersTypes() + + when (parametersTypes.size) { + 1 -> unaryOperationsMap.add(Triple(function.name.asString(), parametersTypes, function is FunctionDescriptor)) + 2 -> binaryOperationsMap.add(function.name.asString() to parametersTypes) + else -> throw IllegalStateException( + "Couldn't add following method from builtins to operations map: ${function.name} in class ${descriptor.name}" + ) + } + } + } +} + +private fun CallableDescriptor.getParametersTypes(): List = + listOf((containingDeclaration as ClassDescriptor).defaultType) + + valueParameters.map { it.type.makeNotNullable() } diff --git a/generators/tests/org/jetbrains/kotlin/generators/evaluate/GenerateFirOperationsMapTest.kt b/generators/tests/org/jetbrains/kotlin/generators/evaluate/GenerateFirOperationsMapTest.kt new file mode 100644 index 00000000000..48ce098eff1 --- /dev/null +++ b/generators/tests/org/jetbrains/kotlin/generators/evaluate/GenerateFirOperationsMapTest.kt @@ -0,0 +1,18 @@ +/* + * Copyright 2010-2020 JetBrains s.r.o. and Kotlin Programming Language contributors. + * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file. + */ + +package org.jetbrains.kotlin.generators.test.evaluate + +import junit.framework.TestCase +import org.jetbrains.kotlin.generators.evaluate.FIR_DEST_FILE +import org.jetbrains.kotlin.generators.evaluate.generateFirMap +import org.jetbrains.kotlin.test.KotlinTestUtils + +class GenerateFirOperationsMapTest : TestCase() { + fun testGeneratedDataIsUpToDate() { + val text = generateFirMap() + KotlinTestUtils.assertEqualsToFile(FIR_DEST_FILE, text) + } +}