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.ImmutableSet; 020 import com.google.common.collect.Lists; 021 import com.intellij.psi.PsiElement; 022 import com.intellij.psi.tree.IElementType; 023 import com.intellij.psi.util.PsiTreeUtil; 024 import org.jetbrains.annotations.NotNull; 025 import org.jetbrains.annotations.Nullable; 026 import org.jetbrains.jet.lang.cfg.pseudocode.JetControlFlowInstructionsGenerator; 027 import org.jetbrains.jet.lang.cfg.pseudocode.Pseudocode; 028 import org.jetbrains.jet.lang.cfg.pseudocode.PseudocodeImpl; 029 import org.jetbrains.jet.lang.descriptors.*; 030 import org.jetbrains.jet.lang.psi.*; 031 import org.jetbrains.jet.lang.resolve.BindingContext; 032 import org.jetbrains.jet.lang.resolve.BindingContextUtils; 033 import org.jetbrains.jet.lang.resolve.BindingTrace; 034 import org.jetbrains.jet.lang.resolve.CompileTimeConstantUtils; 035 import org.jetbrains.jet.lang.resolve.calls.model.ResolvedCall; 036 import org.jetbrains.jet.lang.resolve.calls.model.ResolvedValueArgument; 037 import org.jetbrains.jet.lang.resolve.calls.model.VariableAsFunctionResolvedCall; 038 import org.jetbrains.jet.lang.resolve.constants.CompileTimeConstant; 039 import org.jetbrains.jet.lang.resolve.name.Name; 040 import org.jetbrains.jet.lang.resolve.scopes.receivers.ExpressionReceiver; 041 import org.jetbrains.jet.lang.resolve.scopes.receivers.ReceiverValue; 042 import org.jetbrains.jet.lang.resolve.scopes.receivers.ThisReceiver; 043 import org.jetbrains.jet.lang.resolve.scopes.receivers.TransientReceiver; 044 import org.jetbrains.jet.lang.types.JetType; 045 import org.jetbrains.jet.lang.types.expressions.OperatorConventions; 046 import org.jetbrains.jet.lang.types.lang.KotlinBuiltIns; 047 import org.jetbrains.jet.lexer.JetToken; 048 import org.jetbrains.jet.lexer.JetTokens; 049 050 import java.util.Iterator; 051 import java.util.LinkedList; 052 import java.util.List; 053 054 import static org.jetbrains.jet.lang.cfg.JetControlFlowBuilder.PredefinedOperation.*; 055 import static org.jetbrains.jet.lang.cfg.JetControlFlowProcessor.CFPContext.IN_CONDITION; 056 import static org.jetbrains.jet.lang.cfg.JetControlFlowProcessor.CFPContext.NOT_IN_CONDITION; 057 import static org.jetbrains.jet.lang.diagnostics.Errors.*; 058 import static org.jetbrains.jet.lexer.JetTokens.*; 059 060 public class JetControlFlowProcessor { 061 062 private final JetControlFlowBuilder builder; 063 private final BindingTrace trace; 064 065 public JetControlFlowProcessor(BindingTrace trace) { 066 this.builder = new JetControlFlowInstructionsGenerator(); 067 this.trace = trace; 068 } 069 070 @NotNull 071 public Pseudocode generatePseudocode(@NotNull JetElement subroutine) { 072 Pseudocode pseudocode = generate(subroutine); 073 ((PseudocodeImpl) pseudocode).postProcess(); 074 return pseudocode; 075 } 076 077 @NotNull 078 private Pseudocode generate(@NotNull JetElement subroutine) { 079 builder.enterSubroutine(subroutine); 080 CFPVisitor cfpVisitor = new CFPVisitor(builder); 081 if (subroutine instanceof JetDeclarationWithBody) { 082 JetDeclarationWithBody declarationWithBody = (JetDeclarationWithBody) subroutine; 083 List<JetParameter> valueParameters = declarationWithBody.getValueParameters(); 084 for (JetParameter valueParameter : valueParameters) { 085 cfpVisitor.generateInstructions(valueParameter, NOT_IN_CONDITION); 086 } 087 JetExpression bodyExpression = declarationWithBody.getBodyExpression(); 088 if (bodyExpression != null) { 089 cfpVisitor.generateInstructions(bodyExpression, NOT_IN_CONDITION); 090 } 091 } else { 092 cfpVisitor.generateInstructions(subroutine, NOT_IN_CONDITION); 093 } 094 return builder.exitSubroutine(subroutine); 095 } 096 097 private void processLocalDeclaration(@NotNull JetDeclaration subroutine) { 098 JetElement parent = PsiTreeUtil.getParentOfType(subroutine, JetElement.class); 099 assert parent != null; 100 101 Label afterDeclaration = builder.createUnboundLabel(); 102 103 builder.nondeterministicJump(afterDeclaration, parent); 104 generate(subroutine); 105 builder.bindLabel(afterDeclaration); 106 } 107 108 /*package*/ enum CFPContext { 109 IN_CONDITION(true), 110 NOT_IN_CONDITION(false); 111 112 private final boolean inCondition; 113 114 private CFPContext(boolean inCondition) { 115 this.inCondition = inCondition; 116 } 117 118 public boolean inCondition() { 119 return inCondition; 120 } 121 } 122 123 private class CFPVisitor extends JetVisitorVoidWithParameter<CFPContext> { 124 private final JetControlFlowBuilder builder; 125 126 private final JetVisitorVoidWithParameter<CFPContext> conditionVisitor = new JetVisitorVoidWithParameter<CFPContext>() { 127 128 @Override 129 public void visitWhenConditionInRangeVoid(@NotNull JetWhenConditionInRange condition, CFPContext context) { 130 generateInstructions(condition.getRangeExpression(), context); 131 generateInstructions(condition.getOperationReference(), context); 132 // TODO : read the call to contains()... 133 } 134 135 @Override 136 public void visitWhenConditionIsPatternVoid(@NotNull JetWhenConditionIsPattern condition, CFPContext context) { 137 // TODO: types in CF? 138 } 139 140 @Override 141 public void visitWhenConditionWithExpressionVoid(@NotNull JetWhenConditionWithExpression condition, CFPContext context) { 142 generateInstructions(condition.getExpression(), context); 143 } 144 145 @Override 146 public void visitJetElementVoid(@NotNull JetElement element, CFPContext context) { 147 throw new UnsupportedOperationException("[JetControlFlowProcessor] " + element.toString()); 148 } 149 }; 150 151 private CFPVisitor(@NotNull JetControlFlowBuilder builder) { 152 this.builder = builder; 153 } 154 155 private void mark(JetElement element) { 156 builder.mark(element); 157 } 158 159 public void generateInstructions(@Nullable JetElement element, CFPContext context) { 160 if (element == null) return; 161 element.accept(this, context); 162 checkNothingType(element); 163 } 164 165 private void checkNothingType(JetElement element) { 166 if (!(element instanceof JetExpression)) return; 167 168 JetExpression expression = JetPsiUtil.deparenthesize((JetExpression) element); 169 if (expression == null) return; 170 171 if (expression instanceof JetStatementExpression || expression instanceof JetTryExpression 172 || expression instanceof JetIfExpression || expression instanceof JetWhenExpression) { 173 return; 174 } 175 176 JetType type = trace.getBindingContext().get(BindingContext.EXPRESSION_TYPE, expression); 177 if (type != null && KotlinBuiltIns.getInstance().isNothing(type)) { 178 builder.jumpToError(expression); 179 } 180 } 181 182 @Override 183 public void visitParenthesizedExpressionVoid(@NotNull JetParenthesizedExpression expression, CFPContext context) { 184 mark(expression); 185 JetExpression innerExpression = expression.getExpression(); 186 if (innerExpression != null) { 187 generateInstructions(innerExpression, context); 188 } 189 } 190 191 @Override 192 public void visitAnnotatedExpressionVoid(@NotNull JetAnnotatedExpression expression, CFPContext context) { 193 JetExpression baseExpression = expression.getBaseExpression(); 194 if (baseExpression != null) { 195 generateInstructions(baseExpression, context); 196 } 197 } 198 199 @Override 200 public void visitThisExpressionVoid(@NotNull JetThisExpression expression, CFPContext context) { 201 ResolvedCall<?> resolvedCall = getResolvedCall(expression); 202 if (resolvedCall == null) { 203 builder.readThis(expression, null); 204 return; 205 } 206 207 CallableDescriptor resultingDescriptor = resolvedCall.getResultingDescriptor(); 208 if (resultingDescriptor instanceof ReceiverParameterDescriptor) { 209 builder.readThis(expression, (ReceiverParameterDescriptor) resultingDescriptor); 210 } 211 } 212 213 @Override 214 public void visitConstantExpressionVoid(@NotNull JetConstantExpression expression, CFPContext context) { 215 CompileTimeConstant<?> constant = trace.get(BindingContext.COMPILE_TIME_VALUE, expression); 216 builder.loadConstant(expression, constant); 217 } 218 219 @Override 220 public void visitSimpleNameExpressionVoid(@NotNull JetSimpleNameExpression expression, CFPContext context) { 221 ResolvedCall<?> resolvedCall = getResolvedCall(expression); 222 if (resolvedCall instanceof VariableAsFunctionResolvedCall) { 223 VariableAsFunctionResolvedCall variableAsFunctionResolvedCall = (VariableAsFunctionResolvedCall) resolvedCall; 224 generateCall(expression, variableAsFunctionResolvedCall.getVariableCall()); 225 } 226 else { 227 generateCall(expression); 228 } 229 } 230 231 @Override 232 public void visitLabeledExpressionVoid(@NotNull JetLabeledExpression expression, CFPContext context) { 233 mark(expression); 234 JetExpression baseExpression = expression.getBaseExpression(); 235 if (baseExpression != null) { 236 generateInstructions(baseExpression, context); 237 } 238 } 239 240 @SuppressWarnings("SuspiciousMethodCalls") @Override 241 public void visitBinaryExpressionVoid(@NotNull JetBinaryExpression expression, CFPContext context) { 242 JetSimpleNameExpression operationReference = expression.getOperationReference(); 243 IElementType operationType = operationReference.getReferencedNameElementType(); 244 if (!ImmutableSet.of(ANDAND, OROR, EQ, ELVIS).contains(operationType)) { 245 mark(expression); 246 } 247 JetExpression right = expression.getRight(); 248 if (operationType == ANDAND) { 249 generateInstructions(expression.getLeft(), IN_CONDITION); 250 Label resultLabel = builder.createUnboundLabel(); 251 builder.jumpOnFalse(resultLabel, expression); 252 if (right != null) { 253 generateInstructions(right, IN_CONDITION); 254 } 255 builder.bindLabel(resultLabel); 256 if (!context.inCondition()) { 257 builder.predefinedOperation(expression, AND); 258 } 259 } 260 else if (operationType == OROR) { 261 generateInstructions(expression.getLeft(), IN_CONDITION); 262 Label resultLabel = builder.createUnboundLabel(); 263 builder.jumpOnTrue(resultLabel, expression); 264 if (right != null) { 265 generateInstructions(right, IN_CONDITION); 266 } 267 builder.bindLabel(resultLabel); 268 if (!context.inCondition()) { 269 builder.predefinedOperation(expression, OR); 270 } 271 } 272 else if (operationType == EQ) { 273 visitAssignment(expression.getLeft(), right, expression); 274 } 275 else if (OperatorConventions.ASSIGNMENT_OPERATIONS.containsKey(operationType)) { 276 if (generateCall(operationReference)) { 277 ResolvedCall<?> resolvedCall = getResolvedCall(operationReference); 278 assert resolvedCall != null : "Generation succeeded, but no call is found: " + expression.getText(); 279 CallableDescriptor descriptor = resolvedCall.getResultingDescriptor(); 280 Name assignMethodName = OperatorConventions.getNameForOperationSymbol((JetToken) expression.getOperationToken()); 281 if (!descriptor.getName().equals(assignMethodName)) { 282 // plus() called, assignment needed 283 visitAssignment(expression.getLeft(), null, expression); 284 } 285 } 286 else { 287 generateBothArguments(expression); 288 } 289 } 290 else if (operationType == ELVIS) { 291 generateInstructions(expression.getLeft(), NOT_IN_CONDITION); 292 Label afterElvis = builder.createUnboundLabel(); 293 builder.jumpOnTrue(afterElvis, expression); 294 if (right != null) { 295 generateInstructions(right, NOT_IN_CONDITION); 296 } 297 builder.bindLabel(afterElvis); 298 } 299 else { 300 if (!generateCall(operationReference)) { 301 generateBothArguments(expression); 302 } 303 } 304 } 305 306 private void generateBothArguments(JetBinaryExpression expression) { 307 JetExpression left = JetPsiUtil.deparenthesize(expression.getLeft()); 308 if (left != null) { 309 generateInstructions(left, NOT_IN_CONDITION); 310 } 311 JetExpression right = expression.getRight(); 312 if (right != null) { 313 generateInstructions(right, NOT_IN_CONDITION); 314 } 315 } 316 317 private void visitAssignment(JetExpression lhs, @Nullable JetExpression rhs, JetExpression parentExpression) { 318 JetExpression left = JetPsiUtil.deparenthesize(lhs); 319 if (left == null) { 320 builder.compilationError(lhs, "No lValue in assignment"); 321 return; 322 } 323 324 if (left instanceof JetArrayAccessExpression) { 325 ResolvedCall<FunctionDescriptor> setResolvedCall = trace.get(BindingContext.INDEXED_LVALUE_SET, left); 326 generateArrayAccess((JetArrayAccessExpression) left, setResolvedCall); 327 recordWrite(left, parentExpression); 328 return; 329 } 330 331 generateInstructions(rhs, NOT_IN_CONDITION); 332 if (left instanceof JetSimpleNameExpression || left instanceof JetProperty) { 333 // Do nothing, just record write below 334 } 335 else if (left instanceof JetQualifiedExpression) { 336 generateInstructions(((JetQualifiedExpression) left).getReceiverExpression(), NOT_IN_CONDITION); 337 } 338 else { 339 builder.unsupported(parentExpression); // TODO 340 } 341 342 recordWrite(left, parentExpression); 343 } 344 345 private void recordWrite(JetExpression left, JetExpression parentExpression) { 346 VariableDescriptor descriptor = BindingContextUtils.extractVariableDescriptorIfAny(trace.getBindingContext(), left, false); 347 if (descriptor != null) { 348 builder.write(parentExpression, left); 349 } 350 } 351 352 private void generateArrayAccess(JetArrayAccessExpression arrayAccessExpression, @Nullable ResolvedCall<?> resolvedCall) { 353 mark(arrayAccessExpression); 354 if (!checkAndGenerateCall(arrayAccessExpression, resolvedCall)) { 355 for (JetExpression index : arrayAccessExpression.getIndexExpressions()) { 356 generateInstructions(index, NOT_IN_CONDITION); 357 } 358 359 generateInstructions(arrayAccessExpression.getArrayExpression(), NOT_IN_CONDITION); 360 } 361 } 362 363 @Override 364 public void visitUnaryExpressionVoid(@NotNull JetUnaryExpression expression, CFPContext context) { 365 mark(expression); 366 JetSimpleNameExpression operationSign = expression.getOperationReference(); 367 IElementType operationType = operationSign.getReferencedNameElementType(); 368 JetExpression baseExpression = expression.getBaseExpression(); 369 if (baseExpression == null) return; 370 if (JetTokens.EXCLEXCL == operationType) { 371 generateInstructions(baseExpression, NOT_IN_CONDITION); 372 builder.predefinedOperation(expression, NOT_NULL_ASSERTION); 373 } 374 else { 375 if (!generateCall(expression.getOperationReference())) { 376 generateInstructions(baseExpression, NOT_IN_CONDITION); 377 } 378 379 boolean incrementOrDecrement = isIncrementOrDecrement(operationType); 380 if (incrementOrDecrement) { 381 // We skip dup's and other subtleties here 382 visitAssignment(baseExpression, null, expression); 383 } 384 } 385 } 386 387 private boolean isIncrementOrDecrement(IElementType operationType) { 388 return operationType == JetTokens.PLUSPLUS || operationType == JetTokens.MINUSMINUS; 389 } 390 391 392 @Override 393 public void visitIfExpressionVoid(@NotNull JetIfExpression expression, CFPContext context) { 394 mark(expression); 395 JetExpression condition = expression.getCondition(); 396 if (condition != null) { 397 generateInstructions(condition, IN_CONDITION); 398 } 399 Label elseLabel = builder.createUnboundLabel(); 400 builder.jumpOnFalse(elseLabel, expression); 401 JetExpression thenBranch = expression.getThen(); 402 if (thenBranch != null) { 403 generateInstructions(thenBranch, context); 404 } 405 else { 406 builder.loadUnit(expression); 407 } 408 Label resultLabel = builder.createUnboundLabel(); 409 builder.jump(resultLabel, expression); 410 builder.bindLabel(elseLabel); 411 JetExpression elseBranch = expression.getElse(); 412 if (elseBranch != null) { 413 generateInstructions(elseBranch, context); 414 } 415 else { 416 builder.loadUnit(expression); 417 } 418 builder.bindLabel(resultLabel); 419 } 420 421 private class FinallyBlockGenerator { 422 private final JetFinallySection finallyBlock; 423 private final CFPContext context; 424 private Label startFinally = null; 425 private Label finishFinally = null; 426 427 private FinallyBlockGenerator(JetFinallySection block, CFPContext context) { 428 finallyBlock = block; 429 this.context = context; 430 } 431 432 public void generate() { 433 JetBlockExpression finalExpression = finallyBlock.getFinalExpression(); 434 if (finalExpression == null) return; 435 if (startFinally != null) { 436 assert finishFinally != null; 437 builder.repeatPseudocode(startFinally, finishFinally); 438 return; 439 } 440 startFinally = builder.createUnboundLabel("start finally"); 441 builder.bindLabel(startFinally); 442 generateInstructions(finalExpression, context); 443 finishFinally = builder.createUnboundLabel("finish finally"); 444 builder.bindLabel(finishFinally); 445 } 446 } 447 448 449 @Override 450 public void visitTryExpressionVoid(@NotNull JetTryExpression expression, CFPContext context) { 451 mark(expression); 452 JetFinallySection finallyBlock = expression.getFinallyBlock(); 453 final FinallyBlockGenerator finallyBlockGenerator = new FinallyBlockGenerator(finallyBlock, context); 454 if (finallyBlock != null) { 455 builder.enterTryFinally(new GenerationTrigger() { 456 private boolean working = false; 457 458 @Override 459 public void generate() { 460 // This checks are needed for the case of having e.g. return inside finally: 'try {return} finally{return}' 461 if (working) return; 462 working = true; 463 finallyBlockGenerator.generate(); 464 working = false; 465 } 466 }); 467 } 468 469 List<JetCatchClause> catchClauses = expression.getCatchClauses(); 470 boolean hasCatches = !catchClauses.isEmpty(); 471 Label onException = null; 472 if (hasCatches) { 473 onException = builder.createUnboundLabel("onException"); 474 builder.nondeterministicJump(onException, expression); 475 } 476 Label onExceptionToFinallyBlock = null; 477 if (finallyBlock != null) { 478 onExceptionToFinallyBlock = builder.createUnboundLabel("onExceptionToFinallyBlock"); 479 builder.nondeterministicJump(onExceptionToFinallyBlock, expression); 480 } 481 generateInstructions(expression.getTryBlock(), context); 482 483 if (hasCatches) { 484 Label afterCatches = builder.createUnboundLabel("afterCatches"); 485 builder.jump(afterCatches, expression); 486 487 builder.bindLabel(onException); 488 LinkedList<Label> catchLabels = Lists.newLinkedList(); 489 int catchClausesSize = catchClauses.size(); 490 for (int i = 0; i < catchClausesSize - 1; i++) { 491 catchLabels.add(builder.createUnboundLabel("catch " + i)); 492 } 493 if (!catchLabels.isEmpty()) { 494 builder.nondeterministicJump(catchLabels, expression); 495 } 496 boolean isFirst = true; 497 for (JetCatchClause catchClause : catchClauses) { 498 builder.enterLexicalScope(catchClause); 499 if (!isFirst) { 500 builder.bindLabel(catchLabels.remove()); 501 } 502 else { 503 isFirst = false; 504 } 505 JetParameter catchParameter = catchClause.getCatchParameter(); 506 if (catchParameter != null) { 507 builder.declareParameter(catchParameter); 508 builder.write(catchParameter, catchParameter); 509 } 510 JetExpression catchBody = catchClause.getCatchBody(); 511 if (catchBody != null) { 512 generateInstructions(catchBody, NOT_IN_CONDITION); 513 } 514 builder.jump(afterCatches, expression); 515 builder.exitLexicalScope(catchClause); 516 } 517 518 builder.bindLabel(afterCatches); 519 } 520 521 if (finallyBlock != null) { 522 builder.exitTryFinally(); 523 524 Label skipFinallyToErrorBlock = builder.createUnboundLabel("skipFinallyToErrorBlock"); 525 builder.jump(skipFinallyToErrorBlock, expression); 526 builder.bindLabel(onExceptionToFinallyBlock); 527 finallyBlockGenerator.generate(); 528 builder.jumpToError(expression); 529 builder.bindLabel(skipFinallyToErrorBlock); 530 531 finallyBlockGenerator.generate(); 532 } 533 } 534 535 @Override 536 public void visitWhileExpressionVoid(@NotNull JetWhileExpression expression, CFPContext context) { 537 mark(expression); 538 LoopInfo loopInfo = builder.enterLoop(expression, null, null); 539 540 builder.bindLabel(loopInfo.getConditionEntryPoint()); 541 JetExpression condition = expression.getCondition(); 542 if (condition != null) { 543 generateInstructions(condition, IN_CONDITION); 544 } 545 boolean conditionIsTrueConstant = CompileTimeConstantUtils.canBeReducedToBooleanConstant(condition, trace, true); 546 if (!conditionIsTrueConstant) { 547 builder.jumpOnFalse(loopInfo.getExitPoint(), expression); 548 } 549 550 builder.bindLabel(loopInfo.getBodyEntryPoint()); 551 JetExpression body = expression.getBody(); 552 if (body != null) { 553 generateInstructions(body, NOT_IN_CONDITION); 554 } 555 builder.jump(loopInfo.getEntryPoint(), expression); 556 builder.exitLoop(expression); 557 builder.loadUnit(expression); 558 } 559 560 @Override 561 public void visitDoWhileExpressionVoid(@NotNull JetDoWhileExpression expression, CFPContext context) { 562 builder.enterLexicalScope(expression); 563 mark(expression); 564 LoopInfo loopInfo = builder.enterLoop(expression, null, null); 565 566 builder.bindLabel(loopInfo.getBodyEntryPoint()); 567 JetExpression body = expression.getBody(); 568 if (body != null) { 569 generateInstructions(body, NOT_IN_CONDITION); 570 } 571 builder.bindLabel(loopInfo.getConditionEntryPoint()); 572 JetExpression condition = expression.getCondition(); 573 if (condition != null) { 574 generateInstructions(condition, IN_CONDITION); 575 } 576 builder.jumpOnTrue(loopInfo.getEntryPoint(), expression); 577 builder.exitLoop(expression); 578 builder.loadUnit(expression); 579 builder.exitLexicalScope(expression); 580 } 581 582 @Override 583 public void visitForExpressionVoid(@NotNull JetForExpression expression, CFPContext context) { 584 builder.enterLexicalScope(expression); 585 mark(expression); 586 JetExpression loopRange = expression.getLoopRange(); 587 if (loopRange != null) { 588 generateInstructions(loopRange, NOT_IN_CONDITION); 589 } 590 declareLoopParameter(expression); 591 592 // TODO : primitive cases 593 Label loopExitPoint = builder.createUnboundLabel(); 594 Label conditionEntryPoint = builder.createUnboundLabel(); 595 596 builder.bindLabel(conditionEntryPoint); 597 builder.nondeterministicJump(loopExitPoint, expression); 598 599 LoopInfo loopInfo = builder.enterLoop(expression, loopExitPoint, conditionEntryPoint); 600 601 builder.bindLabel(loopInfo.getBodyEntryPoint()); 602 writeLoopParameterAssignment(expression); 603 604 JetExpression body = expression.getBody(); 605 if (body != null) { 606 generateInstructions(body, NOT_IN_CONDITION); 607 } 608 609 builder.nondeterministicJump(loopInfo.getEntryPoint(), expression); 610 builder.exitLoop(expression); 611 builder.loadUnit(expression); 612 builder.exitLexicalScope(expression); 613 } 614 615 private void declareLoopParameter(JetForExpression expression) { 616 JetParameter loopParameter = expression.getLoopParameter(); 617 JetMultiDeclaration multiDeclaration = expression.getMultiParameter(); 618 if (loopParameter != null) { 619 builder.declareParameter(loopParameter); 620 } 621 else if (multiDeclaration != null) { 622 visitMultiDeclaration(multiDeclaration, false); 623 } 624 } 625 626 private void writeLoopParameterAssignment(JetForExpression expression) { 627 JetParameter loopParameter = expression.getLoopParameter(); 628 JetMultiDeclaration multiDeclaration = expression.getMultiParameter(); 629 if (loopParameter != null) { 630 builder.write(loopParameter, loopParameter); 631 } 632 else if (multiDeclaration != null) { 633 for (JetMultiDeclarationEntry entry : multiDeclaration.getEntries()) { 634 builder.write(entry, entry); 635 } 636 } 637 } 638 639 @Override 640 public void visitBreakExpressionVoid(@NotNull JetBreakExpression expression, CFPContext context) { 641 JetElement loop = getCorrespondingLoop(expression); 642 if (loop != null) { 643 checkJumpDoesNotCrossFunctionBoundary(expression, loop); 644 builder.jump(builder.getExitPoint(loop), expression); 645 } 646 } 647 648 @Override 649 public void visitContinueExpressionVoid(@NotNull JetContinueExpression expression, CFPContext context) { 650 JetElement loop = getCorrespondingLoop(expression); 651 if (loop != null) { 652 checkJumpDoesNotCrossFunctionBoundary(expression, loop); 653 builder.jump(builder.getEntryPoint(loop), expression); 654 } 655 } 656 657 private JetElement getCorrespondingLoop(JetExpressionWithLabel expression) { 658 String labelName = expression.getLabelName(); 659 JetElement loop; 660 if (labelName != null) { 661 JetSimpleNameExpression targetLabel = expression.getTargetLabel(); 662 assert targetLabel != null; 663 PsiElement labeledElement = trace.get(BindingContext.LABEL_TARGET, targetLabel); 664 if (labeledElement instanceof JetLoopExpression) { 665 loop = (JetLoopExpression) labeledElement; 666 } 667 else { 668 trace.report(NOT_A_LOOP_LABEL.on(expression, targetLabel.getText())); 669 loop = null; 670 } 671 } 672 else { 673 loop = builder.getCurrentLoop(); 674 if (loop == null) { 675 trace.report(BREAK_OR_CONTINUE_OUTSIDE_A_LOOP.on(expression)); 676 } 677 } 678 return loop; 679 } 680 681 private void checkJumpDoesNotCrossFunctionBoundary(@NotNull JetExpressionWithLabel jumpExpression, @NotNull JetElement jumpTarget) { 682 BindingContext bindingContext = trace.getBindingContext(); 683 684 FunctionDescriptor labelExprEnclosingFunc = BindingContextUtils.getEnclosingFunctionDescriptor(bindingContext, jumpExpression); 685 FunctionDescriptor labelTargetEnclosingFunc = BindingContextUtils.getEnclosingFunctionDescriptor(bindingContext, jumpTarget); 686 if (labelExprEnclosingFunc != labelTargetEnclosingFunc) { 687 trace.report(BREAK_OR_CONTINUE_JUMPS_ACROSS_FUNCTION_BOUNDARY.on(jumpExpression)); 688 } 689 } 690 691 @Override 692 public void visitReturnExpressionVoid(@NotNull JetReturnExpression expression, CFPContext context) { 693 JetExpression returnedExpression = expression.getReturnedExpression(); 694 if (returnedExpression != null) { 695 generateInstructions(returnedExpression, NOT_IN_CONDITION); 696 } 697 JetSimpleNameExpression labelElement = expression.getTargetLabel(); 698 JetElement subroutine; 699 String labelName = expression.getLabelName(); 700 if (labelElement != null && labelName != null) { 701 PsiElement labeledElement = trace.get(BindingContext.LABEL_TARGET, labelElement); 702 if (labeledElement != null) { 703 assert labeledElement instanceof JetElement; 704 subroutine = (JetElement) labeledElement; 705 } 706 else { 707 subroutine = null; 708 } 709 } 710 else { 711 subroutine = builder.getReturnSubroutine(); 712 // TODO : a context check 713 } 714 715 if (subroutine instanceof JetFunction || subroutine instanceof JetPropertyAccessor) { 716 if (returnedExpression == null) { 717 builder.returnNoValue(expression, subroutine); 718 } 719 else { 720 builder.returnValue(expression, subroutine); 721 } 722 } 723 } 724 725 @Override 726 public void visitParameterVoid(@NotNull JetParameter parameter, CFPContext context) { 727 builder.declareParameter(parameter); 728 JetExpression defaultValue = parameter.getDefaultValue(); 729 if (defaultValue != null) { 730 generateInstructions(defaultValue, context); 731 } 732 builder.write(parameter, parameter); 733 } 734 735 @Override 736 public void visitBlockExpressionVoid(@NotNull JetBlockExpression expression, CFPContext context) { 737 boolean declareLexicalScope = !isBlockInDoWhile(expression); 738 if (declareLexicalScope) { 739 builder.enterLexicalScope(expression); 740 } 741 mark(expression); 742 List<JetElement> statements = expression.getStatements(); 743 for (JetElement statement : statements) { 744 generateInstructions(statement, NOT_IN_CONDITION); 745 } 746 if (statements.isEmpty()) { 747 builder.loadUnit(expression); 748 } 749 if (declareLexicalScope) { 750 builder.exitLexicalScope(expression); 751 } 752 } 753 754 private boolean isBlockInDoWhile(@NotNull JetBlockExpression expression) { 755 PsiElement parent = expression.getParent(); 756 if (parent == null) return false; 757 return parent.getParent() instanceof JetDoWhileExpression; 758 } 759 760 @Override 761 public void visitNamedFunctionVoid(@NotNull JetNamedFunction function, CFPContext context) { 762 processLocalDeclaration(function); 763 } 764 765 @Override 766 public void visitFunctionLiteralExpressionVoid(@NotNull JetFunctionLiteralExpression expression, CFPContext context) { 767 mark(expression); 768 JetFunctionLiteral functionLiteral = expression.getFunctionLiteral(); 769 processLocalDeclaration(functionLiteral); 770 builder.createFunctionLiteral(expression); 771 } 772 773 @Override 774 public void visitQualifiedExpressionVoid(@NotNull JetQualifiedExpression expression, CFPContext context) { 775 mark(expression); 776 JetExpression selectorExpression = expression.getSelectorExpression(); 777 778 if (selectorExpression == null) { 779 generateInstructions(expression.getReceiverExpression(), NOT_IN_CONDITION); 780 return; 781 } 782 783 generateInstructions(selectorExpression, NOT_IN_CONDITION); 784 785 // receiver was generated for resolvedCall 786 JetExpression calleeExpression = JetPsiUtil.getCalleeExpressionIfAny(selectorExpression); 787 if (calleeExpression == null || getResolvedCall(calleeExpression) == null) { 788 generateInstructions(expression.getReceiverExpression(), NOT_IN_CONDITION); 789 } 790 } 791 792 @Override 793 public void visitCallExpressionVoid(@NotNull JetCallExpression expression, CFPContext context) { 794 mark(expression); 795 if (!generateCall(expression.getCalleeExpression())) { 796 for (ValueArgument argument : expression.getValueArguments()) { 797 JetExpression argumentExpression = argument.getArgumentExpression(); 798 if (argumentExpression != null) { 799 generateInstructions(argumentExpression, NOT_IN_CONDITION); 800 } 801 } 802 803 for (JetExpression functionLiteral : expression.getFunctionLiteralArguments()) { 804 generateInstructions(functionLiteral, NOT_IN_CONDITION); 805 } 806 807 generateInstructions(expression.getCalleeExpression(), NOT_IN_CONDITION); 808 } 809 } 810 811 @Override 812 public void visitPropertyVoid(@NotNull JetProperty property, CFPContext context) { 813 builder.declareVariable(property); 814 JetExpression initializer = property.getInitializer(); 815 if (initializer != null) { 816 generateInstructions(initializer, NOT_IN_CONDITION); 817 visitAssignment(property, null, property); 818 } 819 JetExpression delegate = property.getDelegateExpression(); 820 if (delegate != null) { 821 generateInstructions(delegate, NOT_IN_CONDITION); 822 } 823 if (JetPsiUtil.isLocal(property)) { 824 for (JetPropertyAccessor accessor : property.getAccessors()) { 825 generateInstructions(accessor, NOT_IN_CONDITION); 826 } 827 } 828 } 829 830 @Override 831 public void visitMultiDeclarationVoid(@NotNull JetMultiDeclaration declaration, CFPContext context) { 832 visitMultiDeclaration(declaration, true); 833 } 834 835 private void visitMultiDeclaration(@NotNull JetMultiDeclaration declaration, boolean generateWriteForEntries) { 836 generateInstructions(declaration.getInitializer(), NOT_IN_CONDITION); 837 838 for (JetMultiDeclarationEntry entry : declaration.getEntries()) { 839 builder.declareVariable(entry); 840 ResolvedCall<FunctionDescriptor> resolvedCall = trace.get(BindingContext.COMPONENT_RESOLVED_CALL, entry); 841 if (resolvedCall != null) { 842 builder.call(entry, resolvedCall); 843 } 844 if (generateWriteForEntries) { 845 builder.write(entry, entry); 846 } 847 } 848 } 849 850 @Override 851 public void visitPropertyAccessorVoid(@NotNull JetPropertyAccessor accessor, CFPContext context) { 852 processLocalDeclaration(accessor); 853 } 854 855 @Override 856 public void visitBinaryWithTypeRHSExpressionVoid(@NotNull JetBinaryExpressionWithTypeRHS expression, CFPContext context) { 857 mark(expression); 858 IElementType operationType = expression.getOperationReference().getReferencedNameElementType(); 859 if (operationType == JetTokens.COLON || operationType == JetTokens.AS_KEYWORD || operationType == JetTokens.AS_SAFE) { 860 generateInstructions(expression.getLeft(), NOT_IN_CONDITION); 861 } 862 else { 863 visitJetElementVoid(expression, context); 864 } 865 } 866 867 @Override 868 public void visitThrowExpressionVoid(@NotNull JetThrowExpression expression, CFPContext context) { 869 mark(expression); 870 JetExpression thrownExpression = expression.getThrownExpression(); 871 if (thrownExpression != null) { 872 generateInstructions(thrownExpression, NOT_IN_CONDITION); 873 } 874 builder.throwException(expression); 875 } 876 877 @Override 878 public void visitArrayAccessExpressionVoid(@NotNull JetArrayAccessExpression expression, CFPContext context) { 879 mark(expression); 880 ResolvedCall<FunctionDescriptor> getMethodResolvedCall = trace.get(BindingContext.INDEXED_LVALUE_GET, expression); 881 if (!checkAndGenerateCall(expression, getMethodResolvedCall)) { 882 generateArrayAccess(expression, getMethodResolvedCall); 883 } 884 } 885 886 @Override 887 public void visitIsExpressionVoid(@NotNull JetIsExpression expression, CFPContext context) { 888 mark(expression); 889 generateInstructions(expression.getLeftHandSide(), context); 890 } 891 892 @Override 893 public void visitWhenExpressionVoid(@NotNull JetWhenExpression expression, CFPContext context) { 894 mark(expression); 895 JetExpression subjectExpression = expression.getSubjectExpression(); 896 if (subjectExpression != null) { 897 generateInstructions(subjectExpression, context); 898 } 899 boolean hasElse = false; 900 901 Label doneLabel = builder.createUnboundLabel(); 902 903 Label nextLabel = null; 904 for (Iterator<JetWhenEntry> iterator = expression.getEntries().iterator(); iterator.hasNext(); ) { 905 JetWhenEntry whenEntry = iterator.next(); 906 mark(whenEntry); 907 908 boolean isElse = whenEntry.isElse(); 909 if (isElse) { 910 hasElse = true; 911 if (iterator.hasNext()) { 912 trace.report(ELSE_MISPLACED_IN_WHEN.on(whenEntry)); 913 } 914 } 915 Label bodyLabel = builder.createUnboundLabel(); 916 917 JetWhenCondition[] conditions = whenEntry.getConditions(); 918 for (int i = 0; i < conditions.length; i++) { 919 JetWhenCondition condition = conditions[i]; 920 condition.accept(conditionVisitor, context); 921 if (i + 1 < conditions.length) { 922 builder.nondeterministicJump(bodyLabel, expression); 923 } 924 } 925 926 if (!isElse) { 927 nextLabel = builder.createUnboundLabel(); 928 builder.nondeterministicJump(nextLabel, expression); 929 } 930 931 builder.bindLabel(bodyLabel); 932 generateInstructions(whenEntry.getExpression(), context); 933 builder.jump(doneLabel, expression); 934 935 if (!isElse) { 936 builder.bindLabel(nextLabel); 937 } 938 } 939 builder.bindLabel(doneLabel); 940 if (!hasElse && WhenChecker.mustHaveElse(expression, trace)) { 941 trace.report(NO_ELSE_IN_WHEN.on(expression)); 942 } 943 } 944 945 @Override 946 public void visitObjectLiteralExpressionVoid(@NotNull JetObjectLiteralExpression expression, CFPContext context) { 947 mark(expression); 948 JetObjectDeclaration declaration = expression.getObjectDeclaration(); 949 generateInstructions(declaration, context); 950 951 builder.createAnonymousObject(expression); 952 } 953 954 @Override 955 public void visitObjectDeclarationVoid(@NotNull JetObjectDeclaration objectDeclaration, CFPContext context) { 956 visitClassOrObject(objectDeclaration, context); 957 } 958 959 @Override 960 public void visitStringTemplateExpressionVoid(@NotNull JetStringTemplateExpression expression, CFPContext context) { 961 mark(expression); 962 for (JetStringTemplateEntry entry : expression.getEntries()) { 963 if (entry instanceof JetStringTemplateEntryWithExpression) { 964 JetStringTemplateEntryWithExpression entryWithExpression = (JetStringTemplateEntryWithExpression) entry; 965 generateInstructions(entryWithExpression.getExpression(), NOT_IN_CONDITION); 966 } 967 } 968 builder.loadStringTemplate(expression); 969 } 970 971 @Override 972 public void visitTypeProjectionVoid(@NotNull JetTypeProjection typeProjection, CFPContext context) { 973 // TODO : Support Type Arguments. Class object may be initialized at this point"); 974 } 975 976 @Override 977 public void visitAnonymousInitializerVoid(@NotNull JetClassInitializer classInitializer, CFPContext context) { 978 generateInstructions(classInitializer.getBody(), context); 979 } 980 981 private void visitClassOrObject(JetClassOrObject classOrObject, CFPContext context) { 982 for (JetDelegationSpecifier specifier : classOrObject.getDelegationSpecifiers()) { 983 generateInstructions(specifier, context); 984 } 985 List<JetDeclaration> declarations = classOrObject.getDeclarations(); 986 if (classOrObject.isLocal()) { 987 for (JetDeclaration declaration : declarations) { 988 generateInstructions(declaration, context); 989 } 990 return; 991 } 992 //For top-level and inner classes and objects functions are collected and checked separately. 993 for (JetDeclaration declaration : declarations) { 994 if (declaration instanceof JetProperty || declaration instanceof JetClassInitializer) { 995 generateInstructions(declaration, context); 996 } 997 } 998 } 999 1000 @Override 1001 public void visitClassVoid(@NotNull JetClass klass, CFPContext context) { 1002 List<JetParameter> parameters = klass.getPrimaryConstructorParameters(); 1003 for (JetParameter parameter : parameters) { 1004 generateInstructions(parameter, context); 1005 } 1006 visitClassOrObject(klass, context); 1007 } 1008 1009 @Override 1010 public void visitDelegationToSuperCallSpecifierVoid(@NotNull JetDelegatorToSuperCall call, CFPContext context) { 1011 List<? extends ValueArgument> valueArguments = call.getValueArguments(); 1012 for (ValueArgument valueArgument : valueArguments) { 1013 generateInstructions(valueArgument.getArgumentExpression(), context); 1014 } 1015 } 1016 1017 @Override 1018 public void visitDelegationByExpressionSpecifierVoid(@NotNull JetDelegatorByExpressionSpecifier specifier, CFPContext context) { 1019 generateInstructions(specifier.getDelegateExpression(), context); 1020 } 1021 1022 @Override 1023 public void visitJetFileVoid(@NotNull JetFile file, CFPContext context) { 1024 for (JetDeclaration declaration : file.getDeclarations()) { 1025 if (declaration instanceof JetProperty) { 1026 generateInstructions(declaration, context); 1027 } 1028 } 1029 } 1030 1031 @Override 1032 public void visitJetElementVoid(@NotNull JetElement element, CFPContext context) { 1033 builder.unsupported(element); 1034 } 1035 1036 @Nullable 1037 private ResolvedCall<?> getResolvedCall(@NotNull JetElement expression) { 1038 return trace.get(BindingContext.RESOLVED_CALL, expression); 1039 } 1040 1041 private boolean generateCall(@Nullable JetExpression calleeExpression) { 1042 if (calleeExpression == null) return false; 1043 return checkAndGenerateCall(calleeExpression, getResolvedCall(calleeExpression)); 1044 } 1045 1046 private boolean checkAndGenerateCall(JetExpression calleeExpression, @Nullable ResolvedCall<?> resolvedCall) { 1047 if (resolvedCall == null) { 1048 builder.compilationError(calleeExpression, "No resolved call"); 1049 return false; 1050 } 1051 generateCall(calleeExpression, resolvedCall); 1052 return true; 1053 } 1054 1055 private void generateCall(JetExpression calleeExpression, ResolvedCall<?> resolvedCall) { 1056 if (resolvedCall instanceof VariableAsFunctionResolvedCall) { 1057 VariableAsFunctionResolvedCall variableAsFunctionResolvedCall = (VariableAsFunctionResolvedCall) resolvedCall; 1058 generateCall(calleeExpression, variableAsFunctionResolvedCall.getFunctionCall()); 1059 return; 1060 } 1061 1062 CallableDescriptor resultingDescriptor = resolvedCall.getResultingDescriptor(); 1063 1064 generateReceiver(resolvedCall.getThisObject()); 1065 generateReceiver(resolvedCall.getReceiverArgument()); 1066 1067 for (ValueParameterDescriptor parameterDescriptor : resultingDescriptor.getValueParameters()) { 1068 ResolvedValueArgument argument = resolvedCall.getValueArguments().get(parameterDescriptor); 1069 if (argument == null) continue; 1070 1071 generateValueArgument(argument); 1072 } 1073 1074 if (resultingDescriptor instanceof VariableDescriptor) { 1075 builder.readVariable(calleeExpression, (VariableDescriptor) resultingDescriptor); 1076 } 1077 else { 1078 builder.call(calleeExpression, resolvedCall); 1079 } 1080 } 1081 1082 private void generateReceiver(ReceiverValue receiver) { 1083 if (!receiver.exists()) return; 1084 if (receiver instanceof ThisReceiver) { 1085 // TODO: Receiver is passed implicitly: no expression to tie the read to 1086 } 1087 else if (receiver instanceof ExpressionReceiver) { 1088 generateInstructions(((ExpressionReceiver) receiver).getExpression(), NOT_IN_CONDITION); 1089 } 1090 else if (receiver instanceof TransientReceiver) { 1091 // Do nothing 1092 } 1093 else { 1094 throw new IllegalArgumentException("Unknown receiver kind: " + receiver); 1095 } 1096 } 1097 1098 private void generateValueArgument(ResolvedValueArgument argument) { 1099 for (ValueArgument valueArgument : argument.getArguments()) { 1100 JetExpression expression = valueArgument.getArgumentExpression(); 1101 if (expression != null) { 1102 generateInstructions(expression, NOT_IN_CONDITION); 1103 } 1104 } 1105 } 1106 } 1107 }