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