Implicit receivers checked properly. Receiver checks restructured.

This commit is contained in:
Andrey Breslav
2011-10-11 18:25:01 +04:00
parent a39379edbf
commit c53754b3e8
23 changed files with 253 additions and 189 deletions
@@ -73,7 +73,7 @@ public class ClassContext {
thisIdx++; thisIdx++;
} }
final boolean hasReceiver = descriptor.getReceiver().exists(); final boolean hasReceiver = descriptor.getReceiverParameter().exists();
if (hasReceiver) { if (hasReceiver) {
thisIdx++; thisIdx++;
} }
@@ -104,7 +104,7 @@ public class ClassContext {
} }
private ReceiverDescriptor receiver() { private ReceiverDescriptor receiver() {
return contextType instanceof FunctionDescriptor ? ((FunctionDescriptor) contextType).getReceiver() : ReceiverDescriptor.NO_RECEIVER; return contextType instanceof FunctionDescriptor ? ((FunctionDescriptor) contextType).getReceiverParameter() : ReceiverDescriptor.NO_RECEIVER;
} }
private boolean hasReceiver() { private boolean hasReceiver() {
@@ -42,7 +42,7 @@ public class ClosureCodegen {
} }
public static Method erasedInvokeSignature(FunctionDescriptor fd) { public static Method erasedInvokeSignature(FunctionDescriptor fd) {
boolean isExtensionFunction = fd.getReceiver().exists(); boolean isExtensionFunction = fd.getReceiverParameter().exists();
int paramCount = fd.getValueParameters().size(); int paramCount = fd.getValueParameters().size();
if (isExtensionFunction) { if (isExtensionFunction) {
paramCount++; paramCount++;
@@ -151,7 +151,7 @@ public class ClosureCodegen {
iv.load(0, Type.getObjectType(className)); iv.load(0, Type.getObjectType(className));
final ReceiverDescriptor receiver = funDescriptor.getReceiver(); final ReceiverDescriptor receiver = funDescriptor.getReceiverParameter();
int count = 1; int count = 1;
if (receiver.exists()) { if (receiver.exists()) {
StackValue.local(count, JetTypeMapper.TYPE_OBJECT).put(JetTypeMapper.TYPE_OBJECT, iv); StackValue.local(count, JetTypeMapper.TYPE_OBJECT).put(JetTypeMapper.TYPE_OBJECT, iv);
@@ -229,7 +229,7 @@ public class ClosureCodegen {
public static String getInternalClassName(FunctionDescriptor descriptor) { public static String getInternalClassName(FunctionDescriptor descriptor) {
final int paramCount = descriptor.getValueParameters().size(); final int paramCount = descriptor.getValueParameters().size();
if (descriptor.getReceiver().exists()) { if (descriptor.getReceiverParameter().exists()) {
return "jet/ExtensionFunction" + paramCount; return "jet/ExtensionFunction" + paramCount;
} }
else { else {
@@ -250,7 +250,7 @@ public class ClosureCodegen {
Method descriptor = erasedInvokeSignature(fd); Method descriptor = erasedInvokeSignature(fd);
String owner = getInternalClassName(fd); String owner = getInternalClassName(fd);
final CallableMethod result = new CallableMethod(owner, descriptor, Opcodes.INVOKEVIRTUAL, Arrays.asList(descriptor.getArgumentTypes())); final CallableMethod result = new CallableMethod(owner, descriptor, Opcodes.INVOKEVIRTUAL, Arrays.asList(descriptor.getArgumentTypes()));
if (fd.getReceiver().exists()) { if (fd.getReceiverParameter().exists()) {
result.setNeedsReceiver(null); result.setNeedsReceiver(null);
} }
result.requestGenerateCallee(Type.getObjectType(getInternalClassName(fd))); result.requestGenerateCallee(Type.getObjectType(getInternalClassName(fd)));
@@ -2,7 +2,6 @@ package org.jetbrains.jet.codegen;
import com.intellij.psi.*; import com.intellij.psi.*;
import com.intellij.psi.util.PsiTreeUtil; import com.intellij.psi.util.PsiTreeUtil;
import jet.Function1;
import jet.JetObject; import jet.JetObject;
import jet.typeinfo.TypeInfo; import jet.typeinfo.TypeInfo;
import jet.typeinfo.TypeInfoProjection; import jet.typeinfo.TypeInfoProjection;
@@ -546,7 +545,7 @@ public class JetTypeMapper {
} }
public Method mapSignature(String name, FunctionDescriptor f) { public Method mapSignature(String name, FunctionDescriptor f) {
final ReceiverDescriptor receiver = f.getReceiver(); final ReceiverDescriptor receiver = f.getReceiverParameter();
final List<ValueParameterDescriptor> parameters = f.getValueParameters(); final List<ValueParameterDescriptor> parameters = f.getValueParameters();
List<Type> parameterTypes = new ArrayList<Type>(); List<Type> parameterTypes = new ArrayList<Type>();
if (receiver.exists()) { if (receiver.exists()) {
@@ -1,7 +1,6 @@
package org.jetbrains.jet.lang.descriptors; package org.jetbrains.jet.lang.descriptors;
import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.NotNull;
import org.jetbrains.jet.lang.resolve.scopes.receivers.ImplicitReceiverDescriptor;
import org.jetbrains.jet.lang.resolve.scopes.receivers.ReceiverDescriptor; import org.jetbrains.jet.lang.resolve.scopes.receivers.ReceiverDescriptor;
import org.jetbrains.jet.lang.types.JetType; import org.jetbrains.jet.lang.types.JetType;
import org.jetbrains.jet.lang.types.TypeSubstitutor; import org.jetbrains.jet.lang.types.TypeSubstitutor;
@@ -14,7 +13,7 @@ import java.util.Set;
*/ */
public interface CallableDescriptor extends DeclarationDescriptor { public interface CallableDescriptor extends DeclarationDescriptor {
@NotNull @NotNull
ReceiverDescriptor getReceiver(); ReceiverDescriptor getReceiverParameter();
@NotNull @NotNull
List<TypeParameterDescriptor> getTypeParameters(); List<TypeParameterDescriptor> getTypeParameters();
@@ -71,7 +71,7 @@ public class FunctionDescriptorImpl extends DeclarationDescriptorImpl implements
@NotNull @NotNull
@Override @Override
public ReceiverDescriptor getReceiver() { public ReceiverDescriptor getReceiverParameter() {
return receiver; return receiver;
} }
@@ -133,7 +133,7 @@ public class FunctionDescriptorImpl extends DeclarationDescriptorImpl implements
JetType substitutedReceiverType = null; JetType substitutedReceiverType = null;
if (receiver.exists()) { if (receiver.exists()) {
substitutedReceiverType = substitutor.substitute(getReceiver().getType(), Variance.IN_VARIANCE); substitutedReceiverType = substitutor.substitute(getReceiverParameter().getType(), Variance.IN_VARIANCE);
if (substitutedReceiverType == null) { if (substitutedReceiverType == null) {
return null; return null;
} }
@@ -181,7 +181,7 @@ public class FunctionDescriptorImpl extends DeclarationDescriptorImpl implements
public FunctionDescriptor copy(DeclarationDescriptor newOwner, boolean makeNonAbstract) { public FunctionDescriptor copy(DeclarationDescriptor newOwner, boolean makeNonAbstract) {
FunctionDescriptorImpl copy = new FunctionDescriptorImpl(newOwner, Lists.newArrayList(getAnnotations()), getName()); FunctionDescriptorImpl copy = new FunctionDescriptorImpl(newOwner, Lists.newArrayList(getAnnotations()), getName());
copy.initialize( copy.initialize(
getReceiver().exists() ? getReceiver().getType() : null, getReceiverParameter().exists() ? getReceiverParameter().getType() : null,
DescriptorUtils.copyTypeParameters(copy, typeParameters), DescriptorUtils.copyTypeParameters(copy, typeParameters),
DescriptorUtils.copyValueParameters(copy, unsubstitutedValueParameters), DescriptorUtils.copyValueParameters(copy, unsubstitutedValueParameters),
unsubstitutedReturnType, unsubstitutedReturnType,
@@ -95,7 +95,7 @@ public class FunctionDescriptorUtil {
@NotNull @NotNull
public static JetScope getFunctionInnerScope(@NotNull JetScope outerScope, @NotNull FunctionDescriptor descriptor, @NotNull BindingTrace trace) { public static JetScope getFunctionInnerScope(@NotNull JetScope outerScope, @NotNull FunctionDescriptor descriptor, @NotNull BindingTrace trace) {
WritableScope parameterScope = new WritableScopeImpl(outerScope, descriptor, new TraceBasedRedeclarationHandler(trace)).setDebugName("Function inner scope"); WritableScope parameterScope = new WritableScopeImpl(outerScope, descriptor, new TraceBasedRedeclarationHandler(trace)).setDebugName("Function inner scope");
ReceiverDescriptor receiver = descriptor.getReceiver(); ReceiverDescriptor receiver = descriptor.getReceiverParameter();
if (receiver.exists()) { if (receiver.exists()) {
parameterScope.setImplicitReceiver(receiver); parameterScope.setImplicitReceiver(receiver);
} }
@@ -95,7 +95,7 @@ public class PropertyDescriptor extends VariableDescriptorImpl implements Callab
} }
@NotNull @NotNull
public ReceiverDescriptor getReceiver() { public ReceiverDescriptor getReceiverParameter() {
return receiver; return receiver;
} }
@@ -35,8 +35,8 @@ public class PropertyGetterDescriptor extends PropertyAccessorDescriptor {
@NotNull @NotNull
@Override @Override
public ReceiverDescriptor getReceiver() { public ReceiverDescriptor getReceiverParameter() {
return getCorrespondingProperty().getReceiver(); return getCorrespondingProperty().getReceiverParameter();
} }
@NotNull @NotNull
@@ -44,8 +44,8 @@ public class PropertySetterDescriptor extends PropertyAccessorDescriptor {
@NotNull @NotNull
@Override @Override
public ReceiverDescriptor getReceiver() { public ReceiverDescriptor getReceiverParameter() {
return getCorrespondingProperty().getReceiver(); return getCorrespondingProperty().getReceiverParameter();
} }
@NotNull @NotNull
@@ -74,7 +74,7 @@ public abstract class VariableDescriptorImpl extends DeclarationDescriptorImpl i
@NotNull @NotNull
@Override @Override
public ReceiverDescriptor getReceiver() { public ReceiverDescriptor getReceiverParameter() {
return ReceiverDescriptor.NO_RECEIVER; return ReceiverDescriptor.NO_RECEIVER;
} }
@@ -459,7 +459,7 @@ public class BodyResolver {
for (TypeParameterDescriptor typeParameterDescriptor : propertyDescriptor.getTypeParameters()) { for (TypeParameterDescriptor typeParameterDescriptor : propertyDescriptor.getTypeParameters()) {
result.addTypeParameterDescriptor(typeParameterDescriptor); result.addTypeParameterDescriptor(typeParameterDescriptor);
} }
ReceiverDescriptor receiver = propertyDescriptor.getReceiver(); ReceiverDescriptor receiver = propertyDescriptor.getReceiverParameter();
if (receiver.exists()) { if (receiver.exists()) {
result.setImplicitReceiver(receiver); result.setImplicitReceiver(receiver);
} }
@@ -4,11 +4,14 @@ import com.google.common.collect.Lists;
import com.google.common.collect.Maps; import com.google.common.collect.Maps;
import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.NotNull;
import org.jetbrains.jet.lang.descriptors.*; import org.jetbrains.jet.lang.descriptors.*;
import org.jetbrains.jet.lang.resolve.scopes.receivers.ReceiverDescriptor;
import org.jetbrains.jet.lang.types.*; import org.jetbrains.jet.lang.types.*;
import java.util.List; import java.util.List;
import java.util.Map; import java.util.Map;
import static org.jetbrains.jet.lang.resolve.scopes.receivers.ReceiverDescriptor.NO_RECEIVER;
/** /**
* @author abreslav * @author abreslav
*/ */
@@ -22,7 +25,7 @@ public class DescriptorUtils {
@Override @Override
public Boolean visitFunctionDescriptor(FunctionDescriptor descriptor, Void data) { public Boolean visitFunctionDescriptor(FunctionDescriptor descriptor, Void data) {
return descriptor.getReceiver().exists(); return descriptor.getReceiverParameter().exists();
} }
@Override @Override
@@ -32,7 +35,7 @@ public class DescriptorUtils {
@Override @Override
public Boolean visitPropertyDescriptor(PropertyDescriptor descriptor, Void data) { public Boolean visitPropertyDescriptor(PropertyDescriptor descriptor, Void data) {
return descriptor.getReceiver().exists(); return descriptor.getReceiverParameter().exists();
} }
}, null); }, null);
} }
@@ -111,4 +114,19 @@ public class DescriptorUtils {
if (makeNonAbstract && modality == Modality.ABSTRACT) return Modality.OPEN; if (makeNonAbstract && modality == Modality.ABSTRACT) return Modality.OPEN;
return modality; return modality;
} }
@NotNull
public static ReceiverDescriptor getExpectedThisObject(@NotNull DeclarationDescriptor descriptor) {
if (descriptor instanceof ConstructorDescriptor) {
ConstructorDescriptor constructorDescriptor = (ConstructorDescriptor) descriptor;
ClassDescriptor classDescriptor = constructorDescriptor.getContainingDeclaration();
return getExpectedThisObject(classDescriptor);
}
DeclarationDescriptor containingDeclaration = descriptor.getContainingDeclaration();
if (containingDeclaration instanceof ClassDescriptor) {
ClassDescriptor classDescriptor = (ClassDescriptor) containingDeclaration;
return classDescriptor.getImplicitReceiver();
}
return NO_RECEIVER;
}
} }
@@ -15,6 +15,7 @@ import org.jetbrains.jet.lang.resolve.scopes.receivers.ExpressionReceiver;
import org.jetbrains.jet.lang.resolve.scopes.receivers.ReceiverDescriptor; import org.jetbrains.jet.lang.resolve.scopes.receivers.ReceiverDescriptor;
import org.jetbrains.jet.lang.types.*; import org.jetbrains.jet.lang.types.*;
import org.jetbrains.jet.lang.types.inference.ConstraintSystem; import org.jetbrains.jet.lang.types.inference.ConstraintSystem;
import org.jetbrains.jet.lexer.JetTokens;
import java.util.*; import java.util.*;
@@ -22,6 +23,7 @@ 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.calls.ResolvedCall.MAP_TO_CANDIDATE; import static org.jetbrains.jet.lang.resolve.calls.ResolvedCall.MAP_TO_CANDIDATE;
import static org.jetbrains.jet.lang.resolve.calls.ResolvedCall.MAP_TO_RESULT; import static org.jetbrains.jet.lang.resolve.calls.ResolvedCall.MAP_TO_RESULT;
import static org.jetbrains.jet.lang.resolve.scopes.receivers.ReceiverDescriptor.NO_RECEIVER;
import static org.jetbrains.jet.lang.types.JetTypeInferrer.NO_EXPECTED_TYPE; import static org.jetbrains.jet.lang.types.JetTypeInferrer.NO_EXPECTED_TYPE;
/** /**
@@ -142,7 +144,7 @@ public class CallResolver {
trace.report(NO_CONSTRUCTOR.on(reportAbsenceOn)); trace.report(NO_CONSTRUCTOR.on(reportAbsenceOn));
return checkArgumentTypesAndFail(trace, scope, call); return checkArgumentTypesAndFail(trace, scope, call);
} }
prioritizedTasks.add(new ResolutionTask<FunctionDescriptor>(ResolvedCall.convertCollection(constructors), call, DataFlowInfo.getEmpty())); prioritizedTasks.add(new ResolutionTask<FunctionDescriptor>(TaskPrioritizer.convertWithImpliedThis(scope, Collections.<ReceiverDescriptor>singletonList(NO_RECEIVER), constructors), call, DataFlowInfo.getEmpty()));
} }
else { else {
// trace.getErrorHandler().genericError(calleeExpression.getNode(), "Not a class"); // trace.getErrorHandler().genericError(calleeExpression.getNode(), "Not a class");
@@ -173,7 +175,7 @@ public class CallResolver {
} }
private FunctionDescriptor checkArgumentTypesAndFail(BindingTrace trace, JetScope scope, Call call) { private FunctionDescriptor checkArgumentTypesAndFail(BindingTrace trace, JetScope scope, Call call) {
checkTypesWithNoCallee(trace, scope, call.getTypeArguments(), call.getValueArguments(), call.getFunctionLiteralArguments()); checkTypesWithNoCallee(trace, scope, call);
return null; return null;
} }
@@ -235,6 +237,17 @@ public class CallResolver {
trace.report(MISSING_RECEIVER.on(reference, expectedReceiver.getType())); trace.report(MISSING_RECEIVER.on(reference, expectedReceiver.getType()));
} }
@Override
public void wrongReceiverType(@NotNull BindingTrace trace, @NotNull ReceiverDescriptor receiverParameter, @NotNull ReceiverDescriptor receiverArgument) {
if (receiverArgument instanceof ExpressionReceiver) {
ExpressionReceiver expressionReceiver = (ExpressionReceiver) receiverArgument;
trace.report(TYPE_MISMATCH.on(expressionReceiver.getExpression(), receiverParameter.getType(), receiverArgument.getType()));
}
else {
trace.report(TYPE_MISMATCH.on(reference, receiverParameter.getType(), receiverArgument.getType()));
}
}
@Override @Override
public void noReceiverAllowed(@NotNull BindingTrace trace) { public void noReceiverAllowed(@NotNull BindingTrace trace) {
trace.report(NO_RECEIVER_ADMITTED.on(reference)); trace.report(NO_RECEIVER_ADMITTED.on(reference));
@@ -273,6 +286,23 @@ public class CallResolver {
trace.report(TYPE_INFERENCE_FAILED.on(callNode)); trace.report(TYPE_INFERENCE_FAILED.on(callNode));
} }
@Override
public void unsafeCall(@NotNull BindingTrace trace, @NotNull JetType type) {
ASTNode callOperationNode = call.getCallOperationNode();
if (callOperationNode != null) {
trace.report(UNSAFE_CALL.on(callOperationNode, type));
}
else {
trace.report(UNSAFE_CALL.on(reference, type));
}
}
@Override
public void unnecessarySafeCall(@NotNull BindingTrace trace, @NotNull JetType type) {
ASTNode callOperationNode = call.getCallOperationNode();
assert callOperationNode != null;
trace.report(UNNECESSARY_SAFE_CALL.on(reference, callOperationNode, type));
}
}; };
for (ResolutionTask<D> task : prioritizedTasks) { for (ResolutionTask<D> task : prioritizedTasks) {
TemporaryBindingTrace temporaryTrace = TemporaryBindingTrace.create(trace); TemporaryBindingTrace temporaryTrace = TemporaryBindingTrace.create(trace);
@@ -294,7 +324,7 @@ public class CallResolver {
} }
else { else {
trace.report(UNRESOLVED_REFERENCE.on(reference)); trace.report(UNRESOLVED_REFERENCE.on(reference));
checkTypesWithNoCallee(trace, scope, call.getTypeArguments(), call.getValueArguments(), call.getFunctionLiteralArguments()); checkTypesWithNoCallee(trace, scope, call);
} }
return null; return null;
} }
@@ -315,21 +345,19 @@ public class CallResolver {
if (ErrorUtils.isError(candidate)) { if (ErrorUtils.isError(candidate)) {
successfulCandidates.add(candidateCall.setResultingDescriptor(candidate)); successfulCandidates.add(candidateCall.setResultingDescriptor(candidate));
checkTypesWithNoCallee(temporaryTrace, scope, task.getTypeArguments(), task.getValueArguments(), task.getFunctionLiteralArguments()); checkTypesWithNoCallee(temporaryTrace, scope, task.getCall());
continue; continue;
} }
boolean errorInArgumentMapping = ValueArgumentsToParametersMapper.mapValueArgumentsToParameters(task, tracing, candidateCall);
// Map<ValueArgument, ValueParameterDescriptor> argumentsToParameters = Maps.newHashMap(); if (errorInArgumentMapping) {
boolean error = ValueArgumentsToParametersMapper.mapValueArgumentsToParameters(task, tracing, candidateCall);
if (error) {
failedCandidates.add(candidateCall); failedCandidates.add(candidateCall);
checkTypesWithNoCallee(temporaryTrace, scope, task.getTypeArguments(), task.getValueArguments(), task.getFunctionLiteralArguments()); checkTypesWithNoCallee(temporaryTrace, scope, task.getCall());
continue; continue;
} }
if (task.getTypeArguments().isEmpty()) { List<JetTypeProjection> jetTypeArguments = task.getCall().getTypeArguments();
if (jetTypeArguments.isEmpty()) {
if (!candidate.getTypeParameters().isEmpty()) { if (!candidate.getTypeParameters().isEmpty()) {
// Type argument inference // Type argument inference
@@ -356,10 +384,11 @@ public class CallResolver {
} }
} }
checkReceiverAbsence(candidateCall, tracing, candidate); // 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.getReceiverArgument();
ReceiverDescriptor candidateReceiver = candidate.getReceiver(); ReceiverDescriptor candidateReceiver = candidate.getReceiverParameter();
if (receiverParameter.exists() && candidateReceiver.exists()) { if (receiverParameter.exists() && candidateReceiver.exists()) {
constraintSystem.addSubtypingConstraint(receiverParameter.getType(), candidateReceiver.getType()); constraintSystem.addSubtypingConstraint(receiverParameter.getType(), candidateReceiver.getType());
} }
@@ -382,8 +411,7 @@ public class CallResolver {
} }
} }
else { else {
if (checkValueArgumentTypes(scope, candidateCall) if (checkAllValueArguments(scope, tracing, task, candidateCall, candidate)) {
&& checkReceiver(candidateCall, tracing, candidate)) {
successfulCandidates.add(candidateCall.setResultingDescriptor(candidate)); successfulCandidates.add(candidateCall.setResultingDescriptor(candidate));
} }
else { else {
@@ -394,8 +422,6 @@ public class CallResolver {
else { else {
// Explicit type arguments passed // Explicit type arguments passed
final List<JetTypeProjection> jetTypeArguments = task.getTypeArguments();
for (JetTypeProjection typeArgument : jetTypeArguments) { for (JetTypeProjection typeArgument : jetTypeArguments) {
if (typeArgument.getProjectionKind() != JetProjectionKind.NONE) { if (typeArgument.getProjectionKind() != JetProjectionKind.NONE) {
// temporaryTrace.getErrorHandler().genericError(typeArgument.getNode(), "Projections are not allowed on type parameters for methods"); // TODO : better positioning // temporaryTrace.getErrorHandler().genericError(typeArgument.getNode(), "Projections are not allowed on type parameters for methods"); // TODO : better positioning
@@ -415,14 +441,14 @@ 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 substitutedDescriptor = (D) candidate.substitute(TypeSubstitutor.create(substitutionContext)); D substitutedDescriptor = (D) candidate.substitute(TypeSubstitutor.create(substitutionContext));
candidateCall.setResultingDescriptor(substitutedDescriptor);
replaceValueParametersWithSubstitutedOnes(candidateCall, substitutedDescriptor); replaceValueParametersWithSubstitutedOnes(candidateCall, substitutedDescriptor);
if (checkValueArgumentTypes(scope, candidateCall) if (checkAllValueArguments(scope, tracing, task, candidateCall, substitutedDescriptor)) {
&& checkReceiver(candidateCall, tracing, substitutedDescriptor)) { successfulCandidates.add(candidateCall);
successfulCandidates.add(candidateCall.setResultingDescriptor(substitutedDescriptor));
} }
else { else {
failedCandidates.add(candidateCall); failedCandidates.add(candidateCall);
@@ -437,13 +463,13 @@ public class CallResolver {
task.performAdvancedChecks(candidate, temporaryTrace, tracing); task.performAdvancedChecks(candidate, temporaryTrace, tracing);
recordAutoCastIfNecessary(candidateCall.getReceiverParameter(), candidateCall.getTrace()); recordAutoCastIfNecessary(candidateCall.getReceiverArgument(), candidateCall.getTrace());
recordAutoCastIfNecessary(candidateCall.getThisObject(), candidateCall.getTrace()); recordAutoCastIfNecessary(candidateCall.getThisObject(), candidateCall.getTrace());
} }
OverloadResolutionResults<D> results = computeResultAndReportErrors(trace, tracing, successfulCandidates, failedCandidates); 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.getCall());
} }
return results; return results;
} }
@@ -467,19 +493,19 @@ public class CallResolver {
} }
} }
private void checkTypesWithNoCallee(BindingTrace trace, JetScope scope, List<JetTypeProjection> typeArguments, List<? extends ValueArgument> valueArguments, List<JetExpression> functionLiteralArguments) { private void checkTypesWithNoCallee(BindingTrace trace, JetScope scope, Call call) {
for (ValueArgument valueArgument : valueArguments) { for (ValueArgument valueArgument : call.getValueArguments()) {
JetExpression argumentExpression = valueArgument.getArgumentExpression(); JetExpression argumentExpression = valueArgument.getArgumentExpression();
if (argumentExpression != null) { if (argumentExpression != null) {
typeInferrer.getServices(trace).getType(scope, argumentExpression, NO_EXPECTED_TYPE); typeInferrer.getServices(trace).getType(scope, argumentExpression, NO_EXPECTED_TYPE);
} }
} }
for (JetExpression expression : functionLiteralArguments) { for (JetExpression expression : call.getFunctionLiteralArguments()) {
typeInferrer.getServices(trace).getType(scope, expression, NO_EXPECTED_TYPE); typeInferrer.getServices(trace).getType(scope, expression, NO_EXPECTED_TYPE);
} }
for (JetTypeProjection typeProjection : typeArguments) { for (JetTypeProjection typeProjection : call.getTypeArguments()) {
new TypeResolver(semanticServices, trace, true).resolveType(scope, typeProjection.getTypeReference()); new TypeResolver(semanticServices, trace, true).resolveType(scope, typeProjection.getTypeReference());
} }
} }
@@ -515,9 +541,33 @@ public class CallResolver {
} }
} }
private <D extends CallableDescriptor> boolean checkValueArgumentTypes( private <D extends CallableDescriptor> boolean checkAllValueArguments(JetScope scope, TracingStrategy tracing, ResolutionTask<D> task, ResolvedCall<D> candidateCall, D substitutedDescriptor) {
JetScope scope, boolean result = checkValueArgumentTypes(scope, candidateCall);
ResolvedCall<D> candidateCall) { // result &= checkReceiver(task, candidateCall, tracing, substitutedDescriptor);
ReceiverDescriptor receiverArgument = candidateCall.getReceiverArgument();
ReceiverDescriptor receiverParameter = candidateCall.getResultingDescriptor().getReceiverParameter();
boolean safeAccess = task.getCall().getCallOperationNode() == JetTokens.SAFE_ACCESS;
if (receiverParameter.exists() && receiverArgument.exists()) {
JetType receiverArgumentType = receiverArgument.getType();
if (!safeAccess && !receiverParameter.getType().isNullable() && receiverArgumentType.isNullable()) {
tracing.unsafeCall(candidateCall.getTrace(), receiverArgumentType);
result = false;
}
else if (!semanticServices.getTypeChecker().isSubtypeOf(receiverArgument.getType(), receiverParameter.getType())) {
tracing.wrongReceiverType(candidateCall.getTrace(), receiverParameter, receiverArgument);
return false;
}
if (safeAccess && (receiverParameter.getType().isNullable() || !receiverArgumentType.isNullable())) {
tracing.unnecessarySafeCall(candidateCall.getTrace(), receiverArgumentType);
}
}
return result;
}
private <D extends CallableDescriptor> boolean checkValueArgumentTypes(JetScope scope, ResolvedCall<D> candidateCall) {
boolean result = true; boolean result = true;
for (Map.Entry<ValueParameterDescriptor, ResolvedValueArgument> entry : candidateCall.getValueArguments().entrySet()) { for (Map.Entry<ValueParameterDescriptor, ResolvedValueArgument> entry : candidateCall.getValueArguments().entrySet()) {
ValueParameterDescriptor parameterDescriptor = entry.getKey(); ValueParameterDescriptor parameterDescriptor = entry.getKey();
@@ -557,59 +607,40 @@ public class CallResolver {
} }
} }
} }
// 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; return result;
} }
private <D extends CallableDescriptor> boolean checkReceiver(ResolvedCall<D> resolvedCall, TracingStrategy tracing, D candidate) { // private <D extends CallableDescriptor> boolean checkReceiver(ResolutionTask<D> task, ResolvedCall<D> resolvedCall, TracingStrategy tracing, D candidate) {
if (!checkReceiverAbsence(resolvedCall, tracing, candidate)) return false; // if (!checkReceiverAbsence(resolvedCall, tracing, candidate)) return false;
ReceiverDescriptor receiver = resolvedCall.getReceiverParameter(); // ReceiverDescriptor actualReceiver = resolvedCall.getReceiverArgument();
ReceiverDescriptor candidateReceiver = candidate.getReceiver(); // ReceiverDescriptor expectedReceiver = candidate.getReceiverParameter();
if (receiver.exists() //
&& candidateReceiver.exists() // if (actualReceiver.exists()
&& !semanticServices.getTypeChecker().isSubtypeOf(receiver.getType(), candidateReceiver.getType())) { // && expectedReceiver.exists()) {
tracing.missingReceiver(resolvedCall.getTrace(), candidateReceiver); // if (!semanticServices.getTypeChecker().isSubtypeOf(actualReceiver.getType(), expectedReceiver.getType())) {
return false; // tracing.missingReceiver(resolvedCall.getTrace(), expectedReceiver);
} // return false;
return true; // }
} // }
// return true;
private <D extends CallableDescriptor> boolean checkReceiverAbsence(ResolvedCall<D> resolvedCall, TracingStrategy tracing, D candidate) { // }
ReceiverDescriptor receiver = resolvedCall.getReceiverParameter(); //
ReceiverDescriptor candidateReceiver = candidate.getReceiver(); // private <D extends CallableDescriptor> boolean checkReceiverAbsence(ResolvedCall<D> resolvedCall, TracingStrategy tracing, D candidate) {
if (receiver.exists()) { // ReceiverDescriptor receiver = resolvedCall.getReceiverArgument();
if (!candidateReceiver.exists()) { // ReceiverDescriptor candidateReceiver = candidate.getReceiverParameter();
tracing.noReceiverAllowed(resolvedCall.getTrace()); // if (receiver.exists()) {
return false; // if (!candidateReceiver.exists()) {
} // tracing.noReceiverAllowed(resolvedCall.getTrace());
} // return false;
else if (candidateReceiver.exists()) { // }
tracing.missingReceiver(resolvedCall.getTrace(), candidateReceiver); // }
return false; // else if (candidateReceiver.exists()) {
} // tracing.missingReceiver(resolvedCall.getTrace(), candidateReceiver);
return true; // return false;
} // }
// return true;
// }
//
@NotNull @NotNull
private <D extends CallableDescriptor> OverloadResolutionResults<D> computeResultAndReportErrors( private <D extends CallableDescriptor> OverloadResolutionResults<D> computeResultAndReportErrors(
BindingTrace trace, BindingTrace trace,
@@ -747,7 +778,7 @@ public class CallResolver {
boolean found = false; boolean found = false;
for (ResolvedCall<FunctionDescriptor> resolvedCall : candidates) { for (ResolvedCall<FunctionDescriptor> resolvedCall : candidates) {
FunctionDescriptor functionDescriptor = resolvedCall.getResultingDescriptor(); FunctionDescriptor functionDescriptor = resolvedCall.getResultingDescriptor();
if (functionDescriptor.getReceiver().exists()) continue; if (functionDescriptor.getReceiverParameter().exists()) continue;
if (!functionDescriptor.getTypeParameters().isEmpty()) continue; if (!functionDescriptor.getTypeParameters().isEmpty()) continue;
if (!checkValueParameters(functionDescriptor, parameterTypes)) continue; if (!checkValueParameters(functionDescriptor, parameterTypes)) continue;
result.add(resolvedCall); result.add(resolvedCall);
@@ -760,7 +791,7 @@ public class CallResolver {
boolean found = false; boolean found = false;
for (ResolvedCall<FunctionDescriptor> resolvedCall : candidates) { for (ResolvedCall<FunctionDescriptor> resolvedCall : candidates) {
FunctionDescriptor functionDescriptor = resolvedCall.getResultingDescriptor(); FunctionDescriptor functionDescriptor = resolvedCall.getResultingDescriptor();
ReceiverDescriptor functionReceiver = functionDescriptor.getReceiver(); ReceiverDescriptor functionReceiver = functionDescriptor.getReceiverParameter();
if (!functionReceiver.exists()) continue; if (!functionReceiver.exists()) continue;
if (!functionDescriptor.getTypeParameters().isEmpty()) continue; if (!functionDescriptor.getTypeParameters().isEmpty()) continue;
if (!semanticServices.getTypeChecker().isSubtypeOf(receiver.getType(), functionReceiver.getType())) continue; if (!semanticServices.getTypeChecker().isSubtypeOf(receiver.getType(), functionReceiver.getType())) continue;
@@ -72,9 +72,9 @@ public class OverloadingConflictResolver {
if (OverridingUtil.overrides(f, g)) return true; if (OverridingUtil.overrides(f, g)) return true;
if (OverridingUtil.overrides(g, f)) return false; if (OverridingUtil.overrides(g, f)) return false;
ReceiverDescriptor receiverOfF = f.getReceiver(); ReceiverDescriptor receiverOfF = f.getReceiverParameter();
ReceiverDescriptor receiverOfG = g.getReceiver(); ReceiverDescriptor receiverOfG = g.getReceiverParameter();
if (f.getReceiver().exists() && g.getReceiver().exists()) { if (f.getReceiverParameter().exists() && g.getReceiverParameter().exists()) {
if (!typeMoreSpecific(receiverOfF.getType(), receiverOfG.getType())) return false; if (!typeMoreSpecific(receiverOfF.getType(), receiverOfG.getType())) return false;
} }
@@ -3,45 +3,29 @@ package org.jetbrains.jet.lang.resolve.calls;
import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.NotNull;
import org.jetbrains.jet.lang.descriptors.CallableDescriptor; import org.jetbrains.jet.lang.descriptors.CallableDescriptor;
import org.jetbrains.jet.lang.psi.Call; import org.jetbrains.jet.lang.psi.Call;
import org.jetbrains.jet.lang.psi.JetExpression;
import org.jetbrains.jet.lang.psi.JetTypeProjection;
import org.jetbrains.jet.lang.psi.ValueArgument;
import org.jetbrains.jet.lang.resolve.BindingTrace; import org.jetbrains.jet.lang.resolve.BindingTrace;
import org.jetbrains.jet.lang.types.DataFlowInfo; import org.jetbrains.jet.lang.types.DataFlowInfo;
import java.util.Collection; import java.util.Collection;
import java.util.List;
/** /**
* @author abreslav * @author abreslav
*/ */
/*package*/ class ResolutionTask<D extends CallableDescriptor> { /*package*/ class ResolutionTask<D extends CallableDescriptor> {
private final Call call;
private final Collection<ResolvedCall<D>> candidates; private final Collection<ResolvedCall<D>> candidates;
private final List<JetTypeProjection> typeArguments;
private final List<? extends ValueArgument> valueArguments;
private final List<JetExpression> functionLiteralArguments;
private final DataFlowInfo dataFlowInfo; private final DataFlowInfo dataFlowInfo;
private DescriptorCheckStrategy checkingStrategy; private DescriptorCheckStrategy checkingStrategy;
public ResolutionTask(
@NotNull Collection<ResolvedCall<D>> candidates,
@NotNull List<JetTypeProjection> typeArguments,
@NotNull List<? extends ValueArgument> valueArguments,
@NotNull List<JetExpression> functionLiteralArguments,
@NotNull DataFlowInfo dataFlowInfo) {
this.candidates = candidates;
this.typeArguments = typeArguments;
this.valueArguments = valueArguments;
this.functionLiteralArguments = functionLiteralArguments;
this.dataFlowInfo = dataFlowInfo;
}
public ResolutionTask( public ResolutionTask(
@NotNull Collection<ResolvedCall<D>> candidates, @NotNull Collection<ResolvedCall<D>> candidates,
@NotNull Call call, @NotNull Call call,
@NotNull DataFlowInfo dataFlowInfo @NotNull DataFlowInfo dataFlowInfo
) { ) {
this(candidates, call.getTypeArguments(), call.getValueArguments(), call.getFunctionLiteralArguments(), dataFlowInfo); this.candidates = candidates;
this.call = call;
this.dataFlowInfo = dataFlowInfo;
} }
@NotNull @NotNull
@@ -55,20 +39,10 @@ import java.util.List;
} }
@NotNull @NotNull
public List<JetTypeProjection> getTypeArguments() { public Call getCall() {
return typeArguments; return call;
} }
@NotNull
public List<? extends ValueArgument> getValueArguments() {
return valueArguments;
}
@NotNull
public List<JetExpression> getFunctionLiteralArguments() {
return functionLiteralArguments;
}
public void setCheckingStrategy(DescriptorCheckStrategy strategy) { public void setCheckingStrategy(DescriptorCheckStrategy strategy) {
checkingStrategy = strategy; checkingStrategy = strategy;
} }
@@ -4,9 +4,8 @@ import com.google.common.collect.Lists;
import com.google.common.collect.Maps; import com.google.common.collect.Maps;
import com.intellij.util.Function; import com.intellij.util.Function;
import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.NotNull;
import org.jetbrains.jet.lang.descriptors.CallableDescriptor; import org.jetbrains.jet.lang.descriptors.*;
import org.jetbrains.jet.lang.descriptors.TypeParameterDescriptor; import org.jetbrains.jet.lang.resolve.DescriptorUtils;
import org.jetbrains.jet.lang.descriptors.ValueParameterDescriptor;
import org.jetbrains.jet.lang.resolve.TemporaryBindingTrace; import org.jetbrains.jet.lang.resolve.TemporaryBindingTrace;
import org.jetbrains.jet.lang.resolve.scopes.receivers.ReceiverDescriptor; import org.jetbrains.jet.lang.resolve.scopes.receivers.ReceiverDescriptor;
import org.jetbrains.jet.lang.types.JetType; import org.jetbrains.jet.lang.types.JetType;
@@ -53,7 +52,7 @@ public class ResolvedCall<D extends CallableDescriptor> {
private final D candidateDescriptor; private final D candidateDescriptor;
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 receiverArgument = NO_RECEIVER; // receiver of an extension function
private final Map<TypeParameterDescriptor, JetType> typeArguments = Maps.newLinkedHashMap(); 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();
@@ -104,12 +103,12 @@ public class ResolvedCall<D extends CallableDescriptor> {
} }
@NotNull @NotNull
public ReceiverDescriptor getReceiverParameter() { public ReceiverDescriptor getReceiverArgument() {
return receiverParameter; return receiverArgument;
} }
public void setReceiverParameter(@NotNull ReceiverDescriptor receiverParameter) { public void setReceiverArgument(@NotNull ReceiverDescriptor receiverParameter) {
this.receiverParameter = receiverParameter; this.receiverArgument = receiverParameter;
} }
@NotNull @NotNull
@@ -133,4 +132,9 @@ public class ResolvedCall<D extends CallableDescriptor> {
public boolean isDirty() { public boolean isDirty() {
return someArgumentHasNoType; return someArgumentHasNoType;
} }
@NotNull
public ReceiverDescriptor getExpectedThisObject() {
return DescriptorUtils.getExpectedThisObject(getResultingDescriptor());
}
} }
@@ -5,10 +5,13 @@ import org.jetbrains.annotations.NotNull;
import org.jetbrains.jet.lang.descriptors.*; import org.jetbrains.jet.lang.descriptors.*;
import org.jetbrains.jet.lang.psi.Call; import org.jetbrains.jet.lang.psi.Call;
import org.jetbrains.jet.lang.resolve.BindingContext; import org.jetbrains.jet.lang.resolve.BindingContext;
import org.jetbrains.jet.lang.resolve.DescriptorUtils;
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.DataFlowInfo;
import org.jetbrains.jet.lang.types.JetType; import org.jetbrains.jet.lang.types.JetType;
import org.jetbrains.jet.lang.types.JetTypeChecker;
import org.jetbrains.jet.lang.types.NamespaceType;
import java.util.Collection; import java.util.Collection;
import java.util.Collections; import java.util.Collections;
@@ -65,16 +68,14 @@ import static org.jetbrains.jet.lang.resolve.scopes.receivers.ReceiverDescriptor
return false; return false;
} }
// public List<ResolutionTask<D>> computePrioritizedTasks(@NotNull JetScope scope, @NotNull ReceiverDescriptor receiver, @NotNull Call call, @NotNull String name) {
// List<ResolutionTask<D>> result = Lists.newArrayList();
// doComputeTasks(scope, receiver, call, name, result);
// return result;
// }
public List<ResolutionTask<D>> computePrioritizedTasks(@NotNull JetScope scope, @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();
ReceiverDescriptor explicitReceiver = call.getExplicitReceiver(); ReceiverDescriptor explicitReceiver = call.getExplicitReceiver();
if (explicitReceiver.exists() && explicitReceiver.getType() instanceof NamespaceType) {
scope = explicitReceiver.getType().getMemberScope();
explicitReceiver = NO_RECEIVER;
}
doComputeTasks(scope, explicitReceiver, call, name, result, NO_AUTO_CASTS); doComputeTasks(scope, explicitReceiver, call, name, result, NO_AUTO_CASTS);
ReceiverDescriptor receiverToCast = explicitReceiver.exists() ? explicitReceiver : scope.getImplicitReceiver(); ReceiverDescriptor receiverToCast = explicitReceiver.exists() ? explicitReceiver : scope.getImplicitReceiver();
@@ -121,15 +122,15 @@ import static org.jetbrains.jet.lang.resolve.scopes.receivers.ReceiverDescriptor
} }
}; };
private void doComputeTasks(JetScope scope, ReceiverDescriptor explicitReceiver, Call call, String name, List<ResolutionTask<D>> result, @NotNull AutoCastService autoCastService) { private void doComputeTasks(JetScope scope, ReceiverDescriptor receiver, Call call, String name, List<ResolutionTask<D>> result, @NotNull AutoCastService autoCastService) {
DataFlowInfo dataFlowInfo = autoCastService.getDataFlowInfo(); 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) // AutoCastUtils.getAutoCastVariants(bindingContext, dataFlowInfo, receiverToCast)
if (explicitReceiver.exists()) { if (receiver.exists()) {
List<ReceiverDescriptor> variantsForExplicitReceiver = autoCastService.getVariantsForReceiver(explicitReceiver); List<ReceiverDescriptor> variantsForExplicitReceiver = autoCastService.getVariantsForReceiver(receiver);
Collection<ResolvedCall<D>> extensionFunctions = convertWithImpliedThis(variantsForExplicitReceiver, getExtensionsByName(scope, name)); Collection<ResolvedCall<D>> extensionFunctions = convertWithImpliedThis(scope, 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
@@ -153,7 +154,7 @@ import static org.jetbrains.jet.lang.resolve.scopes.receivers.ReceiverDescriptor
addTask(result, call, nonlocals, dataFlowInfo); addTask(result, call, nonlocals, dataFlowInfo);
} }
else { else {
Collection<ResolvedCall<D>> functions = convertWithImpliedThis(Collections.singletonList(explicitReceiver), getNonExtensionsByName(scope, name)); Collection<ResolvedCall<D>> functions = convertWithImpliedThis(scope, Collections.singletonList(receiver), 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();
@@ -183,7 +184,7 @@ import static org.jetbrains.jet.lang.resolve.scopes.receivers.ReceiverDescriptor
for (D extension : descriptors) { for (D extension : descriptors) {
ResolvedCall<D> resolvedCall = ResolvedCall.create(extension); ResolvedCall<D> resolvedCall = ResolvedCall.create(extension);
resolvedCall.setThisObject(thisObject); resolvedCall.setThisObject(thisObject);
resolvedCall.setReceiverParameter(receiverParameter); resolvedCall.setReceiverArgument(receiverParameter);
result.add(resolvedCall); result.add(resolvedCall);
} }
} }
@@ -191,33 +192,36 @@ import static org.jetbrains.jet.lang.resolve.scopes.receivers.ReceiverDescriptor
// return result; // return result;
} }
private Collection<ResolvedCall<D>> convertWithImpliedThis(Iterable<ReceiverDescriptor> receiverParameters, Collection<D> descriptors) { public static <D extends CallableDescriptor> Collection<ResolvedCall<D>> convertWithImpliedThis(JetScope scope, Iterable<ReceiverDescriptor> receiverParameters, Collection<D> descriptors) {
Collection<ResolvedCall<D>> result = Lists.newArrayList(); Collection<ResolvedCall<D>> result = Lists.newArrayList();
for (ReceiverDescriptor receiverParameter : receiverParameters) { for (ReceiverDescriptor receiverParameter : receiverParameters) {
for (D extension : descriptors) { for (D extension : descriptors) {
ResolvedCall<D> resolvedCall = ResolvedCall.create(extension); ResolvedCall<D> resolvedCall = ResolvedCall.create(extension);
resolvedCall.setReceiverParameter(receiverParameter); resolvedCall.setReceiverArgument(receiverParameter);
setImpliedThis(resolvedCall); if (setImpliedThis(scope, resolvedCall)) {
result.add(resolvedCall); result.add(resolvedCall);
}
} }
} }
return result; return result;
} }
private void setImpliedThis(ResolvedCall<D> resolvedCall) { private static <D extends CallableDescriptor> boolean setImpliedThis(@NotNull JetScope scope, ResolvedCall<D> resolvedCall) {
ReceiverDescriptor thisObject; ReceiverDescriptor expectedThisObject = DescriptorUtils.getExpectedThisObject(resolvedCall.getCandidateDescriptor());
DeclarationDescriptor containingDeclaration = resolvedCall.getCandidateDescriptor().getContainingDeclaration(); if (!expectedThisObject.exists()) return true;
if (containingDeclaration instanceof ClassDescriptor) { List<ReceiverDescriptor> receivers = Lists.newArrayList();
ClassDescriptor classDescriptor = (ClassDescriptor) containingDeclaration; scope.getImplicitReceiversHierarchy(receivers);
thisObject = classDescriptor.getImplicitReceiver(); for (ReceiverDescriptor receiver : receivers) {
if (JetTypeChecker.INSTANCE.isSubtypeOf(receiver.getType(), expectedThisObject.getType())) {
// TODO : Autocasts & nullability
resolvedCall.setThisObject(expectedThisObject);
return true;
}
} }
else { return false;
thisObject = NO_RECEIVER;
}
resolvedCall.setThisObject(thisObject);
} }
private void addTask(@NotNull List<ResolutionTask<D>> result, @NotNull Call call, @NotNull Collection<ResolvedCall<D>> candidates, @NotNull DataFlowInfo dataFlowInfo) { private void addTask(@NotNull List<ResolutionTask<D>> result, @NotNull Call call, @NotNull Collection<ResolvedCall<D>> candidates, @NotNull DataFlowInfo dataFlowInfo) {
if (candidates.isEmpty()) return; if (candidates.isEmpty()) return;
result.add(new ResolutionTask<D>(candidates, call, dataFlowInfo)); result.add(new ResolutionTask<D>(candidates, call, dataFlowInfo));
} }
@@ -27,7 +27,7 @@ public class TaskPrioritizers {
Set<FunctionDescriptor> functions = Sets.newLinkedHashSet(scope.getFunctions(name)); Set<FunctionDescriptor> functions = Sets.newLinkedHashSet(scope.getFunctions(name));
for (Iterator<FunctionDescriptor> iterator = functions.iterator(); iterator.hasNext(); ) { for (Iterator<FunctionDescriptor> iterator = functions.iterator(); iterator.hasNext(); ) {
FunctionDescriptor functionDescriptor = iterator.next(); FunctionDescriptor functionDescriptor = iterator.next();
if (functionDescriptor.getReceiver().exists()) { if (functionDescriptor.getReceiverParameter().exists()) {
iterator.remove(); iterator.remove();
} }
} }
@@ -53,7 +53,7 @@ public class TaskPrioritizers {
Set<FunctionDescriptor> extensionFunctions = Sets.newHashSet(scope.getFunctions(name)); Set<FunctionDescriptor> extensionFunctions = Sets.newHashSet(scope.getFunctions(name));
for (Iterator<FunctionDescriptor> iterator = extensionFunctions.iterator(); iterator.hasNext(); ) { for (Iterator<FunctionDescriptor> iterator = extensionFunctions.iterator(); iterator.hasNext(); ) {
FunctionDescriptor descriptor = iterator.next(); FunctionDescriptor descriptor = iterator.next();
if (!descriptor.getReceiver().exists()) { if (!descriptor.getReceiverParameter().exists()) {
iterator.remove(); iterator.remove();
} }
} }
@@ -71,11 +71,11 @@ public class TaskPrioritizers {
private void addVariableAsFunction(JetScope scope, String name, Set<FunctionDescriptor> functions, boolean receiverNeeded) { private void addVariableAsFunction(JetScope scope, String name, Set<FunctionDescriptor> functions, boolean receiverNeeded) {
VariableDescriptor variable = scope.getVariable(name); VariableDescriptor variable = scope.getVariable(name);
if (variable != null && !variable.getReceiver().exists()) { if (variable != null && !variable.getReceiverParameter().exists()) {
JetType outType = variable.getOutType(); JetType outType = variable.getOutType();
if (outType != null && JetStandardClasses.isFunctionType(outType)) { if (outType != null && JetStandardClasses.isFunctionType(outType)) {
VariableAsFunctionDescriptor functionDescriptor = VariableAsFunctionDescriptor.create(variable); VariableAsFunctionDescriptor functionDescriptor = VariableAsFunctionDescriptor.create(variable);
if ((functionDescriptor.getReceiver().exists()) == receiverNeeded) { if ((functionDescriptor.getReceiverParameter().exists()) == receiverNeeded) {
functions.add(functionDescriptor); functions.add(functionDescriptor);
} }
} }
@@ -89,7 +89,7 @@ public class TaskPrioritizers {
@Override @Override
protected Collection<VariableDescriptor> getNonExtensionsByName(JetScope scope, String name) { protected Collection<VariableDescriptor> getNonExtensionsByName(JetScope scope, String name) {
VariableDescriptor variable = scope.getVariable(name); VariableDescriptor variable = scope.getVariable(name);
if (variable != null && !variable.getReceiver().exists()) { if (variable != null && !variable.getReceiverParameter().exists()) {
return Collections.singleton(variable); return Collections.singleton(variable);
} }
return Collections.emptyList(); return Collections.emptyList();
@@ -109,7 +109,7 @@ public class TaskPrioritizers {
@Override @Override
protected Collection<VariableDescriptor> getExtensionsByName(JetScope scope, String name) { protected Collection<VariableDescriptor> getExtensionsByName(JetScope scope, String name) {
VariableDescriptor variable = scope.getVariable(name); VariableDescriptor variable = scope.getVariable(name);
if (variable != null && variable.getReceiver().exists()) { if (variable != null && variable.getReceiverParameter().exists()) {
return Collections.singleton(variable); return Collections.singleton(variable);
} }
return Collections.emptyList(); return Collections.emptyList();
@@ -5,6 +5,7 @@ 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.resolve.BindingTrace; import org.jetbrains.jet.lang.resolve.BindingTrace;
import org.jetbrains.jet.lang.resolve.scopes.receivers.ReceiverDescriptor; import org.jetbrains.jet.lang.resolve.scopes.receivers.ReceiverDescriptor;
import org.jetbrains.jet.lang.types.JetType;
import java.util.Collection; import java.util.Collection;
import java.util.Set; import java.util.Set;
@@ -26,6 +27,9 @@ import java.util.Set;
@Override @Override
public void missingReceiver(@NotNull BindingTrace trace, @NotNull ReceiverDescriptor expectedReceiver) {} public void missingReceiver(@NotNull BindingTrace trace, @NotNull ReceiverDescriptor expectedReceiver) {}
@Override
public void wrongReceiverType(@NotNull BindingTrace trace, @NotNull ReceiverDescriptor receiverParameter, @NotNull ReceiverDescriptor receiverArgument) {}
@Override @Override
public void noReceiverAllowed(@NotNull BindingTrace trace) {} public void noReceiverAllowed(@NotNull BindingTrace trace) {}
@@ -46,6 +50,12 @@ import java.util.Set;
@Override @Override
public void typeInferenceFailed(@NotNull BindingTrace trace) {} public void typeInferenceFailed(@NotNull BindingTrace trace) {}
@Override
public void unsafeCall(@NotNull BindingTrace trace, @NotNull JetType type) {}
@Override
public void unnecessarySafeCall(@NotNull BindingTrace trace, @NotNull JetType type) {}
}; };
<D extends CallableDescriptor> void bindReference(@NotNull BindingTrace trace, @NotNull ResolvedCall<D> resolvedCall); <D extends CallableDescriptor> void bindReference(@NotNull BindingTrace trace, @NotNull ResolvedCall<D> resolvedCall);
@@ -56,6 +66,8 @@ import java.util.Set;
void missingReceiver(@NotNull BindingTrace trace, @NotNull ReceiverDescriptor expectedReceiver); void missingReceiver(@NotNull BindingTrace trace, @NotNull ReceiverDescriptor expectedReceiver);
void wrongReceiverType(@NotNull BindingTrace trace, @NotNull ReceiverDescriptor receiverParameter, @NotNull ReceiverDescriptor receiverArgument);
void noReceiverAllowed(@NotNull BindingTrace trace); void noReceiverAllowed(@NotNull BindingTrace trace);
void noValueForParameter(@NotNull BindingTrace trace, @NotNull ValueParameterDescriptor valueParameter); void noValueForParameter(@NotNull BindingTrace trace, @NotNull ValueParameterDescriptor valueParameter);
@@ -69,4 +81,8 @@ import java.util.Set;
void instantiationOfAbstractClass(@NotNull BindingTrace trace); void instantiationOfAbstractClass(@NotNull BindingTrace trace);
void typeInferenceFailed(@NotNull BindingTrace trace); void typeInferenceFailed(@NotNull BindingTrace trace);
void unsafeCall(@NotNull BindingTrace trace, @NotNull JetType type);
void unnecessarySafeCall(@NotNull BindingTrace trace, @NotNull JetType type);
} }
@@ -7,6 +7,7 @@ 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.TemporaryBindingTrace; import org.jetbrains.jet.lang.resolve.TemporaryBindingTrace;
import org.jetbrains.jet.lang.resolve.scopes.receivers.ReceiverDescriptor;
import org.jetbrains.jet.lang.types.CallMaker; import org.jetbrains.jet.lang.types.CallMaker;
import java.util.List; import java.util.List;
@@ -38,7 +39,7 @@ import static org.jetbrains.jet.lang.resolve.BindingContext.REFERENCE_TARGET;
parameterByName.put(valueParameter.getName(), valueParameter); parameterByName.put(valueParameter.getName(), valueParameter);
} }
List<? extends ValueArgument> valueArguments = task.getValueArguments(); List<? extends ValueArgument> valueArguments = task.getCall().getValueArguments();
boolean error = false; boolean error = false;
boolean someNamed = false; boolean someNamed = false;
@@ -103,7 +104,7 @@ import static org.jetbrains.jet.lang.resolve.BindingContext.REFERENCE_TARGET;
} }
} }
List<JetExpression> functionLiteralArguments = task.getFunctionLiteralArguments(); List<JetExpression> functionLiteralArguments = task.getCall().getFunctionLiteralArguments();
if (!functionLiteralArguments.isEmpty()) { if (!functionLiteralArguments.isEmpty()) {
JetExpression possiblyLabeledFunctionLiteral = functionLiteralArguments.get(0); JetExpression possiblyLabeledFunctionLiteral = functionLiteralArguments.get(0);
@@ -164,6 +165,20 @@ import static org.jetbrains.jet.lang.resolve.BindingContext.REFERENCE_TARGET;
} }
} }
} }
ReceiverDescriptor receiverParameter = candidate.getReceiverParameter();
ReceiverDescriptor receiverArgument = candidateCall.getReceiverArgument();
if (receiverParameter.exists() &&!receiverArgument.exists()) {
tracing.missingReceiver(temporaryTrace, receiverParameter);
error = true;
}
if (!receiverParameter.exists() && receiverArgument.exists()) {
tracing.noReceiverAllowed(temporaryTrace);
error = true;
}
assert candidateCall.getThisObject().exists() == candidateCall.getExpectedThisObject().exists() : "Shouldn't happen because of TaskPrioritizer: " + candidateCall.getCandidateDescriptor();
return error; return error;
} }
@@ -127,6 +127,10 @@ public class CallMaker {
return null; return null;
} }
@Override
public String toString() {
return getCallNode().getText();
}
} }
public static Call makeCallWithExpressions(@NotNull JetElement callElement, @NotNull ReceiverDescriptor explicitReceiver, @Nullable ASTNode callOperationNode, @NotNull JetExpression calleeExpression, @NotNull List<JetExpression> argumentExpressions) { public static Call makeCallWithExpressions(@NotNull JetElement callElement, @NotNull ReceiverDescriptor explicitReceiver, @Nullable ASTNode callOperationNode, @NotNull JetExpression calleeExpression, @NotNull List<JetExpression> argumentExpressions) {
@@ -222,7 +222,7 @@ public class JetTypeInferrer {
// 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.getReceiverParameter();
// boolean calleeForbidsNullableReceiver = !calleeReceiver.exists() || !calleeReceiver.getType().isNullable(); // boolean calleeForbidsNullableReceiver = !calleeReceiver.exists() || !calleeReceiver.getType().isNullable();
// //
// IElementType operationSign = operationTokenNode.getElementType(); // IElementType operationSign = operationTokenNode.getElementType();
@@ -1275,7 +1275,7 @@ public class JetTypeInferrer {
} }
else if (declarationDescriptor instanceof FunctionDescriptor) { else if (declarationDescriptor instanceof FunctionDescriptor) {
FunctionDescriptor functionDescriptor = (FunctionDescriptor) declarationDescriptor; FunctionDescriptor functionDescriptor = (FunctionDescriptor) declarationDescriptor;
thisReceiver = functionDescriptor.getReceiver(); thisReceiver = functionDescriptor.getReceiverParameter();
} }
else { else {
throw new UnsupportedOperationException(); // TODO throw new UnsupportedOperationException(); // TODO
@@ -1289,7 +1289,7 @@ public class JetTypeInferrer {
if (psiElement instanceof JetFunctionLiteralExpression) { if (psiElement instanceof JetFunctionLiteralExpression) {
DeclarationDescriptor declarationDescriptor = context.trace.getBindingContext().get(BindingContext.DECLARATION_TO_DESCRIPTOR, psiElement); DeclarationDescriptor declarationDescriptor = context.trace.getBindingContext().get(BindingContext.DECLARATION_TO_DESCRIPTOR, psiElement);
if (declarationDescriptor instanceof FunctionDescriptor) { if (declarationDescriptor instanceof FunctionDescriptor) {
thisReceiver = ((FunctionDescriptor) declarationDescriptor).getReceiver(); thisReceiver = ((FunctionDescriptor) declarationDescriptor).getReceiverParameter();
if (thisReceiver.exists()) { if (thisReceiver.exists()) {
context.trace.record(REFERENCE_TARGET, targetLabel, declarationDescriptor); context.trace.record(REFERENCE_TARGET, targetLabel, declarationDescriptor);
context.trace.record(REFERENCE_TARGET, expression.getThisReference(), declarationDescriptor); context.trace.record(REFERENCE_TARGET, expression.getThisReference(), declarationDescriptor);
@@ -186,7 +186,7 @@ public class DescriptorRenderer implements Renderer {
renderModality(descriptor.getModality(), builder); renderModality(descriptor.getModality(), builder);
String typeString = renderPropertyPrefixAndComputeTypeString( String typeString = renderPropertyPrefixAndComputeTypeString(
builder, descriptor.getTypeParameters(), builder, descriptor.getTypeParameters(),
descriptor.getReceiver(), descriptor.getReceiverParameter(),
descriptor.getOutType(), descriptor.getOutType(),
descriptor.getInType()); descriptor.getInType());
renderName(descriptor, builder); renderName(descriptor, builder);
@@ -215,7 +215,7 @@ public class DescriptorRenderer implements Renderer {
builder.append(renderKeyword("fun")).append(" "); builder.append(renderKeyword("fun")).append(" ");
renderTypeParameters(descriptor.getTypeParameters(), builder); renderTypeParameters(descriptor.getTypeParameters(), builder);
ReceiverDescriptor receiver = descriptor.getReceiver(); ReceiverDescriptor receiver = descriptor.getReceiverParameter();
if (receiver.exists()) { if (receiver.exists()) {
builder.append(escape(renderType(receiver.getType()))).append("."); builder.append(escape(renderType(receiver.getType()))).append(".");
} }