diff --git a/compiler/ir/backend.common/src/org/jetbrains/kotlin/backend/common/lower/LocalDeclarationsLowering.kt b/compiler/ir/backend.common/src/org/jetbrains/kotlin/backend/common/lower/LocalDeclarationsLowering.kt index 665ec0e7495..b9e5d96f0aa 100644 --- a/compiler/ir/backend.common/src/org/jetbrains/kotlin/backend/common/lower/LocalDeclarationsLowering.kt +++ b/compiler/ir/backend.common/src/org/jetbrains/kotlin/backend/common/lower/LocalDeclarationsLowering.kt @@ -37,7 +37,6 @@ import org.jetbrains.kotlin.ir.visitors.acceptChildrenVoid import org.jetbrains.kotlin.ir.visitors.transformChildrenVoid import org.jetbrains.kotlin.name.Name import org.jetbrains.kotlin.name.NameUtils -import org.jetbrains.kotlin.resolve.descriptorUtil.parents import java.util.* interface LocalNameProvider { @@ -73,13 +72,9 @@ class LocalDeclarationsLowering( override fun lower(irDeclarationContainer: IrDeclarationContainer) { if (irDeclarationContainer is IrDeclaration) { + val parents = irDeclarationContainer.parents - // TODO: in case of `crossinline` lambda the @containingDeclaration and @parent points to completely different locations -// val parentsDecl = irDeclarationContainer.parents - val parentsDesc = irDeclarationContainer.descriptor.parents - - if (parentsDesc.any { it is CallableDescriptor }) { - + if (parents.any { it is IrFunction || it is IrField }) { // Lowering of non-local declarations handles all local declarations inside. // This declaration is local and shouldn't be considered. return @@ -180,9 +175,9 @@ class LocalDeclarationsLowering( val oldParameterToNew: MutableMap = mutableMapOf() val newParameterToCaptured: MutableMap = mutableMapOf() - fun lowerLocalDeclarations(): List? { + fun lowerLocalDeclarations(): List { collectLocalDeclarations() - if (localFunctions.isEmpty() && localClasses.isEmpty()) return null + if (localFunctions.isEmpty() && localClasses.isEmpty()) return listOf(memberDeclaration) collectClosures() @@ -778,4 +773,4 @@ class LocalDeclarationsLowering( } } -} +} \ No newline at end of file diff --git a/compiler/ir/backend.common/src/org/jetbrains/kotlin/backend/common/lower/LowerUtils.kt b/compiler/ir/backend.common/src/org/jetbrains/kotlin/backend/common/lower/LowerUtils.kt index 07ccf7f6285..6b95ff99227 100644 --- a/compiler/ir/backend.common/src/org/jetbrains/kotlin/backend/common/lower/LowerUtils.kt +++ b/compiler/ir/backend.common/src/org/jetbrains/kotlin/backend/common/lower/LowerUtils.kt @@ -208,9 +208,10 @@ fun IrConstructor.callsSuper(irBuiltIns: IrBuiltIns): Boolean { override fun visitDelegatingConstructorCall(expression: IrDelegatingConstructorCall) { assert(++numberOfCalls == 1) { "More than one delegating constructor call: ${symbol.owner}" } val delegatingClass = expression.symbol.owner.parent as IrClass - if (delegatingClass == superClass.classifierOrFail.owner) + // TODO: figure out why Lazy IR multiplies Declarations for descriptors and fix it + if (delegatingClass.descriptor == superClass.classifierOrFail.descriptor) callsSuper = true - else if (delegatingClass != constructedClass) + else if (delegatingClass.descriptor != constructedClass.descriptor) throw AssertionError( "Expected either call to another constructor of the class being constructed or" + " call to super class constructor. But was: $delegatingClass" diff --git a/compiler/ir/backend.js/src/org/jetbrains/kotlin/ir/backend/js/compiler.kt b/compiler/ir/backend.js/src/org/jetbrains/kotlin/ir/backend/js/compiler.kt index 098795be062..a5b0b9212f5 100644 --- a/compiler/ir/backend.js/src/org/jetbrains/kotlin/ir/backend/js/compiler.kt +++ b/compiler/ir/backend.js/src/org/jetbrains/kotlin/ir/backend/js/compiler.kt @@ -12,6 +12,7 @@ import org.jetbrains.kotlin.config.languageVersionSettings import org.jetbrains.kotlin.descriptors.ModuleDescriptor import org.jetbrains.kotlin.descriptors.impl.ModuleDescriptorImpl import org.jetbrains.kotlin.ir.declarations.IrModuleFragment +import org.jetbrains.kotlin.ir.util.SymbolTable import org.jetbrains.kotlin.js.analyze.TopDownAnalyzerFacadeForJS import org.jetbrains.kotlin.name.FqName import org.jetbrains.kotlin.progress.ProgressIndicatorAndCompilationCanceledStatus @@ -29,16 +30,23 @@ fun compile( irDependencyModules: List = listOf() ): Result { val analysisResult = - TopDownAnalyzerFacadeForJS.analyzeFiles(files, project, configuration, dependencies.mapNotNull { it as? ModuleDescriptorImpl }, emptyList()) + TopDownAnalyzerFacadeForJS.analyzeFiles( + files, + project, + configuration, + dependencies.mapNotNull { it as? ModuleDescriptorImpl }, + emptyList() + ) ProgressIndicatorAndCompilationCanceledStatus.checkCanceled() TopDownAnalyzerFacadeForJS.checkForErrors(files, analysisResult.bindingContext) - val psi2IrTranslator = Psi2IrTranslator(configuration.languageVersionSettings) - val psi2IrContext = psi2IrTranslator.createGeneratorContext(analysisResult.moduleDescriptor, analysisResult.bindingContext) + val symbolTable = SymbolTable() + irDependencyModules.forEach { symbolTable.loadModule(it)} - irDependencyModules.forEach { psi2IrContext.symbolTable.loadModule(it)} + val psi2IrTranslator = Psi2IrTranslator(configuration.languageVersionSettings) + val psi2IrContext = psi2IrTranslator.createGeneratorContext(analysisResult.moduleDescriptor, analysisResult.bindingContext, symbolTable) val moduleFragment = psi2IrTranslator.generateModuleFragment(psi2IrContext, files) diff --git a/compiler/ir/backend.js/src/org/jetbrains/kotlin/ir/backend/js/lower/ClassReferenceLowering.kt b/compiler/ir/backend.js/src/org/jetbrains/kotlin/ir/backend/js/lower/ClassReferenceLowering.kt index 943c4905357..b74badeee68 100644 --- a/compiler/ir/backend.js/src/org/jetbrains/kotlin/ir/backend/js/lower/ClassReferenceLowering.kt +++ b/compiler/ir/backend.js/src/org/jetbrains/kotlin/ir/backend/js/lower/ClassReferenceLowering.kt @@ -68,7 +68,7 @@ class ClassReferenceLowering(val context: JsIrBackendContext) : FileLoweringPass override fun visitClassReference(expression: IrClassReference) = callGetKClass( returnType = expression.type, - typeArgument = expression.classType + typeArgument = expression.classType.makeNotNull() ) }) } diff --git a/compiler/ir/backend.js/src/org/jetbrains/kotlin/ir/backend/js/lower/inline/DeepCopyIrTreeWithDescriptors.kt b/compiler/ir/backend.js/src/org/jetbrains/kotlin/ir/backend/js/lower/inline/DeepCopyIrTreeWithDescriptors.kt index 3e6ca98bd77..16c8c0f1db3 100644 --- a/compiler/ir/backend.js/src/org/jetbrains/kotlin/ir/backend/js/lower/inline/DeepCopyIrTreeWithDescriptors.kt +++ b/compiler/ir/backend.js/src/org/jetbrains/kotlin/ir/backend/js/lower/inline/DeepCopyIrTreeWithDescriptors.kt @@ -5,57 +5,255 @@ package org.jetbrains.kotlin.ir.backend.js.lower.inline -import org.jetbrains.kotlin.backend.common.IrElementTransformerVoidWithContext +import org.jetbrains.kotlin.backend.common.* import org.jetbrains.kotlin.backend.common.IrElementVisitorVoidWithContext +import org.jetbrains.kotlin.backend.common.descriptors.* import org.jetbrains.kotlin.backend.common.lower.SimpleMemberScope import org.jetbrains.kotlin.descriptors.* +import org.jetbrains.kotlin.descriptors.annotations.Annotations import org.jetbrains.kotlin.descriptors.impl.* import org.jetbrains.kotlin.ir.IrElement import org.jetbrains.kotlin.ir.backend.js.JsIrBackendContext import org.jetbrains.kotlin.ir.declarations.* -import org.jetbrains.kotlin.ir.declarations.impl.IrFunctionImpl -import org.jetbrains.kotlin.ir.declarations.impl.IrVariableImpl +import org.jetbrains.kotlin.ir.declarations.impl.* import org.jetbrains.kotlin.ir.descriptors.IrTemporaryVariableDescriptorImpl import org.jetbrains.kotlin.ir.expressions.* import org.jetbrains.kotlin.ir.expressions.impl.* -import org.jetbrains.kotlin.ir.symbols.impl.createClassSymbolOrNull -import org.jetbrains.kotlin.ir.symbols.impl.createFunctionSymbol -import org.jetbrains.kotlin.ir.symbols.impl.createValueSymbol +import org.jetbrains.kotlin.ir.symbols.* +import org.jetbrains.kotlin.ir.symbols.impl.* import org.jetbrains.kotlin.ir.types.* -import org.jetbrains.kotlin.ir.util.DeepCopyIrTree -import org.jetbrains.kotlin.ir.util.withScope -import org.jetbrains.kotlin.ir.visitors.IrElementVisitorVoid -import org.jetbrains.kotlin.ir.visitors.acceptChildrenVoid -import org.jetbrains.kotlin.ir.visitors.transformChildrenVoid +import org.jetbrains.kotlin.ir.types.impl.IrSimpleTypeImpl +import org.jetbrains.kotlin.ir.types.impl.IrStarProjectionImpl +import org.jetbrains.kotlin.ir.types.impl.makeTypeProjection +import org.jetbrains.kotlin.ir.util.* +import org.jetbrains.kotlin.ir.visitors.* import org.jetbrains.kotlin.name.Name +import org.jetbrains.kotlin.resolve.DescriptorFactory import org.jetbrains.kotlin.resolve.DescriptorUtils import org.jetbrains.kotlin.resolve.descriptorUtil.getSuperClassOrAny import org.jetbrains.kotlin.resolve.descriptorUtil.getSuperInterfaces -import org.jetbrains.kotlin.resolve.scopes.receivers.ExtensionReceiver import org.jetbrains.kotlin.storage.LockBasedStorageManager -import org.jetbrains.kotlin.types.KotlinType -import org.jetbrains.kotlin.types.TypeSubstitutor -import org.jetbrains.kotlin.types.TypeUtils -import org.jetbrains.kotlin.types.Variance +import org.jetbrains.kotlin.types.* +import org.jetbrains.kotlin.types.typeUtil.immediateSupertypes +internal fun KotlinType?.createExtensionReceiver(owner: CallableDescriptor): ReceiverParameterDescriptor? = + DescriptorFactory.createExtensionReceiverParameterForCallable( + owner, + this, + Annotations.EMPTY + ) + +fun ReferenceSymbolTable.translateErased(type: KotlinType): IrSimpleType { + val descriptor = TypeUtils.getClassDescriptor(type) ?: return translateErased(type.immediateSupertypes().first()) + val classSymbol = this.referenceClass(descriptor) + + val nullable = type.isMarkedNullable + val arguments = type.arguments.map { IrStarProjectionImpl } + + return classSymbol.createType(nullable, arguments) +} + +internal class DeepCopyIrTreeWithSymbolsForInliner(val context: Context, + val typeArguments: Map?, + val parent: IrDeclarationParent?) : IrCopierForInliner { + + override fun copy(irElement: IrElement): IrElement { + // Create new symbols. + irElement.acceptVoid(symbolRemapper) + + // Make symbol remapper aware of the callsite's type arguments. + symbolRemapper.typeArguments = typeArguments + + // Copy IR. + val result = irElement.transform(copier, data = null) + + // Bind newly created IR with wrapped descriptors. + result.acceptVoid(object: IrElementVisitorVoid { + override fun visitElement(element: IrElement) { + element.acceptChildrenVoid(this) + } + + override fun visitClass(declaration: IrClass) { + (declaration.descriptor as WrappedClassDescriptor).bind(declaration) + declaration.acceptChildrenVoid(this) + } + + override fun visitConstructor(declaration: IrConstructor) { + (declaration.descriptor as WrappedClassConstructorDescriptor).bind(declaration) + declaration.acceptChildrenVoid(this) + } + + override fun visitEnumEntry(declaration: IrEnumEntry) { + (declaration.descriptor as WrappedClassDescriptor).bind( + declaration.correspondingClass ?: declaration.parentAsClass) + declaration.acceptChildrenVoid(this) + } + + override fun visitField(declaration: IrField) { + (declaration.descriptor as WrappedPropertyDescriptor).bind(declaration) + declaration.acceptChildrenVoid(this) + } + + override fun visitFunction(declaration: IrFunction) { + (declaration.descriptor as WrappedSimpleFunctionDescriptor).bind(declaration as IrSimpleFunction) + declaration.acceptChildrenVoid(this) + } + + override fun visitValueParameter(declaration: IrValueParameter) { + (declaration.descriptor as? WrappedValueParameterDescriptor)?.bind(declaration) + (declaration.descriptor as? WrappedReceiverParameterDescriptor)?.bind(declaration) + declaration.acceptChildrenVoid(this) + } + + override fun visitTypeParameter(declaration: IrTypeParameter) { + (declaration.descriptor as WrappedTypeParameterDescriptor).bind(declaration) + declaration.acceptChildrenVoid(this) + } + + override fun visitVariable(declaration: IrVariable) { + (declaration.descriptor as WrappedVariableDescriptor).bind(declaration) + declaration.acceptChildrenVoid(this) + } + }) + + result.patchDeclarationParents(parent) + return result + } + + private var nameIndex = 0 + + private fun generateCopyName(name: Name) = Name.identifier(name.toString() + "_" + (nameIndex++).toString()) + + private inner class InlinerSymbolRenamer : SymbolRenamer { + private val map = mutableMapOf() + + override fun getClassName(symbol: IrClassSymbol) = map.getOrPut(symbol) { generateCopyName(symbol.owner.name) } + override fun getFunctionName(symbol: IrSimpleFunctionSymbol) = map.getOrPut(symbol) { generateCopyName(symbol.owner.name) } + override fun getFieldName(symbol: IrFieldSymbol) = symbol.owner.name + override fun getFileName(symbol: IrFileSymbol) = symbol.owner.fqName + override fun getExternalPackageFragmentName(symbol: IrExternalPackageFragmentSymbol) = symbol.owner.fqName + override fun getEnumEntryName(symbol: IrEnumEntrySymbol) = symbol.owner.name + override fun getVariableName(symbol: IrVariableSymbol) = map.getOrPut(symbol) { generateCopyName(symbol.owner.name) } + override fun getTypeParameterName(symbol: IrTypeParameterSymbol) = symbol.owner.name + override fun getValueParameterName(symbol: IrValueParameterSymbol) = symbol.owner.name + } + + private inner class DescriptorsToIrRemapper : DescriptorsRemapper { + override fun remapDeclaredClass(descriptor: ClassDescriptor) = + WrappedClassDescriptor(descriptor.annotations, descriptor.source) + + override fun remapDeclaredConstructor(descriptor: ClassConstructorDescriptor) = + WrappedClassConstructorDescriptor(descriptor.annotations, descriptor.source) + + override fun remapDeclaredEnumEntry(descriptor: ClassDescriptor) = + WrappedClassDescriptor(descriptor.annotations, descriptor.source) + + override fun remapDeclaredField(descriptor: PropertyDescriptor) = + WrappedPropertyDescriptor(descriptor.annotations, descriptor.source) + + override fun remapDeclaredSimpleFunction(descriptor: FunctionDescriptor) = + WrappedSimpleFunctionDescriptor(descriptor.annotations, descriptor.source) + + override fun remapDeclaredTypeParameter(descriptor: TypeParameterDescriptor) = + WrappedTypeParameterDescriptor(descriptor.annotations, descriptor.source) + + override fun remapDeclaredVariable(descriptor: VariableDescriptor) = + WrappedVariableDescriptor(descriptor.annotations, descriptor.source) + + override fun remapDeclaredValueParameter(descriptor: ParameterDescriptor): ParameterDescriptor = + if (descriptor is ReceiverParameterDescriptor) + WrappedReceiverParameterDescriptor(descriptor.annotations, descriptor.source) + else + WrappedValueParameterDescriptor(descriptor.annotations, descriptor.source) + } + + private inner class InlinerTypeRemapper(val symbolRemapper: SymbolRemapper, + val typeArguments: Map?) : TypeRemapper { + + override fun enterScope(irTypeParametersContainer: IrTypeParametersContainer) { } + + override fun leaveScope() { } + + private fun remapTypeArguments(arguments: List) = + arguments.map { argument -> + (argument as? IrTypeProjection)?.let { makeTypeProjection(remapType(it.type), it.variance) } + ?: argument + } + + override fun remapType(type: IrType): IrType { + if (type !is IrSimpleType) return type + + val substitutedType = typeArguments?.get(type.classifier) + if (substitutedType != null) { + substitutedType as IrSimpleType + return IrSimpleTypeImpl( + kotlinType = null, + classifier = substitutedType.classifier, + hasQuestionMark = type.hasQuestionMark or substitutedType.isMarkedNullable(), + arguments = substitutedType.arguments, + annotations = substitutedType.annotations + ) + } + + return IrSimpleTypeImpl( + kotlinType = null, + classifier = symbolRemapper.getReferencedClassifier(type.classifier), + hasQuestionMark = type.hasQuestionMark, + arguments = remapTypeArguments(type.arguments), + annotations = type.annotations.map { it.transform(copier, null) as IrCall } + ) + } + } + + override fun addCurrentSubstituteMap(globalSubstituteMap: MutableMap) { } + + private class SymbolRemapperImpl(descriptorsRemapper: DescriptorsRemapper) + : DeepCopySymbolRemapper(descriptorsRemapper) { + + var typeArguments: Map? = null + set(value) { + if (field != null) return + field = value?.asSequence()?.associate { + (getReferencedClassifier(it.key) as IrTypeParameterSymbol) to it.value + } + } + + override fun getReferencedClassifier(symbol: IrClassifierSymbol): IrClassifierSymbol { + val result = super.getReferencedClassifier(symbol) + if (result !is IrTypeParameterSymbol) + return result + return typeArguments?.get(result)?.classifierOrNull ?: result + } + } + + private val symbolRemapper = SymbolRemapperImpl(DescriptorsToIrRemapper()) + private val copier = DeepCopyIrTreeWithSymbols( + symbolRemapper, + InlinerTypeRemapper(symbolRemapper, typeArguments), + InlinerSymbolRenamer() + ) +} + +internal interface IrCopierForInliner { + fun copy(irElement: IrElement): IrElement + fun addCurrentSubstituteMap(globalSubstituteMap: MutableMap) +} -// backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/lower/DeepCopyIrTreeWithDescriptors.kt internal class DeepCopyIrTreeWithDescriptors(val targetDescriptor: FunctionDescriptor, val parentDescriptor: DeclarationDescriptor, - val context: JsIrBackendContext) { + val context: JsIrBackendContext, + val typeSubstitutor: TypeSubstitutor?) : IrCopierForInliner { private val descriptorSubstituteMap: MutableMap = mutableMapOf() - private var typeSubstitutor: TypeSubstitutor? = null private var nameIndex = 0 //-------------------------------------------------------------------------// - fun copy(irElement: IrElement, typeSubstitutor: TypeSubstitutor?): IrElement { - this.typeSubstitutor = typeSubstitutor + override fun copy(irElement: IrElement): IrElement { // Create all class descriptors and all necessary descriptors in order to create KotlinTypes. - irElement.acceptChildrenVoid(DescriptorCollectorCreatePhase()) + irElement.acceptVoid(DescriptorCollectorCreatePhase()) // Initialize all created descriptors possibly using previously created types. - irElement.acceptChildrenVoid(DescriptorCollectorInitPhase()) + irElement.acceptVoid(DescriptorCollectorInitPhase()) return irElement.accept(InlineCopyIr(), null) } @@ -83,12 +281,12 @@ internal class DeepCopyIrTreeWithDescriptors(val targetDescriptor: FunctionDescr val primaryConstructor = oldPrimaryConstructor?.let { descriptorSubstituteMap[it] as ClassConstructorDescriptor } val contributedDescriptors = oldDescriptor.unsubstitutedMemberScope - .getContributedDescriptors() - .map { descriptorSubstituteMap[it]!! } + .getContributedDescriptors() + .map { descriptorSubstituteMap[it]!! } newDescriptor.initialize( - SimpleMemberScope(contributedDescriptors), - constructors, - primaryConstructor + SimpleMemberScope(contributedDescriptors), + constructors, + primaryConstructor ) } @@ -115,10 +313,10 @@ internal class DeepCopyIrTreeWithDescriptors(val targetDescriptor: FunctionDescr val oldDescriptor = declaration.descriptor if (oldDescriptor !is PropertyAccessorDescriptor) { // Property accessors are copied along with their property. val oldContainingDeclaration = - if (oldDescriptor.visibility == Visibilities.LOCAL) - parentDescriptor - else - oldDescriptor.containingDeclaration + if (oldDescriptor.visibility == Visibilities.LOCAL) + parentDescriptor + else + oldDescriptor.containingDeclaration descriptorSubstituteMap[oldDescriptor] = copyFunctionDescriptor(oldDescriptor, oldContainingDeclaration) } super.visitFunctionNew(declaration) @@ -129,28 +327,28 @@ internal class DeepCopyIrTreeWithDescriptors(val targetDescriptor: FunctionDescr private fun generateCopyName(name: Name): Name { val declarationName = name.toString() // Name of declaration val indexStr = (nameIndex++).toString() // Unique for inline target index - return Name.identifier(declarationName /*+ "_" + indexStr*/) + return Name.identifier(declarationName + "_" + indexStr) } //---------------------------------------------------------------------// private fun copyFunctionDescriptor(oldDescriptor: CallableDescriptor, oldContainingDeclaration: DeclarationDescriptor) = - when (oldDescriptor) { - is ConstructorDescriptor -> copyConstructorDescriptor(oldDescriptor) - is SimpleFunctionDescriptor -> copySimpleFunctionDescriptor(oldDescriptor, oldContainingDeclaration) - else -> TODO("Unsupported FunctionDescriptor subtype: $oldDescriptor") - } + when (oldDescriptor) { + is ConstructorDescriptor -> copyConstructorDescriptor(oldDescriptor) + is SimpleFunctionDescriptor -> copySimpleFunctionDescriptor(oldDescriptor, oldContainingDeclaration) + else -> TODO("Unsupported FunctionDescriptor subtype: $oldDescriptor") + } //---------------------------------------------------------------------// private fun copySimpleFunctionDescriptor(oldDescriptor: SimpleFunctionDescriptor, oldContainingDeclaration: DeclarationDescriptor) : FunctionDescriptor { val newContainingDeclaration = descriptorSubstituteMap.getOrDefault(oldContainingDeclaration, oldContainingDeclaration) return SimpleFunctionDescriptorImpl.create( - /* containingDeclaration = */ newContainingDeclaration, - /* annotations = */ oldDescriptor.annotations, - /* name = */ generateCopyName(oldDescriptor.name), - /* kind = */ oldDescriptor.kind, - /* source = */ oldDescriptor.source + /* containingDeclaration = */ newContainingDeclaration, + /* annotations = */ oldDescriptor.annotations, + /* name = */ generateCopyName(oldDescriptor.name), + /* kind = */ oldDescriptor.kind, + /* source = */ oldDescriptor.source ) } @@ -160,10 +358,10 @@ internal class DeepCopyIrTreeWithDescriptors(val targetDescriptor: FunctionDescr val oldContainingDeclaration = oldDescriptor.containingDeclaration val newContainingDeclaration = descriptorSubstituteMap.getOrDefault(oldContainingDeclaration, oldContainingDeclaration) return ClassConstructorDescriptorImpl.create( - /* containingDeclaration = */ newContainingDeclaration as ClassDescriptor, - /* annotations = */ oldDescriptor.annotations, - /* isPrimary = */ oldDescriptor.isPrimary, - /* source = */ oldDescriptor.source + /* containingDeclaration = */ newContainingDeclaration as ClassDescriptor, + /* annotations = */ oldDescriptor.annotations, + /* isPrimary = */ oldDescriptor.isPrimary, + /* source = */ oldDescriptor.source ) } @@ -174,20 +372,20 @@ internal class DeepCopyIrTreeWithDescriptors(val targetDescriptor: FunctionDescr val newContainingDeclaration = descriptorSubstituteMap.getOrDefault(oldContainingDeclaration, oldContainingDeclaration) as ClassDescriptor @Suppress("DEPRECATION") val newDescriptor = PropertyDescriptorImpl.create( - /* containingDeclaration = */ newContainingDeclaration, - /* annotations = */ oldDescriptor.annotations, - /* modality = */ oldDescriptor.modality, - /* visibility = */ oldDescriptor.visibility, - /* isVar = */ oldDescriptor.isVar, - /* name = */ oldDescriptor.name, - /* kind = */ oldDescriptor.kind, - /* source = */ oldDescriptor.source, - /* lateInit = */ oldDescriptor.isLateInit, - /* isConst = */ oldDescriptor.isConst, - /* isExpect = */ oldDescriptor.isExpect, - /* isActual = */ oldDescriptor.isActual, - /* isExternal = */ oldDescriptor.isExternal, - /* isDelegated = */ oldDescriptor.isDelegated + /* containingDeclaration = */ newContainingDeclaration, + /* annotations = */ oldDescriptor.annotations, + /* modality = */ oldDescriptor.modality, + /* visibility = */ oldDescriptor.visibility, + /* isVar = */ oldDescriptor.isVar, + /* name = */ oldDescriptor.name, + /* kind = */ oldDescriptor.kind, + /* source = */ oldDescriptor.source, + /* lateInit = */ oldDescriptor.isLateInit, + /* isConst = */ oldDescriptor.isConst, + /* isExpect = */ oldDescriptor.isExpect, + /* isActual = */ oldDescriptor.isActual, + /* isExternal = */ oldDescriptor.isExternal, + /* isDelegated = */ oldDescriptor.isDelegated ) descriptorSubstituteMap[oldDescriptor] = newDescriptor } @@ -202,23 +400,27 @@ internal class DeepCopyIrTreeWithDescriptors(val targetDescriptor: FunctionDescr val oldContainingDeclaration = oldDescriptor.containingDeclaration val newContainingDeclaration = descriptorSubstituteMap.getOrDefault(oldContainingDeclaration, oldContainingDeclaration) val newName = if (DescriptorUtils.isAnonymousObject(oldDescriptor)) // Anonymous objects are identified by their name. - oldDescriptor.name // We need to preserve it for LocalDeclarationsLowering. - else - generateCopyName(oldDescriptor.name) + oldDescriptor.name // We need to preserve it for LocalDeclarationsLowering. + else + generateCopyName(oldDescriptor.name) val visibility = oldDescriptor.visibility return object : ClassDescriptorImpl( - /* containingDeclaration = */ newContainingDeclaration, - /* name = */ newName, - /* modality = */ oldDescriptor.modality, - /* kind = */ oldDescriptor.kind, - /* supertypes = */ listOf(newSuperClass.defaultType) + newInterfaces.map { it.defaultType }, - /* source = */ oldDescriptor.source, - /* isExternal = */ oldDescriptor.isExternal, - LockBasedStorageManager.NO_LOCKS + /* containingDeclaration = */ newContainingDeclaration, + /* name = */ newName, + /* modality = */ oldDescriptor.modality, + /* kind = */ oldDescriptor.kind, + /* supertypes = */ listOf(newSuperClass.defaultType) + newInterfaces.map { it.defaultType }, + /* source = */ oldDescriptor.source, + /* isExternal = */ oldDescriptor.isExternal, + /* storageManager = */ LockBasedStorageManager.NO_LOCKS ) { override fun getVisibility() = visibility + + override fun getDeclaredTypeParameters(): List { + return oldDescriptor.declaredTypeParameters + } } } } @@ -284,7 +486,7 @@ internal class DeepCopyIrTreeWithDescriptors(val targetDescriptor: FunctionDescr private fun generateCopyName(name: Name): Name { val declarationName = name.toString() // Name of declaration val indexStr = (nameIndex++).toString() // Unique for inline target index - return Name.identifier(declarationName /*+ "_" + indexStr*/) + return Name.identifier(declarationName + "_" + indexStr) } //---------------------------------------------------------------------// @@ -293,83 +495,80 @@ internal class DeepCopyIrTreeWithDescriptors(val targetDescriptor: FunctionDescr val oldContainingDeclaration = oldDescriptor.containingDeclaration val newContainingDeclaration = descriptorSubstituteMap.getOrDefault(oldContainingDeclaration, oldContainingDeclaration) return IrTemporaryVariableDescriptorImpl( - containingDeclaration = newContainingDeclaration, - name = generateCopyName(oldDescriptor.name), - outType = substituteTypeAndTryGetCopied(oldDescriptor.type)!!, - isMutable = oldDescriptor.isVar + containingDeclaration = newContainingDeclaration, + name = generateCopyName(oldDescriptor.name), + outType = substituteType(oldDescriptor.type)!!, + isMutable = oldDescriptor.isVar ) } //---------------------------------------------------------------------// private fun initFunctionDescriptor(oldDescriptor: CallableDescriptor): CallableDescriptor = - when (oldDescriptor) { - is ConstructorDescriptor -> initConstructorDescriptor(oldDescriptor) - is SimpleFunctionDescriptor -> initSimpleFunctionDescriptor(oldDescriptor) - else -> TODO("Unsupported FunctionDescriptor subtype: $oldDescriptor") - } + when (oldDescriptor) { + is ConstructorDescriptor -> initConstructorDescriptor(oldDescriptor) + is SimpleFunctionDescriptor -> initSimpleFunctionDescriptor(oldDescriptor) + else -> TODO("Unsupported FunctionDescriptor subtype: $oldDescriptor") + } //---------------------------------------------------------------------// private fun initSimpleFunctionDescriptor(oldDescriptor: SimpleFunctionDescriptor): FunctionDescriptor = - (descriptorSubstituteMap[oldDescriptor] as SimpleFunctionDescriptorImpl).apply { - val oldDispatchReceiverParameter = oldDescriptor.dispatchReceiverParameter - val newDispatchReceiverParameter = oldDispatchReceiverParameter?.let { descriptorSubstituteMap.getOrDefault(it, it) as ReceiverParameterDescriptor } - val newTypeParameters = oldDescriptor.typeParameters // TODO substitute types - val newValueParameters = copyValueParameters(oldDescriptor.valueParameters, this) - val newReceiverParameter = copyReceiverParameter(oldDescriptor.extensionReceiverParameter, this) - val newReturnType = substituteTypeAndTryGetCopied(oldDescriptor.returnType) + (descriptorSubstituteMap[oldDescriptor] as SimpleFunctionDescriptorImpl).apply { + val oldDispatchReceiverParameter = oldDescriptor.dispatchReceiverParameter + val newDispatchReceiverParameter = oldDispatchReceiverParameter?.let { descriptorSubstituteMap.getOrDefault(it, it) as ReceiverParameterDescriptor } + val newTypeParameters = oldDescriptor.typeParameters // TODO substitute types + val newValueParameters = copyValueParameters(oldDescriptor.valueParameters, this) + val newReceiverParameterType = substituteType(oldDescriptor.extensionReceiverParameter?.type) + val newReturnType = substituteType(oldDescriptor.returnType) - initialize( - /* extensionReceiverParameter = */ newReceiverParameter, - /* dispatchReceiverParameter = */ newDispatchReceiverParameter, - /* typeParameters = */ newTypeParameters, - /* unsubstitutedValueParameters = */ newValueParameters, - /* unsubstitutedReturnType = */ newReturnType, - /* modality = */ oldDescriptor.modality, - /* visibility = */ oldDescriptor.visibility - ) - isTailrec = oldDescriptor.isTailrec - isSuspend = oldDescriptor.isSuspend - overriddenDescriptors += oldDescriptor.overriddenDescriptors - } + initialize( + /* receiverParameterType = */ newReceiverParameterType.createExtensionReceiver(this), + /* dispatchReceiverParameter = */ newDispatchReceiverParameter, + /* typeParameters = */ newTypeParameters, + /* unsubstitutedValueParameters = */ newValueParameters, + /* unsubstitutedReturnType = */ newReturnType, + /* modality = */ oldDescriptor.modality, + /* visibility = */ oldDescriptor.visibility + ) + isTailrec = oldDescriptor.isTailrec + isSuspend = oldDescriptor.isSuspend + overriddenDescriptors += oldDescriptor.overriddenDescriptors + } //---------------------------------------------------------------------// private fun initConstructorDescriptor(oldDescriptor: ConstructorDescriptor): FunctionDescriptor = - (descriptorSubstituteMap[oldDescriptor] as ClassConstructorDescriptorImpl).apply { - val newTypeParameters = oldDescriptor.typeParameters - val newValueParameters = copyValueParameters(oldDescriptor.valueParameters, this) - val newReceiverParameter = copyReceiverParameter(oldDescriptor.dispatchReceiverParameter, this) - val returnType = substituteTypeAndTryGetCopied(oldDescriptor.returnType) + (descriptorSubstituteMap[oldDescriptor] as ClassConstructorDescriptorImpl).apply { + val newTypeParameters = oldDescriptor.typeParameters + val newValueParameters = copyValueParameters(oldDescriptor.valueParameters, this) + val receiverParameterType = substituteType(oldDescriptor.dispatchReceiverParameter?.type) + val returnType = substituteType(oldDescriptor.returnType) - initialize( - /* extensionReceiverParameter = */ newReceiverParameter, - /* dispatchReceiverParameter = */ null, // For constructor there is no explicit dispatch receiver. - /* typeParameters = */ newTypeParameters, - /* unsubstitutedValueParameters = */ newValueParameters, - /* unsubstitutedReturnType = */ returnType, - /* modality = */ oldDescriptor.modality, - /* visibility = */ oldDescriptor.visibility - ) - } + initialize( + /* receiverParameterType = */ receiverParameterType.createExtensionReceiver(this), + /* dispatchReceiverParameter = */ null, // For constructor there is no explicit dispatch receiver. + /* typeParameters = */ newTypeParameters, + /* unsubstitutedValueParameters = */ newValueParameters, + /* unsubstitutedReturnType = */ returnType, + /* modality = */ oldDescriptor.modality, + /* visibility = */ oldDescriptor.visibility + ) + } //---------------------------------------------------------------------// private fun initPropertyOrField(oldDescriptor: PropertyDescriptor) { val newDescriptor = (descriptorSubstituteMap[oldDescriptor] as PropertyDescriptorImpl).apply { setType( - /* outType = */ substituteTypeAndTryGetCopied(oldDescriptor.type)!!, - /* typeParameters = */ oldDescriptor.typeParameters, - /* dispatchReceiverParameter = */ (containingDeclaration as ClassDescriptor).thisAsReceiverParameter, - /* extensionReceiverParameter= */ copyReceiverParameter(oldDescriptor.extensionReceiverParameter, this) - ) + /* outType = */ substituteType(oldDescriptor.type)!!, + /* typeParameters = */ oldDescriptor.typeParameters, + /* dispatchReceiverParameter = */ (containingDeclaration as ClassDescriptor).thisAsReceiverParameter, + /* extensionReceiverParamter = */ substituteType(oldDescriptor.extensionReceiverParameter?.type).createExtensionReceiver(this)) initialize( - /* getter = */ oldDescriptor.getter?.let { copyPropertyGetterDescriptor(it, this) }, - /* setter = */ oldDescriptor.setter?.let { copyPropertySetterDescriptor(it, this) }, - oldDescriptor.backingField, oldDescriptor.delegateField - ) + /* getter = */ oldDescriptor.getter?.let { copyPropertyGetterDescriptor(it, this) }, + /* setter = */ oldDescriptor.setter?.let { copyPropertySetterDescriptor(it, this) }) overriddenDescriptors += oldDescriptor.overriddenDescriptors } @@ -384,75 +583,58 @@ internal class DeepCopyIrTreeWithDescriptors(val targetDescriptor: FunctionDescr //---------------------------------------------------------------------// private fun copyPropertyGetterDescriptor(oldDescriptor: PropertyGetterDescriptor, newPropertyDescriptor: PropertyDescriptor) = - PropertyGetterDescriptorImpl( - /* correspondingProperty = */ newPropertyDescriptor, - /* annotations = */ oldDescriptor.annotations, - /* modality = */ oldDescriptor.modality, - /* visibility = */ oldDescriptor.visibility, - /* isDefault = */ oldDescriptor.isDefault, - /* isExternal = */ oldDescriptor.isExternal, - /* isInline = */ oldDescriptor.isInline, - /* kind = */ oldDescriptor.kind, - /* original = */ null, - /* source = */ oldDescriptor.source).apply { - initialize(substituteTypeAndTryGetCopied(oldDescriptor.returnType)) - } + PropertyGetterDescriptorImpl( + /* correspondingProperty = */ newPropertyDescriptor, + /* annotations = */ oldDescriptor.annotations, + /* modality = */ oldDescriptor.modality, + /* visibility = */ oldDescriptor.visibility, + /* isDefault = */ oldDescriptor.isDefault, + /* isExternal = */ oldDescriptor.isExternal, + /* isInline = */ oldDescriptor.isInline, + /* kind = */ oldDescriptor.kind, + /* original = */ null, + /* source = */ oldDescriptor.source).apply { + initialize(substituteType(oldDescriptor.returnType)) + } //---------------------------------------------------------------------// private fun copyPropertySetterDescriptor(oldDescriptor: PropertySetterDescriptor, newPropertyDescriptor: PropertyDescriptor) = - PropertySetterDescriptorImpl( - /* correspondingProperty = */ newPropertyDescriptor, - /* annotations = */ oldDescriptor.annotations, - /* modality = */ oldDescriptor.modality, - /* visibility = */ oldDescriptor.visibility, - /* isDefault = */ oldDescriptor.isDefault, - /* isExternal = */ oldDescriptor.isExternal, - /* isInline = */ oldDescriptor.isInline, - /* kind = */ oldDescriptor.kind, - /* original = */ null, - /* source = */ oldDescriptor.source).apply { - initialize(copyValueParameters(oldDescriptor.valueParameters, this).single()) - } + PropertySetterDescriptorImpl( + /* correspondingProperty = */ newPropertyDescriptor, + /* annotations = */ oldDescriptor.annotations, + /* modality = */ oldDescriptor.modality, + /* visibility = */ oldDescriptor.visibility, + /* isDefault = */ oldDescriptor.isDefault, + /* isExternal = */ oldDescriptor.isExternal, + /* isInline = */ oldDescriptor.isInline, + /* kind = */ oldDescriptor.kind, + /* original = */ null, + /* source = */ oldDescriptor.source).apply { + initialize(copyValueParameters(oldDescriptor.valueParameters, this).single()) + } //-------------------------------------------------------------------------// private fun copyValueParameters(oldValueParameters: List , containingDeclaration: CallableDescriptor) = - oldValueParameters.map { oldDescriptor -> - val newDescriptor = ValueParameterDescriptorImpl( - containingDeclaration = containingDeclaration, - original = oldDescriptor.original, - index = oldDescriptor.index, - annotations = oldDescriptor.annotations, - name = oldDescriptor.name, - outType = substituteTypeAndTryGetCopied(oldDescriptor.type)!!, - declaresDefaultValue = oldDescriptor.declaresDefaultValue(), - isCrossinline = oldDescriptor.isCrossinline, - isNoinline = oldDescriptor.isNoinline, - varargElementType = substituteTypeAndTryGetCopied(oldDescriptor.varargElementType), - source = oldDescriptor.source - ) - descriptorSubstituteMap[oldDescriptor] = newDescriptor - newDescriptor - } + oldValueParameters.map { oldDescriptor -> + val newDescriptor = ValueParameterDescriptorImpl( + containingDeclaration = containingDeclaration, + original = oldDescriptor.original, + index = oldDescriptor.index, + annotations = oldDescriptor.annotations, + name = oldDescriptor.name, + outType = substituteType(oldDescriptor.type)!!, + declaresDefaultValue = oldDescriptor.declaresDefaultValue(), + isCrossinline = oldDescriptor.isCrossinline, + isNoinline = oldDescriptor.isNoinline, + varargElementType = substituteType(oldDescriptor.varargElementType), + source = oldDescriptor.source + ) + descriptorSubstituteMap[oldDescriptor] = newDescriptor + newDescriptor + } - private fun copyReceiverParameter( - oldReceiverParameter: ReceiverParameterDescriptor?, containingDeclaration: CallableDescriptor - ): ReceiverParameterDescriptor? { - if (oldReceiverParameter == null) return null - val substituteTypeAndTryGetCopied = substituteTypeAndTryGetCopied(oldReceiverParameter.type) ?: return null - return ReceiverParameterDescriptorImpl( - containingDeclaration, - ExtensionReceiver(containingDeclaration, substituteTypeAndTryGetCopied, oldReceiverParameter.value), - oldReceiverParameter.annotations - ) - } - - private fun substituteTypeAndTryGetCopied(type: KotlinType?): KotlinType? { - val substitutedType = substituteType(type) ?: return null - val oldClassDescriptor = TypeUtils.getClassDescriptor(substitutedType) ?: return substitutedType - return descriptorSubstituteMap[oldClassDescriptor]?.let { (it as ClassDescriptor).defaultType } ?: substitutedType - } } //-----------------------------------------------------------------------------// @@ -496,7 +678,7 @@ internal class DeepCopyIrTreeWithDescriptors(val targetDescriptor: FunctionDescr return IrCallImpl( startOffset = expression.startOffset, endOffset = expression.endOffset, - type = newDescriptor.returnType?.toIrType(context.symbolTable)!!, + type = context.symbolTable.translateErased(newDescriptor.returnType!!), descriptor = newDescriptor, typeArgumentsCount = expression.typeArgumentsCount, origin = expression.origin, @@ -507,6 +689,19 @@ internal class DeepCopyIrTreeWithDescriptors(val targetDescriptor: FunctionDescr } } + override fun visitField(declaration: IrField): IrField { + val descriptor = mapPropertyDeclaration(declaration.descriptor) + return IrFieldImpl( + declaration.startOffset, declaration.endOffset, + mapDeclarationOrigin(declaration.origin), + descriptor, + context.symbolTable.translateErased(descriptor.type), + declaration.initializer?.transform(this@InlineCopyIr, null) + ).apply { + transformAnnotations(declaration) + } + } + //---------------------------------------------------------------------// override fun visitFunction(declaration: IrFunction) = @@ -519,13 +714,106 @@ internal class DeepCopyIrTreeWithDescriptors(val targetDescriptor: FunctionDescr returnType = declaration.returnType, body = declaration.body?.transform(this@InlineCopyIr, null) ).also { + it.returnType = context.symbolTable.translateErased(descriptor.returnType!!) it.setOverrides(context.symbolTable) it.transformParameters(declaration) } } +// override fun visitSimpleFunction(declaration: IrSimpleFunction): IrFunction { +// val descriptor = mapFunctionDeclaration(declaration.descriptor) +// return IrFunctionImpl( +// startOffset = declaration.startOffset, +// endOffset = declaration.endOffset, +// origin = mapDeclarationOrigin(declaration.origin), +// descriptor = descriptor +// ).also { +// it.returnType = context.symbolTable.translateErased(descriptor.returnType!!) +// it.body = declaration.body?.transform(this, null) +// +// it.setOverrides(context.symbolTable) +// }.transformParameters1(declaration) +// } + +// override fun visitConstructor(declaration: IrConstructor): IrConstructor { +// val descriptor = mapConstructorDeclaration(declaration.descriptor) +// return IrConstructorImpl( +// startOffset = declaration.startOffset, +// endOffset = declaration.endOffset, +// origin = mapDeclarationOrigin(declaration.origin), +// descriptor = descriptor +// ).also { +// it.returnType = context.symbolTable.translateErased(descriptor.returnType) +// it.body = declaration.body?.transform(this, null) +// }.transformParameters1(declaration) +// } + + private fun FunctionDescriptor.getTypeParametersToTransform() = + when { + this is PropertyAccessorDescriptor -> correspondingProperty.typeParameters + else -> typeParameters + } + + protected fun T.transformParameters1(original: T): T = + apply { + transformTypeParameters(original, descriptor.getTypeParametersToTransform()) + transformValueParameters1(original) + } + + protected fun T.transformValueParameters1(original: T) = + apply { + dispatchReceiverParameter = + original.dispatchReceiverParameter?.replaceDescriptor1( + descriptor.dispatchReceiverParameter ?: throw AssertionError("No dispatch receiver in $descriptor") + ) + + extensionReceiverParameter = + original.extensionReceiverParameter?.replaceDescriptor1( + descriptor.extensionReceiverParameter ?: throw AssertionError("No extension receiver in $descriptor") + ) + + original.valueParameters.mapIndexedTo(valueParameters) { i, originalValueParameter -> + originalValueParameter.replaceDescriptor1(descriptor.valueParameters[i]) + } + } + + protected fun IrValueParameter.replaceDescriptor1(newDescriptor: ParameterDescriptor) = + IrValueParameterImpl( + startOffset, endOffset, + mapDeclarationOrigin(origin), + newDescriptor, + context.symbolTable.translateErased(newDescriptor.type), + (newDescriptor as? ValueParameterDescriptor)?.varargElementType?.let { context.symbolTable.translateErased(it) }, + defaultValue?.transform(this@InlineCopyIr, null) + ).apply { + transformAnnotations(this) + } + //---------------------------------------------------------------------// + override fun visitGetValue(expression: IrGetValue): IrGetValue { + val descriptor = mapValueReference(expression.descriptor) + return IrGetValueImpl( + expression.startOffset, expression.endOffset, + context.symbolTable.translateErased(descriptor.type), + descriptor, + mapStatementOrigin(expression.origin) + ) + } + + override fun visitVariable(declaration: IrVariable): IrVariable { + val descriptor = mapVariableDeclaration(declaration.descriptor) + return IrVariableImpl( + declaration.startOffset, declaration.endOffset, + mapDeclarationOrigin(declaration.origin), + descriptor, + context.symbolTable.translateErased(descriptor.type), + declaration.initializer?.transform(this, null) + ).apply { + transformAnnotations(declaration) + } + } + private fun T.transformDefaults(original: T): T { for (originalValueParameter in original.descriptor.valueParameters) { val valueParameter = descriptor.valueParameters[originalValueParameter.index] @@ -554,8 +842,9 @@ internal class DeepCopyIrTreeWithDescriptors(val targetDescriptor: FunctionDescr //---------------------------------------------------------------------// override fun visitTypeOperator(expression: IrTypeOperatorCall): IrTypeOperatorCall { - val typeOperand = substituteType(expression.typeOperand)!! - val returnType = getTypeOperatorReturnType(expression.operator, typeOperand) + val erasedTypeOperand = substituteAndEraseType(expression.typeOperand)!! + val typeOperand = substituteAndBreakType(expression.typeOperand) + val returnType = getTypeOperatorReturnType(expression.operator, erasedTypeOperand) return IrTypeOperatorCallImpl( startOffset = expression.startOffset, endOffset = expression.endOffset, @@ -563,7 +852,7 @@ internal class DeepCopyIrTreeWithDescriptors(val targetDescriptor: FunctionDescr operator = expression.operator, typeOperand = typeOperand, argument = expression.argument.transform(this, null), - typeOperandClassifier = typeOperand.classifierOrFail + typeOperandClassifier = (typeOperand as IrSimpleType).classifier ) } @@ -573,7 +862,7 @@ internal class DeepCopyIrTreeWithDescriptors(val targetDescriptor: FunctionDescr IrReturnImpl( startOffset = expression.startOffset, endOffset = expression.endOffset, - type = substituteType(expression.type)!!, + type = substituteAndEraseType(expression.type)!!, returnTargetDescriptor = mapReturnTarget(expression.returnTarget), value = expression.value.transform(this, null) ) @@ -592,14 +881,19 @@ internal class DeepCopyIrTreeWithDescriptors(val targetDescriptor: FunctionDescr sourceFileName = expression.sourceFileName ) } else { - super.visitBlock(expression) + IrBlockImpl( + expression.startOffset, expression.endOffset, + substituteAndEraseType(expression.type)!!, + mapStatementOrigin(expression.origin), + expression.statements.map { it.transform(this, null) } + ) } } //-------------------------------------------------------------------------// override fun visitClassReference(expression: IrClassReference): IrClassReference { - val newExpressionType = substituteType(expression.type)!! // Substituted expression type. + val newExpressionType = substituteAndEraseType(expression.type)!! // Substituted expression type. val newDescriptorType = substituteType(expression.descriptor.defaultType)!! // Substituted type of referenced class. val classDescriptor = newDescriptorType.constructor.declarationDescriptor!! // Get ClassifierDescriptor of the referenced class. return IrClassReferenceImpl( @@ -614,7 +908,7 @@ internal class DeepCopyIrTreeWithDescriptors(val targetDescriptor: FunctionDescr //-------------------------------------------------------------------------// override fun visitGetClass(expression: IrGetClass): IrGetClass { - val type = substituteType(expression.type)!! + val type = substituteAndEraseType(expression.type)!! return IrGetClassImpl( startOffset = expression.startOffset, endOffset = expression.endOffset, @@ -628,16 +922,77 @@ internal class DeepCopyIrTreeWithDescriptors(val targetDescriptor: FunctionDescr override fun getNonTransformedLoop(irLoop: IrLoop): IrLoop { return irLoop } + + override fun visitClass(declaration: IrClass): IrClass { + val descriptor = this.mapClassDeclaration(declaration.descriptor) + + return context.symbolTable.declareClass( + declaration.startOffset, declaration.endOffset, mapDeclarationOrigin(declaration.origin), + descriptor + ).apply { + declaration.declarations.mapTo(this.declarations) { + it.transform(this@InlineCopyIr, null) as IrDeclaration + } + this.transformAnnotations(declaration) + this.thisReceiver = declaration.thisReceiver?.replaceDescriptor1(this.descriptor.thisAsReceiverParameter) + + this.transformTypeParameters(declaration, this.descriptor.declaredTypeParameters) + + descriptor.defaultType.constructor.supertypes.mapTo(this.superTypes) { + context.symbolTable.translateErased(it) + } + } + } } //-------------------------------------------------------------------------// - private fun substituteType(oldType: IrType?): IrType? = substituteType(oldType?.toKotlinType())?.toIrType(context.symbolTable) + private fun substituteType(type: KotlinType?): KotlinType? { + val substitutedType = (type?.let { typeSubstitutor?.substitute(it, Variance.INVARIANT) } ?: type) + ?: return null + val oldClassDescriptor = TypeUtils.getClassDescriptor(substitutedType) ?: return substitutedType + return descriptorSubstituteMap[oldClassDescriptor]?.let { (it as ClassDescriptor).defaultType } ?: substitutedType + } - private fun substituteType(oldType: KotlinType?): KotlinType? { - if (typeSubstitutor == null) return oldType - if (oldType == null) return oldType - return typeSubstitutor!!.substitute(oldType, Variance.INVARIANT) ?: oldType + private fun substituteAndEraseType(oldType: IrType?): IrType? { + oldType ?: return null + + val substitutedKotlinType = substituteType(oldType.toKotlinType()) + ?: return oldType + return context.symbolTable.translateErased(substitutedKotlinType) + } + + fun translateBroken(type: KotlinType): IrType { + val declarationDescriptor = type.constructor.declarationDescriptor + return when (declarationDescriptor) { + is ClassDescriptor -> { + val classifier = context.symbolTable.referenceClassifier(declarationDescriptor) + val typeArguments = type.arguments.map { + if (it.isStarProjection) { + IrStarProjectionImpl + } else { + makeTypeProjection(translateBroken(it.type), it.projectionKind) + } + } + IrSimpleTypeImpl( + classifier, + type.isMarkedNullable, + typeArguments, + emptyList() + ) + } + is TypeParameterDescriptor -> IrSimpleTypeImpl( + context.symbolTable.referenceTypeParameter(declarationDescriptor), + type.isMarkedNullable, + emptyList(), + emptyList() + ) + else -> error(declarationDescriptor ?: "null") + } + } + + private fun substituteAndBreakType(oldType: IrType): IrType { + return translateBroken(substituteType(oldType.toKotlinType())!!) } //-------------------------------------------------------------------------// @@ -645,16 +1000,16 @@ internal class DeepCopyIrTreeWithDescriptors(val targetDescriptor: FunctionDescr private fun IrMemberAccessExpression.substituteTypeArguments(original: IrMemberAccessExpression) { for (index in 0 until original.typeArgumentsCount) { val originalTypeArgument = original.getTypeArgument(index) - val newTypeArgument = substituteType(originalTypeArgument)!! + val newTypeArgument = substituteAndBreakType(originalTypeArgument!!) this.putTypeArgument(index, newTypeArgument) } } //-------------------------------------------------------------------------// - fun addCurrentSubstituteMap(globalSubstituteMap: MutableMap) { + override fun addCurrentSubstituteMap(globalSubstituteMap: MutableMap) { descriptorSubstituteMap.forEach { t, u -> - globalSubstituteMap.put(t, SubstitutedDescriptor(targetDescriptor, u)) + globalSubstituteMap[t] = SubstitutedDescriptor(targetDescriptor, u) } } @@ -662,45 +1017,21 @@ internal class DeepCopyIrTreeWithDescriptors(val targetDescriptor: FunctionDescr class SubstitutedDescriptor(val inlinedFunction: FunctionDescriptor, val descriptor: DeclarationDescriptor) -class DescriptorSubstitutorForExternalScope(val globalSubstituteMap: MutableMap) +internal class DescriptorSubstitutorForExternalScope( + val globalSubstituteMap: Map, + val context: Context +) : IrElementTransformerVoidWithContext() { - private val variableSubstituteMap = mutableMapOf() - fun run(element: IrElement) { - collectVariables(element) element.transformChildrenVoid(this) } - private fun collectVariables(element: IrElement) { - element.acceptChildrenVoid(object: IrElementVisitorVoid { - override fun visitElement(element: IrElement) { - element.acceptChildrenVoid(this) - } - - override fun visitVariable(declaration: IrVariable) { - declaration.acceptChildrenVoid(this) - - val oldDescriptor = declaration.descriptor - val oldClassDescriptor = oldDescriptor.type.constructor.declarationDescriptor as? ClassDescriptor - val substitutedDescriptor = oldClassDescriptor?.let { globalSubstituteMap[it] } - if (substitutedDescriptor == null || allScopes.any { it.scope.scopeOwner == substitutedDescriptor.inlinedFunction }) - return - val newDescriptor = IrTemporaryVariableDescriptorImpl( - containingDeclaration = oldDescriptor.containingDeclaration, - name = oldDescriptor.name, - outType = (substitutedDescriptor.descriptor as ClassDescriptor).defaultType, - isMutable = oldDescriptor.isVar) - variableSubstituteMap[oldDescriptor] = newDescriptor - } - }) - } - override fun visitCall(expression: IrCall): IrExpression { val oldExpression = super.visitCall(expression) as IrCall val substitutedDescriptor = globalSubstituteMap[expression.descriptor.original] - ?: return oldExpression + ?: return oldExpression if (allScopes.any { it.scope.scopeOwner == substitutedDescriptor.inlinedFunction }) return oldExpression return when (oldExpression) { @@ -710,41 +1041,6 @@ class DescriptorSubstitutorForExternalScope(val globalSubstituteMap: MutableMap< } } - //---------------------------------------------------------------------// - - override fun visitVariable(declaration: IrVariable): IrDeclaration { - declaration.transformChildrenVoid(this) - - val oldDescriptor = declaration.descriptor - val newDescriptor = variableSubstituteMap[oldDescriptor] ?: return declaration - - return IrVariableImpl( - startOffset = declaration.startOffset, - endOffset = declaration.endOffset, - origin = declaration.origin, - descriptor = newDescriptor, - initializer = declaration.initializer, - type = declaration.type - ) - } - - //-------------------------------------------------------------------------// - - override fun visitGetValue(expression: IrGetValue): IrExpression { - expression.transformChildrenVoid(this) - - val oldDescriptor = expression.descriptor - val newDescriptor = variableSubstituteMap[oldDescriptor] ?: return expression - - return IrGetValueImpl( - startOffset = expression.startOffset, - endOffset = expression.endOffset, - origin = expression.origin, - symbol = createValueSymbol(newDescriptor), - type = expression.type - ) - } - //-------------------------------------------------------------------------// private fun copyIrCallImpl(oldExpression: IrCallImpl, substitutedDescriptor: SubstitutedDescriptor): IrCallImpl { @@ -758,7 +1054,7 @@ class DescriptorSubstitutorForExternalScope(val globalSubstituteMap: MutableMap< return IrCallImpl( startOffset = oldExpression.startOffset, endOffset = oldExpression.endOffset, - type = oldExpression.type, + type = context.symbolTable.translateErased(newDescriptor.returnType!!), symbol = createFunctionSymbol(newDescriptor), descriptor = newDescriptor, typeArgumentsCount = oldExpression.typeArgumentsCount, @@ -788,4 +1084,4 @@ class DescriptorSubstitutorForExternalScope(val globalSubstituteMap: MutableMap< return oldExpression.shallowCopy(oldExpression.origin, createFunctionSymbol(newDescriptor), oldExpression.superQualifierSymbol) } -} +} \ No newline at end of file diff --git a/compiler/ir/backend.js/src/org/jetbrains/kotlin/ir/backend/js/lower/inline/FunctionInlining.kt b/compiler/ir/backend.js/src/org/jetbrains/kotlin/ir/backend/js/lower/inline/FunctionInlining.kt index 7fce85266bc..1dab156148f 100644 --- a/compiler/ir/backend.js/src/org/jetbrains/kotlin/ir/backend/js/lower/inline/FunctionInlining.kt +++ b/compiler/ir/backend.js/src/org/jetbrains/kotlin/ir/backend/js/lower/inline/FunctionInlining.kt @@ -7,30 +7,31 @@ package org.jetbrains.kotlin.ir.backend.js.lower.inline -import org.jetbrains.kotlin.backend.common.IrElementTransformerVoidWithContext -import org.jetbrains.kotlin.backend.common.ScopeWithIr +import org.jetbrains.kotlin.backend.common.* +import org.jetbrains.kotlin.backend.common.descriptors.explicitParameters import org.jetbrains.kotlin.backend.common.lower.createIrBuilder -import org.jetbrains.kotlin.backend.common.reportWarning import org.jetbrains.kotlin.descriptors.* import org.jetbrains.kotlin.ir.IrElement import org.jetbrains.kotlin.ir.IrStatement import org.jetbrains.kotlin.ir.backend.js.JsIrBackendContext +import org.jetbrains.kotlin.ir.builders.Scope import org.jetbrains.kotlin.ir.builders.irCall import org.jetbrains.kotlin.ir.builders.irGet import org.jetbrains.kotlin.ir.builders.irReturn -import org.jetbrains.kotlin.ir.declarations.IrFunction -import org.jetbrains.kotlin.ir.declarations.IrModuleFragment -import org.jetbrains.kotlin.ir.declarations.getDefault +import org.jetbrains.kotlin.ir.declarations.* import org.jetbrains.kotlin.ir.expressions.* +import org.jetbrains.kotlin.ir.expressions.impl.IrCallImpl import org.jetbrains.kotlin.ir.expressions.impl.IrGetValueImpl import org.jetbrains.kotlin.ir.expressions.impl.IrReturnableBlockImpl import org.jetbrains.kotlin.ir.expressions.impl.IrVarargImpl import org.jetbrains.kotlin.ir.symbols.impl.IrReturnableBlockSymbolImpl import org.jetbrains.kotlin.ir.types.toKotlinType +import org.jetbrains.kotlin.ir.util.getArguments +import org.jetbrains.kotlin.ir.util.parentAsClass +import org.jetbrains.kotlin.ir.visitors.IrElementTransformer import org.jetbrains.kotlin.ir.visitors.IrElementTransformerVoid import org.jetbrains.kotlin.ir.visitors.transformChildrenVoid import org.jetbrains.kotlin.name.FqName -import org.jetbrains.kotlin.resolve.calls.components.hasDefaultValue import org.jetbrains.kotlin.resolve.descriptorUtil.fqNameSafe import org.jetbrains.kotlin.resolve.inline.InlineUtil import org.jetbrains.kotlin.types.TypeConstructor @@ -38,54 +39,147 @@ import org.jetbrains.kotlin.types.TypeProjection import org.jetbrains.kotlin.types.TypeProjectionImpl import org.jetbrains.kotlin.types.TypeSubstitutor +abstract class IrElementTransformerWithContext : IrElementTransformer { + + private val scopeStack = mutableListOf() + + final override fun visitFile(declaration: IrFile, data: D): IrFile { + scopeStack.push(ScopeWithIr(Scope(declaration.symbol), declaration)) + val result = visitFileNew(declaration, data) + scopeStack.pop() + return result + } + + final override fun visitClass(declaration: IrClass, data: D): IrStatement { + scopeStack.push(ScopeWithIr(Scope(declaration.symbol), declaration)) + val result = visitClassNew(declaration, data) + scopeStack.pop() + return result + } + + final override fun visitProperty(declaration: IrProperty, data: D): IrStatement { + scopeStack.push(ScopeWithIr(Scope(declaration.descriptor), declaration)) + val result = visitPropertyNew(declaration, data) + scopeStack.pop() + return result + } + + final override fun visitField(declaration: IrField, data: D): IrStatement { + scopeStack.push(ScopeWithIr(Scope(declaration.symbol), declaration)) + val result = visitFieldNew(declaration, data) + scopeStack.pop() + return result + } + + final override fun visitFunction(declaration: IrFunction, data: D): IrStatement { + scopeStack.push(ScopeWithIr(Scope(declaration.symbol), declaration)) + val result = visitFunctionNew(declaration, data) + scopeStack.pop() + return result + } + + protected val currentFile get() = scopeStack.lastOrNull { it.irElement is IrFile }!!.irElement as IrFile + protected val currentClass get() = scopeStack.lastOrNull { it.scope.scopeOwner is ClassDescriptor } + protected val currentFunction get() = scopeStack.lastOrNull { it.scope.scopeOwner is FunctionDescriptor } + protected val currentProperty get() = scopeStack.lastOrNull { it.scope.scopeOwner is PropertyDescriptor } + protected val currentScope get() = scopeStack.peek() + protected val parentScope get() = if (scopeStack.size < 2) null else scopeStack[scopeStack.size - 2] + protected val allScopes get() = scopeStack + + fun printScopeStack() { + scopeStack.forEach { println(it.scope.scopeOwner) } + } + + open fun visitFileNew(declaration: IrFile, data: D): IrFile { + return super.visitFile(declaration, data) + } + + open fun visitClassNew(declaration: IrClass, data: D): IrStatement { + return super.visitClass(declaration, data) + } + + open fun visitFunctionNew(declaration: IrFunction, data: D): IrStatement { + return super.visitFunction(declaration, data) + } + + open fun visitPropertyNew(declaration: IrProperty, data: D): IrStatement { + return super.visitProperty(declaration, data) + } + + open fun visitFieldNew(declaration: IrField, data: D): IrStatement { + return super.visitField(declaration, data) + } +} + + //-----------------------------------------------------------------------------// typealias Context = JsIrBackendContext +internal class Ref(var value: T) + // backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/lower/FunctionInlining.kt -internal class FunctionInlining(val context: Context): IrElementTransformerVoidWithContext() { +internal class FunctionInlining(val context: Context): IrElementTransformerWithContext>() { // TODO private val deserializer = DeserializerDriver(context) private val globalSubstituteMap = mutableMapOf() + private val inlineFunctions = mutableMapOf() //-------------------------------------------------------------------------// fun inline(irModule: IrModuleFragment): IrElement { - val transformedModule = irModule.accept(this, null) - DescriptorSubstitutorForExternalScope(globalSubstituteMap).run(transformedModule) // Transform calls to object that might be returned from inline function call. + val transformedModule = irModule.accept(this, Ref(false)) + DescriptorSubstitutorForExternalScope(globalSubstituteMap, context).run(transformedModule) // Transform calls to object that might be returned from inline function call. return transformedModule } //-------------------------------------------------------------------------// - override fun visitCall(expression: IrCall): IrExpression { + override fun visitFunctionNew(declaration: IrFunction, data: Ref): IrStatement { + val descriptor = declaration.descriptor - val irCall = super.visitCall(expression) as IrCall - val functionDescriptor = irCall.descriptor - if (!functionDescriptor.needsInlining) return irCall // This call does not need inlining. + val localData = Ref(inlineFunctions[descriptor] ?: false) + val result = super.visitFunctionNew(declaration, localData) + data.value = data.value or localData.value - val functionDeclaration = getFunctionDeclaration(irCall) // Get declaration of the function to be inlined. - if (functionDeclaration == null) { // We failed to get the declaration. + if (descriptor.needsInlining) + inlineFunctions[descriptor] = localData.value + return result + } + + override fun visitCall(expression: IrCall, data: Ref): IrExpression { + + val argsAreBad = Ref(false) + val callSite = super.visitCall(expression, argsAreBad) as IrCall + data.value = data.value or argsAreBad.value + val functionDescriptor = callSite.descriptor + if (!functionDescriptor.needsInlining) return callSite // This call does not need inlining. + + val callee = getFunctionDeclaration(callSite) // Get declaration of the function to be inlined. + if (callee == null) { // We failed to get the declaration. val message = "Inliner failed to obtain function declaration: " + functionDescriptor.fqNameSafe.toString() - getFunctionDeclaration(irCall) - context.reportWarning(message, currentFile, irCall) // Report warning. - return irCall + callee + context.reportWarning(message, currentFile, callSite) // Report warning. + return callSite } + data.value = data.value or callee.second - functionDeclaration.transformChildrenVoid(this) // Process recursive inline. - val inliner = Inliner( - globalSubstituteMap, - functionDeclaration, - currentScope!!, - context - ) // Create inliner for this scope. - return inliner.inline(irCall ) // Return newly created IrInlineBody instead of IrCall. + val childIsBad = Ref(inlineFunctions[functionDescriptor] ?: false) + callee.first.transformChildren(this, childIsBad) + inlineFunctions[functionDescriptor] = childIsBad.value// Process recursive inline. + data.value = data.value or childIsBad.value + + val currentCalleeIsBad = argsAreBad.value or childIsBad.value or callee.second + val inliner = Inliner(globalSubstituteMap, callSite, callee.first, !currentCalleeIsBad, currentScope!!, + allScopes.map { it.irElement }.filterIsInstance().lastOrNull(), context, this) + // Create inliner for this scope. + return inliner.inline() // Return newly created IrInlineBody instead of IrCall. } //-------------------------------------------------------------------------// - private fun getFunctionDeclaration(irCall: IrCall): IrFunction? { + private fun getFunctionDeclaration(irCall: IrCall): Pair? { val functionDescriptor = irCall.descriptor val originalDescriptor = functionDescriptor.resolveFakeOverride().original @@ -94,12 +188,8 @@ internal class FunctionInlining(val context: Context): IrElementTransformerVoidW context.originalModuleIndex.functions[originalDescriptor] ?: context.symbolTable.referenceDeclaredFunction(originalDescriptor).owner // ?: // If function is declared in the current module. // TODO deserializer.deserializeInlineBody(originalDescriptor) // Function is declared in another module. - return functionDeclaration as IrFunction? + return (functionDeclaration as IrFunction?)?.let { it to false } } - - //-------------------------------------------------------------------------// - - override fun visitElement(element: IrElement) = element.accept(this, null) } // TODO: should we keep this at all? @@ -109,58 +199,69 @@ private val FunctionDescriptor.isInlineConstructor get() = annotations.hasAnnota //-----------------------------------------------------------------------------// private class Inliner(val globalSubstituteMap: MutableMap, - val functionDeclaration: IrFunction, // Function to substitute. + val callSite: IrCall, + val callee: IrFunction, + val local: Boolean, val currentScope: ScopeWithIr, - val context: Context -) { + val parent: IrDeclarationParent?, + val context: Context, + val owner: FunctionInlining /*TODO: make inner*/) { + + val copyIrElement = + if (!local) + DeepCopyIrTreeWithDescriptors(callee.descriptor, currentScope.scope.scopeOwner, + context, createTypeSubstitutor(callSite)) + else { + val typeParameters = + if (callee is IrConstructor) + callee.parentAsClass.typeParameters + else callee.typeParameters + val typeArguments = + (0 until callSite.typeArgumentsCount).map { + typeParameters[it].symbol to callSite.getTypeArgument(it) + }.associate { it } + DeepCopyIrTreeWithSymbolsForInliner(context, typeArguments, parent) + } - val copyIrElement = DeepCopyIrTreeWithDescriptors( - functionDeclaration.descriptor, - currentScope.scope.scopeOwner, - context - ) // Create DeepCopy for current scope. val substituteMap = mutableMapOf() - //-------------------------------------------------------------------------// + fun inline() = inlineFunction(callSite, callee) - fun inline(irCall: IrCall): IrReturnableBlockImpl { // Call to be substituted. - val inlineFunctionBody = inlineFunction(irCall, functionDeclaration) - copyIrElement.addCurrentSubstituteMap(globalSubstituteMap) - return inlineFunctionBody - } + /** + * TODO: JVM inliner crashed on attempt inline this function from transform.kt with: + * j.l.IllegalStateException: Couldn't obtain compiled function body for + * public inline fun kotlin.collections.MutableList.transform... + */ + private inline fun MutableList.transform(transformation: (T) -> IrElement) { + forEachIndexed { i, item -> + set(i, transformation(item) as T) + } + } - //-------------------------------------------------------------------------// + private fun inlineFunction(callSite: IrCall, callee: IrFunction): IrReturnableBlockImpl { + val copiedCallee = copyIrElement.copy(callee) as IrFunction - private fun inlineFunction(callee: IrCall, // Call to be substituted. - caller: IrFunction): IrReturnableBlockImpl { // Function to substitute. + val evaluationStatements = evaluateArguments(callSite, copiedCallee) + val statements = (copiedCallee.body as IrBlockBody).statements - val copyFunctionDeclaration = copyIrElement.copy( // Create copy of original function. - irElement = caller, // Descriptors declared inside the function will be copied. - typeSubstitutor = createTypeSubstitutor(callee) // Type parameters will be substituted with type arguments. - ) as IrFunction + val irReturnableBlockSymbol = IrReturnableBlockSymbolImpl(copiedCallee.descriptor.original) + val descriptor = callee.descriptor.original + val startOffset = callee.startOffset + val endOffset = callee.endOffset + val irBuilder = context.createIrBuilder(irReturnableBlockSymbol, startOffset, endOffset) - val irReturnableBlockSymbol = IrReturnableBlockSymbolImpl(copyFunctionDeclaration.descriptor.original) - - val evaluationStatements = evaluateArguments(callee, copyFunctionDeclaration) // And list of evaluation statements. - - val statements = (copyFunctionDeclaration.body as IrBlockBody).statements // IR statements from function copy. - - val startOffset = caller.startOffset - val endOffset = caller.endOffset - val descriptor = caller.descriptor.original if (descriptor.isInlineConstructor) { val delegatingConstructorCall = statements[0] as IrDelegatingConstructorCall - val irBuilder = context.createIrBuilder(irReturnableBlockSymbol, startOffset, endOffset) irBuilder.run { val constructorDescriptor = delegatingConstructorCall.descriptor.original - val constructorCall = irCall(delegatingConstructorCall.symbol).apply { - constructorDescriptor.typeParameters.forEach() { putTypeArgument(it.index, delegatingConstructorCall.getTypeArgument(it)!!) } + val constructorCall = irCall(delegatingConstructorCall.symbol, callSite.type, + constructorDescriptor.typeParameters.map { delegatingConstructorCall.getTypeArgument(it)!! }).apply { constructorDescriptor.valueParameters.forEach { putValueArgument(it, delegatingConstructorCall.getValueArgument(it)) } } val oldThis = delegatingConstructorCall.descriptor.constructedClass.thisAsReceiverParameter val newThis = currentScope.scope.createTemporaryVariable( - irExpression = constructorCall, - nameHint = delegatingConstructorCall.descriptor.fqNameSafe.toString() + ".this" + irExpression = constructorCall, + nameHint = delegatingConstructorCall.descriptor.fqNameSafe.toString() + ".this" ) statements[0] = newThis substituteMap[oldThis] = irGet(newThis) @@ -168,22 +269,33 @@ private class Inliner(val globalSubstituteMap: MutableMap this.dispatchReceiver = argument + functionDescriptor.extensionReceiverParameter -> this.extensionReceiver = argument + else -> putValueArgument((it as ValueParameterDescriptor).index, argument) + } + } + assert(unboundIndex == valueParameters.size) { "Not all arguments of are used" } + } + return owner.visitCall(super.visitCall(immediateCall) as IrCall, Ref(false)) + } + if (functionArgument !is IrBlock) + return super.visitCall(expression) + + val functionDeclaration = functionArgument.statements[0] as IrFunction val newExpression = inlineFunction(expression, functionDeclaration) // Inline the lambda. Lambda parameters will be substituted with lambda arguments. return newExpression.transform(this, null) // Substitute lambda arguments with target function arguments. } @@ -228,22 +379,7 @@ private class Inliner(val globalSubstituteMap: MutableMap { + private fun buildParameterToArgument(callSite: IrCall, callee: IrFunction): List { - val parameterToArgument = mutableListOf() // Result list. - val functionDescriptor = irFunction.descriptor.original // Descriptor of function to be called. + val parameterToArgument = mutableListOf() - if (irCall.dispatchReceiver != null && // Only if there are non null dispatch receivers both - functionDescriptor.dispatchReceiverParameter != null) // on call site and in function declaration. + if (callSite.dispatchReceiver != null && // Only if there are non null dispatch receivers both + callee.dispatchReceiverParameter != null) // on call site and in function declaration. parameterToArgument += ParameterToArgument( - parameterDescriptor = functionDescriptor.dispatchReceiverParameter!!, - argumentExpression = irCall.dispatchReceiver!! + parameter = callee.dispatchReceiverParameter!!, + argumentExpression = callSite.dispatchReceiver!! ) val valueArguments = - irCall.descriptor.valueParameters.map { irCall.getValueArgument(it) }.toMutableList() + callSite.descriptor.valueParameters.map { callSite.getValueArgument(it) }.toMutableList() - if (functionDescriptor.extensionReceiverParameter != null) { + if (callee.extensionReceiverParameter != null) { parameterToArgument += ParameterToArgument( - parameterDescriptor = functionDescriptor.extensionReceiverParameter!!, - argumentExpression = if (irCall.extensionReceiver != null) { - irCall.extensionReceiver!! - } else { - // Special case: lambda with receiver is called as usual lambda: - valueArguments.removeAt(0)!! - } + parameter = callee.extensionReceiverParameter!!, + argumentExpression = if (callSite.extensionReceiver != null) { + callSite.extensionReceiver!! + } else { + // Special case: lambda with receiver is called as usual lambda: + valueArguments.removeAt(0)!! + } ) - } else if (irCall.extensionReceiver != null) { + } else if (callSite.extensionReceiver != null) { // Special case: usual lambda is called as lambda with receiver: - valueArguments.add(0, irCall.extensionReceiver!!) + valueArguments.add(0, callSite.extensionReceiver!!) } val parametersWithDefaultToArgument = mutableListOf() - irFunction.valueParameters.forEach { parameter -> // Iterate value parameter descriptors. - val parameterDescriptor = parameter.descriptor as ValueParameterDescriptor - val argument = valueArguments[parameterDescriptor.index] // Get appropriate argument from call site. + for (parameter in callee.valueParameters) { + val argument = valueArguments[parameter.index] when { - argument != null -> { // Argument is good enough. - parameterToArgument += ParameterToArgument( // Associate current parameter with the argument. - parameterDescriptor = parameterDescriptor, - argumentExpression = argument + argument != null -> { + parameterToArgument += ParameterToArgument( + parameter = parameter, + argumentExpression = argument ) } - parameterDescriptor.hasDefaultValue() -> { // There is no argument - try default value. - val defaultArgument = irFunction.getDefault(parameterDescriptor)!! + // After ExpectDeclarationsRemoving pass default values from expect declarations + // are represented correctly in IR. + parameter.defaultValue != null -> { // There is no argument - try default value. parametersWithDefaultToArgument += ParameterToArgument( - parameterDescriptor = parameterDescriptor, - argumentExpression = defaultArgument.expression + parameter = parameter, + argumentExpression = parameter.defaultValue!!.expression ) } - parameterDescriptor.varargElementType != null -> { + parameter.varargElementType != null -> { val emptyArray = IrVarargImpl( - startOffset = irCall.startOffset, - endOffset = irCall.endOffset, - type = parameter.type, - varargElementType = parameter.varargElementType!! + startOffset = callSite.startOffset, + endOffset = callSite.endOffset, + type = parameter.type, + varargElementType = parameter.varargElementType!! ) parameterToArgument += ParameterToArgument( - parameterDescriptor = parameterDescriptor, - argumentExpression = emptyArray + parameter = parameter, + argumentExpression = emptyArray ) } else -> { - val message = "Incomplete expression: call to $functionDescriptor " + - "has no argument at index ${parameterDescriptor.index}" + val message = "Incomplete expression: call to ${callee.descriptor} " + + "has no argument at index ${parameter.index}" throw Error(message) } } } - return parameterToArgument + parametersWithDefaultToArgument // All arguments except default are evaluated at callsite, - // but default arguments are evaluated inside callee. + return parameterToArgument + parametersWithDefaultToArgument // All arguments except default are evaluated at callsite, + // but default arguments are evaluated inside callee. } //-------------------------------------------------------------------------// - private fun evaluateArguments(irCall : IrCall, // Call site. - functionDeclaration: IrFunction // Function to be called. - ): List { + private fun evaluateArguments(callSite: IrCall, callee: IrFunction): List { - val parameterToArgumentOld = buildParameterToArgument(irCall, functionDeclaration) // Create map parameter_descriptor -> original_argument_expression. - val evaluationStatements = mutableListOf() // List of evaluation statements. + val parameterToArgumentOld = buildParameterToArgument(callSite, callee) + val evaluationStatements = mutableListOf() val substitutor = ParameterSubstitutor() parameterToArgumentOld.forEach { - val parameterDescriptor = it.parameterDescriptor + val parameterDescriptor = it.parameter.descriptor - if (it.isInlinableLambda || it.argumentExpression is IrGetValue) { // If argument is inlinable lambda. IrGetValue is skipped because of recursive inline. - substituteMap[parameterDescriptor] = it.argumentExpression // Associate parameter with lambda argument. + /* + * We need to create temporary variable for each argument except inlinable lambda arguments. + * For simplicity and to produce simpler IR we don't create temporaries for every immutable variable, + * not only for those referring to inlinable lambdas. + */ + if (it.isInlinableLambdaArgument) { + substituteMap[parameterDescriptor] = it.argumentExpression return@forEach } - val newVariable = currentScope.scope.createTemporaryVariable( // Create new variable and init it with the parameter expression. + if (it.isImmutableVariableLoad) { + substituteMap[parameterDescriptor] = it.argumentExpression.transform(substitutor, data = null) // Arguments may reference the previous ones - substitute them. + return@forEach + } + + val newVariable = currentScope.scope.createTemporaryVariable( irExpression = it.argumentExpression.transform(substitutor, data = null), // Arguments may reference the previous ones - substitute them. - nameHint = functionDeclaration.descriptor.name.toString(), + nameHint = callee.descriptor.name.toString(), isMutable = false) - evaluationStatements.add(newVariable) // Add initialization of the new variable in statement list. - val getVal = IrGetValueImpl( // Create new expression, representing access the new variable. + evaluationStatements.add(newVariable) + val getVal = IrGetValueImpl( startOffset = currentScope.irElement.startOffset, endOffset = currentScope.irElement.endOffset, type = newVariable.type, symbol = newVariable.symbol ) - substituteMap[parameterDescriptor] = getVal // Parameter will be replaced with the new variable. + substituteMap[parameterDescriptor] = getVal } return evaluationStatements } diff --git a/compiler/ir/ir.psi2ir/src/org/jetbrains/kotlin/psi2ir/Psi2IrTranslator.kt b/compiler/ir/ir.psi2ir/src/org/jetbrains/kotlin/psi2ir/Psi2IrTranslator.kt index 2069147ec61..b6f11538488 100644 --- a/compiler/ir/ir.psi2ir/src/org/jetbrains/kotlin/psi2ir/Psi2IrTranslator.kt +++ b/compiler/ir/ir.psi2ir/src/org/jetbrains/kotlin/psi2ir/Psi2IrTranslator.kt @@ -20,6 +20,7 @@ import org.jetbrains.kotlin.config.LanguageVersionSettings import org.jetbrains.kotlin.descriptors.ModuleDescriptor import org.jetbrains.kotlin.ir.IrElement import org.jetbrains.kotlin.ir.declarations.IrModuleFragment +import org.jetbrains.kotlin.ir.util.SymbolTable import org.jetbrains.kotlin.ir.util.patchDeclarationParents import org.jetbrains.kotlin.ir.visitors.acceptVoid import org.jetbrains.kotlin.psi.KtFile @@ -49,8 +50,8 @@ class Psi2IrTranslator( return generateModuleFragment(context, ktFiles) } - fun createGeneratorContext(moduleDescriptor: ModuleDescriptor, bindingContext: BindingContext) = - GeneratorContext(configuration, moduleDescriptor, bindingContext, languageVersionSettings) + fun createGeneratorContext(moduleDescriptor: ModuleDescriptor, bindingContext: BindingContext, symbolTable: SymbolTable = SymbolTable()) = + GeneratorContext(configuration, moduleDescriptor, bindingContext, languageVersionSettings, symbolTable) fun generateModuleFragment(context: GeneratorContext, ktFiles: Collection): IrModuleFragment { val moduleGenerator = ModuleGenerator(context) 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 3b60c5db090..0655eb0b415 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 @@ -21,6 +21,7 @@ import org.jetbrains.kotlin.ir.IrElement import org.jetbrains.kotlin.ir.declarations.* import org.jetbrains.kotlin.ir.declarations.impl.* import org.jetbrains.kotlin.ir.declarations.lazy.IrLazySymbolTable +import org.jetbrains.kotlin.ir.expressions.IrCall import org.jetbrains.kotlin.ir.expressions.IrExpression import org.jetbrains.kotlin.ir.expressions.IrExpressionBody import org.jetbrains.kotlin.ir.symbols.* @@ -466,6 +467,17 @@ open class SymbolTable : ReferenceSymbolTable { globalTypeParameterSymbolTable.descriptorToSymbol[declaration.descriptor] = declaration.symbol super.visitTypeParameter(declaration) } + + override fun visitCall(expression: IrCall) { + expression.symbol.let { + when (it) { + is IrSimpleFunctionSymbol -> simpleFunctionSymbolTable.descriptorToSymbol[it.descriptor] = it + is IrConstructorSymbol -> constructorSymbolTable.descriptorToSymbol[it.descriptor] = it + } + } + + super.visitCall(expression) + } }) } }