added DataFlowInfoForArguments

data flow info for argument depends on previous argument analysis
special interface was added to support case with argument types inference
and 'if' (with special data flow info for then and else arguments)
This commit is contained in:
Svetlana Isakova
2013-07-30 15:59:48 +04:00
parent 27cff93ed8
commit 9ccd1e5ddd
13 changed files with 186 additions and 81 deletions
@@ -311,7 +311,7 @@ public class CallExpressionResolver {
}
JetType type = functionDescriptor.getReturnType();
return JetTypeInfo.create(type, resolvedCall.getDataFlowInfo());
return JetTypeInfo.create(type, resolvedCall.getDataFlowInfoForArguments().getResultInfo());
}
JetExpression calleeExpression = callExpression.getCalleeExpression();
@@ -41,8 +41,6 @@ import java.util.Collections;
import java.util.List;
import java.util.Map;
import static org.jetbrains.jet.lang.resolve.calls.CallTransformer.CallForImplicitInvoke;
public class CallResolverUtil {
public static final JetType DONT_CARE = ErrorUtils.createErrorTypeWithCustomDebugName("DONT_CARE");
@@ -61,7 +59,7 @@ public class CallResolverUtil {
call.getReceiverArgument(), call.getExplicitReceiverKind(),
call.isSafeCall());
ResolvedCallImpl<D> copy = ResolvedCallImpl.create(candidate, TraceUtil.DELEGATING_TRACE_STUB, call.getTracing());
ResolvedCallImpl<D> copy = ResolvedCallImpl.create(candidate, TraceUtil.DELEGATING_TRACE_STUB, call.getTracing(), call.getDataFlowInfoForArguments());
context.trace.record(BindingContext.RESOLVED_CALL, context.call.getCalleeExpression(), copy);
copy.addStatus(call.getStatus());
@@ -76,7 +74,6 @@ public class CallResolverUtil {
for (Map.Entry<ValueParameterDescriptor, ResolvedValueArgument> entry : call.getValueArguments().entrySet()) {
copy.recordValueArgument(entry.getKey(), entry.getValue());
}
copy.setInitialDataFlowInfo(call.getDataFlowInfo());
return copy;
}
@@ -68,9 +68,9 @@ public class CallTransformer<D extends CallableDescriptor, F extends D> {
@NotNull
public Collection<CallCandidateResolutionContext<D>> createCallContexts(@NotNull ResolutionCandidate<D> candidate,
@NotNull ResolutionTask<D, F> task,
@NotNull TemporaryBindingTrace candidateTrace) {
ResolvedCallImpl<D> candidateCall = ResolvedCallImpl.create(candidate, candidateTrace, task.tracing);
@NotNull TemporaryBindingTrace candidateTrace
) {
ResolvedCallImpl<D> candidateCall = ResolvedCallImpl.create(candidate, candidateTrace, task.tracing, task.dataFlowInfoForArguments);
return Collections.singleton(CallCandidateResolutionContext.create(candidateCall, task, candidateTrace, task.tracing));
}
@@ -81,8 +81,8 @@ public class CallTransformer<D extends CallableDescriptor, F extends D> {
@NotNull
public Collection<ResolvedCallWithTrace<F>> transformCall(@NotNull CallCandidateResolutionContext<D> callCandidateResolutionContext,
@NotNull CallResolver callResolver,
@NotNull ResolutionTask<D, F> task) {
@NotNull ResolutionTask<D, F> task
) {
return Collections.singleton((ResolvedCallWithTrace<F>) callCandidateResolutionContext.candidateCall);
}
@@ -105,7 +105,7 @@ public class CallTransformer<D extends CallableDescriptor, F extends D> {
Call variableCall = stripCallArguments(task);
if (!hasReceiver) {
CallCandidateResolutionContext<CallableDescriptor> context = CallCandidateResolutionContext.create(
ResolvedCallImpl.create(candidate, candidateTrace, task.tracing), task, candidateTrace, task.tracing, variableCall);
ResolvedCallImpl.create(candidate, candidateTrace, task.tracing, task.dataFlowInfoForArguments), task, candidateTrace, task.tracing, variableCall);
return Collections.singleton(context);
}
Call variableCallWithoutReceiver = stripReceiver(variableCall);
@@ -127,7 +127,7 @@ public class CallTransformer<D extends CallableDescriptor, F extends D> {
Call call, TemporaryBindingTrace temporaryTrace, ResolutionTask<CallableDescriptor, FunctionDescriptor> task) {
ChainedTemporaryBindingTrace chainedTrace = ChainedTemporaryBindingTrace.create(temporaryTrace, "chained trace to resolve candidate", candidate);
ResolvedCallImpl<CallableDescriptor> resolvedCall = ResolvedCallImpl.create(candidate, chainedTrace, task.tracing);
ResolvedCallImpl<CallableDescriptor> resolvedCall = ResolvedCallImpl.create(candidate, chainedTrace, task.tracing, task.dataFlowInfoForArguments);
return CallCandidateResolutionContext.create(resolvedCall, task, chainedTrace, task.tracing, call);
}
@@ -31,6 +31,7 @@ import org.jetbrains.jet.lang.resolve.*;
import org.jetbrains.jet.lang.resolve.calls.autocasts.*;
import org.jetbrains.jet.lang.resolve.calls.context.*;
import org.jetbrains.jet.lang.resolve.calls.inference.*;
import org.jetbrains.jet.lang.resolve.calls.model.MutableDataFlowInfoForArguments;
import org.jetbrains.jet.lang.resolve.calls.model.ResolvedCall;
import org.jetbrains.jet.lang.resolve.calls.model.ResolvedCallImpl;
import org.jetbrains.jet.lang.resolve.calls.model.ResolvedValueArgument;
@@ -418,7 +419,7 @@ public class CandidateResolver {
}
return;
}
DataFlowInfo dataFlowInfoForValueArgument = context.candidateCall.getDataFlowInfoForValueArgument(argument);
DataFlowInfo dataFlowInfoForValueArgument = context.candidateCall.getDataFlowInfoForArguments().getInfo(argument);
ResolutionContext<?> newContext = context.replaceExpectedType(context.expectedType);
if (dataFlowInfoForValueArgument != null) {
newContext = newContext.replaceDataFlowInfo(dataFlowInfoForValueArgument);
@@ -663,6 +664,7 @@ public class CandidateResolver {
@NotNull CallResolverUtil.ResolveArgumentsMode resolveFunctionArgumentBodies) {
ResolutionStatus resultStatus = SUCCESS;
List<JetType> argumentTypes = Lists.newArrayList();
MutableDataFlowInfoForArguments infoForArguments = candidateCall.getDataFlowInfoForArguments();
for (Map.Entry<ValueParameterDescriptor, ResolvedValueArgument> entry : candidateCall.getValueArguments().entrySet()) {
ValueParameterDescriptor parameterDescriptor = entry.getKey();
ResolvedValueArgument resolvedArgument = entry.getValue();
@@ -676,13 +678,13 @@ public class CandidateResolver {
if (TypeUtils.dependsOnTypeParameters(expectedType, candidateCall.getCandidateDescriptor().getTypeParameters())) {
expectedType = NO_EXPECTED_TYPE;
}
candidateCall.setDataFlowInfoForArgument(argument, candidateCall.getDataFlowInfo());
CallResolutionContext<?> newContext = context.replaceDataFlowInfo(candidateCall.getDataFlowInfo()).replaceBindingTrace(trace)
.replaceExpectedType(expectedType);
CallResolutionContext<?> newContext = context.replaceDataFlowInfo(infoForArguments.getInfo(argument))
.replaceBindingTrace(trace).replaceExpectedType(expectedType);
JetTypeInfo typeInfoForCall = argumentTypeResolver.getArgumentTypeInfo(
expression, newContext, resolveFunctionArgumentBodies, null);
JetType type = typeInfoForCall.getType();
candidateCall.addDataFlowInfo(typeInfoForCall.getDataFlowInfo());
infoForArguments.updateInfo(argument, typeInfoForCall.getDataFlowInfo());
if (type == null || (ErrorUtils.isErrorType(type) && type != PLACEHOLDER_FUNCTION_TYPE)) {
candidateCall.argumentHasNoType();
@@ -20,12 +20,15 @@ import org.jetbrains.annotations.NotNull;
import org.jetbrains.jet.lang.psi.Call;
import org.jetbrains.jet.lang.resolve.BindingTrace;
import org.jetbrains.jet.lang.resolve.calls.autocasts.DataFlowInfo;
import org.jetbrains.jet.lang.resolve.calls.model.DataFlowInfoForArgumentsImpl;
import org.jetbrains.jet.lang.resolve.calls.model.MutableDataFlowInfoForArguments;
import org.jetbrains.jet.lang.resolve.scopes.JetScope;
import org.jetbrains.jet.lang.types.JetType;
public abstract class CallResolutionContext<Context extends CallResolutionContext<Context>> extends ResolutionContext<Context> {
public final Call call;
public final CheckValueArgumentsMode checkArguments;
public final MutableDataFlowInfoForArguments dataFlowInfoForArguments;
protected CallResolutionContext(
@NotNull BindingTrace trace,
@@ -41,6 +44,12 @@ public abstract class CallResolutionContext<Context extends CallResolutionContex
super(trace, scope, expectedType, dataFlowInfo, expressionPosition, resolveMode, resolutionResultsCache);
this.call = call;
this.checkArguments = checkArguments;
if (checkArguments == CheckValueArgumentsMode.ENABLED) {
dataFlowInfoForArguments = new DataFlowInfoForArgumentsImpl(call);
}
else {
dataFlowInfoForArguments = MutableDataFlowInfoForArguments.WITHOUT_ARGUMENTS_CHECK;
}
}
public BasicCallResolutionContext toBasic() {
@@ -0,0 +1,13 @@
package org.jetbrains.jet.lang.resolve.calls.model;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.jet.lang.psi.ValueArgument;
import org.jetbrains.jet.lang.resolve.calls.autocasts.DataFlowInfo;
public interface DataFlowInfoForArguments {
@NotNull
DataFlowInfo getInfo(@NotNull ValueArgument valueArgument);
@NotNull
DataFlowInfo getResultInfo();
}
@@ -0,0 +1,71 @@
package org.jetbrains.jet.lang.resolve.calls.model;
import com.google.common.collect.Maps;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.jet.lang.psi.Call;
import org.jetbrains.jet.lang.psi.ValueArgument;
import org.jetbrains.jet.lang.resolve.calls.autocasts.DataFlowInfo;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
public class DataFlowInfoForArgumentsImpl implements MutableDataFlowInfoForArguments {
private final Call call; //for better debug messages only
private final Map<ValueArgument, DataFlowInfo> infoMap = Maps.newHashMap();
private final Map<ValueArgument, ValueArgument> nextArgument = Maps.newHashMap();
private DataFlowInfo initialInfo;
private DataFlowInfo resultInfo;
public DataFlowInfoForArgumentsImpl(@NotNull Call call) {
this.call = call;
initNextArgMap(call.getValueArguments());
}
private void initNextArgMap(@NotNull List<? extends ValueArgument> valueArguments) {
Iterator<? extends ValueArgument> iterator = valueArguments.iterator();
ValueArgument prev = null;
while (iterator.hasNext()) {
ValueArgument argument = iterator.next();
if (prev != null) {
nextArgument.put(prev, argument);
}
prev = argument;
}
}
@Override
public void setInitialDataFlowInfo(@NotNull DataFlowInfo dataFlowInfo) {
//TODO assert initialInfo == null
initialInfo = dataFlowInfo;
}
@NotNull
@Override
public DataFlowInfo getInfo(@NotNull ValueArgument valueArgument) {
DataFlowInfo infoForArgument = infoMap.get(valueArgument);
if (infoForArgument == null) {
return initialInfo;
}
return initialInfo.and(infoForArgument);
}
@Override
public void updateInfo(@NotNull ValueArgument valueArgument, @NotNull DataFlowInfo dataFlowInfo) {
ValueArgument next = nextArgument.get(valueArgument);
if (next != null) {
infoMap.put(next, dataFlowInfo);
return;
}
//TODO assert resultInfo == null
resultInfo = dataFlowInfo;
}
@NotNull
@Override
public DataFlowInfo getResultInfo() {
if (resultInfo == null) return initialInfo;
assert initialInfo != null : "Initial data flow info was not set for call: " + call;
return initialInfo.and(resultInfo);
}
}
@@ -17,12 +17,9 @@
package org.jetbrains.jet.lang.resolve.calls.model;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import org.jetbrains.jet.lang.descriptors.CallableDescriptor;
import org.jetbrains.jet.lang.descriptors.TypeParameterDescriptor;
import org.jetbrains.jet.lang.descriptors.ValueParameterDescriptor;
import org.jetbrains.jet.lang.psi.ValueArgument;
import org.jetbrains.jet.lang.resolve.calls.autocasts.DataFlowInfo;
import org.jetbrains.jet.lang.resolve.calls.tasks.ExplicitReceiverKind;
import org.jetbrains.jet.lang.resolve.scopes.receivers.ReceiverValue;
import org.jetbrains.jet.lang.types.JetType;
@@ -85,16 +82,10 @@ public abstract class DelegatingResolvedCall<D extends CallableDescriptor> imple
return resolvedCall.getTypeArguments();
}
@Nullable
@Override
public DataFlowInfo getDataFlowInfoForValueArgument(@NotNull ValueArgument valueArgument) {
return resolvedCall.getDataFlowInfoForValueArgument(valueArgument);
}
@NotNull
@Override
public DataFlowInfo getDataFlowInfo() {
return resolvedCall.getDataFlowInfo();
public DataFlowInfoForArguments getDataFlowInfoForArguments() {
return resolvedCall.getDataFlowInfoForArguments();
}
@Override
@@ -0,0 +1,40 @@
package org.jetbrains.jet.lang.resolve.calls.model;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.jet.lang.psi.ValueArgument;
import org.jetbrains.jet.lang.resolve.calls.autocasts.DataFlowInfo;
public interface MutableDataFlowInfoForArguments extends DataFlowInfoForArguments {
void setInitialDataFlowInfo(@NotNull DataFlowInfo dataFlowInfo);
void updateInfo(@NotNull ValueArgument valueArgument, @NotNull DataFlowInfo dataFlowInfo);
MutableDataFlowInfoForArguments WITHOUT_ARGUMENTS_CHECK = new MutableDataFlowInfoForArguments() {
private DataFlowInfo dataFlowInfo;
@Override
public void setInitialDataFlowInfo(@NotNull DataFlowInfo dataFlowInfo) {
this.dataFlowInfo = dataFlowInfo;
}
@Override
public void updateInfo(
@NotNull ValueArgument valueArgument, @NotNull DataFlowInfo dataFlowInfo
) {
throw new IllegalStateException();
}
@NotNull
@Override
public DataFlowInfo getInfo(@NotNull ValueArgument valueArgument) {
throw new IllegalStateException();
}
@NotNull
@Override
public DataFlowInfo getResultInfo() {
return dataFlowInfo;
}
};
}
@@ -59,15 +59,12 @@ public interface ResolvedCall<D extends CallableDescriptor> {
@NotNull
List<ResolvedValueArgument> getValueArgumentsByIndex();
@Nullable
DataFlowInfo getDataFlowInfoForValueArgument(@NotNull ValueArgument valueArgument);
/** What's substituted for type parameters */
@NotNull
Map<TypeParameterDescriptor, JetType> getTypeArguments();
@NotNull
DataFlowInfo getDataFlowInfo();
DataFlowInfoForArguments getDataFlowInfoForArguments();
boolean isSafeCall();
}
@@ -22,17 +22,15 @@ import com.intellij.util.Function;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import org.jetbrains.jet.lang.descriptors.CallableDescriptor;
import org.jetbrains.jet.lang.descriptors.FunctionDescriptor;
import org.jetbrains.jet.lang.descriptors.TypeParameterDescriptor;
import org.jetbrains.jet.lang.descriptors.ValueParameterDescriptor;
import org.jetbrains.jet.lang.psi.ValueArgument;
import org.jetbrains.jet.lang.resolve.*;
import org.jetbrains.jet.lang.resolve.DelegatingBindingTrace;
import org.jetbrains.jet.lang.resolve.calls.autocasts.DataFlowInfo;
import org.jetbrains.jet.lang.resolve.calls.context.CallCandidateResolutionContext;
import org.jetbrains.jet.lang.resolve.calls.inference.ConstraintSystem;
import org.jetbrains.jet.lang.resolve.calls.results.ResolutionStatus;
import org.jetbrains.jet.lang.resolve.calls.tasks.ExplicitReceiverKind;
import org.jetbrains.jet.lang.resolve.calls.tasks.ResolutionCandidate;
import org.jetbrains.jet.lang.resolve.calls.results.ResolutionStatus;
import org.jetbrains.jet.lang.resolve.calls.inference.ConstraintSystem;
import org.jetbrains.jet.lang.resolve.calls.tasks.TracingStrategy;
import org.jetbrains.jet.lang.resolve.scopes.receivers.ReceiverValue;
import org.jetbrains.jet.lang.types.JetType;
@@ -61,9 +59,13 @@ public class ResolvedCallImpl<D extends CallableDescriptor> implements ResolvedC
};
@NotNull
public static <D extends CallableDescriptor> ResolvedCallImpl<D> create(@NotNull ResolutionCandidate<D> candidate, @NotNull DelegatingBindingTrace trace,
@NotNull TracingStrategy tracing) {
return new ResolvedCallImpl<D>(candidate, trace, tracing);
public static <D extends CallableDescriptor> ResolvedCallImpl<D> create(
@NotNull ResolutionCandidate<D> candidate,
@NotNull DelegatingBindingTrace trace,
@NotNull TracingStrategy tracing,
@NotNull MutableDataFlowInfoForArguments dataFlowInfoForArguments
) {
return new ResolvedCallImpl<D>(candidate, trace, tracing, dataFlowInfoForArguments);
}
private final D candidateDescriptor;
@@ -75,17 +77,22 @@ public class ResolvedCallImpl<D extends CallableDescriptor> implements ResolvedC
private final Map<TypeParameterDescriptor, JetType> typeArguments = Maps.newLinkedHashMap();
private final Map<ValueParameterDescriptor, ResolvedValueArgument> valueArguments = Maps.newLinkedHashMap();
private final MutableDataFlowInfoForArguments dataFlowInfoForArguments;
private final Set<ValueArgument> unmappedArguments = Sets.newLinkedHashSet();
private final Map<ValueArgument, DataFlowInfo> dataFlowInfoForArguments = Maps.newHashMap();
private boolean someArgumentHasNoType = false;
private final DelegatingBindingTrace trace;
private final TracingStrategy tracing;
private ResolutionStatus status = UNKNOWN_STATUS;
private boolean hasUnknownTypeParameters = false;
private ConstraintSystem constraintSystem = null;
private DataFlowInfo dataFlowInfo;
private ResolvedCallImpl(@NotNull ResolutionCandidate<D> candidate, @NotNull DelegatingBindingTrace trace, @NotNull TracingStrategy tracing) {
private ResolvedCallImpl(
@NotNull ResolutionCandidate<D> candidate,
@NotNull DelegatingBindingTrace trace,
@NotNull TracingStrategy tracing,
@NotNull MutableDataFlowInfoForArguments dataFlowInfoForArguments
) {
this.candidateDescriptor = candidate.getDescriptor();
this.thisObject = candidate.getThisObject();
this.receiverArgument = candidate.getReceiverArgument();
@@ -93,6 +100,7 @@ public class ResolvedCallImpl<D extends CallableDescriptor> implements ResolvedC
this.isSafeCall = candidate.isSafeCall();
this.trace = trace;
this.tracing = tracing;
this.dataFlowInfoForArguments = dataFlowInfoForArguments;
}
@Override
@@ -258,30 +266,14 @@ public class ResolvedCallImpl<D extends CallableDescriptor> implements ResolvedC
return isSafeCall;
}
public void setInitialDataFlowInfo(@NotNull DataFlowInfo info) {
dataFlowInfoForArguments.setInitialDataFlowInfo(info);
}
@NotNull
@Override
public DataFlowInfo getDataFlowInfo() {
return dataFlowInfo;
}
@Override
@Nullable
public DataFlowInfo getDataFlowInfoForValueArgument(@NotNull ValueArgument valueArgument) {
return dataFlowInfoForArguments.get(valueArgument);
}
public void setInitialDataFlowInfo(@NotNull DataFlowInfo info) {
assert dataFlowInfo == null;
dataFlowInfo = info;
}
public void setDataFlowInfoForArgument(@NotNull ValueArgument valueArgument, @NotNull DataFlowInfo info) {
dataFlowInfoForArguments.put(valueArgument, info);
}
public void addDataFlowInfo(@NotNull DataFlowInfo info) {
assert dataFlowInfo != null;
dataFlowInfo = dataFlowInfo.and(info);
public MutableDataFlowInfoForArguments getDataFlowInfoForArguments() {
return dataFlowInfoForArguments;
}
@NotNull
@@ -17,14 +17,11 @@
package org.jetbrains.jet.lang.resolve.calls.model;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import org.jetbrains.jet.lang.descriptors.FunctionDescriptor;
import org.jetbrains.jet.lang.descriptors.TypeParameterDescriptor;
import org.jetbrains.jet.lang.descriptors.ValueParameterDescriptor;
import org.jetbrains.jet.lang.descriptors.VariableDescriptor;
import org.jetbrains.jet.lang.psi.ValueArgument;
import org.jetbrains.jet.lang.resolve.DelegatingBindingTrace;
import org.jetbrains.jet.lang.resolve.calls.autocasts.DataFlowInfo;
import org.jetbrains.jet.lang.resolve.calls.tasks.ExplicitReceiverKind;
import org.jetbrains.jet.lang.resolve.calls.results.ResolutionStatus;
import org.jetbrains.jet.lang.resolve.scopes.receivers.ReceiverValue;
@@ -99,18 +96,6 @@ public class VariableAsFunctionResolvedCall implements ResolvedCallWithTrace<Fun
return functionCall.getTypeArguments();
}
@Nullable
@Override
public DataFlowInfo getDataFlowInfoForValueArgument(@NotNull ValueArgument valueArgument) {
return functionCall.getDataFlowInfoForValueArgument(valueArgument);
}
@NotNull
@Override
public DataFlowInfo getDataFlowInfo() {
return functionCall.getDataFlowInfo();
}
@NotNull
@Override
public ResolutionStatus getStatus() {
@@ -146,4 +131,10 @@ public class VariableAsFunctionResolvedCall implements ResolvedCallWithTrace<Fun
public ResolvedCallImpl<FunctionDescriptor> getCallToCompleteTypeArgumentInference() {
return functionCall.getCallToCompleteTypeArgumentInference();
}
@NotNull
@Override
public DataFlowInfoForArguments getDataFlowInfoForArguments() {
return functionCall.getDataFlowInfoForArguments();
}
}
@@ -24,6 +24,7 @@ import org.jetbrains.jet.lang.descriptors.CallableDescriptor;
import org.jetbrains.jet.lang.resolve.BindingTraceContext;
import org.jetbrains.jet.lang.resolve.DescriptorUtils;
import org.jetbrains.jet.lang.resolve.TemporaryBindingTrace;
import org.jetbrains.jet.lang.resolve.calls.model.MutableDataFlowInfoForArguments;
import org.jetbrains.jet.lang.resolve.calls.tasks.ExplicitReceiverKind;
import org.jetbrains.jet.lang.resolve.calls.tasks.ResolutionCandidate;
import org.jetbrains.jet.lang.resolve.calls.model.ResolvedCall;
@@ -110,7 +111,8 @@ public final class CallBuilder {
DescriptorUtils.safeGetValue(descriptor.getReceiverParameter()),
ExplicitReceiverKind.THIS_OBJECT, false),
TemporaryBindingTrace.create(new BindingTraceContext(), "trace to resolve call (in js)"),
TracingStrategy.EMPTY);
TracingStrategy.EMPTY,
MutableDataFlowInfoForArguments.WITHOUT_ARGUMENTS_CHECK);
}
if (descriptor == null) {
descriptor = resolvedCall.getCandidateDescriptor().getOriginal();