Support for function-valued expressions

This commit is contained in:
Andrey Breslav
2011-11-03 17:37:24 +03:00
parent 6fcf0729f3
commit 95a2afcd19
8 changed files with 98 additions and 12 deletions
@@ -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.<TypeParameterDescriptor>emptyList(),
JetStandardClasses.getValueParameters(functionDescriptor, functionType),
JetStandardClasses.getReturnType(functionType),
Modality.FINAL, Visibility.LOCAL);
}
}
@@ -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.<TypeParameterDescriptor>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.<AnnotationDescriptor>emptyList(), variableDescriptor.getName());
// super(variableDescriptor.getContainingDeclaration(), Collections.<AnnotationDescriptor>emptyList(), variableDescriptor.getName());
this.variableDescriptor = variableDescriptor;
}
@@ -196,6 +196,7 @@ public interface Errors {
AmbiguousDescriptorDiagnosticFactory ITERATOR_AMBIGUITY = AmbiguousDescriptorDiagnosticFactory.create("Method 'iterator()' is ambiguous for this expression: {0}");
ParameterizedDiagnosticFactory1<JetType> COMPARE_TO_TYPE_MISMATCH = ParameterizedDiagnosticFactory1.create(ERROR, "compareTo() must return Int, but returns {0}");
ParameterizedDiagnosticFactory1<JetType> 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 ('{...}')");
@@ -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<FunctionDescriptor>(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.<AnnotationDescriptor>emptyList(), "for expression " + calleeExpression.getText());
FunctionDescriptorUtil.initializeFromFunctionType(functionDescriptor, calleeType);
ResolvedCallImpl<FunctionDescriptor> resolvedCall = ResolvedCallImpl.<FunctionDescriptor>create(functionDescriptor);
prioritizedTasks = Collections.singletonList(new ResolutionTask<FunctionDescriptor>(
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
@@ -16,6 +16,6 @@ class C : T {
super.foo() // OK
<!SUPER_IS_NOT_AN_EXPRESSION!>super<!>.bar() // Error
super.buzz() // OK, resolved to a member
super.<!NO_VALUE_FOR_PARAMETER!>buzz1<!>() // Resolved to a member, but error: no parameter passed where required
super.buzz1<!NO_VALUE_FOR_PARAMETER!>()<!> // Resolved to a member, but error: no parameter passed where required
}
}
@@ -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 : T) : fun() : T {
return {t}
}
fun fooT2<T>() : fun(t : T) : T {
return {it}
}
fun main(args : Array<String>) {
args.foo()()
args.foo1()<!NO_VALUE_FOR_PARAMETER!>()<!>
<!UNRESOLVED_REFERENCE!>a<!>.foo1()()
<!UNRESOLVED_REFERENCE!>a<!>.foo1()(<!UNRESOLVED_REFERENCE!>a<!>)
args.foo1()(1)
args.foo1()(<!TYPE_MISMATCH!>"1"<!>)
<!UNRESOLVED_REFERENCE!>a<!>.foo1()("1")
<!UNRESOLVED_REFERENCE!>a<!>.foo1()(<!UNRESOLVED_REFERENCE!>a<!>)
foo2()({})
foo2()<!TOO_MANY_ARGUMENTS!>{}<!>
(foo2()){}
(foo2())<!TYPE_MISMATCH!>{<!CANNOT_INFER_PARAMETER_TYPE!>x<!> => }<!>
foo2()(<!TYPE_MISMATCH!>{<!CANNOT_INFER_PARAMETER_TYPE!>x<!> => }<!>)
val a = fooT1(1)()
a : Int
val b = fooT2<Int>()(1)
b : Int
fooT2()(1) // : Any?
<!CALLEE_NOT_A_FUNCTION!>1<!>()
<!CALLEE_NOT_A_FUNCTION!>1<!>{}
<!CALLEE_NOT_A_FUNCTION!>1<!>(){}
}
@@ -14,10 +14,10 @@ fun test() {
foo(1, "", <!TOO_MANY_ARGUMENTS!>""<!>)
bar(z = "")
<!NO_VALUE_FOR_PARAMETER!>bar<!>()
<!NO_VALUE_FOR_PARAMETER!>bar<!>("")
bar<!NO_VALUE_FOR_PARAMETER!>()<!>
bar<!NO_VALUE_FOR_PARAMETER!>("")<!>
bar(1, 1, "")
bar(1, 1, "")
bar(1, <!MIXING_NAMED_AND_POSITIONED_ARGUMENTS!>z<!> = "")
<!NO_VALUE_FOR_PARAMETER!>bar<!>(1, <!UNRESOLVED_REFERENCE, MIXING_NAMED_AND_POSITIONED_ARGUMENTS!>zz<!> = "", <!MIXING_NAMED_AND_POSITIONED_ARGUMENTS!><!UNRESOLVED_REFERENCE!>zz<!>.foo<!>)
bar<!NO_VALUE_FOR_PARAMETER!>(1, <!UNRESOLVED_REFERENCE, MIXING_NAMED_AND_POSITIONED_ARGUMENTS!>zz<!> = "", <!MIXING_NAMED_AND_POSITIONED_ARGUMENTS!><!UNRESOLVED_REFERENCE!>zz<!>.foo<!>)<!>
}
+1 -1
View File
@@ -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? {