KT-1151 Code completion for not imported extension functions - ignore parameters

This commit is contained in:
Nikolay Krasko
2012-02-28 20:36:39 +04:00
parent 0a669b9c01
commit 67dc9ba6e3
13 changed files with 199 additions and 88 deletions
@@ -25,29 +25,21 @@ import org.jetbrains.annotations.Nullable;
import org.jetbrains.jet.lang.descriptors.CallableDescriptor; import org.jetbrains.jet.lang.descriptors.CallableDescriptor;
import org.jetbrains.jet.lang.descriptors.DeclarationDescriptor; import org.jetbrains.jet.lang.descriptors.DeclarationDescriptor;
import org.jetbrains.jet.lang.descriptors.NamespaceDescriptor; import org.jetbrains.jet.lang.descriptors.NamespaceDescriptor;
import org.jetbrains.jet.lang.descriptors.TypeParameterDescriptor;
import org.jetbrains.jet.lang.psi.JetExpression; import org.jetbrains.jet.lang.psi.JetExpression;
import org.jetbrains.jet.lang.psi.JetImportDirective; import org.jetbrains.jet.lang.psi.JetImportDirective;
import org.jetbrains.jet.lang.psi.JetNamespaceHeader; import org.jetbrains.jet.lang.psi.JetNamespaceHeader;
import org.jetbrains.jet.lang.psi.JetSimpleNameExpression; import org.jetbrains.jet.lang.psi.JetSimpleNameExpression;
import org.jetbrains.jet.lang.resolve.BindingContext; import org.jetbrains.jet.lang.resolve.BindingContext;
import org.jetbrains.jet.lang.resolve.calls.inference.ConstraintResolutionListener; import org.jetbrains.jet.lang.resolve.calls.CallResolver;
import org.jetbrains.jet.lang.resolve.calls.inference.ConstraintSystem;
import org.jetbrains.jet.lang.resolve.calls.inference.ConstraintSystemImpl;
import org.jetbrains.jet.lang.resolve.calls.inference.ConstraintSystemSolution;
import org.jetbrains.jet.lang.resolve.scopes.JetScope; import org.jetbrains.jet.lang.resolve.scopes.JetScope;
import org.jetbrains.jet.lang.resolve.scopes.JetScopeUtils; import org.jetbrains.jet.lang.resolve.scopes.JetScopeUtils;
import org.jetbrains.jet.lang.resolve.scopes.receivers.ExpressionReceiver; import org.jetbrains.jet.lang.resolve.scopes.receivers.ExpressionReceiver;
import org.jetbrains.jet.lang.resolve.scopes.receivers.ReceiverDescriptor; import org.jetbrains.jet.lang.resolve.scopes.receivers.ReceiverDescriptor;
import org.jetbrains.jet.lang.types.JetType; import org.jetbrains.jet.lang.types.JetType;
import org.jetbrains.jet.lang.types.NamespaceType; import org.jetbrains.jet.lang.types.NamespaceType;
import org.jetbrains.jet.lang.types.TypeUtils;
import org.jetbrains.jet.lang.types.Variance;
import java.util.*; import java.util.*;
import static org.jetbrains.jet.lang.resolve.calls.inference.ConstraintType.RECEIVER;
/** /**
* @author Nikolay Krasko, Alefas * @author Nikolay Krasko, Alefas
*/ */
@@ -146,7 +138,9 @@ public final class TipsManager {
return false; return false;
} }
for (ReceiverDescriptor receiverDescriptor : result) { for (ReceiverDescriptor receiverDescriptor : result) {
if (checkReceiverResolution(receiverDescriptor, callableDescriptor)) return false; if (CallResolver.checkIsExtensionCallable(receiverDescriptor, callableDescriptor)) {
return false;
}
} }
return true; return true;
} }
@@ -183,51 +177,51 @@ public final class TipsManager {
new Predicate<CallableDescriptor>() { new Predicate<CallableDescriptor>() {
@Override @Override
public boolean apply(CallableDescriptor callableDescriptor) { public boolean apply(CallableDescriptor callableDescriptor) {
return checkReceiverResolution(receiverDescriptor, callableDescriptor); return CallResolver.checkIsExtensionCallable(receiverDescriptor, callableDescriptor);
} }
})); }));
return descriptorsSet; return descriptorsSet;
} }
/* // /*
* Checks if receiver declaration could be resolved to call expected receiver. // * Checks if receiver declaration could be resolved to call expected receiver.
*/ // */
private static boolean checkReceiverResolution ( // private static boolean checkReceiverResolution (
@NotNull ReceiverDescriptor expectedReceiver, // @NotNull ReceiverDescriptor expectedReceiver,
@NotNull CallableDescriptor receiverArgument // @NotNull CallableDescriptor receiverArgument
) { // ) {
JetType type = expectedReceiver.getType(); // JetType type = expectedReceiver.getType();
if (checkReceiverResolution(expectedReceiver, type, receiverArgument)) return true; // if (checkReceiverResolution(expectedReceiver, type, receiverArgument)) return true;
if (type.isNullable()) { // if (type.isNullable()) {
JetType notNullableType = TypeUtils.makeNotNullable(type); // JetType notNullableType = TypeUtils.makeNotNullable(type);
if (checkReceiverResolution(expectedReceiver, notNullableType, receiverArgument)) return true; // if (checkReceiverResolution(expectedReceiver, notNullableType, receiverArgument)) return true;
} // }
return false; // return false;
} // }
//
private static boolean checkReceiverResolution ( // private static boolean checkReceiverResolution (
@NotNull ReceiverDescriptor expectedReceiver, // @NotNull ReceiverDescriptor expectedReceiver,
@NotNull JetType receiverType, // @NotNull JetType receiverType,
@NotNull CallableDescriptor receiverArgument // @NotNull CallableDescriptor receiverArgument
) { // ) {
ConstraintSystem constraintSystem = new ConstraintSystemImpl(ConstraintResolutionListener.DO_NOTHING); // ConstraintSystem constraintSystem = new ConstraintSystemImpl(ConstraintResolutionListener.DO_NOTHING);
for (TypeParameterDescriptor typeParameterDescriptor : receiverArgument.getTypeParameters()) { // for (TypeParameterDescriptor typeParameterDescriptor : receiverArgument.getTypeParameters()) {
constraintSystem.registerTypeVariable(typeParameterDescriptor, Variance.INVARIANT); // constraintSystem.registerTypeVariable(typeParameterDescriptor, Variance.INVARIANT);
} // }
//
ReceiverDescriptor receiverParameter = receiverArgument.getReceiverParameter(); // ReceiverDescriptor receiverParameter = receiverArgument.getReceiverParameter();
if (expectedReceiver.exists() && receiverParameter.exists()) { // if (expectedReceiver.exists() && receiverParameter.exists()) {
constraintSystem.addSubtypingConstraint( // constraintSystem.addSubtypingConstraint(
RECEIVER.assertSubtyping(receiverType, receiverParameter.getType())); // RECEIVER.assertSubtyping(receiverType, receiverParameter.getType()));
} // }
else if (expectedReceiver.exists() || receiverParameter.exists()) { // else if (expectedReceiver.exists() || receiverParameter.exists()) {
// Only one of receivers exist // // Only one of receivers exist
return false; // return false;
} // }
//
ConstraintSystemSolution solution = constraintSystem.solve(); // ConstraintSystemSolution solution = constraintSystem.solve();
return solution.getStatus().isSuccessful(); // return solution.getStatus().isSuccessful();
} // }
} }
@@ -140,7 +140,9 @@ public class CallMaker {
} }
} }
public static Call makeCallWithExpressions(@NotNull JetElement callElement, @NotNull ReceiverDescriptor explicitReceiver, @Nullable ASTNode callOperationNode, @NotNull JetExpression calleeExpression, @NotNull List<JetExpression> argumentExpressions) { public static Call makeCallWithExpressions(@NotNull JetElement callElement, @NotNull ReceiverDescriptor explicitReceiver,
@Nullable ASTNode callOperationNode, @NotNull JetExpression calleeExpression,
@NotNull List<JetExpression> argumentExpressions) {
List<ValueArgument> arguments = Lists.newArrayList(); List<ValueArgument> arguments = Lists.newArrayList();
for (JetExpression argumentExpression : argumentExpressions) { for (JetExpression argumentExpression : argumentExpressions) {
arguments.add(makeValueArgument(argumentExpression, calleeExpression)); arguments.add(makeValueArgument(argumentExpression, calleeExpression));
@@ -113,6 +113,39 @@ public class CallResolver {
return doResolveCall(trace, scope, call, expectedType, tasks, functionReference); return doResolveCall(trace, scope, call, expectedType, tasks, functionReference);
} }
/**
* Get all function from the given scope with the given name and check is they could be satisfied for call on given
* receiver.
*
* @param trace
* @param scope
* @param call
* @param name
* @return
*/
public List<FunctionDescriptor> resolveCallsByReceiver(
@NotNull BindingTrace trace,
@NotNull JetScope scope,
@NotNull final Call call,
@NotNull String name) {
List<ResolutionTask<FunctionDescriptor>> tasks = TaskPrioritizers.FUNCTION_TASK_PRIORITIZER.computePrioritizedTasks(
scope, call, name, trace.getBindingContext(), dataFlowInfo);
ArrayList<FunctionDescriptor> functionDescriptors = new ArrayList<FunctionDescriptor>();
for (ResolutionTask<FunctionDescriptor> task : tasks) {
Collection<ResolvedCallImpl<FunctionDescriptor>> candidates = task.getCandidates();
for (ResolvedCallImpl<FunctionDescriptor> candidate : candidates) {
if (checkIsExtensionCallable(call.getExplicitReceiver(), candidate.getCandidateDescriptor())) {
functionDescriptors.add(candidate.getCandidateDescriptor());
}
}
}
return functionDescriptors;
}
@NotNull @NotNull
private OverloadResolutionResults<FunctionDescriptor> resolveSimpleCallToFunctionDescriptor( private OverloadResolutionResults<FunctionDescriptor> resolveSimpleCallToFunctionDescriptor(
@NotNull BindingTrace trace, @NotNull BindingTrace trace,
@@ -366,7 +399,11 @@ public class CallResolver {
if (callElement instanceof JetBinaryExpression) { if (callElement instanceof JetBinaryExpression) {
JetBinaryExpression binaryExpression = (JetBinaryExpression) callElement; JetBinaryExpression binaryExpression = (JetBinaryExpression) callElement;
JetSimpleNameExpression operationReference = binaryExpression.getOperationReference(); JetSimpleNameExpression operationReference = binaryExpression.getOperationReference();
String operationString = operationReference.getReferencedNameElementType() == JetTokens.IDENTIFIER ? operationReference.getText() : OperatorConventions.getNameForOperationSymbol((JetToken) operationReference.getReferencedNameElementType());
String operationString = operationReference.getReferencedNameElementType() == JetTokens.IDENTIFIER ?
operationReference.getText() :
OperatorConventions.getNameForOperationSymbol((JetToken) operationReference.getReferencedNameElementType());
JetExpression right = binaryExpression.getRight(); JetExpression right = binaryExpression.getRight();
if (right != null) { if (right != null) {
trace.report(UNSAFE_INFIX_CALL.on(reference, binaryExpression.getLeft().getText(), operationString, right.getText())); trace.report(UNSAFE_INFIX_CALL.on(reference, binaryExpression.getLeft().getText(), operationString, right.getText()));
@@ -433,6 +470,7 @@ public class CallResolver {
@NotNull ResolutionTask<D> task, @NotNull TracingStrategy tracing @NotNull ResolutionTask<D> task, @NotNull TracingStrategy tracing
) { ) {
OverloadResolutionResultsImpl<D> results = performResolution(trace, scope, expectedType, task, tracing); OverloadResolutionResultsImpl<D> results = performResolution(trace, scope, expectedType, task, tracing);
// If resolution fails, we should check for some of the following situations: // If resolution fails, we should check for some of the following situations:
// class A { // class A {
// val foo = Bar() // The following is intended to be an anonymous initializer, // val foo = Bar() // The following is intended to be an anonymous initializer,
@@ -448,7 +486,8 @@ public class CallResolver {
// {...} // intended to be a returned from the outer literal // {...} // intended to be a returned from the outer literal
// } // }
// } // }
EnumSet<OverloadResolutionResults.Code> someFailed = EnumSet.of(OverloadResolutionResults.Code.MANY_FAILED_CANDIDATES, OverloadResolutionResults.Code.SINGLE_CANDIDATE_ARGUMENT_MISMATCH); EnumSet<OverloadResolutionResults.Code> someFailed = EnumSet.of(OverloadResolutionResults.Code.MANY_FAILED_CANDIDATES,
OverloadResolutionResults.Code.SINGLE_CANDIDATE_ARGUMENT_MISMATCH);
if (someFailed.contains(results.getResultCode()) && !task.getCall().getFunctionLiteralArguments().isEmpty()) { if (someFailed.contains(results.getResultCode()) && !task.getCall().getFunctionLiteralArguments().isEmpty()) {
// We have some candidates that failed for some reason // We have some candidates that failed for some reason
// And we have a suspect: the function literal argument // And we have a suspect: the function literal argument
@@ -658,7 +697,7 @@ public class CallResolver {
return results; return results;
} }
private JetType getEffectiveExpectedType(ValueParameterDescriptor valueParameterDescriptor) { private static JetType getEffectiveExpectedType(ValueParameterDescriptor valueParameterDescriptor) {
JetType effectiveExpectedType = valueParameterDescriptor.getVarargElementType(); JetType effectiveExpectedType = valueParameterDescriptor.getVarargElementType();
if (effectiveExpectedType == null) { if (effectiveExpectedType == null) {
effectiveExpectedType = valueParameterDescriptor.getType(); effectiveExpectedType = valueParameterDescriptor.getType();
@@ -666,7 +705,7 @@ public class CallResolver {
return effectiveExpectedType; return effectiveExpectedType;
} }
private void recordAutoCastIfNecessary(ReceiverDescriptor receiver, BindingTrace trace) { private static void recordAutoCastIfNecessary(ReceiverDescriptor receiver, BindingTrace trace) {
if (receiver instanceof AutoCastReceiver) { if (receiver instanceof AutoCastReceiver) {
AutoCastReceiver autoCastReceiver = (AutoCastReceiver) receiver; AutoCastReceiver autoCastReceiver = (AutoCastReceiver) receiver;
ReceiverDescriptor original = autoCastReceiver.getOriginal(); ReceiverDescriptor original = autoCastReceiver.getOriginal();
@@ -703,7 +742,9 @@ public class CallResolver {
} }
} }
private <D extends CallableDescriptor> void replaceValueParametersWithSubstitutedOnes(ResolvedCallImpl<D> candidateCall, @NotNull D substitutedDescriptor) { private static <D extends CallableDescriptor> void replaceValueParametersWithSubstitutedOnes(
ResolvedCallImpl<D> candidateCall, @NotNull D substitutedDescriptor) {
Map<ValueParameterDescriptor, ValueParameterDescriptor> parameterMap = Maps.newHashMap(); Map<ValueParameterDescriptor, ValueParameterDescriptor> parameterMap = Maps.newHashMap();
for (ValueParameterDescriptor valueParameterDescriptor : substitutedDescriptor.getValueParameters()) { for (ValueParameterDescriptor valueParameterDescriptor : substitutedDescriptor.getValueParameters()) {
parameterMap.put(valueParameterDescriptor.getOriginal(), valueParameterDescriptor); parameterMap.put(valueParameterDescriptor.getOriginal(), valueParameterDescriptor);
@@ -726,7 +767,9 @@ public class CallResolver {
return result; return result;
} }
private <D extends CallableDescriptor> ResolutionStatus checkReceiver(TracingStrategy tracing, ResolvedCallImpl<D> candidateCall, ReceiverDescriptor receiverParameter, ReceiverDescriptor receiverArgument, ResolutionTask<D> task) { private <D extends CallableDescriptor> ResolutionStatus checkReceiver(TracingStrategy tracing, ResolvedCallImpl<D> candidateCall,
ReceiverDescriptor receiverParameter, ReceiverDescriptor receiverArgument,
ResolutionTask<D> task) {
ResolutionStatus result = SUCCESS; ResolutionStatus result = SUCCESS;
if (receiverParameter.exists() && receiverArgument.exists()) { if (receiverParameter.exists() && receiverArgument.exists()) {
ASTNode callOperationNode = task.getCall().getCallOperationNode(); ASTNode callOperationNode = task.getCall().getCallOperationNode();
@@ -841,6 +884,7 @@ public class CallResolver {
return OverloadResolutionResultsImpl.manyFailedCandidates(results.getResultingCalls()); return OverloadResolutionResultsImpl.manyFailedCandidates(results.getResultingCalls());
} }
} }
assert false : "Should not be reachable, cause every status must belong to some level"; assert false : "Should not be reachable, cause every status must belong to some level";
Set<ResolvedCallImpl<D>> noOverrides = OverridingUtil.filterOverrides(failedCandidates, MAP_TO_CANDIDATE); Set<ResolvedCallImpl<D>> noOverrides = OverridingUtil.filterOverrides(failedCandidates, MAP_TO_CANDIDATE);
@@ -849,8 +893,10 @@ public class CallResolver {
tracing.recordAmbiguity(trace, noOverrides); tracing.recordAmbiguity(trace, noOverrides);
return OverloadResolutionResultsImpl.manyFailedCandidates(noOverrides); return OverloadResolutionResultsImpl.manyFailedCandidates(noOverrides);
} }
failedCandidates = noOverrides; failedCandidates = noOverrides;
} }
ResolvedCallImpl<D> failed = failedCandidates.iterator().next(); ResolvedCallImpl<D> failed = failedCandidates.iterator().next();
failed.getTrace().commit(); failed.getTrace().commit();
return OverloadResolutionResultsImpl.singleFailedCandidate(failed); return OverloadResolutionResultsImpl.singleFailedCandidate(failed);
@@ -861,7 +907,7 @@ public class CallResolver {
} }
} }
private <D extends CallableDescriptor> boolean allClean(Collection<ResolvedCallImpl<D>> results) { private static <D extends CallableDescriptor> boolean allClean(Collection<ResolvedCallImpl<D>> results) {
for (ResolvedCallImpl<D> result : results) { for (ResolvedCallImpl<D> result : results) {
if (result.isDirty()) return false; if (result.isDirty()) return false;
} }
@@ -939,7 +985,8 @@ public class CallResolver {
return computeResultAndReportErrors(trace, TracingStrategy.EMPTY, candidates, Collections.<ResolvedCallImpl<FunctionDescriptor>>emptySet()); return computeResultAndReportErrors(trace, TracingStrategy.EMPTY, candidates, Collections.<ResolvedCallImpl<FunctionDescriptor>>emptySet());
} }
private List<ResolvedCallImpl<FunctionDescriptor>> findCandidatesByExactSignature(JetScope scope, ReceiverDescriptor receiver, String name, List<JetType> parameterTypes) { private List<ResolvedCallImpl<FunctionDescriptor>> findCandidatesByExactSignature(JetScope scope, ReceiverDescriptor receiver,
String name, List<JetType> parameterTypes) {
List<ResolvedCallImpl<FunctionDescriptor>> result = Lists.newArrayList(); List<ResolvedCallImpl<FunctionDescriptor>> result = Lists.newArrayList();
if (receiver.exists()) { if (receiver.exists()) {
Collection<ResolvedCallImpl<FunctionDescriptor>> extensionFunctionDescriptors = ResolvedCallImpl.convertCollection(scope.getFunctions(name)); Collection<ResolvedCallImpl<FunctionDescriptor>> extensionFunctionDescriptors = ResolvedCallImpl.convertCollection(scope.getFunctions(name));
@@ -966,7 +1013,8 @@ public class CallResolver {
} }
} }
private boolean lookupExactSignature(Collection<ResolvedCallImpl<FunctionDescriptor>> candidates, List<JetType> parameterTypes, List<ResolvedCallImpl<FunctionDescriptor>> result) { private static boolean lookupExactSignature(Collection<ResolvedCallImpl<FunctionDescriptor>> candidates, List<JetType> parameterTypes,
List<ResolvedCallImpl<FunctionDescriptor>> result) {
boolean found = false; boolean found = false;
for (ResolvedCallImpl<FunctionDescriptor> resolvedCall : candidates) { for (ResolvedCallImpl<FunctionDescriptor> resolvedCall : candidates) {
FunctionDescriptor functionDescriptor = resolvedCall.getResultingDescriptor(); FunctionDescriptor functionDescriptor = resolvedCall.getResultingDescriptor();
@@ -979,7 +1027,8 @@ public class CallResolver {
return found; return found;
} }
private boolean findExtensionFunctions(Collection<ResolvedCallImpl<FunctionDescriptor>> candidates, ReceiverDescriptor receiver, List<JetType> parameterTypes, List<ResolvedCallImpl<FunctionDescriptor>> result) { private boolean findExtensionFunctions(Collection<ResolvedCallImpl<FunctionDescriptor>> candidates, ReceiverDescriptor receiver,
List<JetType> parameterTypes, List<ResolvedCallImpl<FunctionDescriptor>> result) {
boolean found = false; boolean found = false;
for (ResolvedCallImpl<FunctionDescriptor> resolvedCall : candidates) { for (ResolvedCallImpl<FunctionDescriptor> resolvedCall : candidates) {
FunctionDescriptor functionDescriptor = resolvedCall.getResultingDescriptor(); FunctionDescriptor functionDescriptor = resolvedCall.getResultingDescriptor();
@@ -994,7 +1043,7 @@ public class CallResolver {
return found; return found;
} }
private boolean checkValueParameters(@NotNull FunctionDescriptor functionDescriptor, @NotNull List<JetType> parameterTypes) { private static boolean checkValueParameters(@NotNull FunctionDescriptor functionDescriptor, @NotNull List<JetType> parameterTypes) {
List<ValueParameterDescriptor> valueParameters = functionDescriptor.getValueParameters(); List<ValueParameterDescriptor> valueParameters = functionDescriptor.getValueParameters();
if (valueParameters.size() != parameterTypes.size()) return false; if (valueParameters.size() != parameterTypes.size()) return false;
for (int i = 0; i < valueParameters.size(); i++) { for (int i = 0; i < valueParameters.size(); i++) {
@@ -1004,4 +1053,44 @@ public class CallResolver {
} }
return true; return true;
} }
/*
* Checks if receiver declaration could be resolved to call expected receiver.
*/
public static boolean checkIsExtensionCallable (
@NotNull ReceiverDescriptor expectedReceiver,
@NotNull CallableDescriptor receiverArgument
) {
JetType type = expectedReceiver.getType();
if (checkReceiverResolution(expectedReceiver, type, receiverArgument)) return true;
if (type.isNullable()) {
JetType notNullableType = TypeUtils.makeNotNullable(type);
if (checkReceiverResolution(expectedReceiver, notNullableType, receiverArgument)) return true;
}
return false;
}
private static boolean checkReceiverResolution (
@NotNull ReceiverDescriptor expectedReceiver,
@NotNull JetType receiverType,
@NotNull CallableDescriptor receiverArgument
) {
ConstraintSystem constraintSystem = new ConstraintSystemImpl(ConstraintResolutionListener.DO_NOTHING);
for (TypeParameterDescriptor typeParameterDescriptor : receiverArgument.getTypeParameters()) {
constraintSystem.registerTypeVariable(typeParameterDescriptor, Variance.INVARIANT);
}
ReceiverDescriptor receiverParameter = receiverArgument.getReceiverParameter();
if (expectedReceiver.exists() && receiverParameter.exists()) {
constraintSystem.addSubtypingConstraint(
RECEIVER.assertSubtyping(receiverType, receiverParameter.getType()));
}
else if (expectedReceiver.exists() || receiverParameter.exists()) {
// Only one of receivers exist
return false;
}
ConstraintSystemSolution solution = constraintSystem.solve();
return solution.getStatus().isSuccessful();
}
} }
@@ -84,8 +84,8 @@ public class DelegatingCall implements Call {
return delegate.getTypeArgumentList(); return delegate.getTypeArgumentList();
} }
@NotNull
@Override @Override
@Nullable
public PsiElement getCallElement() { public PsiElement getCallElement() {
return delegate.getCallElement(); return delegate.getCallElement();
} }
@@ -168,7 +168,7 @@ import static org.jetbrains.jet.lang.resolve.BindingContext.REFERENCE_TARGET;
candidateCall.recordValueArgument(valueParameter, new VarargValueArgument()); candidateCall.recordValueArgument(valueParameter, new VarargValueArgument());
} }
else { else {
// tracing.reportWrongValueArguments(temporaryTrace, "No value passed for parameter " + valueParameter.getName()); // tracing.reportWrongValueArguments(temporaryTrace, "No value passed for parameter " + valueParameter.getName());
tracing.noValueForParameter(temporaryTrace, valueParameter); tracing.noValueForParameter(temporaryTrace, valueParameter);
error = true; error = true;
} }
@@ -22,6 +22,8 @@ import org.jetbrains.jet.lang.types.JetType;
import java.text.MessageFormat; import java.text.MessageFormat;
/** /**
* A specific type for subtype constraint of types.
*
* @author abreslav * @author abreslav
*/ */
public enum ConstraintType implements Comparable<ConstraintType> { public enum ConstraintType implements Comparable<ConstraintType> {
@@ -33,7 +35,7 @@ public enum ConstraintType implements Comparable<ConstraintType> {
EXPECTED_TYPE("Resulting type is {0} but {1} was expected"), EXPECTED_TYPE("Resulting type is {0} but {1} was expected"),
PARAMETER_BOUND("Type parameter bound is not satisfied: {0} is not a subtype of {1}"); PARAMETER_BOUND("Type parameter bound is not satisfied: {0} is not a subtype of {1}");
private final String errorMessageTemplate; // {0} is subtype, {1} is supertye private final String errorMessageTemplate; // {0} is subtype, {1} is supertype
private ConstraintType(@NotNull String errorMessageTemplate) { private ConstraintType(@NotNull String errorMessageTemplate) {
this.errorMessageTemplate = errorMessageTemplate; this.errorMessageTemplate = errorMessageTemplate;
@@ -347,13 +347,22 @@ public class ControlStructureTypingVisitor extends ExpressionTypingVisitor {
return null; return null;
} }
public static OverloadResolutionResults<FunctionDescriptor> resolveFakeCall(ExpressionReceiver receiver, ExpressionTypingContext context, String name) { public static OverloadResolutionResults<FunctionDescriptor> resolveFakeCall(ExpressionReceiver receiver,
ExpressionTypingContext context, String name) {
JetReferenceExpression fake = JetPsiFactory.createSimpleName(context.getProject(), "fake"); JetReferenceExpression fake = JetPsiFactory.createSimpleName(context.getProject(), "fake");
BindingTrace fakeTrace = new BindingTraceContext(); BindingTrace fakeTrace = new BindingTraceContext();
Call call = CallMaker.makeCall(fake, receiver, null, fake, Collections.<ValueArgument>emptyList()); Call call = CallMaker.makeCall(fake, receiver, null, fake, Collections.<ValueArgument>emptyList());
return context.replaceBindingTrace(fakeTrace).resolveCallWithGivenName(call, fake, name); return context.replaceBindingTrace(fakeTrace).resolveCallWithGivenName(call, fake, name);
} }
public static List<FunctionDescriptor> resolveFakeCallWithReceiverOnly(ExpressionReceiver receiver,
ExpressionTypingContext context, String name) {
JetReferenceExpression fake = JetPsiFactory.createSimpleName(context.getProject(), "fake");
BindingTrace fakeTrace = new BindingTraceContext();
Call call = CallMaker.makeCall(fake, receiver, null, fake, Collections.<ValueArgument>emptyList());
return context.replaceBindingTrace(fakeTrace).resolveForReceiverOnly(call, fake, name);
}
@Nullable @Nullable
private static FunctionDescriptor checkHasNextFunctionSupport(@NotNull JetExpression loopRange, @NotNull JetType iteratorType, ExpressionTypingContext context) { private static FunctionDescriptor checkHasNextFunctionSupport(@NotNull JetExpression loopRange, @NotNull JetType iteratorType, ExpressionTypingContext context) {
OverloadResolutionResults<FunctionDescriptor> hasNextResolutionResults = context.resolveExactSignature(new TransientReceiver(iteratorType), "hasNext", Collections.<JetType>emptyList()); OverloadResolutionResults<FunctionDescriptor> hasNextResolutionResults = context.resolveExactSignature(new TransientReceiver(iteratorType), "hasNext", Collections.<JetType>emptyList());
@@ -42,6 +42,9 @@ import static org.jetbrains.jet.lang.resolve.BindingContext.AUTOCAST;
* @author abreslav * @author abreslav
*/ */
public class DataFlowUtils { public class DataFlowUtils {
private DataFlowUtils() {
}
@NotNull @NotNull
public static DataFlowInfo extractDataFlowInfoFromCondition(@Nullable JetExpression condition, final boolean conditionValue, @Nullable final WritableScope scopeToExtend, final ExpressionTypingContext context) { public static DataFlowInfo extractDataFlowInfoFromCondition(@Nullable JetExpression condition, final boolean conditionValue, @Nullable final WritableScope scopeToExtend, final ExpressionTypingContext context) {
if (condition == null) return context.dataFlowInfo; if (condition == null) return context.dataFlowInfo;
@@ -204,6 +204,12 @@ import java.util.Map;
// return results == null ? null : results.getResultingDescriptor(); // return results == null ? null : results.getResultingDescriptor();
} }
@NotNull
public List<FunctionDescriptor> resolveForReceiverOnly(@NotNull Call call, @NotNull JetReferenceExpression functionReference, @NotNull String name) {
return getCallResolver().resolveCallsByReceiver(trace, scope, call, name);
}
@Nullable @Nullable
public FunctionDescriptor resolveCall(@NotNull ReceiverDescriptor receiver, @Nullable ASTNode callOperationNode, @NotNull JetCallExpression callExpression) { public FunctionDescriptor resolveCall(@NotNull ReceiverDescriptor receiver, @Nullable ASTNode callOperationNode, @NotNull JetCallExpression callExpression) {
OverloadResolutionResults<FunctionDescriptor> results = getCallResolver().resolveCall(trace, scope, CallMaker.makeCall(receiver, callOperationNode, callExpression), expectedType); OverloadResolutionResults<FunctionDescriptor> results = getCallResolver().resolveCall(trace, scope, CallMaker.makeCall(receiver, callOperationNode, callExpression), expectedType);
@@ -29,8 +29,6 @@ import org.jetbrains.jet.lang.descriptors.FunctionDescriptor;
import org.jetbrains.jet.lang.descriptors.VariableDescriptor; import org.jetbrains.jet.lang.descriptors.VariableDescriptor;
import org.jetbrains.jet.lang.psi.*; import org.jetbrains.jet.lang.psi.*;
import org.jetbrains.jet.lang.resolve.*; import org.jetbrains.jet.lang.resolve.*;
import org.jetbrains.jet.lang.resolve.calls.OverloadResolutionResults;
import org.jetbrains.jet.lang.resolve.calls.ResolvedCall;
import org.jetbrains.jet.lang.resolve.calls.autocasts.DataFlowInfo; import org.jetbrains.jet.lang.resolve.calls.autocasts.DataFlowInfo;
import org.jetbrains.jet.lang.resolve.scopes.*; import org.jetbrains.jet.lang.resolve.scopes.*;
import org.jetbrains.jet.lang.resolve.scopes.receivers.ExpressionReceiver; import org.jetbrains.jet.lang.resolve.scopes.receivers.ExpressionReceiver;
@@ -39,7 +37,6 @@ import org.jetbrains.jet.lang.types.JetType;
import org.jetbrains.jet.lang.types.TypeUtils; import org.jetbrains.jet.lang.types.TypeUtils;
import org.jetbrains.jet.util.QualifiedNamesUtil; import org.jetbrains.jet.util.QualifiedNamesUtil;
import java.util.ArrayList;
import java.util.HashMap; import java.util.HashMap;
import java.util.List; import java.util.List;
@@ -167,15 +164,15 @@ public class ExpressionTypingUtils {
} }
/** /**
* Check that function with the given qualified name can be resolved in given scope for given receiver * Check that function or property with the given qualified name can be resolved in given scope for given receiver
* *
* @param functionFQN * @param callableFQN
* @param project * @param project
* @param scope * @param scope
* @return * @return
*/ */
public static ArrayList<FunctionDescriptor> canCallBeResolved( public static List<FunctionDescriptor> canFindSuitableCall(
@NotNull String functionFQN, @NotNull String callableFQN,
@NotNull Project project, @NotNull Project project,
@NotNull JetExpression receiverExpression, @NotNull JetExpression receiverExpression,
@NotNull JetType receiverType, @NotNull JetType receiverType,
@@ -184,7 +181,7 @@ public class ExpressionTypingUtils {
WritableScopeWithImports writableScopeWithImports = new WritableScopeImpl( WritableScopeWithImports writableScopeWithImports = new WritableScopeImpl(
scope, scope.getContainingDeclaration(), RedeclarationHandler.DO_NOTHING); scope, scope.getContainingDeclaration(), RedeclarationHandler.DO_NOTHING);
JetImportDirective importDirective = JetPsiFactory.createImportDirective(project, functionFQN); JetImportDirective importDirective = JetPsiFactory.createImportDirective(project, callableFQN);
ExpressionReceiver expressionReceiver = new ExpressionReceiver(receiverExpression, receiverType); ExpressionReceiver expressionReceiver = new ExpressionReceiver(receiverExpression, receiverType);
@@ -209,19 +206,23 @@ public class ExpressionTypingUtils {
writableScopeWithImports.changeLockLevel(WritableScope.LockLevel.READING); writableScopeWithImports.changeLockLevel(WritableScope.LockLevel.READING);
OverloadResolutionResults<FunctionDescriptor> resolutionResult = return ControlStructureTypingVisitor.resolveFakeCallWithReceiverOnly(expressionReceiver, context, QualifiedNamesUtil.fqnToShortName(callableFQN));
ControlStructureTypingVisitor.resolveFakeCall(expressionReceiver, context, QualifiedNamesUtil.fqnToShortName(functionFQN));
if (!resolutionResult.isSuccess()) {
return new ArrayList<FunctionDescriptor>();
}
ArrayList<FunctionDescriptor> resolvedDescriptors = new ArrayList<FunctionDescriptor>(); // OverloadResolutionResults.Code resultCode = resolutionResult.getResultCode();
// if (resultCode == OverloadResolutionResults.Code.SUCCESS ||
for (ResolvedCall<? extends FunctionDescriptor> resolvedCall : resolutionResult.getResultingCalls()) { // resultCode == OverloadResolutionResults.Code.SINGLE_CANDIDATE_ARGUMENT_MISMATCH ||
resolvedDescriptors.add(resolvedCall.getCandidateDescriptor()); // resultCode == OverloadResolutionResults.Code.MANY_FAILED_CANDIDATES) {
} //
// ArrayList<FunctionDescriptor> resolvedDescriptors = new ArrayList<FunctionDescriptor>();
return resolvedDescriptors; //
// for (ResolvedCall<? extends FunctionDescriptor> resolvedCall : resolutionResult.getResultingCalls()) {
// resolvedDescriptors.add(resolvedCall.getCandidateDescriptor());
// }
//
// return resolvedDescriptors;
// }
//
// return new ArrayList<FunctionDescriptor>();
} }
} }
@@ -135,7 +135,7 @@ public class JetCompletionContributor extends CompletionContributor {
for (String functionFQN : functionFQNs) { for (String functionFQN : functionFQNs) {
// System.out.println(functionFQN); // System.out.println(functionFQN);
List<FunctionDescriptor> functionDescriptors = ExpressionTypingUtils.canCallBeResolved( List<FunctionDescriptor> functionDescriptors = ExpressionTypingUtils.canFindSuitableCall(
functionFQN, position.getProject(), receiverExpression, expressionType, scope); functionFQN, position.getProject(), receiverExpression, expressionType, scope);
// System.out.println(!functionDescriptors.isEmpty()); // System.out.println(!functionDescriptors.isEmpty());
@@ -7,4 +7,5 @@ fun firstFun() {
// EXIST: helloFun // EXIST: helloFun
// EXIST: helloFunPreventAutoInsert // EXIST: helloFunPreventAutoInsert
// NUMBER: 2 // EXIST: helloWithParams
// NUMBER: 3
@@ -3,5 +3,9 @@ package second
fun String.helloFun() { fun String.helloFun() {
} }
fun String.helloWithParams(i : Int) : String {
return ""
}
fun String.helloFunPreventAutoInsert() { fun String.helloFunPreventAutoInsert() {
} }