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.Lists; 020 import com.intellij.psi.PsiElement; 021 import com.intellij.psi.tree.IElementType; 022 import com.intellij.psi.util.PsiTreeUtil; 023 import com.intellij.util.SmartFMap; 024 import kotlin.Function0; 025 import kotlin.Function1; 026 import kotlin.KotlinPackage; 027 import org.jetbrains.annotations.NotNull; 028 import org.jetbrains.annotations.Nullable; 029 import org.jetbrains.jet.lang.cfg.pseudocode.*; 030 import org.jetbrains.jet.lang.cfg.pseudocode.instructions.eval.AccessTarget; 031 import org.jetbrains.jet.lang.cfg.pseudocode.instructions.eval.InstructionWithValue; 032 import org.jetbrains.jet.lang.descriptors.*; 033 import org.jetbrains.jet.lang.psi.*; 034 import org.jetbrains.jet.lang.psi.psiUtil.PsiUtilPackage; 035 import org.jetbrains.jet.lang.resolve.BindingContext; 036 import org.jetbrains.jet.lang.resolve.BindingContextUtils; 037 import org.jetbrains.jet.lang.resolve.BindingTrace; 038 import org.jetbrains.jet.lang.resolve.CompileTimeConstantUtils; 039 import org.jetbrains.jet.lang.resolve.calls.model.*; 040 import org.jetbrains.jet.lang.resolve.constants.CompileTimeConstant; 041 import org.jetbrains.jet.lang.resolve.name.Name; 042 import org.jetbrains.jet.lang.resolve.scopes.receivers.ExpressionReceiver; 043 import org.jetbrains.jet.lang.resolve.scopes.receivers.ReceiverValue; 044 import org.jetbrains.jet.lang.resolve.scopes.receivers.ThisReceiver; 045 import org.jetbrains.jet.lang.resolve.scopes.receivers.TransientReceiver; 046 import org.jetbrains.jet.lang.types.JetType; 047 import org.jetbrains.jet.lang.types.expressions.OperatorConventions; 048 import org.jetbrains.jet.lang.types.lang.KotlinBuiltIns; 049 import org.jetbrains.jet.lexer.JetToken; 050 import org.jetbrains.jet.lexer.JetTokens; 051 052 import java.util.*; 053 054 import static org.jetbrains.jet.lang.cfg.JetControlFlowBuilder.PredefinedOperation.*; 055 import static org.jetbrains.jet.lang.diagnostics.Errors.*; 056 import static org.jetbrains.jet.lexer.JetTokens.*; 057 058 public class JetControlFlowProcessor { 059 060 private final JetControlFlowBuilder builder; 061 private final BindingTrace trace; 062 063 public JetControlFlowProcessor(BindingTrace trace) { 064 this.builder = new JetControlFlowInstructionsGenerator(); 065 this.trace = trace; 066 } 067 068 @NotNull 069 public Pseudocode generatePseudocode(@NotNull JetElement subroutine) { 070 Pseudocode pseudocode = generate(subroutine); 071 ((PseudocodeImpl) pseudocode).postProcess(); 072 return pseudocode; 073 } 074 075 @NotNull 076 private Pseudocode generate(@NotNull JetElement subroutine) { 077 builder.enterSubroutine(subroutine); 078 CFPVisitor cfpVisitor = new CFPVisitor(builder); 079 if (subroutine instanceof JetDeclarationWithBody) { 080 JetDeclarationWithBody declarationWithBody = (JetDeclarationWithBody) subroutine; 081 List<JetParameter> valueParameters = declarationWithBody.getValueParameters(); 082 for (JetParameter valueParameter : valueParameters) { 083 cfpVisitor.generateInstructions(valueParameter); 084 } 085 JetExpression bodyExpression = declarationWithBody.getBodyExpression(); 086 if (bodyExpression != null) { 087 cfpVisitor.generateInstructions(bodyExpression); 088 } 089 } else { 090 cfpVisitor.generateInstructions(subroutine); 091 } 092 return builder.exitSubroutine(subroutine); 093 } 094 095 private void processLocalDeclaration(@NotNull JetDeclaration subroutine) { 096 JetElement parent = PsiTreeUtil.getParentOfType(subroutine, JetElement.class); 097 assert parent != null; 098 099 Label afterDeclaration = builder.createUnboundLabel(); 100 101 builder.nondeterministicJump(afterDeclaration, parent, null); 102 generate(subroutine); 103 builder.bindLabel(afterDeclaration); 104 } 105 106 private class CFPVisitor extends JetVisitorVoid { 107 private final JetControlFlowBuilder builder; 108 109 private final JetVisitorVoid conditionVisitor = new JetVisitorVoid() { 110 111 @Override 112 public void visitWhenConditionInRange(@NotNull JetWhenConditionInRange condition) { 113 generateInstructions(condition.getRangeExpression()); 114 generateInstructions(condition.getOperationReference()); 115 116 // TODO : read the call to contains()... 117 createNonSyntheticValue(condition, condition.getRangeExpression(), condition.getOperationReference()); 118 } 119 120 @Override 121 public void visitWhenConditionIsPattern(@NotNull JetWhenConditionIsPattern condition) { 122 // TODO: types in CF? 123 } 124 125 @Override 126 public void visitWhenConditionWithExpression(@NotNull JetWhenConditionWithExpression condition) { 127 generateInstructions(condition.getExpression()); 128 copyValue(condition.getExpression(), condition); 129 } 130 131 @Override 132 public void visitJetElement(@NotNull JetElement element) { 133 throw new UnsupportedOperationException("[JetControlFlowProcessor] " + element.toString()); 134 } 135 }; 136 137 private CFPVisitor(@NotNull JetControlFlowBuilder builder) { 138 this.builder = builder; 139 } 140 141 private void mark(JetElement element) { 142 builder.mark(element); 143 } 144 145 public void generateInstructions(@Nullable JetElement element) { 146 if (element == null) return; 147 element.accept(this); 148 checkNothingType(element); 149 } 150 151 private void checkNothingType(JetElement element) { 152 if (!(element instanceof JetExpression)) return; 153 154 JetExpression expression = JetPsiUtil.deparenthesize((JetExpression) element); 155 if (expression == null) return; 156 157 if (expression instanceof JetStatementExpression || expression instanceof JetTryExpression 158 || expression instanceof JetIfExpression || expression instanceof JetWhenExpression) { 159 return; 160 } 161 162 JetType type = trace.getBindingContext().get(BindingContext.EXPRESSION_TYPE, expression); 163 if (type != null && KotlinBuiltIns.getInstance().isNothing(type)) { 164 builder.jumpToError(expression); 165 } 166 } 167 168 @NotNull 169 private PseudoValue createSyntheticValue(@NotNull JetElement instructionElement, JetElement... from) { 170 List<PseudoValue> values = elementsToValues(from.length > 0 ? Arrays.asList(from) : Collections.<JetElement>emptyList()); 171 return builder.magic(instructionElement, null, values, defaultTypeMap(values), true).getOutputValue(); 172 } 173 174 @NotNull 175 private PseudoValue createNonSyntheticValue(@NotNull JetElement to, @NotNull List<? extends JetElement> from) { 176 List<PseudoValue> values = elementsToValues(from); 177 return builder.magic(to, to, values, defaultTypeMap(values), false).getOutputValue(); 178 } 179 180 @NotNull 181 private PseudoValue createNonSyntheticValue(@NotNull JetElement to, JetElement... from) { 182 return createNonSyntheticValue(to, Arrays.asList(from)); 183 } 184 185 @NotNull 186 private Map<PseudoValue, TypePredicate> defaultTypeMap(List<PseudoValue> values) { 187 return PseudocodePackage.expectedTypeFor(AllTypes.instance$, values); 188 } 189 190 private void mergeValues(@NotNull List<JetExpression> from, @NotNull JetExpression to) { 191 List<PseudoValue> values = elementsToValues(from); 192 switch (values.size()) { 193 case 0: 194 break; 195 case 1: 196 builder.bindValue(values.get(0), to); 197 break; 198 default: 199 builder.merge(to, values); 200 break; 201 } 202 } 203 204 private void copyValue(@Nullable JetElement from, @NotNull JetElement to) { 205 PseudoValue value = builder.getBoundValue(from); 206 if (value != null) { 207 builder.bindValue(value, to); 208 } 209 } 210 211 private List<PseudoValue> elementsToValues(List<? extends JetElement> from) { 212 if (from.isEmpty()) return Collections.emptyList(); 213 return KotlinPackage.filterNotNull( 214 KotlinPackage.map( 215 from, 216 new Function1<JetElement, PseudoValue>() { 217 @Override 218 public PseudoValue invoke(JetElement element) { 219 return builder.getBoundValue(element); 220 } 221 } 222 ) 223 ); 224 } 225 226 private void generateInitializer(@NotNull JetDeclaration declaration, @NotNull PseudoValue initValue) { 227 builder.write( 228 declaration, 229 declaration, 230 initValue, 231 getDeclarationAccessTarget(declaration), 232 Collections.<PseudoValue, ReceiverValue>emptyMap() 233 ); 234 } 235 236 @NotNull 237 private AccessTarget getResolvedCallAccessTarget(JetElement element) { 238 ResolvedCall<?> resolvedCall = trace.get(BindingContext.RESOLVED_CALL, element); 239 return resolvedCall != null ? new AccessTarget.Call(resolvedCall) : AccessTarget.BlackBox.instance$; 240 } 241 242 @NotNull 243 private AccessTarget getDeclarationAccessTarget(JetElement element) { 244 DeclarationDescriptor descriptor = trace.get(BindingContext.DECLARATION_TO_DESCRIPTOR, element); 245 return descriptor instanceof VariableDescriptor 246 ? new AccessTarget.Declaration((VariableDescriptor) descriptor) 247 : AccessTarget.BlackBox.instance$; 248 } 249 250 @Override 251 public void visitParenthesizedExpression(@NotNull JetParenthesizedExpression expression) { 252 mark(expression); 253 JetExpression innerExpression = expression.getExpression(); 254 if (innerExpression != null) { 255 generateInstructions(innerExpression); 256 copyValue(innerExpression, expression); 257 } 258 } 259 260 @Override 261 public void visitAnnotatedExpression(@NotNull JetAnnotatedExpression expression) { 262 JetExpression baseExpression = expression.getBaseExpression(); 263 if (baseExpression != null) { 264 generateInstructions(baseExpression); 265 copyValue(baseExpression, expression); 266 } 267 } 268 269 @Override 270 public void visitThisExpression(@NotNull JetThisExpression expression) { 271 ResolvedCall<?> resolvedCall = getResolvedCall(expression); 272 if (resolvedCall == null) { 273 createNonSyntheticValue(expression); 274 return; 275 } 276 277 CallableDescriptor resultingDescriptor = resolvedCall.getResultingDescriptor(); 278 if (resultingDescriptor instanceof ReceiverParameterDescriptor) { 279 builder.readVariable(expression, expression, resolvedCall, getReceiverValues(resolvedCall, true)); 280 } 281 282 copyValue(expression, expression.getInstanceReference()); 283 } 284 285 @Override 286 public void visitConstantExpression(@NotNull JetConstantExpression expression) { 287 CompileTimeConstant<?> constant = trace.get(BindingContext.COMPILE_TIME_VALUE, expression); 288 builder.loadConstant(expression, constant); 289 } 290 291 @Override 292 public void visitSimpleNameExpression(@NotNull JetSimpleNameExpression expression) { 293 ResolvedCall<?> resolvedCall = getResolvedCall(expression); 294 if (resolvedCall instanceof VariableAsFunctionResolvedCall) { 295 VariableAsFunctionResolvedCall variableAsFunctionResolvedCall = (VariableAsFunctionResolvedCall) resolvedCall; 296 generateCall(expression, variableAsFunctionResolvedCall.getVariableCall()); 297 } 298 else if (!generateCall(expression) && !(expression.getParent() instanceof JetCallExpression)) { 299 createNonSyntheticValue(expression, generateAndGetReceiverIfAny(expression)); 300 } 301 } 302 303 @Override 304 public void visitLabeledExpression(@NotNull JetLabeledExpression expression) { 305 mark(expression); 306 JetExpression baseExpression = expression.getBaseExpression(); 307 if (baseExpression != null) { 308 generateInstructions(baseExpression); 309 copyValue(baseExpression, expression); 310 } 311 } 312 313 @SuppressWarnings("SuspiciousMethodCalls") 314 @Override 315 public void visitBinaryExpression(@NotNull JetBinaryExpression expression) { 316 JetSimpleNameExpression operationReference = expression.getOperationReference(); 317 IElementType operationType = operationReference.getReferencedNameElementType(); 318 319 JetExpression left = expression.getLeft(); 320 JetExpression right = expression.getRight(); 321 if (operationType == ANDAND || operationType == OROR) { 322 generateBooleanOperation(expression); 323 } 324 else if (operationType == EQ) { 325 visitAssignment(left, getDeferredValue(right), expression); 326 } 327 else if (OperatorConventions.ASSIGNMENT_OPERATIONS.containsKey(operationType)) { 328 ResolvedCall<?> resolvedCall = getResolvedCall(operationReference); 329 if (resolvedCall != null) { 330 PseudoValue rhsValue = generateCall(operationReference, resolvedCall).getOutputValue(); 331 Name assignMethodName = OperatorConventions.getNameForOperationSymbol((JetToken) expression.getOperationToken()); 332 if (!resolvedCall.getResultingDescriptor().getName().equals(assignMethodName)) { 333 /* At this point assignment of the form a += b actually means a = a + b 334 * So we first generate call of "+" operation and then use its output pseudo-value 335 * as a right-hand side when generating assignment call 336 */ 337 visitAssignment(left, getValueAsFunction(rhsValue), expression); 338 } 339 } 340 else { 341 generateBothArgumentsAndMark(expression); 342 } 343 } 344 else if (operationType == ELVIS) { 345 generateInstructions(left); 346 mark(expression); 347 Label afterElvis = builder.createUnboundLabel(); 348 builder.jumpOnTrue(afterElvis, expression, builder.getBoundValue(left)); 349 if (right != null) { 350 generateInstructions(right); 351 } 352 builder.bindLabel(afterElvis); 353 mergeValues(Arrays.asList(left, right), expression); 354 } 355 else { 356 if (!generateCall(operationReference)) { 357 generateBothArgumentsAndMark(expression); 358 } 359 } 360 } 361 362 private void generateBooleanOperation(JetBinaryExpression expression) { 363 IElementType operationType = expression.getOperationReference().getReferencedNameElementType(); 364 JetExpression left = expression.getLeft(); 365 JetExpression right = expression.getRight(); 366 367 Label resultLabel = builder.createUnboundLabel(); 368 generateInstructions(left); 369 if (operationType == ANDAND) { 370 builder.jumpOnFalse(resultLabel, expression, builder.getBoundValue(left)); 371 } 372 else { 373 builder.jumpOnTrue(resultLabel, expression, builder.getBoundValue(left)); 374 } 375 if (right != null) { 376 generateInstructions(right); 377 } 378 builder.bindLabel(resultLabel); 379 JetControlFlowBuilder.PredefinedOperation operation = operationType == ANDAND ? AND : OR; 380 builder.predefinedOperation(expression, operation, elementsToValues(Arrays.asList(left, right))); 381 } 382 383 private Function0<PseudoValue> getValueAsFunction(final PseudoValue value) { 384 return new Function0<PseudoValue>() { 385 @Override 386 public PseudoValue invoke() { 387 return value; 388 } 389 }; 390 } 391 392 private Function0<PseudoValue> getDeferredValue(final JetExpression expression) { 393 return new Function0<PseudoValue>() { 394 @Override 395 public PseudoValue invoke() { 396 generateInstructions(expression); 397 return builder.getBoundValue(expression); 398 } 399 }; 400 } 401 402 private void generateBothArgumentsAndMark(JetBinaryExpression expression) { 403 JetExpression left = JetPsiUtil.deparenthesize(expression.getLeft()); 404 if (left != null) { 405 generateInstructions(left); 406 } 407 JetExpression right = expression.getRight(); 408 if (right != null) { 409 generateInstructions(right); 410 } 411 createNonSyntheticValue(expression, left, right); 412 mark(expression); 413 } 414 415 private void visitAssignment(JetExpression lhs, @NotNull Function0<PseudoValue> rhsDeferredValue, JetExpression parentExpression) { 416 JetExpression left = JetPsiUtil.deparenthesize(lhs); 417 if (left == null) { 418 builder.compilationError(lhs, "No lValue in assignment"); 419 return; 420 } 421 422 if (left instanceof JetArrayAccessExpression) { 423 generateArrayAssignment((JetArrayAccessExpression) left, rhsDeferredValue, parentExpression); 424 return; 425 } 426 427 Map<PseudoValue, ReceiverValue> receiverValues = SmartFMap.emptyMap(); 428 AccessTarget accessTarget = AccessTarget.BlackBox.instance$; 429 boolean unsupported = false; 430 if (left instanceof JetSimpleNameExpression || left instanceof JetQualifiedExpression) { 431 accessTarget = getResolvedCallAccessTarget(PsiUtilPackage.getQualifiedElementSelector(left)); 432 if (accessTarget instanceof AccessTarget.Call) { 433 receiverValues = getReceiverValues(((AccessTarget.Call) accessTarget).getResolvedCall(), true); 434 } 435 } 436 else if (left instanceof JetProperty) { 437 accessTarget = getDeclarationAccessTarget(left); 438 } 439 else { 440 unsupported = true; 441 } 442 443 PseudoValue rhsValue = rhsDeferredValue.invoke(); 444 if (unsupported) { 445 builder.unsupported(parentExpression); // TODO 446 } 447 else { 448 recordWrite(left, accessTarget, rhsValue, receiverValues, parentExpression); 449 } 450 } 451 452 private void generateArrayAssignment( 453 JetArrayAccessExpression lhs, 454 @NotNull Function0<PseudoValue> rhsDeferredValue, 455 JetExpression parentExpression 456 ) { 457 ResolvedCall<FunctionDescriptor> setResolvedCall = trace.get(BindingContext.INDEXED_LVALUE_SET, lhs); 458 459 if (setResolvedCall == null) { 460 generateArrayAccess(lhs, null); 461 return; 462 } 463 464 // In case of simple ('=') array assignment mark instruction is not generated yet, so we put it before generating "set" call 465 if (((JetOperationExpression) parentExpression).getOperationReference().getReferencedNameElementType() == EQ) { 466 mark(lhs); 467 } 468 469 generateInstructions(lhs.getArrayExpression()); 470 471 Map<PseudoValue, ReceiverValue> receiverValues = getReceiverValues(setResolvedCall, false); 472 SmartFMap<PseudoValue, ValueParameterDescriptor> argumentValues = 473 getArraySetterArguments(rhsDeferredValue, setResolvedCall); 474 475 builder.call(parentExpression, parentExpression, setResolvedCall, receiverValues, argumentValues); 476 } 477 478 /* We assume that assignment right-hand side corresponds to the last argument of the call 479 * So receiver instructions/pseudo-values are generated for all arguments except the last one which is replaced 480 * by pre-generated pseudo-value 481 * For example, assignment a[1, 2] += 3 means a.set(1, 2, a.get(1) + 3), so in order to generate "set" call 482 * we first generate instructions for 1 and 2 whereas 3 is replaced by pseudo-value corresponding to "a.get(1) + 3" 483 */ 484 private SmartFMap<PseudoValue, ValueParameterDescriptor> getArraySetterArguments( 485 Function0<PseudoValue> rhsDeferredValue, 486 final ResolvedCall<FunctionDescriptor> setResolvedCall 487 ) { 488 List<ValueArgument> valueArguments = KotlinPackage.flatMapTo( 489 setResolvedCall.getResultingDescriptor().getValueParameters(), 490 new ArrayList<ValueArgument>(), 491 new Function1<ValueParameterDescriptor, Iterable<? extends ValueArgument>>() { 492 @Override 493 public Iterable<? extends ValueArgument> invoke(ValueParameterDescriptor descriptor) { 494 ResolvedValueArgument resolvedValueArgument = setResolvedCall.getValueArguments().get(descriptor); 495 return resolvedValueArgument != null 496 ? resolvedValueArgument.getArguments() 497 : Collections.<ValueArgument>emptyList(); 498 } 499 } 500 ); 501 502 ValueArgument rhsArgument = KotlinPackage.lastOrNull(valueArguments); 503 SmartFMap<PseudoValue, ValueParameterDescriptor> argumentValues = SmartFMap.emptyMap(); 504 for (ValueArgument valueArgument : valueArguments) { 505 ArgumentMapping argumentMapping = setResolvedCall.getArgumentMapping(valueArgument); 506 if (argumentMapping.isError() || (!(argumentMapping instanceof ArgumentMatch))) continue; 507 508 ValueParameterDescriptor parameterDescriptor = ((ArgumentMatch) argumentMapping).getValueParameter(); 509 if (valueArgument != rhsArgument) { 510 argumentValues = generateValueArgument(valueArgument, parameterDescriptor, argumentValues); 511 } 512 else { 513 PseudoValue rhsValue = rhsDeferredValue.invoke(); 514 if (rhsValue != null) { 515 argumentValues = argumentValues.plus(rhsValue, parameterDescriptor); 516 } 517 } 518 } 519 return argumentValues; 520 } 521 522 private void recordWrite( 523 @NotNull JetExpression left, 524 @NotNull AccessTarget target, 525 @Nullable PseudoValue rightValue, 526 @NotNull Map<PseudoValue, ReceiverValue> receiverValues, 527 @NotNull JetExpression parentExpression 528 ) { 529 VariableDescriptor descriptor = BindingContextUtils.extractVariableDescriptorIfAny(trace.getBindingContext(), left, false); 530 if (descriptor != null) { 531 PseudoValue rValue = rightValue != null ? rightValue : createSyntheticValue(parentExpression); 532 builder.write(parentExpression, left, rValue, target, receiverValues); 533 } 534 } 535 536 private void generateArrayAccess(JetArrayAccessExpression arrayAccessExpression, @Nullable ResolvedCall<?> resolvedCall) { 537 mark(arrayAccessExpression); 538 if (!checkAndGenerateCall(arrayAccessExpression, resolvedCall)) { 539 generateArrayAccessWithoutCall(arrayAccessExpression); 540 } 541 } 542 543 private void generateArrayAccessWithoutCall(JetArrayAccessExpression arrayAccessExpression) { 544 createNonSyntheticValue(arrayAccessExpression, generateArrayAccessArguments(arrayAccessExpression)); 545 } 546 547 private List<JetExpression> generateArrayAccessArguments(JetArrayAccessExpression arrayAccessExpression) { 548 List<JetExpression> inputExpressions = new ArrayList<JetExpression>(); 549 550 JetExpression arrayExpression = arrayAccessExpression.getArrayExpression(); 551 inputExpressions.add(arrayExpression); 552 generateInstructions(arrayExpression); 553 554 for (JetExpression index : arrayAccessExpression.getIndexExpressions()) { 555 generateInstructions(index); 556 inputExpressions.add(index); 557 } 558 559 return inputExpressions; 560 } 561 562 @Override 563 public void visitUnaryExpression(@NotNull JetUnaryExpression expression) { 564 JetSimpleNameExpression operationSign = expression.getOperationReference(); 565 IElementType operationType = operationSign.getReferencedNameElementType(); 566 JetExpression baseExpression = expression.getBaseExpression(); 567 if (baseExpression == null) return; 568 if (JetTokens.EXCLEXCL == operationType) { 569 generateInstructions(baseExpression); 570 builder.predefinedOperation(expression, NOT_NULL_ASSERTION, elementsToValues(Collections.singletonList(baseExpression))); 571 return; 572 } 573 574 boolean incrementOrDecrement = isIncrementOrDecrement(operationType); 575 ResolvedCall<?> resolvedCall = getResolvedCall(operationSign); 576 577 PseudoValue rhsValue; 578 if (resolvedCall != null) { 579 rhsValue = generateCall(operationSign, resolvedCall).getOutputValue(); 580 } 581 else { 582 generateInstructions(baseExpression); 583 rhsValue = createNonSyntheticValue(expression, baseExpression); 584 } 585 586 if (incrementOrDecrement) { 587 visitAssignment(baseExpression, getValueAsFunction(rhsValue), expression); 588 if (expression instanceof JetPostfixExpression) { 589 copyValue(baseExpression, expression); 590 } 591 } 592 } 593 594 private boolean isIncrementOrDecrement(IElementType operationType) { 595 return operationType == JetTokens.PLUSPLUS || operationType == JetTokens.MINUSMINUS; 596 } 597 598 @Override 599 public void visitIfExpression(@NotNull JetIfExpression expression) { 600 mark(expression); 601 List<JetExpression> branches = new ArrayList<JetExpression>(2); 602 JetExpression condition = expression.getCondition(); 603 if (condition != null) { 604 generateInstructions(condition); 605 } 606 Label elseLabel = builder.createUnboundLabel(); 607 builder.jumpOnFalse(elseLabel, expression, builder.getBoundValue(condition)); 608 JetExpression thenBranch = expression.getThen(); 609 if (thenBranch != null) { 610 branches.add(thenBranch); 611 generateInstructions(thenBranch); 612 } 613 else { 614 builder.loadUnit(expression); 615 } 616 Label resultLabel = builder.createUnboundLabel(); 617 builder.jump(resultLabel, expression); 618 builder.bindLabel(elseLabel); 619 JetExpression elseBranch = expression.getElse(); 620 if (elseBranch != null) { 621 branches.add(elseBranch); 622 generateInstructions(elseBranch); 623 } 624 else { 625 builder.loadUnit(expression); 626 } 627 builder.bindLabel(resultLabel); 628 mergeValues(branches, expression); 629 } 630 631 private class FinallyBlockGenerator { 632 private final JetFinallySection finallyBlock; 633 private Label startFinally = null; 634 private Label finishFinally = null; 635 636 private FinallyBlockGenerator(JetFinallySection block) { 637 finallyBlock = block; 638 } 639 640 public void generate() { 641 JetBlockExpression finalExpression = finallyBlock.getFinalExpression(); 642 if (finalExpression == null) return; 643 if (startFinally != null) { 644 assert finishFinally != null; 645 builder.repeatPseudocode(startFinally, finishFinally); 646 return; 647 } 648 startFinally = builder.createUnboundLabel("start finally"); 649 builder.bindLabel(startFinally); 650 generateInstructions(finalExpression); 651 finishFinally = builder.createUnboundLabel("finish finally"); 652 builder.bindLabel(finishFinally); 653 } 654 } 655 656 @Override 657 public void visitTryExpression(@NotNull JetTryExpression expression) { 658 mark(expression); 659 660 JetFinallySection finallyBlock = expression.getFinallyBlock(); 661 final FinallyBlockGenerator finallyBlockGenerator = new FinallyBlockGenerator(finallyBlock); 662 boolean hasFinally = finallyBlock != null; 663 if (hasFinally) { 664 builder.enterTryFinally(new GenerationTrigger() { 665 private boolean working = false; 666 667 @Override 668 public void generate() { 669 // This checks are needed for the case of having e.g. return inside finally: 'try {return} finally{return}' 670 if (working) return; 671 working = true; 672 finallyBlockGenerator.generate(); 673 working = false; 674 } 675 }); 676 } 677 678 Label onExceptionToFinallyBlock = generateTryAndCatches(expression); 679 680 if (hasFinally) { 681 assert onExceptionToFinallyBlock != null : "No finally lable generated: " + expression.getText(); 682 683 builder.exitTryFinally(); 684 685 Label skipFinallyToErrorBlock = builder.createUnboundLabel("skipFinallyToErrorBlock"); 686 builder.jump(skipFinallyToErrorBlock, expression); 687 builder.bindLabel(onExceptionToFinallyBlock); 688 finallyBlockGenerator.generate(); 689 builder.jumpToError(expression); 690 builder.bindLabel(skipFinallyToErrorBlock); 691 692 finallyBlockGenerator.generate(); 693 } 694 695 List<JetExpression> branches = new ArrayList<JetExpression>(); 696 branches.add(expression.getTryBlock()); 697 for (JetCatchClause catchClause : expression.getCatchClauses()) { 698 branches.add(catchClause.getCatchBody()); 699 } 700 mergeValues(branches, expression); 701 } 702 703 // Returns label for 'finally' block 704 @Nullable 705 private Label generateTryAndCatches(@NotNull JetTryExpression expression) { 706 List<JetCatchClause> catchClauses = expression.getCatchClauses(); 707 boolean hasCatches = !catchClauses.isEmpty(); 708 709 Label onException = null; 710 if (hasCatches) { 711 onException = builder.createUnboundLabel("onException"); 712 builder.nondeterministicJump(onException, expression, null); 713 } 714 715 Label onExceptionToFinallyBlock = null; 716 if (expression.getFinallyBlock() != null) { 717 onExceptionToFinallyBlock = builder.createUnboundLabel("onExceptionToFinallyBlock"); 718 builder.nondeterministicJump(onExceptionToFinallyBlock, expression, null); 719 } 720 721 JetBlockExpression tryBlock = expression.getTryBlock(); 722 generateInstructions(tryBlock); 723 724 if (hasCatches) { 725 Label afterCatches = builder.createUnboundLabel("afterCatches"); 726 builder.jump(afterCatches, expression); 727 728 builder.bindLabel(onException); 729 LinkedList<Label> catchLabels = Lists.newLinkedList(); 730 int catchClausesSize = catchClauses.size(); 731 for (int i = 0; i < catchClausesSize - 1; i++) { 732 catchLabels.add(builder.createUnboundLabel("catch " + i)); 733 } 734 if (!catchLabels.isEmpty()) { 735 builder.nondeterministicJump(catchLabels, expression); 736 } 737 boolean isFirst = true; 738 for (JetCatchClause catchClause : catchClauses) { 739 builder.enterLexicalScope(catchClause); 740 if (!isFirst) { 741 builder.bindLabel(catchLabels.remove()); 742 } 743 else { 744 isFirst = false; 745 } 746 JetParameter catchParameter = catchClause.getCatchParameter(); 747 if (catchParameter != null) { 748 builder.declareParameter(catchParameter); 749 generateInitializer(catchParameter, createSyntheticValue(catchParameter)); 750 } 751 JetExpression catchBody = catchClause.getCatchBody(); 752 if (catchBody != null) { 753 generateInstructions(catchBody); 754 } 755 builder.jump(afterCatches, expression); 756 builder.exitLexicalScope(catchClause); 757 } 758 759 builder.bindLabel(afterCatches); 760 } 761 762 return onExceptionToFinallyBlock; 763 } 764 765 @Override 766 public void visitWhileExpression(@NotNull JetWhileExpression expression) { 767 LoopInfo loopInfo = builder.enterLoop(expression, null, null); 768 769 builder.bindLabel(loopInfo.getConditionEntryPoint()); 770 JetExpression condition = expression.getCondition(); 771 if (condition != null) { 772 generateInstructions(condition); 773 } 774 mark(expression); 775 boolean conditionIsTrueConstant = CompileTimeConstantUtils.canBeReducedToBooleanConstant(condition, trace, true); 776 if (!conditionIsTrueConstant) { 777 builder.jumpOnFalse(loopInfo.getExitPoint(), expression, builder.getBoundValue(condition)); 778 } 779 780 builder.bindLabel(loopInfo.getBodyEntryPoint()); 781 JetExpression body = expression.getBody(); 782 if (body != null) { 783 generateInstructions(body); 784 } 785 builder.jump(loopInfo.getEntryPoint(), expression); 786 builder.exitLoop(expression); 787 builder.loadUnit(expression); 788 } 789 790 @Override 791 public void visitDoWhileExpression(@NotNull JetDoWhileExpression expression) { 792 builder.enterLexicalScope(expression); 793 mark(expression); 794 LoopInfo loopInfo = builder.enterLoop(expression, null, null); 795 796 builder.bindLabel(loopInfo.getBodyEntryPoint()); 797 JetExpression body = expression.getBody(); 798 if (body != null) { 799 generateInstructions(body); 800 } 801 builder.bindLabel(loopInfo.getConditionEntryPoint()); 802 JetExpression condition = expression.getCondition(); 803 if (condition != null) { 804 generateInstructions(condition); 805 } 806 builder.jumpOnTrue(loopInfo.getEntryPoint(), expression, builder.getBoundValue(condition)); 807 builder.exitLoop(expression); 808 builder.loadUnit(expression); 809 builder.exitLexicalScope(expression); 810 } 811 812 @Override 813 public void visitForExpression(@NotNull JetForExpression expression) { 814 builder.enterLexicalScope(expression); 815 816 JetExpression loopRange = expression.getLoopRange(); 817 if (loopRange != null) { 818 generateInstructions(loopRange); 819 } 820 declareLoopParameter(expression); 821 822 // TODO : primitive cases 823 Label loopExitPoint = builder.createUnboundLabel(); 824 Label conditionEntryPoint = builder.createUnboundLabel(); 825 826 builder.bindLabel(conditionEntryPoint); 827 builder.nondeterministicJump(loopExitPoint, expression, null); 828 829 LoopInfo loopInfo = builder.enterLoop(expression, loopExitPoint, conditionEntryPoint); 830 831 builder.bindLabel(loopInfo.getBodyEntryPoint()); 832 writeLoopParameterAssignment(expression); 833 834 mark(expression); 835 JetExpression body = expression.getBody(); 836 if (body != null) { 837 generateInstructions(body); 838 } 839 840 builder.nondeterministicJump(loopInfo.getEntryPoint(), expression, null); 841 842 builder.exitLoop(expression); 843 builder.loadUnit(expression); 844 builder.exitLexicalScope(expression); 845 } 846 847 private void declareLoopParameter(JetForExpression expression) { 848 JetParameter loopParameter = expression.getLoopParameter(); 849 JetMultiDeclaration multiDeclaration = expression.getMultiParameter(); 850 if (loopParameter != null) { 851 builder.declareParameter(loopParameter); 852 } 853 else if (multiDeclaration != null) { 854 visitMultiDeclaration(multiDeclaration, false); 855 } 856 } 857 858 private void writeLoopParameterAssignment(JetForExpression expression) { 859 JetParameter loopParameter = expression.getLoopParameter(); 860 JetMultiDeclaration multiDeclaration = expression.getMultiParameter(); 861 JetExpression loopRange = expression.getLoopRange(); 862 863 TypePredicate loopRangeTypePredicate = AllTypes.instance$; 864 ResolvedCall<?> iteratorResolvedCall = trace.get(BindingContext.LOOP_RANGE_ITERATOR_RESOLVED_CALL, loopRange); 865 if (iteratorResolvedCall != null) { 866 ReceiverValue iteratorReceiver = getExplicitReceiverValue(iteratorResolvedCall); 867 if (iteratorReceiver.exists()) { 868 loopRangeTypePredicate = PseudocodePackage.getReceiverTypePredicate(iteratorResolvedCall, iteratorReceiver); 869 } 870 } 871 872 PseudoValue loopRangeValue = builder.getBoundValue(loopRange); 873 PseudoValue value = builder.magic( 874 loopRange != null ? loopRange : expression, 875 null, 876 Collections.singletonList(loopRangeValue), 877 Collections.singletonMap(loopRangeValue, loopRangeTypePredicate), 878 true 879 ).getOutputValue(); 880 881 if (loopParameter != null) { 882 generateInitializer(loopParameter, value); 883 } 884 else if (multiDeclaration != null) { 885 for (JetMultiDeclarationEntry entry : multiDeclaration.getEntries()) { 886 generateInitializer(entry, value); 887 } 888 } 889 } 890 891 private ReceiverValue getExplicitReceiverValue(ResolvedCall<?> resolvedCall) { 892 switch(resolvedCall.getExplicitReceiverKind()) { 893 case THIS_OBJECT: 894 return resolvedCall.getThisObject(); 895 case RECEIVER_ARGUMENT: 896 return resolvedCall.getReceiverArgument(); 897 default: 898 return ReceiverValue.NO_RECEIVER; 899 } 900 } 901 902 @Override 903 public void visitBreakExpression(@NotNull JetBreakExpression expression) { 904 JetElement loop = getCorrespondingLoop(expression); 905 if (loop != null) { 906 checkJumpDoesNotCrossFunctionBoundary(expression, loop); 907 builder.jump(builder.getExitPoint(loop), expression); 908 } 909 } 910 911 @Override 912 public void visitContinueExpression(@NotNull JetContinueExpression expression) { 913 JetElement loop = getCorrespondingLoop(expression); 914 if (loop != null) { 915 checkJumpDoesNotCrossFunctionBoundary(expression, loop); 916 builder.jump(builder.getEntryPoint(loop), expression); 917 } 918 } 919 920 private JetElement getCorrespondingLoop(JetExpressionWithLabel expression) { 921 String labelName = expression.getLabelName(); 922 JetElement loop; 923 if (labelName != null) { 924 JetSimpleNameExpression targetLabel = expression.getTargetLabel(); 925 assert targetLabel != null; 926 PsiElement labeledElement = trace.get(BindingContext.LABEL_TARGET, targetLabel); 927 if (labeledElement instanceof JetLoopExpression) { 928 loop = (JetLoopExpression) labeledElement; 929 } 930 else { 931 trace.report(NOT_A_LOOP_LABEL.on(expression, targetLabel.getText())); 932 loop = null; 933 } 934 } 935 else { 936 loop = builder.getCurrentLoop(); 937 if (loop == null) { 938 trace.report(BREAK_OR_CONTINUE_OUTSIDE_A_LOOP.on(expression)); 939 } 940 } 941 return loop; 942 } 943 944 private void checkJumpDoesNotCrossFunctionBoundary(@NotNull JetExpressionWithLabel jumpExpression, @NotNull JetElement jumpTarget) { 945 BindingContext bindingContext = trace.getBindingContext(); 946 947 FunctionDescriptor labelExprEnclosingFunc = BindingContextUtils.getEnclosingFunctionDescriptor(bindingContext, jumpExpression); 948 FunctionDescriptor labelTargetEnclosingFunc = BindingContextUtils.getEnclosingFunctionDescriptor(bindingContext, jumpTarget); 949 if (labelExprEnclosingFunc != labelTargetEnclosingFunc) { 950 trace.report(BREAK_OR_CONTINUE_JUMPS_ACROSS_FUNCTION_BOUNDARY.on(jumpExpression)); 951 } 952 } 953 954 @Override 955 public void visitReturnExpression(@NotNull JetReturnExpression expression) { 956 JetExpression returnedExpression = expression.getReturnedExpression(); 957 if (returnedExpression != null) { 958 generateInstructions(returnedExpression); 959 } 960 JetSimpleNameExpression labelElement = expression.getTargetLabel(); 961 JetElement subroutine; 962 String labelName = expression.getLabelName(); 963 if (labelElement != null && labelName != null) { 964 PsiElement labeledElement = trace.get(BindingContext.LABEL_TARGET, labelElement); 965 if (labeledElement != null) { 966 assert labeledElement instanceof JetElement; 967 subroutine = (JetElement) labeledElement; 968 } 969 else { 970 subroutine = null; 971 } 972 } 973 else { 974 subroutine = builder.getReturnSubroutine(); 975 // TODO : a context check 976 } 977 978 if (subroutine instanceof JetFunction || subroutine instanceof JetPropertyAccessor) { 979 PseudoValue returnValue = returnedExpression != null ? builder.getBoundValue(returnedExpression) : null; 980 if (returnValue == null) { 981 builder.returnNoValue(expression, subroutine); 982 } 983 else { 984 builder.returnValue(expression, returnValue, subroutine); 985 } 986 } 987 } 988 989 @Override 990 public void visitParameter(@NotNull JetParameter parameter) { 991 builder.declareParameter(parameter); 992 JetExpression defaultValue = parameter.getDefaultValue(); 993 if (defaultValue != null) { 994 Label skipDefaultValue = builder.createUnboundLabel("after default value for parameter " + parameter.getName()); 995 builder.nondeterministicJump(skipDefaultValue, defaultValue, null); 996 generateInstructions(defaultValue); 997 builder.bindLabel(skipDefaultValue); 998 } 999 generateInitializer(parameter, computePseudoValueForParameter(parameter)); 1000 } 1001 1002 @NotNull 1003 private PseudoValue computePseudoValueForParameter(@NotNull JetParameter parameter) { 1004 PseudoValue syntheticValue = createSyntheticValue(parameter); 1005 PseudoValue defaultValue = builder.getBoundValue(parameter.getDefaultValue()); 1006 if (defaultValue == null) { 1007 return syntheticValue; 1008 } 1009 return builder.merge(parameter, Lists.newArrayList(defaultValue, syntheticValue)).getOutputValue(); 1010 } 1011 1012 @Override 1013 public void visitBlockExpression(@NotNull JetBlockExpression expression) { 1014 boolean declareLexicalScope = !isBlockInDoWhile(expression); 1015 if (declareLexicalScope) { 1016 builder.enterLexicalScope(expression); 1017 } 1018 mark(expression); 1019 List<JetElement> statements = expression.getStatements(); 1020 for (JetElement statement : statements) { 1021 generateInstructions(statement); 1022 } 1023 if (statements.isEmpty()) { 1024 builder.loadUnit(expression); 1025 } 1026 else { 1027 copyValue(KotlinPackage.lastOrNull(statements), expression); 1028 } 1029 if (declareLexicalScope) { 1030 builder.exitLexicalScope(expression); 1031 } 1032 } 1033 1034 private boolean isBlockInDoWhile(@NotNull JetBlockExpression expression) { 1035 PsiElement parent = expression.getParent(); 1036 if (parent == null) return false; 1037 return parent.getParent() instanceof JetDoWhileExpression; 1038 } 1039 1040 @Override 1041 public void visitNamedFunction(@NotNull JetNamedFunction function) { 1042 processLocalDeclaration(function); 1043 } 1044 1045 @Override 1046 public void visitFunctionLiteralExpression(@NotNull JetFunctionLiteralExpression expression) { 1047 mark(expression); 1048 JetFunctionLiteral functionLiteral = expression.getFunctionLiteral(); 1049 processLocalDeclaration(functionLiteral); 1050 builder.createFunctionLiteral(expression); 1051 } 1052 1053 @Override 1054 public void visitQualifiedExpression(@NotNull JetQualifiedExpression expression) { 1055 mark(expression); 1056 JetExpression selectorExpression = expression.getSelectorExpression(); 1057 JetExpression receiverExpression = expression.getReceiverExpression(); 1058 1059 // todo: replace with selectorExpresion != null after parser is fixed 1060 if (selectorExpression instanceof JetCallExpression || selectorExpression instanceof JetSimpleNameExpression) { 1061 generateInstructions(selectorExpression); 1062 copyValue(selectorExpression, expression); 1063 } 1064 else { 1065 generateInstructions(receiverExpression); 1066 createNonSyntheticValue(expression, receiverExpression); 1067 } 1068 } 1069 1070 @Override 1071 public void visitCallExpression(@NotNull JetCallExpression expression) { 1072 JetExpression calleeExpression = expression.getCalleeExpression(); 1073 if (!generateCall(calleeExpression)) { 1074 List<JetExpression> inputExpressions = new ArrayList<JetExpression>(); 1075 for (ValueArgument argument : expression.getValueArguments()) { 1076 JetExpression argumentExpression = argument.getArgumentExpression(); 1077 if (argumentExpression != null) { 1078 generateInstructions(argumentExpression); 1079 inputExpressions.add(argumentExpression); 1080 } 1081 } 1082 for (JetExpression functionLiteral : expression.getFunctionLiteralArguments()) { 1083 generateInstructions(functionLiteral); 1084 inputExpressions.add(functionLiteral); 1085 } 1086 generateInstructions(calleeExpression); 1087 inputExpressions.add(calleeExpression); 1088 inputExpressions.add(generateAndGetReceiverIfAny(expression)); 1089 1090 mark(expression); 1091 createNonSyntheticValue(expression, inputExpressions); 1092 } 1093 } 1094 1095 @Nullable 1096 private JetExpression generateAndGetReceiverIfAny(JetExpression expression) { 1097 PsiElement parent = expression.getParent(); 1098 if (!(parent instanceof JetQualifiedExpression)) return null; 1099 1100 JetQualifiedExpression qualifiedExpression = (JetQualifiedExpression) parent; 1101 if (qualifiedExpression.getSelectorExpression() != expression) return null; 1102 1103 JetExpression receiverExpression = qualifiedExpression.getReceiverExpression(); 1104 generateInstructions(receiverExpression); 1105 1106 return receiverExpression; 1107 } 1108 1109 @Override 1110 public void visitProperty(@NotNull JetProperty property) { 1111 builder.declareVariable(property); 1112 JetExpression initializer = property.getInitializer(); 1113 if (initializer != null) { 1114 visitAssignment(property, getDeferredValue(initializer), property); 1115 } 1116 JetExpression delegate = property.getDelegateExpression(); 1117 if (delegate != null) { 1118 generateInstructions(delegate); 1119 } 1120 if (JetPsiUtil.isLocal(property)) { 1121 for (JetPropertyAccessor accessor : property.getAccessors()) { 1122 generateInstructions(accessor); 1123 } 1124 } 1125 } 1126 1127 @Override 1128 public void visitMultiDeclaration(@NotNull JetMultiDeclaration declaration) { 1129 visitMultiDeclaration(declaration, true); 1130 } 1131 1132 private void visitMultiDeclaration(@NotNull JetMultiDeclaration declaration, boolean generateWriteForEntries) { 1133 JetExpression initializer = declaration.getInitializer(); 1134 generateInstructions(initializer); 1135 for (JetMultiDeclarationEntry entry : declaration.getEntries()) { 1136 builder.declareVariable(entry); 1137 1138 ResolvedCall<FunctionDescriptor> resolvedCall = trace.get(BindingContext.COMPONENT_RESOLVED_CALL, entry); 1139 1140 PseudoValue writtenValue; 1141 if (resolvedCall != null) { 1142 writtenValue = builder.call( 1143 entry, 1144 entry, 1145 resolvedCall, 1146 getReceiverValues(resolvedCall, false), 1147 Collections.<PseudoValue, ValueParameterDescriptor>emptyMap() 1148 ).getOutputValue(); 1149 } 1150 else { 1151 writtenValue = createSyntheticValue(entry, initializer); 1152 } 1153 1154 if (generateWriteForEntries) { 1155 generateInitializer(entry, writtenValue != null ? writtenValue : createSyntheticValue(entry)); 1156 } 1157 } 1158 } 1159 1160 @Override 1161 public void visitPropertyAccessor(@NotNull JetPropertyAccessor accessor) { 1162 processLocalDeclaration(accessor); 1163 } 1164 1165 @Override 1166 public void visitBinaryWithTypeRHSExpression(@NotNull JetBinaryExpressionWithTypeRHS expression) { 1167 mark(expression); 1168 1169 IElementType operationType = expression.getOperationReference().getReferencedNameElementType(); 1170 JetExpression left = expression.getLeft(); 1171 if (operationType == JetTokens.COLON || operationType == JetTokens.AS_KEYWORD || operationType == JetTokens.AS_SAFE) { 1172 generateInstructions(left); 1173 copyValue(left, expression); 1174 } 1175 else { 1176 visitJetElement(expression); 1177 createNonSyntheticValue(expression, left); 1178 } 1179 } 1180 1181 @Override 1182 public void visitThrowExpression(@NotNull JetThrowExpression expression) { 1183 mark(expression); 1184 1185 JetExpression thrownExpression = expression.getThrownExpression(); 1186 if (thrownExpression == null) return; 1187 1188 generateInstructions(thrownExpression); 1189 1190 PseudoValue thrownValue = builder.getBoundValue(thrownExpression); 1191 if (thrownValue == null) return; 1192 1193 builder.throwException(expression, thrownValue); 1194 } 1195 1196 @Override 1197 public void visitArrayAccessExpression(@NotNull JetArrayAccessExpression expression) { 1198 mark(expression); 1199 ResolvedCall<FunctionDescriptor> getMethodResolvedCall = trace.get(BindingContext.INDEXED_LVALUE_GET, expression); 1200 if (!checkAndGenerateCall(expression, getMethodResolvedCall)) { 1201 generateArrayAccess(expression, getMethodResolvedCall); 1202 } 1203 } 1204 1205 @Override 1206 public void visitIsExpression(@NotNull JetIsExpression expression) { 1207 mark(expression); 1208 JetExpression left = expression.getLeftHandSide(); 1209 generateInstructions(left); 1210 createNonSyntheticValue(expression, left); 1211 } 1212 1213 @Override 1214 public void visitWhenExpression(@NotNull JetWhenExpression expression) { 1215 mark(expression); 1216 1217 JetExpression subjectExpression = expression.getSubjectExpression(); 1218 if (subjectExpression != null) { 1219 generateInstructions(subjectExpression); 1220 } 1221 1222 boolean hasElse = false; 1223 1224 List<JetExpression> branches = new ArrayList<JetExpression>(); 1225 1226 Label doneLabel = builder.createUnboundLabel(); 1227 1228 Label nextLabel = null; 1229 for (Iterator<JetWhenEntry> iterator = expression.getEntries().iterator(); iterator.hasNext(); ) { 1230 JetWhenEntry whenEntry = iterator.next(); 1231 mark(whenEntry); 1232 1233 boolean isElse = whenEntry.isElse(); 1234 if (isElse) { 1235 hasElse = true; 1236 if (iterator.hasNext()) { 1237 trace.report(ELSE_MISPLACED_IN_WHEN.on(whenEntry)); 1238 } 1239 } 1240 Label bodyLabel = builder.createUnboundLabel(); 1241 1242 JetWhenCondition[] conditions = whenEntry.getConditions(); 1243 for (int i = 0; i < conditions.length; i++) { 1244 JetWhenCondition condition = conditions[i]; 1245 condition.accept(conditionVisitor); 1246 if (i + 1 < conditions.length) { 1247 PseudoValue conditionValue = createSyntheticValue(condition, subjectExpression, condition); 1248 builder.nondeterministicJump(bodyLabel, expression, conditionValue); 1249 } 1250 } 1251 1252 if (!isElse) { 1253 nextLabel = builder.createUnboundLabel(); 1254 PseudoValue conditionValue = null; 1255 JetWhenCondition lastCondition = KotlinPackage.lastOrNull(conditions); 1256 if (lastCondition != null) { 1257 conditionValue = createSyntheticValue(lastCondition, subjectExpression, lastCondition); 1258 } 1259 builder.nondeterministicJump(nextLabel, expression, conditionValue); 1260 } 1261 1262 builder.bindLabel(bodyLabel); 1263 JetExpression whenEntryExpression = whenEntry.getExpression(); 1264 if (whenEntryExpression != null) { 1265 generateInstructions(whenEntryExpression); 1266 branches.add(whenEntryExpression); 1267 } 1268 builder.jump(doneLabel, expression); 1269 1270 if (!isElse) { 1271 builder.bindLabel(nextLabel); 1272 } 1273 } 1274 builder.bindLabel(doneLabel); 1275 if (!hasElse && WhenChecker.mustHaveElse(expression, trace)) { 1276 trace.report(NO_ELSE_IN_WHEN.on(expression)); 1277 } 1278 1279 mergeValues(branches, expression); 1280 } 1281 1282 @Override 1283 public void visitObjectLiteralExpression(@NotNull JetObjectLiteralExpression expression) { 1284 mark(expression); 1285 JetObjectDeclaration declaration = expression.getObjectDeclaration(); 1286 generateInstructions(declaration); 1287 1288 builder.createAnonymousObject(expression); 1289 } 1290 1291 @Override 1292 public void visitObjectDeclaration(@NotNull JetObjectDeclaration objectDeclaration) { 1293 visitClassOrObject(objectDeclaration); 1294 } 1295 1296 @Override 1297 public void visitStringTemplateExpression(@NotNull JetStringTemplateExpression expression) { 1298 mark(expression); 1299 1300 List<JetExpression> inputExpressions = new ArrayList<JetExpression>(); 1301 for (JetStringTemplateEntry entry : expression.getEntries()) { 1302 if (entry instanceof JetStringTemplateEntryWithExpression) { 1303 JetExpression entryExpression = entry.getExpression(); 1304 generateInstructions(entryExpression); 1305 inputExpressions.add(entryExpression); 1306 } 1307 } 1308 builder.loadStringTemplate(expression, elementsToValues(inputExpressions)); 1309 } 1310 1311 @Override 1312 public void visitTypeProjection(@NotNull JetTypeProjection typeProjection) { 1313 // TODO : Support Type Arguments. Class object may be initialized at this point"); 1314 } 1315 1316 @Override 1317 public void visitAnonymousInitializer(@NotNull JetClassInitializer classInitializer) { 1318 generateInstructions(classInitializer.getBody()); 1319 } 1320 1321 private void visitClassOrObject(JetClassOrObject classOrObject) { 1322 for (JetDelegationSpecifier specifier : classOrObject.getDelegationSpecifiers()) { 1323 generateInstructions(specifier); 1324 } 1325 List<JetDeclaration> declarations = classOrObject.getDeclarations(); 1326 if (classOrObject.isLocal()) { 1327 for (JetDeclaration declaration : declarations) { 1328 generateInstructions(declaration); 1329 } 1330 return; 1331 } 1332 //For top-level and inner classes and objects functions are collected and checked separately. 1333 for (JetDeclaration declaration : declarations) { 1334 if (declaration instanceof JetProperty || declaration instanceof JetClassInitializer) { 1335 generateInstructions(declaration); 1336 } 1337 } 1338 } 1339 1340 @Override 1341 public void visitClass(@NotNull JetClass klass) { 1342 List<JetParameter> parameters = klass.getPrimaryConstructorParameters(); 1343 for (JetParameter parameter : parameters) { 1344 generateInstructions(parameter); 1345 } 1346 visitClassOrObject(klass); 1347 } 1348 1349 @Override 1350 public void visitDelegationToSuperCallSpecifier(@NotNull JetDelegatorToSuperCall call) { 1351 List<? extends ValueArgument> valueArguments = call.getValueArguments(); 1352 for (ValueArgument valueArgument : valueArguments) { 1353 generateInstructions(valueArgument.getArgumentExpression()); 1354 } 1355 } 1356 1357 @Override 1358 public void visitDelegationByExpressionSpecifier(@NotNull JetDelegatorByExpressionSpecifier specifier) { 1359 generateInstructions(specifier.getDelegateExpression()); 1360 } 1361 1362 @Override 1363 public void visitJetFile(@NotNull JetFile file) { 1364 for (JetDeclaration declaration : file.getDeclarations()) { 1365 if (declaration instanceof JetProperty) { 1366 generateInstructions(declaration); 1367 } 1368 } 1369 } 1370 1371 @Override 1372 public void visitJetElement(@NotNull JetElement element) { 1373 builder.unsupported(element); 1374 } 1375 1376 @Nullable 1377 private ResolvedCall<?> getResolvedCall(@NotNull JetElement expression) { 1378 return trace.get(BindingContext.RESOLVED_CALL, expression); 1379 } 1380 1381 private boolean generateCall(@Nullable JetExpression calleeExpression) { 1382 if (calleeExpression == null) return false; 1383 return checkAndGenerateCall(calleeExpression, getResolvedCall(calleeExpression)); 1384 } 1385 1386 private boolean checkAndGenerateCall( 1387 JetExpression calleeExpression, 1388 @Nullable ResolvedCall<?> resolvedCall 1389 ) { 1390 if (resolvedCall == null) { 1391 builder.compilationError(calleeExpression, "No resolved call"); 1392 return false; 1393 } 1394 generateCall(calleeExpression, resolvedCall); 1395 return true; 1396 } 1397 1398 @NotNull 1399 private InstructionWithValue generateCall(JetExpression calleeExpression, ResolvedCall<?> resolvedCall) { 1400 if (resolvedCall instanceof VariableAsFunctionResolvedCall) { 1401 VariableAsFunctionResolvedCall variableAsFunctionResolvedCall = (VariableAsFunctionResolvedCall) resolvedCall; 1402 return generateCall(calleeExpression, variableAsFunctionResolvedCall.getFunctionCall()); 1403 } 1404 1405 JetElement callElement = resolvedCall.getCall().getCallElement(); 1406 JetExpression callExpression = callElement instanceof JetExpression ? (JetExpression) callElement : null; 1407 1408 CallableDescriptor resultingDescriptor = resolvedCall.getResultingDescriptor(); 1409 Map<PseudoValue, ReceiverValue> receivers = getReceiverValues(resolvedCall, true); 1410 SmartFMap<PseudoValue, ValueParameterDescriptor> parameterValues = SmartFMap.emptyMap(); 1411 for (ValueParameterDescriptor parameterDescriptor : resultingDescriptor.getValueParameters()) { 1412 ResolvedValueArgument argument = resolvedCall.getValueArguments().get(parameterDescriptor); 1413 if (argument == null) continue; 1414 1415 parameterValues = generateValueArgument(argument, parameterDescriptor, parameterValues); 1416 } 1417 1418 if (resultingDescriptor instanceof VariableDescriptor) { 1419 assert callExpression != null 1420 : "Variable-based call without call expression: " + callElement.getText(); 1421 assert parameterValues.isEmpty() 1422 : "Variable-based call with non-empty argument list: " + callElement.getText(); 1423 return builder.readVariable(calleeExpression, callExpression, resolvedCall, receivers); 1424 } 1425 mark(resolvedCall.getCall().getCallElement()); 1426 return builder.call(calleeExpression, callExpression, resolvedCall, receivers, parameterValues); 1427 } 1428 1429 @NotNull 1430 private Map<PseudoValue, ReceiverValue> getReceiverValues( 1431 ResolvedCall<?> resolvedCall, 1432 boolean generateInstructions) { 1433 SmartFMap<PseudoValue, ReceiverValue> receiverValues = SmartFMap.emptyMap(); 1434 JetElement callElement = resolvedCall.getCall().getCallElement(); 1435 receiverValues = getReceiverValues(callElement, resolvedCall.getThisObject(), generateInstructions, receiverValues); 1436 receiverValues = getReceiverValues(callElement, resolvedCall.getReceiverArgument(), generateInstructions, receiverValues); 1437 return receiverValues; 1438 } 1439 1440 @NotNull 1441 private SmartFMap<PseudoValue, ReceiverValue> getReceiverValues( 1442 JetElement callElement, 1443 ReceiverValue receiver, 1444 boolean generateInstructions, 1445 SmartFMap<PseudoValue, ReceiverValue> receiverValues 1446 ) { 1447 if (!receiver.exists()) return receiverValues; 1448 1449 if (receiver instanceof ThisReceiver) { 1450 if (generateInstructions) { 1451 receiverValues = receiverValues.plus(createSyntheticValue(callElement), receiver); 1452 } 1453 } 1454 else if (receiver instanceof ExpressionReceiver) { 1455 JetExpression expression = ((ExpressionReceiver) receiver).getExpression(); 1456 if (generateInstructions) { 1457 generateInstructions(expression); 1458 } 1459 1460 PseudoValue receiverPseudoValue = builder.getBoundValue(expression); 1461 if (receiverPseudoValue != null) { 1462 receiverValues = receiverValues.plus(receiverPseudoValue, receiver); 1463 } 1464 } 1465 else if (receiver instanceof TransientReceiver) { 1466 // Do nothing 1467 } 1468 else { 1469 throw new IllegalArgumentException("Unknown receiver kind: " + receiver); 1470 } 1471 1472 return receiverValues; 1473 } 1474 1475 @NotNull 1476 private SmartFMap<PseudoValue, ValueParameterDescriptor> generateValueArgument( 1477 ResolvedValueArgument argument, 1478 ValueParameterDescriptor parameterDescriptor, 1479 SmartFMap<PseudoValue, ValueParameterDescriptor> parameterValues 1480 ) { 1481 for (ValueArgument valueArgument : argument.getArguments()) { 1482 parameterValues = generateValueArgument(valueArgument, parameterDescriptor, parameterValues); 1483 } 1484 1485 return parameterValues; 1486 } 1487 1488 @NotNull 1489 private SmartFMap<PseudoValue, ValueParameterDescriptor> generateValueArgument( 1490 ValueArgument valueArgument, 1491 ValueParameterDescriptor parameterDescriptor, 1492 SmartFMap<PseudoValue, ValueParameterDescriptor> parameterValues) { 1493 JetExpression expression = valueArgument.getArgumentExpression(); 1494 if (expression != null) { 1495 generateInstructions(expression); 1496 1497 PseudoValue argValue = builder.getBoundValue(expression); 1498 if (argValue != null) { 1499 parameterValues = parameterValues.plus(argValue, parameterDescriptor); 1500 } 1501 } 1502 return parameterValues; 1503 } 1504 } 1505 }