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 }