Receivers made available at CallResolver
This commit is contained in:
@@ -239,7 +239,7 @@ public interface Errors {
|
||||
return constraintOwner.getName();
|
||||
}
|
||||
};
|
||||
ParameterizedDiagnosticFactory2<JetType, VariableDescriptor> AUTOCAST_IMPOSSIBLE = ParameterizedDiagnosticFactory2.create(ERROR, "Automatic cast to {0} is impossible, because variable {1} is mutable", NAME);
|
||||
ParameterizedDiagnosticFactory2<JetType, String> AUTOCAST_IMPOSSIBLE = ParameterizedDiagnosticFactory2.create(ERROR, "Automatic cast to {0} is impossible, because {1} could have changed since the is-check");
|
||||
|
||||
ParameterizedDiagnosticFactory2<JetType, JetType> TYPE_MISMATCH_IN_FOR_LOOP = ParameterizedDiagnosticFactory2.create(ERROR, "The loop iterates over values of type {0} but the parameter is declared to be {1}");
|
||||
ParameterizedDiagnosticFactory1<JetType> TYPE_MISMATCH_IN_CONDITION = ParameterizedDiagnosticFactory1.create(ERROR, "Condition must be of type Boolean, but was of type {0}");
|
||||
|
||||
@@ -1,7 +1,9 @@
|
||||
package org.jetbrains.jet.lang.psi;
|
||||
|
||||
import com.intellij.lang.ASTNode;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
import org.jetbrains.jet.lang.resolve.scopes.receivers.ReceiverDescriptor;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
@@ -9,6 +11,14 @@ import java.util.List;
|
||||
* @author abreslav
|
||||
*/
|
||||
public interface Call {
|
||||
|
||||
// SAFE_ACCESS or DOT or so
|
||||
@Nullable
|
||||
ASTNode getCallOperationNode();
|
||||
|
||||
@NotNull
|
||||
ReceiverDescriptor getExplicitReceiver();
|
||||
|
||||
@Nullable
|
||||
JetExpression getCalleeExpression();
|
||||
|
||||
@@ -26,4 +36,7 @@ public interface Call {
|
||||
|
||||
@Nullable
|
||||
JetTypeArgumentList getTypeArgumentList();
|
||||
|
||||
@NotNull
|
||||
ASTNode getCallNode();
|
||||
}
|
||||
|
||||
@@ -9,6 +9,22 @@ import java.util.List;
|
||||
/**
|
||||
* @author abreslav
|
||||
*/
|
||||
public interface JetCallElement extends PsiElement, Call {
|
||||
public interface JetCallElement extends PsiElement {
|
||||
@Nullable
|
||||
JetExpression getCalleeExpression();
|
||||
|
||||
@Nullable
|
||||
JetValueArgumentList getValueArgumentList();
|
||||
|
||||
@NotNull
|
||||
List<? extends ValueArgument> getValueArguments();
|
||||
|
||||
@NotNull
|
||||
List<JetExpression> getFunctionLiteralArguments();
|
||||
|
||||
@NotNull
|
||||
List<JetTypeProjection> getTypeArguments();
|
||||
|
||||
@Nullable
|
||||
JetTypeArgumentList getTypeArgumentList();
|
||||
}
|
||||
|
||||
@@ -13,10 +13,7 @@ import org.jetbrains.jet.lang.resolve.calls.CallResolver;
|
||||
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.DataFlowInfo;
|
||||
import org.jetbrains.jet.lang.types.ErrorUtils;
|
||||
import org.jetbrains.jet.lang.types.JetType;
|
||||
import org.jetbrains.jet.lang.types.JetTypeInferrer;
|
||||
import org.jetbrains.jet.lang.types.*;
|
||||
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
@@ -53,7 +50,7 @@ public class AnnotationResolver {
|
||||
}
|
||||
|
||||
public void resolveAnnotationStub(@NotNull JetScope scope, @NotNull JetAnnotationEntry entryElement, @NotNull AnnotationDescriptor descriptor) {
|
||||
JetType jetType = callResolver.resolveCall(trace, scope, ReceiverDescriptor.NO_RECEIVER, entryElement, NO_EXPECTED_TYPE);
|
||||
JetType jetType = callResolver.resolveCall(trace, scope, CallMaker.makeCall(ReceiverDescriptor.NO_RECEIVER, null, entryElement), NO_EXPECTED_TYPE);
|
||||
descriptor.setAnnotationType(jetType == null ? ErrorUtils.createErrorType("Unresolved annotation type") : jetType);
|
||||
}
|
||||
|
||||
|
||||
@@ -172,7 +172,9 @@ public class BodyResolver {
|
||||
JetTypeReference typeReference = call.getTypeReference();
|
||||
if (typeReference != null) {
|
||||
if (descriptor.getUnsubstitutedPrimaryConstructor() != null) {
|
||||
JetType supertype = typeInferrer.getCallResolver().resolveCall(context.getTrace(), scopeForConstructor, ReceiverDescriptor.NO_RECEIVER, call, NO_EXPECTED_TYPE);
|
||||
JetType supertype = typeInferrer.getCallResolver().resolveCall(
|
||||
context.getTrace(), scopeForConstructor,
|
||||
CallMaker.makeCall(ReceiverDescriptor.NO_RECEIVER, null, call), NO_EXPECTED_TYPE);
|
||||
if (supertype != null) {
|
||||
recordSupertype(typeReference, supertype);
|
||||
ClassDescriptor classDescriptor = TypeUtils.getClassDescriptor(supertype);
|
||||
@@ -334,7 +336,8 @@ public class BodyResolver {
|
||||
public void visitDelegationToSuperCallSpecifier(JetDelegatorToSuperCall call) {
|
||||
JetTypeReference typeReference = call.getTypeReference();
|
||||
if (typeReference != null) {
|
||||
typeInferrerForInitializers.getCallResolver().resolveCall(context.getTrace(), functionInnerScope, ReceiverDescriptor.NO_RECEIVER, call, NO_EXPECTED_TYPE);
|
||||
typeInferrerForInitializers.getCallResolver().resolveCall(context.getTrace(), functionInnerScope,
|
||||
CallMaker.makeCall(ReceiverDescriptor.NO_RECEIVER, null, call), NO_EXPECTED_TYPE);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -346,7 +349,7 @@ public class BodyResolver {
|
||||
|
||||
typeInferrerForInitializers.getCallResolver().resolveCall(context.getTrace(),
|
||||
functionInnerScope,
|
||||
ReceiverDescriptor.NO_RECEIVER, call, NO_EXPECTED_TYPE);
|
||||
CallMaker.makeCall(ReceiverDescriptor.NO_RECEIVER, null, call), NO_EXPECTED_TYPE);
|
||||
// call.getThisReference(),
|
||||
// classDescriptor,
|
||||
// classDescriptor.getDefaultType(),
|
||||
|
||||
@@ -11,10 +11,16 @@ import org.jetbrains.jet.lang.types.JetType;
|
||||
*/
|
||||
public class AutoCastReceiver extends AbstractReceiverDescriptor {
|
||||
private final ReceiverDescriptor original;
|
||||
private final boolean canCast;
|
||||
|
||||
public AutoCastReceiver(@NotNull ReceiverDescriptor original, @NotNull JetType castTo) {
|
||||
public AutoCastReceiver(@NotNull ReceiverDescriptor original, @NotNull JetType castTo, boolean canCast) {
|
||||
super(castTo);
|
||||
this.original = original;
|
||||
this.canCast = canCast;
|
||||
}
|
||||
|
||||
public boolean canCast() {
|
||||
return canCast;
|
||||
}
|
||||
|
||||
@NotNull
|
||||
|
||||
@@ -4,19 +4,22 @@ import com.google.common.collect.Lists;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
import org.jetbrains.jet.lang.descriptors.*;
|
||||
import org.jetbrains.jet.lang.psi.JetBinaryExpressionWithTypeRHS;
|
||||
import org.jetbrains.jet.lang.psi.JetExpression;
|
||||
import org.jetbrains.jet.lang.psi.JetPsiUtil;
|
||||
import org.jetbrains.jet.lang.psi.JetSimpleNameExpression;
|
||||
import org.jetbrains.jet.lang.psi.JetThisExpression;
|
||||
import org.jetbrains.jet.lang.resolve.BindingContext;
|
||||
import org.jetbrains.jet.lang.resolve.BindingTrace;
|
||||
import org.jetbrains.jet.lang.resolve.scopes.receivers.*;
|
||||
import org.jetbrains.jet.lang.types.DataFlowInfo;
|
||||
import org.jetbrains.jet.lang.types.JetType;
|
||||
import org.jetbrains.jet.lexer.JetTokens;
|
||||
import org.jetbrains.jet.lang.types.JetTypeChecker;
|
||||
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
|
||||
import static org.jetbrains.jet.lang.diagnostics.Errors.AUTOCAST_IMPOSSIBLE;
|
||||
import static org.jetbrains.jet.lang.resolve.BindingContext.AUTOCAST;
|
||||
import static org.jetbrains.jet.lang.resolve.BindingContext.REFERENCE_TARGET;
|
||||
|
||||
/**
|
||||
@@ -26,36 +29,36 @@ public class AutoCastUtils {
|
||||
|
||||
private AutoCastUtils() {}
|
||||
|
||||
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>() {
|
||||
public static List<ReceiverDescriptor> getAutoCastVariants(@NotNull final BindingContext bindingContext, @NotNull final DataFlowInfo dataFlowInfo, @NotNull ReceiverDescriptor receiverToCast) {
|
||||
return receiverToCast.accept(new ReceiverDescriptorVisitor<List<ReceiverDescriptor>, Object>() {
|
||||
@Override
|
||||
public List<? extends ReceiverDescriptor> visitNoReceiver(ReceiverDescriptor noReceiver, Object data) {
|
||||
public List<ReceiverDescriptor> visitNoReceiver(ReceiverDescriptor noReceiver, Object data) {
|
||||
return Collections.emptyList();
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<? extends ReceiverDescriptor> visitTransientReceiver(TransientReceiver receiver, Object data) {
|
||||
public List<ReceiverDescriptor> visitTransientReceiver(TransientReceiver receiver, Object data) {
|
||||
return Collections.emptyList();
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<? extends ReceiverDescriptor> visitExtensionReceiver(ExtensionReceiver receiver, Object data) {
|
||||
public List<ReceiverDescriptor> visitExtensionReceiver(ExtensionReceiver receiver, Object data) {
|
||||
return castThis(dataFlowInfo, receiver);
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<? extends ReceiverDescriptor> visitClassReceiver(ClassReceiver receiver, Object data) {
|
||||
public List<ReceiverDescriptor> visitClassReceiver(ClassReceiver receiver, Object data) {
|
||||
return castThis(dataFlowInfo, receiver);
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<? extends ReceiverDescriptor> visitExpressionReceiver(ExpressionReceiver receiver, Object data) {
|
||||
public List<ReceiverDescriptor> visitExpressionReceiver(ExpressionReceiver receiver, Object data) {
|
||||
JetExpression expression = receiver.getExpression();
|
||||
VariableDescriptor variableDescriptor = getVariableDescriptorFromSimpleName(bindingContext, expression);
|
||||
if (variableDescriptor != null && isAutocastable(variableDescriptor)) {
|
||||
if (variableDescriptor != null) {
|
||||
List<ReceiverDescriptor> result = Lists.newArrayList();
|
||||
for (JetType possibleType : dataFlowInfo.getPossibleTypesForVariable(variableDescriptor)) {
|
||||
result.add(new AutoCastReceiver(receiver, possibleType));
|
||||
result.add(new AutoCastReceiver(receiver, possibleType, isAutoCastable(variableDescriptor)));
|
||||
}
|
||||
return result;
|
||||
}
|
||||
@@ -67,26 +70,56 @@ public class AutoCastUtils {
|
||||
}, null);
|
||||
}
|
||||
|
||||
private static List<? extends ReceiverDescriptor> castThis(@NotNull DataFlowInfo dataFlowInfo, @NotNull ReceiverDescriptor receiver) {
|
||||
private static List<ReceiverDescriptor> castThis(@NotNull DataFlowInfo dataFlowInfo, @NotNull ReceiverDescriptor receiver) {
|
||||
assert receiver.exists();
|
||||
List<ReceiverDescriptor> result = Lists.newArrayList();
|
||||
for (JetType possibleType : dataFlowInfo.getPossibleTypesForReceiver(receiver)) {
|
||||
result.add(new AutoCastReceiver(receiver, possibleType));
|
||||
result.add(new AutoCastReceiver(receiver, possibleType, true));
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
@Nullable
|
||||
public static VariableDescriptor getVariableDescriptorFromSimpleName(@NotNull BindingContext bindingContext, @NotNull JetExpression receiverExpression) {
|
||||
if (receiverExpression instanceof JetBinaryExpressionWithTypeRHS) {
|
||||
JetBinaryExpressionWithTypeRHS expression = (JetBinaryExpressionWithTypeRHS) receiverExpression;
|
||||
if (expression.getOperationSign().getReferencedNameElementType() == JetTokens.COLON) {
|
||||
return getVariableDescriptorFromSimpleName(bindingContext, expression.getLeft());
|
||||
public static JetType castExpression(@NotNull JetExpression expression, @NotNull JetType expectedType, @NotNull DataFlowInfo dataFlowInfo, @NotNull BindingTrace trace) {
|
||||
JetTypeChecker typeChecker = JetTypeChecker.INSTANCE;
|
||||
VariableDescriptor variableDescriptor = getVariableDescriptorFromSimpleName(trace.getBindingContext(), expression);
|
||||
// boolean appropriateTypeFound = false;
|
||||
if (variableDescriptor != null) {
|
||||
List<JetType> possibleTypes = Lists.newArrayList(dataFlowInfo.getPossibleTypesForVariable(variableDescriptor));
|
||||
Collections.reverse(possibleTypes);
|
||||
for (JetType possibleType : possibleTypes) {
|
||||
if (typeChecker.isSubtypeOf(possibleType, expectedType)) {
|
||||
if (isAutoCastable(variableDescriptor)) {
|
||||
trace.record(AUTOCAST, expression, possibleType);
|
||||
}
|
||||
else {
|
||||
trace.report(AUTOCAST_IMPOSSIBLE.on(expression, possibleType, expression.getText()));
|
||||
}
|
||||
return possibleType;
|
||||
}
|
||||
}
|
||||
// if (!appropriateTypeFound) {
|
||||
// JetType notnullType = dataFlowInfo.getOutType(variableDescriptor);
|
||||
// if (notnullType != null && typeChecker.isSubtypeOf(notnullType, expectedType)) {
|
||||
// appropriateTypeFound = true;
|
||||
// }
|
||||
// }
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
@Nullable
|
||||
public static VariableDescriptor getVariableDescriptorFromSimpleName(@NotNull BindingContext bindingContext, @NotNull JetExpression expression) {
|
||||
// if (expression instanceof JetBinaryExpressionWithTypeRHS) {
|
||||
// JetBinaryExpressionWithTypeRHS expression = (JetBinaryExpressionWithTypeRHS) expression;
|
||||
// if (expression.getOperationSign().getReferencedNameElementType() == JetTokens.COLON) {
|
||||
// return getVariableDescriptorFromSimpleName(bindingContext, expression.getLeft());
|
||||
// }
|
||||
// }
|
||||
JetExpression receiver = JetPsiUtil.deparenthesize(expression);
|
||||
VariableDescriptor variableDescriptor = null;
|
||||
if (receiverExpression instanceof JetSimpleNameExpression) {
|
||||
JetSimpleNameExpression nameExpression = (JetSimpleNameExpression) receiverExpression;
|
||||
if (receiver instanceof JetSimpleNameExpression) {
|
||||
JetSimpleNameExpression nameExpression = (JetSimpleNameExpression) receiver;
|
||||
DeclarationDescriptor declarationDescriptor = bindingContext.get(REFERENCE_TARGET, nameExpression);
|
||||
if (declarationDescriptor instanceof VariableDescriptor) {
|
||||
variableDescriptor = (VariableDescriptor) declarationDescriptor;
|
||||
@@ -95,7 +128,7 @@ public class AutoCastUtils {
|
||||
return variableDescriptor;
|
||||
}
|
||||
|
||||
public static boolean isAutocastable(@NotNull VariableDescriptor variableDescriptor) {
|
||||
public static boolean isAutoCastable(@NotNull VariableDescriptor variableDescriptor) {
|
||||
if (variableDescriptor.isVar()) return false;
|
||||
if (variableDescriptor instanceof PropertyDescriptor) {
|
||||
PropertyDescriptor propertyDescriptor = (PropertyDescriptor) variableDescriptor;
|
||||
|
||||
@@ -1,12 +1,9 @@
|
||||
package org.jetbrains.jet.lang.resolve.calls;
|
||||
|
||||
import com.google.common.base.Function;
|
||||
import com.google.common.base.Functions;
|
||||
import com.google.common.collect.Lists;
|
||||
import com.google.common.collect.Maps;
|
||||
import com.google.common.collect.Sets;
|
||||
import com.intellij.lang.ASTNode;
|
||||
import com.intellij.openapi.util.Ref;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
import org.jetbrains.jet.lang.JetSemanticServices;
|
||||
@@ -55,21 +52,19 @@ public class CallResolver {
|
||||
if (referencedName == null) {
|
||||
return null;
|
||||
}
|
||||
Call call = CallMaker.makePropertyCall(nameExpression);
|
||||
List<ResolutionTask<VariableDescriptor>> prioritizedTasks = TaskPrioritizers.PROPERTY_TASK_PRIORITIZER.computePrioritizedTasks(scope, receiver, call, referencedName, trace.getBindingContext(), dataFlowInfo);
|
||||
Call call = CallMaker.makePropertyCall(receiver, null, nameExpression);
|
||||
List<ResolutionTask<VariableDescriptor>> prioritizedTasks = TaskPrioritizers.PROPERTY_TASK_PRIORITIZER.computePrioritizedTasks(scope, call, referencedName, trace.getBindingContext(), dataFlowInfo);
|
||||
return resolveCallToDescriptor(trace, scope, call, nameExpression.getNode(), expectedType, prioritizedTasks, nameExpression);
|
||||
}
|
||||
|
||||
|
||||
@Nullable
|
||||
public JetType resolveCall(
|
||||
@NotNull BindingTrace trace,
|
||||
@NotNull JetScope scope,
|
||||
@NotNull ReceiverDescriptor receiver,
|
||||
@NotNull JetCallElement call,
|
||||
@NotNull Call call,
|
||||
@NotNull JetType expectedType
|
||||
) {
|
||||
FunctionDescriptor functionDescriptor = resolveSimpleCallToFunctionDescriptor(trace, scope, receiver, call, expectedType);
|
||||
FunctionDescriptor functionDescriptor = resolveSimpleCallToFunctionDescriptor(trace, scope, call, expectedType);
|
||||
return functionDescriptor == null ? null : functionDescriptor.getReturnType();
|
||||
}
|
||||
|
||||
@@ -80,9 +75,8 @@ public class CallResolver {
|
||||
@NotNull final Call call,
|
||||
@NotNull final JetReferenceExpression functionReference,
|
||||
@NotNull String name,
|
||||
@NotNull ReceiverDescriptor receiver,
|
||||
@NotNull JetType expectedType) {
|
||||
List<ResolutionTask<FunctionDescriptor>> tasks = TaskPrioritizers.FUNCTION_TASK_PRIORITIZER.computePrioritizedTasks(scope, receiver, call, name, trace.getBindingContext(), dataFlowInfo);
|
||||
List<ResolutionTask<FunctionDescriptor>> tasks = TaskPrioritizers.FUNCTION_TASK_PRIORITIZER.computePrioritizedTasks(scope, call, name, trace.getBindingContext(), dataFlowInfo);
|
||||
return resolveCallToDescriptor(trace, scope, call, functionReference.getNode(), expectedType, tasks, functionReference);
|
||||
}
|
||||
|
||||
@@ -90,8 +84,7 @@ public class CallResolver {
|
||||
public FunctionDescriptor resolveSimpleCallToFunctionDescriptor(
|
||||
@NotNull BindingTrace trace,
|
||||
@NotNull JetScope scope,
|
||||
@NotNull ReceiverDescriptor receiver,
|
||||
@NotNull final JetCallElement call,
|
||||
@NotNull final Call call,
|
||||
@NotNull JetType expectedType
|
||||
) {
|
||||
List<ResolutionTask<FunctionDescriptor>> prioritizedTasks;
|
||||
@@ -105,7 +98,7 @@ public class CallResolver {
|
||||
String name = expression.getReferencedName();
|
||||
if (name == null) return checkArgumentTypesAndFail(trace, scope, call);
|
||||
|
||||
prioritizedTasks = TaskPrioritizers.FUNCTION_TASK_PRIORITIZER.computePrioritizedTasks(scope, receiver, call, name, trace.getBindingContext(), dataFlowInfo);
|
||||
prioritizedTasks = TaskPrioritizers.FUNCTION_TASK_PRIORITIZER.computePrioritizedTasks(scope, call, name, trace.getBindingContext(), dataFlowInfo);
|
||||
ResolutionTask.DescriptorCheckStrategy abstractConstructorCheck = new ResolutionTask.DescriptorCheckStrategy() {
|
||||
@Override
|
||||
public <D extends CallableDescriptor> boolean performAdvancedChecks(D descriptor, BindingTrace trace, TracingStrategy tracing) {
|
||||
@@ -126,9 +119,9 @@ public class CallResolver {
|
||||
}
|
||||
else {
|
||||
JetValueArgumentList valueArgumentList = call.getValueArgumentList();
|
||||
ASTNode reportAbsenceOn = valueArgumentList == null ? call.getNode() : valueArgumentList.getNode();
|
||||
ASTNode reportAbsenceOn = valueArgumentList == null ? call.getCallNode() : valueArgumentList.getNode();
|
||||
if (calleeExpression instanceof JetConstructorCalleeExpression) {
|
||||
assert !receiver.exists();
|
||||
assert !call.getExplicitReceiver().exists();
|
||||
|
||||
prioritizedTasks = Lists.newArrayList();
|
||||
|
||||
@@ -172,14 +165,14 @@ public class CallResolver {
|
||||
prioritizedTasks = Collections.singletonList(new ResolutionTask<FunctionDescriptor>(ResolvedCall.convertCollection(constructors), call, DataFlowInfo.getEmpty()));
|
||||
}
|
||||
else {
|
||||
throw new UnsupportedOperationException("Type argument inference not implemented for " + call.getText());
|
||||
throw new UnsupportedOperationException("Type argument inference not implemented for " + call);
|
||||
}
|
||||
}
|
||||
|
||||
return resolveCallToDescriptor(trace, scope, call, call.getNode(), expectedType, prioritizedTasks, functionReference);
|
||||
return resolveCallToDescriptor(trace, scope, call, call.getCallNode(), expectedType, prioritizedTasks, functionReference);
|
||||
}
|
||||
|
||||
private FunctionDescriptor checkArgumentTypesAndFail(BindingTrace trace, JetScope scope, JetCallElement call) {
|
||||
private FunctionDescriptor checkArgumentTypesAndFail(BindingTrace trace, JetScope scope, Call call) {
|
||||
checkTypesWithNoCallee(trace, scope, call.getTypeArguments(), call.getValueArguments(), call.getFunctionLiteralArguments());
|
||||
return null;
|
||||
}
|
||||
@@ -234,19 +227,6 @@ public class CallResolver {
|
||||
|
||||
@Override
|
||||
public void noValueForParameter(@NotNull BindingTrace trace, @NotNull ValueParameterDescriptor valueParameter) {
|
||||
// ASTNode node;
|
||||
//
|
||||
// JetValueArgumentList valueArgumentList = call.getValueArgumentList();
|
||||
// if (valueArgumentList != null) {
|
||||
// node = valueArgumentList.getNode();
|
||||
// }
|
||||
// else if (!call.getFunctionLiteralArguments().isEmpty()) {
|
||||
// node = call.getFunctionLiteralArguments().get(0).getNode();
|
||||
// }
|
||||
// else {
|
||||
// node = callNode;
|
||||
// }
|
||||
// trace.report(NO_VALUE_FOR_PARAMETER.on(node, valueParameter));
|
||||
trace.report(NO_VALUE_FOR_PARAMETER.on(reference, valueParameter));
|
||||
}
|
||||
|
||||
@@ -325,7 +305,6 @@ public class CallResolver {
|
||||
private <D extends CallableDescriptor> OverloadResolutionResults<D> performResolution(@NotNull BindingTrace trace, @NotNull JetScope scope, @NotNull JetType expectedType, @NotNull ResolutionTask<D> task, @NotNull TracingStrategy tracing) {
|
||||
Set<ResolvedCall<D>> successfulCandidates = Sets.newLinkedHashSet();
|
||||
Set<ResolvedCall<D>> failedCandidates = Sets.newLinkedHashSet();
|
||||
Set<ResolvedCall<D>> dirtyCandidates = Sets.newLinkedHashSet();
|
||||
|
||||
for (ResolvedCall<D> candidateCall : task.getCandidates()) {
|
||||
D candidate = candidateCall.getCandidateDescriptor();
|
||||
@@ -341,8 +320,8 @@ public class CallResolver {
|
||||
}
|
||||
|
||||
|
||||
Map<ValueArgument, ValueParameterDescriptor> argumentsToParameters = Maps.newHashMap();
|
||||
boolean error = ValueArgumentsToParametersMapper.mapValueArgumentsToParameters(task, tracing, candidate, temporaryTrace, argumentsToParameters);
|
||||
// Map<ValueArgument, ValueParameterDescriptor> argumentsToParameters = Maps.newHashMap();
|
||||
boolean error = ValueArgumentsToParametersMapper.mapValueArgumentsToParameters(task, tracing, candidateCall);
|
||||
|
||||
if (error) {
|
||||
failedCandidates.add(candidateCall);
|
||||
@@ -350,18 +329,8 @@ public class CallResolver {
|
||||
continue;
|
||||
}
|
||||
|
||||
Ref<Boolean> dirty = new Ref<Boolean>(false);
|
||||
if (task.getTypeArguments().isEmpty()) {
|
||||
if (candidate.getTypeParameters().isEmpty()) {
|
||||
if (checkValueArgumentTypes(scope, temporaryTrace, argumentsToParameters, dirty, Functions.<ValueParameterDescriptor>identity())
|
||||
&& checkReceiver(candidateCall, tracing, candidate, temporaryTrace)) {
|
||||
successfulCandidates.add(candidateCall.setResultingDescriptor(candidate));
|
||||
}
|
||||
else {
|
||||
failedCandidates.add(candidateCall);
|
||||
}
|
||||
}
|
||||
else {
|
||||
if (!candidate.getTypeParameters().isEmpty()) {
|
||||
// Type argument inference
|
||||
|
||||
ConstraintSystem constraintSystem = new ConstraintSystem();
|
||||
@@ -369,23 +338,25 @@ public class CallResolver {
|
||||
constraintSystem.registerTypeVariable(typeParameterDescriptor, Variance.INVARIANT); // TODO
|
||||
}
|
||||
|
||||
for (Map.Entry<ValueArgument, ValueParameterDescriptor> entry : argumentsToParameters.entrySet()) {
|
||||
ValueArgument valueArgument = entry.getKey();
|
||||
ValueParameterDescriptor valueParameterDescriptor = entry.getValue();
|
||||
for (Map.Entry<ValueParameterDescriptor, ResolvedValueArgument> entry : candidateCall.getValueArguments().entrySet()) {
|
||||
ResolvedValueArgument valueArgument = entry.getValue();
|
||||
ValueParameterDescriptor valueParameterDescriptor = entry.getKey();
|
||||
|
||||
JetExpression expression = valueArgument.getArgumentExpression();
|
||||
// TODO : more attempts, with different expected types
|
||||
JetTypeInferrer.Services temporaryServices = typeInferrer.getServices(temporaryTrace);
|
||||
JetType type = temporaryServices.getType(scope, expression, NO_EXPECTED_TYPE);
|
||||
if (type != null) {
|
||||
constraintSystem.addSubtypingConstraint(type, valueParameterDescriptor.getOutType());
|
||||
}
|
||||
else {
|
||||
dirty.set(true);
|
||||
for (JetExpression expression : valueArgument.getArgumentExpressions()) {
|
||||
// JetExpression expression = valueArgument.getArgumentExpression();
|
||||
// TODO : more attempts, with different expected types
|
||||
JetTypeInferrer.Services temporaryServices = typeInferrer.getServices(temporaryTrace);
|
||||
JetType type = temporaryServices.getType(scope, expression, NO_EXPECTED_TYPE);
|
||||
if (type != null) {
|
||||
constraintSystem.addSubtypingConstraint(type, valueParameterDescriptor.getOutType());
|
||||
}
|
||||
else {
|
||||
candidateCall.argumentHasNoType();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
checkReceiverAbsence(candidateCall, tracing, candidate, temporaryTrace);
|
||||
checkReceiverAbsence(candidateCall, tracing, candidate);
|
||||
// Error is already reported if something is missing
|
||||
ReceiverDescriptor receiverParameter = candidateCall.getReceiverParameter();
|
||||
ReceiverDescriptor candidateReceiver = candidate.getReceiver();
|
||||
@@ -402,6 +373,7 @@ public class CallResolver {
|
||||
if (solution.isSuccessful()) {
|
||||
D substitute = (D) candidate.substitute(solution.getSubstitutor());
|
||||
assert substitute != null;
|
||||
replaceValueParametersWithSubstitutedOnes(candidateCall, substitute);
|
||||
successfulCandidates.add(candidateCall.setResultingDescriptor(substitute));
|
||||
}
|
||||
else {
|
||||
@@ -409,6 +381,15 @@ public class CallResolver {
|
||||
failedCandidates.add(candidateCall);
|
||||
}
|
||||
}
|
||||
else {
|
||||
if (checkValueArgumentTypes(scope, candidateCall)
|
||||
&& checkReceiver(candidateCall, tracing, candidate)) {
|
||||
successfulCandidates.add(candidateCall.setResultingDescriptor(candidate));
|
||||
}
|
||||
else {
|
||||
failedCandidates.add(candidateCall);
|
||||
}
|
||||
}
|
||||
}
|
||||
else {
|
||||
// Explicit type arguments passed
|
||||
@@ -436,12 +417,12 @@ public class CallResolver {
|
||||
checkGenericBoundsInAFunctionCall(jetTypeArguments, typeArguments, candidate, temporaryTrace);
|
||||
|
||||
Map<TypeConstructor, TypeProjection> substitutionContext = FunctionDescriptorUtil.createSubstitutionContext((FunctionDescriptor) candidate, typeArguments);
|
||||
D substitutedFunctionDescriptor = (D) candidate.substitute(TypeSubstitutor.create(substitutionContext));
|
||||
D substitutedDescriptor = (D) candidate.substitute(TypeSubstitutor.create(substitutionContext));
|
||||
|
||||
Function<ValueParameterDescriptor, ValueParameterDescriptor> mapFunction = createMapFunction(substitutedFunctionDescriptor);
|
||||
if (checkValueArgumentTypes(scope, temporaryTrace, argumentsToParameters, dirty, mapFunction)
|
||||
&& checkReceiver(candidateCall, tracing, substitutedFunctionDescriptor, temporaryTrace)) {
|
||||
successfulCandidates.add(candidateCall.setResultingDescriptor(substitutedFunctionDescriptor));
|
||||
replaceValueParametersWithSubstitutedOnes(candidateCall, substitutedDescriptor);
|
||||
if (checkValueArgumentTypes(scope, candidateCall)
|
||||
&& checkReceiver(candidateCall, tracing, substitutedDescriptor)) {
|
||||
successfulCandidates.add(candidateCall.setResultingDescriptor(substitutedDescriptor));
|
||||
}
|
||||
else {
|
||||
failedCandidates.add(candidateCall);
|
||||
@@ -454,16 +435,13 @@ public class CallResolver {
|
||||
}
|
||||
}
|
||||
|
||||
if (dirty.get()) {
|
||||
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);
|
||||
OverloadResolutionResults<D> results = computeResultAndReportErrors(trace, tracing, successfulCandidates, failedCandidates);
|
||||
if (!results.singleDescriptor()) {
|
||||
checkTypesWithNoCallee(trace, scope, task.getTypeArguments(), task.getValueArguments(), task.getFunctionLiteralArguments());
|
||||
}
|
||||
@@ -476,7 +454,15 @@ public class CallResolver {
|
||||
ReceiverDescriptor original = autoCastReceiver.getOriginal();
|
||||
if (original instanceof ExpressionReceiver) {
|
||||
ExpressionReceiver expressionReceiver = (ExpressionReceiver) original;
|
||||
trace.record(AUTOCAST, expressionReceiver.getExpression(), autoCastReceiver.getType());
|
||||
if (autoCastReceiver.canCast()) {
|
||||
trace.record(AUTOCAST, expressionReceiver.getExpression(), autoCastReceiver.getType());
|
||||
}
|
||||
else {
|
||||
trace.report(AUTOCAST_IMPOSSIBLE.on(expressionReceiver.getExpression(), autoCastReceiver.getType(), expressionReceiver.getExpression().getText()));
|
||||
}
|
||||
}
|
||||
else {
|
||||
assert autoCastReceiver.canCast() : "A non-expression receiver must always be autocastabe: " + original;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -498,45 +484,127 @@ public class CallResolver {
|
||||
}
|
||||
}
|
||||
|
||||
private <D extends CallableDescriptor> Function<ValueParameterDescriptor, ValueParameterDescriptor> createMapFunction(D substitutedFunctionDescriptor) {
|
||||
assert substitutedFunctionDescriptor != null;
|
||||
final Map<ValueParameterDescriptor, ValueParameterDescriptor> parameterMap = Maps.newHashMap();
|
||||
for (ValueParameterDescriptor valueParameterDescriptor : substitutedFunctionDescriptor.getValueParameters()) {
|
||||
// private <D extends CallableDescriptor> Function<ValueParameterDescriptor, ValueParameterDescriptor> createMapFunction(D substitutedFunctionDescriptor) {
|
||||
// assert substitutedFunctionDescriptor != null;
|
||||
// final Map<ValueParameterDescriptor, ValueParameterDescriptor> parameterMap = Maps.newHashMap();
|
||||
// for (ValueParameterDescriptor valueParameterDescriptor : substitutedFunctionDescriptor.getValueParameters()) {
|
||||
// parameterMap.put(valueParameterDescriptor.getOriginal(), valueParameterDescriptor);
|
||||
// }
|
||||
//
|
||||
// return new Function<ValueParameterDescriptor, ValueParameterDescriptor>() {
|
||||
// @Override
|
||||
// public ValueParameterDescriptor apply(ValueParameterDescriptor input) {
|
||||
// return parameterMap.get(input.getOriginal());
|
||||
// }
|
||||
// };
|
||||
// }
|
||||
|
||||
private <D extends CallableDescriptor> void replaceValueParametersWithSubstitutedOnes(ResolvedCall<D> candidateCall, @NotNull D substitutedDescriptor) {
|
||||
Map<ValueParameterDescriptor, ValueParameterDescriptor> parameterMap = Maps.newHashMap();
|
||||
for (ValueParameterDescriptor valueParameterDescriptor : substitutedDescriptor.getValueParameters()) {
|
||||
parameterMap.put(valueParameterDescriptor.getOriginal(), valueParameterDescriptor);
|
||||
}
|
||||
|
||||
return new Function<ValueParameterDescriptor, ValueParameterDescriptor>() {
|
||||
@Override
|
||||
public ValueParameterDescriptor apply(ValueParameterDescriptor input) {
|
||||
return parameterMap.get(input.getOriginal());
|
||||
}
|
||||
};
|
||||
Map<ValueParameterDescriptor, ResolvedValueArgument> valueArguments = candidateCall.getValueArguments();
|
||||
Map<ValueParameterDescriptor, ResolvedValueArgument> originalValueArguments = Maps.newHashMap(valueArguments);
|
||||
valueArguments.clear();
|
||||
for (Map.Entry<ValueParameterDescriptor, ResolvedValueArgument> entry : originalValueArguments.entrySet()) {
|
||||
ValueParameterDescriptor substitutedVersion = parameterMap.get(entry.getKey().getOriginal());
|
||||
assert substitutedVersion != null : entry.getKey();
|
||||
valueArguments.put(substitutedVersion, entry.getValue());
|
||||
}
|
||||
}
|
||||
|
||||
private <D extends CallableDescriptor> boolean checkReceiver(ResolvedCall<D> resolvedCall, TracingStrategy tracing, D candidate, TemporaryBindingTrace temporaryTrace) {
|
||||
if (!checkReceiverAbsence(resolvedCall, tracing, candidate, temporaryTrace)) return false;
|
||||
private <D extends CallableDescriptor> boolean checkValueArgumentTypes(
|
||||
JetScope scope,
|
||||
ResolvedCall<D> candidateCall) {
|
||||
boolean result = true;
|
||||
for (Map.Entry<ValueParameterDescriptor, ResolvedValueArgument> entry : candidateCall.getValueArguments().entrySet()) {
|
||||
ValueParameterDescriptor parameterDescriptor = entry.getKey();
|
||||
ResolvedValueArgument resolvedArgument = entry.getValue();
|
||||
|
||||
JetType parameterType = parameterDescriptor.getOutType();
|
||||
|
||||
List<JetExpression> argumentExpressions = resolvedArgument.getArgumentExpressions();
|
||||
for (JetExpression argumentExpression : argumentExpressions) {
|
||||
JetTypeInferrer.Services temporaryServices = typeInferrer.getServices(candidateCall.getTrace());
|
||||
JetType type = temporaryServices.getType(scope, argumentExpression, parameterType);
|
||||
if (type == null) {
|
||||
candidateCall.argumentHasNoType();
|
||||
}
|
||||
else if (!semanticServices.getTypeChecker().isSubtypeOf(type, parameterType)) {
|
||||
// VariableDescriptor variableDescriptor = AutoCastUtils.getVariableDescriptorFromSimpleName(temporaryTrace.getBindingContext(), argumentExpression);
|
||||
// if (variableDescriptor != null) {
|
||||
// JetType autoCastType = null;
|
||||
// for (JetType possibleType : dataFlowInfo.getPossibleTypesForVariable(variableDescriptor)) {
|
||||
// if (semanticServices.getTypeChecker().isSubtypeOf(type, parameterType)) {
|
||||
// autoCastType = possibleType;
|
||||
// break;
|
||||
// }
|
||||
// }
|
||||
// if (autoCastType != null) {
|
||||
// if (AutoCastUtils.isAutoCastable(variableDescriptor)) {
|
||||
// temporaryTrace.record(AUTOCAST, argumentExpression, autoCastType);
|
||||
// }
|
||||
// else {
|
||||
// temporaryTrace.report(AUTOCAST_IMPOSSIBLE.on(argumentExpression, autoCastType, variableDescriptor));
|
||||
// result = false;
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
// else {
|
||||
result = false;
|
||||
}
|
||||
}
|
||||
}
|
||||
// for (Map.Entry<ValueArgument, ValueParameterDescriptor> entry : argumentsToParameters.entrySet()) {
|
||||
// ValueArgument valueArgument = entry.getKey();
|
||||
// ValueParameterDescriptor valueParameterDescriptor = entry.getValue();
|
||||
//
|
||||
// ValueParameterDescriptor substitutedParameter = parameterMap.apply(valueParameterDescriptor);
|
||||
//
|
||||
// assert substitutedParameter != null;
|
||||
//
|
||||
// JetType parameterType = substitutedParameter.getOutType();
|
||||
// JetExpression argumentExpression = valueArgument.getArgumentExpression();
|
||||
// if (argumentExpression != null) {
|
||||
// JetTypeInferrer.Services temporaryServices = typeInferrer.getServices(temporaryTrace);
|
||||
// JetType type = temporaryServices.getType(scope, argumentExpression, parameterType);
|
||||
// if (type == null) {
|
||||
// dirty.set(true);
|
||||
// }
|
||||
// else if (!semanticServices.getTypeChecker().isSubtypeOf(type, parameterType)) {
|
||||
// result = false;
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
return result;
|
||||
}
|
||||
|
||||
private <D extends CallableDescriptor> boolean checkReceiver(ResolvedCall<D> resolvedCall, TracingStrategy tracing, D candidate) {
|
||||
if (!checkReceiverAbsence(resolvedCall, tracing, candidate)) return false;
|
||||
ReceiverDescriptor receiver = resolvedCall.getReceiverParameter();
|
||||
ReceiverDescriptor candidateReceiver = candidate.getReceiver();
|
||||
if (receiver.exists()
|
||||
&& candidateReceiver.exists()
|
||||
&& !semanticServices.getTypeChecker().isSubtypeOf(receiver.getType(), candidateReceiver.getType())) {
|
||||
tracing.missingReceiver(temporaryTrace, candidateReceiver);
|
||||
tracing.missingReceiver(resolvedCall.getTrace(), candidateReceiver);
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
private <D extends CallableDescriptor> boolean checkReceiverAbsence(ResolvedCall<D> resolvedCall, TracingStrategy tracing, D candidate, TemporaryBindingTrace temporaryTrace) {
|
||||
private <D extends CallableDescriptor> boolean checkReceiverAbsence(ResolvedCall<D> resolvedCall, TracingStrategy tracing, D candidate) {
|
||||
ReceiverDescriptor receiver = resolvedCall.getReceiverParameter();
|
||||
ReceiverDescriptor candidateReceiver = candidate.getReceiver();
|
||||
if (receiver.exists()) {
|
||||
if (!candidateReceiver.exists()) {
|
||||
tracing.noReceiverAllowed(temporaryTrace);
|
||||
tracing.noReceiverAllowed(resolvedCall.getTrace());
|
||||
return false;
|
||||
}
|
||||
}
|
||||
else if (candidateReceiver.exists()) {
|
||||
tracing.missingReceiver(temporaryTrace, candidateReceiver);
|
||||
tracing.missingReceiver(resolvedCall.getTrace(), candidateReceiver);
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
@@ -547,13 +615,20 @@ public class CallResolver {
|
||||
BindingTrace trace,
|
||||
TracingStrategy tracing,
|
||||
Set<ResolvedCall<D>> successfulCandidates, // original -> substituted
|
||||
Set<ResolvedCall<D>> failedCandidates,
|
||||
Set<ResolvedCall<D>> dirtyCandidates) {
|
||||
Set<ResolvedCall<D>> failedCandidates) {
|
||||
// TODO : maybe it's better to filter overrides out first, and only then look for the maximally specific
|
||||
if (successfulCandidates.size() > 0) {
|
||||
if (successfulCandidates.size() != 1) {
|
||||
Set<ResolvedCall<D>> cleanCandidates = Sets.newLinkedHashSet(successfulCandidates);
|
||||
cleanCandidates.removeAll(dirtyCandidates);
|
||||
boolean allClean = true;
|
||||
for (Iterator<ResolvedCall<D>> iterator = cleanCandidates.iterator(); iterator.hasNext(); ) {
|
||||
ResolvedCall<D> candidate = iterator.next();
|
||||
if (candidate.isDirty()) {
|
||||
iterator.remove();
|
||||
allClean = false;
|
||||
}
|
||||
}
|
||||
|
||||
if (cleanCandidates.isEmpty()) {
|
||||
cleanCandidates = successfulCandidates;
|
||||
}
|
||||
@@ -568,7 +643,7 @@ public class CallResolver {
|
||||
}
|
||||
|
||||
Set<ResolvedCall<D>> noOverrides = OverridingUtil.filterOverrides(successfulCandidates, MAP_TO_RESULT);
|
||||
if (dirtyCandidates.isEmpty()) {
|
||||
if (allClean) {
|
||||
// tracing.reportOverallResolutionError(trace, "Overload resolution ambiguity: "
|
||||
// + makeErrorMessageForMultipleDescriptors(noOverrides));
|
||||
tracing.ambiguity(trace, noOverrides);
|
||||
@@ -608,58 +683,6 @@ public class CallResolver {
|
||||
}
|
||||
}
|
||||
|
||||
private boolean checkValueArgumentTypes(
|
||||
JetScope scope,
|
||||
BindingTrace temporaryTrace,
|
||||
Map<ValueArgument, ValueParameterDescriptor> argumentsToParameters,
|
||||
Ref<Boolean> dirty,
|
||||
Function<ValueParameterDescriptor, ValueParameterDescriptor> parameterMap) {
|
||||
boolean result = true;
|
||||
for (Map.Entry<ValueArgument, ValueParameterDescriptor> entry : argumentsToParameters.entrySet()) {
|
||||
ValueArgument valueArgument = entry.getKey();
|
||||
ValueParameterDescriptor valueParameterDescriptor = entry.getValue();
|
||||
|
||||
ValueParameterDescriptor substitutedParameter = parameterMap.apply(valueParameterDescriptor);
|
||||
|
||||
assert substitutedParameter != null;
|
||||
|
||||
JetType parameterType = substitutedParameter.getOutType();
|
||||
JetExpression argumentExpression = valueArgument.getArgumentExpression();
|
||||
if (argumentExpression != null) {
|
||||
JetTypeInferrer.Services temporaryServices = typeInferrer.getServices(temporaryTrace);
|
||||
JetType type = temporaryServices.getType(scope, argumentExpression, parameterType);
|
||||
if (type == null) {
|
||||
dirty.set(true);
|
||||
}
|
||||
else if (!semanticServices.getTypeChecker().isSubtypeOf(type, parameterType)) {
|
||||
// VariableDescriptor variableDescriptor = AutoCastUtils.getVariableDescriptorFromSimpleName(temporaryTrace.getBindingContext(), argumentExpression);
|
||||
// if (variableDescriptor != null) {
|
||||
// JetType autoCastType = null;
|
||||
// for (JetType possibleType : dataFlowInfo.getPossibleTypesForVariable(variableDescriptor)) {
|
||||
// if (semanticServices.getTypeChecker().isSubtypeOf(type, parameterType)) {
|
||||
// autoCastType = possibleType;
|
||||
// break;
|
||||
// }
|
||||
// }
|
||||
// if (autoCastType != null) {
|
||||
// if (AutoCastUtils.isAutocastable(variableDescriptor)) {
|
||||
// temporaryTrace.record(AUTOCAST, argumentExpression, autoCastType);
|
||||
// }
|
||||
// else {
|
||||
// temporaryTrace.report(AUTOCAST_IMPOSSIBLE.on(argumentExpression, autoCastType, variableDescriptor));
|
||||
// result = false;
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
// else {
|
||||
result = false;
|
||||
// }
|
||||
}
|
||||
}
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
public void checkGenericBoundsInAFunctionCall(List<JetTypeProjection> jetTypeArguments, List<JetType> typeArguments, CallableDescriptor functionDescriptor, BindingTrace trace) {
|
||||
Map<TypeConstructor, TypeProjection> context = Maps.newHashMap();
|
||||
|
||||
@@ -690,7 +713,7 @@ public class CallResolver {
|
||||
call.setTrace(temporaryBindingTrace);
|
||||
candidates.add(call);
|
||||
}
|
||||
return computeResultAndReportErrors(trace, TracingStrategy.EMPTY, candidates, Collections.<ResolvedCall<FunctionDescriptor>>emptySet(), Collections.<ResolvedCall<FunctionDescriptor>>emptySet());
|
||||
return computeResultAndReportErrors(trace, TracingStrategy.EMPTY, candidates, Collections.<ResolvedCall<FunctionDescriptor>>emptySet());
|
||||
}
|
||||
|
||||
private List<ResolvedCall<FunctionDescriptor>> findCandidatesByExactSignature(JetScope scope, ReceiverDescriptor receiver, String name, List<JetType> parameterTypes) {
|
||||
|
||||
+13
-1
@@ -1,10 +1,22 @@
|
||||
package org.jetbrains.jet.lang.resolve.calls;
|
||||
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.jet.lang.psi.JetExpression;
|
||||
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* @author abreslav
|
||||
*/
|
||||
public class DefaultValueArgument implements ResolvedValueArgument {
|
||||
public static final DefaultValueArgument DEFAULT = new DefaultValueArgument();
|
||||
|
||||
DefaultValueArgument() {}
|
||||
private DefaultValueArgument() {}
|
||||
|
||||
@NotNull
|
||||
@Override
|
||||
public List<JetExpression> getArgumentExpressions() {
|
||||
return Collections.emptyList(); //throw new UnsupportedOperationException("Look into the default value of the parameter");
|
||||
}
|
||||
}
|
||||
|
||||
+14
-2
@@ -1,20 +1,32 @@
|
||||
package org.jetbrains.jet.lang.resolve.calls;
|
||||
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
import org.jetbrains.jet.lang.psi.JetExpression;
|
||||
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* @author abreslav
|
||||
*/
|
||||
public class ExpressionValueArgument implements ResolvedValueArgument {
|
||||
private final JetExpression expression;
|
||||
|
||||
public ExpressionValueArgument(@NotNull JetExpression expression) {
|
||||
public ExpressionValueArgument(@Nullable JetExpression expression) {
|
||||
this.expression = expression;
|
||||
}
|
||||
|
||||
@NotNull
|
||||
// Nullable when something like f(a, , b) was in the source code
|
||||
@Nullable
|
||||
public JetExpression getExpression() {
|
||||
return expression;
|
||||
}
|
||||
|
||||
@NotNull
|
||||
@Override
|
||||
public List<JetExpression> getArgumentExpressions() {
|
||||
if (expression == null) return Collections.emptyList();
|
||||
return Collections.singletonList(expression);
|
||||
}
|
||||
}
|
||||
|
||||
+14
-2
@@ -1,6 +1,7 @@
|
||||
package org.jetbrains.jet.lang.resolve.calls;
|
||||
|
||||
import com.google.common.collect.Sets;
|
||||
import gnu.trove.THashSet;
|
||||
import gnu.trove.TObjectHashingStrategy;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
import org.jetbrains.jet.lang.JetSemanticServices;
|
||||
@@ -28,7 +29,18 @@ public class OverloadingConflictResolver {
|
||||
|
||||
@Nullable
|
||||
public <D extends CallableDescriptor> ResolvedCall<D> findMaximallySpecific(Set<ResolvedCall<D>> candidates, boolean discriminateGenericDescriptors) {
|
||||
Set<ResolvedCall<D>> maximallySpecific = Sets.newHashSet();
|
||||
// Different autocasts may lead to the same candidate descriptor wrapped into different ResolvedCall objects
|
||||
Set<ResolvedCall<D>> maximallySpecific = new THashSet<ResolvedCall<D>>(new TObjectHashingStrategy<ResolvedCall<D>>() {
|
||||
@Override
|
||||
public boolean equals(ResolvedCall<D> o1, ResolvedCall<D> o2) {
|
||||
return o1 == null ? o2 == null : o1.getResultingDescriptor().equals(o2.getResultingDescriptor());
|
||||
}
|
||||
|
||||
@Override
|
||||
public int computeHashCode(ResolvedCall<D> object) {
|
||||
return object == null ? 0 : object.getResultingDescriptor().hashCode();
|
||||
}
|
||||
});
|
||||
meLoop:
|
||||
for (ResolvedCall<D> candidateCall : candidates) {
|
||||
D me = candidateCall.getResultingDescriptor();
|
||||
|
||||
@@ -54,9 +54,10 @@ public class ResolvedCall<D extends CallableDescriptor> {
|
||||
private D resultingDescriptor; // Probably substituted
|
||||
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<TypeParameterDescriptor, JetType> typeArguments = Maps.newLinkedHashMap();
|
||||
private final Map<ValueParameterDescriptor, JetType> autoCasts = Maps.newHashMap();
|
||||
private final Map<ValueParameterDescriptor, ResolvedValueArgument> valueArguments = Maps.newHashMap();
|
||||
private boolean someArgumentHasNoType = false;
|
||||
private TemporaryBindingTrace trace;
|
||||
|
||||
private ResolvedCall(@NotNull D candidateDescriptor) {
|
||||
@@ -120,4 +121,16 @@ public class ResolvedCall<D extends CallableDescriptor> {
|
||||
this.thisObject = thisObject;
|
||||
}
|
||||
|
||||
@NotNull
|
||||
public Map<ValueParameterDescriptor, ResolvedValueArgument> getValueArguments() {
|
||||
return valueArguments;
|
||||
}
|
||||
|
||||
public void argumentHasNoType() {
|
||||
this.someArgumentHasNoType = true;
|
||||
}
|
||||
|
||||
public boolean isDirty() {
|
||||
return someArgumentHasNoType;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,8 +1,15 @@
|
||||
package org.jetbrains.jet.lang.resolve.calls;
|
||||
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.jet.lang.psi.JetExpression;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* @author abreslav
|
||||
*/
|
||||
public interface ResolvedValueArgument {
|
||||
@NotNull
|
||||
List<JetExpression> getArgumentExpressions();
|
||||
|
||||
}
|
||||
|
||||
@@ -11,6 +11,7 @@ import org.jetbrains.jet.lang.types.DataFlowInfo;
|
||||
import org.jetbrains.jet.lang.types.JetType;
|
||||
|
||||
import java.util.Collection;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
|
||||
import static org.jetbrains.jet.lang.resolve.scopes.receivers.ReceiverDescriptor.NO_RECEIVER;
|
||||
@@ -70,43 +71,89 @@ import static org.jetbrains.jet.lang.resolve.scopes.receivers.ReceiverDescriptor
|
||||
// return result;
|
||||
// }
|
||||
|
||||
public List<ResolutionTask<D>> computePrioritizedTasks(@NotNull JetScope scope, @NotNull ReceiverDescriptor explicitReceiver, @NotNull Call call, @NotNull String name, @NotNull BindingContext bindingContext, @NotNull DataFlowInfo dataFlowInfo) {
|
||||
public List<ResolutionTask<D>> computePrioritizedTasks(@NotNull JetScope scope, @NotNull Call call, @NotNull String name, @NotNull BindingContext bindingContext, @NotNull DataFlowInfo dataFlowInfo) {
|
||||
List<ResolutionTask<D>> result = Lists.newArrayList();
|
||||
|
||||
doComputeTasks(scope, explicitReceiver, call, name, result, DataFlowInfo.getEmpty());
|
||||
ReceiverDescriptor explicitReceiver = call.getExplicitReceiver();
|
||||
doComputeTasks(scope, explicitReceiver, call, name, result, NO_AUTO_CASTS);
|
||||
|
||||
ReceiverDescriptor receiverToCast = explicitReceiver.exists() ? explicitReceiver : scope.getImplicitReceiver();
|
||||
if (receiverToCast.exists()) {
|
||||
doComputeTasks(scope, receiverToCast, call, name, result, dataFlowInfo);
|
||||
doComputeTasks(scope, receiverToCast, call, name, result, new AutoCastServiceImpl(dataFlowInfo, bindingContext));
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
private void doComputeTasks(JetScope scope, ReceiverDescriptor explicitReceiver, Call call, String name, List<ResolutionTask<D>> result, @NotNull DataFlowInfo dataFlowInfo) {
|
||||
private interface AutoCastService {
|
||||
List<ReceiverDescriptor> getVariantsForReceiver(ReceiverDescriptor receiverDescriptor);
|
||||
DataFlowInfo getDataFlowInfo();
|
||||
}
|
||||
|
||||
private static class AutoCastServiceImpl implements AutoCastService {
|
||||
private final DataFlowInfo dataFlowInfo;
|
||||
private final BindingContext bindingContext;
|
||||
|
||||
private AutoCastServiceImpl(DataFlowInfo dataFlowInfo, BindingContext bindingContext) {
|
||||
this.dataFlowInfo = dataFlowInfo;
|
||||
this.bindingContext = bindingContext;
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<ReceiverDescriptor> getVariantsForReceiver(ReceiverDescriptor receiverDescriptor) {
|
||||
return AutoCastUtils.getAutoCastVariants(bindingContext, dataFlowInfo, receiverDescriptor);
|
||||
}
|
||||
|
||||
@Override
|
||||
public DataFlowInfo getDataFlowInfo() {
|
||||
return dataFlowInfo;
|
||||
}
|
||||
}
|
||||
|
||||
private static AutoCastService NO_AUTO_CASTS = new AutoCastService() {
|
||||
@Override
|
||||
public DataFlowInfo getDataFlowInfo() {
|
||||
return DataFlowInfo.getEmpty();
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<ReceiverDescriptor> getVariantsForReceiver(ReceiverDescriptor receiverDescriptor) {
|
||||
return Collections.singletonList(receiverDescriptor);
|
||||
}
|
||||
};
|
||||
|
||||
private void doComputeTasks(JetScope scope, ReceiverDescriptor explicitReceiver, Call call, String name, List<ResolutionTask<D>> result, @NotNull AutoCastService autoCastService) {
|
||||
DataFlowInfo dataFlowInfo = autoCastService.getDataFlowInfo();
|
||||
List<ReceiverDescriptor> implicitReceivers = Lists.newArrayList();
|
||||
scope.getImplicitReceiversHierarchy(implicitReceivers);
|
||||
// AutoCastUtils.getAutoCastVariants(bindingContext, dataFlowInfo, receiverToCast)
|
||||
if (explicitReceiver.exists()) {
|
||||
Collection<ResolvedCall<D>> extensionFunctions = convertWithImpliedThis(explicitReceiver, getExtensionsByName(scope, name));
|
||||
List<ReceiverDescriptor> variantsForExplicitReceiver = autoCastService.getVariantsForReceiver(explicitReceiver);
|
||||
|
||||
Collection<ResolvedCall<D>> extensionFunctions = convertWithImpliedThis(variantsForExplicitReceiver, 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);
|
||||
|
||||
// AutoCastUtils.getAutoCastVariants(bindingContext, dataFlowInfo, receiverToCast)
|
||||
Collection<D> members = getMembersByName(explicitReceiver.getType(), name);
|
||||
Collection<ResolvedCall<D>> members = Lists.newArrayList();
|
||||
for (ReceiverDescriptor variant : variantsForExplicitReceiver) {
|
||||
Collection<D> membersForThisVariant = getMembersByName(variant.getType(), name);
|
||||
convertWithReceivers(membersForThisVariant, Collections.singletonList(variant), Collections.singletonList(NO_RECEIVER), members);
|
||||
}
|
||||
|
||||
addTask(result, call, locals, dataFlowInfo);
|
||||
addTask(result, call, convertWithReceivers(members, explicitReceiver, NO_RECEIVER), dataFlowInfo);
|
||||
addTask(result, call, members, dataFlowInfo);
|
||||
|
||||
for (ReceiverDescriptor implicitReceiver : implicitReceivers) {
|
||||
Collection<D> memberExtensions = getExtensionsByName(implicitReceiver.getType().getMemberScope(), name);
|
||||
addTask(result, call, convertWithReceivers(memberExtensions, implicitReceiver, explicitReceiver), dataFlowInfo);
|
||||
List<ReceiverDescriptor> variantsForImplicitReceiver = autoCastService.getVariantsForReceiver(implicitReceiver);
|
||||
addTask(result, call, convertWithReceivers(memberExtensions, variantsForImplicitReceiver, variantsForExplicitReceiver), dataFlowInfo);
|
||||
}
|
||||
|
||||
addTask(result, call, nonlocals, dataFlowInfo);
|
||||
}
|
||||
else {
|
||||
Collection<ResolvedCall<D>> functions = convertWithImpliedThis(explicitReceiver, getNonExtensionsByName(scope, name));
|
||||
Collection<ResolvedCall<D>> functions = convertWithImpliedThis(Collections.singletonList(explicitReceiver), getNonExtensionsByName(scope, name));
|
||||
|
||||
List<ResolvedCall<D>> nonlocals = Lists.newArrayList();
|
||||
List<ResolvedCall<D>> locals = Lists.newArrayList();
|
||||
@@ -116,31 +163,43 @@ import static org.jetbrains.jet.lang.resolve.scopes.receivers.ReceiverDescriptor
|
||||
addTask(result, call, locals, dataFlowInfo);
|
||||
|
||||
for (ReceiverDescriptor implicitReceiver : implicitReceivers) {
|
||||
doComputeTasks(scope, implicitReceiver, call, name, result, dataFlowInfo);
|
||||
doComputeTasks(scope, implicitReceiver, call, name, result, autoCastService);
|
||||
}
|
||||
|
||||
addTask(result, call, nonlocals, dataFlowInfo);
|
||||
}
|
||||
}
|
||||
|
||||
private Collection<ResolvedCall<D>> convertWithReceivers(Collection<D> descriptors, ReceiverDescriptor thisObject, ReceiverDescriptor receiverParameter) {
|
||||
private Collection<ResolvedCall<D>> convertWithReceivers(Collection<D> descriptors, Iterable<ReceiverDescriptor> thisObjects, Iterable<ReceiverDescriptor> receiverParameters) {
|
||||
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);
|
||||
}
|
||||
convertWithReceivers(descriptors, thisObjects, receiverParameters, result);
|
||||
return result;
|
||||
}
|
||||
|
||||
private Collection<ResolvedCall<D>> convertWithImpliedThis(ReceiverDescriptor receiverParameter, Collection<D> descriptors) {
|
||||
private void convertWithReceivers(Collection<D> descriptors, Iterable<ReceiverDescriptor> thisObjects, Iterable<ReceiverDescriptor> receiverParameters, Collection<ResolvedCall<D>> result) {
|
||||
// Collection<ResolvedCall<D>> result = Lists.newArrayList();
|
||||
for (ReceiverDescriptor thisObject : thisObjects) {
|
||||
for (ReceiverDescriptor receiverParameter : receiverParameters) {
|
||||
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(Iterable<ReceiverDescriptor> receiverParameters, 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);
|
||||
for (ReceiverDescriptor receiverParameter : receiverParameters) {
|
||||
for (D extension : descriptors) {
|
||||
ResolvedCall<D> resolvedCall = ResolvedCall.create(extension);
|
||||
resolvedCall.setReceiverParameter(receiverParameter);
|
||||
setImpliedThis(resolvedCall);
|
||||
result.add(resolvedCall);
|
||||
}
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
+41
-16
@@ -6,7 +6,7 @@ import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.jet.lang.descriptors.CallableDescriptor;
|
||||
import org.jetbrains.jet.lang.descriptors.ValueParameterDescriptor;
|
||||
import org.jetbrains.jet.lang.psi.*;
|
||||
import org.jetbrains.jet.lang.resolve.BindingTrace;
|
||||
import org.jetbrains.jet.lang.resolve.TemporaryBindingTrace;
|
||||
import org.jetbrains.jet.lang.types.CallMaker;
|
||||
|
||||
import java.util.List;
|
||||
@@ -20,15 +20,17 @@ import static org.jetbrains.jet.lang.resolve.BindingContext.REFERENCE_TARGET;
|
||||
* @author abreslav
|
||||
*/
|
||||
/*package*/ class ValueArgumentsToParametersMapper {
|
||||
public static <Descriptor extends CallableDescriptor> boolean mapValueArgumentsToParameters(
|
||||
@NotNull ResolutionTask<Descriptor> task,
|
||||
public static <D extends CallableDescriptor> boolean mapValueArgumentsToParameters(
|
||||
@NotNull ResolutionTask<D> task,
|
||||
@NotNull TracingStrategy tracing,
|
||||
@NotNull Descriptor candidate,
|
||||
@NotNull BindingTrace temporaryTrace,
|
||||
@NotNull Map<ValueArgument, ValueParameterDescriptor> argumentsToParameters
|
||||
@NotNull ResolvedCall<D> candidateCall
|
||||
) {
|
||||
|
||||
TemporaryBindingTrace temporaryTrace = candidateCall.getTrace();
|
||||
Map<ValueParameterDescriptor, VarargValueArgument> varargs = Maps.newHashMap();
|
||||
Set<ValueParameterDescriptor> usedParameters = Sets.newHashSet();
|
||||
|
||||
D candidate = candidateCall.getCandidateDescriptor();
|
||||
List<ValueParameterDescriptor> valueParameters = candidate.getValueParameters();
|
||||
|
||||
Map<String, ValueParameterDescriptor> parameterByName = Maps.newHashMap();
|
||||
@@ -58,7 +60,7 @@ import static org.jetbrains.jet.lang.resolve.BindingContext.REFERENCE_TARGET;
|
||||
temporaryTrace.report(ARGUMENT_PASSED_TWICE.on(nameReference));
|
||||
}
|
||||
temporaryTrace.record(REFERENCE_TARGET, nameReference, valueParameterDescriptor);
|
||||
argumentsToParameters.put(valueArgument, valueParameterDescriptor);
|
||||
put(candidateCall, valueParameterDescriptor, valueArgument, varargs);
|
||||
}
|
||||
if (somePositioned) {
|
||||
// temporaryTrace.getErrorHandler().genericError(nameNode, "Mixing named and positioned arguments in not allowed");
|
||||
@@ -78,12 +80,12 @@ import static org.jetbrains.jet.lang.resolve.BindingContext.REFERENCE_TARGET;
|
||||
if (i < parameterCount) {
|
||||
ValueParameterDescriptor valueParameterDescriptor = valueParameters.get(i);
|
||||
usedParameters.add(valueParameterDescriptor);
|
||||
argumentsToParameters.put(valueArgument, valueParameterDescriptor);
|
||||
put(candidateCall, valueParameterDescriptor, valueArgument, varargs);
|
||||
}
|
||||
else if (!valueParameters.isEmpty()) {
|
||||
ValueParameterDescriptor valueParameterDescriptor = valueParameters.get(valueParameters.size() - 1);
|
||||
if (valueParameterDescriptor.isVararg()) {
|
||||
argumentsToParameters.put(valueArgument, valueParameterDescriptor);
|
||||
put(candidateCall, valueParameterDescriptor, valueArgument, varargs);
|
||||
usedParameters.add(valueParameterDescriptor);
|
||||
}
|
||||
else {
|
||||
@@ -109,7 +111,8 @@ import static org.jetbrains.jet.lang.resolve.BindingContext.REFERENCE_TARGET;
|
||||
// temporaryTrace.getErrorHandler().genericError(possiblyLabeledFunctionLiteral.getNode(), getTooManyArgumentsMessage(candidate));
|
||||
temporaryTrace.report(TOO_MANY_ARGUMENTS.on(possiblyLabeledFunctionLiteral, candidate));
|
||||
error = true;
|
||||
} else {
|
||||
}
|
||||
else {
|
||||
JetFunctionLiteralExpression functionLiteral;
|
||||
if (possiblyLabeledFunctionLiteral instanceof JetLabelQualifiedExpression) {
|
||||
JetLabelQualifiedExpression labeledFunctionLiteral = (JetLabelQualifiedExpression) possiblyLabeledFunctionLiteral;
|
||||
@@ -119,20 +122,20 @@ import static org.jetbrains.jet.lang.resolve.BindingContext.REFERENCE_TARGET;
|
||||
functionLiteral = (JetFunctionLiteralExpression) possiblyLabeledFunctionLiteral;
|
||||
}
|
||||
|
||||
ValueParameterDescriptor parameterDescriptor = valueParameters.get(valueParameters.size() - 1);
|
||||
if (parameterDescriptor.isVararg()) {
|
||||
ValueParameterDescriptor valueParameterDescriptor = valueParameters.get(valueParameters.size() - 1);
|
||||
if (valueParameterDescriptor.isVararg()) {
|
||||
// temporaryTrace.getErrorHandler().genericError(possiblyLabeledFunctionLiteral.getNode(), "Passing value as a vararg is only allowed inside a parenthesized argument list");
|
||||
temporaryTrace.report(VARARG_OUTSIDE_PARENTHESES.on(possiblyLabeledFunctionLiteral));
|
||||
error = true;
|
||||
}
|
||||
else {
|
||||
if (!usedParameters.add(parameterDescriptor)) {
|
||||
if (!usedParameters.add(valueParameterDescriptor)) {
|
||||
// temporaryTrace.getErrorHandler().genericError(possiblyLabeledFunctionLiteral.getNode(), getTooManyArgumentsMessage(candidate));
|
||||
temporaryTrace.report(TOO_MANY_ARGUMENTS.on(possiblyLabeledFunctionLiteral, candidate));
|
||||
error = true;
|
||||
}
|
||||
else {
|
||||
argumentsToParameters.put(CallMaker.makeValueArgument(functionLiteral), parameterDescriptor);
|
||||
put(candidateCall, valueParameterDescriptor, CallMaker.makeValueArgument(functionLiteral), varargs);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -148,8 +151,14 @@ import static org.jetbrains.jet.lang.resolve.BindingContext.REFERENCE_TARGET;
|
||||
|
||||
for (ValueParameterDescriptor valueParameter : valueParameters) {
|
||||
if (!usedParameters.contains(valueParameter)) {
|
||||
if (!valueParameter.hasDefaultValue() && !valueParameter.isVararg()) {
|
||||
// tracing.reportWrongValueArguments(temporaryTrace, "No value passed for parameter " + valueParameter.getName());
|
||||
if (valueParameter.hasDefaultValue()) {
|
||||
candidateCall.recordValueArgument(valueParameter, DefaultValueArgument.DEFAULT);
|
||||
}
|
||||
else if (valueParameter.isVararg()) {
|
||||
candidateCall.recordValueArgument(valueParameter, new VarargValueArgument());
|
||||
}
|
||||
else {
|
||||
// tracing.reportWrongValueArguments(temporaryTrace, "No value passed for parameter " + valueParameter.getName());
|
||||
tracing.noValueForParameter(temporaryTrace, valueParameter);
|
||||
error = true;
|
||||
}
|
||||
@@ -158,6 +167,22 @@ import static org.jetbrains.jet.lang.resolve.BindingContext.REFERENCE_TARGET;
|
||||
return error;
|
||||
}
|
||||
|
||||
private static <D extends CallableDescriptor> void put(ResolvedCall<D> candidateCall, ValueParameterDescriptor valueParameterDescriptor, ValueArgument valueArgument, Map<ValueParameterDescriptor, VarargValueArgument> varargs) {
|
||||
if (valueParameterDescriptor.isVararg()) {
|
||||
VarargValueArgument vararg = varargs.get(valueParameterDescriptor);
|
||||
if (vararg == null) {
|
||||
vararg = new VarargValueArgument();
|
||||
varargs.put(valueParameterDescriptor, vararg);
|
||||
candidateCall.recordValueArgument(valueParameterDescriptor, vararg);
|
||||
}
|
||||
vararg.getArgumentExpressions().add(valueArgument.getArgumentExpression());
|
||||
}
|
||||
else {
|
||||
ResolvedValueArgument argument = new ExpressionValueArgument(valueArgument.getArgumentExpression());
|
||||
candidateCall.recordValueArgument(valueParameterDescriptor, argument);
|
||||
}
|
||||
}
|
||||
|
||||
// private static <Descriptor extends CallableDescriptor> String getTooManyArgumentsMessage(Descriptor candidate) {
|
||||
// return "Too many arguments for " + DescriptorRenderer.TEXT.render(candidate);
|
||||
// }
|
||||
|
||||
@@ -13,7 +13,8 @@ public class VarargValueArgument implements ResolvedValueArgument {
|
||||
private final List<JetExpression> values = Lists.newArrayList();
|
||||
|
||||
@NotNull
|
||||
public List<JetExpression> getValues() {
|
||||
@Override
|
||||
public List<JetExpression> getArgumentExpressions() {
|
||||
return values;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,10 +1,12 @@
|
||||
package org.jetbrains.jet.lang.types;
|
||||
|
||||
import com.google.common.collect.Lists;
|
||||
import com.intellij.lang.ASTNode;
|
||||
import com.intellij.psi.PsiElement;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
import org.jetbrains.jet.lang.psi.*;
|
||||
import org.jetbrains.jet.lang.resolve.scopes.receivers.ReceiverDescriptor;
|
||||
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
@@ -17,8 +19,8 @@ public class CallMaker {
|
||||
private static class ExpressionValueArgument implements ValueArgument {
|
||||
|
||||
private final JetExpression expression;
|
||||
private final PsiElement reportErrorsOn;
|
||||
|
||||
private final PsiElement reportErrorsOn;
|
||||
private ExpressionValueArgument(@NotNull JetExpression expression) {
|
||||
this(expression, expression);
|
||||
}
|
||||
@@ -60,18 +62,60 @@ public class CallMaker {
|
||||
}
|
||||
|
||||
}
|
||||
private static abstract class CallStub implements Call {
|
||||
|
||||
private static class CallImpl implements Call {
|
||||
|
||||
private final ASTNode callNode;
|
||||
private final ReceiverDescriptor explicitReceiver;
|
||||
private ASTNode callOperationNode;
|
||||
private final JetExpression calleeExpression;
|
||||
private final List<? extends ValueArgument> valueArguments;
|
||||
protected CallImpl(@NotNull ASTNode callNode, @NotNull ReceiverDescriptor explicitReceiver, @Nullable ASTNode callOperationNode, @NotNull JetExpression calleeExpression, @NotNull List<? extends ValueArgument> valueArguments) {
|
||||
this.callNode = callNode;
|
||||
this.explicitReceiver = explicitReceiver;
|
||||
this.callOperationNode = callOperationNode;
|
||||
this.calleeExpression = calleeExpression;
|
||||
this.valueArguments = valueArguments;
|
||||
}
|
||||
|
||||
@Override
|
||||
public ASTNode getCallOperationNode() {
|
||||
return callOperationNode;
|
||||
}
|
||||
|
||||
@NotNull
|
||||
@Override
|
||||
public ReceiverDescriptor getExplicitReceiver() {
|
||||
return explicitReceiver;
|
||||
}
|
||||
|
||||
@Override
|
||||
public JetExpression getCalleeExpression() {
|
||||
return calleeExpression;
|
||||
}
|
||||
|
||||
@NotNull
|
||||
@Override
|
||||
public List<? extends ValueArgument> getValueArguments() {
|
||||
return valueArguments;
|
||||
}
|
||||
|
||||
@NotNull
|
||||
@Override
|
||||
public ASTNode getCallNode() {
|
||||
return callNode;
|
||||
}
|
||||
|
||||
@Override
|
||||
public JetValueArgumentList getValueArgumentList() {
|
||||
return null;
|
||||
}
|
||||
|
||||
@NotNull
|
||||
@Override
|
||||
public List<JetExpression> getFunctionLiteralArguments() {
|
||||
return Collections.emptyList();
|
||||
}
|
||||
|
||||
@NotNull
|
||||
@Override
|
||||
public List<JetTypeProjection> getTypeArguments() {
|
||||
@@ -84,41 +128,31 @@ public class CallMaker {
|
||||
}
|
||||
|
||||
}
|
||||
public static Call makeCallWithArguments(final JetExpression calleeExpression, final List<? extends ValueArgument> valueArguments) {
|
||||
return new CallStub() {
|
||||
@Override
|
||||
public JetExpression getCalleeExpression() {
|
||||
return calleeExpression;
|
||||
}
|
||||
|
||||
@NotNull
|
||||
@Override
|
||||
public List<? extends ValueArgument> getValueArguments() {
|
||||
return valueArguments;
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
public static Call makeCall(final JetExpression calleeExpression, final 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();
|
||||
for (JetExpression argumentExpression : argumentExpressions) {
|
||||
arguments.add(makeValueArgument(argumentExpression, calleeExpression));
|
||||
}
|
||||
return makeCallWithArguments(calleeExpression, arguments);
|
||||
return makeCall(callElement, explicitReceiver, callOperationNode, calleeExpression, arguments);
|
||||
}
|
||||
|
||||
public static Call makeCall(final JetBinaryExpression expression) {
|
||||
return makeCall(expression.getOperationReference(), Collections.singletonList(expression.getRight()));
|
||||
public static Call makeCall(JetElement callElement, ReceiverDescriptor explicitReceiver, @Nullable ASTNode callOperationNode, JetExpression calleeExpression, List<? extends ValueArgument> arguments) {
|
||||
return new CallImpl(callElement.getNode(), explicitReceiver, callOperationNode, calleeExpression, arguments);
|
||||
}
|
||||
|
||||
public static Call makeCall(final JetUnaryExpression expression) {
|
||||
return makeCallWithArguments(expression.getOperationSign(), Collections.<ValueArgument>emptyList());
|
||||
public static Call makeCall(@NotNull ReceiverDescriptor leftAsReceiver, JetBinaryExpression expression) {
|
||||
return makeCallWithExpressions(expression, leftAsReceiver, null, expression.getOperationReference(), Collections.singletonList(expression.getRight()));
|
||||
}
|
||||
|
||||
public static Call makeCall(final JetArrayAccessExpression arrayAccessExpression, final JetExpression rightHandSide) {
|
||||
public static Call makeCall(@NotNull ReceiverDescriptor baseAsReceiver, JetUnaryExpression expression) {
|
||||
return makeCall(expression, baseAsReceiver, null, expression.getOperationSign(), Collections.<ValueArgument>emptyList());
|
||||
}
|
||||
|
||||
public static Call makeCall(@NotNull ReceiverDescriptor arrayAsReceiver,JetArrayAccessExpression arrayAccessExpression, JetExpression rightHandSide) {
|
||||
List<JetExpression> arguments = Lists.newArrayList(arrayAccessExpression.getIndexExpressions());
|
||||
arguments.add(rightHandSide);
|
||||
return makeCall(arrayAccessExpression, arguments);
|
||||
return makeCallWithExpressions(arrayAccessExpression, arrayAsReceiver, null, arrayAccessExpression, arguments);
|
||||
}
|
||||
|
||||
public static ValueArgument makeValueArgument(@NotNull JetExpression expression) {
|
||||
@@ -129,7 +163,58 @@ public class CallMaker {
|
||||
return new ExpressionValueArgument(expression, reportErrorsOn);
|
||||
}
|
||||
|
||||
public static Call makePropertyCall(@NotNull JetSimpleNameExpression nameExpression) {
|
||||
return makeCall(nameExpression, Collections.<JetExpression>emptyList());
|
||||
public static Call makePropertyCall(@NotNull ReceiverDescriptor explicitReceiver, @Nullable ASTNode callOperationNode, @NotNull JetSimpleNameExpression nameExpression) {
|
||||
return makeCallWithExpressions(nameExpression, explicitReceiver, callOperationNode, nameExpression, Collections.<JetExpression>emptyList());
|
||||
}
|
||||
|
||||
public static Call makeCall(@NotNull final ReceiverDescriptor explicitReceiver, @Nullable final ASTNode callOperationNode, @NotNull final JetCallElement callElement) {
|
||||
return new Call() {
|
||||
@Override
|
||||
public ASTNode getCallOperationNode() {
|
||||
return callOperationNode;
|
||||
}
|
||||
|
||||
@NotNull
|
||||
@Override
|
||||
public ReceiverDescriptor getExplicitReceiver() {
|
||||
return explicitReceiver;
|
||||
}
|
||||
|
||||
@Nullable
|
||||
public JetExpression getCalleeExpression() {
|
||||
return callElement.getCalleeExpression();
|
||||
}
|
||||
|
||||
@Nullable
|
||||
public JetValueArgumentList getValueArgumentList() {
|
||||
return callElement.getValueArgumentList();
|
||||
}
|
||||
|
||||
@NotNull
|
||||
public List<? extends ValueArgument> getValueArguments() {
|
||||
return callElement.getValueArguments();
|
||||
}
|
||||
|
||||
@NotNull
|
||||
public List<JetExpression> getFunctionLiteralArguments() {
|
||||
return callElement.getFunctionLiteralArguments();
|
||||
}
|
||||
|
||||
@NotNull
|
||||
public List<JetTypeProjection> getTypeArguments() {
|
||||
return callElement.getTypeArguments();
|
||||
}
|
||||
|
||||
@Nullable
|
||||
public JetTypeArgumentList getTypeArgumentList() {
|
||||
return callElement.getTypeArgumentList();
|
||||
}
|
||||
|
||||
@NotNull
|
||||
@Override
|
||||
public ASTNode getCallNode() {
|
||||
return callElement.getNode();
|
||||
}
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
@@ -19,6 +19,7 @@ import org.jetbrains.jet.lang.diagnostics.Diagnostic;
|
||||
import org.jetbrains.jet.lang.diagnostics.DiagnosticWithPsiElement;
|
||||
import org.jetbrains.jet.lang.psi.*;
|
||||
import org.jetbrains.jet.lang.resolve.*;
|
||||
import org.jetbrains.jet.lang.resolve.calls.AutoCastUtils;
|
||||
import org.jetbrains.jet.lang.resolve.calls.CallResolver;
|
||||
import org.jetbrains.jet.lang.resolve.calls.OverloadResolutionResults;
|
||||
import org.jetbrains.jet.lang.resolve.constants.*;
|
||||
@@ -36,14 +37,14 @@ import java.util.*;
|
||||
|
||||
import static org.jetbrains.jet.lang.diagnostics.Errors.*;
|
||||
import static org.jetbrains.jet.lang.resolve.BindingContext.*;
|
||||
import static org.jetbrains.jet.lang.resolve.scopes.receivers.ReceiverDescriptor.NO_RECEIVER;
|
||||
|
||||
/**
|
||||
* @author abreslav
|
||||
*/
|
||||
public class JetTypeInferrer {
|
||||
|
||||
private static final Set<String> numberConversions = new HashSet();
|
||||
|
||||
private static final Set<String> numberConversions = Sets.newHashSet();
|
||||
static {
|
||||
numberConversions.add("dbl");
|
||||
numberConversions.add("flt");
|
||||
@@ -216,33 +217,33 @@ public class JetTypeInferrer {
|
||||
return callResolver;
|
||||
}
|
||||
|
||||
//TODO JetElement -> JetWhenConditionCall || JetQualifiedExpression
|
||||
private void checkNullSafety(@Nullable JetType receiverType, @NotNull ASTNode operationTokenNode, @Nullable FunctionDescriptor callee, @NotNull JetElement element) {
|
||||
if (receiverType != null && callee != null) {
|
||||
boolean namespaceType = receiverType instanceof NamespaceType;
|
||||
boolean nullableReceiver = !namespaceType && receiverType.isNullable();
|
||||
ReceiverDescriptor calleeReceiver = callee.getReceiver();
|
||||
boolean calleeForbidsNullableReceiver = !calleeReceiver.exists() || !calleeReceiver.getType().isNullable();
|
||||
|
||||
IElementType operationSign = operationTokenNode.getElementType();
|
||||
if (nullableReceiver && calleeForbidsNullableReceiver && operationSign == JetTokens.DOT) {
|
||||
// trace.getErrorHandler().genericError(operationTokenNode, "Only safe calls (?.) are allowed on a nullable receiver of type " + receiverType);
|
||||
trace.report(UNSAFE_CALL.on(operationTokenNode, receiverType));
|
||||
}
|
||||
else if ((!nullableReceiver || !calleeForbidsNullableReceiver) && operationSign == JetTokens.SAFE_ACCESS) {
|
||||
if (namespaceType) {
|
||||
// trace.getErrorHandler().genericError(operationTokenNode, "Safe calls are not allowed on namespaces");
|
||||
trace.report(SAFE_CALLS_ARE_NOT_ALLOWED_ON_NAMESPACES.on(operationTokenNode));
|
||||
}
|
||||
else {
|
||||
// trace.getErrorHandler().genericWarning(operationTokenNode, "Unnecessary safe call on a non-null receiver of type " + receiverType);
|
||||
|
||||
trace.report(UNNECESSARY_SAFE_CALL.on(element, operationTokenNode, receiverType));
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
// TODO JetElement -> JetWhenConditionCall || JetQualifiedExpression
|
||||
// private void checkNullSafety(@Nullable JetType receiverType, @NotNull ASTNode operationTokenNode, @Nullable FunctionDescriptor callee, @NotNull JetElement element) {
|
||||
// if (receiverType != null && callee != null) {
|
||||
// boolean namespaceType = receiverType instanceof NamespaceType;
|
||||
// boolean nullableReceiver = !namespaceType && receiverType.isNullable();
|
||||
// ReceiverDescriptor calleeReceiver = callee.getReceiver();
|
||||
// boolean calleeForbidsNullableReceiver = !calleeReceiver.exists() || !calleeReceiver.getType().isNullable();
|
||||
//
|
||||
// IElementType operationSign = operationTokenNode.getElementType();
|
||||
// if (nullableReceiver && calleeForbidsNullableReceiver && operationSign == JetTokens.DOT) {
|
||||
//// trace.getErrorHandler().genericError(operationTokenNode, "Only safe calls (?.) are allowed on a nullable receiver of type " + receiverType);
|
||||
// trace.report(UNSAFE_CALL.on(operationTokenNode, receiverType));
|
||||
// }
|
||||
// else if ((!nullableReceiver || !calleeForbidsNullableReceiver) && operationSign == JetTokens.SAFE_ACCESS) {
|
||||
// if (namespaceType) {
|
||||
//// trace.getErrorHandler().genericError(operationTokenNode, "Safe calls are not allowed on namespaces");
|
||||
// trace.report(SAFE_CALLS_ARE_NOT_ALLOWED_ON_NAMESPACES.on(operationTokenNode));
|
||||
// }
|
||||
// else {
|
||||
//// trace.getErrorHandler().genericWarning(operationTokenNode, "Unnecessary safe call on a non-null receiver of type " + receiverType);
|
||||
//
|
||||
// trace.report(UNNECESSARY_SAFE_CALL.on(element, operationTokenNode, receiverType));
|
||||
//
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
|
||||
public void checkFunctionReturnType(@NotNull JetScope outerScope, @NotNull JetDeclarationWithBody function, @NotNull FunctionDescriptor functionDescriptor) {
|
||||
checkFunctionReturnType(outerScope, function, functionDescriptor, DataFlowInfo.getEmpty());
|
||||
@@ -483,67 +484,67 @@ public class JetTypeInferrer {
|
||||
};
|
||||
}
|
||||
|
||||
//TODO
|
||||
private JetType enrichOutType(JetExpression expression, JetType initialType, @NotNull TypeInferenceContext context) {
|
||||
if (expression == null) return initialType;
|
||||
VariableDescriptor variableDescriptor = getVariableDescriptorFromSimpleName(expression, context);
|
||||
if (variableDescriptor != null) {
|
||||
return context.dataFlowInfo.getOutType(variableDescriptor);
|
||||
}
|
||||
return initialType;
|
||||
}
|
||||
// //TODO
|
||||
// private JetType enrichOutType(JetExpression expression, JetType initialType, @NotNull TypeInferenceContext context) {
|
||||
// if (expression == null) return initialType;
|
||||
// VariableDescriptor variableDescriptor = getVariableDescriptorFromSimpleName(expression, context);
|
||||
// if (variableDescriptor != null) {
|
||||
// return context.dataFlowInfo.getOutType(variableDescriptor);
|
||||
// }
|
||||
// return initialType;
|
||||
// }
|
||||
|
||||
// @Nullable
|
||||
// private JetType checkType(@Nullable JetType expressionType, @NotNull JetExpression expression, @NotNull TypeInferenceContext context) {
|
||||
// if (expressionType != null && context.expectedType != null && context.expectedType != NO_EXPECTED_TYPE) {
|
||||
// if (!semanticServices.getTypeChecker().isSubtypeOf(expressionType, context.expectedType)) {
|
||||
// context.trace.report(TYPE_MISMATCH.on(expression, context.expectedType, expressionType));
|
||||
// }
|
||||
// }
|
||||
// return expressionType;
|
||||
// }
|
||||
|
||||
@Nullable
|
||||
private JetType checkType(@Nullable JetType expressionType, @NotNull JetExpression expression, @NotNull TypeInferenceContext context) {
|
||||
if (expressionType != null && context.expectedType != null && context.expectedType != NO_EXPECTED_TYPE) {
|
||||
if (!semanticServices.getTypeChecker().isSubtypeOf(expressionType, context.expectedType)) {
|
||||
context.trace.report(TYPE_MISMATCH.on(expression, context.expectedType, expressionType));
|
||||
}
|
||||
}
|
||||
return expressionType;
|
||||
}
|
||||
|
||||
@Nullable
|
||||
private JetType checkEnrichedType(@Nullable JetType expressionType, @NotNull JetExpression expression, @NotNull TypeInferenceContext context) {
|
||||
if (expressionType == null || context.expectedType == null || context.expectedType == NO_EXPECTED_TYPE ||
|
||||
semanticServices.getTypeChecker().isSubtypeOf(expressionType, context.expectedType)) {
|
||||
return expressionType;
|
||||
}
|
||||
VariableDescriptor variableDescriptor = getVariableDescriptorFromSimpleName(expression, context);
|
||||
boolean appropriateTypeFound = false;
|
||||
if (variableDescriptor != null) {
|
||||
List<JetType> possibleTypes = Lists.newArrayList(context.dataFlowInfo.getPossibleTypesForVariable(variableDescriptor));
|
||||
Collections.reverse(possibleTypes);
|
||||
for (JetType possibleType : possibleTypes) {
|
||||
if (semanticServices.getTypeChecker().isSubtypeOf(possibleType, context.expectedType)) {
|
||||
appropriateTypeFound = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (!appropriateTypeFound) {
|
||||
JetType notnullType = context.dataFlowInfo.getOutType(variableDescriptor);
|
||||
if (notnullType != null && semanticServices.getTypeChecker().isSubtypeOf(notnullType, context.expectedType)) {
|
||||
appropriateTypeFound = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (!appropriateTypeFound) {
|
||||
// VariableDescriptor variableDescriptor = AutoCastUtils.getVariableDescriptorFromSimpleName(context.trace.getBindingContext(), expression);
|
||||
// boolean appropriateTypeFound = false;
|
||||
// if (variableDescriptor != null) {
|
||||
// List<JetType> possibleTypes = Lists.newArrayList(context.dataFlowInfo.getPossibleTypesForVariable(variableDescriptor));
|
||||
// Collections.reverse(possibleTypes);
|
||||
// for (JetType possibleType : possibleTypes) {
|
||||
// if (semanticServices.getTypeChecker().isSubtypeOf(possibleType, context.expectedType)) {
|
||||
// appropriateTypeFound = true;
|
||||
// break;
|
||||
// }
|
||||
// }
|
||||
// if (!appropriateTypeFound) {
|
||||
// JetType notnullType = context.dataFlowInfo.getOutType(variableDescriptor);
|
||||
// if (notnullType != null && semanticServices.getTypeChecker().isSubtypeOf(notnullType, context.expectedType)) {
|
||||
// appropriateTypeFound = true;
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
if (AutoCastUtils.castExpression(expression, context.expectedType, context.dataFlowInfo, context.trace) == null) {
|
||||
// context.trace.getErrorHandler().typeMismatch(expression, context.expectedType, expressionType);
|
||||
context.trace.report(TYPE_MISMATCH.on(expression, context.expectedType, expressionType));
|
||||
return expressionType;
|
||||
}
|
||||
checkAutoCast(expression, context.expectedType, variableDescriptor, context.trace);
|
||||
// checkAutoCast(expression, context.expectedType, variableDescriptor, context.trace);
|
||||
return context.expectedType;
|
||||
}
|
||||
|
||||
private void checkAutoCast(JetExpression expression, JetType type, VariableDescriptor variableDescriptor, BindingTrace trace) {
|
||||
if (variableDescriptor.isVar()) {
|
||||
// trace.getErrorHandler().genericError(expression.getNode(), "Automatic cast to " + type + " is impossible, because variable " + variableDescriptor.getName() + " is mutable");
|
||||
trace.report(AUTOCAST_IMPOSSIBLE.on(expression, type, variableDescriptor));
|
||||
} else {
|
||||
trace.record(BindingContext.AUTOCAST, expression, type);
|
||||
}
|
||||
}
|
||||
// private void checkAutoCast(JetExpression expression, JetType type, VariableDescriptor variableDescriptor, BindingTrace trace) {
|
||||
// if (variableDescriptor.isVar()) {
|
||||
//// trace.getErrorHandler().genericError(expression.getNode(), "Automatic cast to " + type + " is impossible, because variable " + variableDescriptor.getName() + " is mutable");
|
||||
// trace.report(AUTOCAST_IMPOSSIBLE.on(expression, type, variableDescriptor));
|
||||
// } else {
|
||||
// trace.record(BindingContext.AUTOCAST, expression, type);
|
||||
// }
|
||||
// }
|
||||
|
||||
@NotNull
|
||||
private List<JetType> checkArgumentTypes(@NotNull List<JetType> argumentTypes, @NotNull List<JetExpression> arguments, @NotNull List<TypeProjection> expectedArgumentTypes, @NotNull TypeInferenceContext context) {
|
||||
@@ -552,7 +553,7 @@ public class JetTypeInferrer {
|
||||
}
|
||||
List<JetType> result = Lists.newArrayListWithCapacity(arguments.size());
|
||||
for (int i = 0, argumentTypesSize = argumentTypes.size(); i < argumentTypesSize; i++) {
|
||||
result.add(checkEnrichedType(argumentTypes.get(i), arguments.get(i), context.replaceExpectedType(expectedArgumentTypes.get(i).getType())));
|
||||
result.add(checkType(argumentTypes.get(i), arguments.get(i), context.replaceExpectedType(expectedArgumentTypes.get(i).getType())));
|
||||
}
|
||||
return result;
|
||||
}
|
||||
@@ -675,12 +676,12 @@ public class JetTypeInferrer {
|
||||
|
||||
@Nullable
|
||||
public FunctionDescriptor resolveCallWithGivenName(@NotNull Call call, @NotNull JetReferenceExpression functionReference, @NotNull String name, @NotNull ReceiverDescriptor receiver) {
|
||||
return getCallResolver().resolveCallWithGivenName(trace, scope, call, functionReference, name, receiver, expectedType);
|
||||
return getCallResolver().resolveCallWithGivenName(trace, scope, call, functionReference, name, expectedType);
|
||||
}
|
||||
|
||||
@Nullable
|
||||
public JetType resolveCall(@NotNull ReceiverDescriptor receiver, @NotNull JetCallElement call) {
|
||||
return getCallResolver().resolveCall(trace, scope, receiver, call, expectedType);
|
||||
public JetType resolveCall(@NotNull ReceiverDescriptor receiver, @NotNull JetCallExpression callExpression) {
|
||||
return getCallResolver().resolveCall(trace, scope, CallMaker.makeCall(receiver, (ASTNode) null, callExpression), expectedType);
|
||||
}
|
||||
|
||||
@Nullable
|
||||
@@ -802,11 +803,11 @@ public class JetTypeInferrer {
|
||||
}
|
||||
else {
|
||||
context.trace.record(REFERENCE_TARGET, expression, property);
|
||||
return context.services.checkEnrichedType(property.getOutType(), expression, context);
|
||||
return context.services.checkType(property.getOutType(), expression, context);
|
||||
}
|
||||
}
|
||||
else {
|
||||
return getSelectorReturnType(ReceiverDescriptor.NO_RECEIVER, expression, context); // TODO : Extensions to this
|
||||
return getSelectorReturnType(NO_RECEIVER, expression, context); // TODO : Extensions to this
|
||||
// assert JetTokens.IDENTIFIER == expression.getReferencedNameElementType();
|
||||
// if (referencedName != null) {
|
||||
// VariableDescriptor variable = context.scope.getVariable(referencedName);
|
||||
@@ -816,7 +817,7 @@ public class JetTypeInferrer {
|
||||
// if (result == null) {
|
||||
// context.trace.getErrorHandler().genericError(expression.getNode(), "This variable is not readable in this context");
|
||||
// }
|
||||
// return context.services.checkEnrichedType(result, expression, context);
|
||||
// return context.services.checkType(result, expression, context);
|
||||
// }
|
||||
// else {
|
||||
// return lookupNamespaceOrClassObject(expression, referencedName, context);
|
||||
@@ -831,12 +832,12 @@ public class JetTypeInferrer {
|
||||
// context.trace.getErrorHandler().genericError(expression.getNode(), "Classifier " + classifier.getName() + " does not have a class object");
|
||||
// }
|
||||
// context.trace.record(REFERENCE_TARGET, expression, classifier);
|
||||
// return context.services.checkEnrichedType(result, expression, context);
|
||||
// return context.services.checkType(result, expression, context);
|
||||
// }
|
||||
// else {
|
||||
// JetType[] result = new JetType[1];
|
||||
// if (furtherNameLookup(expression, referencedName, result, context)) {
|
||||
// return context.services.checkEnrichedType(result[0], expression, context);
|
||||
// return context.services.checkType(result[0], expression, context);
|
||||
// }
|
||||
//
|
||||
// }
|
||||
@@ -863,12 +864,12 @@ public class JetTypeInferrer {
|
||||
if (result == null) {
|
||||
return ErrorUtils.createErrorType("No class object in " + expression.getReferencedName());
|
||||
}
|
||||
return context.services.checkEnrichedType(result, expression, context);
|
||||
return context.services.checkType(result, expression, context);
|
||||
}
|
||||
else {
|
||||
JetType[] result = new JetType[1];
|
||||
if (furtherNameLookup(expression, referencedName, result, context)) {
|
||||
return context.services.checkEnrichedType(result[0], expression, context);
|
||||
return context.services.checkType(result[0], expression, context);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1440,7 +1441,7 @@ public class JetTypeInferrer {
|
||||
assert subjectExpression != null;
|
||||
JetType selectorReturnType = getSelectorReturnType(new ExpressionReceiver(subjectExpression, subjectType), callSuffixExpression, context);//getType(compositeScope, callSuffixExpression, false, context);
|
||||
ensureBooleanResultWithCustomSubject(callSuffixExpression, selectorReturnType, "This expression", context);
|
||||
context.services.checkNullSafety(subjectType, condition.getOperationTokenNode(), getCalleeFunctionDescriptor(callSuffixExpression, context), condition);
|
||||
// context.services.checkNullSafety(subjectType, condition.getOperationTokenNode(), getCalleeFunctionDescriptor(callSuffixExpression, context), condition);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1449,7 +1450,7 @@ public class JetTypeInferrer {
|
||||
JetExpression rangeExpression = condition.getRangeExpression();
|
||||
if (rangeExpression != null) {
|
||||
assert subjectExpression != null;
|
||||
checkInExpression(condition.getOperationReference(), subjectExpression, rangeExpression, context);
|
||||
checkInExpression(condition, condition.getOperationReference(), subjectExpression, rangeExpression, context);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2042,9 +2043,9 @@ public class JetTypeInferrer {
|
||||
}
|
||||
|
||||
// Clean resolution: no autocasts
|
||||
TemporaryBindingTrace cleanResolutionTrace = TemporaryBindingTrace.create(context.trace);
|
||||
TypeInferenceContext cleanResolutionContext = context.replaceBindingTrace(cleanResolutionTrace);
|
||||
JetType selectorReturnType = getSelectorReturnType(new ExpressionReceiver(receiverExpression, receiverType), selectorExpression, cleanResolutionContext);
|
||||
// TemporaryBindingTrace cleanResolutionTrace = TemporaryBindingTrace.create(context.trace);
|
||||
// TypeInferenceContext cleanResolutionContext = context.replaceBindingTrace(cleanResolutionTrace);
|
||||
JetType selectorReturnType = getSelectorReturnType(new ExpressionReceiver(receiverExpression, receiverType), selectorExpression, context);
|
||||
|
||||
//TODO move further
|
||||
if (expression.getOperationSign() == JetTokens.SAFE_ACCESS) {
|
||||
@@ -2052,40 +2053,40 @@ public class JetTypeInferrer {
|
||||
selectorReturnType = TypeUtils.makeNullable(selectorReturnType);
|
||||
}
|
||||
}
|
||||
if (selectorReturnType != null) {
|
||||
cleanResolutionTrace.addAllMyDataTo(context.trace);
|
||||
}
|
||||
else {
|
||||
VariableDescriptor variableDescriptor = cleanResolutionContext.services.getVariableDescriptorFromSimpleName(receiverExpression, context);
|
||||
boolean somethingFound = false;
|
||||
if (variableDescriptor != null) {
|
||||
List<JetType> possibleTypes = Lists.newArrayList(context.dataFlowInfo.getPossibleTypesForVariable(variableDescriptor));
|
||||
Collections.reverse(possibleTypes);
|
||||
|
||||
TemporaryBindingTrace autocastResolutionTrace = TemporaryBindingTrace.create(context.trace);
|
||||
TypeInferenceContext autocastResolutionContext = context.replaceBindingTrace(autocastResolutionTrace);
|
||||
for (JetType possibleType : possibleTypes) {
|
||||
selectorReturnType = getSelectorReturnType(new ExpressionReceiver(receiverExpression, possibleType), selectorExpression, autocastResolutionContext);
|
||||
if (selectorReturnType != null) {
|
||||
context.services.checkAutoCast(receiverExpression, possibleType, variableDescriptor, autocastResolutionTrace);
|
||||
autocastResolutionTrace.commit();
|
||||
somethingFound = true;
|
||||
break;
|
||||
}
|
||||
else {
|
||||
autocastResolutionTrace = TemporaryBindingTrace.create(context.trace);
|
||||
autocastResolutionContext = context.replaceBindingTrace(autocastResolutionTrace);
|
||||
}
|
||||
}
|
||||
}
|
||||
if (!somethingFound) {
|
||||
cleanResolutionTrace.commit();
|
||||
}
|
||||
}
|
||||
// if (selectorReturnType != null) {
|
||||
// cleanResolutionTrace.addAllMyDataTo(context.trace);
|
||||
// }
|
||||
// else {
|
||||
// VariableDescriptor variableDescriptor = cleanResolutionContext.services.getVariableDescriptorFromSimpleName(receiverExpression, context);
|
||||
// boolean somethingFound = false;
|
||||
// if (variableDescriptor != null) {
|
||||
// List<JetType> possibleTypes = Lists.newArrayList(context.dataFlowInfo.getPossibleTypesForVariable(variableDescriptor));
|
||||
// Collections.reverse(possibleTypes);
|
||||
//
|
||||
// TemporaryBindingTrace autocastResolutionTrace = TemporaryBindingTrace.create(context.trace);
|
||||
// TypeInferenceContext autocastResolutionContext = context.replaceBindingTrace(autocastResolutionTrace);
|
||||
// for (JetType possibleType : possibleTypes) {
|
||||
// selectorReturnType = getSelectorReturnType(new ExpressionReceiver(receiverExpression, possibleType), selectorExpression, autocastResolutionContext);
|
||||
// if (selectorReturnType != null) {
|
||||
// context.services.checkAutoCast(receiverExpression, possibleType, variableDescriptor, autocastResolutionTrace);
|
||||
// autocastResolutionTrace.commit();
|
||||
// somethingFound = true;
|
||||
// break;
|
||||
// }
|
||||
// else {
|
||||
// autocastResolutionTrace = TemporaryBindingTrace.create(context.trace);
|
||||
// autocastResolutionContext = context.replaceBindingTrace(autocastResolutionTrace);
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
// if (!somethingFound) {
|
||||
// cleanResolutionTrace.commit();
|
||||
// }
|
||||
// }
|
||||
|
||||
JetType result;
|
||||
if (expression.getOperationSign() == JetTokens.QUEST) {
|
||||
if (selectorReturnType != null && !isBoolean(selectorReturnType) && selectorExpression != null) {
|
||||
if (selectorReturnType != null && !isBoolean(selectorReturnType)) {
|
||||
// TODO : more comprehensible error message
|
||||
// context.trace.getErrorHandler().typeMismatch(selectorExpression, semanticServices.getStandardLibrary().getBooleanType(), selectorReturnType);
|
||||
context.trace.report(TYPE_MISMATCH.on(selectorExpression, semanticServices.getStandardLibrary().getBooleanType(), selectorReturnType));
|
||||
@@ -2095,16 +2096,15 @@ public class JetTypeInferrer {
|
||||
else {
|
||||
result = selectorReturnType;
|
||||
}
|
||||
if (selectorExpression != null && result != null) {
|
||||
// TODO : this is suspicious: remove this code?
|
||||
if (result != null) {
|
||||
context.trace.record(BindingContext.EXPRESSION_TYPE, selectorExpression, result);
|
||||
}
|
||||
if (selectorReturnType != null) {
|
||||
// TODO : extensions to 'Any?'
|
||||
if (selectorExpression != null) {
|
||||
receiverType = context.services.enrichOutType(receiverExpression, receiverType, context);
|
||||
|
||||
context.services.checkNullSafety(receiverType, expression.getOperationTokenNode(), getCalleeFunctionDescriptor(selectorExpression, context), expression);
|
||||
}
|
||||
// // TODO : extensions to 'Any?'
|
||||
// receiverType = context.services.enrichOutType(receiverExpression, receiverType, context);
|
||||
//
|
||||
// context.services.checkNullSafety(receiverType, expression.getOperationTokenNode(), getCalleeFunctionDescriptor(selectorExpression, context), expression);
|
||||
}
|
||||
return context.services.checkType(result, expression, contextWithExpectedType);
|
||||
}
|
||||
@@ -2139,58 +2139,58 @@ public class JetTypeInferrer {
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@NotNull
|
||||
private FunctionDescriptor getCalleeFunctionDescriptor(@NotNull JetExpression selectorExpression, final TypeInferenceContext context) {
|
||||
final FunctionDescriptor[] result = new FunctionDescriptor[1];
|
||||
selectorExpression.accept(new JetVisitorVoid() {
|
||||
@Override
|
||||
public void visitCallExpression(JetCallExpression callExpression) {
|
||||
JetExpression calleeExpression = callExpression.getCalleeExpression();
|
||||
if (calleeExpression != null) {
|
||||
calleeExpression.accept(this);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void visitReferenceExpression(JetReferenceExpression referenceExpression) {
|
||||
DeclarationDescriptor declarationDescriptor = context.trace.getBindingContext().get(REFERENCE_TARGET, referenceExpression);
|
||||
if (declarationDescriptor instanceof FunctionDescriptor) {
|
||||
result[0] = (FunctionDescriptor) declarationDescriptor;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void visitArrayAccessExpression(JetArrayAccessExpression expression) {
|
||||
expression.getArrayExpression().accept(this);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void visitBinaryExpression(JetBinaryExpression expression) {
|
||||
expression.getLeft().accept(this);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void visitQualifiedExpression(JetQualifiedExpression expression) {
|
||||
expression.getReceiverExpression().accept(this);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void visitJetElement(JetElement element) {
|
||||
// context.trace.getErrorHandler().genericError(element.getNode(), "Unsupported [getCalleeFunctionDescriptor]: " + element);
|
||||
context.trace.report(UNSUPPORTED.on(element, "getCalleeFunctionDescriptor"));
|
||||
}
|
||||
});
|
||||
if (result[0] == null) {
|
||||
result[0] = ErrorUtils.createErrorFunction(0, Collections.<JetType>emptyList());
|
||||
}
|
||||
return result[0];
|
||||
}
|
||||
// @NotNull
|
||||
// private FunctionDescriptor getCalleeFunctionDescriptor(@NotNull JetExpression selectorExpression, final TypeInferenceContext context) {
|
||||
// final FunctionDescriptor[] result = new FunctionDescriptor[1];
|
||||
// selectorExpression.accept(new JetVisitorVoid() {
|
||||
// @Override
|
||||
// public void visitCallExpression(JetCallExpression callExpression) {
|
||||
// JetExpression calleeExpression = callExpression.getCalleeExpression();
|
||||
// if (calleeExpression != null) {
|
||||
// calleeExpression.accept(this);
|
||||
// }
|
||||
// }
|
||||
//
|
||||
// @Override
|
||||
// public void visitReferenceExpression(JetReferenceExpression referenceExpression) {
|
||||
// DeclarationDescriptor declarationDescriptor = context.trace.getBindingContext().get(REFERENCE_TARGET, referenceExpression);
|
||||
// if (declarationDescriptor instanceof FunctionDescriptor) {
|
||||
// result[0] = (FunctionDescriptor) declarationDescriptor;
|
||||
// }
|
||||
// }
|
||||
//
|
||||
// @Override
|
||||
// public void visitArrayAccessExpression(JetArrayAccessExpression expression) {
|
||||
// expression.getArrayExpression().accept(this);
|
||||
// }
|
||||
//
|
||||
// @Override
|
||||
// public void visitBinaryExpression(JetBinaryExpression expression) {
|
||||
// expression.getLeft().accept(this);
|
||||
// }
|
||||
//
|
||||
// @Override
|
||||
// public void visitQualifiedExpression(JetQualifiedExpression expression) {
|
||||
// expression.getReceiverExpression().accept(this);
|
||||
// }
|
||||
//
|
||||
// @Override
|
||||
// public void visitJetElement(JetElement element) {
|
||||
//// context.trace.getErrorHandler().genericError(element.getNode(), "Unsupported [getCalleeFunctionDescriptor]: " + element);
|
||||
// context.trace.report(UNSUPPORTED.on(element, "getCalleeFunctionDescriptor"));
|
||||
// }
|
||||
// });
|
||||
// if (result[0] == null) {
|
||||
// result[0] = ErrorUtils.createErrorFunction(0, Collections.<JetType>emptyList());
|
||||
// }
|
||||
// return result[0];
|
||||
// }
|
||||
|
||||
@Nullable
|
||||
private JetType getSelectorReturnType(@NotNull ReceiverDescriptor receiver, @NotNull JetExpression selectorExpression, @NotNull TypeInferenceContext context) {
|
||||
if (selectorExpression instanceof JetCallExpression) {
|
||||
return context.resolveCall(receiver, (JetCallExpression) selectorExpression);
|
||||
JetCallExpression callExpression = (JetCallExpression) selectorExpression;
|
||||
return context.resolveCall(receiver, callExpression);
|
||||
}
|
||||
else if (selectorExpression instanceof JetSimpleNameExpression) {
|
||||
JetSimpleNameExpression nameExpression = (JetSimpleNameExpression) selectorExpression;
|
||||
@@ -2199,14 +2199,14 @@ public class JetTypeInferrer {
|
||||
VariableDescriptor variableDescriptor = context.replaceBindingTrace(temporaryTrace).resolveSimpleProperty(receiver, nameExpression);
|
||||
if (variableDescriptor != null) {
|
||||
temporaryTrace.commit();
|
||||
return context.services.checkEnrichedType(variableDescriptor.getOutType(), nameExpression, context);
|
||||
return context.services.checkType(variableDescriptor.getOutType(), nameExpression, context);
|
||||
}
|
||||
TypeInferenceContext newContext = receiver.exists() ? context.replaceScope(receiver.getType().getMemberScope()) : context;
|
||||
JetType jetType = lookupNamespaceOrClassObject(nameExpression, nameExpression.getReferencedName(), newContext);
|
||||
if (jetType == null) {
|
||||
context.trace.report(UNRESOLVED_REFERENCE.on(nameExpression));
|
||||
}
|
||||
return context.services.checkEnrichedType(jetType, nameExpression, context);
|
||||
return context.services.checkType(jetType, nameExpression, context);
|
||||
// JetScope scope = receiverType != null ? receiverType.getMemberScope() : context.scope;
|
||||
// return getType(selectorExpression, context.replaceScope(scope));
|
||||
}
|
||||
@@ -2229,7 +2229,7 @@ public class JetTypeInferrer {
|
||||
|
||||
@Override
|
||||
public JetType visitCallExpression(JetCallExpression expression, TypeInferenceContext context) {
|
||||
JetType expressionType = context.resolveCall(ReceiverDescriptor.NO_RECEIVER, expression);
|
||||
JetType expressionType = context.resolveCall(NO_RECEIVER, expression);
|
||||
return context.services.checkType(expressionType, expression, context);
|
||||
}
|
||||
|
||||
@@ -2267,7 +2267,7 @@ public class JetTypeInferrer {
|
||||
if (receiver == null) return null;
|
||||
|
||||
FunctionDescriptor functionDescriptor = context.resolveCallWithGivenName(
|
||||
CallMaker.makeCall(expression),
|
||||
CallMaker.makeCall(receiver, expression),
|
||||
expression.getOperationSign(),
|
||||
name,
|
||||
receiver);
|
||||
@@ -2379,7 +2379,7 @@ public class JetTypeInferrer {
|
||||
result = ErrorUtils.createErrorType("No right argument"); // TODO
|
||||
return null;
|
||||
}
|
||||
checkInExpression(operationSign, left, right, context);
|
||||
checkInExpression(expression, expression.getOperationReference(), expression.getLeft(), expression.getRight(), context);
|
||||
result = semanticServices.getStandardLibrary().getBooleanType();
|
||||
}
|
||||
else if (operationType == JetTokens.ANDAND || operationType == JetTokens.OROR) {
|
||||
@@ -2419,11 +2419,11 @@ public class JetTypeInferrer {
|
||||
return context.services.checkType(result, expression, contextWithExpectedType);
|
||||
}
|
||||
|
||||
private void checkInExpression(JetSimpleNameExpression operationSign, JetExpression left, JetExpression right, TypeInferenceContext context) {
|
||||
private void checkInExpression(JetElement callElement, @NotNull JetSimpleNameExpression operationSign, @NotNull JetExpression left, @NotNull JetExpression right, TypeInferenceContext context) {
|
||||
String name = "contains";
|
||||
ExpressionReceiver receiver = safeGetExpressionReceiver(right, context.replaceExpectedType(NO_EXPECTED_TYPE));
|
||||
FunctionDescriptor functionDescriptor = context.resolveCallWithGivenName(
|
||||
CallMaker.makeCall(operationSign, Collections.singletonList(left)),
|
||||
CallMaker.makeCallWithExpressions(callElement, receiver, null, operationSign, Collections.singletonList(left)),
|
||||
operationSign,
|
||||
name, receiver);
|
||||
JetType containsType = functionDescriptor != null ? functionDescriptor.getReturnType() : null;
|
||||
@@ -2492,7 +2492,7 @@ public class JetTypeInferrer {
|
||||
|
||||
if (receiver != null) {
|
||||
FunctionDescriptor functionDescriptor = context.resolveCallWithGivenName(
|
||||
CallMaker.makeCall(expression, expression.getIndexExpressions()),
|
||||
CallMaker.makeCallWithExpressions(expression, receiver, null, expression, expression.getIndexExpressions()),
|
||||
expression,
|
||||
"get",
|
||||
receiver);
|
||||
@@ -2507,7 +2507,7 @@ public class JetTypeInferrer {
|
||||
protected JetType getTypeForBinaryCall(JetScope scope, String name, TypeInferenceContext context, JetBinaryExpression binaryExpression) {
|
||||
ExpressionReceiver receiver = safeGetExpressionReceiver(binaryExpression.getLeft(), context.replaceScope(scope));
|
||||
FunctionDescriptor functionDescriptor = context.replaceScope(scope).resolveCallWithGivenName(
|
||||
CallMaker.makeCall(binaryExpression),
|
||||
CallMaker.makeCall(receiver, binaryExpression),
|
||||
binaryExpression.getOperationReference(),
|
||||
name,
|
||||
receiver);
|
||||
@@ -2755,7 +2755,7 @@ public class JetTypeInferrer {
|
||||
ExpressionReceiver receiver = getExpressionReceiver(arrayAccessExpression.getArrayExpression(), context.replaceScope(scope));
|
||||
if (receiver == null) return null;
|
||||
//
|
||||
Call call = CallMaker.makeCall(arrayAccessExpression, rightHandSide);
|
||||
Call call = CallMaker.makeCall(receiver, arrayAccessExpression, rightHandSide);
|
||||
// // TODO : nasty hack: effort is duplicated
|
||||
// callResolver.resolveCallWithGivenName(
|
||||
// scope,
|
||||
|
||||
@@ -0,0 +1,16 @@
|
||||
trait B {
|
||||
fun bar() {}
|
||||
}
|
||||
|
||||
class C() {
|
||||
fun bar() {
|
||||
}
|
||||
}
|
||||
|
||||
fun test(a : Any?) {
|
||||
if (a is B) {
|
||||
if (a is C) {
|
||||
a.<!OVERLOAD_RESOLUTION_AMBIGUITY!>bar()<!>;
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user