Support SAM conversion in psi2ir
SAM conversion takes a function value (function type or a subtype), and produces a SAM interface value.
This commit is contained in:
+4
-3
@@ -19,13 +19,13 @@ package org.jetbrains.kotlin.backend.common
|
||||
import org.jetbrains.kotlin.builtins.KotlinBuiltIns
|
||||
import org.jetbrains.kotlin.descriptors.CallableMemberDescriptor
|
||||
import org.jetbrains.kotlin.ir.IrElement
|
||||
import org.jetbrains.kotlin.ir.declarations.*
|
||||
import org.jetbrains.kotlin.ir.declarations.IrClass
|
||||
import org.jetbrains.kotlin.ir.declarations.IrFunction
|
||||
import org.jetbrains.kotlin.ir.expressions.*
|
||||
import org.jetbrains.kotlin.ir.symbols.IrSymbol
|
||||
import org.jetbrains.kotlin.ir.types.*
|
||||
import org.jetbrains.kotlin.ir.util.isAnnotationClass
|
||||
import org.jetbrains.kotlin.ir.util.render
|
||||
import org.jetbrains.kotlin.ir.util.superTypes
|
||||
import org.jetbrains.kotlin.ir.visitors.IrElementVisitorVoid
|
||||
import org.jetbrains.kotlin.resolve.descriptorUtil.isEffectivelyExternal
|
||||
import org.jetbrains.kotlin.types.KotlinType
|
||||
@@ -166,7 +166,8 @@ class CheckIrElementVisitor(
|
||||
IrTypeOperator.IMPLICIT_CAST,
|
||||
IrTypeOperator.IMPLICIT_NOTNULL,
|
||||
IrTypeOperator.IMPLICIT_COERCION_TO_UNIT,
|
||||
IrTypeOperator.IMPLICIT_INTEGER_COERCION -> typeOperand.toKotlinType()
|
||||
IrTypeOperator.IMPLICIT_INTEGER_COERCION,
|
||||
IrTypeOperator.SAM_CONVERSION -> typeOperand.toKotlinType()
|
||||
|
||||
IrTypeOperator.SAFE_CAST -> typeOperand.makeNullable().toKotlinType()
|
||||
|
||||
|
||||
+2
-4
@@ -21,10 +21,7 @@ import org.jetbrains.kotlin.ir.expressions.impl.IrCompositeImpl
|
||||
import org.jetbrains.kotlin.ir.symbols.IrClassSymbol
|
||||
import org.jetbrains.kotlin.ir.symbols.IrTypeParameterSymbol
|
||||
import org.jetbrains.kotlin.ir.types.*
|
||||
import org.jetbrains.kotlin.ir.util.isFunctionOrKFunction
|
||||
import org.jetbrains.kotlin.ir.util.isInterface
|
||||
import org.jetbrains.kotlin.ir.util.isNullable
|
||||
import org.jetbrains.kotlin.ir.util.isTypeParameter
|
||||
import org.jetbrains.kotlin.ir.util.*
|
||||
import org.jetbrains.kotlin.ir.visitors.IrElementTransformer
|
||||
|
||||
class TypeOperatorLowering(val context: JsIrBackendContext) : FileLoweringPass {
|
||||
@@ -80,6 +77,7 @@ class TypeOperatorLowering(val context: JsIrBackendContext) : FileLoweringPass {
|
||||
IrTypeOperator.NOT_INSTANCEOF -> lowerInstanceOf(expression, data, true)
|
||||
IrTypeOperator.CAST -> lowerCast(expression, data, false)
|
||||
IrTypeOperator.SAFE_CAST -> lowerCast(expression, data, true)
|
||||
IrTypeOperator.SAM_CONVERSION -> TODO("SAM conversion: ${expression.render()}")
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
+2
-1
@@ -832,7 +832,8 @@ internal class DeepCopyIrTreeWithDescriptors(val targetDescriptor: FunctionDescr
|
||||
IrTypeOperator.IMPLICIT_CAST,
|
||||
IrTypeOperator.IMPLICIT_NOTNULL,
|
||||
IrTypeOperator.IMPLICIT_COERCION_TO_UNIT,
|
||||
IrTypeOperator.IMPLICIT_INTEGER_COERCION -> type
|
||||
IrTypeOperator.IMPLICIT_INTEGER_COERCION,
|
||||
IrTypeOperator.SAM_CONVERSION -> type
|
||||
IrTypeOperator.SAFE_CAST -> type.makeNullable()
|
||||
IrTypeOperator.INSTANCEOF,
|
||||
IrTypeOperator.NOT_INSTANCEOF -> context.irBuiltIns.booleanType
|
||||
|
||||
+66
-8
@@ -17,6 +17,7 @@
|
||||
package org.jetbrains.kotlin.psi2ir.generators
|
||||
|
||||
import org.jetbrains.kotlin.builtins.isBuiltinFunctionalType
|
||||
import org.jetbrains.kotlin.builtins.isFunctionTypeOrSubtype
|
||||
import org.jetbrains.kotlin.descriptors.*
|
||||
import org.jetbrains.kotlin.descriptors.impl.SyntheticFieldDescriptor
|
||||
import org.jetbrains.kotlin.descriptors.impl.TypeAliasConstructorDescriptor
|
||||
@@ -24,7 +25,11 @@ import org.jetbrains.kotlin.incremental.components.NoLookupLocation
|
||||
import org.jetbrains.kotlin.ir.expressions.IrDeclarationReference
|
||||
import org.jetbrains.kotlin.ir.expressions.IrExpression
|
||||
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
|
||||
@@ -37,6 +42,7 @@ 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
|
||||
|
||||
@@ -158,13 +164,15 @@ fun StatementGenerator.generateCallReceiver(
|
||||
): CallReceiver {
|
||||
val dispatchReceiverValue: IntermediateValue?
|
||||
val extensionReceiverValue: IntermediateValue?
|
||||
val startOffset = ktDefaultElement.startOffsetSkippingComments
|
||||
val endOffset = ktDefaultElement.endOffset
|
||||
when (calleeDescriptor) {
|
||||
is ImportedFromObjectCallableDescriptor<*> -> {
|
||||
assert(dispatchReceiver == null) {
|
||||
"Call for member imported from object $calleeDescriptor has non-null dispatch receiver $dispatchReceiver"
|
||||
}
|
||||
dispatchReceiverValue =
|
||||
generateReceiverForCalleeImportedFromObject(ktDefaultElement.startOffsetSkippingComments, ktDefaultElement.endOffset, calleeDescriptor)
|
||||
generateReceiverForCalleeImportedFromObject(startOffset, endOffset, calleeDescriptor)
|
||||
extensionReceiverValue = generateReceiverOrNull(ktDefaultElement, extensionReceiver)
|
||||
}
|
||||
is TypeAliasConstructorDescriptor -> {
|
||||
@@ -186,7 +194,7 @@ fun StatementGenerator.generateCallReceiver(
|
||||
SimpleCallReceiver(dispatchReceiverValue, extensionReceiverValue)
|
||||
extensionReceiverValue != null || dispatchReceiverValue != null ->
|
||||
SafeCallReceiver(
|
||||
this, ktDefaultElement.startOffsetSkippingComments, ktDefaultElement.endOffset,
|
||||
this, startOffset, endOffset,
|
||||
extensionReceiverValue, dispatchReceiverValue, isAssignmentReceiver
|
||||
)
|
||||
else ->
|
||||
@@ -250,7 +258,7 @@ fun StatementGenerator.generateVarargExpressionUsing(
|
||||
return irVararg
|
||||
}
|
||||
|
||||
private fun StatementGenerator.generateValueArgument(
|
||||
fun StatementGenerator.generateValueArgument(
|
||||
valueArgument: ResolvedValueArgument,
|
||||
valueParameter: ValueParameterDescriptor
|
||||
) = generateValueArgumentUsing(valueArgument, valueParameter) { generateExpression(it) }
|
||||
@@ -369,6 +377,51 @@ private fun StatementGenerator.pregenerateValueArguments(call: CallBuilder, reso
|
||||
pregenerateValueArgumentsUsing(call, resolvedCall) {
|
||||
generateExpression(it)
|
||||
}
|
||||
|
||||
generateSamConversionForValueArgumentsIfRequired(call, resolvedCall.resultingDescriptor)
|
||||
}
|
||||
|
||||
private fun StatementGenerator.generateSamConversionForValueArgumentsIfRequired(call: CallBuilder, originalDescriptor: CallableDescriptor) {
|
||||
val underlyingDescriptor = when (originalDescriptor) {
|
||||
is SamAdapterDescriptor<*> -> originalDescriptor.baseDescriptorForSynthetic
|
||||
is SamAdapterExtensionFunctionDescriptor -> originalDescriptor.baseDescriptorForSynthetic
|
||||
else -> return
|
||||
}
|
||||
|
||||
val originalValueParameters = originalDescriptor.valueParameters
|
||||
val underlyingValueParameters = underlyingDescriptor.valueParameters
|
||||
|
||||
assert(originalValueParameters.size == underlyingValueParameters.size) {
|
||||
"Mismatching value parameters, $originalDescriptor vs $underlyingDescriptor: " +
|
||||
"${originalValueParameters.size} != ${underlyingValueParameters.size}"
|
||||
}
|
||||
assert(originalValueParameters.size == call.argumentsCount) {
|
||||
"Mismatching value parameters, $originalDescriptor vs call: " +
|
||||
"${originalValueParameters.size} != ${call.argumentsCount}"
|
||||
}
|
||||
|
||||
for (i in underlyingValueParameters.indices) {
|
||||
val originalParameterType = originalValueParameters[i].type
|
||||
val underlyingParameterType = underlyingValueParameters[i].type
|
||||
|
||||
if (!SingleAbstractMethodUtils.isSamType(underlyingParameterType)) continue
|
||||
if (!originalParameterType.isFunctionTypeOrSubtype) continue
|
||||
|
||||
val originalArgument = call.irValueArgumentsByIndex[i] ?: continue
|
||||
|
||||
val targetType = underlyingParameterType.toIrType()
|
||||
val targetClassifier = targetType.classifierOrFail
|
||||
|
||||
call.irValueArgumentsByIndex[i] =
|
||||
IrTypeOperatorCallImpl(
|
||||
originalArgument.startOffset, originalArgument.endOffset,
|
||||
targetType,
|
||||
IrTypeOperator.SAM_CONVERSION,
|
||||
targetType,
|
||||
targetClassifier,
|
||||
originalArgument
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
fun StatementGenerator.pregenerateValueArgumentsUsing(
|
||||
@@ -398,15 +451,20 @@ 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
|
||||
}
|
||||
|
||||
fun unwrapCallableDescriptorAndTypeArguments(resolvedCall: ResolvedCall<*>): CallBuilder {
|
||||
val originalDescriptor = resolvedCall.resultingDescriptor
|
||||
val candidateDescriptor = resolvedCall.candidateDescriptor
|
||||
|
||||
val unwrappedDescriptor = when (originalDescriptor) {
|
||||
is ImportedFromObjectCallableDescriptor<*> -> originalDescriptor.callableFromObject
|
||||
is TypeAliasConstructorDescriptor -> originalDescriptor.underlyingConstructorDescriptor
|
||||
else -> originalDescriptor
|
||||
}
|
||||
val unwrappedDescriptor = unwrapSpecialDescriptor(originalDescriptor)
|
||||
|
||||
val originalTypeArguments = resolvedCall.typeArguments
|
||||
val unsubstitutedUnwrappedDescriptor = unwrappedDescriptor.original
|
||||
|
||||
@@ -21,7 +21,9 @@ import org.jetbrains.kotlin.descriptors.impl.LocalVariableDescriptor
|
||||
import org.jetbrains.kotlin.descriptors.impl.SyntheticFieldDescriptor
|
||||
import org.jetbrains.kotlin.ir.expressions.*
|
||||
import org.jetbrains.kotlin.ir.expressions.impl.*
|
||||
import org.jetbrains.kotlin.ir.types.classifierOrFail
|
||||
import org.jetbrains.kotlin.ir.util.referenceFunction
|
||||
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
|
||||
@@ -40,6 +42,8 @@ class CallGenerator(statementGenerator: StatementGenerator) : StatementGenerator
|
||||
val descriptor = call.descriptor
|
||||
|
||||
return when (descriptor) {
|
||||
is SamConstructorDescriptor ->
|
||||
generateSamConstructorCall(descriptor, startOffset, endOffset, call)
|
||||
is PropertyDescriptor ->
|
||||
generatePropertyGetterCall(descriptor, startOffset, endOffset, call)
|
||||
is FunctionDescriptor ->
|
||||
@@ -51,6 +55,24 @@ class CallGenerator(statementGenerator: StatementGenerator) : StatementGenerator
|
||||
}
|
||||
}
|
||||
|
||||
private fun generateSamConstructorCall(
|
||||
descriptor: SamConstructorDescriptor,
|
||||
startOffset: Int,
|
||||
endOffset: Int,
|
||||
call: CallBuilder
|
||||
): IrExpression {
|
||||
val targetType = descriptor.returnType!!.toIrType()
|
||||
|
||||
return IrTypeOperatorCallImpl(
|
||||
startOffset, endOffset,
|
||||
targetType,
|
||||
IrTypeOperator.SAM_CONVERSION,
|
||||
targetType,
|
||||
targetType.classifierOrFail,
|
||||
call.irValueArgumentsByIndex[0]!!
|
||||
)
|
||||
}
|
||||
|
||||
fun generateValueReference(
|
||||
startOffset: Int,
|
||||
endOffset: Int,
|
||||
|
||||
+23
@@ -30,7 +30,10 @@ import org.jetbrains.kotlin.ir.types.IrType
|
||||
import org.jetbrains.kotlin.ir.types.classifierOrFail
|
||||
import org.jetbrains.kotlin.ir.types.impl.originalKotlinType
|
||||
import org.jetbrains.kotlin.ir.util.TypeTranslator
|
||||
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.types.KotlinType
|
||||
@@ -167,6 +170,26 @@ open class InsertImplicitCasts(
|
||||
finallyExpression = finallyExpression?.coerceToUnit()
|
||||
}
|
||||
|
||||
override fun visitTypeOperator(expression: IrTypeOperatorCall): IrExpression =
|
||||
if (expression.operator == IrTypeOperator.SAM_CONVERSION)
|
||||
expression.coerceArgumentToFunctionalType()
|
||||
else
|
||||
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 singleAbstractMethod = SingleAbstractMethodUtils.getSingleAbstractMethodOrNull(targetClassDescriptor)
|
||||
?: throw AssertionError("$targetClassDescriptor should have a single abstract method")
|
||||
|
||||
val functionalType = SingleAbstractMethodUtils.getFunctionTypeForAbstractMethod(singleAbstractMethod, false)
|
||||
|
||||
argument = argument.cast(functionalType)
|
||||
|
||||
return this
|
||||
}
|
||||
|
||||
override fun visitVararg(expression: IrVararg): IrExpression =
|
||||
expression.transformPostfix {
|
||||
elements.forEachIndexed { i, element ->
|
||||
|
||||
@@ -27,7 +27,8 @@ enum class IrTypeOperator {
|
||||
IMPLICIT_INTEGER_COERCION,
|
||||
SAFE_CAST,
|
||||
INSTANCEOF,
|
||||
NOT_INSTANCEOF;
|
||||
NOT_INSTANCEOF,
|
||||
SAM_CONVERSION;
|
||||
}
|
||||
|
||||
interface IrTypeOperatorCall : IrExpression {
|
||||
|
||||
Reference in New Issue
Block a user