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