Do not coerce function literals to suspend.

The design is to use `suspend fun` instead of coercion, just as suspend
lambdas.
However, this syntax is not supported in the parser. But this is not a
problem, since the coercion lead to internal compiler error.
As a workaround everybody uses suspend lambdas.
 #KT-24860: Fixed
This commit is contained in:
Ilmir Usmanov
2018-06-13 16:29:48 +03:00
committed by Ilya Gorbunov
parent d57e1bb68b
commit 9df411481c
11 changed files with 102 additions and 94 deletions
@@ -1,17 +1,6 @@
/*
* Copyright 2010-2017 JetBrains s.r.o.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
* Copyright 2010-2018 JetBrains s.r.o. 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;
@@ -198,7 +187,8 @@ public class ArgumentTypeResolver {
public KotlinTypeInfo getArgumentTypeInfo(
@Nullable KtExpression expression,
@NotNull CallResolutionContext<?> context,
@NotNull ResolveArgumentsMode resolveArgumentsMode
@NotNull ResolveArgumentsMode resolveArgumentsMode,
boolean suspendFunctionTypeExpected
) {
if (expression == null) {
return TypeInfoFactoryKt.noTypeInfo(context);
@@ -206,7 +196,7 @@ public class ArgumentTypeResolver {
KtFunction functionLiteralArgument = getFunctionLiteralArgumentIfAny(expression, context);
if (functionLiteralArgument != null) {
return getFunctionLiteralTypeInfo(expression, functionLiteralArgument, context, resolveArgumentsMode);
return getFunctionLiteralTypeInfo(expression, functionLiteralArgument, context, resolveArgumentsMode, suspendFunctionTypeExpected);
}
KtCallableReferenceExpression callableReferenceExpression = getCallableReferenceExpressionIfAny(expression, context);
@@ -319,10 +309,11 @@ public class ArgumentTypeResolver {
@NotNull KtExpression expression,
@NotNull KtFunction functionLiteral,
@NotNull CallResolutionContext<?> context,
@NotNull ResolveArgumentsMode resolveArgumentsMode
@NotNull ResolveArgumentsMode resolveArgumentsMode,
boolean suspendFunctionTypeExpected
) {
if (resolveArgumentsMode == SHAPE_FUNCTION_ARGUMENTS) {
KotlinType type = getShapeTypeOfFunctionLiteral(functionLiteral, context.scope, context.trace, true);
KotlinType type = getShapeTypeOfFunctionLiteral(functionLiteral, context.scope, context.trace, true, suspendFunctionTypeExpected);
return TypeInfoFactoryKt.createTypeInfo(type, context);
}
return expressionTypingServices.getTypeInfo(expression, context.replaceContextDependency(INDEPENDENT));
@@ -333,7 +324,8 @@ public class ArgumentTypeResolver {
@NotNull KtFunction function,
@NotNull LexicalScope scope,
@NotNull BindingTrace trace,
boolean expectedTypeIsUnknown
boolean expectedTypeIsUnknown,
boolean suspendFunctionTypeExpected
) {
boolean isFunctionLiteral = function instanceof KtFunctionLiteral;
if (function.getValueParameterList() == null && isFunctionLiteral) {
@@ -363,7 +355,7 @@ public class ArgumentTypeResolver {
return expectedTypeIsUnknown && isFunctionLiteral
? functionPlaceholders.createFunctionPlaceholderType(parameterTypes, /* hasDeclaredArguments = */ true)
: FunctionTypesKt.createFunctionType(
builtIns, Annotations.Companion.getEMPTY(), receiverType, parameterTypes, parameterNames, returnType
builtIns, Annotations.Companion.getEMPTY(), receiverType, parameterTypes, parameterNames, returnType, suspendFunctionTypeExpected
);
}
@@ -399,7 +391,7 @@ public class ArgumentTypeResolver {
CallResolutionContext<?> newContext = context.replaceDataFlowInfo(infoForArguments.getInfo(argument));
// Here we go inside arguments and determine additional data flow information for them
KotlinTypeInfo typeInfoForCall = getArgumentTypeInfo(expression, newContext, resolveArgumentsMode);
KotlinTypeInfo typeInfoForCall = getArgumentTypeInfo(expression, newContext, resolveArgumentsMode, false);
infoForArguments.updateInfo(argument, typeInfoForCall.getDataFlowInfo());
}
}
@@ -1,17 +1,6 @@
/*
* Copyright 2010-2017 JetBrains s.r.o.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
* Copyright 2010-2018 JetBrains s.r.o. 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
@@ -367,7 +356,7 @@ class CallCompleter(
// While the expected type is not known, the function literal arguments are not analyzed (to analyze function literal bodies once),
// but they should be analyzed when the expected type is known (during the call completion).
ArgumentTypeResolver.getFunctionLiteralArgumentIfAny(expression, context)?.let { functionLiteralArgument ->
argumentTypeResolver.getFunctionLiteralTypeInfo(expression, functionLiteralArgument, context, RESOLVE_FUNCTION_ARGUMENTS)
argumentTypeResolver.getFunctionLiteralTypeInfo(expression, functionLiteralArgument, context, RESOLVE_FUNCTION_ARGUMENTS, false)
}
// While the expected type is not known, (possibly overloaded) callable references can have placeholder types
@@ -1,23 +1,13 @@
/*
* Copyright 2010-2017 JetBrains s.r.o.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
* Copyright 2010-2018 JetBrains s.r.o. 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
import com.google.common.collect.Lists
import org.jetbrains.kotlin.builtins.ReflectionTypes
import org.jetbrains.kotlin.builtins.isSuspendFunctionType
import org.jetbrains.kotlin.descriptors.*
import org.jetbrains.kotlin.descriptors.annotations.AnnotationDescriptor
import org.jetbrains.kotlin.descriptors.impl.TypeAliasConstructorDescriptor
@@ -362,7 +352,7 @@ class CandidateResolver(
val expectedType = getEffectiveExpectedType(parameterDescriptor, argument, context)
val newContext = context.replaceDataFlowInfo(infoForArguments.getInfo(argument)).replaceExpectedType(expectedType)
val typeInfoForCall = argumentTypeResolver.getArgumentTypeInfo(expression, newContext, resolveFunctionArgumentBodies)
val typeInfoForCall = argumentTypeResolver.getArgumentTypeInfo(expression, newContext, resolveFunctionArgumentBodies, expectedType.isSuspendFunctionType)
val type = typeInfoForCall.type
infoForArguments.updateInfo(argument, typeInfoForCall.dataFlowInfo)
@@ -1,25 +1,11 @@
/*
* Copyright 2010-2017 JetBrains s.r.o.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
* Copyright 2010-2018 JetBrains s.r.o. 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
import org.jetbrains.kotlin.builtins.KotlinBuiltIns
import org.jetbrains.kotlin.builtins.ReflectionTypes
import org.jetbrains.kotlin.builtins.isBuiltinFunctionalTypeOrSubtype
import org.jetbrains.kotlin.builtins.isFunctionTypeOrSubtype
import org.jetbrains.kotlin.builtins.*
import org.jetbrains.kotlin.config.LanguageFeature
import org.jetbrains.kotlin.config.LanguageVersionSettings
import org.jetbrains.kotlin.descriptors.CallableDescriptor
@@ -261,7 +247,12 @@ class GenericCandidateResolver(
val dataFlowInfoForArgument = context.candidateCall.dataFlowInfoForArguments.getInfo(valueArgument)
val newContext = context.replaceExpectedType(expectedType).replaceDataFlowInfo(dataFlowInfoForArgument)
val typeInfoForCall = argumentTypeResolver.getArgumentTypeInfo(argumentExpression, newContext, resolveFunctionArgumentBodies)
val typeInfoForCall = argumentTypeResolver.getArgumentTypeInfo(
argumentExpression,
newContext,
resolveFunctionArgumentBodies,
expectedType?.isSuspendFunctionType == true
)
context.candidateCall.dataFlowInfoForArguments.updateInfo(valueArgument, typeInfoForCall.dataFlowInfo)
val constraintPosition = VALUE_PARAMETER_POSITION.position(valueParameterDescriptor.index)
@@ -435,7 +426,13 @@ class GenericCandidateResolver(
var expectedType = newSubstitution.buildSubstitutor().substitute(effectiveExpectedType, Variance.IN_VARIANCE)
if (expectedType == null || TypeUtils.isDontCarePlaceholder(expectedType)) {
expectedType = argumentTypeResolver.getShapeTypeOfFunctionLiteral(functionLiteral, context.scope, context.trace, false)
expectedType = argumentTypeResolver.getShapeTypeOfFunctionLiteral(
functionLiteral,
context.scope,
context.trace,
false,
expectedType?.isSuspendFunctionType == true
)
}
if (expectedType == null || !expectedType.isBuiltinFunctionalTypeOrSubtype || hasUnknownFunctionParameter(expectedType)) {
return
@@ -463,7 +460,8 @@ class GenericCandidateResolver(
.replaceDataFlowInfo(dataFlowInfoForArgument).replaceResolutionResultsCache(temporaryToResolveFunctionLiteral.cache)
.replaceContextDependency(INDEPENDENT)
val type = argumentTypeResolver.getFunctionLiteralTypeInfo(
argumentExpression, functionLiteral, newContext, RESOLVE_FUNCTION_ARGUMENTS
argumentExpression, functionLiteral, newContext, RESOLVE_FUNCTION_ARGUMENTS,
expectedType.isSuspendFunctionType
).type
if (!mismatch[0]) {
constraintSystem.addSubtypeConstraint(type, effectiveExpectedTypeInSystem, position)
@@ -476,8 +474,10 @@ class GenericCandidateResolver(
val newContext = context.replaceExpectedType(expectedTypeWithEstimatedReturnType).replaceDataFlowInfo(dataFlowInfoForArgument)
.replaceContextDependency(INDEPENDENT)
val type =
argumentTypeResolver.getFunctionLiteralTypeInfo(argumentExpression, functionLiteral, newContext, RESOLVE_FUNCTION_ARGUMENTS)
.type
argumentTypeResolver.getFunctionLiteralTypeInfo(
argumentExpression, functionLiteral, newContext, RESOLVE_FUNCTION_ARGUMENTS,
expectedType.isSuspendFunctionType
).type
constraintSystem.addSubtypeConstraint(type, effectiveExpectedTypeInSystem, position)
}
@@ -1,17 +1,6 @@
/*
* Copyright 2010-2017 JetBrains s.r.o.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
* Copyright 2010-2018 JetBrains s.r.o. 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.inference
@@ -178,7 +167,7 @@ class CoroutineInferenceSupport(
val newContext = context.replaceExpectedType(newExpectedType)
.replaceDataFlowInfo(context.candidateCall.dataFlowInfoForArguments.getInfo(valueArgument))
.replaceContextDependency(ContextDependency.INDEPENDENT).replaceTraceAndCache(temporaryForCoroutine)
argumentTypeResolver.getFunctionLiteralTypeInfo(argumentExpression, functionLiteral, newContext, RESOLVE_FUNCTION_ARGUMENTS)
argumentTypeResolver.getFunctionLiteralTypeInfo(argumentExpression, functionLiteral, newContext, RESOLVE_FUNCTION_ARGUMENTS, true)
inferenceData.reportInferenceResult(csBuilder)
}
@@ -260,7 +249,7 @@ class CoroutineInferenceSupport(
context: CallResolutionContext<*>
): KotlinTypeInfo {
getFunctionLiteralArgumentIfAny(expression, context)?.let {
return argumentTypeResolver.getFunctionLiteralTypeInfo(expression, it, context, RESOLVE_FUNCTION_ARGUMENTS)
return argumentTypeResolver.getFunctionLiteralTypeInfo(expression, it, context, RESOLVE_FUNCTION_ARGUMENTS, false)
}
getCallableReferenceExpressionIfAny(expression, context)?.let {
@@ -1,5 +1,5 @@
/*
* Copyright 2000-2018 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license
* Copyright 2010-2018 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license
* that can be found in the license/LICENSE.txt file.
*/
@@ -118,11 +118,11 @@ internal class FunctionsTypingVisitor(facade: ExpressionTypingInternals) : Expre
val expectedType = context.expectedType
val functionalTypeExpected = expectedType.isBuiltinFunctionalType()
val suspendFunctionTypeExpected = expectedType.isSuspendFunctionType()
val resultType = functionDescriptor.createFunctionType(suspendFunctionTypeExpected)
// We forbid anonymous function expressions to suspend type coercion for now, until `suspend fun` syntax is supported
val resultType = functionDescriptor.createFunctionType(suspendFunction = false)
if (components.languageVersionSettings.supportsFeature(LanguageFeature.NewInference) && functionalTypeExpected)
if (components.languageVersionSettings.supportsFeature(LanguageFeature.NewInference) && functionalTypeExpected && !expectedType.isSuspendFunctionType)
createTypeInfo(resultType, context)
else
components.dataFlowAnalyzer.createCheckedTypeInfo(resultType, context, function)
@@ -0,0 +1,29 @@
// !DIAGNOSTICS: -UNUSED_PARAMETER
fun fail1(c: suspend () -> Unit) {}
fun fail2(c: () -> Unit) {}
fun success1(c: suspend () -> Unit) {}
fun test1() {
fail1(<!TYPE_MISMATCH!>fun () {}<!>)
fun fail2(c: suspend () -> Unit) {}
fail2(<!TYPE_MISMATCH!>fun () {}<!>)
fun success1(c: () -> Unit) {}
success1(fun() {})
}
suspend fun fail3(c: suspend () -> Unit) {}
suspend fun fail4(c: () -> Unit) {}
suspend fun success2(c: suspend () -> Unit) {}
suspend fun test2() {
fail3(<!TYPE_MISMATCH!>fun () {}<!>)
fun fail4(c: suspend () -> Unit) {}
fail4(<!TYPE_MISMATCH!>fun () {}<!>)
fun success2(c: () -> Unit) {}
success2(fun() {})
}
@@ -0,0 +1,10 @@
package
public fun fail1(/*0*/ c: suspend () -> kotlin.Unit): kotlin.Unit
public fun fail2(/*0*/ c: () -> kotlin.Unit): kotlin.Unit
public suspend fun fail3(/*0*/ c: suspend () -> kotlin.Unit): kotlin.Unit
public suspend fun fail4(/*0*/ c: () -> kotlin.Unit): kotlin.Unit
public fun success1(/*0*/ c: suspend () -> kotlin.Unit): kotlin.Unit
public suspend fun success2(/*0*/ c: suspend () -> kotlin.Unit): kotlin.Unit
public fun test1(): kotlin.Unit
public suspend fun test2(): kotlin.Unit
@@ -1,10 +1,9 @@
// !WITH_NEW_INFERENCE
typealias SuspendFn = suspend () -> Unit
val test1f: suspend () -> Unit = fun () {}
val test2f: suspend Any.() -> Unit = fun Any.() {}
val test1f: suspend () -> Unit = <!TYPE_MISMATCH!>fun () {}<!>
val test2f: suspend Any.() -> Unit = <!TYPE_MISMATCH!>fun Any.() {}<!>
// This is a bug in the old inference and should be fixed in new inference
// see "Fix anonymous function literals handling in type checker" for more deatils
val test3f: suspend Any.(Int) -> Int = <!OI;TYPE_MISMATCH!>fun (k: Int) = k + 1<!>
val test4f: SuspendFn = <!OI;TYPE_MISMATCH!>fun Any.() {}<!>
val test3f: suspend Any.(Int) -> Int = <!TYPE_MISMATCH!>fun (k: Int) = k + 1<!>
val test4f: SuspendFn = <!TYPE_MISMATCH!>fun Any.() {}<!>
@@ -9245,6 +9245,11 @@ public class DiagnosticsTestGenerated extends AbstractDiagnosticsTest {
runTest("compiler/testData/diagnostics/tests/inference/cannotCompleteResolveWithFunctionLiterals.kt");
}
@TestMetadata("coerceFunctionLiteralToSuspend.kt")
public void testCoerceFunctionLiteralToSuspend() throws Exception {
runTest("compiler/testData/diagnostics/tests/inference/coerceFunctionLiteralToSuspend.kt");
}
@TestMetadata("completeInferenceIfManyFailed.kt")
public void testCompleteInferenceIfManyFailed() throws Exception {
runTest("compiler/testData/diagnostics/tests/inference/completeInferenceIfManyFailed.kt");
@@ -9245,6 +9245,11 @@ public class DiagnosticsUsingJavacTestGenerated extends AbstractDiagnosticsUsing
runTest("compiler/testData/diagnostics/tests/inference/cannotCompleteResolveWithFunctionLiterals.kt");
}
@TestMetadata("coerceFunctionLiteralToSuspend.kt")
public void testCoerceFunctionLiteralToSuspend() throws Exception {
runTest("compiler/testData/diagnostics/tests/inference/coerceFunctionLiteralToSuspend.kt");
}
@TestMetadata("completeInferenceIfManyFailed.kt")
public void testCompleteInferenceIfManyFailed() throws Exception {
runTest("compiler/testData/diagnostics/tests/inference/completeInferenceIfManyFailed.kt");