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