diff --git a/compiler/frontend/src/org/jetbrains/jet/lang/psi/JetPsiUtil.java b/compiler/frontend/src/org/jetbrains/jet/lang/psi/JetPsiUtil.java index c607278f230..b61108671bd 100644 --- a/compiler/frontend/src/org/jetbrains/jet/lang/psi/JetPsiUtil.java +++ b/compiler/frontend/src/org/jetbrains/jet/lang/psi/JetPsiUtil.java @@ -77,7 +77,7 @@ public class JetPsiUtil { @Nullable public static JetExpression deparenthesize(@Nullable JetExpression expression) { - return deparenthesize(expression, true); + return deparenthesize(expression, /* deparenthesizeBinaryExpressionWithTypeRHS = */ true); } @Nullable @@ -85,15 +85,34 @@ public class JetPsiUtil { @Nullable JetExpression expression, boolean deparenthesizeBinaryExpressionWithTypeRHS ) { - return deparenthesizeWithResolutionStrategy(expression, deparenthesizeBinaryExpressionWithTypeRHS, null); + return deparenthesizeWithResolutionStrategy( + expression, deparenthesizeBinaryExpressionWithTypeRHS, /* deparenthesizeRecursively = */ true, null); + } + + @Nullable + public static JetExpression deparenthesizeOnce( + @Nullable JetExpression expression, + boolean deparenthesizeBinaryExpressionWithTypeRHS + ) { + return deparenthesizeWithResolutionStrategy( + expression, deparenthesizeBinaryExpressionWithTypeRHS, /* deparenthesizeRecursively = */ false, null); } @Nullable - @Deprecated //Use JetPsiUtil.deparenthesize() or ExpressionTypingServices.deparenthesize() public static JetExpression deparenthesizeWithResolutionStrategy( @Nullable JetExpression expression, boolean deparenthesizeBinaryExpressionWithTypeRHS, @Nullable Function typeResolutionStrategy + ) { + return deparenthesizeWithResolutionStrategy(expression, true, true, typeResolutionStrategy); + } + + @Nullable + private static JetExpression deparenthesizeWithResolutionStrategy( + @Nullable JetExpression expression, + boolean deparenthesizeBinaryExpressionWithTypeRHS, + boolean deparenthesizeRecursively, + @Nullable Function typeResolutionStrategy ) { if (deparenthesizeBinaryExpressionWithTypeRHS && expression instanceof JetBinaryExpressionWithTypeRHS) { JetBinaryExpressionWithTypeRHS binaryExpression = (JetBinaryExpressionWithTypeRHS) expression; @@ -117,8 +136,8 @@ public class JetPsiUtil { } if (expression instanceof JetParenthesizedExpression) { JetExpression innerExpression = ((JetParenthesizedExpression) expression).getExpression(); - return innerExpression != null ? deparenthesizeWithResolutionStrategy( - innerExpression, deparenthesizeBinaryExpressionWithTypeRHS, typeResolutionStrategy) : null; + return innerExpression != null && deparenthesizeRecursively ? deparenthesizeWithResolutionStrategy( + innerExpression, deparenthesizeBinaryExpressionWithTypeRHS, true, typeResolutionStrategy) : innerExpression; } return expression; } diff --git a/compiler/frontend/src/org/jetbrains/jet/lang/resolve/calls/CallCompleter.kt b/compiler/frontend/src/org/jetbrains/jet/lang/resolve/calls/CallCompleter.kt index 530bc0b2361..205deb5f85b 100644 --- a/compiler/frontend/src/org/jetbrains/jet/lang/resolve/calls/CallCompleter.kt +++ b/compiler/frontend/src/org/jetbrains/jet/lang/resolve/calls/CallCompleter.kt @@ -57,6 +57,8 @@ import org.jetbrains.jet.lang.psi.JetSafeQualifiedExpression import org.jetbrains.jet.lang.resolve.calls.CallResolverUtil.ResolveArgumentsMode.RESOLVE_FUNCTION_ARGUMENTS import org.jetbrains.jet.lang.resolve.TemporaryBindingTrace import org.jetbrains.jet.lang.resolve.calls.util.getAllValueArguments +import org.jetbrains.jet.lang.psi.JetQualifiedExpression +import java.util.ArrayList public class CallCompleter( val argumentTypeResolver: ArgumentTypeResolver, @@ -247,7 +249,7 @@ public class CallCompleter( updatedType = ArgumentTypeResolver.updateResultArgumentTypeIfNotDenotable(context as ResolutionContext<*>, expression) } - BindingContextUtils.updateRecordedType(updatedType, expression, context.trace, hasNecessarySafeCall(expression, context.trace)) + updateRecordedTypeForArgument(updatedType, expression, context.trace) // 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). @@ -290,6 +292,27 @@ public class CallCompleter( return argument?.getCorrespondingCall(bindingContext) } + private fun updateRecordedTypeForArgument(updatedType: JetType?, argumentExpression: JetExpression, trace: BindingTrace) { + fun deparenthesizeOrGetSelector(expression: JetExpression?): JetExpression? { + val deparenthesized = JetPsiUtil.deparenthesizeOnce(expression, /* deparenthesizeBinaryExpressionWithTypeRHS = */ false) + if (deparenthesized != expression) return deparenthesized + + if (expression is JetQualifiedExpression) return expression.getSelectorExpression() + return null + } + + val expressions = ArrayList() + var expression: JetExpression? = argumentExpression + while (expression != null) { + expressions.add(expression!!) + expression = deparenthesizeOrGetSelector(expression) + } + expressions.forEach { expression -> + BindingContextUtils.updateRecordedType( + updatedType, expression, trace, /* shouldBeMadeNullable = */ hasNecessarySafeCall(expression, trace)) + } + } + private fun hasNecessarySafeCall(expression: JetExpression, trace: BindingTrace): Boolean { // We are interested in type of the last call: // 'a.b?.foo()' is safe call, but 'a?.b.foo()' is not. diff --git a/compiler/testData/diagnostics/tests/resolve/nestedCalls/argumentsInParentheses.kt b/compiler/testData/diagnostics/tests/resolve/nestedCalls/argumentsInParentheses.kt new file mode 100644 index 00000000000..822249e523e --- /dev/null +++ b/compiler/testData/diagnostics/tests/resolve/nestedCalls/argumentsInParentheses.kt @@ -0,0 +1,20 @@ +trait Foo + +class Bar { + fun invoke(): Foo = throw Exception() +} + +class A { + val bar = Bar() +} + +fun fooInt(l: Foo) = l + +fun test(bar: Bar, a: A) { + // no elements with error types + fooInt((bar())) + fooInt(if (true) bar() else bar()) + fooInt(@label bar()) + fooInt(a.bar()) + fooInt(((@label if (true) (a.bar()) else bar()))) +} \ No newline at end of file diff --git a/compiler/tests/org/jetbrains/jet/checkers/JetDiagnosticsTestGenerated.java b/compiler/tests/org/jetbrains/jet/checkers/JetDiagnosticsTestGenerated.java index f0c45efbf0c..3212c3fcc7c 100644 --- a/compiler/tests/org/jetbrains/jet/checkers/JetDiagnosticsTestGenerated.java +++ b/compiler/tests/org/jetbrains/jet/checkers/JetDiagnosticsTestGenerated.java @@ -7042,6 +7042,11 @@ public class JetDiagnosticsTestGenerated extends AbstractJetDiagnosticsTest { doTest("compiler/testData/diagnostics/tests/resolve/nestedCalls/analyzeUnmappedArguments.kt"); } + @TestMetadata("argumentsInParentheses.kt") + public void testArgumentsInParentheses() throws Exception { + doTest("compiler/testData/diagnostics/tests/resolve/nestedCalls/argumentsInParentheses.kt"); + } + @TestMetadata("completeTypeInferenceForNestedInNoneApplicable.kt") public void testCompleteTypeInferenceForNestedInNoneApplicable() throws Exception { doTest("compiler/testData/diagnostics/tests/resolve/nestedCalls/completeTypeInferenceForNestedInNoneApplicable.kt");