From 4e0b6deda55722ed275df9a655eb67e84ed608d0 Mon Sep 17 00:00:00 2001 From: Andrey Breslav Date: Mon, 28 Feb 2011 14:34:03 +0300 Subject: [PATCH] TopDown analysis for method bodies --- .../jet/lang/resolve/OverloadResolver.java | 9 +++-- .../jet/lang/resolve/ResolveUtil.java | 13 +++---- .../jet/lang/resolve/TopDownAnalyzer.java | 34 ++++++++++++++++--- .../jet/lang/types/DeclarationDescriptor.java | 5 +-- .../lang/types/DeclarationDescriptorImpl.java | 3 +- .../jet/lang/types/JetTypeChecker.java | 26 +++++++++----- .../jet/lang/types/PropertyDescriptor.java | 4 ++- .../jet/lang/types/TypeCheckerTrace.java | 24 +++++++++++++ idea/testData/resolve/Basic.jet | 1 + .../jetbrains/jet/resolve/JetResolveTest.java | 16 +++++---- 10 files changed, 98 insertions(+), 37 deletions(-) create mode 100644 idea/src/org/jetbrains/jet/lang/types/TypeCheckerTrace.java diff --git a/idea/src/org/jetbrains/jet/lang/resolve/OverloadResolver.java b/idea/src/org/jetbrains/jet/lang/resolve/OverloadResolver.java index 01b470a3972..4380f675264 100644 --- a/idea/src/org/jetbrains/jet/lang/resolve/OverloadResolver.java +++ b/idea/src/org/jetbrains/jet/lang/resolve/OverloadResolver.java @@ -18,7 +18,12 @@ public class OverloadResolver { private OverloadResolver() {} @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 JetScope scope = receiverType == null ? outerScope : receiverType.getMemberScope(); @@ -30,7 +35,7 @@ public class OverloadResolver { return new OverloadDomain() { @Override - public Type getReturnTypeForPositionedArguments(@NotNull List typeArguments, @NotNull List positionedValueArgumentTypes) { + public Type getReturnTypeForPositionedArguments(@NotNull final List typeArguments, @NotNull List positionedValueArgumentTypes) { Collection possiblyApplicableFunctions = functionGroup.getPossiblyApplicableFunctions(typeArguments, positionedValueArgumentTypes); if (possiblyApplicableFunctions.isEmpty()) { return null; diff --git a/idea/src/org/jetbrains/jet/lang/resolve/ResolveUtil.java b/idea/src/org/jetbrains/jet/lang/resolve/ResolveUtil.java index 0365aec6f7f..c0c1b627c79 100644 --- a/idea/src/org/jetbrains/jet/lang/resolve/ResolveUtil.java +++ b/idea/src/org/jetbrains/jet/lang/resolve/ResolveUtil.java @@ -5,10 +5,7 @@ import org.jetbrains.jet.lang.psi.JetElement; import org.jetbrains.jet.lang.psi.JetFunction; import org.jetbrains.jet.lang.psi.JetParameter; import org.jetbrains.jet.lang.psi.JetTypeParameter; -import org.jetbrains.jet.lang.types.DeclarationDescriptor; -import org.jetbrains.jet.lang.types.FunctionDescriptor; -import org.jetbrains.jet.lang.types.TypeParameterDescriptor; -import org.jetbrains.jet.lang.types.ValueParameterDescriptor; +import org.jetbrains.jet.lang.types.*; /** * @author abreslav @@ -16,16 +13,16 @@ import org.jetbrains.jet.lang.types.ValueParameterDescriptor; public class ResolveUtil { @Nullable private static T getDeclarationElement(Object o) { - if (o instanceof DeclarationDescriptor) { + if (o instanceof DeclarationDescriptorImpl) { @SuppressWarnings({"unchecked", "UnnecessaryLocalVariable"}) - T psiElement = ((DeclarationDescriptor) o).getPsiElement(); + T psiElement = ((DeclarationDescriptorImpl) o).getPsiElement(); return psiElement; } return null; } @Nullable - private static T getDeclarationElement(DeclarationDescriptor descriptor) { + private static T getDeclarationElement(DeclarationDescriptorImpl descriptor) { return descriptor.getPsiElement(); } @@ -36,7 +33,7 @@ public class ResolveUtil { @Nullable public static JetParameter getJetParameter(ValueParameterDescriptor parameterDescriptor) { - return getDeclarationElement(parameterDescriptor); + return (JetParameter) getDeclarationElement(parameterDescriptor); } @Nullable diff --git a/idea/src/org/jetbrains/jet/lang/resolve/TopDownAnalyzer.java b/idea/src/org/jetbrains/jet/lang/resolve/TopDownAnalyzer.java index 1f652add3cf..9b073aeea46 100644 --- a/idea/src/org/jetbrains/jet/lang/resolve/TopDownAnalyzer.java +++ b/idea/src/org/jetbrains/jet/lang/resolve/TopDownAnalyzer.java @@ -15,13 +15,15 @@ public class TopDownAnalyzer { private final Map classes = new LinkedHashMap(); private final Map functions = new HashMap(); private final Map declaringScopes = new HashMap(); + private Map expressionTypes = new HashMap(); + private Map resolutionResults = new HashMap(); public BindingContext process(@NotNull JetScope outerScope, @NotNull List declarations) { WritableScope toplevelScope = new WritableScope(outerScope); collectTypeDeclarators(toplevelScope, declarations); resolveTypeDeclarations(); collectBehaviorDeclarators(toplevelScope, declarations); - resolveBehaviorDeclarations(); + resolveBehaviorDeclarationBodies(); return new BindingContext() { @Override @@ -36,7 +38,7 @@ public class TopDownAnalyzer { @Override public FunctionDescriptor getFunctionDescriptor(JetFunction declaration) { - throw new UnsupportedOperationException(); // TODO + return functions.get(declaration); } @Override @@ -46,12 +48,12 @@ public class TopDownAnalyzer { @Override public Type getExpressionType(JetExpression expression) { - throw new UnsupportedOperationException(); // TODO + return expressionTypes.get(expression); } @Override 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 entry : functions.entrySet()) { JetFunction function = entry.getKey(); FunctionDescriptor descriptor = entry.getValue(); @@ -174,8 +176,30 @@ public class TopDownAnalyzer { WritableScope declaringScope = declaringScopes.get(function); 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); + } + } diff --git a/idea/src/org/jetbrains/jet/lang/types/DeclarationDescriptor.java b/idea/src/org/jetbrains/jet/lang/types/DeclarationDescriptor.java index a0f00bf9b76..64a16665add 100644 --- a/idea/src/org/jetbrains/jet/lang/types/DeclarationDescriptor.java +++ b/idea/src/org/jetbrains/jet/lang/types/DeclarationDescriptor.java @@ -1,10 +1,7 @@ package org.jetbrains.jet.lang.types; -import org.jetbrains.jet.lang.psi.JetElement; - /** * @author abreslav */ -public interface DeclarationDescriptor { - T getPsiElement(); +public interface DeclarationDescriptor extends Annotated, Named { } diff --git a/idea/src/org/jetbrains/jet/lang/types/DeclarationDescriptorImpl.java b/idea/src/org/jetbrains/jet/lang/types/DeclarationDescriptorImpl.java index 5f40ab8be36..d23534f6ab7 100644 --- a/idea/src/org/jetbrains/jet/lang/types/DeclarationDescriptorImpl.java +++ b/idea/src/org/jetbrains/jet/lang/types/DeclarationDescriptorImpl.java @@ -7,7 +7,7 @@ import java.util.List; /** * @author abreslav */ -public abstract class DeclarationDescriptorImpl extends AnnotatedImpl implements Named, DeclarationDescriptor { +public abstract class DeclarationDescriptorImpl extends AnnotatedImpl implements Named, DeclarationDescriptor { private final String name; private final T psiElement; @@ -23,7 +23,6 @@ public abstract class DeclarationDescriptorImpl extends An return name; } - @Override public T getPsiElement() { return psiElement; } diff --git a/idea/src/org/jetbrains/jet/lang/types/JetTypeChecker.java b/idea/src/org/jetbrains/jet/lang/types/JetTypeChecker.java index 000b1dd0310..2dc0fc7bdc9 100644 --- a/idea/src/org/jetbrains/jet/lang/types/JetTypeChecker.java +++ b/idea/src/org/jetbrains/jet/lang/types/JetTypeChecker.java @@ -14,22 +14,28 @@ import java.util.*; * @author abreslav */ 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 - : "namespace" // for the root namespace - */ + : declaration + : "namespace" // for the root namespace + */ public Type getType(@NotNull final JetScope scope, @NotNull JetExpression expression, final boolean preferBlock) { final Type[] result = new Type[1]; expression.accept(new JetVisitor() { @@ -38,6 +44,7 @@ public class JetTypeChecker { // TODO : other members // TODO : type substitutions??? PropertyDescriptor property = scope.getProperty(expression.getReferencedName()); + trace.recordResolutionResult(expression, property); if (property != null) { result[0] = property.getType(); } @@ -321,6 +328,7 @@ public class JetTypeChecker { throw new IllegalArgumentException("Unsupported element: " + elem); } }); + trace.recordExpressionType(expression, result[0]); return result[0]; } diff --git a/idea/src/org/jetbrains/jet/lang/types/PropertyDescriptor.java b/idea/src/org/jetbrains/jet/lang/types/PropertyDescriptor.java index 4a14cc0df28..08b7e154e0c 100644 --- a/idea/src/org/jetbrains/jet/lang/types/PropertyDescriptor.java +++ b/idea/src/org/jetbrains/jet/lang/types/PropertyDescriptor.java @@ -1,8 +1,10 @@ package org.jetbrains.jet.lang.types; +import org.jetbrains.jet.lang.psi.JetDeclaration; + /** * @author abreslav */ -public interface PropertyDescriptor extends Annotated, Named { +public interface PropertyDescriptor extends DeclarationDescriptor { Type getType(); } diff --git a/idea/src/org/jetbrains/jet/lang/types/TypeCheckerTrace.java b/idea/src/org/jetbrains/jet/lang/types/TypeCheckerTrace.java new file mode 100644 index 00000000000..de25b91c7c8 --- /dev/null +++ b/idea/src/org/jetbrains/jet/lang/types/TypeCheckerTrace.java @@ -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); +} diff --git a/idea/testData/resolve/Basic.jet b/idea/testData/resolve/Basic.jet index c60e8190bf7..e0544e69b9d 100644 --- a/idea/testData/resolve/Basic.jet +++ b/idea/testData/resolve/Basic.jet @@ -3,6 +3,7 @@ class A { } + fun foo(a : Int) = a 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 7a9959b112e..1f3bf90828a 100644 --- a/idea/tests/org/jetbrains/jet/resolve/JetResolveTest.java +++ b/idea/tests/org/jetbrains/jet/resolve/JetResolveTest.java @@ -3,10 +3,7 @@ package org.jetbrains.jet.resolve; import com.intellij.codeInsight.daemon.LightDaemonAnalyzerTestCase; import com.intellij.openapi.application.PathManager; import com.intellij.openapi.util.io.FileUtil; -import org.jetbrains.jet.lang.psi.JetChangeUtil; -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.psi.*; import org.jetbrains.jet.lang.resolve.*; import org.jetbrains.jet.lang.types.*; import org.jetbrains.jet.parsing.JetParsingTest; @@ -35,8 +32,8 @@ public class JetResolveTest extends LightDaemonAnalyzerTestCase { List declarations = jetFile.getRootNamespace().getDeclarations(); BindingContext bindingContext = new TopDownAnalyzer().process(JetStandardClasses.STANDARD_CLASSES, declarations); - JetDeclaration declaration = declarations.get(0); - ClassDescriptor classA = bindingContext.getClassDescriptor((JetClass) declaration); + JetClass classADecl = (JetClass) declarations.get(0); + ClassDescriptor classA = bindingContext.getClassDescriptor(classADecl); assertNotNull(classA); JetScope membersOfA = classA.getMemberScope(Collections.emptyList()); @@ -54,6 +51,13 @@ public class JetResolveTest extends LightDaemonAnalyzerTestCase { Type foo1Type = overloadsForFoo1.getReturnTypeForPositionedArguments(Collections.emptyList(), Collections.emptyList()); 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); ClassDescriptor classC = bindingContext.getClassDescriptor(classCDecl); assertNotNull(classC);