diff --git a/compiler/frontend/src/org/jetbrains/kotlin/psi/JetPsiUtil.java b/compiler/frontend/src/org/jetbrains/kotlin/psi/JetPsiUtil.java index 621a1f4d3b6..231b7979758 100644 --- a/compiler/frontend/src/org/jetbrains/kotlin/psi/JetPsiUtil.java +++ b/compiler/frontend/src/org/jetbrains/kotlin/psi/JetPsiUtil.java @@ -410,6 +410,14 @@ public class JetPsiUtil { return element instanceof JetSimpleNameExpression && isBackingFieldReference((JetSimpleNameExpression)element); } + @Nullable + public static JetElement getExpressionOrLastStatementInBlock(@Nullable JetExpression expression) { + if (expression instanceof JetBlockExpression) { + return getLastStatementInABlock((JetBlockExpression) expression); + } + return expression; + } + @Nullable public static JetElement getLastStatementInABlock(@Nullable JetBlockExpression blockExpression) { if (blockExpression == null) return null; 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 148c88742c2..d300bd6eb39 100644 --- a/compiler/frontend/src/org/jetbrains/kotlin/resolve/calls/ArgumentTypeResolver.java +++ b/compiler/frontend/src/org/jetbrains/kotlin/resolve/calls/ArgumentTypeResolver.java @@ -136,7 +136,7 @@ public class ArgumentTypeResolver { } @NotNull - public static JetFunctionLiteralExpression getFunctionLiteralArgument( + public static JetFunction getFunctionLiteralArgument( @NotNull JetExpression expression, @NotNull ResolutionContext context ) { assert isFunctionLiteralArgument(expression, context); @@ -145,12 +145,15 @@ public class ArgumentTypeResolver { } @Nullable - private static JetFunctionLiteralExpression getFunctionLiteralArgumentIfAny( + private static JetFunction getFunctionLiteralArgumentIfAny( @NotNull JetExpression expression, @NotNull ResolutionContext context ) { JetExpression deparenthesizedExpression = getLastElementDeparenthesized(expression, context); if (deparenthesizedExpression instanceof JetFunctionLiteralExpression) { - return (JetFunctionLiteralExpression) deparenthesizedExpression; + return ((JetFunctionLiteralExpression) deparenthesizedExpression).getFunctionLiteral(); + } + if (deparenthesizedExpression instanceof JetFunction) { + return (JetFunction) deparenthesizedExpression; } return null; } @@ -199,12 +202,12 @@ public class ArgumentTypeResolver { @NotNull public JetTypeInfo getFunctionLiteralTypeInfo( @NotNull JetExpression expression, - @NotNull JetFunctionLiteralExpression functionLiteralExpression, + @NotNull JetFunction functionLiteral, @NotNull CallResolutionContext context, @NotNull ResolveArgumentsMode resolveArgumentsMode ) { if (resolveArgumentsMode == SHAPE_FUNCTION_ARGUMENTS) { - JetType type = getShapeTypeOfFunctionLiteral(functionLiteralExpression, context.scope, context.trace, true); + JetType type = getShapeTypeOfFunctionLiteral(functionLiteral, context.scope, context.trace, true); return JetTypeInfo.create(type, context.dataFlowInfo); } return expressionTypingServices.getTypeInfo(expression, context.replaceContextDependency(INDEPENDENT)); @@ -212,28 +215,27 @@ public class ArgumentTypeResolver { @Nullable public JetType getShapeTypeOfFunctionLiteral( - @NotNull JetFunctionLiteralExpression expression, + @NotNull JetFunction functionLiteral, @NotNull JetScope scope, @NotNull BindingTrace trace, boolean expectedTypeIsUnknown ) { - if (expression.getFunctionLiteral().getValueParameterList() == null) { + if (functionLiteral.getValueParameterList() == null) { return expectedTypeIsUnknown ? PLACEHOLDER_FUNCTION_TYPE : builtIns.getFunctionType( Annotations.EMPTY, null, Collections.emptyList(), DONT_CARE); } - List valueParameters = expression.getValueParameters(); + List valueParameters = functionLiteral.getValueParameters(); TemporaryBindingTrace temporaryTrace = TemporaryBindingTrace.create( trace, "trace to resolve function literal parameter types"); List parameterTypes = Lists.newArrayList(); for (JetParameter parameter : valueParameters) { parameterTypes.add(resolveTypeRefWithDefault(parameter.getTypeReference(), scope, temporaryTrace, DONT_CARE)); } - JetFunctionLiteral functionLiteral = expression.getFunctionLiteral(); JetType returnType = resolveTypeRefWithDefault(functionLiteral.getTypeReference(), scope, temporaryTrace, DONT_CARE); assert returnType != null; JetType receiverType = resolveTypeRefWithDefault(functionLiteral.getReceiverTypeReference(), scope, temporaryTrace, null); return builtIns.getFunctionType(Annotations.EMPTY, receiverType, parameterTypes, - returnType); + returnType); } @Nullable diff --git a/compiler/frontend/src/org/jetbrains/kotlin/resolve/calls/CandidateResolver.java b/compiler/frontend/src/org/jetbrains/kotlin/resolve/calls/CandidateResolver.java index c4bcd1e043c..9b33ae89b8e 100644 --- a/compiler/frontend/src/org/jetbrains/kotlin/resolve/calls/CandidateResolver.java +++ b/compiler/frontend/src/org/jetbrains/kotlin/resolve/calls/CandidateResolver.java @@ -281,12 +281,12 @@ public class CandidateResolver { if (argumentExpression == null) return; if (!ArgumentTypeResolver.isFunctionLiteralArgument(argumentExpression, context)) return; - JetFunctionLiteralExpression functionLiteralExpression = ArgumentTypeResolver.getFunctionLiteralArgument(argumentExpression, context); + JetFunction functionLiteral = ArgumentTypeResolver.getFunctionLiteralArgument(argumentExpression, context); JetType effectiveExpectedType = getEffectiveExpectedType(valueParameterDescriptor, valueArgument); JetType expectedType = constraintSystem.getCurrentSubstitutor().substitute(effectiveExpectedType, Variance.INVARIANT); if (expectedType == null || TypeUtils.isDontCarePlaceholder(expectedType)) { - expectedType = argumentTypeResolver.getShapeTypeOfFunctionLiteral(functionLiteralExpression, context.scope, context.trace, false); + expectedType = argumentTypeResolver.getShapeTypeOfFunctionLiteral(functionLiteral, context.scope, context.trace, false); } if (expectedType == null || !KotlinBuiltIns.isFunctionOrExtensionFunctionType(expectedType) || CallResolverUtil.hasUnknownFunctionParameter(expectedType)) { @@ -301,7 +301,7 @@ public class CandidateResolver { TemporaryTraceAndCache temporaryToResolveFunctionLiteral = TemporaryTraceAndCache.create( context, "trace to resolve function literal with expected return type", argumentExpression); - JetElement statementExpression = JetPsiUtil.getLastStatementInABlock(functionLiteralExpression.getBodyExpression()); + JetElement statementExpression = JetPsiUtil.getExpressionOrLastStatementInBlock(functionLiteral.getBodyExpression()); if (statementExpression == null) return; boolean[] mismatch = new boolean[1]; ObservableBindingTrace errorInterceptingTrace = ExpressionTypingUtils.makeTraceInterceptingTypeMismatch( @@ -311,7 +311,7 @@ public class CandidateResolver { .replaceDataFlowInfo(dataFlowInfoForArgument).replaceResolutionResultsCache(temporaryToResolveFunctionLiteral.cache) .replaceContextDependency(INDEPENDENT); JetType type = argumentTypeResolver.getFunctionLiteralTypeInfo( - argumentExpression, functionLiteralExpression, newContext, RESOLVE_FUNCTION_ARGUMENTS).getType(); + argumentExpression, functionLiteral, newContext, RESOLVE_FUNCTION_ARGUMENTS).getType(); if (!mismatch[0]) { constraintSystem.addSubtypeConstraint( type, effectiveExpectedType, VALUE_PARAMETER_POSITION.position(valueParameterDescriptor.getIndex())); @@ -323,7 +323,7 @@ public class CandidateResolver { CallCandidateResolutionContext newContext = context .replaceExpectedType(expectedTypeWithoutReturnType).replaceDataFlowInfo(dataFlowInfoForArgument) .replaceContextDependency(INDEPENDENT); - JetType type = argumentTypeResolver.getFunctionLiteralTypeInfo(argumentExpression, functionLiteralExpression, newContext, + JetType type = argumentTypeResolver.getFunctionLiteralTypeInfo(argumentExpression, functionLiteral, newContext, RESOLVE_FUNCTION_ARGUMENTS).getType(); constraintSystem.addSubtypeConstraint( type, effectiveExpectedType, VALUE_PARAMETER_POSITION.position(valueParameterDescriptor.getIndex())); diff --git a/compiler/testData/diagnostics/tests/functionAsExpression/DifficultInferenceForParameter.kt b/compiler/testData/diagnostics/tests/functionAsExpression/DifficultInferenceForParameter.kt new file mode 100644 index 00000000000..1a46ccb279e --- /dev/null +++ b/compiler/testData/diagnostics/tests/functionAsExpression/DifficultInferenceForParameter.kt @@ -0,0 +1,7 @@ +// !DIAGNOSTICS: -UNUSED_VARIABLE -UNUSED_PARAMETER + +fun foo(f : (T) -> T) : T = throw Exception() + +fun test() { + val a : Int = foo(fun f(x) = x) +} diff --git a/compiler/testData/diagnostics/tests/functionAsExpression/DifficultInferenceForParameter.txt b/compiler/testData/diagnostics/tests/functionAsExpression/DifficultInferenceForParameter.txt new file mode 100644 index 00000000000..55a63f30733 --- /dev/null +++ b/compiler/testData/diagnostics/tests/functionAsExpression/DifficultInferenceForParameter.txt @@ -0,0 +1,4 @@ +package + +internal fun foo(/*0*/ f: (T) -> T): T +internal fun test(): kotlin.Unit diff --git a/compiler/testData/diagnostics/tests/functionAsExpression/InferenceParametersTypes.kt b/compiler/testData/diagnostics/tests/functionAsExpression/InferenceParametersTypes.kt new file mode 100644 index 00000000000..c55cc070498 --- /dev/null +++ b/compiler/testData/diagnostics/tests/functionAsExpression/InferenceParametersTypes.kt @@ -0,0 +1,18 @@ +// !DIAGNOSTICS: -UNUSED_PARAMETER -UNUSED_VARIABLE +fun listOf(): List = null!! + +fun test(a: (Int) -> Int) { + test(fun (x) = 4) + + test(fun (x) = x) + + test(fun (x): Int { x: Int; return 4 }) +} + +fun test2(a: () -> List) { + test2(fun () = listOf()) +} + +val a: (Int) -> Unit = fun(x) { x: Int } + +val b: (Int) -> Unit = fun(x: String) {} \ No newline at end of file diff --git a/compiler/testData/diagnostics/tests/functionAsExpression/InferenceParametersTypes.txt b/compiler/testData/diagnostics/tests/functionAsExpression/InferenceParametersTypes.txt new file mode 100644 index 00000000000..ea8999850c2 --- /dev/null +++ b/compiler/testData/diagnostics/tests/functionAsExpression/InferenceParametersTypes.txt @@ -0,0 +1,7 @@ +package + +internal val a: (kotlin.Int) -> kotlin.Unit +internal val b: (kotlin.Int) -> kotlin.Unit +internal fun listOf(): kotlin.List +internal fun test(/*0*/ a: (kotlin.Int) -> kotlin.Int): kotlin.Unit +internal fun test2(/*0*/ a: () -> kotlin.List): kotlin.Unit diff --git a/compiler/testData/diagnostics/tests/functionAsExpression/MissingParameterTypes.kt b/compiler/testData/diagnostics/tests/functionAsExpression/MissingParameterTypes.kt index 977d970280e..15ef022f0ac 100644 --- a/compiler/testData/diagnostics/tests/functionAsExpression/MissingParameterTypes.kt +++ b/compiler/testData/diagnostics/tests/functionAsExpression/MissingParameterTypes.kt @@ -13,13 +13,13 @@ val e: (Int, String) -> Int = fun Int = fun (x: String) = 3 fun test1(a: (Int) -> Unit) { - test1(fun (x) { x : Int}) + test1(fun (x) { x : Int}) } fun test2(a: (Int) -> Unit) { - test2(fun (x: String) {}) + test2(fun (x: String) {}) } fun test3(a: (Int, String) -> Unit) { - test3(fun (x: String) {}) + test3(fun (x: String) {}) } \ No newline at end of file diff --git a/compiler/tests/org/jetbrains/kotlin/checkers/JetDiagnosticsTestGenerated.java b/compiler/tests/org/jetbrains/kotlin/checkers/JetDiagnosticsTestGenerated.java index b6ca5270998..11daef5149d 100644 --- a/compiler/tests/org/jetbrains/kotlin/checkers/JetDiagnosticsTestGenerated.java +++ b/compiler/tests/org/jetbrains/kotlin/checkers/JetDiagnosticsTestGenerated.java @@ -4634,6 +4634,12 @@ public class JetDiagnosticsTestGenerated extends AbstractJetDiagnosticsTest { doTest(fileName); } + @TestMetadata("DifficultInferenceForParameter.kt") + public void testDifficultInferenceForParameter() throws Exception { + String fileName = JetTestUtils.navigationMetadata("compiler/testData/diagnostics/tests/functionAsExpression/DifficultInferenceForParameter.kt"); + doTest(fileName); + } + @TestMetadata("ForbiddenNonLocalReturn.kt") public void testForbiddenNonLocalReturn() throws Exception { String fileName = JetTestUtils.navigationMetadata("compiler/testData/diagnostics/tests/functionAsExpression/ForbiddenNonLocalReturn.kt"); @@ -4646,6 +4652,12 @@ public class JetDiagnosticsTestGenerated extends AbstractJetDiagnosticsTest { doTest(fileName); } + @TestMetadata("InferenceParametersTypes.kt") + public void testInferenceParametersTypes() throws Exception { + String fileName = JetTestUtils.navigationMetadata("compiler/testData/diagnostics/tests/functionAsExpression/InferenceParametersTypes.kt"); + doTest(fileName); + } + @TestMetadata("MissingParameterTypes.kt") public void testMissingParameterTypes() throws Exception { String fileName = JetTestUtils.navigationMetadata("compiler/testData/diagnostics/tests/functionAsExpression/MissingParameterTypes.kt");