[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
This commit is contained in:
Roman Artemev
2020-08-26 15:48:13 +03:00
parent 8cb8284957
commit fd88914cf9
12 changed files with 90 additions and 42 deletions
@@ -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("<this>"),
0,
-1,
parentAsClass.defaultType,
null,
false,
false
).apply {
parent = this@createDispatchReceiverParameter
newDescriptor.bind(this)
}
}
@@ -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,
@@ -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
@@ -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"
@@ -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-<init>-<init>.
// (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 {
@@ -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()}")
}
@@ -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)
}
}
@@ -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)
@@ -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
@@ -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)
@@ -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)
@@ -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