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 }