From 95a2afcd1987974ec4a5a31aaf622ebb33cb5c93 Mon Sep 17 00:00:00 2001 From: Andrey Breslav Date: Thu, 3 Nov 2011 17:37:24 +0300 Subject: [PATCH] Support for function-valued expressions --- .../descriptors/FunctionDescriptorUtil.java | 9 ++++ .../VariableAsFunctionDescriptor.java | 6 +-- .../jet/lang/diagnostics/Errors.java | 1 + .../jet/lang/resolve/calls/CallResolver.java | 34 ++++++++++++- .../quick/ExtensionsCalledOnSuper.jet | 2 +- .../quick/FunctionCalleeExpressions.jet | 50 +++++++++++++++++++ .../quick/NamedArgumentsAndDefaultValues.jet | 6 +-- stdlib/ktSrc/StandardLibrary.kt | 2 +- 8 files changed, 98 insertions(+), 12 deletions(-) create mode 100644 compiler/testData/checkerWithErrorTypes/quick/FunctionCalleeExpressions.jet 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 cb193b40b69..32e19f286de 100644 --- a/compiler/frontend/src/org/jetbrains/jet/lang/descriptors/FunctionDescriptorUtil.java +++ b/compiler/frontend/src/org/jetbrains/jet/lang/descriptors/FunctionDescriptorUtil.java @@ -83,4 +83,13 @@ public class FunctionDescriptorUtil { return parameterScope; } + public static void initializeFromFunctionType(@NotNull FunctionDescriptorImpl functionDescriptor, @NotNull JetType functionType) { + assert JetStandardClasses.isFunctionType(functionType); + functionDescriptor.initialize(JetStandardClasses.getReceiverType(functionType), + ReceiverDescriptor.NO_RECEIVER, + Collections.emptyList(), + JetStandardClasses.getValueParameters(functionDescriptor, functionType), + JetStandardClasses.getReturnType(functionType), + Modality.FINAL, Visibility.LOCAL); + } } diff --git a/compiler/frontend/src/org/jetbrains/jet/lang/descriptors/VariableAsFunctionDescriptor.java b/compiler/frontend/src/org/jetbrains/jet/lang/descriptors/VariableAsFunctionDescriptor.java index 25b713cd607..fb9b6fcabae 100644 --- a/compiler/frontend/src/org/jetbrains/jet/lang/descriptors/VariableAsFunctionDescriptor.java +++ b/compiler/frontend/src/org/jetbrains/jet/lang/descriptors/VariableAsFunctionDescriptor.java @@ -2,8 +2,6 @@ package org.jetbrains.jet.lang.descriptors; import org.jetbrains.annotations.NotNull; import org.jetbrains.jet.lang.descriptors.annotations.AnnotationDescriptor; -import org.jetbrains.jet.lang.resolve.scopes.receivers.ReceiverDescriptor; -import org.jetbrains.jet.lang.types.JetStandardClasses; import org.jetbrains.jet.lang.types.JetType; import java.util.Collections; @@ -15,9 +13,8 @@ public class VariableAsFunctionDescriptor extends FunctionDescriptorImpl { public static VariableAsFunctionDescriptor create(@NotNull VariableDescriptor variableDescriptor) { JetType outType = variableDescriptor.getOutType(); assert outType != null; - assert JetStandardClasses.isFunctionType(outType); VariableAsFunctionDescriptor result = new VariableAsFunctionDescriptor(variableDescriptor); - result.initialize(JetStandardClasses.getReceiverType(outType), ReceiverDescriptor.NO_RECEIVER, Collections.emptyList(), JetStandardClasses.getValueParameters(result, outType), JetStandardClasses.getReturnType(outType), Modality.FINAL, Visibility.LOCAL); + FunctionDescriptorUtil.initializeFromFunctionType(result, outType); return result; } @@ -25,7 +22,6 @@ public class VariableAsFunctionDescriptor extends FunctionDescriptorImpl { private VariableAsFunctionDescriptor(VariableDescriptor variableDescriptor) { super(variableDescriptor.getContainingDeclaration(), Collections.emptyList(), variableDescriptor.getName()); -// super(variableDescriptor.getContainingDeclaration(), Collections.emptyList(), variableDescriptor.getName()); this.variableDescriptor = variableDescriptor; } 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 11680129eb7..fbec7d4bf64 100644 --- a/compiler/frontend/src/org/jetbrains/jet/lang/diagnostics/Errors.java +++ b/compiler/frontend/src/org/jetbrains/jet/lang/diagnostics/Errors.java @@ -196,6 +196,7 @@ public interface Errors { AmbiguousDescriptorDiagnosticFactory ITERATOR_AMBIGUITY = AmbiguousDescriptorDiagnosticFactory.create("Method 'iterator()' is ambiguous for this expression: {0}"); ParameterizedDiagnosticFactory1 COMPARE_TO_TYPE_MISMATCH = ParameterizedDiagnosticFactory1.create(ERROR, "compareTo() must return Int, but returns {0}"); + ParameterizedDiagnosticFactory1 CALLEE_NOT_A_FUNCTION = ParameterizedDiagnosticFactory1.create(ERROR, "Expecting a function type, but found {0}"); SimpleDiagnosticFactory RETURN_IN_FUNCTION_WITH_EXPRESSION_BODY = SimpleDiagnosticFactory.create(ERROR, "Returns are not allowed for functions with expression body. Use block body in '{...}'"); SimpleDiagnosticFactory NO_RETURN_IN_FUNCTION_WITH_BLOCK_BODY = SimpleDiagnosticFactory.create(ERROR, "A 'return' expression required in a function with a block body ('{...}')"); 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 f722e29c6b2..5341725067d 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 @@ -9,6 +9,7 @@ import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; import org.jetbrains.jet.lang.JetSemanticServices; import org.jetbrains.jet.lang.descriptors.*; +import org.jetbrains.jet.lang.descriptors.annotations.AnnotationDescriptor; import org.jetbrains.jet.lang.psi.*; import org.jetbrains.jet.lang.resolve.*; import org.jetbrains.jet.lang.resolve.calls.autocasts.AutoCastServiceImpl; @@ -173,8 +174,29 @@ public class CallResolver { } prioritizedTasks = Collections.singletonList(new ResolutionTask(ResolvedCallImpl.convertCollection(constructors), call, DataFlowInfo.EMPTY)); } + else if (calleeExpression != null) { + // Here we handle the case where the callee expression must be something of type function, e.g. (foo.bar())(1, 2) + ExpressionTypingServices typingServices = new ExpressionTypingServices(semanticServices, trace); + JetType calleeType = typingServices.safeGetType(scope, calleeExpression, NO_EXPECTED_TYPE);// We are actually expecting a function, but there seems to be no easy way of expressing this + + if (!JetStandardClasses.isFunctionType(calleeType)) { + checkTypesWithNoCallee(trace, scope, call); + if (!ErrorUtils.isErrorType(calleeType)) { + trace.report(CALLEE_NOT_A_FUNCTION.on(calleeExpression, calleeType)); + } + return null; + } + + FunctionDescriptorImpl functionDescriptor = new FunctionDescriptorImpl(scope.getContainingDeclaration(), Collections.emptyList(), "for expression " + calleeExpression.getText()); + FunctionDescriptorUtil.initializeFromFunctionType(functionDescriptor, calleeType); + ResolvedCallImpl resolvedCall = ResolvedCallImpl.create(functionDescriptor); + prioritizedTasks = Collections.singletonList(new ResolutionTask( + Collections.singleton(resolvedCall), call, dataFlowInfo)); + functionReference = new JetReferenceExpression(calleeExpression.getNode()) { + }; + } else { - trace.report(UNSUPPORTED.on(call.getCallNode(), "Type argument inference is not supported for this callee: " + calleeExpression)); + checkTypesWithNoCallee(trace, scope, call); return null; } } @@ -233,7 +255,15 @@ public class CallResolver { @Override public void noValueForParameter(@NotNull BindingTrace trace, @NotNull ValueParameterDescriptor valueParameter) { - trace.report(NO_VALUE_FOR_PARAMETER.on(reference, valueParameter)); + PsiElement reportOn; + JetValueArgumentList valueArgumentList = call.getValueArgumentList(); + if (valueArgumentList != null) { + reportOn = valueArgumentList; + } + else { + reportOn = reference; + } + trace.report(NO_VALUE_FOR_PARAMETER.on(reportOn, valueParameter)); } @Override diff --git a/compiler/testData/checkerWithErrorTypes/quick/ExtensionsCalledOnSuper.jet b/compiler/testData/checkerWithErrorTypes/quick/ExtensionsCalledOnSuper.jet index fe072bcc632..775ec9bef9e 100644 --- a/compiler/testData/checkerWithErrorTypes/quick/ExtensionsCalledOnSuper.jet +++ b/compiler/testData/checkerWithErrorTypes/quick/ExtensionsCalledOnSuper.jet @@ -16,6 +16,6 @@ class C : T { super.foo() // OK super.bar() // Error super.buzz() // OK, resolved to a member - super.buzz1() // Resolved to a member, but error: no parameter passed where required + super.buzz1() // Resolved to a member, but error: no parameter passed where required } } \ No newline at end of file diff --git a/compiler/testData/checkerWithErrorTypes/quick/FunctionCalleeExpressions.jet b/compiler/testData/checkerWithErrorTypes/quick/FunctionCalleeExpressions.jet new file mode 100644 index 00000000000..581493762d3 --- /dev/null +++ b/compiler/testData/checkerWithErrorTypes/quick/FunctionCalleeExpressions.jet @@ -0,0 +1,50 @@ +namespace foo + +fun Any.foo() : fun() : Unit { + return {} +} + +fun Any.foo1() : fun(i : Int) : Unit { + return {} +} + +fun foo2() : fun(i : fun()) : Unit { + return {} +} + +fun fooT1(t : T) : fun() : T { + return {t} +} + +fun fooT2() : fun(t : T) : T { + return {it} +} + +fun main(args : Array) { + args.foo()() + args.foo1()() + a.foo1()() + a.foo1()(a) + + args.foo1()(1) + args.foo1()("1") + a.foo1()("1") + a.foo1()(a) + + foo2()({}) + foo2(){} + (foo2()){} + (foo2()){x => } + foo2()({x => }) + + val a = fooT1(1)() + a : Int + + val b = fooT2()(1) + b : Int + fooT2()(1) // : Any? + + 1() + 1{} + 1(){} +} \ No newline at end of file diff --git a/compiler/testData/checkerWithErrorTypes/quick/NamedArgumentsAndDefaultValues.jet b/compiler/testData/checkerWithErrorTypes/quick/NamedArgumentsAndDefaultValues.jet index 9e75a3ae821..f1d42c6b60d 100644 --- a/compiler/testData/checkerWithErrorTypes/quick/NamedArgumentsAndDefaultValues.jet +++ b/compiler/testData/checkerWithErrorTypes/quick/NamedArgumentsAndDefaultValues.jet @@ -14,10 +14,10 @@ fun test() { foo(1, "", "") bar(z = "") - bar() - bar("") + bar() + bar("") bar(1, 1, "") bar(1, 1, "") bar(1, z = "") - bar(1, zz = "", zz.foo) + bar(1, zz = "", zz.foo) } \ No newline at end of file diff --git a/stdlib/ktSrc/StandardLibrary.kt b/stdlib/ktSrc/StandardLibrary.kt index 85c09473979..bd0fab6b7d9 100644 --- a/stdlib/ktSrc/StandardLibrary.kt +++ b/stdlib/ktSrc/StandardLibrary.kt @@ -26,7 +26,7 @@ namespace io { fun println(message : Float) { System.out?.println(message) } fun println(message : Double) { System.out?.println(message) } - private var systemIn : InputStream? = null // Unfortunately, System.in may change Yt pf xn + private var systemIn : InputStream? = null // Unfortunately, System.in may change private var stdin : BufferedReader? = null // This may introduce leaks of system.in objects... fun readLine() : String? {