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:
Dmitry Petrov
2018-12-17 17:00:58 +03:00
parent 2c327564d5
commit 85f55dec9a
15 changed files with 494 additions and 19 deletions
@@ -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()
@@ -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()}")
}
}
@@ -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
@@ -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,
@@ -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 {
@@ -0,0 +1,7 @@
// WITH_JDK
fun test1() = Runnable { }
fun test2(a: () -> Unit) = Runnable(a)
fun foo() {}
fun test3() = Runnable(::foo)
@@ -0,0 +1,27 @@
FILE fqName:<root> fileName:/samConstructors.kt
FUN name:test1 visibility:public modality:FINAL <> () returnType:java.lang.Runnable flags:
BLOCK_BODY
RETURN type=kotlin.Nothing from='test1(): Runnable'
TYPE_OP type=java.lang.Runnable origin=SAM_CONVERSION typeOperand=java.lang.Runnable
typeOperand: CLASS IR_EXTERNAL_DECLARATION_STUB INTERFACE name:Runnable modality:ABSTRACT visibility:public flags: superTypes:[kotlin.Any]
BLOCK type=kotlin.Function0<kotlin.Unit> origin=LAMBDA
FUN LOCAL_FUNCTION_FOR_LAMBDA name:<anonymous> visibility:local modality:FINAL <> () returnType:kotlin.Unit flags:
BLOCK_BODY
RETURN type=kotlin.Nothing from='<anonymous>(): Unit'
GET_OBJECT 'Unit' type=kotlin.Unit
FUNCTION_REFERENCE '<anonymous>(): Unit' type=kotlin.Function0<kotlin.Unit> origin=LAMBDA
FUN name:test2 visibility:public modality:FINAL <> (a:kotlin.Function0<kotlin.Unit>) returnType:java.lang.Runnable flags:
VALUE_PARAMETER name:a index:0 type:kotlin.Function0<kotlin.Unit> flags:
BLOCK_BODY
RETURN type=kotlin.Nothing from='test2(() -> Unit): Runnable'
TYPE_OP type=java.lang.Runnable origin=SAM_CONVERSION typeOperand=java.lang.Runnable
typeOperand: CLASS IR_EXTERNAL_DECLARATION_STUB INTERFACE name:Runnable modality:ABSTRACT visibility:public flags: superTypes:[kotlin.Any]
GET_VAR 'value-parameter a: () -> Unit' type=kotlin.Function0<kotlin.Unit> origin=null
FUN name:foo visibility:public modality:FINAL <> () returnType:kotlin.Unit flags:
BLOCK_BODY
FUN name:test3 visibility:public modality:FINAL <> () returnType:java.lang.Runnable flags:
BLOCK_BODY
RETURN type=kotlin.Nothing from='test3(): Runnable'
TYPE_OP type=java.lang.Runnable origin=SAM_CONVERSION typeOperand=java.lang.Runnable
typeOperand: CLASS IR_EXTERNAL_DECLARATION_STUB INTERFACE name:Runnable modality:ABSTRACT visibility:public flags: superTypes:[kotlin.Any]
FUNCTION_REFERENCE 'foo(): Unit' type=kotlin.reflect.KFunction0<kotlin.Unit> origin=null
@@ -0,0 +1,31 @@
// WITH_JDK
// FILE: samConversions.kt
fun J.test0(a: Runnable) {
J.runStatic(a)
runIt(a)
}
fun test1() {
J.runStatic { test1() }
}
fun J.test2() {
runIt { test1() }
}
fun J.test3(a: () -> Unit) {
run2(a, a)
}
fun J.test4(a: () -> Unit, b: () -> Unit, flag: Boolean) {
runIt(if (flag) a else b)
}
// FILE: J.java
public class J {
public static void runStatic(Runnable r) {}
public void runIt(Runnable r) {}
public void run2(Runnable r1, Runnable r2) {}
}
@@ -0,0 +1,63 @@
FILE fqName:<root> fileName:/samConversions.kt
FUN name:test0 visibility:public modality:FINAL <> ($receiver:J, a:java.lang.Runnable) returnType:kotlin.Unit flags:
$receiver: VALUE_PARAMETER name:<this> type:J flags:
VALUE_PARAMETER name:a index:0 type:java.lang.Runnable flags:
BLOCK_BODY
CALL 'runStatic(Runnable!): Unit' type=kotlin.Unit origin=null
r: GET_VAR 'value-parameter a: Runnable' type=java.lang.Runnable origin=null
CALL 'runIt(Runnable!): Unit' type=kotlin.Unit origin=null
$this: GET_VAR 'this@test0: J' type=J origin=null
r: GET_VAR 'value-parameter a: Runnable' type=java.lang.Runnable origin=null
FUN name:test1 visibility:public modality:FINAL <> () returnType:kotlin.Unit flags:
BLOCK_BODY
CALL 'runStatic(Runnable!): Unit' type=kotlin.Unit origin=null
r: TYPE_OP type=java.lang.Runnable? origin=SAM_CONVERSION typeOperand=java.lang.Runnable?
typeOperand: CLASS IR_EXTERNAL_DECLARATION_STUB INTERFACE name:Runnable modality:ABSTRACT visibility:public flags: superTypes:[kotlin.Any]
BLOCK type=kotlin.Function0<kotlin.Unit> origin=LAMBDA
FUN LOCAL_FUNCTION_FOR_LAMBDA name:<anonymous> visibility:local modality:FINAL <> () returnType:kotlin.Unit flags:
BLOCK_BODY
RETURN type=kotlin.Nothing from='<anonymous>(): Unit'
CALL 'test1(): Unit' type=kotlin.Unit origin=null
FUNCTION_REFERENCE '<anonymous>(): Unit' type=kotlin.Function0<kotlin.Unit> origin=LAMBDA
FUN name:test2 visibility:public modality:FINAL <> ($receiver:J) returnType:kotlin.Unit flags:
$receiver: VALUE_PARAMETER name:<this> type:J flags:
BLOCK_BODY
CALL 'runIt(Runnable!): Unit' type=kotlin.Unit origin=null
$this: GET_VAR 'this@test2: J' type=J origin=null
r: TYPE_OP type=java.lang.Runnable? origin=SAM_CONVERSION typeOperand=java.lang.Runnable?
typeOperand: CLASS IR_EXTERNAL_DECLARATION_STUB INTERFACE name:Runnable modality:ABSTRACT visibility:public flags: superTypes:[kotlin.Any]
BLOCK type=kotlin.Function0<kotlin.Unit> origin=LAMBDA
FUN LOCAL_FUNCTION_FOR_LAMBDA name:<anonymous> visibility:local modality:FINAL <> () returnType:kotlin.Unit flags:
BLOCK_BODY
RETURN type=kotlin.Nothing from='<anonymous>(): Unit'
CALL 'test1(): Unit' type=kotlin.Unit origin=null
FUNCTION_REFERENCE '<anonymous>(): Unit' type=kotlin.Function0<kotlin.Unit> origin=LAMBDA
FUN name:test3 visibility:public modality:FINAL <> ($receiver:J, a:kotlin.Function0<kotlin.Unit>) returnType:kotlin.Unit flags:
$receiver: VALUE_PARAMETER name:<this> type:J flags:
VALUE_PARAMETER name:a index:0 type:kotlin.Function0<kotlin.Unit> flags:
BLOCK_BODY
CALL 'run2(Runnable!, Runnable!): Unit' type=kotlin.Unit origin=null
$this: GET_VAR 'this@test3: J' type=J origin=null
r1: TYPE_OP type=java.lang.Runnable? origin=SAM_CONVERSION typeOperand=java.lang.Runnable?
typeOperand: CLASS IR_EXTERNAL_DECLARATION_STUB INTERFACE name:Runnable modality:ABSTRACT visibility:public flags: superTypes:[kotlin.Any]
GET_VAR 'value-parameter a: () -> Unit' type=kotlin.Function0<kotlin.Unit> origin=null
r2: TYPE_OP type=java.lang.Runnable? origin=SAM_CONVERSION typeOperand=java.lang.Runnable?
typeOperand: CLASS IR_EXTERNAL_DECLARATION_STUB INTERFACE name:Runnable modality:ABSTRACT visibility:public flags: superTypes:[kotlin.Any]
GET_VAR 'value-parameter a: () -> Unit' type=kotlin.Function0<kotlin.Unit> origin=null
FUN name:test4 visibility:public modality:FINAL <> ($receiver:J, a:kotlin.Function0<kotlin.Unit>, b:kotlin.Function0<kotlin.Unit>, flag:kotlin.Boolean) returnType:kotlin.Unit flags:
$receiver: VALUE_PARAMETER name:<this> type:J flags:
VALUE_PARAMETER name:a index:0 type:kotlin.Function0<kotlin.Unit> flags:
VALUE_PARAMETER name:b index:1 type:kotlin.Function0<kotlin.Unit> flags:
VALUE_PARAMETER name:flag index:2 type:kotlin.Boolean flags:
BLOCK_BODY
CALL 'runIt(Runnable!): Unit' type=kotlin.Unit origin=null
$this: GET_VAR 'this@test4: J' type=J origin=null
r: TYPE_OP type=java.lang.Runnable? origin=SAM_CONVERSION typeOperand=java.lang.Runnable?
typeOperand: CLASS IR_EXTERNAL_DECLARATION_STUB INTERFACE name:Runnable modality:ABSTRACT visibility:public flags: superTypes:[kotlin.Any]
WHEN type=kotlin.Function0<kotlin.Unit> origin=null
BRANCH
if: GET_VAR 'value-parameter flag: Boolean' type=kotlin.Boolean origin=null
then: GET_VAR 'value-parameter a: () -> Unit' type=kotlin.Function0<kotlin.Unit> origin=null
BRANCH
if: CONST Boolean type=kotlin.Boolean value=true
then: GET_VAR 'value-parameter b: () -> Unit' type=kotlin.Function0<kotlin.Unit> origin=null
@@ -0,0 +1,71 @@
// !LANGUAGE: -NewInference
// NB new inference doesn't really work with old JVM back-end.
// WITH_JDK
// FILE: samConversionsWithSmartCasts.kt
fun test1(a: () -> Unit) {
if (a is Runnable) {
J.runStatic(a)
}
}
fun test2(a: () -> Unit) {
if (a is Runnable) {
J().run1(a)
}
}
fun test3(a: () -> Unit) {
if (a is Runnable) {
J().run2(a, a)
}
}
fun test4(a: () -> Unit, b: () -> Unit) {
if (a is Runnable) {
J().run2(a, b)
}
}
fun test5(a: Any) {
if (a is Runnable) {
J().run1(a)
}
}
fun test5x(a: Any) {
if (a is Runnable) {
a as () -> Unit
J().run1(a)
}
}
fun test6(a: Any) {
a as () -> Unit
J().run1(a)
}
fun test7(a: (Int) -> Int) {
a as () -> Unit
J().run1(a)
}
fun test8(a: () -> Unit) {
J().run1(J.id(a))
}
fun test9() {
J().run1(::test9)
}
// FILE: J.java
public class J {
public static void runStatic(Runnable r) {}
public void run1(Runnable r) {}
public void run2(Runnable r1, Runnable r2) {}
public static <T> T id(T x) { return x; }
}
@@ -0,0 +1,143 @@
FILE fqName:<root> fileName:/samConversionsWithSmartCasts.kt
FUN name:test1 visibility:public modality:FINAL <> (a:kotlin.Function0<kotlin.Unit>) returnType:kotlin.Unit flags:
VALUE_PARAMETER name:a index:0 type:kotlin.Function0<kotlin.Unit> flags:
BLOCK_BODY
WHEN type=kotlin.Unit origin=null
BRANCH
if: TYPE_OP type=kotlin.Boolean origin=INSTANCEOF typeOperand=java.lang.Runnable
typeOperand: CLASS IR_EXTERNAL_DECLARATION_STUB INTERFACE name:Runnable modality:ABSTRACT visibility:public flags: superTypes:[kotlin.Any]
GET_VAR 'value-parameter a: () -> Unit' type=kotlin.Function0<kotlin.Unit> origin=null
then: BLOCK type=kotlin.Unit origin=null
CALL 'runStatic(Runnable!): Unit' type=kotlin.Unit origin=null
r: TYPE_OP type=java.lang.Runnable origin=IMPLICIT_CAST typeOperand=java.lang.Runnable
typeOperand: CLASS IR_EXTERNAL_DECLARATION_STUB INTERFACE name:Runnable modality:ABSTRACT visibility:public flags: superTypes:[kotlin.Any]
GET_VAR 'value-parameter a: () -> Unit' type=kotlin.Function0<kotlin.Unit> origin=null
FUN name:test2 visibility:public modality:FINAL <> (a:kotlin.Function0<kotlin.Unit>) returnType:kotlin.Unit flags:
VALUE_PARAMETER name:a index:0 type:kotlin.Function0<kotlin.Unit> flags:
BLOCK_BODY
WHEN type=kotlin.Unit origin=null
BRANCH
if: TYPE_OP type=kotlin.Boolean origin=INSTANCEOF typeOperand=java.lang.Runnable
typeOperand: CLASS IR_EXTERNAL_DECLARATION_STUB INTERFACE name:Runnable modality:ABSTRACT visibility:public flags: superTypes:[kotlin.Any]
GET_VAR 'value-parameter a: () -> Unit' type=kotlin.Function0<kotlin.Unit> origin=null
then: BLOCK type=kotlin.Unit origin=null
CALL 'run1(Runnable!): Unit' type=kotlin.Unit origin=null
$this: CALL 'constructor J()' type=J origin=null
r: TYPE_OP type=java.lang.Runnable origin=IMPLICIT_CAST typeOperand=java.lang.Runnable
typeOperand: CLASS IR_EXTERNAL_DECLARATION_STUB INTERFACE name:Runnable modality:ABSTRACT visibility:public flags: superTypes:[kotlin.Any]
GET_VAR 'value-parameter a: () -> Unit' type=kotlin.Function0<kotlin.Unit> origin=null
FUN name:test3 visibility:public modality:FINAL <> (a:kotlin.Function0<kotlin.Unit>) returnType:kotlin.Unit flags:
VALUE_PARAMETER name:a index:0 type:kotlin.Function0<kotlin.Unit> flags:
BLOCK_BODY
WHEN type=kotlin.Unit origin=null
BRANCH
if: TYPE_OP type=kotlin.Boolean origin=INSTANCEOF typeOperand=java.lang.Runnable
typeOperand: CLASS IR_EXTERNAL_DECLARATION_STUB INTERFACE name:Runnable modality:ABSTRACT visibility:public flags: superTypes:[kotlin.Any]
GET_VAR 'value-parameter a: () -> Unit' type=kotlin.Function0<kotlin.Unit> origin=null
then: BLOCK type=kotlin.Unit origin=null
CALL 'run2(Runnable!, Runnable!): Unit' type=kotlin.Unit origin=null
$this: CALL 'constructor J()' type=J origin=null
r1: TYPE_OP type=java.lang.Runnable origin=IMPLICIT_CAST typeOperand=java.lang.Runnable
typeOperand: CLASS IR_EXTERNAL_DECLARATION_STUB INTERFACE name:Runnable modality:ABSTRACT visibility:public flags: superTypes:[kotlin.Any]
GET_VAR 'value-parameter a: () -> Unit' type=kotlin.Function0<kotlin.Unit> origin=null
r2: TYPE_OP type=java.lang.Runnable origin=IMPLICIT_CAST typeOperand=java.lang.Runnable
typeOperand: CLASS IR_EXTERNAL_DECLARATION_STUB INTERFACE name:Runnable modality:ABSTRACT visibility:public flags: superTypes:[kotlin.Any]
GET_VAR 'value-parameter a: () -> Unit' type=kotlin.Function0<kotlin.Unit> origin=null
FUN name:test4 visibility:public modality:FINAL <> (a:kotlin.Function0<kotlin.Unit>, b:kotlin.Function0<kotlin.Unit>) returnType:kotlin.Unit flags:
VALUE_PARAMETER name:a index:0 type:kotlin.Function0<kotlin.Unit> flags:
VALUE_PARAMETER name:b index:1 type:kotlin.Function0<kotlin.Unit> flags:
BLOCK_BODY
WHEN type=kotlin.Unit origin=null
BRANCH
if: TYPE_OP type=kotlin.Boolean origin=INSTANCEOF typeOperand=java.lang.Runnable
typeOperand: CLASS IR_EXTERNAL_DECLARATION_STUB INTERFACE name:Runnable modality:ABSTRACT visibility:public flags: superTypes:[kotlin.Any]
GET_VAR 'value-parameter a: () -> Unit' type=kotlin.Function0<kotlin.Unit> origin=null
then: BLOCK type=kotlin.Unit origin=null
CALL 'run2(Runnable!, Runnable!): Unit' type=kotlin.Unit origin=null
$this: CALL 'constructor J()' type=J origin=null
r1: TYPE_OP type=java.lang.Runnable? origin=SAM_CONVERSION typeOperand=java.lang.Runnable?
typeOperand: CLASS IR_EXTERNAL_DECLARATION_STUB INTERFACE name:Runnable modality:ABSTRACT visibility:public flags: superTypes:[kotlin.Any]
GET_VAR 'value-parameter a: () -> Unit' type=kotlin.Function0<kotlin.Unit> origin=null
r2: TYPE_OP type=java.lang.Runnable? origin=SAM_CONVERSION typeOperand=java.lang.Runnable?
typeOperand: CLASS IR_EXTERNAL_DECLARATION_STUB INTERFACE name:Runnable modality:ABSTRACT visibility:public flags: superTypes:[kotlin.Any]
GET_VAR 'value-parameter b: () -> Unit' type=kotlin.Function0<kotlin.Unit> origin=null
FUN name:test5 visibility:public modality:FINAL <> (a:kotlin.Any) returnType:kotlin.Unit flags:
VALUE_PARAMETER name:a index:0 type:kotlin.Any flags:
BLOCK_BODY
WHEN type=kotlin.Unit origin=null
BRANCH
if: TYPE_OP type=kotlin.Boolean origin=INSTANCEOF typeOperand=java.lang.Runnable
typeOperand: CLASS IR_EXTERNAL_DECLARATION_STUB INTERFACE name:Runnable modality:ABSTRACT visibility:public flags: superTypes:[kotlin.Any]
GET_VAR 'value-parameter a: Any' type=kotlin.Any origin=null
then: BLOCK type=kotlin.Unit origin=null
CALL 'run1(Runnable!): Unit' type=kotlin.Unit origin=null
$this: CALL 'constructor J()' type=J origin=null
r: TYPE_OP type=java.lang.Runnable origin=IMPLICIT_CAST typeOperand=java.lang.Runnable
typeOperand: CLASS IR_EXTERNAL_DECLARATION_STUB INTERFACE name:Runnable modality:ABSTRACT visibility:public flags: superTypes:[kotlin.Any]
GET_VAR 'value-parameter a: Any' type=kotlin.Any origin=null
FUN name:test5x visibility:public modality:FINAL <> (a:kotlin.Any) returnType:kotlin.Unit flags:
VALUE_PARAMETER name:a index:0 type:kotlin.Any flags:
BLOCK_BODY
WHEN type=kotlin.Unit origin=null
BRANCH
if: TYPE_OP type=kotlin.Boolean origin=INSTANCEOF typeOperand=java.lang.Runnable
typeOperand: CLASS IR_EXTERNAL_DECLARATION_STUB INTERFACE name:Runnable modality:ABSTRACT visibility:public flags: superTypes:[kotlin.Any]
GET_VAR 'value-parameter a: Any' type=kotlin.Any origin=null
then: BLOCK type=kotlin.Unit origin=null
TYPE_OP type=kotlin.Unit origin=IMPLICIT_COERCION_TO_UNIT typeOperand=kotlin.Unit
typeOperand: CLASS IR_EXTERNAL_DECLARATION_STUB OBJECT name:Unit modality:FINAL visibility:public flags: superTypes:[kotlin.Any]
TYPE_OP type=kotlin.Function0<kotlin.Unit> origin=CAST typeOperand=kotlin.Function0<kotlin.Unit>
typeOperand: CLASS IR_EXTERNAL_DECLARATION_STUB INTERFACE name:Function0 modality:ABSTRACT visibility:public flags: superTypes:[kotlin.Function<R>]
GET_VAR 'value-parameter a: Any' type=kotlin.Any origin=null
CALL 'run1(Runnable!): Unit' type=kotlin.Unit origin=null
$this: CALL 'constructor J()' type=J origin=null
r: TYPE_OP type=java.lang.Runnable origin=IMPLICIT_CAST typeOperand=java.lang.Runnable
typeOperand: CLASS IR_EXTERNAL_DECLARATION_STUB INTERFACE name:Runnable modality:ABSTRACT visibility:public flags: superTypes:[kotlin.Any]
GET_VAR 'value-parameter a: Any' type=kotlin.Any origin=null
FUN name:test6 visibility:public modality:FINAL <> (a:kotlin.Any) returnType:kotlin.Unit flags:
VALUE_PARAMETER name:a index:0 type:kotlin.Any flags:
BLOCK_BODY
TYPE_OP type=kotlin.Unit origin=IMPLICIT_COERCION_TO_UNIT typeOperand=kotlin.Unit
typeOperand: CLASS IR_EXTERNAL_DECLARATION_STUB OBJECT name:Unit modality:FINAL visibility:public flags: superTypes:[kotlin.Any]
TYPE_OP type=kotlin.Function0<kotlin.Unit> origin=CAST typeOperand=kotlin.Function0<kotlin.Unit>
typeOperand: CLASS IR_EXTERNAL_DECLARATION_STUB INTERFACE name:Function0 modality:ABSTRACT visibility:public flags: superTypes:[kotlin.Function<R>]
GET_VAR 'value-parameter a: Any' type=kotlin.Any origin=null
CALL 'run1(Runnable!): Unit' type=kotlin.Unit origin=null
$this: CALL 'constructor J()' type=J origin=null
r: TYPE_OP type=java.lang.Runnable? origin=SAM_CONVERSION typeOperand=java.lang.Runnable?
typeOperand: CLASS IR_EXTERNAL_DECLARATION_STUB INTERFACE name:Runnable modality:ABSTRACT visibility:public flags: superTypes:[kotlin.Any]
TYPE_OP type=kotlin.Function0<kotlin.Unit> origin=IMPLICIT_CAST typeOperand=kotlin.Function0<kotlin.Unit>
typeOperand: CLASS IR_EXTERNAL_DECLARATION_STUB INTERFACE name:Function0 modality:ABSTRACT visibility:public flags: superTypes:[kotlin.Function<R>]
GET_VAR 'value-parameter a: Any' type=kotlin.Any origin=null
FUN name:test7 visibility:public modality:FINAL <> (a:kotlin.Function1<kotlin.Int, kotlin.Int>) returnType:kotlin.Unit flags:
VALUE_PARAMETER name:a index:0 type:kotlin.Function1<kotlin.Int, kotlin.Int> flags:
BLOCK_BODY
TYPE_OP type=kotlin.Unit origin=IMPLICIT_COERCION_TO_UNIT typeOperand=kotlin.Unit
typeOperand: CLASS IR_EXTERNAL_DECLARATION_STUB OBJECT name:Unit modality:FINAL visibility:public flags: superTypes:[kotlin.Any]
TYPE_OP type=kotlin.Function0<kotlin.Unit> origin=CAST typeOperand=kotlin.Function0<kotlin.Unit>
typeOperand: CLASS IR_EXTERNAL_DECLARATION_STUB INTERFACE name:Function0 modality:ABSTRACT visibility:public flags: superTypes:[kotlin.Function<R>]
GET_VAR 'value-parameter a: (Int) -> Int' type=kotlin.Function1<kotlin.Int, kotlin.Int> origin=null
CALL 'run1(Runnable!): Unit' type=kotlin.Unit origin=null
$this: CALL 'constructor J()' type=J origin=null
r: TYPE_OP type=java.lang.Runnable? origin=SAM_CONVERSION typeOperand=java.lang.Runnable?
typeOperand: CLASS IR_EXTERNAL_DECLARATION_STUB INTERFACE name:Runnable modality:ABSTRACT visibility:public flags: superTypes:[kotlin.Any]
TYPE_OP type=kotlin.Function0<kotlin.Unit> origin=IMPLICIT_CAST typeOperand=kotlin.Function0<kotlin.Unit>
typeOperand: CLASS IR_EXTERNAL_DECLARATION_STUB INTERFACE name:Function0 modality:ABSTRACT visibility:public flags: superTypes:[kotlin.Function<R>]
GET_VAR 'value-parameter a: (Int) -> Int' type=kotlin.Function1<kotlin.Int, kotlin.Int> origin=null
FUN name:test8 visibility:public modality:FINAL <> (a:kotlin.Function0<kotlin.Unit>) returnType:kotlin.Unit flags:
VALUE_PARAMETER name:a index:0 type:kotlin.Function0<kotlin.Unit> flags:
BLOCK_BODY
CALL 'run1(Runnable!): Unit' type=kotlin.Unit origin=null
$this: CALL 'constructor J()' type=J origin=null
r: TYPE_OP type=java.lang.Runnable? origin=SAM_CONVERSION typeOperand=java.lang.Runnable?
typeOperand: CLASS IR_EXTERNAL_DECLARATION_STUB INTERFACE name:Runnable modality:ABSTRACT visibility:public flags: superTypes:[kotlin.Any]
CALL 'id(T!): T!' type=kotlin.Function0<kotlin.Unit>? origin=null
<T : Any!>: kotlin.Function0<kotlin.Unit>?
x: GET_VAR 'value-parameter a: () -> Unit' type=kotlin.Function0<kotlin.Unit> origin=null
FUN name:test9 visibility:public modality:FINAL <> () returnType:kotlin.Unit flags:
BLOCK_BODY
CALL 'run1(Runnable!): Unit' type=kotlin.Unit origin=null
$this: CALL 'constructor J()' type=J origin=null
r: TYPE_OP type=java.lang.Runnable? origin=SAM_CONVERSION typeOperand=java.lang.Runnable?
typeOperand: CLASS IR_EXTERNAL_DECLARATION_STUB INTERFACE name:Runnable modality:ABSTRACT visibility:public flags: superTypes:[kotlin.Any]
FUNCTION_REFERENCE 'test9(): Unit' type=kotlin.reflect.KFunction0<kotlin.Unit> origin=null
+3 -2
View File
@@ -2,8 +2,9 @@ FILE fqName:<root> fileName:/samAdapter.kt
FUN name:test1 visibility:public modality:FINAL <> () returnType:kotlin.Unit flags:
BLOCK_BODY
VAR name:hello type:java.lang.Runnable flags:val
CALL 'Runnable(() -> Unit): Runnable' type=java.lang.Runnable origin=null
function: BLOCK type=kotlin.Function0<kotlin.Unit> origin=LAMBDA
TYPE_OP type=java.lang.Runnable origin=SAM_CONVERSION typeOperand=java.lang.Runnable
typeOperand: CLASS IR_EXTERNAL_DECLARATION_STUB INTERFACE name:Runnable modality:ABSTRACT visibility:public flags: superTypes:[kotlin.Any]
BLOCK type=kotlin.Function0<kotlin.Unit> origin=LAMBDA
FUN LOCAL_FUNCTION_FOR_LAMBDA name:<anonymous> visibility:local modality:FINAL <> () returnType:kotlin.Unit flags:
BLOCK_BODY
RETURN type=kotlin.Nothing from='<anonymous>(): Unit'
@@ -1284,6 +1284,34 @@ public class IrTextTestCaseGenerated extends AbstractIrTextTestCase {
runTest("compiler/testData/ir/irText/expressions/floatingPointComparisons/whenByFloatingPoint.kt");
}
}
@TestMetadata("compiler/testData/ir/irText/expressions/sam")
@TestDataPath("$PROJECT_ROOT")
@RunWith(JUnit3RunnerWithInners.class)
public static class Sam extends AbstractIrTextTestCase {
private void runTest(String testDataFilePath) throws Exception {
KotlinTestUtils.runTest(this::doTest, TargetBackend.ANY, testDataFilePath);
}
public void testAllFilesPresentInSam() throws Exception {
KotlinTestUtils.assertAllTestsPresentByMetadata(this.getClass(), new File("compiler/testData/ir/irText/expressions/sam"), Pattern.compile("^(.+)\\.kt$"), TargetBackend.ANY, true);
}
@TestMetadata("samConstructors.kt")
public void testSamConstructors() throws Exception {
runTest("compiler/testData/ir/irText/expressions/sam/samConstructors.kt");
}
@TestMetadata("samConversions.kt")
public void testSamConversions() throws Exception {
runTest("compiler/testData/ir/irText/expressions/sam/samConversions.kt");
}
@TestMetadata("samConversionsWithSmartCasts.kt")
public void testSamConversionsWithSmartCasts() throws Exception {
runTest("compiler/testData/ir/irText/expressions/sam/samConversionsWithSmartCasts.kt");
}
}
}
@TestMetadata("compiler/testData/ir/irText/lambdas")