Update recorded type for argument in parentheses correctly
This commit is contained in:
@@ -77,7 +77,7 @@ public class JetPsiUtil {
|
|||||||
|
|
||||||
@Nullable
|
@Nullable
|
||||||
public static JetExpression deparenthesize(@Nullable JetExpression expression) {
|
public static JetExpression deparenthesize(@Nullable JetExpression expression) {
|
||||||
return deparenthesize(expression, true);
|
return deparenthesize(expression, /* deparenthesizeBinaryExpressionWithTypeRHS = */ true);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Nullable
|
@Nullable
|
||||||
@@ -85,15 +85,34 @@ public class JetPsiUtil {
|
|||||||
@Nullable JetExpression expression,
|
@Nullable JetExpression expression,
|
||||||
boolean deparenthesizeBinaryExpressionWithTypeRHS
|
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
|
@Nullable
|
||||||
@Deprecated //Use JetPsiUtil.deparenthesize() or ExpressionTypingServices.deparenthesize()
|
|
||||||
public static JetExpression deparenthesizeWithResolutionStrategy(
|
public static JetExpression deparenthesizeWithResolutionStrategy(
|
||||||
@Nullable JetExpression expression,
|
@Nullable JetExpression expression,
|
||||||
boolean deparenthesizeBinaryExpressionWithTypeRHS,
|
boolean deparenthesizeBinaryExpressionWithTypeRHS,
|
||||||
@Nullable Function<JetTypeReference, Void> typeResolutionStrategy
|
@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) {
|
if (deparenthesizeBinaryExpressionWithTypeRHS && expression instanceof JetBinaryExpressionWithTypeRHS) {
|
||||||
JetBinaryExpressionWithTypeRHS binaryExpression = (JetBinaryExpressionWithTypeRHS) expression;
|
JetBinaryExpressionWithTypeRHS binaryExpression = (JetBinaryExpressionWithTypeRHS) expression;
|
||||||
@@ -117,8 +136,8 @@ public class JetPsiUtil {
|
|||||||
}
|
}
|
||||||
if (expression instanceof JetParenthesizedExpression) {
|
if (expression instanceof JetParenthesizedExpression) {
|
||||||
JetExpression innerExpression = ((JetParenthesizedExpression) expression).getExpression();
|
JetExpression innerExpression = ((JetParenthesizedExpression) expression).getExpression();
|
||||||
return innerExpression != null ? deparenthesizeWithResolutionStrategy(
|
return innerExpression != null && deparenthesizeRecursively ? deparenthesizeWithResolutionStrategy(
|
||||||
innerExpression, deparenthesizeBinaryExpressionWithTypeRHS, typeResolutionStrategy) : null;
|
innerExpression, deparenthesizeBinaryExpressionWithTypeRHS, true, typeResolutionStrategy) : innerExpression;
|
||||||
}
|
}
|
||||||
return expression;
|
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.calls.CallResolverUtil.ResolveArgumentsMode.RESOLVE_FUNCTION_ARGUMENTS
|
||||||
import org.jetbrains.jet.lang.resolve.TemporaryBindingTrace
|
import org.jetbrains.jet.lang.resolve.TemporaryBindingTrace
|
||||||
import org.jetbrains.jet.lang.resolve.calls.util.getAllValueArguments
|
import org.jetbrains.jet.lang.resolve.calls.util.getAllValueArguments
|
||||||
|
import org.jetbrains.jet.lang.psi.JetQualifiedExpression
|
||||||
|
import java.util.ArrayList
|
||||||
|
|
||||||
public class CallCompleter(
|
public class CallCompleter(
|
||||||
val argumentTypeResolver: ArgumentTypeResolver,
|
val argumentTypeResolver: ArgumentTypeResolver,
|
||||||
@@ -247,7 +249,7 @@ public class CallCompleter(
|
|||||||
updatedType = ArgumentTypeResolver.updateResultArgumentTypeIfNotDenotable(context as ResolutionContext<*>, expression)
|
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),
|
// 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).
|
// 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)
|
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 {
|
private fun hasNecessarySafeCall(expression: JetExpression, trace: BindingTrace): Boolean {
|
||||||
// We are interested in type of the last call:
|
// We are interested in type of the last call:
|
||||||
// 'a.b?.foo()' is safe call, but 'a?.b.foo()' is not.
|
// '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");
|
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")
|
@TestMetadata("completeTypeInferenceForNestedInNoneApplicable.kt")
|
||||||
public void testCompleteTypeInferenceForNestedInNoneApplicable() throws Exception {
|
public void testCompleteTypeInferenceForNestedInNoneApplicable() throws Exception {
|
||||||
doTest("compiler/testData/diagnostics/tests/resolve/nestedCalls/completeTypeInferenceForNestedInNoneApplicable.kt");
|
doTest("compiler/testData/diagnostics/tests/resolve/nestedCalls/completeTypeInferenceForNestedInNoneApplicable.kt");
|
||||||
|
|||||||
Reference in New Issue
Block a user