001    /*
002     * Copyright 2010-2015 JetBrains s.r.o.
003     *
004     * Licensed under the Apache License, Version 2.0 (the "License");
005     * you may not use this file except in compliance with the License.
006     * You may obtain a copy of the License at
007     *
008     * http://www.apache.org/licenses/LICENSE-2.0
009     *
010     * Unless required by applicable law or agreed to in writing, software
011     * distributed under the License is distributed on an "AS IS" BASIS,
012     * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
013     * See the License for the specific language governing permissions and
014     * limitations under the License.
015     */
016    
017    package org.jetbrains.kotlin.cfg;
018    
019    import com.google.common.collect.Lists;
020    import com.google.common.collect.Sets;
021    import com.intellij.psi.PsiElement;
022    import com.intellij.psi.tree.IElementType;
023    import com.intellij.psi.util.PsiTreeUtil;
024    import com.intellij.util.SmartFMap;
025    import com.intellij.util.containers.ContainerUtil;
026    import com.intellij.util.containers.MultiMap;
027    import kotlin.KotlinPackage;
028    import kotlin.jvm.functions.Function0;
029    import kotlin.jvm.functions.Function1;
030    import org.jetbrains.annotations.NotNull;
031    import org.jetbrains.annotations.Nullable;
032    import org.jetbrains.kotlin.builtins.KotlinBuiltIns;
033    import org.jetbrains.kotlin.cfg.pseudocode.*;
034    import org.jetbrains.kotlin.cfg.pseudocode.instructions.eval.AccessTarget;
035    import org.jetbrains.kotlin.cfg.pseudocode.instructions.eval.InstructionWithValue;
036    import org.jetbrains.kotlin.cfg.pseudocode.instructions.eval.MagicKind;
037    import org.jetbrains.kotlin.descriptors.*;
038    import org.jetbrains.kotlin.descriptors.impl.AnonymousFunctionDescriptor;
039    import org.jetbrains.kotlin.lexer.JetToken;
040    import org.jetbrains.kotlin.lexer.JetTokens;
041    import org.jetbrains.kotlin.name.Name;
042    import org.jetbrains.kotlin.psi.*;
043    import org.jetbrains.kotlin.psi.psiUtil.PsiUtilPackage;
044    import org.jetbrains.kotlin.resolve.BindingContext;
045    import org.jetbrains.kotlin.resolve.BindingContextUtils;
046    import org.jetbrains.kotlin.resolve.BindingTrace;
047    import org.jetbrains.kotlin.resolve.CompileTimeConstantUtils;
048    import org.jetbrains.kotlin.renderer.DescriptorRenderer;
049    import org.jetbrains.kotlin.resolve.*;
050    import org.jetbrains.kotlin.resolve.bindingContextUtil.BindingContextUtilPackage;
051    import org.jetbrains.kotlin.resolve.calls.ValueArgumentsToParametersMapper;
052    import org.jetbrains.kotlin.resolve.calls.callUtil.CallUtilPackage;
053    import org.jetbrains.kotlin.resolve.calls.model.*;
054    import org.jetbrains.kotlin.resolve.calls.tasks.ExplicitReceiverKind;
055    import org.jetbrains.kotlin.resolve.calls.tasks.ResolutionCandidate;
056    import org.jetbrains.kotlin.resolve.calls.tasks.TracingStrategy;
057    import org.jetbrains.kotlin.resolve.constants.CompileTimeConstant;
058    import org.jetbrains.kotlin.resolve.constants.evaluate.ConstantExpressionEvaluator;
059    import org.jetbrains.kotlin.resolve.scopes.receivers.ExpressionReceiver;
060    import org.jetbrains.kotlin.resolve.scopes.receivers.ReceiverValue;
061    import org.jetbrains.kotlin.resolve.scopes.receivers.ThisReceiver;
062    import org.jetbrains.kotlin.resolve.scopes.receivers.TransientReceiver;
063    import org.jetbrains.kotlin.types.JetType;
064    import org.jetbrains.kotlin.types.expressions.OperatorConventions;
065    
066    import java.util.*;
067    
068    import static org.jetbrains.kotlin.cfg.JetControlFlowBuilder.PredefinedOperation.*;
069    import static org.jetbrains.kotlin.diagnostics.Errors.*;
070    import static org.jetbrains.kotlin.lexer.JetTokens.*;
071    import static org.jetbrains.kotlin.resolve.calls.callUtil.CallUtilPackage.getResolvedCall;
072    
073    public class JetControlFlowProcessor {
074    
075        private final JetControlFlowBuilder builder;
076        private final BindingTrace trace;
077    
078        public JetControlFlowProcessor(BindingTrace trace) {
079            this.builder = new JetControlFlowInstructionsGenerator();
080            this.trace = trace;
081        }
082    
083        @NotNull
084        public Pseudocode generatePseudocode(@NotNull JetElement subroutine) {
085            Pseudocode pseudocode = generate(subroutine);
086            ((PseudocodeImpl) pseudocode).postProcess();
087            return pseudocode;
088        }
089    
090        @NotNull
091        private Pseudocode generate(@NotNull JetElement subroutine) {
092            builder.enterSubroutine(subroutine);
093            CFPVisitor cfpVisitor = new CFPVisitor(builder);
094            if (subroutine instanceof JetDeclarationWithBody && !(subroutine instanceof JetSecondaryConstructor)) {
095                JetDeclarationWithBody declarationWithBody = (JetDeclarationWithBody) subroutine;
096                List<JetParameter> valueParameters = declarationWithBody.getValueParameters();
097                for (JetParameter valueParameter : valueParameters) {
098                    cfpVisitor.generateInstructions(valueParameter);
099                }
100                JetExpression bodyExpression = declarationWithBody.getBodyExpression();
101                if (bodyExpression != null) {
102                    cfpVisitor.generateInstructions(bodyExpression);
103                    if (!declarationWithBody.hasBlockBody()) {
104                        generateImplicitReturnValue(bodyExpression, subroutine);
105                    }
106                }
107            } else {
108                cfpVisitor.generateInstructions(subroutine);
109            }
110            return builder.exitSubroutine(subroutine);
111        }
112    
113        private void generateImplicitReturnValue(@NotNull JetExpression bodyExpression, @NotNull JetElement subroutine) {
114            CallableDescriptor subroutineDescriptor = (CallableDescriptor) trace.get(BindingContext.DECLARATION_TO_DESCRIPTOR, subroutine);
115            if (subroutineDescriptor == null) return;
116    
117            JetType returnType = subroutineDescriptor.getReturnType();
118            if (returnType != null && KotlinBuiltIns.isUnit(returnType) && subroutineDescriptor instanceof AnonymousFunctionDescriptor) return;
119    
120            PseudoValue returnValue = builder.getBoundValue(bodyExpression);
121            if (returnValue == null) return;
122    
123            builder.returnValue(bodyExpression, returnValue, subroutine);
124        }
125    
126        private void processLocalDeclaration(@NotNull JetDeclaration subroutine) {
127            Label afterDeclaration = builder.createUnboundLabel("after local declaration");
128    
129            builder.nondeterministicJump(afterDeclaration, subroutine, null);
130            generate(subroutine);
131            builder.bindLabel(afterDeclaration);
132        }
133    
134        private class CFPVisitor extends JetVisitorVoid {
135            private final JetControlFlowBuilder builder;
136    
137            private final JetVisitorVoid conditionVisitor = new JetVisitorVoid() {
138    
139                private JetExpression getSubjectExpression(JetWhenCondition condition) {
140                    JetWhenExpression whenExpression = PsiTreeUtil.getParentOfType(condition, JetWhenExpression.class);
141                    return whenExpression != null ? whenExpression.getSubjectExpression() : null;
142                }
143    
144                @Override
145                public void visitWhenConditionInRange(@NotNull JetWhenConditionInRange condition) {
146                    if (!generateCall(condition.getOperationReference())) {
147                        JetExpression rangeExpression = condition.getRangeExpression();
148                        generateInstructions(rangeExpression);
149                        createUnresolvedCall(condition, rangeExpression);
150                    }
151                }
152    
153                @Override
154                public void visitWhenConditionIsPattern(@NotNull JetWhenConditionIsPattern condition) {
155                    mark(condition);
156                    createNonSyntheticValue(condition, MagicKind.IS, getSubjectExpression(condition));
157                }
158    
159                @Override
160                public void visitWhenConditionWithExpression(@NotNull JetWhenConditionWithExpression condition) {
161                    mark(condition);
162    
163                    JetExpression expression = condition.getExpression();
164                    generateInstructions(expression);
165    
166                    JetExpression subjectExpression = getSubjectExpression(condition);
167                    if (subjectExpression != null) {
168                        // todo: this can be replaced by equals() invocation (when corresponding resolved call is recorded)
169                        createNonSyntheticValue(condition, MagicKind.EQUALS_IN_WHEN_CONDITION, subjectExpression, expression);
170                    }
171                    else {
172                        copyValue(expression, condition);
173                    }
174                }
175    
176                @Override
177                public void visitJetElement(@NotNull JetElement element) {
178                    throw new UnsupportedOperationException("[JetControlFlowProcessor] " + element.toString());
179                }
180            };
181    
182            private CFPVisitor(@NotNull JetControlFlowBuilder builder) {
183                this.builder = builder;
184            }
185    
186            private void mark(JetElement element) {
187                builder.mark(element);
188            }
189    
190            public void generateInstructions(@Nullable JetElement element) {
191                if (element == null) return;
192                element.accept(this);
193                checkNothingType(element);
194            }
195    
196            private void checkNothingType(JetElement element) {
197                if (!(element instanceof JetExpression)) return;
198    
199                JetExpression expression = JetPsiUtil.deparenthesize((JetExpression) element);
200                if (expression == null) return;
201    
202                if (expression instanceof JetStatementExpression || expression instanceof JetTryExpression
203                        || expression instanceof JetIfExpression || expression instanceof JetWhenExpression) {
204                    return;
205                }
206    
207                JetType type = trace.getBindingContext().getType(expression);
208                if (type != null && KotlinBuiltIns.isNothing(type)) {
209                    builder.jumpToError(expression);
210                }
211            }
212    
213            @NotNull
214            private PseudoValue createSyntheticValue(@NotNull JetElement instructionElement, @NotNull MagicKind kind, JetElement... from) {
215                List<PseudoValue> values = elementsToValues(from.length > 0 ? Arrays.asList(from) : Collections.<JetElement>emptyList());
216                return builder.magic(instructionElement, null, values, defaultTypeMap(values), kind).getOutputValue();
217            }
218    
219            @NotNull
220            private PseudoValue createNonSyntheticValue(
221                    @NotNull JetElement to, @NotNull List<? extends JetElement> from, @NotNull MagicKind kind
222            ) {
223                List<PseudoValue> values = elementsToValues(from);
224                return builder.magic(to, to, values, defaultTypeMap(values), kind).getOutputValue();
225            }
226    
227            @NotNull
228            private PseudoValue createNonSyntheticValue(@NotNull JetElement to, @NotNull MagicKind kind, JetElement... from) {
229                return createNonSyntheticValue(to, Arrays.asList(from), kind);
230            }
231    
232            @Nullable
233            private Map<PseudoValue, TypePredicate> getTypeMapForUnresolvedCall(@NotNull JetElement to, List<PseudoValue> arguments) {
234                Call call = CallUtilPackage.getCall(to, trace.getBindingContext());
235                if (call == null) return null;
236    
237                JetExpression callee = call.getCalleeExpression();
238                if (callee == null) return null;
239    
240                Collection<FunctionDescriptor> candidates = KotlinPackage.sortBy(
241                        KotlinPackage.filterIsInstance(
242                                BindingContextUtilPackage.getReferenceTargets(callee, trace.getBindingContext()),
243                                FunctionDescriptor.class
244                        ),
245                        new Function1<FunctionDescriptor, Comparable>() {
246                            @Override
247                            public Comparable invoke(FunctionDescriptor descriptor) {
248                                return DescriptorRenderer.DEBUG_TEXT.render(descriptor);
249                            }
250                        }
251                );
252                if (candidates.isEmpty()) return null;
253    
254                ReceiverValue explicitReceiver = call.getExplicitReceiver();
255                int argValueOffset = explicitReceiver.exists() ? 1 : 0;
256    
257                MultiMap<PseudoValue, TypePredicate> valuesToPredicates = new MultiMap<PseudoValue, TypePredicate>(arguments.size(), 1);
258    
259                candidateLoop:
260                for (FunctionDescriptor candidate : candidates) {
261                    ResolvedCallImpl<FunctionDescriptor> candidateCall = ResolvedCallImpl.create(
262                            ResolutionCandidate.create(call,
263                                                       candidate,
264                                                       call.getDispatchReceiver(),
265                                                       explicitReceiver,
266                                                       ExplicitReceiverKind.NO_EXPLICIT_RECEIVER,
267                                                       null),
268                            new DelegatingBindingTrace(trace.getBindingContext(), "Compute type predicates for unresolved call arguments"),
269                            TracingStrategy.EMPTY,
270                            new DataFlowInfoForArgumentsImpl(call)
271                    );
272                    ValueArgumentsToParametersMapper.Status status = ValueArgumentsToParametersMapper.mapValueArgumentsToParameters(
273                            call,
274                            TracingStrategy.EMPTY,
275                            candidateCall,
276                            Sets.<ValueArgument>newLinkedHashSet()
277                    );
278                    if (!status.isSuccess()) continue;
279    
280                    Map<ValueParameterDescriptor, ResolvedValueArgument> candidateArgumentMap = candidateCall.getValueArguments();
281                    List<? extends ValueArgument> callArguments = call.getValueArguments();
282                    for (int i = 0; i < callArguments.size(); i++) {
283                        int valueIndex = i + argValueOffset;
284                        if (valueIndex >= arguments.size()) continue candidateLoop;
285                        PseudoValue argumentValue = arguments.get(valueIndex);
286    
287                        ArgumentMapping mapping = candidateCall.getArgumentMapping(callArguments.get(i));
288                        if (!(mapping instanceof ArgumentMatch)) continue candidateLoop;
289    
290                        ValueParameterDescriptor candidateParameter = ((ArgumentMatch) mapping).getValueParameter();
291                        ResolvedValueArgument resolvedArgument = candidateArgumentMap.get(candidateParameter);
292                        JetType expectedType = resolvedArgument instanceof VarargValueArgument
293                                       ? candidateParameter.getVarargElementType()
294                                       : candidateParameter.getType();
295    
296                        valuesToPredicates.putValue(argumentValue, expectedType != null ? new AllSubtypes(expectedType) : AllTypes.INSTANCE$);
297                    }
298                }
299    
300                SmartFMap<PseudoValue, TypePredicate> result = SmartFMap.emptyMap();
301                for (Map.Entry<PseudoValue, Collection<TypePredicate>> entry : valuesToPredicates.entrySet()) {
302                    result = result.plus(entry.getKey(), PseudocodePackage.or(entry.getValue()));
303                }
304    
305                return result;
306            }
307    
308            @NotNull
309            private PseudoValue createUnresolvedCallByValues(@NotNull JetElement to, @Nullable JetElement valueElement, List<PseudoValue> arguments) {
310                Map<PseudoValue, TypePredicate> typeMap = getTypeMapForUnresolvedCall(to, arguments);
311                if (typeMap == null) {
312                    typeMap = defaultTypeMap(arguments);
313                }
314                
315                return builder.magic(to, valueElement, arguments, typeMap, MagicKind.UNRESOLVED_CALL).getOutputValue();
316            }
317    
318            @NotNull
319            private PseudoValue createUnresolvedCallByValues(@NotNull JetElement to, List<PseudoValue> arguments) {
320                return createUnresolvedCallByValues(to, to, arguments);
321            }
322    
323            @NotNull
324            private PseudoValue createUnresolvedCall(@NotNull JetElement to, List<? extends JetElement> from) {
325                return createUnresolvedCallByValues(to, elementsToValues(from));
326            }
327    
328            @NotNull
329            private PseudoValue createUnresolvedCall(@NotNull JetElement to, JetElement... from) {
330                return createUnresolvedCall(to, Arrays.asList(from));
331            }
332    
333            @NotNull
334            private Map<PseudoValue, TypePredicate> defaultTypeMap(List<PseudoValue> values) {
335                return PseudocodePackage.expectedTypeFor(AllTypes.INSTANCE$, values);
336            }
337    
338            private void mergeValues(@NotNull List<JetExpression> from, @NotNull JetExpression to) {
339                builder.merge(to, elementsToValues(from));
340            }
341    
342            private void copyValue(@Nullable JetElement from, @NotNull JetElement to) {
343                PseudoValue value = getBoundOrUnreachableValue(from);
344                if (value != null) {
345                    builder.bindValue(value, to);
346                }
347            }
348    
349            @Nullable
350            private PseudoValue getBoundOrUnreachableValue(@Nullable JetElement element) {
351                if (element == null) return null;
352    
353                PseudoValue value = builder.getBoundValue(element);
354                return value != null || element instanceof JetDeclaration ? value : builder.newValue(element);
355            }
356    
357            private List<PseudoValue> elementsToValues(List<? extends JetElement> from) {
358                if (from.isEmpty()) return Collections.emptyList();
359                return KotlinPackage.filterNotNull(
360                        KotlinPackage.map(
361                                from,
362                                new Function1<JetElement, PseudoValue>() {
363                                    @Override
364                                    public PseudoValue invoke(JetElement element) {
365                                        return getBoundOrUnreachableValue(element);
366                                    }
367                                }
368                        )
369                );
370            }
371    
372            private void generateInitializer(@NotNull JetDeclaration declaration, @NotNull PseudoValue initValue) {
373                builder.write(
374                        declaration,
375                        declaration,
376                        initValue,
377                        getDeclarationAccessTarget(declaration),
378                        Collections.<PseudoValue, ReceiverValue>emptyMap()
379                );
380            }
381    
382            @NotNull
383            private AccessTarget getResolvedCallAccessTarget(JetElement element) {
384                ResolvedCall<?> resolvedCall = getResolvedCall(element, trace.getBindingContext());
385                return resolvedCall != null ? new AccessTarget.Call(resolvedCall) : AccessTarget.BlackBox.INSTANCE$;
386            }
387    
388            @NotNull
389            private AccessTarget getDeclarationAccessTarget(JetElement element) {
390                DeclarationDescriptor descriptor = trace.get(BindingContext.DECLARATION_TO_DESCRIPTOR, element);
391                return descriptor instanceof VariableDescriptor
392                       ? new AccessTarget.Declaration((VariableDescriptor) descriptor)
393                       : AccessTarget.BlackBox.INSTANCE$;
394            }
395    
396            @Override
397            public void visitParenthesizedExpression(@NotNull JetParenthesizedExpression expression) {
398                mark(expression);
399                JetExpression innerExpression = expression.getExpression();
400                if (innerExpression != null) {
401                    generateInstructions(innerExpression);
402                    copyValue(innerExpression, expression);
403                }
404            }
405    
406            @Override
407            public void visitAnnotatedExpression(@NotNull JetAnnotatedExpression expression) {
408                JetExpression baseExpression = expression.getBaseExpression();
409                if (baseExpression != null) {
410                    generateInstructions(baseExpression);
411                    copyValue(baseExpression, expression);
412                }
413            }
414    
415            @Override
416            public void visitThisExpression(@NotNull JetThisExpression expression) {
417                ResolvedCall<?> resolvedCall = getResolvedCall(expression, trace.getBindingContext());
418                if (resolvedCall == null) {
419                    createUnresolvedCall(expression);
420                    return;
421                }
422    
423                CallableDescriptor resultingDescriptor = resolvedCall.getResultingDescriptor();
424                if (resultingDescriptor instanceof ReceiverParameterDescriptor) {
425                    builder.readVariable(expression, resolvedCall, getReceiverValues(resolvedCall));
426                }
427    
428                copyValue(expression, expression.getInstanceReference());
429            }
430    
431            @Override
432            public void visitConstantExpression(@NotNull JetConstantExpression expression) {
433                CompileTimeConstant<?> constant = ConstantExpressionEvaluator.getConstant(expression, trace.getBindingContext());
434                builder.loadConstant(expression, constant);
435            }
436    
437            @Override
438            public void visitSimpleNameExpression(@NotNull JetSimpleNameExpression expression) {
439                ResolvedCall<?> resolvedCall = getResolvedCall(expression, trace.getBindingContext());
440                if (resolvedCall instanceof VariableAsFunctionResolvedCall) {
441                    VariableAsFunctionResolvedCall variableAsFunctionResolvedCall = (VariableAsFunctionResolvedCall) resolvedCall;
442                    generateCall(variableAsFunctionResolvedCall.getVariableCall());
443                }
444                else if (!generateCall(expression) && !(expression.getParent() instanceof JetCallExpression)) {
445                    createUnresolvedCall(expression, generateAndGetReceiverIfAny(expression));
446                }
447            }
448    
449            @Override
450            public void visitLabeledExpression(@NotNull JetLabeledExpression expression) {
451                mark(expression);
452                JetExpression baseExpression = expression.getBaseExpression();
453                if (baseExpression != null) {
454                    generateInstructions(baseExpression);
455                    copyValue(baseExpression, expression);
456                }
457            }
458    
459            @SuppressWarnings("SuspiciousMethodCalls")
460            @Override
461            public void visitBinaryExpression(@NotNull JetBinaryExpression expression) {
462                JetSimpleNameExpression operationReference = expression.getOperationReference();
463                IElementType operationType = operationReference.getReferencedNameElementType();
464    
465                JetExpression left = expression.getLeft();
466                JetExpression right = expression.getRight();
467                if (operationType == ANDAND || operationType == OROR) {
468                    generateBooleanOperation(expression);
469                }
470                else if (operationType == EQ) {
471                    visitAssignment(left, getDeferredValue(right), expression);
472                }
473                else if (OperatorConventions.ASSIGNMENT_OPERATIONS.containsKey(operationType)) {
474                    ResolvedCall<?> resolvedCall = getResolvedCall(expression, trace.getBindingContext());
475                    if (resolvedCall != null) {
476                        PseudoValue rhsValue = generateCall(resolvedCall).getOutputValue();
477                        Name assignMethodName = OperatorConventions.getNameForOperationSymbol((JetToken) expression.getOperationToken());
478                        if (!resolvedCall.getResultingDescriptor().getName().equals(assignMethodName)) {
479                            /* At this point assignment of the form a += b actually means a = a + b
480                             * So we first generate call of "+" operation and then use its output pseudo-value
481                             * as a right-hand side when generating assignment call
482                             */
483                            visitAssignment(left, getValueAsFunction(rhsValue), expression);
484                        }
485                    }
486                    else {
487                        generateBothArgumentsAndMark(expression);
488                    }
489                }
490                else if (operationType == ELVIS) {
491                    generateInstructions(left);
492                    mark(expression);
493                    Label afterElvis = builder.createUnboundLabel("after elvis operator");
494                    builder.jumpOnTrue(afterElvis, expression, builder.getBoundValue(left));
495                    if (right != null) {
496                        generateInstructions(right);
497                    }
498                    builder.bindLabel(afterElvis);
499                    mergeValues(Arrays.asList(left, right), expression);
500                }
501                else {
502                    if (!generateCall(expression)) {
503                        generateBothArgumentsAndMark(expression);
504                    }
505                }
506            }
507    
508            private void generateBooleanOperation(JetBinaryExpression expression) {
509                IElementType operationType = expression.getOperationReference().getReferencedNameElementType();
510                JetExpression left = expression.getLeft();
511                JetExpression right = expression.getRight();
512    
513                Label resultLabel = builder.createUnboundLabel("result of boolean operation");
514                generateInstructions(left);
515                if (operationType == ANDAND) {
516                    builder.jumpOnFalse(resultLabel, expression, builder.getBoundValue(left));
517                }
518                else {
519                    builder.jumpOnTrue(resultLabel, expression, builder.getBoundValue(left));
520                }
521                if (right != null) {
522                    generateInstructions(right);
523                }
524                builder.bindLabel(resultLabel);
525                JetControlFlowBuilder.PredefinedOperation operation = operationType == ANDAND ? AND : OR;
526                builder.predefinedOperation(expression, operation, elementsToValues(Arrays.asList(left, right)));
527            }
528    
529            private Function0<PseudoValue> getValueAsFunction(final PseudoValue value) {
530                return new Function0<PseudoValue>() {
531                    @Override
532                    public PseudoValue invoke() {
533                        return value;
534                    }
535                };
536            }
537    
538            private Function0<PseudoValue> getDeferredValue(final JetExpression expression) {
539                return new Function0<PseudoValue>() {
540                    @Override
541                    public PseudoValue invoke() {
542                        generateInstructions(expression);
543                        return getBoundOrUnreachableValue(expression);
544                    }
545                };
546            }
547    
548            private void generateBothArgumentsAndMark(JetBinaryExpression expression) {
549                JetExpression left = JetPsiUtil.deparenthesize(expression.getLeft());
550                if (left != null) {
551                    generateInstructions(left);
552                }
553                JetExpression right = expression.getRight();
554                if (right != null) {
555                    generateInstructions(right);
556                }
557                mark(expression);
558                createUnresolvedCall(expression, left, right);
559            }
560    
561            private void visitAssignment(
562                    JetExpression lhs,
563                    @NotNull Function0<PseudoValue> rhsDeferredValue,
564                    JetExpression parentExpression
565            ) {
566                JetExpression left = JetPsiUtil.deparenthesize(lhs);
567                if (left == null) {
568                    List<PseudoValue> arguments = Collections.singletonList(rhsDeferredValue.invoke());
569                    builder.magic(parentExpression, parentExpression, arguments, defaultTypeMap(arguments), MagicKind.UNSUPPORTED_ELEMENT);
570                    return;
571                }
572    
573                if (left instanceof JetArrayAccessExpression) {
574                    generateArrayAssignment((JetArrayAccessExpression) left, rhsDeferredValue, parentExpression);
575                    return;
576                }
577    
578                Map<PseudoValue, ReceiverValue> receiverValues = SmartFMap.emptyMap();
579                AccessTarget accessTarget = AccessTarget.BlackBox.INSTANCE$;
580                if (left instanceof JetSimpleNameExpression || left instanceof JetQualifiedExpression) {
581                    accessTarget = getResolvedCallAccessTarget(PsiUtilPackage.getQualifiedElementSelector(left));
582                    if (accessTarget instanceof AccessTarget.Call) {
583                        receiverValues = getReceiverValues(((AccessTarget.Call) accessTarget).getResolvedCall());
584                    }
585                }
586                else if (left instanceof JetProperty) {
587                    accessTarget = getDeclarationAccessTarget(left);
588                }
589    
590                recordWrite(left, accessTarget, rhsDeferredValue.invoke(), receiverValues, parentExpression);
591            }
592    
593            private void generateArrayAssignment(
594                    JetArrayAccessExpression lhs,
595                    @NotNull Function0<PseudoValue> rhsDeferredValue,
596                    @NotNull JetExpression parentExpression
597            ) {
598                ResolvedCall<FunctionDescriptor> setResolvedCall = trace.get(BindingContext.INDEXED_LVALUE_SET, lhs);
599    
600                if (setResolvedCall == null) {
601                    generateArrayAccess(lhs, null);
602    
603                    List<PseudoValue> arguments = KotlinPackage.filterNotNull(
604                            Arrays.asList(getBoundOrUnreachableValue(lhs), rhsDeferredValue.invoke())
605                    );
606                    createUnresolvedCallByValues(parentExpression, arguments);
607    
608                    return;
609                }
610    
611                // In case of simple ('=') array assignment mark instruction is not generated yet, so we put it before generating "set" call
612                if (((JetOperationExpression) parentExpression).getOperationReference().getReferencedNameElementType() == EQ) {
613                    mark(lhs);
614                }
615    
616                generateInstructions(lhs.getArrayExpression());
617    
618                Map<PseudoValue, ReceiverValue> receiverValues = getReceiverValues(setResolvedCall);
619                SmartFMap<PseudoValue, ValueParameterDescriptor> argumentValues = getArraySetterArguments(rhsDeferredValue, setResolvedCall);
620    
621                builder.call(parentExpression, setResolvedCall, receiverValues, argumentValues);
622            }
623    
624            /* We assume that assignment right-hand side corresponds to the last argument of the call
625            *  So receiver instructions/pseudo-values are generated for all arguments except the last one which is replaced
626            *  by pre-generated pseudo-value
627            *  For example, assignment a[1, 2] += 3 means a.set(1, 2, a.get(1) + 3), so in order to generate "set" call
628            *  we first generate instructions for 1 and 2 whereas 3 is replaced by pseudo-value corresponding to "a.get(1) + 3"
629            */
630            private SmartFMap<PseudoValue, ValueParameterDescriptor> getArraySetterArguments(
631                    Function0<PseudoValue> rhsDeferredValue,
632                    final ResolvedCall<FunctionDescriptor> setResolvedCall
633            ) {
634                List<ValueArgument> valueArguments = KotlinPackage.flatMapTo(
635                        setResolvedCall.getResultingDescriptor().getValueParameters(),
636                        new ArrayList<ValueArgument>(),
637                        new Function1<ValueParameterDescriptor, Iterable<? extends ValueArgument>>() {
638                            @Override
639                            public Iterable<? extends ValueArgument> invoke(ValueParameterDescriptor descriptor) {
640                                ResolvedValueArgument resolvedValueArgument = setResolvedCall.getValueArguments().get(descriptor);
641                                return resolvedValueArgument != null
642                                       ? resolvedValueArgument.getArguments()
643                                       : Collections.<ValueArgument>emptyList();
644                            }
645                        }
646                );
647    
648                ValueArgument rhsArgument = KotlinPackage.lastOrNull(valueArguments);
649                SmartFMap<PseudoValue, ValueParameterDescriptor> argumentValues = SmartFMap.emptyMap();
650                for (ValueArgument valueArgument : valueArguments) {
651                    ArgumentMapping argumentMapping = setResolvedCall.getArgumentMapping(valueArgument);
652                    if (argumentMapping.isError() || (!(argumentMapping instanceof ArgumentMatch))) continue;
653    
654                    ValueParameterDescriptor parameterDescriptor = ((ArgumentMatch) argumentMapping).getValueParameter();
655                    if (valueArgument != rhsArgument) {
656                        argumentValues = generateValueArgument(valueArgument, parameterDescriptor, argumentValues);
657                    }
658                    else {
659                        PseudoValue rhsValue = rhsDeferredValue.invoke();
660                        if (rhsValue != null) {
661                            argumentValues = argumentValues.plus(rhsValue, parameterDescriptor);
662                        }
663                    }
664                }
665                return argumentValues;
666            }
667    
668            private void recordWrite(
669                    @NotNull JetExpression left,
670                    @NotNull AccessTarget target,
671                    @Nullable PseudoValue rightValue,
672                    @NotNull Map<PseudoValue, ReceiverValue> receiverValues,
673                    @NotNull JetExpression parentExpression
674            ) {
675                if (target == AccessTarget.BlackBox.INSTANCE$) {
676                    List<PseudoValue> values = ContainerUtil.createMaybeSingletonList(rightValue);
677                    builder.magic(parentExpression, parentExpression, values, defaultTypeMap(values), MagicKind.UNSUPPORTED_ELEMENT);
678                }
679                else {
680                    PseudoValue rValue =
681                            rightValue != null ? rightValue : createSyntheticValue(parentExpression, MagicKind.UNRECOGNIZED_WRITE_RHS);
682                    builder.write(parentExpression, left, rValue, target, receiverValues);
683                }
684            }
685    
686            private void generateArrayAccess(JetArrayAccessExpression arrayAccessExpression, @Nullable ResolvedCall<?> resolvedCall) {
687                if (builder.getBoundValue(arrayAccessExpression) != null) return;
688                mark(arrayAccessExpression);
689                if (!checkAndGenerateCall(resolvedCall)) {
690                    generateArrayAccessWithoutCall(arrayAccessExpression);
691                }
692            }
693    
694            private void generateArrayAccessWithoutCall(JetArrayAccessExpression arrayAccessExpression) {
695                createUnresolvedCall(arrayAccessExpression, generateArrayAccessArguments(arrayAccessExpression));
696            }
697    
698            private List<JetExpression> generateArrayAccessArguments(JetArrayAccessExpression arrayAccessExpression) {
699                List<JetExpression> inputExpressions = new ArrayList<JetExpression>();
700    
701                JetExpression arrayExpression = arrayAccessExpression.getArrayExpression();
702                inputExpressions.add(arrayExpression);
703                generateInstructions(arrayExpression);
704    
705                for (JetExpression index : arrayAccessExpression.getIndexExpressions()) {
706                    generateInstructions(index);
707                    inputExpressions.add(index);
708                }
709    
710                return inputExpressions;
711            }
712    
713            @Override
714            public void visitUnaryExpression(@NotNull JetUnaryExpression expression) {
715                JetSimpleNameExpression operationSign = expression.getOperationReference();
716                IElementType operationType = operationSign.getReferencedNameElementType();
717                JetExpression baseExpression = expression.getBaseExpression();
718                if (baseExpression == null) return;
719                if (JetTokens.EXCLEXCL == operationType) {
720                    generateInstructions(baseExpression);
721                    builder.predefinedOperation(expression, NOT_NULL_ASSERTION, elementsToValues(Collections.singletonList(baseExpression)));
722                    return;
723                }
724    
725                boolean incrementOrDecrement = isIncrementOrDecrement(operationType);
726                ResolvedCall<?> resolvedCall = getResolvedCall(expression, trace.getBindingContext());
727    
728                PseudoValue rhsValue;
729                if (resolvedCall != null) {
730                    rhsValue = generateCall(resolvedCall).getOutputValue();
731                }
732                else {
733                    generateInstructions(baseExpression);
734                    rhsValue = createUnresolvedCall(expression, baseExpression);
735                }
736    
737                if (incrementOrDecrement) {
738                    visitAssignment(baseExpression, getValueAsFunction(rhsValue), expression);
739                    if (expression instanceof JetPostfixExpression) {
740                        copyValue(baseExpression, expression);
741                    }
742                }
743            }
744    
745            private boolean isIncrementOrDecrement(IElementType operationType) {
746                return operationType == JetTokens.PLUSPLUS || operationType == JetTokens.MINUSMINUS;
747            }
748    
749            @Override
750            public void visitIfExpression(@NotNull JetIfExpression expression) {
751                mark(expression);
752                List<JetExpression> branches = new ArrayList<JetExpression>(2);
753                JetExpression condition = expression.getCondition();
754                if (condition != null) {
755                    generateInstructions(condition);
756                }
757                Label elseLabel = builder.createUnboundLabel("else branch");
758                builder.jumpOnFalse(elseLabel, expression, builder.getBoundValue(condition));
759                JetExpression thenBranch = expression.getThen();
760                if (thenBranch != null) {
761                    branches.add(thenBranch);
762                    generateInstructions(thenBranch);
763                }
764                else {
765                    builder.loadUnit(expression);
766                }
767                Label resultLabel = builder.createUnboundLabel("'if' expression result");
768                builder.jump(resultLabel, expression);
769                builder.bindLabel(elseLabel);
770                JetExpression elseBranch = expression.getElse();
771                if (elseBranch != null) {
772                    branches.add(elseBranch);
773                    generateInstructions(elseBranch);
774                }
775                else {
776                    builder.loadUnit(expression);
777                }
778                builder.bindLabel(resultLabel);
779                mergeValues(branches, expression);
780            }
781    
782            private class FinallyBlockGenerator {
783                private final JetFinallySection finallyBlock;
784                private Label startFinally = null;
785                private Label finishFinally = null;
786    
787                private FinallyBlockGenerator(JetFinallySection block) {
788                    finallyBlock = block;
789                }
790    
791                public void generate() {
792                    JetBlockExpression finalExpression = finallyBlock.getFinalExpression();
793                    if (finalExpression == null) return;
794                    if (startFinally != null) {
795                        assert finishFinally != null;
796                        builder.repeatPseudocode(startFinally, finishFinally);
797                        return;
798                    }
799                    startFinally = builder.createUnboundLabel("start finally");
800                    builder.bindLabel(startFinally);
801                    generateInstructions(finalExpression);
802                    finishFinally = builder.createUnboundLabel("finish finally");
803                    builder.bindLabel(finishFinally);
804                }
805            }
806    
807            @Override
808            public void visitTryExpression(@NotNull JetTryExpression expression) {
809                mark(expression);
810    
811                JetFinallySection finallyBlock = expression.getFinallyBlock();
812                final FinallyBlockGenerator finallyBlockGenerator = new FinallyBlockGenerator(finallyBlock);
813                boolean hasFinally = finallyBlock != null;
814                if (hasFinally) {
815                    builder.enterTryFinally(new GenerationTrigger() {
816                        private boolean working = false;
817    
818                        @Override
819                        public void generate() {
820                            // This checks are needed for the case of having e.g. return inside finally: 'try {return} finally{return}'
821                            if (working) return;
822                            working = true;
823                            finallyBlockGenerator.generate();
824                            working = false;
825                        }
826                    });
827                }
828    
829                Label onExceptionToFinallyBlock = generateTryAndCatches(expression);
830    
831                if (hasFinally) {
832                    assert onExceptionToFinallyBlock != null : "No finally lable generated: " + expression.getText();
833    
834                    builder.exitTryFinally();
835    
836                    Label skipFinallyToErrorBlock = builder.createUnboundLabel("skipFinallyToErrorBlock");
837                    builder.jump(skipFinallyToErrorBlock, expression);
838                    builder.bindLabel(onExceptionToFinallyBlock);
839                    finallyBlockGenerator.generate();
840                    builder.jumpToError(expression);
841                    builder.bindLabel(skipFinallyToErrorBlock);
842    
843                    finallyBlockGenerator.generate();
844                }
845    
846                List<JetExpression> branches = new ArrayList<JetExpression>();
847                branches.add(expression.getTryBlock());
848                for (JetCatchClause catchClause : expression.getCatchClauses()) {
849                    branches.add(catchClause.getCatchBody());
850                }
851                mergeValues(branches, expression);
852            }
853    
854            // Returns label for 'finally' block
855            @Nullable
856            private Label generateTryAndCatches(@NotNull JetTryExpression expression) {
857                List<JetCatchClause> catchClauses = expression.getCatchClauses();
858                boolean hasCatches = !catchClauses.isEmpty();
859    
860                Label onException = null;
861                if (hasCatches) {
862                    onException = builder.createUnboundLabel("onException");
863                    builder.nondeterministicJump(onException, expression, null);
864                }
865    
866                Label onExceptionToFinallyBlock = null;
867                if (expression.getFinallyBlock() != null) {
868                    onExceptionToFinallyBlock = builder.createUnboundLabel("onExceptionToFinallyBlock");
869                    builder.nondeterministicJump(onExceptionToFinallyBlock, expression, null);
870                }
871    
872                JetBlockExpression tryBlock = expression.getTryBlock();
873                generateInstructions(tryBlock);
874    
875                if (hasCatches) {
876                    Label afterCatches = builder.createUnboundLabel("afterCatches");
877                    builder.jump(afterCatches, expression);
878    
879                    builder.bindLabel(onException);
880                    LinkedList<Label> catchLabels = Lists.newLinkedList();
881                    int catchClausesSize = catchClauses.size();
882                    for (int i = 0; i < catchClausesSize - 1; i++) {
883                        catchLabels.add(builder.createUnboundLabel("catch " + i));
884                    }
885                    if (!catchLabels.isEmpty()) {
886                        builder.nondeterministicJump(catchLabels, expression);
887                    }
888                    boolean isFirst = true;
889                    for (JetCatchClause catchClause : catchClauses) {
890                        builder.enterLexicalScope(catchClause);
891                        if (!isFirst) {
892                            builder.bindLabel(catchLabels.remove());
893                        }
894                        else {
895                            isFirst = false;
896                        }
897                        JetParameter catchParameter = catchClause.getCatchParameter();
898                        if (catchParameter != null) {
899                            builder.declareParameter(catchParameter);
900                            generateInitializer(catchParameter, createSyntheticValue(catchParameter, MagicKind.FAKE_INITIALIZER));
901                        }
902                        JetExpression catchBody = catchClause.getCatchBody();
903                        if (catchBody != null) {
904                            generateInstructions(catchBody);
905                        }
906                        builder.jump(afterCatches, expression);
907                        builder.exitLexicalScope(catchClause);
908                    }
909    
910                    builder.bindLabel(afterCatches);
911                }
912    
913                return onExceptionToFinallyBlock;
914            }
915    
916            @Override
917            public void visitWhileExpression(@NotNull JetWhileExpression expression) {
918                LoopInfo loopInfo = builder.enterLoop(expression);
919    
920                builder.bindLabel(loopInfo.getConditionEntryPoint());
921                JetExpression condition = expression.getCondition();
922                if (condition != null) {
923                    generateInstructions(condition);
924                }
925                mark(expression);
926                boolean conditionIsTrueConstant = CompileTimeConstantUtils.canBeReducedToBooleanConstant(condition, trace, true);
927                if (!conditionIsTrueConstant) {
928                    builder.jumpOnFalse(loopInfo.getExitPoint(), expression, builder.getBoundValue(condition));
929                }
930                else {
931                    assert condition != null : "Invalid while condition: " + expression.getText();
932                    List<PseudoValue> values = ContainerUtil.createMaybeSingletonList(builder.getBoundValue(condition));
933                    Map<PseudoValue, TypePredicate> typePredicates =
934                            PseudocodePackage.expectedTypeFor(new SingleType(KotlinBuiltIns.getInstance().getBooleanType()), values);
935                    builder.magic(condition, null, values, typePredicates, MagicKind.VALUE_CONSUMER);
936                }
937    
938                builder.enterLoopBody(expression);
939                JetExpression body = expression.getBody();
940                if (body != null) {
941                    generateInstructions(body);
942                }
943                builder.jump(loopInfo.getEntryPoint(), expression);
944                builder.exitLoopBody(expression);
945                builder.bindLabel(loopInfo.getExitPoint());
946                builder.loadUnit(expression);
947            }
948    
949            @Override
950            public void visitDoWhileExpression(@NotNull JetDoWhileExpression expression) {
951                builder.enterLexicalScope(expression);
952                mark(expression);
953                LoopInfo loopInfo = builder.enterLoop(expression);
954    
955                builder.enterLoopBody(expression);
956                JetExpression body = expression.getBody();
957                if (body != null) {
958                    generateInstructions(body);
959                }
960                builder.exitLoopBody(expression);
961                builder.bindLabel(loopInfo.getConditionEntryPoint());
962                JetExpression condition = expression.getCondition();
963                if (condition != null) {
964                    generateInstructions(condition);
965                }
966                builder.jumpOnTrue(loopInfo.getEntryPoint(), expression, builder.getBoundValue(condition));
967                builder.bindLabel(loopInfo.getExitPoint());
968                builder.loadUnit(expression);
969                builder.exitLexicalScope(expression);
970            }
971    
972            @Override
973            public void visitForExpression(@NotNull JetForExpression expression) {
974                builder.enterLexicalScope(expression);
975    
976                JetExpression loopRange = expression.getLoopRange();
977                if (loopRange != null) {
978                    generateInstructions(loopRange);
979                }
980                declareLoopParameter(expression);
981    
982                // TODO : primitive cases
983                LoopInfo loopInfo = builder.enterLoop(expression);
984    
985                builder.bindLabel(loopInfo.getConditionEntryPoint());
986                builder.nondeterministicJump(loopInfo.getExitPoint(), expression, null);
987    
988    
989                writeLoopParameterAssignment(expression);
990    
991                mark(expression);
992                builder.enterLoopBody(expression);
993                JetExpression body = expression.getBody();
994                if (body != null) {
995                    generateInstructions(body);
996                }
997                builder.jump(loopInfo.getEntryPoint(), expression);
998    
999                builder.exitLoopBody(expression);
1000                builder.bindLabel(loopInfo.getExitPoint());
1001                builder.loadUnit(expression);
1002                builder.exitLexicalScope(expression);
1003            }
1004    
1005            private void declareLoopParameter(JetForExpression expression) {
1006                JetParameter loopParameter = expression.getLoopParameter();
1007                JetMultiDeclaration multiDeclaration = expression.getMultiParameter();
1008                if (loopParameter != null) {
1009                    builder.declareParameter(loopParameter);
1010                }
1011                else if (multiDeclaration != null) {
1012                    visitMultiDeclaration(multiDeclaration, false);
1013                }
1014            }
1015    
1016            private void writeLoopParameterAssignment(JetForExpression expression) {
1017                JetParameter loopParameter = expression.getLoopParameter();
1018                JetMultiDeclaration multiDeclaration = expression.getMultiParameter();
1019                JetExpression loopRange = expression.getLoopRange();
1020    
1021                TypePredicate loopRangeTypePredicate =
1022                        getTypePredicateByReceiverValue(trace.get(BindingContext.LOOP_RANGE_ITERATOR_RESOLVED_CALL, loopRange));
1023    
1024                PseudoValue loopRangeValue = builder.getBoundValue(loopRange);
1025                PseudoValue value = builder.magic(
1026                        loopRange != null ? loopRange : expression,
1027                        null,
1028                        ContainerUtil.createMaybeSingletonList(loopRangeValue),
1029                        loopRangeValue != null
1030                            ? Collections.singletonMap(loopRangeValue, loopRangeTypePredicate)
1031                            : Collections.<PseudoValue, TypePredicate>emptyMap(),
1032                        MagicKind.LOOP_RANGE_ITERATION
1033                ).getOutputValue();
1034    
1035                if (loopParameter != null) {
1036                    generateInitializer(loopParameter, value);
1037                }
1038                else if (multiDeclaration != null) {
1039                    for (JetMultiDeclarationEntry entry : multiDeclaration.getEntries()) {
1040                        generateInitializer(entry, value);
1041                    }
1042                }
1043            }
1044    
1045            private ReceiverValue getExplicitReceiverValue(ResolvedCall<?> resolvedCall) {
1046                switch(resolvedCall.getExplicitReceiverKind()) {
1047                    case DISPATCH_RECEIVER:
1048                        return resolvedCall.getDispatchReceiver();
1049                    case EXTENSION_RECEIVER:
1050                        return resolvedCall.getExtensionReceiver();
1051                    default:
1052                        return ReceiverValue.NO_RECEIVER;
1053                }
1054            }
1055    
1056            @Override
1057            public void visitBreakExpression(@NotNull JetBreakExpression expression) {
1058                JetElement loop = getCorrespondingLoop(expression);
1059                if (loop != null) {
1060                    checkJumpDoesNotCrossFunctionBoundary(expression, loop);
1061                    builder.jump(builder.getExitPoint(loop), expression);
1062                }
1063            }
1064    
1065            @Override
1066            public void visitContinueExpression(@NotNull JetContinueExpression expression) {
1067                JetElement loop = getCorrespondingLoop(expression);
1068                if (loop != null) {
1069                    checkJumpDoesNotCrossFunctionBoundary(expression, loop);
1070                    builder.jump(builder.getConditionEntryPoint(loop), expression);
1071                }
1072            }
1073    
1074            @Nullable
1075            private JetElement getCorrespondingLoop(JetExpressionWithLabel expression) {
1076                String labelName = expression.getLabelName();
1077                JetLoopExpression loop;
1078                if (labelName != null) {
1079                    JetSimpleNameExpression targetLabel = expression.getTargetLabel();
1080                    assert targetLabel != null;
1081                    PsiElement labeledElement = trace.get(BindingContext.LABEL_TARGET, targetLabel);
1082                    if (labeledElement instanceof JetLoopExpression) {
1083                        loop = (JetLoopExpression) labeledElement;
1084                    }
1085                    else {
1086                        trace.report(NOT_A_LOOP_LABEL.on(expression, targetLabel.getText()));
1087                        loop = null;
1088                    }
1089                }
1090                else {
1091                    loop = builder.getCurrentLoop();
1092                    if (loop == null) {
1093                        trace.report(BREAK_OR_CONTINUE_OUTSIDE_A_LOOP.on(expression));
1094                    } else {
1095                        JetWhenExpression whenExpression = PsiTreeUtil.getParentOfType(expression, JetWhenExpression.class, true,
1096                                                                                       JetLoopExpression.class);
1097                        if (whenExpression != null) {
1098                            trace.report(BREAK_OR_CONTINUE_IN_WHEN.on(expression));
1099                        }
1100                    }
1101                }
1102                if (loop != null && loop.getBody() != null
1103                        // the faster version of 'isAncestor' check:
1104                        && !loop.getBody().getTextRange().contains(expression.getTextRange())) {
1105                    trace.report(BREAK_OR_CONTINUE_OUTSIDE_A_LOOP.on(expression));
1106                    return null;
1107                }
1108                return loop;
1109            }
1110    
1111            private void checkJumpDoesNotCrossFunctionBoundary(@NotNull JetExpressionWithLabel jumpExpression, @NotNull JetElement jumpTarget) {
1112                BindingContext bindingContext = trace.getBindingContext();
1113    
1114                FunctionDescriptor labelExprEnclosingFunc = BindingContextUtils.getEnclosingFunctionDescriptor(bindingContext, jumpExpression);
1115                FunctionDescriptor labelTargetEnclosingFunc = BindingContextUtils.getEnclosingFunctionDescriptor(bindingContext, jumpTarget);
1116                if (labelExprEnclosingFunc != labelTargetEnclosingFunc) {
1117                    trace.report(BREAK_OR_CONTINUE_JUMPS_ACROSS_FUNCTION_BOUNDARY.on(jumpExpression));
1118                }
1119            }
1120    
1121            @Override
1122            public void visitReturnExpression(@NotNull JetReturnExpression expression) {
1123                JetExpression returnedExpression = expression.getReturnedExpression();
1124                if (returnedExpression != null) {
1125                    generateInstructions(returnedExpression);
1126                }
1127                JetSimpleNameExpression labelElement = expression.getTargetLabel();
1128                JetElement subroutine;
1129                String labelName = expression.getLabelName();
1130                if (labelElement != null && labelName != null) {
1131                    PsiElement labeledElement = trace.get(BindingContext.LABEL_TARGET, labelElement);
1132                    if (labeledElement != null) {
1133                        assert labeledElement instanceof JetElement;
1134                        subroutine = (JetElement) labeledElement;
1135                    }
1136                    else {
1137                        subroutine = null;
1138                    }
1139                }
1140                else {
1141                    subroutine = builder.getReturnSubroutine();
1142                    // TODO : a context check
1143                }
1144    
1145                if (subroutine instanceof JetFunction || subroutine instanceof JetPropertyAccessor) {
1146                    PseudoValue returnValue = returnedExpression != null ? builder.getBoundValue(returnedExpression) : null;
1147                    if (returnValue == null) {
1148                        builder.returnNoValue(expression, subroutine);
1149                    }
1150                    else {
1151                        builder.returnValue(expression, returnValue, subroutine);
1152                    }
1153                }
1154                else {
1155                    createNonSyntheticValue(expression, MagicKind.UNSUPPORTED_ELEMENT, returnedExpression);
1156                }
1157            }
1158    
1159            @Override
1160            public void visitParameter(@NotNull JetParameter parameter) {
1161                builder.declareParameter(parameter);
1162                JetExpression defaultValue = parameter.getDefaultValue();
1163                if (defaultValue != null) {
1164                    Label skipDefaultValue = builder.createUnboundLabel("after default value for parameter " + parameter.getName());
1165                    builder.nondeterministicJump(skipDefaultValue, defaultValue, null);
1166                    generateInstructions(defaultValue);
1167                    builder.bindLabel(skipDefaultValue);
1168                }
1169                generateInitializer(parameter, computePseudoValueForParameter(parameter));
1170            }
1171    
1172            @NotNull
1173            private PseudoValue computePseudoValueForParameter(@NotNull JetParameter parameter) {
1174                PseudoValue syntheticValue = createSyntheticValue(parameter, MagicKind.FAKE_INITIALIZER);
1175                PseudoValue defaultValue = builder.getBoundValue(parameter.getDefaultValue());
1176                if (defaultValue == null) {
1177                    return syntheticValue;
1178                }
1179                return builder.merge(parameter, Lists.newArrayList(defaultValue, syntheticValue)).getOutputValue();
1180            }
1181    
1182            @Override
1183            public void visitBlockExpression(@NotNull JetBlockExpression expression) {
1184                boolean declareLexicalScope = !isBlockInDoWhile(expression);
1185                if (declareLexicalScope) {
1186                    builder.enterLexicalScope(expression);
1187                }
1188                mark(expression);
1189                List<JetElement> statements = expression.getStatements();
1190                for (JetElement statement : statements) {
1191                    generateInstructions(statement);
1192                }
1193                if (statements.isEmpty()) {
1194                    builder.loadUnit(expression);
1195                }
1196                else {
1197                    copyValue(KotlinPackage.lastOrNull(statements), expression);
1198                }
1199                if (declareLexicalScope) {
1200                    builder.exitLexicalScope(expression);
1201                }
1202            }
1203    
1204            private boolean isBlockInDoWhile(@NotNull JetBlockExpression expression) {
1205                PsiElement parent = expression.getParent();
1206                if (parent == null) return false;
1207                return parent.getParent() instanceof JetDoWhileExpression;
1208            }
1209    
1210            private void visitFunction(@NotNull JetFunction function) {
1211                processLocalDeclaration(function);
1212                boolean isAnonymousFunction = function instanceof JetFunctionLiteral || function.getName() == null;
1213                if (isAnonymousFunction || (function.isLocal() && !(function.getParent() instanceof JetBlockExpression))) {
1214                    builder.createLambda(function);
1215                }
1216            }
1217    
1218            @Override
1219            public void visitNamedFunction(@NotNull JetNamedFunction function) {
1220                visitFunction(function);
1221            }
1222    
1223            @Override
1224            public void visitFunctionLiteralExpression(@NotNull JetFunctionLiteralExpression expression) {
1225                mark(expression);
1226                JetFunctionLiteral functionLiteral = expression.getFunctionLiteral();
1227                visitFunction(functionLiteral);
1228                copyValue(functionLiteral, expression);
1229            }
1230    
1231            @Override
1232            public void visitQualifiedExpression(@NotNull JetQualifiedExpression expression) {
1233                mark(expression);
1234                JetExpression selectorExpression = expression.getSelectorExpression();
1235                JetExpression receiverExpression = expression.getReceiverExpression();
1236    
1237                // todo: replace with selectorExpresion != null after parser is fixed
1238                if (selectorExpression instanceof JetCallExpression || selectorExpression instanceof JetSimpleNameExpression) {
1239                    generateInstructions(selectorExpression);
1240                    copyValue(selectorExpression, expression);
1241                }
1242                else {
1243                    generateInstructions(receiverExpression);
1244                    createNonSyntheticValue(expression, MagicKind.UNSUPPORTED_ELEMENT, receiverExpression);
1245                }
1246            }
1247    
1248            @Override
1249            public void visitCallExpression(@NotNull JetCallExpression expression) {
1250                if (!generateCall(expression)) {
1251                    List<JetExpression> inputExpressions = new ArrayList<JetExpression>();
1252                    for (ValueArgument argument : expression.getValueArguments()) {
1253                        JetExpression argumentExpression = argument.getArgumentExpression();
1254                        if (argumentExpression != null) {
1255                            generateInstructions(argumentExpression);
1256                            inputExpressions.add(argumentExpression);
1257                        }
1258                    }
1259                    JetExpression calleeExpression = expression.getCalleeExpression();
1260                    generateInstructions(calleeExpression);
1261                    inputExpressions.add(calleeExpression);
1262                    inputExpressions.add(generateAndGetReceiverIfAny(expression));
1263    
1264                    mark(expression);
1265                    createUnresolvedCall(expression, inputExpressions);
1266                }
1267            }
1268    
1269            @Nullable
1270            private JetExpression generateAndGetReceiverIfAny(JetExpression expression) {
1271                PsiElement parent = expression.getParent();
1272                if (!(parent instanceof JetQualifiedExpression)) return null;
1273    
1274                JetQualifiedExpression qualifiedExpression = (JetQualifiedExpression) parent;
1275                if (qualifiedExpression.getSelectorExpression() != expression) return null;
1276    
1277                JetExpression receiverExpression = qualifiedExpression.getReceiverExpression();
1278                generateInstructions(receiverExpression);
1279    
1280                return receiverExpression;
1281            }
1282    
1283            @Override
1284            public void visitProperty(@NotNull JetProperty property) {
1285                builder.declareVariable(property);
1286                JetExpression initializer = property.getInitializer();
1287                if (initializer != null) {
1288                    visitAssignment(property, getDeferredValue(initializer), property);
1289                }
1290                JetExpression delegate = property.getDelegateExpression();
1291                if (delegate != null) {
1292                    generateInstructions(delegate);
1293                    generateDelegateConsumer(property, delegate);
1294                }
1295    
1296                if (JetPsiUtil.isLocal(property)) {
1297                    for (JetPropertyAccessor accessor : property.getAccessors()) {
1298                        generateInstructions(accessor);
1299                    }
1300                }
1301            }
1302    
1303            private void generateDelegateConsumer(@NotNull JetProperty property, @NotNull JetExpression delegate) {
1304                DeclarationDescriptor descriptor = trace.get(BindingContext.DECLARATION_TO_DESCRIPTOR, property);
1305                if (!(descriptor instanceof PropertyDescriptor)) return;
1306    
1307                PseudoValue delegateValue = builder.getBoundValue(delegate);
1308                if (delegateValue == null) return;
1309    
1310                List<TypePredicate> typePredicates = KotlinPackage.map(
1311                        ((PropertyDescriptor) descriptor).getAccessors(),
1312                        new Function1<PropertyAccessorDescriptor, TypePredicate>() {
1313                            @Override
1314                            public TypePredicate invoke(PropertyAccessorDescriptor descriptor) {
1315                                return getTypePredicateByReceiverValue(trace.get(BindingContext.DELEGATED_PROPERTY_RESOLVED_CALL, descriptor));
1316                            }
1317                        }
1318                );
1319                Map<PseudoValue, TypePredicate> valuesToTypePredicates = SmartFMap
1320                        .<PseudoValue, TypePredicate>emptyMap()
1321                        .plus(delegateValue, PseudocodePackage.and(KotlinPackage.filterNotNull(typePredicates)));
1322                builder.magic(property, null, Collections.singletonList(delegateValue), valuesToTypePredicates, MagicKind.VALUE_CONSUMER);
1323            }
1324    
1325            private TypePredicate getTypePredicateByReceiverValue(@Nullable ResolvedCall<?> resolvedCall) {
1326                if (resolvedCall == null) return AllTypes.INSTANCE$;
1327    
1328                ReceiverValue receiverValue = getExplicitReceiverValue(resolvedCall);
1329                if (receiverValue.exists()) {
1330                    return PseudocodePackage.getReceiverTypePredicate(resolvedCall, receiverValue);
1331                }
1332    
1333                return AllTypes.INSTANCE$;
1334            }
1335    
1336            @Override
1337            public void visitMultiDeclaration(@NotNull JetMultiDeclaration declaration) {
1338                visitMultiDeclaration(declaration, true);
1339            }
1340    
1341            private void visitMultiDeclaration(@NotNull JetMultiDeclaration declaration, boolean generateWriteForEntries) {
1342                JetExpression initializer = declaration.getInitializer();
1343                generateInstructions(initializer);
1344                for (JetMultiDeclarationEntry entry : declaration.getEntries()) {
1345                    builder.declareVariable(entry);
1346    
1347                    ResolvedCall<FunctionDescriptor> resolvedCall = trace.get(BindingContext.COMPONENT_RESOLVED_CALL, entry);
1348    
1349                    PseudoValue writtenValue;
1350                    if (resolvedCall != null) {
1351                        writtenValue = builder.call(
1352                                entry,
1353                                resolvedCall,
1354                                getReceiverValues(resolvedCall),
1355                                Collections.<PseudoValue, ValueParameterDescriptor>emptyMap()
1356                        ).getOutputValue();
1357                    }
1358                    else {
1359                        List<PseudoValue> arguments = ContainerUtil.createMaybeSingletonList(getBoundOrUnreachableValue(initializer));
1360                        writtenValue = createUnresolvedCallByValues(entry, null, arguments);
1361                    }
1362    
1363                    if (generateWriteForEntries) {
1364                        generateInitializer(entry, writtenValue != null ? writtenValue : createSyntheticValue(entry, MagicKind.FAKE_INITIALIZER));
1365                    }
1366                }
1367            }
1368    
1369            @Override
1370            public void visitPropertyAccessor(@NotNull JetPropertyAccessor accessor) {
1371                processLocalDeclaration(accessor);
1372            }
1373    
1374            @Override
1375            public void visitBinaryWithTypeRHSExpression(@NotNull JetBinaryExpressionWithTypeRHS expression) {
1376                mark(expression);
1377    
1378                IElementType operationType = expression.getOperationReference().getReferencedNameElementType();
1379                JetExpression left = expression.getLeft();
1380                if (operationType == JetTokens.COLON || operationType == JetTokens.AS_KEYWORD || operationType == JetTokens.AS_SAFE) {
1381                    generateInstructions(left);
1382                    if (getBoundOrUnreachableValue(left) != null) {
1383                        createNonSyntheticValue(expression, MagicKind.CAST, left);
1384                    }
1385                }
1386                else {
1387                    visitJetElement(expression);
1388                    createNonSyntheticValue(expression, MagicKind.UNSUPPORTED_ELEMENT, left);
1389                }
1390            }
1391    
1392            @Override
1393            public void visitThrowExpression(@NotNull JetThrowExpression expression) {
1394                mark(expression);
1395    
1396                JetExpression thrownExpression = expression.getThrownExpression();
1397                if (thrownExpression == null) return;
1398    
1399                generateInstructions(thrownExpression);
1400    
1401                PseudoValue thrownValue = builder.getBoundValue(thrownExpression);
1402                if (thrownValue == null) return;
1403    
1404                builder.throwException(expression, thrownValue);
1405            }
1406    
1407            @Override
1408            public void visitArrayAccessExpression(@NotNull JetArrayAccessExpression expression) {
1409                generateArrayAccess(expression, trace.get(BindingContext.INDEXED_LVALUE_GET, expression));
1410            }
1411    
1412            @Override
1413            public void visitIsExpression(@NotNull JetIsExpression expression) {
1414                mark(expression);
1415                JetExpression left = expression.getLeftHandSide();
1416                generateInstructions(left);
1417                createNonSyntheticValue(expression, MagicKind.IS, left);
1418            }
1419    
1420            @Override
1421            public void visitWhenExpression(@NotNull JetWhenExpression expression) {
1422                mark(expression);
1423    
1424                JetExpression subjectExpression = expression.getSubjectExpression();
1425                if (subjectExpression != null) {
1426                    generateInstructions(subjectExpression);
1427                }
1428    
1429                List<JetExpression> branches = new ArrayList<JetExpression>();
1430    
1431                Label doneLabel = builder.createUnboundLabel("after 'when' expression");
1432    
1433                Label nextLabel = null;
1434                for (Iterator<JetWhenEntry> iterator = expression.getEntries().iterator(); iterator.hasNext(); ) {
1435                    JetWhenEntry whenEntry = iterator.next();
1436                    mark(whenEntry);
1437    
1438                    boolean isElse = whenEntry.isElse();
1439                    if (isElse) {
1440                        if (iterator.hasNext()) {
1441                            trace.report(ELSE_MISPLACED_IN_WHEN.on(whenEntry));
1442                        }
1443                    }
1444                    Label bodyLabel = builder.createUnboundLabel("'when' entry body");
1445    
1446                    JetWhenCondition[] conditions = whenEntry.getConditions();
1447                    for (int i = 0; i < conditions.length; i++) {
1448                        JetWhenCondition condition = conditions[i];
1449                        condition.accept(conditionVisitor);
1450                        if (i + 1 < conditions.length) {
1451                            builder.nondeterministicJump(bodyLabel, expression, builder.getBoundValue(condition));
1452                        }
1453                    }
1454    
1455                    if (!isElse) {
1456                        nextLabel = builder.createUnboundLabel("next 'when' entry");
1457                        JetWhenCondition lastCondition = KotlinPackage.lastOrNull(conditions);
1458                        builder.nondeterministicJump(nextLabel, expression, builder.getBoundValue(lastCondition));
1459                    }
1460    
1461                    builder.bindLabel(bodyLabel);
1462                    JetExpression whenEntryExpression = whenEntry.getExpression();
1463                    if (whenEntryExpression != null) {
1464                        generateInstructions(whenEntryExpression);
1465                        branches.add(whenEntryExpression);
1466                    }
1467                    builder.jump(doneLabel, expression);
1468    
1469                    if (!isElse) {
1470                        builder.bindLabel(nextLabel);
1471                        // For the last entry of exhaustive when,
1472                        // attempt to jump further should lead to error, not to "done"
1473                        if (!iterator.hasNext() && WhenChecker.isWhenExhaustive(expression, trace)) {
1474                            builder.jumpToError(expression);
1475                        }
1476                    }
1477                }
1478                builder.bindLabel(doneLabel);
1479    
1480                mergeValues(branches, expression);
1481            }
1482    
1483            @Override
1484            public void visitObjectLiteralExpression(@NotNull JetObjectLiteralExpression expression) {
1485                mark(expression);
1486                JetObjectDeclaration declaration = expression.getObjectDeclaration();
1487                generateInstructions(declaration);
1488    
1489                builder.createAnonymousObject(expression);
1490            }
1491    
1492            @Override
1493            public void visitObjectDeclaration(@NotNull JetObjectDeclaration objectDeclaration) {
1494                generateHeaderDelegationSpecifiers(objectDeclaration);
1495                generateClassOrObjectInitializers(objectDeclaration);
1496                generateDeclarationForLocalClassOrObjectIfNeeded(objectDeclaration);
1497            }
1498    
1499            @Override
1500            public void visitStringTemplateExpression(@NotNull JetStringTemplateExpression expression) {
1501                mark(expression);
1502    
1503                List<JetExpression> inputExpressions = new ArrayList<JetExpression>();
1504                for (JetStringTemplateEntry entry : expression.getEntries()) {
1505                    if (entry instanceof JetStringTemplateEntryWithExpression) {
1506                        JetExpression entryExpression = entry.getExpression();
1507                        generateInstructions(entryExpression);
1508                        inputExpressions.add(entryExpression);
1509                    }
1510                }
1511                builder.loadStringTemplate(expression, elementsToValues(inputExpressions));
1512            }
1513    
1514            @Override
1515            public void visitTypeProjection(@NotNull JetTypeProjection typeProjection) {
1516                // TODO : Support Type Arguments. Companion object may be initialized at this point");
1517            }
1518    
1519            @Override
1520            public void visitAnonymousInitializer(@NotNull JetClassInitializer classInitializer) {
1521                generateInstructions(classInitializer.getBody());
1522            }
1523    
1524            private void generateHeaderDelegationSpecifiers(@NotNull JetClassOrObject classOrObject) {
1525                for (JetDelegationSpecifier specifier : classOrObject.getDelegationSpecifiers()) {
1526                    generateInstructions(specifier);
1527                }
1528            }
1529    
1530            private void generateClassOrObjectInitializers(@NotNull JetClassOrObject classOrObject) {
1531                for (JetDeclaration declaration : classOrObject.getDeclarations()) {
1532                    if (declaration instanceof JetProperty || declaration instanceof JetClassInitializer) {
1533                        generateInstructions(declaration);
1534                    }
1535                }
1536            }
1537    
1538            @Override
1539            public void visitClass(@NotNull JetClass klass) {
1540                if (klass.hasPrimaryConstructor()) {
1541                    processParameters(klass.getPrimaryConstructorParameters());
1542    
1543                    // delegation specifiers of primary constructor, anonymous class and property initializers
1544                    generateHeaderDelegationSpecifiers(klass);
1545                    generateClassOrObjectInitializers(klass);
1546                }
1547    
1548                generateDeclarationForLocalClassOrObjectIfNeeded(klass);
1549            }
1550    
1551            private void generateDeclarationForLocalClassOrObjectIfNeeded(@NotNull JetClassOrObject classOrObject) {
1552                if (classOrObject.isLocal()) {
1553                    for (JetDeclaration declaration : classOrObject.getDeclarations()) {
1554                        if (declaration instanceof JetSecondaryConstructor ||
1555                            declaration instanceof JetProperty ||
1556                            declaration instanceof JetClassInitializer) {
1557                            continue;
1558                        }
1559                        generateInstructions(declaration);
1560                    }
1561                }
1562            }
1563    
1564            private void processParameters(@NotNull List<JetParameter> parameters) {
1565                for (JetParameter parameter : parameters) {
1566                    generateInstructions(parameter);
1567                }
1568            }
1569    
1570            @Override
1571            public void visitSecondaryConstructor(@NotNull JetSecondaryConstructor constructor) {
1572                JetClassOrObject classOrObject = PsiTreeUtil.getParentOfType(constructor, JetClassOrObject.class);
1573                assert classOrObject != null : "Guaranteed by parsing contract";
1574    
1575                processParameters(constructor.getValueParameters());
1576                generateCallOrMarkUnresolved(constructor.getDelegationCall());
1577    
1578                if (!constructor.getDelegationCall().isCallToThis()) {
1579                    generateClassOrObjectInitializers(classOrObject);
1580                }
1581    
1582                generateInstructions(constructor.getBodyExpression());
1583            }
1584    
1585            @Override
1586            public void visitDelegationToSuperCallSpecifier(@NotNull JetDelegatorToSuperCall call) {
1587                generateCallOrMarkUnresolved(call);
1588            }
1589    
1590            private void generateCallOrMarkUnresolved(@Nullable JetCallElement call) {
1591                if (call == null) return;
1592                if (!generateCall(call)) {
1593                    List<JetExpression> arguments = KotlinPackage.map(
1594                            call.getValueArguments(),
1595                            new Function1<ValueArgument, JetExpression>() {
1596                                @Override
1597                                public JetExpression invoke(ValueArgument valueArgument) {
1598                                    return valueArgument.getArgumentExpression();
1599                                }
1600                            }
1601                    );
1602    
1603                    for (JetExpression argument : arguments) {
1604                        generateInstructions(argument);
1605                    }
1606                    createUnresolvedCall(call, arguments);
1607                }
1608            }
1609    
1610            @Override
1611            public void visitDelegationByExpressionSpecifier(@NotNull JetDelegatorByExpressionSpecifier specifier) {
1612                generateInstructions(specifier.getDelegateExpression());
1613    
1614                List<PseudoValue> arguments = ContainerUtil.createMaybeSingletonList(builder.getBoundValue(specifier.getDelegateExpression()));
1615                JetType jetType = trace.get(BindingContext.TYPE, specifier.getTypeReference());
1616                TypePredicate expectedTypePredicate = jetType != null ? PseudocodePackage.getSubtypesPredicate(jetType) : AllTypes.INSTANCE$;
1617                builder.magic(specifier, null, arguments, PseudocodePackage.expectedTypeFor(expectedTypePredicate, arguments),
1618                              MagicKind.VALUE_CONSUMER);
1619            }
1620    
1621            @Override
1622            public void visitDelegationToSuperClassSpecifier(@NotNull JetDelegatorToSuperClass specifier) {
1623                // Do not generate UNSUPPORTED_ELEMENT here
1624            }
1625    
1626            @Override
1627            public void visitDelegationSpecifierList(@NotNull JetDelegationSpecifierList list) {
1628                list.acceptChildren(this);
1629            }
1630    
1631            @Override
1632            public void visitJetFile(@NotNull JetFile file) {
1633                for (JetDeclaration declaration : file.getDeclarations()) {
1634                    if (declaration instanceof JetProperty) {
1635                        generateInstructions(declaration);
1636                    }
1637                }
1638            }
1639    
1640            @Override
1641            public void visitDoubleColonExpression(@NotNull JetDoubleColonExpression expression) {
1642                mark(expression);
1643                createNonSyntheticValue(expression, MagicKind.CALLABLE_REFERENCE);
1644            }
1645    
1646            @Override
1647            public void visitJetElement(@NotNull JetElement element) {
1648                createNonSyntheticValue(element, MagicKind.UNSUPPORTED_ELEMENT);
1649            }
1650    
1651            private boolean generateCall(@Nullable JetElement callElement) {
1652                if (callElement == null) return false;
1653                return checkAndGenerateCall(getResolvedCall(callElement, trace.getBindingContext()));
1654            }
1655    
1656            private boolean checkAndGenerateCall(@Nullable ResolvedCall<?> resolvedCall) {
1657                if (resolvedCall == null) return false;
1658                generateCall(resolvedCall);
1659                return true;
1660            }
1661    
1662            @NotNull
1663            private InstructionWithValue generateCall(@NotNull ResolvedCall<?> resolvedCall) {
1664                JetElement callElement = resolvedCall.getCall().getCallElement();
1665    
1666                Map<PseudoValue, ReceiverValue> receivers = getReceiverValues(resolvedCall);
1667    
1668                SmartFMap<PseudoValue, ValueParameterDescriptor> parameterValues = SmartFMap.emptyMap();
1669                for (ValueArgument argument : resolvedCall.getCall().getValueArguments()) {
1670                    ArgumentMapping argumentMapping = resolvedCall.getArgumentMapping(argument);
1671                    JetExpression argumentExpression = argument.getArgumentExpression();
1672                    if (argumentMapping instanceof ArgumentMatch) {
1673                        parameterValues = generateValueArgument(argument, ((ArgumentMatch) argumentMapping).getValueParameter(), parameterValues);
1674                    }
1675                    else if (argumentExpression != null) {
1676                        generateInstructions(argumentExpression);
1677                        createSyntheticValue(argumentExpression, MagicKind.VALUE_CONSUMER, argumentExpression);
1678                    }
1679                }
1680    
1681                if (resolvedCall.getResultingDescriptor() instanceof VariableDescriptor) {
1682                    // If a callee of the call is just a variable (without 'invoke'), 'read variable' is generated.
1683                    // todo : process arguments for such a case (KT-5387)
1684                    JetExpression callExpression = callElement instanceof JetExpression ? (JetExpression) callElement : null;
1685                    assert callExpression != null
1686                            : "Variable-based call without callee expression: " + callElement.getText();
1687                    assert parameterValues.isEmpty()
1688                            : "Variable-based call with non-empty argument list: " + callElement.getText();
1689                    return builder.readVariable(callExpression, resolvedCall, receivers);
1690                }
1691    
1692                mark(resolvedCall.getCall().getCallElement());
1693                return builder.call(callElement, resolvedCall, receivers, parameterValues);
1694            }
1695    
1696            @NotNull
1697            private Map<PseudoValue, ReceiverValue> getReceiverValues(ResolvedCall<?> resolvedCall) {
1698                PseudoValue varCallResult = null;
1699                ReceiverValue explicitReceiver = ReceiverValue.NO_RECEIVER;
1700                if (resolvedCall instanceof VariableAsFunctionResolvedCall) {
1701                    varCallResult = generateCall(((VariableAsFunctionResolvedCall) resolvedCall).getVariableCall()).getOutputValue();
1702    
1703                    ExplicitReceiverKind kind = resolvedCall.getExplicitReceiverKind();
1704                    //noinspection EnumSwitchStatementWhichMissesCases
1705                    switch (kind) {
1706                        case DISPATCH_RECEIVER:
1707                            explicitReceiver = resolvedCall.getDispatchReceiver();
1708                            break;
1709                        case EXTENSION_RECEIVER:
1710                        case BOTH_RECEIVERS:
1711                            explicitReceiver = resolvedCall.getExtensionReceiver();
1712                            break;
1713                    }
1714                }
1715    
1716                SmartFMap<PseudoValue, ReceiverValue> receiverValues = SmartFMap.emptyMap();
1717                if (explicitReceiver.exists() && varCallResult != null) {
1718                    receiverValues = receiverValues.plus(varCallResult, explicitReceiver);
1719                }
1720                JetElement callElement = resolvedCall.getCall().getCallElement();
1721                receiverValues = getReceiverValues(callElement, resolvedCall.getDispatchReceiver(), receiverValues);
1722                receiverValues = getReceiverValues(callElement, resolvedCall.getExtensionReceiver(), receiverValues);
1723                return receiverValues;
1724            }
1725    
1726            @NotNull
1727            private SmartFMap<PseudoValue, ReceiverValue> getReceiverValues(
1728                    JetElement callElement,
1729                    ReceiverValue receiver,
1730                    SmartFMap<PseudoValue, ReceiverValue> receiverValues
1731            ) {
1732                if (!receiver.exists() || receiverValues.containsValue(receiver)) return receiverValues;
1733    
1734                if (receiver instanceof ThisReceiver) {
1735                    receiverValues = receiverValues.plus(createSyntheticValue(callElement, MagicKind.IMPLICIT_RECEIVER), receiver);
1736                }
1737                else if (receiver instanceof ExpressionReceiver) {
1738                    JetExpression expression = ((ExpressionReceiver) receiver).getExpression();
1739                    if (builder.getBoundValue(expression) == null) {
1740                        generateInstructions(expression);
1741                    }
1742    
1743                    PseudoValue receiverPseudoValue = getBoundOrUnreachableValue(expression);
1744                    if (receiverPseudoValue != null) {
1745                        receiverValues = receiverValues.plus(receiverPseudoValue, receiver);
1746                    }
1747                }
1748                else if (receiver instanceof TransientReceiver) {
1749                    // Do nothing
1750                }
1751                else {
1752                    throw new IllegalArgumentException("Unknown receiver kind: " + receiver);
1753                }
1754    
1755                return receiverValues;
1756            }
1757    
1758            @NotNull
1759            private SmartFMap<PseudoValue, ValueParameterDescriptor> generateValueArgument(
1760                    ValueArgument valueArgument,
1761                    ValueParameterDescriptor parameterDescriptor,
1762                    SmartFMap<PseudoValue, ValueParameterDescriptor> parameterValues) {
1763                JetExpression expression = valueArgument.getArgumentExpression();
1764                if (expression != null) {
1765                    if (!valueArgument.isExternal()) {
1766                        generateInstructions(expression);
1767                    }
1768    
1769                    PseudoValue argValue = getBoundOrUnreachableValue(expression);
1770                    if (argValue != null) {
1771                        parameterValues = parameterValues.plus(argValue, parameterDescriptor);
1772                    }
1773                }
1774                return parameterValues;
1775            }
1776        }
1777    }