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