TopDown analysis for method bodies

This commit is contained in:
Andrey Breslav
2011-02-28 14:34:03 +03:00
parent 248ed385d5
commit 4e0b6deda5
10 changed files with 98 additions and 37 deletions
@@ -18,7 +18,12 @@ public class OverloadResolver {
private OverloadResolver() {} private OverloadResolver() {}
@NotNull @NotNull
public OverloadDomain getOverloadDomain(@Nullable 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();
@@ -30,7 +35,7 @@ public class OverloadResolver {
return new OverloadDomain() { return new OverloadDomain() {
@Override @Override
public Type getReturnTypeForPositionedArguments(@NotNull List<Type> typeArguments, @NotNull List<Type> positionedValueArgumentTypes) { public Type getReturnTypeForPositionedArguments(@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;
@@ -5,10 +5,7 @@ import org.jetbrains.jet.lang.psi.JetElement;
import org.jetbrains.jet.lang.psi.JetFunction; import org.jetbrains.jet.lang.psi.JetFunction;
import org.jetbrains.jet.lang.psi.JetParameter; import org.jetbrains.jet.lang.psi.JetParameter;
import org.jetbrains.jet.lang.psi.JetTypeParameter; import org.jetbrains.jet.lang.psi.JetTypeParameter;
import org.jetbrains.jet.lang.types.DeclarationDescriptor; import org.jetbrains.jet.lang.types.*;
import org.jetbrains.jet.lang.types.FunctionDescriptor;
import org.jetbrains.jet.lang.types.TypeParameterDescriptor;
import org.jetbrains.jet.lang.types.ValueParameterDescriptor;
/** /**
* @author abreslav * @author abreslav
@@ -16,16 +13,16 @@ import org.jetbrains.jet.lang.types.ValueParameterDescriptor;
public class ResolveUtil { public class ResolveUtil {
@Nullable @Nullable
private static <T extends JetElement> T getDeclarationElement(Object o) { private static <T extends JetElement> T getDeclarationElement(Object o) {
if (o instanceof DeclarationDescriptor) { if (o instanceof DeclarationDescriptorImpl) {
@SuppressWarnings({"unchecked", "UnnecessaryLocalVariable"}) @SuppressWarnings({"unchecked", "UnnecessaryLocalVariable"})
T psiElement = ((DeclarationDescriptor<T>) o).getPsiElement(); T psiElement = ((DeclarationDescriptorImpl<T>) o).getPsiElement();
return psiElement; return psiElement;
} }
return null; return null;
} }
@Nullable @Nullable
private static <T extends JetElement> T getDeclarationElement(DeclarationDescriptor<T> descriptor) { private static <T extends JetElement> T getDeclarationElement(DeclarationDescriptorImpl<T> descriptor) {
return descriptor.getPsiElement(); return descriptor.getPsiElement();
} }
@@ -36,7 +33,7 @@ public class ResolveUtil {
@Nullable @Nullable
public static JetParameter getJetParameter(ValueParameterDescriptor parameterDescriptor) { public static JetParameter getJetParameter(ValueParameterDescriptor parameterDescriptor) {
return getDeclarationElement(parameterDescriptor); return (JetParameter) getDeclarationElement(parameterDescriptor);
} }
@Nullable @Nullable
@@ -15,13 +15,15 @@ public class TopDownAnalyzer {
private final Map<JetClass, MutableClassDescriptor> classes = new LinkedHashMap<JetClass, MutableClassDescriptor>(); private final Map<JetClass, MutableClassDescriptor> classes = new LinkedHashMap<JetClass, MutableClassDescriptor>();
private final Map<JetFunction, FunctionDescriptor> functions = new HashMap<JetFunction, FunctionDescriptor>(); private final Map<JetFunction, FunctionDescriptor> functions = new HashMap<JetFunction, FunctionDescriptor>();
private final Map<JetDeclaration, WritableScope> declaringScopes = new HashMap<JetDeclaration, WritableScope>(); private final Map<JetDeclaration, WritableScope> declaringScopes = new HashMap<JetDeclaration, WritableScope>();
private Map<JetExpression, Type> expressionTypes = new HashMap<JetExpression, Type>();
private Map<JetReferenceExpression,DeclarationDescriptor> resolutionResults = new HashMap<JetReferenceExpression, DeclarationDescriptor>();
public BindingContext process(@NotNull JetScope outerScope, @NotNull List<JetDeclaration> declarations) { public BindingContext process(@NotNull JetScope outerScope, @NotNull List<JetDeclaration> declarations) {
WritableScope toplevelScope = new WritableScope(outerScope); WritableScope toplevelScope = new WritableScope(outerScope);
collectTypeDeclarators(toplevelScope, declarations); collectTypeDeclarators(toplevelScope, declarations);
resolveTypeDeclarations(); resolveTypeDeclarations();
collectBehaviorDeclarators(toplevelScope, declarations); collectBehaviorDeclarators(toplevelScope, declarations);
resolveBehaviorDeclarations(); resolveBehaviorDeclarationBodies();
return new BindingContext() { return new BindingContext() {
@Override @Override
@@ -36,7 +38,7 @@ public class TopDownAnalyzer {
@Override @Override
public FunctionDescriptor getFunctionDescriptor(JetFunction declaration) { public FunctionDescriptor getFunctionDescriptor(JetFunction declaration) {
throw new UnsupportedOperationException(); // TODO return functions.get(declaration);
} }
@Override @Override
@@ -46,12 +48,12 @@ public class TopDownAnalyzer {
@Override @Override
public Type getExpressionType(JetExpression expression) { public Type getExpressionType(JetExpression expression) {
throw new UnsupportedOperationException(); // TODO return expressionTypes.get(expression);
} }
@Override @Override
public DeclarationDescriptor resolve(JetReferenceExpression referenceExpression) { public DeclarationDescriptor resolve(JetReferenceExpression referenceExpression) {
throw new UnsupportedOperationException(); // TODO return resolutionResults.get(referenceExpression);
} }
}; };
} }
@@ -166,7 +168,7 @@ public class TopDownAnalyzer {
//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
private void resolveBehaviorDeclarations() { private void resolveBehaviorDeclarationBodies() {
for (Map.Entry<JetFunction, FunctionDescriptor> entry : functions.entrySet()) { for (Map.Entry<JetFunction, FunctionDescriptor> entry : functions.entrySet()) {
JetFunction function = entry.getKey(); JetFunction function = entry.getKey();
FunctionDescriptor descriptor = entry.getValue(); FunctionDescriptor descriptor = entry.getValue();
@@ -174,8 +176,30 @@ public class TopDownAnalyzer {
WritableScope declaringScope = declaringScopes.get(function); WritableScope declaringScope = declaringScopes.get(function);
assert declaringScope != null; assert declaringScope != null;
WritableScope parameterScope = new WritableScope(declaringScope);
for (TypeParameterDescriptor typeParameter : descriptor.getTypeParameters()) {
parameterScope.addTypeParameterDescriptor(typeParameter);
}
for (ValueParameterDescriptor valueParameterDescriptor : descriptor.getUnsubstitutedValueParameters()) {
parameterScope.addPropertyDescriptor(valueParameterDescriptor);
}
resolveExpression(parameterScope, function.getBodyExpression(), true);
} }
} }
private void resolveExpression(@NotNull JetScope scope, JetExpression expression, boolean preferBlock) {
new JetTypeChecker(new TypeCheckerTrace() {
@Override
public void recordExpressionType(JetExpression expression, Type type) {
expressionTypes.put(expression, type);
}
@Override
public void recordResolutionResult(JetReferenceExpression expression, DeclarationDescriptor descriptor) {
resolutionResults.put(expression, descriptor);
}
}).getType(scope, expression, preferBlock);
}
} }
@@ -1,10 +1,7 @@
package org.jetbrains.jet.lang.types; package org.jetbrains.jet.lang.types;
import org.jetbrains.jet.lang.psi.JetElement;
/** /**
* @author abreslav * @author abreslav
*/ */
public interface DeclarationDescriptor<T extends JetElement> { public interface DeclarationDescriptor extends Annotated, Named {
T getPsiElement();
} }
@@ -7,7 +7,7 @@ import java.util.List;
/** /**
* @author abreslav * @author abreslav
*/ */
public abstract class DeclarationDescriptorImpl<T extends JetElement> extends AnnotatedImpl implements Named, DeclarationDescriptor<T> { public abstract class DeclarationDescriptorImpl<T extends JetElement> extends AnnotatedImpl implements Named, DeclarationDescriptor {
private final String name; private final String name;
private final T psiElement; private final T psiElement;
@@ -23,7 +23,6 @@ public abstract class DeclarationDescriptorImpl<T extends JetElement> extends An
return name; return name;
} }
@Override
public T getPsiElement() { public T getPsiElement() {
return psiElement; return psiElement;
} }
@@ -14,22 +14,28 @@ import java.util.*;
* @author abreslav * @author abreslav
*/ */
public class JetTypeChecker { public class JetTypeChecker {
public static final JetTypeChecker INSTANCE = new JetTypeChecker(); public static final JetTypeChecker INSTANCE = new JetTypeChecker(TypeCheckerTrace.DUMMY);
private final TypeCheckerTrace trace;
public JetTypeChecker(TypeCheckerTrace trace) {
this.trace = trace;
}
/* /*
: "new" constructorInvocation : "new" constructorInvocation
: objectLiteral : objectLiteral
: SimpleName : SimpleName
: "typeof" "(" expression ")" : "typeof" "(" expression ")"
: functionLiteral : functionLiteral
: declaration : declaration
: "namespace" // for the root namespace : "namespace" // for the root namespace
*/ */
public Type getType(@NotNull final JetScope scope, @NotNull JetExpression expression, final boolean preferBlock) { public Type getType(@NotNull final JetScope scope, @NotNull JetExpression expression, final boolean preferBlock) {
final Type[] result = new Type[1]; final Type[] result = new Type[1];
expression.accept(new JetVisitor() { expression.accept(new JetVisitor() {
@@ -38,6 +44,7 @@ public class JetTypeChecker {
// TODO : other members // TODO : other members
// TODO : type substitutions??? // TODO : type substitutions???
PropertyDescriptor property = scope.getProperty(expression.getReferencedName()); PropertyDescriptor property = scope.getProperty(expression.getReferencedName());
trace.recordResolutionResult(expression, property);
if (property != null) { if (property != null) {
result[0] = property.getType(); result[0] = property.getType();
} }
@@ -321,6 +328,7 @@ public class JetTypeChecker {
throw new IllegalArgumentException("Unsupported element: " + elem); throw new IllegalArgumentException("Unsupported element: " + elem);
} }
}); });
trace.recordExpressionType(expression, result[0]);
return result[0]; return result[0];
} }
@@ -1,8 +1,10 @@
package org.jetbrains.jet.lang.types; package org.jetbrains.jet.lang.types;
import org.jetbrains.jet.lang.psi.JetDeclaration;
/** /**
* @author abreslav * @author abreslav
*/ */
public interface PropertyDescriptor extends Annotated, Named { public interface PropertyDescriptor extends DeclarationDescriptor {
Type getType(); Type getType();
} }
@@ -0,0 +1,24 @@
package org.jetbrains.jet.lang.types;
import org.jetbrains.jet.lang.psi.JetExpression;
import org.jetbrains.jet.lang.psi.JetReferenceExpression;
/**
* @author abreslav
*/
public interface TypeCheckerTrace {
TypeCheckerTrace DUMMY = new TypeCheckerTrace() {
@Override
public void recordExpressionType(JetExpression expression, Type type) {
}
@Override
public void recordResolutionResult(JetReferenceExpression expression, DeclarationDescriptor descriptor) {
}
};
void recordExpressionType(JetExpression expression, Type type);
void recordResolutionResult(JetReferenceExpression expression, DeclarationDescriptor descriptor);
}
+1
View File
@@ -3,6 +3,7 @@ class A {
} }
fun foo(a : Int) = a
fun foo() : Int = 1 fun foo() : Int = 1
fun foo1() : B = new B() fun foo1() : B = new B()
} }
@@ -3,10 +3,7 @@ package org.jetbrains.jet.resolve;
import com.intellij.codeInsight.daemon.LightDaemonAnalyzerTestCase; import com.intellij.codeInsight.daemon.LightDaemonAnalyzerTestCase;
import com.intellij.openapi.application.PathManager; import com.intellij.openapi.application.PathManager;
import com.intellij.openapi.util.io.FileUtil; import com.intellij.openapi.util.io.FileUtil;
import org.jetbrains.jet.lang.psi.JetChangeUtil; import org.jetbrains.jet.lang.psi.*;
import org.jetbrains.jet.lang.psi.JetClass;
import org.jetbrains.jet.lang.psi.JetDeclaration;
import org.jetbrains.jet.lang.psi.JetFile;
import org.jetbrains.jet.lang.resolve.*; import org.jetbrains.jet.lang.resolve.*;
import org.jetbrains.jet.lang.types.*; import org.jetbrains.jet.lang.types.*;
import org.jetbrains.jet.parsing.JetParsingTest; import org.jetbrains.jet.parsing.JetParsingTest;
@@ -35,8 +32,8 @@ public class JetResolveTest extends LightDaemonAnalyzerTestCase {
List<JetDeclaration> declarations = jetFile.getRootNamespace().getDeclarations(); List<JetDeclaration> declarations = jetFile.getRootNamespace().getDeclarations();
BindingContext bindingContext = new TopDownAnalyzer().process(JetStandardClasses.STANDARD_CLASSES, declarations); BindingContext bindingContext = new TopDownAnalyzer().process(JetStandardClasses.STANDARD_CLASSES, declarations);
JetDeclaration declaration = declarations.get(0); JetClass classADecl = (JetClass) declarations.get(0);
ClassDescriptor classA = bindingContext.getClassDescriptor((JetClass) declaration); ClassDescriptor classA = bindingContext.getClassDescriptor(classADecl);
assertNotNull(classA); assertNotNull(classA);
JetScope membersOfA = classA.getMemberScope(Collections.<TypeProjection>emptyList()); JetScope membersOfA = classA.getMemberScope(Collections.<TypeProjection>emptyList());
@@ -54,6 +51,13 @@ public class JetResolveTest extends LightDaemonAnalyzerTestCase {
Type foo1Type = overloadsForFoo1.getReturnTypeForPositionedArguments(Collections.<Type>emptyList(), Collections.<Type>emptyList()); Type foo1Type = overloadsForFoo1.getReturnTypeForPositionedArguments(Collections.<Type>emptyList(), Collections.<Type>emptyList());
assertEquals(new TypeImpl(classB), foo1Type); assertEquals(new TypeImpl(classB), foo1Type);
JetFunction fooDecl = (JetFunction) classADecl.getDeclarations().get(1);
Type expressionType = bindingContext.getExpressionType(fooDecl.getBodyExpression());
assertEquals(JetStandardClasses.getIntType(), expressionType);
DeclarationDescriptor resolve = bindingContext.resolve((JetReferenceExpression) fooDecl.getBodyExpression());
assertSame(bindingContext.getFunctionDescriptor(fooDecl).getUnsubstitutedValueParameters().get(0), resolve);
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);