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 checkJumpDoesNotCrossFunctionBoundary(expression, loop); 640 builder.jump(builder.getExitPoint(loop)); 641 } 642 } 643 644 @Override 645 public void visitContinueExpressionVoid(@NotNull JetContinueExpression expression, CFPContext context) { 646 JetElement loop = getCorrespondingLoop(expression); 647 if (loop != null) { 648 checkJumpDoesNotCrossFunctionBoundary(expression, loop); 649 builder.jump(builder.getEntryPoint(loop)); 650 } 651 } 652 653 private JetElement getCorrespondingLoop(JetLabelQualifiedExpression expression) { 654 String labelName = expression.getLabelName(); 655 JetElement loop; 656 if (labelName != null) { 657 JetSimpleNameExpression targetLabel = expression.getTargetLabel(); 658 assert targetLabel != null; 659 PsiElement labeledElement = trace.get(BindingContext.LABEL_TARGET, targetLabel); 660 if (labeledElement instanceof JetLoopExpression) { 661 loop = (JetLoopExpression) labeledElement; 662 } 663 else { 664 trace.report(NOT_A_LOOP_LABEL.on(expression, targetLabel.getText())); 665 loop = null; 666 } 667 } 668 else { 669 loop = builder.getCurrentLoop(); 670 if (loop == null) { 671 trace.report(BREAK_OR_CONTINUE_OUTSIDE_A_LOOP.on(expression)); 672 } 673 } 674 return loop; 675 } 676 677 private void checkJumpDoesNotCrossFunctionBoundary(@NotNull JetLabelQualifiedExpression jumpExpression, @NotNull JetElement jumpTarget) { 678 BindingContext bindingContext = trace.getBindingContext(); 679 680 FunctionDescriptor labelExprEnclosingFunc = BindingContextUtils.getEnclosingFunctionDescriptor(bindingContext, jumpExpression); 681 FunctionDescriptor labelTargetEnclosingFunc = BindingContextUtils.getEnclosingFunctionDescriptor(bindingContext, jumpTarget); 682 if (labelExprEnclosingFunc != labelTargetEnclosingFunc) { 683 trace.report(BREAK_OR_CONTINUE_JUMPS_ACROSS_FUNCTION_BOUNDARY.on(jumpExpression)); 684 } 685 } 686 687 @Override 688 public void visitReturnExpressionVoid(@NotNull JetReturnExpression expression, CFPContext context) { 689 JetExpression returnedExpression = expression.getReturnedExpression(); 690 if (returnedExpression != null) { 691 generateInstructions(returnedExpression, NOT_IN_CONDITION); 692 } 693 JetSimpleNameExpression labelElement = expression.getTargetLabel(); 694 JetElement subroutine; 695 String labelName = expression.getLabelName(); 696 if (labelElement != null) { 697 assert labelName != null; 698 PsiElement labeledElement = trace.get(BindingContext.LABEL_TARGET, labelElement); 699 if (labeledElement != null) { 700 assert labeledElement instanceof JetElement; 701 subroutine = (JetElement) labeledElement; 702 } 703 else { 704 subroutine = null; 705 } 706 } 707 else { 708 subroutine = builder.getReturnSubroutine(); 709 // TODO : a context check 710 } 711 712 if (subroutine instanceof JetFunction || subroutine instanceof JetPropertyAccessor) { 713 if (returnedExpression == null) { 714 builder.returnNoValue(expression, subroutine); 715 } 716 else { 717 builder.returnValue(expression, subroutine); 718 } 719 } 720 } 721 722 @Override 723 public void visitParameterVoid(@NotNull JetParameter parameter, CFPContext context) { 724 builder.declareParameter(parameter); 725 JetExpression defaultValue = parameter.getDefaultValue(); 726 if (defaultValue != null) { 727 generateInstructions(defaultValue, context); 728 } 729 builder.write(parameter, parameter); 730 } 731 732 @Override 733 public void visitBlockExpressionVoid(@NotNull JetBlockExpression expression, CFPContext context) { 734 mark(expression); 735 List<JetElement> statements = expression.getStatements(); 736 for (JetElement statement : statements) { 737 generateInstructions(statement, NOT_IN_CONDITION); 738 } 739 if (statements.isEmpty()) { 740 builder.loadUnit(expression); 741 } 742 } 743 744 @Override 745 public void visitNamedFunctionVoid(@NotNull JetNamedFunction function, CFPContext context) { 746 processLocalDeclaration(function); 747 } 748 749 @Override 750 public void visitFunctionLiteralExpressionVoid(@NotNull JetFunctionLiteralExpression expression, CFPContext context) { 751 mark(expression); 752 JetFunctionLiteral functionLiteral = expression.getFunctionLiteral(); 753 processLocalDeclaration(functionLiteral); 754 builder.createFunctionLiteral(expression); 755 } 756 757 @Override 758 public void visitQualifiedExpressionVoid(@NotNull JetQualifiedExpression expression, CFPContext context) { 759 mark(expression); 760 JetExpression selectorExpression = expression.getSelectorExpression(); 761 762 if (selectorExpression == null) { 763 generateInstructions(expression.getReceiverExpression(), NOT_IN_CONDITION); 764 return; 765 } 766 767 generateInstructions(selectorExpression, NOT_IN_CONDITION); 768 769 // receiver was generated for resolvedCall 770 JetExpression calleeExpression = JetPsiUtil.getCalleeExpressionIfAny(selectorExpression); 771 if (calleeExpression == null || getResolvedCall(calleeExpression) == null) { 772 generateInstructions(expression.getReceiverExpression(), NOT_IN_CONDITION); 773 } 774 } 775 776 @Override 777 public void visitCallExpressionVoid(@NotNull JetCallExpression expression, CFPContext context) { 778 mark(expression); 779 if (!generateCall(expression.getCalleeExpression())) { 780 for (ValueArgument argument : expression.getValueArguments()) { 781 JetExpression argumentExpression = argument.getArgumentExpression(); 782 if (argumentExpression != null) { 783 generateInstructions(argumentExpression, NOT_IN_CONDITION); 784 } 785 } 786 787 for (JetExpression functionLiteral : expression.getFunctionLiteralArguments()) { 788 generateInstructions(functionLiteral, NOT_IN_CONDITION); 789 } 790 791 generateInstructions(expression.getCalleeExpression(), NOT_IN_CONDITION); 792 } 793 } 794 795 @Override 796 public void visitPropertyVoid(@NotNull JetProperty property, CFPContext context) { 797 builder.declareVariable(property); 798 JetExpression initializer = property.getInitializer(); 799 if (initializer != null) { 800 generateInstructions(initializer, NOT_IN_CONDITION); 801 visitAssignment(property, null, property); 802 } 803 JetExpression delegate = property.getDelegateExpression(); 804 if (delegate != null) { 805 generateInstructions(delegate, NOT_IN_CONDITION); 806 } 807 if (JetPsiUtil.isLocal(property)) { 808 for (JetPropertyAccessor accessor : property.getAccessors()) { 809 generateInstructions(accessor, NOT_IN_CONDITION); 810 } 811 } 812 } 813 814 @Override 815 public void visitMultiDeclarationVoid(@NotNull JetMultiDeclaration declaration, CFPContext context) { 816 JetExpression initializer = declaration.getInitializer(); 817 if (initializer != null) { 818 generateInstructions(initializer, NOT_IN_CONDITION); 819 } 820 List<JetMultiDeclarationEntry> entries = declaration.getEntries(); 821 for (JetMultiDeclarationEntry entry : entries) { 822 builder.declareVariable(entry); 823 ResolvedCall<FunctionDescriptor> resolvedCall = trace.get(BindingContext.COMPONENT_RESOLVED_CALL, entry); 824 if (resolvedCall != null) { 825 builder.call(entry, resolvedCall); 826 } 827 builder.write(entry, entry); 828 } 829 } 830 831 @Override 832 public void visitPropertyAccessorVoid(@NotNull JetPropertyAccessor accessor, CFPContext context) { 833 processLocalDeclaration(accessor); 834 } 835 836 @Override 837 public void visitBinaryWithTypeRHSExpressionVoid(@NotNull JetBinaryExpressionWithTypeRHS expression, CFPContext context) { 838 mark(expression); 839 IElementType operationType = expression.getOperationReference().getReferencedNameElementType(); 840 if (operationType == JetTokens.COLON || operationType == JetTokens.AS_KEYWORD || operationType == JetTokens.AS_SAFE) { 841 generateInstructions(expression.getLeft(), NOT_IN_CONDITION); 842 } 843 else { 844 visitJetElementVoid(expression, context); 845 } 846 } 847 848 @Override 849 public void visitThrowExpressionVoid(@NotNull JetThrowExpression expression, CFPContext context) { 850 mark(expression); 851 JetExpression thrownExpression = expression.getThrownExpression(); 852 if (thrownExpression != null) { 853 generateInstructions(thrownExpression, NOT_IN_CONDITION); 854 } 855 builder.throwException(expression); 856 } 857 858 @Override 859 public void visitArrayAccessExpressionVoid(@NotNull JetArrayAccessExpression expression, CFPContext context) { 860 mark(expression); 861 ResolvedCall<FunctionDescriptor> getMethodResolvedCall = trace.get(BindingContext.INDEXED_LVALUE_GET, expression); 862 if (!checkAndGenerateCall(expression, getMethodResolvedCall)) { 863 generateArrayAccess(expression, getMethodResolvedCall); 864 } 865 } 866 867 @Override 868 public void visitIsExpressionVoid(@NotNull JetIsExpression expression, CFPContext context) { 869 mark(expression); 870 generateInstructions(expression.getLeftHandSide(), context); 871 } 872 873 @Override 874 public void visitWhenExpressionVoid(@NotNull JetWhenExpression expression, CFPContext context) { 875 mark(expression); 876 JetExpression subjectExpression = expression.getSubjectExpression(); 877 if (subjectExpression != null) { 878 generateInstructions(subjectExpression, context); 879 } 880 boolean hasElse = false; 881 882 Label doneLabel = builder.createUnboundLabel(); 883 884 Label nextLabel = null; 885 for (Iterator<JetWhenEntry> iterator = expression.getEntries().iterator(); iterator.hasNext(); ) { 886 JetWhenEntry whenEntry = iterator.next(); 887 mark(whenEntry); 888 889 boolean isElse = whenEntry.isElse(); 890 if (isElse) { 891 hasElse = true; 892 if (iterator.hasNext()) { 893 trace.report(ELSE_MISPLACED_IN_WHEN.on(whenEntry)); 894 } 895 } 896 Label bodyLabel = builder.createUnboundLabel(); 897 898 JetWhenCondition[] conditions = whenEntry.getConditions(); 899 for (int i = 0; i < conditions.length; i++) { 900 JetWhenCondition condition = conditions[i]; 901 condition.accept(conditionVisitor, context); 902 if (i + 1 < conditions.length) { 903 builder.nondeterministicJump(bodyLabel); 904 } 905 } 906 907 if (!isElse) { 908 nextLabel = builder.createUnboundLabel(); 909 builder.nondeterministicJump(nextLabel); 910 } 911 912 builder.bindLabel(bodyLabel); 913 generateInstructions(whenEntry.getExpression(), context); 914 builder.jump(doneLabel); 915 916 if (!isElse) { 917 builder.bindLabel(nextLabel); 918 } 919 } 920 builder.bindLabel(doneLabel); 921 if (!hasElse && WhenChecker.mustHaveElse(expression, trace)) { 922 trace.report(NO_ELSE_IN_WHEN.on(expression)); 923 } 924 } 925 926 @Override 927 public void visitObjectLiteralExpressionVoid(@NotNull JetObjectLiteralExpression expression, CFPContext context) { 928 mark(expression); 929 JetObjectDeclaration declaration = expression.getObjectDeclaration(); 930 generateInstructions(declaration, context); 931 932 builder.createAnonymousObject(expression); 933 } 934 935 @Override 936 public void visitObjectDeclarationVoid(@NotNull JetObjectDeclaration objectDeclaration, CFPContext context) { 937 visitClassOrObject(objectDeclaration, context); 938 } 939 940 @Override 941 public void visitStringTemplateExpressionVoid(@NotNull JetStringTemplateExpression expression, CFPContext context) { 942 mark(expression); 943 for (JetStringTemplateEntry entry : expression.getEntries()) { 944 if (entry instanceof JetStringTemplateEntryWithExpression) { 945 JetStringTemplateEntryWithExpression entryWithExpression = (JetStringTemplateEntryWithExpression) entry; 946 generateInstructions(entryWithExpression.getExpression(), NOT_IN_CONDITION); 947 } 948 } 949 builder.loadStringTemplate(expression); 950 } 951 952 @Override 953 public void visitTypeProjectionVoid(@NotNull JetTypeProjection typeProjection, CFPContext context) { 954 // TODO : Support Type Arguments. Class object may be initialized at this point"); 955 } 956 957 @Override 958 public void visitAnonymousInitializerVoid(@NotNull JetClassInitializer classInitializer, CFPContext context) { 959 generateInstructions(classInitializer.getBody(), context); 960 } 961 962 private void visitClassOrObject(JetClassOrObject classOrObject, CFPContext context) { 963 for (JetDelegationSpecifier specifier : classOrObject.getDelegationSpecifiers()) { 964 generateInstructions(specifier, context); 965 } 966 List<JetDeclaration> declarations = classOrObject.getDeclarations(); 967 if (JetPsiUtil.isLocal(classOrObject)) { 968 for (JetDeclaration declaration : declarations) { 969 generateInstructions(declaration, context); 970 } 971 return; 972 } 973 //For top-level and inner classes and objects functions are collected and checked separately. 974 for (JetDeclaration declaration : declarations) { 975 if (declaration instanceof JetProperty || declaration instanceof JetClassInitializer) { 976 generateInstructions(declaration, context); 977 } 978 } 979 } 980 981 @Override 982 public void visitClassVoid(@NotNull JetClass klass, CFPContext context) { 983 List<JetParameter> parameters = klass.getPrimaryConstructorParameters(); 984 for (JetParameter parameter : parameters) { 985 generateInstructions(parameter, context); 986 } 987 visitClassOrObject(klass, context); 988 } 989 990 @Override 991 public void visitDelegationToSuperCallSpecifierVoid(@NotNull JetDelegatorToSuperCall call, CFPContext context) { 992 List<? extends ValueArgument> valueArguments = call.getValueArguments(); 993 for (ValueArgument valueArgument : valueArguments) { 994 generateInstructions(valueArgument.getArgumentExpression(), context); 995 } 996 } 997 998 @Override 999 public void visitDelegationByExpressionSpecifierVoid(@NotNull JetDelegatorByExpressionSpecifier specifier, CFPContext context) { 1000 generateInstructions(specifier.getDelegateExpression(), context); 1001 } 1002 1003 @Override 1004 public void visitJetFileVoid(@NotNull JetFile file, CFPContext context) { 1005 for (JetDeclaration declaration : file.getDeclarations()) { 1006 if (declaration instanceof JetProperty) { 1007 generateInstructions(declaration, context); 1008 } 1009 } 1010 } 1011 1012 @Override 1013 public void visitJetElementVoid(@NotNull JetElement element, CFPContext context) { 1014 builder.unsupported(element); 1015 } 1016 1017 @Nullable 1018 private ResolvedCall<?> getResolvedCall(@NotNull JetElement expression) { 1019 return trace.get(BindingContext.RESOLVED_CALL, expression); 1020 } 1021 1022 private boolean generateCall(@Nullable JetExpression calleeExpression) { 1023 if (calleeExpression == null) return false; 1024 return checkAndGenerateCall(calleeExpression, getResolvedCall(calleeExpression)); 1025 } 1026 1027 private boolean checkAndGenerateCall(JetExpression calleeExpression, @Nullable ResolvedCall<?> resolvedCall) { 1028 if (resolvedCall == null) { 1029 builder.compilationError(calleeExpression, "No resolved call"); 1030 return false; 1031 } 1032 generateCall(calleeExpression, resolvedCall); 1033 return true; 1034 } 1035 1036 private void generateCall(JetExpression calleeExpression, ResolvedCall<?> resolvedCall) { 1037 if (resolvedCall instanceof VariableAsFunctionResolvedCall) { 1038 VariableAsFunctionResolvedCall variableAsFunctionResolvedCall = (VariableAsFunctionResolvedCall) resolvedCall; 1039 generateCall(calleeExpression, variableAsFunctionResolvedCall.getFunctionCall()); 1040 return; 1041 } 1042 1043 CallableDescriptor resultingDescriptor = resolvedCall.getResultingDescriptor(); 1044 if (resultingDescriptor instanceof ExpressionAsFunctionDescriptor) { 1045 generateInstructions(((ExpressionAsFunctionDescriptor) resultingDescriptor).getExpression(), NOT_IN_CONDITION); 1046 } 1047 1048 generateReceiver(resolvedCall.getThisObject()); 1049 generateReceiver(resolvedCall.getReceiverArgument()); 1050 1051 for (ValueParameterDescriptor parameterDescriptor : resultingDescriptor.getValueParameters()) { 1052 ResolvedValueArgument argument = resolvedCall.getValueArguments().get(parameterDescriptor); 1053 if (argument == null) continue; 1054 1055 generateValueArgument(argument); 1056 } 1057 1058 if (resultingDescriptor instanceof VariableDescriptor) { 1059 builder.readVariable(calleeExpression, (VariableDescriptor) resultingDescriptor); 1060 } 1061 else { 1062 builder.call(calleeExpression, resolvedCall); 1063 } 1064 } 1065 1066 private void generateReceiver(ReceiverValue receiver) { 1067 if (!receiver.exists()) return; 1068 if (receiver instanceof ThisReceiver) { 1069 // TODO: Receiver is passed implicitly: no expression to tie the read to 1070 } 1071 else if (receiver instanceof ExpressionReceiver) { 1072 generateInstructions(((ExpressionReceiver) receiver).getExpression(), NOT_IN_CONDITION); 1073 } 1074 else if (receiver instanceof TransientReceiver) { 1075 // Do nothing 1076 } 1077 else { 1078 throw new IllegalArgumentException("Unknown receiver kind: " + receiver); 1079 } 1080 } 1081 1082 private void generateValueArgument(ResolvedValueArgument argument) { 1083 for (ValueArgument valueArgument : argument.getArguments()) { 1084 JetExpression expression = valueArgument.getArgumentExpression(); 1085 if (expression != null) { 1086 generateInstructions(expression, NOT_IN_CONDITION); 1087 } 1088 } 1089 } 1090 } 1091 }