From 80a710a5c506afeb5394e31175474c9e5f63b533 Mon Sep 17 00:00:00 2001 From: Ilya Chernikov Date: Mon, 10 May 2021 11:09:19 +0200 Subject: [PATCH] FIR: implementing IrBuiltIns over FIR --- .../AbstractAnnotationDeserializer.kt | 2 +- .../fir/backend/Fir2IrComponentsStorage.kt | 8 +- .../kotlin/fir/backend/Fir2IrConverter.kt | 34 +- .../kotlin/fir/backend/Fir2IrTypeConverter.kt | 8 +- .../kotlin/fir/backend/IrBuiltInsOverFir.kt | 908 ++++++++++++++++++ .../backend/evaluate/IrConstTransformer.kt | 2 +- .../generators/DataClassMembersGenerator.kt | 15 +- .../generators/FakeOverrideGenerator.kt | 8 - .../kotlin/fir/lazy/Fir2IrLazyClass.kt | 16 +- .../builder/FirConstExpressionBuilder.kt | 16 +- .../jetbrains/kotlin/ir/interpreter/Utils.kt | 18 +- .../jetbrains/kotlin/ir/util/SymbolTable.kt | 28 + 12 files changed, 1006 insertions(+), 57 deletions(-) create mode 100644 compiler/fir/fir2ir/src/org/jetbrains/kotlin/fir/backend/IrBuiltInsOverFir.kt diff --git a/compiler/fir/fir-deserialization/src/org/jetbrains/kotlin/fir/deserialization/AbstractAnnotationDeserializer.kt b/compiler/fir/fir-deserialization/src/org/jetbrains/kotlin/fir/deserialization/AbstractAnnotationDeserializer.kt index 146deda47b5..9f26093be02 100644 --- a/compiler/fir/fir-deserialization/src/org/jetbrains/kotlin/fir/deserialization/AbstractAnnotationDeserializer.kt +++ b/compiler/fir/fir-deserialization/src/org/jetbrains/kotlin/fir/deserialization/AbstractAnnotationDeserializer.kt @@ -297,6 +297,6 @@ abstract class AbstractAnnotationDeserializer( } private fun const(kind: ConstantValueKind, value: T, typeRef: FirResolvedTypeRef): FirConstExpression { - return buildConstExpression(null, kind, value).apply { this.replaceTypeRef(typeRef) } + return buildConstExpression(null, kind, value, setType = true).apply { this.replaceTypeRef(typeRef) } } } diff --git a/compiler/fir/fir2ir/src/org/jetbrains/kotlin/fir/backend/Fir2IrComponentsStorage.kt b/compiler/fir/fir2ir/src/org/jetbrains/kotlin/fir/backend/Fir2IrComponentsStorage.kt index f39cdc526ef..bd371e1aadf 100644 --- a/compiler/fir/fir2ir/src/org/jetbrains/kotlin/fir/backend/Fir2IrComponentsStorage.kt +++ b/compiler/fir/fir2ir/src/org/jetbrains/kotlin/fir/backend/Fir2IrComponentsStorage.kt @@ -11,27 +11,25 @@ import org.jetbrains.kotlin.fir.backend.generators.CallAndReferenceGenerator import org.jetbrains.kotlin.fir.backend.generators.FakeOverrideGenerator import org.jetbrains.kotlin.fir.resolve.ScopeSession import org.jetbrains.kotlin.fir.signaturer.FirBasedSignatureComposer -import org.jetbrains.kotlin.fir.signaturer.FirMangler +import org.jetbrains.kotlin.ir.IrBuiltIns import org.jetbrains.kotlin.ir.IrLock import org.jetbrains.kotlin.ir.declarations.IrFactory -import org.jetbrains.kotlin.ir.IrBuiltIns import org.jetbrains.kotlin.ir.util.SymbolTable class Fir2IrComponentsStorage( override val session: FirSession, override val scopeSession: ScopeSession, override val symbolTable: SymbolTable, - override val irBuiltIns: IrBuiltIns, override val irFactory: IrFactory, - mangler: FirMangler + override val signatureComposer: FirBasedSignatureComposer ) : Fir2IrComponents { override lateinit var classifierStorage: Fir2IrClassifierStorage override lateinit var declarationStorage: Fir2IrDeclarationStorage + override lateinit var irBuiltIns: IrBuiltIns override lateinit var builtIns: Fir2IrBuiltIns override lateinit var typeConverter: Fir2IrTypeConverter - override val signatureComposer = FirBasedSignatureComposer(mangler) override lateinit var visibilityConverter: Fir2IrVisibilityConverter override lateinit var annotationGenerator: AnnotationGenerator diff --git a/compiler/fir/fir2ir/src/org/jetbrains/kotlin/fir/backend/Fir2IrConverter.kt b/compiler/fir/fir2ir/src/org/jetbrains/kotlin/fir/backend/Fir2IrConverter.kt index 2ae8aae6e86..aae8ab31604 100644 --- a/compiler/fir/fir2ir/src/org/jetbrains/kotlin/fir/backend/Fir2IrConverter.kt +++ b/compiler/fir/fir2ir/src/org/jetbrains/kotlin/fir/backend/Fir2IrConverter.kt @@ -20,13 +20,13 @@ import org.jetbrains.kotlin.fir.descriptors.FirModuleDescriptor import org.jetbrains.kotlin.fir.packageFqName import org.jetbrains.kotlin.fir.psi import org.jetbrains.kotlin.fir.resolve.ScopeSession +import org.jetbrains.kotlin.fir.signaturer.FirBasedSignatureComposer import org.jetbrains.kotlin.fir.signaturer.FirMangler import org.jetbrains.kotlin.ir.ObsoleteDescriptorBasedAPI import org.jetbrains.kotlin.ir.PsiIrFileEntry import org.jetbrains.kotlin.ir.declarations.* import org.jetbrains.kotlin.ir.declarations.impl.IrFileImpl import org.jetbrains.kotlin.ir.declarations.impl.IrModuleFragmentImpl -import org.jetbrains.kotlin.ir.descriptors.IrBuiltInsOverDescriptors import org.jetbrains.kotlin.ir.util.DeclarationStubGenerator import org.jetbrains.kotlin.ir.util.ExternalDependenciesGenerator import org.jetbrains.kotlin.ir.util.IdSignatureComposer @@ -35,7 +35,6 @@ import org.jetbrains.kotlin.ir.visitors.acceptVoid import org.jetbrains.kotlin.name.Name import org.jetbrains.kotlin.psi.KtFile import org.jetbrains.kotlin.psi2ir.generators.GeneratorExtensions -import org.jetbrains.kotlin.psi2ir.generators.TypeTranslatorImpl import org.jetbrains.kotlin.psi2ir.generators.generateTypicalIrProviderList class Fir2IrConverter( @@ -266,25 +265,30 @@ class Fir2IrConverter( ): Fir2IrResult { val moduleDescriptor = FirModuleDescriptor(session) val symbolTable = SymbolTable(signaturer, irFactory) - val typeTranslator = - TypeTranslatorImpl(symbolTable, languageVersionSettings, moduleDescriptor, extensions = generatorExtensions) - val irBuiltIns = IrBuiltInsOverDescriptors(moduleDescriptor.builtIns, typeTranslator, symbolTable) + val signatureComposer = FirBasedSignatureComposer(mangler) // FirBuiltinSymbols(irBuiltIns, symbolTable) - val components = Fir2IrComponentsStorage(session, scopeSession, symbolTable, irBuiltIns, irFactory, mangler) - val conversionScope = Fir2IrConversionScope() + val components = Fir2IrComponentsStorage(session, scopeSession, symbolTable, irFactory, signatureComposer) val classifierStorage = Fir2IrClassifierStorage(components) - val converter = Fir2IrConverter(moduleDescriptor, components) - val fir2irVisitor = Fir2IrVisitor(converter, components, conversionScope) + components.classifierStorage = classifierStorage val declarationStorage = Fir2IrDeclarationStorage(components, moduleDescriptor) + components.declarationStorage = declarationStorage + components.visibilityConverter = visibilityConverter val typeConverter = Fir2IrTypeConverter(components) + components.typeConverter = typeConverter + val irBuiltIns = //IrBuiltInsOverDescriptors(moduleDescriptor.builtIns, typeTranslator, symbolTable) + IrBuiltInsOverFir(components, languageVersionSettings, moduleDescriptor) + components.irBuiltIns = irBuiltIns + val converter = Fir2IrConverter(moduleDescriptor, components) + val conversionScope = Fir2IrConversionScope() + val fir2irVisitor = Fir2IrVisitor(converter, components, conversionScope) val builtIns = Fir2IrBuiltIns(components, specialSymbolProvider) val annotationGenerator = AnnotationGenerator(components) - components.declarationStorage = declarationStorage - components.classifierStorage = classifierStorage - components.typeConverter = typeConverter - components.visibilityConverter = visibilityConverter components.builtIns = builtIns components.annotationGenerator = annotationGenerator + val fakeOverrideGenerator = FakeOverrideGenerator(components, conversionScope) + components.fakeOverrideGenerator = fakeOverrideGenerator + val callGenerator = CallAndReferenceGenerator(components, fir2irVisitor, conversionScope) + components.callGenerator = callGenerator val irModuleFragment = IrModuleFragmentImpl(moduleDescriptor, irBuiltIns) for (firFile in firFiles) { @@ -299,10 +303,6 @@ class Fir2IrConverter( // Necessary call to generate built-in IR classes externalDependenciesGenerator.generateUnboundSymbolsAsDependencies() classifierStorage.preCacheBuiltinClasses() - val fakeOverrideGenerator = FakeOverrideGenerator(components, conversionScope) - components.fakeOverrideGenerator = fakeOverrideGenerator - val callGenerator = CallAndReferenceGenerator(components, fir2irVisitor, conversionScope) - components.callGenerator = callGenerator for (firFile in firFiles) { converter.processClassHeaders(firFile) } diff --git a/compiler/fir/fir2ir/src/org/jetbrains/kotlin/fir/backend/Fir2IrTypeConverter.kt b/compiler/fir/fir2ir/src/org/jetbrains/kotlin/fir/backend/Fir2IrTypeConverter.kt index 4ada34d146f..fa41aca2f26 100644 --- a/compiler/fir/fir2ir/src/org/jetbrains/kotlin/fir/backend/Fir2IrTypeConverter.kt +++ b/compiler/fir/fir2ir/src/org/jetbrains/kotlin/fir/backend/Fir2IrTypeConverter.kt @@ -31,7 +31,7 @@ class Fir2IrTypeConverter( private val components: Fir2IrComponents ) : Fir2IrComponents by components { - internal val classIdToSymbolMap = mapOf( + internal val classIdToSymbolMap by lazy { mapOf( StandardClassIds.Nothing to irBuiltIns.nothingClass, StandardClassIds.Unit to irBuiltIns.unitClass, StandardClassIds.Boolean to irBuiltIns.booleanClass, @@ -45,9 +45,9 @@ class Fir2IrTypeConverter( StandardClassIds.Double to irBuiltIns.doubleClass, StandardClassIds.Char to irBuiltIns.charClass, StandardClassIds.Array to irBuiltIns.arrayClass - ) + )} - internal val classIdToTypeMap = mapOf( + internal val classIdToTypeMap by lazy { mapOf( StandardClassIds.Nothing to irBuiltIns.nothingType, StandardClassIds.Unit to irBuiltIns.unitType, StandardClassIds.Boolean to irBuiltIns.booleanType, @@ -60,7 +60,7 @@ class Fir2IrTypeConverter( StandardClassIds.Float to irBuiltIns.floatType, StandardClassIds.Double to irBuiltIns.doubleType, StandardClassIds.Char to irBuiltIns.charType - ) + )} private val capturedTypeCache = mutableMapOf() private val errorTypeForCapturedTypeStub by lazy { createErrorType() } diff --git a/compiler/fir/fir2ir/src/org/jetbrains/kotlin/fir/backend/IrBuiltInsOverFir.kt b/compiler/fir/fir2ir/src/org/jetbrains/kotlin/fir/backend/IrBuiltInsOverFir.kt new file mode 100644 index 00000000000..ac6ce9cb16f --- /dev/null +++ b/compiler/fir/fir2ir/src/org/jetbrains/kotlin/fir/backend/IrBuiltInsOverFir.kt @@ -0,0 +1,908 @@ +/* + * Copyright 2010-2021 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.fir.backend + +import org.jetbrains.kotlin.backend.common.ir.addFakeOverrides +import org.jetbrains.kotlin.backend.common.ir.createImplicitParameterDeclarationWithWrappedDescriptor +import org.jetbrains.kotlin.builtins.PrimitiveType +import org.jetbrains.kotlin.builtins.StandardNames +import org.jetbrains.kotlin.builtins.UnsignedType +import org.jetbrains.kotlin.config.LanguageVersionSettings +import org.jetbrains.kotlin.descriptors.ClassKind +import org.jetbrains.kotlin.descriptors.DescriptorVisibilities +import org.jetbrains.kotlin.descriptors.DescriptorVisibility +import org.jetbrains.kotlin.descriptors.Modality +import org.jetbrains.kotlin.fir.descriptors.FirModuleDescriptor +import org.jetbrains.kotlin.fir.resolve.symbolProvider +import org.jetbrains.kotlin.fir.symbols.impl.FirClassSymbol +import org.jetbrains.kotlin.ir.BuiltInOperatorNames +import org.jetbrains.kotlin.ir.IrBuiltIns +import org.jetbrains.kotlin.ir.UNDEFINED_OFFSET +import org.jetbrains.kotlin.ir.builders.declarations.* +import org.jetbrains.kotlin.ir.declarations.* +import org.jetbrains.kotlin.ir.declarations.impl.IrExternalPackageFragmentImpl +import org.jetbrains.kotlin.ir.expressions.IrConst +import org.jetbrains.kotlin.ir.expressions.IrExpression +import org.jetbrains.kotlin.ir.expressions.impl.IrConstImpl +import org.jetbrains.kotlin.ir.symbols.IrClassSymbol +import org.jetbrains.kotlin.ir.symbols.IrClassifierSymbol +import org.jetbrains.kotlin.ir.symbols.IrConstructorSymbol +import org.jetbrains.kotlin.ir.symbols.IrSimpleFunctionSymbol +import org.jetbrains.kotlin.ir.symbols.impl.IrClassPublicSymbolImpl +import org.jetbrains.kotlin.ir.symbols.impl.IrConstructorPublicSymbolImpl +import org.jetbrains.kotlin.ir.symbols.impl.IrSimpleFunctionPublicSymbolImpl +import org.jetbrains.kotlin.ir.symbols.impl.IrTypeParameterSymbolImpl +import org.jetbrains.kotlin.ir.types.* +import org.jetbrains.kotlin.ir.types.impl.IrSimpleTypeImpl +import org.jetbrains.kotlin.ir.util.* +import org.jetbrains.kotlin.name.ClassId +import org.jetbrains.kotlin.name.FqName +import org.jetbrains.kotlin.name.Name +import org.jetbrains.kotlin.types.Variance +import org.jetbrains.kotlin.util.OperatorNameConventions + +class IrBuiltInsOverFir( + private val components: Fir2IrComponents, + override val languageVersionSettings: LanguageVersionSettings, + private val moduleDescriptor: FirModuleDescriptor +) : IrBuiltIns() { + + override val irFactory: IrFactory = components.symbolTable.irFactory + + private val kotlinPackage = StandardNames.BUILT_INS_PACKAGE_FQ_NAME + private val kotlinReflectPackage = StandardNames.KOTLIN_REFLECT_FQ_NAME + + private val kotlinCollectionsPackage = StandardNames.COLLECTIONS_PACKAGE_FQ_NAME + + private val internalIrPackage = createPackage(KOTLIN_INTERNAL_IR_FQN) + private val kotlinIrPackage = createPackage(kotlinPackage) + private val kotlinCollectionsIrPackage = createPackage(kotlinCollectionsPackage) + + override lateinit var booleanNotSymbol: IrSimpleFunctionSymbol private set + + override val anyClass: IrClassSymbol = kotlinIrPackage.createClass(IdSignatureValues.any) { + createConstructor() + createMemberFunction(OperatorNameConventions.EQUALS, booleanType, "other" to defaultType.withHasQuestionMark(true), modality = Modality.OPEN, isOperator = true) + createMemberFunction("hashCode", intType, modality = Modality.OPEN) + createMemberFunction("toString", stringType, modality = Modality.OPEN) + } + override val anyType: IrType = anyClass.defaultType + override val anyNType = anyType.withHasQuestionMark(true) + + override val numberClass: IrClassSymbol = kotlinIrPackage.createClass(IdSignatureValues.number, classModality = Modality.ABSTRACT) + override val numberType: IrType get() = numberClass.defaultType + + override val nothingClass: IrClassSymbol = kotlinIrPackage.createClass(IdSignatureValues.nothing) + override val nothingType: IrType get() = nothingClass.defaultType + override val nothingNType: IrType = nothingType.withHasQuestionMark(true) + + override val unitClass: IrClassSymbol = kotlinIrPackage.createClass(IdSignatureValues.unit, classKind = ClassKind.OBJECT, classModality = Modality.FINAL) + override val unitType: IrType get() = unitClass.defaultType + + override val booleanType: IrType get() = booleanClass.defaultType + override val booleanClass: IrClassSymbol = kotlinIrPackage.createClass(IdSignatureValues._boolean) + + override val charType: IrType get() = charClass.defaultType + override val charClass: IrClassSymbol = kotlinIrPackage.createClass(IdSignatureValues._char) + + override val byteType: IrType get() = byteClass.defaultType + override val byteClass: IrClassSymbol = kotlinIrPackage.createNumberClass(IdSignatureValues._byte) + override val shortType: IrType get() = shortClass.defaultType + override val shortClass: IrClassSymbol = kotlinIrPackage.createNumberClass(IdSignatureValues._short) + override val intType: IrType get() = intClass.defaultType + override val intClass: IrClassSymbol = kotlinIrPackage.createNumberClass(IdSignatureValues._int) + override val longType: IrType get() = longClass.defaultType + override val longClass: IrClassSymbol = kotlinIrPackage.createNumberClass(IdSignatureValues._long) + override val floatType: IrType get() = floatClass.defaultType + override val floatClass: IrClassSymbol = kotlinIrPackage.createNumberClass(IdSignatureValues._float) + override val doubleType: IrType get() = doubleClass.defaultType + override val doubleClass: IrClassSymbol = kotlinIrPackage.createNumberClass(IdSignatureValues._double) + + override val charSequenceClass: IrClassSymbol = kotlinIrPackage.createClass(IdSignatureValues.charSequence, classKind = ClassKind.INTERFACE) + + override val stringClass: IrClassSymbol = kotlinIrPackage.createClass(IdSignatureValues.string, charSequenceClass.defaultType) + override val stringType: IrType get() = stringClass.defaultType + + override val arrayClass: IrClassSymbol = kotlinIrPackage.createClass(IdSignatureValues.array) klass@{ + val typeParameter = addTypeParameter("T", anyNType) + addArrayMembers(typeParameter.defaultType) + } + + override val annotationClass: IrClassSymbol by lazy { referenceClassByFqname(kotlinPackage, "Annotation")!! } + override val annotationType: IrType get() = annotationClass.defaultType + + override val collectionClass: IrClassSymbol by lazy { referenceClassByFqname(kotlinCollectionsPackage, "Collection")!! } + override val setClass: IrClassSymbol by lazy { referenceClassByFqname(kotlinCollectionsPackage, "Set")!! } + override val listClass: IrClassSymbol by lazy { referenceClassByFqname(kotlinCollectionsPackage, "List")!! } + override val mapClass: IrClassSymbol by lazy { referenceClassByFqname(kotlinCollectionsPackage, "Map")!! } + override val mapEntryClass: IrClassSymbol by lazy { referenceNestedClass(mapClass, "Entry")!! } + + override val iterableClass: IrClassSymbol by lazy { referenceClassByFqname(StandardNames.FqNames.iterable)!! } + override val listIteratorClass: IrClassSymbol by lazy { referenceClassByFqname(StandardNames.FqNames.listIterator)!! } + override val mutableCollectionClass: IrClassSymbol by lazy { referenceClassByFqname(StandardNames.FqNames.mutableCollection)!! } + override val mutableSetClass: IrClassSymbol by lazy { referenceClassByFqname(StandardNames.FqNames.mutableSet)!! } + override val mutableListClass: IrClassSymbol by lazy { referenceClassByFqname(StandardNames.FqNames.mutableList)!! } + override val mutableMapClass: IrClassSymbol by lazy { referenceClassByFqname(StandardNames.FqNames.mutableMap)!! } + override val mutableMapEntryClass: IrClassSymbol by lazy { referenceNestedClass(StandardNames.FqNames.mutableMapEntry)!! } + override val mutableIterableClass: IrClassSymbol by lazy { referenceClassByFqname(StandardNames.FqNames.mutableIterable)!! } + override val mutableIteratorClass: IrClassSymbol by lazy { referenceClassByFqname(StandardNames.FqNames.mutableIterator)!! } + override val mutableListIteratorClass: IrClassSymbol by lazy { referenceClassByFqname(StandardNames.FqNames.mutableListIterator)!! } + override val comparableClass: IrClassSymbol by lazy { referenceClassByFqname(StandardNames.FqNames.comparable)!! } + override val throwableType: IrType by lazy { throwableClass.defaultType } + override val throwableClass: IrClassSymbol by lazy { referenceClassByFqname(StandardNames.FqNames.throwable)!! } + + override val kCallableClass: IrClassSymbol by lazy { referenceClassByFqname(StandardNames.FqNames.kCallable.toSafe())!! } + override val kPropertyClass: IrClassSymbol by lazy { referenceClassByFqname(StandardNames.FqNames.kPropertyFqName.toSafe())!! } + override val kClassClass: IrClassSymbol by lazy { referenceClassByFqname(StandardNames.FqNames.kClass.toSafe())!! } + override val kProperty0Class: IrClassSymbol by lazy { referenceClassByFqname(StandardNames.FqNames.kProperty0.toSafe())!! } + override val kProperty1Class: IrClassSymbol by lazy { referenceClassByFqname(StandardNames.FqNames.kProperty1.toSafe())!! } + override val kProperty2Class: IrClassSymbol by lazy { referenceClassByFqname(StandardNames.FqNames.kProperty2.toSafe())!! } + override val kMutableProperty0Class: IrClassSymbol by lazy { referenceClassByFqname(StandardNames.FqNames.kMutableProperty0.toSafe())!! } + override val kMutableProperty1Class: IrClassSymbol by lazy { referenceClassByFqname(StandardNames.FqNames.kMutableProperty1.toSafe())!! } + override val kMutableProperty2Class: IrClassSymbol by lazy { referenceClassByFqname(StandardNames.FqNames.kMutableProperty2.toSafe())!! } + + override val functionClass: IrClassSymbol by lazy { referenceClassByFqname(kotlinPackage, "Function")!! } + override val kFunctionClass: IrClassSymbol by lazy { referenceClassByFqname(kotlinReflectPackage, "KFunction")!! } + + override val primitiveTypeToIrType = mapOf( + PrimitiveType.BOOLEAN to booleanType, + PrimitiveType.CHAR to charType, + PrimitiveType.BYTE to byteType, + PrimitiveType.SHORT to shortType, + PrimitiveType.INT to intType, + PrimitiveType.LONG to longType, + PrimitiveType.FLOAT to floatType, + PrimitiveType.DOUBLE to doubleType + ) + + private val primitiveIntegralIrTypes = listOf(byteType, shortType, intType, longType) + override val primitiveFloatingPointIrTypes = listOf(floatType, doubleType) + private val primitiveNumericIrTypes = primitiveIntegralIrTypes + primitiveFloatingPointIrTypes + override val primitiveIrTypesWithComparisons = listOf(charType) + primitiveNumericIrTypes + override val primitiveIrTypes = listOf(booleanType) + primitiveIrTypesWithComparisons + private val baseIrTypes = primitiveIrTypes + stringType + + private fun getPrimitiveArithmeticOperatorResultType(target: IrType, arg: IrType) = + when { + arg == doubleType -> arg + target in primitiveFloatingPointIrTypes -> target + arg in primitiveFloatingPointIrTypes -> arg + target == longType -> target + arg == longType -> arg + else -> intType + } + + init { + val intRange = referenceClassByFqname(StandardNames.RANGES_PACKAGE_FQ_NAME, "IntRange")!!.owner.defaultType + val longRange = referenceClassByFqname(StandardNames.RANGES_PACKAGE_FQ_NAME, "LongRange")!!.owner.defaultType + val charRange = referenceClassByFqname(StandardNames.RANGES_PACKAGE_FQ_NAME, "CharRange")!!.owner.defaultType + + with (anyClass.owner) { + createConstructor() + createMemberFunction(OperatorNameConventions.EQUALS, booleanType, "other" to defaultType.withHasQuestionMark(true), modality = Modality.OPEN, isOperator = true) + createMemberFunction("hashCode", intType, modality = Modality.OPEN) + createMemberFunction("toString", stringType, modality = Modality.OPEN) + } + + for (klass in arrayOf(booleanClass, charClass, numberClass, charSequenceClass, stringClass)) { + klass.owner.superTypes += anyType + } + + with (booleanClass.owner) { + booleanNotSymbol = createMemberFunction(OperatorNameConventions.NOT, defaultType, isOperator = true).symbol + createMemberFunction(OperatorNameConventions.AND, defaultType, "other" to defaultType) { isInfix = true } + createMemberFunction(OperatorNameConventions.OR, defaultType, "other" to defaultType) { isInfix = true } + createMemberFunction(OperatorNameConventions.XOR, defaultType, "other" to defaultType) { isInfix = true } + createMemberFunction(OperatorNameConventions.COMPARE_TO, intType, "other" to booleanType, modality = Modality.OPEN, isOperator = true) + addFakeOverrides(this@IrBuiltInsOverFir) + } + + with (arrayClass.owner) { + val typeParameter = addTypeParameter("T", anyNType) + addArrayMembers(typeParameter.defaultType) + addFakeOverrides(this@IrBuiltInsOverFir) + } + + with (numberClass.owner) { + for (targetPrimitive in primitiveIrTypesWithComparisons) { + createMemberFunction("to${targetPrimitive.classFqName!!.shortName().asString()}", targetPrimitive, modality = Modality.ABSTRACT) + } + addFakeOverrides(this@IrBuiltInsOverFir) + } + + for (numericOrChar in primitiveNumericIrTypes + charType) { + with(numericOrChar.getClass()!!) { + createCompanionObject() { + val constExprs = getNumericConstantsExpressions(numericOrChar) + createProperty("MIN_VALUE", numericOrChar, isConst = true, withGetter = false, fieldInit = constExprs.min) + createProperty("MAX_VALUE", numericOrChar, isConst = true, withGetter = false, fieldInit = constExprs.max) + createProperty("SIZE_BYTES", intType, isConst = true, withGetter = false, fieldInit = constExprs.sizeBytes) + createProperty("SIZE_BITS", intType, isConst = true, withGetter = false, fieldInit = constExprs.sizeBits) + } + for (targetPrimitive in primitiveIrTypesWithComparisons) { + createMemberFunction("to${targetPrimitive.classFqName!!.shortName().asString()}", targetPrimitive, modality = Modality.OPEN) + } + createMemberFunction(OperatorNameConventions.INC, numericOrChar, isOperator = true) + createMemberFunction(OperatorNameConventions.DEC, numericOrChar, isOperator = true) + addFakeOverrides(this@IrBuiltInsOverFir) + } + } + for (numeric in primitiveNumericIrTypes) { + with(numeric.getClass()!!) { + for (argument in primitiveNumericIrTypes) { + createMemberFunction( + OperatorNameConventions.COMPARE_TO, intType, "other" to argument, + modality = if (argument == numeric) Modality.OPEN else Modality.FINAL, + isOperator = true + ) + val targetArithmeticReturnType = getPrimitiveArithmeticOperatorResultType(numeric, argument) + for (op in arrayOf( + OperatorNameConventions.PLUS, + OperatorNameConventions.MINUS, + OperatorNameConventions.TIMES, + OperatorNameConventions.DIV, + OperatorNameConventions.REM + )) { + createMemberFunction(op, targetArithmeticReturnType, "other" to argument, isOperator = true) + } + } + val arithmeticReturnType = getPrimitiveArithmeticOperatorResultType(numeric, numeric) + createMemberFunction(OperatorNameConventions.UNARY_PLUS, arithmeticReturnType, isOperator = true) + createMemberFunction(OperatorNameConventions.UNARY_MINUS, arithmeticReturnType, isOperator = true) + } + } + for (integral in primitiveIntegralIrTypes) { + with(integral.getClass()!!) { + for (argType in primitiveIntegralIrTypes) { + createMemberFunction( + OperatorNameConventions.RANGE_TO, + if (integral == longType || argType == longType) longRange else intRange, + "other" to argType, isOperator = true + ) + } + } + } + for (typeWithBitwiseOps in arrayOf(intType, longType)) { + with(typeWithBitwiseOps.getClass()!!) { + for (op in arrayOf(OperatorNameConventions.AND, OperatorNameConventions.OR, OperatorNameConventions.XOR)) { + createMemberFunction(op, typeWithBitwiseOps, "other" to typeWithBitwiseOps, isOperator = true) + } + for (op in arrayOf(OperatorNameConventions.SHL, OperatorNameConventions.SHR, OperatorNameConventions.USHR)) { + createMemberFunction(op, typeWithBitwiseOps, "bitCount" to intType, isOperator = true) + } + createMemberFunction(OperatorNameConventions.INV, typeWithBitwiseOps, isOperator = true) + } + } + with(charClass.owner) { + createMemberFunction(OperatorNameConventions.COMPARE_TO, intType, "other" to charType, modality = Modality.OPEN, isOperator = true) + createMemberFunction(OperatorNameConventions.PLUS, charType, "other" to intType, isOperator = true) + createMemberFunction(OperatorNameConventions.MINUS, charType, "other" to intType, isOperator = true) + createMemberFunction(OperatorNameConventions.MINUS, intType, "other" to charType, isOperator = true) + createMemberFunction(OperatorNameConventions.RANGE_TO, charRange, "other" to charType) + } + with(charSequenceClass.owner) { + createProperty("length", intType, modality = Modality.ABSTRACT) + createMemberFunction(OperatorNameConventions.GET, charType, "index" to intType, modality = Modality.ABSTRACT, isOperator = true) + createMemberFunction("subSequence", defaultType, "startIndex" to intType, "endIndex" to intType, modality = Modality.ABSTRACT) + addFakeOverrides(this@IrBuiltInsOverFir) + } + with(stringClass.owner) { + createProperty("length", intType, modality = Modality.OPEN) + createMemberFunction(OperatorNameConventions.GET, charType, "index" to intType, modality = Modality.OPEN, isOperator = true) + createMemberFunction("subSequence", charSequenceClass.defaultType, "startIndex" to intType, "endIndex" to intType, modality = Modality.OPEN) + createMemberFunction(OperatorNameConventions.COMPARE_TO, intType, "other" to defaultType, modality = Modality.OPEN, isOperator = true) + createMemberFunction(OperatorNameConventions.PLUS, defaultType, "other" to anyNType, isOperator = true) + addFakeOverrides(this@IrBuiltInsOverFir) + } + } + + override val booleanArray: IrClassSymbol = + kotlinIrPackage.createClass(PrimitiveType.BOOLEAN.arrayTypeName) { addArrayMembers(booleanType) } + override val charArray: IrClassSymbol = kotlinIrPackage.createClass(PrimitiveType.CHAR.arrayTypeName) { addArrayMembers(charType) } + override val byteArray: IrClassSymbol = kotlinIrPackage.createClass(PrimitiveType.BYTE.arrayTypeName) { addArrayMembers(byteType) } + override val shortArray: IrClassSymbol = kotlinIrPackage.createClass(PrimitiveType.SHORT.arrayTypeName) { addArrayMembers(shortType) } + override val intArray: IrClassSymbol = kotlinIrPackage.createClass(PrimitiveType.INT.arrayTypeName) { addArrayMembers(intType) } + override val longArray: IrClassSymbol = kotlinIrPackage.createClass(PrimitiveType.LONG.arrayTypeName) { addArrayMembers(longType) } + override val floatArray: IrClassSymbol = kotlinIrPackage.createClass(PrimitiveType.FLOAT.arrayTypeName) { addArrayMembers(floatType) } + override val doubleArray: IrClassSymbol = + kotlinIrPackage.createClass(PrimitiveType.DOUBLE.arrayTypeName) { addArrayMembers(doubleType) } + + override val primitiveArraysToPrimitiveTypes: Map = mapOf( + booleanArray to PrimitiveType.BOOLEAN, + charArray to PrimitiveType.CHAR, + byteArray to PrimitiveType.BYTE, + shortArray to PrimitiveType.SHORT, + intArray to PrimitiveType.INT, + longArray to PrimitiveType.LONG, + floatArray to PrimitiveType.FLOAT, + doubleArray to PrimitiveType.DOUBLE + ) + + override val primitiveTypesToPrimitiveArrays get() = primitiveArraysToPrimitiveTypes.map { (k, v) -> v to k }.toMap() + override val primitiveArrayElementTypes get() = primitiveArraysToPrimitiveTypes.mapValues { primitiveTypeToIrType[it.value] } + override val primitiveArrayForType get() = primitiveArrayElementTypes.asSequence().associate { it.value to it.key } + + private val _ieee754equalsFunByOperandType = mutableMapOf() + override val ieee754equalsFunByOperandType: MutableMap + get() = _ieee754equalsFunByOperandType + + override lateinit var eqeqeqSymbol: IrSimpleFunctionSymbol private set + override lateinit var eqeqSymbol: IrSimpleFunctionSymbol private set + override lateinit var throwCceSymbol: IrSimpleFunctionSymbol private set + override lateinit var throwIseSymbol: IrSimpleFunctionSymbol private set + override lateinit var andandSymbol: IrSimpleFunctionSymbol private set + override lateinit var ororSymbol: IrSimpleFunctionSymbol private set + override lateinit var noWhenBranchMatchedExceptionSymbol: IrSimpleFunctionSymbol private set + override lateinit var illegalArgumentExceptionSymbol: IrSimpleFunctionSymbol private set + override lateinit var dataClassArrayMemberHashCodeSymbol: IrSimpleFunctionSymbol private set + override lateinit var dataClassArrayMemberToStringSymbol: IrSimpleFunctionSymbol private set + + override lateinit var checkNotNullSymbol: IrSimpleFunctionSymbol private set + override val arrayOfNulls: IrSimpleFunctionSymbol by lazy { + findFunctions(kotlinPackage, Name.identifier("arrayOfNulls")).first { + it.owner.dispatchReceiverParameter == null && it.owner.valueParameters.size == 1 && + it.owner.valueParameters[0].type == intType + } + } + + override lateinit var lessFunByOperandType: Map private set + override lateinit var lessOrEqualFunByOperandType: Map private set + override lateinit var greaterOrEqualFunByOperandType: Map private set + override lateinit var greaterFunByOperandType: Map private set + + init { + with(internalIrPackage) { + + fun addBuiltinOperatorSymbol( + name: String, + returnType: IrType, + vararg valueParameterTypes: Pair, + builder: IrSimpleFunction.() -> Unit = {} + ) = + createFunction(fqName, name, returnType, valueParameterTypes, origin = BUILTIN_OPERATOR).also { + declarations.add(it) + it.builder() + }.symbol + + primitiveFloatingPointIrTypes.forEach { fpType -> + _ieee754equalsFunByOperandType.put( + fpType.classifierOrFail, + addBuiltinOperatorSymbol(BuiltInOperatorNames.IEEE754_EQUALS, booleanType, "arg0" to fpType.makeNullable(), "arg1" to fpType.makeNullable()) + ) + } + eqeqeqSymbol = addBuiltinOperatorSymbol(BuiltInOperatorNames.EQEQEQ, booleanType, "" to anyNType, "" to anyNType) + eqeqSymbol = addBuiltinOperatorSymbol(BuiltInOperatorNames.EQEQ, booleanType, "" to anyNType, "" to anyNType) + throwCceSymbol = addBuiltinOperatorSymbol(BuiltInOperatorNames.THROW_CCE, nothingType) + throwIseSymbol = addBuiltinOperatorSymbol(BuiltInOperatorNames.THROW_ISE, nothingType) + andandSymbol = addBuiltinOperatorSymbol(BuiltInOperatorNames.ANDAND, booleanType, "" to booleanType, "" to booleanType) + ororSymbol = addBuiltinOperatorSymbol(BuiltInOperatorNames.OROR, booleanType, "" to booleanType, "" to booleanType) + noWhenBranchMatchedExceptionSymbol = + addBuiltinOperatorSymbol(BuiltInOperatorNames.NO_WHEN_BRANCH_MATCHED_EXCEPTION, nothingType) + illegalArgumentExceptionSymbol = + addBuiltinOperatorSymbol(BuiltInOperatorNames.ILLEGAL_ARGUMENT_EXCEPTION, nothingType, "" to stringType) + dataClassArrayMemberHashCodeSymbol = addBuiltinOperatorSymbol("dataClassArrayMemberHashCode", intType, "" to anyType) + dataClassArrayMemberToStringSymbol = addBuiltinOperatorSymbol("dataClassArrayMemberToString", stringType, "" to anyNType) + + checkNotNullSymbol = run { + val typeParameter: IrTypeParameter = irFactory.createTypeParameter( + UNDEFINED_OFFSET, UNDEFINED_OFFSET, BUILTIN_OPERATOR, IrTypeParameterSymbolImpl(), Name.identifier("T0"), 0, true, + Variance.INVARIANT + ).apply { + superTypes += anyType + } + + createFunction( + fqName, "CHECK_NOT_NULL", + IrSimpleTypeImpl(typeParameter.symbol, hasQuestionMark = false, emptyList(), emptyList()), + arrayOf("" to IrSimpleTypeImpl(typeParameter.symbol, hasQuestionMark = true, emptyList(), emptyList())), + origin = BUILTIN_OPERATOR + ).also { + it.typeParameters = listOf(typeParameter) + typeParameter.parent = it + declarations.add(it) + }.symbol + } + + fun List.defineComparisonOperatorForEachIrType(name: String) = + associate { it.classifierOrFail to addBuiltinOperatorSymbol(name, booleanType, "" to it, "" to it) } + + lessFunByOperandType = primitiveIrTypesWithComparisons.defineComparisonOperatorForEachIrType(BuiltInOperatorNames.LESS) + lessOrEqualFunByOperandType = + primitiveIrTypesWithComparisons.defineComparisonOperatorForEachIrType(BuiltInOperatorNames.LESS_OR_EQUAL) + greaterOrEqualFunByOperandType = + primitiveIrTypesWithComparisons.defineComparisonOperatorForEachIrType(BuiltInOperatorNames.GREATER_OR_EQUAL) + greaterFunByOperandType = primitiveIrTypesWithComparisons.defineComparisonOperatorForEachIrType(BuiltInOperatorNames.GREATER) + + } + } + + override val unsignedTypesToUnsignedArrays: Map by lazy { + UnsignedType.values().mapNotNull { unsignedType -> + val array = referenceClassByClassId(unsignedType.arrayClassId) + if (array == null) null else unsignedType to array + }.toMap() + } + + override fun getKPropertyClass(mutable: Boolean, n: Int): IrClassSymbol = when (n) { + 0 -> if (mutable) kMutableProperty0Class else kProperty0Class + 1 -> if (mutable) kMutableProperty1Class else kProperty1Class + 2 -> if (mutable) kMutableProperty2Class else kProperty2Class + else -> error("No KProperty for n=$n mutable=$mutable") + } + + override val enumClass: IrClassSymbol by lazy { referenceClassByFqname(kotlinPackage, "Enum")!! } + + override val intPlusSymbol: IrSimpleFunctionSymbol + get() = intClass.functions.single { + it.owner.name == OperatorNameConventions.PLUS && it.owner.valueParameters[0].type == intType + } + + override val intTimesSymbol: IrSimpleFunctionSymbol + get() = intClass.functions.single { + it.owner.name == OperatorNameConventions.TIMES && it.owner.valueParameters[0].type == intType + } + + override val extensionToString: IrSimpleFunctionSymbol by lazy { + findFunctions(kotlinPackage, Name.identifier("toString")).first { function -> + function.owner.extensionReceiverParameter?.let { receiver -> receiver.type == anyNType } ?: false + } + } + + override val stringPlus: IrSimpleFunctionSymbol + get() = intClass.functions.single { + it.owner.name == OperatorNameConventions.PLUS && it.owner.valueParameters[0].type == stringType + } + + private class KotlinPackageFuns( + val arrayOf: IrSimpleFunctionSymbol, + ) + + private val kotlinBuiltinFunctions by lazy { + fun IrClassSymbol.addPackageFun( + name: String, + returnType: IrType, + vararg argumentTypes: Pair, + builder: IrSimpleFunction.() -> Unit + ) = + owner.createFunction(kotlinPackage, name, returnType, argumentTypes).also { + it.builder() + this.owner.declarations.add(it) + }.symbol + + val kotlinKt = kotlinIrPackage.createClass(kotlinPackage.child(Name.identifier("KotlinKt"))) + KotlinPackageFuns( + arrayOf = kotlinKt.addPackageFun("arrayOf", arrayClass.defaultType) arrayOf@ { + addTypeParameter("T", anyNType) + addValueParameter { + this.name = Name.identifier("elements") + this.type = arrayClass.defaultType + this.varargElementType = typeParameters[0].defaultType + this.origin = this@arrayOf.origin + } + } + ) + } + + override val arrayOf: IrSimpleFunctionSymbol get() = kotlinBuiltinFunctions.arrayOf + + override val toUIntByExtensionReceiver: Map by lazy { + findFunctions(kotlinPackage, Name.identifier("toUInt")).mapNotNull { fn -> + fn.owner.extensionReceiverParameter?.type?.classifierOrNull?.let { klass -> + klass to fn + } + }.toMap() + } + + override val toULongByExtensionReceiver: Map by lazy { + findFunctions(kotlinPackage, Name.identifier("toULong")).mapNotNull { fn -> + fn.owner.extensionReceiverParameter?.type?.classifierOrNull?.let { klass -> + klass to fn + } + }.toMap() + } + + private val functionNMap = mutableMapOf() + private val kFunctionNMap = mutableMapOf() + private val suspendFunctionNMap = mutableMapOf() + private val kSuspendFunctionNMap = mutableMapOf() + + override fun functionN(arity: Int, declarator: SymbolTable.((IrClassSymbol) -> IrClass) -> IrClass): IrClass = functionN(arity) + + override fun kFunctionN(arity: Int, declarator: SymbolTable.((IrClassSymbol) -> IrClass) -> IrClass): IrClass = kFunctionN(arity) + + override fun suspendFunctionN(arity: Int, declarator: SymbolTable.((IrClassSymbol) -> IrClass) -> IrClass): IrClass = + suspendFunctionN(arity) + + override fun kSuspendFunctionN(arity: Int, declarator: SymbolTable.((IrClassSymbol) -> IrClass) -> IrClass): IrClass = + kSuspendFunctionN(arity) + + override fun functionN(arity: Int): IrClass = functionNMap.getOrPut(arity) { + referenceClassByClassId(StandardNames.getFunctionClassId(arity))!!.owner + } + + override fun kFunctionN(arity: Int): IrClass = kFunctionNMap.getOrPut(arity) { + referenceClassByClassId(StandardNames.getKFunctionClassId(arity))!!.owner + } + + override fun suspendFunctionN(arity: Int): IrClass = suspendFunctionNMap.getOrPut(arity) { + referenceClassByClassId(StandardNames.getSuspendFunctionClassId(arity))!!.owner + } + + override fun kSuspendFunctionN(arity: Int): IrClass = kSuspendFunctionNMap.getOrPut(arity) { + referenceClassByClassId(StandardNames.getKSuspendFunctionClassId(arity))!!.owner + } + + override fun findFunctions(name: Name, vararg packageNameSegments: String): Iterable = + findFunctions(FqName.fromSegments(packageNameSegments.asList()), name) + + override fun findFunctions(name: Name, packageFqName: FqName): Iterable = + findFunctions(packageFqName, name) + + override fun findClass(name: Name, vararg packageNameSegments: String): IrClassSymbol? = + referenceClassByFqname(FqName.fromSegments(packageNameSegments.asList()), name) + + override fun findClass(name: Name, packageFqName: FqName): IrClassSymbol? = + referenceClassByFqname(packageFqName, name) + + private val builtInClasses by lazy { + setOf(anyClass) + } + + override fun findBuiltInClassMemberFunctions(builtInClass: IrClassSymbol, name: Name): Iterable { + require(builtInClass in builtInClasses) + return builtInClass.functions.filter { it.owner.name == name }.asIterable() + } + + override fun getBinaryOperator(name: Name, lhsType: IrType, rhsType: IrType): IrSimpleFunctionSymbol { + val definingClass = lhsType.getMaybeBuiltinClass() ?: error("Defining class not found: $lhsType") + return definingClass.functions.single { function -> + function.name == name && function.valueParameters.size == 1 && function.valueParameters[0].type == rhsType + }.symbol + } + + override fun getUnaryOperator(name: Name, receiverType: IrType): IrSimpleFunctionSymbol { + val definingClass = receiverType.getMaybeBuiltinClass() ?: error("Defining class not found: $receiverType") + return definingClass.functions.single { function -> + function.name == name && function.valueParameters.isEmpty() + }.symbol + } + + override val getProgressionLastElementByReturnType: Map by lazy { + findFunctions(kotlinPackage.child(Name.identifier("internal")), Name.identifier("getProgressionLastElement")).mapNotNull { fn -> + fn.owner.returnType.classOrNull?.let { it to fn } + }.toMap() + } + + private fun referenceClassByFqname(topLevelFqName: FqName) = + referenceClassByClassId(ClassId.topLevel(topLevelFqName)) + + private fun referenceClassByFqname(packageName: FqName, identifier: Name) = + referenceClassByClassId(ClassId(packageName, identifier)) + + private fun referenceClassByFqname(packageName: FqName, identifier: String) = + referenceClassByClassId(ClassId(packageName, Name.identifier(identifier))) + + private fun referenceClassByClassId(classId: ClassId): IrClassSymbol? { + val firSymbol = components.session.symbolProvider.getClassLikeSymbolByFqName(classId) ?: return null + val firClassSymbol = firSymbol as? FirClassSymbol ?: return null + return components.classifierStorage.getIrClassSymbol(firClassSymbol) + } + + private fun referenceNestedClass(klass: IrClassSymbol, identifier: String): IrClassSymbol? = + referenceClassByClassId(klass.owner.classId!!.createNestedClassId(Name.identifier(identifier))) + + private fun referenceNestedClass(fqName: FqName): IrClassSymbol? = + referenceClassByClassId(ClassId(fqName.parent().parent(), fqName.parent().shortName()).createNestedClassId(fqName.shortName())) + + private fun IrType.getMaybeBuiltinClass(): IrClass? { + val lhsClassFqName = classFqName!! + return baseIrTypes.find { it.classFqName == lhsClassFqName }?.getClass() + ?: referenceClassByFqname(lhsClassFqName)?.owner + } + + private fun createPackage(fqName: FqName): IrPackageFragment = + IrExternalPackageFragmentImpl.createEmptyExternalPackageFragment(moduleDescriptor, fqName) + + private fun IrDeclarationParent.createClass( + fqName: FqName, + vararg supertypes: IrType, + classKind: ClassKind = ClassKind.CLASS, + classModality: Modality = Modality.OPEN, + classIsInline: Boolean = false, + builderBlock: IrClassBuilder.() -> Unit = {}, + block: IrClass.() -> Unit = {} + ): IrClassSymbol { + val signature = IdSignature.PublicSignature(fqName.parent().asString(), fqName.shortName().asString(), null, 0) + + return this.createClass( + signature, *supertypes, + classKind = classKind, classModality = classModality, classIsInline = classIsInline, builderBlock = builderBlock, block = block + ) + } + + private fun IrDeclarationParent.createClass( + signature: IdSignature.PublicSignature, + vararg supertypes: IrType, + classKind: ClassKind = ClassKind.CLASS, + classModality: Modality = Modality.OPEN, + classIsInline: Boolean = false, + builderBlock: IrClassBuilder.() -> Unit = {}, + block: IrClass.() -> Unit = {} + ): IrClassSymbol = components.symbolTable.declareClass( + signature, + { IrClassPublicSymbolImpl(signature) }, + { symbol -> + IrClassBuilder().run { + name = Name.identifier(signature.shortName) + kind = classKind + modality = classModality + isInline = classIsInline + origin = IrDeclarationOrigin.IR_EXTERNAL_DECLARATION_STUB + builderBlock() + irFactory.createClass( + startOffset, endOffset, origin, symbol, name, kind, visibility, modality, + isCompanion, isInner, isData, isExternal, isInline, isExpect, isFun + ) + }.also { + it.parent = this + it.createImplicitParameterDeclarationWithWrappedDescriptor() + it.block() + it.superTypes = supertypes.asList() + } + } + ).symbol + + private fun IrPackageFragment.createClass( + name: Name, + vararg supertypes: IrType, + classKind: ClassKind = ClassKind.CLASS, + classModality: Modality = Modality.OPEN, + classIsInline: Boolean = false, + builderBlock: IrClassBuilder.() -> Unit = {}, + block: IrClass.() -> Unit = {} + ): IrClassSymbol = + this.createClass( + fqName.child(name), *supertypes, + classKind = classKind, classModality = classModality, classIsInline = classIsInline, builderBlock = builderBlock, block = block + ) + + private fun IrClass.createConstructor( + origin: IrDeclarationOrigin = object : IrDeclarationOriginImpl("BUILTIN_CLASS_CONSTRUCTOR") {}, + isPrimary: Boolean = true, + visibility: DescriptorVisibility = DescriptorVisibilities.PUBLIC, + build: IrConstructor.() -> Unit = {} + ): IrConstructorSymbol { + val name = Name.special("") + val signature = + IdSignature.PublicSignature(this.packageFqName!!.asString(), classId!!.relativeClassName.child(name).asString(), null, 0) + val ctor = irFactory.createConstructor( + UNDEFINED_OFFSET, UNDEFINED_OFFSET, origin, IrConstructorPublicSymbolImpl(signature), name, visibility, defaultType, + isInline = false, isExternal = false, isPrimary = isPrimary, isExpect = false + ) + ctor.parent = this + ctor.build() + declarations.add(ctor) + return ctor.symbol + } + + private fun IrClass.forEachSuperClass(body: IrClass.() -> Unit) { + for (st in superTypes) { + st.getClass()?.let { + it.body() + it.forEachSuperClass(body) + } + } + } + + private fun IrClass.createMemberFunction( + name: String, returnType: IrType, vararg valueParameterTypes: Pair, + origin: IrDeclarationOrigin = object : IrDeclarationOriginImpl("BUILTIN_CLASS_METHOD") {}, + modality: Modality = Modality.FINAL, + isOperator: Boolean = false, + build: IrFunctionBuilder.() -> Unit = {} + ) = parent.createFunction( + IdSignature.PublicSignature( + this.packageFqName!!.asString(), + classId!!.relativeClassName.child(Name.identifier(name)).asString(), + null, + 0 + ), + name, returnType, valueParameterTypes, origin, modality, isOperator, build + ).also { fn -> + fn.addDispatchReceiver { type = this@createMemberFunction.defaultType } + declarations.add(fn) + fn.parent = this@createMemberFunction + + // very simple and fragile logic, but works for all current usages + // TODO: replace with correct logic or explicit specification if cases become more complex + forEachSuperClass { + functions.find { + it.name == fn.name && it.typeParameters.count() == fn.typeParameters.count() && + it.valueParameters.count() == fn.valueParameters.count() && + it.valueParameters.zip(fn.valueParameters).all { (l, r) -> l.type == r.type } + }?.let { + fn.overriddenSymbols += it.symbol + } + } + } + + private fun IrClass.createMemberFunction( + name: Name, returnType: IrType, vararg valueParameterTypes: Pair, + origin: IrDeclarationOrigin = object : IrDeclarationOriginImpl("BUILTIN_CLASS_METHOD") {}, + modality: Modality = Modality.FINAL, + isOperator: Boolean = false, + build: IrFunctionBuilder.() -> Unit = {} + ) = + createMemberFunction( + name.asString(), returnType, *valueParameterTypes, origin = origin, modality = modality, isOperator = isOperator, build = build + ) + + private fun IrDeclarationParent.createFunction( + signature: IdSignature, + name: String, + returnType: IrType, + valueParameterTypes: Array>, + origin: IrDeclarationOrigin = IrDeclarationOrigin.IR_EXTERNAL_DECLARATION_STUB, + modality: Modality = Modality.FINAL, + isOperator: Boolean = false, + build: IrFunctionBuilder.() -> Unit = {} + ) = IrFunctionBuilder().run { + this.name = Name.identifier(name) + this.returnType = returnType + this.origin = origin + this.modality = modality + this.isOperator = isOperator + build() + irFactory.createFunction( + startOffset, endOffset, origin, IrSimpleFunctionPublicSymbolImpl(signature), this.name, visibility, modality, this.returnType, + isInline, isExternal, isTailrec, isSuspend, isOperator, isInfix, isExpect, isFakeOverride, containerSource, + ).also { fn -> + valueParameterTypes.forEachIndexed { index, (pName, irType) -> + fn.addValueParameter(Name.identifier(if (pName.isBlank()) "arg$index" else pName), irType, origin) + } + fn.parent = this@createFunction + } + } + + private fun IrDeclarationParent.createFunction( + packageFqName: FqName, + name: String, + returnType: IrType, + valueParameterTypes: Array>, + origin: IrDeclarationOrigin = IrDeclarationOrigin.IR_EXTERNAL_DECLARATION_STUB, + modality: Modality = Modality.FINAL, + isOperator: Boolean = false + ) = createFunction( + IdSignature.PublicSignature(packageFqName.asString(), name, null, 0), + name, returnType, valueParameterTypes, origin, modality, isOperator + ) + + private fun IrClass.addArrayMembers(elementType: IrType) { + addConstructor { + origin = object : IrDeclarationOriginImpl("BUILTIN_CLASS_CONSTRUCTOR") {} + returnType = defaultType + isPrimary = true + }.also { + it.addValueParameter("size", intType, object : IrDeclarationOriginImpl("BUILTIN_CLASS_CONSTRUCTOR") {}) + } + createMemberFunction(OperatorNameConventions.GET, elementType, "index" to intType, isOperator = true) + createMemberFunction(OperatorNameConventions.SET, unitType, "index" to intType, "value" to elementType, isOperator = true) + createProperty("size", intType) + } + + private fun IrClass.createProperty( + propertyName: String, returnType: IrType, + modality: Modality = Modality.FINAL, + isConst: Boolean = false, withGetter: Boolean = true, withField: Boolean = false, fieldInit: IrExpression? = null, + builder: IrProperty.() -> Unit = {} + ) { + addProperty { + this.name = Name.identifier(propertyName) + this.isConst = isConst + this.modality = modality + }.also { property -> + + // very simple and fragile logic, but works for all current usages + // TODO: replace with correct logic or explicit specification if cases become more complex + forEachSuperClass { + properties.find { it.name == property.name }?.let { + property.overriddenSymbols += it.symbol + } + } + + if (withGetter) { + property.getter = irFactory.buildFun { + this.name = Name.special("") + this.returnType = returnType + this.modality = modality + this.isOperator = false + }.also { + it.addDispatchReceiver { type = this@createProperty.defaultType } + it.parent = this + it.correspondingPropertySymbol = property.symbol + it.overriddenSymbols = property.overriddenSymbols.mapNotNull { it.owner.getter?.symbol } + } + } + if (withField || fieldInit != null) { + property.backingField = irFactory.buildField { + this.name = property.name + this.type = defaultType + }.also { + if (fieldInit != null) { + it.initializer = irFactory.createExpressionBody(0, 0) { + expression = fieldInit + } + } + it.correspondingPropertySymbol = property.symbol + } + } + property.builder() + } + } + + private class NumericConstantsExpressions( + val min: IrConst, + val max: IrConst, + val sizeBytes: IrConst, + val sizeBits: IrConst + ) + + private fun getNumericConstantsExpressions(type: IrType): NumericConstantsExpressions<*> { + val so = UNDEFINED_OFFSET + val eo = UNDEFINED_OFFSET + return when (type.getPrimitiveType()) { + PrimitiveType.CHAR -> NumericConstantsExpressions( + IrConstImpl.char(so, eo, type, Char.MIN_VALUE), IrConstImpl.char(so, eo, type, Char.MAX_VALUE), + IrConstImpl.int(so, eo, intType, Char.SIZE_BYTES), IrConstImpl.int(so, eo, intType, Char.SIZE_BITS) + ) + PrimitiveType.BYTE -> NumericConstantsExpressions( + IrConstImpl.byte(so, eo, type, Byte.MIN_VALUE), IrConstImpl.byte(so, eo, type, Byte.MAX_VALUE), + IrConstImpl.int(so, eo, intType, Byte.SIZE_BYTES), IrConstImpl.int(so, eo, intType, Byte.SIZE_BITS) + ) + PrimitiveType.SHORT -> NumericConstantsExpressions( + IrConstImpl.short(so, eo, type, Short.MIN_VALUE), IrConstImpl.short(so, eo, type, Short.MAX_VALUE), + IrConstImpl.int(so, eo, intType, Short.SIZE_BYTES), IrConstImpl.int(so, eo, intType, Short.SIZE_BITS) + ) + PrimitiveType.INT -> NumericConstantsExpressions( + IrConstImpl.int(so, eo, type, Int.MIN_VALUE), IrConstImpl.int(so, eo, type, Int.MAX_VALUE), + IrConstImpl.int(so, eo, intType, Int.SIZE_BYTES), IrConstImpl.int(so, eo, intType, Int.SIZE_BITS) + ) + PrimitiveType.LONG -> NumericConstantsExpressions( + IrConstImpl.long(so, eo, type, Long.MIN_VALUE), IrConstImpl.long(so, eo, type, Long.MAX_VALUE), + IrConstImpl.int(so, eo, intType, Long.SIZE_BYTES), IrConstImpl.int(so, eo, intType, Long.SIZE_BITS) + ) + PrimitiveType.FLOAT -> NumericConstantsExpressions( + IrConstImpl.float(so, eo, type, Float.MIN_VALUE), IrConstImpl.float(so, eo, type, Float.MAX_VALUE), + IrConstImpl.int(so, eo, intType, Float.SIZE_BYTES), IrConstImpl.int(so, eo, intType, Float.SIZE_BITS) + ) + PrimitiveType.DOUBLE -> NumericConstantsExpressions( + IrConstImpl.double(so, eo, type, Double.MIN_VALUE), IrConstImpl.double(so, eo, type, Double.MAX_VALUE), + IrConstImpl.int(so, eo, intType, Double.SIZE_BYTES), IrConstImpl.int(so, eo, intType, Double.SIZE_BITS) + ) + else -> error("unsupported type") + } + } + + private fun IrPackageFragment.createNumberClass(signature: IdSignature.PublicSignature, builder: IrClass.() -> Unit = {}): IrClassSymbol = + createClass(signature, numberType) { + builder() + } + + private fun IrClass.createCompanionObject(block: IrClass.() -> Unit = {}): IrClassSymbol = + this.createClass( + kotlinFqName.child(Name.identifier("Companion")), classKind = ClassKind.OBJECT, builderBlock = { + isCompanion = true + } + ).also { + it.owner.block() + declarations.add(it.owner) + } + + private fun findFunctions(packageName: FqName, name: Name) = + components.session.symbolProvider.getTopLevelFunctionSymbols(packageName, name).mapNotNull { firOpSymbol -> + components.declarationStorage.getIrFunctionSymbol(firOpSymbol) as? IrSimpleFunctionSymbol + } +} diff --git a/compiler/fir/fir2ir/src/org/jetbrains/kotlin/fir/backend/evaluate/IrConstTransformer.kt b/compiler/fir/fir2ir/src/org/jetbrains/kotlin/fir/backend/evaluate/IrConstTransformer.kt index a5cf2719276..852231bc22b 100644 --- a/compiler/fir/fir2ir/src/org/jetbrains/kotlin/fir/backend/evaluate/IrConstTransformer.kt +++ b/compiler/fir/fir2ir/src/org/jetbrains/kotlin/fir/backend/evaluate/IrConstTransformer.kt @@ -100,6 +100,6 @@ class IrConstTransformer(private val interpreter: IrInterpreter, private val irF private fun IrExpression.convertToConstIfPossible(type: IrType): IrExpression { if (this !is IrConst<*> || type is IrErrorType) return this if (type.isArray()) return this.convertToConstIfPossible((type as IrSimpleType).arguments.single().typeOrNull!!) - return this.value.toIrConst(type, this.startOffset, this.endOffset) + return this.value.toIrConst(type, interpreter.irBuiltIns, this.startOffset, this.endOffset) } } diff --git a/compiler/fir/fir2ir/src/org/jetbrains/kotlin/fir/backend/generators/DataClassMembersGenerator.kt b/compiler/fir/fir2ir/src/org/jetbrains/kotlin/fir/backend/generators/DataClassMembersGenerator.kt index 7d26cace35f..130e18b93cc 100644 --- a/compiler/fir/fir2ir/src/org/jetbrains/kotlin/fir/backend/generators/DataClassMembersGenerator.kt +++ b/compiler/fir/fir2ir/src/org/jetbrains/kotlin/fir/backend/generators/DataClassMembersGenerator.kt @@ -31,8 +31,6 @@ import org.jetbrains.kotlin.fir.types.impl.FirImplicitBooleanTypeRef import org.jetbrains.kotlin.fir.types.impl.FirImplicitIntTypeRef import org.jetbrains.kotlin.fir.types.impl.FirImplicitNullableAnyTypeRef import org.jetbrains.kotlin.fir.types.impl.FirImplicitStringTypeRef -import org.jetbrains.kotlin.incremental.components.NoLookupLocation -import org.jetbrains.kotlin.ir.ObsoleteDescriptorBasedAPI import org.jetbrains.kotlin.ir.UNDEFINED_OFFSET import org.jetbrains.kotlin.ir.builders.IrGeneratorContextBase import org.jetbrains.kotlin.ir.declarations.* @@ -59,7 +57,6 @@ import org.jetbrains.kotlin.util.OperatorNameConventions.TO_STRING * fir own logic that traverses class hierarchies in fir elements. Also, this one creates and passes IR elements, instead of providing how * to declare them, to [DataClassMembersGenerator]. */ -@OptIn(ObsoleteDescriptorBasedAPI::class) class DataClassMembersGenerator(val components: Fir2IrComponents) { fun generateInlineClassMembers(klass: FirClass, irClass: IrClass): List = @@ -313,12 +310,12 @@ class DataClassMembersGenerator(val components: Fir2IrComponents) { }.apply { parent = irClass dispatchReceiverParameter = generateDispatchReceiverParameter(this) - components.irBuiltIns.anyClass.descriptor.unsubstitutedMemberScope - .getContributedFunctions(this.name, NoLookupLocation.FROM_BACKEND) - .singleOrNull { function -> function.name == this.name } - ?.let { - overriddenSymbols = listOf(components.symbolTable.referenceSimpleFunction(it)) - } + components.irBuiltIns.findBuiltInClassMemberFunctions( + components.irBuiltIns.anyClass, + this.name + ).singleOrNull()?.let { + overriddenSymbols = listOf(it) + } } } diff --git a/compiler/fir/fir2ir/src/org/jetbrains/kotlin/fir/backend/generators/FakeOverrideGenerator.kt b/compiler/fir/fir2ir/src/org/jetbrains/kotlin/fir/backend/generators/FakeOverrideGenerator.kt index a81ec7ff146..27d8347949c 100644 --- a/compiler/fir/fir2ir/src/org/jetbrains/kotlin/fir/backend/generators/FakeOverrideGenerator.kt +++ b/compiler/fir/fir2ir/src/org/jetbrains/kotlin/fir/backend/generators/FakeOverrideGenerator.kt @@ -329,14 +329,6 @@ class FakeOverrideGenerator( @Suppress("UNCHECKED_CAST") irProducer(fakeOverrideInClass.symbol as F) } - }.run { - // TODO: Get rid of this hack - // It's only needed for built-in super classes, because they are built via descriptors and - // don't register fake overrides at org.jetbrains.kotlin.fir.backend.Fir2IrDeclarationStorage.fakeOverridesInClass - if (isEmpty()) - listOf(irProducer(overridden)) - else - this } } } diff --git a/compiler/fir/fir2ir/src/org/jetbrains/kotlin/fir/lazy/Fir2IrLazyClass.kt b/compiler/fir/fir2ir/src/org/jetbrains/kotlin/fir/lazy/Fir2IrLazyClass.kt index 0d0897d3cda..02c5fa5ce94 100644 --- a/compiler/fir/fir2ir/src/org/jetbrains/kotlin/fir/lazy/Fir2IrLazyClass.kt +++ b/compiler/fir/fir2ir/src/org/jetbrains/kotlin/fir/lazy/Fir2IrLazyClass.kt @@ -27,8 +27,6 @@ import org.jetbrains.kotlin.ir.expressions.IrConstructorCall import org.jetbrains.kotlin.ir.types.IrSimpleType import org.jetbrains.kotlin.ir.types.IrType import org.jetbrains.kotlin.ir.types.impl.IrSimpleTypeImpl -import org.jetbrains.kotlin.ir.util.isFakeOverride -import org.jetbrains.kotlin.ir.util.render import org.jetbrains.kotlin.name.Name class Fir2IrLazyClass( @@ -189,13 +187,13 @@ class Fir2IrLazyClass( } // TODO: remove this check to save time - for (declaration in result) { - if (declaration.parent != this) { - throw AssertionError( - "Unmatched parent for lazy class ${fir.name} member ${declaration.render()} f/o ${declaration.isFakeOverride}" - ) - } - } +// for (declaration in result) { +// if (declaration.parent != this) { +// throw AssertionError( +// "Unmatched parent for lazy class ${fir.name} member ${declaration.render()} f/o ${declaration.isFakeOverride}" +// ) +// } +// } result } diff --git a/compiler/fir/tree/src/org/jetbrains/kotlin/fir/expressions/builder/FirConstExpressionBuilder.kt b/compiler/fir/tree/src/org/jetbrains/kotlin/fir/expressions/builder/FirConstExpressionBuilder.kt index b2315b13b3e..ecece802ee2 100644 --- a/compiler/fir/tree/src/org/jetbrains/kotlin/fir/expressions/builder/FirConstExpressionBuilder.kt +++ b/compiler/fir/tree/src/org/jetbrains/kotlin/fir/expressions/builder/FirConstExpressionBuilder.kt @@ -9,6 +9,7 @@ import org.jetbrains.kotlin.fir.FirSourceElement import org.jetbrains.kotlin.fir.expressions.FirAnnotationCall import org.jetbrains.kotlin.fir.expressions.FirConstExpression import org.jetbrains.kotlin.fir.expressions.impl.FirConstExpressionImpl +import org.jetbrains.kotlin.fir.types.impl.* import org.jetbrains.kotlin.types.ConstantValueKind fun buildConstExpression( @@ -16,6 +17,19 @@ fun buildConstExpression( kind: ConstantValueKind, value: T, annotations: MutableList = mutableListOf(), + setType: Boolean = false ): FirConstExpression { - return FirConstExpressionImpl(source, annotations, kind, value) + return FirConstExpressionImpl(source, annotations, kind, value).also { + if (setType) { + when (value) { + null -> it.typeRef = FirImplicitNullableAnyTypeRef(null) + is String -> it.typeRef = FirImplicitStringTypeRef(null) + is Long -> it.typeRef = FirImplicitLongTypeRef(null) + is Int -> it.typeRef = FirImplicitIntTypeRef(null) + is Boolean -> it.typeRef = FirImplicitBooleanTypeRef(null) + is Double -> it.typeRef = FirImplicitDoubleTypeRef(null) + is Float -> it.typeRef = FirImplicitFloatTypeRef(null) + } + } + } } \ No newline at end of file diff --git a/compiler/ir/ir.interpreter/src/org/jetbrains/kotlin/ir/interpreter/Utils.kt b/compiler/ir/ir.interpreter/src/org/jetbrains/kotlin/ir/interpreter/Utils.kt index 7b9d8e95c32..f2e34fe2b63 100644 --- a/compiler/ir/ir.interpreter/src/org/jetbrains/kotlin/ir/interpreter/Utils.kt +++ b/compiler/ir/ir.interpreter/src/org/jetbrains/kotlin/ir/interpreter/Utils.kt @@ -8,6 +8,7 @@ package org.jetbrains.kotlin.ir.interpreter import org.jetbrains.kotlin.builtins.PrimitiveType import org.jetbrains.kotlin.builtins.StandardNames import org.jetbrains.kotlin.builtins.UnsignedType +import org.jetbrains.kotlin.ir.IrBuiltIns import org.jetbrains.kotlin.ir.UNDEFINED_OFFSET import org.jetbrains.kotlin.ir.declarations.* import org.jetbrains.kotlin.ir.expressions.* @@ -79,7 +80,7 @@ internal fun Any?.toState(irType: IrType): State { } } -fun Any?.toIrConst(irType: IrType, startOffset: Int = UNDEFINED_OFFSET, endOffset: Int = UNDEFINED_OFFSET): IrConst<*> { +fun Any?.toIrConstOrNull(irType: IrType, startOffset: Int = UNDEFINED_OFFSET, endOffset: Int = UNDEFINED_OFFSET): IrConst<*>? { if (this == null) return IrConstImpl.constNull(startOffset, endOffset, irType) val constType = irType.makeNotNull() @@ -99,12 +100,25 @@ fun Any?.toIrConst(irType: IrType, startOffset: Int = UNDEFINED_OFFSET, endOffse UnsignedType.ULONG -> IrConstImpl.long(startOffset, endOffset, constType, (this as Number).toLong()) null -> when { constType.isString() -> IrConstImpl.string(startOffset, endOffset, constType, this as String) - else -> throw UnsupportedOperationException("Unsupported const element type ${constType.render()}") + else -> null } } } } +fun Any?.toIrConst(irType: IrType, startOffset: Int = UNDEFINED_OFFSET, endOffset: Int = UNDEFINED_OFFSET): IrConst<*> = + toIrConstOrNull(irType, startOffset, endOffset) + ?: throw UnsupportedOperationException("Unsupported const element type ${irType.makeNotNull().render()}") + +fun Any?.toIrConst( + irType: IrType, irBuiltIns: IrBuiltIns, + startOffset: Int = UNDEFINED_OFFSET, endOffset: Int = UNDEFINED_OFFSET +): IrConst<*> = + toIrConstOrNull(irType, startOffset, endOffset) ?: run { + if (irType == irBuiltIns.stringType) IrConstImpl.string(startOffset, endOffset, irType.makeNotNull(), this as String) + else throw UnsupportedOperationException("Unsupported const element type ${irType.makeNotNull().render()}") + } + @Suppress("UNCHECKED_CAST") internal fun IrConst.toPrimitive(): Primitive = when { type.isByte() -> Primitive((value as Number).toByte() as T, type) diff --git a/compiler/ir/ir.tree/src/org/jetbrains/kotlin/ir/util/SymbolTable.kt b/compiler/ir/ir.tree/src/org/jetbrains/kotlin/ir/util/SymbolTable.kt index d333aa851df..9bbb0a8af36 100644 --- a/compiler/ir/ir.tree/src/org/jetbrains/kotlin/ir/util/SymbolTable.kt +++ b/compiler/ir/ir.tree/src/org/jetbrains/kotlin/ir/util/SymbolTable.kt @@ -156,6 +156,27 @@ class SymbolTable( } } + inline fun declareIfNotExists(sig: IdSignature, d: D?, createSymbol: () -> S, createOwner: (S) -> B): B { + synchronized(lock) { + @Suppress("UNCHECKED_CAST") + val d0 = d?.original as D + assert(d0 === d) { + "Non-original descriptor in declaration: $d\n\tExpected: $d0" + } + val existing = get(sig) + val symbol = if (existing == null) { + val new = createSymbol() + set(new) + new + } else { + if (!existing.isBound) unboundSymbols.remove(existing) + existing + } + return if (symbol.isBound) symbol.owner else createOwner(symbol) + } + } + + inline fun referenced(d: D, orElse: () -> S): S { synchronized(lock) { @Suppress("UNCHECKED_CAST") @@ -482,6 +503,13 @@ class SymbolTable( override fun referenceClass(descriptor: ClassDescriptor) = classSymbolTable.referenced(descriptor) { createClassSymbol(descriptor) } + fun referenceClass( + sig: IdSignature, + symbolFactory: () -> IrClassSymbol, + classFactory: (IrClassSymbol) -> IrClass + ) = + classSymbolTable.referenced(sig) { declareClass(sig, symbolFactory, classFactory).symbol } + fun referenceClassIfAny(sig: IdSignature): IrClassSymbol? = classSymbolTable.get(sig)