Use Call instead of CallKey as a map key in ResolutionResultsCache

This commit is contained in:
Svetlana Isakova
2014-05-02 13:32:37 +04:00
parent 17a6c1fd54
commit 05e5f2437e
8 changed files with 96 additions and 197 deletions
@@ -1,59 +0,0 @@
/*
* Copyright 2010-2013 JetBrains s.r.o.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.jetbrains.jet.lang.psi;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.jet.lang.psi.Call.CallType;
public class CallKey {
private final CallType callType;
private final JetExpression element;
public CallKey(CallType callType, JetExpression element) {
this.callType = callType;
this.element = element;
}
@NotNull
public static CallKey create(@NotNull CallType callType, @NotNull JetExpression element) {
return new CallKey(callType, element);
}
public static CallKey create(JetExpression element) {
return new CallKey(CallType.DEFAULT, element);
}
@Override
public boolean equals(Object o) {
if (this == o) return true;
if (!(o instanceof CallKey)) return false;
CallKey key = (CallKey) o;
if (callType != key.callType) return false;
if (element != null ? !element.equals(key.element) : key.element != null) return false;
return true;
}
@Override
public int hashCode() {
int result = callType != null ? callType.hashCode() : 0;
result = 31 * result + (element != null ? element.hashCode() : 0);
return result;
}
}
@@ -326,15 +326,15 @@ public class CallResolver {
@NotNull CallTransformer<D, F> callTransformer,
@NotNull TracingStrategy tracing
) {
tracing.bindCall(context.trace, context.call);
Call call = context.call;
tracing.bindCall(context.trace, call);
OverloadResolutionResultsImpl<F> results = null;
TemporaryBindingTrace traceToResolveCall = TemporaryBindingTrace.create(context.trace, "trace to resolve call", context.call);
CallKey callKey = CallResolverUtil.createCallKey(context);
if (callKey != null) {
OverloadResolutionResultsImpl<F> cachedResults = context.resolutionResultsCache.getResolutionResults(callKey);
TemporaryBindingTrace traceToResolveCall = TemporaryBindingTrace.create(context.trace, "trace to resolve call", call);
if (!CallResolverUtil.isInvokeCallOnVariable(call)) {
OverloadResolutionResultsImpl<F> cachedResults = context.resolutionResultsCache.getResolutionResults(call);
if (cachedResults != null) {
DelegatingBindingTrace deltasTraceForResolve = context.resolutionResultsCache.getResolutionTrace(callKey);
DelegatingBindingTrace deltasTraceForResolve = context.resolutionResultsCache.getResolutionTrace(call);
assert deltasTraceForResolve != null;
deltasTraceForResolve.addAllMyDataTo(traceToResolveCall);
results = cachedResults;
@@ -419,20 +419,20 @@ public class CallResolver {
@NotNull DelegatingBindingTrace traceToResolveCall,
@NotNull TracingStrategy tracing
) {
CallKey callKey = CallResolverUtil.createCallKey(context);
if (callKey == null) return;
Call call = context.call;
if (CallResolverUtil.isInvokeCallOnVariable(call)) return;
DelegatingBindingTrace deltasTraceToCacheResolve = new DelegatingBindingTrace(
BindingContext.EMPTY, "delta trace for caching resolve of", context.call);
traceToResolveCall.addAllMyDataTo(deltasTraceToCacheResolve);
context.resolutionResultsCache.recordResolutionResults(callKey, results);
context.resolutionResultsCache.recordResolutionTrace(callKey, deltasTraceToCacheResolve);
context.resolutionResultsCache.recordResolutionResults(call, results);
context.resolutionResultsCache.recordResolutionTrace(call, deltasTraceToCacheResolve);
if (results.isSingleResult()) {
CallCandidateResolutionContext<F> contextForCallToCompleteTypeArgumentInference =
CallCandidateResolutionContext.createForCallBeingAnalyzed(results.getResultingCall(), context, tracing);
context.resolutionResultsCache.recordDeferredComputationForCall(callKey, contextForCallToCompleteTypeArgumentInference);
context.resolutionResultsCache.recordDeferredComputationForCall(call, contextForCallToCompleteTypeArgumentInference);
}
}
@@ -586,12 +586,13 @@ public class CallResolver {
to have a binding to variable while 'invoke' call resolve */
task.tracing.bindReference(context.candidateCall.getTrace(), context.candidateCall);
Collection<MutableResolvedCall<F>> calls = callTransformer.transformCall(context, this, task);
Collection<MutableResolvedCall<F>> resolvedCalls = callTransformer.transformCall(context, this, task);
for (MutableResolvedCall<F> call : calls) {
task.tracing.bindReference(call.getTrace(), call);
task.tracing.bindResolvedCall(call.getTrace(), call);
task.addResolvedCall(call);
for (MutableResolvedCall<F> resolvedCall : resolvedCalls) {
BindingTrace trace = resolvedCall.getTrace();
task.tracing.bindReference(trace, resolvedCall);
task.tracing.bindResolvedCall(trace, resolvedCall);
task.addResolvedCall(resolvedCall);
}
}
}
@@ -102,16 +102,6 @@ public class CallResolverUtil {
return true;
}
@Nullable
public static CallKey createCallKey(@NotNull BasicCallResolutionContext context) {
if (isInvokeCallOnVariable(context.call)) {
return null;
}
PsiElement callElement = context.call.getCallElement();
if (!(callElement instanceof JetExpression)) return null;
return CallKey.create(context.call.getCallType(), (JetExpression) callElement);
}
@NotNull
public static JetType getErasedReceiverType(
@NotNull ReceiverParameterDescriptor receiverParameterDescriptor,
@@ -27,6 +27,7 @@ import org.jetbrains.annotations.Nullable;
import org.jetbrains.jet.lang.descriptors.*;
import org.jetbrains.jet.lang.psi.*;
import org.jetbrains.jet.lang.resolve.*;
import org.jetbrains.jet.lang.resolve.bindingContextUtil.BindingContextUtilPackage;
import org.jetbrains.jet.lang.resolve.calls.autocasts.AutoCastUtils;
import org.jetbrains.jet.lang.resolve.calls.autocasts.DataFlowInfo;
import org.jetbrains.jet.lang.resolve.calls.autocasts.DataFlowValue;
@@ -273,15 +274,14 @@ public class CandidateResolver {
private <D extends CallableDescriptor> void completeTypeInferenceForAllCandidatesForArgument(
@NotNull CallCandidateResolutionContext<D> context,
@Nullable JetExpression argumentExpression
@Nullable Call call
) {
// All candidates for inner calls are not needed, so there is no need to complete them
if (context.collectAllCandidates) return;
if (argumentExpression == null) return;
if (call == null) return;
CallKey callKey = CallKey.create(argumentExpression);
OverloadResolutionResultsImpl<CallableDescriptor> resolutionResults = context.resolutionResultsCache.getResolutionResults(callKey);
OverloadResolutionResultsImpl<CallableDescriptor> resolutionResults = context.resolutionResultsCache.getResolutionResults(call);
if (resolutionResults == null) return;
completeTypeInferenceForAllCandidates(context.toBasic(), resolutionResults);
@@ -390,6 +390,20 @@ public class CandidateResolver {
recordReferenceForInvokeFunction(context);
}
@Nullable
private static Call getCallForArgument(@Nullable JetExpression argument, @NotNull BindingContext bindingContext) {
if (!ExpressionTypingUtils.dependsOnExpectedType(argument)) {
return null;
}
if (argument instanceof JetBlockExpression) {
JetElement lastStatement = JetPsiUtil.getLastStatementInABlock((JetBlockExpression) argument);
if (lastStatement instanceof JetExpression) {
return getCallForArgument((JetExpression) lastStatement, bindingContext);
}
}
return BindingContextUtilPackage.getCorrespondingCall(argument, bindingContext);
}
private <D extends CallableDescriptor> void completeInferenceForArgument(
@NotNull ValueArgument argument,
@NotNull ValueParameterDescriptor parameterDescriptor,
@@ -401,8 +415,8 @@ public class CandidateResolver {
JetType expectedType = getEffectiveExpectedType(parameterDescriptor, argument);
context = context.replaceExpectedType(expectedType);
JetExpression keyExpression = getDeferredComputationKeyExpression(expression);
CallCandidateResolutionContext<?> storedContextForArgument = context.resolutionResultsCache.getDeferredComputation(keyExpression);
Call call = getCallForArgument(expression, context.trace.getBindingContext());
CallCandidateResolutionContext<?> storedContextForArgument = context.resolutionResultsCache.getDeferredComputation(call);
PsiElement parent = expression.getParent();
if (parent instanceof JetWhenExpression && expression == ((JetWhenExpression) parent).getSubjectExpression()
@@ -412,7 +426,7 @@ public class CandidateResolver {
if (storedContextForArgument == null) {
JetType type = ArgumentTypeResolver.updateResultArgumentTypeIfNotDenotable(context, expression);
checkResultArgumentType(type, argument, context);
completeTypeInferenceForAllCandidatesForArgument(context, keyExpression);
completeTypeInferenceForAllCandidatesForArgument(context, call);
return;
}
@@ -427,7 +441,7 @@ public class CandidateResolver {
JetType result = BindingContextUtils.updateRecordedType(
type, expression, context.trace, isFairSafeCallExpression(expression, context.trace));
completeTypeInferenceForAllCandidatesForArgument(context, keyExpression);
completeTypeInferenceForAllCandidatesForArgument(context, call);
DataFlowUtils.checkType(result, expression, contextForArgument);
}
@@ -447,10 +461,8 @@ public class CandidateResolver {
for (ValueArgument argument : arguments) {
JetExpression expression = argument.getArgumentExpression();
JetExpression keyExpression = getDeferredComputationKeyExpression(expression);
CallCandidateResolutionContext<?> storedContextForArgument =
context.resolutionResultsCache.getDeferredComputation(keyExpression);
Call call = getCallForArgument(expression, context.trace.getBindingContext());
CallCandidateResolutionContext<?> storedContextForArgument = context.resolutionResultsCache.getDeferredComputation(call);
if (storedContextForArgument == null) continue;
if (storedContextForArgument.candidateCall.isCompleted()) continue;
@@ -460,57 +472,6 @@ public class CandidateResolver {
}
}
@Nullable
private JetExpression getDeferredComputationKeyExpression(@Nullable JetExpression expression) {
if (expression == null) return null;
return expression.accept(new JetVisitor<JetExpression, Void>() {
@Nullable
private JetExpression visitInnerExpression(@Nullable JetElement expression) {
if (expression == null) return null;
return expression.accept(this, null);
}
@Override
public JetExpression visitQualifiedExpression(@NotNull JetQualifiedExpression expression, Void data) {
return visitInnerExpression(expression.getSelectorExpression());
}
@Override
public JetExpression visitExpression(@NotNull JetExpression expression, Void data) {
return expression;
}
@Override
public JetExpression visitParenthesizedExpression(@NotNull JetParenthesizedExpression expression, Void data) {
return visitInnerExpression(expression.getExpression());
}
@Override
public JetExpression visitUnaryExpression(@NotNull JetUnaryExpression expression, Void data) {
return ExpressionTypingUtils.isUnaryExpressionDependentOnExpectedType(expression) ? expression : null;
}
@Override
public JetExpression visitLabeledExpression(@NotNull JetLabeledExpression expression, Void data) {
return visitInnerExpression(expression.getBaseExpression());
}
@Override
public JetExpression visitBlockExpression(@NotNull JetBlockExpression expression, Void data) {
JetElement lastStatement = JetPsiUtil.getLastStatementInABlock(expression);
if (lastStatement != null) {
return visitInnerExpression(lastStatement);
}
return expression;
}
@Override
public JetExpression visitBinaryExpression(@NotNull JetBinaryExpression expression, Void data) {
return ExpressionTypingUtils.isBinaryExpressionDependentOnExpectedType(expression) ? expression : null;
}
}, null);
}
private static boolean isFairSafeCallExpression(@NotNull JetExpression expression, @NotNull BindingTrace trace) {
// We are interested in type of the last call:
// 'a.b?.foo()' is safe call, but 'a?.b.foo()' is not.
@@ -19,29 +19,27 @@ package org.jetbrains.jet.lang.resolve.calls.context;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import org.jetbrains.jet.lang.descriptors.CallableDescriptor;
import org.jetbrains.jet.lang.psi.CallKey;
import org.jetbrains.jet.lang.psi.JetExpression;
import org.jetbrains.jet.lang.psi.Call;
import org.jetbrains.jet.lang.resolve.DelegatingBindingTrace;
import org.jetbrains.jet.lang.resolve.calls.model.MutableResolvedCall;
import org.jetbrains.jet.lang.resolve.calls.results.OverloadResolutionResultsImpl;
public interface ResolutionResultsCache {
<D extends CallableDescriptor> void recordResolutionResults(@NotNull CallKey callKey, @NotNull OverloadResolutionResultsImpl<D> results);
<D extends CallableDescriptor> void recordResolutionResults(@NotNull Call call, @NotNull OverloadResolutionResultsImpl<D> results);
@Nullable
<D extends CallableDescriptor> OverloadResolutionResultsImpl<D> getResolutionResults(@NotNull CallKey callKey);
<D extends CallableDescriptor> OverloadResolutionResultsImpl<D> getResolutionResults(@NotNull Call call);
void recordResolutionTrace(@NotNull CallKey callKey, @NotNull DelegatingBindingTrace delegatingTrace);
void recordResolutionTrace(@NotNull Call call, @NotNull DelegatingBindingTrace delegatingTrace);
@Nullable
DelegatingBindingTrace getResolutionTrace(@NotNull CallKey callKey);
DelegatingBindingTrace getResolutionTrace(@NotNull Call call);
<D extends CallableDescriptor> void recordDeferredComputationForCall(
@NotNull CallKey callKey,
@NotNull Call call,
@NotNull CallCandidateResolutionContext<D> deferredComputation
);
@Nullable
CallCandidateResolutionContext<?> getDeferredComputation(@Nullable JetExpression expression);
CallCandidateResolutionContext<?> getDeferredComputation(@Nullable Call call);
}
@@ -17,12 +17,11 @@
package org.jetbrains.jet.lang.resolve.calls.context
import org.jetbrains.jet.lang.descriptors.CallableDescriptor
import org.jetbrains.jet.lang.psi.CallKey
import org.jetbrains.jet.lang.resolve.calls.results.OverloadResolutionResultsImpl
import org.jetbrains.jet.lang.resolve.DelegatingBindingTrace
import org.jetbrains.jet.lang.psi.JetExpression
import java.util.HashMap
import org.jetbrains.jet.lang.psi.Call.CallType.*
import org.jetbrains.jet.lang.psi.Call
class ResolutionResultsCacheImpl : ResolutionResultsCache {
private class CachedData(
@@ -31,40 +30,34 @@ class ResolutionResultsCacheImpl : ResolutionResultsCache {
var deferredComputation: CallCandidateResolutionContext<*>? = null
)
private val data = HashMap<CallKey, CachedData>()
private val data = HashMap<Call, CachedData>()
private fun getOrCreateCachedInfo(callKey: CallKey) = data.getOrPut(callKey, { CachedData() })
private fun getOrCreateCachedInfo(call: Call) = data.getOrPut(call, { CachedData() })
override fun <D : CallableDescriptor?> recordResolutionResults(callKey: CallKey, results: OverloadResolutionResultsImpl<D>) {
getOrCreateCachedInfo(callKey).results = results
override fun <D : CallableDescriptor?> recordResolutionResults(call: Call, results: OverloadResolutionResultsImpl<D>) {
getOrCreateCachedInfo(call).results = results
}
override fun <D : CallableDescriptor?> getResolutionResults(callKey: CallKey): OverloadResolutionResultsImpl<D>? {
return data[callKey]?.results as OverloadResolutionResultsImpl<D>?
override fun <D : CallableDescriptor?> getResolutionResults(call: Call): OverloadResolutionResultsImpl<D>? {
return data[call]?.results as OverloadResolutionResultsImpl<D>?
}
override fun recordResolutionTrace(callKey: CallKey, delegatingTrace: DelegatingBindingTrace) {
getOrCreateCachedInfo(callKey).resolutionTrace = delegatingTrace
override fun recordResolutionTrace(call: Call, delegatingTrace: DelegatingBindingTrace) {
getOrCreateCachedInfo(call).resolutionTrace = delegatingTrace
}
override fun getResolutionTrace(callKey: CallKey): DelegatingBindingTrace? {
return data[callKey]?.resolutionTrace
override fun getResolutionTrace(call: Call): DelegatingBindingTrace? {
return data[call]?.resolutionTrace
}
override fun <D : CallableDescriptor?> recordDeferredComputationForCall(callKey: CallKey, deferredComputation: CallCandidateResolutionContext<D>) {
getOrCreateCachedInfo(callKey).deferredComputation = deferredComputation
override fun <D : CallableDescriptor?> recordDeferredComputationForCall(call: Call, deferredComputation: CallCandidateResolutionContext<D>) {
getOrCreateCachedInfo(call).deferredComputation = deferredComputation
}
override fun getDeferredComputation(expression: JetExpression?): CallCandidateResolutionContext<out CallableDescriptor?>? {
if (expression == null) return null
override fun getDeferredComputation(call: Call?): CallCandidateResolutionContext<out CallableDescriptor?>? {
if (call == null) return null
for (callType in listOf(DEFAULT, ARRAY_GET_METHOD, ARRAY_SET_METHOD, INVOKE)) {
val deferredComputation = data[CallKey.create(callType, expression)]?.deferredComputation
if (deferredComputation != null) {
return deferredComputation
}
}
return null
return data[call]?.deferredComputation
}
fun addData(cache: ResolutionResultsCacheImpl) {
@@ -19,8 +19,7 @@ package org.jetbrains.jet.lang.resolve.calls.context;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import org.jetbrains.jet.lang.descriptors.CallableDescriptor;
import org.jetbrains.jet.lang.psi.CallKey;
import org.jetbrains.jet.lang.psi.JetExpression;
import org.jetbrains.jet.lang.psi.Call;
import org.jetbrains.jet.lang.resolve.DelegatingBindingTrace;
import org.jetbrains.jet.lang.resolve.calls.results.OverloadResolutionResultsImpl;
@@ -37,57 +36,57 @@ public class TemporaryResolutionResultsCache implements ResolutionResultsCache {
@Override
public <D extends CallableDescriptor> void recordResolutionResults(
@NotNull CallKey callKey,
@NotNull Call call,
@NotNull OverloadResolutionResultsImpl<D> results
) {
innerCache.recordResolutionResults(callKey, results);
innerCache.recordResolutionResults(call, results);
}
@Nullable
@Override
public <D extends CallableDescriptor> OverloadResolutionResultsImpl<D> getResolutionResults(
@NotNull CallKey callKey
@NotNull Call call
) {
OverloadResolutionResultsImpl<D> results = innerCache.getResolutionResults(callKey);
OverloadResolutionResultsImpl<D> results = innerCache.getResolutionResults(call);
if (results != null) {
return results;
}
return parentCache.getResolutionResults(callKey);
return parentCache.getResolutionResults(call);
}
@Override
public void recordResolutionTrace(
@NotNull CallKey callKey, @NotNull DelegatingBindingTrace delegatingTrace
@NotNull Call call, @NotNull DelegatingBindingTrace delegatingTrace
) {
innerCache.recordResolutionTrace(callKey, delegatingTrace);
innerCache.recordResolutionTrace(call, delegatingTrace);
}
@Nullable
@Override
public DelegatingBindingTrace getResolutionTrace(@NotNull CallKey callKey) {
DelegatingBindingTrace trace = innerCache.getResolutionTrace(callKey);
public DelegatingBindingTrace getResolutionTrace(@NotNull Call call) {
DelegatingBindingTrace trace = innerCache.getResolutionTrace(call);
if (trace != null) {
return trace;
}
return parentCache.getResolutionTrace(callKey);
return parentCache.getResolutionTrace(call);
}
@Override
public <D extends CallableDescriptor> void recordDeferredComputationForCall(
@NotNull CallKey callKey,
@NotNull Call call,
@NotNull CallCandidateResolutionContext<D> deferredComputation
) {
innerCache.recordDeferredComputationForCall(callKey, deferredComputation);
innerCache.recordDeferredComputationForCall(call, deferredComputation);
}
@Nullable
@Override
public CallCandidateResolutionContext<?> getDeferredComputation(@Nullable JetExpression expression) {
CallCandidateResolutionContext<?> computation = innerCache.getDeferredComputation(expression);
public CallCandidateResolutionContext<?> getDeferredComputation(@Nullable Call call) {
CallCandidateResolutionContext<?> computation = innerCache.getDeferredComputation(call);
if (computation != null) {
return computation;
}
return parentCache.getDeferredComputation(expression);
return parentCache.getDeferredComputation(call);
}
public void commit() {
@@ -526,4 +526,20 @@ public class ExpressionTypingUtils {
}
return false;
}
public static boolean dependsOnExpectedType(@Nullable JetExpression expression) {
JetExpression expr = JetPsiUtil.deparenthesize(expression, false);
if (expr == null) return false;
if (expr instanceof JetBinaryExpressionWithTypeRHS) {
return false;
}
if (expr instanceof JetBinaryExpression) {
return isBinaryExpressionDependentOnExpectedType((JetBinaryExpression) expr);
}
if (expr instanceof JetUnaryExpression) {
return isUnaryExpressionDependentOnExpectedType((JetUnaryExpression) expr);
}
return true;
}
}