WritableScope.changeLockLevel()
This patch allows WritableScope "locking". WritableScope now has three lock levels: reading, writing, both. Scope modification is not allowed in "reading" state, scope data access is not allowed in "writing". Scope lock level can only be raised: from "writing" to "both" and from "both" to "reading". There are two reasons for this enhancement: 1. Code self-documentation. It is clear where WritableScope is used as readonly scope. For example developers can see that class structure is not modified after DelegationResolver.process(), because MutableClassDescriptor.lockScopes() is called right after that method. 2. Ease of debugging, program gets more assertions. For example, if some scope is not yet filled and some member resolution is triggered, IllegalStateException is thrown instead of wrong unresolved reference. Currently not all scope locks are configured strictly. In many cases lock level is set to safe "both" value.
This commit is contained in:
@@ -80,6 +80,7 @@ public class FunctionDescriptorUtil {
|
||||
parameterScope.addVariableDescriptor(valueParameterDescriptor);
|
||||
}
|
||||
parameterScope.addLabeledDeclaration(descriptor);
|
||||
parameterScope.changeLockLevel(WritableScope.LockLevel.READING);
|
||||
return parameterScope;
|
||||
}
|
||||
|
||||
|
||||
@@ -59,10 +59,15 @@ public class MutableClassDescriptor extends MutableDeclarationDescriptor impleme
|
||||
TraceBasedRedeclarationHandler redeclarationHandler = new TraceBasedRedeclarationHandler(trace);
|
||||
this.redeclarationHandler = redeclarationHandler;
|
||||
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.scopeForAnyConstructor = new WritableScopeImpl(scopeForMemberResolution, this, redeclarationHandler).setDebugName("AnyConstrutor");
|
||||
this.scopeForAnyConstructor.changeLockLevel(WritableScope.LockLevel.BOTH);
|
||||
this.scopeForPrimaryConstructor = new WritableScopeImpl(scopeForAnyConstructor, this, redeclarationHandler).setDebugName("PrimaryConstructor");
|
||||
this.scopeForPrimaryConstructor.changeLockLevel(WritableScope.LockLevel.BOTH);
|
||||
this.scopesForConstructors = new HashMap<ConstructorDescriptor, WritableScope>();
|
||||
this.kind = kind;
|
||||
}
|
||||
@@ -151,6 +156,8 @@ public class MutableClassDescriptor extends MutableDeclarationDescriptor impleme
|
||||
}
|
||||
|
||||
scope.addLabeledDeclaration(constructorDescriptor); // TODO : Labels for constructors?!
|
||||
|
||||
scope.changeLockLevel(WritableScope.LockLevel.READING);
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -212,6 +219,7 @@ public class MutableClassDescriptor extends MutableDeclarationDescriptor impleme
|
||||
this.typeParameters.add(typeParameterDescriptor);
|
||||
scopeForSupertypeResolution.addTypeParameterDescriptor(typeParameterDescriptor);
|
||||
}
|
||||
scopeForSupertypeResolution.changeLockLevel(WritableScope.LockLevel.READING);
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
@@ -386,5 +394,20 @@ 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);
|
||||
scopeForAnyConstructor.changeLockLevel(WritableScope.LockLevel.READING);
|
||||
scopeForPrimaryConstructor.changeLockLevel(WritableScope.LockLevel.READING);
|
||||
for (WritableScope scope : scopesForConstructors.values()) {
|
||||
scope.changeLockLevel(WritableScope.LockLevel.READING);
|
||||
}
|
||||
|
||||
if (classObjectDescriptor != null) {
|
||||
classObjectDescriptor.lockScopes();
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -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) {
|
||||
|
||||
|
||||
@@ -423,6 +423,7 @@ public class BodyResolver {
|
||||
declaringScope, propertyDescriptor, propertyDescriptor.getTypeParameters(), propertyDescriptor.getReceiverParameter());
|
||||
WritableScope accessorScope = new WritableScopeImpl(propertyDeclarationInnerScope, declaringScope.getContainingDeclaration(), new TraceBasedRedeclarationHandler(context.getTrace())).setDebugName("Accessor scope");
|
||||
accessorScope.addPropertyDescriptorByFieldName("$" + propertyDescriptor.getName(), propertyDescriptor);
|
||||
accessorScope.changeLockLevel(WritableScope.LockLevel.READING);
|
||||
|
||||
return accessorScope;
|
||||
}
|
||||
|
||||
@@ -148,6 +148,7 @@ public class DescriptorResolver {
|
||||
innerScope.addLabeledDeclaration(functionDescriptor);
|
||||
|
||||
List<TypeParameterDescriptor> typeParameterDescriptors = resolveTypeParameters(functionDescriptor, innerScope, function.getTypeParameters());
|
||||
innerScope.changeLockLevel(WritableScope.LockLevel.BOTH);
|
||||
resolveGenericBounds(function, innerScope, typeParameterDescriptors);
|
||||
|
||||
JetType receiverType = null;
|
||||
@@ -162,6 +163,8 @@ public class DescriptorResolver {
|
||||
|
||||
List<ValueParameterDescriptor> valueParameterDescriptors = resolveValueParameters(functionDescriptor, innerScope, function.getValueParameters());
|
||||
|
||||
innerScope.changeLockLevel(WritableScope.LockLevel.READING);
|
||||
|
||||
JetTypeReference returnTypeRef = function.getReturnTypeRef();
|
||||
JetType returnType;
|
||||
if (returnTypeRef != null) {
|
||||
@@ -497,6 +500,7 @@ public class DescriptorResolver {
|
||||
if (receiver.exists()) {
|
||||
result.setImplicitReceiver(receiver);
|
||||
}
|
||||
result.changeLockLevel(WritableScope.LockLevel.READING);
|
||||
return result;
|
||||
}
|
||||
|
||||
@@ -531,6 +535,7 @@ public class DescriptorResolver {
|
||||
else {
|
||||
WritableScope writableScope = new WritableScopeImpl(scope, containingDeclaration, new TraceBasedRedeclarationHandler(trace)).setDebugName("Scope with type parameters of a property");
|
||||
typeParameterDescriptors = resolveTypeParameters(containingDeclaration, writableScope, typeParameters);
|
||||
writableScope.changeLockLevel(WritableScope.LockLevel.READING);
|
||||
resolveGenericBounds(property, writableScope, typeParameterDescriptors);
|
||||
scopeWithTypeParameters = writableScope;
|
||||
}
|
||||
@@ -785,11 +790,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));
|
||||
|
||||
@@ -60,6 +60,7 @@ public class TopDownAnalyzer {
|
||||
new TypeHierarchyResolver(context).process(outerScope, owner, declarations);
|
||||
new DeclarationResolver(context).process();
|
||||
new DelegationResolver(context).process();
|
||||
lockScopes(context);
|
||||
new OverrideResolver(context).process();
|
||||
new OverloadResolver(context).process();
|
||||
if (!context.analyzingBootstrapLibrary()) {
|
||||
@@ -72,6 +73,18 @@ public class TopDownAnalyzer {
|
||||
context.printDebugOutput(System.out);
|
||||
}
|
||||
|
||||
private static void lockScopes(TopDownAnalysisContext context) {
|
||||
for (MutableClassDescriptor mutableClassDescriptor : context.getClasses().values()) {
|
||||
mutableClassDescriptor.lockScopes();
|
||||
}
|
||||
for (MutableClassDescriptor mutableClassDescriptor : context.getObjects().values()) {
|
||||
mutableClassDescriptor.lockScopes();
|
||||
}
|
||||
for (WritableScope namespaceScope : context.getNamespaceScopes().values()) {
|
||||
namespaceScope.changeLockLevel(WritableScope.LockLevel.READING);
|
||||
}
|
||||
}
|
||||
|
||||
public static void processStandardLibraryNamespace(
|
||||
@NotNull JetSemanticServices semanticServices,
|
||||
@NotNull BindingTrace trace,
|
||||
|
||||
@@ -73,6 +73,7 @@ public class TypeHierarchyResolver {
|
||||
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);
|
||||
|
||||
@@ -210,7 +211,9 @@ public class TypeHierarchyResolver {
|
||||
Collections.<AnnotationDescriptor>emptyList(), // TODO: annotations
|
||||
name
|
||||
);
|
||||
namespaceDescriptor.initialize(new WritableScopeImpl(JetScope.EMPTY, namespaceDescriptor, new TraceBasedRedeclarationHandler(context.getTrace())).setDebugName("Namespace member scope"));
|
||||
WritableScopeImpl scope = new WritableScopeImpl(JetScope.EMPTY, namespaceDescriptor, new TraceBasedRedeclarationHandler(context.getTrace())).setDebugName("Namespace member scope");
|
||||
scope.changeLockLevel(WritableScope.LockLevel.BOTH);
|
||||
namespaceDescriptor.initialize(scope);
|
||||
owner.addNamespace(namespaceDescriptor);
|
||||
if (namespace != null) {
|
||||
context.getTrace().record(BindingContext.NAMESPACE, namespace, namespaceDescriptor);
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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<DeclarationDescriptor> getAllDescriptors() {
|
||||
checkMayRead();
|
||||
|
||||
if (!allDescriptorsDone) {
|
||||
allDescriptorsDone = true;
|
||||
allDescriptors.addAll(getWorkerScope().getAllDescriptors());
|
||||
@@ -94,6 +101,8 @@ public class WritableScopeImpl extends WritableScopeWithImports {
|
||||
@NotNull
|
||||
@Override
|
||||
public Collection<DeclarationDescriptor> getDeclarationsByLabel(@NotNull String labelName) {
|
||||
checkMayRead();
|
||||
|
||||
Collection<DeclarationDescriptor> superResult = super.getDeclarationsByLabel(labelName);
|
||||
Map<String, List<DeclarationDescriptor>> labelsToDescriptors = getLabelsToDescriptors();
|
||||
List<DeclarationDescriptor> declarationDescriptors = labelsToDescriptors.get(labelName);
|
||||
@@ -108,6 +117,8 @@ public class WritableScopeImpl extends WritableScopeWithImports {
|
||||
|
||||
@Override
|
||||
public void addLabeledDeclaration(@NotNull DeclarationDescriptor descriptor) {
|
||||
checkMayWrite();
|
||||
|
||||
Map<String, List<DeclarationDescriptor>> 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<String, DeclarationDescriptor> 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<String, DeclarationDescriptor> 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<FunctionDescriptor> getFunctions(@NotNull String name) {
|
||||
checkMayRead();
|
||||
|
||||
Set<FunctionDescriptor> 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<String, DeclarationDescriptor> 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<String, DeclarationDescriptor> 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<String, DeclarationDescriptor> 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<ReceiverDescriptor> result) {
|
||||
checkMayRead();
|
||||
|
||||
if (implicitReceiver != null && implicitReceiver.exists()) {
|
||||
result.add(implicitReceiver);
|
||||
}
|
||||
@@ -299,6 +340,8 @@ public class WritableScopeImpl extends WritableScopeWithImports {
|
||||
|
||||
@Override
|
||||
public void addPropertyDescriptorByFieldName(@NotNull String fieldName, @NotNull PropertyDescriptor propertyDescriptor) {
|
||||
checkMayWrite();
|
||||
|
||||
if (!fieldName.startsWith("$")) {
|
||||
throw new IllegalStateException();
|
||||
}
|
||||
@@ -308,6 +351,8 @@ public class WritableScopeImpl extends WritableScopeWithImports {
|
||||
|
||||
@Override
|
||||
public PropertyDescriptor getPropertyByFieldReference(@NotNull String fieldName) {
|
||||
checkMayRead();
|
||||
|
||||
if (!fieldName.startsWith("$")) {
|
||||
throw new IllegalStateException();
|
||||
}
|
||||
@@ -318,6 +363,8 @@ public class WritableScopeImpl extends WritableScopeWithImports {
|
||||
}
|
||||
|
||||
public List<VariableDescriptor> getDeclaredVariables() {
|
||||
checkMayRead();
|
||||
|
||||
List<VariableDescriptor> 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;
|
||||
}
|
||||
|
||||
+46
@@ -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<ReceiverDescriptor> 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<FunctionDescriptor> 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);
|
||||
}
|
||||
|
||||
|
||||
@@ -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<DeclarationDescriptor> 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<FunctionDescriptor> getFunctions(@NotNull String name) {
|
||||
checkMayRead();
|
||||
|
||||
Set<FunctionDescriptor> 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<DeclarationDescriptor> 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();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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));
|
||||
|
||||
|
||||
@@ -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());
|
||||
|
||||
+1
@@ -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);
|
||||
}
|
||||
|
||||
|
||||
+4
-1
@@ -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) {
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
|
||||
@@ -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<TypeParameterDescriptor> 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<JetDeclaration> declarations = classElement.getDeclarations();
|
||||
for (JetDeclaration declaration : declarations) {
|
||||
|
||||
Reference in New Issue
Block a user