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