Skip to content

Commit 0f80df7

Browse files
committed
initialDataFlowInfoForArguments introduced in CallExpressionResolver methods #KT-10175 Fixed
1 parent 16d97ab commit 0f80df7

File tree

6 files changed

+61
-19
lines changed

6 files changed

+61
-19
lines changed

compiler/frontend/src/org/jetbrains/kotlin/resolve/calls/CallExpressionResolver.java

Lines changed: 35 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,7 @@
3232
import org.jetbrains.kotlin.resolve.calls.context.CheckArgumentTypesMode;
3333
import org.jetbrains.kotlin.resolve.calls.context.ResolutionContext;
3434
import org.jetbrains.kotlin.resolve.calls.context.TemporaryTraceAndCache;
35+
import org.jetbrains.kotlin.resolve.calls.model.DataFlowInfoForArgumentsImpl;
3536
import org.jetbrains.kotlin.resolve.calls.model.ResolvedCall;
3637
import org.jetbrains.kotlin.resolve.calls.results.OverloadResolutionResults;
3738
import org.jetbrains.kotlin.resolve.calls.results.OverloadResolutionResultsUtil;
@@ -95,13 +96,15 @@ public void setExpressionTypingServices(@NotNull ExpressionTypingServices expres
9596
}
9697

9798
@Nullable
98-
public ResolvedCall<FunctionDescriptor> getResolvedCallForFunction(
99+
private ResolvedCall<FunctionDescriptor> getResolvedCallForFunction(
99100
@NotNull Call call,
100101
@NotNull ResolutionContext context, @NotNull CheckArgumentTypesMode checkArguments,
101-
@NotNull boolean[] result
102+
@NotNull boolean[] result,
103+
@NotNull DataFlowInfo initialDataFlowInfoForArguments
102104
) {
103105
OverloadResolutionResults<FunctionDescriptor> results = callResolver.resolveFunctionCall(
104-
BasicCallResolutionContext.create(context, call, checkArguments));
106+
BasicCallResolutionContext.create(context, call, checkArguments,
107+
new DataFlowInfoForArgumentsImpl(initialDataFlowInfoForArguments, call)));
105108
if (!results.isNothing()) {
106109
result[0] = true;
107110
return OverloadResolutionResultsUtil.getResultingCall(results, context.contextDependency);
@@ -145,6 +148,15 @@ private KotlinType getVariableType(
145148
public KotlinTypeInfo getSimpleNameExpressionTypeInfo(
146149
@NotNull KtSimpleNameExpression nameExpression, @Nullable Receiver receiver,
147150
@Nullable ASTNode callOperationNode, @NotNull ExpressionTypingContext context
151+
) {
152+
return getSimpleNameExpressionTypeInfo(nameExpression, receiver, callOperationNode, context, context.dataFlowInfo);
153+
}
154+
155+
@NotNull
156+
private KotlinTypeInfo getSimpleNameExpressionTypeInfo(
157+
@NotNull KtSimpleNameExpression nameExpression, @Nullable Receiver receiver,
158+
@Nullable ASTNode callOperationNode, @NotNull ExpressionTypingContext context,
159+
@NotNull DataFlowInfo initialDataFlowInfoForArguments
148160
) {
149161
boolean[] result = new boolean[1];
150162

@@ -155,15 +167,15 @@ public KotlinTypeInfo getSimpleNameExpressionTypeInfo(
155167

156168
if (result[0]) {
157169
temporaryForVariable.commit();
158-
return TypeInfoFactoryKt.createTypeInfo(type, context);
170+
return TypeInfoFactoryKt.createTypeInfo(type, initialDataFlowInfoForArguments);
159171
}
160172

161173
Call call = CallMaker.makeCall(nameExpression, receiver, callOperationNode, nameExpression, Collections.<ValueArgument>emptyList());
162174
TemporaryTraceAndCache temporaryForFunction = TemporaryTraceAndCache.create(
163175
context, "trace to resolve as function", nameExpression);
164176
ResolutionContext newContext = context.replaceTraceAndCache(temporaryForFunction);
165177
ResolvedCall<FunctionDescriptor> resolvedCall = getResolvedCallForFunction(
166-
call, newContext, CheckArgumentTypesMode.CHECK_VALUE_ARGUMENTS, result);
178+
call, newContext, CheckArgumentTypesMode.CHECK_VALUE_ARGUMENTS, result, initialDataFlowInfoForArguments);
167179
if (result[0]) {
168180
FunctionDescriptor functionDescriptor = resolvedCall != null ? resolvedCall.getResultingDescriptor() : null;
169181
if (!(functionDescriptor instanceof ConstructorDescriptor)) {
@@ -193,7 +205,8 @@ public KotlinTypeInfo getCallExpressionTypeInfo(
193205
@NotNull KtCallExpression callExpression, @Nullable ReceiverValue receiver,
194206
@Nullable ASTNode callOperationNode, @NotNull ExpressionTypingContext context
195207
) {
196-
KotlinTypeInfo typeInfo = getCallExpressionTypeInfoWithoutFinalTypeCheck(callExpression, receiver, callOperationNode, context);
208+
KotlinTypeInfo typeInfo = getCallExpressionTypeInfoWithoutFinalTypeCheck(
209+
callExpression, receiver, callOperationNode, context, context.dataFlowInfo);
197210
if (context.contextDependency == INDEPENDENT) {
198211
dataFlowAnalyzer.checkType(typeInfo.getType(), callExpression, context);
199212
}
@@ -207,7 +220,8 @@ public KotlinTypeInfo getCallExpressionTypeInfo(
207220
@NotNull
208221
private KotlinTypeInfo getCallExpressionTypeInfoWithoutFinalTypeCheck(
209222
@NotNull KtCallExpression callExpression, @Nullable Receiver receiver,
210-
@Nullable ASTNode callOperationNode, @NotNull ExpressionTypingContext context
223+
@Nullable ASTNode callOperationNode, @NotNull ExpressionTypingContext context,
224+
@NotNull DataFlowInfo initialDataFlowInfoForArguments
211225
) {
212226
boolean[] result = new boolean[1];
213227
Call call = CallMaker.makeCall(receiver, callOperationNode, callExpression);
@@ -217,7 +231,9 @@ private KotlinTypeInfo getCallExpressionTypeInfoWithoutFinalTypeCheck(
217231
ResolvedCall<FunctionDescriptor> resolvedCall = getResolvedCallForFunction(
218232
call,
219233
context.replaceTraceAndCache(temporaryForFunction),
220-
CheckArgumentTypesMode.CHECK_VALUE_ARGUMENTS, result);
234+
CheckArgumentTypesMode.CHECK_VALUE_ARGUMENTS,
235+
result,
236+
initialDataFlowInfoForArguments);
221237
if (result[0]) {
222238
FunctionDescriptor functionDescriptor = resolvedCall != null ? resolvedCall.getResultingDescriptor() : null;
223239
temporaryForFunction.commit();
@@ -311,14 +327,16 @@ private KotlinTypeInfo getSelectorReturnTypeInfo(
311327
@NotNull Receiver receiver,
312328
@Nullable ASTNode callOperationNode,
313329
@Nullable KtExpression selectorExpression,
314-
@NotNull ExpressionTypingContext context
330+
@NotNull ExpressionTypingContext context,
331+
@NotNull DataFlowInfo initialDataFlowInfoForArguments
315332
) {
316333
if (selectorExpression instanceof KtCallExpression) {
317334
return getCallExpressionTypeInfoWithoutFinalTypeCheck((KtCallExpression) selectorExpression, receiver,
318-
callOperationNode, context);
335+
callOperationNode, context, initialDataFlowInfoForArguments);
319336
}
320337
else if (selectorExpression instanceof KtSimpleNameExpression) {
321-
return getSimpleNameExpressionTypeInfo((KtSimpleNameExpression) selectorExpression, receiver, callOperationNode, context);
338+
return getSimpleNameExpressionTypeInfo(
339+
(KtSimpleNameExpression) selectorExpression, receiver, callOperationNode, context, initialDataFlowInfoForArguments);
322340
}
323341
else if (selectorExpression != null) {
324342
expressionTypingServices.getTypeInfo(selectorExpression, context);
@@ -422,15 +440,15 @@ public Boolean invoke(KtSimpleNameExpression nameExpression) {
422440
contextForSelector = contextForSelector.replaceDataFlowInfo(receiverDataFlowInfo);
423441
}
424442

443+
DataFlowInfo initialDataFlowInfoForArguments = contextForSelector.dataFlowInfo;
425444
if (receiver instanceof ReceiverValue) {
426445
DataFlowValue receiverDataFlowValue = DataFlowValueFactory.createDataFlowValue((ReceiverValue) receiver, context);
427446
// Additional "receiver != null" information
428447
// Should be applied if we consider a safe call
429448
if (element.getSafe()) {
430-
DataFlowInfo dataFlowInfo = contextForSelector.dataFlowInfo;
431-
if (dataFlowInfo.getPredictableNullability(receiverDataFlowValue).canBeNull()) {
432-
contextForSelector = contextForSelector.replaceDataFlowInfo(
433-
dataFlowInfo.disequate(receiverDataFlowValue, DataFlowValue.nullValue(builtIns)));
449+
if (initialDataFlowInfoForArguments.getPredictableNullability(receiverDataFlowValue).canBeNull()) {
450+
initialDataFlowInfoForArguments = initialDataFlowInfoForArguments.disequate(
451+
receiverDataFlowValue, DataFlowValue.nullValue(builtIns));
434452
}
435453
else {
436454
reportUnnecessarySafeCall(trace, receiverType, element.getNode(), receiver);
@@ -439,8 +457,8 @@ public Boolean invoke(KtSimpleNameExpression nameExpression) {
439457
}
440458

441459
KtExpression selectorExpression = element.getSelector();
442-
KotlinTypeInfo selectorReturnTypeInfo =
443-
getSelectorReturnTypeInfo(receiver, element.getNode(), selectorExpression, contextForSelector);
460+
KotlinTypeInfo selectorReturnTypeInfo = getSelectorReturnTypeInfo(
461+
receiver, element.getNode(), selectorExpression, contextForSelector, initialDataFlowInfoForArguments);
444462
KotlinType selectorReturnType = selectorReturnTypeInfo.getType();
445463

446464
if (qualifierReceiver != null) {

compiler/testData/diagnostics/tests/nullableTypes/safeCallOnTypeWithNullableUpperBound.kt

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,5 +9,5 @@ fun <T> T.testThis(): String? {
99
if (this != null) {
1010
return this<!UNNECESSARY_SAFE_CALL!>?.<!>toString()
1111
}
12-
return this?.toString()
12+
return <!DEBUG_INFO_CONSTANT!>this<!>?.toString()
1313
}
Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
fun Any?.foo(my: My) = my === this
2+
3+
class My(val x: Any)
4+
5+
// my is nullable in brackets because Any?.foo has nullable receiver
6+
fun foo(my: My?) = my?.x.foo(<!TYPE_MISMATCH!>my<!>)
Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
package
2+
3+
public fun foo(/*0*/ my: My?): kotlin.Boolean
4+
public fun kotlin.Any?.foo(/*0*/ my: My): kotlin.Boolean
5+
6+
public final class My {
7+
public constructor My(/*0*/ x: kotlin.Any)
8+
public final val x: kotlin.Any
9+
public open override /*1*/ /*fake_override*/ fun equals(/*0*/ other: kotlin.Any?): kotlin.Boolean
10+
public open override /*1*/ /*fake_override*/ fun hashCode(): kotlin.Int
11+
public open override /*1*/ /*fake_override*/ fun toString(): kotlin.String
12+
}

compiler/tests/org/jetbrains/kotlin/checkers/DiagnosticsTestGenerated.java

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16652,6 +16652,12 @@ public void testSimple() throws Exception {
1665216652
doTest(fileName);
1665316653
}
1665416654

16655+
@TestMetadata("simpleNullableReceiver.kt")
16656+
public void testSimpleNullableReceiver() throws Exception {
16657+
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/diagnostics/tests/smartCasts/safecalls/simpleNullableReceiver.kt");
16658+
doTest(fileName);
16659+
}
16660+
1665516661
@TestMetadata("twoArgs.kt")
1665616662
public void testTwoArgs() throws Exception {
1665716663
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/diagnostics/tests/smartCasts/safecalls/twoArgs.kt");

idea/testData/checker/infos/SmartCastsWithSafeAccess.kt

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,7 @@ fun test(a: A?) {
2020
}
2121

2222
if (a is B? && a is C?) {
23-
<info descr="Smart cast to B">a</info><info>?.</info>bar()
23+
<info descr="Smart cast to B?">a</info><info>?.</info>bar()
2424
}
2525

2626
a<info>?.</info>foo()

0 commit comments

Comments
 (0)