diff --git a/compiler/backend/src/org/jetbrains/jet/codegen/ClassContext.java b/compiler/backend/src/org/jetbrains/jet/codegen/ClassContext.java index 81d06bf4ea8..e0fe6e08cb3 100644 --- a/compiler/backend/src/org/jetbrains/jet/codegen/ClassContext.java +++ b/compiler/backend/src/org/jetbrains/jet/codegen/ClassContext.java @@ -73,7 +73,7 @@ public class ClassContext { thisIdx++; } - final boolean hasReceiver = descriptor.getReceiver().exists(); + final boolean hasReceiver = descriptor.getReceiverParameter().exists(); if (hasReceiver) { thisIdx++; } @@ -104,7 +104,7 @@ public class ClassContext { } 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() { diff --git a/compiler/backend/src/org/jetbrains/jet/codegen/ClosureCodegen.java b/compiler/backend/src/org/jetbrains/jet/codegen/ClosureCodegen.java index 864111bee96..4fe118bd598 100644 --- a/compiler/backend/src/org/jetbrains/jet/codegen/ClosureCodegen.java +++ b/compiler/backend/src/org/jetbrains/jet/codegen/ClosureCodegen.java @@ -42,7 +42,7 @@ public class ClosureCodegen { } public static Method erasedInvokeSignature(FunctionDescriptor fd) { - boolean isExtensionFunction = fd.getReceiver().exists(); + boolean isExtensionFunction = fd.getReceiverParameter().exists(); int paramCount = fd.getValueParameters().size(); if (isExtensionFunction) { paramCount++; @@ -151,7 +151,7 @@ public class ClosureCodegen { iv.load(0, Type.getObjectType(className)); - final ReceiverDescriptor receiver = funDescriptor.getReceiver(); + final ReceiverDescriptor receiver = funDescriptor.getReceiverParameter(); int count = 1; if (receiver.exists()) { StackValue.local(count, JetTypeMapper.TYPE_OBJECT).put(JetTypeMapper.TYPE_OBJECT, iv); @@ -229,7 +229,7 @@ public class ClosureCodegen { public static String getInternalClassName(FunctionDescriptor descriptor) { final int paramCount = descriptor.getValueParameters().size(); - if (descriptor.getReceiver().exists()) { + if (descriptor.getReceiverParameter().exists()) { return "jet/ExtensionFunction" + paramCount; } else { @@ -250,7 +250,7 @@ public class ClosureCodegen { Method descriptor = erasedInvokeSignature(fd); String owner = getInternalClassName(fd); 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.requestGenerateCallee(Type.getObjectType(getInternalClassName(fd))); diff --git a/compiler/backend/src/org/jetbrains/jet/codegen/JetTypeMapper.java b/compiler/backend/src/org/jetbrains/jet/codegen/JetTypeMapper.java index 61a1584b381..83a86b339dc 100644 --- a/compiler/backend/src/org/jetbrains/jet/codegen/JetTypeMapper.java +++ b/compiler/backend/src/org/jetbrains/jet/codegen/JetTypeMapper.java @@ -2,7 +2,6 @@ package org.jetbrains.jet.codegen; import com.intellij.psi.*; import com.intellij.psi.util.PsiTreeUtil; -import jet.Function1; import jet.JetObject; import jet.typeinfo.TypeInfo; import jet.typeinfo.TypeInfoProjection; @@ -546,7 +545,7 @@ public class JetTypeMapper { } public Method mapSignature(String name, FunctionDescriptor f) { - final ReceiverDescriptor receiver = f.getReceiver(); + final ReceiverDescriptor receiver = f.getReceiverParameter(); final List parameters = f.getValueParameters(); List parameterTypes = new ArrayList(); if (receiver.exists()) { diff --git a/compiler/frontend/src/org/jetbrains/jet/lang/descriptors/CallableDescriptor.java b/compiler/frontend/src/org/jetbrains/jet/lang/descriptors/CallableDescriptor.java index 47eac9f2bee..c69a68f4d69 100644 --- a/compiler/frontend/src/org/jetbrains/jet/lang/descriptors/CallableDescriptor.java +++ b/compiler/frontend/src/org/jetbrains/jet/lang/descriptors/CallableDescriptor.java @@ -1,7 +1,6 @@ package org.jetbrains.jet.lang.descriptors; 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.types.JetType; import org.jetbrains.jet.lang.types.TypeSubstitutor; @@ -14,7 +13,7 @@ import java.util.Set; */ public interface CallableDescriptor extends DeclarationDescriptor { @NotNull - ReceiverDescriptor getReceiver(); + ReceiverDescriptor getReceiverParameter(); @NotNull List getTypeParameters(); diff --git a/compiler/frontend/src/org/jetbrains/jet/lang/descriptors/FunctionDescriptorImpl.java b/compiler/frontend/src/org/jetbrains/jet/lang/descriptors/FunctionDescriptorImpl.java index 3dd21e79fea..21864c09dfa 100644 --- a/compiler/frontend/src/org/jetbrains/jet/lang/descriptors/FunctionDescriptorImpl.java +++ b/compiler/frontend/src/org/jetbrains/jet/lang/descriptors/FunctionDescriptorImpl.java @@ -71,7 +71,7 @@ public class FunctionDescriptorImpl extends DeclarationDescriptorImpl implements @NotNull @Override - public ReceiverDescriptor getReceiver() { + public ReceiverDescriptor getReceiverParameter() { return receiver; } @@ -133,7 +133,7 @@ public class FunctionDescriptorImpl extends DeclarationDescriptorImpl implements JetType substitutedReceiverType = null; if (receiver.exists()) { - substitutedReceiverType = substitutor.substitute(getReceiver().getType(), Variance.IN_VARIANCE); + substitutedReceiverType = substitutor.substitute(getReceiverParameter().getType(), Variance.IN_VARIANCE); if (substitutedReceiverType == null) { return null; } @@ -181,7 +181,7 @@ public class FunctionDescriptorImpl extends DeclarationDescriptorImpl implements public FunctionDescriptor copy(DeclarationDescriptor newOwner, boolean makeNonAbstract) { FunctionDescriptorImpl copy = new FunctionDescriptorImpl(newOwner, Lists.newArrayList(getAnnotations()), getName()); copy.initialize( - getReceiver().exists() ? getReceiver().getType() : null, + getReceiverParameter().exists() ? getReceiverParameter().getType() : null, DescriptorUtils.copyTypeParameters(copy, typeParameters), DescriptorUtils.copyValueParameters(copy, unsubstitutedValueParameters), unsubstitutedReturnType, diff --git a/compiler/frontend/src/org/jetbrains/jet/lang/descriptors/FunctionDescriptorUtil.java b/compiler/frontend/src/org/jetbrains/jet/lang/descriptors/FunctionDescriptorUtil.java index 07a14eece99..3990e09e9a7 100644 --- a/compiler/frontend/src/org/jetbrains/jet/lang/descriptors/FunctionDescriptorUtil.java +++ b/compiler/frontend/src/org/jetbrains/jet/lang/descriptors/FunctionDescriptorUtil.java @@ -95,7 +95,7 @@ public class FunctionDescriptorUtil { @NotNull 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"); - ReceiverDescriptor receiver = descriptor.getReceiver(); + ReceiverDescriptor receiver = descriptor.getReceiverParameter(); if (receiver.exists()) { parameterScope.setImplicitReceiver(receiver); } diff --git a/compiler/frontend/src/org/jetbrains/jet/lang/descriptors/PropertyDescriptor.java b/compiler/frontend/src/org/jetbrains/jet/lang/descriptors/PropertyDescriptor.java index 5c6c5212c78..77582ab8e92 100644 --- a/compiler/frontend/src/org/jetbrains/jet/lang/descriptors/PropertyDescriptor.java +++ b/compiler/frontend/src/org/jetbrains/jet/lang/descriptors/PropertyDescriptor.java @@ -95,7 +95,7 @@ public class PropertyDescriptor extends VariableDescriptorImpl implements Callab } @NotNull - public ReceiverDescriptor getReceiver() { + public ReceiverDescriptor getReceiverParameter() { return receiver; } diff --git a/compiler/frontend/src/org/jetbrains/jet/lang/descriptors/PropertyGetterDescriptor.java b/compiler/frontend/src/org/jetbrains/jet/lang/descriptors/PropertyGetterDescriptor.java index 747a27e64a7..6a1590cb807 100644 --- a/compiler/frontend/src/org/jetbrains/jet/lang/descriptors/PropertyGetterDescriptor.java +++ b/compiler/frontend/src/org/jetbrains/jet/lang/descriptors/PropertyGetterDescriptor.java @@ -35,8 +35,8 @@ public class PropertyGetterDescriptor extends PropertyAccessorDescriptor { @NotNull @Override - public ReceiverDescriptor getReceiver() { - return getCorrespondingProperty().getReceiver(); + public ReceiverDescriptor getReceiverParameter() { + return getCorrespondingProperty().getReceiverParameter(); } @NotNull diff --git a/compiler/frontend/src/org/jetbrains/jet/lang/descriptors/PropertySetterDescriptor.java b/compiler/frontend/src/org/jetbrains/jet/lang/descriptors/PropertySetterDescriptor.java index 13752d9743c..e6147696f67 100644 --- a/compiler/frontend/src/org/jetbrains/jet/lang/descriptors/PropertySetterDescriptor.java +++ b/compiler/frontend/src/org/jetbrains/jet/lang/descriptors/PropertySetterDescriptor.java @@ -44,8 +44,8 @@ public class PropertySetterDescriptor extends PropertyAccessorDescriptor { @NotNull @Override - public ReceiverDescriptor getReceiver() { - return getCorrespondingProperty().getReceiver(); + public ReceiverDescriptor getReceiverParameter() { + return getCorrespondingProperty().getReceiverParameter(); } @NotNull diff --git a/compiler/frontend/src/org/jetbrains/jet/lang/descriptors/VariableDescriptorImpl.java b/compiler/frontend/src/org/jetbrains/jet/lang/descriptors/VariableDescriptorImpl.java index c941fae9605..c18d8293a4b 100644 --- a/compiler/frontend/src/org/jetbrains/jet/lang/descriptors/VariableDescriptorImpl.java +++ b/compiler/frontend/src/org/jetbrains/jet/lang/descriptors/VariableDescriptorImpl.java @@ -74,7 +74,7 @@ public abstract class VariableDescriptorImpl extends DeclarationDescriptorImpl i @NotNull @Override - public ReceiverDescriptor getReceiver() { + public ReceiverDescriptor getReceiverParameter() { return ReceiverDescriptor.NO_RECEIVER; } diff --git a/compiler/frontend/src/org/jetbrains/jet/lang/resolve/BodyResolver.java b/compiler/frontend/src/org/jetbrains/jet/lang/resolve/BodyResolver.java index a5e6b491cea..6e1033b67e2 100644 --- a/compiler/frontend/src/org/jetbrains/jet/lang/resolve/BodyResolver.java +++ b/compiler/frontend/src/org/jetbrains/jet/lang/resolve/BodyResolver.java @@ -459,7 +459,7 @@ public class BodyResolver { for (TypeParameterDescriptor typeParameterDescriptor : propertyDescriptor.getTypeParameters()) { result.addTypeParameterDescriptor(typeParameterDescriptor); } - ReceiverDescriptor receiver = propertyDescriptor.getReceiver(); + ReceiverDescriptor receiver = propertyDescriptor.getReceiverParameter(); if (receiver.exists()) { result.setImplicitReceiver(receiver); } diff --git a/compiler/frontend/src/org/jetbrains/jet/lang/resolve/DescriptorUtils.java b/compiler/frontend/src/org/jetbrains/jet/lang/resolve/DescriptorUtils.java index 42fb64620ed..48dd916e6c7 100644 --- a/compiler/frontend/src/org/jetbrains/jet/lang/resolve/DescriptorUtils.java +++ b/compiler/frontend/src/org/jetbrains/jet/lang/resolve/DescriptorUtils.java @@ -4,11 +4,14 @@ import com.google.common.collect.Lists; import com.google.common.collect.Maps; import org.jetbrains.annotations.NotNull; import org.jetbrains.jet.lang.descriptors.*; +import org.jetbrains.jet.lang.resolve.scopes.receivers.ReceiverDescriptor; import org.jetbrains.jet.lang.types.*; import java.util.List; import java.util.Map; +import static org.jetbrains.jet.lang.resolve.scopes.receivers.ReceiverDescriptor.NO_RECEIVER; + /** * @author abreslav */ @@ -22,7 +25,7 @@ public class DescriptorUtils { @Override public Boolean visitFunctionDescriptor(FunctionDescriptor descriptor, Void data) { - return descriptor.getReceiver().exists(); + return descriptor.getReceiverParameter().exists(); } @Override @@ -32,7 +35,7 @@ public class DescriptorUtils { @Override public Boolean visitPropertyDescriptor(PropertyDescriptor descriptor, Void data) { - return descriptor.getReceiver().exists(); + return descriptor.getReceiverParameter().exists(); } }, null); } @@ -111,4 +114,19 @@ public class DescriptorUtils { if (makeNonAbstract && modality == Modality.ABSTRACT) return Modality.OPEN; 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; + } } diff --git a/compiler/frontend/src/org/jetbrains/jet/lang/resolve/calls/CallResolver.java b/compiler/frontend/src/org/jetbrains/jet/lang/resolve/calls/CallResolver.java index aa3b60642aa..9788fb2b164 100644 --- a/compiler/frontend/src/org/jetbrains/jet/lang/resolve/calls/CallResolver.java +++ b/compiler/frontend/src/org/jetbrains/jet/lang/resolve/calls/CallResolver.java @@ -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.types.*; import org.jetbrains.jet.lang.types.inference.ConstraintSystem; +import org.jetbrains.jet.lexer.JetTokens; 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.calls.ResolvedCall.MAP_TO_CANDIDATE; 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; /** @@ -142,7 +144,7 @@ public class CallResolver { trace.report(NO_CONSTRUCTOR.on(reportAbsenceOn)); return checkArgumentTypesAndFail(trace, scope, call); } - prioritizedTasks.add(new ResolutionTask(ResolvedCall.convertCollection(constructors), call, DataFlowInfo.getEmpty())); + prioritizedTasks.add(new ResolutionTask(TaskPrioritizer.convertWithImpliedThis(scope, Collections.singletonList(NO_RECEIVER), constructors), call, DataFlowInfo.getEmpty())); } else { // trace.getErrorHandler().genericError(calleeExpression.getNode(), "Not a class"); @@ -173,7 +175,7 @@ public class CallResolver { } private FunctionDescriptor checkArgumentTypesAndFail(BindingTrace trace, JetScope scope, Call call) { - checkTypesWithNoCallee(trace, scope, call.getTypeArguments(), call.getValueArguments(), call.getFunctionLiteralArguments()); + checkTypesWithNoCallee(trace, scope, call); return null; } @@ -235,6 +237,17 @@ public class CallResolver { 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 public void noReceiverAllowed(@NotNull BindingTrace trace) { trace.report(NO_RECEIVER_ADMITTED.on(reference)); @@ -273,6 +286,23 @@ public class CallResolver { 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 task : prioritizedTasks) { TemporaryBindingTrace temporaryTrace = TemporaryBindingTrace.create(trace); @@ -294,7 +324,7 @@ public class CallResolver { } else { trace.report(UNRESOLVED_REFERENCE.on(reference)); - checkTypesWithNoCallee(trace, scope, call.getTypeArguments(), call.getValueArguments(), call.getFunctionLiteralArguments()); + checkTypesWithNoCallee(trace, scope, call); } return null; } @@ -315,21 +345,19 @@ public class CallResolver { if (ErrorUtils.isError(candidate)) { successfulCandidates.add(candidateCall.setResultingDescriptor(candidate)); - checkTypesWithNoCallee(temporaryTrace, scope, task.getTypeArguments(), task.getValueArguments(), task.getFunctionLiteralArguments()); + checkTypesWithNoCallee(temporaryTrace, scope, task.getCall()); continue; } - -// Map argumentsToParameters = Maps.newHashMap(); - boolean error = ValueArgumentsToParametersMapper.mapValueArgumentsToParameters(task, tracing, candidateCall); - - if (error) { + boolean errorInArgumentMapping = ValueArgumentsToParametersMapper.mapValueArgumentsToParameters(task, tracing, candidateCall); + if (errorInArgumentMapping) { failedCandidates.add(candidateCall); - checkTypesWithNoCallee(temporaryTrace, scope, task.getTypeArguments(), task.getValueArguments(), task.getFunctionLiteralArguments()); + checkTypesWithNoCallee(temporaryTrace, scope, task.getCall()); continue; } - if (task.getTypeArguments().isEmpty()) { + List jetTypeArguments = task.getCall().getTypeArguments(); + if (jetTypeArguments.isEmpty()) { if (!candidate.getTypeParameters().isEmpty()) { // 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 - ReceiverDescriptor receiverParameter = candidateCall.getReceiverParameter(); - ReceiverDescriptor candidateReceiver = candidate.getReceiver(); + ReceiverDescriptor receiverParameter = candidateCall.getReceiverArgument(); + ReceiverDescriptor candidateReceiver = candidate.getReceiverParameter(); if (receiverParameter.exists() && candidateReceiver.exists()) { constraintSystem.addSubtypingConstraint(receiverParameter.getType(), candidateReceiver.getType()); } @@ -382,8 +411,7 @@ public class CallResolver { } } else { - if (checkValueArgumentTypes(scope, candidateCall) - && checkReceiver(candidateCall, tracing, candidate)) { + if (checkAllValueArguments(scope, tracing, task, candidateCall, candidate)) { successfulCandidates.add(candidateCall.setResultingDescriptor(candidate)); } else { @@ -394,8 +422,6 @@ public class CallResolver { else { // Explicit type arguments passed - final List jetTypeArguments = task.getTypeArguments(); - for (JetTypeProjection typeArgument : jetTypeArguments) { if (typeArgument.getProjectionKind() != JetProjectionKind.NONE) { // 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); - + Map substitutionContext = FunctionDescriptorUtil.createSubstitutionContext((FunctionDescriptor) candidate, typeArguments); D substitutedDescriptor = (D) candidate.substitute(TypeSubstitutor.create(substitutionContext)); + candidateCall.setResultingDescriptor(substitutedDescriptor); replaceValueParametersWithSubstitutedOnes(candidateCall, substitutedDescriptor); - if (checkValueArgumentTypes(scope, candidateCall) - && checkReceiver(candidateCall, tracing, substitutedDescriptor)) { - successfulCandidates.add(candidateCall.setResultingDescriptor(substitutedDescriptor)); + if (checkAllValueArguments(scope, tracing, task, candidateCall, substitutedDescriptor)) { + successfulCandidates.add(candidateCall); } else { failedCandidates.add(candidateCall); @@ -437,13 +463,13 @@ public class CallResolver { task.performAdvancedChecks(candidate, temporaryTrace, tracing); - recordAutoCastIfNecessary(candidateCall.getReceiverParameter(), candidateCall.getTrace()); + recordAutoCastIfNecessary(candidateCall.getReceiverArgument(), candidateCall.getTrace()); recordAutoCastIfNecessary(candidateCall.getThisObject(), candidateCall.getTrace()); } OverloadResolutionResults results = computeResultAndReportErrors(trace, tracing, successfulCandidates, failedCandidates); if (!results.singleDescriptor()) { - checkTypesWithNoCallee(trace, scope, task.getTypeArguments(), task.getValueArguments(), task.getFunctionLiteralArguments()); + checkTypesWithNoCallee(trace, scope, task.getCall()); } return results; } @@ -467,19 +493,19 @@ public class CallResolver { } } - private void checkTypesWithNoCallee(BindingTrace trace, JetScope scope, List typeArguments, List valueArguments, List functionLiteralArguments) { - for (ValueArgument valueArgument : valueArguments) { + private void checkTypesWithNoCallee(BindingTrace trace, JetScope scope, Call call) { + for (ValueArgument valueArgument : call.getValueArguments()) { JetExpression argumentExpression = valueArgument.getArgumentExpression(); if (argumentExpression != null) { 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); } - for (JetTypeProjection typeProjection : typeArguments) { + for (JetTypeProjection typeProjection : call.getTypeArguments()) { new TypeResolver(semanticServices, trace, true).resolveType(scope, typeProjection.getTypeReference()); } } @@ -515,9 +541,33 @@ public class CallResolver { } } - private boolean checkValueArgumentTypes( - JetScope scope, - ResolvedCall candidateCall) { + private boolean checkAllValueArguments(JetScope scope, TracingStrategy tracing, ResolutionTask task, ResolvedCall candidateCall, D substitutedDescriptor) { + boolean result = checkValueArgumentTypes(scope, 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 boolean checkValueArgumentTypes(JetScope scope, ResolvedCall candidateCall) { boolean result = true; for (Map.Entry entry : candidateCall.getValueArguments().entrySet()) { ValueParameterDescriptor parameterDescriptor = entry.getKey(); @@ -557,59 +607,40 @@ public class CallResolver { } } } -// for (Map.Entry 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 boolean checkReceiver(ResolvedCall resolvedCall, TracingStrategy tracing, D candidate) { - if (!checkReceiverAbsence(resolvedCall, tracing, candidate)) return false; - ReceiverDescriptor receiver = resolvedCall.getReceiverParameter(); - ReceiverDescriptor candidateReceiver = candidate.getReceiver(); - if (receiver.exists() - && candidateReceiver.exists() - && !semanticServices.getTypeChecker().isSubtypeOf(receiver.getType(), candidateReceiver.getType())) { - tracing.missingReceiver(resolvedCall.getTrace(), candidateReceiver); - return false; - } - return true; - } - - private boolean checkReceiverAbsence(ResolvedCall resolvedCall, TracingStrategy tracing, D candidate) { - ReceiverDescriptor receiver = resolvedCall.getReceiverParameter(); - ReceiverDescriptor candidateReceiver = candidate.getReceiver(); - if (receiver.exists()) { - if (!candidateReceiver.exists()) { - tracing.noReceiverAllowed(resolvedCall.getTrace()); - return false; - } - } - else if (candidateReceiver.exists()) { - tracing.missingReceiver(resolvedCall.getTrace(), candidateReceiver); - return false; - } - return true; - } - +// private boolean checkReceiver(ResolutionTask task, ResolvedCall resolvedCall, TracingStrategy tracing, D candidate) { +// if (!checkReceiverAbsence(resolvedCall, tracing, candidate)) return false; +// ReceiverDescriptor actualReceiver = resolvedCall.getReceiverArgument(); +// ReceiverDescriptor expectedReceiver = candidate.getReceiverParameter(); +// +// if (actualReceiver.exists() +// && expectedReceiver.exists()) { +// if (!semanticServices.getTypeChecker().isSubtypeOf(actualReceiver.getType(), expectedReceiver.getType())) { +// tracing.missingReceiver(resolvedCall.getTrace(), expectedReceiver); +// return false; +// } +// } +// return true; +// } +// +// private boolean checkReceiverAbsence(ResolvedCall resolvedCall, TracingStrategy tracing, D candidate) { +// ReceiverDescriptor receiver = resolvedCall.getReceiverArgument(); +// ReceiverDescriptor candidateReceiver = candidate.getReceiverParameter(); +// if (receiver.exists()) { +// if (!candidateReceiver.exists()) { +// tracing.noReceiverAllowed(resolvedCall.getTrace()); +// return false; +// } +// } +// else if (candidateReceiver.exists()) { +// tracing.missingReceiver(resolvedCall.getTrace(), candidateReceiver); +// return false; +// } +// return true; +// } +// @NotNull private OverloadResolutionResults computeResultAndReportErrors( BindingTrace trace, @@ -747,7 +778,7 @@ public class CallResolver { boolean found = false; for (ResolvedCall resolvedCall : candidates) { FunctionDescriptor functionDescriptor = resolvedCall.getResultingDescriptor(); - if (functionDescriptor.getReceiver().exists()) continue; + if (functionDescriptor.getReceiverParameter().exists()) continue; if (!functionDescriptor.getTypeParameters().isEmpty()) continue; if (!checkValueParameters(functionDescriptor, parameterTypes)) continue; result.add(resolvedCall); @@ -760,7 +791,7 @@ public class CallResolver { boolean found = false; for (ResolvedCall resolvedCall : candidates) { FunctionDescriptor functionDescriptor = resolvedCall.getResultingDescriptor(); - ReceiverDescriptor functionReceiver = functionDescriptor.getReceiver(); + ReceiverDescriptor functionReceiver = functionDescriptor.getReceiverParameter(); if (!functionReceiver.exists()) continue; if (!functionDescriptor.getTypeParameters().isEmpty()) continue; if (!semanticServices.getTypeChecker().isSubtypeOf(receiver.getType(), functionReceiver.getType())) continue; diff --git a/compiler/frontend/src/org/jetbrains/jet/lang/resolve/calls/OverloadingConflictResolver.java b/compiler/frontend/src/org/jetbrains/jet/lang/resolve/calls/OverloadingConflictResolver.java index af2341f1bb8..dc12c9ab9bc 100644 --- a/compiler/frontend/src/org/jetbrains/jet/lang/resolve/calls/OverloadingConflictResolver.java +++ b/compiler/frontend/src/org/jetbrains/jet/lang/resolve/calls/OverloadingConflictResolver.java @@ -72,9 +72,9 @@ public class OverloadingConflictResolver { if (OverridingUtil.overrides(f, g)) return true; if (OverridingUtil.overrides(g, f)) return false; - ReceiverDescriptor receiverOfF = f.getReceiver(); - ReceiverDescriptor receiverOfG = g.getReceiver(); - if (f.getReceiver().exists() && g.getReceiver().exists()) { + ReceiverDescriptor receiverOfF = f.getReceiverParameter(); + ReceiverDescriptor receiverOfG = g.getReceiverParameter(); + if (f.getReceiverParameter().exists() && g.getReceiverParameter().exists()) { if (!typeMoreSpecific(receiverOfF.getType(), receiverOfG.getType())) return false; } diff --git a/compiler/frontend/src/org/jetbrains/jet/lang/resolve/calls/ResolutionTask.java b/compiler/frontend/src/org/jetbrains/jet/lang/resolve/calls/ResolutionTask.java index a8dbede8e64..25e01c32074 100644 --- a/compiler/frontend/src/org/jetbrains/jet/lang/resolve/calls/ResolutionTask.java +++ b/compiler/frontend/src/org/jetbrains/jet/lang/resolve/calls/ResolutionTask.java @@ -3,45 +3,29 @@ package org.jetbrains.jet.lang.resolve.calls; import org.jetbrains.annotations.NotNull; import org.jetbrains.jet.lang.descriptors.CallableDescriptor; 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.types.DataFlowInfo; import java.util.Collection; -import java.util.List; /** * @author abreslav */ /*package*/ class ResolutionTask { + private final Call call; private final Collection> candidates; - private final List typeArguments; - private final List valueArguments; - private final List functionLiteralArguments; private final DataFlowInfo dataFlowInfo; private DescriptorCheckStrategy checkingStrategy; - public ResolutionTask( - @NotNull Collection> candidates, - @NotNull List typeArguments, - @NotNull List valueArguments, - @NotNull List functionLiteralArguments, - @NotNull DataFlowInfo dataFlowInfo) { - this.candidates = candidates; - this.typeArguments = typeArguments; - this.valueArguments = valueArguments; - this.functionLiteralArguments = functionLiteralArguments; - this.dataFlowInfo = dataFlowInfo; - } public ResolutionTask( @NotNull Collection> candidates, @NotNull Call call, @NotNull DataFlowInfo dataFlowInfo ) { - this(candidates, call.getTypeArguments(), call.getValueArguments(), call.getFunctionLiteralArguments(), dataFlowInfo); + this.candidates = candidates; + this.call = call; + this.dataFlowInfo = dataFlowInfo; } @NotNull @@ -55,20 +39,10 @@ import java.util.List; } @NotNull - public List getTypeArguments() { - return typeArguments; + public Call getCall() { + return call; } - @NotNull - public List getValueArguments() { - return valueArguments; - } - - @NotNull - public List getFunctionLiteralArguments() { - return functionLiteralArguments; - } - public void setCheckingStrategy(DescriptorCheckStrategy strategy) { checkingStrategy = strategy; } diff --git a/compiler/frontend/src/org/jetbrains/jet/lang/resolve/calls/ResolvedCall.java b/compiler/frontend/src/org/jetbrains/jet/lang/resolve/calls/ResolvedCall.java index 491524d6172..fa28e6ccef4 100644 --- a/compiler/frontend/src/org/jetbrains/jet/lang/resolve/calls/ResolvedCall.java +++ b/compiler/frontend/src/org/jetbrains/jet/lang/resolve/calls/ResolvedCall.java @@ -4,9 +4,8 @@ import com.google.common.collect.Lists; import com.google.common.collect.Maps; import com.intellij.util.Function; import org.jetbrains.annotations.NotNull; -import org.jetbrains.jet.lang.descriptors.CallableDescriptor; -import org.jetbrains.jet.lang.descriptors.TypeParameterDescriptor; -import org.jetbrains.jet.lang.descriptors.ValueParameterDescriptor; +import org.jetbrains.jet.lang.descriptors.*; +import org.jetbrains.jet.lang.resolve.DescriptorUtils; import org.jetbrains.jet.lang.resolve.TemporaryBindingTrace; import org.jetbrains.jet.lang.resolve.scopes.receivers.ReceiverDescriptor; import org.jetbrains.jet.lang.types.JetType; @@ -53,7 +52,7 @@ public class ResolvedCall { private final D candidateDescriptor; private D resultingDescriptor; // Probably substituted private ReceiverDescriptor thisObject = NO_RECEIVER; // receiver object of a method - private ReceiverDescriptor receiverParameter = NO_RECEIVER; // receiver of an extension function + private ReceiverDescriptor receiverArgument = NO_RECEIVER; // receiver of an extension function private final Map typeArguments = Maps.newLinkedHashMap(); private final Map autoCasts = Maps.newHashMap(); private final Map valueArguments = Maps.newHashMap(); @@ -104,12 +103,12 @@ public class ResolvedCall { } @NotNull - public ReceiverDescriptor getReceiverParameter() { - return receiverParameter; + public ReceiverDescriptor getReceiverArgument() { + return receiverArgument; } - public void setReceiverParameter(@NotNull ReceiverDescriptor receiverParameter) { - this.receiverParameter = receiverParameter; + public void setReceiverArgument(@NotNull ReceiverDescriptor receiverParameter) { + this.receiverArgument = receiverParameter; } @NotNull @@ -133,4 +132,9 @@ public class ResolvedCall { public boolean isDirty() { return someArgumentHasNoType; } + + @NotNull + public ReceiverDescriptor getExpectedThisObject() { + return DescriptorUtils.getExpectedThisObject(getResultingDescriptor()); + } } diff --git a/compiler/frontend/src/org/jetbrains/jet/lang/resolve/calls/TaskPrioritizer.java b/compiler/frontend/src/org/jetbrains/jet/lang/resolve/calls/TaskPrioritizer.java index 2abfc50d1dc..adc25b80ce0 100644 --- a/compiler/frontend/src/org/jetbrains/jet/lang/resolve/calls/TaskPrioritizer.java +++ b/compiler/frontend/src/org/jetbrains/jet/lang/resolve/calls/TaskPrioritizer.java @@ -5,10 +5,13 @@ import org.jetbrains.annotations.NotNull; import org.jetbrains.jet.lang.descriptors.*; import org.jetbrains.jet.lang.psi.Call; 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.receivers.ReceiverDescriptor; import org.jetbrains.jet.lang.types.DataFlowInfo; 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.Collections; @@ -65,16 +68,14 @@ import static org.jetbrains.jet.lang.resolve.scopes.receivers.ReceiverDescriptor return false; } -// public List> computePrioritizedTasks(@NotNull JetScope scope, @NotNull ReceiverDescriptor receiver, @NotNull Call call, @NotNull String name) { -// List> result = Lists.newArrayList(); -// doComputeTasks(scope, receiver, call, name, result); -// return result; -// } - public List> computePrioritizedTasks(@NotNull JetScope scope, @NotNull Call call, @NotNull String name, @NotNull BindingContext bindingContext, @NotNull DataFlowInfo dataFlowInfo) { List> result = Lists.newArrayList(); 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); 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> result, @NotNull AutoCastService autoCastService) { + private void doComputeTasks(JetScope scope, ReceiverDescriptor receiver, Call call, String name, List> result, @NotNull AutoCastService autoCastService) { DataFlowInfo dataFlowInfo = autoCastService.getDataFlowInfo(); List implicitReceivers = Lists.newArrayList(); scope.getImplicitReceiversHierarchy(implicitReceivers); // AutoCastUtils.getAutoCastVariants(bindingContext, dataFlowInfo, receiverToCast) - if (explicitReceiver.exists()) { - List variantsForExplicitReceiver = autoCastService.getVariantsForReceiver(explicitReceiver); + if (receiver.exists()) { + List variantsForExplicitReceiver = autoCastService.getVariantsForReceiver(receiver); - Collection> extensionFunctions = convertWithImpliedThis(variantsForExplicitReceiver, getExtensionsByName(scope, name)); + Collection> extensionFunctions = convertWithImpliedThis(scope, variantsForExplicitReceiver, getExtensionsByName(scope, name)); List> nonlocals = Lists.newArrayList(); List> locals = Lists.newArrayList(); //noinspection unchecked,RedundantTypeArguments @@ -153,7 +154,7 @@ import static org.jetbrains.jet.lang.resolve.scopes.receivers.ReceiverDescriptor addTask(result, call, nonlocals, dataFlowInfo); } else { - Collection> functions = convertWithImpliedThis(Collections.singletonList(explicitReceiver), getNonExtensionsByName(scope, name)); + Collection> functions = convertWithImpliedThis(scope, Collections.singletonList(receiver), getNonExtensionsByName(scope, name)); List> nonlocals = Lists.newArrayList(); List> locals = Lists.newArrayList(); @@ -183,7 +184,7 @@ import static org.jetbrains.jet.lang.resolve.scopes.receivers.ReceiverDescriptor for (D extension : descriptors) { ResolvedCall resolvedCall = ResolvedCall.create(extension); resolvedCall.setThisObject(thisObject); - resolvedCall.setReceiverParameter(receiverParameter); + resolvedCall.setReceiverArgument(receiverParameter); result.add(resolvedCall); } } @@ -191,33 +192,36 @@ import static org.jetbrains.jet.lang.resolve.scopes.receivers.ReceiverDescriptor // return result; } - private Collection> convertWithImpliedThis(Iterable receiverParameters, Collection descriptors) { + public static Collection> convertWithImpliedThis(JetScope scope, Iterable receiverParameters, Collection descriptors) { Collection> result = Lists.newArrayList(); for (ReceiverDescriptor receiverParameter : receiverParameters) { for (D extension : descriptors) { ResolvedCall resolvedCall = ResolvedCall.create(extension); - resolvedCall.setReceiverParameter(receiverParameter); - setImpliedThis(resolvedCall); - result.add(resolvedCall); + resolvedCall.setReceiverArgument(receiverParameter); + if (setImpliedThis(scope, resolvedCall)) { + result.add(resolvedCall); + } } } return result; } - private void setImpliedThis(ResolvedCall resolvedCall) { - ReceiverDescriptor thisObject; - DeclarationDescriptor containingDeclaration = resolvedCall.getCandidateDescriptor().getContainingDeclaration(); - if (containingDeclaration instanceof ClassDescriptor) { - ClassDescriptor classDescriptor = (ClassDescriptor) containingDeclaration; - thisObject = classDescriptor.getImplicitReceiver(); + private static boolean setImpliedThis(@NotNull JetScope scope, ResolvedCall resolvedCall) { + ReceiverDescriptor expectedThisObject = DescriptorUtils.getExpectedThisObject(resolvedCall.getCandidateDescriptor()); + if (!expectedThisObject.exists()) return true; + List receivers = Lists.newArrayList(); + scope.getImplicitReceiversHierarchy(receivers); + for (ReceiverDescriptor receiver : receivers) { + if (JetTypeChecker.INSTANCE.isSubtypeOf(receiver.getType(), expectedThisObject.getType())) { + // TODO : Autocasts & nullability + resolvedCall.setThisObject(expectedThisObject); + return true; + } } - else { - thisObject = NO_RECEIVER; - } - resolvedCall.setThisObject(thisObject); + return false; } - private void addTask(@NotNull List> result, @NotNull Call call, @NotNull Collection> candidates, @NotNull DataFlowInfo dataFlowInfo) { + private void addTask(@NotNull List> result, @NotNull Call call, @NotNull Collection> candidates, @NotNull DataFlowInfo dataFlowInfo) { if (candidates.isEmpty()) return; result.add(new ResolutionTask(candidates, call, dataFlowInfo)); } diff --git a/compiler/frontend/src/org/jetbrains/jet/lang/resolve/calls/TaskPrioritizers.java b/compiler/frontend/src/org/jetbrains/jet/lang/resolve/calls/TaskPrioritizers.java index 943493fa76c..292cfd760d1 100644 --- a/compiler/frontend/src/org/jetbrains/jet/lang/resolve/calls/TaskPrioritizers.java +++ b/compiler/frontend/src/org/jetbrains/jet/lang/resolve/calls/TaskPrioritizers.java @@ -27,7 +27,7 @@ public class TaskPrioritizers { Set functions = Sets.newLinkedHashSet(scope.getFunctions(name)); for (Iterator iterator = functions.iterator(); iterator.hasNext(); ) { FunctionDescriptor functionDescriptor = iterator.next(); - if (functionDescriptor.getReceiver().exists()) { + if (functionDescriptor.getReceiverParameter().exists()) { iterator.remove(); } } @@ -53,7 +53,7 @@ public class TaskPrioritizers { Set extensionFunctions = Sets.newHashSet(scope.getFunctions(name)); for (Iterator iterator = extensionFunctions.iterator(); iterator.hasNext(); ) { FunctionDescriptor descriptor = iterator.next(); - if (!descriptor.getReceiver().exists()) { + if (!descriptor.getReceiverParameter().exists()) { iterator.remove(); } } @@ -71,11 +71,11 @@ public class TaskPrioritizers { private void addVariableAsFunction(JetScope scope, String name, Set functions, boolean receiverNeeded) { VariableDescriptor variable = scope.getVariable(name); - if (variable != null && !variable.getReceiver().exists()) { + if (variable != null && !variable.getReceiverParameter().exists()) { JetType outType = variable.getOutType(); if (outType != null && JetStandardClasses.isFunctionType(outType)) { VariableAsFunctionDescriptor functionDescriptor = VariableAsFunctionDescriptor.create(variable); - if ((functionDescriptor.getReceiver().exists()) == receiverNeeded) { + if ((functionDescriptor.getReceiverParameter().exists()) == receiverNeeded) { functions.add(functionDescriptor); } } @@ -89,7 +89,7 @@ public class TaskPrioritizers { @Override protected Collection getNonExtensionsByName(JetScope scope, String name) { VariableDescriptor variable = scope.getVariable(name); - if (variable != null && !variable.getReceiver().exists()) { + if (variable != null && !variable.getReceiverParameter().exists()) { return Collections.singleton(variable); } return Collections.emptyList(); @@ -109,7 +109,7 @@ public class TaskPrioritizers { @Override protected Collection getExtensionsByName(JetScope scope, String name) { VariableDescriptor variable = scope.getVariable(name); - if (variable != null && variable.getReceiver().exists()) { + if (variable != null && variable.getReceiverParameter().exists()) { return Collections.singleton(variable); } return Collections.emptyList(); diff --git a/compiler/frontend/src/org/jetbrains/jet/lang/resolve/calls/TracingStrategy.java b/compiler/frontend/src/org/jetbrains/jet/lang/resolve/calls/TracingStrategy.java index 2a8e81158c1..a7e7096b2de 100644 --- a/compiler/frontend/src/org/jetbrains/jet/lang/resolve/calls/TracingStrategy.java +++ b/compiler/frontend/src/org/jetbrains/jet/lang/resolve/calls/TracingStrategy.java @@ -5,6 +5,7 @@ import org.jetbrains.jet.lang.descriptors.CallableDescriptor; import org.jetbrains.jet.lang.descriptors.ValueParameterDescriptor; import org.jetbrains.jet.lang.resolve.BindingTrace; import org.jetbrains.jet.lang.resolve.scopes.receivers.ReceiverDescriptor; +import org.jetbrains.jet.lang.types.JetType; import java.util.Collection; import java.util.Set; @@ -26,6 +27,9 @@ import java.util.Set; @Override public void missingReceiver(@NotNull BindingTrace trace, @NotNull ReceiverDescriptor expectedReceiver) {} + @Override + public void wrongReceiverType(@NotNull BindingTrace trace, @NotNull ReceiverDescriptor receiverParameter, @NotNull ReceiverDescriptor receiverArgument) {} + @Override public void noReceiverAllowed(@NotNull BindingTrace trace) {} @@ -46,6 +50,12 @@ import java.util.Set; @Override 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) {} }; void bindReference(@NotNull BindingTrace trace, @NotNull ResolvedCall resolvedCall); @@ -56,6 +66,8 @@ import java.util.Set; 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 noValueForParameter(@NotNull BindingTrace trace, @NotNull ValueParameterDescriptor valueParameter); @@ -69,4 +81,8 @@ import java.util.Set; void instantiationOfAbstractClass(@NotNull BindingTrace trace); void typeInferenceFailed(@NotNull BindingTrace trace); + + void unsafeCall(@NotNull BindingTrace trace, @NotNull JetType type); + + void unnecessarySafeCall(@NotNull BindingTrace trace, @NotNull JetType type); } diff --git a/compiler/frontend/src/org/jetbrains/jet/lang/resolve/calls/ValueArgumentsToParametersMapper.java b/compiler/frontend/src/org/jetbrains/jet/lang/resolve/calls/ValueArgumentsToParametersMapper.java index 25ffed7b609..6fff221d1e1 100644 --- a/compiler/frontend/src/org/jetbrains/jet/lang/resolve/calls/ValueArgumentsToParametersMapper.java +++ b/compiler/frontend/src/org/jetbrains/jet/lang/resolve/calls/ValueArgumentsToParametersMapper.java @@ -7,6 +7,7 @@ import org.jetbrains.jet.lang.descriptors.CallableDescriptor; import org.jetbrains.jet.lang.descriptors.ValueParameterDescriptor; import org.jetbrains.jet.lang.psi.*; import org.jetbrains.jet.lang.resolve.TemporaryBindingTrace; +import org.jetbrains.jet.lang.resolve.scopes.receivers.ReceiverDescriptor; import org.jetbrains.jet.lang.types.CallMaker; import java.util.List; @@ -38,7 +39,7 @@ import static org.jetbrains.jet.lang.resolve.BindingContext.REFERENCE_TARGET; parameterByName.put(valueParameter.getName(), valueParameter); } - List valueArguments = task.getValueArguments(); + List valueArguments = task.getCall().getValueArguments(); boolean error = false; boolean someNamed = false; @@ -103,7 +104,7 @@ import static org.jetbrains.jet.lang.resolve.BindingContext.REFERENCE_TARGET; } } - List functionLiteralArguments = task.getFunctionLiteralArguments(); + List functionLiteralArguments = task.getCall().getFunctionLiteralArguments(); if (!functionLiteralArguments.isEmpty()) { 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; } diff --git a/compiler/frontend/src/org/jetbrains/jet/lang/types/CallMaker.java b/compiler/frontend/src/org/jetbrains/jet/lang/types/CallMaker.java index ff80325db84..4aa1f807e2d 100644 --- a/compiler/frontend/src/org/jetbrains/jet/lang/types/CallMaker.java +++ b/compiler/frontend/src/org/jetbrains/jet/lang/types/CallMaker.java @@ -127,6 +127,10 @@ public class CallMaker { 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 argumentExpressions) { diff --git a/compiler/frontend/src/org/jetbrains/jet/lang/types/JetTypeInferrer.java b/compiler/frontend/src/org/jetbrains/jet/lang/types/JetTypeInferrer.java index 1cf27e2b015..d890e7dc64f 100644 --- a/compiler/frontend/src/org/jetbrains/jet/lang/types/JetTypeInferrer.java +++ b/compiler/frontend/src/org/jetbrains/jet/lang/types/JetTypeInferrer.java @@ -222,7 +222,7 @@ public class JetTypeInferrer { // if (receiverType != null && callee != null) { // boolean namespaceType = receiverType instanceof NamespaceType; // boolean nullableReceiver = !namespaceType && receiverType.isNullable(); -// ReceiverDescriptor calleeReceiver = callee.getReceiver(); +// ReceiverDescriptor calleeReceiver = callee.getReceiverParameter(); // boolean calleeForbidsNullableReceiver = !calleeReceiver.exists() || !calleeReceiver.getType().isNullable(); // // IElementType operationSign = operationTokenNode.getElementType(); @@ -1275,7 +1275,7 @@ public class JetTypeInferrer { } else if (declarationDescriptor instanceof FunctionDescriptor) { FunctionDescriptor functionDescriptor = (FunctionDescriptor) declarationDescriptor; - thisReceiver = functionDescriptor.getReceiver(); + thisReceiver = functionDescriptor.getReceiverParameter(); } else { throw new UnsupportedOperationException(); // TODO @@ -1289,7 +1289,7 @@ public class JetTypeInferrer { if (psiElement instanceof JetFunctionLiteralExpression) { DeclarationDescriptor declarationDescriptor = context.trace.getBindingContext().get(BindingContext.DECLARATION_TO_DESCRIPTOR, psiElement); if (declarationDescriptor instanceof FunctionDescriptor) { - thisReceiver = ((FunctionDescriptor) declarationDescriptor).getReceiver(); + thisReceiver = ((FunctionDescriptor) declarationDescriptor).getReceiverParameter(); if (thisReceiver.exists()) { context.trace.record(REFERENCE_TARGET, targetLabel, declarationDescriptor); context.trace.record(REFERENCE_TARGET, expression.getThisReference(), declarationDescriptor); diff --git a/compiler/frontend/src/org/jetbrains/jet/resolve/DescriptorRenderer.java b/compiler/frontend/src/org/jetbrains/jet/resolve/DescriptorRenderer.java index 4e3542c197e..2a52a1d3f54 100644 --- a/compiler/frontend/src/org/jetbrains/jet/resolve/DescriptorRenderer.java +++ b/compiler/frontend/src/org/jetbrains/jet/resolve/DescriptorRenderer.java @@ -186,7 +186,7 @@ public class DescriptorRenderer implements Renderer { renderModality(descriptor.getModality(), builder); String typeString = renderPropertyPrefixAndComputeTypeString( builder, descriptor.getTypeParameters(), - descriptor.getReceiver(), + descriptor.getReceiverParameter(), descriptor.getOutType(), descriptor.getInType()); renderName(descriptor, builder); @@ -215,7 +215,7 @@ public class DescriptorRenderer implements Renderer { builder.append(renderKeyword("fun")).append(" "); renderTypeParameters(descriptor.getTypeParameters(), builder); - ReceiverDescriptor receiver = descriptor.getReceiver(); + ReceiverDescriptor receiver = descriptor.getReceiverParameter(); if (receiver.exists()) { builder.append(escape(renderType(receiver.getType()))).append("."); }