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.collections.ArraysKt;
026    import kotlin.collections.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.ControlFlowInstructionsGenerator;
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.KtPsiUtilKt;
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.ImplicitReceiver;
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.ControlFlowBuilder.PredefinedOperation.*;
065    import static org.jetbrains.kotlin.diagnostics.Errors.*;
066    import static org.jetbrains.kotlin.lexer.KtTokens.*;
067    
068    public class ControlFlowProcessor {
069    
070        private final ControlFlowBuilder builder;
071        private final BindingTrace trace;
072    
073        public ControlFlowProcessor(BindingTrace trace) {
074            this.builder = new ControlFlowInstructionsGenerator();
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 ControlFlowBuilder 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 visitKtElement(@NotNull KtElement element) {
173                    throw new UnsupportedOperationException("[ControlFlowProcessor] " + element.toString());
174                }
175            };
176    
177            private CFPVisitor(@NotNull ControlFlowBuilder 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                ControlFlowBuilder.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(KtPsiUtilKt.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                if (!CompileTimeConstantUtils.canBeReducedToBooleanConstant(condition, trace.getBindingContext(), true)) {
806                    builder.jumpOnFalse(loopInfo.getExitPoint(), expression, builder.getBoundValue(condition));
807                }
808                else {
809                    assert condition != null : "Invalid while condition: " + expression.getText();
810                    createSyntheticValue(condition, MagicKind.VALUE_CONSUMER, condition);
811                }
812    
813                builder.enterLoopBody(expression);
814                KtExpression body = expression.getBody();
815                if (body != null) {
816                    generateInstructions(body);
817                }
818                builder.jump(loopInfo.getEntryPoint(), expression);
819                builder.exitLoopBody(expression);
820                builder.bindLabel(loopInfo.getExitPoint());
821                builder.loadUnit(expression);
822            }
823    
824            @Override
825            public void visitDoWhileExpression(@NotNull KtDoWhileExpression expression) {
826                builder.enterLexicalScope(expression);
827                mark(expression);
828                LoopInfo loopInfo = builder.enterLoop(expression);
829    
830                builder.enterLoopBody(expression);
831                KtExpression body = expression.getBody();
832                if (body != null) {
833                    generateInstructions(body);
834                }
835                builder.exitLoopBody(expression);
836                builder.bindLabel(loopInfo.getConditionEntryPoint());
837                KtExpression condition = expression.getCondition();
838                if (condition != null) {
839                    generateInstructions(condition);
840                }
841                builder.jumpOnTrue(loopInfo.getEntryPoint(), expression, builder.getBoundValue(condition));
842                builder.bindLabel(loopInfo.getExitPoint());
843                builder.loadUnit(expression);
844                builder.exitLexicalScope(expression);
845            }
846    
847            @Override
848            public void visitForExpression(@NotNull KtForExpression expression) {
849                builder.enterLexicalScope(expression);
850    
851                KtExpression loopRange = expression.getLoopRange();
852                if (loopRange != null) {
853                    generateInstructions(loopRange);
854                }
855                declareLoopParameter(expression);
856    
857                // TODO : primitive cases
858                LoopInfo loopInfo = builder.enterLoop(expression);
859    
860                builder.bindLabel(loopInfo.getConditionEntryPoint());
861                builder.nondeterministicJump(loopInfo.getExitPoint(), expression, null);
862    
863    
864                writeLoopParameterAssignment(expression);
865    
866                mark(expression);
867                builder.enterLoopBody(expression);
868                KtExpression body = expression.getBody();
869                if (body != null) {
870                    generateInstructions(body);
871                }
872                builder.jump(loopInfo.getEntryPoint(), expression);
873    
874                builder.exitLoopBody(expression);
875                builder.bindLabel(loopInfo.getExitPoint());
876                builder.loadUnit(expression);
877                builder.exitLexicalScope(expression);
878            }
879    
880            private void declareLoopParameter(KtForExpression expression) {
881                KtParameter loopParameter = expression.getLoopParameter();
882                KtDestructuringDeclaration multiDeclaration = expression.getDestructuringParameter();
883                if (loopParameter != null) {
884                    builder.declareParameter(loopParameter);
885                }
886                else if (multiDeclaration != null) {
887                    visitDestructuringDeclaration(multiDeclaration, false);
888                }
889            }
890    
891            private void writeLoopParameterAssignment(KtForExpression expression) {
892                KtParameter loopParameter = expression.getLoopParameter();
893                KtDestructuringDeclaration multiDeclaration = expression.getDestructuringParameter();
894                KtExpression loopRange = expression.getLoopRange();
895    
896                PseudoValue value = builder.magic(
897                        loopRange != null ? loopRange : expression,
898                        null,
899                        ContainerUtil.createMaybeSingletonList(builder.getBoundValue(loopRange)),
900                        MagicKind.LOOP_RANGE_ITERATION
901                ).getOutputValue();
902    
903                if (loopParameter != null) {
904                    generateInitializer(loopParameter, value);
905                }
906                else if (multiDeclaration != null) {
907                    for (KtDestructuringDeclarationEntry entry : multiDeclaration.getEntries()) {
908                        generateInitializer(entry, value);
909                    }
910                }
911            }
912    
913            @Override
914            public void visitBreakExpression(@NotNull KtBreakExpression expression) {
915                KtElement loop = getCorrespondingLoop(expression);
916                if (loop != null) {
917                    checkJumpDoesNotCrossFunctionBoundary(expression, loop);
918                    builder.jump(builder.getExitPoint(loop), expression);
919                }
920            }
921    
922            @Override
923            public void visitContinueExpression(@NotNull KtContinueExpression expression) {
924                KtElement loop = getCorrespondingLoop(expression);
925                if (loop != null) {
926                    checkJumpDoesNotCrossFunctionBoundary(expression, loop);
927                    builder.jump(builder.getConditionEntryPoint(loop), expression);
928                }
929            }
930    
931            @Nullable
932            private KtElement getCorrespondingLoop(KtExpressionWithLabel expression) {
933                String labelName = expression.getLabelName();
934                KtLoopExpression loop;
935                if (labelName != null) {
936                    KtSimpleNameExpression targetLabel = expression.getTargetLabel();
937                    assert targetLabel != null;
938                    PsiElement labeledElement = trace.get(BindingContext.LABEL_TARGET, targetLabel);
939                    if (labeledElement instanceof KtLoopExpression) {
940                        loop = (KtLoopExpression) labeledElement;
941                    }
942                    else {
943                        trace.report(NOT_A_LOOP_LABEL.on(expression, targetLabel.getText()));
944                        loop = null;
945                    }
946                }
947                else {
948                    loop = builder.getCurrentLoop();
949                    if (loop == null) {
950                        trace.report(BREAK_OR_CONTINUE_OUTSIDE_A_LOOP.on(expression));
951                    } else {
952                        KtWhenExpression whenExpression = PsiTreeUtil.getParentOfType(expression, KtWhenExpression.class, true,
953                                                                                      KtLoopExpression.class);
954                        if (whenExpression != null) {
955                            trace.report(BREAK_OR_CONTINUE_IN_WHEN.on(expression));
956                        }
957                    }
958                }
959                if (loop != null && loop.getBody() != null
960                        // the faster version of 'isAncestor' check:
961                        && !loop.getBody().getTextRange().contains(expression.getTextRange())) {
962                    trace.report(BREAK_OR_CONTINUE_OUTSIDE_A_LOOP.on(expression));
963                    return null;
964                }
965                return loop;
966            }
967    
968            private void checkJumpDoesNotCrossFunctionBoundary(@NotNull KtExpressionWithLabel jumpExpression, @NotNull KtElement jumpTarget) {
969                BindingContext bindingContext = trace.getBindingContext();
970    
971                FunctionDescriptor labelExprEnclosingFunc = BindingContextUtils.getEnclosingFunctionDescriptor(bindingContext, jumpExpression);
972                FunctionDescriptor labelTargetEnclosingFunc = BindingContextUtils.getEnclosingFunctionDescriptor(bindingContext, jumpTarget);
973                if (labelExprEnclosingFunc != labelTargetEnclosingFunc) {
974                    trace.report(BREAK_OR_CONTINUE_JUMPS_ACROSS_FUNCTION_BOUNDARY.on(jumpExpression));
975                }
976            }
977    
978            @Override
979            public void visitReturnExpression(@NotNull KtReturnExpression expression) {
980                KtExpression returnedExpression = expression.getReturnedExpression();
981                if (returnedExpression != null) {
982                    generateInstructions(returnedExpression);
983                }
984                KtSimpleNameExpression labelElement = expression.getTargetLabel();
985                KtElement subroutine;
986                String labelName = expression.getLabelName();
987                if (labelElement != null && labelName != null) {
988                    PsiElement labeledElement = trace.get(BindingContext.LABEL_TARGET, labelElement);
989                    if (labeledElement != null) {
990                        assert labeledElement instanceof KtElement;
991                        subroutine = (KtElement) labeledElement;
992                    }
993                    else {
994                        subroutine = null;
995                    }
996                }
997                else {
998                    subroutine = builder.getReturnSubroutine();
999                    // TODO : a context check
1000                }
1001    
1002                if (subroutine instanceof KtFunction || subroutine instanceof KtPropertyAccessor) {
1003                    PseudoValue returnValue = returnedExpression != null ? builder.getBoundValue(returnedExpression) : null;
1004                    if (returnValue == null) {
1005                        builder.returnNoValue(expression, subroutine);
1006                    }
1007                    else {
1008                        builder.returnValue(expression, returnValue, subroutine);
1009                    }
1010                }
1011                else {
1012                    createNonSyntheticValue(expression, MagicKind.UNSUPPORTED_ELEMENT, returnedExpression);
1013                }
1014            }
1015    
1016            @Override
1017            public void visitParameter(@NotNull KtParameter parameter) {
1018                builder.declareParameter(parameter);
1019                KtExpression defaultValue = parameter.getDefaultValue();
1020                if (defaultValue != null) {
1021                    Label skipDefaultValue = builder.createUnboundLabel("after default value for parameter " + parameter.getName());
1022                    builder.nondeterministicJump(skipDefaultValue, defaultValue, null);
1023                    generateInstructions(defaultValue);
1024                    builder.bindLabel(skipDefaultValue);
1025                }
1026                generateInitializer(parameter, computePseudoValueForParameter(parameter));
1027            }
1028    
1029            @NotNull
1030            private PseudoValue computePseudoValueForParameter(@NotNull KtParameter parameter) {
1031                PseudoValue syntheticValue = createSyntheticValue(parameter, MagicKind.FAKE_INITIALIZER);
1032                PseudoValue defaultValue = builder.getBoundValue(parameter.getDefaultValue());
1033                if (defaultValue == null) {
1034                    return syntheticValue;
1035                }
1036                return builder.merge(parameter, Lists.newArrayList(defaultValue, syntheticValue)).getOutputValue();
1037            }
1038    
1039            @Override
1040            public void visitBlockExpression(@NotNull KtBlockExpression expression) {
1041                boolean declareLexicalScope = !isBlockInDoWhile(expression);
1042                if (declareLexicalScope) {
1043                    builder.enterLexicalScope(expression);
1044                }
1045                mark(expression);
1046                List<KtExpression> statements = expression.getStatements();
1047                for (KtExpression statement : statements) {
1048                    generateInstructions(statement);
1049                }
1050                if (statements.isEmpty()) {
1051                    builder.loadUnit(expression);
1052                }
1053                else {
1054                    copyValue(CollectionsKt.lastOrNull(statements), expression);
1055                }
1056                if (declareLexicalScope) {
1057                    builder.exitLexicalScope(expression);
1058                }
1059            }
1060    
1061            private boolean isBlockInDoWhile(@NotNull KtBlockExpression expression) {
1062                PsiElement parent = expression.getParent();
1063                if (parent == null) return false;
1064                return parent.getParent() instanceof KtDoWhileExpression;
1065            }
1066    
1067            private void visitFunction(@NotNull KtFunction function) {
1068                processLocalDeclaration(function);
1069                boolean isAnonymousFunction = function instanceof KtFunctionLiteral || function.getName() == null;
1070                if (isAnonymousFunction || (function.isLocal() && !(function.getParent() instanceof KtBlockExpression))) {
1071                    builder.createLambda(function);
1072                }
1073            }
1074    
1075            @Override
1076            public void visitNamedFunction(@NotNull KtNamedFunction function) {
1077                visitFunction(function);
1078            }
1079    
1080            @Override
1081            public void visitLambdaExpression(@NotNull KtLambdaExpression lambdaExpression) {
1082                mark(lambdaExpression);
1083                KtFunctionLiteral functionLiteral = lambdaExpression.getFunctionLiteral();
1084                visitFunction(functionLiteral);
1085                copyValue(functionLiteral, lambdaExpression);
1086            }
1087    
1088            @Override
1089            public void visitQualifiedExpression(@NotNull KtQualifiedExpression expression) {
1090                mark(expression);
1091                KtExpression selectorExpression = expression.getSelectorExpression();
1092                KtExpression receiverExpression = expression.getReceiverExpression();
1093    
1094                // todo: replace with selectorExpresion != null after parser is fixed
1095                if (selectorExpression instanceof KtCallExpression || selectorExpression instanceof KtSimpleNameExpression) {
1096                    generateInstructions(selectorExpression);
1097                    copyValue(selectorExpression, expression);
1098                }
1099                else {
1100                    generateInstructions(receiverExpression);
1101                    createNonSyntheticValue(expression, MagicKind.UNSUPPORTED_ELEMENT, receiverExpression);
1102                }
1103            }
1104    
1105            @Override
1106            public void visitCallExpression(@NotNull KtCallExpression expression) {
1107                if (!generateCall(expression)) {
1108                    List<KtExpression> inputExpressions = new ArrayList<KtExpression>();
1109                    for (ValueArgument argument : expression.getValueArguments()) {
1110                        KtExpression argumentExpression = argument.getArgumentExpression();
1111                        if (argumentExpression != null) {
1112                            generateInstructions(argumentExpression);
1113                            inputExpressions.add(argumentExpression);
1114                        }
1115                    }
1116                    KtExpression calleeExpression = expression.getCalleeExpression();
1117                    generateInstructions(calleeExpression);
1118                    inputExpressions.add(calleeExpression);
1119                    inputExpressions.add(generateAndGetReceiverIfAny(expression));
1120    
1121                    mark(expression);
1122                    createNonSyntheticValue(expression, inputExpressions, MagicKind.UNRESOLVED_CALL);
1123                }
1124            }
1125    
1126            @Nullable
1127            private KtExpression generateAndGetReceiverIfAny(KtExpression expression) {
1128                PsiElement parent = expression.getParent();
1129                if (!(parent instanceof KtQualifiedExpression)) return null;
1130    
1131                KtQualifiedExpression qualifiedExpression = (KtQualifiedExpression) parent;
1132                if (qualifiedExpression.getSelectorExpression() != expression) return null;
1133    
1134                KtExpression receiverExpression = qualifiedExpression.getReceiverExpression();
1135                generateInstructions(receiverExpression);
1136    
1137                return receiverExpression;
1138            }
1139    
1140            @Override
1141            public void visitProperty(@NotNull KtProperty property) {
1142                builder.declareVariable(property);
1143                KtExpression initializer = property.getInitializer();
1144                if (initializer != null) {
1145                    visitAssignment(property, getDeferredValue(initializer), property);
1146                }
1147                KtExpression delegate = property.getDelegateExpression();
1148                if (delegate != null) {
1149                    // We do not want to have getDeferredValue(delegate) here, because delegate value will be read anyway later
1150                    visitAssignment(property, getDeferredValue(null), property);
1151                    generateInstructions(delegate);
1152                    if (builder.getBoundValue(delegate) != null) {
1153                        createSyntheticValue(property, MagicKind.VALUE_CONSUMER, delegate);
1154                    }
1155                }
1156    
1157                if (KtPsiUtil.isLocal(property)) {
1158                    for (KtPropertyAccessor accessor : property.getAccessors()) {
1159                        generateInstructions(accessor);
1160                    }
1161                }
1162            }
1163    
1164            @Override
1165            public void visitDestructuringDeclaration(@NotNull KtDestructuringDeclaration declaration) {
1166                visitDestructuringDeclaration(declaration, true);
1167            }
1168    
1169            private void visitDestructuringDeclaration(@NotNull KtDestructuringDeclaration declaration, boolean generateWriteForEntries) {
1170                KtExpression initializer = declaration.getInitializer();
1171                generateInstructions(initializer);
1172                for (KtDestructuringDeclarationEntry entry : declaration.getEntries()) {
1173                    builder.declareVariable(entry);
1174    
1175                    ResolvedCall<FunctionDescriptor> resolvedCall = trace.get(BindingContext.COMPONENT_RESOLVED_CALL, entry);
1176    
1177                    PseudoValue writtenValue;
1178                    if (resolvedCall != null) {
1179                        writtenValue = builder.call(
1180                                entry,
1181                                resolvedCall,
1182                                getReceiverValues(resolvedCall),
1183                                Collections.<PseudoValue, ValueParameterDescriptor>emptyMap()
1184                        ).getOutputValue();
1185                    }
1186                    else {
1187                        writtenValue = createSyntheticValue(entry, MagicKind.UNRESOLVED_CALL, initializer);
1188                    }
1189    
1190                    if (generateWriteForEntries) {
1191                        generateInitializer(entry, writtenValue != null ? writtenValue : createSyntheticValue(entry, MagicKind.FAKE_INITIALIZER));
1192                    }
1193                }
1194            }
1195    
1196            @Override
1197            public void visitPropertyAccessor(@NotNull KtPropertyAccessor accessor) {
1198                processLocalDeclaration(accessor);
1199            }
1200    
1201            @Override
1202            public void visitBinaryWithTypeRHSExpression(@NotNull KtBinaryExpressionWithTypeRHS expression) {
1203                mark(expression);
1204    
1205                IElementType operationType = expression.getOperationReference().getReferencedNameElementType();
1206                KtExpression left = expression.getLeft();
1207                if (operationType == KtTokens.AS_KEYWORD || operationType == KtTokens.AS_SAFE) {
1208                    generateInstructions(left);
1209                    if (getBoundOrUnreachableValue(left) != null) {
1210                        createNonSyntheticValue(expression, MagicKind.CAST, left);
1211                    }
1212                }
1213                else {
1214                    visitKtElement(expression);
1215                    createNonSyntheticValue(expression, MagicKind.UNSUPPORTED_ELEMENT, left);
1216                }
1217            }
1218    
1219            @Override
1220            public void visitThrowExpression(@NotNull KtThrowExpression expression) {
1221                mark(expression);
1222    
1223                KtExpression thrownExpression = expression.getThrownExpression();
1224                if (thrownExpression == null) return;
1225    
1226                generateInstructions(thrownExpression);
1227    
1228                PseudoValue thrownValue = builder.getBoundValue(thrownExpression);
1229                if (thrownValue == null) return;
1230    
1231                builder.throwException(expression, thrownValue);
1232            }
1233    
1234            @Override
1235            public void visitArrayAccessExpression(@NotNull KtArrayAccessExpression expression) {
1236                generateArrayAccess(expression, trace.get(BindingContext.INDEXED_LVALUE_GET, expression));
1237            }
1238    
1239            @Override
1240            public void visitIsExpression(@NotNull KtIsExpression expression) {
1241                mark(expression);
1242                KtExpression left = expression.getLeftHandSide();
1243                generateInstructions(left);
1244                createNonSyntheticValue(expression, MagicKind.IS, left);
1245            }
1246    
1247            @Override
1248            public void visitWhenExpression(@NotNull KtWhenExpression expression) {
1249                mark(expression);
1250    
1251                KtExpression subjectExpression = expression.getSubjectExpression();
1252                if (subjectExpression != null) {
1253                    generateInstructions(subjectExpression);
1254                }
1255    
1256                List<KtExpression> branches = new ArrayList<KtExpression>();
1257    
1258                Label doneLabel = builder.createUnboundLabel("after 'when' expression");
1259    
1260                Label nextLabel = null;
1261                for (Iterator<KtWhenEntry> iterator = expression.getEntries().iterator(); iterator.hasNext(); ) {
1262                    KtWhenEntry whenEntry = iterator.next();
1263                    mark(whenEntry);
1264    
1265                    boolean isElse = whenEntry.isElse();
1266                    if (isElse) {
1267                        if (iterator.hasNext()) {
1268                            trace.report(ELSE_MISPLACED_IN_WHEN.on(whenEntry));
1269                        }
1270                    }
1271                    Label bodyLabel = builder.createUnboundLabel("'when' entry body");
1272    
1273                    KtWhenCondition[] conditions = whenEntry.getConditions();
1274                    for (int i = 0; i < conditions.length; i++) {
1275                        KtWhenCondition condition = conditions[i];
1276                        condition.accept(conditionVisitor);
1277                        if (i + 1 < conditions.length) {
1278                            builder.nondeterministicJump(bodyLabel, expression, builder.getBoundValue(condition));
1279                        }
1280                    }
1281    
1282                    if (!isElse) {
1283                        nextLabel = builder.createUnboundLabel("next 'when' entry");
1284                        KtWhenCondition lastCondition = ArraysKt.lastOrNull(conditions);
1285                        builder.nondeterministicJump(nextLabel, expression, builder.getBoundValue(lastCondition));
1286                    }
1287    
1288                    builder.bindLabel(bodyLabel);
1289                    KtExpression whenEntryExpression = whenEntry.getExpression();
1290                    if (whenEntryExpression != null) {
1291                        generateInstructions(whenEntryExpression);
1292                        branches.add(whenEntryExpression);
1293                    }
1294                    builder.jump(doneLabel, expression);
1295    
1296                    if (!isElse) {
1297                        builder.bindLabel(nextLabel);
1298                        // For the last entry of exhaustive when,
1299                        // attempt to jump further should lead to error, not to "done"
1300                        if (!iterator.hasNext() && WhenChecker.isWhenExhaustive(expression, trace)) {
1301                            builder.magic(expression, null, Collections.<PseudoValue>emptyList(), MagicKind.EXHAUSTIVE_WHEN_ELSE);
1302                        }
1303                    }
1304                }
1305                builder.bindLabel(doneLabel);
1306    
1307                mergeValues(branches, expression);
1308            }
1309    
1310            @Override
1311            public void visitObjectLiteralExpression(@NotNull KtObjectLiteralExpression expression) {
1312                mark(expression);
1313                KtObjectDeclaration declaration = expression.getObjectDeclaration();
1314                generateInstructions(declaration);
1315    
1316                builder.createAnonymousObject(expression);
1317            }
1318    
1319            @Override
1320            public void visitObjectDeclaration(@NotNull KtObjectDeclaration objectDeclaration) {
1321                generateHeaderDelegationSpecifiers(objectDeclaration);
1322                generateInitializersForScriptClassOrObject(objectDeclaration);
1323                generateDeclarationForLocalClassOrObjectIfNeeded(objectDeclaration);
1324            }
1325    
1326            @Override
1327            public void visitStringTemplateExpression(@NotNull KtStringTemplateExpression expression) {
1328                mark(expression);
1329    
1330                List<KtExpression> inputExpressions = new ArrayList<KtExpression>();
1331                for (KtStringTemplateEntry entry : expression.getEntries()) {
1332                    if (entry instanceof KtStringTemplateEntryWithExpression) {
1333                        KtExpression entryExpression = entry.getExpression();
1334                        generateInstructions(entryExpression);
1335                        inputExpressions.add(entryExpression);
1336                    }
1337                }
1338                builder.loadStringTemplate(expression, elementsToValues(inputExpressions));
1339            }
1340    
1341            @Override
1342            public void visitTypeProjection(@NotNull KtTypeProjection typeProjection) {
1343                // TODO : Support Type Arguments. Companion object may be initialized at this point");
1344            }
1345    
1346            @Override
1347            public void visitAnonymousInitializer(@NotNull KtAnonymousInitializer classInitializer) {
1348                generateInstructions(classInitializer.getBody());
1349            }
1350    
1351            private void generateHeaderDelegationSpecifiers(@NotNull KtClassOrObject classOrObject) {
1352                for (KtSuperTypeListEntry specifier : classOrObject.getSuperTypeListEntries()) {
1353                    generateInstructions(specifier);
1354                }
1355            }
1356    
1357            private void generateInitializersForScriptClassOrObject(@NotNull KtDeclarationContainer classOrObject) {
1358                for (KtDeclaration declaration : classOrObject.getDeclarations()) {
1359                    if (declaration instanceof KtProperty || declaration instanceof KtAnonymousInitializer) {
1360                        generateInstructions(declaration);
1361                    }
1362                }
1363            }
1364    
1365            @Override
1366            public void visitClass(@NotNull KtClass klass) {
1367                if (klass.hasPrimaryConstructor()) {
1368                    processParameters(klass.getPrimaryConstructorParameters());
1369    
1370                    // delegation specifiers of primary constructor, anonymous class and property initializers
1371                    generateHeaderDelegationSpecifiers(klass);
1372                    generateInitializersForScriptClassOrObject(klass);
1373                }
1374    
1375                generateDeclarationForLocalClassOrObjectIfNeeded(klass);
1376            }
1377    
1378            @Override
1379            public void visitScript(@NotNull KtScript script) {
1380                generateInitializersForScriptClassOrObject(script);
1381            }
1382    
1383            private void generateDeclarationForLocalClassOrObjectIfNeeded(@NotNull KtClassOrObject classOrObject) {
1384                if (classOrObject.isLocal()) {
1385                    for (KtDeclaration declaration : classOrObject.getDeclarations()) {
1386                        if (declaration instanceof KtSecondaryConstructor ||
1387                            declaration instanceof KtProperty ||
1388                            declaration instanceof KtAnonymousInitializer) {
1389                            continue;
1390                        }
1391                        generateInstructions(declaration);
1392                    }
1393                }
1394            }
1395    
1396            private void processParameters(@NotNull List<KtParameter> parameters) {
1397                for (KtParameter parameter : parameters) {
1398                    generateInstructions(parameter);
1399                }
1400            }
1401    
1402            @Override
1403            public void visitSecondaryConstructor(@NotNull KtSecondaryConstructor constructor) {
1404                KtClassOrObject classOrObject = PsiTreeUtil.getParentOfType(constructor, KtClassOrObject.class);
1405                assert classOrObject != null : "Guaranteed by parsing contract";
1406    
1407                processParameters(constructor.getValueParameters());
1408                generateCallOrMarkUnresolved(constructor.getDelegationCall());
1409    
1410                if (!constructor.getDelegationCall().isCallToThis()) {
1411                    generateInitializersForScriptClassOrObject(classOrObject);
1412                }
1413    
1414                generateInstructions(constructor.getBodyExpression());
1415            }
1416    
1417            @Override
1418            public void visitSuperTypeCallEntry(@NotNull KtSuperTypeCallEntry call) {
1419                generateCallOrMarkUnresolved(call);
1420            }
1421    
1422            private void generateCallOrMarkUnresolved(@Nullable KtCallElement call) {
1423                if (call == null) return;
1424                if (!generateCall(call)) {
1425                    List<KtExpression> arguments = CollectionsKt.map(
1426                            call.getValueArguments(),
1427                            new Function1<ValueArgument, KtExpression>() {
1428                                @Override
1429                                public KtExpression invoke(ValueArgument valueArgument) {
1430                                    return valueArgument.getArgumentExpression();
1431                                }
1432                            }
1433                    );
1434    
1435                    for (KtExpression argument : arguments) {
1436                        generateInstructions(argument);
1437                    }
1438                    createNonSyntheticValue(call, arguments, MagicKind.UNRESOLVED_CALL);
1439                }
1440            }
1441    
1442            @Override
1443            public void visitDelegatedSuperTypeEntry(@NotNull KtDelegatedSuperTypeEntry specifier) {
1444                KtExpression delegateExpression = specifier.getDelegateExpression();
1445                generateInstructions(delegateExpression);
1446                createSyntheticValue(specifier, MagicKind.VALUE_CONSUMER, delegateExpression);
1447            }
1448    
1449            @Override
1450            public void visitSuperTypeEntry(@NotNull KtSuperTypeEntry specifier) {
1451                // Do not generate UNSUPPORTED_ELEMENT here
1452            }
1453    
1454            @Override
1455            public void visitSuperTypeList(@NotNull KtSuperTypeList list) {
1456                list.acceptChildren(this);
1457            }
1458    
1459            @Override
1460            public void visitKtFile(@NotNull KtFile file) {
1461                for (KtDeclaration declaration : file.getDeclarations()) {
1462                    if (declaration instanceof KtProperty) {
1463                        generateInstructions(declaration);
1464                    }
1465                }
1466            }
1467    
1468            @Override
1469            public void visitDoubleColonExpression(@NotNull KtDoubleColonExpression expression) {
1470                mark(expression);
1471                createNonSyntheticValue(expression, MagicKind.CALLABLE_REFERENCE);
1472            }
1473    
1474            @Override
1475            public void visitKtElement(@NotNull KtElement element) {
1476                createNonSyntheticValue(element, MagicKind.UNSUPPORTED_ELEMENT);
1477            }
1478    
1479            private boolean generateCall(@Nullable KtElement callElement) {
1480                if (callElement == null) return false;
1481                return checkAndGenerateCall(CallUtilKt.getResolvedCall(callElement, trace.getBindingContext()));
1482            }
1483    
1484            private boolean checkAndGenerateCall(@Nullable ResolvedCall<?> resolvedCall) {
1485                if (resolvedCall == null) return false;
1486                generateCall(resolvedCall);
1487                return true;
1488            }
1489    
1490            @NotNull
1491            private InstructionWithValue generateCall(@NotNull ResolvedCall<?> resolvedCall) {
1492                KtElement callElement = resolvedCall.getCall().getCallElement();
1493    
1494                Map<PseudoValue, ReceiverValue> receivers = getReceiverValues(resolvedCall);
1495    
1496                SmartFMap<PseudoValue, ValueParameterDescriptor> parameterValues = SmartFMap.emptyMap();
1497                for (ValueArgument argument : resolvedCall.getCall().getValueArguments()) {
1498                    ArgumentMapping argumentMapping = resolvedCall.getArgumentMapping(argument);
1499                    KtExpression argumentExpression = argument.getArgumentExpression();
1500                    if (argumentMapping instanceof ArgumentMatch) {
1501                        parameterValues = generateValueArgument(argument, ((ArgumentMatch) argumentMapping).getValueParameter(), parameterValues);
1502                    }
1503                    else if (argumentExpression != null) {
1504                        generateInstructions(argumentExpression);
1505                        createSyntheticValue(argumentExpression, MagicKind.VALUE_CONSUMER, argumentExpression);
1506                    }
1507                }
1508    
1509                if (resolvedCall.getResultingDescriptor() instanceof VariableDescriptor) {
1510                    // If a callee of the call is just a variable (without 'invoke'), 'read variable' is generated.
1511                    // todo : process arguments for such a case (KT-5387)
1512                    KtExpression callExpression = callElement instanceof KtExpression ? (KtExpression) callElement : null;
1513                    assert callExpression != null
1514                            : "Variable-based call without callee expression: " + callElement.getText();
1515                    assert parameterValues.isEmpty()
1516                            : "Variable-based call with non-empty argument list: " + callElement.getText();
1517                    return builder.readVariable(callExpression, resolvedCall, receivers);
1518                }
1519    
1520                mark(resolvedCall.getCall().getCallElement());
1521                return builder.call(callElement, resolvedCall, receivers, parameterValues);
1522            }
1523    
1524            @NotNull
1525            private Map<PseudoValue, ReceiverValue> getReceiverValues(ResolvedCall<?> resolvedCall) {
1526                PseudoValue varCallResult = null;
1527                ReceiverValue explicitReceiver = null;
1528                if (resolvedCall instanceof VariableAsFunctionResolvedCall) {
1529                    varCallResult = generateCall(((VariableAsFunctionResolvedCall) resolvedCall).getVariableCall()).getOutputValue();
1530    
1531                    ExplicitReceiverKind kind = resolvedCall.getExplicitReceiverKind();
1532                    //noinspection EnumSwitchStatementWhichMissesCases
1533                    switch (kind) {
1534                        case DISPATCH_RECEIVER:
1535                            explicitReceiver = resolvedCall.getDispatchReceiver();
1536                            break;
1537                        case EXTENSION_RECEIVER:
1538                        case BOTH_RECEIVERS:
1539                            explicitReceiver = (ReceiverValue) resolvedCall.getExtensionReceiver();
1540                            break;
1541                    }
1542                }
1543    
1544                SmartFMap<PseudoValue, ReceiverValue> receiverValues = SmartFMap.emptyMap();
1545                if (explicitReceiver != null && varCallResult != null) {
1546                    receiverValues = receiverValues.plus(varCallResult, explicitReceiver);
1547                }
1548                KtElement callElement = resolvedCall.getCall().getCallElement();
1549                receiverValues = getReceiverValues(callElement, resolvedCall.getDispatchReceiver(), receiverValues);
1550                receiverValues = getReceiverValues(callElement, (ReceiverValue) resolvedCall.getExtensionReceiver(), receiverValues);
1551                return receiverValues;
1552            }
1553    
1554            @NotNull
1555            private SmartFMap<PseudoValue, ReceiverValue> getReceiverValues(
1556                    KtElement callElement,
1557                    @Nullable ReceiverValue receiver,
1558                    SmartFMap<PseudoValue, ReceiverValue> receiverValues
1559            ) {
1560                if (receiver == null || receiverValues.containsValue(receiver)) return receiverValues;
1561    
1562                if (receiver instanceof ImplicitReceiver) {
1563                    receiverValues = receiverValues.plus(createSyntheticValue(callElement, MagicKind.IMPLICIT_RECEIVER), receiver);
1564                }
1565                else if (receiver instanceof ExpressionReceiver) {
1566                    KtExpression expression = ((ExpressionReceiver) receiver).getExpression();
1567                    if (builder.getBoundValue(expression) == null) {
1568                        generateInstructions(expression);
1569                    }
1570    
1571                    PseudoValue receiverPseudoValue = getBoundOrUnreachableValue(expression);
1572                    if (receiverPseudoValue != null) {
1573                        receiverValues = receiverValues.plus(receiverPseudoValue, receiver);
1574                    }
1575                }
1576                else if (receiver instanceof TransientReceiver) {
1577                    // Do nothing
1578                }
1579                else {
1580                    throw new IllegalArgumentException("Unknown receiver kind: " + receiver);
1581                }
1582    
1583                return receiverValues;
1584            }
1585    
1586            @NotNull
1587            private SmartFMap<PseudoValue, ValueParameterDescriptor> generateValueArgument(
1588                    ValueArgument valueArgument,
1589                    ValueParameterDescriptor parameterDescriptor,
1590                    SmartFMap<PseudoValue, ValueParameterDescriptor> parameterValues) {
1591                KtExpression expression = valueArgument.getArgumentExpression();
1592                if (expression != null) {
1593                    if (!valueArgument.isExternal()) {
1594                        generateInstructions(expression);
1595                    }
1596    
1597                    PseudoValue argValue = getBoundOrUnreachableValue(expression);
1598                    if (argValue != null) {
1599                        parameterValues = parameterValues.plus(argValue, parameterDescriptor);
1600                    }
1601                }
1602                return parameterValues;
1603            }
1604        }
1605    }