Update recorded type for argument in parentheses correctly
This commit is contained in:
@@ -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");
|
||||
|
||||
Reference in New Issue
Block a user