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