KT-2842 Function with declared non-null receiver resolves with nullable argument receiver
#KT-2842 fixed
This commit is contained in:
@@ -20,7 +20,10 @@ import org.jetbrains.annotations.NotNull;
|
|||||||
import org.jetbrains.jet.lang.descriptors.CallableDescriptor;
|
import org.jetbrains.jet.lang.descriptors.CallableDescriptor;
|
||||||
import org.jetbrains.jet.lang.psi.Call;
|
import org.jetbrains.jet.lang.psi.Call;
|
||||||
import org.jetbrains.jet.lang.resolve.BindingTrace;
|
import org.jetbrains.jet.lang.resolve.BindingTrace;
|
||||||
|
import org.jetbrains.jet.lang.resolve.calls.autocasts.DataFlowInfo;
|
||||||
|
import org.jetbrains.jet.lang.resolve.scopes.JetScope;
|
||||||
import org.jetbrains.jet.lang.resolve.scopes.receivers.ReceiverDescriptor;
|
import org.jetbrains.jet.lang.resolve.scopes.receivers.ReceiverDescriptor;
|
||||||
|
import org.jetbrains.jet.lang.types.JetType;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @author svtk
|
* @author svtk
|
||||||
@@ -36,6 +39,12 @@ public final class CallResolutionContext<D extends CallableDescriptor, F extends
|
|||||||
this.tracing = tracing;
|
this.tracing = tracing;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private CallResolutionContext(@NotNull BasicResolutionContext context, @NotNull TracingStrategy tracing, @NotNull ResolvedCallImpl<D> candidateCall) {
|
||||||
|
super(context.trace, context.scope, context.call, context.expectedType, context.dataFlowInfo);
|
||||||
|
this.candidateCall = candidateCall;
|
||||||
|
this.tracing = tracing;
|
||||||
|
}
|
||||||
|
|
||||||
public static <D extends CallableDescriptor, F extends D> CallResolutionContext<D, F> create(@NotNull ResolvedCallImpl<D> candidateCall, @NotNull ResolutionTask<D, F> task, @NotNull BindingTrace trace, @NotNull TracingStrategy tracing, @NotNull Call call) {
|
public static <D extends CallableDescriptor, F extends D> CallResolutionContext<D, F> create(@NotNull ResolvedCallImpl<D> candidateCall, @NotNull ResolutionTask<D, F> task, @NotNull BindingTrace trace, @NotNull TracingStrategy tracing, @NotNull Call call) {
|
||||||
return new CallResolutionContext<D, F>(candidateCall, task, trace, tracing, call);
|
return new CallResolutionContext<D, F>(candidateCall, task, trace, tracing, call);
|
||||||
}
|
}
|
||||||
@@ -43,4 +52,8 @@ public final class CallResolutionContext<D extends CallableDescriptor, F extends
|
|||||||
public static <D extends CallableDescriptor, F extends D> CallResolutionContext<D, F> create(@NotNull ResolvedCallImpl<D> candidateCall, @NotNull ResolutionTask<D, F> task, @NotNull BindingTrace trace, @NotNull TracingStrategy tracing) {
|
public static <D extends CallableDescriptor, F extends D> CallResolutionContext<D, F> create(@NotNull ResolvedCallImpl<D> candidateCall, @NotNull ResolutionTask<D, F> task, @NotNull BindingTrace trace, @NotNull TracingStrategy tracing) {
|
||||||
return create(candidateCall, task, trace, tracing, task.call);
|
return create(candidateCall, task, trace, tracing, task.call);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static <D extends CallableDescriptor> CallResolutionContext<D, D> create(@NotNull BasicResolutionContext context, @NotNull TracingStrategy tracing, @NotNull ResolvedCallImpl<D> candidateCall) {
|
||||||
|
return new CallResolutionContext<D, D>(context, tracing, candidateCall);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -328,7 +328,7 @@ public class CallResolver {
|
|||||||
}
|
}
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
completeTypeInferenceDependentOnExpectedTypeForCall(resolvedCall, context, tracing, successful, failed);
|
completeTypeInferenceDependentOnExpectedTypeForCall(CallResolutionContext.create(context, tracing, resolvedCall), successful, failed);
|
||||||
}
|
}
|
||||||
OverloadResolutionResultsImpl<D> results = computeResultAndReportErrors(context.trace, tracing, successful, failed);
|
OverloadResolutionResultsImpl<D> results = computeResultAndReportErrors(context.trace, tracing, successful, failed);
|
||||||
if (!results.isSingleResult()) {
|
if (!results.isSingleResult()) {
|
||||||
@@ -337,12 +337,12 @@ public class CallResolver {
|
|||||||
return results;
|
return results;
|
||||||
}
|
}
|
||||||
|
|
||||||
private <D extends CallableDescriptor> void completeTypeInferenceDependentOnExpectedTypeForCall(ResolvedCallImpl<D> resolvedCall,
|
private <D extends CallableDescriptor> void completeTypeInferenceDependentOnExpectedTypeForCall(
|
||||||
BasicResolutionContext context,
|
CallResolutionContext<D, D> context,
|
||||||
TracingStrategy tracing,
|
|
||||||
Set<ResolvedCallWithTrace<D>> successful,
|
Set<ResolvedCallWithTrace<D>> successful,
|
||||||
Set<ResolvedCallWithTrace<D>> failed
|
Set<ResolvedCallWithTrace<D>> failed
|
||||||
) {
|
) {
|
||||||
|
ResolvedCallImpl<D> resolvedCall = context.candidateCall;
|
||||||
assert resolvedCall.hasUnknownTypeParameters();
|
assert resolvedCall.hasUnknownTypeParameters();
|
||||||
D descriptor = resolvedCall.getCandidateDescriptor();
|
D descriptor = resolvedCall.getCandidateDescriptor();
|
||||||
ConstraintSystem constraintSystem = resolvedCall.getConstraintSystem();
|
ConstraintSystem constraintSystem = resolvedCall.getConstraintSystem();
|
||||||
@@ -383,7 +383,7 @@ public class CallResolver {
|
|||||||
}
|
}
|
||||||
List<JetType> argumentTypes = checkValueArgumentTypes(context, resolvedCall, resolvedCall.getTrace()).argumentTypes;
|
List<JetType> argumentTypes = checkValueArgumentTypes(context, resolvedCall, resolvedCall.getTrace()).argumentTypes;
|
||||||
JetType receiverType = resolvedCall.getReceiverArgument().exists() ? resolvedCall.getReceiverArgument().getType() : null;
|
JetType receiverType = resolvedCall.getReceiverArgument().exists() ? resolvedCall.getReceiverArgument().getType() : null;
|
||||||
tracing.typeInferenceFailed(resolvedCall.getTrace(),
|
context.tracing.typeInferenceFailed(resolvedCall.getTrace(),
|
||||||
InferenceErrorData
|
InferenceErrorData
|
||||||
.create(descriptor, constraintSystem, argumentTypes, receiverType, context.expectedType),
|
.create(descriptor, constraintSystem, argumentTypes, receiverType, context.expectedType),
|
||||||
constraintSystemWithoutExpectedTypeConstraint);
|
constraintSystemWithoutExpectedTypeConstraint);
|
||||||
@@ -394,9 +394,9 @@ public class CallResolver {
|
|||||||
|
|
||||||
resolvedCall.setResultingSubstitutor(constraintSystem.getResultingSubstitutor());
|
resolvedCall.setResultingSubstitutor(constraintSystem.getResultingSubstitutor());
|
||||||
// Here we type check the arguments with inferred types expected
|
// Here we type check the arguments with inferred types expected
|
||||||
checkValueArgumentTypes(context, resolvedCall, resolvedCall.getTrace());
|
checkAllValueArguments(context);
|
||||||
|
|
||||||
checkBounds(resolvedCall, constraintSystem, resolvedCall.getTrace(), tracing);
|
checkBounds(resolvedCall, constraintSystem, resolvedCall.getTrace(), context.tracing);
|
||||||
resolvedCall.setHasUnknownTypeParameters(false);
|
resolvedCall.setHasUnknownTypeParameters(false);
|
||||||
if (resolvedCall.getStatus().isSuccess() || resolvedCall.getStatus() == ResolutionStatus.UNKNOWN_STATUS) {
|
if (resolvedCall.getStatus().isSuccess() || resolvedCall.getStatus() == ResolutionStatus.UNKNOWN_STATUS) {
|
||||||
resolvedCall.addStatus(ResolutionStatus.SUCCESS);
|
resolvedCall.addStatus(ResolutionStatus.SUCCESS);
|
||||||
@@ -866,7 +866,7 @@ public class CallResolver {
|
|||||||
|
|
||||||
|
|
||||||
private <D extends CallableDescriptor, F extends D> ValueArgumentsCheckingResult checkAllValueArguments(CallResolutionContext<D, F> context) {
|
private <D extends CallableDescriptor, F extends D> ValueArgumentsCheckingResult checkAllValueArguments(CallResolutionContext<D, F> context) {
|
||||||
ValueArgumentsCheckingResult checkingResult = checkValueArgumentTypes(context, context.candidateCall);
|
ValueArgumentsCheckingResult checkingResult = checkValueArgumentTypes(context, context.candidateCall, context.candidateCall.getTrace());
|
||||||
ResolutionStatus resultStatus = checkingResult.status;
|
ResolutionStatus resultStatus = checkingResult.status;
|
||||||
ResolvedCall<D> candidateCall = context.candidateCall;
|
ResolvedCall<D> candidateCall = context.candidateCall;
|
||||||
|
|
||||||
@@ -927,10 +927,6 @@ public class CallResolver {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private <D extends CallableDescriptor> ValueArgumentsCheckingResult checkValueArgumentTypes(ResolutionContext context, ResolvedCallImpl<D> candidateCall) {
|
|
||||||
return checkValueArgumentTypes(context, candidateCall, candidateCall.getTrace());
|
|
||||||
}
|
|
||||||
|
|
||||||
private <D extends CallableDescriptor> ValueArgumentsCheckingResult checkValueArgumentTypes(ResolutionContext context, ResolvedCallImpl<D> candidateCall, BindingTrace trace) {
|
private <D extends CallableDescriptor> ValueArgumentsCheckingResult checkValueArgumentTypes(ResolutionContext context, ResolvedCallImpl<D> candidateCall, BindingTrace trace) {
|
||||||
ResolutionStatus resultStatus = SUCCESS;
|
ResolutionStatus resultStatus = SUCCESS;
|
||||||
DataFlowInfo dataFlowInfo = context.dataFlowInfo;
|
DataFlowInfo dataFlowInfo = context.dataFlowInfo;
|
||||||
|
|||||||
@@ -0,0 +1,27 @@
|
|||||||
|
package c
|
||||||
|
|
||||||
|
trait A<T>
|
||||||
|
|
||||||
|
fun test(a: A<Int>?) {
|
||||||
|
a<!UNSAFE_CALL!>.<!>foo() //no error
|
||||||
|
}
|
||||||
|
|
||||||
|
fun <R> A<R>.foo() {}
|
||||||
|
|
||||||
|
//------------
|
||||||
|
fun test(nullabilityInfoMap: Map<Int, Any>?) {
|
||||||
|
nullabilityInfoMap<!UNSAFE_CALL!>.<!>iterator() //no error
|
||||||
|
}
|
||||||
|
|
||||||
|
//resolves to
|
||||||
|
public inline fun <K,V> Map<K,V>.iterator(): Iterator<Map.Entry<K,V>> {<!NO_RETURN_IN_FUNCTION_WITH_BLOCK_BODY!>}<!>
|
||||||
|
|
||||||
|
|
||||||
|
//-------------
|
||||||
|
fun foo() : Boolean {
|
||||||
|
val nullableList = getNullableList()
|
||||||
|
return nullableList<!UNSAFE_CALL!>.<!>contains("")
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
fun getNullableList(): List<String>? = null
|
||||||
@@ -1889,6 +1889,11 @@ public class JetDiagnosticsTestGenerated extends AbstractDiagnosticsTestWithEage
|
|||||||
doTest("compiler/testData/diagnostics/tests/inference/regressions/kt2514.kt");
|
doTest("compiler/testData/diagnostics/tests/inference/regressions/kt2514.kt");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@TestMetadata("kt2842.kt")
|
||||||
|
public void testKt2842() throws Exception {
|
||||||
|
doTest("compiler/testData/diagnostics/tests/inference/regressions/kt2842.kt");
|
||||||
|
}
|
||||||
|
|
||||||
@TestMetadata("kt702.kt")
|
@TestMetadata("kt702.kt")
|
||||||
public void testKt702() throws Exception {
|
public void testKt702() throws Exception {
|
||||||
doTest("compiler/testData/diagnostics/tests/inference/regressions/kt702.kt");
|
doTest("compiler/testData/diagnostics/tests/inference/regressions/kt702.kt");
|
||||||
|
|||||||
@@ -10,7 +10,7 @@ class StringUtilTest() : TestCase() {
|
|||||||
|
|
||||||
fun testToRegex() {
|
fun testToRegex() {
|
||||||
val re = """foo""".toRegex()
|
val re = """foo""".toRegex()
|
||||||
val list = re.split("hellofoobar").filterNotNull()
|
val list = re.split("hellofoobar").toList()
|
||||||
assertEquals(arrayList("hello", "bar"), list)
|
assertEquals(arrayList("hello", "bar"), list)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user