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