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