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