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