From 4884af389fe2bf4593ea6dfabdac6cc5c33868c2 Mon Sep 17 00:00:00 2001 From: Andrey Breslav Date: Fri, 3 Jun 2011 18:37:47 +0400 Subject: [PATCH] JET-61 Support class objects --- grammar/src/class_members.grm | 2 +- .../jet/lang/descriptors/ClassDescriptor.java | 3 ++ .../lang/descriptors/ClassDescriptorImpl.java | 5 ++ .../descriptors/ClassifierDescriptor.java | 4 ++ .../LazySubstitutingClassDescriptor.java | 5 ++ .../descriptors/MutableClassDescriptor.java | 20 ++++++++ .../descriptors/NamespaceDescriptorImpl.java | 5 ++ .../jet/lang/descriptors/NamespaceLike.java | 2 + .../descriptors/TypeParameterDescriptor.java | 25 +++++++--- .../jet/lang/parsing/JetParsing.java | 7 +-- .../jet/lang/psi/JetClassObject.java | 6 ++- .../jet/lang/resolve/AnalyzingUtils.java | 47 ++++++++++--------- .../jet/lang/resolve/TopDownAnalyzer.java | 17 ++++++- .../resolve/java/JavaClassDescriptor.java | 5 ++ .../jet/lang/types/JetTypeInferrer.java | 19 +++++++- 15 files changed, 136 insertions(+), 36 deletions(-) diff --git a/grammar/src/class_members.grm b/grammar/src/class_members.grm index dddeca9b181..2a355ca1ccc 100644 --- a/grammar/src/class_members.grm +++ b/grammar/src/class_members.grm @@ -43,7 +43,7 @@ memberDeclaration ; classObject - : modifiers "class" objectLiteral + : modifiers "class" object ; constructor diff --git a/idea/src/org/jetbrains/jet/lang/descriptors/ClassDescriptor.java b/idea/src/org/jetbrains/jet/lang/descriptors/ClassDescriptor.java index b2473699b46..f7e54b4e687 100644 --- a/idea/src/org/jetbrains/jet/lang/descriptors/ClassDescriptor.java +++ b/idea/src/org/jetbrains/jet/lang/descriptors/ClassDescriptor.java @@ -38,4 +38,7 @@ public interface ClassDescriptor extends ClassifierDescriptor { @NotNull @Override ClassDescriptor substitute(TypeSubstitutor substitutor); + + @Nullable + JetType getClassObjectType(); } diff --git a/idea/src/org/jetbrains/jet/lang/descriptors/ClassDescriptorImpl.java b/idea/src/org/jetbrains/jet/lang/descriptors/ClassDescriptorImpl.java index aeaf05e194c..165d264cc99 100644 --- a/idea/src/org/jetbrains/jet/lang/descriptors/ClassDescriptorImpl.java +++ b/idea/src/org/jetbrains/jet/lang/descriptors/ClassDescriptorImpl.java @@ -81,6 +81,11 @@ public class ClassDescriptorImpl extends DeclarationDescriptorImpl implements Cl throw new UnsupportedOperationException(); // TODO } + @Override + public JetType getClassObjectType() { + return null; + } + @Override public R accept(DeclarationDescriptorVisitor visitor, D data) { return visitor.visitClassDescriptor(this, data); diff --git a/idea/src/org/jetbrains/jet/lang/descriptors/ClassifierDescriptor.java b/idea/src/org/jetbrains/jet/lang/descriptors/ClassifierDescriptor.java index 036913dc649..48fc0d4f991 100644 --- a/idea/src/org/jetbrains/jet/lang/descriptors/ClassifierDescriptor.java +++ b/idea/src/org/jetbrains/jet/lang/descriptors/ClassifierDescriptor.java @@ -1,6 +1,7 @@ package org.jetbrains.jet.lang.descriptors; import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; import org.jetbrains.jet.lang.types.JetType; import org.jetbrains.jet.lang.types.TypeConstructor; @@ -13,4 +14,7 @@ public interface ClassifierDescriptor extends DeclarationDescriptor { @NotNull JetType getDefaultType(); + + @Nullable + JetType getClassObjectType(); } diff --git a/idea/src/org/jetbrains/jet/lang/descriptors/LazySubstitutingClassDescriptor.java b/idea/src/org/jetbrains/jet/lang/descriptors/LazySubstitutingClassDescriptor.java index 15d2ee7f4c2..fef61c7690c 100644 --- a/idea/src/org/jetbrains/jet/lang/descriptors/LazySubstitutingClassDescriptor.java +++ b/idea/src/org/jetbrains/jet/lang/descriptors/LazySubstitutingClassDescriptor.java @@ -90,6 +90,11 @@ public class LazySubstitutingClassDescriptor implements ClassDescriptor { throw new UnsupportedOperationException(); // TODO } + @Override + public JetType getClassObjectType() { + return original.getClassObjectType(); + } + @Override public R accept(DeclarationDescriptorVisitor visitor, D data) { return visitor.visitClassDescriptor(this, data); diff --git a/idea/src/org/jetbrains/jet/lang/descriptors/MutableClassDescriptor.java b/idea/src/org/jetbrains/jet/lang/descriptors/MutableClassDescriptor.java index 16bd49db7c4..6965692e0ac 100644 --- a/idea/src/org/jetbrains/jet/lang/descriptors/MutableClassDescriptor.java +++ b/idea/src/org/jetbrains/jet/lang/descriptors/MutableClassDescriptor.java @@ -27,6 +27,8 @@ public class MutableClassDescriptor extends MutableDeclarationDescriptor impleme private final WritableScope scopeForMemberLookup; // This scope contains type parameters but does not contain inner classes private final WritableScope scopeForSupertypeResolution; + private MutableClassDescriptor classObjectDescriptor; + private JetType classObjectType; public MutableClassDescriptor(@NotNull BindingTrace trace, @NotNull DeclarationDescriptor containingDeclaration, @NotNull JetScope outerScope) { super(containingDeclaration); @@ -37,6 +39,16 @@ public class MutableClassDescriptor extends MutableDeclarationDescriptor impleme //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + @Override + public void setClassObjectDescriptor(@NotNull MutableClassDescriptor classObjectDescriptor) { + this.classObjectDescriptor = classObjectDescriptor; + } + + @Nullable + public MutableClassDescriptor getClassObjectDescriptor() { + return classObjectDescriptor; + } + public void setPrimaryConstructor(@NotNull ConstructorDescriptor constructorDescriptor) { assert this.primaryConstructor == null : "Primary constructor assigned twice " + this; this.primaryConstructor = constructorDescriptor; @@ -187,6 +199,14 @@ public class MutableClassDescriptor extends MutableDeclarationDescriptor impleme throw new UnsupportedOperationException(); // TODO } + @Override + public JetType getClassObjectType() { + if (classObjectType == null && classObjectDescriptor != null) { + classObjectType = classObjectDescriptor.getDefaultType(); + } + return classObjectType; + } + @Override public R accept(DeclarationDescriptorVisitor visitor, D data) { return visitor.visitClassDescriptor(this, data); diff --git a/idea/src/org/jetbrains/jet/lang/descriptors/NamespaceDescriptorImpl.java b/idea/src/org/jetbrains/jet/lang/descriptors/NamespaceDescriptorImpl.java index 5ea4e4c24cc..49c7950a8a7 100644 --- a/idea/src/org/jetbrains/jet/lang/descriptors/NamespaceDescriptorImpl.java +++ b/idea/src/org/jetbrains/jet/lang/descriptors/NamespaceDescriptorImpl.java @@ -51,4 +51,9 @@ public class NamespaceDescriptorImpl extends AbstractNamespaceDescriptorImpl imp public void addPropertyDescriptor(@NotNull PropertyDescriptor variableDescriptor) { memberScope.addVariableDescriptor(variableDescriptor); } + + @Override + public void setClassObjectDescriptor(@NotNull MutableClassDescriptor classObjectDescriptor) { + throw new IllegalStateException("Must be guaranteed not to happen by the parser"); + } } diff --git a/idea/src/org/jetbrains/jet/lang/descriptors/NamespaceLike.java b/idea/src/org/jetbrains/jet/lang/descriptors/NamespaceLike.java index 5fa2421a753..0ad5305aaa2 100644 --- a/idea/src/org/jetbrains/jet/lang/descriptors/NamespaceLike.java +++ b/idea/src/org/jetbrains/jet/lang/descriptors/NamespaceLike.java @@ -67,4 +67,6 @@ public interface NamespaceLike extends DeclarationDescriptor { void addFunctionDescriptor(@NotNull FunctionDescriptor functionDescriptor); void addPropertyDescriptor(@NotNull PropertyDescriptor propertyDescriptor); + + void setClassObjectDescriptor(@NotNull MutableClassDescriptor classObjectDescriptor); } diff --git a/idea/src/org/jetbrains/jet/lang/descriptors/TypeParameterDescriptor.java b/idea/src/org/jetbrains/jet/lang/descriptors/TypeParameterDescriptor.java index 62ca17522a9..74f3580c93b 100644 --- a/idea/src/org/jetbrains/jet/lang/descriptors/TypeParameterDescriptor.java +++ b/idea/src/org/jetbrains/jet/lang/descriptors/TypeParameterDescriptor.java @@ -37,9 +37,11 @@ public class TypeParameterDescriptor extends DeclarationDescriptorImpl implement private final int index; private final Variance variance; private final Set upperBounds; - private final TypeConstructor typeConstructor; private JetType boundsAsType; - private JetType type; + private final TypeConstructor typeConstructor; + private JetType defaultType; + private final Set classObjectUpperBounds = Sets.newLinkedHashSet(); + private JetType classObjectBoundsAsType; private TypeParameterDescriptor( @NotNull DeclarationDescriptor containingDeclaration, @@ -89,7 +91,7 @@ public class TypeParameterDescriptor extends DeclarationDescriptorImpl implement if (boundsAsType == null) { assert upperBounds != null; assert upperBounds.size() > 0; - boundsAsType = upperBounds.size() == 1 ? upperBounds.iterator().next() : TypeUtils.intersect(JetTypeChecker.INSTANCE, upperBounds); + boundsAsType = TypeUtils.intersect(JetTypeChecker.INSTANCE, upperBounds); if (boundsAsType == null) { boundsAsType = JetStandardClasses.getNothingType(); // TODO : some error message? } @@ -111,8 +113,8 @@ public class TypeParameterDescriptor extends DeclarationDescriptorImpl implement @NotNull @Override public JetType getDefaultType() { - if (type == null) { - type = new JetTypeImpl( + if (defaultType == null) { + defaultType = new JetTypeImpl( Collections.emptyList(), getTypeConstructor(), TypeUtils.hasNullableBound(this), @@ -124,7 +126,18 @@ public class TypeParameterDescriptor extends DeclarationDescriptorImpl implement } })); } - return type; + return defaultType; + } + + @Override + public JetType getClassObjectType() { + if (classObjectUpperBounds.isEmpty()) return null; + + if (classObjectBoundsAsType == null) { + classObjectBoundsAsType = TypeUtils.intersect(JetTypeChecker.INSTANCE, classObjectUpperBounds); + assert classObjectBoundsAsType != null; // TODO : Error message + } + return classObjectBoundsAsType; } public int getIndex() { diff --git a/idea/src/org/jetbrains/jet/lang/parsing/JetParsing.java b/idea/src/org/jetbrains/jet/lang/parsing/JetParsing.java index 89658c76d97..4b170ebf368 100644 --- a/idea/src/org/jetbrains/jet/lang/parsing/JetParsing.java +++ b/idea/src/org/jetbrains/jet/lang/parsing/JetParsing.java @@ -712,7 +712,7 @@ public class JetParsing extends AbstractJetParsing { /* * classObject - * : modifiers "class" objectLiteral + * : modifiers "class" object * ; */ private JetNodeType parseClassObject() { @@ -720,8 +720,9 @@ public class JetParsing extends AbstractJetParsing { advance(); // CLASS_KEYWORD - myExpressionParsing.parseObjectLiteral(); - + final PsiBuilder.Marker objectDeclaration = mark(); + parseObject(false); + objectDeclaration.done(OBJECT_DECLARATION); return CLASS_OBJECT; } diff --git a/idea/src/org/jetbrains/jet/lang/psi/JetClassObject.java b/idea/src/org/jetbrains/jet/lang/psi/JetClassObject.java index 14c87f964c0..ff08a04506b 100644 --- a/idea/src/org/jetbrains/jet/lang/psi/JetClassObject.java +++ b/idea/src/org/jetbrains/jet/lang/psi/JetClassObject.java @@ -2,6 +2,7 @@ package org.jetbrains.jet.lang.psi; import com.intellij.lang.ASTNode; import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; import org.jetbrains.jet.JetNodeTypes; /** @@ -17,8 +18,9 @@ public class JetClassObject extends JetDeclaration { visitor.visitClassObject(this); } - public JetObjectLiteralExpression getObject() { - return (JetObjectLiteralExpression) findChildByType(JetNodeTypes.OBJECT_LITERAL); + @Nullable @IfNotParsed + public JetObjectDeclaration getObjectDeclaration() { + return (JetObjectDeclaration) findChildByType(JetNodeTypes.OBJECT_DECLARATION); } } diff --git a/idea/src/org/jetbrains/jet/lang/resolve/AnalyzingUtils.java b/idea/src/org/jetbrains/jet/lang/resolve/AnalyzingUtils.java index a0b83f3a7ea..ea7d8560e09 100644 --- a/idea/src/org/jetbrains/jet/lang/resolve/AnalyzingUtils.java +++ b/idea/src/org/jetbrains/jet/lang/resolve/AnalyzingUtils.java @@ -81,31 +81,36 @@ public class AnalyzingUtils { // if (false) topDownAnalyzer.process(scope, new NamespaceLike.Adapter(owner) { - @Override - public NamespaceDescriptorImpl getNamespace(String name) { - return null; - } + @Override + public NamespaceDescriptorImpl getNamespace(String name) { + return null; + } - @Override - public void addNamespace(@NotNull NamespaceDescriptor namespaceDescriptor) { - scope.addNamespace(namespaceDescriptor); - } + @Override + public void addNamespace(@NotNull NamespaceDescriptor namespaceDescriptor) { + scope.addNamespace(namespaceDescriptor); + } - @Override - public void addClassifierDescriptor(@NotNull MutableClassDescriptor classDescriptor) { - scope.addClassifierDescriptor(classDescriptor); - } + @Override + public void addClassifierDescriptor(@NotNull MutableClassDescriptor classDescriptor) { + scope.addClassifierDescriptor(classDescriptor); + } - @Override - public void addFunctionDescriptor(@NotNull FunctionDescriptor functionDescriptor) { - scope.addFunctionDescriptor(functionDescriptor); - } + @Override + public void addFunctionDescriptor(@NotNull FunctionDescriptor functionDescriptor) { + scope.addFunctionDescriptor(functionDescriptor); + } - @Override - public void addPropertyDescriptor(@NotNull PropertyDescriptor propertyDescriptor) { - scope.addVariableDescriptor(propertyDescriptor); - } - }, Collections.singletonList(namespace)); + @Override + public void addPropertyDescriptor(@NotNull PropertyDescriptor propertyDescriptor) { + scope.addVariableDescriptor(propertyDescriptor); + } + + @Override + public void setClassObjectDescriptor(@NotNull MutableClassDescriptor classObjectDescriptor) { + throw new IllegalStateException("Must be guaranteed not to happen by the parser"); + } + }, Collections.singletonList(namespace)); return bindingTraceContext; } diff --git a/idea/src/org/jetbrains/jet/lang/resolve/TopDownAnalyzer.java b/idea/src/org/jetbrains/jet/lang/resolve/TopDownAnalyzer.java index dd6788ff844..ea7d345e246 100644 --- a/idea/src/org/jetbrains/jet/lang/resolve/TopDownAnalyzer.java +++ b/idea/src/org/jetbrains/jet/lang/resolve/TopDownAnalyzer.java @@ -112,6 +112,11 @@ public class TopDownAnalyzer { public void addPropertyDescriptor(@NotNull PropertyDescriptor propertyDescriptor) { } + + @Override + public void setClassObjectDescriptor(@NotNull MutableClassDescriptor classObjectDescriptor) { + + } }, Collections.singletonList(object)); } @@ -168,15 +173,20 @@ public class TopDownAnalyzer { @Override public void visitObjectDeclaration(JetObjectDeclaration declaration) { + createClassDescriptorForObject(declaration); + } + + private MutableClassDescriptor createClassDescriptorForObject(@NotNull JetObjectDeclaration declaration) { MutableClassDescriptor mutableClassDescriptor = visitClassOrObject(declaration, (Map) objects, owner, outerScope); ConstructorDescriptorImpl constructorDescriptor = new ConstructorDescriptorImpl(mutableClassDescriptor, Collections.emptyList(), true); constructorDescriptor.initialize(Collections.emptyList()); // TODO : make the constructor private? mutableClassDescriptor.setPrimaryConstructor(constructorDescriptor); trace.recordDeclarationResolution(declaration, mutableClassDescriptor); + return mutableClassDescriptor; } - private MutableClassDescriptor visitClassOrObject(JetClassOrObject declaration, Map map, NamespaceLike owner, JetScope outerScope) { + private MutableClassDescriptor visitClassOrObject(@NotNull JetClassOrObject declaration, Map map, NamespaceLike owner, JetScope outerScope) { MutableClassDescriptor mutableClassDescriptor = new MutableClassDescriptor(trace, owner, outerScope); mutableClassDescriptor.setName(JetPsiUtil.safeName(declaration.getName())); @@ -202,6 +212,11 @@ public class TopDownAnalyzer { public void visitExtension(JetExtension extension) { trace.getErrorHandler().genericError(extension.getNode(), "Unsupported [TopDownAnalyzer]"); } + + @Override + public void visitClassObject(JetClassObject classObject) { + owner.setClassObjectDescriptor(createClassDescriptorForObject(classObject.getObjectDeclaration())); + } }); } } diff --git a/idea/src/org/jetbrains/jet/lang/resolve/java/JavaClassDescriptor.java b/idea/src/org/jetbrains/jet/lang/resolve/java/JavaClassDescriptor.java index f98b8a3eda6..1e7092c3ecb 100644 --- a/idea/src/org/jetbrains/jet/lang/resolve/java/JavaClassDescriptor.java +++ b/idea/src/org/jetbrains/jet/lang/resolve/java/JavaClassDescriptor.java @@ -87,6 +87,11 @@ public class JavaClassDescriptor extends MutableDeclarationDescriptor implements throw new UnsupportedOperationException(); // TODO } + @Override + public JetType getClassObjectType() { + return null; // TODO : static members as class object members + } + @Override public R accept(DeclarationDescriptorVisitor visitor, D data) { return visitor.visitClassDescriptor(this, data); diff --git a/idea/src/org/jetbrains/jet/lang/types/JetTypeInferrer.java b/idea/src/org/jetbrains/jet/lang/types/JetTypeInferrer.java index f5065ee630a..3991cd4c595 100644 --- a/idea/src/org/jetbrains/jet/lang/types/JetTypeInferrer.java +++ b/idea/src/org/jetbrains/jet/lang/types/JetTypeInferrer.java @@ -704,8 +704,23 @@ public class JetTypeInferrer { trace.getErrorHandler().genericError(expression.getNode(), "This variable is not readable in this context"); } return; - } else if (furtherNameLookup(expression, referencedName)) { - return; + } + else { + ClassifierDescriptor classifier = scope.getClassifier(referencedName); + if (classifier != null) { + JetType classObjectType = classifier.getClassObjectType(); + if (classObjectType != null) { + result = classObjectType; + } + else { + trace.getErrorHandler().genericError(expression.getNode(), "This class does not have a class object"); + } + trace.recordReferenceResolution(expression, classifier); + return; + } + else if (furtherNameLookup(expression, referencedName)) { + return; + } } trace.getErrorHandler().unresolvedReference(expression); }