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