Do not use JVM-specific code for SAM conversions in psi2ir

Extract all JVM-specific code into GeneratorExtensions.SamConversion.
This is needed in order to remove dependency of ir.tree on frontend.java
This commit is contained in:
Alexander Udalov
2019-03-01 15:58:45 +01:00
parent aaa2bad719
commit 45e8d2e1df
6 changed files with 92 additions and 37 deletions
@@ -5,10 +5,18 @@
package org.jetbrains.kotlin.backend.jvm
import org.jetbrains.kotlin.descriptors.CallableDescriptor
import org.jetbrains.kotlin.descriptors.ClassDescriptor
import org.jetbrains.kotlin.descriptors.DeclarationDescriptor
import org.jetbrains.kotlin.ir.declarations.IrDeclarationOrigin
import org.jetbrains.kotlin.load.java.descriptors.JavaCallableMemberDescriptor
import org.jetbrains.kotlin.load.java.descriptors.JavaClassDescriptor
import org.jetbrains.kotlin.load.java.sam.SamAdapterDescriptor
import org.jetbrains.kotlin.load.java.sam.SamConstructorDescriptor
import org.jetbrains.kotlin.load.java.sam.SingleAbstractMethodUtils
import org.jetbrains.kotlin.psi2ir.generators.GeneratorExtensions
import org.jetbrains.kotlin.synthetic.SamAdapterExtensionFunctionDescriptor
import org.jetbrains.kotlin.types.KotlinType
object JvmGeneratorExtensions : GeneratorExtensions() {
override val externalDeclarationOrigin: ((DeclarationDescriptor) -> IrDeclarationOrigin)? = { descriptor ->
@@ -17,4 +25,35 @@ object JvmGeneratorExtensions : GeneratorExtensions() {
else
IrDeclarationOrigin.IR_EXTERNAL_DECLARATION_STUB
}
override val samConversion: SamConversion
get() = JvmSamConversion
open class JvmSamConversion : SamConversion() {
override fun getOriginalForSamAdapter(descriptor: CallableDescriptor): CallableDescriptor? =
when (descriptor) {
is SamAdapterDescriptor<*> -> descriptor.baseDescriptorForSynthetic
is SamAdapterExtensionFunctionDescriptor -> descriptor.baseDescriptorForSynthetic
else -> null
}
override fun isSamConstructor(descriptor: CallableDescriptor): Boolean =
descriptor is SamConstructorDescriptor
override fun isSamType(type: KotlinType): Boolean =
SingleAbstractMethodUtils.isSamType(type)
override fun getFunctionTypeForSAMClass(descriptor: ClassDescriptor): KotlinType {
if (descriptor !is JavaClassDescriptor) {
throw AssertionError("SAM should be represented by a Java class: $descriptor")
}
val singleAbstractMethod = SingleAbstractMethodUtils.getSingleAbstractMethodOrNull(descriptor)
?: throw AssertionError("$descriptor should have a single abstract method")
return SingleAbstractMethodUtils.getFunctionTypeForAbstractMethod(singleAbstractMethod, false)
}
companion object Instance : JvmSamConversion()
}
}
@@ -9,6 +9,7 @@ import org.jetbrains.kotlin.backend.common.FileLoweringPass
import org.jetbrains.kotlin.backend.common.phaser.makeIrFilePhase
import org.jetbrains.kotlin.backend.common.utils.isSubtypeOf
import org.jetbrains.kotlin.backend.jvm.JvmBackendContext
import org.jetbrains.kotlin.backend.jvm.JvmGeneratorExtensions
import org.jetbrains.kotlin.ir.declarations.IrFile
import org.jetbrains.kotlin.ir.expressions.IrCall
import org.jetbrains.kotlin.ir.expressions.IrExpression
@@ -27,7 +28,8 @@ internal val jvmCoercionToUnitPhase = makeIrFilePhase(
class JvmCoercionToUnitPatcher(val context: JvmBackendContext) :
InsertImplicitCasts(
context.builtIns, context.irBuiltIns,
TypeTranslator(context.ir.symbols.externalSymbolTable, context.state.languageVersionSettings)
TypeTranslator(context.ir.symbols.externalSymbolTable, context.state.languageVersionSettings),
JvmGeneratorExtensions.samConversion
),
FileLoweringPass {
@@ -42,4 +44,4 @@ class JvmCoercionToUnitPatcher(val context: JvmBackendContext) :
return this
}
}
}
@@ -28,8 +28,6 @@ import org.jetbrains.kotlin.ir.expressions.IrExpressionWithCopy
import org.jetbrains.kotlin.ir.expressions.IrTypeOperator
import org.jetbrains.kotlin.ir.expressions.impl.*
import org.jetbrains.kotlin.ir.types.classifierOrFail
import org.jetbrains.kotlin.load.java.sam.SamAdapterDescriptor
import org.jetbrains.kotlin.load.java.sam.SingleAbstractMethodUtils
import org.jetbrains.kotlin.psi.KtElement
import org.jetbrains.kotlin.psi.KtExpression
import org.jetbrains.kotlin.psi.psiUtil.endOffset
@@ -42,7 +40,6 @@ import org.jetbrains.kotlin.resolve.calls.callResolverUtil.getSuperCallExpressio
import org.jetbrains.kotlin.resolve.calls.callUtil.isSafeCall
import org.jetbrains.kotlin.resolve.calls.model.*
import org.jetbrains.kotlin.resolve.scopes.receivers.*
import org.jetbrains.kotlin.synthetic.SamAdapterExtensionFunctionDescriptor
import org.jetbrains.kotlin.types.KotlinType
import org.jetbrains.kotlin.types.TypeSubstitutor
@@ -383,11 +380,7 @@ private fun StatementGenerator.pregenerateValueArguments(call: CallBuilder, reso
}
private fun StatementGenerator.generateSamConversionForValueArgumentsIfRequired(call: CallBuilder, originalDescriptor: CallableDescriptor) {
val underlyingDescriptor = when (originalDescriptor) {
is SamAdapterDescriptor<*> -> originalDescriptor.baseDescriptorForSynthetic
is SamAdapterExtensionFunctionDescriptor -> originalDescriptor.baseDescriptorForSynthetic
else -> return
}
val underlyingDescriptor = context.extensions.samConversion.getOriginalForSamAdapter(originalDescriptor) ?: return
val originalValueParameters = originalDescriptor.valueParameters
val underlyingValueParameters = underlyingDescriptor.valueParameters
@@ -405,7 +398,7 @@ private fun StatementGenerator.generateSamConversionForValueArgumentsIfRequired(
val originalParameterType = originalValueParameters[i].type
val underlyingParameterType = underlyingValueParameters[i].type
if (!SingleAbstractMethodUtils.isSamType(underlyingParameterType)) continue
if (!context.extensions.samConversion.isSamType(underlyingParameterType)) continue
if (!originalParameterType.isFunctionTypeOrSubtype) continue
val originalArgument = call.irValueArgumentsByIndex[i] ?: continue
@@ -437,7 +430,7 @@ fun StatementGenerator.pregenerateValueArgumentsUsing(
}
fun StatementGenerator.pregenerateCallReceivers(resolvedCall: ResolvedCall<*>): CallBuilder {
val call = unwrapCallableDescriptorAndTypeArguments(resolvedCall)
val call = unwrapCallableDescriptorAndTypeArguments(resolvedCall, context.extensions.samConversion)
call.callReceiver = generateCallReceiver(
resolvedCall.call.callElement,
@@ -452,20 +445,21 @@ fun StatementGenerator.pregenerateCallReceivers(resolvedCall: ResolvedCall<*>):
return call
}
private fun unwrapSpecialDescriptor(originalDescriptor: CallableDescriptor): CallableDescriptor =
when (originalDescriptor) {
is ImportedFromObjectCallableDescriptor<*> -> unwrapSpecialDescriptor(originalDescriptor.callableFromObject)
is TypeAliasConstructorDescriptor -> originalDescriptor.underlyingConstructorDescriptor
is SamAdapterDescriptor<*> -> unwrapSpecialDescriptor(originalDescriptor.baseDescriptorForSynthetic)
is SamAdapterExtensionFunctionDescriptor -> unwrapSpecialDescriptor(originalDescriptor.baseDescriptorForSynthetic)
else -> originalDescriptor
private fun unwrapSpecialDescriptor(
descriptor: CallableDescriptor,
samConversion: GeneratorExtensions.SamConversion
): CallableDescriptor =
when (descriptor) {
is ImportedFromObjectCallableDescriptor<*> -> unwrapSpecialDescriptor(descriptor.callableFromObject, samConversion)
is TypeAliasConstructorDescriptor -> descriptor.underlyingConstructorDescriptor
else -> samConversion.getOriginalForSamAdapter(descriptor)?.let { unwrapSpecialDescriptor(it, samConversion) } ?: descriptor
}
fun unwrapCallableDescriptorAndTypeArguments(resolvedCall: ResolvedCall<*>): CallBuilder {
fun unwrapCallableDescriptorAndTypeArguments(resolvedCall: ResolvedCall<*>, samConversion: GeneratorExtensions.SamConversion): CallBuilder {
val originalDescriptor = resolvedCall.resultingDescriptor
val candidateDescriptor = resolvedCall.candidateDescriptor
val unwrappedDescriptor = unwrapSpecialDescriptor(originalDescriptor)
val unwrappedDescriptor = unwrapSpecialDescriptor(originalDescriptor, samConversion)
val originalTypeArguments = resolvedCall.typeArguments
val unsubstitutedUnwrappedDescriptor = unwrappedDescriptor.original
@@ -25,7 +25,6 @@ import org.jetbrains.kotlin.ir.types.IrDynamicType
import org.jetbrains.kotlin.ir.types.classifierOrFail
import org.jetbrains.kotlin.ir.util.referenceFunction
import org.jetbrains.kotlin.ir.util.render
import org.jetbrains.kotlin.load.java.sam.SamConstructorDescriptor
import org.jetbrains.kotlin.psi.KtElement
import org.jetbrains.kotlin.psi.psiUtil.endOffset
import org.jetbrains.kotlin.psi.psiUtil.startOffsetSkippingComments
@@ -44,9 +43,11 @@ class CallGenerator(statementGenerator: StatementGenerator) : StatementGenerator
fun generateCall(startOffset: Int, endOffset: Int, call: CallBuilder, origin: IrStatementOrigin? = null): IrExpression {
val descriptor = call.descriptor
if (context.extensions.samConversion.isSamConstructor(descriptor)) {
return generateSamConstructorCall(descriptor, startOffset, endOffset, call)
}
return when (descriptor) {
is SamConstructorDescriptor ->
generateSamConstructorCall(descriptor, startOffset, endOffset, call)
is PropertyDescriptor ->
generatePropertyGetterCall(descriptor, startOffset, endOffset, call)
is FunctionDescriptor ->
@@ -59,7 +60,7 @@ class CallGenerator(statementGenerator: StatementGenerator) : StatementGenerator
}
private fun generateSamConstructorCall(
descriptor: SamConstructorDescriptor,
descriptor: CallableDescriptor,
startOffset: Int,
endOffset: Int,
call: CallBuilder
@@ -5,10 +5,30 @@
package org.jetbrains.kotlin.psi2ir.generators
import org.jetbrains.kotlin.descriptors.CallableDescriptor
import org.jetbrains.kotlin.descriptors.ClassDescriptor
import org.jetbrains.kotlin.descriptors.DeclarationDescriptor
import org.jetbrains.kotlin.ir.declarations.IrDeclarationOrigin
import org.jetbrains.kotlin.types.KotlinType
open class GeneratorExtensions {
open val externalDeclarationOrigin: ((DeclarationDescriptor) -> IrDeclarationOrigin)?
get() = null
open val samConversion: SamConversion
get() = SamConversion
open class SamConversion {
// Returns null if descriptor is not a SAM adapter
open fun getOriginalForSamAdapter(descriptor: CallableDescriptor): CallableDescriptor? = null
open fun isSamConstructor(descriptor: CallableDescriptor): Boolean = false
open fun isSamType(type: KotlinType): Boolean = false
open fun getFunctionTypeForSAMClass(descriptor: ClassDescriptor): KotlinType =
throw UnsupportedOperationException("SAM conversion is not supported in this configuration (class=$descriptor)")
companion object Instance : SamConversion()
}
}
@@ -17,6 +17,7 @@
package org.jetbrains.kotlin.psi2ir.transformations
import org.jetbrains.kotlin.builtins.KotlinBuiltIns
import org.jetbrains.kotlin.descriptors.ClassDescriptor
import org.jetbrains.kotlin.ir.IrElement
import org.jetbrains.kotlin.ir.IrStatement
import org.jetbrains.kotlin.ir.declarations.IrClass
@@ -33,10 +34,9 @@ import org.jetbrains.kotlin.ir.util.TypeTranslator
import org.jetbrains.kotlin.ir.util.coerceToUnitIfNeeded
import org.jetbrains.kotlin.ir.util.render
import org.jetbrains.kotlin.ir.visitors.IrElementTransformerVoid
import org.jetbrains.kotlin.load.java.descriptors.JavaClassDescriptor
import org.jetbrains.kotlin.load.java.sam.SingleAbstractMethodUtils
import org.jetbrains.kotlin.psi2ir.containsNull
import org.jetbrains.kotlin.psi2ir.generators.GeneratorContext
import org.jetbrains.kotlin.psi2ir.generators.GeneratorExtensions
import org.jetbrains.kotlin.types.*
import org.jetbrains.kotlin.types.checker.KotlinTypeChecker
import org.jetbrains.kotlin.types.typeUtil.isNullableAny
@@ -45,13 +45,17 @@ import org.jetbrains.kotlin.types.typeUtil.makeNotNullable
import org.jetbrains.kotlin.types.typeUtil.makeNullable
fun insertImplicitCasts(element: IrElement, context: GeneratorContext) {
element.transformChildren(InsertImplicitCasts(context.builtIns, context.irBuiltIns, context.typeTranslator), null)
element.transformChildren(
InsertImplicitCasts(context.builtIns, context.irBuiltIns, context.typeTranslator, context.extensions.samConversion),
null
)
}
open class InsertImplicitCasts(
private val builtIns: KotlinBuiltIns,
private val irBuiltIns: IrBuiltIns,
private val typeTranslator: TypeTranslator
private val typeTranslator: TypeTranslator,
private val samConversion: GeneratorExtensions.SamConversion
) : IrElementTransformerVoid() {
private fun KotlinType.toIrType() = typeTranslator.translateType(this)
@@ -177,15 +181,10 @@ open class InsertImplicitCasts(
super.visitTypeOperator(expression)
private fun IrTypeOperatorCall.coerceArgumentToFunctionalType(): IrExpression {
val targetClassDescriptor = typeOperandClassifier.descriptor as? JavaClassDescriptor
?: throw AssertionError("Target type of $operator should be a Java class: ${render()}")
val targetClassDescriptor = typeOperandClassifier.descriptor as? ClassDescriptor
?: throw AssertionError("Target type of $operator should be a class: ${render()}")
val singleAbstractMethod = SingleAbstractMethodUtils.getSingleAbstractMethodOrNull(targetClassDescriptor)
?: throw AssertionError("$targetClassDescriptor should have a single abstract method")
val functionalType = SingleAbstractMethodUtils.getFunctionTypeForAbstractMethod(singleAbstractMethod, false)
argument = argument.cast(functionalType)
argument = argument.cast(samConversion.getFunctionTypeForSAMClass(targetClassDescriptor))
return this
}