From 11fbe375fa4ed41592b1dfc9797395226d28e0d0 Mon Sep 17 00:00:00 2001 From: Svetlana Isakova Date: Tue, 20 May 2014 18:42:10 +0400 Subject: [PATCH] Logic of completing call rewritten in CallCompleter Changed interface ResolutionResultsCache --- .../resolve/calls/ArgumentTypeResolver.java | 14 +- .../jet/lang/resolve/calls/CallCompleter.kt | 275 +++++++++++++++ .../jet/lang/resolve/calls/CallResolver.java | 53 +-- .../lang/resolve/calls/CandidateResolver.java | 319 +----------------- .../calls/context/ResolutionResultsCache.java | 45 --- .../calls/context/ResolutionResultsCache.kt | 88 +++++ .../context/ResolutionResultsCacheImpl.kt | 66 ---- .../TemporaryResolutionResultsCache.java | 100 ------ .../resolve/calls/model/ResolvedCallImpl.java | 9 + .../calls/tasks/TracingStrategyForInvoke.java | 7 + .../lang/resolve/calls/util/CallMaker.java | 19 +- .../ControlStructureTypingUtils.java | 2 +- .../lang/types/expressions/DataFlowUtils.java | 1 + .../extensionMemberInClassObject.kt | 4 +- 14 files changed, 419 insertions(+), 583 deletions(-) delete mode 100644 compiler/frontend/src/org/jetbrains/jet/lang/resolve/calls/context/ResolutionResultsCache.java create mode 100644 compiler/frontend/src/org/jetbrains/jet/lang/resolve/calls/context/ResolutionResultsCache.kt delete mode 100644 compiler/frontend/src/org/jetbrains/jet/lang/resolve/calls/context/ResolutionResultsCacheImpl.kt delete mode 100644 compiler/frontend/src/org/jetbrains/jet/lang/resolve/calls/context/TemporaryResolutionResultsCache.java diff --git a/compiler/frontend/src/org/jetbrains/jet/lang/resolve/calls/ArgumentTypeResolver.java b/compiler/frontend/src/org/jetbrains/jet/lang/resolve/calls/ArgumentTypeResolver.java index 3eba4a8a729..4bf742e62d6 100644 --- a/compiler/frontend/src/org/jetbrains/jet/lang/resolve/calls/ArgumentTypeResolver.java +++ b/compiler/frontend/src/org/jetbrains/jet/lang/resolve/calls/ArgumentTypeResolver.java @@ -48,6 +48,7 @@ import static org.jetbrains.jet.lang.resolve.calls.CallResolverUtil.ResolveArgum import static org.jetbrains.jet.lang.resolve.calls.CallResolverUtil.ResolveArgumentsMode.RESOLVE_FUNCTION_ARGUMENTS; import static org.jetbrains.jet.lang.resolve.calls.CallResolverUtil.ResolveArgumentsMode.SHAPE_FUNCTION_ARGUMENTS; import static org.jetbrains.jet.lang.resolve.calls.context.ContextDependency.DEPENDENT; +import static org.jetbrains.jet.lang.resolve.calls.context.ContextDependency.INDEPENDENT; import static org.jetbrains.jet.lang.types.TypeUtils.*; public class ArgumentTypeResolver { @@ -125,15 +126,6 @@ public class ArgumentTypeResolver { } } - public void checkUnmappedArgumentTypes(CallResolutionContext context, Set unmappedArguments) { - for (ValueArgument valueArgument : unmappedArguments) { - JetExpression argumentExpression = valueArgument.getArgumentExpression(); - if (argumentExpression != null) { - checkArgumentTypeWithNoCallee(context, argumentExpression); - } - } - } - private void checkArgumentTypeWithNoCallee(CallResolutionContext context, JetExpression argumentExpression) { expressionTypingServices.getTypeInfo(argumentExpression, context.replaceExpectedType(NO_EXPECTED_TYPE)); updateResultArgumentTypeIfNotDenotable(context, argumentExpression); @@ -201,7 +193,7 @@ public class ArgumentTypeResolver { JetType type = getShapeTypeOfFunctionLiteral(functionLiteralExpression, context.scope, context.trace, true); return JetTypeInfo.create(type, context.dataFlowInfo); } - return expressionTypingServices.getTypeInfo(expression, context); + return expressionTypingServices.getTypeInfo(expression, context.replaceContextDependency(INDEPENDENT)); } @Nullable @@ -260,7 +252,7 @@ public class ArgumentTypeResolver { } @Nullable - public static JetType updateResultArgumentTypeIfNotDenotable( + public static JetType updateResultArgumentTypeIfNotDenotable( @NotNull ResolutionContext context, @NotNull JetExpression expression ) { diff --git a/compiler/frontend/src/org/jetbrains/jet/lang/resolve/calls/CallCompleter.kt b/compiler/frontend/src/org/jetbrains/jet/lang/resolve/calls/CallCompleter.kt index efef044e57f..f6a8c1224ae 100644 --- a/compiler/frontend/src/org/jetbrains/jet/lang/resolve/calls/CallCompleter.kt +++ b/compiler/frontend/src/org/jetbrains/jet/lang/resolve/calls/CallCompleter.kt @@ -18,9 +18,284 @@ package org.jetbrains.jet.lang.resolve.calls import javax.inject.Inject import kotlin.properties.Delegates +import java.util.ArrayList +import org.jetbrains.jet.lang.descriptors.CallableDescriptor +import org.jetbrains.jet.lang.resolve.calls.context.BasicCallResolutionContext +import org.jetbrains.jet.lang.resolve.calls.results.OverloadResolutionResultsImpl +import org.jetbrains.jet.lang.resolve.calls.tasks.TracingStrategy +import org.jetbrains.jet.lang.resolve.calls.context.CheckValueArgumentsMode +import org.jetbrains.jet.lang.resolve.calls.model.MutableResolvedCall +import org.jetbrains.jet.lang.types.JetType +import org.jetbrains.jet.lang.resolve.BindingTrace +import org.jetbrains.jet.lang.resolve.calls.inference.ConstraintSystem +import org.jetbrains.jet.lang.resolve.calls.inference.ConstraintPosition.EXPECTED_TYPE_POSITION +import org.jetbrains.jet.lang.types.TypeUtils +import org.jetbrains.jet.lang.types.lang.KotlinBuiltIns +import org.jetbrains.jet.lang.resolve.BindingContext.CONSTRAINT_SYSTEM_COMPLETER +import org.jetbrains.jet.lang.resolve.calls.inference.ConstraintPosition +import org.jetbrains.jet.lang.resolve.calls.inference.ConstraintSystemImpl +import org.jetbrains.jet.lang.resolve.calls.context.CallCandidateResolutionContext +import org.jetbrains.jet.lang.resolve.calls.results.ResolutionStatus +import org.jetbrains.jet.lang.resolve.calls.inference.InferenceErrorData +import org.jetbrains.jet.lang.psi.ValueArgument +import org.jetbrains.jet.lang.resolve.calls.model.ArgumentMapping +import org.jetbrains.jet.lang.resolve.calls.autocasts.DataFlowInfo +import org.jetbrains.jet.lang.resolve.calls.model.ArgumentUnmapped +import org.jetbrains.jet.lang.resolve.calls.util.CallMaker +import org.jetbrains.jet.lang.resolve.calls.model.ArgumentMatch +import org.jetbrains.jet.lang.psi.JetWhenExpression +import org.jetbrains.jet.lang.resolve.BindingContext +import org.jetbrains.jet.lang.resolve.calls.context.ResolutionContext +import org.jetbrains.jet.lang.resolve.BindingContextUtils +import org.jetbrains.jet.lang.resolve.calls.context.CallResolutionContext +import org.jetbrains.jet.lang.types.expressions.DataFlowUtils +import org.jetbrains.jet.lang.psi.JetExpression +import org.jetbrains.jet.lang.psi.Call +import org.jetbrains.jet.lang.types.expressions.ExpressionTypingUtils +import org.jetbrains.jet.lang.psi.JetBlockExpression +import org.jetbrains.jet.lang.psi.JetPsiUtil +import org.jetbrains.jet.lang.resolve.bindingContextUtil.getCorrespondingCall +import org.jetbrains.jet.lang.psi.JetSafeQualifiedExpression +import org.jetbrains.jet.lang.resolve.calls.CallResolverUtil.ResolveArgumentsMode.RESOLVE_FUNCTION_ARGUMENTS +import org.jetbrains.jet.lang.resolve.TemporaryBindingTrace public class CallCompleter( val argumentTypeResolver: ArgumentTypeResolver, val candidateResolver: CandidateResolver ) { + fun completeCall( + context: BasicCallResolutionContext, + results: OverloadResolutionResultsImpl, + tracing: TracingStrategy + ): OverloadResolutionResultsImpl { + // for the case 'foo(a)' where 'foo' is a variable, the call 'foo.invoke(a)' shouldn't be completed separately, + // it's completed when the outer (variable as function call) is completed + if (CallResolverUtil.isInvokeCallOnVariable(context.call)) return results + + if (results.isSingleResult()) { + completeResolvedCall(results.getResultingCall(), context, tracing) + } + if (context.checkArguments == CheckValueArgumentsMode.ENABLED) { + completeArguments(context, results) + } + + completeAllCandidates(context, results) + if (results.isSingleResult() && results.getResultingCall().getStatus().isSuccess()) { + return results.changeStatusToSuccess() + } + return results + } + + private fun completeAllCandidates( + context: BasicCallResolutionContext, + results: OverloadResolutionResultsImpl + ) { + [suppress("UNCHECKED_CAST")] + val candidates = (if (context.collectAllCandidates) { + results.getAllCandidates()!! + } + else { + results.getResultingCalls() + }) as Collection> + + candidates.filter { resolvedCall -> !resolvedCall.isCompleted() }.forEach { + resolvedCall -> + + val temporaryBindingTrace = TemporaryBindingTrace.create(context.trace, "Trace to complete a candidate that is not a resulting call") + completeResolvedCall(resolvedCall, context.replaceBindingTrace(temporaryBindingTrace), TracingStrategy.EMPTY) + } + } + + private fun completeResolvedCall( + resolvedCall: MutableResolvedCall, + context: BasicCallResolutionContext, + tracing: TracingStrategy + ) { + if (resolvedCall.isCompleted() || resolvedCall.getConstraintSystem() == null) { + resolvedCall.markCallAsCompleted() + return + } + + resolvedCall.completeConstraintSystem(context.expectedType, context.trace) + resolvedCall.updateResolutionStatusFromConstraintSystem(context, tracing) + resolvedCall.markCallAsCompleted() + } + + private fun MutableResolvedCall.completeConstraintSystem( + expectedType: JetType, + trace: BindingTrace + ) { + fun updateSystemIfSuccessful(update: (ConstraintSystem) -> Boolean) { + val copy = getConstraintSystem()!!.copy() + if (update(copy)) { + setConstraintSystem(copy) + } + } + + val returnType = getCandidateDescriptor().getReturnType() + if (returnType != null) { + getConstraintSystem()!!.addSupertypeConstraint(expectedType, returnType, EXPECTED_TYPE_POSITION) + + if (expectedType === TypeUtils.UNIT_EXPECTED_TYPE) { + updateSystemIfSuccessful { + system -> + system.addSupertypeConstraint(KotlinBuiltIns.getInstance().getUnitType(), returnType, EXPECTED_TYPE_POSITION) + system.getStatus().isSuccessful() + } + } + } + + val constraintSystemCompleter = trace[CONSTRAINT_SYSTEM_COMPLETER, getCall().getCalleeExpression()] + if (constraintSystemCompleter != null) { + //todo improve error reporting with errors in constraints from completer + updateSystemIfSuccessful { + system -> + constraintSystemCompleter.completeConstraintSystem(system, this) + !system.getStatus().hasOnlyErrorsFromPosition(ConstraintPosition.FROM_COMPLETER) + } + } + + (getConstraintSystem() as ConstraintSystemImpl).processDeclaredBoundConstraints() + + setResultingSubstitutor(getConstraintSystem()!!.getResultingSubstitutor()) + } + + private fun MutableResolvedCall.updateResolutionStatusFromConstraintSystem( + context: BasicCallResolutionContext, + tracing: TracingStrategy + ) { + val contextWithResolvedCall = CallCandidateResolutionContext.createForCallBeingAnalyzed(this, context, tracing) + val valueArgumentsCheckingResult = candidateResolver.checkAllValueArguments( + contextWithResolvedCall, context.trace, RESOLVE_FUNCTION_ARGUMENTS) + + val status = getStatus() + if (getConstraintSystem()!!.getStatus().isSuccessful()) { + if (status == ResolutionStatus.UNKNOWN_STATUS || status == ResolutionStatus.INCOMPLETE_TYPE_INFERENCE) { + setStatusToSuccess() + } + return + } + + val receiverType = if (getReceiverArgument().exists()) getReceiverArgument().getType() else null + val errorData = InferenceErrorData.create( + getCandidateDescriptor(), getConstraintSystem()!!, valueArgumentsCheckingResult.argumentTypes, + receiverType, context.expectedType) + tracing.typeInferenceFailed(context.trace, errorData) + + addStatus(ResolutionStatus.OTHER_ERROR) + } + + private fun completeArguments( + context: BasicCallResolutionContext, + results: OverloadResolutionResultsImpl + ) { + if (context.checkArguments == CheckValueArgumentsMode.DISABLED) return + + val getArgumentMapping: (ValueArgument) -> ArgumentMapping + val getDataFlowInfoForArgument: (ValueArgument) -> DataFlowInfo + if (results.isSingleResult()) { + val resolvedCall = results.getResultingCall() + getArgumentMapping = { argument -> resolvedCall.getArgumentMapping(argument) } + getDataFlowInfoForArgument = {argument -> resolvedCall.getDataFlowInfoForArguments().getInfo(argument) } + } + else { + getArgumentMapping = { ArgumentUnmapped } + getDataFlowInfoForArgument = { context.dataFlowInfo } + } + + val arguments = ArrayList(context.call.getValueArguments()) + arguments.addAll(context.call.getFunctionLiteralArguments().map { functionLiteral -> CallMaker.makeValueArgument(functionLiteral) }) + + for (valueArgument in arguments) { + val argumentMapping = getArgumentMapping(valueArgument!!) + val expectedType = when (argumentMapping) { + is ArgumentMatch -> CandidateResolver.getEffectiveExpectedType(argumentMapping.valueParameter, valueArgument) + else -> TypeUtils.NO_EXPECTED_TYPE + } + val newContext = context.replaceDataFlowInfo(getDataFlowInfoForArgument(valueArgument)).replaceExpectedType(expectedType) + completeOneArgument(valueArgument, newContext) + } + } + + private fun completeOneArgument( + valueArgument: ValueArgument, + context: BasicCallResolutionContext + ) { + val expression = valueArgument.getArgumentExpression() + if (expression == null) return + + // for the 'in' call 'when (b) { in 1..10 -> true }' 'b' is an argument, but an error shouldn't be generated on it + // todo add special call type for such a case, and check this call type instead + val parent = expression.getParent() + if (parent is JetWhenExpression && expression == parent.getSubjectExpression()) return + + val recordedType = context.trace[BindingContext.EXPRESSION_TYPE, expression] + var updatedType: JetType? = recordedType + + val results = completeCallForArgument(expression, context) + if (results != null && results.isSingleResult()) { + val resolvedCall = results.getResultingCall() + updatedType = if (resolvedCall.hasInferredReturnType()) resolvedCall.getResultingDescriptor()?.getReturnType() else null + } + + // For the cases like 'foo(1)' the type of '1' depends on expected type (it can be Int, Byte, etc.), + // so while the expected type is not known, it's IntegerValueType(1), and should be updated when the expected type is known. + if (recordedType != null && !recordedType.getConstructor().isDenotable()) { + updatedType = ArgumentTypeResolver.updateResultArgumentTypeIfNotDenotable(context as ResolutionContext<*>, expression) + } + + BindingContextUtils.updateRecordedType(updatedType, expression, context.trace, hasNecessarySafeCall(expression, context.trace)) + + // While the expected type is not known, the function literal arguments are not analyzed (to analyze function literal bodies once), + // but they should be analyzed when the expected type is known (during the call completion). + if (ArgumentTypeResolver.isFunctionLiteralArgument(expression)) { + argumentTypeResolver.getFunctionLiteralTypeInfo( + expression, ArgumentTypeResolver.getFunctionLiteralArgument(expression), + context as CallResolutionContext<*>, RESOLVE_FUNCTION_ARGUMENTS) + } + + DataFlowUtils.checkType(updatedType, expression, context as ResolutionContext<*>) + } + + private fun completeCallForArgument( + expression: JetExpression, + context: BasicCallResolutionContext + ): OverloadResolutionResultsImpl<*>? { + val argumentCall = getCallForArgument(expression, context.trace.getBindingContext()) + if (argumentCall == null) return null + + val cachedDataForCall = context.resolutionResultsCache[argumentCall] + if (cachedDataForCall == null) return null + + val (cachedResolutionResults, cachedContext, tracing) = cachedDataForCall + [suppress("UNCHECKED_CAST")] + val cachedResults = cachedResolutionResults as OverloadResolutionResultsImpl + val contextForArgument = cachedContext.replaceBindingTrace(context.trace) + .replaceExpectedType(context.expectedType).replaceCollectAllCandidates(false) + + return completeCall(contextForArgument, cachedResults, tracing) + } + + private fun getCallForArgument(argument: JetExpression?, bindingContext: BindingContext): Call? { + if (!ExpressionTypingUtils.dependsOnExpectedType(argument)) { + return null + } + if (argument is JetBlockExpression) { + val lastStatement = JetPsiUtil.getLastStatementInABlock(argument) + return getCallForArgument(lastStatement as? JetExpression, bindingContext) + } + return argument?.getCorrespondingCall(bindingContext) + } + + private fun hasNecessarySafeCall(expression: JetExpression, trace: BindingTrace): Boolean { + // We are interested in type of the last call: + // 'a.b?.foo()' is safe call, but 'a?.b.foo()' is not. + // Since receiver is 'a.b' and selector is 'foo()', + // we can only check if an expression is safe call. + if (expression !is JetSafeQualifiedExpression) return false + + //If a receiver type is not null, then this safe expression is useless, and we don't need to make the result type nullable. + val expressionType = trace[BindingContext.EXPRESSION_TYPE, expression.getReceiverExpression()] + return expressionType != null && expressionType.isNullable() + } } \ No newline at end of file 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 eb25f862a29..40f0b964d80 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 @@ -339,12 +339,12 @@ public class CallResolver { OverloadResolutionResultsImpl results = null; 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(call); - assert deltasTraceForResolve != null; + ResolutionResultsCache.CachedData data = context.resolutionResultsCache.get(call); + if (data != null) { + DelegatingBindingTrace deltasTraceForResolve = data.getResolutionTrace(); deltasTraceForResolve.addAllMyDataTo(traceToResolveCall); - results = cachedResults; + //noinspection unchecked + results = (OverloadResolutionResultsImpl) data.getResolutionResults(); } } if (results == null) { @@ -360,7 +360,7 @@ public class CallResolver { traceToResolveCall.commit(); if (context.contextDependency == ContextDependency.INDEPENDENT) { - results = completeTypeInferenceDependentOnExpectedType(context, results, tracing); + results = callCompleter.completeCall(context, results, tracing); } if (results.isSingleResult()) { @@ -388,38 +388,6 @@ public class CallResolver { candidateResolver.completeTypeInferenceDependentOnFunctionLiteralsForCall(candidateContext); } - private OverloadResolutionResultsImpl completeTypeInferenceDependentOnExpectedType( - @NotNull BasicCallResolutionContext context, - @NotNull OverloadResolutionResultsImpl results, - @NotNull TracingStrategy tracing - ) { - if (CallResolverUtil.isInvokeCallOnVariable(context.call)) return results; - - if (!results.isSingleResult()) { - argumentTypeResolver.checkTypesForFunctionArgumentsWithNoCallee(context); - candidateResolver.completeNestedCallsForNotResolvedInvocation(context); - candidateResolver.completeTypeInferenceForAllCandidates(context, results); - return results; - } - - MutableResolvedCall resolvedCall = results.getResultingCall(); - - Set unmappedArguments = resolvedCall.getUnmappedArguments(); - argumentTypeResolver.checkUnmappedArgumentTypes(context, unmappedArguments); - candidateResolver.completeUnmappedArguments(context, unmappedArguments); - - CallCandidateResolutionContext callCandidateResolutionContext = - CallCandidateResolutionContext.createForCallBeingAnalyzed(resolvedCall, context, tracing); - candidateResolver.completeTypeInferenceDependentOnExpectedTypeForCall(callCandidateResolutionContext, false); - - candidateResolver.completeTypeInferenceForAllCandidates(context, results); - - if (resolvedCall.getStatus().isSuccess()) { - return results.changeStatusToSuccess(); - } - return results; - } - private static void cacheResults( @NotNull BasicCallResolutionContext context, @NotNull OverloadResolutionResultsImpl results, @@ -433,14 +401,7 @@ public class CallResolver { BindingContext.EMPTY, "delta trace for caching resolve of", context.call); traceToResolveCall.addAllMyDataTo(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(call, contextForCallToCompleteTypeArgumentInference); - } + context.resolutionResultsCache.record(call, results, context, tracing, deltasTraceToCacheResolve); } private OverloadResolutionResultsImpl checkArgumentTypesAndFail(BasicCallResolutionContext context) { 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 acc0e2bfa13..a9a5add62fd 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 @@ -214,303 +214,6 @@ public class CandidateResolver { resolvedCall.setResultingSubstitutor(constraintSystem.getResultingSubstitutor()); } - @Nullable - public JetType completeTypeInferenceDependentOnExpectedTypeForCall( - @NotNull CallCandidateResolutionContext context, - boolean isInnerCall - ) { - MutableResolvedCall resolvedCall = context.candidateCall; - if (resolvedCall.isCompleted()) { - return resolvedCall.getResultingDescriptor().getReturnType(); - } - if (!resolvedCall.hasIncompleteTypeParameters()) { - completeNestedCallsInference(context); - checkValueArgumentTypes(context); - resolvedCall.markCallAsCompleted(); - return resolvedCall.getResultingDescriptor().getReturnType(); - } - - assert resolvedCall.getConstraintSystem() != null; - - JetType unsubstitutedReturnType = resolvedCall.getCandidateDescriptor().getReturnType(); - if (unsubstitutedReturnType != null) { - resolvedCall.getConstraintSystem().addSupertypeConstraint( - context.expectedType, unsubstitutedReturnType, ConstraintPosition.EXPECTED_TYPE_POSITION); - } - - updateSystemWithConstraintSystemCompleter(context, resolvedCall); - - updateSystemIfExpectedTypeIsUnit(context, resolvedCall); - - ((ConstraintSystemImpl)resolvedCall.getConstraintSystem()).processDeclaredBoundConstraints(); - - JetType returnType; - if (!resolvedCall.getConstraintSystem().getStatus().isSuccessful()) { - returnType = reportInferenceError(context); - } - else { - resolvedCall.setResultingSubstitutor(resolvedCall.getConstraintSystem().getResultingSubstitutor()); - - completeNestedCallsInference(context); - // Here we type check the arguments with inferred types expected - checkAllValueArguments(context, context.trace, RESOLVE_FUNCTION_ARGUMENTS); - - resolvedCall.setHasIncompleteTypeParameters(false); - ResolutionStatus status = resolvedCall.getStatus(); - if (status == ResolutionStatus.UNKNOWN_STATUS || status == ResolutionStatus.INCOMPLETE_TYPE_INFERENCE) { - resolvedCall.setStatusToSuccess(); - } - returnType = resolvedCall.getResultingDescriptor().getReturnType(); - if (isInnerCall) { - PsiElement callElement = context.call.getCallElement(); - if (callElement instanceof JetCallExpression) { - DataFlowUtils.checkType(returnType, (JetCallExpression) callElement, context, context.dataFlowInfo); - } - } - } - resolvedCall.markCallAsCompleted(); - return returnType; - } - - private void completeTypeInferenceForAllCandidatesForArgument( - @NotNull CallCandidateResolutionContext context, - @Nullable Call call - ) { - // All candidates for inner calls are not needed, so there is no need to complete them - if (context.collectAllCandidates) return; - - if (call == null) return; - - OverloadResolutionResultsImpl resolutionResults = context.resolutionResultsCache.getResolutionResults(call); - if (resolutionResults == null) return; - - completeTypeInferenceForAllCandidates(context.toBasic(), resolutionResults); - } - - public void completeTypeInferenceForAllCandidates( - @NotNull BasicCallResolutionContext context, - @NotNull OverloadResolutionResultsImpl results - ) { - Collection> candidates; - if (context.collectAllCandidates) { - candidates = results.getAllCandidates(); - assert candidates != null : "Should be guaranteed by collectAllCandidates == true"; - } - else { - candidates = results.getResultingCalls(); - } - for (ResolvedCall resolvedCall : candidates) { - MutableResolvedCall mutableResolvedCall = (MutableResolvedCall) resolvedCall; - if (mutableResolvedCall.isCompleted()) continue; - - TemporaryBindingTrace temporaryBindingTrace = TemporaryBindingTrace.create( - context.trace, "Trace to complete a candidate that is not a resulting call"); - - CallCandidateResolutionContext callCandidateResolutionContext = CallCandidateResolutionContext.createForCallBeingAnalyzed( - mutableResolvedCall, context.replaceBindingTrace(temporaryBindingTrace), TracingStrategy.EMPTY); - - completeTypeInferenceDependentOnExpectedTypeForCall(callCandidateResolutionContext, false); - } - } - - private static void updateSystemWithConstraintSystemCompleter( - @NotNull CallCandidateResolutionContext context, - @NotNull MutableResolvedCall resolvedCall - ) { - ConstraintSystem constraintSystem = resolvedCall.getConstraintSystem(); - assert constraintSystem != null; - ConstraintSystemCompleter constraintSystemCompleter = context.trace.get( - BindingContext.CONSTRAINT_SYSTEM_COMPLETER, context.call.getCalleeExpression()); - if (constraintSystemCompleter == null) return; - - ConstraintSystem copy = constraintSystem.copy(); - - constraintSystemCompleter.completeConstraintSystem(copy, resolvedCall); - - //todo improve error reporting with errors in constraints from completer - if (!copy.getStatus().hasOnlyErrorsFromPosition(ConstraintPosition.FROM_COMPLETER)) { - resolvedCall.setConstraintSystem(copy); - } - } - - private static void updateSystemIfExpectedTypeIsUnit( - @NotNull CallCandidateResolutionContext context, - @NotNull MutableResolvedCall resolvedCall - ) { - ConstraintSystem constraintSystem = resolvedCall.getConstraintSystem(); - assert constraintSystem != null; - JetType returnType = resolvedCall.getCandidateDescriptor().getReturnType(); - if (returnType == null) return; - - if (!constraintSystem.getStatus().isSuccessful() && context.expectedType == TypeUtils.UNIT_EXPECTED_TYPE) { - ConstraintSystemImpl copy = (ConstraintSystemImpl) constraintSystem.copy(); - - copy.addSupertypeConstraint(KotlinBuiltIns.getInstance().getUnitType(), returnType, ConstraintPosition.EXPECTED_TYPE_POSITION); - if (copy.getStatus().isSuccessful()) { - resolvedCall.setConstraintSystem(copy); - } - } - } - - private JetType reportInferenceError( - @NotNull CallCandidateResolutionContext context - ) { - MutableResolvedCall resolvedCall = context.candidateCall; - ConstraintSystem constraintSystem = resolvedCall.getConstraintSystem(); - assert constraintSystem != null; - - resolvedCall.setResultingSubstitutor(constraintSystem.getResultingSubstitutor()); - completeNestedCallsInference(context); - List argumentTypes = checkValueArgumentTypes( - context, resolvedCall, context.trace, RESOLVE_FUNCTION_ARGUMENTS).argumentTypes; - JetType receiverType = resolvedCall.getReceiverArgument().exists() ? resolvedCall.getReceiverArgument().getType() : null; - InferenceErrorData errorData = InferenceErrorData - .create(resolvedCall.getCandidateDescriptor(), constraintSystem, argumentTypes, receiverType, context.expectedType); - - context.tracing.typeInferenceFailed(context.trace, errorData); - resolvedCall.addStatus(ResolutionStatus.OTHER_ERROR); - if (!resolvedCall.hasInferredReturnType()) return null; - return resolvedCall.getResultingDescriptor().getReturnType(); - } - - public void completeNestedCallsInference( - @NotNull CallCandidateResolutionContext context - ) { - if (CallResolverUtil.isInvokeCallOnVariable(context.call)) return; - MutableResolvedCall resolvedCall = context.candidateCall; - for (Map.Entry entry : resolvedCall.getValueArguments().entrySet()) { - ValueParameterDescriptor parameterDescriptor = entry.getKey(); - ResolvedValueArgument resolvedArgument = entry.getValue(); - - for (ValueArgument argument : resolvedArgument.getArguments()) { - completeInferenceForArgument(argument, parameterDescriptor, context); - } - } - completeUnmappedArguments(context, context.candidateCall.getUnmappedArguments()); - 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, - @NotNull CallCandidateResolutionContext context - ) { - JetExpression expression = argument.getArgumentExpression(); - if (expression == null) return; - - JetType expectedType = getEffectiveExpectedType(parameterDescriptor, argument); - context = context.replaceExpectedType(expectedType); - - 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() - || (expression instanceof JetFunctionLiteralExpression)) { - return; - } - if (storedContextForArgument == null) { - JetType type = ArgumentTypeResolver.updateResultArgumentTypeIfNotDenotable(context, expression); - checkResultArgumentType(type, argument, context); - completeTypeInferenceForAllCandidatesForArgument(context, call); - return; - } - - CallCandidateResolutionContext contextForArgument = storedContextForArgument - .replaceContextDependency(INDEPENDENT).replaceBindingTrace(context.trace).replaceExpectedType(expectedType); - JetType type = completeTypeInferenceDependentOnExpectedTypeForCall(contextForArgument, true); - JetType recordedType = context.trace.get(BindingContext.EXPRESSION_TYPE, expression); - if (recordedType != null && !recordedType.getConstructor().isDenotable()) { - type = ArgumentTypeResolver.updateResultArgumentTypeIfNotDenotable(context, expression); - } - - JetType result = BindingContextUtils.updateRecordedType( - type, expression, context.trace, isFairSafeCallExpression(expression, context.trace)); - - completeTypeInferenceForAllCandidatesForArgument(context, call); - - DataFlowUtils.checkType(result, expression, contextForArgument); - } - - public void completeNestedCallsForNotResolvedInvocation(@NotNull CallResolutionContext context) { - completeNestedCallsForNotResolvedInvocation(context, context.call.getValueArguments()); - } - - public void completeUnmappedArguments(@NotNull CallResolutionContext context, @NotNull Collection unmappedArguments) { - completeNestedCallsForNotResolvedInvocation(context, unmappedArguments); - } - - private void completeNestedCallsForNotResolvedInvocation(@NotNull CallResolutionContext context, @NotNull Collection arguments) { - if (CallResolverUtil.isInvokeCallOnVariable(context.call)) return; - if (context.checkArguments == CheckValueArgumentsMode.DISABLED) return; - - for (ValueArgument argument : arguments) { - JetExpression expression = argument.getArgumentExpression(); - - Call call = getCallForArgument(expression, context.trace.getBindingContext()); - CallCandidateResolutionContext storedContextForArgument = context.resolutionResultsCache.getDeferredComputation(call); - if (storedContextForArgument == null) continue; - if (storedContextForArgument.candidateCall.isCompleted()) continue; - - CallCandidateResolutionContext newContext = - storedContextForArgument.replaceBindingTrace(context.trace).replaceContextDependency(INDEPENDENT); - completeTypeInferenceDependentOnExpectedTypeForCall(newContext, true); - } - } - - 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. - // Since receiver is 'a.b' and selector is 'foo()', - // we can only check if an expression is safe call. - if (!(expression instanceof JetSafeQualifiedExpression)) return false; - - JetSafeQualifiedExpression safeQualifiedExpression = (JetSafeQualifiedExpression) expression; - //If a receiver type is not null, then this safe expression is useless, and we don't need to make the result type nullable. - JetType type = trace.get(BindingContext.EXPRESSION_TYPE, safeQualifiedExpression.getReceiverExpression()); - return type != null && type.isNullable(); - } - - private static void checkResultArgumentType( - @Nullable JetType type, - @NotNull ValueArgument argument, - @NotNull CallCandidateResolutionContext context - ) { - JetExpression expression = argument.getArgumentExpression(); - if (expression == null) return; - - DataFlowInfo dataFlowInfoForValueArgument = context.candidateCall.getDataFlowInfoForArguments().getInfo(argument); - ResolutionContext newContext = context.replaceExpectedType(context.expectedType).replaceDataFlowInfo( - dataFlowInfoForValueArgument); - DataFlowUtils.checkType(type, expression, newContext); - } - - private static void recordReferenceForInvokeFunction(CallCandidateResolutionContext context) { - PsiElement callElement = context.call.getCallElement(); - if (!(callElement instanceof JetCallExpression)) return; - - JetCallExpression callExpression = (JetCallExpression) callElement; - if (BindingContextUtils.isCallExpressionWithValidReference(callExpression, context.trace.getBindingContext())) { - CallableDescriptor resultingDescriptor = context.candidateCall.getResultingDescriptor(); - context.trace.record(BindingContext.EXPRESSION_TYPE, callExpression, resultingDescriptor.getReturnType()); - context.trace.record(BindingContext.REFERENCE_TARGET, callExpression, context.candidateCall.getCandidateDescriptor()); - } - } - private void addConstraintForFunctionLiteral( @NotNull ValueArgument valueArgument, @NotNull ValueParameterDescriptor valueParameterDescriptor, @@ -647,9 +350,7 @@ public class CandidateResolver { if (!hasContradiction) { return INCOMPLETE_TYPE_INFERENCE; } - ValueArgumentsCheckingResult checkingResult = checkAllValueArguments(context, SHAPE_FUNCTION_ARGUMENTS); - ResolutionStatus argumentsStatus = checkingResult.status; - return OTHER_ERROR.combine(argumentsStatus); + return OTHER_ERROR; } private void addConstraintForValueArgument( @@ -699,13 +400,15 @@ public class CandidateResolver { return TypeUtils.intersect(JetTypeChecker.DEFAULT, possibleTypes); } + @NotNull private ValueArgumentsCheckingResult checkAllValueArguments( @NotNull CallCandidateResolutionContext context, @NotNull CallResolverUtil.ResolveArgumentsMode resolveFunctionArgumentBodies) { return checkAllValueArguments(context, context.candidateCall.getTrace(), resolveFunctionArgumentBodies); } - private ValueArgumentsCheckingResult checkAllValueArguments( + @NotNull + public ValueArgumentsCheckingResult checkAllValueArguments( @NotNull CallCandidateResolutionContext context, @NotNull BindingTrace trace, @NotNull CallResolverUtil.ResolveArgumentsMode resolveFunctionArgumentBodies @@ -746,12 +449,7 @@ public class CandidateResolver { return resultStatus; } - public ValueArgumentsCheckingResult checkValueArgumentTypes( - @NotNull CallCandidateResolutionContext context - ) { - return checkValueArgumentTypes(context, context.candidateCall, context.trace, RESOLVE_FUNCTION_ARGUMENTS); - } - + @NotNull private > ValueArgumentsCheckingResult checkValueArgumentTypes( @NotNull CallResolutionContext context, @NotNull MutableResolvedCall candidateCall, @@ -903,9 +601,10 @@ public class CandidateResolver { return SUCCESS; } - private static class ValueArgumentsCheckingResult { - + public static class ValueArgumentsCheckingResult { + @NotNull public final List argumentTypes; + @NotNull public final ResolutionStatus status; private ValueArgumentsCheckingResult(@NotNull ResolutionStatus status, @NotNull List argumentTypes) { @@ -915,7 +614,7 @@ public class CandidateResolver { } @NotNull - private static JetType getEffectiveExpectedType(ValueParameterDescriptor parameterDescriptor, ValueArgument argument) { + public static JetType getEffectiveExpectedType(ValueParameterDescriptor parameterDescriptor, ValueArgument argument) { if (argument.getSpreadElement() != null) { if (parameterDescriptor.getVarargElementType() == null) { // Spread argument passed to a non-vararg parameter, an error is already reported by ValueArgumentsToParametersMapper 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 deleted file mode 100644 index 7a243378568..00000000000 --- a/compiler/frontend/src/org/jetbrains/jet/lang/resolve/calls/context/ResolutionResultsCache.java +++ /dev/null @@ -1,45 +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.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.Call; -import org.jetbrains.jet.lang.resolve.DelegatingBindingTrace; -import org.jetbrains.jet.lang.resolve.calls.results.OverloadResolutionResultsImpl; - -public interface ResolutionResultsCache { - - void recordResolutionResults(@NotNull Call call, @NotNull OverloadResolutionResultsImpl results); - - @Nullable - OverloadResolutionResultsImpl getResolutionResults(@NotNull Call call); - - void recordResolutionTrace(@NotNull Call call, @NotNull DelegatingBindingTrace delegatingTrace); - - @Nullable - DelegatingBindingTrace getResolutionTrace(@NotNull Call call); - - void recordDeferredComputationForCall( - @NotNull Call call, - @NotNull CallCandidateResolutionContext deferredComputation - ); - - @Nullable - CallCandidateResolutionContext getDeferredComputation(@Nullable Call call); -} diff --git a/compiler/frontend/src/org/jetbrains/jet/lang/resolve/calls/context/ResolutionResultsCache.kt b/compiler/frontend/src/org/jetbrains/jet/lang/resolve/calls/context/ResolutionResultsCache.kt new file mode 100644 index 00000000000..c638e2cbcf1 --- /dev/null +++ b/compiler/frontend/src/org/jetbrains/jet/lang/resolve/calls/context/ResolutionResultsCache.kt @@ -0,0 +1,88 @@ +/* + * Copyright 2010-2014 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.resolve.calls.context + +import org.jetbrains.jet.lang.descriptors.CallableDescriptor +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 +import org.jetbrains.jet.lang.resolve.calls.tasks.TracingStrategy +import org.jetbrains.jet.lang.resolve.calls.context.ResolutionResultsCache.CachedData + +public trait ResolutionResultsCache { + public data class CachedData( + val resolutionResults: OverloadResolutionResultsImpl<*>, + val deferredComputation: BasicCallResolutionContext, + val tracing: TracingStrategy, + val resolutionTrace: DelegatingBindingTrace + ) + + fun record( + call: Call, + results: OverloadResolutionResultsImpl<*>, + deferredComputation: BasicCallResolutionContext, + tracing: TracingStrategy, + resolutionTrace: DelegatingBindingTrace + ) + + fun get(call: Call): CachedData? +} + +class ResolutionResultsCacheImpl : ResolutionResultsCache { + private val data = HashMap() + + override fun record( + call: Call, + results: OverloadResolutionResultsImpl, + deferredComputation: BasicCallResolutionContext, + tracing: TracingStrategy, + resolutionTrace: DelegatingBindingTrace + ) { + data[call] = CachedData(results, deferredComputation, tracing, resolutionTrace) + } + + override fun get(call: Call): CachedData? = data[call] + + fun addData(cache: ResolutionResultsCacheImpl) { + data.putAll(cache.data) + } +} + +public class TemporaryResolutionResultsCache(private val parentCache: ResolutionResultsCache) : ResolutionResultsCache { + private val innerCache = ResolutionResultsCacheImpl() + + override fun record( + call: Call, + results: OverloadResolutionResultsImpl, + deferredComputation: BasicCallResolutionContext, + tracing: TracingStrategy, + resolutionTrace: DelegatingBindingTrace + ) { + innerCache.record(call, results, deferredComputation, tracing, resolutionTrace) + } + + override fun get(call: Call): CachedData? = innerCache[call] ?: parentCache[call] + + public fun commit() { + when (parentCache) { + is ResolutionResultsCacheImpl -> parentCache.addData(innerCache) + is TemporaryResolutionResultsCache -> parentCache.innerCache.addData(innerCache) + } + } +} \ No newline at end of file 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 deleted file mode 100644 index a20ca88218b..00000000000 --- a/compiler/frontend/src/org/jetbrains/jet/lang/resolve/calls/context/ResolutionResultsCacheImpl.kt +++ /dev/null @@ -1,66 +0,0 @@ -/* - * Copyright 2010-2014 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.resolve.calls.context - -import org.jetbrains.jet.lang.descriptors.CallableDescriptor -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 - -class ResolutionResultsCacheImpl : ResolutionResultsCache { - private class CachedData( - var results: OverloadResolutionResultsImpl<*>? = null, - var resolutionTrace: DelegatingBindingTrace? = null, - var deferredComputation: CallCandidateResolutionContext<*>? = null - ) - - private val data = HashMap() - - private fun getOrCreateCachedInfo(call: Call) = data.getOrPut(call, { CachedData() }) - - override fun recordResolutionResults(call: Call, results: OverloadResolutionResultsImpl) { - getOrCreateCachedInfo(call).results = results - } - - override fun getResolutionResults(call: Call): OverloadResolutionResultsImpl? { - return data[call]?.results as OverloadResolutionResultsImpl? - } - - override fun recordResolutionTrace(call: Call, delegatingTrace: DelegatingBindingTrace) { - getOrCreateCachedInfo(call).resolutionTrace = delegatingTrace - } - - override fun getResolutionTrace(call: Call): DelegatingBindingTrace? { - return data[call]?.resolutionTrace - } - - override fun recordDeferredComputationForCall(call: Call, deferredComputation: CallCandidateResolutionContext) { - getOrCreateCachedInfo(call).deferredComputation = deferredComputation - } - - override fun getDeferredComputation(call: Call?): CallCandidateResolutionContext? { - if (call == null) return null - - return data[call]?.deferredComputation - } - - fun addData(cache: ResolutionResultsCacheImpl) { - data.putAll(cache.data) - } -} \ No newline at end of file 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 deleted file mode 100644 index acb0c7230f2..00000000000 --- a/compiler/frontend/src/org/jetbrains/jet/lang/resolve/calls/context/TemporaryResolutionResultsCache.java +++ /dev/null @@ -1,100 +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.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.Call; -import org.jetbrains.jet.lang.resolve.DelegatingBindingTrace; -import org.jetbrains.jet.lang.resolve.calls.results.OverloadResolutionResultsImpl; - -public class TemporaryResolutionResultsCache implements ResolutionResultsCache { - private final ResolutionResultsCache parentCache; - private final ResolutionResultsCacheImpl innerCache; - - public TemporaryResolutionResultsCache(@NotNull ResolutionResultsCache parentCache) { - assert parentCache instanceof ResolutionResultsCacheImpl || parentCache instanceof TemporaryResolutionResultsCache : - "Unsupported parent cache: " + parentCache; - this.parentCache = parentCache; - this.innerCache = new ResolutionResultsCacheImpl(); - } - - @Override - public void recordResolutionResults( - @NotNull Call call, - @NotNull OverloadResolutionResultsImpl results - ) { - innerCache.recordResolutionResults(call, results); - } - - @Nullable - @Override - public OverloadResolutionResultsImpl getResolutionResults( - @NotNull Call call - ) { - OverloadResolutionResultsImpl results = innerCache.getResolutionResults(call); - if (results != null) { - return results; - } - return parentCache.getResolutionResults(call); - } - - @Override - public void recordResolutionTrace( - @NotNull Call call, @NotNull DelegatingBindingTrace delegatingTrace - ) { - innerCache.recordResolutionTrace(call, delegatingTrace); - } - - @Nullable - @Override - public DelegatingBindingTrace getResolutionTrace(@NotNull Call call) { - DelegatingBindingTrace trace = innerCache.getResolutionTrace(call); - if (trace != null) { - return trace; - } - return parentCache.getResolutionTrace(call); - } - - @Override - public void recordDeferredComputationForCall( - @NotNull Call call, - @NotNull CallCandidateResolutionContext deferredComputation - ) { - innerCache.recordDeferredComputationForCall(call, deferredComputation); - } - - @Nullable - @Override - public CallCandidateResolutionContext getDeferredComputation(@Nullable Call call) { - CallCandidateResolutionContext computation = innerCache.getDeferredComputation(call); - if (computation != null) { - return computation; - } - return parentCache.getDeferredComputation(call); - } - - public void commit() { - if (parentCache instanceof ResolutionResultsCacheImpl) { - ((ResolutionResultsCacheImpl) parentCache).addData(innerCache); - return; - } - assert parentCache instanceof TemporaryResolutionResultsCache; - ((TemporaryResolutionResultsCache) parentCache).innerCache.addData(innerCache); - } -} diff --git a/compiler/frontend/src/org/jetbrains/jet/lang/resolve/calls/model/ResolvedCallImpl.java b/compiler/frontend/src/org/jetbrains/jet/lang/resolve/calls/model/ResolvedCallImpl.java index 4be344faa18..b1a9179d775 100644 --- a/compiler/frontend/src/org/jetbrains/jet/lang/resolve/calls/model/ResolvedCallImpl.java +++ b/compiler/frontend/src/org/jetbrains/jet/lang/resolve/calls/model/ResolvedCallImpl.java @@ -192,6 +192,15 @@ public class ResolvedCallImpl implements MutableRe assert substitutedVersion != null : entry.getKey(); valueArguments.put(substitutedVersion, entry.getValue()); } + + Map originalArgumentToParameterMap = Maps.newLinkedHashMap(argumentToParameterMap); + argumentToParameterMap.clear(); + for (Map.Entry entry : originalArgumentToParameterMap.entrySet()) { + ArgumentMatch argumentMatch = entry.getValue(); + ValueParameterDescriptor substitutedVersion = parameterMap.get(argumentMatch.getValueParameter().getOriginal()); + assert substitutedVersion != null : argumentMatch.getValueParameter(); + argumentToParameterMap.put(entry.getKey(), new ArgumentMatch(substitutedVersion, argumentMatch.getHasTypeMismatch())); + } } @Override diff --git a/compiler/frontend/src/org/jetbrains/jet/lang/resolve/calls/tasks/TracingStrategyForInvoke.java b/compiler/frontend/src/org/jetbrains/jet/lang/resolve/calls/tasks/TracingStrategyForInvoke.java index a0e52771b29..48663af04e1 100644 --- a/compiler/frontend/src/org/jetbrains/jet/lang/resolve/calls/tasks/TracingStrategyForInvoke.java +++ b/compiler/frontend/src/org/jetbrains/jet/lang/resolve/calls/tasks/TracingStrategyForInvoke.java @@ -16,11 +16,14 @@ package org.jetbrains.jet.lang.resolve.calls.tasks; +import com.intellij.psi.PsiElement; import org.jetbrains.annotations.NotNull; import org.jetbrains.jet.lang.descriptors.CallableDescriptor; import org.jetbrains.jet.lang.psi.Call; import org.jetbrains.jet.lang.psi.JetExpression; import org.jetbrains.jet.lang.psi.JetSimpleNameExpression; +import org.jetbrains.jet.lang.psi.JetReferenceExpression; +import org.jetbrains.jet.lang.resolve.BindingContext; import org.jetbrains.jet.lang.resolve.BindingTrace; import org.jetbrains.jet.lang.resolve.calls.model.ResolvedCall; import org.jetbrains.jet.lang.types.JetType; @@ -55,6 +58,10 @@ public class TracingStrategyForInvoke extends AbstractTracingStrategy { public void bindReference( @NotNull BindingTrace trace, @NotNull ResolvedCall resolvedCall ) { + PsiElement callElement = call.getCallElement(); + if (callElement instanceof JetReferenceExpression) { + trace.record(BindingContext.REFERENCE_TARGET, (JetReferenceExpression) callElement, resolvedCall.getCandidateDescriptor()); + } } @Override diff --git a/compiler/frontend/src/org/jetbrains/jet/lang/resolve/calls/util/CallMaker.java b/compiler/frontend/src/org/jetbrains/jet/lang/resolve/calls/util/CallMaker.java index b8924a1de5f..4ae7105d09a 100644 --- a/compiler/frontend/src/org/jetbrains/jet/lang/resolve/calls/util/CallMaker.java +++ b/compiler/frontend/src/org/jetbrains/jet/lang/resolve/calls/util/CallMaker.java @@ -18,12 +18,10 @@ package org.jetbrains.jet.lang.resolve.calls.util; import com.google.common.collect.Lists; import com.intellij.lang.ASTNode; -import com.intellij.psi.PsiElement; import com.intellij.psi.impl.source.tree.LeafPsiElement; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; import org.jetbrains.jet.lang.psi.*; -import org.jetbrains.jet.lang.resolve.scopes.receivers.ReceiverValue; import org.jetbrains.jet.lang.psi.Call.CallType; import org.jetbrains.jet.lang.psi.debugText.DebugTextPackage; import org.jetbrains.jet.lang.resolve.scopes.receivers.ReceiverValue; @@ -69,6 +67,23 @@ public class CallMaker { public LeafPsiElement getSpreadElement() { return null; } + + @Override + public boolean equals(Object o) { + if (this == o) return true; + if (o == null || getClass() != o.getClass()) return false; + + ExpressionValueArgument argument = (ExpressionValueArgument) o; + + if (expression != null ? !expression.equals(argument.expression) : argument.expression != null) return false; + + return true; + } + + @Override + public int hashCode() { + return expression != null ? expression.hashCode() : 0; + } } private static class CallImpl implements Call { diff --git a/compiler/frontend/src/org/jetbrains/jet/lang/types/expressions/ControlStructureTypingUtils.java b/compiler/frontend/src/org/jetbrains/jet/lang/types/expressions/ControlStructureTypingUtils.java index 9904fa84267..b3ed5ba3b98 100644 --- a/compiler/frontend/src/org/jetbrains/jet/lang/types/expressions/ControlStructureTypingUtils.java +++ b/compiler/frontend/src/org/jetbrains/jet/lang/types/expressions/ControlStructureTypingUtils.java @@ -163,7 +163,7 @@ public class ControlStructureTypingUtils { ) { final List valueArguments = Lists.newArrayList(); for (JetExpression argument : arguments) { - valueArguments.add(CallMaker.makeValueArgument(argument, argument)); + valueArguments.add(CallMaker.makeValueArgument(argument)); } return new Call() { @Nullable diff --git a/compiler/frontend/src/org/jetbrains/jet/lang/types/expressions/DataFlowUtils.java b/compiler/frontend/src/org/jetbrains/jet/lang/types/expressions/DataFlowUtils.java index d8bf889087c..f88cdcb6c94 100644 --- a/compiler/frontend/src/org/jetbrains/jet/lang/types/expressions/DataFlowUtils.java +++ b/compiler/frontend/src/org/jetbrains/jet/lang/types/expressions/DataFlowUtils.java @@ -41,6 +41,7 @@ import org.jetbrains.jet.lang.types.lang.KotlinBuiltIns; import org.jetbrains.jet.lexer.JetTokens; import static org.jetbrains.jet.lang.diagnostics.Errors.*; +import static org.jetbrains.jet.lang.resolve.calls.context.ContextDependency.DEPENDENT; import static org.jetbrains.jet.lang.resolve.calls.context.ContextDependency.INDEPENDENT; import static org.jetbrains.jet.lang.types.TypeUtils.*; diff --git a/compiler/testData/diagnostics/tests/extensions/extensionMemberInClassObject.kt b/compiler/testData/diagnostics/tests/extensions/extensionMemberInClassObject.kt index ae0f30a4c04..08174cbd6fe 100644 --- a/compiler/testData/diagnostics/tests/extensions/extensionMemberInClassObject.kt +++ b/compiler/testData/diagnostics/tests/extensions/extensionMemberInClassObject.kt @@ -9,9 +9,9 @@ class Foo { } fun main(args: Array) { - with("", { + with("", { Foo.findByName("") - }) + }) } fun with(t: T, f: T.() -> Unit) {} \ No newline at end of file