TopDown resolve for functions

This commit is contained in:
Andrey Breslav
2011-02-28 15:09:32 +03:00
parent 4e0b6deda5
commit a532b6db11
11 changed files with 94 additions and 26 deletions
@@ -131,6 +131,7 @@ public class ClassDescriptorResolver {
return new FunctionDescriptorImpl( return new FunctionDescriptorImpl(
function, function,
null,
AttributeResolver.INSTANCE.resolveAttributes(function.getModifierList()), AttributeResolver.INSTANCE.resolveAttributes(function.getModifierList()),
function.getName(), function.getName(),
typeParameterDescriptors, typeParameterDescriptors,
@@ -29,4 +29,9 @@ public class MutableFunctionDescriptor extends MutableDeclarationDescriptor impl
public Type getUnsubstitutedReturnType() { public Type getUnsubstitutedReturnType() {
throw new UnsupportedOperationException(); // TODO throw new UnsupportedOperationException(); // TODO
} }
@Override
public FunctionDescriptor getOriginal() {
throw new UnsupportedOperationException(); // TODO
}
} }
@@ -2,6 +2,7 @@ package org.jetbrains.jet.lang.resolve;
import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable; import org.jetbrains.annotations.Nullable;
import org.jetbrains.jet.lang.types.FunctionDescriptor;
import org.jetbrains.jet.lang.types.Type; import org.jetbrains.jet.lang.types.Type;
import java.util.List; import java.util.List;
@@ -14,25 +15,36 @@ public interface OverloadDomain {
OverloadDomain EMPTY = new OverloadDomain() { OverloadDomain EMPTY = new OverloadDomain() {
@Nullable @Nullable
@Override @Override
public Type getReturnTypeForNamedArguments(@NotNull List<Type> typeArguments, @NotNull Map<String, Type> valueArgumentTypes, @Nullable Type functionLiteralArgumentType) { public FunctionDescriptor getFunctionDescriptorForNamedArguments(@NotNull List<Type> typeArguments, @NotNull Map<String, Type> valueArgumentTypes, @Nullable Type functionLiteralArgumentType) {
return null; return null;
} }
@Nullable @Nullable
@Override @Override
public Type getReturnTypeForPositionedArguments(@NotNull List<Type> typeArguments, @NotNull List<Type> positionedValueArgumentTypes) { public FunctionDescriptor getFunctionDescriptorForPositionedArguments(@NotNull List<Type> typeArguments, @NotNull List<Type> positionedValueArgumentTypes) {
return null; return null;
} }
}; };
/**
* @param typeArguments
* @param valueArgumentTypes
* @param functionLiteralArgumentType
* @return A function descriptor with NO type parameters (they are already substituted), or null
*/
@Nullable @Nullable
Type getReturnTypeForNamedArguments( FunctionDescriptor getFunctionDescriptorForNamedArguments(
@NotNull List<Type> typeArguments, @NotNull List<Type> typeArguments,
@NotNull Map<String, Type> valueArgumentTypes, @NotNull Map<String, Type> valueArgumentTypes,
@Nullable Type functionLiteralArgumentType); @Nullable Type functionLiteralArgumentType);
/**
* @param typeArguments
* @param positionedValueArgumentTypes
* @return A function descriptor with NO type parameters (they are already substituted), or null
*/
@Nullable @Nullable
Type getReturnTypeForPositionedArguments( FunctionDescriptor getFunctionDescriptorForPositionedArguments(
@NotNull List<Type> typeArguments, @NotNull List<Type> typeArguments,
@NotNull List<Type> positionedValueArgumentTypes); @NotNull List<Type> positionedValueArgumentTypes);
} }
@@ -19,11 +19,6 @@ public class OverloadResolver {
@NotNull @NotNull
public OverloadDomain getOverloadDomain(Type receiverType, @NotNull JetScope outerScope, @NotNull String name) { 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 // TODO : extension lookup
JetScope scope = receiverType == null ? outerScope : receiverType.getMemberScope(); JetScope scope = receiverType == null ? outerScope : receiverType.getMemberScope();
@@ -35,7 +30,7 @@ public class OverloadResolver {
return new OverloadDomain() { return new OverloadDomain() {
@Override @Override
public Type getReturnTypeForPositionedArguments(@NotNull final List<Type> typeArguments, @NotNull List<Type> positionedValueArgumentTypes) { public FunctionDescriptor getFunctionDescriptorForPositionedArguments(@NotNull final List<Type> typeArguments, @NotNull List<Type> positionedValueArgumentTypes) {
Collection<FunctionDescriptor> possiblyApplicableFunctions = functionGroup.getPossiblyApplicableFunctions(typeArguments, positionedValueArgumentTypes); Collection<FunctionDescriptor> possiblyApplicableFunctions = functionGroup.getPossiblyApplicableFunctions(typeArguments, positionedValueArgumentTypes);
if (possiblyApplicableFunctions.isEmpty()) { if (possiblyApplicableFunctions.isEmpty()) {
return null; return null;
@@ -86,14 +81,14 @@ public class OverloadResolver {
if (applicable.size() == 0) { if (applicable.size() == 0) {
return null; return null;
} else if (applicable.size() == 1) { } else if (applicable.size() == 1) {
return applicable.get(0).getUnsubstitutedReturnType(); return applicable.get(0);
} else { } else {
throw new UnsupportedOperationException(); throw new UnsupportedOperationException();
} }
} }
@Override @Override
public Type getReturnTypeForNamedArguments(@NotNull List<Type> typeArguments, @NotNull Map<String, Type> valueArgumentTypes, @Nullable Type functionLiteralArgumentType) { public FunctionDescriptor getFunctionDescriptorForNamedArguments(@NotNull List<Type> typeArguments, @NotNull Map<String, Type> valueArgumentTypes, @Nullable Type functionLiteralArgumentType) {
throw new UnsupportedOperationException(); // TODO throw new UnsupportedOperationException(); // TODO
} }
}; };
@@ -1,13 +1,14 @@
package org.jetbrains.jet.lang.types; package org.jetbrains.jet.lang.types;
import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import java.util.List; import java.util.List;
/** /**
* @author abreslav * @author abreslav
*/ */
public interface FunctionDescriptor extends Annotated, Named { public interface FunctionDescriptor extends DeclarationDescriptor {
@NotNull @NotNull
List<TypeParameterDescriptor> getTypeParameters(); List<TypeParameterDescriptor> getTypeParameters();
@@ -16,4 +17,13 @@ public interface FunctionDescriptor extends Annotated, Named {
@NotNull @NotNull
Type getUnsubstitutedReturnType(); 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();
} }
@@ -1,6 +1,7 @@
package org.jetbrains.jet.lang.types; package org.jetbrains.jet.lang.types;
import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import org.jetbrains.jet.lang.psi.JetFunction; import org.jetbrains.jet.lang.psi.JetFunction;
import java.util.*; import java.util.*;
@@ -15,15 +16,19 @@ public class FunctionDescriptorImpl extends DeclarationDescriptorImpl<JetFunctio
private final List<ValueParameterDescriptor> unsubstitutedValueParameters; private final List<ValueParameterDescriptor> unsubstitutedValueParameters;
@NotNull @NotNull
private final Type unsubstitutedReturnType; private final Type unsubstitutedReturnType;
@Nullable
private final FunctionDescriptor original;
public FunctionDescriptorImpl( public FunctionDescriptorImpl(
JetFunction psiElement, JetFunction psiElement,
@Nullable FunctionDescriptor original,
@NotNull List<Attribute> attributes, @NotNull List<Attribute> attributes,
String name, String name,
@NotNull List<TypeParameterDescriptor> typeParameters, @NotNull List<TypeParameterDescriptor> typeParameters,
@NotNull List<ValueParameterDescriptor> unsubstitutedValueParameters, @NotNull List<ValueParameterDescriptor> unsubstitutedValueParameters,
@NotNull Type unsubstitutedReturnType) { @NotNull Type unsubstitutedReturnType) {
super(psiElement, attributes, name); super(psiElement, attributes, name);
this.original = original;
this.typeParameters = typeParameters; this.typeParameters = typeParameters;
this.unsubstitutedValueParameters = unsubstitutedValueParameters; this.unsubstitutedValueParameters = unsubstitutedValueParameters;
this.unsubstitutedReturnType = unsubstitutedReturnType; this.unsubstitutedReturnType = unsubstitutedReturnType;
@@ -47,4 +52,9 @@ public class FunctionDescriptorImpl extends DeclarationDescriptorImpl<JetFunctio
return unsubstitutedReturnType; return unsubstitutedReturnType;
} }
@Override
public FunctionDescriptor getOriginal() {
return original;
}
} }
@@ -79,6 +79,7 @@ public class FunctionDescriptorUtil {
public static FunctionDescriptor substituteFunctionDescriptor(@NotNull List<Type> typeArguments, @NotNull FunctionDescriptor functionDescriptor) { public static FunctionDescriptor substituteFunctionDescriptor(@NotNull List<Type> typeArguments, @NotNull FunctionDescriptor functionDescriptor) {
return new FunctionDescriptorImpl( return new FunctionDescriptorImpl(
ResolveUtil.getJetFunction(functionDescriptor), ResolveUtil.getJetFunction(functionDescriptor),
functionDescriptor,
// TODO : substitute // TODO : substitute
functionDescriptor.getAttributes(), functionDescriptor.getAttributes(),
functionDescriptor.getName(), functionDescriptor.getName(),
@@ -299,7 +299,7 @@ public class JetTypeChecker {
// TODO : check that all are named // TODO : check that all are named
throw new UnsupportedOperationException(); // TODO throw new UnsupportedOperationException(); // TODO
// result[0] = overloadDomain.getReturnTypeForNamedArguments(typeArguments, valueArguments, functionLiteralArgument); // result[0] = overloadDomain.getFunctionDescriptorForNamedArguments(typeArguments, valueArguments, functionLiteralArgument);
} else { } else {
List<JetExpression> positionedValueArguments = new ArrayList<JetExpression>(); List<JetExpression> positionedValueArguments = new ArrayList<JetExpression>();
for (JetArgument argument : valueArguments) { for (JetArgument argument : valueArguments) {
@@ -319,7 +319,10 @@ public class JetTypeChecker {
valueArgumentTypes.add(getType(scope, valueArgument, false)); 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) { private OverloadDomain getOverloadDomain(final JetScope scope, JetExpression calleeExpression) {
final OverloadDomain[] result = new OverloadDomain[1]; final OverloadDomain[] result = new OverloadDomain[1];
final JetReferenceExpression[] reference = new JetReferenceExpression[1];
calleeExpression.accept(new JetVisitor() { calleeExpression.accept(new JetVisitor() {
@Override @Override
@@ -357,6 +361,7 @@ public class JetTypeChecker {
Type receiverType = getType(scope, expression.getReceiverExpression(), false); Type receiverType = getType(scope, expression.getReceiverExpression(), false);
result[0] = OverloadResolver.INSTANCE.getOverloadDomain(receiverType, scope, referenceExpression.getReferencedName()); result[0] = OverloadResolver.INSTANCE.getOverloadDomain(receiverType, scope, referenceExpression.getReferencedName());
reference[0] = referenceExpression;
} else { } else {
throw new UnsupportedOperationException(); // TODO throw new UnsupportedOperationException(); // TODO
} }
@@ -366,6 +371,7 @@ public class JetTypeChecker {
public void visitReferenceExpression(JetReferenceExpression expression) { public void visitReferenceExpression(JetReferenceExpression expression) {
// a -- create a hierarchical lookup domain for this.a // a -- create a hierarchical lookup domain for this.a
result[0] = OverloadResolver.INSTANCE.getOverloadDomain(null, scope, expression.getReferencedName()); result[0] = OverloadResolver.INSTANCE.getOverloadDomain(null, scope, expression.getReferencedName());
reference[0] = expression;
} }
@Override @Override
@@ -379,7 +385,21 @@ public class JetTypeChecker {
throw new IllegalArgumentException("Unsupported element: " + elem); throw new IllegalArgumentException("Unsupported element: " + elem);
} }
}); });
return result[0]; return new OverloadDomain() {
@Override
public FunctionDescriptor getFunctionDescriptorForNamedArguments(@NotNull List<Type> typeArguments, @NotNull Map<String, Type> 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<Type> typeArguments, @NotNull List<Type> positionedValueArgumentTypes) {
FunctionDescriptor descriptor = result[0].getFunctionDescriptorForPositionedArguments(typeArguments, positionedValueArgumentTypes);
trace.recordResolutionResult(reference[0], descriptor);
return descriptor;
}
};
} }
private Type getBlockReturnedType(@NotNull JetScope outerScope, List<JetElement> block) { private Type getBlockReturnedType(@NotNull JetScope outerScope, List<JetElement> block) {
@@ -58,6 +58,11 @@ public class LazySubstitutingFunctionDescriptor implements FunctionDescriptor {
return TypeSubstitutor.INSTANCE.substitute(substitutionContext, functionDescriptor.getUnsubstitutedReturnType(), Variance.OUT_VARIANCE); return TypeSubstitutor.INSTANCE.substitute(substitutionContext, functionDescriptor.getUnsubstitutedReturnType(), Variance.OUT_VARIANCE);
} }
@Override
public FunctionDescriptor getOriginal() {
return functionDescriptor;
}
@Override @Override
public List<Attribute> getAttributes() { public List<Attribute> getAttributes() {
// TODO : Substitute? // TODO : Substitute?
+1
View File
@@ -4,6 +4,7 @@ class A {
} }
fun foo(a : Int) = a fun foo(a : Int) = a
fun fooB() = foo(1)
fun foo() : Int = 1 fun foo() : Int = 1
fun foo1() : B = new B() fun foo1() : B = new B()
} }
@@ -40,16 +40,12 @@ public class JetResolveTest extends LightDaemonAnalyzerTestCase {
ClassDescriptor classB = membersOfA.getClass("B"); ClassDescriptor classB = membersOfA.getClass("B");
assertNotNull(classB); assertNotNull(classB);
FunctionGroup foo = membersOfA.getFunctionGroup("foo"); FunctionGroup fooFG = membersOfA.getFunctionGroup("foo");
assertFalse(foo.isEmpty()); assertFalse(fooFG.isEmpty());
OverloadDomain overloadsForFoo = OverloadResolver.INSTANCE.getOverloadDomain(null, membersOfA, "foo"); assertReturnType(membersOfA, "foo", JetStandardClasses.getIntType());
Type fooType = overloadsForFoo.getReturnTypeForPositionedArguments(Collections.<Type>emptyList(), Collections.<Type>emptyList()); assertReturnType(membersOfA, "foo1", new TypeImpl(classB));
assertEquals(JetStandardClasses.getIntType(), fooType); assertReturnType(membersOfA, "fooB", JetStandardClasses.getIntType());
OverloadDomain overloadsForFoo1 = OverloadResolver.INSTANCE.getOverloadDomain(null, membersOfA, "foo1");
Type foo1Type = overloadsForFoo1.getReturnTypeForPositionedArguments(Collections.<Type>emptyList(), Collections.<Type>emptyList());
assertEquals(new TypeImpl(classB), foo1Type);
JetFunction fooDecl = (JetFunction) classADecl.getDeclarations().get(1); JetFunction fooDecl = (JetFunction) classADecl.getDeclarations().get(1);
Type expressionType = bindingContext.getExpressionType(fooDecl.getBodyExpression()); Type expressionType = bindingContext.getExpressionType(fooDecl.getBodyExpression());
@@ -58,6 +54,12 @@ public class JetResolveTest extends LightDaemonAnalyzerTestCase {
DeclarationDescriptor resolve = bindingContext.resolve((JetReferenceExpression) fooDecl.getBodyExpression()); DeclarationDescriptor resolve = bindingContext.resolve((JetReferenceExpression) fooDecl.getBodyExpression());
assertSame(bindingContext.getFunctionDescriptor(fooDecl).getUnsubstitutedValueParameters().get(0), resolve); 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); JetClass classCDecl = (JetClass) declarations.get(1);
ClassDescriptor classC = bindingContext.getClassDescriptor(classCDecl); ClassDescriptor classC = bindingContext.getClassDescriptor(classCDecl);
assertNotNull(classC); assertNotNull(classC);
@@ -69,7 +71,13 @@ public class JetResolveTest extends LightDaemonAnalyzerTestCase {
assertNotNull(classC_B); assertNotNull(classC_B);
assertNotSame(classC_B, classB); assertNotSame(classC_B, classB);
assertEquals(classC.getTypeConstructor(), classC_B.getTypeConstructor().getSupertypes().iterator().next().getConstructor()); 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.<Type>emptyList(), Collections.<Type>emptyList());
assertNotNull(descriptorForFoo);
Type fooType = descriptorForFoo.getUnsubstitutedReturnType();
assertEquals(returnType, fooType);
} }
} }