Receivers made available at CallResolver

This commit is contained in:
Andrey Breslav
2011-10-10 21:38:40 +04:00
parent 114763b0b2
commit a39379edbf
19 changed files with 769 additions and 436 deletions
@@ -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) {
@@ -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");
}
}
@@ -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);
}
}
@@ -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;
}
@@ -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()<!>;
}
}
}