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