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