diff --git a/compiler/frontend/src/org/jetbrains/jet/lang/diagnostics/Errors.java b/compiler/frontend/src/org/jetbrains/jet/lang/diagnostics/Errors.java index 553a6f2e167..dbf8fbd70fc 100644 --- a/compiler/frontend/src/org/jetbrains/jet/lang/diagnostics/Errors.java +++ b/compiler/frontend/src/org/jetbrains/jet/lang/diagnostics/Errors.java @@ -320,6 +320,8 @@ public interface Errors { DiagnosticFactory2 CONFLICTING_OVERLOADS = DiagnosticFactory2.create(ERROR, DECLARATION); + DiagnosticFactory2 FUNCTION_EXPECTED = DiagnosticFactory2.create(ERROR); + DiagnosticFactory2 FUNCTION_CALL_EXPECTED = DiagnosticFactory2.create(ERROR); DiagnosticFactory3 RESULT_TYPE_MISMATCH = DiagnosticFactory3.create(ERROR); DiagnosticFactory3 UNSAFE_INFIX_CALL = DiagnosticFactory3.create(ERROR); diff --git a/compiler/frontend/src/org/jetbrains/jet/lang/diagnostics/rendering/DefaultErrorMessages.java b/compiler/frontend/src/org/jetbrains/jet/lang/diagnostics/rendering/DefaultErrorMessages.java index bd148492f1f..c2f601fb248 100644 --- a/compiler/frontend/src/org/jetbrains/jet/lang/diagnostics/rendering/DefaultErrorMessages.java +++ b/compiler/frontend/src/org/jetbrains/jet/lang/diagnostics/rendering/DefaultErrorMessages.java @@ -23,6 +23,7 @@ import org.jetbrains.jet.lang.diagnostics.Errors; import org.jetbrains.jet.lang.psi.JetExpression; import org.jetbrains.jet.lang.psi.JetSimpleNameExpression; import org.jetbrains.jet.lang.psi.JetTypeConstraint; +import org.jetbrains.jet.lang.types.ErrorUtils; import org.jetbrains.jet.lang.types.JetType; import org.jetbrains.jet.lexer.JetKeywordToken; import org.jetbrains.jet.resolve.DescriptorRenderer; @@ -364,6 +365,22 @@ public class DefaultErrorMessages { MAP.put(CONFLICTING_OVERLOADS, "{1} is already defined in ''{0}''", DescriptorRenderer.TEXT, TO_STRING); + MAP.put(FUNCTION_EXPECTED, "Expression ''{0}''{1} cannot be invoked as a function", ELEMENT_TEXT, new Renderer() { + @NotNull + @Override + public String render(@NotNull JetType type) { + if (ErrorUtils.isErrorType(type)) return ""; + return " of type '" + type.toString() + "'"; + } + }); + MAP.put(FUNCTION_CALL_EXPECTED, "Function invocation ''{0}({1})'' expected", ELEMENT_TEXT,new Renderer() { + @NotNull + @Override + public String render(@NotNull Boolean hasValueParameters) { + return hasValueParameters ? "..." : ""; + } + }); + MAP.put(RESULT_TYPE_MISMATCH, "{0} must return {1} but returns {2}", TO_STRING, RENDER_TYPE, RENDER_TYPE); MAP.put(UNSAFE_INFIX_CALL, 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 389db065a2d..9734d55e89c 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 @@ -124,7 +124,13 @@ public class CallResolver { } @NotNull - public OverloadResolutionResults resolveFunctionCall(BindingTrace trace, JetScope scope, Call call, JetType expectedType, DataFlowInfo dataFlowInfo) { + public OverloadResolutionResults resolveFunctionCall( + @NotNull BindingTrace trace, + @NotNull JetScope scope, + @NotNull Call call, + @NotNull JetType expectedType, + @NotNull DataFlowInfo dataFlowInfo) { + return resolveFunctionCall(BasicResolutionContext.create(trace, scope, call, expectedType, dataFlowInfo)); } diff --git a/compiler/frontend/src/org/jetbrains/jet/lang/types/expressions/BasicExpressionTypingVisitor.java b/compiler/frontend/src/org/jetbrains/jet/lang/types/expressions/BasicExpressionTypingVisitor.java index a4759062e3a..375823e9608 100644 --- a/compiler/frontend/src/org/jetbrains/jet/lang/types/expressions/BasicExpressionTypingVisitor.java +++ b/compiler/frontend/src/org/jetbrains/jet/lang/types/expressions/BasicExpressionTypingVisitor.java @@ -595,50 +595,62 @@ public class BasicExpressionTypingVisitor extends ExpressionTypingVisitor { } @Nullable - public JetType getSelectorReturnType(@NotNull ReceiverDescriptor receiver, @Nullable ASTNode callOperationNode, @NotNull JetExpression selectorExpression, @NotNull ExpressionTypingContext context) { - if (selectorExpression instanceof JetCallExpression) { - JetCallExpression callExpression = (JetCallExpression) selectorExpression; - FunctionDescriptor functionDescriptor = context.resolveCall(receiver, callOperationNode, callExpression); - checkSuper(receiver, functionDescriptor, context.trace, selectorExpression); - return functionDescriptor != null ? functionDescriptor.getReturnType() : null; - } - else if (selectorExpression instanceof JetSimpleNameExpression) { - JetSimpleNameExpression nameExpression = (JetSimpleNameExpression) selectorExpression; + private FunctionDescriptor getFunctionDescriptor(@NotNull Call call, @NotNull JetExpression callExpression, @NotNull ReceiverDescriptor receiver, + @NotNull ExpressionTypingContext context, @NotNull boolean[] result) { - TemporaryBindingTrace temporaryTrace = TemporaryBindingTrace.create(context.trace); - OverloadResolutionResults resolutionResult = context.replaceBindingTrace(temporaryTrace).resolveSimpleProperty(receiver, callOperationNode, nameExpression); - if (resolutionResult.isSuccess()) { - temporaryTrace.commit(); - VariableDescriptor resultingDescriptor = resolutionResult.getResultingDescriptor(); - checkSuper(receiver, resultingDescriptor, context.trace, selectorExpression); - return resultingDescriptor.getType(); - } - if (resolutionResult.isSingleResult()) { - temporaryTrace.commit(); - return resolutionResult.getResultingDescriptor().getReturnType(); - } - if (resolutionResult.isAmbiguity()) { - temporaryTrace.commit(); - return null; - } + OverloadResolutionResults results = context.resolveFunctionCall(call); + if (!results.isNothing()) { + checkSuper(receiver, results, context.trace, callExpression); + result[0] = true; + return results.isSingleResult() ? results.getResultingDescriptor() : null; + } + result[0] = false; + return null; + } + + @Nullable + private JetType getVariableType(@NotNull JetSimpleNameExpression nameExpression, @NotNull ReceiverDescriptor receiver, + @Nullable ASTNode callOperationNode, @NotNull ExpressionTypingContext context, @NotNull boolean[] result) { + + TemporaryBindingTrace temporaryTrace = TemporaryBindingTrace.create(context.trace); + OverloadResolutionResults resolutionResult = context.replaceBindingTrace(temporaryTrace).resolveSimpleProperty(receiver, callOperationNode, nameExpression); + if (!resolutionResult.isNothing()) { + temporaryTrace.commit(); + checkSuper(receiver, resolutionResult, context.trace, nameExpression); + result[0] = true; + return resolutionResult.isSingleResult() ? resolutionResult.getResultingDescriptor().getReturnType() : null; + } + + ExpressionTypingContext newContext = receiver.exists() + ? context.replaceScope(receiver.getType().getMemberScope()) + : context; + JetType jetType = lookupNamespaceOrClassObject(nameExpression, nameExpression.getReferencedNameAsName(), newContext); + if (jetType != null) { // Uncommitted changes in temp context context.trace.record(RESOLUTION_SCOPE, nameExpression, context.scope); if (context.dataFlowInfo.hasTypeInfoConstraints()) { context.trace.record(NON_DEFAULT_EXPRESSION_DATA_FLOW, nameExpression, context.dataFlowInfo); } - - ExpressionTypingContext newContext = receiver.exists() - ? context.replaceScope(receiver.getType().getMemberScope()) - : context; - JetType jetType = lookupNamespaceOrClassObject(nameExpression, nameExpression.getReferencedNameAsName(), newContext); - if (jetType == null) { - context.trace.report(UNRESOLVED_REFERENCE.on(nameExpression)); - } - + result[0] = true; return jetType; } + result[0] = false; + return null; + } + + @Nullable + public JetType getSelectorReturnType(@NotNull ReceiverDescriptor receiver, @Nullable ASTNode callOperationNode, @NotNull JetExpression selectorExpression, @NotNull ExpressionTypingContext context) { + if (selectorExpression instanceof JetCallExpression) { + + return getCallExpressionType((JetCallExpression) selectorExpression, receiver, callOperationNode, context); + } + else if (selectorExpression instanceof JetSimpleNameExpression) { + + return getSimpleNameExpressionType((JetSimpleNameExpression) selectorExpression, receiver, callOperationNode, context); + } else if (selectorExpression instanceof JetQualifiedExpression) { + JetQualifiedExpression qualifiedExpression = (JetQualifiedExpression) selectorExpression; JetExpression newReceiverExpression = qualifiedExpression.getReceiverExpression(); JetType newReceiverType = getSelectorReturnType(receiver, callOperationNode, newReceiverExpression, context.replaceExpectedType(NO_EXPECTED_TYPE)); @@ -653,11 +665,70 @@ public class BasicExpressionTypingVisitor extends ExpressionTypingVisitor { return null; } - private static void checkSuper(@NotNull ReceiverDescriptor receiverDescriptor, @Nullable DeclarationDescriptor member, @NotNull BindingTrace trace, @NotNull JetExpression expression) { + @Nullable + private JetType getSimpleNameExpressionType(@NotNull JetSimpleNameExpression nameExpression, @NotNull ReceiverDescriptor receiver, + @Nullable ASTNode callOperationNode, @NotNull ExpressionTypingContext context) { + + boolean[] result = new boolean[1]; + + TemporaryBindingTrace traceForVariable = TemporaryBindingTrace.create(context.trace); + JetType type = getVariableType(nameExpression, receiver, callOperationNode, context.replaceBindingTrace(traceForVariable), result); + if (result[0]) { + traceForVariable.commit(); + return type; + } + + Call call = CallMaker.makeCall(nameExpression, receiver, callOperationNode, nameExpression, Collections.emptyList()); + TemporaryBindingTrace traceForFunction = TemporaryBindingTrace.create(context.trace); + FunctionDescriptor functionDescriptor = getFunctionDescriptor(call, nameExpression, receiver, context, result); + if (result[0]) { + traceForFunction.commit(); + boolean hasValueParameters = functionDescriptor == null || functionDescriptor.getValueParameters().size() > 0; + context.trace.report(Errors.FUNCTION_CALL_EXPECTED.on(nameExpression, nameExpression, hasValueParameters)); + return functionDescriptor != null ? functionDescriptor.getReturnType() : null; + } + + traceForVariable.commit(); + return null; + } + + @Nullable + private JetType getCallExpressionType(@NotNull JetCallExpression callExpression, @NotNull ReceiverDescriptor receiver, + @Nullable ASTNode callOperationNode, @NotNull ExpressionTypingContext context) { + + boolean[] result = new boolean[1]; + Call call = CallMaker.makeCall(receiver, callOperationNode, callExpression); + + TemporaryBindingTrace traceForFunction = TemporaryBindingTrace.create(context.trace); + FunctionDescriptor functionDescriptor = getFunctionDescriptor(call, callExpression, receiver, + context.replaceBindingTrace(traceForFunction), result); + if (result[0]) { + traceForFunction.commit(); + return functionDescriptor != null ? functionDescriptor.getReturnType() : null; + } + + JetExpression calleeExpression = callExpression.getCalleeExpression(); + if (calleeExpression instanceof JetSimpleNameExpression) { + TemporaryBindingTrace traceForVariable = TemporaryBindingTrace.create(context.trace); + JetType type = getVariableType((JetSimpleNameExpression) calleeExpression, receiver, callOperationNode, + context.replaceBindingTrace(traceForVariable), result); + if (result[0]) { + traceForVariable.commit(); + context.trace.report(Errors.FUNCTION_EXPECTED.on((JetReferenceExpression) calleeExpression, callExpression, type != null ? type : ErrorUtils.createErrorType(""))); + return null; + } + } + traceForFunction.commit(); + return null; + } + + private static void checkSuper(@NotNull ReceiverDescriptor receiverDescriptor, @NotNull OverloadResolutionResults results, @NotNull BindingTrace trace, @NotNull JetExpression expression) { + if (!results.isSingleResult()) return; if (!(receiverDescriptor instanceof ExpressionReceiver)) return; JetExpression receiver = ((ExpressionReceiver) receiverDescriptor).getExpression(); - if (receiver instanceof JetSuperExpression && member instanceof MemberDescriptor) { - if (((MemberDescriptor) member).getModality() == Modality.ABSTRACT) { + CallableDescriptor descriptor = results.getResultingDescriptor(); + if (receiver instanceof JetSuperExpression && descriptor instanceof MemberDescriptor) { + if (((MemberDescriptor) descriptor).getModality() == Modality.ABSTRACT) { trace.report(ABSTRACT_SUPER_CALL.on(expression)); } } @@ -665,8 +736,7 @@ public class BasicExpressionTypingVisitor extends ExpressionTypingVisitor { @Override public JetType visitCallExpression(JetCallExpression expression, ExpressionTypingContext context) { - FunctionDescriptor functionDescriptor = context.resolveCall(NO_RECEIVER, null, expression); - JetType expressionType = functionDescriptor != null ? functionDescriptor.getReturnType() : null; + JetType expressionType = getCallExpressionType(expression, NO_RECEIVER, null, context); return DataFlowUtils.checkType(expressionType, expression, context); } @@ -732,7 +802,7 @@ public class BasicExpressionTypingVisitor extends ExpressionTypingVisitor { ExpressionReceiver receiver = new ExpressionReceiver(baseExpression, type); // Resolve the operation reference - OverloadResolutionResults resolutionResults = context.resolveCallWithGivenNameToDescriptor( + OverloadResolutionResults resolutionResults = context.resolveCallWithGivenName( CallMaker.makeCall(receiver, expression), expression.getOperationReference(), name); @@ -929,7 +999,7 @@ public class BasicExpressionTypingVisitor extends ExpressionTypingVisitor { public boolean checkInExpression(JetElement callElement, @NotNull JetSimpleNameExpression operationSign, @Nullable JetExpression left, @NotNull JetExpression right, ExpressionTypingContext context) { Name name = Name.identifier("contains"); ExpressionReceiver receiver = safeGetExpressionReceiver(facade, right, context.replaceExpectedType(NO_EXPECTED_TYPE)); - OverloadResolutionResults resolutionResult = context.resolveCallWithGivenNameToDescriptor( + OverloadResolutionResults resolutionResult = context.resolveCallWithGivenName( CallMaker.makeCallWithExpressions(callElement, receiver, null, operationSign, Collections.singletonList(left)), operationSign, name); @@ -994,7 +1064,7 @@ public class BasicExpressionTypingVisitor extends ExpressionTypingVisitor { @NotNull /*package*/ OverloadResolutionResults getResolutionResultsForBinaryCall(JetScope scope, Name name, ExpressionTypingContext context, JetBinaryExpression binaryExpression, ExpressionReceiver receiver) { // ExpressionReceiver receiver = safeGetExpressionReceiver(facade, binaryExpression.getLeft(), context.replaceScope(scope)); - return context.replaceScope(scope).resolveCallWithGivenNameToDescriptor( + return context.replaceScope(scope).resolveCallWithGivenName( CallMaker.makeCall(receiver, binaryExpression), binaryExpression.getOperationReference(), name diff --git a/compiler/frontend/src/org/jetbrains/jet/lang/types/expressions/ExpressionTypingContext.java b/compiler/frontend/src/org/jetbrains/jet/lang/types/expressions/ExpressionTypingContext.java index 406dc22dae8..56397e99b70 100644 --- a/compiler/frontend/src/org/jetbrains/jet/lang/types/expressions/ExpressionTypingContext.java +++ b/compiler/frontend/src/org/jetbrains/jet/lang/types/expressions/ExpressionTypingContext.java @@ -19,10 +19,13 @@ package org.jetbrains.jet.lang.types.expressions; import com.intellij.lang.ASTNode; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; +import org.jetbrains.jet.lang.descriptors.CallableDescriptor; import org.jetbrains.jet.lang.descriptors.FunctionDescriptor; import org.jetbrains.jet.lang.descriptors.VariableDescriptor; +import org.jetbrains.jet.lang.diagnostics.Errors; import org.jetbrains.jet.lang.psi.*; import org.jetbrains.jet.lang.resolve.BindingTrace; +import org.jetbrains.jet.lang.resolve.TemporaryBindingTrace; import org.jetbrains.jet.lang.resolve.calls.BasicResolutionContext; import org.jetbrains.jet.lang.resolve.calls.CallMaker; import org.jetbrains.jet.lang.resolve.calls.OverloadResolutionResults; @@ -34,6 +37,7 @@ import org.jetbrains.jet.lang.resolve.scopes.receivers.ReceiverDescriptor; import org.jetbrains.jet.lang.types.JetType; import org.jetbrains.jet.lang.types.TypeUtils; +import java.util.Collections; import java.util.List; import java.util.Map; @@ -57,17 +61,6 @@ public class ExpressionTypingContext { labelResolver, trace, scope, dataFlowInfo, expectedType, namespacesAllowed); } -// @NotNull -// public static ExpressionTypingContext newRootContext( -// @NotNull JetSemanticServices semanticServices, -// @NotNull BindingTrace trace, -// @NotNull JetScope scope, -// @NotNull DataFlowInfo dataFlowInfo, -// @NotNull JetType expectedType, -// @NotNull JetType expectedReturnType) { -// return newContext(semanticServices, new HashMap(), new HashMap>(), new LabelResolver(), trace, scope, dataFlowInfo, expectedType, expectedReturnType); -// } -// public final ExpressionTypingServices expressionTypingServices; public final BindingTrace trace; public final JetScope scope; @@ -155,15 +148,8 @@ public class ExpressionTypingContext { } @NotNull - public OverloadResolutionResults resolveCallWithGivenNameToDescriptor(@NotNull Call call, @NotNull JetReferenceExpression functionReference, @NotNull Name name) { - return resolveCallWithGivenName(call, functionReference, name); -// return results == null ? null : results.getResultingDescriptor(); - } - - @Nullable - public FunctionDescriptor resolveCall(@NotNull ReceiverDescriptor receiver, @Nullable ASTNode callOperationNode, @NotNull JetCallExpression callExpression) { - OverloadResolutionResults results = expressionTypingServices.getCallResolver().resolveFunctionCall(trace, scope, CallMaker.makeCall(receiver, callOperationNode, callExpression), expectedType, dataFlowInfo); - return results.isSingleResult() ? results.getResultingDescriptor() : null; + public OverloadResolutionResults resolveFunctionCall(@NotNull Call call) { + return expressionTypingServices.getCallResolver().resolveFunctionCall(makeResolutionContext(call)); } @NotNull @@ -176,5 +162,4 @@ public class ExpressionTypingContext { public OverloadResolutionResults resolveExactSignature(@NotNull ReceiverDescriptor receiver, @NotNull Name name, @NotNull List parameterTypes) { return expressionTypingServices.getCallResolver().resolveExactSignature(scope, receiver, name, parameterTypes); } - } diff --git a/compiler/testData/diagnostics/tests/incompleteCode/kt2014.jet b/compiler/testData/diagnostics/tests/incompleteCode/kt2014.jet new file mode 100644 index 00000000000..e57d8b9853f --- /dev/null +++ b/compiler/testData/diagnostics/tests/incompleteCode/kt2014.jet @@ -0,0 +1,20 @@ +//KT-2014 Better diagnostic when using property syntax to call a method +package c + +class Foo { + fun prop() : Int = 1 + fun bar(i: Int) : Int = i + + val a : Int = 1 +} + +fun x(f : Foo) { + f.prop + f.bar + + f.a() + c() + R() +} + +object R {} \ No newline at end of file diff --git a/compiler/testData/diagnostics/tests/incompleteCode/senselessComparisonWithNull.jet b/compiler/testData/diagnostics/tests/incompleteCode/senselessComparisonWithNull.jet index 1653843d3d8..c68923aad7b 100644 --- a/compiler/testData/diagnostics/tests/incompleteCode/senselessComparisonWithNull.jet +++ b/compiler/testData/diagnostics/tests/incompleteCode/senselessComparisonWithNull.jet @@ -1,5 +1,5 @@ package d -fun foo(a : IntArray) { - if (null == a() +fun foo(a : IntArray) { + if (null == a() } \ No newline at end of file