private <D extends CallableDescriptor, F extends D> OverloadResolutionResultsImpl<F> doResolveCallOrGetCachedResults( @NotNull ResolutionResultsCache.MemberType<F> memberType, @NotNull BasicCallResolutionContext context, @NotNull List<ResolutionTask<D, F>> prioritizedTasks, @NotNull CallTransformer<D, F> callTransformer, @NotNull JetReferenceExpression reference) { OverloadResolutionResultsImpl<F> results = null; TracingStrategy tracing = prioritizedTasks.isEmpty() ? TracingStrategy.EMPTY : prioritizedTasks.iterator().next().tracing; 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, memberType); if (cachedResults != null) { DelegatingBindingTrace deltasTraceForResolve = context.resolutionResultsCache.getResolutionTrace(callKey); assert deltasTraceForResolve != null; deltasTraceForResolve.addAllMyDataTo(traceToResolveCall); results = cachedResults; } } if (results == null) { BasicCallResolutionContext newContext = context.replaceBindingTrace(traceToResolveCall); results = doResolveCall(newContext, prioritizedTasks, callTransformer, reference); DelegatingBindingTrace deltasTraceForTypeInference = ((OverloadResolutionResultsImpl) results).getTrace(); if (deltasTraceForTypeInference != null) { deltasTraceForTypeInference.addAllMyDataTo(traceToResolveCall); } completeTypeInferenceDependentOnFunctionLiterals(newContext, results, tracing); cacheResults(memberType, context, results, traceToResolveCall, tracing); } traceToResolveCall.commit(); if (!prioritizedTasks.isEmpty() && context.contextDependency == ContextDependency.INDEPENDENT) { results = completeTypeInferenceDependentOnExpectedType(context, results, tracing); } if (extension != null) { extension.run(results, context); } return results; }
@NotNull private <D extends CallableDescriptor, F extends D> OverloadResolutionResultsImpl<F> performResolutionGuardedForExtraFunctionLiteralArguments( @NotNull ResolutionTask<D, F> task, @NotNull CallTransformer<D, F> callTransformer) { OverloadResolutionResultsImpl<F> results = performResolution(task, callTransformer); // If resolution fails, we should check for some of the following situations: // class A { // val foo = Bar() // The following is intended to be an anonymous initializer, // // but is treated as a function literal argument // { // ... // } // } // // fun foo() { // bar { // buzz() // {...} // intended to be a returned from the outer literal // } // } ImmutableSet<OverloadResolutionResults.Code> someFailed = ImmutableSet.of(MANY_FAILED_CANDIDATES, SINGLE_CANDIDATE_ARGUMENT_MISMATCH); if (someFailed.contains(results.getResultCode()) && !task.call.getFunctionLiteralArguments().isEmpty() && task.contextDependency == ContextDependency.INDEPENDENT) { // For nested calls there are no such cases // We have some candidates that failed for some reason // And we have a suspect: the function literal argument // Now, we try to remove this argument and see if it helps DelegatingCall callWithoutFLArgs = new DelegatingCall(task.call) { @NotNull @Override public List<JetExpression> getFunctionLiteralArguments() { return Collections.emptyList(); } }; TemporaryBindingTrace temporaryTrace = TemporaryBindingTrace.create( task.trace, "trace for resolution guarded for extra function literal arguments"); ResolutionTask<D, F> newTask = task.replaceBindingTrace(temporaryTrace).replaceCall(callWithoutFLArgs); OverloadResolutionResultsImpl<F> resultsWithFunctionLiteralsStripped = performResolution(newTask, callTransformer); if (resultsWithFunctionLiteralsStripped.isSuccess() || resultsWithFunctionLiteralsStripped.isAmbiguity()) { task.tracing.danglingFunctionLiteralArgumentSuspected( task.trace, task.call.getFunctionLiteralArguments()); } } return results; }
@NotNull private <D extends CallableDescriptor, F extends D> OverloadResolutionResultsImpl<F> performResolution( @NotNull ResolutionTask<D, F> task, @NotNull CallTransformer<D, F> callTransformer) { for (ResolutionCandidate<D> resolutionCandidate : task.getCandidates()) { TemporaryBindingTrace candidateTrace = TemporaryBindingTrace.create(task.trace, "trace to resolve candidate"); Collection<CallCandidateResolutionContext<D>> contexts = callTransformer.createCallContexts(resolutionCandidate, task, candidateTrace); for (CallCandidateResolutionContext<D> context : contexts) { candidateResolver.performResolutionForCandidateCall(context, task); /* important for 'variable as function case': temporary bind reference to descriptor (will be rewritten) to have a binding to variable while 'invoke' call resolve */ task.tracing.bindReference(context.candidateCall.getTrace(), context.candidateCall); Collection<ResolvedCallWithTrace<F>> calls = callTransformer.transformCall(context, this, task); for (ResolvedCallWithTrace<F> call : calls) { task.tracing.bindReference(call.getTrace(), call); task.tracing.bindResolvedCall(call.getTrace(), call); task.getResolvedCalls().add(call); } } } OverloadResolutionResultsImpl<F> results = ResolutionResultsHandler.INSTANCE.computeResultAndReportErrors( task.trace, task.tracing, task.getResolvedCalls()); if (!results.isSingleResult() && !results.isIncomplete()) { argumentTypeResolver.checkTypesWithNoCallee(task.toBasic()); } return results; }
@NotNull private <D extends CallableDescriptor, F extends D> OverloadResolutionResultsImpl<F> doResolveCall( @NotNull BasicCallResolutionContext context, @NotNull List<ResolutionTask<D, F>> prioritizedTasks, // high to low priority @NotNull CallTransformer<D, F> callTransformer, @NotNull JetReferenceExpression reference) { ResolutionDebugInfo.Data debugInfo = ResolutionDebugInfo.create(); context.trace.record( ResolutionDebugInfo.RESOLUTION_DEBUG_INFO, context.call.getCallElement(), debugInfo); context.trace.record(RESOLUTION_SCOPE, context.call.getCalleeExpression(), context.scope); if (context.dataFlowInfo.hasTypeInfoConstraints()) { context.trace.record( NON_DEFAULT_EXPRESSION_DATA_FLOW, context.call.getCalleeExpression(), context.dataFlowInfo); } debugInfo.set(ResolutionDebugInfo.TASKS, prioritizedTasks); if (context.checkArguments == CheckValueArgumentsMode.ENABLED) { argumentTypeResolver.analyzeArgumentsAndRecordTypes(context); } TemporaryBindingTrace traceForFirstNonemptyCandidateSet = null; OverloadResolutionResultsImpl<F> resultsForFirstNonemptyCandidateSet = null; for (ResolutionTask<D, F> task : prioritizedTasks) { TemporaryBindingTrace taskTrace = TemporaryBindingTrace.create( context.trace, "trace to resolve a task for", task.reference); OverloadResolutionResultsImpl<F> results = performResolutionGuardedForExtraFunctionLiteralArguments( task.replaceBindingTrace(taskTrace), callTransformer); if (results.isSuccess() || results.isAmbiguity()) { taskTrace.commit(); if (results.isSuccess()) { debugInfo.set(ResolutionDebugInfo.RESULT, results.getResultingCall()); } resolveFunctionArguments(context, results); return results; } if (results.getResultCode() == INCOMPLETE_TYPE_INFERENCE) { results.setTrace(taskTrace); return results; } boolean updateResults = traceForFirstNonemptyCandidateSet == null || (resultsForFirstNonemptyCandidateSet.getResultCode() == CANDIDATES_WITH_WRONG_RECEIVER && results.getResultCode() != CANDIDATES_WITH_WRONG_RECEIVER); if (!task.getCandidates().isEmpty() && !results.isNothing() && updateResults) { traceForFirstNonemptyCandidateSet = taskTrace; resultsForFirstNonemptyCandidateSet = results; } } if (traceForFirstNonemptyCandidateSet != null) { traceForFirstNonemptyCandidateSet.commit(); if (resultsForFirstNonemptyCandidateSet.isSingleResult()) { debugInfo.set( ResolutionDebugInfo.RESULT, resultsForFirstNonemptyCandidateSet.getResultingCall()); } resolveFunctionArguments(context, resultsForFirstNonemptyCandidateSet); } else { context.trace.report(UNRESOLVED_REFERENCE.on(reference, reference)); argumentTypeResolver.checkTypesWithNoCallee(context, RESOLVE_FUNCTION_ARGUMENTS); } return resultsForFirstNonemptyCandidateSet != null ? resultsForFirstNonemptyCandidateSet : OverloadResolutionResultsImpl.<F>nameNotFound(); }