initialDataFlowInfoForArguments introduced in CallExpressionResolver methods #KT-10175 Fixed
This commit is contained in:
+35
-17
@@ -32,6 +32,7 @@ import org.jetbrains.kotlin.resolve.calls.context.BasicCallResolutionContext;
|
||||
import org.jetbrains.kotlin.resolve.calls.context.CheckArgumentTypesMode;
|
||||
import org.jetbrains.kotlin.resolve.calls.context.ResolutionContext;
|
||||
import org.jetbrains.kotlin.resolve.calls.context.TemporaryTraceAndCache;
|
||||
import org.jetbrains.kotlin.resolve.calls.model.DataFlowInfoForArgumentsImpl;
|
||||
import org.jetbrains.kotlin.resolve.calls.model.ResolvedCall;
|
||||
import org.jetbrains.kotlin.resolve.calls.results.OverloadResolutionResults;
|
||||
import org.jetbrains.kotlin.resolve.calls.results.OverloadResolutionResultsUtil;
|
||||
@@ -95,13 +96,15 @@ public class CallExpressionResolver {
|
||||
}
|
||||
|
||||
@Nullable
|
||||
public ResolvedCall<FunctionDescriptor> getResolvedCallForFunction(
|
||||
private ResolvedCall<FunctionDescriptor> getResolvedCallForFunction(
|
||||
@NotNull Call call,
|
||||
@NotNull ResolutionContext context, @NotNull CheckArgumentTypesMode checkArguments,
|
||||
@NotNull boolean[] result
|
||||
@NotNull boolean[] result,
|
||||
@NotNull DataFlowInfo initialDataFlowInfoForArguments
|
||||
) {
|
||||
OverloadResolutionResults<FunctionDescriptor> results = callResolver.resolveFunctionCall(
|
||||
BasicCallResolutionContext.create(context, call, checkArguments));
|
||||
BasicCallResolutionContext.create(context, call, checkArguments,
|
||||
new DataFlowInfoForArgumentsImpl(initialDataFlowInfoForArguments, call)));
|
||||
if (!results.isNothing()) {
|
||||
result[0] = true;
|
||||
return OverloadResolutionResultsUtil.getResultingCall(results, context.contextDependency);
|
||||
@@ -145,6 +148,15 @@ public class CallExpressionResolver {
|
||||
public KotlinTypeInfo getSimpleNameExpressionTypeInfo(
|
||||
@NotNull KtSimpleNameExpression nameExpression, @Nullable Receiver receiver,
|
||||
@Nullable ASTNode callOperationNode, @NotNull ExpressionTypingContext context
|
||||
) {
|
||||
return getSimpleNameExpressionTypeInfo(nameExpression, receiver, callOperationNode, context, context.dataFlowInfo);
|
||||
}
|
||||
|
||||
@NotNull
|
||||
private KotlinTypeInfo getSimpleNameExpressionTypeInfo(
|
||||
@NotNull KtSimpleNameExpression nameExpression, @Nullable Receiver receiver,
|
||||
@Nullable ASTNode callOperationNode, @NotNull ExpressionTypingContext context,
|
||||
@NotNull DataFlowInfo initialDataFlowInfoForArguments
|
||||
) {
|
||||
boolean[] result = new boolean[1];
|
||||
|
||||
@@ -155,7 +167,7 @@ public class CallExpressionResolver {
|
||||
|
||||
if (result[0]) {
|
||||
temporaryForVariable.commit();
|
||||
return TypeInfoFactoryKt.createTypeInfo(type, context);
|
||||
return TypeInfoFactoryKt.createTypeInfo(type, initialDataFlowInfoForArguments);
|
||||
}
|
||||
|
||||
Call call = CallMaker.makeCall(nameExpression, receiver, callOperationNode, nameExpression, Collections.<ValueArgument>emptyList());
|
||||
@@ -163,7 +175,7 @@ public class CallExpressionResolver {
|
||||
context, "trace to resolve as function", nameExpression);
|
||||
ResolutionContext newContext = context.replaceTraceAndCache(temporaryForFunction);
|
||||
ResolvedCall<FunctionDescriptor> resolvedCall = getResolvedCallForFunction(
|
||||
call, newContext, CheckArgumentTypesMode.CHECK_VALUE_ARGUMENTS, result);
|
||||
call, newContext, CheckArgumentTypesMode.CHECK_VALUE_ARGUMENTS, result, initialDataFlowInfoForArguments);
|
||||
if (result[0]) {
|
||||
FunctionDescriptor functionDescriptor = resolvedCall != null ? resolvedCall.getResultingDescriptor() : null;
|
||||
if (!(functionDescriptor instanceof ConstructorDescriptor)) {
|
||||
@@ -193,7 +205,8 @@ public class CallExpressionResolver {
|
||||
@NotNull KtCallExpression callExpression, @Nullable ReceiverValue receiver,
|
||||
@Nullable ASTNode callOperationNode, @NotNull ExpressionTypingContext context
|
||||
) {
|
||||
KotlinTypeInfo typeInfo = getCallExpressionTypeInfoWithoutFinalTypeCheck(callExpression, receiver, callOperationNode, context);
|
||||
KotlinTypeInfo typeInfo = getCallExpressionTypeInfoWithoutFinalTypeCheck(
|
||||
callExpression, receiver, callOperationNode, context, context.dataFlowInfo);
|
||||
if (context.contextDependency == INDEPENDENT) {
|
||||
dataFlowAnalyzer.checkType(typeInfo.getType(), callExpression, context);
|
||||
}
|
||||
@@ -207,7 +220,8 @@ public class CallExpressionResolver {
|
||||
@NotNull
|
||||
private KotlinTypeInfo getCallExpressionTypeInfoWithoutFinalTypeCheck(
|
||||
@NotNull KtCallExpression callExpression, @Nullable Receiver receiver,
|
||||
@Nullable ASTNode callOperationNode, @NotNull ExpressionTypingContext context
|
||||
@Nullable ASTNode callOperationNode, @NotNull ExpressionTypingContext context,
|
||||
@NotNull DataFlowInfo initialDataFlowInfoForArguments
|
||||
) {
|
||||
boolean[] result = new boolean[1];
|
||||
Call call = CallMaker.makeCall(receiver, callOperationNode, callExpression);
|
||||
@@ -217,7 +231,9 @@ public class CallExpressionResolver {
|
||||
ResolvedCall<FunctionDescriptor> resolvedCall = getResolvedCallForFunction(
|
||||
call,
|
||||
context.replaceTraceAndCache(temporaryForFunction),
|
||||
CheckArgumentTypesMode.CHECK_VALUE_ARGUMENTS, result);
|
||||
CheckArgumentTypesMode.CHECK_VALUE_ARGUMENTS,
|
||||
result,
|
||||
initialDataFlowInfoForArguments);
|
||||
if (result[0]) {
|
||||
FunctionDescriptor functionDescriptor = resolvedCall != null ? resolvedCall.getResultingDescriptor() : null;
|
||||
temporaryForFunction.commit();
|
||||
@@ -311,14 +327,16 @@ public class CallExpressionResolver {
|
||||
@NotNull Receiver receiver,
|
||||
@Nullable ASTNode callOperationNode,
|
||||
@Nullable KtExpression selectorExpression,
|
||||
@NotNull ExpressionTypingContext context
|
||||
@NotNull ExpressionTypingContext context,
|
||||
@NotNull DataFlowInfo initialDataFlowInfoForArguments
|
||||
) {
|
||||
if (selectorExpression instanceof KtCallExpression) {
|
||||
return getCallExpressionTypeInfoWithoutFinalTypeCheck((KtCallExpression) selectorExpression, receiver,
|
||||
callOperationNode, context);
|
||||
callOperationNode, context, initialDataFlowInfoForArguments);
|
||||
}
|
||||
else if (selectorExpression instanceof KtSimpleNameExpression) {
|
||||
return getSimpleNameExpressionTypeInfo((KtSimpleNameExpression) selectorExpression, receiver, callOperationNode, context);
|
||||
return getSimpleNameExpressionTypeInfo(
|
||||
(KtSimpleNameExpression) selectorExpression, receiver, callOperationNode, context, initialDataFlowInfoForArguments);
|
||||
}
|
||||
else if (selectorExpression != null) {
|
||||
expressionTypingServices.getTypeInfo(selectorExpression, context);
|
||||
@@ -422,15 +440,15 @@ public class CallExpressionResolver {
|
||||
contextForSelector = contextForSelector.replaceDataFlowInfo(receiverDataFlowInfo);
|
||||
}
|
||||
|
||||
DataFlowInfo initialDataFlowInfoForArguments = contextForSelector.dataFlowInfo;
|
||||
if (receiver instanceof ReceiverValue) {
|
||||
DataFlowValue receiverDataFlowValue = DataFlowValueFactory.createDataFlowValue((ReceiverValue) receiver, context);
|
||||
// Additional "receiver != null" information
|
||||
// Should be applied if we consider a safe call
|
||||
if (element.getSafe()) {
|
||||
DataFlowInfo dataFlowInfo = contextForSelector.dataFlowInfo;
|
||||
if (dataFlowInfo.getPredictableNullability(receiverDataFlowValue).canBeNull()) {
|
||||
contextForSelector = contextForSelector.replaceDataFlowInfo(
|
||||
dataFlowInfo.disequate(receiverDataFlowValue, DataFlowValue.nullValue(builtIns)));
|
||||
if (initialDataFlowInfoForArguments.getPredictableNullability(receiverDataFlowValue).canBeNull()) {
|
||||
initialDataFlowInfoForArguments = initialDataFlowInfoForArguments.disequate(
|
||||
receiverDataFlowValue, DataFlowValue.nullValue(builtIns));
|
||||
}
|
||||
else {
|
||||
reportUnnecessarySafeCall(trace, receiverType, element.getNode(), receiver);
|
||||
@@ -439,8 +457,8 @@ public class CallExpressionResolver {
|
||||
}
|
||||
|
||||
KtExpression selectorExpression = element.getSelector();
|
||||
KotlinTypeInfo selectorReturnTypeInfo =
|
||||
getSelectorReturnTypeInfo(receiver, element.getNode(), selectorExpression, contextForSelector);
|
||||
KotlinTypeInfo selectorReturnTypeInfo = getSelectorReturnTypeInfo(
|
||||
receiver, element.getNode(), selectorExpression, contextForSelector, initialDataFlowInfoForArguments);
|
||||
KotlinType selectorReturnType = selectorReturnTypeInfo.getType();
|
||||
|
||||
if (qualifierReceiver != null) {
|
||||
|
||||
+1
-1
@@ -9,5 +9,5 @@ fun <T> T.testThis(): String? {
|
||||
if (this != null) {
|
||||
return this<!UNNECESSARY_SAFE_CALL!>?.<!>toString()
|
||||
}
|
||||
return this?.toString()
|
||||
return <!DEBUG_INFO_CONSTANT!>this<!>?.toString()
|
||||
}
|
||||
+6
@@ -0,0 +1,6 @@
|
||||
fun Any?.foo(my: My) = my === this
|
||||
|
||||
class My(val x: Any)
|
||||
|
||||
// my is nullable in brackets because Any?.foo has nullable receiver
|
||||
fun foo(my: My?) = my?.x.foo(<!TYPE_MISMATCH!>my<!>)
|
||||
+12
@@ -0,0 +1,12 @@
|
||||
package
|
||||
|
||||
public fun foo(/*0*/ my: My?): kotlin.Boolean
|
||||
public fun kotlin.Any?.foo(/*0*/ my: My): kotlin.Boolean
|
||||
|
||||
public final class My {
|
||||
public constructor My(/*0*/ x: kotlin.Any)
|
||||
public final val x: kotlin.Any
|
||||
public open override /*1*/ /*fake_override*/ fun equals(/*0*/ other: kotlin.Any?): kotlin.Boolean
|
||||
public open override /*1*/ /*fake_override*/ fun hashCode(): kotlin.Int
|
||||
public open override /*1*/ /*fake_override*/ fun toString(): kotlin.String
|
||||
}
|
||||
@@ -16652,6 +16652,12 @@ public class DiagnosticsTestGenerated extends AbstractDiagnosticsTest {
|
||||
doTest(fileName);
|
||||
}
|
||||
|
||||
@TestMetadata("simpleNullableReceiver.kt")
|
||||
public void testSimpleNullableReceiver() throws Exception {
|
||||
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/diagnostics/tests/smartCasts/safecalls/simpleNullableReceiver.kt");
|
||||
doTest(fileName);
|
||||
}
|
||||
|
||||
@TestMetadata("twoArgs.kt")
|
||||
public void testTwoArgs() throws Exception {
|
||||
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/diagnostics/tests/smartCasts/safecalls/twoArgs.kt");
|
||||
|
||||
+1
-1
@@ -20,7 +20,7 @@ fun test(a: A?) {
|
||||
}
|
||||
|
||||
if (a is B? && a is C?) {
|
||||
<info descr="Smart cast to B">a</info><info>?.</info>bar()
|
||||
<info descr="Smart cast to B?">a</info><info>?.</info>bar()
|
||||
}
|
||||
|
||||
a<info>?.</info>foo()
|
||||
|
||||
Reference in New Issue
Block a user