Update recorded type for argument in parentheses correctly

This commit is contained in:
Svetlana Isakova
2014-05-08 17:52:28 +04:00
parent 12ddf76df4
commit a3e306b820
4 changed files with 73 additions and 6 deletions
@@ -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<JetTypeReference, Void> typeResolutionStrategy
) {
return deparenthesizeWithResolutionStrategy(expression, true, true, typeResolutionStrategy);
}
@Nullable
private static JetExpression deparenthesizeWithResolutionStrategy(
@Nullable JetExpression expression,
boolean deparenthesizeBinaryExpressionWithTypeRHS,
boolean deparenthesizeRecursively,
@Nullable Function<JetTypeReference, Void> 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;
}
@@ -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<JetExpression>()
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.
@@ -0,0 +1,20 @@
trait Foo<T>
class Bar {
fun <T> invoke(): Foo<T> = throw Exception()
}
class A {
val bar = Bar()
}
fun fooInt(l: Foo<Int>) = 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())))
}
@@ -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");