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
017package org.jetbrains.jet.lang.cfg;
018
019import com.google.common.collect.Lists;
020import com.intellij.psi.PsiElement;
021import com.intellij.psi.tree.IElementType;
022import org.jetbrains.annotations.NotNull;
023import org.jetbrains.annotations.Nullable;
024import org.jetbrains.jet.JetNodeTypes;
025import org.jetbrains.jet.lang.cfg.pseudocode.JetControlFlowInstructionsGenerator;
026import org.jetbrains.jet.lang.cfg.pseudocode.LocalDeclarationInstruction;
027import org.jetbrains.jet.lang.cfg.pseudocode.Pseudocode;
028import org.jetbrains.jet.lang.cfg.pseudocode.PseudocodeImpl;
029import org.jetbrains.jet.lang.psi.*;
030import org.jetbrains.jet.lang.resolve.BindingContext;
031import org.jetbrains.jet.lang.resolve.BindingContextUtils;
032import org.jetbrains.jet.lang.resolve.BindingTrace;
033import org.jetbrains.jet.lang.resolve.constants.BooleanValue;
034import org.jetbrains.jet.lang.resolve.constants.CompileTimeConstantResolver;
035import org.jetbrains.jet.lang.types.JetType;
036import org.jetbrains.jet.lang.types.expressions.OperatorConventions;
037import org.jetbrains.jet.lang.types.lang.KotlinBuiltIns;
038import org.jetbrains.jet.lexer.JetTokens;
039
040import java.util.Collection;
041import java.util.Iterator;
042import java.util.LinkedList;
043import java.util.List;
044
045import static org.jetbrains.jet.lang.diagnostics.Errors.*;
046
047public class JetControlFlowProcessor {
048
049    private final JetControlFlowBuilder builder;
050    private final BindingTrace trace;
051
052    public JetControlFlowProcessor(BindingTrace trace) {
053        this.builder = new JetControlFlowInstructionsGenerator();
054        this.trace = trace;
055    }
056
057    public Pseudocode generatePseudocode(@NotNull JetElement subroutine) {
058        Pseudocode pseudocode = generate(subroutine);
059        ((PseudocodeImpl) pseudocode).postProcess();
060        for (LocalDeclarationInstruction localDeclarationInstruction : pseudocode.getLocalDeclarations()) {
061            ((PseudocodeImpl)localDeclarationInstruction.getBody()).postProcess();
062        }
063        return pseudocode;
064    }
065
066    private Pseudocode generate(@NotNull JetElement subroutine) {
067        builder.enterSubroutine(subroutine);
068        CFPVisitor cfpVisitor = new CFPVisitor(false);
069        if (subroutine instanceof JetDeclarationWithBody) {
070            JetDeclarationWithBody declarationWithBody = (JetDeclarationWithBody) subroutine;
071            List<JetParameter> valueParameters = declarationWithBody.getValueParameters();
072            for (JetParameter valueParameter : valueParameters) {
073                valueParameter.accept(cfpVisitor);
074            }
075            JetExpression bodyExpression = declarationWithBody.getBodyExpression();
076            if (bodyExpression != null) {
077                bodyExpression.accept(cfpVisitor);
078            }
079        } else {
080            subroutine.accept(cfpVisitor);
081        }
082        return builder.exitSubroutine(subroutine);
083    }
084
085    private void processLocalDeclaration(@NotNull JetDeclaration subroutine) {
086        Label afterDeclaration = builder.createUnboundLabel();
087        builder.nondeterministicJump(afterDeclaration);
088        generate(subroutine);
089        builder.bindLabel(afterDeclaration);
090    }
091
092    
093    private class CFPVisitor extends JetVisitorVoid {
094        private final boolean inCondition;
095        private final JetVisitorVoid conditionVisitor = new JetVisitorVoid() {
096
097            @Override
098            public void visitWhenConditionInRange(JetWhenConditionInRange condition) {
099                generateInstructions(condition.getRangeExpression(), CFPVisitor.this.inCondition); // TODO : inCondition?
100                generateInstructions(condition.getOperationReference(), CFPVisitor.this.inCondition); // TODO : inCondition?
101                // TODO : read the call to contains()...
102            }
103
104            @Override
105            public void visitWhenConditionIsPattern(JetWhenConditionIsPattern condition) {
106                // TODO: types in CF?
107            }
108
109            @Override
110            public void visitWhenConditionWithExpression(JetWhenConditionWithExpression condition) {
111                generateInstructions(condition.getExpression(), inCondition);
112            }
113
114            @Override
115            public void visitJetElement(JetElement element) {
116                throw new UnsupportedOperationException("[JetControlFlowProcessor] " + element.toString());
117            }
118        };
119        private final JetVisitorVoid patternVisitor = new JetVisitorVoid() {
120
121            @Override
122            public void visitJetElement(JetElement element) {
123                throw new UnsupportedOperationException("[JetControlFlowProcessor] " + element.toString());
124            }
125        };
126
127        private CFPVisitor(boolean inCondition) {
128            this.inCondition = inCondition;
129        }
130
131        private void generateInstructions(@Nullable JetElement element, boolean inCondition) {
132            if (element == null) return;
133            CFPVisitor visitor;
134            if (this.inCondition == inCondition) {
135                visitor = this;
136            }
137            else {
138                visitor = new CFPVisitor(inCondition);
139            }
140            element.accept(visitor);
141        }
142
143        @Override
144        public void visitParenthesizedExpression(JetParenthesizedExpression expression) {
145            builder.read(expression);
146
147            JetExpression innerExpression = expression.getExpression();
148            if (innerExpression != null) {
149                generateInstructions(innerExpression, inCondition);
150            }
151        }
152
153        @Override
154        public void visitThisExpression(JetThisExpression expression) {
155            builder.read(expression);
156        }
157
158        @Override
159        public void visitConstantExpression(JetConstantExpression expression) {
160            builder.read(expression);
161        }
162
163        @Override
164        public void visitSimpleNameExpression(JetSimpleNameExpression expression) {
165            builder.read(expression);
166            if (trace.get(BindingContext.PROCESSED, expression)) {
167                JetType type = trace.getBindingContext().get(BindingContext.EXPRESSION_TYPE, expression);
168                if (type != null && KotlinBuiltIns.getInstance().isNothing(type)) {
169                    builder.jumpToError();
170                }
171            }
172        }
173
174        @Override
175        public void visitLabelQualifiedExpression(JetLabelQualifiedExpression expression) {
176            String labelName = expression.getLabelName();
177            JetExpression labeledExpression = expression.getLabeledExpression();
178            if (labelName != null && labeledExpression != null) {
179                visitLabeledExpression(labelName, labeledExpression);
180            }
181        }
182
183        private void visitLabeledExpression(@NotNull String labelName, @NotNull JetExpression labeledExpression) {
184            JetExpression deparenthesized = JetPsiUtil.deparenthesizeWithNoTypeResolution(labeledExpression);
185            if (deparenthesized != null) {
186                generateInstructions(labeledExpression, inCondition);
187            }
188        }
189
190        @SuppressWarnings("SuspiciousMethodCalls") @Override
191        public void visitBinaryExpression(JetBinaryExpression expression) {
192            IElementType operationType = expression.getOperationReference().getReferencedNameElementType();
193            JetExpression right = expression.getRight();
194            if (operationType == JetTokens.ANDAND) {
195                generateInstructions(expression.getLeft(), true);
196                Label resultLabel = builder.createUnboundLabel();
197                builder.jumpOnFalse(resultLabel);
198                if (right != null) {
199                    generateInstructions(right, true);
200                }
201                builder.bindLabel(resultLabel);
202                if (!inCondition) {
203                    builder.read(expression);
204                }
205            }
206            else if (operationType == JetTokens.OROR) {
207                generateInstructions(expression.getLeft(), true);
208                Label resultLabel = builder.createUnboundLabel();
209                builder.jumpOnTrue(resultLabel);
210                if (right != null) {
211                    generateInstructions(right, true);
212                }
213                builder.bindLabel(resultLabel);
214                if (!inCondition) {
215                    builder.read(expression);
216                }
217            }
218            else if (operationType == JetTokens.EQ) {
219                JetExpression left = JetPsiUtil.deparenthesizeWithNoTypeResolution(expression.getLeft());
220                if (right != null) {
221                    generateInstructions(right, false);
222                }
223                if (left instanceof JetSimpleNameExpression) {
224                    builder.write(expression, left);
225                }
226                else if (left instanceof JetArrayAccessExpression) {
227                    JetArrayAccessExpression arrayAccessExpression = (JetArrayAccessExpression) left;
228                    visitAssignToArrayAccess(expression, arrayAccessExpression);
229                }
230                else if (left instanceof JetQualifiedExpression) {
231                    JetQualifiedExpression qualifiedExpression = (JetQualifiedExpression) left;
232                    generateInstructions(qualifiedExpression.getReceiverExpression(), false);
233                    generateInstructions(expression.getOperationReference(), false);
234                    builder.write(expression, left);
235                }
236                else {
237                    builder.unsupported(expression); // TODO
238                }
239            }
240            else if (OperatorConventions.ASSIGNMENT_OPERATIONS.containsKey(operationType)) {
241                JetExpression left = JetPsiUtil.deparenthesizeWithNoTypeResolution(expression.getLeft());
242                if (left != null) {
243                    generateInstructions(left, false);
244                }
245                if (right != null) {
246                    generateInstructions(right, false);
247                }
248                if (left instanceof JetSimpleNameExpression || left instanceof JetArrayAccessExpression) {
249                    generateInstructions(expression.getOperationReference(), false);
250                    builder.write(expression, left);
251                }
252                else if (left != null) {
253                    builder.unsupported(expression); // TODO
254                }
255            }
256            else if (operationType == JetTokens.ELVIS) {
257                builder.read(expression);
258                generateInstructions(expression.getLeft(), false);
259                generateInstructions(expression.getOperationReference(), false);
260                Label afterElvis = builder.createUnboundLabel();
261                builder.jumpOnTrue(afterElvis);
262                if (right != null) {
263                    generateInstructions(right, false);
264                }
265                builder.bindLabel(afterElvis);
266            }
267            else {
268                generateInstructions(expression.getLeft(), false);
269                if (right != null) {
270                    generateInstructions(right, false);
271                }
272                generateInstructions(expression.getOperationReference(), false);
273                builder.read(expression);
274            }
275        }
276
277        private void visitAssignToArrayAccess(JetBinaryExpression expression, JetArrayAccessExpression arrayAccessExpression) {
278            for (JetExpression index : arrayAccessExpression.getIndexExpressions()) {
279                generateInstructions(index, false);
280            }
281            generateInstructions(arrayAccessExpression.getArrayExpression(), false);
282            generateInstructions(expression.getOperationReference(), false);
283            builder.write(expression, arrayAccessExpression); // TODO : ???
284        }
285
286        @Override
287        public void visitUnaryExpression(JetUnaryExpression expression) {
288            JetSimpleNameExpression operationSign = expression.getOperationReference();
289            IElementType operationType = operationSign.getReferencedNameElementType();
290            JetExpression baseExpression = expression.getBaseExpression();
291            if (baseExpression == null) return;
292            if (JetTokens.LABELS.contains(operationType)) {
293                String referencedName = operationSign.getReferencedName();
294                visitLabeledExpression(referencedName.substring(1), baseExpression);
295            }
296            else {
297                generateInstructions(baseExpression, false);
298                generateInstructions(operationSign, false);
299
300                boolean incrementOrDecrement = isIncrementOrDecrement(operationType);
301                if (incrementOrDecrement) {
302                    builder.write(expression, baseExpression);
303                }
304
305                builder.read(expression);
306            }
307        }
308
309        private boolean isIncrementOrDecrement(IElementType operationType) {
310            return operationType == JetTokens.PLUSPLUS || operationType == JetTokens.MINUSMINUS;
311        }
312
313
314        @Override
315        public void visitIfExpression(JetIfExpression expression) {
316            JetExpression condition = expression.getCondition();
317            if (condition != null) {
318                generateInstructions(condition, true);
319            }
320            Label elseLabel = builder.createUnboundLabel();
321            builder.jumpOnFalse(elseLabel);
322            JetExpression thenBranch = expression.getThen();
323            if (thenBranch != null) {
324                generateInstructions(thenBranch, inCondition);
325            }
326            else {
327                builder.readUnit(expression);
328            }
329            Label resultLabel = builder.createUnboundLabel();
330            builder.jump(resultLabel);
331            builder.bindLabel(elseLabel);
332            JetExpression elseBranch = expression.getElse();
333            if (elseBranch != null) {
334                generateInstructions(elseBranch, inCondition);
335            }
336            else {
337                builder.readUnit(expression);
338            }
339            builder.bindLabel(resultLabel);
340        }
341        
342        private class FinallyBlockGenerator {
343            private final JetFinallySection finallyBlock;
344            private Label startFinally = null;
345            private Label finishFinally = null;
346
347            private FinallyBlockGenerator(JetFinallySection block) {
348                finallyBlock = block;
349            }
350
351            public void generate() {
352                JetBlockExpression finalExpression = finallyBlock.getFinalExpression();
353                if (finalExpression == null) return;
354                if (startFinally != null) {
355                    assert finishFinally != null;
356                    builder.repeatPseudocode(startFinally, finishFinally);
357                    return;
358                }
359                startFinally = builder.createUnboundLabel("start finally");
360                builder.bindLabel(startFinally);
361                generateInstructions(finalExpression, inCondition);
362                finishFinally = builder.createUnboundLabel("finish finally");
363                builder.bindLabel(finishFinally);
364            }
365        }
366       
367
368        @Override
369        public void visitTryExpression(JetTryExpression expression) {
370            builder.read(expression);
371            JetFinallySection finallyBlock = expression.getFinallyBlock();
372            final FinallyBlockGenerator finallyBlockGenerator = new FinallyBlockGenerator(finallyBlock);
373            if (finallyBlock != null) {
374                builder.enterTryFinally(new GenerationTrigger() {
375                    private boolean working = false;
376
377                    @Override
378                    public void generate() {
379                        // This checks are needed for the case of having e.g. return inside finally: 'try {return} finally{return}'
380                        if (working) return;
381                        working = true;
382                        finallyBlockGenerator.generate();
383                        working = false;
384                    }
385                });
386            }
387
388            List<JetCatchClause> catchClauses = expression.getCatchClauses();
389            boolean hasCatches = !catchClauses.isEmpty();
390            Label onException = null;
391            if (hasCatches) {
392                onException = builder.createUnboundLabel("onException");
393                builder.nondeterministicJump(onException);
394            }
395            Label onExceptionToFinallyBlock = null;
396            if (finallyBlock != null) {
397                onExceptionToFinallyBlock = builder.createUnboundLabel("onExceptionToFinallyBlock");
398                builder.nondeterministicJump(onExceptionToFinallyBlock);
399            }
400            generateInstructions(expression.getTryBlock(), inCondition);
401
402            Collection<Label> allowDeadLabels = Lists.newArrayList();
403            if (hasCatches) {
404                Label afterCatches = builder.createUnboundLabel("afterCatches");
405                builder.jump(afterCatches);
406
407                builder.bindLabel(onException);
408                LinkedList<Label> catchLabels = Lists.newLinkedList();
409                int catchClausesSize = catchClauses.size();
410                for (int i = 0; i < catchClausesSize - 1; i++) {
411                    catchLabels.add(builder.createUnboundLabel("catch " + i));
412                }
413                if (!catchLabels.isEmpty()) {
414                    builder.nondeterministicJump(catchLabels);
415                }
416                boolean isFirst = true;
417                for (JetCatchClause catchClause : catchClauses) {
418                    if (!isFirst) {
419                        builder.bindLabel(catchLabels.remove());
420                    }
421                    else {
422                        isFirst = false;
423                    }
424                    JetParameter catchParameter = catchClause.getCatchParameter();
425                    if (catchParameter != null) {
426                        builder.declare(catchParameter);
427                        builder.write(catchParameter, catchParameter);
428                    }
429                    JetExpression catchBody = catchClause.getCatchBody();
430                    if (catchBody != null) {
431                        generateInstructions(catchBody, false);
432                    }
433                    builder.jump(afterCatches);
434                }
435
436                builder.bindLabel(afterCatches);
437            }
438
439            if (finallyBlock != null) {
440                builder.exitTryFinally();
441
442                Label skipFinallyToErrorBlock = builder.createUnboundLabel("skipFinallyToErrorBlock");
443                builder.jump(skipFinallyToErrorBlock);
444                builder.bindLabel(onExceptionToFinallyBlock);
445                finallyBlockGenerator.generate();
446                builder.jumpToError();
447                builder.bindLabel(skipFinallyToErrorBlock);
448
449                finallyBlockGenerator.generate();
450            }
451        }
452
453        @Override
454        public void visitWhileExpression(JetWhileExpression expression) {
455            builder.read(expression);
456            LoopInfo loopInfo = builder.enterLoop(expression, null, null);
457
458            builder.bindLabel(loopInfo.getConditionEntryPoint());
459            JetExpression condition = expression.getCondition();
460            if (condition != null) {
461                generateInstructions(condition, true);
462            }
463            boolean conditionIsTrueConstant = false;
464            if (condition instanceof JetConstantExpression && condition.getNode().getElementType() == JetNodeTypes.BOOLEAN_CONSTANT) {
465                if (BooleanValue.TRUE == new CompileTimeConstantResolver().getBooleanValue(condition.getText(), KotlinBuiltIns.getInstance().getBooleanType())) {
466                    conditionIsTrueConstant = true;
467                }
468            }
469            if (!conditionIsTrueConstant) {
470                builder.jumpOnFalse(loopInfo.getExitPoint());
471            }
472
473            builder.bindLabel(loopInfo.getBodyEntryPoint());
474            JetExpression body = expression.getBody();
475            if (body != null) {
476                generateInstructions(body, false);
477            }
478            builder.jump(loopInfo.getEntryPoint());
479            builder.exitLoop(expression);
480            builder.readUnit(expression);
481        }
482
483        @Override
484        public void visitDoWhileExpression(JetDoWhileExpression expression) {
485            builder.read(expression);
486            LoopInfo loopInfo = builder.enterLoop(expression, null, null);
487
488            builder.bindLabel(loopInfo.getBodyEntryPoint());
489            JetExpression body = expression.getBody();
490            if (body != null) {
491                generateInstructions(body, false);
492            }
493            builder.bindLabel(loopInfo.getConditionEntryPoint());
494            JetExpression condition = expression.getCondition();
495            if (condition != null) {
496                generateInstructions(condition, true);
497            }
498            builder.jumpOnTrue(loopInfo.getEntryPoint());
499            builder.exitLoop(expression);
500            builder.readUnit(expression);
501        }
502
503        @Override
504        public void visitForExpression(JetForExpression expression) {
505            builder.read(expression);
506            JetExpression loopRange = expression.getLoopRange();
507            if (loopRange != null) {
508                generateInstructions(loopRange, false);
509            }
510            JetParameter loopParameter = expression.getLoopParameter();
511            if (loopParameter != null) {
512                generateInstructions(loopParameter, inCondition);
513            }
514            else {
515                JetMultiDeclaration multiParameter = expression.getMultiParameter();
516                generateInstructions(multiParameter, inCondition);
517            }
518
519            // TODO : primitive cases
520            Label loopExitPoint = builder.createUnboundLabel();
521            Label conditionEntryPoint = builder.createUnboundLabel();
522
523            builder.bindLabel(conditionEntryPoint);
524            builder.nondeterministicJump(loopExitPoint);
525
526            LoopInfo loopInfo = builder.enterLoop(expression, loopExitPoint, conditionEntryPoint);
527
528            builder.bindLabel(loopInfo.getBodyEntryPoint());
529            JetExpression body = expression.getBody();
530            if (body != null) {
531                generateInstructions(body, false);
532            }
533
534            builder.nondeterministicJump(loopInfo.getEntryPoint());
535            builder.exitLoop(expression);
536            builder.readUnit(expression);
537        }
538
539        @Override
540        public void visitBreakExpression(JetBreakExpression expression) {
541            JetElement loop = getCorrespondingLoop(expression);
542            if (loop != null) {
543                builder.jump(builder.getExitPoint(loop));
544            }
545        }
546
547        @Override
548        public void visitContinueExpression(JetContinueExpression expression) {
549            JetElement loop = getCorrespondingLoop(expression);
550            if (loop != null) {
551                builder.jump(builder.getEntryPoint(loop));
552            }
553        }
554
555        private JetElement getCorrespondingLoop(JetLabelQualifiedExpression expression) {
556            String labelName = expression.getLabelName();
557            JetElement loop;
558            if (labelName != null) {
559                JetSimpleNameExpression targetLabel = expression.getTargetLabel();
560                assert targetLabel != null;
561                PsiElement labeledElement = BindingContextUtils.resolveToDeclarationPsiElement(trace.getBindingContext(), targetLabel);
562                if (labeledElement instanceof JetLoopExpression) {
563                    loop = (JetLoopExpression) labeledElement;
564                }
565                else {
566                    trace.report(NOT_A_LOOP_LABEL.on(expression, targetLabel.getText()));
567                    loop = null;
568                }
569            }
570            else {
571                loop = builder.getCurrentLoop();
572                if (loop == null) {
573                    trace.report(BREAK_OR_CONTINUE_OUTSIDE_A_LOOP.on(expression));
574                }
575            }
576            return loop;
577        }
578
579        @Override
580        public void visitReturnExpression(JetReturnExpression expression) {
581            JetExpression returnedExpression = expression.getReturnedExpression();
582            if (returnedExpression != null) {
583                generateInstructions(returnedExpression, false);
584            }
585            JetSimpleNameExpression labelElement = expression.getTargetLabel();
586            JetElement subroutine;
587            String labelName = expression.getLabelName();
588            if (labelElement != null) {
589                assert labelName != null;
590                PsiElement labeledElement = BindingContextUtils.resolveToDeclarationPsiElement(trace.getBindingContext(), labelElement);
591                if (labeledElement != null) {
592                    assert labeledElement instanceof JetElement;
593                    subroutine = (JetElement) labeledElement;
594                }
595                else {
596                    subroutine = null;
597                }
598            }
599            else {
600                subroutine = builder.getReturnSubroutine();
601                // TODO : a context check
602            }
603
604            if (subroutine instanceof JetFunction || subroutine instanceof JetPropertyAccessor) {
605                if (returnedExpression == null) {
606                    builder.returnNoValue(expression, subroutine);
607                }
608                else {
609                    builder.returnValue(expression, subroutine);
610                }
611            }
612        }
613
614        @Override
615        public void visitParameter(JetParameter parameter) {
616            builder.declare(parameter);
617            JetExpression defaultValue = parameter.getDefaultValue();
618            if (defaultValue != null) {
619                generateInstructions(defaultValue, inCondition);
620            }
621            builder.write(parameter, parameter);
622        }
623
624        @Override
625        public void visitBlockExpression(JetBlockExpression expression) {
626            List<JetElement> statements = expression.getStatements();
627            for (JetElement statement : statements) {
628                generateInstructions(statement, false);
629            }
630            if (statements.isEmpty()) {
631                builder.readUnit(expression);
632            }
633        }
634
635        @Override
636        public void visitNamedFunction(JetNamedFunction function) {
637            processLocalDeclaration(function);
638        }
639
640        @Override
641        public void visitFunctionLiteralExpression(JetFunctionLiteralExpression expression) {
642            JetFunctionLiteral functionLiteral = expression.getFunctionLiteral();
643            processLocalDeclaration(functionLiteral);
644            builder.read(expression);
645        }
646
647        @Override
648        public void visitQualifiedExpression(JetQualifiedExpression expression) {
649            generateInstructions(expression.getReceiverExpression(), false);
650            JetExpression selectorExpression = expression.getSelectorExpression();
651            if (selectorExpression != null) {
652                generateInstructions(selectorExpression, false);
653            }
654            builder.read(expression);
655            if (trace.get(BindingContext.PROCESSED, expression)) {
656                JetType type = trace.getBindingContext().get(BindingContext.EXPRESSION_TYPE, expression);
657                if (type != null && KotlinBuiltIns.getInstance().isNothing(type)) {
658                    builder.jumpToError();
659                }
660            }
661        }
662
663        private void visitCall(JetCallElement call) {
664            for (ValueArgument argument : call.getValueArguments()) {
665                JetExpression argumentExpression = argument.getArgumentExpression();
666                if (argumentExpression != null) {
667                    generateInstructions(argumentExpression, false);
668                }
669            }
670
671            for (JetExpression functionLiteral : call.getFunctionLiteralArguments()) {
672                generateInstructions(functionLiteral, false);
673            }
674        }
675
676        @Override
677        public void visitCallExpression(JetCallExpression expression) {
678            //inline functions after M1
679//            ResolvedCall<? extends CallableDescriptor> resolvedCall = trace.get(BindingContext.RESOLVED_CALL, expression.getCalleeExpression());
680//            assert resolvedCall != null;
681//            CallableDescriptor resultingDescriptor = resolvedCall.getResultingDescriptor();
682//            PsiElement element = trace.get(BindingContext.DESCRIPTOR_TO_DECLARATION, resultingDescriptor);
683//            if (element instanceof JetNamedFunction) {
684//                JetNamedFunction namedFunction = (JetNamedFunction) element;
685//                if (namedFunction.hasModifier(JetTokens.INLINE_KEYWORD)) {
686//                }
687//            }
688
689            for (JetTypeProjection typeArgument : expression.getTypeArguments()) {
690                generateInstructions(typeArgument, false);
691            }
692
693            visitCall(expression);
694
695            generateInstructions(expression.getCalleeExpression(), false);
696            builder.read(expression);
697            if (trace.get(BindingContext.PROCESSED, expression)) {
698                JetType type = trace.getBindingContext().get(BindingContext.EXPRESSION_TYPE, expression);
699                if (type != null && KotlinBuiltIns.getInstance().isNothing(type)) {
700                    builder.jumpToError();
701                }
702            }
703        }
704
705//        @Override
706//        public void visitNewExpression(JetNewExpression expression) {
707//            // TODO : Instantiated class is loaded
708//            // TODO : type arguments?
709//            visitCall(expression);
710//            builder.read(expression);
711//        }
712
713        @Override
714        public void visitProperty(JetProperty property) {
715            builder.declare(property);
716            JetExpression initializer = property.getInitializer();
717            if (initializer != null) {
718                generateInstructions(initializer, false);
719                builder.write(property, property);
720            }
721            JetExpression delegate = property.getDelegateExpression();
722            if (delegate != null) {
723                generateInstructions(delegate, false);
724            }
725            for (JetPropertyAccessor accessor : property.getAccessors()) {
726                generateInstructions(accessor, false);
727            }
728        }
729
730        @Override
731        public void visitMultiDeclaration(JetMultiDeclaration declaration) {
732            JetExpression initializer = declaration.getInitializer();
733            if (initializer != null) {
734                generateInstructions(initializer, false);
735            }
736            List<JetMultiDeclarationEntry> entries = declaration.getEntries();
737            for (JetMultiDeclarationEntry entry : entries) {
738                builder.declare(entry);
739                builder.write(entry, entry);
740            }
741        }
742
743        @Override
744        public void visitPropertyAccessor(JetPropertyAccessor accessor) {
745            processLocalDeclaration(accessor);
746        }
747
748        @Override
749        public void visitBinaryWithTypeRHSExpression(JetBinaryExpressionWithTypeRHS expression) {
750            IElementType operationType = expression.getOperationReference().getReferencedNameElementType();
751            if (operationType == JetTokens.COLON || operationType == JetTokens.AS_KEYWORD || operationType == JetTokens.AS_SAFE) {
752                generateInstructions(expression.getLeft(), false);
753                builder.read(expression);
754            }
755            else {
756                visitJetElement(expression);
757            }
758        }
759
760        @Override
761        public void visitThrowExpression(JetThrowExpression expression) {
762            JetExpression thrownExpression = expression.getThrownExpression();
763            if (thrownExpression != null) {
764                generateInstructions(thrownExpression, false);
765            }
766            builder.throwException(expression);
767        }
768
769        @Override
770        public void visitArrayAccessExpression(JetArrayAccessExpression expression) {
771            for (JetExpression index : expression.getIndexExpressions()) {
772                generateInstructions(index, false);
773            }
774            generateInstructions(expression.getArrayExpression(), false);
775            // TODO : read 'get' or 'set' function
776            builder.read(expression);
777        }
778
779        @Override
780        public void visitIsExpression(JetIsExpression expression) {
781            generateInstructions(expression.getLeftHandSide(), inCondition);
782            // no CF for types
783            // TODO : builder.read(expression.getPattern());
784            builder.read(expression);
785        }
786
787        @Override
788        public void visitWhenExpression(JetWhenExpression expression) {
789            JetExpression subjectExpression = expression.getSubjectExpression();
790            if (subjectExpression != null) {
791                generateInstructions(subjectExpression, inCondition);
792            }
793            boolean hasElseOrIrrefutableBranch = false;
794
795            Label doneLabel = builder.createUnboundLabel();
796
797            Label nextLabel = null;
798            Collection<Label> allowDeadLabels = Lists.newArrayList();
799            for (Iterator<JetWhenEntry> iterator = expression.getEntries().iterator(); iterator.hasNext(); ) {
800                JetWhenEntry whenEntry = iterator.next();
801
802                builder.read(whenEntry);
803
804                if (whenEntry.isElse()) {
805                    hasElseOrIrrefutableBranch = true;
806                    if (iterator.hasNext()) {
807                        trace.report(ELSE_MISPLACED_IN_WHEN.on(whenEntry));
808                    }
809                }
810                boolean isIrrefutable = whenEntry.isElse();
811                if (isIrrefutable) {
812                    hasElseOrIrrefutableBranch = true;
813                }
814
815                Label bodyLabel = builder.createUnboundLabel();
816
817                JetWhenCondition[] conditions = whenEntry.getConditions();
818                for (int i = 0; i < conditions.length; i++) {
819                    JetWhenCondition condition = conditions[i];
820                    condition.accept(conditionVisitor);
821                    if (i + 1 < conditions.length) {
822                        builder.nondeterministicJump(bodyLabel);
823                    }
824                }
825
826                if (!isIrrefutable) {
827                    nextLabel = builder.createUnboundLabel();
828                    builder.nondeterministicJump(nextLabel);
829                }
830
831                builder.bindLabel(bodyLabel);
832                generateInstructions(whenEntry.getExpression(), inCondition);
833                builder.jump(doneLabel);
834
835                if (!isIrrefutable) {
836                    builder.bindLabel(nextLabel);
837                }
838            }
839            builder.bindLabel(doneLabel);
840            boolean isWhenExhaust = WhenChecker.isWhenExhaustive(expression, trace);
841            if (!hasElseOrIrrefutableBranch && !isWhenExhaust) {
842                trace.report(NO_ELSE_IN_WHEN.on(expression));
843            }
844        }
845
846        @Override
847        public void visitObjectLiteralExpression(JetObjectLiteralExpression expression) {
848            JetObjectDeclaration declaration = expression.getObjectDeclaration();
849            generateInstructions(declaration, inCondition);
850
851            List<JetDeclaration> declarations = declaration.getDeclarations();
852            List<JetDeclaration> functions = Lists.newArrayList();
853            for (JetDeclaration localDeclaration : declarations) {
854                if (!(localDeclaration instanceof JetProperty) && !(localDeclaration instanceof JetClassInitializer)) {
855                    functions.add(localDeclaration);
856                }
857            }
858            for (JetDeclaration function : functions) {
859                generateInstructions(function, inCondition);
860            }
861            builder.read(expression);
862        }
863
864        @Override
865        public void visitObjectDeclaration(JetObjectDeclaration objectDeclaration) {
866            visitClassOrObject(objectDeclaration);
867        }
868
869        @Override
870        public void visitStringTemplateExpression(JetStringTemplateExpression expression) {
871            for (JetStringTemplateEntry entry : expression.getEntries()) {
872                if (entry instanceof JetStringTemplateEntryWithExpression) {
873                    JetStringTemplateEntryWithExpression entryWithExpression = (JetStringTemplateEntryWithExpression) entry;
874                    generateInstructions(entryWithExpression.getExpression(), false);
875                }
876            }
877            builder.read(expression);
878        }
879
880        @Override
881        public void visitTypeProjection(JetTypeProjection typeProjection) {
882            // TODO : Support Type Arguments. Class object may be initialized at this point");
883        }
884
885        @Override
886        public void visitAnonymousInitializer(JetClassInitializer classInitializer) {
887            generateInstructions(classInitializer.getBody(), inCondition);
888        }
889
890        private void visitClassOrObject(JetClassOrObject classOrObject) {
891            for (JetDelegationSpecifier specifier : classOrObject.getDelegationSpecifiers()) {
892                generateInstructions(specifier, inCondition);
893            }
894            List<JetDeclaration> declarations = classOrObject.getDeclarations();
895            for (JetDeclaration declaration : declarations) {
896                if (declaration instanceof JetProperty || declaration instanceof JetClassInitializer) {
897                    generateInstructions(declaration, inCondition);
898                }
899            }
900        }
901
902        @Override
903        public void visitClass(JetClass klass) {
904            List<JetParameter> parameters = klass.getPrimaryConstructorParameters();
905            for (JetParameter parameter : parameters) {
906                generateInstructions(parameter, inCondition);
907            }
908            visitClassOrObject(klass);
909        }
910
911        @Override
912        public void visitDelegationToSuperCallSpecifier(JetDelegatorToSuperCall call) {
913            List<? extends ValueArgument> valueArguments = call.getValueArguments();
914            for (ValueArgument valueArgument : valueArguments) {
915                generateInstructions(valueArgument.getArgumentExpression(), inCondition);
916            }
917        }
918
919        @Override
920        public void visitDelegationByExpressionSpecifier(JetDelegatorByExpressionSpecifier specifier) {
921            generateInstructions(specifier.getDelegateExpression(), inCondition);
922        }
923
924        @Override
925        public void visitJetFile(JetFile file) {
926            for (JetDeclaration declaration : file.getDeclarations()) {
927                if (declaration instanceof JetProperty) {
928                    generateInstructions(declaration, inCondition);
929                }
930            }
931        }
932
933        @Override
934        public void visitJetElement(JetElement element) {
935            builder.unsupported(element);
936        }
937    }
938}