Refactoring autocasts
This commit is contained in:
@@ -7,7 +7,6 @@ import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
import org.jetbrains.jet.lang.descriptors.*;
|
||||
import org.jetbrains.jet.lang.psi.*;
|
||||
import org.jetbrains.jet.lang.resolve.calls.ResolvedCall;
|
||||
import org.jetbrains.jet.lang.types.JetType;
|
||||
import org.jetbrains.jet.lexer.JetKeywordToken;
|
||||
import org.jetbrains.jet.resolve.DescriptorRenderer;
|
||||
@@ -351,7 +350,7 @@ public interface Errors {
|
||||
};
|
||||
|
||||
ParameterizedDiagnosticFactory3<String, JetType, JetType> RESULT_TYPE_MISMATCH = ParameterizedDiagnosticFactory3.create(ERROR, "{0} must return {1} but returns {2}");
|
||||
ParameterizedDiagnosticFactory3<String, String, String> UNSAFE_INFIX_CALL = ParameterizedDiagnosticFactory3.create(ERROR, "Infix call corresponds to a dot-qualified call ''{0}.{1}({2})' which is not allowed on a nullable receiver ''{0}''. Use '?.'-qualified call instead");
|
||||
ParameterizedDiagnosticFactory3<String, String, String> UNSAFE_INFIX_CALL = ParameterizedDiagnosticFactory3.create(ERROR, "Infix call corresponds to a dot-qualified call ''{0}.{1}({2})'' which is not allowed on a nullable receiver ''{0}''. Use '?.'-qualified call instead");
|
||||
|
||||
AmbiguousDescriptorDiagnosticFactory OVERLOAD_RESOLUTION_AMBIGUITY = new AmbiguousDescriptorDiagnosticFactory("Overload resolution ambiguity: {0}");
|
||||
AmbiguousDescriptorDiagnosticFactory NONE_APPLICABLE = new AmbiguousDescriptorDiagnosticFactory("None of the following functions can be called with the arguments supplied: {0}");
|
||||
|
||||
@@ -9,7 +9,6 @@ import org.jetbrains.jet.lang.psi.*;
|
||||
import org.jetbrains.jet.lang.resolve.calls.ResolvedCall;
|
||||
import org.jetbrains.jet.lang.resolve.constants.CompileTimeConstant;
|
||||
import org.jetbrains.jet.lang.resolve.scopes.JetScope;
|
||||
import org.jetbrains.jet.lang.resolve.scopes.receivers.ReceiverDescriptor;
|
||||
import org.jetbrains.jet.lang.types.DeferredType;
|
||||
import org.jetbrains.jet.lang.types.JetType;
|
||||
import org.jetbrains.jet.util.CommonSuppliers;
|
||||
@@ -21,14 +20,15 @@ import java.util.Collection;
|
||||
* @author abreslav
|
||||
*/
|
||||
public interface BindingContext {
|
||||
WritableSlice<JetElement, ReceiverDescriptor> RECEIVER = Slices.createSimpleSlice("RECEIVER");
|
||||
|
||||
WritableSlice<JetAnnotationEntry, AnnotationDescriptor> ANNOTATION = Slices.createSimpleSlice("ANNOTATION");
|
||||
|
||||
WritableSlice<JetExpression, CompileTimeConstant<?>> COMPILE_TIME_VALUE = Slices.createSimpleSlice("COMPILE_TIME_VALUE");
|
||||
WritableSlice<JetTypeReference, JetType> TYPE = Slices.createSimpleSlice("TYPE");
|
||||
WritableSlice<JetExpression, JetType> EXPRESSION_TYPE = new BasicWritableSlice<JetExpression, JetType>("EXPRESSION_TYPE", RewritePolicy.DO_NOTHING);
|
||||
|
||||
WritableSlice<JetReferenceExpression, DeclarationDescriptor> REFERENCE_TARGET = new BasicWritableSlice<JetReferenceExpression, DeclarationDescriptor>("REFERENCE_TARGET", RewritePolicy.DO_NOTHING);
|
||||
WritableSlice<JetElement, ResolvedCall<? extends CallableDescriptor>> RESOLVED_CALL = new BasicWritableSlice<JetElement, ResolvedCall<? extends CallableDescriptor>>("RESOLVED_CALL", RewritePolicy.DO_NOTHING);
|
||||
|
||||
WritableSlice<JetReferenceExpression, Collection<? extends ResolvedCall<? extends DeclarationDescriptor>>> AMBIGUOUS_REFERENCE_TARGET = new BasicWritableSlice<JetReferenceExpression, Collection<? extends ResolvedCall<? extends DeclarationDescriptor>>>("AMBIGUOUS_REFERENCE_TARGET", RewritePolicy.DO_NOTHING);
|
||||
|
||||
WritableSlice<JetExpression, FunctionDescriptor> LOOP_RANGE_ITERATOR = Slices.createSimpleSlice("LOOP_RANGE_ITERATOR");
|
||||
|
||||
@@ -26,7 +26,7 @@ public class AutoCastUtils {
|
||||
|
||||
private AutoCastUtils() {}
|
||||
|
||||
public static List<? extends ReceiverDescriptor> getAutocastVariants(@NotNull final BindingContext bindingContext, @NotNull final DataFlowInfo dataFlowInfo, @NotNull ReceiverDescriptor receiverToCast) {
|
||||
public static List<? extends ReceiverDescriptor> getAutoCastVariants(@NotNull final BindingContext bindingContext, @NotNull final DataFlowInfo dataFlowInfo, @NotNull ReceiverDescriptor receiverToCast) {
|
||||
return receiverToCast.accept(new ReceiverDescriptorVisitor<List<? extends ReceiverDescriptor>, Object>() {
|
||||
@Override
|
||||
public List<? extends ReceiverDescriptor> visitNoReceiver(ReceiverDescriptor noReceiver, Object data) {
|
||||
|
||||
@@ -25,7 +25,6 @@ import static org.jetbrains.jet.lang.diagnostics.Errors.*;
|
||||
import static org.jetbrains.jet.lang.resolve.BindingContext.*;
|
||||
import static org.jetbrains.jet.lang.resolve.calls.ResolvedCall.MAP_TO_CANDIDATE;
|
||||
import static org.jetbrains.jet.lang.resolve.calls.ResolvedCall.MAP_TO_RESULT;
|
||||
import static org.jetbrains.jet.lang.resolve.scopes.receivers.ReceiverDescriptor.NO_RECEIVER;
|
||||
import static org.jetbrains.jet.lang.types.JetTypeInferrer.NO_EXPECTED_TYPE;
|
||||
|
||||
/**
|
||||
@@ -150,7 +149,7 @@ public class CallResolver {
|
||||
trace.report(NO_CONSTRUCTOR.on(reportAbsenceOn));
|
||||
return checkArgumentTypesAndFail(trace, scope, call);
|
||||
}
|
||||
prioritizedTasks.add(new ResolutionTask<FunctionDescriptor>(ResolvedCall.convertCollection(constructors), NO_RECEIVER, call));
|
||||
prioritizedTasks.add(new ResolutionTask<FunctionDescriptor>(ResolvedCall.convertCollection(constructors), call, DataFlowInfo.getEmpty()));
|
||||
}
|
||||
else {
|
||||
// trace.getErrorHandler().genericError(calleeExpression.getNode(), "Not a class");
|
||||
@@ -170,7 +169,7 @@ public class CallResolver {
|
||||
trace.report(NO_CONSTRUCTOR.on(reportAbsenceOn));
|
||||
return checkArgumentTypesAndFail(trace, scope, call);
|
||||
}
|
||||
prioritizedTasks = Collections.singletonList(new ResolutionTask<FunctionDescriptor>(ResolvedCall.convertCollection(constructors), NO_RECEIVER, call));
|
||||
prioritizedTasks = Collections.singletonList(new ResolutionTask<FunctionDescriptor>(ResolvedCall.convertCollection(constructors), call, DataFlowInfo.getEmpty()));
|
||||
}
|
||||
else {
|
||||
throw new UnsupportedOperationException("Type argument inference not implemented for " + call.getText());
|
||||
@@ -211,17 +210,16 @@ public class CallResolver {
|
||||
OverloadResolutionResults<D> resultsForFirstNonemptyCandidateSet = null;
|
||||
TracingStrategy tracing = new TracingStrategy() {
|
||||
@Override
|
||||
public void bindReference(@NotNull BindingTrace trace, @NotNull ReceiverDescriptor receiver, @NotNull CallableDescriptor descriptor) {
|
||||
trace.record(REFERENCE_TARGET, reference, descriptor);
|
||||
trace.record(RECEIVER, reference, receiver);
|
||||
if (receiver instanceof AutoCastReceiver) {
|
||||
AutoCastReceiver autoCastReceiver = (AutoCastReceiver) receiver;
|
||||
ReceiverDescriptor original = autoCastReceiver.getOriginal();
|
||||
if (original instanceof ExpressionReceiver) {
|
||||
ExpressionReceiver expressionReceiver = (ExpressionReceiver) original;
|
||||
trace.record(AUTOCAST, expressionReceiver.getExpression(), autoCastReceiver.getType());
|
||||
}
|
||||
}
|
||||
public <D extends CallableDescriptor> void bindReference(@NotNull BindingTrace trace, @NotNull ResolvedCall<D> resolvedCall) {
|
||||
D descriptor = resolvedCall.getCandidateDescriptor();
|
||||
// if (descriptor instanceof VariableAsFunctionDescriptor) {
|
||||
// VariableAsFunctionDescriptor variableAsFunctionDescriptor = (VariableAsFunctionDescriptor) descriptor;
|
||||
// trace.record(REFERENCE_TARGET, reference, variableAsFunctionDescriptor.getVariableDescriptor());
|
||||
// }
|
||||
// else {
|
||||
trace.record(REFERENCE_TARGET, reference, descriptor);
|
||||
// }
|
||||
trace.record(RESOLVED_CALL, reference, resolvedCall);
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -334,7 +332,7 @@ public class CallResolver {
|
||||
TemporaryBindingTrace temporaryTrace = TemporaryBindingTrace.create(trace);
|
||||
candidateCall.setTrace(temporaryTrace);
|
||||
|
||||
tracing.bindReference(temporaryTrace, task.getReceiver(), candidate);
|
||||
tracing.bindReference(temporaryTrace, candidateCall);
|
||||
|
||||
if (ErrorUtils.isError(candidate)) {
|
||||
successfulCandidates.add(candidateCall.setResultingDescriptor(candidate));
|
||||
@@ -356,7 +354,7 @@ public class CallResolver {
|
||||
if (task.getTypeArguments().isEmpty()) {
|
||||
if (candidate.getTypeParameters().isEmpty()) {
|
||||
if (checkValueArgumentTypes(scope, temporaryTrace, argumentsToParameters, dirty, Functions.<ValueParameterDescriptor>identity())
|
||||
&& checkReceiver(task, tracing, candidate, temporaryTrace)) {
|
||||
&& checkReceiver(candidateCall, tracing, candidate, temporaryTrace)) {
|
||||
successfulCandidates.add(candidateCall.setResultingDescriptor(candidate));
|
||||
}
|
||||
else {
|
||||
@@ -387,12 +385,12 @@ public class CallResolver {
|
||||
}
|
||||
}
|
||||
|
||||
checkReceiverAbsence(task, tracing, candidate, temporaryTrace);
|
||||
checkReceiverAbsence(candidateCall, tracing, candidate, temporaryTrace);
|
||||
// Error is already reported if something is missing
|
||||
ReceiverDescriptor receiver = task.getReceiver();
|
||||
ReceiverDescriptor receiverParameter = candidateCall.getReceiverParameter();
|
||||
ReceiverDescriptor candidateReceiver = candidate.getReceiver();
|
||||
if (receiver.exists() && candidateReceiver.exists()) {
|
||||
constraintSystem.addSubtypingConstraint(receiver.getType(), candidateReceiver.getType());
|
||||
if (receiverParameter.exists() && candidateReceiver.exists()) {
|
||||
constraintSystem.addSubtypingConstraint(receiverParameter.getType(), candidateReceiver.getType());
|
||||
}
|
||||
|
||||
if (expectedType != NO_EXPECTED_TYPE) {
|
||||
@@ -442,7 +440,7 @@ public class CallResolver {
|
||||
|
||||
Function<ValueParameterDescriptor, ValueParameterDescriptor> mapFunction = createMapFunction(substitutedFunctionDescriptor);
|
||||
if (checkValueArgumentTypes(scope, temporaryTrace, argumentsToParameters, dirty, mapFunction)
|
||||
&& checkReceiver(task, tracing, substitutedFunctionDescriptor, temporaryTrace)) {
|
||||
&& checkReceiver(candidateCall, tracing, substitutedFunctionDescriptor, temporaryTrace)) {
|
||||
successfulCandidates.add(candidateCall.setResultingDescriptor(substitutedFunctionDescriptor));
|
||||
}
|
||||
else {
|
||||
@@ -460,6 +458,9 @@ public class CallResolver {
|
||||
dirtyCandidates.add(candidateCall);
|
||||
}
|
||||
task.performAdvancedChecks(candidate, temporaryTrace, tracing);
|
||||
|
||||
recordAutoCastIfNecessary(candidateCall.getReceiverParameter(), candidateCall.getTrace());
|
||||
recordAutoCastIfNecessary(candidateCall.getThisObject(), candidateCall.getTrace());
|
||||
}
|
||||
|
||||
OverloadResolutionResults<D> results = computeResultAndReportErrors(trace, tracing, successfulCandidates, failedCandidates, dirtyCandidates);
|
||||
@@ -469,6 +470,17 @@ public class CallResolver {
|
||||
return results;
|
||||
}
|
||||
|
||||
private void recordAutoCastIfNecessary(ReceiverDescriptor receiver, BindingTrace trace) {
|
||||
if (receiver instanceof AutoCastReceiver) {
|
||||
AutoCastReceiver autoCastReceiver = (AutoCastReceiver) receiver;
|
||||
ReceiverDescriptor original = autoCastReceiver.getOriginal();
|
||||
if (original instanceof ExpressionReceiver) {
|
||||
ExpressionReceiver expressionReceiver = (ExpressionReceiver) original;
|
||||
trace.record(AUTOCAST, expressionReceiver.getExpression(), autoCastReceiver.getType());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void checkTypesWithNoCallee(BindingTrace trace, JetScope scope, List<JetTypeProjection> typeArguments, List<? extends ValueArgument> valueArguments, List<JetExpression> functionLiteralArguments) {
|
||||
for (ValueArgument valueArgument : valueArguments) {
|
||||
JetExpression argumentExpression = valueArgument.getArgumentExpression();
|
||||
@@ -501,9 +513,9 @@ public class CallResolver {
|
||||
};
|
||||
}
|
||||
|
||||
private <D extends CallableDescriptor> boolean checkReceiver(ResolutionTask<D> task, TracingStrategy tracing, D candidate, TemporaryBindingTrace temporaryTrace) {
|
||||
if (!checkReceiverAbsence(task, tracing, candidate, temporaryTrace)) return false;
|
||||
ReceiverDescriptor receiver = task.getReceiver();
|
||||
private <D extends CallableDescriptor> boolean checkReceiver(ResolvedCall<D> resolvedCall, TracingStrategy tracing, D candidate, TemporaryBindingTrace temporaryTrace) {
|
||||
if (!checkReceiverAbsence(resolvedCall, tracing, candidate, temporaryTrace)) return false;
|
||||
ReceiverDescriptor receiver = resolvedCall.getReceiverParameter();
|
||||
ReceiverDescriptor candidateReceiver = candidate.getReceiver();
|
||||
if (receiver.exists()
|
||||
&& candidateReceiver.exists()
|
||||
@@ -514,8 +526,8 @@ public class CallResolver {
|
||||
return true;
|
||||
}
|
||||
|
||||
private <D extends CallableDescriptor> boolean checkReceiverAbsence(ResolutionTask<D> task, TracingStrategy tracing, D candidate, TemporaryBindingTrace temporaryTrace) {
|
||||
ReceiverDescriptor receiver = task.getReceiver();
|
||||
private <D extends CallableDescriptor> boolean checkReceiverAbsence(ResolvedCall<D> resolvedCall, TracingStrategy tracing, D candidate, TemporaryBindingTrace temporaryTrace) {
|
||||
ReceiverDescriptor receiver = resolvedCall.getReceiverParameter();
|
||||
ReceiverDescriptor candidateReceiver = candidate.getReceiver();
|
||||
if (receiver.exists()) {
|
||||
if (!candidateReceiver.exists()) {
|
||||
@@ -669,25 +681,24 @@ public class CallResolver {
|
||||
|
||||
@NotNull
|
||||
public OverloadResolutionResults<FunctionDescriptor> resolveExactSignature(@NotNull JetScope scope, @NotNull ReceiverDescriptor receiver, @NotNull String name, @NotNull List<JetType> parameterTypes) {
|
||||
List<FunctionDescriptor> result = findCandidatesByExactSignature(scope, receiver, name, parameterTypes);
|
||||
List<ResolvedCall<FunctionDescriptor>> result = findCandidatesByExactSignature(scope, receiver, name, parameterTypes);
|
||||
|
||||
BindingTraceContext trace = new BindingTraceContext();
|
||||
TemporaryBindingTrace temporaryBindingTrace = TemporaryBindingTrace.create(trace);
|
||||
Set<ResolvedCall<FunctionDescriptor>> candidates = Sets.newLinkedHashSet();
|
||||
for (FunctionDescriptor functionDescriptor : result) {
|
||||
ResolvedCall<FunctionDescriptor> resolvedCall = ResolvedCall.create(functionDescriptor);
|
||||
candidates.add(resolvedCall.setResultingDescriptor(functionDescriptor));
|
||||
resolvedCall.setTrace(temporaryBindingTrace);
|
||||
for (ResolvedCall<FunctionDescriptor> call : result) {
|
||||
call.setTrace(temporaryBindingTrace);
|
||||
candidates.add(call);
|
||||
}
|
||||
return computeResultAndReportErrors(trace, TracingStrategy.EMPTY, candidates, Collections.<ResolvedCall<FunctionDescriptor>>emptySet(), Collections.<ResolvedCall<FunctionDescriptor>>emptySet());
|
||||
}
|
||||
|
||||
private List<FunctionDescriptor> findCandidatesByExactSignature(JetScope scope, ReceiverDescriptor receiver, String name, List<JetType> parameterTypes) {
|
||||
List<FunctionDescriptor> result = Lists.newArrayList();
|
||||
private List<ResolvedCall<FunctionDescriptor>> findCandidatesByExactSignature(JetScope scope, ReceiverDescriptor receiver, String name, List<JetType> parameterTypes) {
|
||||
List<ResolvedCall<FunctionDescriptor>> result = Lists.newArrayList();
|
||||
if (receiver.exists()) {
|
||||
Set<FunctionDescriptor> extensionFunctionDescriptors = scope.getFunctions(name);
|
||||
List<FunctionDescriptor> nonlocal = Lists.newArrayList();
|
||||
List<FunctionDescriptor> local = Lists.newArrayList();
|
||||
Collection<ResolvedCall<FunctionDescriptor>> extensionFunctionDescriptors = ResolvedCall.convertCollection(scope.getFunctions(name));
|
||||
List<ResolvedCall<FunctionDescriptor>> nonlocal = Lists.newArrayList();
|
||||
List<ResolvedCall<FunctionDescriptor>> local = Lists.newArrayList();
|
||||
TaskPrioritizer.splitLexicallyLocalDescriptors(extensionFunctionDescriptors, scope.getContainingDeclaration(), local, nonlocal);
|
||||
|
||||
|
||||
@@ -695,7 +706,7 @@ public class CallResolver {
|
||||
return result;
|
||||
}
|
||||
|
||||
Set<FunctionDescriptor> functionDescriptors = receiver.getType().getMemberScope().getFunctions(name);
|
||||
Collection<ResolvedCall<FunctionDescriptor>> functionDescriptors = ResolvedCall.convertCollection(receiver.getType().getMemberScope().getFunctions(name));
|
||||
if (lookupExactSignature(functionDescriptors, parameterTypes, result)) {
|
||||
return result;
|
||||
|
||||
@@ -704,32 +715,34 @@ public class CallResolver {
|
||||
return result;
|
||||
}
|
||||
else {
|
||||
lookupExactSignature(scope.getFunctions(name), parameterTypes, result);
|
||||
lookupExactSignature(ResolvedCall.convertCollection(scope.getFunctions(name)), parameterTypes, result);
|
||||
return result;
|
||||
}
|
||||
}
|
||||
|
||||
private boolean lookupExactSignature(Set<FunctionDescriptor> candidates, List<JetType> parameterTypes, List<FunctionDescriptor> result) {
|
||||
private boolean lookupExactSignature(Collection<ResolvedCall<FunctionDescriptor>> candidates, List<JetType> parameterTypes, List<ResolvedCall<FunctionDescriptor>> result) {
|
||||
boolean found = false;
|
||||
for (FunctionDescriptor functionDescriptor : candidates) {
|
||||
for (ResolvedCall<FunctionDescriptor> resolvedCall : candidates) {
|
||||
FunctionDescriptor functionDescriptor = resolvedCall.getResultingDescriptor();
|
||||
if (functionDescriptor.getReceiver().exists()) continue;
|
||||
if (!functionDescriptor.getTypeParameters().isEmpty()) continue;
|
||||
if (!checkValueParameters(functionDescriptor, parameterTypes)) continue;
|
||||
result.add(functionDescriptor);
|
||||
result.add(resolvedCall);
|
||||
found = true;
|
||||
}
|
||||
return found;
|
||||
}
|
||||
|
||||
private boolean findExtensionFunctions(Collection<FunctionDescriptor> candidates, ReceiverDescriptor receiver, List<JetType> parameterTypes, List<FunctionDescriptor> result) {
|
||||
private boolean findExtensionFunctions(Collection<ResolvedCall<FunctionDescriptor>> candidates, ReceiverDescriptor receiver, List<JetType> parameterTypes, List<ResolvedCall<FunctionDescriptor>> result) {
|
||||
boolean found = false;
|
||||
for (FunctionDescriptor functionDescriptor : candidates) {
|
||||
for (ResolvedCall<FunctionDescriptor> resolvedCall : candidates) {
|
||||
FunctionDescriptor functionDescriptor = resolvedCall.getResultingDescriptor();
|
||||
ReceiverDescriptor functionReceiver = functionDescriptor.getReceiver();
|
||||
if (!functionReceiver.exists()) continue;
|
||||
if (!functionDescriptor.getTypeParameters().isEmpty()) continue;
|
||||
if (!semanticServices.getTypeChecker().isSubtypeOf(receiver.getType(), functionReceiver.getType())) continue;
|
||||
if (!checkValueParameters(functionDescriptor, parameterTypes))continue;
|
||||
result.add(functionDescriptor);
|
||||
result.add(resolvedCall);
|
||||
found = true;
|
||||
}
|
||||
return found;
|
||||
|
||||
@@ -0,0 +1,10 @@
|
||||
package org.jetbrains.jet.lang.resolve.calls;
|
||||
|
||||
/**
|
||||
* @author abreslav
|
||||
*/
|
||||
public class DefaultValueArgument implements ResolvedValueArgument {
|
||||
public static final DefaultValueArgument DEFAULT = new DefaultValueArgument();
|
||||
|
||||
DefaultValueArgument() {}
|
||||
}
|
||||
+20
@@ -0,0 +1,20 @@
|
||||
package org.jetbrains.jet.lang.resolve.calls;
|
||||
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.jet.lang.psi.JetExpression;
|
||||
|
||||
/**
|
||||
* @author abreslav
|
||||
*/
|
||||
public class ExpressionValueArgument implements ResolvedValueArgument {
|
||||
private final JetExpression expression;
|
||||
|
||||
public ExpressionValueArgument(@NotNull JetExpression expression) {
|
||||
this.expression = expression;
|
||||
}
|
||||
|
||||
@NotNull
|
||||
public JetExpression getExpression() {
|
||||
return expression;
|
||||
}
|
||||
}
|
||||
@@ -7,7 +7,7 @@ import org.jetbrains.jet.lang.psi.JetExpression;
|
||||
import org.jetbrains.jet.lang.psi.JetTypeProjection;
|
||||
import org.jetbrains.jet.lang.psi.ValueArgument;
|
||||
import org.jetbrains.jet.lang.resolve.BindingTrace;
|
||||
import org.jetbrains.jet.lang.resolve.scopes.receivers.ReceiverDescriptor;
|
||||
import org.jetbrains.jet.lang.types.DataFlowInfo;
|
||||
|
||||
import java.util.Collection;
|
||||
import java.util.List;
|
||||
@@ -17,31 +17,36 @@ import java.util.List;
|
||||
*/
|
||||
/*package*/ class ResolutionTask<D extends CallableDescriptor> {
|
||||
private final Collection<ResolvedCall<D>> candidates;
|
||||
private final ReceiverDescriptor receiver;
|
||||
private final List<JetTypeProjection> typeArguments;
|
||||
private final List<? extends ValueArgument> valueArguments;
|
||||
private final List<JetExpression> functionLiteralArguments;
|
||||
private final DataFlowInfo dataFlowInfo;
|
||||
private DescriptorCheckStrategy checkingStrategy;
|
||||
|
||||
public ResolutionTask(
|
||||
@NotNull Collection<ResolvedCall<D>> candidates,
|
||||
@NotNull ReceiverDescriptor receiver,
|
||||
@NotNull List<JetTypeProjection> typeArguments,
|
||||
@NotNull List<? extends ValueArgument> valueArguments,
|
||||
@NotNull List<JetExpression> functionLiteralArguments) {
|
||||
@NotNull List<JetExpression> functionLiteralArguments,
|
||||
@NotNull DataFlowInfo dataFlowInfo) {
|
||||
this.candidates = candidates;
|
||||
this.receiver = receiver;
|
||||
this.typeArguments = typeArguments;
|
||||
this.valueArguments = valueArguments;
|
||||
this.functionLiteralArguments = functionLiteralArguments;
|
||||
this.dataFlowInfo = dataFlowInfo;
|
||||
}
|
||||
|
||||
public ResolutionTask(
|
||||
@NotNull Collection<ResolvedCall<D>> candidates,
|
||||
@NotNull ReceiverDescriptor receiver,
|
||||
@NotNull Call call
|
||||
@NotNull Call call,
|
||||
@NotNull DataFlowInfo dataFlowInfo
|
||||
) {
|
||||
this(candidates, receiver, call.getTypeArguments(), call.getValueArguments(), call.getFunctionLiteralArguments());
|
||||
this(candidates, call.getTypeArguments(), call.getValueArguments(), call.getFunctionLiteralArguments(), dataFlowInfo);
|
||||
}
|
||||
|
||||
@NotNull
|
||||
public DataFlowInfo getDataFlowInfo() {
|
||||
return dataFlowInfo;
|
||||
}
|
||||
|
||||
@NotNull
|
||||
@@ -49,11 +54,6 @@ import java.util.List;
|
||||
return candidates;
|
||||
}
|
||||
|
||||
@NotNull
|
||||
public ReceiverDescriptor getReceiver() {
|
||||
return receiver;
|
||||
}
|
||||
|
||||
@NotNull
|
||||
public List<JetTypeProjection> getTypeArguments() {
|
||||
return typeArguments;
|
||||
|
||||
@@ -4,7 +4,6 @@ import com.google.common.collect.Lists;
|
||||
import com.google.common.collect.Maps;
|
||||
import com.intellij.util.Function;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
import org.jetbrains.jet.lang.descriptors.CallableDescriptor;
|
||||
import org.jetbrains.jet.lang.descriptors.TypeParameterDescriptor;
|
||||
import org.jetbrains.jet.lang.descriptors.ValueParameterDescriptor;
|
||||
@@ -16,6 +15,8 @@ import java.util.Collection;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
import static org.jetbrains.jet.lang.resolve.scopes.receivers.ReceiverDescriptor.NO_RECEIVER;
|
||||
|
||||
/**
|
||||
* @author abreslav
|
||||
*/
|
||||
@@ -51,8 +52,8 @@ public class ResolvedCall<D extends CallableDescriptor> {
|
||||
|
||||
private final D candidateDescriptor;
|
||||
private D resultingDescriptor; // Probably substituted
|
||||
private ReceiverDescriptor thisObject; // receiver object of a method
|
||||
private ReceiverDescriptor receiverParameter; // receiver of an extension function
|
||||
private ReceiverDescriptor thisObject = NO_RECEIVER; // receiver object of a method
|
||||
private ReceiverDescriptor receiverParameter = NO_RECEIVER; // receiver of an extension function
|
||||
private final Map<TypeParameterDescriptor, JetType> typeArguments = Maps.newHashMap();
|
||||
private final Map<ValueParameterDescriptor, JetType> autoCasts = Maps.newHashMap();
|
||||
private final Map<ValueParameterDescriptor, ResolvedValueArgument> valueArguments = Maps.newHashMap();
|
||||
@@ -101,7 +102,7 @@ public class ResolvedCall<D extends CallableDescriptor> {
|
||||
autoCasts.put(parameter, target);
|
||||
}
|
||||
|
||||
@Nullable
|
||||
@NotNull
|
||||
public ReceiverDescriptor getReceiverParameter() {
|
||||
return receiverParameter;
|
||||
}
|
||||
@@ -110,7 +111,7 @@ public class ResolvedCall<D extends CallableDescriptor> {
|
||||
this.receiverParameter = receiverParameter;
|
||||
}
|
||||
|
||||
@Nullable
|
||||
@NotNull
|
||||
public ReceiverDescriptor getThisObject() {
|
||||
return thisObject;
|
||||
}
|
||||
|
||||
@@ -2,15 +2,13 @@ package org.jetbrains.jet.lang.resolve.calls;
|
||||
|
||||
import com.google.common.collect.Lists;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.jet.lang.descriptors.CallableDescriptor;
|
||||
import org.jetbrains.jet.lang.descriptors.DeclarationDescriptor;
|
||||
import org.jetbrains.jet.lang.descriptors.FunctionDescriptor;
|
||||
import org.jetbrains.jet.lang.descriptors.ValueParameterDescriptor;
|
||||
import org.jetbrains.jet.lang.descriptors.*;
|
||||
import org.jetbrains.jet.lang.psi.Call;
|
||||
import org.jetbrains.jet.lang.resolve.BindingContext;
|
||||
import org.jetbrains.jet.lang.resolve.scopes.JetScope;
|
||||
import org.jetbrains.jet.lang.resolve.scopes.receivers.ReceiverDescriptor;
|
||||
import org.jetbrains.jet.lang.types.DataFlowInfo;
|
||||
import org.jetbrains.jet.lang.types.JetType;
|
||||
|
||||
import java.util.Collection;
|
||||
import java.util.List;
|
||||
@@ -22,15 +20,15 @@ import static org.jetbrains.jet.lang.resolve.scopes.receivers.ReceiverDescriptor
|
||||
*/
|
||||
/*package*/ abstract class TaskPrioritizer<D extends CallableDescriptor> {
|
||||
|
||||
public static <T extends DeclarationDescriptor> void splitLexicallyLocalDescriptors(
|
||||
Collection<? extends T> allDescriptors, DeclarationDescriptor containerOfTheCurrentLocality, List<? super T> local, List<? super T> nonlocal) {
|
||||
public static <D extends CallableDescriptor> void splitLexicallyLocalDescriptors(
|
||||
Collection<ResolvedCall<D>> allDescriptors, DeclarationDescriptor containerOfTheCurrentLocality, Collection<ResolvedCall<D>> local, Collection<ResolvedCall<D>> nonlocal) {
|
||||
|
||||
for (T descriptor : allDescriptors) {
|
||||
if (isLocal(containerOfTheCurrentLocality, descriptor)) {
|
||||
local.add(descriptor);
|
||||
for (ResolvedCall<D> resolvedCall : allDescriptors) {
|
||||
if (isLocal(containerOfTheCurrentLocality, resolvedCall.getCandidateDescriptor())) {
|
||||
local.add(resolvedCall);
|
||||
}
|
||||
else {
|
||||
nonlocal.add(descriptor);
|
||||
nonlocal.add(resolvedCall);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -47,7 +45,7 @@ import static org.jetbrains.jet.lang.resolve.scopes.receivers.ReceiverDescriptor
|
||||
*
|
||||
* local extension prevail over members (and members prevail over all non-local extensions)
|
||||
*/
|
||||
public static boolean isLocal(DeclarationDescriptor containerOfTheCurrentLocality, DeclarationDescriptor candidate) {
|
||||
private static boolean isLocal(DeclarationDescriptor containerOfTheCurrentLocality, DeclarationDescriptor candidate) {
|
||||
if (candidate instanceof ValueParameterDescriptor) {
|
||||
return true;
|
||||
}
|
||||
@@ -72,75 +70,105 @@ import static org.jetbrains.jet.lang.resolve.scopes.receivers.ReceiverDescriptor
|
||||
// return result;
|
||||
// }
|
||||
|
||||
public List<ResolutionTask<D>> computePrioritizedTasks(@NotNull JetScope scope, @NotNull ReceiverDescriptor receiver, @NotNull Call call, @NotNull String name, @NotNull BindingContext bindingContext, @NotNull DataFlowInfo dataFlowInfo) {
|
||||
public List<ResolutionTask<D>> computePrioritizedTasks(@NotNull JetScope scope, @NotNull ReceiverDescriptor explicitReceiver, @NotNull Call call, @NotNull String name, @NotNull BindingContext bindingContext, @NotNull DataFlowInfo dataFlowInfo) {
|
||||
List<ResolutionTask<D>> result = Lists.newArrayList();
|
||||
|
||||
doComputeTasks(scope, receiver, call, name, result);
|
||||
doComputeTasks(scope, explicitReceiver, call, name, result, DataFlowInfo.getEmpty());
|
||||
|
||||
// ReceiverDescriptor receiverToCast = receiver.exists() ? receiver : scope.getImplicitReceiver();
|
||||
// if (receiverToCast.exists()) {
|
||||
// for (ReceiverDescriptor castReceiver : AutoCastUtils.getAutocastVariants(bindingContext, dataFlowInfo, receiverToCast)) {
|
||||
// doComputeTasks(scope, castReceiver, call, name, result);
|
||||
// }
|
||||
// }
|
||||
ReceiverDescriptor receiverToCast = explicitReceiver.exists() ? explicitReceiver : scope.getImplicitReceiver();
|
||||
if (receiverToCast.exists()) {
|
||||
doComputeTasks(scope, receiverToCast, call, name, result, dataFlowInfo);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
private void doComputeTasks(JetScope scope, ReceiverDescriptor receiver, Call call, String name, List<ResolutionTask<D>> result) {
|
||||
private void doComputeTasks(JetScope scope, ReceiverDescriptor explicitReceiver, Call call, String name, List<ResolutionTask<D>> result, @NotNull DataFlowInfo dataFlowInfo) {
|
||||
List<ReceiverDescriptor> implicitReceivers = Lists.newArrayList();
|
||||
scope.getImplicitReceiversHierarchy(implicitReceivers);
|
||||
if (receiver.exists()) {
|
||||
Collection<D> extensionFunctions = getExtensionsByName(scope, name);
|
||||
List<D> nonlocals = Lists.newArrayList();
|
||||
List<D> locals = Lists.newArrayList();
|
||||
if (explicitReceiver.exists()) {
|
||||
Collection<ResolvedCall<D>> extensionFunctions = convertWithImpliedThis(explicitReceiver, getExtensionsByName(scope, name));
|
||||
List<ResolvedCall<D>> nonlocals = Lists.newArrayList();
|
||||
List<ResolvedCall<D>> locals = Lists.newArrayList();
|
||||
//noinspection unchecked,RedundantTypeArguments
|
||||
TaskPrioritizer.<D>splitLexicallyLocalDescriptors(extensionFunctions, scope.getContainingDeclaration(), locals, nonlocals);
|
||||
|
||||
Collection<D> members = getMembersByName(receiver, name);
|
||||
// AutoCastUtils.getAutoCastVariants(bindingContext, dataFlowInfo, receiverToCast)
|
||||
Collection<D> members = getMembersByName(explicitReceiver.getType(), name);
|
||||
|
||||
addTask(result, receiver, call, locals);
|
||||
addTask(result, NO_RECEIVER, call, members);
|
||||
addTask(result, call, locals, dataFlowInfo);
|
||||
addTask(result, call, convertWithReceivers(members, explicitReceiver, NO_RECEIVER), dataFlowInfo);
|
||||
|
||||
for (ReceiverDescriptor implicitReceiver : implicitReceivers) {
|
||||
Collection<D> memberExtensions = getExtensionsByName(implicitReceiver.getType().getMemberScope(), name);
|
||||
addTask(result, receiver, call, memberExtensions);
|
||||
addTask(result, call, convertWithReceivers(memberExtensions, implicitReceiver, explicitReceiver), dataFlowInfo);
|
||||
}
|
||||
|
||||
addTask(result, receiver, call, nonlocals);
|
||||
addTask(result, call, nonlocals, dataFlowInfo);
|
||||
}
|
||||
else {
|
||||
Collection<D> functions = getNonExtensionsByName(scope, name);
|
||||
Collection<ResolvedCall<D>> functions = convertWithImpliedThis(explicitReceiver, getNonExtensionsByName(scope, name));
|
||||
|
||||
List<D> nonlocals = Lists.newArrayList();
|
||||
List<D> locals = Lists.newArrayList();
|
||||
List<ResolvedCall<D>> nonlocals = Lists.newArrayList();
|
||||
List<ResolvedCall<D>> locals = Lists.newArrayList();
|
||||
//noinspection unchecked,RedundantTypeArguments
|
||||
TaskPrioritizer.<D>splitLexicallyLocalDescriptors(functions, scope.getContainingDeclaration(), locals, nonlocals);
|
||||
|
||||
addTask(result, receiver, call, locals);
|
||||
addTask(result, call, locals, dataFlowInfo);
|
||||
|
||||
for (ReceiverDescriptor implicitReceiver : implicitReceivers) {
|
||||
doComputeTasks(scope, implicitReceiver, call, name, result);
|
||||
doComputeTasks(scope, implicitReceiver, call, name, result, dataFlowInfo);
|
||||
}
|
||||
|
||||
addTask(result, receiver, call, nonlocals);
|
||||
addTask(result, call, nonlocals, dataFlowInfo);
|
||||
}
|
||||
}
|
||||
|
||||
private void addTask(@NotNull List<ResolutionTask<D>> result, @NotNull ReceiverDescriptor receiver, @NotNull Call call, @NotNull Collection<D> candidateDescriptors) {
|
||||
if (candidateDescriptors.isEmpty()) return;
|
||||
result.add(createTask(receiver, call, ResolvedCall.convertCollection(candidateDescriptors)));
|
||||
private Collection<ResolvedCall<D>> convertWithReceivers(Collection<D> descriptors, ReceiverDescriptor thisObject, ReceiverDescriptor receiverParameter) {
|
||||
Collection<ResolvedCall<D>> result = Lists.newArrayList();
|
||||
for (D extension : descriptors) {
|
||||
ResolvedCall<D> resolvedCall = ResolvedCall.create(extension);
|
||||
resolvedCall.setThisObject(thisObject);
|
||||
resolvedCall.setReceiverParameter(receiverParameter);
|
||||
result.add(resolvedCall);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
private Collection<ResolvedCall<D>> convertWithImpliedThis(ReceiverDescriptor receiverParameter, Collection<D> descriptors) {
|
||||
Collection<ResolvedCall<D>> result = Lists.newArrayList();
|
||||
for (D extension : descriptors) {
|
||||
ResolvedCall<D> resolvedCall = ResolvedCall.create(extension);
|
||||
resolvedCall.setReceiverParameter(receiverParameter);
|
||||
setImpliedThis(resolvedCall);
|
||||
result.add(resolvedCall);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
private void setImpliedThis(ResolvedCall<D> resolvedCall) {
|
||||
ReceiverDescriptor thisObject;
|
||||
DeclarationDescriptor containingDeclaration = resolvedCall.getCandidateDescriptor().getContainingDeclaration();
|
||||
if (containingDeclaration instanceof ClassDescriptor) {
|
||||
ClassDescriptor classDescriptor = (ClassDescriptor) containingDeclaration;
|
||||
thisObject = classDescriptor.getImplicitReceiver();
|
||||
}
|
||||
else {
|
||||
thisObject = NO_RECEIVER;
|
||||
}
|
||||
resolvedCall.setThisObject(thisObject);
|
||||
}
|
||||
|
||||
private void addTask(@NotNull List<ResolutionTask<D>> result, @NotNull Call call, @NotNull Collection<ResolvedCall<D>> candidates, @NotNull DataFlowInfo dataFlowInfo) {
|
||||
if (candidates.isEmpty()) return;
|
||||
result.add(new ResolutionTask<D>(candidates, call, dataFlowInfo));
|
||||
}
|
||||
|
||||
@NotNull
|
||||
protected abstract Collection<D> getNonExtensionsByName(JetScope scope, String name);
|
||||
|
||||
@NotNull
|
||||
protected abstract Collection<D> getMembersByName(@NotNull ReceiverDescriptor receiver, String name);
|
||||
protected abstract Collection<D> getMembersByName(@NotNull JetType receiver, String name);
|
||||
|
||||
@NotNull
|
||||
protected abstract Collection<D> getExtensionsByName(JetScope scope, String name);
|
||||
|
||||
@NotNull
|
||||
protected abstract ResolutionTask<D> createTask(ReceiverDescriptor receiver, Call call, Collection<ResolvedCall<D>> candidates);
|
||||
|
||||
}
|
||||
|
||||
@@ -3,9 +3,7 @@ package org.jetbrains.jet.lang.resolve.calls;
|
||||
import com.google.common.collect.Sets;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.jet.lang.descriptors.*;
|
||||
import org.jetbrains.jet.lang.psi.Call;
|
||||
import org.jetbrains.jet.lang.resolve.scopes.JetScope;
|
||||
import org.jetbrains.jet.lang.resolve.scopes.receivers.ReceiverDescriptor;
|
||||
import org.jetbrains.jet.lang.types.ErrorUtils;
|
||||
import org.jetbrains.jet.lang.types.JetStandardClasses;
|
||||
import org.jetbrains.jet.lang.types.JetType;
|
||||
@@ -41,8 +39,8 @@ public class TaskPrioritizers {
|
||||
|
||||
@NotNull
|
||||
@Override
|
||||
protected Collection<FunctionDescriptor> getMembersByName(@NotNull ReceiverDescriptor receiver, String name) {
|
||||
JetScope receiverScope = receiver.getType().getMemberScope();
|
||||
protected Collection<FunctionDescriptor> getMembersByName(@NotNull JetType receiverType, String name) {
|
||||
JetScope receiverScope = receiverType.getMemberScope();
|
||||
Set<FunctionDescriptor> members = Sets.newHashSet(receiverScope.getFunctions(name));
|
||||
addConstructors(receiverScope, name, members);
|
||||
addVariableAsFunction(receiverScope, name, members, false);
|
||||
@@ -63,12 +61,6 @@ public class TaskPrioritizers {
|
||||
return extensionFunctions;
|
||||
}
|
||||
|
||||
@NotNull
|
||||
@Override
|
||||
protected ResolutionTask<FunctionDescriptor> createTask(@NotNull ReceiverDescriptor receiver, Call call, Collection<ResolvedCall<FunctionDescriptor>> candidates) {
|
||||
return new ResolutionTask<FunctionDescriptor>(candidates, receiver, call);
|
||||
}
|
||||
|
||||
private void addConstructors(JetScope scope, String name, Collection<FunctionDescriptor> functions) {
|
||||
ClassifierDescriptor classifier = scope.getClassifier(name);
|
||||
if (classifier instanceof ClassDescriptor && !ErrorUtils.isError(classifier.getTypeConstructor())) {
|
||||
@@ -105,8 +97,8 @@ public class TaskPrioritizers {
|
||||
|
||||
@NotNull
|
||||
@Override
|
||||
protected Collection<VariableDescriptor> getMembersByName(@NotNull ReceiverDescriptor receiver, String name) {
|
||||
VariableDescriptor variable = receiver.getType().getMemberScope().getVariable(name);
|
||||
protected Collection<VariableDescriptor> getMembersByName(@NotNull JetType receiverType, String name) {
|
||||
VariableDescriptor variable = receiverType.getMemberScope().getVariable(name);
|
||||
if (variable != null) {
|
||||
return Collections.singleton(variable);
|
||||
}
|
||||
@@ -122,11 +114,5 @@ public class TaskPrioritizers {
|
||||
}
|
||||
return Collections.emptyList();
|
||||
}
|
||||
|
||||
@NotNull
|
||||
@Override
|
||||
protected ResolutionTask<VariableDescriptor> createTask(@NotNull ReceiverDescriptor receiver, Call call, Collection<ResolvedCall<VariableDescriptor>> candidates) {
|
||||
return new ResolutionTask<VariableDescriptor>(candidates, receiver, call);
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
@@ -15,7 +15,7 @@ import java.util.Set;
|
||||
/*package*/ interface TracingStrategy {
|
||||
TracingStrategy EMPTY = new TracingStrategy() {
|
||||
@Override
|
||||
public void bindReference(@NotNull BindingTrace trace, @NotNull ReceiverDescriptor receiver, @NotNull CallableDescriptor descriptor) {}
|
||||
public <D extends CallableDescriptor> void bindReference(@NotNull BindingTrace trace, @NotNull ResolvedCall<D> resolvedCall) {}
|
||||
|
||||
@Override
|
||||
public void unresolvedReference(@NotNull BindingTrace trace) {}
|
||||
@@ -48,7 +48,7 @@ import java.util.Set;
|
||||
public void typeInferenceFailed(@NotNull BindingTrace trace) {}
|
||||
};
|
||||
|
||||
void bindReference(@NotNull BindingTrace trace, @NotNull ReceiverDescriptor receiver, @NotNull CallableDescriptor descriptor);
|
||||
<D extends CallableDescriptor> void bindReference(@NotNull BindingTrace trace, @NotNull ResolvedCall<D> resolvedCall);
|
||||
|
||||
void unresolvedReference(@NotNull BindingTrace trace);
|
||||
|
||||
|
||||
@@ -0,0 +1,19 @@
|
||||
package org.jetbrains.jet.lang.resolve.calls;
|
||||
|
||||
import com.google.common.collect.Lists;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.jet.lang.psi.JetExpression;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* @author abreslav
|
||||
*/
|
||||
public class VarargValueArgument implements ResolvedValueArgument {
|
||||
private final List<JetExpression> values = Lists.newArrayList();
|
||||
|
||||
@NotNull
|
||||
public List<JetExpression> getValues() {
|
||||
return values;
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user