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