[NI] Commonize type-conversions (SAM/Suspend)

- Allow participating subtypes of functional types in conversions
 - Fix several subtle inconsistencies
 - Place logic about conversions at one place

 Now conversions operations have two stages: before usual subtyping
 check and after one. This is needed to support conversions of
 subtypes (of functional types, for example). First, the compiler
 checks if it possible to resolve an argument without conversion and
 only then it tries to perform conversion.
 Note that it'd be incorrect to perform conversion eagerly as it can
 change resolve (Runnable & () -> Unit <: KRunnable), plus we can't
 guess whether conversion is needed at all as it's important not to
 look into supertypes if resolution doesn't actually needed it

 #KT-36448 Fixed
 #KT-37574 Fixed
 #KT-38604 Fixed
This commit is contained in:
Mikhail Zarechenskiy
2020-05-15 15:27:37 +03:00
parent f702da5c51
commit 8bdc4d34f7
24 changed files with 636 additions and 107 deletions
@@ -23167,6 +23167,11 @@ public class FirOldFrontendDiagnosticsTestGenerated extends AbstractFirOldFronte
runTest("compiler/testData/diagnostics/tests/suspendConversion/suspendConversionDisabled.kt");
}
@TestMetadata("suspendConversionOnVarargElements.kt")
public void testSuspendConversionOnVarargElements() throws Exception {
runTest("compiler/testData/diagnostics/tests/suspendConversion/suspendConversionOnVarargElements.kt");
}
@TestMetadata("suspendConversionWithFunInterfaces.kt")
public void testSuspendConversionWithFunInterfaces() throws Exception {
runTest("compiler/testData/diagnostics/tests/suspendConversion/suspendConversionWithFunInterfaces.kt");
@@ -7869,10 +7869,20 @@ public class FirBlackBoxCodegenTestGenerated extends AbstractFirBlackBoxCodegenT
KotlinTestUtils.assertAllTestsPresentByMetadataWithExcluded(this.getClass(), new File("compiler/testData/codegen/box/coroutines/suspendConversion"), Pattern.compile("^(.+)\\.kt$"), null, TargetBackend.JVM_IR, true);
}
@TestMetadata("intersectionTypeToSubtypeConversion.kt")
public void testIntersectionTypeToSubtypeConversion() throws Exception {
runTest("compiler/testData/codegen/box/coroutines/suspendConversion/intersectionTypeToSubtypeConversion.kt");
}
@TestMetadata("onArgument.kt")
public void testOnArgument() throws Exception {
runTest("compiler/testData/codegen/box/coroutines/suspendConversion/onArgument.kt");
}
@TestMetadata("subtypeOfFunctionalTypeToSuspendConversion.kt")
public void testSubtypeOfFunctionalTypeToSuspendConversion() throws Exception {
runTest("compiler/testData/codegen/box/coroutines/suspendConversion/subtypeOfFunctionalTypeToSuspendConversion.kt");
}
}
@TestMetadata("compiler/testData/codegen/box/coroutines/suspendFunctionAsCoroutine")
@@ -11170,6 +11180,11 @@ public class FirBlackBoxCodegenTestGenerated extends AbstractFirBlackBoxCodegenT
runTest("compiler/testData/codegen/box/funInterface/inlinedSamWrapper.kt");
}
@TestMetadata("intersectionTypeToFunInterfaceConversion.kt")
public void testIntersectionTypeToFunInterfaceConversion() throws Exception {
runTest("compiler/testData/codegen/box/funInterface/intersectionTypeToFunInterfaceConversion.kt");
}
@TestMetadata("multimodule.kt")
public void testMultimodule() throws Exception {
runTest("compiler/testData/codegen/box/funInterface/multimodule.kt");
@@ -11200,6 +11215,11 @@ public class FirBlackBoxCodegenTestGenerated extends AbstractFirBlackBoxCodegenT
runTest("compiler/testData/codegen/box/funInterface/samConstructorExplicitInvocation.kt");
}
@TestMetadata("subtypeOfFunctionalTypeToFunInterfaceConversion.kt")
public void testSubtypeOfFunctionalTypeToFunInterfaceConversion() throws Exception {
runTest("compiler/testData/codegen/box/funInterface/subtypeOfFunctionalTypeToFunInterfaceConversion.kt");
}
@TestMetadata("suspendFunInterfaceConversionCodegen.kt")
public void testSuspendFunInterfaceConversionCodegen() throws Exception {
runTest("compiler/testData/codegen/box/funInterface/suspendFunInterfaceConversionCodegen.kt");
@@ -28073,6 +28093,11 @@ public class FirBlackBoxCodegenTestGenerated extends AbstractFirBlackBoxCodegenT
runTest("compiler/testData/codegen/box/sam/partialSamKT.kt");
}
@TestMetadata("passSubtypeOfFunctionSamConversion.kt")
public void testPassSubtypeOfFunctionSamConversion() throws Exception {
runTest("compiler/testData/codegen/box/sam/passSubtypeOfFunctionSamConversion.kt");
}
@TestMetadata("predicateSamWrapper.kt")
public void testPredicateSamWrapper() throws Exception {
runTest("compiler/testData/codegen/box/sam/predicateSamWrapper.kt");
@@ -413,7 +413,21 @@ private fun KotlinResolutionCandidate.resolveKotlinArgument(
candidateParameter: ParameterDescriptor?,
receiverInfo: ReceiverInfo
) {
val expectedType = candidateParameter?.let { prepareExpectedType(argument, candidateParameter) }
val candidateExpectedType = candidateParameter?.let { argument.getExpectedType(it, callComponents.languageVersionSettings) }
val conversionDataBeforeSubtyping =
if (candidateParameter == null || candidateExpectedType == null) {
null
} else {
TypeConversions.performCompositeConversionBeforeSubtyping(
this, argument, candidateParameter, candidateExpectedType
)
}
val convertedExpectedType = conversionDataBeforeSubtyping?.convertedType
val unsubstitutedExpectedType = conversionDataBeforeSubtyping?.convertedType ?: candidateExpectedType
val expectedType = unsubstitutedExpectedType?.let { prepareExpectedType(it) }
val convertedArgument = if (expectedType != null && shouldRunConversionForConstants(expectedType)) {
val convertedConstant = resolutionCallbacks.convertSignedConstantToUnsigned(argument)
if (convertedConstant != null) {
@@ -423,8 +437,14 @@ private fun KotlinResolutionCandidate.resolveKotlinArgument(
convertedConstant
} else null
addResolvedKtPrimitive(
resolveKtPrimitive(
if (candidateExpectedType == null || // Nothing to convert
convertedExpectedType != null || // Type is already converted
conversionDataBeforeSubtyping?.wasConversion == true || // We tried to convert type but failed
conversionDataBeforeSubtyping?.conversionDefinitelyNotNeeded == true ||
csBuilder.hasContradiction
) {
val resolvedAtom = resolveKtPrimitive(
csBuilder,
argument,
expectedType,
@@ -432,7 +452,54 @@ private fun KotlinResolutionCandidate.resolveKotlinArgument(
receiverInfo,
convertedArgument?.unknownIntegerType?.unwrap()
)
)
addResolvedKtPrimitive(resolvedAtom)
} else {
var convertedTypeAfterSubtyping: UnwrappedType? = null
csBuilder.runTransaction {
val resolvedAtom = resolveKtPrimitive(
csBuilder,
argument,
expectedType,
this@resolveKotlinArgument,
receiverInfo,
convertedArgument?.unknownIntegerType?.unwrap()
)
if (!hasContradiction) {
addResolvedKtPrimitive(resolvedAtom)
return@runTransaction true
}
convertedTypeAfterSubtyping =
TypeConversions.performCompositeConversionAfterSubtyping(
this@resolveKotlinArgument,
argument,
candidateParameter,
candidateExpectedType
)?.let { prepareExpectedType(it) }
if (convertedTypeAfterSubtyping == null) {
addResolvedKtPrimitive(resolvedAtom)
return@runTransaction true
}
false
}
if (convertedTypeAfterSubtyping != null) {
val resolvedAtom = resolveKtPrimitive(
csBuilder,
argument,
convertedTypeAfterSubtyping,
this@resolveKotlinArgument,
receiverInfo,
convertedArgument?.unknownIntegerType?.unwrap()
)
addResolvedKtPrimitive(resolvedAtom)
}
}
}
private fun KotlinResolutionCandidate.shouldRunConversionForConstants(expectedType: UnwrappedType): Boolean {
@@ -474,23 +541,6 @@ private fun KotlinResolutionCandidate.checkUnsafeImplicitInvokeAfterSafeCall(arg
return ImplicitInvokeCheckStatus.INVOKE_ON_NOT_NULL_VARIABLE
}
private fun KotlinResolutionCandidate.prepareExpectedType(
argument: KotlinCallArgument,
parameter: ParameterDescriptor
): UnwrappedType {
val expectedType =
performExpectedTypeConversion(argument, parameter)
?: argument.getExpectedType(parameter, callComponents.languageVersionSettings)
return prepareExpectedType(expectedType)
}
private fun KotlinResolutionCandidate.performExpectedTypeConversion(
argument: KotlinCallArgument,
parameter: ParameterDescriptor
): UnwrappedType? {
return getExpectedTypeWithSAMConversion(argument, parameter) ?: getExpectedTypeWithSuspendConversion(argument, parameter)
}
private fun KotlinResolutionCandidate.prepareExpectedType(expectedType: UnwrappedType): UnwrappedType {
val resultType = knownTypeParametersResultingSubstitutor?.substitute(expectedType) ?: expectedType
return resolvedCall.freshVariablesSubstitutor.safeSubstitute(resultType)
@@ -17,23 +17,11 @@ import org.jetbrains.kotlin.resolve.sam.getFunctionTypeForPossibleSamType
import org.jetbrains.kotlin.types.UnwrappedType
import org.jetbrains.kotlin.types.typeUtil.isNothing
object SamTypeConversions {
fun conversionMightBeNeededBeforeSubtypingCheck(argument: KotlinCallArgument): Boolean {
return when (argument) {
is SimpleKotlinCallArgument -> argument.receiver.stableType.isFunctionType
is LambdaKotlinCallArgument, is CallableReferenceKotlinCallArgument -> true
else -> false
}
}
fun conversionMightBeNeededAfterSubtypingCheck(argument: KotlinCallArgument): Boolean {
return argument is SimpleKotlinCallArgument && argument.receiver.stableType.isFunctionTypeOrSubtype
}
fun conversionDefinitelyNotNeeded(
object SamTypeConversions : ParameterTypeConversion {
override fun conversionDefinitelyNotNeeded(
candidate: KotlinResolutionCandidate,
candidateParameter: ParameterDescriptor
argument: KotlinCallArgument,
expectedParameterType: UnwrappedType
): Boolean {
val callComponents = candidate.callComponents
val generatingAdditionalSamCandidateIsEnabled =
@@ -41,7 +29,7 @@ object SamTypeConversions {
!callComponents.languageVersionSettings.supportsFeature(LanguageFeature.ProhibitVarargAsArrayAfterSamArgument)
if (generatingAdditionalSamCandidateIsEnabled) return true
if (candidateParameter.type.isNothing()) return true
if (expectedParameterType.isNothing()) return true
val samConversionOracle = callComponents.samConversionOracle
if (!callComponents.languageVersionSettings.supportsFeature(LanguageFeature.SamConversionForKotlinFunctions)) {
@@ -50,48 +38,56 @@ object SamTypeConversions {
return false
}
}
fun KotlinResolutionCandidate.getExpectedTypeWithSAMConversion(
argument: KotlinCallArgument,
candidateParameter: ParameterDescriptor
): UnwrappedType? {
if (SamTypeConversions.conversionDefinitelyNotNeeded(this, candidateParameter)) return null
val argumentIsFunctional = when (argument) {
is SimpleKotlinCallArgument -> argument.receiver.stableType.isFunctionType
is LambdaKotlinCallArgument, is CallableReferenceKotlinCallArgument -> true
else -> false
override fun conversionIsNeededBeforeSubtypingCheck(argument: KotlinCallArgument): Boolean {
return when (argument) {
is SimpleKotlinCallArgument -> argument.receiver.stableType.isFunctionType
is LambdaKotlinCallArgument, is CallableReferenceKotlinCallArgument -> true
else -> false
}
}
if (!argumentIsFunctional) return null
val originalExpectedType = argument.getExpectedType(candidateParameter.original, callComponents.languageVersionSettings)
override fun conversionIsNeededAfterSubtypingCheck(argument: KotlinCallArgument): Boolean {
return argument is SimpleKotlinCallArgument && argument.receiver.stableType.isFunctionTypeOrSubtype
}
val convertedTypeByOriginal =
callComponents.samConversionResolver.getFunctionTypeForPossibleSamType(
originalExpectedType,
callComponents.samConversionOracle
) ?: return null
override fun convertParameterType(
candidate: KotlinResolutionCandidate,
argument: KotlinCallArgument,
parameter: ParameterDescriptor,
expectedParameterType: UnwrappedType
): UnwrappedType? {
val callComponents = candidate.callComponents
val originalExpectedType = argument.getExpectedType(parameter.original, callComponents.languageVersionSettings)
val candidateExpectedType = argument.getExpectedType(candidateParameter, callComponents.languageVersionSettings)
val convertedTypeByCandidate =
callComponents.samConversionResolver.getFunctionTypeForPossibleSamType(
candidateExpectedType,
callComponents.samConversionOracle
val convertedTypeByOriginal =
callComponents.samConversionResolver.getFunctionTypeForPossibleSamType(
originalExpectedType,
callComponents.samConversionOracle
) ?: return null
val convertedTypeByCandidate =
callComponents.samConversionResolver.getFunctionTypeForPossibleSamType(
expectedParameterType,
callComponents.samConversionOracle
)
assert(expectedParameterType.constructor == originalExpectedType.constructor && convertedTypeByCandidate != null) {
"If original type is SAM type, then candidate should have same type constructor and corresponding function type\n" +
"originalExpectType: $originalExpectedType, candidateExpectType: $expectedParameterType\n" +
"functionTypeByOriginal: $convertedTypeByOriginal, functionTypeByCandidate: $convertedTypeByCandidate"
}
candidate.resolvedCall.registerArgumentWithSamConversion(
argument,
SamConversionDescription(convertedTypeByOriginal, convertedTypeByCandidate!!)
)
assert(candidateExpectedType.constructor == originalExpectedType.constructor && convertedTypeByCandidate != null) {
"If original type is SAM type, then candidate should have same type constructor and corresponding function type\n" +
"originalExpectType: $originalExpectedType, candidateExpectType: $candidateExpectedType\n" +
"functionTypeByOriginal: $convertedTypeByOriginal, functionTypeByCandidate: $convertedTypeByCandidate"
val samDescriptor = originalExpectedType.constructor.declarationDescriptor
if (samDescriptor is ClassDescriptor) {
callComponents.lookupTracker.record(candidate.scopeTower.location, samDescriptor, SAM_LOOKUP_NAME)
}
return convertedTypeByCandidate
}
resolvedCall.registerArgumentWithSamConversion(argument, SamConversionDescription(convertedTypeByOriginal, convertedTypeByCandidate!!))
val samDescriptor = originalExpectedType.constructor.declarationDescriptor
if (samDescriptor is ClassDescriptor) {
callComponents.lookupTracker.record(scopeTower.location, samDescriptor, SAM_LOOKUP_NAME)
}
return convertedTypeByCandidate
}
@@ -11,11 +11,11 @@ import org.jetbrains.kotlin.descriptors.ParameterDescriptor
import org.jetbrains.kotlin.resolve.calls.model.*
import org.jetbrains.kotlin.types.UnwrappedType
object SuspendTypeConversions {
fun conversionDefinitelyNotNeeded(
object SuspendTypeConversions : ParameterTypeConversion {
override fun conversionDefinitelyNotNeeded(
candidate: KotlinResolutionCandidate,
argument: KotlinCallArgument,
candidateParameter: ParameterDescriptor
expectedParameterType: UnwrappedType
): Boolean {
if (!candidate.callComponents.languageVersionSettings.supportsFeature(LanguageFeature.SuspendConversion)) return true
@@ -25,34 +25,33 @@ object SuspendTypeConversions {
if (!argumentType.isFunctionType) return true
if (argumentType.isSuspendFunctionType) return true
if (!candidateParameter.type.isSuspendFunctionType) return true
if (!expectedParameterType.isSuspendFunctionType) return true
return false
}
fun KotlinResolutionCandidate.conversionMightBeNeededBeforeSubtypingCheck(): Boolean = true
fun KotlinResolutionCandidate.conversionMightBeNeededAfterSubtypingCheck(): Boolean = false
override fun conversionIsNeededBeforeSubtypingCheck(argument: KotlinCallArgument): Boolean = true
override fun conversionIsNeededAfterSubtypingCheck(argument: KotlinCallArgument): Boolean =
argument is SimpleKotlinCallArgument && argument.receiver.stableType.isFunctionTypeOrSubtype
override fun convertParameterType(
candidate: KotlinResolutionCandidate,
argument: KotlinCallArgument,
parameter: ParameterDescriptor,
expectedParameterType: UnwrappedType
): UnwrappedType? {
val nonSuspendParameterType = createFunctionType(
candidate.callComponents.builtIns,
expectedParameterType.annotations,
expectedParameterType.getReceiverTypeFromFunctionType(),
expectedParameterType.getValueParameterTypesFromFunctionType().map { it.type },
parameterNames = null,
expectedParameterType.getReturnTypeFromFunctionType(),
suspendFunction = false
)
candidate.resolvedCall.registerArgumentWithSuspendConversion(argument, nonSuspendParameterType)
return nonSuspendParameterType
}
}
fun KotlinResolutionCandidate.getExpectedTypeWithSuspendConversion(
argument: KotlinCallArgument,
candidateParameter: ParameterDescriptor
): UnwrappedType? {
if (SuspendTypeConversions.conversionDefinitelyNotNeeded(this, argument, candidateParameter)) return null
val parameterType = candidateParameter.type
val nonSuspendParameterType = createFunctionType(
callComponents.builtIns,
parameterType.annotations,
parameterType.getReceiverTypeFromFunctionType(),
parameterType.getValueParameterTypesFromFunctionType().map { it.type },
parameterNames = null,
parameterType.getReturnTypeFromFunctionType(),
suspendFunction = false
)
resolvedCall.registerArgumentWithSuspendConversion(argument, nonSuspendParameterType)
return nonSuspendParameterType
}
@@ -0,0 +1,107 @@
/*
* Copyright 2010-2020 JetBrains s.r.o. and Kotlin Programming Language contributors.
* Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
*/
package org.jetbrains.kotlin.resolve.calls.components
import org.jetbrains.kotlin.descriptors.ParameterDescriptor
import org.jetbrains.kotlin.resolve.calls.model.KotlinCallArgument
import org.jetbrains.kotlin.resolve.calls.model.KotlinResolutionCandidate
import org.jetbrains.kotlin.types.UnwrappedType
interface ParameterTypeConversion {
fun conversionDefinitelyNotNeeded(
candidate: KotlinResolutionCandidate,
argument: KotlinCallArgument,
expectedParameterType: UnwrappedType
): Boolean
fun conversionIsNeededBeforeSubtypingCheck(argument: KotlinCallArgument): Boolean
fun conversionIsNeededAfterSubtypingCheck(argument: KotlinCallArgument): Boolean
fun convertParameterType(
candidate: KotlinResolutionCandidate,
argument: KotlinCallArgument,
parameter: ParameterDescriptor,
expectedParameterType: UnwrappedType
): UnwrappedType?
}
object TypeConversions {
fun performCompositeConversionBeforeSubtyping(
candidate: KotlinResolutionCandidate,
argument: KotlinCallArgument,
candidateParameter: ParameterDescriptor,
candidateExpectedType: UnwrappedType,
): ConversionData {
val samConversionData = performConversionBeforeSubtyping(
candidate, argument, candidateParameter, candidateExpectedType, SamTypeConversions
)
val suspendConversionData = if (samConversionData.convertedType == null) {
performConversionBeforeSubtyping(candidate, argument, candidateParameter, candidateExpectedType, SuspendTypeConversions)
} else {
null
}
return ConversionData(
convertedType = samConversionData.convertedType ?: suspendConversionData?.convertedType,
wasConversion = samConversionData.wasConversion || suspendConversionData?.wasConversion == true,
conversionDefinitelyNotNeeded = samConversionData.conversionDefinitelyNotNeeded &&
(suspendConversionData == null || suspendConversionData.conversionDefinitelyNotNeeded)
)
}
fun performCompositeConversionAfterSubtyping(
candidate: KotlinResolutionCandidate,
argument: KotlinCallArgument,
candidateParameter: ParameterDescriptor,
candidateExpectedType: UnwrappedType,
): UnwrappedType? {
val samConvertedType = performConversionAfterSubtyping(
candidate, argument, candidateParameter, candidateExpectedType, SamTypeConversions
)
if (samConvertedType != null) return samConvertedType
return performConversionAfterSubtyping(candidate, argument, candidateParameter, candidateExpectedType, SuspendTypeConversions)
}
private fun performConversionAfterSubtyping(
candidate: KotlinResolutionCandidate,
argument: KotlinCallArgument,
candidateParameter: ParameterDescriptor,
candidateExpectedType: UnwrappedType,
conversion: ParameterTypeConversion
): UnwrappedType? {
return if (
conversion.conversionIsNeededAfterSubtypingCheck(argument) &&
!conversion.conversionDefinitelyNotNeeded(candidate, argument, candidateExpectedType)
) {
conversion.convertParameterType(candidate, argument, candidateParameter, candidateExpectedType)
} else {
null
}
}
private fun performConversionBeforeSubtyping(
candidate: KotlinResolutionCandidate,
argument: KotlinCallArgument,
candidateParameter: ParameterDescriptor,
candidateExpectedType: UnwrappedType,
conversion: ParameterTypeConversion
): ConversionData {
val conversionDefinitelyNotNeeded = conversion.conversionDefinitelyNotNeeded(candidate, argument, candidateExpectedType)
return if (!conversionDefinitelyNotNeeded && conversion.conversionIsNeededBeforeSubtypingCheck(argument)) {
ConversionData(
conversion.convertParameterType(candidate, argument, candidateParameter, candidateExpectedType),
wasConversion = true,
conversionDefinitelyNotNeeded
)
} else {
ConversionData(convertedType = null, wasConversion = false, conversionDefinitelyNotNeeded)
}
}
class ConversionData(val convertedType: UnwrappedType?, val wasConversion: Boolean, val conversionDefinitelyNotNeeded: Boolean)
}
@@ -1,5 +1,3 @@
// !LANGUAGE: -NewInference
// IGNORE_BACKEND_FIR: JVM_IR
// TARGET_BACKEND: JVM
@@ -0,0 +1,39 @@
// !LANGUAGE: +SuspendConversion
// WITH_RUNTIME
// WITH_COROUTINES
// IGNORE_BACKEND: JVM, NATIVE, JS, JS_IR
// IGNORE_BACKEND_FIR: JVM_IR
// IGNORE_LIGHT_ANALYSIS
import helpers.*
import kotlin.coroutines.*
import kotlin.coroutines.intrinsics.*
fun builder(c: suspend () -> Unit) {
c.startCoroutine(EmptyContinuation)
}
suspend fun useSuspendFun(fn : suspend () -> String) = fn()
suspend fun useSuspendFunInt(fn: suspend (Int) -> String) = fn(42)
suspend fun <T> testIntersection(x: T): String where T : () -> String, T : (Int) -> String {
val a = useSuspendFun(x)
val b = useSuspendFunInt(x)
return a + b
}
class Test : () -> String, (Int) -> String {
override fun invoke(): String = "OKEmpty"
override fun invoke(p: Int) = "OK$p"
}
fun box(): String {
var test = "Failed"
builder {
test = testIntersection(Test())
}
if (test != "OKEmptyOK42") return "failed: $test"
return "OK"
}
@@ -0,0 +1,39 @@
// !LANGUAGE: +SuspendConversion
// WITH_RUNTIME
// WITH_COROUTINES
// IGNORE_BACKEND: JVM, NATIVE, JS, JS_IR
// IGNORE_BACKEND_FIR: JVM_IR
// IGNORE_LIGHT_ANALYSIS
import helpers.*
import kotlin.coroutines.*
import kotlin.coroutines.intrinsics.*
fun builder(c: suspend () -> Unit) {
c.startCoroutine(EmptyContinuation)
}
suspend fun useSuspendFun(fn : suspend () -> String) = fn()
suspend fun useSuspendFunInt(fn: suspend (Int) -> String) = fn(42)
class Test : () -> String, (Int) -> String {
override fun invoke(): String = "OKEmpty"
override fun invoke(p: Int) = "OK$p"
}
fun box(): String {
var test = "Failed"
builder {
test = useSuspendFun(Test())
}
if (test != "OKEmpty") return "failed 1"
builder {
test = useSuspendFunInt(Test())
}
if (test != "OK42") return "failed 2"
return "OK"
}
@@ -0,0 +1,39 @@
// IGNORE_BACKEND_FIR: JVM_IR
// IGNORE_BACKEND: JS, JS_IR
fun interface KRunnable {
fun invoke()
}
fun interface KBoolean {
fun invoke(b: Boolean)
}
fun useFunInterface(fn: KRunnable) {
fn.invoke()
}
fun useFunInterfacePredicate(fn: KBoolean) {
fn.invoke(true)
}
fun <T> testIntersection(x: T) where T : () -> Unit, T : (Boolean) -> Unit {
useFunInterface(x)
useFunInterfacePredicate(x)
}
var result = ""
object Test : () -> Unit, (Boolean) -> Unit {
override fun invoke() {
result += "O"
}
override fun invoke(p1: Boolean) {
if (p1) result += "K"
}
}
fun box(): String {
testIntersection(Test)
return result
}
@@ -0,0 +1,23 @@
// IGNORE_BACKEND_FIR: JVM_IR
// IGNORE_BACKEND: JS, JS_IR
fun interface KRunnable {
fun invoke()
}
object OK : () -> Unit {
override fun invoke() {
result = "OK"
}
}
fun foo(k: KRunnable) {
k.invoke()
}
var result: String = ""
fun box(): String {
foo(OK)
return result
}
@@ -1,5 +1,4 @@
// TARGET_BACKEND: JVM
// !LANGUAGE: -NewInference
// WITH_RUNTIME
// FILE: Base.java
import java.lang.Runnable;
@@ -0,0 +1,40 @@
// TARGET_BACKEND: JVM
// IGNORE_BACKEND_FIR: JVM_IR
// FILE: a.kt
object IntMapper : (Int) -> String {
override fun invoke(value: Int): String {
return value.toString()
}
}
// FILE: Sam.java
public interface Sam<T, R> {
R apply(T t);
}
// FILE: Foo.java
public class Foo {
public static String bar1(IntMapper mapper) {
return mapper.invoke(0);
}
public static <T, R> R bar2(Sam<? super T, ? extends R> mapper, T input) {
return mapper.apply(input);
}
}
// FILE: test.kt
fun box(): String {
val a = Foo.bar1(IntMapper)
if (a != "0") return "Failed 0: $a"
val b = Foo.bar2(IntMapper, 1)
if (b != "1") return "Failed 1: $b"
return "OK"
}
@@ -49,7 +49,7 @@ fun test6(a: Any) {
fun test7(a: (Int) -> Int) {
a <!UNCHECKED_CAST!>as () -> Unit<!>
J().run1(<!TYPE_MISMATCH!>a<!>)
J().run1(<!DEBUG_INFO_SMARTCAST!>a<!>)
}
fun test8(a: () -> Unit) {
@@ -0,0 +1,20 @@
// !LANGUAGE: +SuspendConversion
// !DIAGNOSTICS: -UNUSED_PARAMETER
fun useSuspendVararg(vararg sfn: suspend () -> Unit) {}
fun testSuspendConversionInVarargElementsSome(
sf1: suspend () -> Unit,
f2: () -> Unit,
sf3: suspend () -> Unit
) {
<!INAPPLICABLE_CANDIDATE!>useSuspendVararg<!>(sf1, f2, sf3)
}
fun testSuspendConversionInVarargElementsAll(
f1: () -> Unit,
f2: () -> Unit,
f3: () -> Unit
) {
<!INAPPLICABLE_CANDIDATE!>useSuspendVararg<!>(f1, f2, f3)
}
@@ -0,0 +1,20 @@
// !LANGUAGE: +SuspendConversion
// !DIAGNOSTICS: -UNUSED_PARAMETER
fun useSuspendVararg(vararg sfn: suspend () -> Unit) {}
fun testSuspendConversionInVarargElementsSome(
sf1: suspend () -> Unit,
f2: () -> Unit,
sf3: suspend () -> Unit
) {
useSuspendVararg(sf1, f2, sf3)
}
fun testSuspendConversionInVarargElementsAll(
f1: () -> Unit,
f2: () -> Unit,
f3: () -> Unit
) {
useSuspendVararg(f1, f2, f3)
}
@@ -0,0 +1,5 @@
package
public fun testSuspendConversionInVarargElementsAll(/*0*/ f1: () -> kotlin.Unit, /*1*/ f2: () -> kotlin.Unit, /*2*/ f3: () -> kotlin.Unit): kotlin.Unit
public fun testSuspendConversionInVarargElementsSome(/*0*/ sf1: suspend () -> kotlin.Unit, /*1*/ f2: () -> kotlin.Unit, /*2*/ sf3: suspend () -> kotlin.Unit): kotlin.Unit
public fun useSuspendVararg(/*0*/ vararg sfn: suspend () -> kotlin.Unit /*kotlin.Array<out suspend () -> kotlin.Unit>*/): kotlin.Unit
@@ -23249,6 +23249,11 @@ public class DiagnosticsTestGenerated extends AbstractDiagnosticsTestWithFirVali
runTest("compiler/testData/diagnostics/tests/suspendConversion/suspendConversionDisabled.kt");
}
@TestMetadata("suspendConversionOnVarargElements.kt")
public void testSuspendConversionOnVarargElements() throws Exception {
runTest("compiler/testData/diagnostics/tests/suspendConversion/suspendConversionOnVarargElements.kt");
}
@TestMetadata("suspendConversionWithFunInterfaces.kt")
public void testSuspendConversionWithFunInterfaces() throws Exception {
runTest("compiler/testData/diagnostics/tests/suspendConversion/suspendConversionWithFunInterfaces.kt");
@@ -23169,6 +23169,11 @@ public class DiagnosticsUsingJavacTestGenerated extends AbstractDiagnosticsUsing
runTest("compiler/testData/diagnostics/tests/suspendConversion/suspendConversionDisabled.kt");
}
@TestMetadata("suspendConversionOnVarargElements.kt")
public void testSuspendConversionOnVarargElements() throws Exception {
runTest("compiler/testData/diagnostics/tests/suspendConversion/suspendConversionOnVarargElements.kt");
}
@TestMetadata("suspendConversionWithFunInterfaces.kt")
public void testSuspendConversionWithFunInterfaces() throws Exception {
runTest("compiler/testData/diagnostics/tests/suspendConversion/suspendConversionWithFunInterfaces.kt");
@@ -8904,10 +8904,20 @@ public class BlackBoxCodegenTestGenerated extends AbstractBlackBoxCodegenTest {
KotlinTestUtils.assertAllTestsPresentByMetadataWithExcluded(this.getClass(), new File("compiler/testData/codegen/box/coroutines/suspendConversion"), Pattern.compile("^(.+)\\.kt$"), null, TargetBackend.JVM, true);
}
@TestMetadata("intersectionTypeToSubtypeConversion.kt")
public void testIntersectionTypeToSubtypeConversion() throws Exception {
runTest("compiler/testData/codegen/box/coroutines/suspendConversion/intersectionTypeToSubtypeConversion.kt");
}
@TestMetadata("onArgument.kt")
public void testOnArgument() throws Exception {
runTest("compiler/testData/codegen/box/coroutines/suspendConversion/onArgument.kt");
}
@TestMetadata("subtypeOfFunctionalTypeToSuspendConversion.kt")
public void testSubtypeOfFunctionalTypeToSuspendConversion() throws Exception {
runTest("compiler/testData/codegen/box/coroutines/suspendConversion/subtypeOfFunctionalTypeToSuspendConversion.kt");
}
}
@TestMetadata("compiler/testData/codegen/box/coroutines/suspendFunctionAsCoroutine")
@@ -12385,6 +12395,11 @@ public class BlackBoxCodegenTestGenerated extends AbstractBlackBoxCodegenTest {
runTest("compiler/testData/codegen/box/funInterface/inlinedSamWrapper.kt");
}
@TestMetadata("intersectionTypeToFunInterfaceConversion.kt")
public void testIntersectionTypeToFunInterfaceConversion() throws Exception {
runTest("compiler/testData/codegen/box/funInterface/intersectionTypeToFunInterfaceConversion.kt");
}
@TestMetadata("multimodule.kt")
public void testMultimodule() throws Exception {
runTest("compiler/testData/codegen/box/funInterface/multimodule.kt");
@@ -12415,6 +12430,11 @@ public class BlackBoxCodegenTestGenerated extends AbstractBlackBoxCodegenTest {
runTest("compiler/testData/codegen/box/funInterface/samConstructorExplicitInvocation.kt");
}
@TestMetadata("subtypeOfFunctionalTypeToFunInterfaceConversion.kt")
public void testSubtypeOfFunctionalTypeToFunInterfaceConversion() throws Exception {
runTest("compiler/testData/codegen/box/funInterface/subtypeOfFunctionalTypeToFunInterfaceConversion.kt");
}
@TestMetadata("suspendFunInterfaceConversionCodegen.kt")
public void testSuspendFunInterfaceConversionCodegen() throws Exception {
runTest("compiler/testData/codegen/box/funInterface/suspendFunInterfaceConversionCodegen.kt");
@@ -29659,6 +29679,11 @@ public class BlackBoxCodegenTestGenerated extends AbstractBlackBoxCodegenTest {
runTest("compiler/testData/codegen/box/sam/partialSamKT.kt");
}
@TestMetadata("passSubtypeOfFunctionSamConversion.kt")
public void testPassSubtypeOfFunctionSamConversion() throws Exception {
runTest("compiler/testData/codegen/box/sam/passSubtypeOfFunctionSamConversion.kt");
}
@TestMetadata("predicateSamWrapper.kt")
public void testPredicateSamWrapper() throws Exception {
runTest("compiler/testData/codegen/box/sam/predicateSamWrapper.kt");
@@ -8896,11 +8896,21 @@ public class LightAnalysisModeTestGenerated extends AbstractLightAnalysisModeTes
@TestDataPath("$PROJECT_ROOT")
@RunWith(JUnit3RunnerWithInners.class)
public static class SuspendConversion extends AbstractLightAnalysisModeTest {
@TestMetadata("intersectionTypeToSubtypeConversion.kt")
public void ignoreIntersectionTypeToSubtypeConversion() throws Exception {
runTest("compiler/testData/codegen/box/coroutines/suspendConversion/intersectionTypeToSubtypeConversion.kt");
}
@TestMetadata("onArgument.kt")
public void ignoreOnArgument() throws Exception {
runTest("compiler/testData/codegen/box/coroutines/suspendConversion/onArgument.kt");
}
@TestMetadata("subtypeOfFunctionalTypeToSuspendConversion.kt")
public void ignoreSubtypeOfFunctionalTypeToSuspendConversion() throws Exception {
runTest("compiler/testData/codegen/box/coroutines/suspendConversion/subtypeOfFunctionalTypeToSuspendConversion.kt");
}
private void runTest(String testDataFilePath) throws Exception {
KotlinTestUtils.runTest(this::doTest, TargetBackend.JVM, testDataFilePath);
}
@@ -12385,6 +12395,11 @@ public class LightAnalysisModeTestGenerated extends AbstractLightAnalysisModeTes
runTest("compiler/testData/codegen/box/funInterface/inlinedSamWrapper.kt");
}
@TestMetadata("intersectionTypeToFunInterfaceConversion.kt")
public void testIntersectionTypeToFunInterfaceConversion() throws Exception {
runTest("compiler/testData/codegen/box/funInterface/intersectionTypeToFunInterfaceConversion.kt");
}
@TestMetadata("multimodule.kt")
public void testMultimodule() throws Exception {
runTest("compiler/testData/codegen/box/funInterface/multimodule.kt");
@@ -12415,6 +12430,11 @@ public class LightAnalysisModeTestGenerated extends AbstractLightAnalysisModeTes
runTest("compiler/testData/codegen/box/funInterface/samConstructorExplicitInvocation.kt");
}
@TestMetadata("subtypeOfFunctionalTypeToFunInterfaceConversion.kt")
public void testSubtypeOfFunctionalTypeToFunInterfaceConversion() throws Exception {
runTest("compiler/testData/codegen/box/funInterface/subtypeOfFunctionalTypeToFunInterfaceConversion.kt");
}
@TestMetadata("suspendFunInterfaceConversionCodegen.kt")
public void testSuspendFunInterfaceConversionCodegen() throws Exception {
runTest("compiler/testData/codegen/box/funInterface/suspendFunInterfaceConversionCodegen.kt");
@@ -27293,6 +27313,11 @@ public class LightAnalysisModeTestGenerated extends AbstractLightAnalysisModeTes
runTest("compiler/testData/codegen/box/sam/partialSamKT.kt");
}
@TestMetadata("passSubtypeOfFunctionSamConversion.kt")
public void testPassSubtypeOfFunctionSamConversion() throws Exception {
runTest("compiler/testData/codegen/box/sam/passSubtypeOfFunctionSamConversion.kt");
}
@TestMetadata("predicateSamWrapper.kt")
public void testPredicateSamWrapper() throws Exception {
runTest("compiler/testData/codegen/box/sam/predicateSamWrapper.kt");
@@ -7869,10 +7869,20 @@ public class IrBlackBoxCodegenTestGenerated extends AbstractIrBlackBoxCodegenTes
KotlinTestUtils.assertAllTestsPresentByMetadataWithExcluded(this.getClass(), new File("compiler/testData/codegen/box/coroutines/suspendConversion"), Pattern.compile("^(.+)\\.kt$"), null, TargetBackend.JVM_IR, true);
}
@TestMetadata("intersectionTypeToSubtypeConversion.kt")
public void testIntersectionTypeToSubtypeConversion() throws Exception {
runTest("compiler/testData/codegen/box/coroutines/suspendConversion/intersectionTypeToSubtypeConversion.kt");
}
@TestMetadata("onArgument.kt")
public void testOnArgument() throws Exception {
runTest("compiler/testData/codegen/box/coroutines/suspendConversion/onArgument.kt");
}
@TestMetadata("subtypeOfFunctionalTypeToSuspendConversion.kt")
public void testSubtypeOfFunctionalTypeToSuspendConversion() throws Exception {
runTest("compiler/testData/codegen/box/coroutines/suspendConversion/subtypeOfFunctionalTypeToSuspendConversion.kt");
}
}
@TestMetadata("compiler/testData/codegen/box/coroutines/suspendFunctionAsCoroutine")
@@ -11170,6 +11180,11 @@ public class IrBlackBoxCodegenTestGenerated extends AbstractIrBlackBoxCodegenTes
runTest("compiler/testData/codegen/box/funInterface/inlinedSamWrapper.kt");
}
@TestMetadata("intersectionTypeToFunInterfaceConversion.kt")
public void testIntersectionTypeToFunInterfaceConversion() throws Exception {
runTest("compiler/testData/codegen/box/funInterface/intersectionTypeToFunInterfaceConversion.kt");
}
@TestMetadata("multimodule.kt")
public void testMultimodule() throws Exception {
runTest("compiler/testData/codegen/box/funInterface/multimodule.kt");
@@ -11200,6 +11215,11 @@ public class IrBlackBoxCodegenTestGenerated extends AbstractIrBlackBoxCodegenTes
runTest("compiler/testData/codegen/box/funInterface/samConstructorExplicitInvocation.kt");
}
@TestMetadata("subtypeOfFunctionalTypeToFunInterfaceConversion.kt")
public void testSubtypeOfFunctionalTypeToFunInterfaceConversion() throws Exception {
runTest("compiler/testData/codegen/box/funInterface/subtypeOfFunctionalTypeToFunInterfaceConversion.kt");
}
@TestMetadata("suspendFunInterfaceConversionCodegen.kt")
public void testSuspendFunInterfaceConversionCodegen() throws Exception {
runTest("compiler/testData/codegen/box/funInterface/suspendFunInterfaceConversionCodegen.kt");
@@ -28073,6 +28093,11 @@ public class IrBlackBoxCodegenTestGenerated extends AbstractIrBlackBoxCodegenTes
runTest("compiler/testData/codegen/box/sam/partialSamKT.kt");
}
@TestMetadata("passSubtypeOfFunctionSamConversion.kt")
public void testPassSubtypeOfFunctionSamConversion() throws Exception {
runTest("compiler/testData/codegen/box/sam/passSubtypeOfFunctionSamConversion.kt");
}
@TestMetadata("predicateSamWrapper.kt")
public void testPredicateSamWrapper() throws Exception {
runTest("compiler/testData/codegen/box/sam/predicateSamWrapper.kt");
@@ -6714,10 +6714,20 @@ public class IrJsCodegenBoxTestGenerated extends AbstractIrJsCodegenBoxTest {
KotlinTestUtils.assertAllTestsPresentByMetadataWithExcluded(this.getClass(), new File("compiler/testData/codegen/box/coroutines/suspendConversion"), Pattern.compile("^(.+)\\.kt$"), null, TargetBackend.JS_IR, true);
}
@TestMetadata("intersectionTypeToSubtypeConversion.kt")
public void testIntersectionTypeToSubtypeConversion() throws Exception {
runTest("compiler/testData/codegen/box/coroutines/suspendConversion/intersectionTypeToSubtypeConversion.kt");
}
@TestMetadata("onArgument.kt")
public void testOnArgument() throws Exception {
runTest("compiler/testData/codegen/box/coroutines/suspendConversion/onArgument.kt");
}
@TestMetadata("subtypeOfFunctionalTypeToSuspendConversion.kt")
public void testSubtypeOfFunctionalTypeToSuspendConversion() throws Exception {
runTest("compiler/testData/codegen/box/coroutines/suspendConversion/subtypeOfFunctionalTypeToSuspendConversion.kt");
}
}
@TestMetadata("compiler/testData/codegen/box/coroutines/suspendFunctionAsCoroutine")
@@ -9580,6 +9590,11 @@ public class IrJsCodegenBoxTestGenerated extends AbstractIrJsCodegenBoxTest {
runTest("compiler/testData/codegen/box/funInterface/inlinedSamWrapper.kt");
}
@TestMetadata("intersectionTypeToFunInterfaceConversion.kt")
public void testIntersectionTypeToFunInterfaceConversion() throws Exception {
runTest("compiler/testData/codegen/box/funInterface/intersectionTypeToFunInterfaceConversion.kt");
}
@TestMetadata("multimodule.kt")
public void testMultimodule() throws Exception {
runTest("compiler/testData/codegen/box/funInterface/multimodule.kt");
@@ -9610,6 +9625,11 @@ public class IrJsCodegenBoxTestGenerated extends AbstractIrJsCodegenBoxTest {
runTest("compiler/testData/codegen/box/funInterface/samConstructorExplicitInvocation.kt");
}
@TestMetadata("subtypeOfFunctionalTypeToFunInterfaceConversion.kt")
public void testSubtypeOfFunctionalTypeToFunInterfaceConversion() throws Exception {
runTest("compiler/testData/codegen/box/funInterface/subtypeOfFunctionalTypeToFunInterfaceConversion.kt");
}
@TestMetadata("suspendFunInterfaceConversionCodegen.kt")
public void testSuspendFunInterfaceConversionCodegen() throws Exception {
runTest("compiler/testData/codegen/box/funInterface/suspendFunInterfaceConversionCodegen.kt");
@@ -6714,10 +6714,20 @@ public class JsCodegenBoxTestGenerated extends AbstractJsCodegenBoxTest {
KotlinTestUtils.assertAllTestsPresentByMetadataWithExcluded(this.getClass(), new File("compiler/testData/codegen/box/coroutines/suspendConversion"), Pattern.compile("^(.+)\\.kt$"), null, TargetBackend.JS, true);
}
@TestMetadata("intersectionTypeToSubtypeConversion.kt")
public void testIntersectionTypeToSubtypeConversion() throws Exception {
runTest("compiler/testData/codegen/box/coroutines/suspendConversion/intersectionTypeToSubtypeConversion.kt");
}
@TestMetadata("onArgument.kt")
public void testOnArgument() throws Exception {
runTest("compiler/testData/codegen/box/coroutines/suspendConversion/onArgument.kt");
}
@TestMetadata("subtypeOfFunctionalTypeToSuspendConversion.kt")
public void testSubtypeOfFunctionalTypeToSuspendConversion() throws Exception {
runTest("compiler/testData/codegen/box/coroutines/suspendConversion/subtypeOfFunctionalTypeToSuspendConversion.kt");
}
}
@TestMetadata("compiler/testData/codegen/box/coroutines/suspendFunctionAsCoroutine")
@@ -9580,6 +9590,11 @@ public class JsCodegenBoxTestGenerated extends AbstractJsCodegenBoxTest {
runTest("compiler/testData/codegen/box/funInterface/inlinedSamWrapper.kt");
}
@TestMetadata("intersectionTypeToFunInterfaceConversion.kt")
public void testIntersectionTypeToFunInterfaceConversion() throws Exception {
runTest("compiler/testData/codegen/box/funInterface/intersectionTypeToFunInterfaceConversion.kt");
}
@TestMetadata("multimodule.kt")
public void testMultimodule() throws Exception {
runTest("compiler/testData/codegen/box/funInterface/multimodule.kt");
@@ -9610,6 +9625,11 @@ public class JsCodegenBoxTestGenerated extends AbstractJsCodegenBoxTest {
runTest("compiler/testData/codegen/box/funInterface/samConstructorExplicitInvocation.kt");
}
@TestMetadata("subtypeOfFunctionalTypeToFunInterfaceConversion.kt")
public void testSubtypeOfFunctionalTypeToFunInterfaceConversion() throws Exception {
runTest("compiler/testData/codegen/box/funInterface/subtypeOfFunctionalTypeToFunInterfaceConversion.kt");
}
@TestMetadata("suspendFunInterfaceConversionCodegen.kt")
public void testSuspendFunInterfaceConversionCodegen() throws Exception {
runTest("compiler/testData/codegen/box/funInterface/suspendFunInterfaceConversionCodegen.kt");