Proper resolved calls for '=='
This commit is contained in:
@@ -32,10 +32,12 @@ import org.jetbrains.jet.lang.psi.*;
|
|||||||
import org.jetbrains.jet.lang.resolve.BindingContext;
|
import org.jetbrains.jet.lang.resolve.BindingContext;
|
||||||
import org.jetbrains.jet.lang.resolve.BindingContextUtils;
|
import org.jetbrains.jet.lang.resolve.BindingContextUtils;
|
||||||
import org.jetbrains.jet.lang.resolve.BindingTrace;
|
import org.jetbrains.jet.lang.resolve.BindingTrace;
|
||||||
|
import org.jetbrains.jet.lang.resolve.DelegatingBindingTrace;
|
||||||
import org.jetbrains.jet.lang.resolve.calls.autocasts.AutoCastReceiver;
|
import org.jetbrains.jet.lang.resolve.calls.autocasts.AutoCastReceiver;
|
||||||
import org.jetbrains.jet.lang.resolve.calls.model.ResolvedCall;
|
import org.jetbrains.jet.lang.resolve.calls.model.*;
|
||||||
import org.jetbrains.jet.lang.resolve.calls.model.ResolvedValueArgument;
|
import org.jetbrains.jet.lang.resolve.calls.tasks.ResolutionCandidate;
|
||||||
import org.jetbrains.jet.lang.resolve.calls.model.VariableAsFunctionResolvedCall;
|
import org.jetbrains.jet.lang.resolve.calls.tasks.TracingStrategy;
|
||||||
|
import org.jetbrains.jet.lang.resolve.calls.util.CallMaker;
|
||||||
import org.jetbrains.jet.lang.resolve.calls.util.ExpressionAsFunctionDescriptor;
|
import org.jetbrains.jet.lang.resolve.calls.util.ExpressionAsFunctionDescriptor;
|
||||||
import org.jetbrains.jet.lang.resolve.constants.BooleanValue;
|
import org.jetbrains.jet.lang.resolve.constants.BooleanValue;
|
||||||
import org.jetbrains.jet.lang.resolve.constants.CompileTimeConstant;
|
import org.jetbrains.jet.lang.resolve.constants.CompileTimeConstant;
|
||||||
@@ -285,6 +287,36 @@ public class JetControlFlowProcessor {
|
|||||||
}
|
}
|
||||||
builder.bindLabel(afterElvis);
|
builder.bindLabel(afterElvis);
|
||||||
}
|
}
|
||||||
|
else if (operationType == JetTokens.EQEQ || operationType == JetTokens.EXCLEQ) {
|
||||||
|
// Equals is resolved on a fake argument, to ensure "Any?" in the signature, so we have to read the right argument manually
|
||||||
|
@SuppressWarnings("unchecked")
|
||||||
|
ResolvedCall<FunctionDescriptor> resolvedCall = (ResolvedCall<FunctionDescriptor>) getResolvedCall(operationReference);
|
||||||
|
if (resolvedCall != null && !resolvedCall.getValueArguments().isEmpty() && right != null) {
|
||||||
|
ResolvedCallImpl<FunctionDescriptor> fakeCall = ResolvedCallImpl.create(
|
||||||
|
ResolutionCandidate.create(
|
||||||
|
resolvedCall.getCandidateDescriptor(),
|
||||||
|
resolvedCall.getThisObject(),
|
||||||
|
resolvedCall.getReceiverArgument(),
|
||||||
|
resolvedCall.getExplicitReceiverKind(),
|
||||||
|
resolvedCall.isSafeCall()
|
||||||
|
),
|
||||||
|
new DelegatingBindingTrace(BindingContext.EMPTY, "Fake call for =="),
|
||||||
|
TracingStrategy.EMPTY,
|
||||||
|
MutableDataFlowInfoForArguments.WITHOUT_ARGUMENTS_CHECK
|
||||||
|
);
|
||||||
|
|
||||||
|
ValueParameterDescriptor parameterDescriptor = resolvedCall.getValueArguments().keySet().iterator().next();
|
||||||
|
fakeCall.recordValueArgument(
|
||||||
|
parameterDescriptor,
|
||||||
|
new ExpressionValueArgument(CallMaker.makeValueArgument(right))
|
||||||
|
);
|
||||||
|
fakeCall.setStatusToSuccess();
|
||||||
|
generateCall(expression, fakeCall);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
generateBothArguments(expression);
|
||||||
|
}
|
||||||
|
}
|
||||||
else {
|
else {
|
||||||
if (!generateCall(operationReference)) {
|
if (!generateCall(operationReference)) {
|
||||||
generateBothArguments(expression);
|
generateBothArguments(expression);
|
||||||
|
|||||||
@@ -0,0 +1,28 @@
|
|||||||
|
== foo ==
|
||||||
|
fun foo(a: Int, b: Int) {
|
||||||
|
if (a == b) {
|
||||||
|
}
|
||||||
|
}
|
||||||
|
---------------------
|
||||||
|
L0:
|
||||||
|
<START> NEXT:[v(a: Int)] PREV:[]
|
||||||
|
v(a: Int) NEXT:[w(a)] PREV:[<START>]
|
||||||
|
w(a) NEXT:[v(b: Int)] PREV:[v(a: Int)]
|
||||||
|
v(b: Int) NEXT:[w(b)] PREV:[w(a)]
|
||||||
|
w(b) NEXT:[r(a)] PREV:[v(b: Int)]
|
||||||
|
r(a) NEXT:[r(b)] PREV:[w(b)]
|
||||||
|
r(b) NEXT:[call(a == b, equals)] PREV:[r(a)]
|
||||||
|
call(a == b, equals) NEXT:[jf(L2)] PREV:[r(b)]
|
||||||
|
jf(L2) NEXT:[read (Unit), read (Unit)] PREV:[call(a == b, equals)]
|
||||||
|
read (Unit) NEXT:[jmp(L3)] PREV:[jf(L2)]
|
||||||
|
jmp(L3) NEXT:[<END>] PREV:[read (Unit)]
|
||||||
|
L2:
|
||||||
|
read (Unit) NEXT:[<END>] PREV:[jf(L2)]
|
||||||
|
L1:
|
||||||
|
L3:
|
||||||
|
<END> NEXT:[<SINK>] PREV:[jmp(L3), read (Unit)]
|
||||||
|
error:
|
||||||
|
<ERROR> NEXT:[<SINK>] PREV:[]
|
||||||
|
sink:
|
||||||
|
<SINK> NEXT:[] PREV:[<ERROR>, <END>]
|
||||||
|
=====================
|
||||||
@@ -0,0 +1,4 @@
|
|||||||
|
fun foo(a: Int, b: Int) {
|
||||||
|
if (a == b) {
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,27 @@
|
|||||||
|
== neq ==
|
||||||
|
fun neq(a: Int, b: Int) {
|
||||||
|
if (a != b) {}
|
||||||
|
}
|
||||||
|
---------------------
|
||||||
|
L0:
|
||||||
|
<START> NEXT:[v(a: Int)] PREV:[]
|
||||||
|
v(a: Int) NEXT:[w(a)] PREV:[<START>]
|
||||||
|
w(a) NEXT:[v(b: Int)] PREV:[v(a: Int)]
|
||||||
|
v(b: Int) NEXT:[w(b)] PREV:[w(a)]
|
||||||
|
w(b) NEXT:[r(a)] PREV:[v(b: Int)]
|
||||||
|
r(a) NEXT:[r(b)] PREV:[w(b)]
|
||||||
|
r(b) NEXT:[call(a != b, equals)] PREV:[r(a)]
|
||||||
|
call(a != b, equals) NEXT:[jf(L2)] PREV:[r(b)]
|
||||||
|
jf(L2) NEXT:[read (Unit), read (Unit)] PREV:[call(a != b, equals)]
|
||||||
|
read (Unit) NEXT:[jmp(L3)] PREV:[jf(L2)]
|
||||||
|
jmp(L3) NEXT:[<END>] PREV:[read (Unit)]
|
||||||
|
L2:
|
||||||
|
read (Unit) NEXT:[<END>] PREV:[jf(L2)]
|
||||||
|
L1:
|
||||||
|
L3:
|
||||||
|
<END> NEXT:[<SINK>] PREV:[jmp(L3), read (Unit)]
|
||||||
|
error:
|
||||||
|
<ERROR> NEXT:[<SINK>] PREV:[]
|
||||||
|
sink:
|
||||||
|
<SINK> NEXT:[] PREV:[<ERROR>, <END>]
|
||||||
|
=====================
|
||||||
@@ -0,0 +1,3 @@
|
|||||||
|
fun neq(a: Int, b: Int) {
|
||||||
|
if (a != b) {}
|
||||||
|
}
|
||||||
@@ -81,6 +81,11 @@ public class ControlFlowTestGenerated extends AbstractControlFlowTest {
|
|||||||
doTest("compiler/testData/cfg/EmptyFunction.kt");
|
doTest("compiler/testData/cfg/EmptyFunction.kt");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@TestMetadata("equals.kt")
|
||||||
|
public void testEquals() throws Exception {
|
||||||
|
doTest("compiler/testData/cfg/equals.kt");
|
||||||
|
}
|
||||||
|
|
||||||
@TestMetadata("FailFunction.kt")
|
@TestMetadata("FailFunction.kt")
|
||||||
public void testFailFunction() throws Exception {
|
public void testFailFunction() throws Exception {
|
||||||
doTest("compiler/testData/cfg/FailFunction.kt");
|
doTest("compiler/testData/cfg/FailFunction.kt");
|
||||||
@@ -136,6 +141,11 @@ public class ControlFlowTestGenerated extends AbstractControlFlowTest {
|
|||||||
doTest("compiler/testData/cfg/multiDeclarationWithError.kt");
|
doTest("compiler/testData/cfg/multiDeclarationWithError.kt");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@TestMetadata("notEqual.kt")
|
||||||
|
public void testNotEqual() throws Exception {
|
||||||
|
doTest("compiler/testData/cfg/notEqual.kt");
|
||||||
|
}
|
||||||
|
|
||||||
@TestMetadata("ObjectExpression.kt")
|
@TestMetadata("ObjectExpression.kt")
|
||||||
public void testObjectExpression() throws Exception {
|
public void testObjectExpression() throws Exception {
|
||||||
doTest("compiler/testData/cfg/ObjectExpression.kt");
|
doTest("compiler/testData/cfg/ObjectExpression.kt");
|
||||||
|
|||||||
Reference in New Issue
Block a user