Refactoring autocasts

This commit is contained in:
Andrey Breslav
2011-10-06 20:20:10 +04:00
parent b6fbbd84f5
commit 114763b0b2
12 changed files with 207 additions and 131 deletions
@@ -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() {}
}
@@ -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;
}
}