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