diff --git a/compiler/frontend/src/org/jetbrains/jet/lang/psi/CallKey.java b/compiler/frontend/src/org/jetbrains/jet/lang/psi/CallKey.java deleted file mode 100644 index edbe1e660ba..00000000000 --- a/compiler/frontend/src/org/jetbrains/jet/lang/psi/CallKey.java +++ /dev/null @@ -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; - } -} diff --git a/compiler/frontend/src/org/jetbrains/jet/lang/resolve/calls/CallResolver.java b/compiler/frontend/src/org/jetbrains/jet/lang/resolve/calls/CallResolver.java index c28dac0bb01..bf71a284f3d 100644 --- a/compiler/frontend/src/org/jetbrains/jet/lang/resolve/calls/CallResolver.java +++ b/compiler/frontend/src/org/jetbrains/jet/lang/resolve/calls/CallResolver.java @@ -326,15 +326,15 @@ public class CallResolver { @NotNull CallTransformer callTransformer, @NotNull TracingStrategy tracing ) { - tracing.bindCall(context.trace, context.call); + Call call = context.call; + tracing.bindCall(context.trace, call); OverloadResolutionResultsImpl results = null; - TemporaryBindingTrace traceToResolveCall = TemporaryBindingTrace.create(context.trace, "trace to resolve call", context.call); - CallKey callKey = CallResolverUtil.createCallKey(context); - if (callKey != null) { - OverloadResolutionResultsImpl cachedResults = context.resolutionResultsCache.getResolutionResults(callKey); + TemporaryBindingTrace traceToResolveCall = TemporaryBindingTrace.create(context.trace, "trace to resolve call", call); + if (!CallResolverUtil.isInvokeCallOnVariable(call)) { + OverloadResolutionResultsImpl 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 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> calls = callTransformer.transformCall(context, this, task); + Collection> resolvedCalls = callTransformer.transformCall(context, this, task); - for (MutableResolvedCall call : calls) { - task.tracing.bindReference(call.getTrace(), call); - task.tracing.bindResolvedCall(call.getTrace(), call); - task.addResolvedCall(call); + for (MutableResolvedCall resolvedCall : resolvedCalls) { + BindingTrace trace = resolvedCall.getTrace(); + task.tracing.bindReference(trace, resolvedCall); + task.tracing.bindResolvedCall(trace, resolvedCall); + task.addResolvedCall(resolvedCall); } } } diff --git a/compiler/frontend/src/org/jetbrains/jet/lang/resolve/calls/CallResolverUtil.java b/compiler/frontend/src/org/jetbrains/jet/lang/resolve/calls/CallResolverUtil.java index 334bc8fe4a3..9246854e85d 100644 --- a/compiler/frontend/src/org/jetbrains/jet/lang/resolve/calls/CallResolverUtil.java +++ b/compiler/frontend/src/org/jetbrains/jet/lang/resolve/calls/CallResolverUtil.java @@ -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, diff --git a/compiler/frontend/src/org/jetbrains/jet/lang/resolve/calls/CandidateResolver.java b/compiler/frontend/src/org/jetbrains/jet/lang/resolve/calls/CandidateResolver.java index 2259350c967..acc0e2bfa13 100644 --- a/compiler/frontend/src/org/jetbrains/jet/lang/resolve/calls/CandidateResolver.java +++ b/compiler/frontend/src/org/jetbrains/jet/lang/resolve/calls/CandidateResolver.java @@ -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 void completeTypeInferenceForAllCandidatesForArgument( @NotNull CallCandidateResolutionContext 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 resolutionResults = context.resolutionResultsCache.getResolutionResults(callKey); + OverloadResolutionResultsImpl 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 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() { - @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. diff --git a/compiler/frontend/src/org/jetbrains/jet/lang/resolve/calls/context/ResolutionResultsCache.java b/compiler/frontend/src/org/jetbrains/jet/lang/resolve/calls/context/ResolutionResultsCache.java index 87e99311f14..7a243378568 100644 --- a/compiler/frontend/src/org/jetbrains/jet/lang/resolve/calls/context/ResolutionResultsCache.java +++ b/compiler/frontend/src/org/jetbrains/jet/lang/resolve/calls/context/ResolutionResultsCache.java @@ -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 { - void recordResolutionResults(@NotNull CallKey callKey, @NotNull OverloadResolutionResultsImpl results); + void recordResolutionResults(@NotNull Call call, @NotNull OverloadResolutionResultsImpl results); @Nullable - OverloadResolutionResultsImpl getResolutionResults(@NotNull CallKey callKey); + OverloadResolutionResultsImpl 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); void recordDeferredComputationForCall( - @NotNull CallKey callKey, + @NotNull Call call, @NotNull CallCandidateResolutionContext deferredComputation ); @Nullable - CallCandidateResolutionContext getDeferredComputation(@Nullable JetExpression expression); + CallCandidateResolutionContext getDeferredComputation(@Nullable Call call); } diff --git a/compiler/frontend/src/org/jetbrains/jet/lang/resolve/calls/context/ResolutionResultsCacheImpl.kt b/compiler/frontend/src/org/jetbrains/jet/lang/resolve/calls/context/ResolutionResultsCacheImpl.kt index 0fb32456136..a20ca88218b 100644 --- a/compiler/frontend/src/org/jetbrains/jet/lang/resolve/calls/context/ResolutionResultsCacheImpl.kt +++ b/compiler/frontend/src/org/jetbrains/jet/lang/resolve/calls/context/ResolutionResultsCacheImpl.kt @@ -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() + private val data = HashMap() - private fun getOrCreateCachedInfo(callKey: CallKey) = data.getOrPut(callKey, { CachedData() }) + private fun getOrCreateCachedInfo(call: Call) = data.getOrPut(call, { CachedData() }) - override fun recordResolutionResults(callKey: CallKey, results: OverloadResolutionResultsImpl) { - getOrCreateCachedInfo(callKey).results = results + override fun recordResolutionResults(call: Call, results: OverloadResolutionResultsImpl) { + getOrCreateCachedInfo(call).results = results } - override fun getResolutionResults(callKey: CallKey): OverloadResolutionResultsImpl? { - return data[callKey]?.results as OverloadResolutionResultsImpl? + override fun getResolutionResults(call: Call): OverloadResolutionResultsImpl? { + return data[call]?.results as OverloadResolutionResultsImpl? } - 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 recordDeferredComputationForCall(callKey: CallKey, deferredComputation: CallCandidateResolutionContext) { - getOrCreateCachedInfo(callKey).deferredComputation = deferredComputation + override fun recordDeferredComputationForCall(call: Call, deferredComputation: CallCandidateResolutionContext) { + getOrCreateCachedInfo(call).deferredComputation = deferredComputation } - override fun getDeferredComputation(expression: JetExpression?): CallCandidateResolutionContext? { - if (expression == null) return null + override fun getDeferredComputation(call: Call?): CallCandidateResolutionContext? { + 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) { diff --git a/compiler/frontend/src/org/jetbrains/jet/lang/resolve/calls/context/TemporaryResolutionResultsCache.java b/compiler/frontend/src/org/jetbrains/jet/lang/resolve/calls/context/TemporaryResolutionResultsCache.java index ac8b05b7d94..acb0c7230f2 100644 --- a/compiler/frontend/src/org/jetbrains/jet/lang/resolve/calls/context/TemporaryResolutionResultsCache.java +++ b/compiler/frontend/src/org/jetbrains/jet/lang/resolve/calls/context/TemporaryResolutionResultsCache.java @@ -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 void recordResolutionResults( - @NotNull CallKey callKey, + @NotNull Call call, @NotNull OverloadResolutionResultsImpl results ) { - innerCache.recordResolutionResults(callKey, results); + innerCache.recordResolutionResults(call, results); } @Nullable @Override public OverloadResolutionResultsImpl getResolutionResults( - @NotNull CallKey callKey + @NotNull Call call ) { - OverloadResolutionResultsImpl results = innerCache.getResolutionResults(callKey); + OverloadResolutionResultsImpl 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 void recordDeferredComputationForCall( - @NotNull CallKey callKey, + @NotNull Call call, @NotNull CallCandidateResolutionContext 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() { diff --git a/compiler/frontend/src/org/jetbrains/jet/lang/types/expressions/ExpressionTypingUtils.java b/compiler/frontend/src/org/jetbrains/jet/lang/types/expressions/ExpressionTypingUtils.java index ee3202b6044..cc9a520d5ac 100644 --- a/compiler/frontend/src/org/jetbrains/jet/lang/types/expressions/ExpressionTypingUtils.java +++ b/compiler/frontend/src/org/jetbrains/jet/lang/types/expressions/ExpressionTypingUtils.java @@ -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; + } }