Support coroutine inference under version <= 1.2
Follow-up #KT-26958
This commit is contained in:
+1
-1
@@ -414,7 +414,7 @@ class GenericCandidateResolver(
|
|||||||
|
|
||||||
val effectiveExpectedType = getEffectiveExpectedType(valueParameterDescriptor, valueArgument, context)
|
val effectiveExpectedType = getEffectiveExpectedType(valueParameterDescriptor, valueArgument, context)
|
||||||
|
|
||||||
if (isCoroutineCallWithAdditionalInference(valueParameterDescriptor, valueArgument)) {
|
if (isCoroutineCallWithAdditionalInference(valueParameterDescriptor, valueArgument, languageVersionSettings)) {
|
||||||
coroutineInferenceSupport.analyzeCoroutine(functionLiteral, valueArgument, constraintSystem, context, effectiveExpectedType)
|
coroutineInferenceSupport.analyzeCoroutine(functionLiteral, valueArgument, constraintSystem, context, effectiveExpectedType)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
+44
-6
@@ -6,8 +6,12 @@
|
|||||||
package org.jetbrains.kotlin.resolve.calls.inference
|
package org.jetbrains.kotlin.resolve.calls.inference
|
||||||
|
|
||||||
import org.jetbrains.kotlin.builtins.*
|
import org.jetbrains.kotlin.builtins.*
|
||||||
|
import org.jetbrains.kotlin.config.LanguageFeature
|
||||||
|
import org.jetbrains.kotlin.config.LanguageVersionSettings
|
||||||
import org.jetbrains.kotlin.coroutines.hasFunctionOrSuspendFunctionType
|
import org.jetbrains.kotlin.coroutines.hasFunctionOrSuspendFunctionType
|
||||||
|
import org.jetbrains.kotlin.coroutines.hasSuspendFunctionType
|
||||||
import org.jetbrains.kotlin.descriptors.CallableDescriptor
|
import org.jetbrains.kotlin.descriptors.CallableDescriptor
|
||||||
|
import org.jetbrains.kotlin.descriptors.FunctionDescriptor
|
||||||
import org.jetbrains.kotlin.descriptors.ValueParameterDescriptor
|
import org.jetbrains.kotlin.descriptors.ValueParameterDescriptor
|
||||||
import org.jetbrains.kotlin.descriptors.annotations.Annotations
|
import org.jetbrains.kotlin.descriptors.annotations.Annotations
|
||||||
import org.jetbrains.kotlin.psi.KtExpression
|
import org.jetbrains.kotlin.psi.KtExpression
|
||||||
@@ -111,6 +115,8 @@ class CoroutineInferenceSupport(
|
|||||||
@set:Inject
|
@set:Inject
|
||||||
lateinit var callCompleter: CallCompleter
|
lateinit var callCompleter: CallCompleter
|
||||||
|
|
||||||
|
private val languageVersionSettings get() = expressionTypingServices.languageVersionSettings
|
||||||
|
|
||||||
fun analyzeCoroutine(
|
fun analyzeCoroutine(
|
||||||
functionLiteral: KtFunction,
|
functionLiteral: KtFunction,
|
||||||
valueArgument: ValueArgument,
|
valueArgument: ValueArgument,
|
||||||
@@ -119,7 +125,8 @@ class CoroutineInferenceSupport(
|
|||||||
lambdaExpectedType: KotlinType
|
lambdaExpectedType: KotlinType
|
||||||
) {
|
) {
|
||||||
val argumentExpression = valueArgument.getArgumentExpression() ?: return
|
val argumentExpression = valueArgument.getArgumentExpression() ?: return
|
||||||
if (!lambdaExpectedType.isFunctionOrSuspendFunctionType) return
|
if (!checkExpectedTypeForArgument(lambdaExpectedType)) return
|
||||||
|
|
||||||
val lambdaReceiverType = lambdaExpectedType.getReceiverTypeFromFunctionType() ?: return
|
val lambdaReceiverType = lambdaExpectedType.getReceiverTypeFromFunctionType() ?: return
|
||||||
|
|
||||||
val inferenceData = CoroutineInferenceData()
|
val inferenceData = CoroutineInferenceData()
|
||||||
@@ -173,6 +180,13 @@ class CoroutineInferenceSupport(
|
|||||||
inferenceData.reportInferenceResult(csBuilder)
|
inferenceData.reportInferenceResult(csBuilder)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private fun checkExpectedTypeForArgument(expectedType: KotlinType): Boolean {
|
||||||
|
return if (languageVersionSettings.supportsFeature(LanguageFeature.ExperimentalBuilderInference))
|
||||||
|
expectedType.isFunctionOrSuspendFunctionType
|
||||||
|
else
|
||||||
|
expectedType.isSuspendFunctionType
|
||||||
|
}
|
||||||
|
|
||||||
fun checkCoroutineCalls(
|
fun checkCoroutineCalls(
|
||||||
context: BasicCallResolutionContext,
|
context: BasicCallResolutionContext,
|
||||||
tracingStrategy: TracingStrategy,
|
tracingStrategy: TracingStrategy,
|
||||||
@@ -209,17 +223,32 @@ class CoroutineInferenceSupport(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private fun KotlinType.containsTypeTemplate() = contains { it is TypeTemplate }
|
||||||
|
|
||||||
private fun isGoodCall(resultingDescriptor: CallableDescriptor): Boolean {
|
private fun isGoodCall(resultingDescriptor: CallableDescriptor): Boolean {
|
||||||
|
if (!languageVersionSettings.supportsFeature(LanguageFeature.ExperimentalBuilderInference)) {
|
||||||
|
return isGoodCallForOldCoroutines(resultingDescriptor)
|
||||||
|
}
|
||||||
|
|
||||||
if (resultingDescriptor.isExtension && !resultingDescriptor.hasBuilderInferenceAnnotation()) {
|
if (resultingDescriptor.isExtension && !resultingDescriptor.hasBuilderInferenceAnnotation()) {
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
|
|
||||||
fun KotlinType.containsTypeTemplate() = contains { it is TypeTemplate }
|
|
||||||
|
|
||||||
val returnType = resultingDescriptor.returnType ?: return false
|
val returnType = resultingDescriptor.returnType ?: return false
|
||||||
return !returnType.containsTypeTemplate()
|
return !returnType.containsTypeTemplate()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private fun isGoodCallForOldCoroutines(resultingDescriptor: CallableDescriptor): Boolean {
|
||||||
|
val returnType = resultingDescriptor.returnType ?: return false
|
||||||
|
if (returnType.containsTypeTemplate()) return false
|
||||||
|
|
||||||
|
if (resultingDescriptor !is FunctionDescriptor || resultingDescriptor.isSuspend) return true
|
||||||
|
|
||||||
|
if (resultingDescriptor.valueParameters.any { it.type.containsTypeTemplate() }) return false
|
||||||
|
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
|
||||||
private class CoroutineTypeCheckerContext : TypeCheckerContext(errorTypeEqualsToAnything = true) {
|
private class CoroutineTypeCheckerContext : TypeCheckerContext(errorTypeEqualsToAnything = true) {
|
||||||
override fun addSubtypeConstraint(subType: UnwrappedType, superType: UnwrappedType): Boolean? {
|
override fun addSubtypeConstraint(subType: UnwrappedType, superType: UnwrappedType): Boolean? {
|
||||||
(subType as? TypeTemplate ?: superType as? TypeTemplate)?.coroutineInferenceData?.addConstraint(subType, superType)
|
(subType as? TypeTemplate ?: superType as? TypeTemplate)?.coroutineInferenceData?.addConstraint(subType, superType)
|
||||||
@@ -258,11 +287,20 @@ class CoroutineInferenceSupport(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fun isCoroutineCallWithAdditionalInference(parameterDescriptor: ValueParameterDescriptor, argument: ValueArgument) =
|
fun isCoroutineCallWithAdditionalInference(
|
||||||
parameterDescriptor.hasBuilderInferenceAnnotation() &&
|
parameterDescriptor: ValueParameterDescriptor,
|
||||||
parameterDescriptor.hasFunctionOrSuspendFunctionType &&
|
argument: ValueArgument,
|
||||||
|
languageVersionSettings: LanguageVersionSettings
|
||||||
|
): Boolean {
|
||||||
|
val parameterHasOptIn = if (languageVersionSettings.supportsFeature(LanguageFeature.ExperimentalBuilderInference))
|
||||||
|
parameterDescriptor.hasBuilderInferenceAnnotation() && parameterDescriptor.hasFunctionOrSuspendFunctionType
|
||||||
|
else
|
||||||
|
parameterDescriptor.hasSuspendFunctionType
|
||||||
|
|
||||||
|
return parameterHasOptIn &&
|
||||||
argument.getArgumentExpression() is KtLambdaExpression &&
|
argument.getArgumentExpression() is KtLambdaExpression &&
|
||||||
parameterDescriptor.type.let { it.isBuiltinFunctionalType && it.getReceiverTypeFromFunctionType() != null }
|
parameterDescriptor.type.let { it.isBuiltinFunctionalType && it.getReceiverTypeFromFunctionType() != null }
|
||||||
|
}
|
||||||
|
|
||||||
fun OverloadResolutionResultsImpl<*>.isResultWithCoroutineInference() = getCoroutineInferenceData() != null
|
fun OverloadResolutionResultsImpl<*>.isResultWithCoroutineInference() = getCoroutineInferenceData() != null
|
||||||
|
|
||||||
|
|||||||
+4
-2
@@ -16,6 +16,7 @@
|
|||||||
|
|
||||||
package org.jetbrains.kotlin.resolve.calls.tower
|
package org.jetbrains.kotlin.resolve.calls.tower
|
||||||
|
|
||||||
|
import org.jetbrains.kotlin.config.LanguageVersionSettings
|
||||||
import org.jetbrains.kotlin.descriptors.CallableDescriptor
|
import org.jetbrains.kotlin.descriptors.CallableDescriptor
|
||||||
import org.jetbrains.kotlin.descriptors.DeclarationDescriptor
|
import org.jetbrains.kotlin.descriptors.DeclarationDescriptor
|
||||||
import org.jetbrains.kotlin.descriptors.ValueParameterDescriptor
|
import org.jetbrains.kotlin.descriptors.ValueParameterDescriptor
|
||||||
@@ -35,7 +36,8 @@ import org.jetbrains.kotlin.resolve.deprecation.DeprecationResolver
|
|||||||
import org.jetbrains.kotlin.utils.addToStdlib.safeAs
|
import org.jetbrains.kotlin.utils.addToStdlib.safeAs
|
||||||
|
|
||||||
class KotlinResolutionStatelessCallbacksImpl(
|
class KotlinResolutionStatelessCallbacksImpl(
|
||||||
private val deprecationResolver: DeprecationResolver
|
private val deprecationResolver: DeprecationResolver,
|
||||||
|
private val languageVersionSettings: LanguageVersionSettings
|
||||||
) : KotlinResolutionStatelessCallbacks {
|
) : KotlinResolutionStatelessCallbacks {
|
||||||
override fun isDescriptorFromSource(descriptor: CallableDescriptor) =
|
override fun isDescriptorFromSource(descriptor: CallableDescriptor) =
|
||||||
DescriptorToSourceUtils.descriptorToDeclaration(descriptor) != null
|
DescriptorToSourceUtils.descriptorToDeclaration(descriptor) != null
|
||||||
@@ -70,5 +72,5 @@ class KotlinResolutionStatelessCallbacksImpl(
|
|||||||
functionCall.safeAs<PSIKotlinCallForInvoke>()?.variableCall
|
functionCall.safeAs<PSIKotlinCallForInvoke>()?.variableCall
|
||||||
|
|
||||||
override fun isCoroutineCall(argument: KotlinCallArgument, parameter: ValueParameterDescriptor): Boolean =
|
override fun isCoroutineCall(argument: KotlinCallArgument, parameter: ValueParameterDescriptor): Boolean =
|
||||||
isCoroutineCallWithAdditionalInference(parameter, argument.psiCallArgument.valueArgument)
|
isCoroutineCallWithAdditionalInference(parameter, argument.psiCallArgument.valueArgument, languageVersionSettings)
|
||||||
}
|
}
|
||||||
|
|||||||
compiler/testData/diagnostics/testsWithStdLib/coroutines/inference/inferCoroutineTypeInOldVersion.kt
Vendored
+29
@@ -0,0 +1,29 @@
|
|||||||
|
// !LANGUAGE: -ExperimentalBuilderInference
|
||||||
|
// !DIAGNOSTICS: -UNUSED_PARAMETER
|
||||||
|
|
||||||
|
class Builder<T> {
|
||||||
|
suspend fun add(t: T) {}
|
||||||
|
}
|
||||||
|
|
||||||
|
fun <S> build(g: suspend Builder<S>.() -> Unit): List<S> = TODO()
|
||||||
|
fun <S> wrongBuild(g: Builder<S>.() -> Unit): List<S> = TODO()
|
||||||
|
|
||||||
|
fun <S> Builder<S>.extensionAdd(s: S) {}
|
||||||
|
|
||||||
|
suspend fun <S> Builder<S>.safeExtensionAdd(s: S) {}
|
||||||
|
|
||||||
|
val member = build {
|
||||||
|
add(42)
|
||||||
|
}
|
||||||
|
|
||||||
|
val memberWithoutAnn = <!TYPE_INFERENCE_NO_INFORMATION_FOR_PARAMETER!>wrongBuild<!> {
|
||||||
|
<!ILLEGAL_SUSPEND_FUNCTION_CALL!>add<!>(42)
|
||||||
|
}
|
||||||
|
|
||||||
|
val extension = <!TYPE_INFERENCE_NO_INFORMATION_FOR_PARAMETER!>build<!> {
|
||||||
|
extensionAdd("foo")
|
||||||
|
}
|
||||||
|
|
||||||
|
val safeExtension = build {
|
||||||
|
safeExtensionAdd("foo")
|
||||||
|
}
|
||||||
+22
@@ -0,0 +1,22 @@
|
|||||||
|
package
|
||||||
|
|
||||||
|
public val extension: [ERROR : Type for build {
|
||||||
|
extensionAdd("foo")
|
||||||
|
}]
|
||||||
|
public val member: kotlin.collections.List<kotlin.Int>
|
||||||
|
public val memberWithoutAnn: [ERROR : Type for wrongBuild {
|
||||||
|
add(42)
|
||||||
|
}]
|
||||||
|
public val safeExtension: kotlin.collections.List<kotlin.String>
|
||||||
|
public fun </*0*/ S> build(/*0*/ g: suspend Builder<S>.() -> kotlin.Unit): kotlin.collections.List<S>
|
||||||
|
public fun </*0*/ S> wrongBuild(/*0*/ g: Builder<S>.() -> kotlin.Unit): kotlin.collections.List<S>
|
||||||
|
public fun </*0*/ S> Builder<S>.extensionAdd(/*0*/ s: S): kotlin.Unit
|
||||||
|
public suspend fun </*0*/ S> Builder<S>.safeExtensionAdd(/*0*/ s: S): kotlin.Unit
|
||||||
|
|
||||||
|
public final class Builder</*0*/ T> {
|
||||||
|
public constructor Builder</*0*/ T>()
|
||||||
|
public final suspend fun add(/*0*/ t: T): kotlin.Unit
|
||||||
|
public open override /*1*/ /*fake_override*/ fun equals(/*0*/ other: kotlin.Any?): kotlin.Boolean
|
||||||
|
public open override /*1*/ /*fake_override*/ fun hashCode(): kotlin.Int
|
||||||
|
public open override /*1*/ /*fake_override*/ fun toString(): kotlin.String
|
||||||
|
}
|
||||||
+5
@@ -1752,6 +1752,11 @@ public class DiagnosticsTestWithStdLibGenerated extends AbstractDiagnosticsTestW
|
|||||||
runTest("compiler/testData/diagnostics/testsWithStdLib/coroutines/inference/incorrectCalls.kt");
|
runTest("compiler/testData/diagnostics/testsWithStdLib/coroutines/inference/incorrectCalls.kt");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@TestMetadata("inferCoroutineTypeInOldVersion.kt")
|
||||||
|
public void testInferCoroutineTypeInOldVersion() throws Exception {
|
||||||
|
runTest("compiler/testData/diagnostics/testsWithStdLib/coroutines/inference/inferCoroutineTypeInOldVersion.kt");
|
||||||
|
}
|
||||||
|
|
||||||
@TestMetadata("kt15516.kt")
|
@TestMetadata("kt15516.kt")
|
||||||
public void testKt15516() throws Exception {
|
public void testKt15516() throws Exception {
|
||||||
runTest("compiler/testData/diagnostics/testsWithStdLib/coroutines/inference/kt15516.kt");
|
runTest("compiler/testData/diagnostics/testsWithStdLib/coroutines/inference/kt15516.kt");
|
||||||
|
|||||||
compiler/tests/org/jetbrains/kotlin/checkers/javac/DiagnosticsTestWithStdLibUsingJavacGenerated.java
Generated
+5
@@ -1752,6 +1752,11 @@ public class DiagnosticsTestWithStdLibUsingJavacGenerated extends AbstractDiagno
|
|||||||
runTest("compiler/testData/diagnostics/testsWithStdLib/coroutines/inference/incorrectCalls.kt");
|
runTest("compiler/testData/diagnostics/testsWithStdLib/coroutines/inference/incorrectCalls.kt");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@TestMetadata("inferCoroutineTypeInOldVersion.kt")
|
||||||
|
public void testInferCoroutineTypeInOldVersion() throws Exception {
|
||||||
|
runTest("compiler/testData/diagnostics/testsWithStdLib/coroutines/inference/inferCoroutineTypeInOldVersion.kt");
|
||||||
|
}
|
||||||
|
|
||||||
@TestMetadata("kt15516.kt")
|
@TestMetadata("kt15516.kt")
|
||||||
public void testKt15516() throws Exception {
|
public void testKt15516() throws Exception {
|
||||||
runTest("compiler/testData/diagnostics/testsWithStdLib/coroutines/inference/kt15516.kt");
|
runTest("compiler/testData/diagnostics/testsWithStdLib/coroutines/inference/kt15516.kt");
|
||||||
|
|||||||
@@ -89,6 +89,7 @@ enum class LanguageFeature(
|
|||||||
ProhibitErroneousExpressionsInAnnotationsWithUseSiteTargets(KOTLIN_1_3, kind = BUG_FIX),
|
ProhibitErroneousExpressionsInAnnotationsWithUseSiteTargets(KOTLIN_1_3, kind = BUG_FIX),
|
||||||
NewCapturedReceiverFieldNamingConvention(KOTLIN_1_3, kind = BUG_FIX),
|
NewCapturedReceiverFieldNamingConvention(KOTLIN_1_3, kind = BUG_FIX),
|
||||||
ExtendedMainConvention(KOTLIN_1_3),
|
ExtendedMainConvention(KOTLIN_1_3),
|
||||||
|
ExperimentalBuilderInference(KOTLIN_1_3),
|
||||||
|
|
||||||
RestrictReturnStatementTarget(KOTLIN_1_4, kind = BUG_FIX),
|
RestrictReturnStatementTarget(KOTLIN_1_4, kind = BUG_FIX),
|
||||||
NoConstantValueAttributeForNonConstVals(KOTLIN_1_4, kind = BUG_FIX),
|
NoConstantValueAttributeForNonConstVals(KOTLIN_1_4, kind = BUG_FIX),
|
||||||
|
|||||||
Reference in New Issue
Block a user