@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(); }
@NotNull /*package*/ OverloadResolutionResultsImpl<FunctionDescriptor> resolveFunctionCall( @NotNull BasicCallResolutionContext context) { ProgressIndicatorProvider.checkCanceled(); List<ResolutionTask<CallableDescriptor, FunctionDescriptor>> prioritizedTasks; JetExpression calleeExpression = context.call.getCalleeExpression(); JetReferenceExpression functionReference; if (calleeExpression instanceof JetSimpleNameExpression) { JetSimpleNameExpression expression = (JetSimpleNameExpression) calleeExpression; functionReference = expression; ExpressionTypingUtils.checkCapturingInClosure(expression, context.trace, context.scope); Name name = expression.getReferencedNameAsName(); prioritizedTasks = TaskPrioritizer.<CallableDescriptor, FunctionDescriptor>computePrioritizedTasks( context, name, functionReference, CallableDescriptorCollectors.FUNCTIONS_AND_VARIABLES); ResolutionTask.DescriptorCheckStrategy abstractConstructorCheck = new ResolutionTask.DescriptorCheckStrategy() { @Override public <D extends CallableDescriptor> boolean performAdvancedChecks( D descriptor, BindingTrace trace, TracingStrategy tracing) { if (descriptor instanceof ConstructorDescriptor) { Modality modality = ((ConstructorDescriptor) descriptor).getContainingDeclaration().getModality(); if (modality == Modality.ABSTRACT) { tracing.instantiationOfAbstractClass(trace); return false; } } return true; } }; for (ResolutionTask task : prioritizedTasks) { task.setCheckingStrategy(abstractConstructorCheck); } } else { JetValueArgumentList valueArgumentList = context.call.getValueArgumentList(); PsiElement reportAbsenceOn = valueArgumentList == null ? context.call.getCallElement() : valueArgumentList; if (calleeExpression instanceof JetConstructorCalleeExpression) { assert !context.call.getExplicitReceiver().exists(); JetConstructorCalleeExpression expression = (JetConstructorCalleeExpression) calleeExpression; functionReference = expression.getConstructorReferenceExpression(); if (functionReference == null) { return checkArgumentTypesAndFail(context); // No type there } JetTypeReference typeReference = expression.getTypeReference(); assert typeReference != null; JetType constructedType = typeResolver.resolveType(context.scope, typeReference, context.trace, true); if (constructedType.isError()) { return checkArgumentTypesAndFail(context); } DeclarationDescriptor declarationDescriptor = constructedType.getConstructor().getDeclarationDescriptor(); if (declarationDescriptor instanceof ClassDescriptor) { ClassDescriptor classDescriptor = (ClassDescriptor) declarationDescriptor; Collection<ConstructorDescriptor> constructors = classDescriptor.getConstructors(); if (constructors.isEmpty()) { context.trace.report(NO_CONSTRUCTOR.on(reportAbsenceOn)); return checkArgumentTypesAndFail(context); } Collection<ResolutionCandidate<CallableDescriptor>> candidates = TaskPrioritizer.<CallableDescriptor>convertWithImpliedThis( context.scope, Collections.<ReceiverValue>singletonList(NO_RECEIVER), constructors); prioritizedTasks = TaskPrioritizer .<CallableDescriptor, FunctionDescriptor>computePrioritizedTasksFromCandidates( context, functionReference, candidates, null); } else { context.trace.report(NOT_A_CLASS.on(calleeExpression)); return checkArgumentTypesAndFail(context); } } else if (calleeExpression instanceof JetThisReferenceExpression) { functionReference = (JetThisReferenceExpression) calleeExpression; DeclarationDescriptor containingDeclaration = context.scope.getContainingDeclaration(); if (containingDeclaration instanceof ConstructorDescriptor) { containingDeclaration = containingDeclaration.getContainingDeclaration(); } assert containingDeclaration instanceof ClassDescriptor; ClassDescriptor classDescriptor = (ClassDescriptor) containingDeclaration; Collection<ConstructorDescriptor> constructors = classDescriptor.getConstructors(); if (constructors.isEmpty()) { context.trace.report(NO_CONSTRUCTOR.on(reportAbsenceOn)); return checkArgumentTypesAndFail(context); } List<ResolutionCandidate<CallableDescriptor>> candidates = ResolutionCandidate.<CallableDescriptor>convertCollection( constructors, JetPsiUtil.isSafeCall(context.call)); prioritizedTasks = Collections.singletonList( new ResolutionTask<CallableDescriptor, FunctionDescriptor>( candidates, functionReference, context)); // !! DataFlowInfo.EMPTY } else if (calleeExpression != null) { // Here we handle the case where the callee expression must be something of type function, // e.g. (foo.bar())(1, 2) JetType calleeType = expressionTypingServices.safeGetType( context.scope, calleeExpression, NO_EXPECTED_TYPE, context.dataFlowInfo, context .trace); // We are actually expecting a function, but there seems to be no easy // way of expressing this if (!KotlinBuiltIns.getInstance().isFunctionOrExtensionFunctionType(calleeType)) { // checkTypesWithNoCallee(trace, scope, call); if (!calleeType.isError()) { context.trace.report(CALLEE_NOT_A_FUNCTION.on(calleeExpression, calleeType)); } return checkArgumentTypesAndFail(context); } FunctionDescriptorImpl functionDescriptor = new ExpressionAsFunctionDescriptor( context.scope.getContainingDeclaration(), Name.special("<for expression " + calleeExpression.getText() + ">"), calleeExpression); FunctionDescriptorUtil.initializeFromFunctionType( functionDescriptor, calleeType, NO_RECEIVER_PARAMETER, Modality.FINAL, Visibilities.LOCAL); ResolutionCandidate<CallableDescriptor> resolutionCandidate = ResolutionCandidate.<CallableDescriptor>create( functionDescriptor, JetPsiUtil.isSafeCall(context.call)); resolutionCandidate.setReceiverArgument(context.call.getExplicitReceiver()); resolutionCandidate.setExplicitReceiverKind(ExplicitReceiverKind.RECEIVER_ARGUMENT); // strictly speaking, this is a hack: // we need to pass a reference, but there's no reference in the PSI, // so we wrap what we have into a fake reference and pass it on (unwrap on the other end) functionReference = new JetFakeReference(calleeExpression); prioritizedTasks = Collections.singletonList( new ResolutionTask<CallableDescriptor, FunctionDescriptor>( Collections.singleton(resolutionCandidate), functionReference, context)); } else { // checkTypesWithNoCallee(trace, scope, call); return checkArgumentTypesAndFail(context); } } return doResolveCallOrGetCachedResults( ResolutionResultsCache.FUNCTION_MEMBER_TYPE, context, prioritizedTasks, CallTransformer.FUNCTION_CALL_TRANSFORMER, functionReference); }