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