From fd88914cf9c0df66b620db7ed1147f9219055eba Mon Sep 17 00:00:00 2001 From: Roman Artemev Date: Wed, 26 Aug 2020 15:48:13 +0300 Subject: [PATCH] [IR] Remove some descriptor usage from Common/JS/JVM backends - replace descriptor-based builders with pure IR ones - fix matchers - fix Ir2Js - rewrite some inliner-helpers to pure-IR implementations --- .../kotlin/backend/common/ir/IrUtils.kt | 21 +++++----- .../common/lower/ArrayConstructorLowering.kt | 13 ++++--- .../common/lower/LocalDeclarationsLowering.kt | 2 +- .../kotlin/backend/common/lower/LowerUtils.kt | 5 +-- .../lower/SingleAbstractMethodLowering.kt | 4 +- .../common/lower/inline/FunctionInlining.kt | 38 +++++++++++++++---- .../lower/matchers/IrFunctionMatcher.kt | 7 +--- .../ir/backend/js/lower/VarargLowering.kt | 2 +- .../transformers/irToJs/MultiModuleSupport.kt | 4 +- .../kotlin/ir/util/AdditionalIrUtils.kt | 17 +++++++++ .../ir/util/DeepCopyIrTreeWithSymbols.kt | 3 +- .../ir/util/ExpectDeclarationRemover.kt | 16 ++++++-- 12 files changed, 90 insertions(+), 42 deletions(-) diff --git a/compiler/ir/backend.common/src/org/jetbrains/kotlin/backend/common/ir/IrUtils.kt b/compiler/ir/backend.common/src/org/jetbrains/kotlin/backend/common/ir/IrUtils.kt index a565085166e..b75390e1de6 100644 --- a/compiler/ir/backend.common/src/org/jetbrains/kotlin/backend/common/ir/IrUtils.kt +++ b/compiler/ir/backend.common/src/org/jetbrains/kotlin/backend/common/ir/IrUtils.kt @@ -109,7 +109,6 @@ val IrClass.isFinalClass: Boolean val IrTypeParametersContainer.classIfConstructor get() = if (this is IrConstructor) parentAsClass else this -@OptIn(ObsoleteDescriptorBasedAPI::class) fun IrValueParameter.copyTo( irFunction: IrFunction, origin: IrDeclarationOrigin = this.origin, @@ -129,9 +128,9 @@ fun IrValueParameter.copyTo( isNoinline: Boolean = this.isNoinline ): IrValueParameter { val descriptor = if (index < 0) { - WrappedReceiverParameterDescriptor(this.descriptor.annotations, this.descriptor.source) + WrappedReceiverParameterDescriptor() } else { - WrappedValueParameterDescriptor(this.descriptor.annotations, this.descriptor.source) + WrappedValueParameterDescriptor() } val symbol = IrValueParameterSymbolImpl(descriptor) val defaultValueCopy = defaultValue?.let { originalDefault -> @@ -166,12 +165,15 @@ fun IrTypeParameter.copyToWithoutSuperTypes( @OptIn(ObsoleteDescriptorBasedAPI::class) fun IrFunction.copyReceiverParametersFrom(from: IrFunction) { dispatchReceiverParameter = from.dispatchReceiverParameter?.run { + val newDescriptor = WrappedReceiverParameterDescriptor() factory.createValueParameter( - startOffset, endOffset, origin, IrValueParameterSymbolImpl(descriptor), descriptor.name, - descriptor.indexOrMinusOne, type, varargElementType, descriptor.isCrossinline, - descriptor.isNoinline + startOffset, endOffset, origin, + IrValueParameterSymbolImpl(newDescriptor), + name, + index, type, varargElementType, isCrossinline, isNoinline ).also { parameter -> parameter.parent = this@copyReceiverParametersFrom + newDescriptor.bind(this) } } extensionReceiverParameter = from.extensionReceiverParameter?.copyTo(this) @@ -406,22 +408,23 @@ fun IrClass.createParameterDeclarations() { thisReceiver = buildReceiverParameter(this, IrDeclarationOrigin.INSTANCE_RECEIVER, symbol.typeWithParameters(typeParameters)) } -@OptIn(ObsoleteDescriptorBasedAPI::class) fun IrFunction.createDispatchReceiverParameter(origin: IrDeclarationOrigin? = null) { assert(dispatchReceiverParameter == null) + val newDescriptor = WrappedReceiverParameterDescriptor() dispatchReceiverParameter = factory.createValueParameter( startOffset, endOffset, origin ?: parentAsClass.origin, - IrValueParameterSymbolImpl(parentAsClass.thisReceiver!!.descriptor), + IrValueParameterSymbolImpl(newDescriptor), Name.special(""), - 0, + -1, parentAsClass.defaultType, null, false, false ).apply { parent = this@createDispatchReceiverParameter + newDescriptor.bind(this) } } diff --git a/compiler/ir/backend.common/src/org/jetbrains/kotlin/backend/common/lower/ArrayConstructorLowering.kt b/compiler/ir/backend.common/src/org/jetbrains/kotlin/backend/common/lower/ArrayConstructorLowering.kt index 4efc6d31551..adc7b12e5ea 100644 --- a/compiler/ir/backend.common/src/org/jetbrains/kotlin/backend/common/lower/ArrayConstructorLowering.kt +++ b/compiler/ir/backend.common/src/org/jetbrains/kotlin/backend/common/lower/ArrayConstructorLowering.kt @@ -73,23 +73,24 @@ private class ArrayConstructorTransformer( val invokable = expression.getValueArgument(1)!!.transform(this, null) val scope = (currentScope ?: createScope(container)).scope return context.createIrBuilder(scope.scopeOwnerSymbol).irBlock(expression.startOffset, expression.endOffset) { - val index = irTemporaryVar(irInt(0)) - val sizeVar = irTemporary(size) - val result = irTemporary(irCall(sizeConstructor, expression.type).apply { - copyTypeArgumentsFrom(expression) + val index = createTmpVariable(irInt(0), isMutable = true) + val sizeVar = createTmpVariable(size) + val result = createTmpVariable(irCall(sizeConstructor, expression.type).apply { + + copyTypeArgumentsFrom(expression) putValueArgument(0, irGet(sizeVar)) }) val lambda = invokable.asSingleArgumentLambda() val invoke = invokable.type.getClass()!!.functions.single { it.name == OperatorNameConventions.INVOKE } - val invokableVar = if (lambda == null) irTemporary(invokable) else null + val invokableVar = if (lambda == null) createTmpVariable(invokable) else null +irWhile().apply { condition = irCall(context.irBuiltIns.lessFunByOperandType[index.type.classifierOrFail]!!).apply { putValueArgument(0, irGet(index)) putValueArgument(1, irGet(sizeVar)) } body = irBlock { - val tempIndex = irTemporary(irGet(index)) + val tempIndex = createTmpVariable(irGet(index)) val value = lambda?.inline(parent, listOf(tempIndex))?.patchDeclarationParents(scope.getLocalDeclarationParent()) ?: irCallOp( invoke.symbol, invoke.returnType, 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 d28d64017f7..ce05f66b044 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 @@ -646,7 +646,7 @@ class LocalDeclarationsLowering( startOffset = p.startOffset endOffset = p.endOffset origin = - if (p.descriptor is ReceiverParameterDescriptor && newDeclaration is IrConstructor) BOUND_RECEIVER_PARAMETER + if (p is IrValueParameter && p.index < 0 && newDeclaration is IrConstructor) BOUND_RECEIVER_PARAMETER else BOUND_VALUE_PARAMETER name = suggestNameForCapturedValue(p, generatedNames) index = i 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 eb355d23787..eecaf0f2769 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 @@ -163,7 +163,6 @@ open class IrBuildingTransformer(private val context: BackendContext) : IrElemen } } -@OptIn(ObsoleteDescriptorBasedAPI::class) fun IrConstructor.callsSuper(irBuiltIns: IrBuiltIns): Boolean { val constructedClass = parent as IrClass val superClass = constructedClass.superTypes @@ -186,9 +185,9 @@ fun IrConstructor.callsSuper(irBuiltIns: IrBuiltIns): Boolean { val delegatingClass = expression.symbol.owner.parent as IrClass // TODO: figure out why Lazy IR multiplies Declarations for descriptors and fix it // It happens because of IrBuiltIns whose IrDeclarations are different for runtime and test - if (delegatingClass.descriptor == superClass.classifierOrFail.descriptor) + if (delegatingClass.symbol == superClass.classifierOrFail) callsSuper = true - else if (delegatingClass.descriptor != constructedClass.descriptor) + else if (delegatingClass.symbol != constructedClass.symbol) throw AssertionError( "Expected either call to another constructor of the class being constructed or" + " call to super class constructor. But was: $delegatingClass with '${delegatingClass.name}' name" diff --git a/compiler/ir/backend.common/src/org/jetbrains/kotlin/backend/common/lower/SingleAbstractMethodLowering.kt b/compiler/ir/backend.common/src/org/jetbrains/kotlin/backend/common/lower/SingleAbstractMethodLowering.kt index 576f6c9be08..7cd0e7fd55d 100644 --- a/compiler/ir/backend.common/src/org/jetbrains/kotlin/backend/common/lower/SingleAbstractMethodLowering.kt +++ b/compiler/ir/backend.common/src/org/jetbrains/kotlin/backend/common/lower/SingleAbstractMethodLowering.kt @@ -117,7 +117,7 @@ abstract class SingleAbstractMethodLowering(val context: CommonBackendContext) : return if (superType.isNullable() && invokable.type.isNullable()) { irBlock(invokable, null, superType) { - val invokableVariable = irTemporary(invokable) + val invokableVariable = createTmpVariable(invokable) val instance = irCall(implementation.constructors.single()).apply { putValueArgument(0, irGet(invokableVariable)) } @@ -129,7 +129,7 @@ abstract class SingleAbstractMethodLowering(val context: CommonBackendContext) : // otherwise, e.g. if the argument constructs an anonymous object, resulting in new-new--. // (See KT-21781 for a similar problem with anonymous object constructor arguments.) irBlock(invokable, null, superType) { - val invokableVariable = irTemporary(invokable) + val invokableVariable = createTmpVariable(invokable) +irCall(implementation.constructors.single()).apply { putValueArgument(0, irGet(invokableVariable)) } } } else { diff --git a/compiler/ir/backend.common/src/org/jetbrains/kotlin/backend/common/lower/inline/FunctionInlining.kt b/compiler/ir/backend.common/src/org/jetbrains/kotlin/backend/common/lower/inline/FunctionInlining.kt index f1c8e9afff1..96f5a382ed3 100644 --- a/compiler/ir/backend.common/src/org/jetbrains/kotlin/backend/common/lower/inline/FunctionInlining.kt +++ b/compiler/ir/backend.common/src/org/jetbrains/kotlin/backend/common/lower/inline/FunctionInlining.kt @@ -10,7 +10,14 @@ import org.jetbrains.kotlin.backend.common.* import org.jetbrains.kotlin.backend.common.ir.Symbols import org.jetbrains.kotlin.backend.common.ir.createTemporaryVariableWithWrappedDescriptor import org.jetbrains.kotlin.backend.common.lower.createIrBuilder +import org.jetbrains.kotlin.config.LanguageFeature +import org.jetbrains.kotlin.config.LanguageVersionSettings +import org.jetbrains.kotlin.config.coroutinesIntrinsicsPackageFqName import org.jetbrains.kotlin.config.languageVersionSettings +import org.jetbrains.kotlin.descriptors.DeclarationDescriptor +import org.jetbrains.kotlin.descriptors.FunctionDescriptor +import org.jetbrains.kotlin.descriptors.PackageFragmentDescriptor +import org.jetbrains.kotlin.descriptors.isTopLevelInPackage import org.jetbrains.kotlin.ir.IrElement import org.jetbrains.kotlin.ir.IrStatement import org.jetbrains.kotlin.ir.ObsoleteDescriptorBasedAPI @@ -19,9 +26,7 @@ import org.jetbrains.kotlin.ir.builders.irReturn import org.jetbrains.kotlin.ir.declarations.* import org.jetbrains.kotlin.ir.expressions.* import org.jetbrains.kotlin.ir.expressions.impl.* -import org.jetbrains.kotlin.ir.symbols.IrFunctionSymbol -import org.jetbrains.kotlin.ir.symbols.IrSymbol -import org.jetbrains.kotlin.ir.symbols.IrValueSymbol +import org.jetbrains.kotlin.ir.symbols.* import org.jetbrains.kotlin.ir.symbols.impl.IrReturnableBlockSymbolImpl import org.jetbrains.kotlin.ir.types.* import org.jetbrains.kotlin.ir.util.* @@ -37,17 +42,34 @@ interface InlineFunctionResolver { fun getFunctionDeclaration(symbol: IrFunctionSymbol): IrFunction } -@OptIn(ObsoleteDescriptorBasedAPI::class) +fun IrFunction.isTopLevelInPackage(name: String, packageName: String): Boolean { + if (name != this.name.asString()) return false + + val containingDeclaration = parent as? IrPackageFragment ?: return false + val packageFqName = containingDeclaration.fqName.asString() + return packageName == packageFqName +} + +fun IrFunction.isBuiltInIntercepted(languageVersionSettings: LanguageVersionSettings): Boolean = + !languageVersionSettings.supportsFeature(LanguageFeature.ReleaseCoroutines) && + isTopLevelInPackage("intercepted", languageVersionSettings.coroutinesIntrinsicsPackageFqName().asString()) + +fun IrFunction.isBuiltInSuspendCoroutineUninterceptedOrReturn(languageVersionSettings: LanguageVersionSettings): Boolean = + isTopLevelInPackage( + "suspendCoroutineUninterceptedOrReturn", + languageVersionSettings.coroutinesIntrinsicsPackageFqName().asString() + ) + open class DefaultInlineFunctionResolver(open val context: CommonBackendContext) : InlineFunctionResolver { override fun getFunctionDeclaration(symbol: IrFunctionSymbol): IrFunction { - val descriptor = symbol.descriptor.original + val function = symbol.owner val languageVersionSettings = context.configuration.languageVersionSettings // TODO: Remove these hacks when coroutine intrinsics are fixed. return when { - descriptor.isBuiltInIntercepted(languageVersionSettings) -> + function.isBuiltInIntercepted(languageVersionSettings) -> error("Continuation.intercepted is not available with release coroutines") - descriptor.isBuiltInSuspendCoroutineUninterceptedOrReturn(languageVersionSettings) -> + function.isBuiltInSuspendCoroutineUninterceptedOrReturn(languageVersionSettings) -> context.ir.symbols.suspendCoroutineUninterceptedOrReturn.owner symbol == context.ir.symbols.coroutineContextGetter -> @@ -246,7 +268,7 @@ class FunctionInlining( ) } is IrSimpleFunction -> - IrCallImpl(startOffset, endOffset, function.returnType, function.symbol) + IrCallImpl(startOffset, endOffset, function.returnType, function.symbol, function.typeParameters.size, function.valueParameters.size) else -> error("Unknown function kind : ${function.render()}") } diff --git a/compiler/ir/backend.common/src/org/jetbrains/kotlin/backend/common/lower/matchers/IrFunctionMatcher.kt b/compiler/ir/backend.common/src/org/jetbrains/kotlin/backend/common/lower/matchers/IrFunctionMatcher.kt index 785cfe7a747..dde73bda50e 100644 --- a/compiler/ir/backend.common/src/org/jetbrains/kotlin/backend/common/lower/matchers/IrFunctionMatcher.kt +++ b/compiler/ir/backend.common/src/org/jetbrains/kotlin/backend/common/lower/matchers/IrFunctionMatcher.kt @@ -5,12 +5,11 @@ package org.jetbrains.kotlin.backend.common.lower.matchers -import org.jetbrains.kotlin.ir.ObsoleteDescriptorBasedAPI import org.jetbrains.kotlin.ir.declarations.IrFunction import org.jetbrains.kotlin.ir.declarations.IrValueParameter import org.jetbrains.kotlin.ir.types.IrType +import org.jetbrains.kotlin.ir.util.kotlinFqName import org.jetbrains.kotlin.name.FqName -import org.jetbrains.kotlin.resolve.descriptorUtil.fqNameSafe internal interface IrFunctionMatcher : (IrFunction) -> Boolean @@ -52,13 +51,11 @@ internal class ParameterCountMatcher( } } -@OptIn(ObsoleteDescriptorBasedAPI::class) internal class FqNameMatcher( val restriction: (FqName) -> Boolean ) : IrFunctionMatcher { - override fun invoke(function: IrFunction): Boolean { - return restriction(function.descriptor.fqNameSafe) + return restriction(function.kotlinFqName) } } diff --git a/compiler/ir/backend.js/src/org/jetbrains/kotlin/ir/backend/js/lower/VarargLowering.kt b/compiler/ir/backend.js/src/org/jetbrains/kotlin/ir/backend/js/lower/VarargLowering.kt index 7bdbe9ad232..7afd3f27f1e 100644 --- a/compiler/ir/backend.js/src/org/jetbrains/kotlin/ir/backend/js/lower/VarargLowering.kt +++ b/compiler/ir/backend.js/src/org/jetbrains/kotlin/ir/backend/js/lower/VarargLowering.kt @@ -36,7 +36,7 @@ private class VarargTransformer( // TODO: Use symbols when builtins symbol table is fixes val primitiveType = context.intrinsics.primitiveArrays - .mapKeys { it.key.descriptor }[type.classifierOrNull?.descriptor] + .mapKeys { it.key }[type.classifierOrNull] val intrinsic = if (primitiveType != null) diff --git a/compiler/ir/backend.js/src/org/jetbrains/kotlin/ir/backend/js/transformers/irToJs/MultiModuleSupport.kt b/compiler/ir/backend.js/src/org/jetbrains/kotlin/ir/backend/js/transformers/irToJs/MultiModuleSupport.kt index e0e479aa657..d7afc286f6f 100644 --- a/compiler/ir/backend.js/src/org/jetbrains/kotlin/ir/backend/js/transformers/irToJs/MultiModuleSupport.kt +++ b/compiler/ir/backend.js/src/org/jetbrains/kotlin/ir/backend/js/transformers/irToJs/MultiModuleSupport.kt @@ -188,7 +188,7 @@ fun breakCrossModuleFieldAccess( return expression.symbol.owner.transformAccess { val getter = getter() - IrCallImpl(UNDEFINED_OFFSET, UNDEFINED_OFFSET, getter.returnType, getter.symbol) + IrCallImpl(UNDEFINED_OFFSET, UNDEFINED_OFFSET, getter.returnType, getter.symbol, getter.typeParameters.size, getter.valueParameters.size) } ?: expression } @@ -197,7 +197,7 @@ fun breakCrossModuleFieldAccess( return expression.symbol.owner.transformAccess { val setter = setter() - IrCallImpl(UNDEFINED_OFFSET, UNDEFINED_OFFSET, setter.returnType, setter.symbol).apply { + IrCallImpl(UNDEFINED_OFFSET, UNDEFINED_OFFSET, setter.returnType, setter.symbol, setter.typeParameters.size, setter.valueParameters.size).apply { putValueArgument(0, expression.value) } } ?: expression diff --git a/compiler/ir/ir.tree/src/org/jetbrains/kotlin/ir/util/AdditionalIrUtils.kt b/compiler/ir/ir.tree/src/org/jetbrains/kotlin/ir/util/AdditionalIrUtils.kt index 2f442a34242..84c951777db 100644 --- a/compiler/ir/ir.tree/src/org/jetbrains/kotlin/ir/util/AdditionalIrUtils.kt +++ b/compiler/ir/ir.tree/src/org/jetbrains/kotlin/ir/util/AdditionalIrUtils.kt @@ -30,6 +30,23 @@ val IrDeclarationParent.fqNameForIrSerialization: FqName else -> error(this) } +/** + * Skips synthetic FILE_CLASS to make top-level functions look as in kotlin source + */ +val IrDeclarationParent.kotlinFqName: FqName + get() = when (this) { + is IrPackageFragment -> this.fqName + is IrClass -> { + if (origin == IrDeclarationOrigin.FILE_CLASS) { + parent.kotlinFqName + } else { + parent.kotlinFqName.child(nameForIrSerialization) + } + } + is IrDeclaration -> this.parent.kotlinFqName.child(nameForIrSerialization) + else -> error(this) + } + val IrClass.classId: ClassId? get() = when (val parent = this.parent) { is IrClass -> parent.classId?.createNestedClassId(this.name) diff --git a/compiler/ir/ir.tree/src/org/jetbrains/kotlin/ir/util/DeepCopyIrTreeWithSymbols.kt b/compiler/ir/ir.tree/src/org/jetbrains/kotlin/ir/util/DeepCopyIrTreeWithSymbols.kt index 7a0f34bae85..7f7837b0a54 100644 --- a/compiler/ir/ir.tree/src/org/jetbrains/kotlin/ir/util/DeepCopyIrTreeWithSymbols.kt +++ b/compiler/ir/ir.tree/src/org/jetbrains/kotlin/ir/util/DeepCopyIrTreeWithSymbols.kt @@ -552,7 +552,8 @@ open class DeepCopyIrTreeWithSymbols( expression.startOffset, expression.endOffset, expression.type.remapType(), newConstructor, - expression.typeArgumentsCount + expression.typeArgumentsCount, + expression.valueArgumentsCount ).apply { copyRemappedTypeArgumentsFrom(expression) transformValueArguments(expression) diff --git a/compiler/ir/ir.tree/src/org/jetbrains/kotlin/ir/util/ExpectDeclarationRemover.kt b/compiler/ir/ir.tree/src/org/jetbrains/kotlin/ir/util/ExpectDeclarationRemover.kt index f75af02ee43..f7478b1b464 100644 --- a/compiler/ir/ir.tree/src/org/jetbrains/kotlin/ir/util/ExpectDeclarationRemover.kt +++ b/compiler/ir/ir.tree/src/org/jetbrains/kotlin/ir/util/ExpectDeclarationRemover.kt @@ -5,6 +5,8 @@ package org.jetbrains.kotlin.ir.util +import org.jetbrains.kotlin.descriptors.ClassDescriptor +import org.jetbrains.kotlin.descriptors.ClassKind import org.jetbrains.kotlin.descriptors.MemberDescriptor import org.jetbrains.kotlin.ir.IrElement import org.jetbrains.kotlin.ir.ObsoleteDescriptorBasedAPI @@ -62,6 +64,12 @@ class ExpectDeclarationRemover(val symbolTable: ReferenceSymbolTable, private va } } + private fun isOptionalAnnotationClass(klass: IrClass): Boolean { + return klass.kind == ClassKind.ANNOTATION_CLASS && + klass.isExpect && + klass.annotations.hasAnnotation(ExpectedActualDeclarationChecker.OPTIONAL_EXPECTATION_FQ_NAME) + } + private fun tryCopyDefaultArguments(declaration: IrValueParameter) { // Keep actual default value if present. They are generally not allowed but can be suppressed with // @Suppress("ACTUAL_FUNCTION_WITH_DEFAULT_ARGUMENTS") @@ -71,10 +79,10 @@ class ExpectDeclarationRemover(val symbolTable: ReferenceSymbolTable, private va val function = declaration.parent as? IrFunction ?: return - if (function is IrConstructor && - ExpectedActualDeclarationChecker.isOptionalAnnotationClass(function.descriptor.constructedClass) - ) { - return + if (function is IrConstructor) { + if (isOptionalAnnotationClass(function.constructedClass)) { + return + } } if (!function.descriptor.isActual) return