diff --git a/compiler/frontend/src/org/jetbrains/jet/lang/cfg/JetControlFlowProcessor.java b/compiler/frontend/src/org/jetbrains/jet/lang/cfg/JetControlFlowProcessor.java index 276c7c395f2..3fd84976263 100644 --- a/compiler/frontend/src/org/jetbrains/jet/lang/cfg/JetControlFlowProcessor.java +++ b/compiler/frontend/src/org/jetbrains/jet/lang/cfg/JetControlFlowProcessor.java @@ -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 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 receiverValues = getReceiverValues(lhs, setResolvedCall, false); + Map receiverValues = getReceiverValues(setResolvedCall, false); SmartFMap 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 inputExpressions = new ArrayList(); 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.emptyMap() ).getOutputValue(); } @@ -1182,7 +1177,7 @@ public class JetControlFlowProcessor { public void visitArrayAccessExpression(@NotNull JetArrayAccessExpression expression) { mark(expression); ResolvedCall 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 receivers = getReceiverValues(callExpression, resolvedCall, true); + Map receivers = getReceiverValues(resolvedCall, true); SmartFMap 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 getReceiverValues( - JetExpression callExpression, ResolvedCall resolvedCall, boolean generateInstructions) { SmartFMap 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 getReceiverValues( - JetExpression callExpression, + JetElement callElement, ReceiverValue receiver, boolean generateInstructions, SmartFMap 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) { diff --git a/compiler/frontend/src/org/jetbrains/jet/lang/resolve/calls/CallTransformer.java b/compiler/frontend/src/org/jetbrains/jet/lang/resolve/calls/CallTransformer.java index 1718a96ab8d..40f3d802061 100644 --- a/compiler/frontend/src/org/jetbrains/jet/lang/resolve/calls/CallTransformer.java +++ b/compiler/frontend/src/org/jetbrains/jet/lang/resolve/calls/CallTransformer.java @@ -102,18 +102,22 @@ public class CallTransformer { assert candidate.getDescriptor() instanceof VariableDescriptor; boolean hasReceiver = candidate.getReceiverArgument().exists(); - Call variableCall = stripCallArguments(task); + Call variableCall = stripCallArguments(task.call); + ResolutionCandidate variableCandidate = getVariableCallCandidate(candidate, variableCall); if (!hasReceiver) { CallCandidateResolutionContext 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 contextWithReceiver = createContextWithChainedTrace( - candidate, variableCall, candidateTrace, task, ReceiverValue.NO_RECEIVER); + variableCandidate, variableCall, candidateTrace, task, ReceiverValue.NO_RECEIVER); Call variableCallWithoutReceiver = stripReceiver(variableCall); ResolutionCandidate 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 contextWithoutReceiver = createContextWithChainedTrace( @@ -131,8 +135,22 @@ public class CallTransformer { return CallCandidateResolutionContext.create(resolvedCall, task, chainedTrace, task.tracing, call, receiverValue); } - private Call stripCallArguments(@NotNull ResolutionTask task) { - return new DelegatingCall(task.call) { + @NotNull + private ResolutionCandidate getVariableCallCandidate( + @NotNull ResolutionCandidate 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 { public JetTypeArgumentList getTypeArgumentList() { return null; } + + @NotNull + @Override + public JetElement getCallElement() { + JetExpression calleeExpression = getCalleeExpression(); + assert calleeExpression != null : "No callee expression: " + getCallElement().getText(); + + return calleeExpression; + } }; } diff --git a/compiler/testData/cfg/conventions/incrementAtTheEnd.values b/compiler/testData/cfg/conventions/incrementAtTheEnd.values index 708871cea55..c25eae8f5a4 100644 --- a/compiler/testData/cfg/conventions/incrementAtTheEnd.values +++ b/compiler/testData/cfg/conventions/incrementAtTheEnd.values @@ -4,6 +4,8 @@ fun foo() { i++ } --------------------- -1 NEW() -i NEW() +1 NEW() +i NEW() +i++ NEW() +{ var i = 1 i++ } COPY ===================== diff --git a/compiler/testData/cfg/expressions/Assignments.values b/compiler/testData/cfg/expressions/Assignments.values index 122e8516b37..80cc3e47236 100644 --- a/compiler/testData/cfg/expressions/Assignments.values +++ b/compiler/testData/cfg/expressions/Assignments.values @@ -20,25 +20,28 @@ fun assignments() : Unit { t.x += 1 } --------------------- -1 NEW() -2 NEW() -x NEW() -2 NEW() -true NEW() -1 NEW() -2 NEW() -if (true) 1 else 2 NEW(, ) -true NEW() -false NEW() -true && false NEW(, ) -false NEW() -true NEW() -false && true NEW(, ) -Test() NEW() -t NEW() -1 NEW() -t NEW() -x NEW() -t.x COPY -1 NEW() +1 NEW() +2 NEW() +x NEW() +2 NEW() +x += 2 NEW(, ) +true NEW() +1 NEW() +2 NEW() +if (true) 1 else 2 NEW(, ) +true NEW() +false NEW() +true && false NEW(, ) +false NEW() +true NEW() +false && true NEW(, ) +Test() NEW() +t NEW() +1 NEW() +t NEW() +x NEW() +t.x COPY +1 NEW() +t.x += 1 NEW(, ) +{ 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 } COPY =====================