From aa4c6e8e8ea90e8155bcf43a65f35270f7e86d4f Mon Sep 17 00:00:00 2001 From: Stepan Koltsov Date: Wed, 30 Nov 2011 20:48:37 +0400 Subject: [PATCH 1/2] Make proper scope for property declaration Make sure same scope is used for both property creation and for properly body resolution. This fixes KT-421 Strange 'unresolved' bug with backing fields. --- .../jetbrains/jet/codegen/CodegenContext.java | 25 ++-- .../descriptors/MutableClassDescriptor.java | 49 +++++++- .../lang/descriptors/PropertyDescriptor.java | 84 +++++++++---- .../descriptors/PropertyGetterDescriptor.java | 9 +- .../descriptors/PropertySetterDescriptor.java | 5 +- .../descriptors/VariableDescriptorImpl.java | 9 ++ .../jet/lang/resolve/BodyResolver.java | 69 ++++------- .../jet/lang/resolve/DeclarationResolver.java | 34 +++-- .../jet/lang/resolve/DescriptorResolver.java | 117 +++++++++++------- .../lang/resolve/TypeHierarchyResolver.java | 2 +- .../UninitializedOrReassignedVariables.jet | 4 +- .../CyclicReferenceInitializer.jet | 2 +- .../quick/regressions/kt421Scopes.jet | 8 ++ 13 files changed, 276 insertions(+), 141 deletions(-) create mode 100644 compiler/testData/checkerWithErrorTypes/quick/regressions/kt421Scopes.jet diff --git a/compiler/backend/src/org/jetbrains/jet/codegen/CodegenContext.java b/compiler/backend/src/org/jetbrains/jet/codegen/CodegenContext.java index a1135e9c65c..11c1bf1c810 100644 --- a/compiler/backend/src/org/jetbrains/jet/codegen/CodegenContext.java +++ b/compiler/backend/src/org/jetbrains/jet/codegen/CodegenContext.java @@ -220,26 +220,29 @@ public abstract class CodegenContext { else if(descriptor instanceof PropertyDescriptor) { PropertyDescriptor pd = (PropertyDescriptor) descriptor; PropertyDescriptor myAccessor = new PropertyDescriptor(contextType, - Collections.emptyList(), - pd.getModality(), - pd.getVisibility(), - pd.isVar(), - pd.getReceiverParameter().exists() ? pd.getReceiverParameter().getType() : null, - pd.getExpectedThisObject(), - pd.getName() + "$bridge$" + accessors.size(), - pd.getInType(), - pd.getOutType()); + Collections.emptyList(), + pd.getModality(), + pd.getVisibility(), + pd.isVar(), + pd.getExpectedThisObject(), + pd.getName() + "$bridge$" + accessors.size() + ); + JetType receiverType = pd.getReceiverParameter().exists() ? pd.getReceiverParameter().getType() : null; + myAccessor.setType(pd.getInType(), pd.getOutType(), Collections.emptyList(), receiverType); + PropertyGetterDescriptor pgd = new PropertyGetterDescriptor( myAccessor, Collections.emptyList(), myAccessor.getModality(), myAccessor.getVisibility(), - myAccessor.getOutType(), false, false); + false, false); + pgd.initialize(myAccessor.getOutType()); + PropertySetterDescriptor psd = new PropertySetterDescriptor( myAccessor.getModality(), myAccessor.getVisibility(), myAccessor, Collections.emptyList(), false, false); - myAccessor.initialize(Collections.emptyList(), pgd, psd); + myAccessor.initialize(pgd, psd); accessor = myAccessor; } else { 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..375f472e527 100644 --- a/compiler/frontend/src/org/jetbrains/jet/lang/descriptors/MutableClassDescriptor.java +++ b/compiler/frontend/src/org/jetbrains/jet/lang/descriptors/MutableClassDescriptor.java @@ -5,10 +5,13 @@ import com.google.common.collect.Sets; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; import org.jetbrains.jet.lang.descriptors.annotations.AnnotationDescriptor; +import org.jetbrains.jet.lang.psi.JetParameter; import org.jetbrains.jet.lang.resolve.AbstractScopeAdapter; +import org.jetbrains.jet.lang.resolve.BindingContext; import org.jetbrains.jet.lang.resolve.BindingTrace; import org.jetbrains.jet.lang.resolve.TraceBasedRedeclarationHandler; import org.jetbrains.jet.lang.resolve.scopes.JetScope; +import org.jetbrains.jet.lang.resolve.scopes.RedeclarationHandler; import org.jetbrains.jet.lang.resolve.scopes.SubstitutingScope; import org.jetbrains.jet.lang.resolve.scopes.WritableScope; import org.jetbrains.jet.lang.resolve.scopes.WritableScopeImpl; @@ -34,10 +37,16 @@ public class MutableClassDescriptor extends MutableDeclarationDescriptor impleme private Modality modality; private Visibility visibility; private TypeConstructor typeConstructor; + private final RedeclarationHandler redeclarationHandler; private final WritableScope scopeForMemberResolution; private final WritableScope scopeForMemberLookup; // This scope contains type parameters but does not contain inner classes private final WritableScope scopeForSupertypeResolution; + private final WritableScope scopeForAnyConstructor; + private final Map scopesForConstructors; + // for primary constructor and property initializers + private final WritableScope scopeForPrimaryConstructor; + private MutableClassDescriptor classObjectDescriptor; private JetType classObjectType; private JetType defaultType; @@ -48,9 +57,13 @@ public class MutableClassDescriptor extends MutableDeclarationDescriptor impleme public MutableClassDescriptor(@NotNull BindingTrace trace, @NotNull DeclarationDescriptor containingDeclaration, @NotNull JetScope outerScope, ClassKind kind) { super(containingDeclaration); TraceBasedRedeclarationHandler redeclarationHandler = new TraceBasedRedeclarationHandler(trace); + this.redeclarationHandler = redeclarationHandler; this.scopeForMemberLookup = new WritableScopeImpl(JetScope.EMPTY, this, redeclarationHandler).setDebugName("MemberLookup"); this.scopeForSupertypeResolution = new WritableScopeImpl(outerScope, this, redeclarationHandler).setDebugName("SupertypeResolution"); this.scopeForMemberResolution = new WritableScopeImpl(scopeForSupertypeResolution, this, redeclarationHandler).setDebugName("MemberResolution"); + this.scopeForAnyConstructor = new WritableScopeImpl(scopeForMemberResolution, this, redeclarationHandler).setDebugName("AnyConstrutor"); + this.scopeForPrimaryConstructor = new WritableScopeImpl(scopeForAnyConstructor, this, redeclarationHandler).setDebugName("PrimaryConstructor"); + this.scopesForConstructors = new HashMap(); this.kind = kind; } @@ -100,10 +113,10 @@ public class MutableClassDescriptor extends MutableDeclarationDescriptor impleme return classObjectDescriptor; } - public void setPrimaryConstructor(@NotNull ConstructorDescriptor constructorDescriptor) { + public void setPrimaryConstructor(@NotNull ConstructorDescriptor constructorDescriptor, BindingTrace trace) { assert this.primaryConstructor == null : "Primary constructor assigned twice " + this; this.primaryConstructor = constructorDescriptor; - addConstructor(constructorDescriptor); + addConstructor(constructorDescriptor, trace); } @Override @@ -112,7 +125,7 @@ public class MutableClassDescriptor extends MutableDeclarationDescriptor impleme return primaryConstructor; } - public void addConstructor(@NotNull ConstructorDescriptor constructorDescriptor) { + public void addConstructor(@NotNull ConstructorDescriptor constructorDescriptor, BindingTrace trace) { assert constructorDescriptor.getContainingDeclaration() == this; // assert constructorDescriptor.getTypeParameters().size() == getTypeConstructor().getValueParameters().size(); constructors.add(constructorDescriptor); @@ -120,6 +133,24 @@ public class MutableClassDescriptor extends MutableDeclarationDescriptor impleme // constructorDescriptor.getTypeParameters().addAll(typeParameters); ((ConstructorDescriptorImpl) constructorDescriptor).setReturnType(getDefaultType()); } + + WritableScope scope = constructorDescriptor.isPrimary() ? + scopeForPrimaryConstructor : + new WritableScopeImpl(scopeForAnyConstructor, this, redeclarationHandler).setDebugName("SecondaryConstructor"); + + WritableScope old = scopesForConstructors.put(constructorDescriptor, scope); + if (old != null) { + throw new IllegalStateException(); + } + + for (ValueParameterDescriptor valueParameterDescriptor : constructorDescriptor.getValueParameters()) { + JetParameter parameter = (JetParameter) trace.getBindingContext().get(BindingContext.DESCRIPTOR_TO_DECLARATION, valueParameterDescriptor); + if (parameter.getValOrVarNode() == null || !constructorDescriptor.isPrimary()) { + scope.addVariableDescriptor(valueParameterDescriptor); + } + } + + scope.addLabeledDeclaration(constructorDescriptor); // TODO : Labels for constructors?! } @Override @@ -128,6 +159,7 @@ public class MutableClassDescriptor extends MutableDeclarationDescriptor impleme callableMembers.add(propertyDescriptor); scopeForMemberLookup.addVariableDescriptor(propertyDescriptor); scopeForMemberResolution.addVariableDescriptor(propertyDescriptor); + scopeForAnyConstructor.addPropertyDescriptorByFieldName("$" + propertyDescriptor.getName(), propertyDescriptor); } @Override @@ -257,6 +289,16 @@ public class MutableClassDescriptor extends MutableDeclarationDescriptor impleme public JetScope getScopeForMemberResolution() { return scopeForMemberResolution; } + + @NotNull + public JetScope getScopeForConstructor(@NotNull ConstructorDescriptor constructorDescriptor) { + return scopesForConstructors.get(constructorDescriptor); + } + + @NotNull + public JetScope getScopeForPropertyIntiailizer() { + return scopeForPrimaryConstructor; + } @NotNull @Override @@ -344,4 +386,5 @@ public class MutableClassDescriptor extends MutableDeclarationDescriptor impleme } return implicitReceiver; } + } diff --git a/compiler/frontend/src/org/jetbrains/jet/lang/descriptors/PropertyDescriptor.java b/compiler/frontend/src/org/jetbrains/jet/lang/descriptors/PropertyDescriptor.java index 27768fa2b22..30f49dbfd31 100644 --- a/compiler/frontend/src/org/jetbrains/jet/lang/descriptors/PropertyDescriptor.java +++ b/compiler/frontend/src/org/jetbrains/jet/lang/descriptors/PropertyDescriptor.java @@ -13,6 +13,7 @@ import org.jetbrains.jet.lang.types.JetType; import org.jetbrains.jet.lang.types.TypeSubstitutor; import org.jetbrains.jet.lang.types.Variance; +import java.util.Collections; import java.util.List; import java.util.Set; @@ -24,12 +25,13 @@ public class PropertyDescriptor extends VariableDescriptorImpl implements Callab private final Modality modality; private final Visibility visibility; private final boolean isVar; - private final ReceiverDescriptor receiver; private final ReceiverDescriptor expectedThisObject; private final Set overriddenProperties = Sets.newLinkedHashSet(); private final Set overridingProperties = Sets.newLinkedHashSet(); - private final List typeParemeters = Lists.newArrayListWithCapacity(0); private final PropertyDescriptor original; + + private ReceiverDescriptor receiver; + private List typeParemeters; private PropertyGetterDescriptor getter; private PropertySetterDescriptor setter; @@ -40,22 +42,28 @@ public class PropertyDescriptor extends VariableDescriptorImpl implements Callab @NotNull Modality modality, @NotNull Visibility visibility, boolean isVar, - @Nullable JetType receiverType, @NotNull ReceiverDescriptor expectedThisObject, - @NotNull String name, - @Nullable JetType inType, - @NotNull JetType outType) { - super(containingDeclaration, annotations, name, inType, outType); - assert !isVar || inType != null; + @NotNull String name) { + super(containingDeclaration, annotations, name); // assert outType != null; this.isVar = isVar; this.modality = modality; this.visibility = visibility; - this.receiver = receiverType == null ? ReceiverDescriptor.NO_RECEIVER : new ExtensionReceiver(this, receiverType); this.expectedThisObject = expectedThisObject; this.original = original == null ? this : original.getOriginal(); } + public PropertyDescriptor( + @NotNull DeclarationDescriptor containingDeclaration, + @NotNull List annotations, + @NotNull Modality modality, + @NotNull Visibility visibility, + boolean isVar, + @NotNull ReceiverDescriptor expectedThisObject, + @NotNull String name) { + this(null, containingDeclaration, annotations, modality, visibility, isVar, expectedThisObject, name); + } + public PropertyDescriptor( @NotNull DeclarationDescriptor containingDeclaration, @NotNull List annotations, @@ -66,8 +74,11 @@ public class PropertyDescriptor extends VariableDescriptorImpl implements Callab @NotNull ReceiverDescriptor expectedThisObject, @NotNull String name, @Nullable JetType inType, - @NotNull JetType outType) { - this(null, containingDeclaration, annotations, modality, visibility, isVar, receiverType, expectedThisObject, name, inType, outType); + @NotNull JetType outType + ) + { + this(containingDeclaration, annotations, modality, visibility, isVar, expectedThisObject, name); + setType(inType, outType, Collections.emptyList(), receiverType); } private PropertyDescriptor( @@ -75,7 +86,9 @@ public class PropertyDescriptor extends VariableDescriptorImpl implements Callab @Nullable JetType receiverType, @NotNull ReceiverDescriptor expectedThisObject, @Nullable JetType inType, - @NotNull JetType outType) { + @NotNull JetType outType + ) + { this( original, original.getContainingDeclaration(), @@ -83,15 +96,38 @@ public class PropertyDescriptor extends VariableDescriptorImpl implements Callab original.getModality(), original.getVisibility(), original.isVar, - receiverType, expectedThisObject, - original.getName(), - inType, - outType); + original.getName() + ); + setType(inType, outType, Collections.emptyList(), receiverType); } - public void initialize(@NotNull List typeParameters, @Nullable PropertyGetterDescriptor getter, @Nullable PropertySetterDescriptor setter) { - this.typeParemeters.addAll(typeParameters); + public void setType(@Nullable JetType inType, @NotNull JetType outType, + @NotNull List typeParameters, + @Nullable JetType receiverType + ) + { + ReceiverDescriptor receiver = receiverType == null + ? ReceiverDescriptor.NO_RECEIVER + : new ExtensionReceiver(this, receiverType); + setType(inType, outType, typeParameters, receiver); + } + + public void setType(@Nullable JetType inType, @NotNull JetType outType, + @NotNull List typeParameters, @NotNull ReceiverDescriptor receiver) + { + assert !isVar || inType != null; + setInType(inType); + setOutType(outType); + + this.typeParemeters = typeParameters; + + this.receiver = receiver; + } + + public void initialize( + @Nullable PropertyGetterDescriptor getter, @Nullable PropertySetterDescriptor setter) + { this.getter = getter; this.setter = setter; } @@ -209,20 +245,24 @@ public class PropertyDescriptor extends VariableDescriptorImpl implements Callab newOwner, Lists.newArrayList(getAnnotations()), DescriptorUtils.convertModality(modality, makeNonAbstract), visibility, isVar, - receiver.exists() ? receiver.getType() : null, expectedThisObject, - getName(), getInType(), getOutType()); + getName()); + + propertyDescriptor.setType(getInType(), getOutType(), DescriptorUtils.copyTypeParameters(propertyDescriptor, getTypeParameters()), receiver.exists() ? receiver.getType() : null); + PropertyGetterDescriptor newGetter = getter == null ? null : new PropertyGetterDescriptor( propertyDescriptor, Lists.newArrayList(getter.getAnnotations()), DescriptorUtils.convertModality(getter.getModality(), makeNonAbstract), getter.getVisibility(), - getter.getReturnType(), getter.hasBody(), getter.isDefault()); + if (newGetter != null) { + newGetter.initialize(getter.getReturnType()); + } PropertySetterDescriptor newSetter = setter == null ? null : new PropertySetterDescriptor( DescriptorUtils.convertModality(setter.getModality(), makeNonAbstract), setter.getVisibility(), propertyDescriptor, Lists.newArrayList(setter.getAnnotations()), setter.hasBody(), setter.isDefault()); - propertyDescriptor.initialize(DescriptorUtils.copyTypeParameters(propertyDescriptor, getTypeParameters()), newGetter, newSetter); + propertyDescriptor.initialize(newGetter, newSetter); return propertyDescriptor; } } diff --git a/compiler/frontend/src/org/jetbrains/jet/lang/descriptors/PropertyGetterDescriptor.java b/compiler/frontend/src/org/jetbrains/jet/lang/descriptors/PropertyGetterDescriptor.java index 095254c7f3d..2574235361c 100644 --- a/compiler/frontend/src/org/jetbrains/jet/lang/descriptors/PropertyGetterDescriptor.java +++ b/compiler/frontend/src/org/jetbrains/jet/lang/descriptors/PropertyGetterDescriptor.java @@ -17,9 +17,14 @@ import java.util.Set; public class PropertyGetterDescriptor extends PropertyAccessorDescriptor { private JetType returnType; - public PropertyGetterDescriptor(@NotNull PropertyDescriptor correspondingProperty, @NotNull List annotations, @NotNull Modality modality, @NotNull Visibility visibility, @Nullable JetType returnType, boolean hasBody, boolean isDefault) { + public PropertyGetterDescriptor(@NotNull PropertyDescriptor correspondingProperty, @NotNull List annotations, + @NotNull Modality modality, @NotNull Visibility visibility, boolean hasBody, boolean isDefault) + { super(modality, visibility, correspondingProperty, annotations, "get-" + correspondingProperty.getName(), hasBody, isDefault); - this.returnType = returnType == null ? correspondingProperty.getOutType() : returnType; + } + + public void initialize(JetType returnType) { + this.returnType = returnType == null ? getCorrespondingProperty().getOutType() : returnType; } @NotNull diff --git a/compiler/frontend/src/org/jetbrains/jet/lang/descriptors/PropertySetterDescriptor.java b/compiler/frontend/src/org/jetbrains/jet/lang/descriptors/PropertySetterDescriptor.java index 7319cb5ce3b..f0590c49604 100644 --- a/compiler/frontend/src/org/jetbrains/jet/lang/descriptors/PropertySetterDescriptor.java +++ b/compiler/frontend/src/org/jetbrains/jet/lang/descriptors/PropertySetterDescriptor.java @@ -17,7 +17,10 @@ public class PropertySetterDescriptor extends PropertyAccessorDescriptor { private MutableValueParameterDescriptor parameter; - public PropertySetterDescriptor(@NotNull Modality modality, @NotNull Visibility visibility, @NotNull PropertyDescriptor correspondingProperty, @NotNull List annotations, boolean hasBody, boolean isDefault) { + public PropertySetterDescriptor(@NotNull Modality modality, @NotNull Visibility visibility, + @NotNull PropertyDescriptor correspondingProperty, @NotNull List annotations, + boolean hasBody, boolean isDefault) + { super(modality, visibility, correspondingProperty, annotations, "set-" + correspondingProperty.getName(), hasBody, isDefault); } diff --git a/compiler/frontend/src/org/jetbrains/jet/lang/descriptors/VariableDescriptorImpl.java b/compiler/frontend/src/org/jetbrains/jet/lang/descriptors/VariableDescriptorImpl.java index 9ff1027e6c6..a8038dd3bba 100644 --- a/compiler/frontend/src/org/jetbrains/jet/lang/descriptors/VariableDescriptorImpl.java +++ b/compiler/frontend/src/org/jetbrains/jet/lang/descriptors/VariableDescriptorImpl.java @@ -30,6 +30,15 @@ public abstract class VariableDescriptorImpl extends DeclarationDescriptorImpl i this.outType = outType; } + protected VariableDescriptorImpl( + @NotNull DeclarationDescriptor containingDeclaration, + @NotNull List annotations, + @NotNull String name + ) + { + super(containingDeclaration, annotations, name); + } + @Override public JetType getOutType() { return outType; 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..c759c83f741 100644 --- a/compiler/frontend/src/org/jetbrains/jet/lang/resolve/BodyResolver.java +++ b/compiler/frontend/src/org/jetbrains/jet/lang/resolve/BodyResolver.java @@ -100,7 +100,7 @@ public class BodyResolver { final ConstructorDescriptor primaryConstructor = descriptor.getUnsubstitutedPrimaryConstructor(); final JetScope scopeForConstructor = primaryConstructor == null ? null - : getInnerScopeForConstructor(primaryConstructor, descriptor.getScopeForMemberResolution(), true); + : getInnerScopeForConstructor(primaryConstructor); final ExpressionTypingServices typeInferrer = context.getSemanticServices().getTypeInferrerServices(traceForConstructors); // TODO : flow final Map supertypes = Maps.newLinkedHashMap(); @@ -267,7 +267,7 @@ public class BodyResolver { if (jetClassOrObject.hasPrimaryConstructor()) { ConstructorDescriptor primaryConstructor = classDescriptor.getUnsubstitutedPrimaryConstructor(); assert primaryConstructor != null; - final JetScope scopeForConstructor = getInnerScopeForConstructor(primaryConstructor, classDescriptor.getScopeForMemberResolution(), true); + final JetScope scopeForConstructor = getInnerScopeForConstructor(primaryConstructor); ExpressionTypingServices typeInferrer = context.getSemanticServices().getTypeInferrerServices(traceForConstructors); for (JetClassInitializer anonymousInitializer : anonymousInitializers) { typeInferrer.getType(scopeForConstructor, anonymousInitializer.getBody(), NO_EXPECTED_TYPE); @@ -293,7 +293,7 @@ public class BodyResolver { private void resolveSecondaryConstructorBody(JetSecondaryConstructor declaration, final ConstructorDescriptor descriptor, final JetScope declaringScope) { if (!context.completeAnalysisNeeded(declaration)) return; - final JetScope functionInnerScope = getInnerScopeForConstructor(descriptor, declaringScope, false); + final JetScope functionInnerScope = getInnerScopeForConstructor(descriptor); final CallResolver callResolver = new CallResolver(context.getSemanticServices(), DataFlowInfo.EMPTY); // TODO: dataFlowInfo @@ -366,24 +366,9 @@ public class BodyResolver { } @NotNull - private JetScope getInnerScopeForConstructor(@NotNull ConstructorDescriptor descriptor, @NotNull JetScope declaringScope, boolean primary) { - WritableScope constructorScope = new WritableScopeImpl(declaringScope, declaringScope.getContainingDeclaration(), new TraceBasedRedeclarationHandler(context.getTrace())).setDebugName("Inner scope for constructor"); - for (PropertyDescriptor propertyDescriptor : ((MutableClassDescriptor) descriptor.getContainingDeclaration()).getProperties()) { - constructorScope.addPropertyDescriptorByFieldName("$" + propertyDescriptor.getName(), propertyDescriptor); - } - -// constructorScope.setImplicitReceiver(new ClassReceiver(descriptor.getContainingDeclaration())); - - for (ValueParameterDescriptor valueParameterDescriptor : descriptor.getValueParameters()) { - JetParameter parameter = (JetParameter) context.getTrace().getBindingContext().get(BindingContext.DESCRIPTOR_TO_DECLARATION, valueParameterDescriptor); - if (parameter.getValOrVarNode() == null || !primary) { - constructorScope.addVariableDescriptor(valueParameterDescriptor); - } - } - - constructorScope.addLabeledDeclaration(descriptor); // TODO : Labels for constructors?! - - return constructorScope; + private JetScope getInnerScopeForConstructor(@NotNull ConstructorDescriptor descriptor) { + MutableClassDescriptor mutableClassDescriptor = (MutableClassDescriptor) descriptor.getContainingDeclaration(); + return mutableClassDescriptor.getScopeForConstructor(descriptor); } private void resolvePropertyDeclarationBodies() { @@ -399,18 +384,16 @@ public class BodyResolver { final PropertyDescriptor propertyDescriptor = this.context.getProperties().get(property); assert propertyDescriptor != null; - JetScope declaringScope = this.context.getDeclaringScopes().get(property); - JetExpression initializer = property.getInitializer(); if (initializer != null) { ConstructorDescriptor primaryConstructor = classDescriptor.getUnsubstitutedPrimaryConstructor(); if (primaryConstructor != null) { - JetScope scope = getInnerScopeForConstructor(primaryConstructor, classDescriptor.getScopeForMemberResolution(), true); - resolvePropertyInitializer(property, propertyDescriptor, initializer, scope); + JetScope declaringScopeForPropertyInitializer = this.context.getDeclaringScopes().get(property); + resolvePropertyInitializer(property, propertyDescriptor, initializer, declaringScopeForPropertyInitializer); } } - resolvePropertyAccessors(property, propertyDescriptor, declaringScope); + resolvePropertyAccessors(property, propertyDescriptor); processed.add(property); } } @@ -429,37 +412,35 @@ public class BodyResolver { resolvePropertyInitializer(property, propertyDescriptor, initializer, declaringScope); } - resolvePropertyAccessors(property, propertyDescriptor, declaringScope); + resolvePropertyAccessors(property, propertyDescriptor); } } + + private JetScope makeScopeForPropertyAccessor(@NotNull JetPropertyAccessor accessor, PropertyDescriptor propertyDescriptor) { + JetScope declaringScope = context.getDeclaringScopes().get(accessor); - private JetScope getPropertyDeclarationInnerScope(@NotNull JetScope outerScope, @NotNull PropertyDescriptor propertyDescriptor) { - WritableScopeImpl result = new WritableScopeImpl(outerScope, propertyDescriptor, new TraceBasedRedeclarationHandler(context.getTrace())).setDebugName("Property declaration inner scope"); - for (TypeParameterDescriptor typeParameterDescriptor : propertyDescriptor.getTypeParameters()) { - result.addTypeParameterDescriptor(typeParameterDescriptor); - } - ReceiverDescriptor receiver = propertyDescriptor.getReceiverParameter(); - if (receiver.exists()) { - result.setImplicitReceiver(receiver); - } - return result; - } - - private void resolvePropertyAccessors(JetProperty property, PropertyDescriptor propertyDescriptor, JetScope declaringScope) { - ObservableBindingTrace fieldAccessTrackingTrace = createFieldTrackingTrace(propertyDescriptor); - - WritableScope accessorScope = new WritableScopeImpl(getPropertyDeclarationInnerScope(declaringScope, propertyDescriptor), declaringScope.getContainingDeclaration(), new TraceBasedRedeclarationHandler(context.getTrace())).setDebugName("Accessor scope"); + JetScope propertyDeclarationInnerScope = context.getDescriptorResolver().getPropertyDeclarationInnerScope( + 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); + return accessorScope; + } + + private void resolvePropertyAccessors(JetProperty property, PropertyDescriptor propertyDescriptor) { + ObservableBindingTrace fieldAccessTrackingTrace = createFieldTrackingTrace(propertyDescriptor); + JetPropertyAccessor getter = property.getGetter(); PropertyGetterDescriptor getterDescriptor = propertyDescriptor.getGetter(); if (getter != null && getterDescriptor != null) { + JetScope accessorScope = makeScopeForPropertyAccessor(getter, propertyDescriptor); resolveFunctionBody(fieldAccessTrackingTrace, getter, getterDescriptor, accessorScope); } JetPropertyAccessor setter = property.getSetter(); PropertySetterDescriptor setterDescriptor = propertyDescriptor.getSetter(); if (setter != null && setterDescriptor != null) { + JetScope accessorScope = makeScopeForPropertyAccessor(setter, propertyDescriptor); resolveFunctionBody(fieldAccessTrackingTrace, setter, setterDescriptor, accessorScope); } } @@ -485,7 +466,7 @@ public class BodyResolver { //JetFlowInformationProvider flowInformationProvider = context.getDescriptorResolver().computeFlowData(property, initializer); // TODO : flow JET-15 ExpressionTypingServices typeInferrer = context.getSemanticServices().getTypeInferrerServices(traceForConstructors); JetType expectedTypeForInitializer = property.getPropertyTypeRef() != null ? propertyDescriptor.getOutType() : NO_EXPECTED_TYPE; - JetType type = typeInferrer.getType(getPropertyDeclarationInnerScope(scope, propertyDescriptor), initializer, expectedTypeForInitializer); + JetType type = typeInferrer.getType(context.getDescriptorResolver().getPropertyDeclarationInnerScope(scope, propertyDescriptor, propertyDescriptor.getTypeParameters(), propertyDescriptor.getReceiverParameter()), initializer, expectedTypeForInitializer); // // JetType expectedType = propertyDescriptor.getInType(); // if (expectedType == null) { diff --git a/compiler/frontend/src/org/jetbrains/jet/lang/resolve/DeclarationResolver.java b/compiler/frontend/src/org/jetbrains/jet/lang/resolve/DeclarationResolver.java index 8c645412d1f..66de67baa15 100644 --- a/compiler/frontend/src/org/jetbrains/jet/lang/resolve/DeclarationResolver.java +++ b/compiler/frontend/src/org/jetbrains/jet/lang/resolve/DeclarationResolver.java @@ -67,13 +67,15 @@ public class DeclarationResolver { WritableScope namespaceScope = entry.getValue(); NamespaceLike namespaceDescriptor = context.getNamespaceDescriptors().get(namespace); - resolveFunctionAndPropertyHeaders(namespace.getDeclarations(), namespaceScope, namespaceDescriptor); + resolveFunctionAndPropertyHeaders(namespace.getDeclarations(), namespaceScope, namespaceScope, namespaceScope, namespaceDescriptor); } for (Map.Entry entry : context.getClasses().entrySet()) { JetClass jetClass = entry.getKey(); MutableClassDescriptor classDescriptor = entry.getValue(); - resolveFunctionAndPropertyHeaders(jetClass.getDeclarations(), classDescriptor.getScopeForMemberResolution(), classDescriptor); + resolveFunctionAndPropertyHeaders(jetClass.getDeclarations(), classDescriptor.getScopeForMemberResolution(), + classDescriptor.getScopeForPropertyIntiailizer(), classDescriptor.getScopeForMemberResolution(), + classDescriptor); // processPrimaryConstructor(classDescriptor, jetClass); // for (JetSecondaryConstructor jetConstructor : jetClass.getSecondaryConstructors()) { // processSecondaryConstructor(classDescriptor, jetConstructor); @@ -83,29 +85,41 @@ public class DeclarationResolver { JetObjectDeclaration object = entry.getKey(); MutableClassDescriptor classDescriptor = entry.getValue(); - resolveFunctionAndPropertyHeaders(object.getDeclarations(), classDescriptor.getScopeForMemberResolution(), classDescriptor); + resolveFunctionAndPropertyHeaders(object.getDeclarations(), classDescriptor.getScopeForMemberResolution(), + classDescriptor.getScopeForPropertyIntiailizer(), classDescriptor.getScopeForMemberResolution(), + classDescriptor); } // TODO : Extensions } - private void resolveFunctionAndPropertyHeaders(@NotNull List declarations, final @NotNull JetScope scope, final @NotNull NamespaceLike namespaceLike) { + private void resolveFunctionAndPropertyHeaders(@NotNull List declarations, + final @NotNull JetScope scopeForFunctions, + final @NotNull JetScope scopeForPropertyInitializers, final @NotNull JetScope scopeForPropertyAccessors, + final @NotNull NamespaceLike namespaceLike) + { for (JetDeclaration declaration : declarations) { declaration.accept(new JetVisitorVoid() { @Override public void visitNamedFunction(JetNamedFunction function) { - FunctionDescriptorImpl functionDescriptor = context.getDescriptorResolver().resolveFunctionDescriptor(namespaceLike, scope, function); + FunctionDescriptorImpl functionDescriptor = context.getDescriptorResolver().resolveFunctionDescriptor(namespaceLike, scopeForFunctions, function); namespaceLike.addFunctionDescriptor(functionDescriptor); context.getFunctions().put(function, functionDescriptor); - context.getDeclaringScopes().put(function, scope); + context.getDeclaringScopes().put(function, scopeForFunctions); } @Override public void visitProperty(JetProperty property) { - PropertyDescriptor propertyDescriptor = context.getDescriptorResolver().resolvePropertyDescriptor(namespaceLike, scope, property); + PropertyDescriptor propertyDescriptor = context.getDescriptorResolver().resolvePropertyDescriptor(namespaceLike, scopeForPropertyInitializers, property); namespaceLike.addPropertyDescriptor(propertyDescriptor); context.getProperties().put(property, propertyDescriptor); - context.getDeclaringScopes().put(property, scope); + context.getDeclaringScopes().put(property, scopeForPropertyInitializers); + if (property.getGetter() != null) { + context.getDeclaringScopes().put(property.getGetter(), scopeForPropertyAccessors); + } + if (property.getSetter() != null) { + context.getDeclaringScopes().put(property.getSetter(), scopeForPropertyAccessors); + } } @Override @@ -150,7 +164,7 @@ public class DeclarationResolver { } } if (constructorDescriptor != null) { - classDescriptor.setPrimaryConstructor(constructorDescriptor); + classDescriptor.setPrimaryConstructor(constructorDescriptor, context.getTrace()); } } @@ -163,7 +177,7 @@ public class DeclarationResolver { classDescriptor.getScopeForMemberResolution(), classDescriptor, constructor); - classDescriptor.addConstructor(constructorDescriptor); + classDescriptor.addConstructor(constructorDescriptor, context.getTrace()); context.getConstructors().put(constructor, constructorDescriptor); context.getDeclaringScopes().put(constructor, classDescriptor.getScopeForMemberLookup()); } 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..0b70a64d8c1 100644 --- a/compiler/frontend/src/org/jetbrains/jet/lang/resolve/DescriptorResolver.java +++ b/compiler/frontend/src/org/jetbrains/jet/lang/resolve/DescriptorResolver.java @@ -15,6 +15,8 @@ import org.jetbrains.jet.lang.psi.*; import org.jetbrains.jet.lang.resolve.scopes.JetScope; import org.jetbrains.jet.lang.resolve.scopes.WritableScope; import org.jetbrains.jet.lang.resolve.scopes.WritableScopeImpl; +import org.jetbrains.jet.lang.resolve.scopes.receivers.ExtensionReceiver; +import org.jetbrains.jet.lang.resolve.scopes.receivers.ReceiverDescriptor; import org.jetbrains.jet.lang.types.*; import org.jetbrains.jet.lexer.JetTokens; import org.jetbrains.jet.util.lazy.LazyValue; @@ -470,16 +472,12 @@ public class DescriptorResolver { Modality.FINAL, resolveVisibilityFromModifiers(objectDeclaration.getModifierList()), false, - null, DescriptorUtils.getExpectedThisObjectIfNeeded(containingDeclaration), - JetPsiUtil.safeName(objectDeclaration.getName()), - null, - classDescriptor.getDefaultType()); + JetPsiUtil.safeName(objectDeclaration.getName()) + ); - propertyDescriptor.initialize( - Collections.emptyList(), - null, // TODO : is it really OK? - null); + propertyDescriptor.setType(null, classDescriptor.getDefaultType(), Collections.emptyList(), ReceiverDescriptor.NO_RECEIVER); + propertyDescriptor.initialize(null, null); JetObjectDeclarationName nameAsDeclaration = objectDeclaration.getNameAsDeclaration(); if (nameAsDeclaration != null) { @@ -488,33 +486,26 @@ public class DescriptorResolver { return propertyDescriptor; } + public JetScope getPropertyDeclarationInnerScope(@NotNull JetScope outerScope, + @NotNull PropertyDescriptor propertyDescriptor, List typeParameters, + ReceiverDescriptor receiver) + { + WritableScopeImpl result = new WritableScopeImpl(outerScope, propertyDescriptor, new TraceBasedRedeclarationHandler(trace)).setDebugName("Property declaration inner scope"); + for (TypeParameterDescriptor typeParameterDescriptor : typeParameters) { + result.addTypeParameterDescriptor(typeParameterDescriptor); + } + if (receiver.exists()) { + result.setImplicitReceiver(receiver); + } + return result; + } + @NotNull public PropertyDescriptor resolvePropertyDescriptor(@NotNull DeclarationDescriptor containingDeclaration, @NotNull JetScope scope, JetProperty property) { - JetScope scopeWithTypeParameters; - List typeParameterDescriptors; - List typeParameters = property.getTypeParameters(); - if (typeParameters.isEmpty()) { - scopeWithTypeParameters = scope; - typeParameterDescriptors = Collections.emptyList(); - } - else { - WritableScope writableScope = new WritableScopeImpl(scope, containingDeclaration, new TraceBasedRedeclarationHandler(trace)).setDebugName("Scope with type parameters of a property"); - typeParameterDescriptors = resolveTypeParameters(containingDeclaration, writableScope, typeParameters); - resolveGenericBounds(property, writableScope, typeParameterDescriptors); - scopeWithTypeParameters = writableScope; - } - - JetType receiverType = null; - JetTypeReference receiverTypeRef = property.getReceiverTypeRef(); - if (receiverTypeRef != null) { - receiverType = typeResolver.resolveType(scopeWithTypeParameters, receiverTypeRef); - } JetModifierList modifierList = property.getModifierList(); boolean isVar = property.isVar(); - JetType type = getVariableType(scopeWithTypeParameters, property, true); - boolean hasBody = hasBody(property); Modality defaultModality = getDefaultModality(containingDeclaration, hasBody); PropertyDescriptor propertyDescriptor = new PropertyDescriptor( @@ -523,16 +514,48 @@ public class DescriptorResolver { resolveModalityFromModifiers(property.getModifierList(), defaultModality), resolveVisibilityFromModifiers(property.getModifierList()), isVar, - receiverType, DescriptorUtils.getExpectedThisObjectIfNeeded(containingDeclaration), - JetPsiUtil.safeName(property.getName()), - isVar ? type : null, - type); + JetPsiUtil.safeName(property.getName()) + ); - propertyDescriptor.initialize( - typeParameterDescriptors, - resolvePropertyGetterDescriptor(scopeWithTypeParameters, property, propertyDescriptor), - resolvePropertySetterDescriptor(scopeWithTypeParameters, property, propertyDescriptor)); + List typeParameterDescriptors; + JetScope scopeWithTypeParameters; + JetType receiverType = null; + + { + List typeParameters = property.getTypeParameters(); + if (typeParameters.isEmpty()) { + scopeWithTypeParameters = scope; + typeParameterDescriptors = Collections.emptyList(); + } + else { + WritableScope writableScope = new WritableScopeImpl(scope, containingDeclaration, new TraceBasedRedeclarationHandler(trace)).setDebugName("Scope with type parameters of a property"); + typeParameterDescriptors = resolveTypeParameters(containingDeclaration, writableScope, typeParameters); + resolveGenericBounds(property, writableScope, typeParameterDescriptors); + scopeWithTypeParameters = writableScope; + } + + JetTypeReference receiverTypeRef = property.getReceiverTypeRef(); + if (receiverTypeRef != null) { + receiverType = typeResolver.resolveType(scopeWithTypeParameters, receiverTypeRef); + } + } + + ReceiverDescriptor receiverDescriptor = receiverType == null + ? ReceiverDescriptor.NO_RECEIVER + : new ExtensionReceiver(propertyDescriptor, receiverType); + + JetScope scope2 = getPropertyDeclarationInnerScope(scope, propertyDescriptor, typeParameterDescriptors, receiverDescriptor); + + JetType type = getVariableType(scope2, property, true); + + JetType inType = isVar ? type : null; + propertyDescriptor.setType(inType, type, typeParameterDescriptors, receiverDescriptor); + + PropertyGetterDescriptor getter = resolvePropertyGetterDescriptor(scopeWithTypeParameters, property, propertyDescriptor); + PropertySetterDescriptor setter = resolvePropertySetterDescriptor(scopeWithTypeParameters, property, propertyDescriptor); + + propertyDescriptor.initialize(getter, setter); trace.record(BindingContext.VARIABLE, property, propertyDescriptor); return propertyDescriptor; @@ -724,7 +747,8 @@ public class DescriptorResolver { getterDescriptor = new PropertyGetterDescriptor( propertyDescriptor, annotations, resolveModalityFromModifiers(getter.getModifierList(), propertyDescriptor.getModality()), resolveVisibilityFromModifiers(getter.getModifierList(), propertyDescriptor.getVisibility()), - returnType, getter.getBodyExpression() != null, false); + getter.getBodyExpression() != null, false); + getterDescriptor.initialize(returnType); trace.record(BindingContext.PROPERTY_ACCESSOR, getter, getterDescriptor); } else { @@ -738,7 +762,7 @@ public class DescriptorResolver { getterDescriptor = new PropertyGetterDescriptor( propertyDescriptor, Collections.emptyList(), propertyDescriptor.getModality(), propertyDescriptor.getVisibility(), - propertyDescriptor.getOutType(), false, true); + false, true); return getterDescriptor; } @@ -807,12 +831,17 @@ public class DescriptorResolver { resolveModalityFromModifiers(parameter.getModifierList(), Modality.FINAL), resolveVisibilityFromModifiers(parameter.getModifierList()), isMutable, - null, DescriptorUtils.getExpectedThisObjectIfNeeded(classDescriptor), - name == null ? "" : name, - isMutable ? type : null, - type); - propertyDescriptor.initialize(Collections.emptyList(), createDefaultGetter(propertyDescriptor), createDefaultSetter(propertyDescriptor)); + name == null ? "" : name + ); + PropertyGetterDescriptor getter = createDefaultGetter(propertyDescriptor); + PropertySetterDescriptor setter = createDefaultSetter(propertyDescriptor); + + JetType inType = isMutable ? type : null; + propertyDescriptor.setType(inType, type, Collections.emptyList(), ReceiverDescriptor.NO_RECEIVER); + propertyDescriptor.initialize(getter, setter); + getter.initialize(propertyDescriptor.getOutType()); + trace.record(BindingContext.PRIMARY_CONSTRUCTOR_PARAMETER, parameter, propertyDescriptor); return propertyDescriptor; } 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 61d117433f4..9990c09921a 100644 --- a/compiler/frontend/src/org/jetbrains/jet/lang/resolve/TypeHierarchyResolver.java +++ b/compiler/frontend/src/org/jetbrains/jet/lang/resolve/TypeHierarchyResolver.java @@ -147,7 +147,7 @@ public class TypeHierarchyResolver { constructorDescriptor.initialize(Collections.emptyList(), Collections.emptyList(), Modality.FINAL, Visibility.INTERNAL);//TODO check set mutableClassDescriptor.getVisibility() // TODO : make the constructor private? - mutableClassDescriptor.setPrimaryConstructor(constructorDescriptor); + mutableClassDescriptor.setPrimaryConstructor(constructorDescriptor, context.getTrace()); if (object != null) { context.getTrace().record(CONSTRUCTOR, object, constructorDescriptor); } diff --git a/compiler/testData/checkerWithErrorTypes/quick/UninitializedOrReassignedVariables.jet b/compiler/testData/checkerWithErrorTypes/quick/UninitializedOrReassignedVariables.jet index 593d34b02c4..a3dcf7c81cf 100644 --- a/compiler/testData/checkerWithErrorTypes/quick/UninitializedOrReassignedVariables.jet +++ b/compiler/testData/checkerWithErrorTypes/quick/UninitializedOrReassignedVariables.jet @@ -243,7 +243,7 @@ class Outer() { } class ForwardAccessToBackingField() { //kt-147 - val a = $a // error + val a = $a // error val b = $c // error val c = 1 } @@ -349,4 +349,4 @@ fun test(m : M) { fun test1(m : M) { m.x++ m.y-- -} \ No newline at end of file +} diff --git a/compiler/testData/checkerWithErrorTypes/quick/backingField/CyclicReferenceInitializer.jet b/compiler/testData/checkerWithErrorTypes/quick/backingField/CyclicReferenceInitializer.jet index 9970bbe43b7..088063e7df9 100644 --- a/compiler/testData/checkerWithErrorTypes/quick/backingField/CyclicReferenceInitializer.jet +++ b/compiler/testData/checkerWithErrorTypes/quick/backingField/CyclicReferenceInitializer.jet @@ -1,3 +1,3 @@ class Cyclic() { - val a = $a + val a = $a } diff --git a/compiler/testData/checkerWithErrorTypes/quick/regressions/kt421Scopes.jet b/compiler/testData/checkerWithErrorTypes/quick/regressions/kt421Scopes.jet new file mode 100644 index 00000000000..1e7138507ad --- /dev/null +++ b/compiler/testData/checkerWithErrorTypes/quick/regressions/kt421Scopes.jet @@ -0,0 +1,8 @@ +// http://youtrack.jetbrains.net/issue/KT-421 +// KT-421 Strange 'unresolved' bug with backing fields + +class A() { + val c = 1 + val a = b + val b = $c // '$c' is unresolved +} From 957b2173d98d0c39500a627ed064b6af95084758 Mon Sep 17 00:00:00 2001 From: Stepan Koltsov Date: Wed, 30 Nov 2011 23:24:02 +0400 Subject: [PATCH 2/2] 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. --- .../descriptors/FunctionDescriptorUtil.java | 1 + .../descriptors/MutableClassDescriptor.java | 23 +++++++++ .../jet/lang/resolve/AnalyzingUtils.java | 1 + .../jet/lang/resolve/BodyResolver.java | 1 + .../jet/lang/resolve/DescriptorResolver.java | 9 +++- .../jet/lang/resolve/TopDownAnalyzer.java | 13 +++++ .../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, 212 insertions(+), 3 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 375f472e527..19ff65681ca 100644 --- a/compiler/frontend/src/org/jetbrains/jet/lang/descriptors/MutableClassDescriptor.java +++ b/compiler/frontend/src/org/jetbrains/jet/lang/descriptors/MutableClassDescriptor.java @@ -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(); 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(); + } + } } 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 c759c83f741..d6c8a64c8df 100644 --- a/compiler/frontend/src/org/jetbrains/jet/lang/resolve/BodyResolver.java +++ b/compiler/frontend/src/org/jetbrains/jet/lang/resolve/BodyResolver.java @@ -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; } 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 0b70a64d8c1..87b1f0a72b2 100644 --- a/compiler/frontend/src/org/jetbrains/jet/lang/resolve/DescriptorResolver.java +++ b/compiler/frontend/src/org/jetbrains/jet/lang/resolve/DescriptorResolver.java @@ -148,6 +148,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; @@ -162,6 +163,8 @@ public class DescriptorResolver { List 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)); 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..5e311a37bd8 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(); + 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, 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 9990c09921a..49fb12d2294 100644 --- a/compiler/frontend/src/org/jetbrains/jet/lang/resolve/TypeHierarchyResolver.java +++ b/compiler/frontend/src/org/jetbrains/jet/lang/resolve/TypeHierarchyResolver.java @@ -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.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); 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..bacaa26ea9e 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); } @@ -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 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) {