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