diff --git a/compiler/frontend/src/org/jetbrains/kotlin/resolve/calls/ArgumentTypeResolver.java b/compiler/frontend/src/org/jetbrains/kotlin/resolve/calls/ArgumentTypeResolver.java index 481676f64ac..f48f7db6aac 100644 --- a/compiler/frontend/src/org/jetbrains/kotlin/resolve/calls/ArgumentTypeResolver.java +++ b/compiler/frontend/src/org/jetbrains/kotlin/resolve/calls/ArgumentTypeResolver.java @@ -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()); } } diff --git a/compiler/frontend/src/org/jetbrains/kotlin/resolve/calls/CallCompleter.kt b/compiler/frontend/src/org/jetbrains/kotlin/resolve/calls/CallCompleter.kt index 2427ed1d7e5..0e3ccceaef1 100644 --- a/compiler/frontend/src/org/jetbrains/kotlin/resolve/calls/CallCompleter.kt +++ b/compiler/frontend/src/org/jetbrains/kotlin/resolve/calls/CallCompleter.kt @@ -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 diff --git a/compiler/frontend/src/org/jetbrains/kotlin/resolve/calls/CandidateResolver.kt b/compiler/frontend/src/org/jetbrains/kotlin/resolve/calls/CandidateResolver.kt index 2572992aa19..55fb2383ee9 100644 --- a/compiler/frontend/src/org/jetbrains/kotlin/resolve/calls/CandidateResolver.kt +++ b/compiler/frontend/src/org/jetbrains/kotlin/resolve/calls/CandidateResolver.kt @@ -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) diff --git a/compiler/frontend/src/org/jetbrains/kotlin/resolve/calls/GenericCandidateResolver.kt b/compiler/frontend/src/org/jetbrains/kotlin/resolve/calls/GenericCandidateResolver.kt index fc596e8c6af..b05634fd28c 100644 --- a/compiler/frontend/src/org/jetbrains/kotlin/resolve/calls/GenericCandidateResolver.kt +++ b/compiler/frontend/src/org/jetbrains/kotlin/resolve/calls/GenericCandidateResolver.kt @@ -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) } diff --git a/compiler/frontend/src/org/jetbrains/kotlin/resolve/calls/inference/CoroutineInferenceUtil.kt b/compiler/frontend/src/org/jetbrains/kotlin/resolve/calls/inference/CoroutineInferenceUtil.kt index 9d83e4f4489..2094ccdc6f7 100644 --- a/compiler/frontend/src/org/jetbrains/kotlin/resolve/calls/inference/CoroutineInferenceUtil.kt +++ b/compiler/frontend/src/org/jetbrains/kotlin/resolve/calls/inference/CoroutineInferenceUtil.kt @@ -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 { diff --git a/compiler/frontend/src/org/jetbrains/kotlin/types/expressions/FunctionsTypingVisitor.kt b/compiler/frontend/src/org/jetbrains/kotlin/types/expressions/FunctionsTypingVisitor.kt index ab4d37f19d5..ef928a19c07 100644 --- a/compiler/frontend/src/org/jetbrains/kotlin/types/expressions/FunctionsTypingVisitor.kt +++ b/compiler/frontend/src/org/jetbrains/kotlin/types/expressions/FunctionsTypingVisitor.kt @@ -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) diff --git a/compiler/testData/diagnostics/tests/inference/coerceFunctionLiteralToSuspend.kt b/compiler/testData/diagnostics/tests/inference/coerceFunctionLiteralToSuspend.kt new file mode 100644 index 00000000000..f5b78c252bb --- /dev/null +++ b/compiler/testData/diagnostics/tests/inference/coerceFunctionLiteralToSuspend.kt @@ -0,0 +1,29 @@ +// !DIAGNOSTICS: -UNUSED_PARAMETER + +fun fail1(c: suspend () -> Unit) {} + +fun fail2(c: () -> Unit) {} + +fun success1(c: suspend () -> Unit) {} + +fun test1() { + fail1(fun () {}) + fun fail2(c: suspend () -> Unit) {} + fail2(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(fun () {}) + fun fail4(c: suspend () -> Unit) {} + fail4(fun () {}) + fun success2(c: () -> Unit) {} + success2(fun() {}) +} \ No newline at end of file diff --git a/compiler/testData/diagnostics/tests/inference/coerceFunctionLiteralToSuspend.txt b/compiler/testData/diagnostics/tests/inference/coerceFunctionLiteralToSuspend.txt new file mode 100644 index 00000000000..632a3b034f4 --- /dev/null +++ b/compiler/testData/diagnostics/tests/inference/coerceFunctionLiteralToSuspend.txt @@ -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 diff --git a/compiler/testData/diagnostics/tests/inference/lambdaInValInitializerWithAnonymousFunctions.kt b/compiler/testData/diagnostics/tests/inference/lambdaInValInitializerWithAnonymousFunctions.kt index 31903b638ca..7cea82da7a0 100644 --- a/compiler/testData/diagnostics/tests/inference/lambdaInValInitializerWithAnonymousFunctions.kt +++ b/compiler/testData/diagnostics/tests/inference/lambdaInValInitializerWithAnonymousFunctions.kt @@ -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 = fun () {} +val test2f: suspend Any.() -> Unit = 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 = fun (k: Int) = k + 1 -val test4f: SuspendFn = fun Any.() {} \ No newline at end of file +val test3f: suspend Any.(Int) -> Int = fun (k: Int) = k + 1 +val test4f: SuspendFn = fun Any.() {} \ No newline at end of file diff --git a/compiler/tests/org/jetbrains/kotlin/checkers/DiagnosticsTestGenerated.java b/compiler/tests/org/jetbrains/kotlin/checkers/DiagnosticsTestGenerated.java index d089c895604..f81ceb597ae 100644 --- a/compiler/tests/org/jetbrains/kotlin/checkers/DiagnosticsTestGenerated.java +++ b/compiler/tests/org/jetbrains/kotlin/checkers/DiagnosticsTestGenerated.java @@ -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"); diff --git a/compiler/tests/org/jetbrains/kotlin/checkers/javac/DiagnosticsUsingJavacTestGenerated.java b/compiler/tests/org/jetbrains/kotlin/checkers/javac/DiagnosticsUsingJavacTestGenerated.java index bd398426850..0ec223cba82 100644 --- a/compiler/tests/org/jetbrains/kotlin/checkers/javac/DiagnosticsUsingJavacTestGenerated.java +++ b/compiler/tests/org/jetbrains/kotlin/checkers/javac/DiagnosticsUsingJavacTestGenerated.java @@ -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");