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.BindingContextUtils;
|
||||
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.model.ResolvedCall;
|
||||
import org.jetbrains.jet.lang.resolve.calls.model.ResolvedValueArgument;
|
||||
import org.jetbrains.jet.lang.resolve.calls.model.VariableAsFunctionResolvedCall;
|
||||
import org.jetbrains.jet.lang.resolve.calls.model.*;
|
||||
import org.jetbrains.jet.lang.resolve.calls.tasks.ResolutionCandidate;
|
||||
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.constants.BooleanValue;
|
||||
import org.jetbrains.jet.lang.resolve.constants.CompileTimeConstant;
|
||||
@@ -285,6 +287,36 @@ public class JetControlFlowProcessor {
|
||||
}
|
||||
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 {
|
||||
if (!generateCall(operationReference)) {
|
||||
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");
|
||||
}
|
||||
|
||||
@TestMetadata("equals.kt")
|
||||
public void testEquals() throws Exception {
|
||||
doTest("compiler/testData/cfg/equals.kt");
|
||||
}
|
||||
|
||||
@TestMetadata("FailFunction.kt")
|
||||
public void testFailFunction() throws Exception {
|
||||
doTest("compiler/testData/cfg/FailFunction.kt");
|
||||
@@ -136,6 +141,11 @@ public class ControlFlowTestGenerated extends AbstractControlFlowTest {
|
||||
doTest("compiler/testData/cfg/multiDeclarationWithError.kt");
|
||||
}
|
||||
|
||||
@TestMetadata("notEqual.kt")
|
||||
public void testNotEqual() throws Exception {
|
||||
doTest("compiler/testData/cfg/notEqual.kt");
|
||||
}
|
||||
|
||||
@TestMetadata("ObjectExpression.kt")
|
||||
public void testObjectExpression() throws Exception {
|
||||
doTest("compiler/testData/cfg/ObjectExpression.kt");
|
||||
|
||||
Reference in New Issue
Block a user