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 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.descriptors.DeclarationDescriptor
import org.jetbrains.kotlin.ir.declarations.IrDeclarationOrigin import org.jetbrains.kotlin.ir.declarations.IrDeclarationOrigin
import org.jetbrains.kotlin.load.java.descriptors.JavaCallableMemberDescriptor 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.psi2ir.generators.GeneratorExtensions
import org.jetbrains.kotlin.synthetic.SamAdapterExtensionFunctionDescriptor
import org.jetbrains.kotlin.types.KotlinType
object JvmGeneratorExtensions : GeneratorExtensions() { object JvmGeneratorExtensions : GeneratorExtensions() {
override val externalDeclarationOrigin: ((DeclarationDescriptor) -> IrDeclarationOrigin)? = { descriptor -> override val externalDeclarationOrigin: ((DeclarationDescriptor) -> IrDeclarationOrigin)? = { descriptor ->
@@ -17,4 +25,35 @@ object JvmGeneratorExtensions : GeneratorExtensions() {
else else
IrDeclarationOrigin.IR_EXTERNAL_DECLARATION_STUB 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.phaser.makeIrFilePhase
import org.jetbrains.kotlin.backend.common.utils.isSubtypeOf import org.jetbrains.kotlin.backend.common.utils.isSubtypeOf
import org.jetbrains.kotlin.backend.jvm.JvmBackendContext 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.declarations.IrFile
import org.jetbrains.kotlin.ir.expressions.IrCall import org.jetbrains.kotlin.ir.expressions.IrCall
import org.jetbrains.kotlin.ir.expressions.IrExpression import org.jetbrains.kotlin.ir.expressions.IrExpression
@@ -27,7 +28,8 @@ internal val jvmCoercionToUnitPhase = makeIrFilePhase(
class JvmCoercionToUnitPatcher(val context: JvmBackendContext) : class JvmCoercionToUnitPatcher(val context: JvmBackendContext) :
InsertImplicitCasts( InsertImplicitCasts(
context.builtIns, context.irBuiltIns, context.builtIns, context.irBuiltIns,
TypeTranslator(context.ir.symbols.externalSymbolTable, context.state.languageVersionSettings) TypeTranslator(context.ir.symbols.externalSymbolTable, context.state.languageVersionSettings),
JvmGeneratorExtensions.samConversion
), ),
FileLoweringPass { FileLoweringPass {
@@ -28,8 +28,6 @@ import org.jetbrains.kotlin.ir.expressions.IrExpressionWithCopy
import org.jetbrains.kotlin.ir.expressions.IrTypeOperator import org.jetbrains.kotlin.ir.expressions.IrTypeOperator
import org.jetbrains.kotlin.ir.expressions.impl.* import org.jetbrains.kotlin.ir.expressions.impl.*
import org.jetbrains.kotlin.ir.types.classifierOrFail 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.KtElement
import org.jetbrains.kotlin.psi.KtExpression import org.jetbrains.kotlin.psi.KtExpression
import org.jetbrains.kotlin.psi.psiUtil.endOffset 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.callUtil.isSafeCall
import org.jetbrains.kotlin.resolve.calls.model.* import org.jetbrains.kotlin.resolve.calls.model.*
import org.jetbrains.kotlin.resolve.scopes.receivers.* import org.jetbrains.kotlin.resolve.scopes.receivers.*
import org.jetbrains.kotlin.synthetic.SamAdapterExtensionFunctionDescriptor
import org.jetbrains.kotlin.types.KotlinType import org.jetbrains.kotlin.types.KotlinType
import org.jetbrains.kotlin.types.TypeSubstitutor 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) { private fun StatementGenerator.generateSamConversionForValueArgumentsIfRequired(call: CallBuilder, originalDescriptor: CallableDescriptor) {
val underlyingDescriptor = when (originalDescriptor) { val underlyingDescriptor = context.extensions.samConversion.getOriginalForSamAdapter(originalDescriptor) ?: return
is SamAdapterDescriptor<*> -> originalDescriptor.baseDescriptorForSynthetic
is SamAdapterExtensionFunctionDescriptor -> originalDescriptor.baseDescriptorForSynthetic
else -> return
}
val originalValueParameters = originalDescriptor.valueParameters val originalValueParameters = originalDescriptor.valueParameters
val underlyingValueParameters = underlyingDescriptor.valueParameters val underlyingValueParameters = underlyingDescriptor.valueParameters
@@ -405,7 +398,7 @@ private fun StatementGenerator.generateSamConversionForValueArgumentsIfRequired(
val originalParameterType = originalValueParameters[i].type val originalParameterType = originalValueParameters[i].type
val underlyingParameterType = underlyingValueParameters[i].type val underlyingParameterType = underlyingValueParameters[i].type
if (!SingleAbstractMethodUtils.isSamType(underlyingParameterType)) continue if (!context.extensions.samConversion.isSamType(underlyingParameterType)) continue
if (!originalParameterType.isFunctionTypeOrSubtype) continue if (!originalParameterType.isFunctionTypeOrSubtype) continue
val originalArgument = call.irValueArgumentsByIndex[i] ?: continue val originalArgument = call.irValueArgumentsByIndex[i] ?: continue
@@ -437,7 +430,7 @@ fun StatementGenerator.pregenerateValueArgumentsUsing(
} }
fun StatementGenerator.pregenerateCallReceivers(resolvedCall: ResolvedCall<*>): CallBuilder { fun StatementGenerator.pregenerateCallReceivers(resolvedCall: ResolvedCall<*>): CallBuilder {
val call = unwrapCallableDescriptorAndTypeArguments(resolvedCall) val call = unwrapCallableDescriptorAndTypeArguments(resolvedCall, context.extensions.samConversion)
call.callReceiver = generateCallReceiver( call.callReceiver = generateCallReceiver(
resolvedCall.call.callElement, resolvedCall.call.callElement,
@@ -452,20 +445,21 @@ fun StatementGenerator.pregenerateCallReceivers(resolvedCall: ResolvedCall<*>):
return call return call
} }
private fun unwrapSpecialDescriptor(originalDescriptor: CallableDescriptor): CallableDescriptor = private fun unwrapSpecialDescriptor(
when (originalDescriptor) { descriptor: CallableDescriptor,
is ImportedFromObjectCallableDescriptor<*> -> unwrapSpecialDescriptor(originalDescriptor.callableFromObject) samConversion: GeneratorExtensions.SamConversion
is TypeAliasConstructorDescriptor -> originalDescriptor.underlyingConstructorDescriptor ): CallableDescriptor =
is SamAdapterDescriptor<*> -> unwrapSpecialDescriptor(originalDescriptor.baseDescriptorForSynthetic) when (descriptor) {
is SamAdapterExtensionFunctionDescriptor -> unwrapSpecialDescriptor(originalDescriptor.baseDescriptorForSynthetic) is ImportedFromObjectCallableDescriptor<*> -> unwrapSpecialDescriptor(descriptor.callableFromObject, samConversion)
else -> originalDescriptor 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 originalDescriptor = resolvedCall.resultingDescriptor
val candidateDescriptor = resolvedCall.candidateDescriptor val candidateDescriptor = resolvedCall.candidateDescriptor
val unwrappedDescriptor = unwrapSpecialDescriptor(originalDescriptor) val unwrappedDescriptor = unwrapSpecialDescriptor(originalDescriptor, samConversion)
val originalTypeArguments = resolvedCall.typeArguments val originalTypeArguments = resolvedCall.typeArguments
val unsubstitutedUnwrappedDescriptor = unwrappedDescriptor.original 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.types.classifierOrFail
import org.jetbrains.kotlin.ir.util.referenceFunction import org.jetbrains.kotlin.ir.util.referenceFunction
import org.jetbrains.kotlin.ir.util.render 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.KtElement
import org.jetbrains.kotlin.psi.psiUtil.endOffset import org.jetbrains.kotlin.psi.psiUtil.endOffset
import org.jetbrains.kotlin.psi.psiUtil.startOffsetSkippingComments 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 { fun generateCall(startOffset: Int, endOffset: Int, call: CallBuilder, origin: IrStatementOrigin? = null): IrExpression {
val descriptor = call.descriptor val descriptor = call.descriptor
if (context.extensions.samConversion.isSamConstructor(descriptor)) {
return generateSamConstructorCall(descriptor, startOffset, endOffset, call)
}
return when (descriptor) { return when (descriptor) {
is SamConstructorDescriptor ->
generateSamConstructorCall(descriptor, startOffset, endOffset, call)
is PropertyDescriptor -> is PropertyDescriptor ->
generatePropertyGetterCall(descriptor, startOffset, endOffset, call) generatePropertyGetterCall(descriptor, startOffset, endOffset, call)
is FunctionDescriptor -> is FunctionDescriptor ->
@@ -59,7 +60,7 @@ class CallGenerator(statementGenerator: StatementGenerator) : StatementGenerator
} }
private fun generateSamConstructorCall( private fun generateSamConstructorCall(
descriptor: SamConstructorDescriptor, descriptor: CallableDescriptor,
startOffset: Int, startOffset: Int,
endOffset: Int, endOffset: Int,
call: CallBuilder call: CallBuilder
@@ -5,10 +5,30 @@
package org.jetbrains.kotlin.psi2ir.generators 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.descriptors.DeclarationDescriptor
import org.jetbrains.kotlin.ir.declarations.IrDeclarationOrigin import org.jetbrains.kotlin.ir.declarations.IrDeclarationOrigin
import org.jetbrains.kotlin.types.KotlinType
open class GeneratorExtensions { open class GeneratorExtensions {
open val externalDeclarationOrigin: ((DeclarationDescriptor) -> IrDeclarationOrigin)? open val externalDeclarationOrigin: ((DeclarationDescriptor) -> IrDeclarationOrigin)?
get() = null 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 package org.jetbrains.kotlin.psi2ir.transformations
import org.jetbrains.kotlin.builtins.KotlinBuiltIns import org.jetbrains.kotlin.builtins.KotlinBuiltIns
import org.jetbrains.kotlin.descriptors.ClassDescriptor
import org.jetbrains.kotlin.ir.IrElement import org.jetbrains.kotlin.ir.IrElement
import org.jetbrains.kotlin.ir.IrStatement import org.jetbrains.kotlin.ir.IrStatement
import org.jetbrains.kotlin.ir.declarations.IrClass 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.coerceToUnitIfNeeded
import org.jetbrains.kotlin.ir.util.render import org.jetbrains.kotlin.ir.util.render
import org.jetbrains.kotlin.ir.visitors.IrElementTransformerVoid 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.containsNull
import org.jetbrains.kotlin.psi2ir.generators.GeneratorContext import org.jetbrains.kotlin.psi2ir.generators.GeneratorContext
import org.jetbrains.kotlin.psi2ir.generators.GeneratorExtensions
import org.jetbrains.kotlin.types.* import org.jetbrains.kotlin.types.*
import org.jetbrains.kotlin.types.checker.KotlinTypeChecker import org.jetbrains.kotlin.types.checker.KotlinTypeChecker
import org.jetbrains.kotlin.types.typeUtil.isNullableAny 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 import org.jetbrains.kotlin.types.typeUtil.makeNullable
fun insertImplicitCasts(element: IrElement, context: GeneratorContext) { 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( open class InsertImplicitCasts(
private val builtIns: KotlinBuiltIns, private val builtIns: KotlinBuiltIns,
private val irBuiltIns: IrBuiltIns, private val irBuiltIns: IrBuiltIns,
private val typeTranslator: TypeTranslator private val typeTranslator: TypeTranslator,
private val samConversion: GeneratorExtensions.SamConversion
) : IrElementTransformerVoid() { ) : IrElementTransformerVoid() {
private fun KotlinType.toIrType() = typeTranslator.translateType(this) private fun KotlinType.toIrType() = typeTranslator.translateType(this)
@@ -177,15 +181,10 @@ open class InsertImplicitCasts(
super.visitTypeOperator(expression) super.visitTypeOperator(expression)
private fun IrTypeOperatorCall.coerceArgumentToFunctionalType(): IrExpression { private fun IrTypeOperatorCall.coerceArgumentToFunctionalType(): IrExpression {
val targetClassDescriptor = typeOperandClassifier.descriptor as? JavaClassDescriptor val targetClassDescriptor = typeOperandClassifier.descriptor as? ClassDescriptor
?: throw AssertionError("Target type of $operator should be a Java class: ${render()}") ?: throw AssertionError("Target type of $operator should be a class: ${render()}")
val singleAbstractMethod = SingleAbstractMethodUtils.getSingleAbstractMethodOrNull(targetClassDescriptor) argument = argument.cast(samConversion.getFunctionTypeForSAMClass(targetClassDescriptor))
?: throw AssertionError("$targetClassDescriptor should have a single abstract method")
val functionalType = SingleAbstractMethodUtils.getFunctionTypeForAbstractMethod(singleAbstractMethod, false)
argument = argument.cast(functionalType)
return this return this
} }