Control-Flow: Move type predicate computation out of control-flow analysis
This commit is contained in:
@@ -20,7 +20,6 @@ import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
import org.jetbrains.kotlin.cfg.pseudocode.PseudoValue;
|
||||
import org.jetbrains.kotlin.cfg.pseudocode.Pseudocode;
|
||||
import org.jetbrains.kotlin.cfg.pseudocode.TypePredicate;
|
||||
import org.jetbrains.kotlin.cfg.pseudocode.instructions.eval.*;
|
||||
import org.jetbrains.kotlin.descriptors.ValueParameterDescriptor;
|
||||
import org.jetbrains.kotlin.psi.*;
|
||||
@@ -120,7 +119,6 @@ public interface JetControlFlowBuilder {
|
||||
@NotNull JetElement instructionElement,
|
||||
@Nullable JetElement valueElement,
|
||||
@NotNull List<PseudoValue> inputValues,
|
||||
@NotNull Map<PseudoValue, TypePredicate> expectedTypes,
|
||||
@NotNull MagicKind kind
|
||||
);
|
||||
|
||||
|
||||
@@ -20,7 +20,6 @@ import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
import org.jetbrains.kotlin.cfg.pseudocode.PseudoValue;
|
||||
import org.jetbrains.kotlin.cfg.pseudocode.Pseudocode;
|
||||
import org.jetbrains.kotlin.cfg.pseudocode.TypePredicate;
|
||||
import org.jetbrains.kotlin.cfg.pseudocode.instructions.eval.*;
|
||||
import org.jetbrains.kotlin.descriptors.ValueParameterDescriptor;
|
||||
import org.jetbrains.kotlin.psi.*;
|
||||
@@ -71,10 +70,9 @@ public abstract class JetControlFlowBuilderAdapter implements JetControlFlowBuil
|
||||
@NotNull JetElement instructionElement,
|
||||
@Nullable JetElement valueElement,
|
||||
@NotNull List<PseudoValue> inputValues,
|
||||
@NotNull Map<PseudoValue, TypePredicate> expectedTypes,
|
||||
@NotNull MagicKind kind
|
||||
) {
|
||||
return getDelegateBuilder().magic(instructionElement, valueElement, inputValues, expectedTypes, kind);
|
||||
return getDelegateBuilder().magic(instructionElement, valueElement, inputValues, kind);
|
||||
}
|
||||
|
||||
@NotNull
|
||||
|
||||
@@ -17,20 +17,21 @@
|
||||
package org.jetbrains.kotlin.cfg;
|
||||
|
||||
import com.google.common.collect.Lists;
|
||||
import com.google.common.collect.Sets;
|
||||
import com.intellij.psi.PsiElement;
|
||||
import com.intellij.psi.tree.IElementType;
|
||||
import com.intellij.psi.util.PsiTreeUtil;
|
||||
import com.intellij.util.SmartFMap;
|
||||
import com.intellij.util.containers.ContainerUtil;
|
||||
import com.intellij.util.containers.MultiMap;
|
||||
import kotlin.KotlinPackage;
|
||||
import kotlin.jvm.functions.Function0;
|
||||
import kotlin.jvm.functions.Function1;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
import org.jetbrains.kotlin.builtins.KotlinBuiltIns;
|
||||
import org.jetbrains.kotlin.cfg.pseudocode.*;
|
||||
import org.jetbrains.kotlin.cfg.pseudocode.JetControlFlowInstructionsGenerator;
|
||||
import org.jetbrains.kotlin.cfg.pseudocode.PseudoValue;
|
||||
import org.jetbrains.kotlin.cfg.pseudocode.Pseudocode;
|
||||
import org.jetbrains.kotlin.cfg.pseudocode.PseudocodeImpl;
|
||||
import org.jetbrains.kotlin.cfg.pseudocode.instructions.eval.AccessTarget;
|
||||
import org.jetbrains.kotlin.cfg.pseudocode.instructions.eval.InstructionWithValue;
|
||||
import org.jetbrains.kotlin.cfg.pseudocode.instructions.eval.MagicKind;
|
||||
@@ -41,15 +42,12 @@ import org.jetbrains.kotlin.lexer.JetTokens;
|
||||
import org.jetbrains.kotlin.name.Name;
|
||||
import org.jetbrains.kotlin.psi.*;
|
||||
import org.jetbrains.kotlin.psi.psiUtil.PsiUtilPackage;
|
||||
import org.jetbrains.kotlin.renderer.DescriptorRenderer;
|
||||
import org.jetbrains.kotlin.resolve.*;
|
||||
import org.jetbrains.kotlin.resolve.bindingContextUtil.BindingContextUtilPackage;
|
||||
import org.jetbrains.kotlin.resolve.calls.ValueArgumentsToParametersMapper;
|
||||
import org.jetbrains.kotlin.resolve.calls.callUtil.CallUtilPackage;
|
||||
import org.jetbrains.kotlin.resolve.BindingContext;
|
||||
import org.jetbrains.kotlin.resolve.BindingContextUtils;
|
||||
import org.jetbrains.kotlin.resolve.BindingTrace;
|
||||
import org.jetbrains.kotlin.resolve.CompileTimeConstantUtils;
|
||||
import org.jetbrains.kotlin.resolve.calls.model.*;
|
||||
import org.jetbrains.kotlin.resolve.calls.tasks.ExplicitReceiverKind;
|
||||
import org.jetbrains.kotlin.resolve.calls.tasks.ResolutionCandidate;
|
||||
import org.jetbrains.kotlin.resolve.calls.tasks.TracingStrategy;
|
||||
import org.jetbrains.kotlin.resolve.constants.CompileTimeConstant;
|
||||
import org.jetbrains.kotlin.resolve.constants.evaluate.ConstantExpressionEvaluator;
|
||||
import org.jetbrains.kotlin.resolve.scopes.receivers.ExpressionReceiver;
|
||||
@@ -142,7 +140,7 @@ public class JetControlFlowProcessor {
|
||||
if (!generateCall(condition.getOperationReference())) {
|
||||
JetExpression rangeExpression = condition.getRangeExpression();
|
||||
generateInstructions(rangeExpression);
|
||||
createUnresolvedCall(condition, rangeExpression);
|
||||
createNonSyntheticValue(condition, MagicKind.UNRESOLVED_CALL, rangeExpression);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -209,7 +207,7 @@ public class JetControlFlowProcessor {
|
||||
@NotNull
|
||||
private PseudoValue createSyntheticValue(@NotNull JetElement instructionElement, @NotNull MagicKind kind, JetElement... from) {
|
||||
List<PseudoValue> values = elementsToValues(from.length > 0 ? Arrays.asList(from) : Collections.<JetElement>emptyList());
|
||||
return builder.magic(instructionElement, null, values, defaultTypeMap(values), kind).getOutputValue();
|
||||
return builder.magic(instructionElement, null, values, kind).getOutputValue();
|
||||
}
|
||||
|
||||
@NotNull
|
||||
@@ -217,7 +215,7 @@ public class JetControlFlowProcessor {
|
||||
@NotNull JetElement to, @NotNull List<? extends JetElement> from, @NotNull MagicKind kind
|
||||
) {
|
||||
List<PseudoValue> values = elementsToValues(from);
|
||||
return builder.magic(to, to, values, defaultTypeMap(values), kind).getOutputValue();
|
||||
return builder.magic(to, to, values, kind).getOutputValue();
|
||||
}
|
||||
|
||||
@NotNull
|
||||
@@ -225,114 +223,6 @@ public class JetControlFlowProcessor {
|
||||
return createNonSyntheticValue(to, Arrays.asList(from), kind);
|
||||
}
|
||||
|
||||
@Nullable
|
||||
private Map<PseudoValue, TypePredicate> getTypeMapForUnresolvedCall(@NotNull JetElement to, List<PseudoValue> arguments) {
|
||||
Call call = CallUtilPackage.getCall(to, trace.getBindingContext());
|
||||
if (call == null) return null;
|
||||
|
||||
JetExpression callee = call.getCalleeExpression();
|
||||
if (callee == null) return null;
|
||||
|
||||
Collection<FunctionDescriptor> candidates = KotlinPackage.sortBy(
|
||||
KotlinPackage.filterIsInstance(
|
||||
BindingContextUtilPackage.getReferenceTargets(callee, trace.getBindingContext()),
|
||||
FunctionDescriptor.class
|
||||
),
|
||||
new Function1<FunctionDescriptor, Comparable>() {
|
||||
@Override
|
||||
public Comparable invoke(FunctionDescriptor descriptor) {
|
||||
return DescriptorRenderer.DEBUG_TEXT.render(descriptor);
|
||||
}
|
||||
}
|
||||
);
|
||||
if (candidates.isEmpty()) return null;
|
||||
|
||||
ReceiverValue explicitReceiver = call.getExplicitReceiver();
|
||||
int argValueOffset = explicitReceiver.exists() ? 1 : 0;
|
||||
|
||||
MultiMap<PseudoValue, TypePredicate> valuesToPredicates = new MultiMap<PseudoValue, TypePredicate>(arguments.size(), 1);
|
||||
|
||||
candidateLoop:
|
||||
for (FunctionDescriptor candidate : candidates) {
|
||||
ResolvedCallImpl<FunctionDescriptor> candidateCall = ResolvedCallImpl.create(
|
||||
ResolutionCandidate.create(call,
|
||||
candidate,
|
||||
call.getDispatchReceiver(),
|
||||
explicitReceiver,
|
||||
ExplicitReceiverKind.NO_EXPLICIT_RECEIVER,
|
||||
null),
|
||||
new DelegatingBindingTrace(trace.getBindingContext(), "Compute type predicates for unresolved call arguments"),
|
||||
TracingStrategy.EMPTY,
|
||||
new DataFlowInfoForArgumentsImpl(call)
|
||||
);
|
||||
ValueArgumentsToParametersMapper.Status status = ValueArgumentsToParametersMapper.mapValueArgumentsToParameters(
|
||||
call,
|
||||
TracingStrategy.EMPTY,
|
||||
candidateCall,
|
||||
Sets.<ValueArgument>newLinkedHashSet()
|
||||
);
|
||||
if (!status.isSuccess()) continue;
|
||||
|
||||
if ((candidate.getExtensionReceiverParameter() == null) == candidateCall.getExtensionReceiver().exists()) continue;
|
||||
|
||||
Map<ValueParameterDescriptor, ResolvedValueArgument> candidateArgumentMap = candidateCall.getValueArguments();
|
||||
List<? extends ValueArgument> callArguments = call.getValueArguments();
|
||||
for (int i = 0; i < callArguments.size(); i++) {
|
||||
int valueIndex = i + argValueOffset;
|
||||
if (valueIndex >= arguments.size()) continue candidateLoop;
|
||||
PseudoValue argumentValue = arguments.get(valueIndex);
|
||||
|
||||
ArgumentMapping mapping = candidateCall.getArgumentMapping(callArguments.get(i));
|
||||
if (!(mapping instanceof ArgumentMatch)) continue candidateLoop;
|
||||
|
||||
ValueParameterDescriptor candidateParameter = ((ArgumentMatch) mapping).getValueParameter();
|
||||
ResolvedValueArgument resolvedArgument = candidateArgumentMap.get(candidateParameter);
|
||||
JetType expectedType = resolvedArgument instanceof VarargValueArgument
|
||||
? candidateParameter.getVarargElementType()
|
||||
: candidateParameter.getType();
|
||||
|
||||
valuesToPredicates.putValue(argumentValue, expectedType != null ? new AllSubtypes(expectedType) : AllTypes.INSTANCE$);
|
||||
}
|
||||
}
|
||||
|
||||
SmartFMap<PseudoValue, TypePredicate> result = SmartFMap.emptyMap();
|
||||
for (Map.Entry<PseudoValue, Collection<TypePredicate>> entry : valuesToPredicates.entrySet()) {
|
||||
result = result.plus(entry.getKey(), PseudocodePackage.or(entry.getValue()));
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
@NotNull
|
||||
private PseudoValue createUnresolvedCallByValues(@NotNull JetElement to, @Nullable JetElement valueElement, List<PseudoValue> arguments) {
|
||||
Map<PseudoValue, TypePredicate> typeMap = getTypeMapForUnresolvedCall(to, arguments);
|
||||
if (typeMap == null) {
|
||||
typeMap = defaultTypeMap(arguments);
|
||||
}
|
||||
|
||||
return builder.magic(to, valueElement, arguments, typeMap, MagicKind.UNRESOLVED_CALL).getOutputValue();
|
||||
}
|
||||
|
||||
@NotNull
|
||||
private PseudoValue createUnresolvedCallByValues(@NotNull JetElement to, List<PseudoValue> arguments) {
|
||||
return createUnresolvedCallByValues(to, to, arguments);
|
||||
}
|
||||
|
||||
@NotNull
|
||||
private PseudoValue createUnresolvedCall(@NotNull JetElement to, List<? extends JetElement> from) {
|
||||
return createUnresolvedCallByValues(to, elementsToValues(from));
|
||||
}
|
||||
|
||||
@NotNull
|
||||
private PseudoValue createUnresolvedCall(@NotNull JetElement to, JetElement... from) {
|
||||
return createUnresolvedCall(to, Arrays.asList(from));
|
||||
}
|
||||
|
||||
@NotNull
|
||||
private Map<PseudoValue, TypePredicate> defaultTypeMap(List<PseudoValue> values) {
|
||||
return PseudocodePackage.expectedTypeFor(AllTypes.INSTANCE$, values);
|
||||
}
|
||||
|
||||
private void mergeValues(@NotNull List<JetExpression> from, @NotNull JetExpression to) {
|
||||
builder.merge(to, elementsToValues(from));
|
||||
}
|
||||
@@ -414,7 +304,7 @@ public class JetControlFlowProcessor {
|
||||
public void visitThisExpression(@NotNull JetThisExpression expression) {
|
||||
ResolvedCall<?> resolvedCall = getResolvedCall(expression, trace.getBindingContext());
|
||||
if (resolvedCall == null) {
|
||||
createUnresolvedCall(expression);
|
||||
createNonSyntheticValue(expression, MagicKind.UNRESOLVED_CALL);
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -440,7 +330,7 @@ public class JetControlFlowProcessor {
|
||||
generateCall(variableAsFunctionResolvedCall.getVariableCall());
|
||||
}
|
||||
else if (!generateCall(expression) && !(expression.getParent() instanceof JetCallExpression)) {
|
||||
createUnresolvedCall(expression, generateAndGetReceiverIfAny(expression));
|
||||
createNonSyntheticValue(expression, MagicKind.UNRESOLVED_CALL, generateAndGetReceiverIfAny(expression));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -553,7 +443,7 @@ public class JetControlFlowProcessor {
|
||||
generateInstructions(right);
|
||||
}
|
||||
mark(expression);
|
||||
createUnresolvedCall(expression, left, right);
|
||||
createNonSyntheticValue(expression, MagicKind.UNRESOLVED_CALL, left, right);
|
||||
}
|
||||
|
||||
private void visitAssignment(
|
||||
@@ -564,7 +454,7 @@ public class JetControlFlowProcessor {
|
||||
JetExpression left = JetPsiUtil.deparenthesize(lhs);
|
||||
if (left == null) {
|
||||
List<PseudoValue> arguments = Collections.singletonList(rhsDeferredValue.invoke());
|
||||
builder.magic(parentExpression, parentExpression, arguments, defaultTypeMap(arguments), MagicKind.UNSUPPORTED_ELEMENT);
|
||||
builder.magic(parentExpression, parentExpression, arguments, MagicKind.UNSUPPORTED_ELEMENT);
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -609,7 +499,7 @@ public class JetControlFlowProcessor {
|
||||
List<PseudoValue> arguments = KotlinPackage.filterNotNull(
|
||||
Arrays.asList(getBoundOrUnreachableValue(lhs), rhsDeferredValue.invoke())
|
||||
);
|
||||
createUnresolvedCallByValues(parentExpression, arguments);
|
||||
builder.magic(parentExpression, parentExpression, arguments, MagicKind.UNRESOLVED_CALL);
|
||||
|
||||
return;
|
||||
}
|
||||
@@ -680,7 +570,7 @@ public class JetControlFlowProcessor {
|
||||
}
|
||||
|
||||
private void generateArrayAccessWithoutCall(JetArrayAccessExpression arrayAccessExpression) {
|
||||
createUnresolvedCall(arrayAccessExpression, generateArrayAccessArguments(arrayAccessExpression));
|
||||
createNonSyntheticValue(arrayAccessExpression, generateArrayAccessArguments(arrayAccessExpression), MagicKind.UNRESOLVED_CALL);
|
||||
}
|
||||
|
||||
private List<JetExpression> generateArrayAccessArguments(JetArrayAccessExpression arrayAccessExpression) {
|
||||
@@ -719,7 +609,7 @@ public class JetControlFlowProcessor {
|
||||
}
|
||||
else {
|
||||
generateInstructions(baseExpression);
|
||||
rhsValue = createUnresolvedCall(expression, baseExpression);
|
||||
rhsValue = createNonSyntheticValue(expression, MagicKind.UNRESOLVED_CALL, baseExpression);
|
||||
}
|
||||
|
||||
if (incrementOrDecrement) {
|
||||
@@ -917,10 +807,7 @@ public class JetControlFlowProcessor {
|
||||
}
|
||||
else {
|
||||
assert condition != null : "Invalid while condition: " + expression.getText();
|
||||
List<PseudoValue> values = ContainerUtil.createMaybeSingletonList(builder.getBoundValue(condition));
|
||||
Map<PseudoValue, TypePredicate> typePredicates =
|
||||
PseudocodePackage.expectedTypeFor(new SingleType(KotlinBuiltIns.getInstance().getBooleanType()), values);
|
||||
builder.magic(condition, null, values, typePredicates, MagicKind.VALUE_CONSUMER);
|
||||
createSyntheticValue(condition, MagicKind.VALUE_CONSUMER, condition);
|
||||
}
|
||||
|
||||
builder.enterLoopBody(expression);
|
||||
@@ -1006,17 +893,10 @@ public class JetControlFlowProcessor {
|
||||
JetMultiDeclaration multiDeclaration = expression.getMultiParameter();
|
||||
JetExpression loopRange = expression.getLoopRange();
|
||||
|
||||
TypePredicate loopRangeTypePredicate =
|
||||
getTypePredicateByReceiverValue(trace.get(BindingContext.LOOP_RANGE_ITERATOR_RESOLVED_CALL, loopRange));
|
||||
|
||||
PseudoValue loopRangeValue = builder.getBoundValue(loopRange);
|
||||
PseudoValue value = builder.magic(
|
||||
loopRange != null ? loopRange : expression,
|
||||
null,
|
||||
ContainerUtil.createMaybeSingletonList(loopRangeValue),
|
||||
loopRangeValue != null
|
||||
? Collections.singletonMap(loopRangeValue, loopRangeTypePredicate)
|
||||
: Collections.<PseudoValue, TypePredicate>emptyMap(),
|
||||
ContainerUtil.createMaybeSingletonList(builder.getBoundValue(loopRange)),
|
||||
MagicKind.LOOP_RANGE_ITERATION
|
||||
).getOutputValue();
|
||||
|
||||
@@ -1030,17 +910,6 @@ public class JetControlFlowProcessor {
|
||||
}
|
||||
}
|
||||
|
||||
private ReceiverValue getExplicitReceiverValue(ResolvedCall<?> resolvedCall) {
|
||||
switch(resolvedCall.getExplicitReceiverKind()) {
|
||||
case DISPATCH_RECEIVER:
|
||||
return resolvedCall.getDispatchReceiver();
|
||||
case EXTENSION_RECEIVER:
|
||||
return resolvedCall.getExtensionReceiver();
|
||||
default:
|
||||
return ReceiverValue.NO_RECEIVER;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void visitBreakExpression(@NotNull JetBreakExpression expression) {
|
||||
JetElement loop = getCorrespondingLoop(expression);
|
||||
@@ -1250,7 +1119,7 @@ public class JetControlFlowProcessor {
|
||||
inputExpressions.add(generateAndGetReceiverIfAny(expression));
|
||||
|
||||
mark(expression);
|
||||
createUnresolvedCall(expression, inputExpressions);
|
||||
createNonSyntheticValue(expression, inputExpressions, MagicKind.UNRESOLVED_CALL);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1292,33 +1161,9 @@ public class JetControlFlowProcessor {
|
||||
DeclarationDescriptor descriptor = trace.get(BindingContext.DECLARATION_TO_DESCRIPTOR, property);
|
||||
if (!(descriptor instanceof PropertyDescriptor)) return;
|
||||
|
||||
PseudoValue delegateValue = builder.getBoundValue(delegate);
|
||||
if (delegateValue == null) return;
|
||||
if (builder.getBoundValue(delegate) == null) return;
|
||||
|
||||
List<TypePredicate> typePredicates = KotlinPackage.map(
|
||||
((PropertyDescriptor) descriptor).getAccessors(),
|
||||
new Function1<PropertyAccessorDescriptor, TypePredicate>() {
|
||||
@Override
|
||||
public TypePredicate invoke(PropertyAccessorDescriptor descriptor) {
|
||||
return getTypePredicateByReceiverValue(trace.get(BindingContext.DELEGATED_PROPERTY_RESOLVED_CALL, descriptor));
|
||||
}
|
||||
}
|
||||
);
|
||||
Map<PseudoValue, TypePredicate> valuesToTypePredicates = SmartFMap
|
||||
.<PseudoValue, TypePredicate>emptyMap()
|
||||
.plus(delegateValue, PseudocodePackage.and(KotlinPackage.filterNotNull(typePredicates)));
|
||||
builder.magic(property, null, Collections.singletonList(delegateValue), valuesToTypePredicates, MagicKind.VALUE_CONSUMER);
|
||||
}
|
||||
|
||||
private TypePredicate getTypePredicateByReceiverValue(@Nullable ResolvedCall<?> resolvedCall) {
|
||||
if (resolvedCall == null) return AllTypes.INSTANCE$;
|
||||
|
||||
ReceiverValue receiverValue = getExplicitReceiverValue(resolvedCall);
|
||||
if (receiverValue.exists()) {
|
||||
return PseudocodePackage.getReceiverTypePredicate(resolvedCall, receiverValue);
|
||||
}
|
||||
|
||||
return AllTypes.INSTANCE$;
|
||||
createSyntheticValue(property, MagicKind.VALUE_CONSUMER, delegate);
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -1344,8 +1189,7 @@ public class JetControlFlowProcessor {
|
||||
).getOutputValue();
|
||||
}
|
||||
else {
|
||||
List<PseudoValue> arguments = ContainerUtil.createMaybeSingletonList(getBoundOrUnreachableValue(initializer));
|
||||
writtenValue = createUnresolvedCallByValues(entry, null, arguments);
|
||||
writtenValue = createSyntheticValue(entry, MagicKind.UNRESOLVED_CALL, initializer);
|
||||
}
|
||||
|
||||
if (generateWriteForEntries) {
|
||||
@@ -1591,19 +1435,15 @@ public class JetControlFlowProcessor {
|
||||
for (JetExpression argument : arguments) {
|
||||
generateInstructions(argument);
|
||||
}
|
||||
createUnresolvedCall(call, arguments);
|
||||
createNonSyntheticValue(call, arguments, MagicKind.UNRESOLVED_CALL);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void visitDelegationByExpressionSpecifier(@NotNull JetDelegatorByExpressionSpecifier specifier) {
|
||||
generateInstructions(specifier.getDelegateExpression());
|
||||
|
||||
List<PseudoValue> arguments = ContainerUtil.createMaybeSingletonList(builder.getBoundValue(specifier.getDelegateExpression()));
|
||||
JetType jetType = trace.get(BindingContext.TYPE, specifier.getTypeReference());
|
||||
TypePredicate expectedTypePredicate = jetType != null ? PseudocodePackage.getSubtypesPredicate(jetType) : AllTypes.INSTANCE$;
|
||||
builder.magic(specifier, null, arguments, PseudocodePackage.expectedTypeFor(expectedTypePredicate, arguments),
|
||||
MagicKind.VALUE_CONSUMER);
|
||||
JetExpression delegateExpression = specifier.getDelegateExpression();
|
||||
generateInstructions(delegateExpression);
|
||||
createSyntheticValue(specifier, MagicKind.VALUE_CONSUMER, delegateExpression);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
+3
-20
@@ -432,9 +432,7 @@ public class JetControlFlowInstructionsGenerator extends JetControlFlowBuilderAd
|
||||
@NotNull
|
||||
@Override
|
||||
public InstructionWithValue loadStringTemplate(@NotNull JetStringTemplateExpression expression, @NotNull List<PseudoValue> inputValues) {
|
||||
if (inputValues.isEmpty()) return read(expression);
|
||||
Map<PseudoValue, TypePredicate> predicate = PseudocodePackage.expectedTypeFor(AllTypes.INSTANCE$, inputValues);
|
||||
return magic(expression, expression, inputValues, predicate, MagicKind.STRING_TEMPLATE);
|
||||
return inputValues.isEmpty() ? read(expression) : magic(expression, expression, inputValues, MagicKind.STRING_TEMPLATE);
|
||||
}
|
||||
|
||||
@NotNull
|
||||
@@ -443,11 +441,10 @@ public class JetControlFlowInstructionsGenerator extends JetControlFlowBuilderAd
|
||||
@NotNull JetElement instructionElement,
|
||||
@Nullable JetElement valueElement,
|
||||
@NotNull List<PseudoValue> inputValues,
|
||||
@NotNull Map<PseudoValue, TypePredicate> expectedTypes,
|
||||
@NotNull MagicKind kind
|
||||
) {
|
||||
MagicInstruction instruction = new MagicInstruction(
|
||||
instructionElement, valueElement, getCurrentScope(), inputValues, expectedTypes, kind, valueFactory
|
||||
instructionElement, valueElement, getCurrentScope(), inputValues, kind, valueFactory
|
||||
);
|
||||
add(instruction);
|
||||
return instruction;
|
||||
@@ -499,21 +496,7 @@ public class JetControlFlowInstructionsGenerator extends JetControlFlowBuilderAd
|
||||
@NotNull PredefinedOperation operation,
|
||||
@NotNull List<PseudoValue> inputValues
|
||||
) {
|
||||
Map<PseudoValue, TypePredicate> expectedTypes;
|
||||
switch(operation) {
|
||||
case AND:
|
||||
case OR:
|
||||
SingleType onlyBoolean = new SingleType(KotlinBuiltIns.getInstance().getBooleanType());
|
||||
expectedTypes = PseudocodePackage.expectedTypeFor(onlyBoolean, inputValues);
|
||||
break;
|
||||
case NOT_NULL_ASSERTION:
|
||||
expectedTypes = PseudocodePackage.expectedTypeFor(AllTypes.INSTANCE$, inputValues);
|
||||
break;
|
||||
default:
|
||||
throw new IllegalArgumentException("Invalid operation: " + operation);
|
||||
}
|
||||
|
||||
return magic(expression, expression, inputValues, expectedTypes, getMagicKind(operation));
|
||||
return magic(expression, expression, inputValues, getMagicKind(operation));
|
||||
}
|
||||
|
||||
@NotNull
|
||||
|
||||
+2
-4
@@ -95,7 +95,6 @@ public class MagicInstruction(
|
||||
element: JetElement,
|
||||
lexicalScope: LexicalScope,
|
||||
inputValues: List<PseudoValue>,
|
||||
val expectedTypes: Map<PseudoValue, TypePredicate>,
|
||||
val kind: MagicKind
|
||||
) : OperationInstruction(element, lexicalScope, inputValues) {
|
||||
public constructor (
|
||||
@@ -103,10 +102,9 @@ public class MagicInstruction(
|
||||
valueElement: JetElement?,
|
||||
lexicalScope: LexicalScope,
|
||||
inputValues: List<PseudoValue>,
|
||||
expectedTypes: Map<PseudoValue, TypePredicate>,
|
||||
kind: MagicKind,
|
||||
factory: PseudoValueFactory
|
||||
): this(element, lexicalScope, inputValues, expectedTypes, kind) {
|
||||
): this(element, lexicalScope, inputValues, kind) {
|
||||
setResult(factory, valueElement)
|
||||
}
|
||||
|
||||
@@ -120,7 +118,7 @@ public class MagicInstruction(
|
||||
override fun <R> accept(visitor: InstructionVisitorWithResult<R>): R = visitor.visitMagic(this)
|
||||
|
||||
override fun createCopy() =
|
||||
MagicInstruction(element, lexicalScope, inputValues, expectedTypes, kind).setResult(resultValue)
|
||||
MagicInstruction(element, lexicalScope, inputValues, kind).setResult(resultValue)
|
||||
|
||||
override fun toString() = renderInstruction("magic[$kind]", render(element))
|
||||
}
|
||||
|
||||
@@ -16,8 +16,12 @@
|
||||
|
||||
package org.jetbrains.kotlin.cfg.pseudocode
|
||||
|
||||
import com.google.common.collect.Sets
|
||||
import com.intellij.psi.util.PsiTreeUtil
|
||||
import com.intellij.util.SmartFMap
|
||||
import com.intellij.util.containers.MultiMap
|
||||
import org.jetbrains.kotlin.builtins.KotlinBuiltIns
|
||||
import org.jetbrains.kotlin.cfg.pseudocode.instructions.eval.MagicKind.*
|
||||
import org.jetbrains.kotlin.cfg.pseudocode.instructions.Instruction
|
||||
import org.jetbrains.kotlin.cfg.pseudocode.instructions.eval.*
|
||||
import org.jetbrains.kotlin.cfg.pseudocode.instructions.jumps.ConditionalJumpInstruction
|
||||
@@ -26,23 +30,28 @@ import org.jetbrains.kotlin.cfg.pseudocode.instructions.jumps.ThrowExceptionInst
|
||||
import org.jetbrains.kotlin.descriptors.*
|
||||
import org.jetbrains.kotlin.descriptors.impl.LocalVariableDescriptor
|
||||
import org.jetbrains.kotlin.psi.*
|
||||
import org.jetbrains.kotlin.psi.psiUtil.getElementTextWithContext
|
||||
import org.jetbrains.kotlin.psi.psiUtil.getNonStrictParentOfType
|
||||
import org.jetbrains.kotlin.psi.psiUtil.parents
|
||||
import org.jetbrains.kotlin.psi.psiUtil.*
|
||||
import org.jetbrains.kotlin.renderer.DescriptorRenderer
|
||||
import org.jetbrains.kotlin.resolve.BindingContext
|
||||
import org.jetbrains.kotlin.resolve.BindingContext.*
|
||||
import org.jetbrains.kotlin.resolve.DelegatingBindingTrace
|
||||
import org.jetbrains.kotlin.resolve.OverridingUtil
|
||||
import org.jetbrains.kotlin.resolve.bindingContextUtil.getReferenceTargets
|
||||
import org.jetbrains.kotlin.resolve.bindingContextUtil.getTargetFunctionDescriptor
|
||||
import org.jetbrains.kotlin.resolve.calls.model.ResolvedCall
|
||||
import org.jetbrains.kotlin.resolve.calls.model.VarargValueArgument
|
||||
import org.jetbrains.kotlin.resolve.calls.ValueArgumentsToParametersMapper
|
||||
import org.jetbrains.kotlin.resolve.calls.callUtil.getCall
|
||||
import org.jetbrains.kotlin.resolve.calls.model.*
|
||||
import org.jetbrains.kotlin.resolve.calls.resolvedCallUtil.getExplicitReceiverValue
|
||||
import org.jetbrains.kotlin.resolve.calls.tasks.ExplicitReceiverKind
|
||||
import org.jetbrains.kotlin.resolve.calls.tasks.ResolutionCandidate
|
||||
import org.jetbrains.kotlin.resolve.calls.tasks.TracingStrategy
|
||||
import org.jetbrains.kotlin.resolve.scopes.receivers.ReceiverValue
|
||||
import org.jetbrains.kotlin.types.JetType
|
||||
import org.jetbrains.kotlin.types.TypeUtils
|
||||
import java.util.ArrayList
|
||||
import java.util.LinkedHashSet
|
||||
import java.util.*
|
||||
|
||||
fun getReceiverTypePredicate(resolvedCall: ResolvedCall<*>, receiverValue: ReceiverValue): TypePredicate? {
|
||||
val callableDescriptor = resolvedCall.getResultingDescriptor()
|
||||
if (callableDescriptor == null) return null
|
||||
val callableDescriptor = resolvedCall.getResultingDescriptor() ?: return null
|
||||
|
||||
when (receiverValue) {
|
||||
resolvedCall.getExtensionReceiver() -> {
|
||||
@@ -61,13 +70,75 @@ fun getReceiverTypePredicate(resolvedCall: ResolvedCall<*>, receiverValue: Recei
|
||||
}
|
||||
|
||||
public fun getExpectedTypePredicate(value: PseudoValue, bindingContext: BindingContext): TypePredicate {
|
||||
val pseudocode = value.createdAt?.owner
|
||||
if (pseudocode == null) return AllTypes
|
||||
val pseudocode = value.createdAt?.owner ?: return AllTypes
|
||||
val builtIns = KotlinBuiltIns.getInstance()
|
||||
|
||||
val typePredicates = LinkedHashSet<TypePredicate?>()
|
||||
|
||||
fun addSubtypesOf(jetType: JetType?) = typePredicates.add(jetType?.getSubtypesPredicate())
|
||||
|
||||
fun addByExplicitReceiver(resolvedCall: ResolvedCall<*>?) {
|
||||
val receiverValue = (resolvedCall ?: return).getExplicitReceiverValue()
|
||||
if (receiverValue.exists()) typePredicates.add(getReceiverTypePredicate(resolvedCall, receiverValue))
|
||||
}
|
||||
|
||||
fun getTypePredicateForUnresolvedCallArgument(to: JetElement, inputValueIndex: Int): TypePredicate? {
|
||||
if (inputValueIndex < 0) return null
|
||||
val call = to.getCall(bindingContext) ?: return null
|
||||
val callee = call.getCalleeExpression() ?: return null
|
||||
|
||||
val candidates = callee.getReferenceTargets(bindingContext)
|
||||
.filterIsInstance<FunctionDescriptor>()
|
||||
.sortBy { DescriptorRenderer.DEBUG_TEXT.render(it) }
|
||||
if (candidates.isEmpty()) return null
|
||||
|
||||
val explicitReceiver = call.getExplicitReceiver()
|
||||
val argValueOffset = if (explicitReceiver.exists()) 1 else 0
|
||||
|
||||
val predicates = ArrayList<TypePredicate>()
|
||||
|
||||
for (candidate in candidates) {
|
||||
val resolutionCandidate = ResolutionCandidate.create(
|
||||
call,
|
||||
candidate,
|
||||
call.getDispatchReceiver(),
|
||||
explicitReceiver,
|
||||
ExplicitReceiverKind.NO_EXPLICIT_RECEIVER,
|
||||
null
|
||||
)
|
||||
val candidateCall = ResolvedCallImpl.create(
|
||||
resolutionCandidate,
|
||||
DelegatingBindingTrace(bindingContext, "Compute type predicates for unresolved call arguments"),
|
||||
TracingStrategy.EMPTY,
|
||||
DataFlowInfoForArgumentsImpl(call)
|
||||
)
|
||||
val status = ValueArgumentsToParametersMapper.mapValueArgumentsToParameters(call,
|
||||
TracingStrategy.EMPTY,
|
||||
candidateCall,
|
||||
LinkedHashSet())
|
||||
if (!status.isSuccess()) continue
|
||||
|
||||
val candidateArgumentMap = candidateCall.getValueArguments()
|
||||
val callArguments = call.getValueArguments()
|
||||
val i = inputValueIndex - argValueOffset
|
||||
if (i < 0 || i >= callArguments.size()) continue
|
||||
|
||||
val mapping = candidateCall.getArgumentMapping(callArguments.get(i))
|
||||
if (mapping !is ArgumentMatch) continue
|
||||
|
||||
val candidateParameter = mapping.valueParameter
|
||||
val resolvedArgument = candidateArgumentMap.get(candidateParameter)
|
||||
val expectedType = if (resolvedArgument is VarargValueArgument)
|
||||
candidateParameter.getVarargElementType()
|
||||
else
|
||||
candidateParameter.getType()
|
||||
|
||||
predicates.add(if (expectedType != null) AllSubtypes(expectedType) else AllTypes)
|
||||
}
|
||||
|
||||
return or(predicates)
|
||||
}
|
||||
|
||||
fun addTypePredicates(value: PseudoValue) {
|
||||
pseudocode.getUsages(value).forEach {
|
||||
when (it) {
|
||||
@@ -75,16 +146,16 @@ public fun getExpectedTypePredicate(value: PseudoValue, bindingContext: BindingC
|
||||
val returnElement = it.element
|
||||
val functionDescriptor = when(returnElement) {
|
||||
is JetReturnExpression -> returnElement.getTargetFunctionDescriptor(bindingContext)
|
||||
else -> bindingContext[BindingContext.DECLARATION_TO_DESCRIPTOR, pseudocode.getCorrespondingElement()]
|
||||
else -> bindingContext[DECLARATION_TO_DESCRIPTOR, pseudocode.getCorrespondingElement()]
|
||||
}
|
||||
addSubtypesOf((functionDescriptor as? CallableDescriptor)?.getReturnType())
|
||||
}
|
||||
|
||||
is ConditionalJumpInstruction ->
|
||||
addSubtypesOf(KotlinBuiltIns.getInstance().getBooleanType())
|
||||
addSubtypesOf(builtIns.getBooleanType())
|
||||
|
||||
is ThrowExceptionInstruction ->
|
||||
addSubtypesOf(KotlinBuiltIns.getInstance().getThrowable().getDefaultType())
|
||||
addSubtypesOf(builtIns.getThrowable().getDefaultType())
|
||||
|
||||
is MergeInstruction ->
|
||||
addTypePredicates(it.outputValue)
|
||||
@@ -126,8 +197,36 @@ public fun getExpectedTypePredicate(value: PseudoValue, bindingContext: BindingC
|
||||
}
|
||||
}
|
||||
|
||||
is MagicInstruction ->
|
||||
typePredicates.add(it.expectedTypes[value])
|
||||
is MagicInstruction -> @suppress("NON_EXHAUSTIVE_WHEN") when (it.kind) {
|
||||
AND, OR ->
|
||||
addSubtypesOf(builtIns.getBooleanType())
|
||||
|
||||
LOOP_RANGE_ITERATION ->
|
||||
addByExplicitReceiver(bindingContext[LOOP_RANGE_ITERATOR_RESOLVED_CALL, value.element as? JetExpression])
|
||||
|
||||
VALUE_CONSUMER -> {
|
||||
val element = it.element
|
||||
when {
|
||||
element.getStrictParentOfType<JetWhileExpression>()?.getCondition() == element ->
|
||||
addSubtypesOf(builtIns.getBooleanType())
|
||||
|
||||
element is JetProperty -> {
|
||||
val propertyDescriptor = bindingContext[DECLARATION_TO_DESCRIPTOR, element] as? PropertyDescriptor
|
||||
propertyDescriptor?.getAccessors()?.map {
|
||||
addByExplicitReceiver(bindingContext[DELEGATED_PROPERTY_RESOLVED_CALL, it])
|
||||
}
|
||||
}
|
||||
|
||||
element is JetDelegatorByExpressionSpecifier ->
|
||||
addSubtypesOf(bindingContext[TYPE, element.getTypeReference()])
|
||||
}
|
||||
}
|
||||
|
||||
UNRESOLVED_CALL -> {
|
||||
val typePredicate = getTypePredicateForUnresolvedCallArgument(it.element, it.inputValues.indexOf(value))
|
||||
typePredicates.add(typePredicate)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -26,8 +26,10 @@ import org.jetbrains.kotlin.psi.JetThisExpression
|
||||
import org.jetbrains.kotlin.resolve.BindingContext
|
||||
import org.jetbrains.kotlin.resolve.DescriptorUtils
|
||||
import org.jetbrains.kotlin.resolve.calls.model.ResolvedCall
|
||||
import org.jetbrains.kotlin.resolve.calls.tasks.ExplicitReceiverKind
|
||||
import org.jetbrains.kotlin.resolve.descriptorUtil.getOwnerForEffectiveDispatchReceiverParameter
|
||||
import org.jetbrains.kotlin.resolve.scopes.receivers.ExpressionReceiver
|
||||
import org.jetbrains.kotlin.resolve.scopes.receivers.ReceiverValue
|
||||
import org.jetbrains.kotlin.resolve.scopes.receivers.ThisReceiver
|
||||
|
||||
// it returns true if call has no dispatch receiver (e.g. resulting descriptor is top-level function or local variable)
|
||||
@@ -66,3 +68,10 @@ private fun ResolvedCall<*>.hasThisOrNoDispatchReceiver(
|
||||
return dispatchReceiverDescriptor == getResultingDescriptor().getOwnerForEffectiveDispatchReceiverParameter()
|
||||
}
|
||||
|
||||
public fun ResolvedCall<*>.getExplicitReceiverValue(): ReceiverValue {
|
||||
return when (getExplicitReceiverKind()) {
|
||||
ExplicitReceiverKind.DISPATCH_RECEIVER -> getDispatchReceiver()
|
||||
ExplicitReceiverKind.EXTENSION_RECEIVER, ExplicitReceiverKind.BOTH_RECEIVERS -> getExtensionReceiver()
|
||||
else -> ReceiverValue.NO_RECEIVER
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user