From 1866a245faefa5284718181b802ea17efb8323e1 Mon Sep 17 00:00:00 2001 From: Stepan Koltsov Date: Wed, 30 Nov 2011 02:44:17 +0400 Subject: [PATCH] WritableScope.changeLockLevel() There are thress lock levels: reading, writing, both. Scope modification is not allowed in "reading" and scope data access is not allowed in "writing". --- .../descriptors/FunctionDescriptorUtil.java | 1 + .../descriptors/MutableClassDescriptor.java | 13 +++++ .../jet/lang/resolve/AnalyzingUtils.java | 1 + .../jet/lang/resolve/BodyResolver.java | 4 ++ .../jet/lang/resolve/DescriptorResolver.java | 11 ++++- .../jet/lang/resolve/TopDownAnalyzer.java | 10 ++++ .../lang/resolve/TypeHierarchyResolver.java | 5 +- .../lang/resolve/scopes/WritableScope.java | 8 +++ .../resolve/scopes/WritableScopeImpl.java | 49 +++++++++++++++++++ .../scopes/WritableScopeWithImports.java | 46 +++++++++++++++++ .../resolve/scopes/WriteThroughScope.java | 44 +++++++++++++++++ .../jet/lang/types/JetStandardClasses.java | 2 + .../jet/lang/types/JetStandardLibrary.java | 2 + .../expressions/ExpressionTypingServices.java | 1 + .../expressions/ExpressionTypingUtils.java | 5 +- .../JetDefaultModalityModifiersTest.java | 2 + .../jet/types/JetTypeCheckerTest.java | 3 ++ 17 files changed, 203 insertions(+), 4 deletions(-) diff --git a/compiler/frontend/src/org/jetbrains/jet/lang/descriptors/FunctionDescriptorUtil.java b/compiler/frontend/src/org/jetbrains/jet/lang/descriptors/FunctionDescriptorUtil.java index e4bc91d4854..8208b807e8f 100644 --- a/compiler/frontend/src/org/jetbrains/jet/lang/descriptors/FunctionDescriptorUtil.java +++ b/compiler/frontend/src/org/jetbrains/jet/lang/descriptors/FunctionDescriptorUtil.java @@ -80,6 +80,7 @@ public class FunctionDescriptorUtil { parameterScope.addVariableDescriptor(valueParameterDescriptor); } parameterScope.addLabeledDeclaration(descriptor); + parameterScope.changeLockLevel(WritableScope.LockLevel.READING); return parameterScope; } diff --git a/compiler/frontend/src/org/jetbrains/jet/lang/descriptors/MutableClassDescriptor.java b/compiler/frontend/src/org/jetbrains/jet/lang/descriptors/MutableClassDescriptor.java index 669af46b9ae..525a8d93d05 100644 --- a/compiler/frontend/src/org/jetbrains/jet/lang/descriptors/MutableClassDescriptor.java +++ b/compiler/frontend/src/org/jetbrains/jet/lang/descriptors/MutableClassDescriptor.java @@ -49,8 +49,11 @@ public class MutableClassDescriptor extends MutableDeclarationDescriptor impleme super(containingDeclaration); TraceBasedRedeclarationHandler redeclarationHandler = new TraceBasedRedeclarationHandler(trace); this.scopeForMemberLookup = new WritableScopeImpl(JetScope.EMPTY, this, redeclarationHandler).setDebugName("MemberLookup"); + this.scopeForMemberLookup.changeLockLevel(WritableScope.LockLevel.BOTH); this.scopeForSupertypeResolution = new WritableScopeImpl(outerScope, this, redeclarationHandler).setDebugName("SupertypeResolution"); + this.scopeForSupertypeResolution.changeLockLevel(WritableScope.LockLevel.BOTH); this.scopeForMemberResolution = new WritableScopeImpl(scopeForSupertypeResolution, this, redeclarationHandler).setDebugName("MemberResolution"); + this.scopeForMemberResolution.changeLockLevel(WritableScope.LockLevel.BOTH); this.kind = kind; } @@ -180,6 +183,7 @@ public class MutableClassDescriptor extends MutableDeclarationDescriptor impleme this.typeParameters.add(typeParameterDescriptor); scopeForSupertypeResolution.addTypeParameterDescriptor(typeParameterDescriptor); } + scopeForSupertypeResolution.changeLockLevel(WritableScope.LockLevel.READING); } //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// @@ -344,4 +348,13 @@ public class MutableClassDescriptor extends MutableDeclarationDescriptor impleme } return implicitReceiver; } + + public void lockScopes() { + scopeForSupertypeResolution.changeLockLevel(WritableScope.LockLevel.READING); + scopeForMemberLookup.changeLockLevel(WritableScope.LockLevel.READING); + scopeForMemberResolution.changeLockLevel(WritableScope.LockLevel.READING); + if (classObjectDescriptor != null) { + classObjectDescriptor.lockScopes(); + } + } } diff --git a/compiler/frontend/src/org/jetbrains/jet/lang/resolve/AnalyzingUtils.java b/compiler/frontend/src/org/jetbrains/jet/lang/resolve/AnalyzingUtils.java index da5cb3020b5..13cb17841bc 100644 --- a/compiler/frontend/src/org/jetbrains/jet/lang/resolve/AnalyzingUtils.java +++ b/compiler/frontend/src/org/jetbrains/jet/lang/resolve/AnalyzingUtils.java @@ -96,6 +96,7 @@ public class AnalyzingUtils { final WritableScope scope = new WritableScopeImpl(JetScope.EMPTY, owner, new TraceBasedRedeclarationHandler(bindingTraceContext)).setDebugName("Root scope in analyzeNamespace"); importingStrategy.addImports(project, semanticServices, bindingTraceContext, scope); scope.importScope(libraryScope); + scope.changeLockLevel(WritableScope.LockLevel.BOTH); TopDownAnalyzer.process(semanticServices, bindingTraceContext, scope, new NamespaceLike.Adapter(owner) { diff --git a/compiler/frontend/src/org/jetbrains/jet/lang/resolve/BodyResolver.java b/compiler/frontend/src/org/jetbrains/jet/lang/resolve/BodyResolver.java index dd45fdd7af9..eeab159c182 100644 --- a/compiler/frontend/src/org/jetbrains/jet/lang/resolve/BodyResolver.java +++ b/compiler/frontend/src/org/jetbrains/jet/lang/resolve/BodyResolver.java @@ -382,6 +382,8 @@ public class BodyResolver { } constructorScope.addLabeledDeclaration(descriptor); // TODO : Labels for constructors?! + + constructorScope.changeLockLevel(WritableScope.LockLevel.READING); return constructorScope; } @@ -442,6 +444,7 @@ public class BodyResolver { if (receiver.exists()) { result.setImplicitReceiver(receiver); } + result.changeLockLevel(WritableScope.LockLevel.READING); return result; } @@ -450,6 +453,7 @@ public class BodyResolver { WritableScope accessorScope = new WritableScopeImpl(getPropertyDeclarationInnerScope(declaringScope, propertyDescriptor), declaringScope.getContainingDeclaration(), new TraceBasedRedeclarationHandler(context.getTrace())).setDebugName("Accessor scope"); accessorScope.addPropertyDescriptorByFieldName("$" + propertyDescriptor.getName(), propertyDescriptor); + accessorScope.changeLockLevel(WritableScope.LockLevel.READING); JetPropertyAccessor getter = property.getGetter(); PropertyGetterDescriptor getterDescriptor = propertyDescriptor.getGetter(); diff --git a/compiler/frontend/src/org/jetbrains/jet/lang/resolve/DescriptorResolver.java b/compiler/frontend/src/org/jetbrains/jet/lang/resolve/DescriptorResolver.java index 8be709898fd..8cf81b34574 100644 --- a/compiler/frontend/src/org/jetbrains/jet/lang/resolve/DescriptorResolver.java +++ b/compiler/frontend/src/org/jetbrains/jet/lang/resolve/DescriptorResolver.java @@ -146,6 +146,7 @@ public class DescriptorResolver { innerScope.addLabeledDeclaration(functionDescriptor); List typeParameterDescriptors = resolveTypeParameters(functionDescriptor, innerScope, function.getTypeParameters()); + innerScope.changeLockLevel(WritableScope.LockLevel.BOTH); resolveGenericBounds(function, innerScope, typeParameterDescriptors); JetType receiverType = null; @@ -157,8 +158,10 @@ public class DescriptorResolver { : scope; receiverType = typeResolver.resolveType(scopeForReceiver, receiverTypeRef); } - + List valueParameterDescriptors = resolveValueParameters(functionDescriptor, innerScope, function.getValueParameters()); + + innerScope.changeLockLevel(WritableScope.LockLevel.READING); JetTypeReference returnTypeRef = function.getReturnTypeRef(); JetType returnType; @@ -499,8 +502,10 @@ public class DescriptorResolver { } else { WritableScope writableScope = new WritableScopeImpl(scope, containingDeclaration, new TraceBasedRedeclarationHandler(trace)).setDebugName("Scope with type parameters of a property"); + writableScope.changeLockLevel(WritableScope.LockLevel.BOTH); typeParameterDescriptors = resolveTypeParameters(containingDeclaration, writableScope, typeParameters); resolveGenericBounds(property, writableScope, typeParameterDescriptors); + writableScope.changeLockLevel(WritableScope.LockLevel.READING); scopeWithTypeParameters = writableScope; } @@ -761,11 +766,13 @@ public class DescriptorResolver { isPrimary ); trace.record(BindingContext.CONSTRUCTOR, declarationToTrace, constructorDescriptor); + WritableScopeImpl parameterScope = new WritableScopeImpl(scope, classDescriptor, new TraceBasedRedeclarationHandler(trace)).setDebugName("Scope with value parameters of a constructor"); + parameterScope.changeLockLevel(WritableScope.LockLevel.BOTH); return constructorDescriptor.initialize( typeParameters, resolveValueParameters( constructorDescriptor, - new WritableScopeImpl(scope, classDescriptor, new TraceBasedRedeclarationHandler(trace)).setDebugName("Scope with value parameters of a constructor"), + parameterScope, valueParameters), Modality.FINAL, resolveVisibilityFromModifiers(modifierList)); diff --git a/compiler/frontend/src/org/jetbrains/jet/lang/resolve/TopDownAnalyzer.java b/compiler/frontend/src/org/jetbrains/jet/lang/resolve/TopDownAnalyzer.java index e6a9f31e64d..89bed40037e 100644 --- a/compiler/frontend/src/org/jetbrains/jet/lang/resolve/TopDownAnalyzer.java +++ b/compiler/frontend/src/org/jetbrains/jet/lang/resolve/TopDownAnalyzer.java @@ -60,6 +60,7 @@ public class TopDownAnalyzer { new TypeHierarchyResolver(context).process(outerScope, owner, declarations); new DeclarationResolver(context).process(); new DelegationResolver(context).process(); + lockClasses(context); new OverrideResolver(context).process(); new OverloadResolver(context).process(); if (!context.analyzingBootstrapLibrary()) { @@ -72,6 +73,15 @@ public class TopDownAnalyzer { context.printDebugOutput(System.out); } + private static void lockClasses(TopDownAnalysisContext context) { + for (MutableClassDescriptor mutableClassDescriptor : context.getClasses().values()) { + mutableClassDescriptor.lockScopes(); + } + for (MutableClassDescriptor mutableClassDescriptor : context.getObjects().values()) { + mutableClassDescriptor.lockScopes(); + } + } + public static void processStandardLibraryNamespace( @NotNull JetSemanticServices semanticServices, @NotNull BindingTrace trace, diff --git a/compiler/frontend/src/org/jetbrains/jet/lang/resolve/TypeHierarchyResolver.java b/compiler/frontend/src/org/jetbrains/jet/lang/resolve/TypeHierarchyResolver.java index 2585e655d35..ca5c16a1887 100644 --- a/compiler/frontend/src/org/jetbrains/jet/lang/resolve/TypeHierarchyResolver.java +++ b/compiler/frontend/src/org/jetbrains/jet/lang/resolve/TypeHierarchyResolver.java @@ -78,13 +78,16 @@ public class TypeHierarchyResolver { Collections.emptyList(), // TODO: annotations name ); - namespaceDescriptor.initialize(new WritableScopeImpl(JetScope.EMPTY, namespaceDescriptor, new TraceBasedRedeclarationHandler(context.getTrace())).setDebugName("Namespace member scope")); + WritableScopeImpl memberScope = new WritableScopeImpl(JetScope.EMPTY, namespaceDescriptor, new TraceBasedRedeclarationHandler(context.getTrace())).setDebugName("Namespace member scope"); + memberScope.changeLockLevel(WritableScope.LockLevel.BOTH); + namespaceDescriptor.initialize(memberScope); owner.addNamespace(namespaceDescriptor); context.getTrace().record(BindingContext.NAMESPACE, namespace, namespaceDescriptor); } context.getNamespaceDescriptors().put(namespace, namespaceDescriptor); WriteThroughScope namespaceScope = new WriteThroughScope(outerScope, namespaceDescriptor.getMemberScope(), new TraceBasedRedeclarationHandler(context.getTrace())); + namespaceScope.changeLockLevel(WritableScope.LockLevel.BOTH); context.getNamespaceScopes().put(namespace, namespaceScope); context.getDeclaringScopes().put(namespace, outerScope); diff --git a/compiler/frontend/src/org/jetbrains/jet/lang/resolve/scopes/WritableScope.java b/compiler/frontend/src/org/jetbrains/jet/lang/resolve/scopes/WritableScope.java index f56816079fb..4716d808cc0 100644 --- a/compiler/frontend/src/org/jetbrains/jet/lang/resolve/scopes/WritableScope.java +++ b/compiler/frontend/src/org/jetbrains/jet/lang/resolve/scopes/WritableScope.java @@ -9,6 +9,14 @@ import org.jetbrains.jet.lang.resolve.scopes.receivers.ReceiverDescriptor; * @author abreslav */ public interface WritableScope extends JetScope { + enum LockLevel { + WRITING, + BOTH, + READING, + } + + void changeLockLevel(LockLevel lockLevel); + void addLabeledDeclaration(@NotNull DeclarationDescriptor descriptor); void addVariableDescriptor(@NotNull VariableDescriptor variableDescriptor); diff --git a/compiler/frontend/src/org/jetbrains/jet/lang/resolve/scopes/WritableScopeImpl.java b/compiler/frontend/src/org/jetbrains/jet/lang/resolve/scopes/WritableScopeImpl.java index ed1febfd63a..97bd74167b8 100644 --- a/compiler/frontend/src/org/jetbrains/jet/lang/resolve/scopes/WritableScopeImpl.java +++ b/compiler/frontend/src/org/jetbrains/jet/lang/resolve/scopes/WritableScopeImpl.java @@ -55,17 +55,22 @@ public class WritableScopeImpl extends WritableScopeWithImports { @Override public void importScope(@NotNull JetScope imported) { + checkMayWrite(); super.importScope(imported); } @Override public void importClassifierAlias(@NotNull String importedClassifierName, @NotNull ClassifierDescriptor classifierDescriptor) { + checkMayWrite(); + allDescriptors.add(classifierDescriptor); super.importClassifierAlias(importedClassifierName, classifierDescriptor); } @Override public void importNamespaceAlias(String aliasName, NamespaceDescriptor namespaceDescriptor) { + checkMayWrite(); + allDescriptors.add(namespaceDescriptor); super.importNamespaceAlias(aliasName, namespaceDescriptor); } @@ -73,6 +78,8 @@ public class WritableScopeImpl extends WritableScopeWithImports { @NotNull @Override public Collection getAllDescriptors() { + checkMayRead(); + if (!allDescriptorsDone) { allDescriptorsDone = true; allDescriptors.addAll(getWorkerScope().getAllDescriptors()); @@ -94,6 +101,8 @@ public class WritableScopeImpl extends WritableScopeWithImports { @NotNull @Override public Collection getDeclarationsByLabel(@NotNull String labelName) { + checkMayRead(); + Collection superResult = super.getDeclarationsByLabel(labelName); Map> labelsToDescriptors = getLabelsToDescriptors(); List declarationDescriptors = labelsToDescriptors.get(labelName); @@ -108,6 +117,8 @@ public class WritableScopeImpl extends WritableScopeWithImports { @Override public void addLabeledDeclaration(@NotNull DeclarationDescriptor descriptor) { + checkMayWrite(); + Map> labelsToDescriptors = getLabelsToDescriptors(); String name = descriptor.getName(); assert name != null; @@ -137,6 +148,8 @@ public class WritableScopeImpl extends WritableScopeWithImports { @Override public void addVariableDescriptor(@NotNull VariableDescriptor variableDescriptor) { + checkMayWrite(); + Map variableClassOrNamespaceDescriptors = getVariableClassOrNamespaceDescriptors(); DeclarationDescriptor existingDescriptor = variableClassOrNamespaceDescriptors.get(variableDescriptor.getName()); if (existingDescriptor != null) { @@ -149,6 +162,8 @@ public class WritableScopeImpl extends WritableScopeWithImports { @Override public VariableDescriptor getVariable(@NotNull String name) { + checkMayRead(); + Map variableClassOrNamespaceDescriptors = getVariableClassOrNamespaceDescriptors(); DeclarationDescriptor descriptor = variableClassOrNamespaceDescriptors.get(name); if (descriptor instanceof VariableDescriptor) { @@ -172,6 +187,8 @@ public class WritableScopeImpl extends WritableScopeWithImports { @Override public void addFunctionDescriptor(@NotNull FunctionDescriptor functionDescriptor) { + checkMayWrite(); + getFunctionGroups().put(functionDescriptor.getName(), functionDescriptor); allDescriptors.add(functionDescriptor); } @@ -179,6 +196,8 @@ public class WritableScopeImpl extends WritableScopeWithImports { @Override @NotNull public Set getFunctions(@NotNull String name) { + checkMayRead(); + Set result = Sets.newLinkedHashSet(getFunctionGroups().get(name)); result.addAll(getWorkerScope().getFunctions(name)); @@ -190,17 +209,23 @@ public class WritableScopeImpl extends WritableScopeWithImports { @Override public void addTypeParameterDescriptor(@NotNull TypeParameterDescriptor typeParameterDescriptor) { + checkMayWrite(); + String name = typeParameterDescriptor.getName(); addClassifierAlias(name, typeParameterDescriptor); } @Override public void addClassifierDescriptor(@NotNull ClassifierDescriptor classDescriptor) { + checkMayWrite(); + addClassifierAlias(classDescriptor.getName(), classDescriptor); } @Override public void addClassifierAlias(@NotNull String name, @NotNull ClassifierDescriptor classifierDescriptor) { + checkMayWrite(); + checkForRedeclaration(name, classifierDescriptor); getVariableClassOrNamespaceDescriptors().put(name, classifierDescriptor); allDescriptors.add(classifierDescriptor); @@ -208,6 +233,8 @@ public class WritableScopeImpl extends WritableScopeWithImports { @Override public void addNamespaceAlias(@NotNull String name, @NotNull NamespaceDescriptor namespaceDescriptor) { + checkMayWrite(); + checkForRedeclaration(name, namespaceDescriptor); getNamespaceAliases().put(name, namespaceDescriptor); allDescriptors.add(namespaceDescriptor); @@ -222,6 +249,8 @@ public class WritableScopeImpl extends WritableScopeWithImports { @Override public ClassifierDescriptor getClassifier(@NotNull String name) { + checkMayRead(); + Map variableClassOrNamespaceDescriptors = getVariableClassOrNamespaceDescriptors(); DeclarationDescriptor descriptor = variableClassOrNamespaceDescriptors.get(name); if (descriptor instanceof ClassifierDescriptor) return (ClassifierDescriptor) descriptor; @@ -234,6 +263,8 @@ public class WritableScopeImpl extends WritableScopeWithImports { @Override public void addNamespace(@NotNull NamespaceDescriptor namespaceDescriptor) { + checkMayWrite(); + Map variableClassOrNamespaceDescriptors = getVariableClassOrNamespaceDescriptors(); DeclarationDescriptor oldValue = variableClassOrNamespaceDescriptors.put(namespaceDescriptor.getName(), namespaceDescriptor); if (oldValue != null) { @@ -244,6 +275,8 @@ public class WritableScopeImpl extends WritableScopeWithImports { @Override public NamespaceDescriptor getDeclaredNamespace(@NotNull String name) { + checkMayRead(); + Map variableClassOrNamespaceDescriptors = getVariableClassOrNamespaceDescriptors(); DeclarationDescriptor namespaceDescriptor = variableClassOrNamespaceDescriptors.get(name); if (namespaceDescriptor instanceof NamespaceDescriptor) return (NamespaceDescriptor) namespaceDescriptor; @@ -252,6 +285,8 @@ public class WritableScopeImpl extends WritableScopeWithImports { @Override public NamespaceDescriptor getNamespace(@NotNull String name) { + checkMayRead(); + NamespaceDescriptor declaredNamespace = getDeclaredNamespace(name); if (declaredNamespace != null) return declaredNamespace; @@ -266,6 +301,8 @@ public class WritableScopeImpl extends WritableScopeWithImports { @NotNull @Override public ReceiverDescriptor getImplicitReceiver() { + checkMayRead(); + if (implicitReceiver == null) { return super.getImplicitReceiver(); } @@ -274,6 +311,8 @@ public class WritableScopeImpl extends WritableScopeWithImports { @Override public void setImplicitReceiver(@NotNull ReceiverDescriptor implicitReceiver) { + checkMayWrite(); + if (this.implicitReceiver != null) { throw new UnsupportedOperationException("Receiver redeclared"); } @@ -282,6 +321,8 @@ public class WritableScopeImpl extends WritableScopeWithImports { @Override public void getImplicitReceiversHierarchy(@NotNull List result) { + checkMayRead(); + if (implicitReceiver != null && implicitReceiver.exists()) { result.add(implicitReceiver); } @@ -303,6 +344,8 @@ public class WritableScopeImpl extends WritableScopeWithImports { throw new IllegalStateException(); } + checkMayWrite(); + getPropertyDescriptorsByFieldNames().put(fieldName, propertyDescriptor); } @@ -312,12 +355,16 @@ public class WritableScopeImpl extends WritableScopeWithImports { throw new IllegalStateException(); } + checkMayRead(); + PropertyDescriptor descriptor = getPropertyDescriptorsByFieldNames().get(fieldName); if (descriptor != null) return descriptor; return super.getPropertyByFieldReference(fieldName); } public List getDeclaredVariables() { + checkMayRead(); + List result = Lists.newArrayList(); for (DeclarationDescriptor descriptor : getVariableClassOrNamespaceDescriptors().values()) { if (descriptor instanceof VariableDescriptor) { @@ -334,6 +381,8 @@ public class WritableScopeImpl extends WritableScopeWithImports { @Override public WritableScopeImpl setDebugName(@NotNull String debugName) { + checkMayWrite(); + super.setDebugName(debugName); return this; } diff --git a/compiler/frontend/src/org/jetbrains/jet/lang/resolve/scopes/WritableScopeWithImports.java b/compiler/frontend/src/org/jetbrains/jet/lang/resolve/scopes/WritableScopeWithImports.java index 97cdb1df602..ecca869bd2c 100644 --- a/compiler/frontend/src/org/jetbrains/jet/lang/resolve/scopes/WritableScopeWithImports.java +++ b/compiler/frontend/src/org/jetbrains/jet/lang/resolve/scopes/WritableScopeWithImports.java @@ -31,7 +31,36 @@ public abstract class WritableScopeWithImports extends JetScopeAdapter implement this.redeclarationHandler = redeclarationHandler; } + + + private LockLevel lockLevel = LockLevel.WRITING; + + @Override + public void changeLockLevel(LockLevel lockLevel) { + if (lockLevel.ordinal() < this.lockLevel.ordinal()) { + throw new IllegalStateException("cannot lower lock level from " + this.lockLevel + " to " + lockLevel); + } + this.lockLevel = lockLevel; + } + + protected void checkMayRead() { + if (lockLevel != LockLevel.READING && lockLevel != LockLevel.BOTH) { + throw new IllegalStateException("cannot read with lock level " + lockLevel); + } + } + + protected void checkMayWrite() { + if (lockLevel != LockLevel.WRITING && lockLevel != LockLevel.BOTH) { + throw new IllegalStateException("cannot write with lock level " + lockLevel); + } + } + + + + public WritableScopeWithImports setDebugName(@NotNull String debugName) { + checkMayWrite(); + assert this.debugName == null : this.debugName; this.debugName = debugName; return this; @@ -47,12 +76,16 @@ public abstract class WritableScopeWithImports extends JetScopeAdapter implement @Override public void importScope(@NotNull JetScope imported) { + checkMayWrite(); + getImports().add(0, imported); currentIndividualImportScope = null; } @Override public void getImplicitReceiversHierarchy(@NotNull List result) { + checkMayRead(); + super.getImplicitReceiversHierarchy(result); // Imported scopes come with their receivers // Example: class member resolution scope imports a scope of it's class object @@ -67,6 +100,8 @@ public abstract class WritableScopeWithImports extends JetScopeAdapter implement @Override public VariableDescriptor getVariable(@NotNull String name) { + checkMayRead(); + // Meaningful lookup goes here for (JetScope imported : getImports()) { VariableDescriptor importedDescriptor = imported.getVariable(name); @@ -80,6 +115,8 @@ public abstract class WritableScopeWithImports extends JetScopeAdapter implement @NotNull @Override public Set getFunctions(@NotNull String name) { + checkMayRead(); + if (getImports().isEmpty()) { return Collections.emptySet(); } @@ -92,6 +129,8 @@ public abstract class WritableScopeWithImports extends JetScopeAdapter implement @Override public ClassifierDescriptor getClassifier(@NotNull String name) { + checkMayRead(); + for (JetScope imported : getImports()) { ClassifierDescriptor importedClassifier = imported.getClassifier(name); if (importedClassifier != null) { @@ -103,6 +142,8 @@ public abstract class WritableScopeWithImports extends JetScopeAdapter implement @Override public NamespaceDescriptor getNamespace(@NotNull String name) { + checkMayRead(); + for (JetScope imported : getImports()) { NamespaceDescriptor importedDescriptor = imported.getNamespace(name); if (importedDescriptor != null) { @@ -115,6 +156,7 @@ public abstract class WritableScopeWithImports extends JetScopeAdapter implement private WritableScope getCurrentIndividualImportScope() { if (currentIndividualImportScope == null) { WritableScopeImpl writableScope = new WritableScopeImpl(EMPTY, getContainingDeclaration(), RedeclarationHandler.DO_NOTHING).setDebugName("Individual import scope"); + writableScope.changeLockLevel(LockLevel.BOTH); importScope(writableScope); currentIndividualImportScope = writableScope; } @@ -123,12 +165,16 @@ public abstract class WritableScopeWithImports extends JetScopeAdapter implement @Override public void importClassifierAlias(@NotNull String importedClassifierName, @NotNull ClassifierDescriptor classifierDescriptor) { + checkMayWrite(); + getCurrentIndividualImportScope().addClassifierAlias(importedClassifierName, classifierDescriptor); } @Override public void importNamespaceAlias(String aliasName, NamespaceDescriptor namespaceDescriptor) { + checkMayWrite(); + getCurrentIndividualImportScope().addNamespaceAlias(aliasName, namespaceDescriptor); } diff --git a/compiler/frontend/src/org/jetbrains/jet/lang/resolve/scopes/WriteThroughScope.java b/compiler/frontend/src/org/jetbrains/jet/lang/resolve/scopes/WriteThroughScope.java index 9c3a2abc7e6..c00a3e04547 100644 --- a/compiler/frontend/src/org/jetbrains/jet/lang/resolve/scopes/WriteThroughScope.java +++ b/compiler/frontend/src/org/jetbrains/jet/lang/resolve/scopes/WriteThroughScope.java @@ -25,30 +25,40 @@ public class WriteThroughScope extends WritableScopeWithImports { @Override @Nullable public PropertyDescriptor getPropertyByFieldReference(@NotNull String fieldName) { + checkMayRead(); + return writableWorker.getPropertyByFieldReference(fieldName); } @Override @NotNull public Collection getDeclarationsByLabel(String labelName) { + checkMayRead(); + return writableWorker.getDeclarationsByLabel(labelName); } @Override @NotNull public DeclarationDescriptor getContainingDeclaration() { + checkMayRead(); + return writableWorker.getContainingDeclaration(); } @Override @NotNull public ReceiverDescriptor getImplicitReceiver() { + checkMayRead(); + return writableWorker.getImplicitReceiver(); } @Override @NotNull public Set getFunctions(@NotNull String name) { + checkMayRead(); + Set result = Sets.newLinkedHashSet(); result.addAll(writableWorker.getFunctions(name)); @@ -63,6 +73,8 @@ public class WriteThroughScope extends WritableScopeWithImports { @Override @Nullable public VariableDescriptor getVariable(@NotNull String name) { + checkMayRead(); + VariableDescriptor variable = writableWorker.getVariable(name); if (variable != null) return variable; @@ -75,6 +87,8 @@ public class WriteThroughScope extends WritableScopeWithImports { @Override @Nullable public NamespaceDescriptor getNamespace(@NotNull String name) { + checkMayRead(); + NamespaceDescriptor namespace = writableWorker.getNamespace(name); if (namespace != null) return namespace; @@ -87,6 +101,8 @@ public class WriteThroughScope extends WritableScopeWithImports { @Override @Nullable public ClassifierDescriptor getClassifier(@NotNull String name) { + checkMayRead(); + ClassifierDescriptor classifier = writableWorker.getClassifier(name); if (classifier != null) return classifier; @@ -98,68 +114,94 @@ public class WriteThroughScope extends WritableScopeWithImports { @Override public void addLabeledDeclaration(@NotNull DeclarationDescriptor descriptor) { + checkMayWrite(); + writableWorker.addLabeledDeclaration(descriptor); // TODO : review } @Override public void addVariableDescriptor(@NotNull VariableDescriptor variableDescriptor) { + checkMayWrite(); + writableWorker.addVariableDescriptor(variableDescriptor); } @Override public void addFunctionDescriptor(@NotNull FunctionDescriptor functionDescriptor) { + checkMayWrite(); + writableWorker.addFunctionDescriptor(functionDescriptor); } @Override public void addTypeParameterDescriptor(@NotNull TypeParameterDescriptor typeParameterDescriptor) { + checkMayWrite(); + writableWorker.addTypeParameterDescriptor(typeParameterDescriptor); } @Override public void addClassifierDescriptor(@NotNull ClassifierDescriptor classDescriptor) { + checkMayWrite(); + writableWorker.addClassifierDescriptor(classDescriptor); } @Override public void addClassifierAlias(@NotNull String name, @NotNull ClassifierDescriptor classifierDescriptor) { + checkMayWrite(); + writableWorker.addClassifierAlias(name, classifierDescriptor); } @Override public void addNamespaceAlias(@NotNull String name, @NotNull NamespaceDescriptor namespaceDescriptor) { + checkMayWrite(); + writableWorker.addNamespaceAlias(name, namespaceDescriptor); } @Override public void addNamespace(@NotNull NamespaceDescriptor namespaceDescriptor) { + checkMayWrite(); + writableWorker.addNamespace(namespaceDescriptor); } @Override @Nullable public NamespaceDescriptor getDeclaredNamespace(@NotNull String name) { + checkMayRead(); + return writableWorker.getDeclaredNamespace(name); } @Override public void addPropertyDescriptorByFieldName(@NotNull String fieldName, @NotNull PropertyDescriptor propertyDescriptor) { + checkMayWrite(); + writableWorker.addPropertyDescriptorByFieldName(fieldName, propertyDescriptor); } @Override public void importScope(@NotNull JetScope imported) { + checkMayWrite(); + super.importScope(imported); // } @Override public void setImplicitReceiver(@NotNull ReceiverDescriptor implicitReceiver) { + checkMayWrite(); + writableWorker.setImplicitReceiver(implicitReceiver); } @NotNull @Override public Collection getAllDescriptors() { + checkMayRead(); + if (allDescriptors == null) { allDescriptors = Lists.newArrayList(); allDescriptors.addAll(writableWorker.getAllDescriptors()); @@ -170,6 +212,8 @@ public class WriteThroughScope extends WritableScopeWithImports { @NotNull public JetScope getOuterScope() { + checkMayRead(); + return getWorkerScope(); } } diff --git a/compiler/frontend/src/org/jetbrains/jet/lang/types/JetStandardClasses.java b/compiler/frontend/src/org/jetbrains/jet/lang/types/JetStandardClasses.java index 55908afd1b6..a6e120b1e8d 100644 --- a/compiler/frontend/src/org/jetbrains/jet/lang/types/JetStandardClasses.java +++ b/compiler/frontend/src/org/jetbrains/jet/lang/types/JetStandardClasses.java @@ -194,6 +194,8 @@ public class JetStandardClasses { static { WritableScope writableScope = new WritableScopeImpl(JetScope.EMPTY, STANDARD_CLASSES_NAMESPACE, RedeclarationHandler.DO_NOTHING).setDebugName("JetStandardClasses.STANDARD_CLASSES"); + writableScope.changeLockLevel(WritableScope.LockLevel.BOTH); + STANDARD_CLASSES = writableScope; writableScope.addClassifierAlias("Unit", getTuple(0)); diff --git a/compiler/frontend/src/org/jetbrains/jet/lang/types/JetStandardLibrary.java b/compiler/frontend/src/org/jetbrains/jet/lang/types/JetStandardLibrary.java index c095764a3ab..0b99cbe5f69 100644 --- a/compiler/frontend/src/org/jetbrains/jet/lang/types/JetStandardLibrary.java +++ b/compiler/frontend/src/org/jetbrains/jet/lang/types/JetStandardLibrary.java @@ -13,6 +13,7 @@ import org.jetbrains.jet.lang.psi.JetFile; import org.jetbrains.jet.lang.resolve.*; import org.jetbrains.jet.lang.resolve.scopes.JetScope; import org.jetbrains.jet.lang.resolve.scopes.RedeclarationHandler; +import org.jetbrains.jet.lang.resolve.scopes.WritableScope; import org.jetbrains.jet.lang.resolve.scopes.WritableScopeImpl; import org.jetbrains.jet.plugin.JetFileType; @@ -133,6 +134,7 @@ public class JetStandardLibrary { JetSemanticServices bootstrappingSemanticServices = JetSemanticServices.createSemanticServices(this); BindingTraceContext bindingTraceContext = new BindingTraceContext(); WritableScopeImpl writableScope = new WritableScopeImpl(JetStandardClasses.STANDARD_CLASSES, JetStandardClasses.STANDARD_CLASSES_NAMESPACE, RedeclarationHandler.THROW_EXCEPTION).setDebugName("Root bootstrap scope"); + writableScope.changeLockLevel(WritableScope.LockLevel.BOTH); // this.libraryScope = bootstrappingTDA.process(JetStandardClasses.STANDARD_CLASSES, file.getRootNamespace().getDeclarations()); // bootstrappingTDA.process(writableScope, JetStandardClasses.STANDARD_CLASSES_NAMESPACE, file.getRootNamespace().getDeclarations()); TopDownAnalyzer.processStandardLibraryNamespace(bootstrappingSemanticServices, bindingTraceContext, writableScope, JetStandardClasses.STANDARD_CLASSES_NAMESPACE, file.getRootNamespace()); diff --git a/compiler/frontend/src/org/jetbrains/jet/lang/types/expressions/ExpressionTypingServices.java b/compiler/frontend/src/org/jetbrains/jet/lang/types/expressions/ExpressionTypingServices.java index db493f27c06..a6be38a744c 100644 --- a/compiler/frontend/src/org/jetbrains/jet/lang/types/expressions/ExpressionTypingServices.java +++ b/compiler/frontend/src/org/jetbrains/jet/lang/types/expressions/ExpressionTypingServices.java @@ -140,6 +140,7 @@ public class ExpressionTypingServices { DeclarationDescriptor containingDescriptor = outerScope.getContainingDeclaration(); WritableScope scope = new WritableScopeImpl(outerScope, containingDescriptor, new TraceBasedRedeclarationHandler(context.trace)).setDebugName("getBlockReturnedType"); + scope.changeLockLevel(WritableScope.LockLevel.BOTH); return getBlockReturnedTypeWithWritableScope(scope, block, coercionStrategyForLastExpression, context); } diff --git a/compiler/frontend/src/org/jetbrains/jet/lang/types/expressions/ExpressionTypingUtils.java b/compiler/frontend/src/org/jetbrains/jet/lang/types/expressions/ExpressionTypingUtils.java index f9cdac37fcb..368b8e912b3 100644 --- a/compiler/frontend/src/org/jetbrains/jet/lang/types/expressions/ExpressionTypingUtils.java +++ b/compiler/frontend/src/org/jetbrains/jet/lang/types/expressions/ExpressionTypingUtils.java @@ -13,6 +13,7 @@ import org.jetbrains.jet.lang.psi.JetExpression; import org.jetbrains.jet.lang.psi.JetSimpleNameExpression; import org.jetbrains.jet.lang.resolve.BindingContextUtils; import org.jetbrains.jet.lang.resolve.TraceBasedRedeclarationHandler; +import org.jetbrains.jet.lang.resolve.scopes.WritableScope; import org.jetbrains.jet.lang.resolve.scopes.WritableScopeImpl; import org.jetbrains.jet.lang.resolve.scopes.receivers.ExpressionReceiver; import org.jetbrains.jet.lang.types.JetStandardClasses; @@ -42,7 +43,9 @@ public class ExpressionTypingUtils { @NotNull public static WritableScopeImpl newWritableScopeImpl(ExpressionTypingContext context) { - return new WritableScopeImpl(context.scope, context.scope.getContainingDeclaration(), new TraceBasedRedeclarationHandler(context.trace)); + WritableScopeImpl scope = new WritableScopeImpl(context.scope, context.scope.getContainingDeclaration(), new TraceBasedRedeclarationHandler(context.trace)); + scope.changeLockLevel(WritableScope.LockLevel.BOTH); + return scope; } public static boolean isBoolean(@NotNull JetSemanticServices semanticServices, @NotNull JetType type) { diff --git a/compiler/tests/org/jetbrains/jet/types/JetDefaultModalityModifiersTest.java b/compiler/tests/org/jetbrains/jet/types/JetDefaultModalityModifiersTest.java index fb9556a89c3..ea1f05d8935 100644 --- a/compiler/tests/org/jetbrains/jet/types/JetDefaultModalityModifiersTest.java +++ b/compiler/tests/org/jetbrains/jet/types/JetDefaultModalityModifiersTest.java @@ -10,6 +10,7 @@ import org.jetbrains.jet.lang.resolve.DescriptorResolver; import org.jetbrains.jet.lang.resolve.java.AnalyzerFacade; import org.jetbrains.jet.lang.resolve.scopes.JetScope; import org.jetbrains.jet.lang.resolve.scopes.RedeclarationHandler; +import org.jetbrains.jet.lang.resolve.scopes.WritableScope; import org.jetbrains.jet.lang.resolve.scopes.WritableScopeImpl; import org.jetbrains.jet.lang.types.JetStandardLibrary; @@ -49,6 +50,7 @@ public class JetDefaultModalityModifiersTest extends JetLiteFixture { WritableScopeImpl scope = new WritableScopeImpl(libraryScope, root, RedeclarationHandler.DO_NOTHING); assert classDescriptor instanceof ClassifierDescriptor; scope.addClassifierDescriptor((ClassifierDescriptor) classDescriptor); + scope.changeLockLevel(WritableScope.LockLevel.READING); return scope; } diff --git a/compiler/tests/org/jetbrains/jet/types/JetTypeCheckerTest.java b/compiler/tests/org/jetbrains/jet/types/JetTypeCheckerTest.java index 1ead89fcde2..e765cef474a 100644 --- a/compiler/tests/org/jetbrains/jet/types/JetTypeCheckerTest.java +++ b/compiler/tests/org/jetbrains/jet/types/JetTypeCheckerTest.java @@ -545,6 +545,7 @@ public class JetTypeCheckerTest extends JetLiteFixture { JavaSemanticServices javaSemanticServices = new JavaSemanticServices(getProject(), semanticServices, JetTestUtils.DUMMY_TRACE); writableScope.importScope(new JavaPackageScope("", null, javaSemanticServices)); writableScope.importScope(new JavaPackageScope("java.lang", null, javaSemanticServices)); + writableScope.changeLockLevel(WritableScope.LockLevel.BOTH); return writableScope; } @@ -641,6 +642,7 @@ public class JetTypeCheckerTest extends JetLiteFixture { trace.record(BindingContext.CLASS, classElement, classDescriptor); final WritableScope parameterScope = new WritableScopeImpl(scope, classDescriptor, new TraceBasedRedeclarationHandler(trace)); + parameterScope.changeLockLevel(WritableScope.LockLevel.BOTH); // This call has side-effects on the parameterScope (fills it in) List typeParameters @@ -660,6 +662,7 @@ public class JetTypeCheckerTest extends JetLiteFixture { boolean open = classElement.hasModifier(JetTokens.OPEN_KEYWORD); final WritableScope memberDeclarations = new WritableScopeImpl(JetScope.EMPTY, classDescriptor, new TraceBasedRedeclarationHandler(trace)); + memberDeclarations.changeLockLevel(WritableScope.LockLevel.BOTH); List declarations = classElement.getDeclarations(); for (JetDeclaration declaration : declarations) {