Pseudocode: Add receiver values to call instructions. Refactor InstructionWithReceiver

This commit is contained in:
Alexey Sedunov
2014-06-03 18:55:11 +04:00
parent 650fac0081
commit 9ddfc32cdc
10 changed files with 179 additions and 77 deletions
@@ -21,12 +21,15 @@ import org.jetbrains.annotations.Nullable;
import org.jetbrains.jet.lang.cfg.pseudocode.PseudoValue; import org.jetbrains.jet.lang.cfg.pseudocode.PseudoValue;
import org.jetbrains.jet.lang.cfg.pseudocode.Pseudocode; import org.jetbrains.jet.lang.cfg.pseudocode.Pseudocode;
import org.jetbrains.jet.lang.descriptors.ReceiverParameterDescriptor; import org.jetbrains.jet.lang.descriptors.ReceiverParameterDescriptor;
import org.jetbrains.jet.lang.descriptors.ValueParameterDescriptor;
import org.jetbrains.jet.lang.descriptors.VariableDescriptor; import org.jetbrains.jet.lang.descriptors.VariableDescriptor;
import org.jetbrains.jet.lang.psi.*; import org.jetbrains.jet.lang.psi.*;
import org.jetbrains.jet.lang.resolve.calls.model.ResolvedCall; import org.jetbrains.jet.lang.resolve.calls.model.ResolvedCall;
import org.jetbrains.jet.lang.resolve.constants.CompileTimeConstant; import org.jetbrains.jet.lang.resolve.constants.CompileTimeConstant;
import org.jetbrains.jet.lang.resolve.scopes.receivers.ReceiverValue;
import java.util.List; import java.util.List;
import java.util.Map;
public interface JetControlFlowBuilder { public interface JetControlFlowBuilder {
// Subroutines // Subroutines
@@ -123,7 +126,12 @@ public interface JetControlFlowBuilder {
); );
@Nullable @Nullable
PseudoValue call(@NotNull JetExpression expression, @NotNull ResolvedCall<?> resolvedCall, @NotNull List<PseudoValue> inputValues); PseudoValue call(
@NotNull JetExpression expression,
@NotNull ResolvedCall<?> resolvedCall,
@NotNull Map<PseudoValue, ReceiverValue> receiverValues,
@NotNull Map<PseudoValue, ValueParameterDescriptor> arguments
);
enum PredefinedOperation { enum PredefinedOperation {
AND, AND,
@@ -21,12 +21,15 @@ import org.jetbrains.annotations.Nullable;
import org.jetbrains.jet.lang.cfg.pseudocode.PseudoValue; import org.jetbrains.jet.lang.cfg.pseudocode.PseudoValue;
import org.jetbrains.jet.lang.cfg.pseudocode.Pseudocode; import org.jetbrains.jet.lang.cfg.pseudocode.Pseudocode;
import org.jetbrains.jet.lang.descriptors.ReceiverParameterDescriptor; import org.jetbrains.jet.lang.descriptors.ReceiverParameterDescriptor;
import org.jetbrains.jet.lang.descriptors.ValueParameterDescriptor;
import org.jetbrains.jet.lang.descriptors.VariableDescriptor; import org.jetbrains.jet.lang.descriptors.VariableDescriptor;
import org.jetbrains.jet.lang.psi.*; import org.jetbrains.jet.lang.psi.*;
import org.jetbrains.jet.lang.resolve.calls.model.ResolvedCall; import org.jetbrains.jet.lang.resolve.calls.model.ResolvedCall;
import org.jetbrains.jet.lang.resolve.constants.CompileTimeConstant; import org.jetbrains.jet.lang.resolve.constants.CompileTimeConstant;
import org.jetbrains.jet.lang.resolve.scopes.receivers.ReceiverValue;
import java.util.List; import java.util.List;
import java.util.Map;
public abstract class JetControlFlowBuilderAdapter implements JetControlFlowBuilder { public abstract class JetControlFlowBuilderAdapter implements JetControlFlowBuilder {
@@ -90,8 +93,13 @@ public abstract class JetControlFlowBuilderAdapter implements JetControlFlowBuil
@Nullable @Nullable
@Override @Override
public PseudoValue call(@NotNull JetExpression expression, @NotNull ResolvedCall<?> resolvedCall, @NotNull List<PseudoValue> inputValues) { public PseudoValue call(
return getDelegateBuilder().call(expression, resolvedCall, inputValues); @NotNull JetExpression expression,
@NotNull ResolvedCall<?> resolvedCall,
@NotNull Map<PseudoValue, ReceiverValue> receiverValues,
@NotNull Map<PseudoValue, ValueParameterDescriptor> arguments
) {
return getDelegateBuilder().call(expression, resolvedCall, receiverValues, arguments);
} }
@NotNull @NotNull
@@ -21,6 +21,8 @@ import com.google.common.collect.Lists;
import com.intellij.psi.PsiElement; import com.intellij.psi.PsiElement;
import com.intellij.psi.tree.IElementType; import com.intellij.psi.tree.IElementType;
import com.intellij.psi.util.PsiTreeUtil; import com.intellij.psi.util.PsiTreeUtil;
import com.intellij.util.SmartFMap;
import com.intellij.util.containers.ContainerUtil;
import kotlin.Function0; import kotlin.Function0;
import kotlin.Function1; import kotlin.Function1;
import kotlin.KotlinPackage; import kotlin.KotlinPackage;
@@ -36,9 +38,7 @@ import org.jetbrains.jet.lang.resolve.BindingContext;
import org.jetbrains.jet.lang.resolve.BindingContextUtils; import org.jetbrains.jet.lang.resolve.BindingContextUtils;
import org.jetbrains.jet.lang.resolve.BindingTrace; import org.jetbrains.jet.lang.resolve.BindingTrace;
import org.jetbrains.jet.lang.resolve.CompileTimeConstantUtils; import org.jetbrains.jet.lang.resolve.CompileTimeConstantUtils;
import org.jetbrains.jet.lang.resolve.calls.model.ResolvedCall; import org.jetbrains.jet.lang.resolve.calls.model.*;
import org.jetbrains.jet.lang.resolve.calls.model.ResolvedValueArgument;
import org.jetbrains.jet.lang.resolve.calls.model.VariableAsFunctionResolvedCall;
import org.jetbrains.jet.lang.resolve.constants.CompileTimeConstant; import org.jetbrains.jet.lang.resolve.constants.CompileTimeConstant;
import org.jetbrains.jet.lang.resolve.name.Name; import org.jetbrains.jet.lang.resolve.name.Name;
import org.jetbrains.jet.lang.resolve.scopes.receivers.ExpressionReceiver; import org.jetbrains.jet.lang.resolve.scopes.receivers.ExpressionReceiver;
@@ -438,25 +438,64 @@ public class JetControlFlowProcessor {
mark(lhs); mark(lhs);
} }
generateArrayAccessArguments(lhs); generateInstructions(lhs.getArrayExpression(), NOT_IN_CONDITION);
List<JetExpression> inputExpressions = new ArrayList<JetExpression>(); Map<PseudoValue, ReceiverValue> receiverValues = getReceiverValues(setResolvedCall, false);
inputExpressions.add(lhs.getArrayExpression()); SmartFMap<PseudoValue, ValueParameterDescriptor> argumentValues =
inputExpressions.addAll(lhs.getIndexExpressions()); getArraySetterArguments(rhsDeferredValue, setResolvedCall);
List<PseudoValue> inputValues = elementsToValues(inputExpressions); builder.call(parentExpression, setResolvedCall, receiverValues, argumentValues);
PseudoValue rhsValue = rhsDeferredValue.invoke(); }
if (rhsValue != null) {
inputValues.add(rhsValue); /* We assume that assignment right-hand side corresponds to the last argument of the call
* So receiver instructions/pseudo-values are generated for all arguments except the last one which is replaced
* by pre-generated pseudo-value
* For example, assignment a[1, 2] += 3 means a.set(1, 2, a.get(1) + 3), so in order to generate "set" call
* we first generate instructions for 1 and 2 whereas 3 is replaced by pseudo-value corresponding to "a.get(1) + 3"
*/
private SmartFMap<PseudoValue, ValueParameterDescriptor> getArraySetterArguments(
Function0<PseudoValue> rhsDeferredValue,
final ResolvedCall<FunctionDescriptor> setResolvedCall
) {
List<ValueArgument> valueArguments = KotlinPackage.flatMapTo(
setResolvedCall.getResultingDescriptor().getValueParameters(),
new ArrayList<ValueArgument>(),
new Function1<ValueParameterDescriptor, Iterable<? extends ValueArgument>>() {
@Override
public Iterable<? extends ValueArgument> invoke(ValueParameterDescriptor descriptor) {
ResolvedValueArgument resolvedValueArgument = setResolvedCall.getValueArguments().get(descriptor);
return resolvedValueArgument != null
? resolvedValueArgument.getArguments()
: Collections.<ValueArgument>emptyList();
}
}
);
ValueArgument rhsArgument = KotlinPackage.lastOrNull(valueArguments);
SmartFMap<PseudoValue, ValueParameterDescriptor> argumentValues = SmartFMap.emptyMap();
for (ValueArgument valueArgument : valueArguments) {
ArgumentMapping argumentMapping = setResolvedCall.getArgumentMapping(valueArgument);
if (argumentMapping.isError() || (!(argumentMapping instanceof ArgumentMatch))) continue;
ValueParameterDescriptor parameterDescriptor = ((ArgumentMatch) argumentMapping).getValueParameter();
if (valueArgument != rhsArgument) {
argumentValues = generateValueArgument(valueArgument, parameterDescriptor, argumentValues);
}
else {
PseudoValue rhsValue = rhsDeferredValue.invoke();
if (rhsValue != null) {
argumentValues = argumentValues.plus(rhsValue, parameterDescriptor);
}
}
} }
return argumentValues;
builder.call(parentExpression, setResolvedCall, inputValues);
} }
private void recordWrite(JetExpression left, PseudoValue rightValue, PseudoValue receiverValue, JetExpression parentExpression) { private void recordWrite(JetExpression left, PseudoValue rightValue, PseudoValue receiverValue, JetExpression parentExpression) {
VariableDescriptor descriptor = BindingContextUtils.extractVariableDescriptorIfAny(trace.getBindingContext(), left, false); VariableDescriptor descriptor = BindingContextUtils.extractVariableDescriptorIfAny(trace.getBindingContext(), left, false);
if (descriptor != null) { if (descriptor != null) {
builder.write(parentExpression, left, rightValue != null ? rightValue : createSyntheticValue(parentExpression), receiverValue); builder.write(parentExpression, left, rightValue != null ? rightValue : createSyntheticValue(parentExpression),
receiverValue);
} }
} }
@@ -1027,13 +1066,18 @@ public class JetControlFlowProcessor {
private void visitMultiDeclaration(@NotNull JetMultiDeclaration declaration, boolean generateWriteForEntries) { private void visitMultiDeclaration(@NotNull JetMultiDeclaration declaration, boolean generateWriteForEntries) {
JetExpression initializer = declaration.getInitializer(); JetExpression initializer = declaration.getInitializer();
generateInstructions(initializer, NOT_IN_CONDITION); generateInstructions(initializer, NOT_IN_CONDITION);
List<PseudoValue> inputValues = elementsToValues(Collections.singletonList(initializer));
for (JetMultiDeclarationEntry entry : declaration.getEntries()) { for (JetMultiDeclarationEntry entry : declaration.getEntries()) {
builder.declareVariable(entry); builder.declareVariable(entry);
ResolvedCall<FunctionDescriptor> resolvedCall = trace.get(BindingContext.COMPONENT_RESOLVED_CALL, entry); ResolvedCall<FunctionDescriptor> resolvedCall = trace.get(BindingContext.COMPONENT_RESOLVED_CALL, entry);
PseudoValue writtenValue = resolvedCall != null PseudoValue writtenValue = resolvedCall != null
? builder.call(entry, resolvedCall, inputValues) ? builder.call(
: builder.magic(entry, null, inputValues, true); entry,
resolvedCall,
getReceiverValues(resolvedCall, false),
Collections.<PseudoValue, ValueParameterDescriptor>emptyMap()
)
: builder.magic(entry, null,
ContainerUtil.createMaybeSingletonList(builder.getBoundValue(initializer)), true);
if (generateWriteForEntries) { if (generateWriteForEntries) {
builder.write(entry, entry, writtenValue != null ? writtenValue : createSyntheticValue(entry), null); builder.write(entry, entry, writtenValue != null ? writtenValue : createSyntheticValue(entry), null);
} }
@@ -1286,41 +1330,54 @@ public class JetControlFlowProcessor {
return; return;
} }
List<PseudoValue> inputValues = new ArrayList<PseudoValue>();
CallableDescriptor resultingDescriptor = resolvedCall.getResultingDescriptor(); CallableDescriptor resultingDescriptor = resolvedCall.getResultingDescriptor();
Map<PseudoValue, ReceiverValue> receivers = getReceiverValues(resolvedCall, true);
generateReceiver(resolvedCall.getThisObject(), inputValues); SmartFMap<PseudoValue, ValueParameterDescriptor> parameterValues = SmartFMap.emptyMap();
generateReceiver(resolvedCall.getReceiverArgument(), inputValues);
for (ValueParameterDescriptor parameterDescriptor : resultingDescriptor.getValueParameters()) { for (ValueParameterDescriptor parameterDescriptor : resultingDescriptor.getValueParameters()) {
ResolvedValueArgument argument = resolvedCall.getValueArguments().get(parameterDescriptor); ResolvedValueArgument argument = resolvedCall.getValueArguments().get(parameterDescriptor);
if (argument == null) continue; if (argument == null) continue;
generateValueArgument(argument, inputValues); parameterValues = generateValueArgument(argument, parameterDescriptor, parameterValues);
} }
if (resultingDescriptor instanceof VariableDescriptor) { if (resultingDescriptor instanceof VariableDescriptor) {
assert inputValues.size() <= 1 : "Wrong input values for variable-based call (must be at most 1): " + resolvedCall.getCall().getCallElement(); assert parameterValues.isEmpty() && receivers.size() <= 1
builder.readVariable(calleeExpression, (VariableDescriptor) resultingDescriptor, KotlinPackage.firstOrNull(inputValues)); : "Wrong input values for variable-based call (must be at most 1 receiver): " + resolvedCall.getCall().getCallElement().getText();
builder.readVariable(calleeExpression, (VariableDescriptor) resultingDescriptor, KotlinPackage.firstOrNull(receivers.keySet()));
} }
else { else {
builder.call(calleeExpression, resolvedCall, inputValues); builder.call(calleeExpression, resolvedCall, receivers, parameterValues);
} }
} }
private void generateReceiver(ReceiverValue receiver, List<PseudoValue> values) { @NotNull
if (!receiver.exists()) return; private Map<PseudoValue, ReceiverValue> getReceiverValues(ResolvedCall<?> resolvedCall, boolean generateInstructions) {
SmartFMap<PseudoValue, ReceiverValue> receiverValues = SmartFMap.emptyMap();
receiverValues = getReceiverValues(resolvedCall.getThisObject(), generateInstructions, receiverValues);
receiverValues = getReceiverValues(resolvedCall.getReceiverArgument(), generateInstructions, receiverValues);
return receiverValues;
}
@NotNull
private SmartFMap<PseudoValue, ReceiverValue> getReceiverValues(
ReceiverValue receiver,
boolean generateInstructions,
SmartFMap<PseudoValue, ReceiverValue> receiverValues
) {
if (!receiver.exists()) return receiverValues;
if (receiver instanceof ThisReceiver) { if (receiver instanceof ThisReceiver) {
// TODO: Receiver is passed implicitly: no expression to tie the read to // TODO: Receiver is passed implicitly: no expression to tie the read to
} }
else if (receiver instanceof ExpressionReceiver) { else if (receiver instanceof ExpressionReceiver) {
JetExpression expression = ((ExpressionReceiver) receiver).getExpression(); JetExpression expression = ((ExpressionReceiver) receiver).getExpression();
generateInstructions(expression, NOT_IN_CONDITION); if (generateInstructions) {
generateInstructions(expression, NOT_IN_CONDITION);
}
PseudoValue receiverValue = builder.getBoundValue(expression); PseudoValue receiverPseudoValue = builder.getBoundValue(expression);
if (receiverValue != null) { if (receiverPseudoValue != null) {
values.add(receiverValue); receiverValues = receiverValues.plus(receiverPseudoValue, receiver);
} }
} }
else if (receiver instanceof TransientReceiver) { else if (receiver instanceof TransientReceiver) {
@@ -1329,20 +1386,38 @@ public class JetControlFlowProcessor {
else { else {
throw new IllegalArgumentException("Unknown receiver kind: " + receiver); throw new IllegalArgumentException("Unknown receiver kind: " + receiver);
} }
return receiverValues;
} }
private void generateValueArgument(ResolvedValueArgument argument, List<PseudoValue> values) { @NotNull
private SmartFMap<PseudoValue, ValueParameterDescriptor> generateValueArgument(
ResolvedValueArgument argument,
ValueParameterDescriptor parameterDescriptor,
SmartFMap<PseudoValue, ValueParameterDescriptor> parameterValues
) {
for (ValueArgument valueArgument : argument.getArguments()) { for (ValueArgument valueArgument : argument.getArguments()) {
JetExpression expression = valueArgument.getArgumentExpression(); parameterValues = generateValueArgument(valueArgument, parameterDescriptor, parameterValues);
if (expression != null) { }
generateInstructions(expression, NOT_IN_CONDITION);
PseudoValue argValue = builder.getBoundValue(expression); return parameterValues;
if (argValue != null) { }
values.add(argValue);
} @NotNull
private SmartFMap<PseudoValue, ValueParameterDescriptor> generateValueArgument(
ValueArgument valueArgument,
ValueParameterDescriptor parameterDescriptor,
SmartFMap<PseudoValue, ValueParameterDescriptor> parameterValues) {
JetExpression expression = valueArgument.getArgumentExpression();
if (expression != null) {
generateInstructions(expression, NOT_IN_CONDITION);
PseudoValue argValue = builder.getBoundValue(expression);
if (argValue != null) {
parameterValues = parameterValues.plus(argValue, parameterDescriptor);
} }
} }
return parameterValues;
} }
} }
} }
@@ -26,10 +26,12 @@ import org.jetbrains.jet.lang.cfg.pseudocode.instructions.eval.*;
import org.jetbrains.jet.lang.cfg.pseudocode.instructions.jumps.*; import org.jetbrains.jet.lang.cfg.pseudocode.instructions.jumps.*;
import org.jetbrains.jet.lang.cfg.pseudocode.instructions.special.*; import org.jetbrains.jet.lang.cfg.pseudocode.instructions.special.*;
import org.jetbrains.jet.lang.descriptors.ReceiverParameterDescriptor; import org.jetbrains.jet.lang.descriptors.ReceiverParameterDescriptor;
import org.jetbrains.jet.lang.descriptors.ValueParameterDescriptor;
import org.jetbrains.jet.lang.descriptors.VariableDescriptor; import org.jetbrains.jet.lang.descriptors.VariableDescriptor;
import org.jetbrains.jet.lang.psi.*; import org.jetbrains.jet.lang.psi.*;
import org.jetbrains.jet.lang.resolve.calls.model.ResolvedCall; import org.jetbrains.jet.lang.resolve.calls.model.ResolvedCall;
import org.jetbrains.jet.lang.resolve.constants.CompileTimeConstant; import org.jetbrains.jet.lang.resolve.constants.CompileTimeConstant;
import org.jetbrains.jet.lang.resolve.scopes.receivers.ReceiverValue;
import org.jetbrains.jet.lang.types.JetType; import org.jetbrains.jet.lang.types.JetType;
import org.jetbrains.jet.lang.types.lang.KotlinBuiltIns; import org.jetbrains.jet.lang.types.lang.KotlinBuiltIns;
@@ -456,14 +458,16 @@ public class JetControlFlowInstructionsGenerator extends JetControlFlowBuilderAd
public PseudoValue call( public PseudoValue call(
@NotNull JetExpression expression, @NotNull JetExpression expression,
@NotNull ResolvedCall<?> resolvedCall, @NotNull ResolvedCall<?> resolvedCall,
@NotNull List<PseudoValue> inputValues @NotNull Map<PseudoValue, ReceiverValue> receiverValues,
@NotNull Map<PseudoValue, ValueParameterDescriptor> arguments
) { ) {
JetType returnType = resolvedCall.getResultingDescriptor().getReturnType(); JetType returnType = resolvedCall.getResultingDescriptor().getReturnType();
OperationInstruction instruction = CallInstruction.object$.create( OperationInstruction instruction = CallInstruction.object$.create(
expression, expression,
getCurrentScope(), getCurrentScope(),
resolvedCall, resolvedCall,
inputValues, receiverValues,
arguments,
returnType != null && KotlinBuiltIns.getInstance().isNothing(returnType) ? null : valueFactory returnType != null && KotlinBuiltIns.getInstance().isNothing(returnType) ? null : valueFactory
); );
add(instruction); add(instruction);
@@ -22,12 +22,8 @@ import org.jetbrains.jet.lang.cfg.pseudocode.instructions.special.*
import org.jetbrains.jet.lang.cfg.pseudocode.instructions.eval.* import org.jetbrains.jet.lang.cfg.pseudocode.instructions.eval.*
public open class InstructionVisitor() { public open class InstructionVisitor() {
public open fun visitInstructionWithReceiver(instruction: InstructionWithReceiver) {
visitInstructionWithNext(instruction)
}
public open fun visitReadValue(instruction: ReadValueInstruction) { public open fun visitReadValue(instruction: ReadValueInstruction) {
visitInstructionWithReceiver(instruction) visitInstructionWithNext(instruction)
} }
public open fun visitLocalFunctionDeclarationInstruction(instruction: LocalFunctionDeclarationInstruction) { public open fun visitLocalFunctionDeclarationInstruction(instruction: LocalFunctionDeclarationInstruction) {
@@ -90,7 +86,7 @@ public open class InstructionVisitor() {
} }
public open fun visitWriteValue(instruction: WriteValueInstruction) { public open fun visitWriteValue(instruction: WriteValueInstruction) {
visitInstructionWithReceiver(instruction) visitInstructionWithNext(instruction)
} }
public open fun visitLoadUnitValue(instruction: LoadUnitValueInstruction) { public open fun visitLoadUnitValue(instruction: LoadUnitValueInstruction) {
@@ -24,12 +24,8 @@ import org.jetbrains.jet.lang.cfg.pseudocode.instructions.special.*
public abstract class InstructionVisitorWithResult<R>() { public abstract class InstructionVisitorWithResult<R>() {
public abstract fun visitInstruction(instruction: Instruction): R public abstract fun visitInstruction(instruction: Instruction): R
public open fun visitInstructionWithReceiver(instruction: InstructionWithReceiver): R {
return visitInstructionWithNext(instruction)
}
public open fun visitReadValue(instruction: ReadValueInstruction): R { public open fun visitReadValue(instruction: ReadValueInstruction): R {
return visitInstructionWithReceiver(instruction) return visitInstructionWithNext(instruction)
} }
public open fun visitLocalFunctionDeclarationInstruction(instruction: LocalFunctionDeclarationInstruction): R { public open fun visitLocalFunctionDeclarationInstruction(instruction: LocalFunctionDeclarationInstruction): R {
@@ -89,7 +85,7 @@ public abstract class InstructionVisitorWithResult<R>() {
} }
public open fun visitWriteValue(instruction: WriteValueInstruction): R { public open fun visitWriteValue(instruction: WriteValueInstruction): R {
return visitInstructionWithReceiver(instruction) return visitInstructionWithNext(instruction)
} }
public open fun visitLoadUnitValue(instruction: LoadUnitValueInstruction): R { public open fun visitLoadUnitValue(instruction: LoadUnitValueInstruction): R {
@@ -16,16 +16,9 @@
package org.jetbrains.jet.lang.cfg.pseudocode.instructions.eval package org.jetbrains.jet.lang.cfg.pseudocode.instructions.eval
import org.jetbrains.jet.lang.cfg.pseudocode.instructions.InstructionWithNext
import org.jetbrains.jet.lang.psi.JetElement
import org.jetbrains.jet.lang.cfg.pseudocode.instructions.LexicalScope
import org.jetbrains.jet.lang.cfg.pseudocode.PseudoValue import org.jetbrains.jet.lang.cfg.pseudocode.PseudoValue
import com.intellij.util.containers.ContainerUtil import org.jetbrains.jet.lang.cfg.pseudocode.instructions.Instruction
public abstract class InstructionWithReceiver( public trait InstructionWithReceivers: Instruction {
element: JetElement, public val receiverValues: List<PseudoValue>
lexicalScope: LexicalScope,
protected val receiverValue: PseudoValue?
) : InstructionWithNext(element, lexicalScope) {
override val inputValues: List<PseudoValue> = ContainerUtil.createMaybeSingletonList(receiverValue)
} }
@@ -23,17 +23,26 @@ import org.jetbrains.jet.lang.cfg.pseudocode.instructions.LexicalScope
import org.jetbrains.jet.lang.cfg.pseudocode.instructions.InstructionVisitor import org.jetbrains.jet.lang.cfg.pseudocode.instructions.InstructionVisitor
import org.jetbrains.jet.lang.cfg.pseudocode.instructions.InstructionVisitorWithResult import org.jetbrains.jet.lang.cfg.pseudocode.instructions.InstructionVisitorWithResult
import org.jetbrains.jet.lang.cfg.pseudocode.instructions.InstructionImpl import org.jetbrains.jet.lang.cfg.pseudocode.instructions.InstructionImpl
import org.jetbrains.jet.lang.cfg.pseudocode.instructions.InstructionWithNext
import com.intellij.util.containers.ContainerUtil
import org.jetbrains.jet.lang.resolve.scopes.receivers.ReceiverValue
public class ReadValueInstruction private ( public class ReadValueInstruction private (
element: JetElement, element: JetElement,
lexicalScope: LexicalScope, lexicalScope: LexicalScope,
receiverValue: PseudoValue?, public val receiverValue: PseudoValue?,
private var _outputValue: PseudoValue? private var _outputValue: PseudoValue?
) : InstructionWithReceiver(element, lexicalScope, receiverValue), InstructionWithValue { ) : InstructionWithNext(element, lexicalScope), InstructionWithReceivers, InstructionWithValue {
private fun newResultValue(factory: PseudoValueFactory) { private fun newResultValue(factory: PseudoValueFactory) {
_outputValue = factory.newValue(element, this) _outputValue = factory.newValue(element, this)
} }
override val receiverValues: List<PseudoValue>
get() = ContainerUtil.createMaybeSingletonList(receiverValue)
override val inputValues: List<PseudoValue>
get() = receiverValues
override val outputValue: PseudoValue override val outputValue: PseudoValue
get() = _outputValue!! get() = _outputValue!!
@@ -25,14 +25,19 @@ import org.jetbrains.jet.lang.cfg.pseudocode.instructions.InstructionVisitor
import java.util.Arrays import java.util.Arrays
import org.jetbrains.jet.lang.cfg.pseudocode.instructions.InstructionVisitorWithResult import org.jetbrains.jet.lang.cfg.pseudocode.instructions.InstructionVisitorWithResult
import org.jetbrains.jet.lang.cfg.pseudocode.instructions.InstructionImpl import org.jetbrains.jet.lang.cfg.pseudocode.instructions.InstructionImpl
import org.jetbrains.jet.lang.cfg.pseudocode.instructions.InstructionWithNext
import com.intellij.util.containers.ContainerUtil
public class WriteValueInstruction( public class WriteValueInstruction(
assignment: JetElement, assignment: JetElement,
public val lValue: JetElement, public val lValue: JetElement,
public val rValue: PseudoValue, public val rValue: PseudoValue,
receiverValue: PseudoValue?, public val receiverValue: PseudoValue?,
lexicalScope: LexicalScope lexicalScope: LexicalScope
) : InstructionWithReceiver(assignment, lexicalScope, receiverValue) { ) : InstructionWithNext(assignment, lexicalScope), InstructionWithReceivers {
override val receiverValues: List<PseudoValue>
get() = ContainerUtil.createMaybeSingletonList(receiverValue)
override val inputValues: List<PseudoValue> override val inputValues: List<PseudoValue>
get() = receiverValue?.let{ receiverValue -> Arrays.asList(receiverValue, rValue) } ?: Collections.singletonList(rValue) get() = receiverValue?.let{ receiverValue -> Arrays.asList(receiverValue, rValue) } ?: Collections.singletonList(rValue)
@@ -24,6 +24,8 @@ import org.jetbrains.jet.lang.cfg.pseudocode.instructions.LexicalScope
import org.jetbrains.jet.lang.cfg.pseudocode.instructions.InstructionWithNext import org.jetbrains.jet.lang.cfg.pseudocode.instructions.InstructionWithNext
import org.jetbrains.jet.lang.cfg.pseudocode.instructions.InstructionVisitor import org.jetbrains.jet.lang.cfg.pseudocode.instructions.InstructionVisitor
import org.jetbrains.jet.lang.cfg.pseudocode.instructions.InstructionVisitorWithResult import org.jetbrains.jet.lang.cfg.pseudocode.instructions.InstructionVisitorWithResult
import org.jetbrains.jet.lang.resolve.scopes.receivers.ReceiverValue
import org.jetbrains.jet.lang.descriptors.ValueParameterDescriptor
public abstract class OperationInstruction protected( public abstract class OperationInstruction protected(
element: JetElement, element: JetElement,
@@ -54,8 +56,12 @@ public class CallInstruction private(
element: JetElement, element: JetElement,
lexicalScope: LexicalScope, lexicalScope: LexicalScope,
val resolvedCall: ResolvedCall<*>, val resolvedCall: ResolvedCall<*>,
inputValues: List<PseudoValue> public val receiverValueMap: Map<PseudoValue, ReceiverValue>,
) : OperationInstruction(element, lexicalScope, inputValues) { public val arguments: Map<PseudoValue, ValueParameterDescriptor>
) : OperationInstruction(element, lexicalScope, receiverValueMap.keySet() + arguments.keySet()), InstructionWithReceivers {
override val receiverValues: List<PseudoValue>
get() = receiverValueMap.keySet().toList()
override fun accept(visitor: InstructionVisitor) { override fun accept(visitor: InstructionVisitor) {
visitor.visitCallInstruction(this) visitor.visitCallInstruction(this)
} }
@@ -65,7 +71,7 @@ public class CallInstruction private(
} }
override fun createCopy() = override fun createCopy() =
CallInstruction(element, lexicalScope, resolvedCall, inputValues).setResult(resultValue) CallInstruction(element, lexicalScope, resolvedCall, receiverValueMap, arguments).setResult(resultValue)
override fun toString() = override fun toString() =
renderInstruction("call", "${render(element)}, ${resolvedCall.getResultingDescriptor()!!.getName()}") renderInstruction("call", "${render(element)}, ${resolvedCall.getResultingDescriptor()!!.getName()}")
@@ -75,9 +81,11 @@ public class CallInstruction private(
element: JetElement, element: JetElement,
lexicalScope: LexicalScope, lexicalScope: LexicalScope,
resolvedCall: ResolvedCall<*>, resolvedCall: ResolvedCall<*>,
inputValues: List<PseudoValue>, receiverValues: Map<PseudoValue, ReceiverValue>,
arguments: Map<PseudoValue, ValueParameterDescriptor>,
factory: PseudoValueFactory? factory: PseudoValueFactory?
): CallInstruction = CallInstruction(element, lexicalScope, resolvedCall, inputValues).setResult(factory) as CallInstruction ): CallInstruction =
CallInstruction(element, lexicalScope, resolvedCall, receiverValues, arguments).setResult(factory) as CallInstruction
} }
} }