From d818af5287b2790ad8b6679333d634e327890bdd Mon Sep 17 00:00:00 2001 From: Mikhail Zarechenskiy Date: Mon, 18 Dec 2017 04:43:04 +0300 Subject: [PATCH] [NI] Don't forget to analyze whole block for last postponed expression --- .../resolve/calls/tower/NewCallArguments.kt | 6 +- .../resolve/calls/tower/PSICallResolver.kt | 67 ++++++++++--------- ...allableReferenceAsLastExpressionInBlock.kt | 17 +++++ ...llableReferenceAsLastExpressionInBlock.txt | 4 ++ ...nctionExpressionAsLastExpressionInBlock.kt | 15 +++++ ...ctionExpressionAsLastExpressionInBlock.txt | 3 + .../functionLIteralInBlockInIf.kt | 7 +- .../functionLiterals/functionLiteralInIf.kt | 5 +- .../checkers/DiagnosticsTestGenerated.java | 12 ++++ .../DiagnosticsUsingJavacTestGenerated.java | 12 ++++ 10 files changed, 108 insertions(+), 40 deletions(-) create mode 100644 compiler/testData/diagnostics/tests/callableReference/callableReferenceAsLastExpressionInBlock.kt create mode 100644 compiler/testData/diagnostics/tests/callableReference/callableReferenceAsLastExpressionInBlock.txt create mode 100644 compiler/testData/diagnostics/tests/functionLiterals/functionExpressionAsLastExpressionInBlock.kt create mode 100644 compiler/testData/diagnostics/tests/functionLiterals/functionExpressionAsLastExpressionInBlock.txt diff --git a/compiler/frontend/src/org/jetbrains/kotlin/resolve/calls/tower/NewCallArguments.kt b/compiler/frontend/src/org/jetbrains/kotlin/resolve/calls/tower/NewCallArguments.kt index a01494afca1..8b07e2f7d8b 100644 --- a/compiler/frontend/src/org/jetbrains/kotlin/resolve/calls/tower/NewCallArguments.kt +++ b/compiler/frontend/src/org/jetbrains/kotlin/resolve/calls/tower/NewCallArguments.kt @@ -106,10 +106,11 @@ class LambdaKotlinCallArgumentImpl( dataFlowInfoBeforeThisArgument: DataFlowInfo, argumentName: Name?, val ktLambdaExpression: KtLambdaExpression, + val containingBlockForLambda: KtExpression, override val parametersTypes: Array? ) : PSIFunctionKotlinCallArgument(outerCallContext, valueArgument, dataFlowInfoBeforeThisArgument, argumentName) { override val ktFunction get() = ktLambdaExpression.functionLiteral - override val expression get() = ktLambdaExpression + override val expression get() = containingBlockForLambda } class FunctionExpressionImpl( @@ -117,12 +118,13 @@ class FunctionExpressionImpl( valueArgument: ValueArgument, dataFlowInfoBeforeThisArgument: DataFlowInfo, argumentName: Name?, + val containingBlockForFunction: KtExpression, override val ktFunction: KtNamedFunction, override val receiverType: UnwrappedType?, override val parametersTypes: Array, override val returnType: UnwrappedType? ) : FunctionExpression, PSIFunctionKotlinCallArgument(outerCallContext, valueArgument, dataFlowInfoBeforeThisArgument, argumentName) { - override val expression get() = ktFunction + override val expression get() = containingBlockForFunction } class CallableReferenceKotlinCallArgumentImpl( diff --git a/compiler/frontend/src/org/jetbrains/kotlin/resolve/calls/tower/PSICallResolver.kt b/compiler/frontend/src/org/jetbrains/kotlin/resolve/calls/tower/PSICallResolver.kt index 1b5af6ad871..8a83b41ffb2 100644 --- a/compiler/frontend/src/org/jetbrains/kotlin/resolve/calls/tower/PSICallResolver.kt +++ b/compiler/frontend/src/org/jetbrains/kotlin/resolve/calls/tower/PSICallResolver.kt @@ -16,6 +16,7 @@ package org.jetbrains.kotlin.resolve.calls.tower +import org.jetbrains.kotlin.builtins.KotlinBuiltIns import org.jetbrains.kotlin.config.LanguageFeature import org.jetbrains.kotlin.config.LanguageVersionSettings import org.jetbrains.kotlin.contracts.EffectSystem @@ -521,27 +522,14 @@ class PSICallResolver( ): PSIKotlinCallArgument { val builtIns = outerCallContext.scope.ownerDescriptor.builtIns val parseErrorArgument = ParseErrorKotlinCallArgument(valueArgument, startDataFlowInfo, builtIns) - val ktExpression = extractArgumentExpression(outerCallContext, valueArgument) ?: parseErrorArgument + val argumentExpression = valueArgument.getArgumentExpression() ?: return parseErrorArgument + + val ktExpression = KtPsiUtil.deparenthesize(argumentExpression) ?: parseErrorArgument val argumentName = valueArgument.getArgumentName()?.asName - val lambdaArgument: PSIKotlinCallArgument? = when (ktExpression) { - is KtLambdaExpression -> - LambdaKotlinCallArgumentImpl(outerCallContext, valueArgument, startDataFlowInfo, argumentName, ktExpression, - resolveParametersTypes(outerCallContext, ktExpression.functionLiteral)) - is KtNamedFunction -> { - val receiverType = resolveType(outerCallContext, ktExpression.receiverTypeReference) - val parametersTypes = resolveParametersTypes(outerCallContext, ktExpression) ?: emptyArray() - val returnType = resolveType(outerCallContext, ktExpression.typeReference) ?: - if (ktExpression.hasBlockBody()) builtIns.unitType else null - FunctionExpressionImpl(outerCallContext, valueArgument, startDataFlowInfo, argumentName, ktExpression, receiverType, parametersTypes, returnType) - } - - else -> null - } - if (lambdaArgument != null) { - checkNoSpread(outerCallContext, valueArgument) - return lambdaArgument + processFunctionalExpression(outerCallContext, argumentExpression, startDataFlowInfo, valueArgument, argumentName, builtIns)?.let { + return it } if (ktExpression is KtCollectionLiteralExpression) { @@ -596,24 +584,43 @@ class PSICallResolver( ktExpression, argumentName, lhsNewResult, name) } - val argumentExpression = valueArgument.getArgumentExpression() ?: return parseErrorArgument - // argumentExpression instead of ktExpression is hack -- type info should be stored also for parenthesized expression val typeInfo = expressionTypingServices.getTypeInfo(argumentExpression, context) return createSimplePSICallArgument(context, valueArgument, typeInfo) ?: parseErrorArgument } - private fun extractArgumentExpression(outerCallContext: BasicCallResolutionContext, valueArgument: ValueArgument): KtExpression? { - val argumentExpression = valueArgument.getArgumentExpression() ?: return null + private fun processFunctionalExpression( + outerCallContext: BasicCallResolutionContext, + argumentExpression: KtExpression, + startDataFlowInfo: DataFlowInfo, + valueArgument: ValueArgument, + argumentName: Name?, + builtIns: KotlinBuiltIns + ): PSIKotlinCallArgument? { + val expression = ArgumentTypeResolver.getFunctionLiteralArgumentIfAny(argumentExpression, outerCallContext) ?: return null + val postponedExpression = if (expression is KtFunctionLiteral) expression.getParentOfType(true) else expression - val ktExpression = ArgumentTypeResolver.getFunctionLiteralArgumentIfAny(argumentExpression, outerCallContext) ?: - ArgumentTypeResolver.getCallableReferenceExpressionIfAny(argumentExpression, outerCallContext) ?: - KtPsiUtil.deparenthesize(argumentExpression) + val lambdaArgument: PSIKotlinCallArgument? = when (postponedExpression) { + is KtLambdaExpression -> + LambdaKotlinCallArgumentImpl(outerCallContext, valueArgument, startDataFlowInfo, argumentName, postponedExpression, + argumentExpression, resolveParametersTypes(outerCallContext, postponedExpression.functionLiteral)) - return when (ktExpression) { - is KtFunctionLiteral -> ktExpression.getParentOfType(true) - else -> ktExpression + is KtNamedFunction -> { + val receiverType = resolveType(outerCallContext, postponedExpression.receiverTypeReference) + val parametersTypes = resolveParametersTypes(outerCallContext, postponedExpression) ?: emptyArray() + val returnType = resolveType(outerCallContext, postponedExpression.typeReference) ?: + if (postponedExpression.hasBlockBody()) builtIns.unitType else null + + FunctionExpressionImpl(outerCallContext, valueArgument, startDataFlowInfo, argumentName, + argumentExpression, postponedExpression, receiverType, parametersTypes, returnType) + } + + else -> return null } + + checkNoSpread(outerCallContext, valueArgument) + + return lambdaArgument } private fun checkNoSpread(context: BasicCallResolutionContext, valueArgument: ValueArgument) { @@ -629,6 +636,4 @@ class PSICallResolver( parameterList.parameters[it]?.typeReference?.let { resolveType(context, it) } } } - - -} \ No newline at end of file +} diff --git a/compiler/testData/diagnostics/tests/callableReference/callableReferenceAsLastExpressionInBlock.kt b/compiler/testData/diagnostics/tests/callableReference/callableReferenceAsLastExpressionInBlock.kt new file mode 100644 index 00000000000..325d94a202b --- /dev/null +++ b/compiler/testData/diagnostics/tests/callableReference/callableReferenceAsLastExpressionInBlock.kt @@ -0,0 +1,17 @@ +// !DIAGNOSTICS: -UNUSED_VARIABLE +// !CHECK_TYPE + +import kotlin.reflect.KFunction0 + +fun test() { + val a = if (true) { + val x = 1 + "".length + ::foo + } else { + ::foo + } + a checkType { _>() } +} + +fun foo(): Int = 0 \ No newline at end of file diff --git a/compiler/testData/diagnostics/tests/callableReference/callableReferenceAsLastExpressionInBlock.txt b/compiler/testData/diagnostics/tests/callableReference/callableReferenceAsLastExpressionInBlock.txt new file mode 100644 index 00000000000..27ef292e20e --- /dev/null +++ b/compiler/testData/diagnostics/tests/callableReference/callableReferenceAsLastExpressionInBlock.txt @@ -0,0 +1,4 @@ +package + +public fun foo(): kotlin.Int +public fun test(): kotlin.Unit diff --git a/compiler/testData/diagnostics/tests/functionLiterals/functionExpressionAsLastExpressionInBlock.kt b/compiler/testData/diagnostics/tests/functionLiterals/functionExpressionAsLastExpressionInBlock.kt new file mode 100644 index 00000000000..61f1611b10e --- /dev/null +++ b/compiler/testData/diagnostics/tests/functionLiterals/functionExpressionAsLastExpressionInBlock.kt @@ -0,0 +1,15 @@ +// !DIAGNOSTICS: -UNUSED_VARIABLE -UNUSED_EXPRESSION + +import java.util.HashSet + +fun test123() { + val g: (Int) -> Unit = if (true) { + val set = HashSet() + fun (i: Int) { + set.add(i) + } + } + else { + { it -> it } + } +} \ No newline at end of file diff --git a/compiler/testData/diagnostics/tests/functionLiterals/functionExpressionAsLastExpressionInBlock.txt b/compiler/testData/diagnostics/tests/functionLiterals/functionExpressionAsLastExpressionInBlock.txt new file mode 100644 index 00000000000..5c0518ec7d0 --- /dev/null +++ b/compiler/testData/diagnostics/tests/functionLiterals/functionExpressionAsLastExpressionInBlock.txt @@ -0,0 +1,3 @@ +package + +public fun test123(): kotlin.Unit diff --git a/compiler/testData/diagnostics/tests/functionLiterals/functionLIteralInBlockInIf.kt b/compiler/testData/diagnostics/tests/functionLiterals/functionLIteralInBlockInIf.kt index 0e07db55cba..678ab68bc0c 100644 --- a/compiler/testData/diagnostics/tests/functionLiterals/functionLIteralInBlockInIf.kt +++ b/compiler/testData/diagnostics/tests/functionLiterals/functionLIteralInBlockInIf.kt @@ -1,11 +1,10 @@ -// !WITH_NEW_INFERENCE // !CHECK_TYPE fun test() { val a = if (true) { val x = 1 - ({ x }) + ({ x }) } else { - { 2 } + { 2 } } - a checkType { _<() -> Int>() } + a checkType { _<() -> Int>() } } \ No newline at end of file diff --git a/compiler/testData/diagnostics/tests/functionLiterals/functionLiteralInIf.kt b/compiler/testData/diagnostics/tests/functionLiterals/functionLiteralInIf.kt index cb6b38f6b9f..b007414c1bd 100644 --- a/compiler/testData/diagnostics/tests/functionLiterals/functionLiteralInIf.kt +++ b/compiler/testData/diagnostics/tests/functionLiterals/functionLiteralInIf.kt @@ -1,13 +1,12 @@ -// !WITH_NEW_INFERENCE // !DIAGNOSTICS: -UNUSED_VARIABLE -UNUSED_EXPRESSION import java.util.HashSet fun test123() { val g: (Int) -> Unit = if (true) { - val set = HashSet<Int>(); + val set = HashSet(); { i -> - set.add(i) + set.add(i) } } else { diff --git a/compiler/tests/org/jetbrains/kotlin/checkers/DiagnosticsTestGenerated.java b/compiler/tests/org/jetbrains/kotlin/checkers/DiagnosticsTestGenerated.java index 10f9f25e199..0f64b293c59 100644 --- a/compiler/tests/org/jetbrains/kotlin/checkers/DiagnosticsTestGenerated.java +++ b/compiler/tests/org/jetbrains/kotlin/checkers/DiagnosticsTestGenerated.java @@ -1858,6 +1858,12 @@ public class DiagnosticsTestGenerated extends AbstractDiagnosticsTest { doTest(fileName); } + @TestMetadata("callableReferenceAsLastExpressionInBlock.kt") + public void testCallableReferenceAsLastExpressionInBlock() throws Exception { + String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/diagnostics/tests/callableReference/callableReferenceAsLastExpressionInBlock.kt"); + doTest(fileName); + } + @TestMetadata("classVsPackage.kt") public void testClassVsPackage() throws Exception { String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/diagnostics/tests/callableReference/classVsPackage.kt"); @@ -8422,6 +8428,12 @@ public class DiagnosticsTestGenerated extends AbstractDiagnosticsTest { doTest(fileName); } + @TestMetadata("functionExpressionAsLastExpressionInBlock.kt") + public void testFunctionExpressionAsLastExpressionInBlock() throws Exception { + String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/diagnostics/tests/functionLiterals/functionExpressionAsLastExpressionInBlock.kt"); + doTest(fileName); + } + @TestMetadata("functionLIteralInBlockInIf.kt") public void testFunctionLIteralInBlockInIf() throws Exception { String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/diagnostics/tests/functionLiterals/functionLIteralInBlockInIf.kt"); diff --git a/compiler/tests/org/jetbrains/kotlin/checkers/javac/DiagnosticsUsingJavacTestGenerated.java b/compiler/tests/org/jetbrains/kotlin/checkers/javac/DiagnosticsUsingJavacTestGenerated.java index 0df2fd13e20..934dab18fde 100644 --- a/compiler/tests/org/jetbrains/kotlin/checkers/javac/DiagnosticsUsingJavacTestGenerated.java +++ b/compiler/tests/org/jetbrains/kotlin/checkers/javac/DiagnosticsUsingJavacTestGenerated.java @@ -1858,6 +1858,12 @@ public class DiagnosticsUsingJavacTestGenerated extends AbstractDiagnosticsUsing doTest(fileName); } + @TestMetadata("callableReferenceAsLastExpressionInBlock.kt") + public void testCallableReferenceAsLastExpressionInBlock() throws Exception { + String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/diagnostics/tests/callableReference/callableReferenceAsLastExpressionInBlock.kt"); + doTest(fileName); + } + @TestMetadata("classVsPackage.kt") public void testClassVsPackage() throws Exception { String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/diagnostics/tests/callableReference/classVsPackage.kt"); @@ -8422,6 +8428,12 @@ public class DiagnosticsUsingJavacTestGenerated extends AbstractDiagnosticsUsing doTest(fileName); } + @TestMetadata("functionExpressionAsLastExpressionInBlock.kt") + public void testFunctionExpressionAsLastExpressionInBlock() throws Exception { + String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/diagnostics/tests/functionLiterals/functionExpressionAsLastExpressionInBlock.kt"); + doTest(fileName); + } + @TestMetadata("functionLIteralInBlockInIf.kt") public void testFunctionLIteralInBlockInIf() throws Exception { String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/diagnostics/tests/functionLiterals/functionLIteralInBlockInIf.kt");