From 43742828c44d453e55b922071ec07217b31cb76b Mon Sep 17 00:00:00 2001 From: Andrey Breslav Date: Mon, 25 Apr 2011 18:54:05 +0400 Subject: [PATCH] Multiple declarations contributing to the same namespace are supported --- grammar/src/class.grm | 2 +- .../jet/lang/JetSemanticServices.java | 7 +- .../jet/lang/parsing/JetParsing.java | 10 +- .../jet/lang/resolve/JetScopeAdapter.java | 5 + .../jet/lang/resolve/SubstitutingScope.java | 2 +- .../jet/lang/resolve/TopDownAnalyzer.java | 5 +- .../jet/lang/resolve/WritableScope.java | 296 +----------------- .../jet/lang/resolve/WritableScopeImpl.java | 296 ++++++++++++++++++ .../resolve/WritableScopeWithImports.java | 83 +++++ .../jet/lang/resolve/WriteThroughScope.java | 147 +++++++++ .../jetbrains/jet/lang/types/ErrorUtils.java | 8 +- .../jet/lang/types/JetStandardClasses.java | 3 +- .../jet/lang/types/NamespaceDescriptor.java | 1 + .../jet/lang/types/NamespaceType.java | 3 +- idea/testData/checker/NamespaceQualified.jet | 52 +++ idea/testData/resolve/Namespaces.jet | 22 ++ .../jetbrains/jet/resolve/JetResolveTest.java | 4 + 17 files changed, 649 insertions(+), 297 deletions(-) create mode 100644 idea/src/org/jetbrains/jet/lang/resolve/WritableScopeImpl.java create mode 100644 idea/src/org/jetbrains/jet/lang/resolve/WritableScopeWithImports.java create mode 100644 idea/src/org/jetbrains/jet/lang/resolve/WriteThroughScope.java create mode 100644 idea/testData/checker/NamespaceQualified.jet create mode 100644 idea/testData/resolve/Namespaces.jet diff --git a/grammar/src/class.grm b/grammar/src/class.grm index e94fdfecd12..d808ea17add 100644 --- a/grammar/src/class.grm +++ b/grammar/src/class.grm @@ -13,7 +13,7 @@ internal class Example>(protected val x : Foo, y : So class : modifiers "class" SimpleName typeParameters? - "wraps"? + ("wraps" | modifiers)? valueParameters? (":" attributes delegationSpecifier{","})? (classBody? | enumClassBody) diff --git a/idea/src/org/jetbrains/jet/lang/JetSemanticServices.java b/idea/src/org/jetbrains/jet/lang/JetSemanticServices.java index 2092d88e075..7a78f779de7 100644 --- a/idea/src/org/jetbrains/jet/lang/JetSemanticServices.java +++ b/idea/src/org/jetbrains/jet/lang/JetSemanticServices.java @@ -3,10 +3,7 @@ package org.jetbrains.jet.lang; import com.intellij.openapi.project.Project; import org.jetbrains.annotations.NotNull; import org.jetbrains.jet.lang.cfg.JetFlowInformationProvider; -import org.jetbrains.jet.lang.resolve.ClassDescriptorResolver; -import org.jetbrains.jet.lang.resolve.JetScope; -import org.jetbrains.jet.lang.resolve.OverloadResolver; -import org.jetbrains.jet.lang.resolve.WritableScope; +import org.jetbrains.jet.lang.resolve.*; import org.jetbrains.jet.lang.types.*; /** @@ -66,6 +63,6 @@ public class JetSemanticServices { @NotNull public WritableScope createWritableScope(@NotNull JetScope scope, @NotNull DeclarationDescriptor owner) { - return new WritableScope(scope, owner, errorHandler); + return new WritableScopeImpl(scope, owner, errorHandler); } } diff --git a/idea/src/org/jetbrains/jet/lang/parsing/JetParsing.java b/idea/src/org/jetbrains/jet/lang/parsing/JetParsing.java index f9981016787..0ccc475b30d 100644 --- a/idea/src/org/jetbrains/jet/lang/parsing/JetParsing.java +++ b/idea/src/org/jetbrains/jet/lang/parsing/JetParsing.java @@ -371,7 +371,7 @@ public class JetParsing extends AbstractJetParsing { * class * : modifiers "class" SimpleName * typeParameters? - * "wraps"? + * ("wraps" | modifiers)? * ("(" primaryConstructorParameter{","} ")")? * (":" attributes delegationSpecifier{","})? * (classBody? | enumClassBody) @@ -384,7 +384,13 @@ public class JetParsing extends AbstractJetParsing { expect(IDENTIFIER, "Class name expected", CLASS_NAME_RECOVERY_SET); parseTypeParameterList(TYPE_PARAMETER_GT_RECOVERY_SET); - consumeIf(WRAPS_KEYWORD); + if (at(WRAPS_KEYWORD)) { + advance(); // WRAPS_KEYWORD + } + else { + parseModifierList(); + } + if (at(LPAR)) { parseValueParameterList(false, TokenSet.EMPTY); } diff --git a/idea/src/org/jetbrains/jet/lang/resolve/JetScopeAdapter.java b/idea/src/org/jetbrains/jet/lang/resolve/JetScopeAdapter.java index 7b1e07c50b3..64a1e5eff41 100644 --- a/idea/src/org/jetbrains/jet/lang/resolve/JetScopeAdapter.java +++ b/idea/src/org/jetbrains/jet/lang/resolve/JetScopeAdapter.java @@ -16,6 +16,11 @@ public class JetScopeAdapter implements JetScope { this.scope = scope; } + @NotNull + protected final JetScope getWorkerScope() { + return scope; + } + @NotNull @Override public JetType getThisType() { diff --git a/idea/src/org/jetbrains/jet/lang/resolve/SubstitutingScope.java b/idea/src/org/jetbrains/jet/lang/resolve/SubstitutingScope.java index a4e3930d9c4..ff655795089 100644 --- a/idea/src/org/jetbrains/jet/lang/resolve/SubstitutingScope.java +++ b/idea/src/org/jetbrains/jet/lang/resolve/SubstitutingScope.java @@ -38,7 +38,7 @@ public class SubstitutingScope implements JetScope { if (descriptor instanceof ClassDescriptor) { return new LazySubstitutingClassDescriptor((ClassDescriptor) descriptor, substitutor); } - throw new UnsupportedOperationException(); + throw new UnsupportedOperationException(); // TODO } @Override diff --git a/idea/src/org/jetbrains/jet/lang/resolve/TopDownAnalyzer.java b/idea/src/org/jetbrains/jet/lang/resolve/TopDownAnalyzer.java index 27645f9f5b4..bff4df6c9f4 100644 --- a/idea/src/org/jetbrains/jet/lang/resolve/TopDownAnalyzer.java +++ b/idea/src/org/jetbrains/jet/lang/resolve/TopDownAnalyzer.java @@ -99,11 +99,12 @@ public class TopDownAnalyzer { Collections.emptyList(), // TODO name ); + namespaceDescriptor.initialize(semanticServices.createWritableScope(JetScope.EMPTY, namespaceDescriptor)); declaringScope.addNamespace(namespaceDescriptor); trace.recordDeclarationResolution(namespace, namespaceDescriptor); } - WritableScope namespaceScope = semanticServices.createWritableScope(declaringScope, namespaceDescriptor); + WritableScope namespaceScope = new WriteThroughScope(declaringScope, (WritableScope) namespaceDescriptor.getMemberScope()); namespaceScopes.put(namespace, namespaceScope); for (JetImportDirective importDirective : importDirectives) { @@ -264,7 +265,7 @@ public class TopDownAnalyzer { } private void processClassObject(JetClassObject classObject) { - throw new UnsupportedOperationException(); // TODO + semanticServices.getErrorHandler().genericError(classObject.getNode(), "Class objects are not supported yet"); // TODO } //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// diff --git a/idea/src/org/jetbrains/jet/lang/resolve/WritableScope.java b/idea/src/org/jetbrains/jet/lang/resolve/WritableScope.java index 21f4fa722a3..8f3019cc91a 100644 --- a/idea/src/org/jetbrains/jet/lang/resolve/WritableScope.java +++ b/idea/src/org/jetbrains/jet/lang/resolve/WritableScope.java @@ -2,296 +2,32 @@ package org.jetbrains.jet.lang.resolve; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; -import org.jetbrains.jet.lang.ErrorHandler; import org.jetbrains.jet.lang.types.*; -import java.util.*; - /** * @author abreslav */ -public class WritableScope extends JetScopeAdapter { - @NotNull - private final ErrorHandler errorHandler; +public interface WritableScope extends JetScope { + void addLabeledDeclaration(@NotNull DeclarationDescriptor descriptor); - @NotNull - private final DeclarationDescriptor ownerDeclarationDescriptor; + void addVariableDescriptor(@NotNull VariableDescriptor variableDescriptor); - // FieldNames include "$" - @Nullable - private Map propertyDescriptorsByFieldNames; + void addFunctionDescriptor(@NotNull FunctionDescriptor functionDescriptor); + + void addTypeParameterDescriptor(@NotNull TypeParameterDescriptor typeParameterDescriptor); + + void addClassifierDescriptor(@NotNull ClassifierDescriptor classDescriptor); + + void addClassifierAlias(@NotNull String name, @NotNull ClassifierDescriptor classifierDescriptor); + + void addNamespace(@NotNull NamespaceDescriptor namespaceDescriptor); @Nullable - private Map variableDescriptors; - @Nullable - private Map functionGroups; - @Nullable - private Map classifierDescriptors; - @Nullable - private Map namespaceDescriptors; - @Nullable - private Map> labelsToDescriptors; - @Nullable - private JetType thisType; + NamespaceDescriptor getDeclaredNamespace(@NotNull String name); - @Nullable - private List imports; + void addPropertyDescriptorByFieldName(@NotNull String fieldName, @NotNull PropertyDescriptor propertyDescriptor); - public WritableScope(@NotNull JetScope scope, @NotNull DeclarationDescriptor owner, @NotNull ErrorHandler errorHandler) { - super(scope); - this.ownerDeclarationDescriptor = owner; - this.errorHandler = errorHandler; - } + void importScope(@NotNull JetScope imported); - @NotNull - @Override - public DeclarationDescriptor getContainingDeclaration() { - return ownerDeclarationDescriptor; - } - - @NotNull - private Map> getLabelsToDescriptors() { - if (labelsToDescriptors == null) { - labelsToDescriptors = new HashMap>(); - } - return labelsToDescriptors; - } - - @NotNull - @Override - public Collection getDeclarationsByLabel(@NotNull String labelName) { - Map> labelsToDescriptors = getLabelsToDescriptors(); - Collection superResult = super.getDeclarationsByLabel(labelName); - List declarationDescriptors = labelsToDescriptors.get(labelName); - if (declarationDescriptors == null) { - return superResult; - } - if (superResult.isEmpty()) return declarationDescriptors; - List result = new ArrayList(declarationDescriptors); - result.addAll(superResult); - return result; - } - - public void addLabeledDeclaration(@NotNull DeclarationDescriptor descriptor) { - Map> labelsToDescriptors = getLabelsToDescriptors(); - String name = descriptor.getName(); - assert name != null; - List declarationDescriptors = labelsToDescriptors.get(name); - if (declarationDescriptors == null) { - declarationDescriptors = new ArrayList(); - labelsToDescriptors.put(name, declarationDescriptors); - } - declarationDescriptors.add(descriptor); - } - - public void importScope(@NotNull JetScope imported) { - getImports().add(0, imported); - } - - @NotNull - private List getImports() { - if (imports == null) { - imports = new ArrayList(); - } - return imports; - } - - @NotNull - private Map getVariableDescriptors() { - if (variableDescriptors == null) { - variableDescriptors = new HashMap(); - } - return variableDescriptors; - } - - public void addVariableDescriptor(VariableDescriptor variableDescriptor) { - Map propertyDescriptors = getVariableDescriptors(); - VariableDescriptor existingDescriptor = propertyDescriptors.get(variableDescriptor.getName()); - if (existingDescriptor != null) { - errorHandler.redeclaration(existingDescriptor, variableDescriptor); - } - // TODO : Should this always happen? - propertyDescriptors.put(variableDescriptor.getName(), variableDescriptor); - } - - @Override - public VariableDescriptor getVariable(@NotNull String name) { - @NotNull - Map propertyDescriptors = getVariableDescriptors(); - VariableDescriptor variableDescriptor = propertyDescriptors.get(name); - if (variableDescriptor != null) { - return variableDescriptor; - } - variableDescriptor = super.getVariable(name); - if (variableDescriptor != null) { - return variableDescriptor; - } - for (JetScope imported : getImports()) { - VariableDescriptor importedDescriptor = imported.getVariable(name); - if (importedDescriptor != null) { - return importedDescriptor; - } - } - return null; - } - - @NotNull - private Map getFunctionGroups() { - if (functionGroups == null) { - functionGroups = new HashMap(); - } - return functionGroups; - } - - public void addFunctionDescriptor(FunctionDescriptor functionDescriptor) { - String name = functionDescriptor.getName(); - Map functionGroups = getFunctionGroups(); - - @Nullable - WritableFunctionGroup functionGroup = functionGroups.get(name); - if (functionGroup == null) { - functionGroup = new WritableFunctionGroup(name); - functionGroups.put(name, functionGroup); - } - functionGroup.addFunction(functionDescriptor); - } - - @Override - @NotNull - public FunctionGroup getFunctionGroup(@NotNull String name) { - FunctionGroup functionGroup = getFunctionGroups().get(name); - if (functionGroup != null && !functionGroup.isEmpty()) { - return functionGroup; - } - // TODO : this logic is questionable - functionGroup = super.getFunctionGroup(name); - if (!functionGroup.isEmpty()) return functionGroup; - for (JetScope imported : getImports()) { - FunctionGroup importedDescriptor = imported.getFunctionGroup(name); - if (!importedDescriptor.isEmpty()) { - return importedDescriptor; - } - } - return functionGroup; - } - - public void addTypeParameterDescriptor(TypeParameterDescriptor typeParameterDescriptor) { - String name = typeParameterDescriptor.getName(); - Map classifierDescriptors = getClassifierDescriptors(); - ClassifierDescriptor originalDescriptor = classifierDescriptors.get(name); - if (originalDescriptor != null) { - errorHandler.redeclaration(originalDescriptor, typeParameterDescriptor); - } - classifierDescriptors.put(name, typeParameterDescriptor); - } - - @NotNull - private Map getClassifierDescriptors() { - if (classifierDescriptors == null) { - classifierDescriptors = new HashMap(); - } - return classifierDescriptors; - } - - public void addClassifierDescriptor(@NotNull ClassifierDescriptor classDescriptor) { - addClassifierAlias(classDescriptor.getName(), classDescriptor); - } - - public void addClassifierAlias(String name, ClassifierDescriptor classifierDescriptor) { - Map classifierDescriptors = getClassifierDescriptors(); - ClassifierDescriptor originalDescriptor = classifierDescriptors.get(name); - if (originalDescriptor != null) { - errorHandler.redeclaration(originalDescriptor, classifierDescriptor); - } - classifierDescriptors.put(name, classifierDescriptor); - } - - @Override - public ClassifierDescriptor getClassifier(@NotNull String name) { - ClassifierDescriptor classifierDescriptor = getClassifierDescriptors().get(name); - if (classifierDescriptor != null) return classifierDescriptor; - - classifierDescriptor = super.getClassifier(name); - if (classifierDescriptor != null) return classifierDescriptor; - for (JetScope imported : getImports()) { - ClassifierDescriptor importedClassifier = imported.getClassifier(name); - if (importedClassifier != null) { - return importedClassifier; - } - } - return null; - } - - @NotNull - @Override - public JetType getThisType() { - if (thisType == null) { - return super.getThisType(); - } - return thisType; - } - - @NotNull - public Map getNamespaceDescriptors() { - if (namespaceDescriptors == null) { - namespaceDescriptors = new HashMap(); - } - return namespaceDescriptors; - } - - public void addNamespace(NamespaceDescriptor namespaceDescriptor) { - NamespaceDescriptor oldValue = getNamespaceDescriptors().put(namespaceDescriptor.getName(), namespaceDescriptor); - if (oldValue != null) { - errorHandler.redeclaration(oldValue, namespaceDescriptor); - } - } - - public NamespaceDescriptor getDeclaredNamespace(@NotNull String name) { - NamespaceDescriptor namespaceDescriptor = getNamespaceDescriptors().get(name); - if (namespaceDescriptor != null) return namespaceDescriptor; - return null; - } - - @Override - public NamespaceDescriptor getNamespace(@NotNull String name) { - NamespaceDescriptor declaredNamespace = getDeclaredNamespace(name); - if (declaredNamespace != null) return declaredNamespace; - - NamespaceDescriptor namespace = super.getNamespace(name); - if (namespace != null) return namespace; - for (JetScope imported : getImports()) { - NamespaceDescriptor importedDescriptor = imported.getNamespace(name); - if (importedDescriptor != null) { - return importedDescriptor; - } - } - return null; - } - - public void setThisType(JetType thisType) { - if (this.thisType != null) { - throw new UnsupportedOperationException("Receiver redeclared"); - } - this.thisType = thisType; - } - - @SuppressWarnings({"NullableProblems"}) - @NotNull - private Map getPropertyDescriptorsByFieldNames() { - if (propertyDescriptorsByFieldNames == null) { - propertyDescriptorsByFieldNames = new HashMap(); - } - return propertyDescriptorsByFieldNames; - } - - public void addPropertyDescriptorByFieldName(@NotNull String fieldName, PropertyDescriptor propertyDescriptor) { - getPropertyDescriptorsByFieldNames().put(fieldName, propertyDescriptor); - } - - @Override - public PropertyDescriptor getPropertyByFieldReference(@NotNull String fieldName) { - PropertyDescriptor descriptor = getPropertyDescriptorsByFieldNames().get(fieldName); - if (descriptor != null) return descriptor; - return super.getPropertyByFieldReference(fieldName); - } + void setThisType(@NotNull JetType thisType); } diff --git a/idea/src/org/jetbrains/jet/lang/resolve/WritableScopeImpl.java b/idea/src/org/jetbrains/jet/lang/resolve/WritableScopeImpl.java new file mode 100644 index 00000000000..1f15ab77962 --- /dev/null +++ b/idea/src/org/jetbrains/jet/lang/resolve/WritableScopeImpl.java @@ -0,0 +1,296 @@ +package org.jetbrains.jet.lang.resolve; + +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; +import org.jetbrains.jet.lang.ErrorHandler; +import org.jetbrains.jet.lang.types.*; + +import java.util.*; + +/** + * @author abreslav + */ +public class WritableScopeImpl extends WritableScopeWithImports { + @NotNull + private final ErrorHandler errorHandler; + + @NotNull + private final DeclarationDescriptor ownerDeclarationDescriptor; + + // FieldNames include "$" + @Nullable + private Map propertyDescriptorsByFieldNames; + + @Nullable + private Map variableDescriptors; + @Nullable + private Map functionGroups; + @Nullable + private Map classifierDescriptors; + @Nullable + private Map namespaceDescriptors; + @Nullable + private Map> labelsToDescriptors; + @Nullable + private JetType thisType; + + public WritableScopeImpl(@NotNull JetScope scope, @NotNull DeclarationDescriptor owner, @NotNull ErrorHandler errorHandler) { + super(scope); + this.ownerDeclarationDescriptor = owner; + this.errorHandler = errorHandler; + } + + @NotNull + @Override + public DeclarationDescriptor getContainingDeclaration() { + return ownerDeclarationDescriptor; + } + + @NotNull + private Map> getLabelsToDescriptors() { + if (labelsToDescriptors == null) { + labelsToDescriptors = new HashMap>(); + } + return labelsToDescriptors; + } + + @NotNull + @Override + public Collection getDeclarationsByLabel(@NotNull String labelName) { + Map> labelsToDescriptors = getLabelsToDescriptors(); + Collection superResult = super.getDeclarationsByLabel(labelName); + List declarationDescriptors = labelsToDescriptors.get(labelName); + if (declarationDescriptors == null) { + return superResult; + } + if (superResult.isEmpty()) return declarationDescriptors; + List result = new ArrayList(declarationDescriptors); + result.addAll(superResult); + return result; + } + + @Override + public void addLabeledDeclaration(@NotNull DeclarationDescriptor descriptor) { + Map> labelsToDescriptors = getLabelsToDescriptors(); + String name = descriptor.getName(); + assert name != null; + List declarationDescriptors = labelsToDescriptors.get(name); + if (declarationDescriptors == null) { + declarationDescriptors = new ArrayList(); + labelsToDescriptors.put(name, declarationDescriptors); + } + declarationDescriptors.add(descriptor); + } + + @NotNull + private Map getVariableDescriptors() { + if (variableDescriptors == null) { + variableDescriptors = new HashMap(); + } + return variableDescriptors; + } + + @Override + public void addVariableDescriptor(@NotNull VariableDescriptor variableDescriptor) { + Map propertyDescriptors = getVariableDescriptors(); + VariableDescriptor existingDescriptor = propertyDescriptors.get(variableDescriptor.getName()); + if (existingDescriptor != null) { + errorHandler.redeclaration(existingDescriptor, variableDescriptor); + } + // TODO : Should this always happen? + propertyDescriptors.put(variableDescriptor.getName(), variableDescriptor); + } + + @Override + public VariableDescriptor getVariable(@NotNull String name) { + @NotNull + Map propertyDescriptors = getVariableDescriptors(); + VariableDescriptor variableDescriptor = propertyDescriptors.get(name); + if (variableDescriptor != null) { + return variableDescriptor; + } + variableDescriptor = getWorkerScope().getVariable(name); + if (variableDescriptor != null) { + return variableDescriptor; + } +// for (JetScope imported : getImports()) { +// VariableDescriptor importedDescriptor = imported.getVariable(name); +// if (importedDescriptor != null) { +// return importedDescriptor; +// } +// } +// return null; + return super.getVariable(name); + } + + @NotNull + private Map getFunctionGroups() { + if (functionGroups == null) { + functionGroups = new HashMap(); + } + return functionGroups; + } + + @Override + public void addFunctionDescriptor(@NotNull FunctionDescriptor functionDescriptor) { + String name = functionDescriptor.getName(); + Map functionGroups = getFunctionGroups(); + + @Nullable + WritableFunctionGroup functionGroup = functionGroups.get(name); + if (functionGroup == null) { + functionGroup = new WritableFunctionGroup(name); + functionGroups.put(name, functionGroup); + } + functionGroup.addFunction(functionDescriptor); + } + + @Override + @NotNull + public FunctionGroup getFunctionGroup(@NotNull String name) { + FunctionGroup functionGroup = getFunctionGroups().get(name); + if (functionGroup != null && !functionGroup.isEmpty()) { + return functionGroup; + } + // TODO : this logic is questionable + functionGroup = getWorkerScope().getFunctionGroup(name); + if (!functionGroup.isEmpty()) return functionGroup; +// for (JetScope imported : getImports()) { +// FunctionGroup importedDescriptor = imported.getFunctionGroup(name); +// if (!importedDescriptor.isEmpty()) { +// return importedDescriptor; +// } +// } +// return functionGroup; + return super.getFunctionGroup(name); + } + + @Override + public void addTypeParameterDescriptor(@NotNull TypeParameterDescriptor typeParameterDescriptor) { + String name = typeParameterDescriptor.getName(); + Map classifierDescriptors = getClassifierDescriptors(); + ClassifierDescriptor originalDescriptor = classifierDescriptors.get(name); + if (originalDescriptor != null) { + errorHandler.redeclaration(originalDescriptor, typeParameterDescriptor); + } + classifierDescriptors.put(name, typeParameterDescriptor); + } + + @NotNull + private Map getClassifierDescriptors() { + if (classifierDescriptors == null) { + classifierDescriptors = new HashMap(); + } + return classifierDescriptors; + } + + @Override + public void addClassifierDescriptor(@NotNull ClassifierDescriptor classDescriptor) { + addClassifierAlias(classDescriptor.getName(), classDescriptor); + } + + @Override + public void addClassifierAlias(@NotNull String name, @NotNull ClassifierDescriptor classifierDescriptor) { + Map classifierDescriptors = getClassifierDescriptors(); + ClassifierDescriptor originalDescriptor = classifierDescriptors.get(name); + if (originalDescriptor != null) { + errorHandler.redeclaration(originalDescriptor, classifierDescriptor); + } + classifierDescriptors.put(name, classifierDescriptor); + } + + @Override + public ClassifierDescriptor getClassifier(@NotNull String name) { + ClassifierDescriptor classifierDescriptor = getClassifierDescriptors().get(name); + if (classifierDescriptor != null) return classifierDescriptor; + + classifierDescriptor = getWorkerScope().getClassifier(name); + if (classifierDescriptor != null) return classifierDescriptor; +// for (JetScope imported : getImports()) { +// ClassifierDescriptor importedClassifier = imported.getClassifier(name); +// if (importedClassifier != null) { +// return importedClassifier; +// } +// } +// return null; + return super.getClassifier(name); + } + + @NotNull + @Override + public JetType getThisType() { + if (thisType == null) { + return super.getThisType(); + } + return thisType; + } + + @NotNull + public Map getNamespaceDescriptors() { + if (namespaceDescriptors == null) { + namespaceDescriptors = new HashMap(); + } + return namespaceDescriptors; + } + + @Override + public void addNamespace(@NotNull NamespaceDescriptor namespaceDescriptor) { + NamespaceDescriptor oldValue = getNamespaceDescriptors().put(namespaceDescriptor.getName(), namespaceDescriptor); + if (oldValue != null) { + errorHandler.redeclaration(oldValue, namespaceDescriptor); + } + } + + @Override + public NamespaceDescriptor getDeclaredNamespace(@NotNull String name) { + NamespaceDescriptor namespaceDescriptor = getNamespaceDescriptors().get(name); + if (namespaceDescriptor != null) return namespaceDescriptor; + return null; + } + + @Override + public NamespaceDescriptor getNamespace(@NotNull String name) { + NamespaceDescriptor declaredNamespace = getDeclaredNamespace(name); + if (declaredNamespace != null) return declaredNamespace; + + NamespaceDescriptor namespace = getWorkerScope().getNamespace(name); + if (namespace != null) return namespace; +// for (JetScope imported : getImports()) { +// NamespaceDescriptor importedDescriptor = imported.getNamespace(name); +// if (importedDescriptor != null) { +// return importedDescriptor; +// } +// } +// return null; + return super.getNamespace(name); + } + + @Override + public void setThisType(@NotNull JetType thisType) { + if (this.thisType != null) { + throw new UnsupportedOperationException("Receiver redeclared"); + } + this.thisType = thisType; + } + + @SuppressWarnings({"NullableProblems"}) + @NotNull + private Map getPropertyDescriptorsByFieldNames() { + if (propertyDescriptorsByFieldNames == null) { + propertyDescriptorsByFieldNames = new HashMap(); + } + return propertyDescriptorsByFieldNames; + } + + @Override + public void addPropertyDescriptorByFieldName(@NotNull String fieldName, @NotNull PropertyDescriptor propertyDescriptor) { + getPropertyDescriptorsByFieldNames().put(fieldName, propertyDescriptor); + } + + @Override + public PropertyDescriptor getPropertyByFieldReference(@NotNull String fieldName) { + PropertyDescriptor descriptor = getPropertyDescriptorsByFieldNames().get(fieldName); + if (descriptor != null) return descriptor; + return super.getPropertyByFieldReference(fieldName); + } +} diff --git a/idea/src/org/jetbrains/jet/lang/resolve/WritableScopeWithImports.java b/idea/src/org/jetbrains/jet/lang/resolve/WritableScopeWithImports.java new file mode 100644 index 00000000000..f2c4c2af854 --- /dev/null +++ b/idea/src/org/jetbrains/jet/lang/resolve/WritableScopeWithImports.java @@ -0,0 +1,83 @@ +package org.jetbrains.jet.lang.resolve; + +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; +import org.jetbrains.jet.lang.types.ClassifierDescriptor; +import org.jetbrains.jet.lang.types.FunctionGroup; +import org.jetbrains.jet.lang.types.NamespaceDescriptor; +import org.jetbrains.jet.lang.types.VariableDescriptor; + +import java.util.ArrayList; +import java.util.List; + +/** + * @author abreslav + */ +public abstract class WritableScopeWithImports extends JetScopeAdapter implements WritableScope { + + @Nullable + private List imports; + + public WritableScopeWithImports(@NotNull JetScope scope) { + super(scope); + } + + @NotNull + protected final List getImports() { + if (imports == null) { + imports = new ArrayList(); + } + return imports; + } + + @Override + public void importScope(@NotNull JetScope imported) { + getImports().add(0, imported); + } + + @Override + public VariableDescriptor getVariable(@NotNull String name) { + // Meaningful lookup goes here + for (JetScope imported : getImports()) { + VariableDescriptor importedDescriptor = imported.getVariable(name); + if (importedDescriptor != null) { + return importedDescriptor; + } + } + return null; + } + + @NotNull + @Override + public FunctionGroup getFunctionGroup(@NotNull String name) { + for (JetScope imported : getImports()) { + FunctionGroup importedDescriptor = imported.getFunctionGroup(name); + if (!importedDescriptor.isEmpty()) { + return importedDescriptor; + } + } + return FunctionGroup.EMPTY; + } + + @Override + public ClassifierDescriptor getClassifier(@NotNull String name) { + for (JetScope imported : getImports()) { + ClassifierDescriptor importedClassifier = imported.getClassifier(name); + if (importedClassifier != null) { + return importedClassifier; + } + } + return null; + } + + @Override + public NamespaceDescriptor getNamespace(@NotNull String name) { + for (JetScope imported : getImports()) { + NamespaceDescriptor importedDescriptor = imported.getNamespace(name); + if (importedDescriptor != null) { + return importedDescriptor; + } + } + return null; + } +} diff --git a/idea/src/org/jetbrains/jet/lang/resolve/WriteThroughScope.java b/idea/src/org/jetbrains/jet/lang/resolve/WriteThroughScope.java new file mode 100644 index 00000000000..425c8a5f281 --- /dev/null +++ b/idea/src/org/jetbrains/jet/lang/resolve/WriteThroughScope.java @@ -0,0 +1,147 @@ +package org.jetbrains.jet.lang.resolve; + +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; +import org.jetbrains.jet.lang.types.*; + +import java.util.Collection; + +/** + * @author abreslav + */ +public class WriteThroughScope extends WritableScopeWithImports { + private final WritableScope writableWorker; + + public WriteThroughScope(@NotNull JetScope outerScope, @NotNull WritableScope scope) { + super(outerScope); + this.writableWorker = scope; + } + + @Override + @Nullable + public PropertyDescriptor getPropertyByFieldReference(@NotNull String fieldName) { + return writableWorker.getPropertyByFieldReference(fieldName); + } + + @Override + @NotNull + public Collection getDeclarationsByLabel(String labelName) { + return writableWorker.getDeclarationsByLabel(labelName); + } + + @Override + @NotNull + public DeclarationDescriptor getContainingDeclaration() { + return writableWorker.getContainingDeclaration(); + } + + @Override + @NotNull + public JetType getThisType() { + return writableWorker.getThisType(); + } + + @Override + @NotNull + public FunctionGroup getFunctionGroup(@NotNull String name) { + FunctionGroup functionGroup = writableWorker.getFunctionGroup(name); + if (!functionGroup.isEmpty()) return functionGroup; // TODO : Overloads from different places + + functionGroup = getWorkerScope().getFunctionGroup(name); + if (!functionGroup.isEmpty()) return functionGroup; // TODO : Overloads from different places + + return super.getFunctionGroup(name); // Imports + } + + @Override + @Nullable + public VariableDescriptor getVariable(@NotNull String name) { + VariableDescriptor variable = writableWorker.getVariable(name); + if (variable != null) return variable; + + variable = getWorkerScope().getVariable(name); + if (variable != null) return variable; + + return super.getVariable(name); // Imports + } + + @Override + @Nullable + public NamespaceDescriptor getNamespace(@NotNull String name) { + NamespaceDescriptor namespace = writableWorker.getNamespace(name); + if (namespace != null) return namespace; + + namespace = getWorkerScope().getNamespace(name); + if (namespace != null) return namespace; + + return super.getNamespace(name); // Imports + } + + @Override + @Nullable + public ClassifierDescriptor getClassifier(@NotNull String name) { + ClassifierDescriptor classifier = writableWorker.getClassifier(name); + if (classifier != null) return classifier; + + classifier = getWorkerScope().getClassifier(name); + if (classifier != null) return classifier; + + return super.getClassifier(name); // Imports + } + + @Override + public void addLabeledDeclaration(@NotNull DeclarationDescriptor descriptor) { + writableWorker.addLabeledDeclaration(descriptor); // TODO : review + } + + @Override + public void addVariableDescriptor(@NotNull VariableDescriptor variableDescriptor) { + writableWorker.addVariableDescriptor(variableDescriptor); + } + + @Override + public void addFunctionDescriptor(@NotNull FunctionDescriptor functionDescriptor) { + writableWorker.addFunctionDescriptor(functionDescriptor); + } + + @Override + public void addTypeParameterDescriptor(@NotNull TypeParameterDescriptor typeParameterDescriptor) { + writableWorker.addTypeParameterDescriptor(typeParameterDescriptor); + } + + @Override + public void addClassifierDescriptor(@NotNull ClassifierDescriptor classDescriptor) { + writableWorker.addClassifierDescriptor(classDescriptor); + } + + @Override + public void addClassifierAlias(@NotNull String name, @NotNull ClassifierDescriptor classifierDescriptor) { + writableWorker.addClassifierAlias(name, classifierDescriptor); + } + + @Override + public void addNamespace(@NotNull NamespaceDescriptor namespaceDescriptor) { + writableWorker.addNamespace(namespaceDescriptor); + } + + @Override + @Nullable + public NamespaceDescriptor getDeclaredNamespace(@NotNull String name) { + return writableWorker.getDeclaredNamespace(name); + } + + @Override + public void addPropertyDescriptorByFieldName(@NotNull String fieldName, @NotNull PropertyDescriptor propertyDescriptor) { + writableWorker.addPropertyDescriptorByFieldName(fieldName, propertyDescriptor); + } + + @Override + public void importScope(@NotNull JetScope imported) { + super.importScope(imported); // + } + + @Override + public void setThisType(@NotNull JetType thisType) { + writableWorker.setThisType(thisType); + } +} diff --git a/idea/src/org/jetbrains/jet/lang/types/ErrorUtils.java b/idea/src/org/jetbrains/jet/lang/types/ErrorUtils.java index 5d87e93b6bb..e260e39a396 100644 --- a/idea/src/org/jetbrains/jet/lang/types/ErrorUtils.java +++ b/idea/src/org/jetbrains/jet/lang/types/ErrorUtils.java @@ -141,10 +141,6 @@ public class ErrorUtils { return createErrorType(value + " is not allowed here]", value.getType().getMemberScope()); } - public static boolean isErrorType(JetType type) { - return type instanceof ErrorTypeImpl; - } - public static ClassifierDescriptor getErrorClass() { return ERROR_CLASS; } @@ -153,6 +149,10 @@ public class ErrorUtils { return typeConstructor == ERROR_CLASS.getTypeConstructor(); } + public static boolean isErrorType(JetType type) { + return type instanceof ErrorTypeImpl || isError(type.getConstructor()); + } + private static class ErrorTypeImpl implements JetType { private final TypeConstructor constructor; diff --git a/idea/src/org/jetbrains/jet/lang/types/JetStandardClasses.java b/idea/src/org/jetbrains/jet/lang/types/JetStandardClasses.java index 2a7a07109e1..7e3f8a6e45b 100644 --- a/idea/src/org/jetbrains/jet/lang/types/JetStandardClasses.java +++ b/idea/src/org/jetbrains/jet/lang/types/JetStandardClasses.java @@ -5,6 +5,7 @@ import org.jetbrains.annotations.Nullable; import org.jetbrains.jet.lang.ErrorHandler; import org.jetbrains.jet.lang.resolve.JetScope; import org.jetbrains.jet.lang.resolve.WritableScope; +import org.jetbrains.jet.lang.resolve.WritableScopeImpl; import java.lang.reflect.Field; import java.lang.reflect.Modifier; @@ -164,7 +165,7 @@ public class JetStandardClasses { /*package*/ static final JetScope STANDARD_CLASSES; static { - WritableScope writableScope = new WritableScope(JetScope.EMPTY, STANDARD_CLASSES_NAMESPACE, ErrorHandler.DO_NOTHING); + WritableScope writableScope = new WritableScopeImpl(JetScope.EMPTY, STANDARD_CLASSES_NAMESPACE, ErrorHandler.DO_NOTHING); STANDARD_CLASSES = writableScope; writableScope.addClassifierAlias("Unit", getTuple(0)); diff --git a/idea/src/org/jetbrains/jet/lang/types/NamespaceDescriptor.java b/idea/src/org/jetbrains/jet/lang/types/NamespaceDescriptor.java index ac86cb5d552..3a23fc65a40 100644 --- a/idea/src/org/jetbrains/jet/lang/types/NamespaceDescriptor.java +++ b/idea/src/org/jetbrains/jet/lang/types/NamespaceDescriptor.java @@ -30,6 +30,7 @@ public class NamespaceDescriptor extends DeclarationDescriptorImpl { @NotNull public NamespaceType getNamespaceType() { if (namespaceType == null) { + assert memberScope != null : "Member scope not set"; namespaceType = new NamespaceType(getName(), memberScope); } return namespaceType; diff --git a/idea/src/org/jetbrains/jet/lang/types/NamespaceType.java b/idea/src/org/jetbrains/jet/lang/types/NamespaceType.java index 8560b94cfef..3f96c27a153 100644 --- a/idea/src/org/jetbrains/jet/lang/types/NamespaceType.java +++ b/idea/src/org/jetbrains/jet/lang/types/NamespaceType.java @@ -13,9 +13,10 @@ import java.util.List; */ public class NamespaceType implements JetType { private final String name; + @NotNull private final JetScope memberScope; - public NamespaceType(String name, JetScope memberScope) { + public NamespaceType(@NotNull String name, @NotNull JetScope memberScope) { this.name = name; this.memberScope = memberScope; } diff --git a/idea/testData/checker/NamespaceQualified.jet b/idea/testData/checker/NamespaceQualified.jet new file mode 100644 index 00000000000..407c67e2cd0 --- /dev/null +++ b/idea/testData/checker/NamespaceQualified.jet @@ -0,0 +1,52 @@ +namespace foobar + +namespace a { + import java.* + + val a : util.List? = null + val a1 : List? = null + +} + +namespace a { + import java.util.* + + val b : List? = a + val b1 : util.List? = a +} + +val x1 = a.a + +val y1 = a.b + + +///////////////////////////////////////////////////////////////////////// + +fun done(result : O) : Iteratee + +class Iteratee { + abstract fun process(item : I) : Iteratee + abstract val isDone : Boolean + abstract val result : O + abstract fun done() : O +} + +class Sum : Iteratee { + override fun process(item : Int) : Iteratee { + return foobar.done(item); + } + override val isDone : Boolean + override val result : Int + override fun done() : Int +} + +class Collection : Iterable { + fun iterate(iteratee : Iteratee) : O { + for (x in this) { + val it = iteratee.process(x) + if (it.isDone) return it.result + iteratee = it + } + return iteratee.done() + } +} \ No newline at end of file diff --git a/idea/testData/resolve/Namespaces.jet b/idea/testData/resolve/Namespaces.jet new file mode 100644 index 00000000000..42a3a88bef1 --- /dev/null +++ b/idea/testData/resolve/Namespaces.jet @@ -0,0 +1,22 @@ +namespace root + +~a~namespace a { + import java.* + + ~a.a~val a : util.List? = null + + val y : Any? = `a.b`b + +} + +namespace a { + import java.util.* + + ~a.b~val b : List? = null + + val x = `a.a`a +} + +val x = `a`a.`a.a`a + +val y = `a`a.`a.b`b \ No newline at end of file diff --git a/idea/tests/org/jetbrains/jet/resolve/JetResolveTest.java b/idea/tests/org/jetbrains/jet/resolve/JetResolveTest.java index b2d41cb04b2..3a96087952a 100644 --- a/idea/tests/org/jetbrains/jet/resolve/JetResolveTest.java +++ b/idea/tests/org/jetbrains/jet/resolve/JetResolveTest.java @@ -147,4 +147,8 @@ public class JetResolveTest extends ExtensibleResolveTestCase { doTest("/resolve/ConstructorsAndInitializers.jet", true, true); } + public void testNamespaces() throws Exception { + doTest("/resolve/Namespaces.jet", true, true); + } + } \ No newline at end of file