org.jetbrains.kotlin.resolve.constants.CompileTimeConstant.kt Maven / Gradle / Ivy
/*
* Copyright 2010-2016 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.resolve.constants
import org.jetbrains.kotlin.builtins.KotlinBuiltIns
import org.jetbrains.kotlin.builtins.StandardNames
import org.jetbrains.kotlin.descriptors.ModuleDescriptor
import org.jetbrains.kotlin.descriptors.findClassAcrossModuleDependencies
import org.jetbrains.kotlin.types.*
import org.jetbrains.kotlin.types.error.ErrorScopeKind
import org.jetbrains.kotlin.types.error.ErrorUtils
interface CompileTimeConstant {
val isError: Boolean
get() = false
val parameters: Parameters
val moduleDescriptor: ModuleDescriptor
fun toConstantValue(expectedType: KotlinType): ConstantValue
fun getValue(expectedType: KotlinType): T = toConstantValue(expectedType).value
val canBeUsedInAnnotations: Boolean get() = parameters.canBeUsedInAnnotation
val usesVariableAsConstant: Boolean get() = parameters.usesVariableAsConstant
val usesNonConstValAsConstant: Boolean get() = parameters.usesNonConstValAsConstant
val isPure: Boolean get() = parameters.isPure
val isUnsignedNumberLiteral: Boolean get() = parameters.isUnsignedNumberLiteral
val hasIntegerLiteralType: Boolean
data class Parameters(
val canBeUsedInAnnotation: Boolean,
val isPure: Boolean,
// `isUnsignedNumberLiteral` means that this constant represents simple number literal with `u` suffix (123u, 0xFEu)
val isUnsignedNumberLiteral: Boolean,
// `isUnsignedLongNumberLiteral` means that this constant represents simple number literal with `{uU}{lL}` suffix (123uL, 0xFEUL)
val isUnsignedLongNumberLiteral: Boolean,
val usesVariableAsConstant: Boolean,
val usesNonConstValAsConstant: Boolean,
// `isConvertableConstVal` means that this is `const val` that can participate in signed to unsigned conversion
// see LanguageFeature.ImplicitSignedToUnsignedIntegerConversion
val isConvertableConstVal: Boolean
)
override fun equals(other: Any?): Boolean
override fun hashCode(): Int
}
class TypedCompileTimeConstant(
val constantValue: ConstantValue,
override val moduleDescriptor: ModuleDescriptor,
override val parameters: CompileTimeConstant.Parameters
) : CompileTimeConstant {
override val isError: Boolean
get() = constantValue is ErrorValue
val type: KotlinType = constantValue.getType(moduleDescriptor)
override fun toConstantValue(expectedType: KotlinType): ConstantValue = constantValue
override fun equals(other: Any?): Boolean {
if (this === other) return true
if (other !is TypedCompileTimeConstant<*>) return false
if (isError) return other.isError
if (other.isError) return false
return constantValue.value == other.constantValue.value && type == other.type
}
override fun hashCode(): Int {
if (isError) return 13
var result = constantValue.value?.hashCode() ?: 0
result = 31 * result + type.hashCode()
return result
}
override val hasIntegerLiteralType: Boolean
get() = false
}
fun createIntegerValueTypeConstant(
value: Number,
module: ModuleDescriptor,
parameters: CompileTimeConstant.Parameters,
newInferenceEnabled: Boolean
): CompileTimeConstant<*> {
return IntegerValueTypeConstant(value, module, parameters, newInferenceEnabled)
}
fun hasUnsignedTypesInModuleDependencies(module: ModuleDescriptor): Boolean {
return module.findClassAcrossModuleDependencies(StandardNames.FqNames.uInt) != null
}
class UnsignedErrorValueTypeConstant(
private val value: Number,
override val moduleDescriptor: ModuleDescriptor,
override val parameters: CompileTimeConstant.Parameters
) : CompileTimeConstant {
val errorValue = ErrorValue.ErrorValueWithMessage(
"Type cannot be resolved. Please make sure you have the required dependencies for unsigned types in the classpath"
)
override fun toConstantValue(expectedType: KotlinType): ConstantValue {
return errorValue
}
override fun equals(other: Any?) = other is UnsignedErrorValueTypeConstant && value == other.value
override fun hashCode() = value.hashCode()
override val hasIntegerLiteralType: Boolean
get() = false
}
class IntegerValueTypeConstant(
private val value: Number,
override val moduleDescriptor: ModuleDescriptor,
override val parameters: CompileTimeConstant.Parameters,
private val newInferenceEnabled: Boolean,
val convertedFromSigned: Boolean = false
) : CompileTimeConstant {
companion object {
@JvmStatic
fun IntegerValueTypeConstant.convertToUnsignedConstant(module: ModuleDescriptor): IntegerValueTypeConstant {
val newParameters = CompileTimeConstant.Parameters(
parameters.canBeUsedInAnnotation,
parameters.isPure,
isUnsignedNumberLiteral = true,
isUnsignedLongNumberLiteral = parameters.isUnsignedLongNumberLiteral,
usesVariableAsConstant = parameters.usesVariableAsConstant,
usesNonConstValAsConstant = parameters.usesNonConstValAsConstant,
isConvertableConstVal = parameters.isConvertableConstVal
)
return IntegerValueTypeConstant(value, module, newParameters, newInferenceEnabled, convertedFromSigned = true)
}
fun IntegerValueTypeConstant.convertToSignedConstant(module: ModuleDescriptor): IntegerValueTypeConstant {
val newParameters = CompileTimeConstant.Parameters(
parameters.canBeUsedInAnnotation,
parameters.isPure,
isUnsignedNumberLiteral = false,
isUnsignedLongNumberLiteral = parameters.isUnsignedLongNumberLiteral,
usesVariableAsConstant = parameters.usesVariableAsConstant,
usesNonConstValAsConstant = parameters.usesNonConstValAsConstant,
isConvertableConstVal = parameters.isConvertableConstVal
)
return IntegerValueTypeConstant(value, module, newParameters, newInferenceEnabled, convertedFromSigned = true)
}
}
private val typeConstructor =
if (newInferenceEnabled) {
IntegerLiteralTypeConstructor(value.toLong(), moduleDescriptor, parameters)
} else {
IntegerValueTypeConstructor(value.toLong(), moduleDescriptor, parameters)
}
override fun toConstantValue(expectedType: KotlinType): ConstantValue {
val type = getType(expectedType)
return when {
KotlinBuiltIns.isInt(type) -> IntValue(value.toInt())
KotlinBuiltIns.isByte(type) -> ByteValue(value.toByte())
KotlinBuiltIns.isShort(type) -> ShortValue(value.toShort())
KotlinBuiltIns.isLong(type) -> LongValue(value.toLong())
KotlinBuiltIns.isUInt(type) -> UIntValue(value.toInt())
KotlinBuiltIns.isUByte(type) -> UByteValue(value.toByte())
KotlinBuiltIns.isUShort(type) -> UShortValue(value.toShort())
KotlinBuiltIns.isULong(type) -> ULongValue(value.toLong())
else -> LongValue(value.toLong())
}
}
val unknownIntegerType = KotlinTypeFactory.simpleTypeWithNonTrivialMemberScope(
TypeAttributes.Empty, typeConstructor, emptyList(), false,
ErrorUtils.createErrorScope(ErrorScopeKind.INTEGER_LITERAL_TYPE_SCOPE, throwExceptions = true, typeConstructor.toString())
)
fun getType(expectedType: KotlinType): KotlinType =
if (newInferenceEnabled) {
TypeUtils.getPrimitiveNumberType(typeConstructor as IntegerLiteralTypeConstructor, expectedType)
} else {
TypeUtils.getPrimitiveNumberType(typeConstructor as IntegerValueTypeConstructor, expectedType)
}
override fun toString() = typeConstructor.toString()
override fun equals(other: Any?) = other is IntegerValueTypeConstant && value == other.value && parameters == other.parameters
override fun hashCode() = 31 * value.hashCode() + parameters.hashCode()
override val hasIntegerLiteralType: Boolean
get() = true
}
© 2015 - 2024 Weber Informatics LLC | Privacy Policy