Pseudocode: Bind result values to elements retrieved from resolved calls

This commit is contained in:
Alexey Sedunov
2014-06-19 19:32:56 +04:00
parent 4debb6eb6a
commit 7c837909d8
4 changed files with 93 additions and 61 deletions
@@ -276,7 +276,7 @@ public class JetControlFlowProcessor {
CallableDescriptor resultingDescriptor = resolvedCall.getResultingDescriptor();
if (resultingDescriptor instanceof ReceiverParameterDescriptor) {
builder.readVariable(expression, expression, resolvedCall, getReceiverValues(expression, resolvedCall, true));
builder.readVariable(expression, expression, resolvedCall, getReceiverValues(resolvedCall, true));
}
copyValue(expression, expression.getInstanceReference());
@@ -293,9 +293,9 @@ public class JetControlFlowProcessor {
ResolvedCall<?> resolvedCall = getResolvedCall(expression);
if (resolvedCall instanceof VariableAsFunctionResolvedCall) {
VariableAsFunctionResolvedCall variableAsFunctionResolvedCall = (VariableAsFunctionResolvedCall) resolvedCall;
generateCall(expression, expression, variableAsFunctionResolvedCall.getVariableCall());
generateCall(expression, variableAsFunctionResolvedCall.getVariableCall());
}
else if (!generateCall(expression, expression) && !(expression.getParent() instanceof JetCallExpression)) {
else if (!generateCall(expression, true) && !(expression.getParent() instanceof JetCallExpression)) {
createNonSyntheticValue(expression, generateAndGetReceiverIfAny(expression));
}
}
@@ -327,19 +327,14 @@ public class JetControlFlowProcessor {
else if (OperatorConventions.ASSIGNMENT_OPERATIONS.containsKey(operationType)) {
ResolvedCall<?> resolvedCall = getResolvedCall(operationReference);
if (resolvedCall != null) {
CallableDescriptor descriptor = resolvedCall.getResultingDescriptor();
PseudoValue rhsValue = generateCall(operationReference, resolvedCall).getOutputValue();
Name assignMethodName = OperatorConventions.getNameForOperationSymbol((JetToken) expression.getOperationToken());
if (descriptor.getName().equals(assignMethodName)) {
generateCall(expression, operationReference, resolvedCall);
}
else {
if (!resolvedCall.getResultingDescriptor().getName().equals(assignMethodName)) {
/* At this point assignment of the form a += b actually means a = a + b
* So we first generate call of "+" operation and then use its output pseudo-value
* as a right-hand side when generating assignment call
*/
Function0<PseudoValue> rhsDeferredValue =
getValueAsFunction(generateCall(null, operationReference, resolvedCall).getOutputValue());
visitAssignment(left, rhsDeferredValue, expression);
visitAssignment(left, getValueAsFunction(rhsValue), expression);
}
}
else {
@@ -358,7 +353,7 @@ public class JetControlFlowProcessor {
mergeValues(Arrays.asList(left, right), expression);
}
else {
if (!generateCall(expression, operationReference)) {
if (!generateCall(operationReference, true)) {
generateBothArgumentsAndMark(expression);
}
}
@@ -435,7 +430,7 @@ public class JetControlFlowProcessor {
if (left instanceof JetSimpleNameExpression || left instanceof JetQualifiedExpression) {
accessTarget = getResolvedCallAccessTarget(PsiUtilPackage.getQualifiedElementSelector(left));
if (accessTarget instanceof AccessTarget.Call) {
receiverValues = getReceiverValues(lhs, ((AccessTarget.Call) accessTarget).getResolvedCall(), true);
receiverValues = getReceiverValues(((AccessTarget.Call) accessTarget).getResolvedCall(), true);
}
}
else if (left instanceof JetProperty) {
@@ -473,7 +468,7 @@ public class JetControlFlowProcessor {
generateInstructions(lhs.getArrayExpression());
Map<PseudoValue, ReceiverValue> receiverValues = getReceiverValues(lhs, setResolvedCall, false);
Map<PseudoValue, ReceiverValue> receiverValues = getReceiverValues(setResolvedCall, false);
SmartFMap<PseudoValue, ValueParameterDescriptor> argumentValues =
getArraySetterArguments(rhsDeferredValue, setResolvedCall);
@@ -540,7 +535,7 @@ public class JetControlFlowProcessor {
private void generateArrayAccess(JetArrayAccessExpression arrayAccessExpression, @Nullable ResolvedCall<?> resolvedCall) {
mark(arrayAccessExpression);
if (!checkAndGenerateCall(arrayAccessExpression, arrayAccessExpression, resolvedCall)) {
if (!checkAndGenerateCall(arrayAccessExpression, resolvedCall, true)) {
generateArrayAccessWithoutCall(arrayAccessExpression);
}
}
@@ -581,7 +576,7 @@ public class JetControlFlowProcessor {
PseudoValue rhsValue;
if (resolvedCall != null) {
rhsValue = generateCall(incrementOrDecrement ? null : expression, operationSign, resolvedCall).getOutputValue();
rhsValue = generateCall(operationSign, resolvedCall).getOutputValue();
}
else {
generateInstructions(baseExpression);
@@ -1055,7 +1050,7 @@ public class JetControlFlowProcessor {
@Override
public void visitCallExpression(@NotNull JetCallExpression expression) {
JetExpression calleeExpression = expression.getCalleeExpression();
if (!generateCall(expression, calleeExpression)) {
if (!generateCall(calleeExpression, true)) {
List<JetExpression> inputExpressions = new ArrayList<JetExpression>();
for (ValueArgument argument : expression.getValueArguments()) {
JetExpression argumentExpression = argument.getArgumentExpression();
@@ -1128,7 +1123,7 @@ public class JetControlFlowProcessor {
entry,
entry,
resolvedCall,
getReceiverValues(initializer, resolvedCall, false),
getReceiverValues(resolvedCall, false),
Collections.<PseudoValue, ValueParameterDescriptor>emptyMap()
).getOutputValue();
}
@@ -1182,7 +1177,7 @@ public class JetControlFlowProcessor {
public void visitArrayAccessExpression(@NotNull JetArrayAccessExpression expression) {
mark(expression);
ResolvedCall<FunctionDescriptor> getMethodResolvedCall = trace.get(BindingContext.INDEXED_LVALUE_GET, expression);
if (!checkAndGenerateCall(expression, expression, getMethodResolvedCall)) {
if (!checkAndGenerateCall(expression, getMethodResolvedCall, true)) {
generateArrayAccess(expression, getMethodResolvedCall);
}
}
@@ -1363,29 +1358,32 @@ public class JetControlFlowProcessor {
return trace.get(BindingContext.RESOLVED_CALL, expression);
}
private boolean generateCall(JetExpression callExpression, @Nullable JetExpression calleeExpression) {
private boolean generateCall(@Nullable JetExpression calleeExpression, boolean bindResultValue) {
if (calleeExpression == null) return false;
return checkAndGenerateCall(callExpression, calleeExpression, getResolvedCall(calleeExpression));
return checkAndGenerateCall(calleeExpression, getResolvedCall(calleeExpression), bindResultValue);
}
private boolean checkAndGenerateCall(JetExpression callExpression, JetExpression calleeExpression, @Nullable ResolvedCall<?> resolvedCall) {
private boolean checkAndGenerateCall(JetExpression calleeExpression, @Nullable ResolvedCall<?> resolvedCall, boolean bindResultValue) {
if (resolvedCall == null) {
builder.compilationError(calleeExpression, "No resolved call");
return false;
}
generateCall(callExpression, calleeExpression, resolvedCall);
generateCall(calleeExpression, resolvedCall);
return true;
}
@NotNull
private InstructionWithValue generateCall(JetExpression callExpression, JetExpression calleeExpression, ResolvedCall<?> resolvedCall) {
private InstructionWithValue generateCall(JetExpression calleeExpression, ResolvedCall<?> resolvedCall) {
if (resolvedCall instanceof VariableAsFunctionResolvedCall) {
VariableAsFunctionResolvedCall variableAsFunctionResolvedCall = (VariableAsFunctionResolvedCall) resolvedCall;
return generateCall(callExpression, calleeExpression, variableAsFunctionResolvedCall.getFunctionCall());
return generateCall(calleeExpression, variableAsFunctionResolvedCall.getFunctionCall());
}
JetElement callElement = resolvedCall.getCall().getCallElement();
JetExpression callExpression = callElement instanceof JetExpression ? (JetExpression) callElement : null;
CallableDescriptor resultingDescriptor = resolvedCall.getResultingDescriptor();
Map<PseudoValue, ReceiverValue> receivers = getReceiverValues(callExpression, resolvedCall, true);
Map<PseudoValue, ReceiverValue> receivers = getReceiverValues(resolvedCall, true);
SmartFMap<PseudoValue, ValueParameterDescriptor> parameterValues = SmartFMap.emptyMap();
for (ValueParameterDescriptor parameterDescriptor : resultingDescriptor.getValueParameters()) {
ResolvedValueArgument argument = resolvedCall.getValueArguments().get(parameterDescriptor);
@@ -1395,8 +1393,10 @@ public class JetControlFlowProcessor {
}
if (resultingDescriptor instanceof VariableDescriptor) {
assert callExpression != null
: "Variable-based call without call expression: " + callElement.getText();
assert parameterValues.isEmpty()
: "Variable-based call with non-empty argument list: " + resolvedCall.getCall().getCallElement().getText();
: "Variable-based call with non-empty argument list: " + callElement.getText();
return builder.readVariable(calleeExpression, callExpression, resolvedCall, receivers);
}
mark(resolvedCall.getCall().getCallElement());
@@ -1405,18 +1405,18 @@ public class JetControlFlowProcessor {
@NotNull
private Map<PseudoValue, ReceiverValue> getReceiverValues(
JetExpression callExpression,
ResolvedCall<?> resolvedCall,
boolean generateInstructions) {
SmartFMap<PseudoValue, ReceiverValue> receiverValues = SmartFMap.emptyMap();
receiverValues = getReceiverValues(callExpression, resolvedCall.getThisObject(), generateInstructions, receiverValues);
receiverValues = getReceiverValues(callExpression, resolvedCall.getReceiverArgument(), generateInstructions, receiverValues);
JetElement callElement = resolvedCall.getCall().getCallElement();
receiverValues = getReceiverValues(callElement, resolvedCall.getThisObject(), generateInstructions, receiverValues);
receiverValues = getReceiverValues(callElement, resolvedCall.getReceiverArgument(), generateInstructions, receiverValues);
return receiverValues;
}
@NotNull
private SmartFMap<PseudoValue, ReceiverValue> getReceiverValues(
JetExpression callExpression,
JetElement callElement,
ReceiverValue receiver,
boolean generateInstructions,
SmartFMap<PseudoValue, ReceiverValue> receiverValues
@@ -1425,7 +1425,7 @@ public class JetControlFlowProcessor {
if (receiver instanceof ThisReceiver) {
if (generateInstructions) {
receiverValues = receiverValues.plus(createSyntheticValue(callExpression), receiver);
receiverValues = receiverValues.plus(createSyntheticValue(callElement), receiver);
}
}
else if (receiver instanceof ExpressionReceiver) {
@@ -102,18 +102,22 @@ public class CallTransformer<D extends CallableDescriptor, F extends D> {
assert candidate.getDescriptor() instanceof VariableDescriptor;
boolean hasReceiver = candidate.getReceiverArgument().exists();
Call variableCall = stripCallArguments(task);
Call variableCall = stripCallArguments(task.call);
ResolutionCandidate<CallableDescriptor> variableCandidate = getVariableCallCandidate(candidate, variableCall);
if (!hasReceiver) {
CallCandidateResolutionContext<CallableDescriptor> context = CallCandidateResolutionContext.create(
ResolvedCallImpl.create(candidate, candidateTrace, task.tracing, task.dataFlowInfoForArguments), task, candidateTrace, task.tracing, variableCall);
ResolvedCallImpl.create(variableCandidate, candidateTrace, task.tracing, task.dataFlowInfoForArguments), task, candidateTrace, task.tracing, variableCall);
return Collections.singleton(context);
}
CallCandidateResolutionContext<CallableDescriptor> contextWithReceiver = createContextWithChainedTrace(
candidate, variableCall, candidateTrace, task, ReceiverValue.NO_RECEIVER);
variableCandidate, variableCall, candidateTrace, task, ReceiverValue.NO_RECEIVER);
Call variableCallWithoutReceiver = stripReceiver(variableCall);
ResolutionCandidate<CallableDescriptor> candidateWithoutReceiver = ResolutionCandidate.create(
candidate.getCall(), candidate.getDescriptor(), candidate.getThisObject(), ReceiverValue.NO_RECEIVER,
variableCandidate.getCall(),
variableCandidate.getDescriptor(),
variableCandidate.getThisObject(),
ReceiverValue.NO_RECEIVER,
ExplicitReceiverKind.NO_EXPLICIT_RECEIVER, false);
CallCandidateResolutionContext<CallableDescriptor> contextWithoutReceiver = createContextWithChainedTrace(
@@ -131,8 +135,22 @@ public class CallTransformer<D extends CallableDescriptor, F extends D> {
return CallCandidateResolutionContext.create(resolvedCall, task, chainedTrace, task.tracing, call, receiverValue);
}
private Call stripCallArguments(@NotNull ResolutionTask<CallableDescriptor, FunctionDescriptor> task) {
return new DelegatingCall(task.call) {
@NotNull
private ResolutionCandidate<CallableDescriptor> getVariableCallCandidate(
@NotNull ResolutionCandidate<CallableDescriptor> candidate,
@NotNull Call variableCall
) {
return ResolutionCandidate.create(
variableCall,
candidate.getDescriptor(),
candidate.getThisObject(),
candidate.getReceiverArgument(),
candidate.getExplicitReceiverKind(),
candidate.isSafeCall());
}
private Call stripCallArguments(@NotNull Call call) {
return new DelegatingCall(call) {
@Override
public JetValueArgumentList getValueArgumentList() {
return null;
@@ -160,6 +178,15 @@ public class CallTransformer<D extends CallableDescriptor, F extends D> {
public JetTypeArgumentList getTypeArgumentList() {
return null;
}
@NotNull
@Override
public JetElement getCallElement() {
JetExpression calleeExpression = getCalleeExpression();
assert calleeExpression != null : "No callee expression: " + getCallElement().getText();
return calleeExpression;
}
};
}
@@ -4,6 +4,8 @@ fun foo() {
i++
}
---------------------
1 <v0> NEW()
i <v1> NEW()
1 <v0> NEW()
i <v1> NEW()
i++ <v2> NEW(<v1>)
{ var i = 1 i++ } <v2> COPY
=====================
@@ -20,25 +20,28 @@ fun assignments() : Unit {
t.x += 1
}
---------------------
1 <v0> NEW()
2 <v1> NEW()
x <v2> NEW()
2 <v3> NEW()
true <v5> NEW()
1 <v6> NEW()
2 <v7> NEW()
if (true) 1 else 2 <v8> NEW(<v6>, <v7>)
true <v9> NEW()
false <v10> NEW()
true && false <v11> NEW(<v9>, <v10>)
false <v12> NEW()
true <v13> NEW()
false && true <v14> NEW(<v12>, <v13>)
Test() <v15> NEW()
t <v16> NEW()
1 <v17> NEW()
t <v22> NEW()
x <v19> NEW(<v18>)
t.x <v19> COPY
1 <v20> NEW()
1 <v0> NEW()
2 <v1> NEW()
x <v2> NEW()
2 <v3> NEW()
x += 2 <v4> NEW(<v2>, <v3>)
true <v5> NEW()
1 <v6> NEW()
2 <v7> NEW()
if (true) 1 else 2 <v8> NEW(<v6>, <v7>)
true <v9> NEW()
false <v10> NEW()
true && false <v11> NEW(<v9>, <v10>)
false <v12> NEW()
true <v13> NEW()
false && true <v14> NEW(<v12>, <v13>)
Test() <v15> NEW()
t <v16> NEW()
1 <v17> NEW()
t <v22> NEW()
x <v19> NEW(<v18>)
t.x <v19> COPY
1 <v20> NEW()
t.x += 1 <v21> NEW(<v19>, <v20>)
{ var x = 1 x = 2 x += 2 x = if (true) 1 else 2 val y = true && false val z = false && true val t = Test(); t.x = 1 t.x += 1 } <v21> COPY
=====================