JET-16 Check property initializers as parts of the primary constructor's body

This commit is contained in:
Andrey Breslav
2011-04-26 20:20:30 +04:00
parent 244fc31da8
commit 4e24405bea
6 changed files with 65 additions and 28 deletions
@@ -107,6 +107,11 @@ public class JetPsiChecker implements Annotator {
} }
} }
// @Override
// public void visitParameter(JetParameter parameter) {
// bindingContext.get
// }
@Override @Override
public void visitJetElement(JetElement elem) { public void visitJetElement(JetElement elem) {
elem.acceptChildren(this); elem.acceptChildren(this);
@@ -1,5 +1,6 @@
package org.jetbrains.jet.lang.resolve; package org.jetbrains.jet.lang.resolve;
import com.google.common.collect.Maps;
import com.intellij.psi.PsiElement; import com.intellij.psi.PsiElement;
import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable; import org.jetbrains.annotations.Nullable;
@@ -22,9 +23,10 @@ public class BindingTraceContext implements BindingContext, BindingTrace {
private final Map<DeclarationDescriptor, PsiElement> descriptorToDeclarations = new HashMap<DeclarationDescriptor, PsiElement>(); private final Map<DeclarationDescriptor, PsiElement> descriptorToDeclarations = new HashMap<DeclarationDescriptor, PsiElement>();
private final Map<PsiElement, DeclarationDescriptor> declarationsToDescriptors = new HashMap<PsiElement, DeclarationDescriptor>(); private final Map<PsiElement, DeclarationDescriptor> declarationsToDescriptors = new HashMap<PsiElement, DeclarationDescriptor>();
private final Map<PsiElement, ConstructorDescriptor> constructorDeclarationsToDescriptors = new HashMap<PsiElement, ConstructorDescriptor>(); private final Map<PsiElement, ConstructorDescriptor> constructorDeclarationsToDescriptors = new HashMap<PsiElement, ConstructorDescriptor>();
private final Map<PsiElement, PropertyDescriptor> propertyDeclarationsToDescriptors = Maps.newHashMap();
private final Set<JetFunctionLiteralExpression> blocks = new HashSet<JetFunctionLiteralExpression>(); private final Set<JetFunctionLiteralExpression> blocks = new HashSet<JetFunctionLiteralExpression>();
private final Set<JetElement> statements = new HashSet<JetElement>(); private final Set<JetElement> statements = new HashSet<JetElement>();
private final Set<PropertyDescriptor> fieldMentionedInAccessor = new HashSet<PropertyDescriptor>(); private final Set<PropertyDescriptor> backingFieldRequired = new HashSet<PropertyDescriptor>();
private JetScope toplevelScope; private JetScope toplevelScope;
@@ -58,23 +60,32 @@ public class BindingTraceContext implements BindingContext, BindingTrace {
@Override @Override
public void recordDeclarationResolution(@NotNull PsiElement declaration, @NotNull DeclarationDescriptor descriptor) { public void recordDeclarationResolution(@NotNull PsiElement declaration, @NotNull DeclarationDescriptor descriptor) {
safePut(descriptorToDeclarations, descriptor.getOriginal(), declaration); safePut(descriptorToDeclarations, descriptor.getOriginal(), declaration);
if (descriptor instanceof ConstructorDescriptor) { descriptor.accept(new DeclarationDescriptorVisitor<Void, PsiElement>() {
safePut(constructorDeclarationsToDescriptors, declaration, (ConstructorDescriptor) descriptor); @Override
} public Void visitConstructorDescriptor(ConstructorDescriptor constructorDescriptor, PsiElement declaration) {
else { safePut(constructorDeclarationsToDescriptors, declaration, constructorDescriptor);
safePut(declarationsToDescriptors, declaration, descriptor.getOriginal()); return null;
} }
@Override
public Void visitDeclarationDescriptor(DeclarationDescriptor descriptor, PsiElement declaration) {
safePut(declarationsToDescriptors, declaration, descriptor.getOriginal());
return null;
}
}, declaration);
} }
private <K, V> void safePut(Map<K, V> map, K key, V value) { private <K, V> void safePut(Map<K, V> map, K key, V value) {
V oldValue = map.put(key, value); V oldValue = map.put(key, value);
// TODO: // TODO:
// assert oldValue == null || oldValue == value : key + ": " + oldValue + " and " + value; assert oldValue == null || oldValue == value : key + ": " + oldValue + " and " + value;
} }
@Override @Override
public void recordFieldAccessFromAccessor(@NotNull PropertyDescriptor propertyDescriptor) { public void requireBackingField(@NotNull PropertyDescriptor propertyDescriptor) {
fieldMentionedInAccessor.add(propertyDescriptor); backingFieldRequired.add(propertyDescriptor);
} }
@Override @Override
@@ -195,6 +206,6 @@ public class BindingTraceContext implements BindingContext, BindingTrace {
else if (!getter.hasBody()) { else if (!getter.hasBody()) {
return true; return true;
} }
return fieldMentionedInAccessor.contains(propertyDescriptor); return backingFieldRequired.contains(propertyDescriptor);
} }
} }
@@ -28,6 +28,7 @@ public class TopDownAnalyzer {
private final Map<JetProperty, PropertyDescriptor> properties = new LinkedHashMap<JetProperty, PropertyDescriptor>(); private final Map<JetProperty, PropertyDescriptor> properties = new LinkedHashMap<JetProperty, PropertyDescriptor>();
private final Map<JetDeclaration, WritableScope> declaringScopes = new HashMap<JetDeclaration, WritableScope>(); private final Map<JetDeclaration, WritableScope> declaringScopes = new HashMap<JetDeclaration, WritableScope>();
private final Multimap<DeclarationDescriptor, PropertyDescriptor> declaringScopesToProperties = ArrayListMultimap.create(); private final Multimap<DeclarationDescriptor, PropertyDescriptor> declaringScopesToProperties = ArrayListMultimap.create();
private final Set<PropertyDescriptor> primaryConstructorParameterProperties = Sets.newHashSet();
private final JetSemanticServices semanticServices; private final JetSemanticServices semanticServices;
private final ClassDescriptorResolver classDescriptorResolver; private final ClassDescriptorResolver classDescriptorResolver;
@@ -35,6 +36,7 @@ public class TopDownAnalyzer {
private final JetControlFlowDataTraceFactory flowDataTraceFactory; private final JetControlFlowDataTraceFactory flowDataTraceFactory;
private boolean readyToProcessExpressions = false; private boolean readyToProcessExpressions = false;
private final BindingTraceAdapter traceForConstructors; private final BindingTraceAdapter traceForConstructors;
private final BindingTraceAdapter traceForMembers;
public TopDownAnalyzer(JetSemanticServices semanticServices, @NotNull BindingTraceContext bindingTrace, @NotNull JetControlFlowDataTraceFactory flowDataTraceFactory) { public TopDownAnalyzer(JetSemanticServices semanticServices, @NotNull BindingTraceContext bindingTrace, @NotNull JetControlFlowDataTraceFactory flowDataTraceFactory) {
this.semanticServices = semanticServices; this.semanticServices = semanticServices;
@@ -43,7 +45,7 @@ public class TopDownAnalyzer {
this.flowDataTraceFactory = flowDataTraceFactory; this.flowDataTraceFactory = flowDataTraceFactory;
// This allows access to backing fields // This allows access to backing fields
this.traceForConstructors = new BindingTraceAdapter(trace) { this.traceForConstructors = new BindingTraceAdapter(bindingTrace) {
@Override @Override
public void recordReferenceResolution(@NotNull JetReferenceExpression expression, @NotNull DeclarationDescriptor descriptor) { public void recordReferenceResolution(@NotNull JetReferenceExpression expression, @NotNull DeclarationDescriptor descriptor) {
super.recordReferenceResolution(expression, descriptor); super.recordReferenceResolution(expression, descriptor);
@@ -57,6 +59,20 @@ public class TopDownAnalyzer {
} }
} }
}; };
// This tracks access to properties in order to register primary constructor parameters that yield real fields (JET-9)
this.traceForMembers = new BindingTraceAdapter(bindingTrace) {
@Override
public void recordReferenceResolution(@NotNull JetReferenceExpression expression, @NotNull DeclarationDescriptor descriptor) {
super.recordReferenceResolution(expression, descriptor);
if (descriptor instanceof PropertyDescriptor) {
PropertyDescriptor propertyDescriptor = (PropertyDescriptor) descriptor;
if (primaryConstructorParameterProperties.contains(propertyDescriptor)) {
requireBackingField(propertyDescriptor);
}
}
}
};
} }
public TopDownAnalyzer(JetSemanticServices semanticServices, @NotNull BindingTraceContext bindingTrace) { public TopDownAnalyzer(JetSemanticServices semanticServices, @NotNull BindingTraceContext bindingTrace) {
@@ -242,13 +258,14 @@ public class TopDownAnalyzer {
WritableScope memberScope = classDescriptor.getWritableUnsubstitutedMemberScope(); // TODO : this is REALLY questionable WritableScope memberScope = classDescriptor.getWritableUnsubstitutedMemberScope(); // TODO : this is REALLY questionable
ConstructorDescriptor constructorDescriptor = classDescriptorResolver.resolvePrimaryConstructorDescriptor(memberScope, classDescriptor, klass); ConstructorDescriptor constructorDescriptor = classDescriptorResolver.resolvePrimaryConstructorDescriptor(memberScope, classDescriptor, klass);
for (JetParameter parameter : klass.getPrimaryConstructorParameters()) { for (JetParameter parameter : klass.getPrimaryConstructorParameters()) {
VariableDescriptor propertyDescriptor = classDescriptorResolver.resolvePrimaryConstructorParameterToAProperty( PropertyDescriptor propertyDescriptor = classDescriptorResolver.resolvePrimaryConstructorParameterToAProperty(
classDescriptor, classDescriptor,
memberScope, memberScope,
parameter parameter
); );
memberScope.addVariableDescriptor( memberScope.addVariableDescriptor(
propertyDescriptor); propertyDescriptor);
primaryConstructorParameterProperties.add(propertyDescriptor);
} }
if (constructorDescriptor != null) { if (constructorDescriptor != null) {
classDescriptor.setPrimaryConstructor(constructorDescriptor); classDescriptor.setPrimaryConstructor(constructorDescriptor);
@@ -552,7 +569,7 @@ public class TopDownAnalyzer {
} }
private BindingTraceAdapter createFieldTrackingTrace(final PropertyDescriptor propertyDescriptor) { private BindingTraceAdapter createFieldTrackingTrace(final PropertyDescriptor propertyDescriptor) {
return new BindingTraceAdapter(trace) { return new BindingTraceAdapter(traceForMembers) {
@Override @Override
public void recordReferenceResolution(@NotNull JetReferenceExpression expression, @NotNull DeclarationDescriptor descriptor) { public void recordReferenceResolution(@NotNull JetReferenceExpression expression, @NotNull DeclarationDescriptor descriptor) {
super.recordReferenceResolution(expression, descriptor); super.recordReferenceResolution(expression, descriptor);
@@ -561,7 +578,7 @@ public class TopDownAnalyzer {
if (simpleNameExpression.getReferencedNameElementType() == JetTokens.FIELD_IDENTIFIER) { if (simpleNameExpression.getReferencedNameElementType() == JetTokens.FIELD_IDENTIFIER) {
// This check may be considered redundant as long as $x is only accessible from accessors to $x // This check may be considered redundant as long as $x is only accessible from accessors to $x
if (descriptor == propertyDescriptor) { // TODO : original? if (descriptor == propertyDescriptor) { // TODO : original?
recordFieldAccessFromAccessor(propertyDescriptor); requireBackingField(propertyDescriptor);
} }
} }
} }
@@ -571,7 +588,7 @@ public class TopDownAnalyzer {
private void resolvePropertyInitializer(JetProperty property, PropertyDescriptor propertyDescriptor, JetExpression initializer, JetScope scope) { private void resolvePropertyInitializer(JetProperty property, PropertyDescriptor propertyDescriptor, JetExpression initializer, JetScope scope) {
JetFlowInformationProvider flowInformationProvider = computeFlowData(property, initializer); // TODO : flow JET-15 JetFlowInformationProvider flowInformationProvider = computeFlowData(property, initializer); // TODO : flow JET-15
JetTypeInferrer typeInferrer = semanticServices.getTypeInferrer(trace, flowInformationProvider); JetTypeInferrer typeInferrer = semanticServices.getTypeInferrer(traceForConstructors, flowInformationProvider);
JetType type = typeInferrer.getType(scope, initializer, false); JetType type = typeInferrer.getType(scope, initializer, false);
JetType expectedType; JetType expectedType;
@@ -599,7 +616,7 @@ public class TopDownAnalyzer {
WritableScope declaringScope = declaringScopes.get(declaration); WritableScope declaringScope = declaringScopes.get(declaration);
assert declaringScope != null; assert declaringScope != null;
resolveFunctionBody(trace, (JetFunction) declaration, (FunctionDescriptorImpl) descriptor, declaringScope); resolveFunctionBody(traceForMembers, (JetFunction) declaration, (FunctionDescriptorImpl) descriptor, declaringScope);
assert descriptor.getUnsubstitutedReturnType() != null; assert descriptor.getUnsubstitutedReturnType() != null;
} }
@@ -52,7 +52,7 @@ public interface BindingTrace {
} }
@Override @Override
public void recordFieldAccessFromAccessor(@NotNull PropertyDescriptor propertyDescriptor) { public void requireBackingField(@NotNull PropertyDescriptor propertyDescriptor) {
} }
}; };
@@ -76,5 +76,5 @@ public interface BindingTrace {
public void removeReferenceResolution(@NotNull JetReferenceExpression referenceExpression); public void removeReferenceResolution(@NotNull JetReferenceExpression referenceExpression);
public void recordFieldAccessFromAccessor(@NotNull PropertyDescriptor propertyDescriptor); public void requireBackingField(@NotNull PropertyDescriptor propertyDescriptor);
} }
@@ -53,8 +53,8 @@ public class BindingTraceAdapter implements BindingTrace {
} }
@Override @Override
public void recordFieldAccessFromAccessor(@NotNull PropertyDescriptor propertyDescriptor) { public void requireBackingField(@NotNull PropertyDescriptor propertyDescriptor) {
originalTrace.recordFieldAccessFromAccessor(propertyDescriptor); originalTrace.requireBackingField(propertyDescriptor);
} }
@Override @Override
@@ -4,28 +4,32 @@ package org.jetbrains.jet.lang.types;
* @author abreslav * @author abreslav
*/ */
public class DeclarationDescriptorVisitor<R, D> { public class DeclarationDescriptorVisitor<R, D> {
public R visitVariableDescriptor(VariableDescriptor descriptor, D data) { public R visitDeclarationDescriptor(DeclarationDescriptor descriptor, D data) {
return null; return null;
} }
public R visitVariableDescriptor(VariableDescriptor descriptor, D data) {
return visitDeclarationDescriptor(descriptor, data);
}
public R visitFunctionDescriptor(FunctionDescriptor descriptor, D data) { public R visitFunctionDescriptor(FunctionDescriptor descriptor, D data) {
return null; return visitDeclarationDescriptor(descriptor, data);
} }
public R visitTypeParameterDescriptor(TypeParameterDescriptor descriptor, D data) { public R visitTypeParameterDescriptor(TypeParameterDescriptor descriptor, D data) {
return null; return visitDeclarationDescriptor(descriptor, data);
} }
public R visitNamespaceDescriptor(NamespaceDescriptor namespaceDescriptor, D data) { public R visitNamespaceDescriptor(NamespaceDescriptor descriptor, D data) {
return null; return visitDeclarationDescriptor(descriptor, data);
} }
public R visitClassDescriptor(ClassDescriptor descriptor, D data) { public R visitClassDescriptor(ClassDescriptor descriptor, D data) {
return null; return visitDeclarationDescriptor(descriptor, data);
} }
public R visitModuleDeclaration(ModuleDescriptor descriptor, D data) { public R visitModuleDeclaration(ModuleDescriptor descriptor, D data) {
return null; return visitDeclarationDescriptor(descriptor, data);
} }
public R visitConstructorDescriptor(ConstructorDescriptor constructorDescriptor, D data) { public R visitConstructorDescriptor(ConstructorDescriptor constructorDescriptor, D data) {