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