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