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 List<PseudoValue> arguments = Collections.singletonList(rhsDeferredValue.invoke());
461 builder.magic(parentExpression, parentExpression, arguments, defaultTypeMap(arguments), MagicKind.UNSUPPORTED_ELEMENT);
462 return;
463 }
464
465 if (left instanceof JetArrayAccessExpression) {
466 generateArrayAssignment((JetArrayAccessExpression) left, rhsDeferredValue, parentExpression);
467 return;
468 }
469
470 Map<PseudoValue, ReceiverValue> receiverValues = SmartFMap.emptyMap();
471 AccessTarget accessTarget = AccessTarget.BlackBox.INSTANCE$;
472 if (left instanceof JetSimpleNameExpression || left instanceof JetQualifiedExpression) {
473 accessTarget = getResolvedCallAccessTarget(PsiUtilPackage.getQualifiedElementSelector(left));
474 if (accessTarget instanceof AccessTarget.Call) {
475 receiverValues = getReceiverValues(((AccessTarget.Call) accessTarget).getResolvedCall());
476 }
477 }
478 else if (left instanceof JetProperty) {
479 accessTarget = getDeclarationAccessTarget(left);
480 }
481
482 recordWrite(left, accessTarget, rhsDeferredValue.invoke(), receiverValues, parentExpression);
483 }
484
485 private void generateArrayAssignment(
486 JetArrayAccessExpression lhs,
487 @NotNull Function0<PseudoValue> rhsDeferredValue,
488 @NotNull JetExpression parentExpression
489 ) {
490 ResolvedCall<FunctionDescriptor> setResolvedCall = trace.get(BindingContext.INDEXED_LVALUE_SET, lhs);
491
492 if (setResolvedCall == null) {
493 generateArrayAccess(lhs, null);
494
495 List<PseudoValue> arguments = Arrays.asList(getBoundOrUnreachableValue(lhs), rhsDeferredValue.invoke());
496 builder.magic(parentExpression, parentExpression, arguments, defaultTypeMap(arguments), MagicKind.UNRESOLVED_CALL);
497
498 return;
499 }
500
501 // In case of simple ('=') array assignment mark instruction is not generated yet, so we put it before generating "set" call
502 if (((JetOperationExpression) parentExpression).getOperationReference().getReferencedNameElementType() == EQ) {
503 mark(lhs);
504 }
505
506 generateInstructions(lhs.getArrayExpression());
507
508 Map<PseudoValue, ReceiverValue> receiverValues = getReceiverValues(setResolvedCall);
509 SmartFMap<PseudoValue, ValueParameterDescriptor> argumentValues =
510 getArraySetterArguments(rhsDeferredValue, setResolvedCall);
511
512 builder.call(parentExpression, setResolvedCall, receiverValues, argumentValues);
513 }
514
515 /* We assume that assignment right-hand side corresponds to the last argument of the call
516 * So receiver instructions/pseudo-values are generated for all arguments except the last one which is replaced
517 * by pre-generated pseudo-value
518 * For example, assignment a[1, 2] += 3 means a.set(1, 2, a.get(1) + 3), so in order to generate "set" call
519 * we first generate instructions for 1 and 2 whereas 3 is replaced by pseudo-value corresponding to "a.get(1) + 3"
520 */
521 private SmartFMap<PseudoValue, ValueParameterDescriptor> getArraySetterArguments(
522 Function0<PseudoValue> rhsDeferredValue,
523 final ResolvedCall<FunctionDescriptor> setResolvedCall
524 ) {
525 List<ValueArgument> valueArguments = KotlinPackage.flatMapTo(
526 setResolvedCall.getResultingDescriptor().getValueParameters(),
527 new ArrayList<ValueArgument>(),
528 new Function1<ValueParameterDescriptor, Iterable<? extends ValueArgument>>() {
529 @Override
530 public Iterable<? extends ValueArgument> invoke(ValueParameterDescriptor descriptor) {
531 ResolvedValueArgument resolvedValueArgument = setResolvedCall.getValueArguments().get(descriptor);
532 return resolvedValueArgument != null
533 ? resolvedValueArgument.getArguments()
534 : Collections.<ValueArgument>emptyList();
535 }
536 }
537 );
538
539 ValueArgument rhsArgument = KotlinPackage.lastOrNull(valueArguments);
540 SmartFMap<PseudoValue, ValueParameterDescriptor> argumentValues = SmartFMap.emptyMap();
541 for (ValueArgument valueArgument : valueArguments) {
542 ArgumentMapping argumentMapping = setResolvedCall.getArgumentMapping(valueArgument);
543 if (argumentMapping.isError() || (!(argumentMapping instanceof ArgumentMatch))) continue;
544
545 ValueParameterDescriptor parameterDescriptor = ((ArgumentMatch) argumentMapping).getValueParameter();
546 if (valueArgument != rhsArgument) {
547 argumentValues = generateValueArgument(valueArgument, parameterDescriptor, argumentValues);
548 }
549 else {
550 PseudoValue rhsValue = rhsDeferredValue.invoke();
551 if (rhsValue != null) {
552 argumentValues = argumentValues.plus(rhsValue, parameterDescriptor);
553 }
554 }
555 }
556 return argumentValues;
557 }
558
559 private void recordWrite(
560 @NotNull JetExpression left,
561 @NotNull AccessTarget target,
562 @Nullable PseudoValue rightValue,
563 @NotNull Map<PseudoValue, ReceiverValue> receiverValues,
564 @NotNull JetExpression parentExpression
565 ) {
566 if (target == AccessTarget.BlackBox.INSTANCE$) {
567 List<PseudoValue> values = ContainerUtil.createMaybeSingletonList(rightValue);
568 builder.magic(parentExpression, parentExpression, values, defaultTypeMap(values), MagicKind.UNSUPPORTED_ELEMENT);
569 }
570 else {
571 PseudoValue rValue =
572 rightValue != null ? rightValue : createSyntheticValue(parentExpression, MagicKind.UNRECOGNIZED_WRITE_RHS);
573 builder.write(parentExpression, left, rValue, target, receiverValues);
574 }
575 }
576
577 private void generateArrayAccess(JetArrayAccessExpression arrayAccessExpression, @Nullable ResolvedCall<?> resolvedCall) {
578 if (builder.getBoundValue(arrayAccessExpression) != null) return;
579 mark(arrayAccessExpression);
580 if (!checkAndGenerateCall(resolvedCall)) {
581 generateArrayAccessWithoutCall(arrayAccessExpression);
582 }
583 }
584
585 private void generateArrayAccessWithoutCall(JetArrayAccessExpression arrayAccessExpression) {
586 createNonSyntheticValue(arrayAccessExpression, generateArrayAccessArguments(arrayAccessExpression), MagicKind.UNRESOLVED_CALL);
587 }
588
589 private List<JetExpression> generateArrayAccessArguments(JetArrayAccessExpression arrayAccessExpression) {
590 List<JetExpression> inputExpressions = new ArrayList<JetExpression>();
591
592 JetExpression arrayExpression = arrayAccessExpression.getArrayExpression();
593 inputExpressions.add(arrayExpression);
594 generateInstructions(arrayExpression);
595
596 for (JetExpression index : arrayAccessExpression.getIndexExpressions()) {
597 generateInstructions(index);
598 inputExpressions.add(index);
599 }
600
601 return inputExpressions;
602 }
603
604 @Override
605 public void visitUnaryExpression(@NotNull JetUnaryExpression expression) {
606 JetSimpleNameExpression operationSign = expression.getOperationReference();
607 IElementType operationType = operationSign.getReferencedNameElementType();
608 JetExpression baseExpression = expression.getBaseExpression();
609 if (baseExpression == null) return;
610 if (JetTokens.EXCLEXCL == operationType) {
611 generateInstructions(baseExpression);
612 builder.predefinedOperation(expression, NOT_NULL_ASSERTION, elementsToValues(Collections.singletonList(baseExpression)));
613 return;
614 }
615
616 boolean incrementOrDecrement = isIncrementOrDecrement(operationType);
617 ResolvedCall<?> resolvedCall = getResolvedCall(expression, trace.getBindingContext());
618
619 PseudoValue rhsValue;
620 if (resolvedCall != null) {
621 rhsValue = generateCall(resolvedCall).getOutputValue();
622 }
623 else {
624 generateInstructions(baseExpression);
625 rhsValue = createNonSyntheticValue(expression, MagicKind.UNRESOLVED_CALL, baseExpression);
626 }
627
628 if (incrementOrDecrement) {
629 visitAssignment(baseExpression, getValueAsFunction(rhsValue), expression);
630 if (expression instanceof JetPostfixExpression) {
631 copyValue(baseExpression, expression);
632 }
633 }
634 }
635
636 private boolean isIncrementOrDecrement(IElementType operationType) {
637 return operationType == JetTokens.PLUSPLUS || operationType == JetTokens.MINUSMINUS;
638 }
639
640 @Override
641 public void visitIfExpression(@NotNull JetIfExpression expression) {
642 mark(expression);
643 List<JetExpression> branches = new ArrayList<JetExpression>(2);
644 JetExpression condition = expression.getCondition();
645 if (condition != null) {
646 generateInstructions(condition);
647 }
648 Label elseLabel = builder.createUnboundLabel("else branch");
649 builder.jumpOnFalse(elseLabel, expression, builder.getBoundValue(condition));
650 JetExpression thenBranch = expression.getThen();
651 if (thenBranch != null) {
652 branches.add(thenBranch);
653 generateInstructions(thenBranch);
654 }
655 else {
656 builder.loadUnit(expression);
657 }
658 Label resultLabel = builder.createUnboundLabel("'if' expression result");
659 builder.jump(resultLabel, expression);
660 builder.bindLabel(elseLabel);
661 JetExpression elseBranch = expression.getElse();
662 if (elseBranch != null) {
663 branches.add(elseBranch);
664 generateInstructions(elseBranch);
665 }
666 else {
667 builder.loadUnit(expression);
668 }
669 builder.bindLabel(resultLabel);
670 mergeValues(branches, expression);
671 }
672
673 private class FinallyBlockGenerator {
674 private final JetFinallySection finallyBlock;
675 private Label startFinally = null;
676 private Label finishFinally = null;
677
678 private FinallyBlockGenerator(JetFinallySection block) {
679 finallyBlock = block;
680 }
681
682 public void generate() {
683 JetBlockExpression finalExpression = finallyBlock.getFinalExpression();
684 if (finalExpression == null) return;
685 if (startFinally != null) {
686 assert finishFinally != null;
687 builder.repeatPseudocode(startFinally, finishFinally);
688 return;
689 }
690 startFinally = builder.createUnboundLabel("start finally");
691 builder.bindLabel(startFinally);
692 generateInstructions(finalExpression);
693 finishFinally = builder.createUnboundLabel("finish finally");
694 builder.bindLabel(finishFinally);
695 }
696 }
697
698 @Override
699 public void visitTryExpression(@NotNull JetTryExpression expression) {
700 mark(expression);
701
702 JetFinallySection finallyBlock = expression.getFinallyBlock();
703 final FinallyBlockGenerator finallyBlockGenerator = new FinallyBlockGenerator(finallyBlock);
704 boolean hasFinally = finallyBlock != null;
705 if (hasFinally) {
706 builder.enterTryFinally(new GenerationTrigger() {
707 private boolean working = false;
708
709 @Override
710 public void generate() {
711 // This checks are needed for the case of having e.g. return inside finally: 'try {return} finally{return}'
712 if (working) return;
713 working = true;
714 finallyBlockGenerator.generate();
715 working = false;
716 }
717 });
718 }
719
720 Label onExceptionToFinallyBlock = generateTryAndCatches(expression);
721
722 if (hasFinally) {
723 assert onExceptionToFinallyBlock != null : "No finally lable generated: " + expression.getText();
724
725 builder.exitTryFinally();
726
727 Label skipFinallyToErrorBlock = builder.createUnboundLabel("skipFinallyToErrorBlock");
728 builder.jump(skipFinallyToErrorBlock, expression);
729 builder.bindLabel(onExceptionToFinallyBlock);
730 finallyBlockGenerator.generate();
731 builder.jumpToError(expression);
732 builder.bindLabel(skipFinallyToErrorBlock);
733
734 finallyBlockGenerator.generate();
735 }
736
737 List<JetExpression> branches = new ArrayList<JetExpression>();
738 branches.add(expression.getTryBlock());
739 for (JetCatchClause catchClause : expression.getCatchClauses()) {
740 branches.add(catchClause.getCatchBody());
741 }
742 mergeValues(branches, expression);
743 }
744
745 // Returns label for 'finally' block
746 @Nullable
747 private Label generateTryAndCatches(@NotNull JetTryExpression expression) {
748 List<JetCatchClause> catchClauses = expression.getCatchClauses();
749 boolean hasCatches = !catchClauses.isEmpty();
750
751 Label onException = null;
752 if (hasCatches) {
753 onException = builder.createUnboundLabel("onException");
754 builder.nondeterministicJump(onException, expression, null);
755 }
756
757 Label onExceptionToFinallyBlock = null;
758 if (expression.getFinallyBlock() != null) {
759 onExceptionToFinallyBlock = builder.createUnboundLabel("onExceptionToFinallyBlock");
760 builder.nondeterministicJump(onExceptionToFinallyBlock, expression, null);
761 }
762
763 JetBlockExpression tryBlock = expression.getTryBlock();
764 generateInstructions(tryBlock);
765
766 if (hasCatches) {
767 Label afterCatches = builder.createUnboundLabel("afterCatches");
768 builder.jump(afterCatches, expression);
769
770 builder.bindLabel(onException);
771 LinkedList<Label> catchLabels = Lists.newLinkedList();
772 int catchClausesSize = catchClauses.size();
773 for (int i = 0; i < catchClausesSize - 1; i++) {
774 catchLabels.add(builder.createUnboundLabel("catch " + i));
775 }
776 if (!catchLabels.isEmpty()) {
777 builder.nondeterministicJump(catchLabels, expression);
778 }
779 boolean isFirst = true;
780 for (JetCatchClause catchClause : catchClauses) {
781 builder.enterLexicalScope(catchClause);
782 if (!isFirst) {
783 builder.bindLabel(catchLabels.remove());
784 }
785 else {
786 isFirst = false;
787 }
788 JetParameter catchParameter = catchClause.getCatchParameter();
789 if (catchParameter != null) {
790 builder.declareParameter(catchParameter);
791 generateInitializer(catchParameter, createSyntheticValue(catchParameter, MagicKind.FAKE_INITIALIZER));
792 }
793 JetExpression catchBody = catchClause.getCatchBody();
794 if (catchBody != null) {
795 generateInstructions(catchBody);
796 }
797 builder.jump(afterCatches, expression);
798 builder.exitLexicalScope(catchClause);
799 }
800
801 builder.bindLabel(afterCatches);
802 }
803
804 return onExceptionToFinallyBlock;
805 }
806
807 @Override
808 public void visitWhileExpression(@NotNull JetWhileExpression expression) {
809 LoopInfo loopInfo = builder.enterLoop(expression);
810
811 builder.bindLabel(loopInfo.getConditionEntryPoint());
812 JetExpression condition = expression.getCondition();
813 if (condition != null) {
814 generateInstructions(condition);
815 }
816 mark(expression);
817 boolean conditionIsTrueConstant = CompileTimeConstantUtils.canBeReducedToBooleanConstant(condition, trace, true);
818 if (!conditionIsTrueConstant) {
819 builder.jumpOnFalse(loopInfo.getExitPoint(), expression, builder.getBoundValue(condition));
820 }
821 else {
822 assert condition != null : "Invalid while condition: " + expression.getText();
823 List<PseudoValue> values = ContainerUtil.createMaybeSingletonList(builder.getBoundValue(condition));
824 Map<PseudoValue, TypePredicate> typePredicates =
825 PseudocodePackage.expectedTypeFor(new SingleType(KotlinBuiltIns.getInstance().getBooleanType()), values);
826 builder.magic(condition, null, values, typePredicates, MagicKind.VALUE_CONSUMER);
827 }
828
829 builder.enterLoopBody(expression);
830 JetExpression body = expression.getBody();
831 if (body != null) {
832 generateInstructions(body);
833 }
834 builder.jump(loopInfo.getEntryPoint(), expression);
835 builder.exitLoopBody(expression);
836 builder.bindLabel(loopInfo.getExitPoint());
837 builder.loadUnit(expression);
838 }
839
840 @Override
841 public void visitDoWhileExpression(@NotNull JetDoWhileExpression expression) {
842 builder.enterLexicalScope(expression);
843 mark(expression);
844 LoopInfo loopInfo = builder.enterLoop(expression);
845
846 builder.enterLoopBody(expression);
847 JetExpression body = expression.getBody();
848 if (body != null) {
849 generateInstructions(body);
850 }
851 builder.exitLoopBody(expression);
852 builder.bindLabel(loopInfo.getConditionEntryPoint());
853 JetExpression condition = expression.getCondition();
854 if (condition != null) {
855 generateInstructions(condition);
856 }
857 builder.jumpOnTrue(loopInfo.getEntryPoint(), expression, builder.getBoundValue(condition));
858 builder.bindLabel(loopInfo.getExitPoint());
859 builder.loadUnit(expression);
860 builder.exitLexicalScope(expression);
861 }
862
863 @Override
864 public void visitForExpression(@NotNull JetForExpression expression) {
865 builder.enterLexicalScope(expression);
866
867 JetExpression loopRange = expression.getLoopRange();
868 if (loopRange != null) {
869 generateInstructions(loopRange);
870 }
871 declareLoopParameter(expression);
872
873 // TODO : primitive cases
874 LoopInfo loopInfo = builder.enterLoop(expression);
875
876 builder.bindLabel(loopInfo.getConditionEntryPoint());
877 builder.nondeterministicJump(loopInfo.getExitPoint(), expression, null);
878
879
880 writeLoopParameterAssignment(expression);
881
882 mark(expression);
883 builder.enterLoopBody(expression);
884 JetExpression body = expression.getBody();
885 if (body != null) {
886 generateInstructions(body);
887 }
888 builder.jump(loopInfo.getEntryPoint(), expression);
889
890 builder.exitLoopBody(expression);
891 builder.bindLabel(loopInfo.getExitPoint());
892 builder.loadUnit(expression);
893 builder.exitLexicalScope(expression);
894 }
895
896 private void declareLoopParameter(JetForExpression expression) {
897 JetParameter loopParameter = expression.getLoopParameter();
898 JetMultiDeclaration multiDeclaration = expression.getMultiParameter();
899 if (loopParameter != null) {
900 builder.declareParameter(loopParameter);
901 }
902 else if (multiDeclaration != null) {
903 visitMultiDeclaration(multiDeclaration, false);
904 }
905 }
906
907 private void writeLoopParameterAssignment(JetForExpression expression) {
908 JetParameter loopParameter = expression.getLoopParameter();
909 JetMultiDeclaration multiDeclaration = expression.getMultiParameter();
910 JetExpression loopRange = expression.getLoopRange();
911
912 TypePredicate loopRangeTypePredicate =
913 getTypePredicateByReceiverValue(trace.get(BindingContext.LOOP_RANGE_ITERATOR_RESOLVED_CALL, loopRange));
914
915 PseudoValue loopRangeValue = builder.getBoundValue(loopRange);
916 PseudoValue value = builder.magic(
917 loopRange != null ? loopRange : expression,
918 null,
919 ContainerUtil.createMaybeSingletonList(loopRangeValue),
920 loopRangeValue != null
921 ? Collections.singletonMap(loopRangeValue, loopRangeTypePredicate)
922 : Collections.<PseudoValue, TypePredicate>emptyMap(),
923 MagicKind.LOOP_RANGE_ITERATION
924 ).getOutputValue();
925
926 if (loopParameter != null) {
927 generateInitializer(loopParameter, value);
928 }
929 else if (multiDeclaration != null) {
930 for (JetMultiDeclarationEntry entry : multiDeclaration.getEntries()) {
931 generateInitializer(entry, value);
932 }
933 }
934 }
935
936 private ReceiverValue getExplicitReceiverValue(ResolvedCall<?> resolvedCall) {
937 switch(resolvedCall.getExplicitReceiverKind()) {
938 case DISPATCH_RECEIVER:
939 return resolvedCall.getDispatchReceiver();
940 case EXTENSION_RECEIVER:
941 return resolvedCall.getExtensionReceiver();
942 default:
943 return ReceiverValue.NO_RECEIVER;
944 }
945 }
946
947 @Override
948 public void visitBreakExpression(@NotNull JetBreakExpression expression) {
949 JetElement loop = getCorrespondingLoop(expression);
950 if (loop != null) {
951 checkJumpDoesNotCrossFunctionBoundary(expression, loop);
952 builder.jump(builder.getExitPoint(loop), expression);
953 }
954 }
955
956 @Override
957 public void visitContinueExpression(@NotNull JetContinueExpression expression) {
958 JetElement loop = getCorrespondingLoop(expression);
959 if (loop != null) {
960 checkJumpDoesNotCrossFunctionBoundary(expression, loop);
961 builder.jump(builder.getConditionEntryPoint(loop), expression);
962 }
963 }
964
965 @Nullable
966 private JetElement getCorrespondingLoop(JetExpressionWithLabel expression) {
967 String labelName = expression.getLabelName();
968 JetLoopExpression loop;
969 if (labelName != null) {
970 JetSimpleNameExpression targetLabel = expression.getTargetLabel();
971 assert targetLabel != null;
972 PsiElement labeledElement = trace.get(BindingContext.LABEL_TARGET, targetLabel);
973 if (labeledElement instanceof JetLoopExpression) {
974 loop = (JetLoopExpression) labeledElement;
975 }
976 else {
977 trace.report(NOT_A_LOOP_LABEL.on(expression, targetLabel.getText()));
978 loop = null;
979 }
980 }
981 else {
982 loop = builder.getCurrentLoop();
983 if (loop == null) {
984 trace.report(BREAK_OR_CONTINUE_OUTSIDE_A_LOOP.on(expression));
985 }
986 }
987 if (loop != null && loop.getBody() != null
988 // the faster version of 'isAncestor' check:
989 && !loop.getBody().getTextRange().contains(expression.getTextRange())) {
990 trace.report(BREAK_OR_CONTINUE_OUTSIDE_A_LOOP.on(expression));
991 return null;
992 }
993 return loop;
994 }
995
996 private void checkJumpDoesNotCrossFunctionBoundary(@NotNull JetExpressionWithLabel jumpExpression, @NotNull JetElement jumpTarget) {
997 BindingContext bindingContext = trace.getBindingContext();
998
999 FunctionDescriptor labelExprEnclosingFunc = BindingContextUtils.getEnclosingFunctionDescriptor(bindingContext, jumpExpression);
1000 FunctionDescriptor labelTargetEnclosingFunc = BindingContextUtils.getEnclosingFunctionDescriptor(bindingContext, jumpTarget);
1001 if (labelExprEnclosingFunc != labelTargetEnclosingFunc) {
1002 trace.report(BREAK_OR_CONTINUE_JUMPS_ACROSS_FUNCTION_BOUNDARY.on(jumpExpression));
1003 }
1004 }
1005
1006 @Override
1007 public void visitReturnExpression(@NotNull JetReturnExpression expression) {
1008 JetExpression returnedExpression = expression.getReturnedExpression();
1009 if (returnedExpression != null) {
1010 generateInstructions(returnedExpression);
1011 }
1012 JetSimpleNameExpression labelElement = expression.getTargetLabel();
1013 JetElement subroutine;
1014 String labelName = expression.getLabelName();
1015 if (labelElement != null && labelName != null) {
1016 PsiElement labeledElement = trace.get(BindingContext.LABEL_TARGET, labelElement);
1017 if (labeledElement != null) {
1018 assert labeledElement instanceof JetElement;
1019 subroutine = (JetElement) labeledElement;
1020 }
1021 else {
1022 subroutine = null;
1023 }
1024 }
1025 else {
1026 subroutine = builder.getReturnSubroutine();
1027 // TODO : a context check
1028 }
1029
1030 if (subroutine instanceof JetFunction || subroutine instanceof JetPropertyAccessor) {
1031 PseudoValue returnValue = returnedExpression != null ? builder.getBoundValue(returnedExpression) : null;
1032 if (returnValue == null) {
1033 builder.returnNoValue(expression, subroutine);
1034 }
1035 else {
1036 builder.returnValue(expression, returnValue, subroutine);
1037 }
1038 }
1039 else {
1040 createNonSyntheticValue(expression, MagicKind.UNSUPPORTED_ELEMENT, returnedExpression);
1041 }
1042 }
1043
1044 @Override
1045 public void visitParameter(@NotNull JetParameter parameter) {
1046 builder.declareParameter(parameter);
1047 JetExpression defaultValue = parameter.getDefaultValue();
1048 if (defaultValue != null) {
1049 Label skipDefaultValue = builder.createUnboundLabel("after default value for parameter " + parameter.getName());
1050 builder.nondeterministicJump(skipDefaultValue, defaultValue, null);
1051 generateInstructions(defaultValue);
1052 builder.bindLabel(skipDefaultValue);
1053 }
1054 generateInitializer(parameter, computePseudoValueForParameter(parameter));
1055 }
1056
1057 @NotNull
1058 private PseudoValue computePseudoValueForParameter(@NotNull JetParameter parameter) {
1059 PseudoValue syntheticValue = createSyntheticValue(parameter, MagicKind.FAKE_INITIALIZER);
1060 PseudoValue defaultValue = builder.getBoundValue(parameter.getDefaultValue());
1061 if (defaultValue == null) {
1062 return syntheticValue;
1063 }
1064 return builder.merge(parameter, Lists.newArrayList(defaultValue, syntheticValue)).getOutputValue();
1065 }
1066
1067 @Override
1068 public void visitBlockExpression(@NotNull JetBlockExpression expression) {
1069 boolean declareLexicalScope = !isBlockInDoWhile(expression);
1070 if (declareLexicalScope) {
1071 builder.enterLexicalScope(expression);
1072 }
1073 mark(expression);
1074 List<JetElement> statements = expression.getStatements();
1075 for (JetElement statement : statements) {
1076 generateInstructions(statement);
1077 }
1078 if (statements.isEmpty()) {
1079 builder.loadUnit(expression);
1080 }
1081 else {
1082 copyValue(KotlinPackage.lastOrNull(statements), expression);
1083 }
1084 if (declareLexicalScope) {
1085 builder.exitLexicalScope(expression);
1086 }
1087 }
1088
1089 private boolean isBlockInDoWhile(@NotNull JetBlockExpression expression) {
1090 PsiElement parent = expression.getParent();
1091 if (parent == null) return false;
1092 return parent.getParent() instanceof JetDoWhileExpression;
1093 }
1094
1095 @Override
1096 public void visitNamedFunction(@NotNull JetNamedFunction function) {
1097 processLocalDeclaration(function);
1098 }
1099
1100 @Override
1101 public void visitFunctionLiteralExpression(@NotNull JetFunctionLiteralExpression expression) {
1102 mark(expression);
1103 JetFunctionLiteral functionLiteral = expression.getFunctionLiteral();
1104 processLocalDeclaration(functionLiteral);
1105 builder.createFunctionLiteral(expression);
1106 }
1107
1108 @Override
1109 public void visitQualifiedExpression(@NotNull JetQualifiedExpression expression) {
1110 mark(expression);
1111 JetExpression selectorExpression = expression.getSelectorExpression();
1112 JetExpression receiverExpression = expression.getReceiverExpression();
1113
1114 // todo: replace with selectorExpresion != null after parser is fixed
1115 if (selectorExpression instanceof JetCallExpression || selectorExpression instanceof JetSimpleNameExpression) {
1116 generateInstructions(selectorExpression);
1117 copyValue(selectorExpression, expression);
1118 }
1119 else {
1120 generateInstructions(receiverExpression);
1121 createNonSyntheticValue(expression, MagicKind.UNSUPPORTED_ELEMENT, receiverExpression);
1122 }
1123 }
1124
1125 @Override
1126 public void visitCallExpression(@NotNull JetCallExpression expression) {
1127 if (!generateCall(expression)) {
1128 List<JetExpression> inputExpressions = new ArrayList<JetExpression>();
1129 for (ValueArgument argument : expression.getValueArguments()) {
1130 JetExpression argumentExpression = argument.getArgumentExpression();
1131 if (argumentExpression != null) {
1132 generateInstructions(argumentExpression);
1133 inputExpressions.add(argumentExpression);
1134 }
1135 }
1136 JetExpression calleeExpression = expression.getCalleeExpression();
1137 generateInstructions(calleeExpression);
1138 inputExpressions.add(calleeExpression);
1139 inputExpressions.add(generateAndGetReceiverIfAny(expression));
1140
1141 mark(expression);
1142 createNonSyntheticValue(expression, inputExpressions, MagicKind.UNRESOLVED_CALL);
1143 }
1144 }
1145
1146 @Nullable
1147 private JetExpression generateAndGetReceiverIfAny(JetExpression expression) {
1148 PsiElement parent = expression.getParent();
1149 if (!(parent instanceof JetQualifiedExpression)) return null;
1150
1151 JetQualifiedExpression qualifiedExpression = (JetQualifiedExpression) parent;
1152 if (qualifiedExpression.getSelectorExpression() != expression) return null;
1153
1154 JetExpression receiverExpression = qualifiedExpression.getReceiverExpression();
1155 generateInstructions(receiverExpression);
1156
1157 return receiverExpression;
1158 }
1159
1160 @Override
1161 public void visitProperty(@NotNull JetProperty property) {
1162 builder.declareVariable(property);
1163 JetExpression initializer = property.getInitializer();
1164 if (initializer != null) {
1165 visitAssignment(property, getDeferredValue(initializer), property);
1166 }
1167 JetExpression delegate = property.getDelegateExpression();
1168 if (delegate != null) {
1169 generateInstructions(delegate);
1170 generateDelegateConsumer(property, delegate);
1171 }
1172
1173 if (JetPsiUtil.isLocal(property)) {
1174 for (JetPropertyAccessor accessor : property.getAccessors()) {
1175 generateInstructions(accessor);
1176 }
1177 }
1178 }
1179
1180 private void generateDelegateConsumer(@NotNull JetProperty property, @NotNull JetExpression delegate) {
1181 DeclarationDescriptor descriptor = trace.get(BindingContext.DECLARATION_TO_DESCRIPTOR, property);
1182 if (!(descriptor instanceof PropertyDescriptor)) return;
1183
1184 PseudoValue delegateValue = builder.getBoundValue(delegate);
1185 if (delegateValue == null) return;
1186
1187 List<TypePredicate> typePredicates = KotlinPackage.map(
1188 ((PropertyDescriptor) descriptor).getAccessors(),
1189 new Function1<PropertyAccessorDescriptor, TypePredicate>() {
1190 @Override
1191 public TypePredicate invoke(PropertyAccessorDescriptor descriptor) {
1192 return getTypePredicateByReceiverValue(trace.get(BindingContext.DELEGATED_PROPERTY_RESOLVED_CALL, descriptor));
1193 }
1194 }
1195 );
1196 Map<PseudoValue, TypePredicate> valuesToTypePredicates = SmartFMap
1197 .<PseudoValue, TypePredicate>emptyMap()
1198 .plus(delegateValue, PseudocodePackage.and(KotlinPackage.filterNotNull(typePredicates)));
1199 builder.magic(property, null, Collections.singletonList(delegateValue), valuesToTypePredicates, MagicKind.VALUE_CONSUMER);
1200 }
1201
1202 private TypePredicate getTypePredicateByReceiverValue(@Nullable ResolvedCall<?> resolvedCall) {
1203 if (resolvedCall == null) return AllTypes.INSTANCE$;
1204
1205 ReceiverValue receiverValue = getExplicitReceiverValue(resolvedCall);
1206 if (receiverValue.exists()) {
1207 return PseudocodePackage.getReceiverTypePredicate(resolvedCall, receiverValue);
1208 }
1209
1210 return AllTypes.INSTANCE$;
1211 }
1212
1213 @Override
1214 public void visitMultiDeclaration(@NotNull JetMultiDeclaration declaration) {
1215 visitMultiDeclaration(declaration, true);
1216 }
1217
1218 private void visitMultiDeclaration(@NotNull JetMultiDeclaration declaration, boolean generateWriteForEntries) {
1219 JetExpression initializer = declaration.getInitializer();
1220 generateInstructions(initializer);
1221 for (JetMultiDeclarationEntry entry : declaration.getEntries()) {
1222 builder.declareVariable(entry);
1223
1224 ResolvedCall<FunctionDescriptor> resolvedCall = trace.get(BindingContext.COMPONENT_RESOLVED_CALL, entry);
1225
1226 PseudoValue writtenValue;
1227 if (resolvedCall != null) {
1228 writtenValue = builder.call(
1229 entry,
1230 resolvedCall,
1231 getReceiverValues(resolvedCall),
1232 Collections.<PseudoValue, ValueParameterDescriptor>emptyMap()
1233 ).getOutputValue();
1234 }
1235 else {
1236 writtenValue = createSyntheticValue(entry, MagicKind.UNRESOLVED_CALL, initializer);
1237 }
1238
1239 if (generateWriteForEntries) {
1240 generateInitializer(entry, writtenValue != null ? writtenValue : createSyntheticValue(entry, MagicKind.FAKE_INITIALIZER));
1241 }
1242 }
1243 }
1244
1245 @Override
1246 public void visitPropertyAccessor(@NotNull JetPropertyAccessor accessor) {
1247 processLocalDeclaration(accessor);
1248 }
1249
1250 @Override
1251 public void visitBinaryWithTypeRHSExpression(@NotNull JetBinaryExpressionWithTypeRHS expression) {
1252 mark(expression);
1253
1254 IElementType operationType = expression.getOperationReference().getReferencedNameElementType();
1255 JetExpression left = expression.getLeft();
1256 if (operationType == JetTokens.COLON || operationType == JetTokens.AS_KEYWORD || operationType == JetTokens.AS_SAFE) {
1257 generateInstructions(left);
1258 if (getBoundOrUnreachableValue(left) != null) {
1259 createNonSyntheticValue(expression, MagicKind.CAST, left);
1260 }
1261 }
1262 else {
1263 visitJetElement(expression);
1264 createNonSyntheticValue(expression, MagicKind.UNSUPPORTED_ELEMENT, left);
1265 }
1266 }
1267
1268 @Override
1269 public void visitThrowExpression(@NotNull JetThrowExpression expression) {
1270 mark(expression);
1271
1272 JetExpression thrownExpression = expression.getThrownExpression();
1273 if (thrownExpression == null) return;
1274
1275 generateInstructions(thrownExpression);
1276
1277 PseudoValue thrownValue = builder.getBoundValue(thrownExpression);
1278 if (thrownValue == null) return;
1279
1280 builder.throwException(expression, thrownValue);
1281 }
1282
1283 @Override
1284 public void visitArrayAccessExpression(@NotNull JetArrayAccessExpression expression) {
1285 generateArrayAccess(expression, trace.get(BindingContext.INDEXED_LVALUE_GET, expression));
1286 }
1287
1288 @Override
1289 public void visitIsExpression(@NotNull JetIsExpression expression) {
1290 mark(expression);
1291 JetExpression left = expression.getLeftHandSide();
1292 generateInstructions(left);
1293 createNonSyntheticValue(expression, MagicKind.IS, left);
1294 }
1295
1296 @Override
1297 public void visitWhenExpression(@NotNull JetWhenExpression expression) {
1298 mark(expression);
1299
1300 JetExpression subjectExpression = expression.getSubjectExpression();
1301 if (subjectExpression != null) {
1302 generateInstructions(subjectExpression);
1303 }
1304
1305 List<JetExpression> branches = new ArrayList<JetExpression>();
1306
1307 Label doneLabel = builder.createUnboundLabel("after 'when' expression");
1308
1309 Label nextLabel = null;
1310 for (Iterator<JetWhenEntry> iterator = expression.getEntries().iterator(); iterator.hasNext(); ) {
1311 JetWhenEntry whenEntry = iterator.next();
1312 mark(whenEntry);
1313
1314 boolean isElse = whenEntry.isElse();
1315 if (isElse) {
1316 if (iterator.hasNext()) {
1317 trace.report(ELSE_MISPLACED_IN_WHEN.on(whenEntry));
1318 }
1319 }
1320 Label bodyLabel = builder.createUnboundLabel("'when' entry body");
1321
1322 JetWhenCondition[] conditions = whenEntry.getConditions();
1323 for (int i = 0; i < conditions.length; i++) {
1324 JetWhenCondition condition = conditions[i];
1325 condition.accept(conditionVisitor);
1326 if (i + 1 < conditions.length) {
1327 builder.nondeterministicJump(bodyLabel, expression, builder.getBoundValue(condition));
1328 }
1329 }
1330
1331 if (!isElse) {
1332 nextLabel = builder.createUnboundLabel("next 'when' entry");
1333 JetWhenCondition lastCondition = KotlinPackage.lastOrNull(conditions);
1334 builder.nondeterministicJump(nextLabel, expression, builder.getBoundValue(lastCondition));
1335 }
1336
1337 builder.bindLabel(bodyLabel);
1338 JetExpression whenEntryExpression = whenEntry.getExpression();
1339 if (whenEntryExpression != null) {
1340 generateInstructions(whenEntryExpression);
1341 branches.add(whenEntryExpression);
1342 }
1343 builder.jump(doneLabel, expression);
1344
1345 if (!isElse) {
1346 builder.bindLabel(nextLabel);
1347 }
1348 }
1349 builder.bindLabel(doneLabel);
1350
1351 mergeValues(branches, expression);
1352 }
1353
1354 @Override
1355 public void visitObjectLiteralExpression(@NotNull JetObjectLiteralExpression expression) {
1356 mark(expression);
1357 JetObjectDeclaration declaration = expression.getObjectDeclaration();
1358 generateInstructions(declaration);
1359
1360 builder.createAnonymousObject(expression);
1361 }
1362
1363 @Override
1364 public void visitObjectDeclaration(@NotNull JetObjectDeclaration objectDeclaration) {
1365 visitClassOrObject(objectDeclaration);
1366 }
1367
1368 @Override
1369 public void visitStringTemplateExpression(@NotNull JetStringTemplateExpression expression) {
1370 mark(expression);
1371
1372 List<JetExpression> inputExpressions = new ArrayList<JetExpression>();
1373 for (JetStringTemplateEntry entry : expression.getEntries()) {
1374 if (entry instanceof JetStringTemplateEntryWithExpression) {
1375 JetExpression entryExpression = entry.getExpression();
1376 generateInstructions(entryExpression);
1377 inputExpressions.add(entryExpression);
1378 }
1379 }
1380 builder.loadStringTemplate(expression, elementsToValues(inputExpressions));
1381 }
1382
1383 @Override
1384 public void visitTypeProjection(@NotNull JetTypeProjection typeProjection) {
1385 // TODO : Support Type Arguments. Class object may be initialized at this point");
1386 }
1387
1388 @Override
1389 public void visitAnonymousInitializer(@NotNull JetClassInitializer classInitializer) {
1390 generateInstructions(classInitializer.getBody());
1391 }
1392
1393 private void visitClassOrObject(JetClassOrObject classOrObject) {
1394 for (JetDelegationSpecifier specifier : classOrObject.getDelegationSpecifiers()) {
1395 generateInstructions(specifier);
1396 }
1397 List<JetDeclaration> declarations = classOrObject.getDeclarations();
1398 if (classOrObject.isLocal()) {
1399 for (JetDeclaration declaration : declarations) {
1400 generateInstructions(declaration);
1401 }
1402 return;
1403 }
1404 //For top-level and inner classes and objects functions are collected and checked separately.
1405 for (JetDeclaration declaration : declarations) {
1406 if (declaration instanceof JetProperty || declaration instanceof JetClassInitializer) {
1407 generateInstructions(declaration);
1408 }
1409 }
1410 }
1411
1412 @Override
1413 public void visitClass(@NotNull JetClass klass) {
1414 List<JetParameter> parameters = klass.getPrimaryConstructorParameters();
1415 for (JetParameter parameter : parameters) {
1416 generateInstructions(parameter);
1417 }
1418 visitClassOrObject(klass);
1419 }
1420
1421 @Override
1422 public void visitDelegationToSuperCallSpecifier(@NotNull JetDelegatorToSuperCall call) {
1423 if (!generateCall(call)) {
1424 List<JetExpression> arguments = KotlinPackage.map(
1425 call.getValueArguments(),
1426 new Function1<ValueArgument, JetExpression>() {
1427 @Override
1428 public JetExpression invoke(ValueArgument valueArgument) {
1429 return valueArgument.getArgumentExpression();
1430 }
1431 }
1432 );
1433
1434 for (JetExpression argument : arguments) {
1435 generateInstructions(argument);
1436 }
1437 createNonSyntheticValue(call, arguments, MagicKind.UNRESOLVED_CALL);
1438 }
1439 }
1440
1441 @Override
1442 public void visitDelegationByExpressionSpecifier(@NotNull JetDelegatorByExpressionSpecifier specifier) {
1443 generateInstructions(specifier.getDelegateExpression());
1444
1445 List<PseudoValue> arguments = ContainerUtil.createMaybeSingletonList(builder.getBoundValue(specifier.getDelegateExpression()));
1446 JetType jetType = trace.get(BindingContext.TYPE, specifier.getTypeReference());
1447 TypePredicate expectedTypePredicate = jetType != null ? PseudocodePackage.getSubtypesPredicate(jetType) : AllTypes.INSTANCE$;
1448 builder.magic(specifier, null, arguments, PseudocodePackage.expectedTypeFor(expectedTypePredicate, arguments),
1449 MagicKind.VALUE_CONSUMER);
1450 }
1451
1452 @Override
1453 public void visitDelegationToSuperClassSpecifier(@NotNull JetDelegatorToSuperClass specifier) {
1454 // Do not generate UNSUPPORTED_ELEMENT here
1455 }
1456
1457 @Override
1458 public void visitDelegationSpecifierList(@NotNull JetDelegationSpecifierList list) {
1459 list.acceptChildren(this);
1460 }
1461
1462 @Override
1463 public void visitJetFile(@NotNull JetFile file) {
1464 for (JetDeclaration declaration : file.getDeclarations()) {
1465 if (declaration instanceof JetProperty) {
1466 generateInstructions(declaration);
1467 }
1468 }
1469 }
1470
1471 @Override
1472 public void visitCallableReferenceExpression(@NotNull JetCallableReferenceExpression expression) {
1473 mark(expression);
1474 createNonSyntheticValue(expression, MagicKind.CALLABLE_REFERENCE);
1475 }
1476
1477 @Override
1478 public void visitJetElement(@NotNull JetElement element) {
1479 createNonSyntheticValue(element, MagicKind.UNSUPPORTED_ELEMENT);
1480 }
1481
1482 private boolean generateCall(@Nullable JetElement callElement) {
1483 if (callElement == null) return false;
1484 return checkAndGenerateCall(getResolvedCall(callElement, trace.getBindingContext()));
1485 }
1486
1487 private boolean checkAndGenerateCall(@Nullable ResolvedCall<?> resolvedCall) {
1488 if (resolvedCall == null) return false;
1489 generateCall(resolvedCall);
1490 return true;
1491 }
1492
1493 @NotNull
1494 private InstructionWithValue generateCall(@NotNull ResolvedCall<?> resolvedCall) {
1495 JetElement callElement = resolvedCall.getCall().getCallElement();
1496
1497 if (resolvedCall instanceof VariableAsFunctionResolvedCall) {
1498 VariableAsFunctionResolvedCall variableAsFunctionResolvedCall = (VariableAsFunctionResolvedCall) resolvedCall;
1499 return generateCall(variableAsFunctionResolvedCall.getFunctionCall());
1500 }
1501
1502 CallableDescriptor resultingDescriptor = resolvedCall.getResultingDescriptor();
1503 Map<PseudoValue, ReceiverValue> receivers = getReceiverValues(resolvedCall);
1504 SmartFMap<PseudoValue, ValueParameterDescriptor> parameterValues = SmartFMap.emptyMap();
1505 for (ValueArgument argument : resolvedCall.getCall().getValueArguments()) {
1506 ArgumentMapping argumentMapping = resolvedCall.getArgumentMapping(argument);
1507 JetExpression argumentExpression = argument.getArgumentExpression();
1508 if (argumentMapping instanceof ArgumentMatch) {
1509 parameterValues = generateValueArgument(argument, ((ArgumentMatch) argumentMapping).getValueParameter(), parameterValues);
1510 }
1511 else if (argumentExpression != null) {
1512 generateInstructions(argumentExpression);
1513 createSyntheticValue(argumentExpression, MagicKind.VALUE_CONSUMER, argumentExpression);
1514 }
1515 }
1516
1517 if (resultingDescriptor instanceof VariableDescriptor) {
1518 // If a callee of the call is just a variable (without 'invoke'), 'read variable' is generated.
1519 // todo : process arguments for such a case (KT-5387)
1520 JetExpression callExpression = callElement instanceof JetExpression ? (JetExpression) callElement : null;
1521 assert callExpression != null
1522 : "Variable-based call without callee expression: " + callElement.getText();
1523 assert parameterValues.isEmpty()
1524 : "Variable-based call with non-empty argument list: " + callElement.getText();
1525 return builder.readVariable(callExpression, resolvedCall, receivers);
1526 }
1527 mark(resolvedCall.getCall().getCallElement());
1528 return builder.call(callElement, resolvedCall, receivers, parameterValues);
1529 }
1530
1531 @NotNull
1532 private Map<PseudoValue, ReceiverValue> getReceiverValues(ResolvedCall<?> resolvedCall) {
1533 SmartFMap<PseudoValue, ReceiverValue> receiverValues = SmartFMap.emptyMap();
1534 JetElement callElement = resolvedCall.getCall().getCallElement();
1535 receiverValues = getReceiverValues(callElement, resolvedCall.getDispatchReceiver(), receiverValues);
1536 receiverValues = getReceiverValues(callElement, resolvedCall.getExtensionReceiver(), receiverValues);
1537 return receiverValues;
1538 }
1539
1540 @NotNull
1541 private SmartFMap<PseudoValue, ReceiverValue> getReceiverValues(
1542 JetElement callElement,
1543 ReceiverValue receiver,
1544 SmartFMap<PseudoValue, ReceiverValue> receiverValues
1545 ) {
1546 if (!receiver.exists()) return receiverValues;
1547
1548 if (receiver instanceof ThisReceiver) {
1549 receiverValues = receiverValues.plus(createSyntheticValue(callElement, MagicKind.IMPLICIT_RECEIVER), receiver);
1550 }
1551 else if (receiver instanceof ExpressionReceiver) {
1552 JetExpression expression = ((ExpressionReceiver) receiver).getExpression();
1553 if (builder.getBoundValue(expression) == null) {
1554 generateInstructions(expression);
1555 }
1556
1557 PseudoValue receiverPseudoValue = getBoundOrUnreachableValue(expression);
1558 if (receiverPseudoValue != null) {
1559 receiverValues = receiverValues.plus(receiverPseudoValue, receiver);
1560 }
1561 }
1562 else if (receiver instanceof TransientReceiver) {
1563 // Do nothing
1564 }
1565 else {
1566 throw new IllegalArgumentException("Unknown receiver kind: " + receiver);
1567 }
1568
1569 return receiverValues;
1570 }
1571
1572 @NotNull
1573 private SmartFMap<PseudoValue, ValueParameterDescriptor> generateValueArgument(
1574 ValueArgument valueArgument,
1575 ValueParameterDescriptor parameterDescriptor,
1576 SmartFMap<PseudoValue, ValueParameterDescriptor> parameterValues) {
1577 JetExpression expression = valueArgument.getArgumentExpression();
1578 if (expression != null) {
1579 if (!valueArgument.isExternal()) {
1580 generateInstructions(expression);
1581 }
1582
1583 PseudoValue argValue = getBoundOrUnreachableValue(expression);
1584 if (argValue != null) {
1585 parameterValues = parameterValues.plus(argValue, parameterDescriptor);
1586 }
1587 }
1588 return parameterValues;
1589 }
1590 }
1591 }