cache for resolved simple calls added

simple: without type parameters
This commit is contained in:
Svetlana Isakova
2012-06-07 17:14:13 +04:00
parent c40cd03a08
commit 7f02af0ce8
2 changed files with 109 additions and 22 deletions
@@ -16,13 +16,16 @@
package org.jetbrains.jet.lang.resolve;
import com.intellij.openapi.util.Pair;
import com.intellij.psi.PsiElement;
import com.intellij.util.PlusMinus;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import org.jetbrains.jet.lang.descriptors.*;
import org.jetbrains.jet.lang.descriptors.annotations.AnnotationDescriptor;
import org.jetbrains.jet.lang.diagnostics.Diagnostic;
import org.jetbrains.jet.lang.psi.*;
import org.jetbrains.jet.lang.resolve.calls.OverloadResolutionResults;
import org.jetbrains.jet.lang.resolve.calls.ResolvedCall;
import org.jetbrains.jet.lang.resolve.calls.autocasts.DataFlowInfo;
import org.jetbrains.jet.lang.resolve.constants.CompileTimeConstant;
@@ -34,6 +37,7 @@ import org.jetbrains.jet.util.Box;
import org.jetbrains.jet.util.slicedmap.*;
import java.util.Collection;
import java.util.Collections;
import static org.jetbrains.jet.util.slicedmap.RewritePolicy.DO_NOTHING;
@@ -41,6 +45,24 @@ import static org.jetbrains.jet.util.slicedmap.RewritePolicy.DO_NOTHING;
* @author abreslav
*/
public interface BindingContext {
BindingContext EMPTY = new BindingContext() {
@Override
public Collection<Diagnostic> getDiagnostics() {
return Collections.emptyList();
}
@Override
public <K, V> V get(ReadOnlySlice<K, V> slice, K key) {
return null;
}
@NotNull
@Override
public <K, V> Collection<K> getKeys(WritableSlice<K, V> slice) {
return Collections.emptyList();
}
};
WritableSlice<JetAnnotationEntry, AnnotationDescriptor> ANNOTATION = Slices.createSimpleSlice();
WritableSlice<JetExpression, CompileTimeConstant<?>> COMPILE_TIME_VALUE = Slices.createSimpleSlice();
@@ -52,6 +74,10 @@ public interface BindingContext {
WritableSlice<JetReferenceExpression, Collection<? extends DeclarationDescriptor>> AMBIGUOUS_REFERENCE_TARGET = new BasicWritableSlice<JetReferenceExpression, Collection<? extends DeclarationDescriptor>>(DO_NOTHING);
WritableSlice<CallKey, OverloadResolutionResults<FunctionDescriptor>> RESOLUTION_RESULTS_FOR_FUNCTION = Slices.createSimpleSlice();
WritableSlice<CallKey, OverloadResolutionResults<VariableDescriptor>> RESOLUTION_RESULTS_FOR_PROPERTY = Slices.createSimpleSlice();
WritableSlice<JetExpression, DelegatingBindingTrace> TRACE_DELTAS_CACHE = Slices.createSimpleSlice();
WritableSlice<JetExpression, FunctionDescriptor> LOOP_RANGE_ITERATOR = Slices.createSimpleSlice();
WritableSlice<JetExpression, CallableDescriptor> LOOP_RANGE_HAS_NEXT = Slices.createSimpleSlice();
WritableSlice<JetExpression, FunctionDescriptor> LOOP_RANGE_NEXT = Slices.createSimpleSlice();
@@ -16,11 +16,14 @@
package org.jetbrains.jet.lang.resolve.calls;
import com.google.common.base.Predicate;
import com.google.common.collect.Lists;
import com.google.common.collect.Maps;
import com.google.common.collect.Sets;
import com.intellij.openapi.util.Pair;
import com.intellij.psi.PsiElement;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import org.jetbrains.jet.lang.descriptors.*;
import org.jetbrains.jet.lang.diagnostics.Errors;
import org.jetbrains.jet.lang.psi.*;
@@ -40,6 +43,7 @@ import org.jetbrains.jet.lang.types.checker.JetTypeChecker;
import org.jetbrains.jet.lang.types.expressions.ExpressionTypingServices;
import org.jetbrains.jet.lang.types.lang.JetStandardClasses;
import org.jetbrains.jet.lexer.JetTokens;
import org.jetbrains.jet.util.slicedmap.WritableSlice;
import javax.inject.Inject;
import java.util.*;
@@ -111,7 +115,7 @@ public class CallResolver {
callableDescriptorCollectors.add(CallableDescriptorCollectors.VARIABLES);
}
List<ResolutionTask<VariableDescriptor, VariableDescriptor>> prioritizedTasks = TaskPrioritizer.computePrioritizedTasks(context, referencedName, nameExpression, callableDescriptorCollectors);
return doResolveCall(context, prioritizedTasks, CallTransformer.PROPERTY_CALL_TRANSFORMER, nameExpression);
return doResolveCallOrGetCachedResults(RESOLUTION_RESULTS_FOR_PROPERTY, context, prioritizedTasks, CallTransformer.PROPERTY_CALL_TRANSFORMER, nameExpression);
}
@NotNull
@@ -120,7 +124,7 @@ public class CallResolver {
@NotNull final JetReferenceExpression functionReference,
@NotNull Name name) {
List<ResolutionTask<CallableDescriptor, FunctionDescriptor>> tasks = TaskPrioritizer.computePrioritizedTasks(context, name, functionReference, CallableDescriptorCollectors.FUNCTIONS_AND_VARIABLES);
return doResolveCall(context, tasks, CallTransformer.FUNCTION_CALL_TRANSFORMER, functionReference);
return doResolveCallOrGetCachedResults(RESOLUTION_RESULTS_FOR_FUNCTION, context, tasks, CallTransformer.FUNCTION_CALL_TRANSFORMER, functionReference);
}
@NotNull
@@ -248,7 +252,51 @@ public class CallResolver {
}
}
return doResolveCall(context, prioritizedTasks, CallTransformer.FUNCTION_CALL_TRANSFORMER, functionReference);
return doResolveCallOrGetCachedResults(RESOLUTION_RESULTS_FOR_FUNCTION, context, prioritizedTasks, CallTransformer.FUNCTION_CALL_TRANSFORMER, functionReference);
}
private <D extends CallableDescriptor, F extends D> OverloadResolutionResults<F> doResolveCallOrGetCachedResults(
@NotNull WritableSlice<CallKey, OverloadResolutionResults<F>> resolutionResultsSlice,
@NotNull final BasicResolutionContext context,
@NotNull final List<ResolutionTask<D, F>> prioritizedTasks,
@NotNull CallTransformer<D, F> callTransformer,
@NotNull final JetReferenceExpression reference) {
PsiElement element = context.call.getCallElement();
if (element instanceof JetExpression) {
OverloadResolutionResults<F> cachedResults = context.trace.get(resolutionResultsSlice, CallKey.create(context.call.getCallType(), (JetExpression) element));
if (cachedResults != null) {
DelegatingBindingTrace delegatingTrace = context.trace.get(TRACE_DELTAS_CACHE, (JetExpression) element);
assert delegatingTrace != null;
delegatingTrace.addAllMyDataTo(context.trace);
return cachedResults;
}
}
TemporaryBindingTrace delegatingBindingTrace = TemporaryBindingTrace.create(context.trace);
OverloadResolutionResults<F> results = doResolveCall(context.replaceTrace(delegatingBindingTrace),
prioritizedTasks,
callTransformer, reference);
DelegatingBindingTrace cloneDelta = new DelegatingBindingTrace(new BindingTraceContext().getBindingContext());
delegatingBindingTrace.addAllMyDataTo(cloneDelta);
cacheResults(resolutionResultsSlice, context, results, cloneDelta);
delegatingBindingTrace.commit();
return results;
}
private <F extends CallableDescriptor> void cacheResults(@NotNull WritableSlice<CallKey, OverloadResolutionResults<F>> resolutionResultsSlice,
@NotNull BasicResolutionContext context, @NotNull OverloadResolutionResults<F> results,
@NotNull DelegatingBindingTrace delegatingBindingTrace) {
boolean canBeCached = true;
for (ResolvedCall<? extends CallableDescriptor> call : results.getResultingCalls()) {
if (!call.getCandidateDescriptor().getTypeParameters().isEmpty()) {
canBeCached = false;
}
}
if (!canBeCached) return;
PsiElement callElement = context.call.getCallElement();
if (!(callElement instanceof JetExpression)) return;
context.trace.record(resolutionResultsSlice, CallKey.create(context.call.getCallType(), (JetExpression)callElement), results);
context.trace.record(TRACE_DELTAS_CACHE, (JetExpression) callElement, delegatingBindingTrace);
}
private <D extends CallableDescriptor> OverloadResolutionResults<D> checkArgumentTypesAndFail(BasicResolutionContext context) {
@@ -276,11 +324,11 @@ public class CallResolver {
TemporaryBindingTrace traceForFirstNonemptyCandidateSet = null;
OverloadResolutionResultsImpl<F> resultsForFirstNonemptyCandidateSet = null;
for (ResolutionTask<D, F> task : prioritizedTasks) {
TemporaryBindingTrace temporaryTrace = TemporaryBindingTrace.create(context.trace);
OverloadResolutionResultsImpl<F> results = performResolutionGuardedForExtraFunctionLiteralArguments(task.withTrace(temporaryTrace),
callTransformer);
TemporaryBindingTrace taskTrace = TemporaryBindingTrace.create(context.trace);
OverloadResolutionResultsImpl<F> results = performResolutionGuardedForExtraFunctionLiteralArguments(task.withTrace(taskTrace),
callTransformer, context.trace);
if (results.isSuccess() || results.isAmbiguity()) {
temporaryTrace.commit();
taskTrace.commit();
if (results.isSuccess()) {
debugInfo.set(ResolutionDebugInfo.RESULT, results.getResultingCall());
@@ -289,7 +337,7 @@ public class CallResolver {
return results;
}
if (traceForFirstNonemptyCandidateSet == null && !task.getCandidates().isEmpty() && !results.isNothing()) {
traceForFirstNonemptyCandidateSet = temporaryTrace;
traceForFirstNonemptyCandidateSet = taskTrace;
resultsForFirstNonemptyCandidateSet = results;
}
}
@@ -310,9 +358,11 @@ public class CallResolver {
//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
@NotNull
private <D extends CallableDescriptor, F extends D> OverloadResolutionResultsImpl<F> performResolutionGuardedForExtraFunctionLiteralArguments(@NotNull ResolutionTask<D, F> task,
@NotNull CallTransformer<D, F> callTransformer) {
OverloadResolutionResultsImpl<F> results = performResolution(task, callTransformer);
private <D extends CallableDescriptor, F extends D> OverloadResolutionResultsImpl<F> performResolutionGuardedForExtraFunctionLiteralArguments(
@NotNull ResolutionTask<D, F> task,
@NotNull CallTransformer<D, F> callTransformer,
@NotNull BindingTrace traceForResolutionCache) {
OverloadResolutionResultsImpl<F> results = performResolution(task, callTransformer, traceForResolutionCache);
// If resolution fails, we should check for some of the following situations:
// class A {
@@ -335,14 +385,15 @@ public class CallResolver {
// We have some candidates that failed for some reason
// And we have a suspect: the function literal argument
// Now, we try to remove this argument and see if it helps
ResolutionTask<D, F> newContext = new ResolutionTask<D, F>(task.getCandidates(), task.reference, TemporaryBindingTrace.create(task.trace), task.scope, new DelegatingCall(task.call) {
ResolutionTask<D, F> newTask = new ResolutionTask<D, F>(task.getCandidates(), task.reference, TemporaryBindingTrace.create(task.trace), task.scope,
new DelegatingCall(task.call) {
@NotNull
@Override
public List<JetExpression> getFunctionLiteralArguments() {
return Collections.emptyList();
}
}, task.expectedType, task.dataFlowInfo);
OverloadResolutionResultsImpl<F> resultsWithFunctionLiteralsStripped = performResolution(newContext, callTransformer);
OverloadResolutionResultsImpl<F> resultsWithFunctionLiteralsStripped = performResolution(newTask, callTransformer, traceForResolutionCache);
if (resultsWithFunctionLiteralsStripped.isSuccess() || resultsWithFunctionLiteralsStripped.isAmbiguity()) {
task.tracing.danglingFunctionLiteralArgumentSuspected(task.trace, task.call.getFunctionLiteralArguments());
}
@@ -352,17 +403,27 @@ public class CallResolver {
}
@NotNull
private <D extends CallableDescriptor, F extends D> OverloadResolutionResultsImpl<F> performResolution(@NotNull ResolutionTask<D, F> task,
@NotNull CallTransformer<D, F> callTransformer) {
private <D extends CallableDescriptor, F extends D> OverloadResolutionResultsImpl<F> performResolution(
@NotNull ResolutionTask<D, F> task,
@NotNull CallTransformer<D, F> callTransformer,
@NotNull BindingTrace traceForResolutionCache) {
for (ResolutionCandidate<D> resolutionCandidate : task.getCandidates()) {
TemporaryBindingTrace temporaryTrace = TemporaryBindingTrace.create(task.trace);
Collection<CallResolutionContext<D, F>> contexts = callTransformer.createCallContexts(resolutionCandidate, task, temporaryTrace);
TemporaryBindingTrace candidateTrace = TemporaryBindingTrace.create(task.trace);
Collection<CallResolutionContext<D, F>> contexts = callTransformer.createCallContexts(resolutionCandidate, task, candidateTrace);
Collection<ResolvedCallWithTrace<F>> calls = Lists.newArrayList();
for (CallResolutionContext<D, F> context : contexts) {
performResolutionForCandidateCall(context, task);
calls.addAll(callTransformer.transformCall(context, this, task));
context.candidateCall.getTrace().addAllMyDataTo(traceForResolutionCache, new Predicate<WritableSlice>() {
@Override
public boolean apply(@Nullable WritableSlice slice) {
return slice == BindingContext.RESOLUTION_RESULTS_FOR_FUNCTION || slice == BindingContext.RESOLUTION_RESULTS_FOR_PROPERTY ||
slice == BindingContext.TRACE_DELTAS_CACHE;
}
}, false);
}
for (ResolvedCallWithTrace<F> call : calls) {
@@ -533,8 +594,9 @@ public class CallResolver {
// We'll type check the arguments later, with the inferred types expected
TemporaryBindingTrace traceForUnknown = TemporaryBindingTrace.create(context.trace);
JetExpression argumentExpression = valueArgument.getArgumentExpression();
JetType type = argumentExpression != null ? expressionTypingServices.getType(context.scope, argumentExpression,
substituteDontCare.substitute(valueParameterDescriptor.getType(), Variance.INVARIANT), traceForUnknown) : null;
JetType type = argumentExpression != null ? expressionTypingServices.getType(
context.scope, argumentExpression, substituteDontCare.substitute(valueParameterDescriptor.getType(), Variance.INVARIANT),
context.dataFlowInfo, traceForUnknown) : null;
if (type != null && !ErrorUtils.isErrorType(type)) {
constraintSystem.addSubtypingConstraint(VALUE_ARGUMENT.assertSubtyping(type, effectiveExpectedType));
}
@@ -603,7 +665,7 @@ public class CallResolver {
for (ValueArgument valueArgument : context.call.getValueArguments()) {
JetExpression argumentExpression = valueArgument.getArgumentExpression();
if (argumentExpression != null) {
expressionTypingServices.getType(context.scope, argumentExpression, NO_EXPECTED_TYPE, context.trace);
expressionTypingServices.getType(context.scope, argumentExpression, NO_EXPECTED_TYPE, context.dataFlowInfo, context.trace);
}
}
@@ -626,7 +688,7 @@ public class CallResolver {
for (ValueArgument valueArgument : unmappedArguments) {
JetExpression argumentExpression = valueArgument.getArgumentExpression();
if (argumentExpression != null) {
expressionTypingServices.getType(context.scope, argumentExpression, NO_EXPECTED_TYPE, context.trace);
expressionTypingServices.getType(context.scope, argumentExpression, NO_EXPECTED_TYPE, context.dataFlowInfo, context.trace);
}
}
}
@@ -710,7 +772,6 @@ public class CallResolver {
if (expression == null) continue;
JetType expectedType = getEffectiveExpectedType(parameterDescriptor, argument);
JetType type = expressionTypingServices.getType(context.scope, expression, expectedType, context.dataFlowInfo, context.candidateCall.getTrace());
if (type == null || ErrorUtils.isErrorType(type)) {
context.candidateCall.argumentHasNoType();