Remove descriptors from ToArrayLowering

This commit is contained in:
Georgy Bronnikov
2019-01-11 19:49:29 +03:00
parent c3652a47c6
commit 3531f47bfb
3 changed files with 256 additions and 168 deletions
@@ -6,42 +6,29 @@
package org.jetbrains.kotlin.backend.jvm.lower package org.jetbrains.kotlin.backend.jvm.lower
import org.jetbrains.kotlin.backend.common.ClassLoweringPass import org.jetbrains.kotlin.backend.common.ClassLoweringPass
import org.jetbrains.kotlin.backend.common.descriptors.KnownClassDescriptor import org.jetbrains.kotlin.backend.common.descriptors.*
import org.jetbrains.kotlin.backend.common.descriptors.KnownPackageFragmentDescriptor
import org.jetbrains.kotlin.backend.common.lower.createIrBuilder import org.jetbrains.kotlin.backend.common.lower.createIrBuilder
import org.jetbrains.kotlin.backend.common.phaser.makeIrFilePhase import org.jetbrains.kotlin.backend.common.phaser.makeIrFilePhase
import org.jetbrains.kotlin.backend.jvm.JvmBackendContext import org.jetbrains.kotlin.backend.jvm.JvmBackendContext
import org.jetbrains.kotlin.backend.jvm.JvmLoweredDeclarationOrigin import org.jetbrains.kotlin.backend.jvm.JvmLoweredDeclarationOrigin
import org.jetbrains.kotlin.backend.jvm.codegen.isJvmInterface import org.jetbrains.kotlin.backend.jvm.codegen.isJvmInterface
import org.jetbrains.kotlin.builtins.KotlinBuiltIns import org.jetbrains.kotlin.descriptors.*
import org.jetbrains.kotlin.codegen.isGenericToArray import org.jetbrains.kotlin.descriptors.impl.EmptyPackageFragmentDescriptor
import org.jetbrains.kotlin.codegen.isNonGenericToArray
import org.jetbrains.kotlin.descriptors.CallableMemberDescriptor
import org.jetbrains.kotlin.descriptors.Modality
import org.jetbrains.kotlin.descriptors.SourceElement
import org.jetbrains.kotlin.descriptors.Visibilities
import org.jetbrains.kotlin.descriptors.annotations.Annotations
import org.jetbrains.kotlin.descriptors.impl.SimpleFunctionDescriptorImpl
import org.jetbrains.kotlin.descriptors.impl.TypeParameterDescriptorImpl
import org.jetbrains.kotlin.descriptors.impl.ValueParameterDescriptorImpl
import org.jetbrains.kotlin.incremental.components.NoLookupLocation
import org.jetbrains.kotlin.ir.UNDEFINED_OFFSET import org.jetbrains.kotlin.ir.UNDEFINED_OFFSET
import org.jetbrains.kotlin.ir.builders.irBlockBody import org.jetbrains.kotlin.ir.builders.irBlockBody
import org.jetbrains.kotlin.ir.builders.irCall import org.jetbrains.kotlin.ir.builders.irCall
import org.jetbrains.kotlin.ir.builders.irReturn import org.jetbrains.kotlin.ir.builders.irReturn
import org.jetbrains.kotlin.ir.declarations.IrClass import org.jetbrains.kotlin.ir.declarations.*
import org.jetbrains.kotlin.ir.declarations.impl.IrFunctionImpl import org.jetbrains.kotlin.ir.declarations.impl.*
import org.jetbrains.kotlin.ir.expressions.impl.IrGetValueImpl import org.jetbrains.kotlin.ir.expressions.impl.IrGetValueImpl
import org.jetbrains.kotlin.ir.symbols.impl.IrSimpleFunctionSymbolImpl import org.jetbrains.kotlin.ir.symbols.IrClassSymbol
import org.jetbrains.kotlin.ir.types.toIrType import org.jetbrains.kotlin.ir.symbols.impl.*
import org.jetbrains.kotlin.ir.util.createParameterDeclarations import org.jetbrains.kotlin.ir.types.*
import org.jetbrains.kotlin.load.java.descriptors.JavaClassDescriptor import org.jetbrains.kotlin.ir.util.*
import org.jetbrains.kotlin.name.FqName import org.jetbrains.kotlin.name.FqName
import org.jetbrains.kotlin.name.Name import org.jetbrains.kotlin.name.Name
import org.jetbrains.kotlin.resolve.DescriptorUtils.isSubclass
import org.jetbrains.kotlin.resolve.descriptorUtil.builtIns
import org.jetbrains.kotlin.resolve.descriptorUtil.getAllSuperclassesWithoutAny
import org.jetbrains.kotlin.types.Variance import org.jetbrains.kotlin.types.Variance
import org.jetbrains.kotlin.utils.DFS
internal val toArrayPhase = makeIrFilePhase( internal val toArrayPhase = makeIrFilePhase(
::ToArrayLowering, ::ToArrayLowering,
@@ -54,118 +41,93 @@ private class ToArrayLowering(private val context: JvmBackendContext) : ClassLow
override fun lower(irClass: IrClass) { override fun lower(irClass: IrClass) {
if (irClass.isJvmInterface) return if (irClass.isJvmInterface) return
val descriptor = irClass.descriptor val irBuiltIns = context.irBuiltIns
val builtIns = descriptor.builtIns if (!irClass.isCollectionSubClass()) return
if (!isSubclass(descriptor, builtIns.collection)) return
if (descriptor.getAllSuperclassesWithoutAny().any { classDescriptor -> if (irClass.hasSuperClass {
classDescriptor !is JavaClassDescriptor && isSubclass( it != irClass &&
classDescriptor, it.isClass &&
builtIns.collection it.origin != IrDeclarationOrigin.IR_EXTERNAL_JAVA_DECLARATION_STUB &&
) it.isCollectionSubClass()
}) { }) return
return
}
val toArrayName = Name.identifier("toArray") val toArrayName = Name.identifier("toArray")
val functions = descriptor.defaultType.memberScope.getContributedFunctions( val genericToArray = irClass.declarations.find { it.isGenericToArray() }
toArrayName, NoLookupLocation.FROM_BACKEND val nonGenericToArray = irClass.declarations.find { it.isNonGenericToArray() }
)
val genericToArray = functions.firstOrNull { it.isGenericToArray() }
val nonGenericToArray = functions.firstOrNull { it.isNonGenericToArray() }
val arrayType = builtIns.getArrayType(Variance.INVARIANT, builtIns.anyType)
if (genericToArray == null) { if (genericToArray == null) {
val toArrayDescriptor = SimpleFunctionDescriptorImpl.create( val typeParameterDescriptor = WrappedTypeParameterDescriptor()
irClass.descriptor, org.jetbrains.kotlin.descriptors.annotations.Annotations.EMPTY, val typeParameter = IrTypeParameterImpl(
toArrayName, CallableMemberDescriptor.Kind.SYNTHESIZED, SourceElement.NO_SOURCE UNDEFINED_OFFSET, UNDEFINED_OFFSET,
)
toArrayDescriptor.initialize(
null, irClass.descriptor.thisAsReceiverParameter, emptyList(), emptyList(),
arrayType, Modality.OPEN, Visibilities.PUBLIC
)
val toArrayUtilDescriptor = createToArrayUtilDescriptor(builtIns, false)
val toArrayType = toArrayUtilDescriptor.returnType!!.toIrType()!!
val irFunction = IrFunctionImpl(
UNDEFINED_OFFSET,
UNDEFINED_OFFSET,
JvmLoweredDeclarationOrigin.TO_ARRAY, JvmLoweredDeclarationOrigin.TO_ARRAY,
toArrayDescriptor, IrTypeParameterSymbolImpl(typeParameterDescriptor),
returnType = toArrayType
)
irFunction.createParameterDeclarations()
irFunction.body = context.createIrBuilder(irFunction.symbol).irBlockBody {
+irReturn(
irCall(IrSimpleFunctionSymbolImpl(toArrayUtilDescriptor), toArrayType).apply {
putValueArgument(
0,
IrGetValueImpl(UNDEFINED_OFFSET, UNDEFINED_OFFSET, irFunction.dispatchReceiverParameter!!.symbol)
)
})
}
irClass.declarations.add(irFunction)
} else {
//TODO patch visibility
}
if (nonGenericToArray == null) {
val toArrayDescriptor = SimpleFunctionDescriptorImpl.create(
irClass.descriptor, org.jetbrains.kotlin.descriptors.annotations.Annotations.EMPTY,
toArrayName, CallableMemberDescriptor.Kind.SYNTHESIZED, SourceElement.NO_SOURCE
)
val createWithDefaultBound = TypeParameterDescriptorImpl.createWithDefaultBound(
toArrayDescriptor,
Annotations.EMPTY,
false,
Variance.INVARIANT,
Name.identifier("T"), Name.identifier("T"),
0 index = 0,
) variance = Variance.INVARIANT,
isReified = false
val genericArrayType = builtIns.getArrayType(Variance.INVARIANT, createWithDefaultBound.defaultType) ).apply {
toArrayDescriptor.initialize( typeParameterDescriptor.bind(this)
null, superTypes.add(irBuiltIns.anyNType)
irClass.descriptor.thisAsReceiverParameter, }
listOf(createWithDefaultBound),
listOf(
ValueParameterDescriptorImpl(
toArrayDescriptor,
null,
0,
Annotations.EMPTY,
Name.identifier("array"),
genericArrayType,
false,
false,
false,
null,
SourceElement.NO_SOURCE
)
),
genericArrayType,
Modality.OPEN,
Visibilities.PUBLIC
)
val toArrayUtilDescriptor = createToArrayUtilDescriptor(builtIns, true)
val toArrayType = toArrayUtilDescriptor.returnType!!.toIrType()!!
val substitutedArrayType = irBuiltIns.arrayClass.typeWith(typeParameter.defaultType)
val functionDescriptor = WrappedSimpleFunctionDescriptor()
val irFunction = IrFunctionImpl( val irFunction = IrFunctionImpl(
UNDEFINED_OFFSET, UNDEFINED_OFFSET, UNDEFINED_OFFSET,
UNDEFINED_OFFSET,
JvmLoweredDeclarationOrigin.TO_ARRAY, JvmLoweredDeclarationOrigin.TO_ARRAY,
toArrayDescriptor, IrSimpleFunctionSymbolImpl(functionDescriptor),
toArrayType toArrayName,
Visibilities.PUBLIC,
Modality.OPEN,
returnType = substitutedArrayType,
isInline = false,
isExternal = false,
isTailrec = false,
isSuspend = false
)
functionDescriptor.bind(irFunction)
irFunction.parent = irClass
typeParameter.parent = irFunction
irFunction.typeParameters.add(typeParameter)
val dispatchReceiverParameterDescriptor = WrappedValueParameterDescriptor()
irFunction.dispatchReceiverParameter = IrValueParameterImpl(
UNDEFINED_OFFSET, UNDEFINED_OFFSET,
JvmLoweredDeclarationOrigin.TO_ARRAY,
IrValueParameterSymbolImpl(dispatchReceiverParameterDescriptor),
Name.special("<this>"),
index = -1,
type = irClass.defaultType,
varargElementType = null,
isCrossinline = false,
isNoinline = false
).apply {
parent = irFunction
}
val valueParameterDescriptor = WrappedValueParameterDescriptor()
irFunction.valueParameters.add(
IrValueParameterImpl(
UNDEFINED_OFFSET, UNDEFINED_OFFSET,
JvmLoweredDeclarationOrigin.TO_ARRAY,
IrValueParameterSymbolImpl(valueParameterDescriptor),
Name.identifier("array"),
index = 0,
varargElementType = null,
type = substitutedArrayType,
isCrossinline = false,
isNoinline = false
).apply {
valueParameterDescriptor.bind(this)
parent = irFunction
}
) )
irFunction.createParameterDeclarations()
irFunction.body = context.createIrBuilder(irFunction.symbol).irBlockBody { irFunction.body = context.createIrBuilder(irFunction.symbol).irBlockBody {
+irReturn( +irReturn(
irCall(IrSimpleFunctionSymbolImpl(toArrayUtilDescriptor), toArrayType).apply { irCall(genericToArrayUtilFunction.symbol, genericToArrayUtilFunction.returnType).apply {
putValueArgument( putValueArgument(
0, 0,
IrGetValueImpl(UNDEFINED_OFFSET, UNDEFINED_OFFSET, irFunction.dispatchReceiverParameter!!.symbol) IrGetValueImpl(UNDEFINED_OFFSET, UNDEFINED_OFFSET, irFunction.dispatchReceiverParameter!!.symbol)
@@ -178,57 +140,180 @@ private class ToArrayLowering(private val context: JvmBackendContext) : ClassLow
} else { } else {
//TODO patch visibility //TODO patch visibility
} }
if (nonGenericToArray == null) {
val functionDescriptor = WrappedSimpleFunctionDescriptor()
val irFunction = IrFunctionImpl(
UNDEFINED_OFFSET, UNDEFINED_OFFSET,
JvmLoweredDeclarationOrigin.TO_ARRAY,
IrSimpleFunctionSymbolImpl(functionDescriptor),
toArrayName,
Visibilities.PUBLIC,
Modality.OPEN,
returnType = irBuiltIns.arrayClass.typeWith(irBuiltIns.anyType),
isInline = false,
isExternal = false,
isTailrec = false,
isSuspend = false
)
functionDescriptor.bind(irFunction)
irFunction.parent = irClass
val dispatchReceiverParameterDescriptor = WrappedValueParameterDescriptor()
irFunction.dispatchReceiverParameter = IrValueParameterImpl(
UNDEFINED_OFFSET, UNDEFINED_OFFSET,
JvmLoweredDeclarationOrigin.TO_ARRAY,
IrValueParameterSymbolImpl(dispatchReceiverParameterDescriptor),
Name.special("<this>"),
index = -1,
type = irClass.defaultType,
varargElementType = null,
isCrossinline = false,
isNoinline = false
).apply {
parent = irFunction
}
irFunction.body = context.createIrBuilder(irFunction.symbol).irBlockBody {
+irReturn(
irCall(nonGenericToArrayUtilFunction.symbol, nonGenericToArrayUtilFunction.returnType).apply {
putValueArgument(
0,
IrGetValueImpl(UNDEFINED_OFFSET, UNDEFINED_OFFSET, irFunction.dispatchReceiverParameter!!.symbol)
)
})
}
irClass.declarations.add(irFunction)
} else {
//TODO patch visibility
}
} }
private fun createToArrayUtilDescriptor( private val kotlinJvmInternalPackageFragment: IrPackageFragment by lazy {
builtIns: KotlinBuiltIns, IrExternalPackageFragmentImpl(
isGeneric: Boolean IrExternalPackageFragmentSymbolImpl(
): SimpleFunctionDescriptorImpl { EmptyPackageFragmentDescriptor(
val kotlinJvmInternalPackage = KnownPackageFragmentDescriptor(builtIns.builtInsModule, FqName("kotlin.jvm.internal")) context.ir.irModule.descriptor,
FqName("kotlin.jvm.internal")
)
)
)
}
val toArrayUtil = SimpleFunctionDescriptorImpl.create( private val collectionUtilClass: IrClass by lazy {
KnownClassDescriptor.createClass(Name.identifier("CollectionToArray"), kotlinJvmInternalPackage, listOf(builtIns.anyType)), val descriptor = WrappedClassDescriptor()
Annotations.EMPTY, IrClassImpl(
UNDEFINED_OFFSET, UNDEFINED_OFFSET,
JvmLoweredDeclarationOrigin.TO_ARRAY,
IrClassSymbolImpl(descriptor),
Name.identifier("CollectionToArray"),
ClassKind.CLASS,
Visibilities.PUBLIC,
Modality.FINAL,
isCompanion = false,
isInner = false,
isInline = false,
isData = false,
isExternal = false
).apply {
descriptor.bind(this)
parent = kotlinJvmInternalPackageFragment
superTypes.add(context.irBuiltIns.anyType)
kotlinJvmInternalPackageFragment.declarations.add(this)
}
}
private fun createToArrayUtilFunction(isGeneric: Boolean): IrSimpleFunction {
val irBuiltIns = context.irBuiltIns
val arrayType = irBuiltIns.arrayClass.typeWith(irBuiltIns.anyNType)
val utilFunctionDescriptor = WrappedSimpleFunctionDescriptor()
return IrFunctionImpl(
UNDEFINED_OFFSET, UNDEFINED_OFFSET,
JvmLoweredDeclarationOrigin.TO_ARRAY,
IrSimpleFunctionSymbolImpl(utilFunctionDescriptor),
Name.identifier("toArray"), Name.identifier("toArray"),
CallableMemberDescriptor.Kind.SYNTHESIZED, Visibilities.PUBLIC,
SourceElement.NO_SOURCE Modality.FINAL,
) returnType = arrayType,
toArrayUtil.initialize( isInline = false,
null, isExternal = false,
null, isTailrec = false,
emptyList(), isSuspend = false
listOfNotNull( ).also { irFunction ->
ValueParameterDescriptorImpl( utilFunctionDescriptor.bind(irFunction)
toArrayUtil, irFunction.parent = collectionUtilClass
null,
0, val collectionParameterDescriptor = WrappedValueParameterDescriptor()
Annotations.EMPTY, irFunction.valueParameters.add(
IrValueParameterImpl(
UNDEFINED_OFFSET, UNDEFINED_OFFSET,
JvmLoweredDeclarationOrigin.TO_ARRAY,
IrValueParameterSymbolImpl(collectionParameterDescriptor),
Name.identifier("collection"), Name.identifier("collection"),
builtIns.collection.defaultType, 0,
false, irBuiltIns.collectionClass.owner.defaultType,
false, varargElementType = null,
false, isCrossinline = false,
null, isNoinline = false
SourceElement.NO_SOURCE ).apply {
), collectionParameterDescriptor.bind(this)
if (isGeneric) ValueParameterDescriptorImpl( parent = irFunction
toArrayUtil, }
null, )
1, if (isGeneric) {
Annotations.EMPTY, val arrayParameterDescriptor = WrappedValueParameterDescriptor()
Name.identifier("array"), irFunction.valueParameters.add(
builtIns.getArrayType(Variance.INVARIANT, builtIns.anyType), IrValueParameterImpl(
false, UNDEFINED_OFFSET, UNDEFINED_OFFSET,
false, JvmLoweredDeclarationOrigin.TO_ARRAY,
false, IrValueParameterSymbolImpl(arrayParameterDescriptor),
null, Name.identifier("array"),
SourceElement.NO_SOURCE 1,
) else null arrayType,
), varargElementType = null,
builtIns.array.defaultType, isCrossinline = false,
Modality.OPEN, isNoinline = false
Visibilities.PUBLIC ).apply {
) arrayParameterDescriptor.bind(this)
return toArrayUtil parent = irFunction
}
)
}
collectionUtilClass.declarations.add(irFunction)
}
} }
}
private val nonGenericToArrayUtilFunction: IrSimpleFunction by lazy { createToArrayUtilFunction(false) }
private val genericToArrayUtilFunction: IrSimpleFunction by lazy { createToArrayUtilFunction(true) }
private fun IrDeclaration.isGenericToArray(): Boolean {
if (this !is IrSimpleFunction) return false
val signature = context.state.typeMapper.mapAsmMethod(descriptor)
return signature.toString() == "toArray([Ljava/lang/Object;)[Ljava/lang/Object;"
}
private fun IrDeclaration.isNonGenericToArray(): Boolean {
if (this !is IrSimpleFunction) return false
if (this.name.asString() != "toArray") return false
if (!typeParameters.isEmpty() || !valueParameters.isEmpty()) return false
if (!returnType.isArray()) return false
return true
}
}
private fun IrClass.hasSuperClass(pred: (IrClass) -> Boolean): Boolean =
DFS.ifAny(
listOf(this),
{ irClass -> irClass.superTypes.mapNotNull { ((it as? IrSimpleType)?.classifier as? IrClassSymbol)?.owner } },
pred
)
// Have to check by name, since irBuiltins is unreliable.
private fun IrClass.isCollectionSubClass() =
hasSuperClass {
it.defaultType.isCollection()
}
@@ -128,6 +128,8 @@ class IrBuiltIns(
val stringType = string.toIrType() val stringType = string.toIrType()
val stringClass = builtIns.string.toIrSymbol() val stringClass = builtIns.string.toIrSymbol()
val collectionClass = builtIns.collection.toIrSymbol()
val arrayClass = builtIns.array.toIrSymbol() val arrayClass = builtIns.array.toIrSymbol()
val throwableType = builtIns.throwable.defaultType.toIrType() val throwableType = builtIns.throwable.defaultType.toIrType()
@@ -37,6 +37,7 @@ fun IrType.isNullableAny(): Boolean = isBuiltInClassType(KotlinBuiltIns::isAny,
fun IrType.isString(): Boolean = isNotNullClassType(KotlinBuiltIns.FQ_NAMES.string) fun IrType.isString(): Boolean = isNotNullClassType(KotlinBuiltIns.FQ_NAMES.string)
fun IrType.isNullableString(): Boolean = isNullableClassType(KotlinBuiltIns.FQ_NAMES.string) fun IrType.isNullableString(): Boolean = isNullableClassType(KotlinBuiltIns.FQ_NAMES.string)
fun IrType.isArray(): Boolean = isNotNullClassType(KotlinBuiltIns.FQ_NAMES.array) fun IrType.isArray(): Boolean = isNotNullClassType(KotlinBuiltIns.FQ_NAMES.array)
fun IrType.isCollection(): Boolean = isNotNullClassType(KotlinBuiltIns.FQ_NAMES.collection.toUnsafe())
fun IrType.isNothing(): Boolean = isNotNullClassType(KotlinBuiltIns.FQ_NAMES.nothing) fun IrType.isNothing(): Boolean = isNotNullClassType(KotlinBuiltIns.FQ_NAMES.nothing)
fun IrType.isPrimitiveType(): Boolean = fun IrType.isPrimitiveType(): Boolean =
isBuiltInClassType(KotlinBuiltIns::isPrimitiveClass, hasQuestionMark = false) isBuiltInClassType(KotlinBuiltIns::isPrimitiveClass, hasQuestionMark = false)