From 45e8d2e1dfe61ab41a9d2de9e60f6eb733f1b154 Mon Sep 17 00:00:00 2001 From: Alexander Udalov Date: Fri, 1 Mar 2019 15:58:45 +0100 Subject: [PATCH] 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 --- .../backend/jvm/JvmGeneratorExtensions.kt | 39 +++++++++++++++++++ .../jvm/lower/JvmCoercionToUnitPatcher.kt | 6 ++- .../generators/ArgumentsGenerationUtils.kt | 32 +++++++-------- .../kotlin/psi2ir/generators/CallGenerator.kt | 9 +++-- .../psi2ir/generators/GeneratorExtensions.kt | 20 ++++++++++ .../transformations/InsertImplicitCasts.kt | 23 ++++++----- 6 files changed, 92 insertions(+), 37 deletions(-) diff --git a/compiler/ir/backend.jvm/src/org/jetbrains/kotlin/backend/jvm/JvmGeneratorExtensions.kt b/compiler/ir/backend.jvm/src/org/jetbrains/kotlin/backend/jvm/JvmGeneratorExtensions.kt index 438236f02dd..513646fbbe8 100644 --- a/compiler/ir/backend.jvm/src/org/jetbrains/kotlin/backend/jvm/JvmGeneratorExtensions.kt +++ b/compiler/ir/backend.jvm/src/org/jetbrains/kotlin/backend/jvm/JvmGeneratorExtensions.kt @@ -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() + } } diff --git a/compiler/ir/backend.jvm/src/org/jetbrains/kotlin/backend/jvm/lower/JvmCoercionToUnitPatcher.kt b/compiler/ir/backend.jvm/src/org/jetbrains/kotlin/backend/jvm/lower/JvmCoercionToUnitPatcher.kt index 2221e8594b3..46ad1ed5d03 100644 --- a/compiler/ir/backend.jvm/src/org/jetbrains/kotlin/backend/jvm/lower/JvmCoercionToUnitPatcher.kt +++ b/compiler/ir/backend.jvm/src/org/jetbrains/kotlin/backend/jvm/lower/JvmCoercionToUnitPatcher.kt @@ -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 } -} \ No newline at end of file +} diff --git a/compiler/ir/ir.psi2ir/src/org/jetbrains/kotlin/psi2ir/generators/ArgumentsGenerationUtils.kt b/compiler/ir/ir.psi2ir/src/org/jetbrains/kotlin/psi2ir/generators/ArgumentsGenerationUtils.kt index ab418920595..789ed70888e 100644 --- a/compiler/ir/ir.psi2ir/src/org/jetbrains/kotlin/psi2ir/generators/ArgumentsGenerationUtils.kt +++ b/compiler/ir/ir.psi2ir/src/org/jetbrains/kotlin/psi2ir/generators/ArgumentsGenerationUtils.kt @@ -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 diff --git a/compiler/ir/ir.psi2ir/src/org/jetbrains/kotlin/psi2ir/generators/CallGenerator.kt b/compiler/ir/ir.psi2ir/src/org/jetbrains/kotlin/psi2ir/generators/CallGenerator.kt index f195eae4daa..e429d9a5427 100644 --- a/compiler/ir/ir.psi2ir/src/org/jetbrains/kotlin/psi2ir/generators/CallGenerator.kt +++ b/compiler/ir/ir.psi2ir/src/org/jetbrains/kotlin/psi2ir/generators/CallGenerator.kt @@ -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 diff --git a/compiler/ir/ir.psi2ir/src/org/jetbrains/kotlin/psi2ir/generators/GeneratorExtensions.kt b/compiler/ir/ir.psi2ir/src/org/jetbrains/kotlin/psi2ir/generators/GeneratorExtensions.kt index 0564f9d658b..6d9139dfbbf 100644 --- a/compiler/ir/ir.psi2ir/src/org/jetbrains/kotlin/psi2ir/generators/GeneratorExtensions.kt +++ b/compiler/ir/ir.psi2ir/src/org/jetbrains/kotlin/psi2ir/generators/GeneratorExtensions.kt @@ -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() + } } diff --git a/compiler/ir/ir.psi2ir/src/org/jetbrains/kotlin/psi2ir/transformations/InsertImplicitCasts.kt b/compiler/ir/ir.psi2ir/src/org/jetbrains/kotlin/psi2ir/transformations/InsertImplicitCasts.kt index 75e5974f115..21911426506 100644 --- a/compiler/ir/ir.psi2ir/src/org/jetbrains/kotlin/psi2ir/transformations/InsertImplicitCasts.kt +++ b/compiler/ir/ir.psi2ir/src/org/jetbrains/kotlin/psi2ir/transformations/InsertImplicitCasts.kt @@ -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 }