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