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