Remove old resolution algorithm.
This commit is contained in:
@@ -16,12 +16,8 @@
|
|||||||
|
|
||||||
package org.jetbrains.kotlin.resolve.calls;
|
package org.jetbrains.kotlin.resolve.calls;
|
||||||
|
|
||||||
import com.google.common.collect.Lists;
|
|
||||||
import com.intellij.openapi.util.Condition;
|
|
||||||
import com.intellij.psi.PsiElement;
|
import com.intellij.psi.PsiElement;
|
||||||
import com.intellij.util.containers.ContainerUtil;
|
|
||||||
import kotlin.Pair;
|
import kotlin.Pair;
|
||||||
import kotlin.Unit;
|
|
||||||
import kotlin.jvm.functions.Function0;
|
import kotlin.jvm.functions.Function0;
|
||||||
import org.jetbrains.annotations.NotNull;
|
import org.jetbrains.annotations.NotNull;
|
||||||
import org.jetbrains.annotations.Nullable;
|
import org.jetbrains.annotations.Nullable;
|
||||||
@@ -39,14 +35,10 @@ import org.jetbrains.kotlin.resolve.calls.callUtil.CallUtilKt;
|
|||||||
import org.jetbrains.kotlin.resolve.calls.checkers.CallChecker;
|
import org.jetbrains.kotlin.resolve.calls.checkers.CallChecker;
|
||||||
import org.jetbrains.kotlin.resolve.calls.context.*;
|
import org.jetbrains.kotlin.resolve.calls.context.*;
|
||||||
import org.jetbrains.kotlin.resolve.calls.model.MutableDataFlowInfoForArguments;
|
import org.jetbrains.kotlin.resolve.calls.model.MutableDataFlowInfoForArguments;
|
||||||
import org.jetbrains.kotlin.resolve.calls.model.MutableResolvedCall;
|
|
||||||
import org.jetbrains.kotlin.resolve.calls.model.ResolvedCall;
|
|
||||||
import org.jetbrains.kotlin.resolve.calls.results.OverloadResolutionResults;
|
import org.jetbrains.kotlin.resolve.calls.results.OverloadResolutionResults;
|
||||||
import org.jetbrains.kotlin.resolve.calls.results.OverloadResolutionResultsImpl;
|
import org.jetbrains.kotlin.resolve.calls.results.OverloadResolutionResultsImpl;
|
||||||
import org.jetbrains.kotlin.resolve.calls.results.ResolutionResultsHandler;
|
|
||||||
import org.jetbrains.kotlin.resolve.calls.smartcasts.DataFlowInfo;
|
import org.jetbrains.kotlin.resolve.calls.smartcasts.DataFlowInfo;
|
||||||
import org.jetbrains.kotlin.resolve.calls.tasks.*;
|
import org.jetbrains.kotlin.resolve.calls.tasks.*;
|
||||||
import org.jetbrains.kotlin.resolve.calls.tasks.collectors.CallableDescriptorCollectors;
|
|
||||||
import org.jetbrains.kotlin.resolve.calls.tower.NewResolveOldInference;
|
import org.jetbrains.kotlin.resolve.calls.tower.NewResolveOldInference;
|
||||||
import org.jetbrains.kotlin.resolve.calls.util.CallMaker;
|
import org.jetbrains.kotlin.resolve.calls.util.CallMaker;
|
||||||
import org.jetbrains.kotlin.resolve.descriptorUtil.DescriptorUtilsKt;
|
import org.jetbrains.kotlin.resolve.descriptorUtil.DescriptorUtilsKt;
|
||||||
@@ -66,10 +58,6 @@ import java.util.*;
|
|||||||
|
|
||||||
import static org.jetbrains.kotlin.diagnostics.Errors.*;
|
import static org.jetbrains.kotlin.diagnostics.Errors.*;
|
||||||
import static org.jetbrains.kotlin.resolve.calls.callResolverUtil.ResolveArgumentsMode.RESOLVE_FUNCTION_ARGUMENTS;
|
import static org.jetbrains.kotlin.resolve.calls.callResolverUtil.ResolveArgumentsMode.RESOLVE_FUNCTION_ARGUMENTS;
|
||||||
import static org.jetbrains.kotlin.resolve.calls.callResolverUtil.ResolveArgumentsMode.SHAPE_FUNCTION_ARGUMENTS;
|
|
||||||
import static org.jetbrains.kotlin.resolve.calls.context.CandidateResolveMode.EXIT_ON_FIRST_ERROR;
|
|
||||||
import static org.jetbrains.kotlin.resolve.calls.context.CandidateResolveMode.FULLY;
|
|
||||||
import static org.jetbrains.kotlin.resolve.calls.results.OverloadResolutionResults.Code.CANDIDATES_WITH_WRONG_RECEIVER;
|
|
||||||
import static org.jetbrains.kotlin.resolve.calls.results.OverloadResolutionResults.Code.INCOMPLETE_TYPE_INFERENCE;
|
import static org.jetbrains.kotlin.resolve.calls.results.OverloadResolutionResults.Code.INCOMPLETE_TYPE_INFERENCE;
|
||||||
import static org.jetbrains.kotlin.types.TypeUtils.NO_EXPECTED_TYPE;
|
import static org.jetbrains.kotlin.types.TypeUtils.NO_EXPECTED_TYPE;
|
||||||
|
|
||||||
@@ -77,27 +65,19 @@ import static org.jetbrains.kotlin.types.TypeUtils.NO_EXPECTED_TYPE;
|
|||||||
public class CallResolver {
|
public class CallResolver {
|
||||||
private ExpressionTypingServices expressionTypingServices;
|
private ExpressionTypingServices expressionTypingServices;
|
||||||
private TypeResolver typeResolver;
|
private TypeResolver typeResolver;
|
||||||
private CandidateResolver candidateResolver;
|
|
||||||
private ArgumentTypeResolver argumentTypeResolver;
|
private ArgumentTypeResolver argumentTypeResolver;
|
||||||
private GenericCandidateResolver genericCandidateResolver;
|
private GenericCandidateResolver genericCandidateResolver;
|
||||||
private CallCompleter callCompleter;
|
private CallCompleter callCompleter;
|
||||||
private NewResolveOldInference newCallResolver;
|
private NewResolveOldInference newCallResolver;
|
||||||
private final TaskPrioritizer taskPrioritizer;
|
private final KotlinBuiltIns builtIns;
|
||||||
private final ResolutionResultsHandler resolutionResultsHandler;
|
|
||||||
@NotNull private KotlinBuiltIns builtIns;
|
|
||||||
|
|
||||||
private static final PerformanceCounter callResolvePerfCounter = PerformanceCounter.Companion.create("Call resolve", ExpressionTypingVisitorDispatcher.typeInfoPerfCounter);
|
private static final PerformanceCounter callResolvePerfCounter = PerformanceCounter.Companion.create("Call resolve", ExpressionTypingVisitorDispatcher.typeInfoPerfCounter);
|
||||||
private static final PerformanceCounter candidatePerfCounter = PerformanceCounter.Companion.create("Call resolve candidate analysis", true);
|
|
||||||
|
|
||||||
public static boolean useNewResolve = !"false".equals(System.getProperty("kotlin.internal.new_resolve"));
|
public static boolean useNewResolve = !"false".equals(System.getProperty("kotlin.internal.new_resolve"));
|
||||||
|
|
||||||
public CallResolver(
|
public CallResolver(
|
||||||
@NotNull TaskPrioritizer taskPrioritizer,
|
|
||||||
@NotNull ResolutionResultsHandler resolutionResultsHandler,
|
|
||||||
@NotNull KotlinBuiltIns builtIns
|
@NotNull KotlinBuiltIns builtIns
|
||||||
) {
|
) {
|
||||||
this.taskPrioritizer = taskPrioritizer;
|
|
||||||
this.resolutionResultsHandler = resolutionResultsHandler;
|
|
||||||
this.builtIns = builtIns;
|
this.builtIns = builtIns;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -113,12 +93,6 @@ public class CallResolver {
|
|||||||
this.typeResolver = typeResolver;
|
this.typeResolver = typeResolver;
|
||||||
}
|
}
|
||||||
|
|
||||||
// component dependency cycle
|
|
||||||
@Inject
|
|
||||||
public void setCandidateResolver(@NotNull CandidateResolver candidateResolver) {
|
|
||||||
this.candidateResolver = candidateResolver;
|
|
||||||
}
|
|
||||||
|
|
||||||
// component dependency cycle
|
// component dependency cycle
|
||||||
@Inject
|
@Inject
|
||||||
public void setArgumentTypeResolver(@NotNull ArgumentTypeResolver argumentTypeResolver) {
|
public void setArgumentTypeResolver(@NotNull ArgumentTypeResolver argumentTypeResolver) {
|
||||||
@@ -149,10 +123,9 @@ public class CallResolver {
|
|||||||
assert calleeExpression instanceof KtSimpleNameExpression;
|
assert calleeExpression instanceof KtSimpleNameExpression;
|
||||||
KtSimpleNameExpression nameExpression = (KtSimpleNameExpression) calleeExpression;
|
KtSimpleNameExpression nameExpression = (KtSimpleNameExpression) calleeExpression;
|
||||||
Name referencedName = nameExpression.getReferencedNameAsName();
|
Name referencedName = nameExpression.getReferencedNameAsName();
|
||||||
CallableDescriptorCollectors<VariableDescriptor> callableDescriptorCollectors = CallableDescriptorCollectors.VARIABLES;
|
|
||||||
return computeTasksAndResolveCall(
|
return computeTasksAndResolveCall(
|
||||||
context, referencedName, nameExpression,
|
context, referencedName, nameExpression,
|
||||||
callableDescriptorCollectors, CallTransformer.VARIABLE_CALL_TRANSFORMER, ResolveKind.VARIABLE);
|
ResolveKind.VARIABLE);
|
||||||
}
|
}
|
||||||
|
|
||||||
@NotNull
|
@NotNull
|
||||||
@@ -162,7 +135,7 @@ public class CallResolver {
|
|||||||
) {
|
) {
|
||||||
return computeTasksAndResolveCall(
|
return computeTasksAndResolveCall(
|
||||||
context, nameExpression.getReferencedNameAsName(), nameExpression,
|
context, nameExpression.getReferencedNameAsName(), nameExpression,
|
||||||
CallableDescriptorCollectors.FUNCTIONS_AND_VARIABLES, CallTransformer.MEMBER_CALL_TRANSFORMER, ResolveKind.CALLABLE_REFERENCE);
|
ResolveKind.CALLABLE_REFERENCE);
|
||||||
}
|
}
|
||||||
|
|
||||||
@NotNull
|
@NotNull
|
||||||
@@ -175,7 +148,7 @@ public class CallResolver {
|
|||||||
BasicCallResolutionContext callResolutionContext = BasicCallResolutionContext.create(context, call, CheckArgumentTypesMode.CHECK_VALUE_ARGUMENTS);
|
BasicCallResolutionContext callResolutionContext = BasicCallResolutionContext.create(context, call, CheckArgumentTypesMode.CHECK_VALUE_ARGUMENTS);
|
||||||
return computeTasksAndResolveCall(
|
return computeTasksAndResolveCall(
|
||||||
callResolutionContext, name, functionReference,
|
callResolutionContext, name, functionReference,
|
||||||
CallableDescriptorCollectors.FUNCTIONS_AND_VARIABLES, CallTransformer.FUNCTION_CALL_TRANSFORMER, ResolveKind.FUNCTION);
|
ResolveKind.FUNCTION);
|
||||||
}
|
}
|
||||||
|
|
||||||
@NotNull
|
@NotNull
|
||||||
@@ -185,7 +158,6 @@ public class CallResolver {
|
|||||||
) {
|
) {
|
||||||
return computeTasksAndResolveCall(
|
return computeTasksAndResolveCall(
|
||||||
context, OperatorNameConventions.INVOKE, tracing,
|
context, OperatorNameConventions.INVOKE, tracing,
|
||||||
CallableDescriptorCollectors.FUNCTIONS, CallTransformer.FUNCTION_CALL_TRANSFORMER,
|
|
||||||
ResolveKind.INVOKE);
|
ResolveKind.INVOKE);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -194,12 +166,10 @@ public class CallResolver {
|
|||||||
@NotNull BasicCallResolutionContext context,
|
@NotNull BasicCallResolutionContext context,
|
||||||
@NotNull Name name,
|
@NotNull Name name,
|
||||||
@NotNull KtReferenceExpression referenceExpression,
|
@NotNull KtReferenceExpression referenceExpression,
|
||||||
@NotNull CallableDescriptorCollectors<D> collectors,
|
|
||||||
@NotNull CallTransformer<D, F> callTransformer,
|
|
||||||
@NotNull ResolveKind kind
|
@NotNull ResolveKind kind
|
||||||
) {
|
) {
|
||||||
TracingStrategy tracing = TracingStrategyImpl.create(referenceExpression, context.call);
|
TracingStrategy tracing = TracingStrategyImpl.create(referenceExpression, context.call);
|
||||||
return computeTasksAndResolveCall(context, name, tracing, collectors, callTransformer, kind);
|
return computeTasksAndResolveCall(context, name, tracing, kind);
|
||||||
}
|
}
|
||||||
|
|
||||||
@NotNull
|
@NotNull
|
||||||
@@ -207,21 +177,14 @@ public class CallResolver {
|
|||||||
@NotNull final BasicCallResolutionContext context,
|
@NotNull final BasicCallResolutionContext context,
|
||||||
@NotNull final Name name,
|
@NotNull final Name name,
|
||||||
@NotNull final TracingStrategy tracing,
|
@NotNull final TracingStrategy tracing,
|
||||||
@NotNull final CallableDescriptorCollectors<D> collectors,
|
|
||||||
@NotNull final CallTransformer<D, F> callTransformer,
|
|
||||||
@NotNull final ResolveKind kind
|
@NotNull final ResolveKind kind
|
||||||
) {
|
) {
|
||||||
return callResolvePerfCounter.time(new Function0<OverloadResolutionResults<F>>() {
|
return callResolvePerfCounter.time(new Function0<OverloadResolutionResults<F>>() {
|
||||||
@Override
|
@Override
|
||||||
public OverloadResolutionResults<F> invoke() {
|
public OverloadResolutionResults<F> invoke() {
|
||||||
TaskContextForMigration<D, F> contextForMigration = new TaskContextForMigration<D, F>(
|
TaskContextForMigration<D> contextForMigration = new TaskContextForMigration<D>(
|
||||||
kind, callTransformer, name, null,
|
kind, name, null
|
||||||
new Function0<List<ResolutionTask<D, F>>>() {
|
);
|
||||||
@Override
|
|
||||||
public List<ResolutionTask<D, F>> invoke() {
|
|
||||||
return taskPrioritizer.<D, F>computePrioritizedTasks(context, name, tracing, collectors);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
return doResolveCallOrGetCachedResults(context, contextForMigration, tracing);
|
return doResolveCallOrGetCachedResults(context, contextForMigration, tracing);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
@@ -231,10 +194,9 @@ public class CallResolver {
|
|||||||
private <D extends CallableDescriptor, F extends D> OverloadResolutionResults<F> computeTasksFromCandidatesAndResolvedCall(
|
private <D extends CallableDescriptor, F extends D> OverloadResolutionResults<F> computeTasksFromCandidatesAndResolvedCall(
|
||||||
@NotNull BasicCallResolutionContext context,
|
@NotNull BasicCallResolutionContext context,
|
||||||
@NotNull KtReferenceExpression referenceExpression,
|
@NotNull KtReferenceExpression referenceExpression,
|
||||||
@NotNull Collection<ResolutionCandidate<D>> candidates,
|
@NotNull Collection<ResolutionCandidate<D>> candidates
|
||||||
@NotNull CallTransformer<D, F> callTransformer
|
|
||||||
) {
|
) {
|
||||||
return computeTasksFromCandidatesAndResolvedCall(context, candidates, callTransformer,
|
return computeTasksFromCandidatesAndResolvedCall(context, candidates,
|
||||||
TracingStrategyImpl.create(referenceExpression, context.call));
|
TracingStrategyImpl.create(referenceExpression, context.call));
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -242,21 +204,14 @@ public class CallResolver {
|
|||||||
private <D extends CallableDescriptor, F extends D> OverloadResolutionResults<F> computeTasksFromCandidatesAndResolvedCall(
|
private <D extends CallableDescriptor, F extends D> OverloadResolutionResults<F> computeTasksFromCandidatesAndResolvedCall(
|
||||||
@NotNull final BasicCallResolutionContext context,
|
@NotNull final BasicCallResolutionContext context,
|
||||||
@NotNull final Collection<ResolutionCandidate<D>> candidates,
|
@NotNull final Collection<ResolutionCandidate<D>> candidates,
|
||||||
@NotNull final CallTransformer<D, F> callTransformer,
|
|
||||||
@NotNull final TracingStrategy tracing
|
@NotNull final TracingStrategy tracing
|
||||||
) {
|
) {
|
||||||
return callResolvePerfCounter.time(new Function0<OverloadResolutionResults<F>>() {
|
return callResolvePerfCounter.time(new Function0<OverloadResolutionResults<F>>() {
|
||||||
@Override
|
@Override
|
||||||
public OverloadResolutionResults<F> invoke() {
|
public OverloadResolutionResults<F> invoke() {
|
||||||
TaskContextForMigration<D, F> contextForMigration = new TaskContextForMigration<D, F>(
|
TaskContextForMigration<D> contextForMigration = new TaskContextForMigration<D>(
|
||||||
ResolveKind.GIVEN_CANDIDATES, callTransformer, null, candidates,
|
ResolveKind.GIVEN_CANDIDATES, null, candidates
|
||||||
new Function0<List<ResolutionTask<D, F>>>() {
|
);
|
||||||
@Override
|
|
||||||
public List<ResolutionTask<D, F>> invoke() {
|
|
||||||
return taskPrioritizer.<D, F>computePrioritizedTasksFromCandidates(
|
|
||||||
context, candidates, tracing);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
return doResolveCallOrGetCachedResults(context, contextForMigration, tracing);
|
return doResolveCallOrGetCachedResults(context, contextForMigration, tracing);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
@@ -304,8 +259,6 @@ public class CallResolver {
|
|||||||
KtArrayAccessExpression arrayAccessExpression = (KtArrayAccessExpression) context.call.getCallElement();
|
KtArrayAccessExpression arrayAccessExpression = (KtArrayAccessExpression) context.call.getCallElement();
|
||||||
return computeTasksAndResolveCall(
|
return computeTasksAndResolveCall(
|
||||||
context, name, arrayAccessExpression,
|
context, name, arrayAccessExpression,
|
||||||
CallableDescriptorCollectors.FUNCTIONS_AND_VARIABLES,
|
|
||||||
CallTransformer.FUNCTION_CALL_TRANSFORMER,
|
|
||||||
ResolveKind.FUNCTION);
|
ResolveKind.FUNCTION);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -314,7 +267,7 @@ public class CallResolver {
|
|||||||
KtSimpleNameExpression expression = (KtSimpleNameExpression) calleeExpression;
|
KtSimpleNameExpression expression = (KtSimpleNameExpression) calleeExpression;
|
||||||
return computeTasksAndResolveCall(
|
return computeTasksAndResolveCall(
|
||||||
context, expression.getReferencedNameAsName(), expression,
|
context, expression.getReferencedNameAsName(), expression,
|
||||||
CallableDescriptorCollectors.FUNCTIONS_AND_VARIABLES, CallTransformer.FUNCTION_CALL_TRANSFORMER, ResolveKind.FUNCTION);
|
ResolveKind.FUNCTION);
|
||||||
}
|
}
|
||||||
else if (calleeExpression instanceof KtConstructorCalleeExpression) {
|
else if (calleeExpression instanceof KtConstructorCalleeExpression) {
|
||||||
return resolveCallForConstructor(context, (KtConstructorCalleeExpression) calleeExpression);
|
return resolveCallForConstructor(context, (KtConstructorCalleeExpression) calleeExpression);
|
||||||
@@ -388,7 +341,7 @@ public class CallResolver {
|
|||||||
Collection<ResolutionCandidate<CallableDescriptor>> candidates = candidatesAndContext.getFirst();
|
Collection<ResolutionCandidate<CallableDescriptor>> candidates = candidatesAndContext.getFirst();
|
||||||
context = candidatesAndContext.getSecond();
|
context = candidatesAndContext.getSecond();
|
||||||
|
|
||||||
return computeTasksFromCandidatesAndResolvedCall(context, functionReference, candidates, CallTransformer.FUNCTION_CALL_TRANSFORMER);
|
return computeTasksFromCandidatesAndResolvedCall(context, functionReference, candidates);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Nullable
|
@Nullable
|
||||||
@@ -479,7 +432,7 @@ public class CallResolver {
|
|||||||
return checkArgumentTypesAndFail(context);
|
return checkArgumentTypesAndFail(context);
|
||||||
}
|
}
|
||||||
|
|
||||||
return computeTasksFromCandidatesAndResolvedCall(context, candidates, CallTransformer.FUNCTION_CALL_TRANSFORMER, tracing);
|
return computeTasksFromCandidatesAndResolvedCall(context, candidates, tracing);
|
||||||
}
|
}
|
||||||
|
|
||||||
@NotNull
|
@NotNull
|
||||||
@@ -529,22 +482,14 @@ public class CallResolver {
|
|||||||
return callResolvePerfCounter.time(new Function0<OverloadResolutionResults<FunctionDescriptor>>() {
|
return callResolvePerfCounter.time(new Function0<OverloadResolutionResults<FunctionDescriptor>>() {
|
||||||
@Override
|
@Override
|
||||||
public OverloadResolutionResults<FunctionDescriptor> invoke() {
|
public OverloadResolutionResults<FunctionDescriptor> invoke() {
|
||||||
final BasicCallResolutionContext basicCallResolutionContext =
|
BasicCallResolutionContext basicCallResolutionContext =
|
||||||
BasicCallResolutionContext.create(context, call, CheckArgumentTypesMode.CHECK_VALUE_ARGUMENTS, dataFlowInfoForArguments);
|
BasicCallResolutionContext.create(context, call, CheckArgumentTypesMode.CHECK_VALUE_ARGUMENTS, dataFlowInfoForArguments);
|
||||||
|
|
||||||
final Set<ResolutionCandidate<CallableDescriptor>> candidates = Collections.singleton(candidate);
|
Set<ResolutionCandidate<CallableDescriptor>> candidates = Collections.singleton(candidate);
|
||||||
|
|
||||||
TaskContextForMigration<CallableDescriptor, FunctionDescriptor> contextForMigration =
|
TaskContextForMigration<CallableDescriptor> contextForMigration =
|
||||||
new TaskContextForMigration<CallableDescriptor, FunctionDescriptor>(
|
new TaskContextForMigration<CallableDescriptor>(
|
||||||
ResolveKind.GIVEN_CANDIDATES, CallTransformer.FUNCTION_CALL_TRANSFORMER, null, candidates,
|
ResolveKind.GIVEN_CANDIDATES, null, candidates
|
||||||
new Function0<List<ResolutionTask<CallableDescriptor, FunctionDescriptor>>>() {
|
|
||||||
@Override
|
|
||||||
public List<ResolutionTask<CallableDescriptor, FunctionDescriptor>> invoke() {
|
|
||||||
|
|
||||||
return taskPrioritizer.<CallableDescriptor, FunctionDescriptor>computePrioritizedTasksFromCandidates(
|
|
||||||
basicCallResolutionContext, candidates, tracing);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
);
|
);
|
||||||
|
|
||||||
|
|
||||||
@@ -555,7 +500,7 @@ public class CallResolver {
|
|||||||
|
|
||||||
private <D extends CallableDescriptor, F extends D> OverloadResolutionResultsImpl<F> doResolveCallOrGetCachedResults(
|
private <D extends CallableDescriptor, F extends D> OverloadResolutionResultsImpl<F> doResolveCallOrGetCachedResults(
|
||||||
@NotNull BasicCallResolutionContext context,
|
@NotNull BasicCallResolutionContext context,
|
||||||
@NotNull TaskContextForMigration<D, F> contextForMigration,
|
@NotNull TaskContextForMigration<D> contextForMigration,
|
||||||
@NotNull TracingStrategy tracing
|
@NotNull TracingStrategy tracing
|
||||||
) {
|
) {
|
||||||
Call call = context.call;
|
Call call = context.call;
|
||||||
@@ -627,7 +572,7 @@ public class CallResolver {
|
|||||||
@NotNull
|
@NotNull
|
||||||
private <D extends CallableDescriptor, F extends D> OverloadResolutionResultsImpl<F> doResolveCall(
|
private <D extends CallableDescriptor, F extends D> OverloadResolutionResultsImpl<F> doResolveCall(
|
||||||
@NotNull BasicCallResolutionContext context,
|
@NotNull BasicCallResolutionContext context,
|
||||||
@NotNull TaskContextForMigration<D, F> contextForMigration,
|
@NotNull TaskContextForMigration<D> contextForMigration,
|
||||||
@NotNull TracingStrategy tracing
|
@NotNull TracingStrategy tracing
|
||||||
) {
|
) {
|
||||||
if (context.checkArguments == CheckArgumentTypesMode.CHECK_VALUE_ARGUMENTS) {
|
if (context.checkArguments == CheckArgumentTypesMode.CHECK_VALUE_ARGUMENTS) {
|
||||||
@@ -656,151 +601,11 @@ public class CallResolver {
|
|||||||
else {
|
else {
|
||||||
return (OverloadResolutionResultsImpl<F>) newCallResolver.runResolveForGivenCandidates(context, tracing, contextForMigration.givenCandidates);
|
return (OverloadResolutionResultsImpl<F>) newCallResolver.runResolveForGivenCandidates(context, tracing, contextForMigration.givenCandidates);
|
||||||
}
|
}
|
||||||
|
|
||||||
//return doResolveCall(context, contextForMigration.lazyTasks.invoke(), contextForMigration.callTransformer, tracing);
|
|
||||||
}
|
|
||||||
|
|
||||||
@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 TracingStrategy tracing
|
|
||||||
) {
|
|
||||||
Collection<ResolvedCall<F>> allCandidates = Lists.newArrayList();
|
|
||||||
OverloadResolutionResultsImpl<F> successfulResults = null;
|
|
||||||
TemporaryBindingTrace traceForFirstNonemptyCandidateSet = null;
|
|
||||||
OverloadResolutionResultsImpl<F> resultsForFirstNonemptyCandidateSet = null;
|
|
||||||
for (ResolutionTask<D, F> task : prioritizedTasks) {
|
|
||||||
if (task.getCandidates().isEmpty()) continue;
|
|
||||||
|
|
||||||
TemporaryBindingTrace taskTrace =
|
|
||||||
TemporaryBindingTrace.create(context.trace, "trace to resolve a task for", task.call.getCalleeExpression());
|
|
||||||
OverloadResolutionResultsImpl<F> results = performResolution(task.replaceBindingTrace(taskTrace), callTransformer);
|
|
||||||
|
|
||||||
|
|
||||||
allCandidates.addAll(task.getResolvedCalls());
|
|
||||||
|
|
||||||
if (successfulResults != null) continue;
|
|
||||||
|
|
||||||
if (results.isSuccess() || results.isAmbiguity()) {
|
|
||||||
taskTrace.commit();
|
|
||||||
successfulResults = results;
|
|
||||||
}
|
|
||||||
if (results.getResultCode() == INCOMPLETE_TYPE_INFERENCE) {
|
|
||||||
results.setTrace(taskTrace);
|
|
||||||
successfulResults = 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 (successfulResults != null && !context.collectAllCandidates) break;
|
|
||||||
}
|
|
||||||
OverloadResolutionResultsImpl<F> results;
|
|
||||||
if (successfulResults != null) {
|
|
||||||
results = successfulResults;
|
|
||||||
}
|
|
||||||
else if (traceForFirstNonemptyCandidateSet == null) {
|
|
||||||
tracing.unresolvedReference(context.trace);
|
|
||||||
argumentTypeResolver.checkTypesWithNoCallee(context, SHAPE_FUNCTION_ARGUMENTS);
|
|
||||||
results = OverloadResolutionResultsImpl.<F>nameNotFound();
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
traceForFirstNonemptyCandidateSet.commit();
|
|
||||||
results = resultsForFirstNonemptyCandidateSet;
|
|
||||||
}
|
|
||||||
results.setAllCandidates(context.collectAllCandidates ? allCandidates : null);
|
|
||||||
return results;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
@NotNull
|
private static class TaskContextForMigration<D extends CallableDescriptor> {
|
||||||
private <D extends CallableDescriptor, F extends D> OverloadResolutionResultsImpl<F> performResolution(
|
|
||||||
@NotNull ResolutionTask<D, F> task,
|
|
||||||
@NotNull CallTransformer<D, F> callTransformer
|
|
||||||
) {
|
|
||||||
CandidateResolveMode mode = task.collectAllCandidates ? FULLY : EXIT_ON_FIRST_ERROR;
|
|
||||||
List<CallCandidateResolutionContext<D>> contexts = collectCallCandidateContext(task, callTransformer, mode);
|
|
||||||
boolean isSuccess = ContainerUtil.exists(contexts, new Condition<CallCandidateResolutionContext<D>>() {
|
|
||||||
@Override
|
|
||||||
public boolean value(CallCandidateResolutionContext<D> context) {
|
|
||||||
return context.candidateCall.getStatus().possibleTransformToSuccess();
|
|
||||||
}
|
|
||||||
});
|
|
||||||
if (!isSuccess && mode == EXIT_ON_FIRST_ERROR) {
|
|
||||||
contexts = collectCallCandidateContext(task, callTransformer, FULLY);
|
|
||||||
}
|
|
||||||
|
|
||||||
for (CallCandidateResolutionContext<D> context : contexts) {
|
|
||||||
addResolvedCall(task, callTransformer, context);
|
|
||||||
}
|
|
||||||
|
|
||||||
OverloadResolutionResultsImpl<F> results = resolutionResultsHandler.computeResultAndReportErrors(
|
|
||||||
task, task.tracing, task.getResolvedCalls());
|
|
||||||
if (!results.isSingleResult() && !results.isIncomplete()) {
|
|
||||||
argumentTypeResolver.checkTypesWithNoCallee(task.toBasic());
|
|
||||||
}
|
|
||||||
return results;
|
|
||||||
}
|
|
||||||
|
|
||||||
@NotNull
|
|
||||||
private <D extends CallableDescriptor, F extends D> List<CallCandidateResolutionContext<D>> collectCallCandidateContext(
|
|
||||||
@NotNull final ResolutionTask<D, F> task,
|
|
||||||
@NotNull final CallTransformer<D, F> callTransformer,
|
|
||||||
@NotNull final CandidateResolveMode candidateResolveMode
|
|
||||||
) {
|
|
||||||
final List<CallCandidateResolutionContext<D>> candidateResolutionContexts = ContainerUtil.newArrayList();
|
|
||||||
for (final ResolutionCandidate<D> resolutionCandidate : task.getCandidates()) {
|
|
||||||
if (DeprecationUtilKt.isHiddenInResolution(resolutionCandidate.getDescriptor())) continue;
|
|
||||||
|
|
||||||
candidatePerfCounter.time(new Function0<Unit>() {
|
|
||||||
@Override
|
|
||||||
public Unit invoke() {
|
|
||||||
TemporaryBindingTrace candidateTrace = TemporaryBindingTrace.create(
|
|
||||||
task.trace, "trace to resolve candidate");
|
|
||||||
Collection<CallCandidateResolutionContext<D>> contexts =
|
|
||||||
callTransformer.createCallContexts(resolutionCandidate, task, candidateTrace, candidateResolveMode);
|
|
||||||
for (CallCandidateResolutionContext<D> context : contexts) {
|
|
||||||
candidateResolver.performResolutionForCandidateCall(context, task.checkArguments);
|
|
||||||
candidateResolutionContexts.add(context);
|
|
||||||
}
|
|
||||||
return Unit.INSTANCE;
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
|
||||||
return candidateResolutionContexts;
|
|
||||||
}
|
|
||||||
|
|
||||||
private <D extends CallableDescriptor, F extends D> void addResolvedCall(
|
|
||||||
@NotNull ResolutionTask<D, F> task,
|
|
||||||
@NotNull CallTransformer<D, F> callTransformer,
|
|
||||||
@NotNull CallCandidateResolutionContext<D> context) {
|
|
||||||
/* 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<MutableResolvedCall<F>> resolvedCalls = callTransformer.transformCall(context, this, task);
|
|
||||||
|
|
||||||
for (MutableResolvedCall<F> resolvedCall : resolvedCalls) {
|
|
||||||
BindingTrace trace = resolvedCall.getTrace();
|
|
||||||
task.tracing.bindReference(trace, resolvedCall);
|
|
||||||
task.tracing.bindResolvedCall(trace, resolvedCall);
|
|
||||||
task.addResolvedCall(resolvedCall);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private static class TaskContextForMigration<D extends CallableDescriptor, F extends D> {
|
|
||||||
@NotNull
|
|
||||||
final Function0<List<ResolutionTask<D, F>>> lazyTasks;
|
|
||||||
|
|
||||||
@NotNull
|
|
||||||
final CallTransformer<D, F> callTransformer;
|
|
||||||
|
|
||||||
@Nullable
|
@Nullable
|
||||||
final Name name;
|
final Name name;
|
||||||
@@ -813,12 +618,9 @@ public class CallResolver {
|
|||||||
|
|
||||||
private TaskContextForMigration(
|
private TaskContextForMigration(
|
||||||
@NotNull ResolveKind kind,
|
@NotNull ResolveKind kind,
|
||||||
@NotNull CallTransformer<D, F> transformer,
|
|
||||||
@Nullable Name name,
|
@Nullable Name name,
|
||||||
@Nullable Collection<ResolutionCandidate<D>> candidates, @NotNull Function0<List<ResolutionTask<D, F>>> tasks
|
@Nullable Collection<ResolutionCandidate<D>> candidates
|
||||||
) {
|
) {
|
||||||
lazyTasks = tasks;
|
|
||||||
callTransformer = transformer;
|
|
||||||
this.name = name;
|
this.name = name;
|
||||||
givenCandidates = candidates;
|
givenCandidates = candidates;
|
||||||
resolveKind = kind;
|
resolveKind = kind;
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
/*
|
/*
|
||||||
* Copyright 2010-2015 JetBrains s.r.o.
|
* Copyright 2010-2016 JetBrains s.r.o.
|
||||||
*
|
*
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
* you may not use this file except in compliance with the License.
|
* you may not use this file except in compliance with the License.
|
||||||
@@ -16,88 +16,22 @@
|
|||||||
|
|
||||||
package org.jetbrains.kotlin.resolve.calls;
|
package org.jetbrains.kotlin.resolve.calls;
|
||||||
|
|
||||||
import com.google.common.base.Function;
|
|
||||||
import com.google.common.collect.Collections2;
|
|
||||||
import com.google.common.collect.Lists;
|
|
||||||
import com.intellij.lang.ASTNode;
|
import com.intellij.lang.ASTNode;
|
||||||
import org.jetbrains.annotations.NotNull;
|
import org.jetbrains.annotations.NotNull;
|
||||||
import org.jetbrains.annotations.Nullable;
|
import org.jetbrains.annotations.Nullable;
|
||||||
import org.jetbrains.kotlin.descriptors.CallableDescriptor;
|
|
||||||
import org.jetbrains.kotlin.descriptors.FunctionDescriptor;
|
|
||||||
import org.jetbrains.kotlin.descriptors.VariableDescriptor;
|
|
||||||
import org.jetbrains.kotlin.psi.*;
|
import org.jetbrains.kotlin.psi.*;
|
||||||
import org.jetbrains.kotlin.resolve.ChainedTemporaryBindingTrace;
|
|
||||||
import org.jetbrains.kotlin.resolve.DelegatingBindingTrace;
|
|
||||||
import org.jetbrains.kotlin.resolve.TemporaryBindingTrace;
|
|
||||||
import org.jetbrains.kotlin.resolve.calls.context.BasicCallResolutionContext;
|
|
||||||
import org.jetbrains.kotlin.resolve.calls.context.CallCandidateResolutionContext;
|
|
||||||
import org.jetbrains.kotlin.resolve.calls.context.CandidateResolveMode;
|
|
||||||
import org.jetbrains.kotlin.resolve.calls.context.ContextDependency;
|
|
||||||
import org.jetbrains.kotlin.resolve.calls.model.MutableResolvedCall;
|
|
||||||
import org.jetbrains.kotlin.resolve.calls.model.ResolvedCallImpl;
|
|
||||||
import org.jetbrains.kotlin.resolve.calls.model.VariableAsFunctionResolvedCallImpl;
|
|
||||||
import org.jetbrains.kotlin.resolve.calls.results.OverloadResolutionResults;
|
|
||||||
import org.jetbrains.kotlin.resolve.calls.results.OverloadResolutionResultsImpl;
|
|
||||||
import org.jetbrains.kotlin.resolve.calls.tasks.ExplicitReceiverKind;
|
|
||||||
import org.jetbrains.kotlin.resolve.calls.tasks.ResolutionCandidate;
|
|
||||||
import org.jetbrains.kotlin.resolve.calls.tasks.ResolutionTask;
|
|
||||||
import org.jetbrains.kotlin.resolve.calls.tasks.TracingStrategyForInvoke;
|
|
||||||
import org.jetbrains.kotlin.resolve.calls.util.DelegatingCall;
|
import org.jetbrains.kotlin.resolve.calls.util.DelegatingCall;
|
||||||
import org.jetbrains.kotlin.resolve.scopes.receivers.ExpressionReceiver;
|
import org.jetbrains.kotlin.resolve.scopes.receivers.ExpressionReceiver;
|
||||||
import org.jetbrains.kotlin.resolve.scopes.receivers.Receiver;
|
import org.jetbrains.kotlin.resolve.scopes.receivers.Receiver;
|
||||||
import org.jetbrains.kotlin.resolve.scopes.receivers.ReceiverValue;
|
import org.jetbrains.kotlin.resolve.scopes.receivers.ReceiverValue;
|
||||||
import org.jetbrains.kotlin.types.KotlinType;
|
|
||||||
import org.jetbrains.kotlin.util.OperatorNameConventions;
|
import org.jetbrains.kotlin.util.OperatorNameConventions;
|
||||||
|
|
||||||
import java.util.Collection;
|
|
||||||
import java.util.Collections;
|
import java.util.Collections;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
|
||||||
/**
|
public class CallTransformer {
|
||||||
* CallTransformer treats specially 'variable as function' call case, other cases keeps unchanged (base realization).
|
|
||||||
*
|
|
||||||
* For the call 'b.foo(1)' where foo is a variable that has method 'invoke' (for example of function type)
|
|
||||||
* CallTransformer creates two contexts, two calls in each, and performs second ('invoke') call resolution:
|
|
||||||
*
|
|
||||||
* context#1. calls: 'b.foo' 'invoke(1)'
|
|
||||||
* context#2. calls: 'foo' 'b.invoke(1)'
|
|
||||||
*
|
|
||||||
* If success VariableAsFunctionResolvedCall is created.
|
|
||||||
*/
|
|
||||||
public class CallTransformer<D extends CallableDescriptor, F extends D> {
|
|
||||||
private CallTransformer() {}
|
private CallTransformer() {}
|
||||||
|
|
||||||
/**
|
|
||||||
* Returns two contexts for 'variable as function' case (in FUNCTION_CALL_TRANSFORMER), one context otherwise
|
|
||||||
*/
|
|
||||||
@NotNull
|
|
||||||
public Collection<CallCandidateResolutionContext<D>> createCallContexts(@NotNull ResolutionCandidate<D> candidate,
|
|
||||||
@NotNull ResolutionTask<D, F> task,
|
|
||||||
@NotNull TemporaryBindingTrace candidateTrace,
|
|
||||||
@NotNull CandidateResolveMode candidateResolveMode
|
|
||||||
) {
|
|
||||||
ResolvedCallImpl<D> candidateCall = ResolvedCallImpl.create(candidate, candidateTrace, task.tracing, task.dataFlowInfoForArguments);
|
|
||||||
return Collections.singleton(CallCandidateResolutionContext.create(candidateCall, task, candidateTrace, task.tracing, task.call,
|
|
||||||
null, candidateResolveMode));
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Returns collection of resolved calls for 'invoke' for 'variable as function' case (in FUNCTION_CALL_TRANSFORMER),
|
|
||||||
* the resolved call from callCandidateResolutionContext otherwise
|
|
||||||
*/
|
|
||||||
@NotNull
|
|
||||||
public Collection<MutableResolvedCall<F>> transformCall(@NotNull CallCandidateResolutionContext<D> callCandidateResolutionContext,
|
|
||||||
@NotNull CallResolver callResolver,
|
|
||||||
@NotNull ResolutionTask<D, F> task
|
|
||||||
) {
|
|
||||||
return Collections.singleton((MutableResolvedCall<F>) callCandidateResolutionContext.candidateCall);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
public static CallTransformer<CallableDescriptor, CallableDescriptor> MEMBER_CALL_TRANSFORMER = new CallTransformer<CallableDescriptor, CallableDescriptor>();
|
|
||||||
|
|
||||||
public static CallTransformer<VariableDescriptor, VariableDescriptor> VARIABLE_CALL_TRANSFORMER = new CallTransformer<VariableDescriptor, VariableDescriptor>();
|
|
||||||
|
|
||||||
public static Call stripCallArguments(@NotNull Call call) {
|
public static Call stripCallArguments(@NotNull Call call) {
|
||||||
return new DelegatingCall(call) {
|
return new DelegatingCall(call) {
|
||||||
@Override
|
@Override
|
||||||
@@ -155,112 +89,6 @@ public class CallTransformer<D extends CallableDescriptor, F extends D> {
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
public static CallTransformer<CallableDescriptor, FunctionDescriptor> FUNCTION_CALL_TRANSFORMER = new CallTransformer<CallableDescriptor, FunctionDescriptor>() {
|
|
||||||
@NotNull
|
|
||||||
@Override
|
|
||||||
public Collection<CallCandidateResolutionContext<CallableDescriptor>> createCallContexts(@NotNull ResolutionCandidate<CallableDescriptor> candidate,
|
|
||||||
@NotNull ResolutionTask<CallableDescriptor, FunctionDescriptor> task, @NotNull TemporaryBindingTrace candidateTrace,
|
|
||||||
@NotNull CandidateResolveMode candidateResolveMode
|
|
||||||
) {
|
|
||||||
|
|
||||||
if (candidate.getDescriptor() instanceof FunctionDescriptor) {
|
|
||||||
return super.createCallContexts(candidate, task, candidateTrace, candidateResolveMode);
|
|
||||||
}
|
|
||||||
|
|
||||||
assert candidate.getDescriptor() instanceof VariableDescriptor;
|
|
||||||
|
|
||||||
boolean hasReceiver = candidate.getReceiverArgument() != null;
|
|
||||||
Call variableCall = stripCallArguments(task.call);
|
|
||||||
ResolutionCandidate<CallableDescriptor> variableCandidate = ResolutionCandidate.create(
|
|
||||||
variableCall,
|
|
||||||
candidate.getDescriptor(),
|
|
||||||
candidate.getDispatchReceiver(),
|
|
||||||
candidate.getReceiverArgument(),
|
|
||||||
candidate.getExplicitReceiverKind(),
|
|
||||||
null);
|
|
||||||
if (!hasReceiver) {
|
|
||||||
CallCandidateResolutionContext<CallableDescriptor> context = CallCandidateResolutionContext.create(
|
|
||||||
ResolvedCallImpl.create(variableCandidate, candidateTrace, task.tracing, task.dataFlowInfoForArguments),
|
|
||||||
task, candidateTrace, task.tracing, variableCall, null, candidateResolveMode);
|
|
||||||
return Collections.singleton(context);
|
|
||||||
}
|
|
||||||
CallCandidateResolutionContext<CallableDescriptor> contextWithReceiver = createContextWithChainedTrace(
|
|
||||||
variableCandidate, variableCall, candidateTrace, task, null, candidateResolveMode);
|
|
||||||
|
|
||||||
Call variableCallWithoutReceiver = stripReceiver(variableCall);
|
|
||||||
ResolutionCandidate<CallableDescriptor> candidateWithoutReceiver = ResolutionCandidate.create(
|
|
||||||
variableCallWithoutReceiver,
|
|
||||||
candidate.getDescriptor(),
|
|
||||||
candidate.getDispatchReceiver(),
|
|
||||||
null,
|
|
||||||
ExplicitReceiverKind.NO_EXPLICIT_RECEIVER, null);
|
|
||||||
|
|
||||||
CallCandidateResolutionContext<CallableDescriptor> contextWithoutReceiver = createContextWithChainedTrace(
|
|
||||||
candidateWithoutReceiver, variableCallWithoutReceiver, candidateTrace, task, variableCall.getExplicitReceiver(),
|
|
||||||
candidateResolveMode);
|
|
||||||
|
|
||||||
return Lists.newArrayList(contextWithReceiver, contextWithoutReceiver);
|
|
||||||
}
|
|
||||||
|
|
||||||
private CallCandidateResolutionContext<CallableDescriptor> createContextWithChainedTrace(
|
|
||||||
@NotNull ResolutionCandidate<CallableDescriptor> candidate, @NotNull Call call, @NotNull TemporaryBindingTrace temporaryTrace,
|
|
||||||
@NotNull ResolutionTask<CallableDescriptor, FunctionDescriptor> task, @Nullable Receiver receiverValue,
|
|
||||||
@NotNull CandidateResolveMode candidateResolveMode
|
|
||||||
) {
|
|
||||||
ChainedTemporaryBindingTrace chainedTrace = ChainedTemporaryBindingTrace.create(temporaryTrace, "chained trace to resolve candidate", candidate);
|
|
||||||
ResolvedCallImpl<CallableDescriptor> resolvedCall = ResolvedCallImpl.create(candidate, chainedTrace, task.tracing, task.dataFlowInfoForArguments);
|
|
||||||
return CallCandidateResolutionContext.create(resolvedCall, task, chainedTrace, task.tracing, call, receiverValue,
|
|
||||||
candidateResolveMode);
|
|
||||||
}
|
|
||||||
|
|
||||||
@NotNull
|
|
||||||
@Override
|
|
||||||
public Collection<MutableResolvedCall<FunctionDescriptor>> transformCall(
|
|
||||||
@NotNull CallCandidateResolutionContext<CallableDescriptor> context,
|
|
||||||
@NotNull CallResolver callResolver,
|
|
||||||
@NotNull ResolutionTask<CallableDescriptor, FunctionDescriptor> task
|
|
||||||
) {
|
|
||||||
CallableDescriptor descriptor = context.candidateCall.getCandidateDescriptor();
|
|
||||||
if (descriptor instanceof FunctionDescriptor) {
|
|
||||||
return super.transformCall(context, callResolver, task);
|
|
||||||
}
|
|
||||||
|
|
||||||
assert descriptor instanceof VariableDescriptor;
|
|
||||||
KotlinType returnType = descriptor.getReturnType();
|
|
||||||
if (returnType == null) {
|
|
||||||
return Collections.emptyList();
|
|
||||||
}
|
|
||||||
|
|
||||||
final MutableResolvedCall<VariableDescriptor> variableResolvedCall = (MutableResolvedCall)context.candidateCall;
|
|
||||||
|
|
||||||
KtExpression calleeExpression = task.call.getCalleeExpression();
|
|
||||||
if (calleeExpression == null) return Collections.emptyList();
|
|
||||||
|
|
||||||
ExpressionReceiver variableReceiver = ExpressionReceiver.Companion.create(
|
|
||||||
calleeExpression, variableResolvedCall.getResultingDescriptor().getType(), context.trace.getBindingContext());
|
|
||||||
Call functionCall = new CallForImplicitInvoke(context.explicitExtensionReceiverForInvoke, variableReceiver, task.call);
|
|
||||||
|
|
||||||
DelegatingBindingTrace variableCallTrace = context.candidateCall.getTrace();
|
|
||||||
BasicCallResolutionContext basicCallResolutionContext = BasicCallResolutionContext.create(
|
|
||||||
context.replaceBindingTrace(variableCallTrace).replaceContextDependency(ContextDependency.DEPENDENT),
|
|
||||||
functionCall, context.checkArguments, context.dataFlowInfoForArguments);
|
|
||||||
|
|
||||||
// 'invoke' call resolve
|
|
||||||
TracingStrategyForInvoke tracingForInvoke = new TracingStrategyForInvoke(
|
|
||||||
calleeExpression, functionCall, variableReceiver.getType());
|
|
||||||
OverloadResolutionResults<FunctionDescriptor> results = callResolver.resolveCallForInvoke(
|
|
||||||
basicCallResolutionContext, tracingForInvoke);
|
|
||||||
Collection<MutableResolvedCall<FunctionDescriptor>> calls = ((OverloadResolutionResultsImpl<FunctionDescriptor>)results).getResultingCalls();
|
|
||||||
|
|
||||||
return Collections2.transform(calls, new Function<MutableResolvedCall<FunctionDescriptor>, MutableResolvedCall<FunctionDescriptor>>() {
|
|
||||||
@Override
|
|
||||||
public MutableResolvedCall<FunctionDescriptor> apply(MutableResolvedCall<FunctionDescriptor> functionResolvedCall) {
|
|
||||||
return new VariableAsFunctionResolvedCallImpl(functionResolvedCall, variableResolvedCall);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
public static class CallForImplicitInvoke extends DelegatingCall {
|
public static class CallForImplicitInvoke extends DelegatingCall {
|
||||||
private final Call outerCall;
|
private final Call outerCall;
|
||||||
private final Receiver explicitExtensionReceiver;
|
private final Receiver explicitExtensionReceiver;
|
||||||
|
|||||||
-259
@@ -1,259 +0,0 @@
|
|||||||
/*
|
|
||||||
* Copyright 2010-2015 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.kotlin.resolve.calls.tasks.collectors
|
|
||||||
|
|
||||||
import com.intellij.util.SmartList
|
|
||||||
import org.jetbrains.kotlin.builtins.KotlinBuiltIns
|
|
||||||
import org.jetbrains.kotlin.builtins.functions.FunctionInvokeDescriptor
|
|
||||||
import org.jetbrains.kotlin.descriptors.*
|
|
||||||
import org.jetbrains.kotlin.incremental.components.LookupLocation
|
|
||||||
import org.jetbrains.kotlin.name.Name
|
|
||||||
import org.jetbrains.kotlin.resolve.DescriptorUtils.isStaticNestedClass
|
|
||||||
import org.jetbrains.kotlin.resolve.LibrarySourceHacks
|
|
||||||
import org.jetbrains.kotlin.resolve.calls.tasks.createSynthesizedInvokes
|
|
||||||
import org.jetbrains.kotlin.resolve.calls.util.FakeCallableDescriptorForObject
|
|
||||||
import org.jetbrains.kotlin.resolve.descriptorUtil.hasClassValueDescriptor
|
|
||||||
import org.jetbrains.kotlin.resolve.scopes.*
|
|
||||||
import org.jetbrains.kotlin.resolve.scopes.utils.*
|
|
||||||
import org.jetbrains.kotlin.types.ErrorUtils
|
|
||||||
import org.jetbrains.kotlin.types.KotlinType
|
|
||||||
import org.jetbrains.kotlin.util.OperatorNameConventions
|
|
||||||
import org.jetbrains.kotlin.utils.addIfNotNull
|
|
||||||
|
|
||||||
interface CallableDescriptorCollector<D : CallableDescriptor> {
|
|
||||||
|
|
||||||
fun getLocalNonExtensionsByName(lexicalScope: LexicalScope, name: Name, location: LookupLocation): Collection<D>
|
|
||||||
|
|
||||||
fun getNonExtensionsByName(scope: HierarchicalScope, name: Name, location: LookupLocation): Collection<D>
|
|
||||||
|
|
||||||
// todo this is hack for static members priority
|
|
||||||
fun getStaticInheritanceByName(lexicalScope: LexicalScope, name: Name, location: LookupLocation): Collection<D>
|
|
||||||
|
|
||||||
fun getMembersByName(receiver: KotlinType, name: Name, location: LookupLocation): Collection<D>
|
|
||||||
|
|
||||||
fun getStaticMembersByName(receiver: KotlinType, name: Name, location: LookupLocation): Collection<D>
|
|
||||||
|
|
||||||
fun getExtensionsByName(scope: HierarchicalScope, syntheticScopes: SyntheticScopes, name: Name, receiverTypes: Collection<KotlinType>, location: LookupLocation): Collection<D>
|
|
||||||
}
|
|
||||||
|
|
||||||
private fun <D : CallableDescriptor> CallableDescriptorCollector<D>.withDefaultFilter() = filtered { !LibrarySourceHacks.shouldSkip(it) }
|
|
||||||
|
|
||||||
private val FUNCTIONS_COLLECTOR = FunctionCollector.withDefaultFilter()
|
|
||||||
private val VARIABLES_COLLECTOR = VariableCollector.withDefaultFilter()
|
|
||||||
|
|
||||||
class CallableDescriptorCollectors<D : CallableDescriptor>(val collectors: List<CallableDescriptorCollector<D>>) :
|
|
||||||
Iterable<CallableDescriptorCollector<D>> {
|
|
||||||
override fun iterator(): Iterator<CallableDescriptorCollector<D>> = collectors.iterator()
|
|
||||||
|
|
||||||
@Suppress("UNCHECKED_CAST")
|
|
||||||
companion object {
|
|
||||||
|
|
||||||
@JvmField val FUNCTIONS_AND_VARIABLES: CallableDescriptorCollectors<CallableDescriptor> =
|
|
||||||
CallableDescriptorCollectors(listOf(
|
|
||||||
FUNCTIONS_COLLECTOR as CallableDescriptorCollector<CallableDescriptor>,
|
|
||||||
VARIABLES_COLLECTOR as CallableDescriptorCollector<CallableDescriptor>
|
|
||||||
))
|
|
||||||
|
|
||||||
@JvmField val FUNCTIONS: CallableDescriptorCollectors<CallableDescriptor> =
|
|
||||||
CallableDescriptorCollectors(listOf(FUNCTIONS_COLLECTOR as CallableDescriptorCollector<CallableDescriptor>))
|
|
||||||
|
|
||||||
@JvmField val VARIABLES: CallableDescriptorCollectors<VariableDescriptor> = CallableDescriptorCollectors(listOf(VARIABLES_COLLECTOR))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fun <D : CallableDescriptor> CallableDescriptorCollectors<D>.filtered(filter: (D) -> Boolean): CallableDescriptorCollectors<D> =
|
|
||||||
CallableDescriptorCollectors(this.collectors.map { it.filtered(filter) })
|
|
||||||
|
|
||||||
private object FunctionCollector : CallableDescriptorCollector<FunctionDescriptor> {
|
|
||||||
override fun getStaticInheritanceByName(lexicalScope: LexicalScope, name: Name, location: LookupLocation): Collection<FunctionDescriptor> {
|
|
||||||
return lexicalScope.collectAllFromMeAndParent {
|
|
||||||
if (it is LexicalChainedScope && it.isStaticScope) {
|
|
||||||
it.getContributedFunctions(name, location).filter { it.extensionReceiverParameter == null }
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
emptyList()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun getLocalNonExtensionsByName(lexicalScope: LexicalScope, name: Name, location: LookupLocation): Collection<FunctionDescriptor> {
|
|
||||||
return lexicalScope.collectAllFromMeAndParent {
|
|
||||||
if (it is LexicalScope && it.ownerDescriptor is FunctionDescriptor) {
|
|
||||||
it.getContributedFunctions(name, location).filter { it.extensionReceiverParameter == null } +
|
|
||||||
getConstructors(it.getContributedClassifier(name, location))
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
emptyList()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun getNonExtensionsByName(scope: HierarchicalScope, name: Name, location: LookupLocation): Collection<FunctionDescriptor> {
|
|
||||||
return scope.collectFunctions(name, location).filter { it.extensionReceiverParameter == null } + getConstructors(scope, name, location)
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun getMembersByName(receiver: KotlinType, name: Name, location: LookupLocation): Collection<FunctionDescriptor> {
|
|
||||||
val receiverScope = receiver.memberScope
|
|
||||||
val members = receiverScope.getContributedFunctions(name, location)
|
|
||||||
val constructors = getConstructors(receiverScope.memberScopeAsImportingScope(), name, location, { !isStaticNestedClass(it) })
|
|
||||||
|
|
||||||
if (name == OperatorNameConventions.INVOKE && KotlinBuiltIns.isExtensionFunctionType(receiver)) {
|
|
||||||
// If we're looking for members of an extension function type, we ignore the non-extension "invoke"s
|
|
||||||
// that originate from the Function{n} class and only consider the synthesized "invoke" extensions.
|
|
||||||
// Otherwise confusing errors will be reported because the non-extension here beats the extension
|
|
||||||
// (because declarations beat synthesized members)
|
|
||||||
val (candidatesForReplacement, irrelevantInvokes) =
|
|
||||||
members.partition { it is FunctionInvokeDescriptor && it.valueParameters.isNotEmpty() }
|
|
||||||
return createSynthesizedInvokes(candidatesForReplacement) + candidatesForReplacement + irrelevantInvokes + constructors
|
|
||||||
}
|
|
||||||
|
|
||||||
return members + constructors
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun getStaticMembersByName(receiver: KotlinType, name: Name, location: LookupLocation): Collection<FunctionDescriptor> {
|
|
||||||
return getConstructors(receiver.memberScope.memberScopeAsImportingScope(), name, location, { isStaticNestedClass(it) })
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun getExtensionsByName(scope: HierarchicalScope, syntheticScopes: SyntheticScopes, name: Name, receiverTypes: Collection<KotlinType>, location: LookupLocation): Collection<FunctionDescriptor> {
|
|
||||||
val functions = scope.collectFunctions(name, location)
|
|
||||||
val (extensions, nonExtensions) = functions.partition { it.extensionReceiverParameter != null }
|
|
||||||
val syntheticExtensions = syntheticScopes.collectSyntheticExtensionFunctions(receiverTypes, name, location)
|
|
||||||
|
|
||||||
if (name == OperatorNameConventions.INVOKE) {
|
|
||||||
// Create synthesized "invoke" extensions for each non-extension "invoke" found in the scope
|
|
||||||
return extensions + createSynthesizedInvokes(nonExtensions) + syntheticExtensions
|
|
||||||
}
|
|
||||||
|
|
||||||
return extensions + syntheticExtensions
|
|
||||||
}
|
|
||||||
|
|
||||||
private fun getConstructors(
|
|
||||||
scope: HierarchicalScope,
|
|
||||||
name: Name,
|
|
||||||
location: LookupLocation,
|
|
||||||
filterClassPredicate: (ClassDescriptor) -> Boolean = { true }
|
|
||||||
): Collection<FunctionDescriptor> {
|
|
||||||
val classifier = scope.findClassifier(name, location)
|
|
||||||
return getConstructors(classifier, filterClassPredicate)
|
|
||||||
}
|
|
||||||
|
|
||||||
private fun getConstructors(
|
|
||||||
classifier: ClassifierDescriptor?,
|
|
||||||
filterClassPredicate: (ClassDescriptor) -> Boolean = { true }
|
|
||||||
): Collection<FunctionDescriptor> {
|
|
||||||
if (classifier !is ClassDescriptor || ErrorUtils.isError(classifier) || !filterClassPredicate(classifier)
|
|
||||||
// Constructors of singletons shouldn't be callable from the code
|
|
||||||
|| classifier.kind.isSingleton) {
|
|
||||||
return listOf()
|
|
||||||
}
|
|
||||||
return classifier.constructors
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun toString() = "FUNCTIONS"
|
|
||||||
}
|
|
||||||
|
|
||||||
private object VariableCollector : CallableDescriptorCollector<VariableDescriptor> {
|
|
||||||
override fun getLocalNonExtensionsByName(lexicalScope: LexicalScope, name: Name, location: LookupLocation): Collection<VariableDescriptor> {
|
|
||||||
val result = SmartList<VariableDescriptor>()
|
|
||||||
result.addIfNotNull(lexicalScope.findLocalVariable(name))
|
|
||||||
// Although local objects are prohibited, we'll include objects declared in current scope so that their usages are still resolved.
|
|
||||||
result.addIfNotNull(getContributedFakeDescriptorForObject(lexicalScope, name, location))
|
|
||||||
return result
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun getStaticInheritanceByName(lexicalScope: LexicalScope, name: Name, location: LookupLocation): Collection<VariableDescriptor> {
|
|
||||||
return lexicalScope.collectAllFromMeAndParent {
|
|
||||||
if (it is LexicalChainedScope && it.isStaticScope) {
|
|
||||||
it.getContributedVariables(name, location)
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
emptyList()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private fun getContributedFakeDescriptorForObject(scope: LexicalScope, name: Name, location: LookupLocation): VariableDescriptor? {
|
|
||||||
val classifier = scope.getContributedClassifier(name, location)
|
|
||||||
if (classifier !is ClassDescriptor || !classifier.hasClassValueDescriptor) return null
|
|
||||||
return FakeCallableDescriptorForObject(classifier)
|
|
||||||
}
|
|
||||||
|
|
||||||
private fun findFakeDescriptorForObject(scope: HierarchicalScope, name: Name, location: LookupLocation): VariableDescriptor? {
|
|
||||||
val classifier = scope.findClassifier(name, location)
|
|
||||||
if (classifier !is ClassDescriptor || !classifier.hasClassValueDescriptor) return null
|
|
||||||
|
|
||||||
return FakeCallableDescriptorForObject(classifier)
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun getNonExtensionsByName(scope: HierarchicalScope, name: Name, location: LookupLocation): Collection<VariableDescriptor> {
|
|
||||||
val properties = scope.collectVariables(name, location).filter { it.extensionReceiverParameter == null }
|
|
||||||
val fakeDescriptor = findFakeDescriptorForObject(scope, name, location)
|
|
||||||
return if (fakeDescriptor != null) properties + fakeDescriptor else properties
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun getMembersByName(receiver: KotlinType, name: Name, location: LookupLocation): Collection<VariableDescriptor> {
|
|
||||||
val memberScope = receiver.memberScope
|
|
||||||
val properties = memberScope.getContributedVariables(name, location)
|
|
||||||
val fakeDescriptor = findFakeDescriptorForObject(memberScope.memberScopeAsImportingScope(), name, location)
|
|
||||||
return if (fakeDescriptor != null) properties + fakeDescriptor else properties
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun getStaticMembersByName(receiver: KotlinType, name: Name, location: LookupLocation): Collection<VariableDescriptor> {
|
|
||||||
return listOf()
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun getExtensionsByName(scope: HierarchicalScope, syntheticScopes: SyntheticScopes, name: Name, receiverTypes: Collection<KotlinType>, location: LookupLocation): Collection<VariableDescriptor> {
|
|
||||||
// property may have an extension function type, we check the applicability later to avoid an early computing of deferred types
|
|
||||||
return scope.collectVariables(name, location) +
|
|
||||||
syntheticScopes.collectSyntheticExtensionProperties(receiverTypes, name, location)
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun toString() = "VARIABLES"
|
|
||||||
}
|
|
||||||
|
|
||||||
private fun <D : CallableDescriptor> CallableDescriptorCollector<D>.filtered(filter: (D) -> Boolean): CallableDescriptorCollector<D> {
|
|
||||||
val delegate = this
|
|
||||||
return object : CallableDescriptorCollector<D> {
|
|
||||||
override fun getLocalNonExtensionsByName(lexicalScope: LexicalScope, name: Name, location: LookupLocation): Collection<D> {
|
|
||||||
return delegate.getLocalNonExtensionsByName(lexicalScope, name, location).filter(filter)
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun getStaticInheritanceByName(lexicalScope: LexicalScope, name: Name, location: LookupLocation): Collection<D> {
|
|
||||||
return delegate.getStaticInheritanceByName(lexicalScope, name, location)
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun getNonExtensionsByName(scope: HierarchicalScope, name: Name, location: LookupLocation): Collection<D> {
|
|
||||||
return delegate.getNonExtensionsByName(scope, name, location).filter(filter)
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun getMembersByName(receiver: KotlinType, name: Name, location: LookupLocation): Collection<D> {
|
|
||||||
return delegate.getMembersByName(receiver, name, location).filter(filter)
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun getStaticMembersByName(receiver: KotlinType, name: Name, location: LookupLocation): Collection<D> {
|
|
||||||
return delegate.getStaticMembersByName(receiver, name, location).filter(filter)
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun getExtensionsByName(scope: HierarchicalScope, syntheticScopes: SyntheticScopes, name: Name, receiverTypes: Collection<KotlinType>, location: LookupLocation): Collection<D> {
|
|
||||||
return delegate.getExtensionsByName(scope, syntheticScopes, name, receiverTypes, location).filter(filter)
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun toString(): String {
|
|
||||||
return delegate.toString()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,124 +0,0 @@
|
|||||||
/*
|
|
||||||
* Copyright 2010-2015 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.kotlin.resolve.calls.tasks;
|
|
||||||
|
|
||||||
import com.intellij.util.SmartList;
|
|
||||||
import kotlin.jvm.functions.Function0;
|
|
||||||
import org.jetbrains.annotations.NotNull;
|
|
||||||
import org.jetbrains.annotations.Nullable;
|
|
||||||
import org.jetbrains.kotlin.descriptors.CallableDescriptor;
|
|
||||||
import org.jetbrains.kotlin.psi.Call;
|
|
||||||
import org.jetbrains.kotlin.resolve.BindingTrace;
|
|
||||||
import org.jetbrains.kotlin.resolve.StatementFilter;
|
|
||||||
import org.jetbrains.kotlin.resolve.calls.checkers.CallChecker;
|
|
||||||
import org.jetbrains.kotlin.resolve.calls.context.*;
|
|
||||||
import org.jetbrains.kotlin.resolve.calls.model.MutableDataFlowInfoForArguments;
|
|
||||||
import org.jetbrains.kotlin.resolve.calls.model.MutableResolvedCall;
|
|
||||||
import org.jetbrains.kotlin.resolve.calls.smartcasts.DataFlowInfo;
|
|
||||||
import org.jetbrains.kotlin.resolve.scopes.LexicalScope;
|
|
||||||
import org.jetbrains.kotlin.types.KotlinType;
|
|
||||||
|
|
||||||
import java.util.Collection;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Stores candidates for call resolution.
|
|
||||||
*/
|
|
||||||
public class ResolutionTask<D extends CallableDescriptor, F extends D> extends CallResolutionContext<ResolutionTask<D, F>> {
|
|
||||||
private final Function0<Collection<ResolutionCandidate<D>>> lazyCandidates;
|
|
||||||
private final Collection<MutableResolvedCall<F>> resolvedCalls;
|
|
||||||
public final TracingStrategy tracing;
|
|
||||||
|
|
||||||
private ResolutionTask(
|
|
||||||
@NotNull Function0<Collection<ResolutionCandidate<D>>> lazyCandidates,
|
|
||||||
@NotNull TracingStrategy tracing,
|
|
||||||
@NotNull BindingTrace trace,
|
|
||||||
@NotNull LexicalScope scope,
|
|
||||||
@NotNull Call call,
|
|
||||||
@NotNull KotlinType expectedType,
|
|
||||||
@NotNull DataFlowInfo dataFlowInfo,
|
|
||||||
@NotNull ContextDependency contextDependency,
|
|
||||||
@NotNull CheckArgumentTypesMode checkArguments,
|
|
||||||
@NotNull ResolutionResultsCache resolutionResultsCache,
|
|
||||||
@Nullable MutableDataFlowInfoForArguments dataFlowInfoForArguments,
|
|
||||||
@NotNull CallChecker callChecker,
|
|
||||||
@NotNull StatementFilter statementFilter,
|
|
||||||
@NotNull Collection<MutableResolvedCall<F>> resolvedCalls,
|
|
||||||
boolean isAnnotationContext,
|
|
||||||
boolean isDebuggerContext,
|
|
||||||
boolean collectAllCandidates,
|
|
||||||
@NotNull CallPosition callPosition
|
|
||||||
) {
|
|
||||||
super(trace, scope, call, expectedType, dataFlowInfo, contextDependency, checkArguments, resolutionResultsCache,
|
|
||||||
dataFlowInfoForArguments, callChecker, statementFilter, isAnnotationContext, isDebuggerContext, collectAllCandidates, callPosition);
|
|
||||||
this.lazyCandidates = lazyCandidates;
|
|
||||||
this.resolvedCalls = resolvedCalls;
|
|
||||||
this.tracing = tracing;
|
|
||||||
}
|
|
||||||
|
|
||||||
public ResolutionTask(
|
|
||||||
@NotNull BasicCallResolutionContext context,
|
|
||||||
@NotNull TracingStrategy tracing,
|
|
||||||
@NotNull Function0<Collection<ResolutionCandidate<D>>> lazyCandidates
|
|
||||||
) {
|
|
||||||
this(lazyCandidates, tracing,
|
|
||||||
context.trace, context.scope, context.call,
|
|
||||||
context.expectedType, context.dataFlowInfo, context.contextDependency, context.checkArguments,
|
|
||||||
context.resolutionResultsCache, context.dataFlowInfoForArguments,
|
|
||||||
context.callChecker,
|
|
||||||
context.statementFilter, new SmartList<MutableResolvedCall<F>>(),
|
|
||||||
context.isAnnotationContext, context.isDebuggerContext, context.collectAllCandidates, context.callPosition);
|
|
||||||
}
|
|
||||||
|
|
||||||
@NotNull
|
|
||||||
public Collection<ResolutionCandidate<D>> getCandidates() {
|
|
||||||
return lazyCandidates.invoke();
|
|
||||||
}
|
|
||||||
|
|
||||||
public void addResolvedCall(@NotNull MutableResolvedCall<F> resolvedCall) {
|
|
||||||
resolvedCalls.add(resolvedCall);
|
|
||||||
}
|
|
||||||
|
|
||||||
@NotNull
|
|
||||||
public Collection<MutableResolvedCall<F>> getResolvedCalls() {
|
|
||||||
return resolvedCalls;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
protected ResolutionTask<D, F> create(
|
|
||||||
@NotNull BindingTrace trace,
|
|
||||||
@NotNull LexicalScope scope,
|
|
||||||
@NotNull DataFlowInfo dataFlowInfo,
|
|
||||||
@NotNull KotlinType expectedType,
|
|
||||||
@NotNull ContextDependency contextDependency,
|
|
||||||
@NotNull ResolutionResultsCache resolutionResultsCache,
|
|
||||||
@NotNull StatementFilter statementFilter,
|
|
||||||
boolean collectAllCandidates,
|
|
||||||
@NotNull CallPosition callPosition
|
|
||||||
) {
|
|
||||||
return new ResolutionTask<D, F>(
|
|
||||||
lazyCandidates, tracing, trace, scope, call, expectedType, dataFlowInfo, contextDependency, checkArguments,
|
|
||||||
resolutionResultsCache, dataFlowInfoForArguments,
|
|
||||||
callChecker,
|
|
||||||
statementFilter, resolvedCalls,
|
|
||||||
isAnnotationContext, isDebuggerContext, collectAllCandidates, callPosition);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public String toString() {
|
|
||||||
return lazyCandidates.toString();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
-66
@@ -1,66 +0,0 @@
|
|||||||
/*
|
|
||||||
* Copyright 2010-2015 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.kotlin.resolve.calls.tasks
|
|
||||||
|
|
||||||
import org.jetbrains.kotlin.descriptors.CallableDescriptor
|
|
||||||
import org.jetbrains.kotlin.psi.KtPsiUtil
|
|
||||||
import org.jetbrains.kotlin.resolve.calls.context.BasicCallResolutionContext
|
|
||||||
import org.jetbrains.kotlin.storage.StorageManager
|
|
||||||
import java.util.ArrayList
|
|
||||||
import org.jetbrains.kotlin.utils.toReadOnlyList
|
|
||||||
|
|
||||||
class ResolutionTaskHolder<D : CallableDescriptor, F : D>(
|
|
||||||
private val storageManager: StorageManager,
|
|
||||||
private val basicCallResolutionContext: BasicCallResolutionContext,
|
|
||||||
private val priorityProvider: ResolutionTaskHolder.PriorityProvider<ResolutionCandidate<D>>,
|
|
||||||
private val tracing: TracingStrategy
|
|
||||||
) {
|
|
||||||
private val candidatesList = ArrayList<() -> Collection<ResolutionCandidate<D>>>()
|
|
||||||
private var internalTasks: List<ResolutionTask<D, F>>? = null
|
|
||||||
|
|
||||||
fun addCandidates(lazyCandidates: () -> Collection<ResolutionCandidate<D>>) {
|
|
||||||
assertNotFinished()
|
|
||||||
candidatesList.add(storageManager.createLazyValue { lazyCandidates().toReadOnlyList() })
|
|
||||||
}
|
|
||||||
|
|
||||||
private fun assertNotFinished() {
|
|
||||||
assert(internalTasks == null) { "Can't add candidates after the resulting tasks were computed." }
|
|
||||||
}
|
|
||||||
|
|
||||||
fun getTasks(): List<ResolutionTask<D, F>> {
|
|
||||||
if (internalTasks == null) {
|
|
||||||
val tasks = ArrayList<ResolutionTask<D, F>>()
|
|
||||||
for (priority in (0..priorityProvider.getMaxPriority()).reversed()) {
|
|
||||||
for (candidateIndex in candidatesList.indices) {
|
|
||||||
val lazyCandidates = {
|
|
||||||
candidatesList[candidateIndex]().filter { priorityProvider.getPriority(it) == priority }.toReadOnlyList()
|
|
||||||
}
|
|
||||||
tasks.add(ResolutionTask<D, F>(basicCallResolutionContext, tracing, lazyCandidates))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
internalTasks = tasks
|
|
||||||
}
|
|
||||||
return internalTasks!!
|
|
||||||
}
|
|
||||||
|
|
||||||
interface PriorityProvider<D> {
|
|
||||||
fun getPriority(candidate: D): Int
|
|
||||||
|
|
||||||
fun getMaxPriority(): Int
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,538 +0,0 @@
|
|||||||
/*
|
|
||||||
* Copyright 2010-2016 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.kotlin.resolve.calls.tasks
|
|
||||||
|
|
||||||
import com.google.common.collect.Lists
|
|
||||||
import org.jetbrains.kotlin.descriptors.*
|
|
||||||
import org.jetbrains.kotlin.name.Name
|
|
||||||
import org.jetbrains.kotlin.progress.ProgressIndicatorAndCompilationCanceledStatus
|
|
||||||
import org.jetbrains.kotlin.psi.Call
|
|
||||||
import org.jetbrains.kotlin.resolve.DescriptorUtils
|
|
||||||
import org.jetbrains.kotlin.resolve.calls.callResolverUtil.getUnaryPlusOrMinusOperatorFunctionName
|
|
||||||
import org.jetbrains.kotlin.resolve.calls.callResolverUtil.isConventionCall
|
|
||||||
import org.jetbrains.kotlin.resolve.calls.callResolverUtil.isInfixCall
|
|
||||||
import org.jetbrains.kotlin.resolve.calls.callResolverUtil.isOrOverridesSynthesized
|
|
||||||
import org.jetbrains.kotlin.resolve.calls.callUtil.createLookupLocation
|
|
||||||
import org.jetbrains.kotlin.resolve.calls.context.BasicCallResolutionContext
|
|
||||||
import org.jetbrains.kotlin.resolve.calls.context.ResolutionContext
|
|
||||||
import org.jetbrains.kotlin.resolve.calls.smartcasts.SmartCastManager
|
|
||||||
import org.jetbrains.kotlin.resolve.calls.tasks.ExplicitReceiverKind.*
|
|
||||||
import org.jetbrains.kotlin.resolve.calls.tasks.collectors.CallableDescriptorCollector
|
|
||||||
import org.jetbrains.kotlin.resolve.calls.tasks.collectors.CallableDescriptorCollectors
|
|
||||||
import org.jetbrains.kotlin.resolve.calls.tasks.collectors.filtered
|
|
||||||
import org.jetbrains.kotlin.resolve.calls.util.FakeCallableDescriptorForObject
|
|
||||||
import org.jetbrains.kotlin.resolve.descriptorUtil.hasLowPriorityInOverloadResolution
|
|
||||||
import org.jetbrains.kotlin.resolve.scopes.ImportingScope
|
|
||||||
import org.jetbrains.kotlin.resolve.scopes.LexicalScope
|
|
||||||
import org.jetbrains.kotlin.resolve.scopes.SyntheticScopes
|
|
||||||
import org.jetbrains.kotlin.resolve.scopes.receivers.*
|
|
||||||
import org.jetbrains.kotlin.resolve.scopes.utils.getImplicitReceiversHierarchy
|
|
||||||
import org.jetbrains.kotlin.resolve.scopes.utils.memberScopeAsImportingScope
|
|
||||||
import org.jetbrains.kotlin.resolve.selectMostSpecificInEachOverridableGroup
|
|
||||||
import org.jetbrains.kotlin.storage.StorageManager
|
|
||||||
import org.jetbrains.kotlin.types.ErrorUtils
|
|
||||||
import org.jetbrains.kotlin.types.KotlinType
|
|
||||||
import org.jetbrains.kotlin.types.TypeSubstitutor
|
|
||||||
import org.jetbrains.kotlin.types.checker.KotlinTypeChecker
|
|
||||||
import org.jetbrains.kotlin.types.expressions.ExpressionTypingUtils
|
|
||||||
import org.jetbrains.kotlin.types.isDynamic
|
|
||||||
import org.jetbrains.kotlin.util.OperatorNameConventions
|
|
||||||
|
|
||||||
class TaskPrioritizer(
|
|
||||||
private val storageManager: StorageManager,
|
|
||||||
private val smartCastManager: SmartCastManager,
|
|
||||||
private val dynamicCallableDescriptors: DynamicCallableDescriptors,
|
|
||||||
private val syntheticScopes: SyntheticScopes
|
|
||||||
) {
|
|
||||||
|
|
||||||
fun <D : CallableDescriptor, F : D> computePrioritizedTasks(
|
|
||||||
context: BasicCallResolutionContext,
|
|
||||||
name: Name,
|
|
||||||
tracing: TracingStrategy,
|
|
||||||
callableDescriptorCollectors: CallableDescriptorCollectors<D>
|
|
||||||
): List<ResolutionTask<D, F>> {
|
|
||||||
val explicitReceiver = context.call.explicitReceiver
|
|
||||||
val result = ResolutionTaskHolder<D, F>(storageManager, context, PriorityProviderImpl<D>(context), tracing)
|
|
||||||
val taskPrioritizerContext = TaskPrioritizerContext(name, result, context, context.scope, callableDescriptorCollectors)
|
|
||||||
|
|
||||||
when (explicitReceiver) {
|
|
||||||
is QualifierReceiver -> {
|
|
||||||
val qualifierReceiver: QualifierReceiver = explicitReceiver
|
|
||||||
val receiverScope = LexicalScope.empty(qualifierReceiver.getNestedClassesAndPackageMembersScope().memberScopeAsImportingScope(),
|
|
||||||
qualifierReceiver.descriptor)
|
|
||||||
doComputeTasks(null, taskPrioritizerContext.replaceScope(receiverScope))
|
|
||||||
computeTasksForClassObjectReceiver(qualifierReceiver, taskPrioritizerContext)
|
|
||||||
}
|
|
||||||
is ReceiverValue? -> {
|
|
||||||
doComputeTasks(explicitReceiver, taskPrioritizerContext)
|
|
||||||
|
|
||||||
// Temporary fix for code migration (unaryPlus()/unaryMinus())
|
|
||||||
val unaryConventionName = getUnaryPlusOrMinusOperatorFunctionName(context.call)
|
|
||||||
if (unaryConventionName != null) {
|
|
||||||
val deprecatedName = if (name == OperatorNameConventions.UNARY_PLUS)
|
|
||||||
OperatorNameConventions.PLUS
|
|
||||||
else
|
|
||||||
OperatorNameConventions.MINUS
|
|
||||||
|
|
||||||
val additionalContext = TaskPrioritizerContext(deprecatedName, result, context, context.scope, callableDescriptorCollectors)
|
|
||||||
doComputeTasks(explicitReceiver, additionalContext)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return result.getTasks()
|
|
||||||
}
|
|
||||||
|
|
||||||
private fun <D : CallableDescriptor, F : D> computeTasksForClassObjectReceiver(
|
|
||||||
qualifier: Qualifier,
|
|
||||||
taskPrioritizerContext: TaskPrioritizerContext<D, F>
|
|
||||||
) {
|
|
||||||
if (qualifier is ClassQualifier) {
|
|
||||||
val companionObject = qualifier.classValueReceiver ?: return
|
|
||||||
val classifierDescriptor = qualifier.classifier
|
|
||||||
doComputeTasks(companionObject, taskPrioritizerContext.filterCollectors {
|
|
||||||
when {
|
|
||||||
classifierDescriptor is ClassDescriptor && classifierDescriptor.companionObjectDescriptor != null -> {
|
|
||||||
// nested classes and objects should not be accessible via short reference to companion object
|
|
||||||
it !is ConstructorDescriptor && it !is FakeCallableDescriptorForObject
|
|
||||||
}
|
|
||||||
DescriptorUtils.isEnumEntry(classifierDescriptor) -> {
|
|
||||||
// objects nested in enum should not be accessible via enum entries reference
|
|
||||||
it !is FakeCallableDescriptorForObject
|
|
||||||
}
|
|
||||||
else -> true
|
|
||||||
}
|
|
||||||
})
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private fun <D : CallableDescriptor, F : D> doComputeTasks(receiver: ReceiverValue?, c: TaskPrioritizerContext<D, F>) {
|
|
||||||
ProgressIndicatorAndCompilationCanceledStatus.checkCanceled()
|
|
||||||
|
|
||||||
val receiverWithTypes = ReceiverWithTypes(receiver, c.context)
|
|
||||||
|
|
||||||
val resolveInvoke = c.context.call.dispatchReceiver != null
|
|
||||||
if (resolveInvoke) {
|
|
||||||
addCandidatesForInvoke(receiverWithTypes, c)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
val implicitReceivers = c.scope.getImplicitReceiversHierarchy().map { it.value }
|
|
||||||
if (receiver != null) {
|
|
||||||
addCandidatesForExplicitReceiver(receiverWithTypes, implicitReceivers, c, isExplicit = true)
|
|
||||||
addMembers(receiverWithTypes, c, staticMembers = true, isExplicit = true)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
addCandidatesForNoReceiver(implicitReceivers, c)
|
|
||||||
}
|
|
||||||
|
|
||||||
private inner class ReceiverWithTypes(
|
|
||||||
val value: ReceiverValue?,
|
|
||||||
private val context: ResolutionContext<*>
|
|
||||||
) {
|
|
||||||
val types: Collection<KotlinType> by lazy { smartCastManager.getSmartCastVariants(value!!, context) }
|
|
||||||
}
|
|
||||||
|
|
||||||
private fun <D : CallableDescriptor, F : D> addCandidatesForExplicitReceiver(
|
|
||||||
explicitReceiver: ReceiverWithTypes,
|
|
||||||
implicitReceivers: Collection<ReceiverValue>,
|
|
||||||
c: TaskPrioritizerContext<D, F>,
|
|
||||||
isExplicit: Boolean
|
|
||||||
) {
|
|
||||||
val explicitReceiverTypeIsDynamic = explicitReceiver.value!!.type.isDynamic()
|
|
||||||
|
|
||||||
fun addMembersAndExtensionsWithFilter(filter: (CallableDescriptor) -> Boolean) {
|
|
||||||
// If the explicit receiver is erroneous, an error function is returned by getMembersByName().
|
|
||||||
// An error function should not be sorted out by our custom filters to prevent looking for extension functions.
|
|
||||||
if (explicitReceiver.types.any { it.isError }) return
|
|
||||||
|
|
||||||
addMembers(explicitReceiver, c, staticMembers = false, isExplicit = isExplicit, filter = filter)
|
|
||||||
if (!explicitReceiverTypeIsDynamic) {
|
|
||||||
addExtensionCandidates(explicitReceiver, implicitReceivers, c, isExplicit, filter)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Members and extensions with 'operator' and 'infix' modifiers have higher priority
|
|
||||||
if (isConventionCall(c.context.call)) {
|
|
||||||
addMembersAndExtensionsWithFilter { d: CallableDescriptor -> d is FunctionDescriptor && d.isOperator }
|
|
||||||
}
|
|
||||||
if (isInfixCall(c.context.call)) {
|
|
||||||
addMembersAndExtensionsWithFilter { d: CallableDescriptor -> d is FunctionDescriptor && d.isInfix }
|
|
||||||
}
|
|
||||||
|
|
||||||
addMembers(explicitReceiver, c, staticMembers = false, isExplicit = isExplicit)
|
|
||||||
|
|
||||||
if (explicitReceiverTypeIsDynamic) {
|
|
||||||
addCandidatesForDynamicReceiver(explicitReceiver, implicitReceivers, c, isExplicit)
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
addExtensionCandidates(explicitReceiver, implicitReceivers, c, isExplicit)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private fun <D : CallableDescriptor, F : D> addExtensionCandidates(
|
|
||||||
explicitReceiver: ReceiverWithTypes,
|
|
||||||
implicitReceivers: Collection<ReceiverValue>,
|
|
||||||
c: TaskPrioritizerContext<D, F>,
|
|
||||||
isExplicit: Boolean,
|
|
||||||
filter: ((CallableDescriptor) -> Boolean)? = null
|
|
||||||
) {
|
|
||||||
for (callableDescriptorCollector in c.callableDescriptorCollectors) {
|
|
||||||
//member extensions
|
|
||||||
for (implicitReceiver in implicitReceivers) {
|
|
||||||
addMemberExtensionCandidates(
|
|
||||||
implicitReceiver,
|
|
||||||
explicitReceiver,
|
|
||||||
callableDescriptorCollector,
|
|
||||||
c,
|
|
||||||
createKind(EXTENSION_RECEIVER, isExplicit)
|
|
||||||
)
|
|
||||||
}
|
|
||||||
//extensions
|
|
||||||
c.result.addCandidates {
|
|
||||||
val extensions = callableDescriptorCollector.getExtensionsByName(
|
|
||||||
c.scope, syntheticScopes, c.name, explicitReceiver.types, createLookupLocation(c))
|
|
||||||
val filteredExtensions = if (filter == null) extensions else extensions.filter(filter)
|
|
||||||
|
|
||||||
convertWithImpliedThis(
|
|
||||||
c.scope,
|
|
||||||
explicitReceiver.value,
|
|
||||||
filteredExtensions,
|
|
||||||
createKind(EXTENSION_RECEIVER, isExplicit),
|
|
||||||
c.context.call
|
|
||||||
)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private fun <D : CallableDescriptor, F : D> addMembers(
|
|
||||||
explicitReceiver: ReceiverWithTypes,
|
|
||||||
c: TaskPrioritizerContext<D, F>,
|
|
||||||
staticMembers: Boolean,
|
|
||||||
isExplicit: Boolean,
|
|
||||||
filter: ((CallableDescriptor) -> Boolean)? = null
|
|
||||||
) {
|
|
||||||
for (callableDescriptorCollector in c.callableDescriptorCollectors) {
|
|
||||||
c.result.addCandidates {
|
|
||||||
val members = Lists.newArrayList<ResolutionCandidate<D>>()
|
|
||||||
for (type in explicitReceiver.types) {
|
|
||||||
val membersForThisVariant = if (staticMembers) {
|
|
||||||
callableDescriptorCollector.getStaticMembersByName(type, c.name, createLookupLocation(c))
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
callableDescriptorCollector.getMembersByName(type, c.name, createLookupLocation(c))
|
|
||||||
}
|
|
||||||
val filteredMembers = if (filter == null) membersForThisVariant else membersForThisVariant.filter(filter)
|
|
||||||
|
|
||||||
val dispatchReceiver =
|
|
||||||
if (explicitReceiver.value is ImplicitClassReceiver && type != explicitReceiver.value.type) {
|
|
||||||
CastImplicitClassReceiver(explicitReceiver.value.classDescriptor, type)
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
explicitReceiver.value
|
|
||||||
}
|
|
||||||
convertWithReceivers(
|
|
||||||
filteredMembers,
|
|
||||||
dispatchReceiver,
|
|
||||||
null,
|
|
||||||
members,
|
|
||||||
createKind(DISPATCH_RECEIVER, isExplicit),
|
|
||||||
c.context.call
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
if (explicitReceiver.types.size > 1) {
|
|
||||||
members.retainAll( members.selectMostSpecificInEachOverridableGroup { descriptor } )
|
|
||||||
}
|
|
||||||
|
|
||||||
members
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private fun <D : CallableDescriptor, F : D> addCandidatesForDynamicReceiver(
|
|
||||||
explicitReceiver: ReceiverWithTypes,
|
|
||||||
implicitReceivers: Collection<ReceiverValue>,
|
|
||||||
c: TaskPrioritizerContext<D, F>,
|
|
||||||
isExplicit: Boolean
|
|
||||||
) {
|
|
||||||
val onlyDynamicReceivers = c.replaceCollectors(c.callableDescriptorCollectors.onlyDynamicReceivers<D>())
|
|
||||||
addExtensionCandidates(explicitReceiver, implicitReceivers, onlyDynamicReceivers, isExplicit)
|
|
||||||
|
|
||||||
c.result.addCandidates {
|
|
||||||
val dynamicScope = dynamicCallableDescriptors.createDynamicDescriptorScope(c.context.call, c.scope.ownerDescriptor)
|
|
||||||
|
|
||||||
val dynamicDescriptors = c.callableDescriptorCollectors.flatMap {
|
|
||||||
it.getNonExtensionsByName(dynamicScope.memberScopeAsImportingScope(), c.name, createLookupLocation(c))
|
|
||||||
}
|
|
||||||
|
|
||||||
convertWithReceivers(dynamicDescriptors, explicitReceiver.value, null, createKind(DISPATCH_RECEIVER, isExplicit), c.context.call)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private fun createKind(kind: ExplicitReceiverKind, isExplicit: Boolean): ExplicitReceiverKind {
|
|
||||||
if (isExplicit) return kind
|
|
||||||
return ExplicitReceiverKind.NO_EXPLICIT_RECEIVER
|
|
||||||
}
|
|
||||||
|
|
||||||
private fun <D : CallableDescriptor, F : D> addMemberExtensionCandidates(
|
|
||||||
dispatchReceiver: ReceiverValue,
|
|
||||||
receiverParameter: ReceiverWithTypes,
|
|
||||||
callableDescriptorCollector: CallableDescriptorCollector<D>,
|
|
||||||
c: TaskPrioritizerContext<D, F>,
|
|
||||||
receiverKind: ExplicitReceiverKind
|
|
||||||
) {
|
|
||||||
c.result.addCandidates {
|
|
||||||
val memberExtensions =
|
|
||||||
callableDescriptorCollector.getExtensionsByName(dispatchReceiver.type.memberScope.memberScopeAsImportingScope(), syntheticScopes, c.name, receiverParameter.types, createLookupLocation(c))
|
|
||||||
convertWithReceivers(memberExtensions, dispatchReceiver, receiverParameter.value, receiverKind, c.context.call)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private fun <D : CallableDescriptor, F : D> addCandidatesForNoReceiver(
|
|
||||||
implicitReceivers: Collection<ReceiverValue>,
|
|
||||||
c: TaskPrioritizerContext<D, F>
|
|
||||||
) {
|
|
||||||
val lookupLocation = createLookupLocation(c)
|
|
||||||
|
|
||||||
//locals
|
|
||||||
c.callableDescriptorCollectors.forEach {
|
|
||||||
c.result.addCandidates {
|
|
||||||
convertWithImpliedThisAndNoReceiver(
|
|
||||||
c.scope,
|
|
||||||
it.getLocalNonExtensionsByName(c.scope, c.name, lookupLocation),
|
|
||||||
c.context.call
|
|
||||||
)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
val implicitReceiversWithTypes = implicitReceivers.map { ReceiverWithTypes(it, c.context) }
|
|
||||||
|
|
||||||
//try all implicit receivers as explicit
|
|
||||||
for (implicitReceiver in implicitReceiversWithTypes) {
|
|
||||||
addCandidatesForExplicitReceiver(implicitReceiver, implicitReceivers, c, isExplicit = false)
|
|
||||||
}
|
|
||||||
|
|
||||||
// static members hack
|
|
||||||
c.callableDescriptorCollectors.forEach {
|
|
||||||
c.result.addCandidates {
|
|
||||||
val descriptors = it.getStaticInheritanceByName(c.scope, c.name, lookupLocation)
|
|
||||||
convertWithImpliedThisAndNoReceiver(c.scope, descriptors, c.context.call)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
//nonlocals
|
|
||||||
c.callableDescriptorCollectors.forEach {
|
|
||||||
c.result.addCandidates {
|
|
||||||
val descriptors = it.getNonExtensionsByName(c.scope, c.name, lookupLocation)
|
|
||||||
.filter { c.scope is ImportingScope || !ExpressionTypingUtils.isLocal(c.scope.ownerDescriptor, it) }
|
|
||||||
convertWithImpliedThisAndNoReceiver(c.scope, descriptors, c.context.call)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
//static (only for better error reporting)
|
|
||||||
for (implicitReceiver in implicitReceiversWithTypes) {
|
|
||||||
addMembers(implicitReceiver, c, staticMembers = true, isExplicit = false)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private fun createLookupLocation(c: TaskPrioritizerContext<*, *>) = c.context.call.createLookupLocation()
|
|
||||||
|
|
||||||
private fun <D : CallableDescriptor, F : D> addCandidatesForInvoke(explicitReceiver: ReceiverWithTypes, c: TaskPrioritizerContext<D, F>) {
|
|
||||||
val implicitReceivers = c.scope.getImplicitReceiversHierarchy().map { it.value }
|
|
||||||
|
|
||||||
// For 'a.foo()' where foo has function type,
|
|
||||||
// a is explicitReceiver, foo is variableReceiver.
|
|
||||||
val variableReceiver = c.context.call.dispatchReceiver
|
|
||||||
assert(variableReceiver != null) { "'Invoke' call hasn't got variable receiver" }
|
|
||||||
|
|
||||||
// For invocation a.foo() explicit receiver 'a'
|
|
||||||
// can be a receiver for 'foo' variable
|
|
||||||
// or for 'invoke' function.
|
|
||||||
|
|
||||||
// (1) a.foo + foo.invoke()
|
|
||||||
if (explicitReceiver.value == null) {
|
|
||||||
addCandidatesForExplicitReceiver(ReceiverWithTypes(variableReceiver!!, c.context), implicitReceivers, c, isExplicit = true)
|
|
||||||
}
|
|
||||||
|
|
||||||
// (2) foo + a.invoke()
|
|
||||||
|
|
||||||
// 'invoke' is member extension to explicit receiver while variable receiver is 'this object'
|
|
||||||
//trait A
|
|
||||||
//trait Foo { fun A.invoke() }
|
|
||||||
|
|
||||||
if (explicitReceiver.value != null) {
|
|
||||||
//a.foo()
|
|
||||||
addCandidatesWhenInvokeIsMemberAndExtensionToExplicitReceiver(variableReceiver!!, explicitReceiver, c, BOTH_RECEIVERS)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
// with (a) { foo() }
|
|
||||||
for (implicitReceiver in implicitReceivers) {
|
|
||||||
addCandidatesWhenInvokeIsMemberAndExtensionToExplicitReceiver(variableReceiver!!, ReceiverWithTypes(implicitReceiver, c.context), c, DISPATCH_RECEIVER)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private fun <D : CallableDescriptor, F : D> addCandidatesWhenInvokeIsMemberAndExtensionToExplicitReceiver(
|
|
||||||
dispatchReceiver: ReceiverValue,
|
|
||||||
receiverParameter: ReceiverWithTypes,
|
|
||||||
c: TaskPrioritizerContext<D, F>,
|
|
||||||
receiverKind: ExplicitReceiverKind
|
|
||||||
) {
|
|
||||||
for (callableDescriptorCollector in c.callableDescriptorCollectors) {
|
|
||||||
addMemberExtensionCandidates(dispatchReceiver, receiverParameter, callableDescriptorCollector, c, receiverKind)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private fun <D : CallableDescriptor> convertWithReceivers(
|
|
||||||
descriptors: Collection<D>,
|
|
||||||
dispatchReceiver: ReceiverValue?,
|
|
||||||
extensionReceiver: ReceiverValue?,
|
|
||||||
explicitReceiverKind: ExplicitReceiverKind,
|
|
||||||
call: Call
|
|
||||||
): Collection<ResolutionCandidate<D>> {
|
|
||||||
val result = Lists.newArrayList<ResolutionCandidate<D>>()
|
|
||||||
convertWithReceivers(descriptors, dispatchReceiver, extensionReceiver, result, explicitReceiverKind, call)
|
|
||||||
return result
|
|
||||||
}
|
|
||||||
|
|
||||||
private fun <D : CallableDescriptor> convertWithReceivers(
|
|
||||||
descriptors: Collection<D>,
|
|
||||||
dispatchReceiver: ReceiverValue?,
|
|
||||||
extensionReceiver: ReceiverValue?,
|
|
||||||
result: MutableCollection<ResolutionCandidate<D>>,
|
|
||||||
explicitReceiverKind: ExplicitReceiverKind,
|
|
||||||
call: Call
|
|
||||||
) {
|
|
||||||
for (descriptor in descriptors) {
|
|
||||||
val candidate = ResolutionCandidate.create<D>(call, descriptor)
|
|
||||||
candidate.dispatchReceiver = dispatchReceiver
|
|
||||||
candidate.setReceiverArgument(extensionReceiver)
|
|
||||||
candidate.explicitReceiverKind = explicitReceiverKind
|
|
||||||
result.add(candidate)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private fun <D : CallableDescriptor> convertWithImpliedThisAndNoReceiver(
|
|
||||||
scope: LexicalScope,
|
|
||||||
descriptors: Collection<D>,
|
|
||||||
call: Call,
|
|
||||||
knownSubstitutor: TypeSubstitutor? = null
|
|
||||||
): Collection<ResolutionCandidate<D>> {
|
|
||||||
return convertWithImpliedThis(scope, null, descriptors, NO_EXPLICIT_RECEIVER, call, knownSubstitutor)
|
|
||||||
}
|
|
||||||
|
|
||||||
private fun <D : CallableDescriptor> convertWithImpliedThis(
|
|
||||||
scope: LexicalScope,
|
|
||||||
receiverValue: ReceiverValue?,
|
|
||||||
descriptors: Collection<D>,
|
|
||||||
receiverKind: ExplicitReceiverKind,
|
|
||||||
call: Call,
|
|
||||||
knownSubstitutor: TypeSubstitutor? = null
|
|
||||||
): Collection<ResolutionCandidate<D>> {
|
|
||||||
val result = Lists.newArrayList<ResolutionCandidate<D>>()
|
|
||||||
for (descriptor in descriptors) {
|
|
||||||
val candidate = ResolutionCandidate.create(call, descriptor, null, receiverValue, receiverKind, knownSubstitutor)
|
|
||||||
if (setImpliedThis(scope, candidate, knownSubstitutor)) {
|
|
||||||
result.add(candidate)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return result
|
|
||||||
}
|
|
||||||
|
|
||||||
private fun <D : CallableDescriptor> setImpliedThis(
|
|
||||||
scope: LexicalScope,
|
|
||||||
candidate: ResolutionCandidate<D>,
|
|
||||||
knownSubstitutor: TypeSubstitutor?
|
|
||||||
): Boolean {
|
|
||||||
val dispatchReceiver = candidate.descriptor.dispatchReceiverParameter ?: return true
|
|
||||||
val substitutedDispatchReceiver = knownSubstitutor?.let {
|
|
||||||
dispatchReceiver.substitute(it) ?: return false
|
|
||||||
} ?: dispatchReceiver
|
|
||||||
|
|
||||||
val receivers = scope.getImplicitReceiversHierarchy()
|
|
||||||
for (receiver in receivers) {
|
|
||||||
if (KotlinTypeChecker.DEFAULT.isSubtypeOf(receiver.type, substitutedDispatchReceiver.type)) {
|
|
||||||
candidate.dispatchReceiver = substitutedDispatchReceiver.value
|
|
||||||
return true
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
|
|
||||||
fun <D : CallableDescriptor, F : D> computePrioritizedTasksFromCandidates(
|
|
||||||
context: BasicCallResolutionContext,
|
|
||||||
candidates: Collection<ResolutionCandidate<D>>,
|
|
||||||
tracing: TracingStrategy
|
|
||||||
): List<ResolutionTask<D, F>> {
|
|
||||||
val result = ResolutionTaskHolder<D, F>(storageManager, context, PriorityProviderImpl<D>(context), tracing)
|
|
||||||
result.addCandidates {
|
|
||||||
candidates
|
|
||||||
}
|
|
||||||
return result.getTasks()
|
|
||||||
}
|
|
||||||
|
|
||||||
private class PriorityProviderImpl<D : CallableDescriptor>(private val context: BasicCallResolutionContext) :
|
|
||||||
ResolutionTaskHolder.PriorityProvider<ResolutionCandidate<D>> {
|
|
||||||
|
|
||||||
override fun getPriority(candidate: ResolutionCandidate<D>)
|
|
||||||
= if (hasImplicitDynamicReceiver(candidate)) 0
|
|
||||||
else (if (!isVisible(candidate) || hasLowPriority(candidate)) 0 else 2) + (if (isSynthesized(candidate)) 0 else 1)
|
|
||||||
|
|
||||||
override fun getMaxPriority() = 3
|
|
||||||
|
|
||||||
private fun isVisible(candidate: ResolutionCandidate<D>?): Boolean {
|
|
||||||
if (candidate == null) return false
|
|
||||||
val candidateDescriptor = candidate.descriptor
|
|
||||||
if (ErrorUtils.isError(candidateDescriptor)) return true
|
|
||||||
return Visibilities.isVisible(candidate.dispatchReceiver, candidateDescriptor, context.scope.ownerDescriptor)
|
|
||||||
}
|
|
||||||
|
|
||||||
private fun hasLowPriority(candidate: ResolutionCandidate<D>?): Boolean {
|
|
||||||
if (candidate == null) return false
|
|
||||||
return candidate.descriptor.hasLowPriorityInOverloadResolution()
|
|
||||||
}
|
|
||||||
|
|
||||||
private fun isSynthesized(candidate: ResolutionCandidate<D>): Boolean {
|
|
||||||
val descriptor = candidate.descriptor
|
|
||||||
return descriptor is CallableMemberDescriptor && isOrOverridesSynthesized(descriptor)
|
|
||||||
}
|
|
||||||
|
|
||||||
fun hasImplicitDynamicReceiver(candidate: ResolutionCandidate<D>): Boolean {
|
|
||||||
return (!candidate.explicitReceiverKind.isDispatchReceiver || candidate.call.explicitReceiver == null)
|
|
||||||
&& candidate.descriptor.isDynamic()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private class TaskPrioritizerContext<D : CallableDescriptor, F : D>(
|
|
||||||
val name: Name,
|
|
||||||
val result: ResolutionTaskHolder<D, F>,
|
|
||||||
val context: BasicCallResolutionContext,
|
|
||||||
val scope: LexicalScope,
|
|
||||||
val callableDescriptorCollectors: CallableDescriptorCollectors<D>
|
|
||||||
) {
|
|
||||||
fun replaceScope(newScope: LexicalScope): TaskPrioritizerContext<D, F> {
|
|
||||||
return TaskPrioritizerContext(name, result, context, newScope, callableDescriptorCollectors)
|
|
||||||
}
|
|
||||||
|
|
||||||
fun replaceCollectors(newCollectors: CallableDescriptorCollectors<D>): TaskPrioritizerContext<D, F> {
|
|
||||||
return TaskPrioritizerContext(name, result, context, scope, newCollectors)
|
|
||||||
}
|
|
||||||
|
|
||||||
fun filterCollectors(filter: (D) -> Boolean): TaskPrioritizerContext<D, F> {
|
|
||||||
return TaskPrioritizerContext(name, result, context, scope, callableDescriptorCollectors.filtered(filter))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,5 +1,5 @@
|
|||||||
/*
|
/*
|
||||||
* Copyright 2010-2015 JetBrains s.r.o.
|
* Copyright 2010-2016 JetBrains s.r.o.
|
||||||
*
|
*
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
* you may not use this file except in compliance with the License.
|
* you may not use this file except in compliance with the License.
|
||||||
@@ -25,12 +25,8 @@ import org.jetbrains.kotlin.lexer.KtTokens
|
|||||||
import org.jetbrains.kotlin.name.Name
|
import org.jetbrains.kotlin.name.Name
|
||||||
import org.jetbrains.kotlin.psi.*
|
import org.jetbrains.kotlin.psi.*
|
||||||
import org.jetbrains.kotlin.resolve.DescriptorFactory
|
import org.jetbrains.kotlin.resolve.DescriptorFactory
|
||||||
import org.jetbrains.kotlin.resolve.calls.tasks.collectors.CallableDescriptorCollector
|
|
||||||
import org.jetbrains.kotlin.resolve.calls.tasks.collectors.CallableDescriptorCollectors
|
|
||||||
import org.jetbrains.kotlin.resolve.descriptorUtil.builtIns
|
import org.jetbrains.kotlin.resolve.descriptorUtil.builtIns
|
||||||
import org.jetbrains.kotlin.resolve.scopes.HierarchicalScope
|
|
||||||
import org.jetbrains.kotlin.resolve.scopes.MemberScopeImpl
|
import org.jetbrains.kotlin.resolve.scopes.MemberScopeImpl
|
||||||
import org.jetbrains.kotlin.resolve.scopes.SyntheticScopes
|
|
||||||
import org.jetbrains.kotlin.resolve.scopes.receivers.TransientReceiver
|
import org.jetbrains.kotlin.resolve.scopes.receivers.TransientReceiver
|
||||||
import org.jetbrains.kotlin.types.KotlinType
|
import org.jetbrains.kotlin.types.KotlinType
|
||||||
import org.jetbrains.kotlin.types.Variance
|
import org.jetbrains.kotlin.types.Variance
|
||||||
@@ -227,14 +223,3 @@ fun DeclarationDescriptor.isDynamic(): Boolean {
|
|||||||
return dispatchReceiverParameter != null && dispatchReceiverParameter.type.isDynamic()
|
return dispatchReceiverParameter != null && dispatchReceiverParameter.type.isDynamic()
|
||||||
}
|
}
|
||||||
|
|
||||||
class CollectorForDynamicReceivers<D: CallableDescriptor>(val delegate: CallableDescriptorCollector<D>) : CallableDescriptorCollector<D> by delegate {
|
|
||||||
override fun getExtensionsByName(scope: HierarchicalScope, syntheticScopes: SyntheticScopes, name: Name, receiverTypes: Collection<KotlinType>, location: LookupLocation): Collection<D> {
|
|
||||||
return delegate.getExtensionsByName(scope, syntheticScopes, name, receiverTypes, location).filter {
|
|
||||||
it.extensionReceiverParameter?.type?.isDynamic() ?: false
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fun <D : CallableDescriptor> CallableDescriptorCollectors<D>.onlyDynamicReceivers(): CallableDescriptorCollectors<D> {
|
|
||||||
return CallableDescriptorCollectors(this.map { CollectorForDynamicReceivers(it) })
|
|
||||||
}
|
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
/*
|
/*
|
||||||
* Copyright 2010-2015 JetBrains s.r.o.
|
* Copyright 2010-2016 JetBrains s.r.o.
|
||||||
*
|
*
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
* you may not use this file except in compliance with the License.
|
* you may not use this file except in compliance with the License.
|
||||||
@@ -22,12 +22,9 @@ import org.jetbrains.kotlin.load.java.structure.impl.JavaClassImpl
|
|||||||
import org.jetbrains.kotlin.load.java.structure.impl.JavaTypeImpl
|
import org.jetbrains.kotlin.load.java.structure.impl.JavaTypeImpl
|
||||||
import org.jetbrains.kotlin.name.FqName
|
import org.jetbrains.kotlin.name.FqName
|
||||||
import org.jetbrains.kotlin.name.Name
|
import org.jetbrains.kotlin.name.Name
|
||||||
import org.jetbrains.kotlin.psi.debugText.getDebugText
|
|
||||||
import org.jetbrains.kotlin.renderer.DescriptorRenderer
|
import org.jetbrains.kotlin.renderer.DescriptorRenderer
|
||||||
import org.jetbrains.kotlin.resolve.DescriptorUtils
|
import org.jetbrains.kotlin.resolve.DescriptorUtils
|
||||||
import org.jetbrains.kotlin.resolve.calls.context.BasicCallResolutionContext
|
|
||||||
import org.jetbrains.kotlin.resolve.calls.tasks.ResolutionCandidate
|
import org.jetbrains.kotlin.resolve.calls.tasks.ResolutionCandidate
|
||||||
import org.jetbrains.kotlin.resolve.calls.tasks.ResolutionTaskHolder
|
|
||||||
import org.jetbrains.kotlin.resolve.scopes.MemberScope
|
import org.jetbrains.kotlin.resolve.scopes.MemberScope
|
||||||
import org.jetbrains.kotlin.serialization.ProtoBuf
|
import org.jetbrains.kotlin.serialization.ProtoBuf
|
||||||
import org.jetbrains.kotlin.serialization.deserialization.DeserializationContext
|
import org.jetbrains.kotlin.serialization.deserialization.DeserializationContext
|
||||||
@@ -189,7 +186,6 @@ class LazyOperationsLog(
|
|||||||
}.appendQuoted()
|
}.appendQuoted()
|
||||||
}
|
}
|
||||||
o is ResolutionCandidate<*> -> DescriptorRenderer.COMPACT.render(o.descriptor).appendQuoted()
|
o is ResolutionCandidate<*> -> DescriptorRenderer.COMPACT.render(o.descriptor).appendQuoted()
|
||||||
o is ResolutionTaskHolder<*, *> -> o.field<BasicCallResolutionContext>("basicCallResolutionContext").call.callElement.getDebugText().appendQuoted()
|
|
||||||
}
|
}
|
||||||
return sb.toString()
|
return sb.toString()
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user