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