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