From a532b6db115b4b56b5eeb54f41df9c5a408f0d87 Mon Sep 17 00:00:00 2001 From: Andrey Breslav Date: Mon, 28 Feb 2011 15:09:32 +0300 Subject: [PATCH] TopDown resolve for functions --- .../lang/resolve/ClassDescriptorResolver.java | 1 + .../resolve/MutableFunctionDescriptor.java | 5 ++++ .../jet/lang/resolve/OverloadDomain.java | 20 ++++++++++--- .../jet/lang/resolve/OverloadResolver.java | 11 ++------ .../jet/lang/types/FunctionDescriptor.java | 12 +++++++- .../lang/types/FunctionDescriptorImpl.java | 10 +++++++ .../lang/types/FunctionDescriptorUtil.java | 1 + .../jet/lang/types/JetTypeChecker.java | 26 +++++++++++++++-- .../LazySubstitutingFunctionDescriptor.java | 5 ++++ idea/testData/resolve/Basic.jet | 1 + .../jetbrains/jet/resolve/JetResolveTest.java | 28 ++++++++++++------- 11 files changed, 94 insertions(+), 26 deletions(-) diff --git a/idea/src/org/jetbrains/jet/lang/resolve/ClassDescriptorResolver.java b/idea/src/org/jetbrains/jet/lang/resolve/ClassDescriptorResolver.java index 33dc8d5cf8f..711fe1a62b5 100644 --- a/idea/src/org/jetbrains/jet/lang/resolve/ClassDescriptorResolver.java +++ b/idea/src/org/jetbrains/jet/lang/resolve/ClassDescriptorResolver.java @@ -131,6 +131,7 @@ public class ClassDescriptorResolver { return new FunctionDescriptorImpl( function, + null, AttributeResolver.INSTANCE.resolveAttributes(function.getModifierList()), function.getName(), typeParameterDescriptors, diff --git a/idea/src/org/jetbrains/jet/lang/resolve/MutableFunctionDescriptor.java b/idea/src/org/jetbrains/jet/lang/resolve/MutableFunctionDescriptor.java index a36c65f17f4..eaeb16161fd 100644 --- a/idea/src/org/jetbrains/jet/lang/resolve/MutableFunctionDescriptor.java +++ b/idea/src/org/jetbrains/jet/lang/resolve/MutableFunctionDescriptor.java @@ -29,4 +29,9 @@ public class MutableFunctionDescriptor extends MutableDeclarationDescriptor impl public Type getUnsubstitutedReturnType() { throw new UnsupportedOperationException(); // TODO } + + @Override + public FunctionDescriptor getOriginal() { + throw new UnsupportedOperationException(); // TODO + } } diff --git a/idea/src/org/jetbrains/jet/lang/resolve/OverloadDomain.java b/idea/src/org/jetbrains/jet/lang/resolve/OverloadDomain.java index a8b645821bf..a76abeaa51e 100644 --- a/idea/src/org/jetbrains/jet/lang/resolve/OverloadDomain.java +++ b/idea/src/org/jetbrains/jet/lang/resolve/OverloadDomain.java @@ -2,6 +2,7 @@ package org.jetbrains.jet.lang.resolve; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; +import org.jetbrains.jet.lang.types.FunctionDescriptor; import org.jetbrains.jet.lang.types.Type; import java.util.List; @@ -14,25 +15,36 @@ public interface OverloadDomain { OverloadDomain EMPTY = new OverloadDomain() { @Nullable @Override - public Type getReturnTypeForNamedArguments(@NotNull List typeArguments, @NotNull Map valueArgumentTypes, @Nullable Type functionLiteralArgumentType) { + public FunctionDescriptor getFunctionDescriptorForNamedArguments(@NotNull List typeArguments, @NotNull Map valueArgumentTypes, @Nullable Type functionLiteralArgumentType) { return null; } @Nullable @Override - public Type getReturnTypeForPositionedArguments(@NotNull List typeArguments, @NotNull List positionedValueArgumentTypes) { + public FunctionDescriptor getFunctionDescriptorForPositionedArguments(@NotNull List typeArguments, @NotNull List positionedValueArgumentTypes) { return null; } }; + /** + * @param typeArguments + * @param valueArgumentTypes + * @param functionLiteralArgumentType + * @return A function descriptor with NO type parameters (they are already substituted), or null + */ @Nullable - Type getReturnTypeForNamedArguments( + FunctionDescriptor getFunctionDescriptorForNamedArguments( @NotNull List typeArguments, @NotNull Map valueArgumentTypes, @Nullable Type functionLiteralArgumentType); + /** + * @param typeArguments + * @param positionedValueArgumentTypes + * @return A function descriptor with NO type parameters (they are already substituted), or null + */ @Nullable - Type getReturnTypeForPositionedArguments( + FunctionDescriptor getFunctionDescriptorForPositionedArguments( @NotNull List typeArguments, @NotNull List positionedValueArgumentTypes); } diff --git a/idea/src/org/jetbrains/jet/lang/resolve/OverloadResolver.java b/idea/src/org/jetbrains/jet/lang/resolve/OverloadResolver.java index 4380f675264..0516180b7b8 100644 --- a/idea/src/org/jetbrains/jet/lang/resolve/OverloadResolver.java +++ b/idea/src/org/jetbrains/jet/lang/resolve/OverloadResolver.java @@ -19,11 +19,6 @@ public class OverloadResolver { @NotNull public OverloadDomain getOverloadDomain(Type receiverType, @NotNull JetScope outerScope, @NotNull String name) { - return getOverloadDomain(TypeCheckerTrace.DUMMY, receiverType, outerScope, name); - } - - @NotNull - public OverloadDomain getOverloadDomain(@NotNull TypeCheckerTrace trace, @Nullable Type receiverType, @NotNull JetScope outerScope, @NotNull String name) { // TODO : extension lookup JetScope scope = receiverType == null ? outerScope : receiverType.getMemberScope(); @@ -35,7 +30,7 @@ public class OverloadResolver { return new OverloadDomain() { @Override - public Type getReturnTypeForPositionedArguments(@NotNull final List typeArguments, @NotNull List positionedValueArgumentTypes) { + public FunctionDescriptor getFunctionDescriptorForPositionedArguments(@NotNull final List typeArguments, @NotNull List positionedValueArgumentTypes) { Collection possiblyApplicableFunctions = functionGroup.getPossiblyApplicableFunctions(typeArguments, positionedValueArgumentTypes); if (possiblyApplicableFunctions.isEmpty()) { return null; @@ -86,14 +81,14 @@ public class OverloadResolver { if (applicable.size() == 0) { return null; } else if (applicable.size() == 1) { - return applicable.get(0).getUnsubstitutedReturnType(); + return applicable.get(0); } else { throw new UnsupportedOperationException(); } } @Override - public Type getReturnTypeForNamedArguments(@NotNull List typeArguments, @NotNull Map valueArgumentTypes, @Nullable Type functionLiteralArgumentType) { + public FunctionDescriptor getFunctionDescriptorForNamedArguments(@NotNull List typeArguments, @NotNull Map valueArgumentTypes, @Nullable Type functionLiteralArgumentType) { throw new UnsupportedOperationException(); // TODO } }; diff --git a/idea/src/org/jetbrains/jet/lang/types/FunctionDescriptor.java b/idea/src/org/jetbrains/jet/lang/types/FunctionDescriptor.java index 6ecc529aef7..72902232c47 100644 --- a/idea/src/org/jetbrains/jet/lang/types/FunctionDescriptor.java +++ b/idea/src/org/jetbrains/jet/lang/types/FunctionDescriptor.java @@ -1,13 +1,14 @@ package org.jetbrains.jet.lang.types; import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; import java.util.List; /** * @author abreslav */ -public interface FunctionDescriptor extends Annotated, Named { +public interface FunctionDescriptor extends DeclarationDescriptor { @NotNull List getTypeParameters(); @@ -16,4 +17,13 @@ public interface FunctionDescriptor extends Annotated, Named { @NotNull Type getUnsubstitutedReturnType(); + + /** + * @return The descriptor that corresponds to the original declaration of this function. + * A descriptor can be obtained from its original by substituting type arguments (of the declaring class + * or of the function itself). + * null if the current descriptor is original itself + */ + @Nullable + FunctionDescriptor getOriginal(); } diff --git a/idea/src/org/jetbrains/jet/lang/types/FunctionDescriptorImpl.java b/idea/src/org/jetbrains/jet/lang/types/FunctionDescriptorImpl.java index bcc4e52e1fa..7b340bdbd92 100644 --- a/idea/src/org/jetbrains/jet/lang/types/FunctionDescriptorImpl.java +++ b/idea/src/org/jetbrains/jet/lang/types/FunctionDescriptorImpl.java @@ -1,6 +1,7 @@ package org.jetbrains.jet.lang.types; import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; import org.jetbrains.jet.lang.psi.JetFunction; import java.util.*; @@ -15,15 +16,19 @@ public class FunctionDescriptorImpl extends DeclarationDescriptorImpl unsubstitutedValueParameters; @NotNull private final Type unsubstitutedReturnType; + @Nullable + private final FunctionDescriptor original; public FunctionDescriptorImpl( JetFunction psiElement, + @Nullable FunctionDescriptor original, @NotNull List attributes, String name, @NotNull List typeParameters, @NotNull List unsubstitutedValueParameters, @NotNull Type unsubstitutedReturnType) { super(psiElement, attributes, name); + this.original = original; this.typeParameters = typeParameters; this.unsubstitutedValueParameters = unsubstitutedValueParameters; this.unsubstitutedReturnType = unsubstitutedReturnType; @@ -47,4 +52,9 @@ public class FunctionDescriptorImpl extends DeclarationDescriptorImpl typeArguments, @NotNull FunctionDescriptor functionDescriptor) { return new FunctionDescriptorImpl( ResolveUtil.getJetFunction(functionDescriptor), + functionDescriptor, // TODO : substitute functionDescriptor.getAttributes(), functionDescriptor.getName(), diff --git a/idea/src/org/jetbrains/jet/lang/types/JetTypeChecker.java b/idea/src/org/jetbrains/jet/lang/types/JetTypeChecker.java index 2dc0fc7bdc9..e4755f543c3 100644 --- a/idea/src/org/jetbrains/jet/lang/types/JetTypeChecker.java +++ b/idea/src/org/jetbrains/jet/lang/types/JetTypeChecker.java @@ -299,7 +299,7 @@ public class JetTypeChecker { // TODO : check that all are named throw new UnsupportedOperationException(); // TODO -// result[0] = overloadDomain.getReturnTypeForNamedArguments(typeArguments, valueArguments, functionLiteralArgument); +// result[0] = overloadDomain.getFunctionDescriptorForNamedArguments(typeArguments, valueArguments, functionLiteralArgument); } else { List positionedValueArguments = new ArrayList(); for (JetArgument argument : valueArguments) { @@ -319,7 +319,10 @@ public class JetTypeChecker { valueArgumentTypes.add(getType(scope, valueArgument, false)); } - result[0] = overloadDomain.getReturnTypeForPositionedArguments(types, valueArgumentTypes); + FunctionDescriptor functionDescriptor = overloadDomain.getFunctionDescriptorForPositionedArguments(types, valueArgumentTypes); + if (functionDescriptor != null) { + result[0] = functionDescriptor.getUnsubstitutedReturnType(); + } } } @@ -334,6 +337,7 @@ public class JetTypeChecker { private OverloadDomain getOverloadDomain(final JetScope scope, JetExpression calleeExpression) { final OverloadDomain[] result = new OverloadDomain[1]; + final JetReferenceExpression[] reference = new JetReferenceExpression[1]; calleeExpression.accept(new JetVisitor() { @Override @@ -357,6 +361,7 @@ public class JetTypeChecker { Type receiverType = getType(scope, expression.getReceiverExpression(), false); result[0] = OverloadResolver.INSTANCE.getOverloadDomain(receiverType, scope, referenceExpression.getReferencedName()); + reference[0] = referenceExpression; } else { throw new UnsupportedOperationException(); // TODO } @@ -366,6 +371,7 @@ public class JetTypeChecker { public void visitReferenceExpression(JetReferenceExpression expression) { // a -- create a hierarchical lookup domain for this.a result[0] = OverloadResolver.INSTANCE.getOverloadDomain(null, scope, expression.getReferencedName()); + reference[0] = expression; } @Override @@ -379,7 +385,21 @@ public class JetTypeChecker { throw new IllegalArgumentException("Unsupported element: " + elem); } }); - return result[0]; + return new OverloadDomain() { + @Override + public FunctionDescriptor getFunctionDescriptorForNamedArguments(@NotNull List typeArguments, @NotNull Map valueArgumentTypes, @Nullable Type functionLiteralArgumentType) { + FunctionDescriptor descriptor = result[0].getFunctionDescriptorForNamedArguments(typeArguments, valueArgumentTypes, functionLiteralArgumentType); + trace.recordResolutionResult(reference[0], descriptor); + return descriptor; + } + + @Override + public FunctionDescriptor getFunctionDescriptorForPositionedArguments(@NotNull List typeArguments, @NotNull List positionedValueArgumentTypes) { + FunctionDescriptor descriptor = result[0].getFunctionDescriptorForPositionedArguments(typeArguments, positionedValueArgumentTypes); + trace.recordResolutionResult(reference[0], descriptor); + return descriptor; + } + }; } private Type getBlockReturnedType(@NotNull JetScope outerScope, List block) { diff --git a/idea/src/org/jetbrains/jet/lang/types/LazySubstitutingFunctionDescriptor.java b/idea/src/org/jetbrains/jet/lang/types/LazySubstitutingFunctionDescriptor.java index 0c108ef8e85..885c405c428 100644 --- a/idea/src/org/jetbrains/jet/lang/types/LazySubstitutingFunctionDescriptor.java +++ b/idea/src/org/jetbrains/jet/lang/types/LazySubstitutingFunctionDescriptor.java @@ -58,6 +58,11 @@ public class LazySubstitutingFunctionDescriptor implements FunctionDescriptor { return TypeSubstitutor.INSTANCE.substitute(substitutionContext, functionDescriptor.getUnsubstitutedReturnType(), Variance.OUT_VARIANCE); } + @Override + public FunctionDescriptor getOriginal() { + return functionDescriptor; + } + @Override public List getAttributes() { // TODO : Substitute? diff --git a/idea/testData/resolve/Basic.jet b/idea/testData/resolve/Basic.jet index e0544e69b9d..8bd26115014 100644 --- a/idea/testData/resolve/Basic.jet +++ b/idea/testData/resolve/Basic.jet @@ -4,6 +4,7 @@ class A { } fun foo(a : Int) = a + fun fooB() = foo(1) fun foo() : Int = 1 fun foo1() : B = new B() } diff --git a/idea/tests/org/jetbrains/jet/resolve/JetResolveTest.java b/idea/tests/org/jetbrains/jet/resolve/JetResolveTest.java index 1f3bf90828a..6d71ff5e1f3 100644 --- a/idea/tests/org/jetbrains/jet/resolve/JetResolveTest.java +++ b/idea/tests/org/jetbrains/jet/resolve/JetResolveTest.java @@ -40,16 +40,12 @@ public class JetResolveTest extends LightDaemonAnalyzerTestCase { ClassDescriptor classB = membersOfA.getClass("B"); assertNotNull(classB); - FunctionGroup foo = membersOfA.getFunctionGroup("foo"); - assertFalse(foo.isEmpty()); + FunctionGroup fooFG = membersOfA.getFunctionGroup("foo"); + assertFalse(fooFG.isEmpty()); - OverloadDomain overloadsForFoo = OverloadResolver.INSTANCE.getOverloadDomain(null, membersOfA, "foo"); - Type fooType = overloadsForFoo.getReturnTypeForPositionedArguments(Collections.emptyList(), Collections.emptyList()); - assertEquals(JetStandardClasses.getIntType(), fooType); - - OverloadDomain overloadsForFoo1 = OverloadResolver.INSTANCE.getOverloadDomain(null, membersOfA, "foo1"); - Type foo1Type = overloadsForFoo1.getReturnTypeForPositionedArguments(Collections.emptyList(), Collections.emptyList()); - assertEquals(new TypeImpl(classB), foo1Type); + assertReturnType(membersOfA, "foo", JetStandardClasses.getIntType()); + assertReturnType(membersOfA, "foo1", new TypeImpl(classB)); + assertReturnType(membersOfA, "fooB", JetStandardClasses.getIntType()); JetFunction fooDecl = (JetFunction) classADecl.getDeclarations().get(1); Type expressionType = bindingContext.getExpressionType(fooDecl.getBodyExpression()); @@ -58,6 +54,12 @@ public class JetResolveTest extends LightDaemonAnalyzerTestCase { DeclarationDescriptor resolve = bindingContext.resolve((JetReferenceExpression) fooDecl.getBodyExpression()); assertSame(bindingContext.getFunctionDescriptor(fooDecl).getUnsubstitutedValueParameters().get(0), resolve); + JetFunction fooBDecl = (JetFunction) classADecl.getDeclarations().get(2); + JetCallExpression fooBBody = (JetCallExpression) fooBDecl.getBodyExpression(); + JetReferenceExpression refToFoo = (JetReferenceExpression) fooBBody.getCalleeExpression(); + FunctionDescriptor mustBeFoo = (FunctionDescriptor) bindingContext.resolve(refToFoo); + assertSame(bindingContext.getFunctionDescriptor(fooDecl), mustBeFoo.getOriginal()); + JetClass classCDecl = (JetClass) declarations.get(1); ClassDescriptor classC = bindingContext.getClassDescriptor(classCDecl); assertNotNull(classC); @@ -69,7 +71,13 @@ public class JetResolveTest extends LightDaemonAnalyzerTestCase { assertNotNull(classC_B); assertNotSame(classC_B, classB); assertEquals(classC.getTypeConstructor(), classC_B.getTypeConstructor().getSupertypes().iterator().next().getConstructor()); + } - + private void assertReturnType(JetScope membersOfA, String foo, Type returnType) { + OverloadDomain overloadsForFoo = OverloadResolver.INSTANCE.getOverloadDomain(null, membersOfA, foo); + FunctionDescriptor descriptorForFoo = overloadsForFoo.getFunctionDescriptorForPositionedArguments(Collections.emptyList(), Collections.emptyList()); + assertNotNull(descriptorForFoo); + Type fooType = descriptorForFoo.getUnsubstitutedReturnType(); + assertEquals(returnType, fooType); } } \ No newline at end of file